diff --git a/.travis.yml b/.travis.yml
index 090a4291b3609aa4a214acbc64db8adf8e51356c..b313620187bb425e00375559ed176e68060f4b5c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -75,12 +75,12 @@ matrix:
       env: TEST_SUITE=AngularJSTests MYSQL_ADAPTER=PDO_MYSQL
     - php: hhvm
       env: TEST_SUITE=AngularJSTests MYSQL_ADAPTER=PDO_MYSQL
-    # Only run Mysqli tests on PHP 5.3
-    - php: 5.4
+    # Only run Mysqli tests on PHP 5.4
+    - php: 5.3.3
       env: TEST_SUITE=IntegrationTests MYSQL_ADAPTER=MYSQLI
-    - php: 5.4
+    - php: 5.3.3
       env: TEST_SUITE=PluginTests MYSQL_ADAPTER=MYSQLI
-    - php: 5.4
+    - php: 5.3.3
       env: TEST_SUITE=CoreTests MYSQL_ADAPTER=MYSQLI
     - php: 5.5
       env: TEST_SUITE=IntegrationTests MYSQL_ADAPTER=MYSQLI
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8e6ad088e26a8581b6cf551b37a813f9aad4046d..93a02516f4e309ecd0a70c08c6d5db3b5391a2fd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,13 @@ This is a changelog for Piwik platform developers. All changes for our HTTP API'
   * The following methods have been added: setPassword, setPasswordHash, getTokenAuthSecret and getLogin.
   * Clarifying semantics of each method and what they must support and can support.
   * **Read the documentation for the [Auth interface](http://developer.piwik.org/api-reference/Piwik/Auth) to learn more.**
+* The `Piwik\Unzip\*` classes have been extracted out of the Piwik repository into a separate component named [Decompress](https://github.com/piwik/component-decompress).
+  * `Piwik\Unzip` has not moved, it is kept for backward compatibility. If you have been using that class, you don't need to change anything.
+  * The `Piwik\Unzip\*` classes (Tar, PclZip, Gzip, ZipArchive) have moved to the `Piwik\Decompress\*` namespace (inside the new repository).
+  * `Piwik\Unzip\UncompressInterface` has been moved and renamed to `Piwik\Decompress\DecompressInterface` (inside the new repository).
+
+### Deprecations
+* The Piwik::setUserHasSuperUserAccess method is deprecated, instead use Access::doAsSuperUser. This method will ensure that super user access is properly rescinded after the callback finishes.
 
 ### New commands
 * `generate:angular-directive` Let's you easily generate a template for a new angular directive for any plugin.
diff --git a/composer.json b/composer.json
index be32b796bfc0f58d95a21e9be31f5e667460ac1a..270968a3ba475298d4468eefccbbd690203808ae 100644
--- a/composer.json
+++ b/composer.json
@@ -37,7 +37,8 @@
         "symfony/console": ">=v2.3.5",
         "tedivm/jshrink": "v0.5.1",
         "mustangostang/spyc": "0.5.*",
-        "piwik/device-detector": "2.*"
+        "piwik/device-detector": "2.*",
+        "piwik/decompress": "~0.1.0"
     },
     "require-dev": {
         "phpunit/phpunit": "~4.1",
diff --git a/composer.lock b/composer.lock
index 47fe2533ba01f89a0e900126c574d828ff5169c6..a8676c511ef5e216491b8257fbe84f3ec0ac97c7 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "hash": "37a6e1fcbf0ec87f900f82bf83c0804f",
+    "hash": "d9542e577717b3fa1b0fa3d1fee3803b",
     "packages": [
         {
             "name": "leafo/lessphp",
@@ -94,18 +94,53 @@
             ],
             "time": "2013-02-21 10:52:01"
         },
+        {
+            "name": "piwik/decompress",
+            "version": "0.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/piwik/component-decompress.git",
+                "reference": "f02c7f1d92b33955ce1b44a9623d8467fd2e2c49"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/piwik/component-decompress/zipball/f02c7f1d92b33955ce1b44a9623d8467fd2e2c49",
+                "reference": "f02c7f1d92b33955ce1b44a9623d8467fd2e2c49",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Piwik\\Decompress\\": "src/"
+                },
+                "classmap": [
+                    "libs/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-3.0"
+            ],
+            "time": "2014-10-02 22:01:11"
+        },
         {
             "name": "piwik/device-detector",
-            "version": "dev-master",
+            "version": "2.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/piwik/device-detector.git",
-                "reference": "1c7334cd35052b9b7661e13396d4da7a7f47e323"
+                "reference": "64d91375aea2340b81e2cb46745dc3b2213d3231"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/piwik/device-detector/zipball/1c7334cd35052b9b7661e13396d4da7a7f47e323",
-                "reference": "1c7334cd35052b9b7661e13396d4da7a7f47e323",
+                "url": "https://api.github.com/repos/piwik/device-detector/zipball/64d91375aea2340b81e2cb46745dc3b2213d3231",
+                "reference": "64d91375aea2340b81e2cb46745dc3b2213d3231",
                 "shasum": ""
             },
             "require": {
@@ -139,7 +174,7 @@
                 "parser",
                 "useragent"
             ],
-            "time": "2014-09-24 16:59:50"
+            "time": "2014-08-29 18:24:04"
         },
         {
             "name": "symfony/console",
@@ -438,6 +473,56 @@
             ],
             "time": "2013-11-09 22:30:54"
         },
+        {
+            "name": "pear/archive_tar",
+            "version": "1.3.11",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/pear/Archive_Tar.git",
+                "reference": "23341344e19bbab1056cf2d2773f28cfccf787a3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/pear/Archive_Tar/zipball/23341344e19bbab1056cf2d2773f28cfccf787a3",
+                "reference": "23341344e19bbab1056cf2d2773f28cfccf787a3",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=4.3.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Archive_Tar": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Michiel Rook",
+                    "email": "mrook@php.net",
+                    "role": "Lead"
+                },
+                {
+                    "name": "Vincent Blavet",
+                    "email": "vincent@phpconcept.net"
+                },
+                {
+                    "name": "Greg Beaver",
+                    "email": "greg@chiaraquartet.net"
+                }
+            ],
+            "description": "Tar file management class",
+            "homepage": "https://github.com/pear/Archive_Tar",
+            "keywords": [
+                "archive",
+                "tar"
+            ],
+            "time": "2013-02-09 11:44:32"
+        },
         {
             "name": "phpunit/php-code-coverage",
             "version": "2.0.11",
@@ -687,16 +772,16 @@
         },
         {
             "name": "phpunit/phpunit",
-            "version": "4.2.6",
+            "version": "4.2.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "c28a790620fe30b049bb693be1ef9cd4e0fe906c"
+                "reference": "c3abe5953d1e60a0bf23012b1bc8c4d07f4832d7"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c28a790620fe30b049bb693be1ef9cd4e0fe906c",
-                "reference": "c28a790620fe30b049bb693be1ef9cd4e0fe906c",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c3abe5953d1e60a0bf23012b1bc8c4d07f4832d7",
+                "reference": "c3abe5953d1e60a0bf23012b1bc8c4d07f4832d7",
                 "shasum": ""
             },
             "require": {
@@ -757,7 +842,7 @@
                 "testing",
                 "xunit"
             ],
-            "time": "2014-09-14 09:31:24"
+            "time": "2014-09-06 18:38:27"
         },
         {
             "name": "phpunit/phpunit-mock-objects",
@@ -1129,19 +1214,14 @@
             "time": "2014-08-31 03:22:04"
         }
     ],
-    "aliases": [
-
-    ],
+    "aliases": [],
     "minimum-stability": "stable",
     "stability-flags": {
-        "piwik/device-detector": 20,
         "facebook/xhprof": 20
     },
     "prefer-stable": false,
     "platform": {
         "php": ">=5.3.2"
     },
-    "platform-dev": [
-
-    ]
+    "platform-dev": []
 }
diff --git a/core/API/DataTableManipulator.php b/core/API/DataTableManipulator.php
index 69dc62063b3299773aef8a46e9ac891880ae7999..30513daaf3df76776bec40092a753f822903689a 100644
--- a/core/API/DataTableManipulator.php
+++ b/core/API/DataTableManipulator.php
@@ -141,6 +141,7 @@ abstract class DataTableManipulator
     /**
      * Extract the API method for loading subtables from the meta data
      *
+     * @throws Exception
      * @return string
      */
     private function getApiMethodForSubtable()
@@ -148,7 +149,7 @@ abstract class DataTableManipulator
         if (!$this->apiMethodForSubtable) {
             $meta = API::getInstance()->getMetadata('all', $this->apiModule, $this->apiMethod);
 
-            if(empty($meta)) {
+            if (empty($meta)) {
                 throw new Exception(sprintf(
                     "The DataTable cannot be manipulated: Metadata for report %s.%s could not be found. You can define the metadata in a hook, see example at: http://developer.piwik.org/api-reference/events#apigetreportmetadata",
                     $this->apiModule, $this->apiMethod
diff --git a/core/API/DataTableManipulator/Flattener.php b/core/API/DataTableManipulator/Flattener.php
index 211af52d2bf5b76f22dd78c543a232620db99378..cfee16e6ba8207c73a0975ef0151fa64712cc5d0 100644
--- a/core/API/DataTableManipulator/Flattener.php
+++ b/core/API/DataTableManipulator/Flattener.php
@@ -127,6 +127,7 @@ class Flattener extends DataTableManipulator
      * Remove the flat parameter from the subtable request
      *
      * @param array $request
+     * @return array
      */
     protected function manipulateSubtableRequest($request)
     {
diff --git a/core/API/DataTableManipulator/ReportTotalsCalculator.php b/core/API/DataTableManipulator/ReportTotalsCalculator.php
index 1dc3bc85d91bdf85a3b5e13afff0f8490483db45..1cbfeeb3623cf0445a280a501faa0b836ed26bcf 100644
--- a/core/API/DataTableManipulator/ReportTotalsCalculator.php
+++ b/core/API/DataTableManipulator/ReportTotalsCalculator.php
@@ -194,6 +194,7 @@ class ReportTotalsCalculator extends DataTableManipulator
      * Make sure to get all rows of the first level table.
      *
      * @param array $request
+     * @return array
      */
     protected function manipulateSubtableRequest($request)
     {
diff --git a/core/API/DocumentationGenerator.php b/core/API/DocumentationGenerator.php
index 668f97bb6064fea0561187bec506fad8cc7bce53..63ae943433c30b6defbf65cd270294df830d43b6 100644
--- a/core/API/DocumentationGenerator.php
+++ b/core/API/DocumentationGenerator.php
@@ -47,8 +47,8 @@ class DocumentationGenerator
         if (!empty($prefixUrls)) {
             $prefixUrls = 'http://demo.piwik.org/';
         }
+
         $str = $toc = '';
-        $token_auth = "&token_auth=" . Piwik::getCurrentUserTokenAuth();
         $parametersToSet = array(
             'idSite' => Common::getRequestVar('idSite', 1, 'int'),
             'period' => Common::getRequestVar('period', 'day', 'string'),
@@ -57,52 +57,38 @@ class DocumentationGenerator
 
         foreach (Proxy::getInstance()->getMetadata() as $class => $info) {
             $moduleName = Proxy::getInstance()->getModuleNameFromClassName($class);
+
             if (in_array($moduleName, $this->modulesToHide)) {
                 continue;
             }
+
             $toc .= "<a href='#$moduleName'>$moduleName</a><br/>";
-            $str .= "\n<a  name='$moduleName' id='$moduleName'></a><h2>Module " . $moduleName . "</h2>";
-            $str .= "<div class='apiDescription'> " . $info['__documentation'] . " </div>";
-            foreach ($info as $methodName => $infoMethod) {
-                if ($methodName == '__documentation') {
-                    continue;
-                }
-                $params = $this->getParametersString($class, $methodName);
-                $str .= "\n <div class='apiMethod'>- <b>$moduleName.$methodName </b>" . $params . "";
-                $str .= '<small>';
-
-                if ($outputExampleUrls) {
-                    // we prefix all URLs with $prefixUrls
-                    // used when we include this output in the Piwik official documentation for example
-                    $str .= "<span class=\"example\">";
-                    $exampleUrl = $this->getExampleUrl($class, $methodName, $parametersToSet);
-                    if ($exampleUrl !== false) {
-                        $lastNUrls = '';
-                        if (preg_match('/(&period)|(&date)/', $exampleUrl)) {
-                            $exampleUrlRss = $prefixUrls . $this->getExampleUrl($class, $methodName, array('date' => 'last10', 'period' => 'day') + $parametersToSet);
-                            $lastNUrls = ",	RSS of the last <a target=_blank href='$exampleUrlRss&format=rss$token_auth&translateColumnNames=1'>10 days</a>";
-                        }
-                        $exampleUrl = $prefixUrls . $exampleUrl;
-                        $str .= " [ Example in
-									<a target=_blank href='$exampleUrl&format=xml$token_auth'>XML</a>,
-									<a target=_blank href='$exampleUrl&format=JSON$token_auth'>Json</a>,
-									<a target=_blank href='$exampleUrl&format=Tsv$token_auth&translateColumnNames=1'>Tsv (Excel)</a>
-									$lastNUrls
-									]";
-                    } else {
-                        $str .= " [ No example available ]";
-                    }
-                    $str .= "</span>";
-                }
-                $str .= '</small>';
-                $str .= "</div>\n";
-            }
-            $str .= '<div style="margin:15px;"><a href="#topApiRef">↑ Back to top</a></div>';
+            $str .= $this->getInterfaceString($moduleName, $class, $info, $parametersToSet, $outputExampleUrls, $prefixUrls);
         }
 
         $str = "<h2 id='topApiRef' name='topApiRef'>Quick access to APIs</h2>
 				$toc
 				$str";
+
+        return $str;
+    }
+
+    private function getInterfaceString($moduleName, $class, $info, $parametersToSet, $outputExampleUrls, $prefixUrls)
+    {
+        $str = '';
+
+        $str .= "\n<a  name='$moduleName' id='$moduleName'></a><h2>Module " . $moduleName . "</h2>";
+        $str .= "<div class='apiDescription'> " . $info['__documentation'] . " </div>";
+        foreach ($info as $methodName => $infoMethod) {
+            if ($methodName == '__documentation') {
+                continue;
+            }
+
+            $str .= $this->getMethodString($moduleName, $class, $parametersToSet, $outputExampleUrls, $prefixUrls, $methodName, $str);
+        }
+
+        $str .= '<div style="margin:15px;"><a href="#topApiRef">↑ Back to top</a></div>';
+
         return $str;
     }
 
@@ -241,4 +227,43 @@ class DocumentationGenerator
         $sParameters = implode(", ", $asParameters);
         return "($sParameters)";
     }
+
+    private function getMethodString($moduleName, $class, $parametersToSet, $outputExampleUrls, $prefixUrls, $methodName)
+    {
+        $str = '';
+        $token_auth = "&token_auth=" . Piwik::getCurrentUserTokenAuth();
+
+        $params = $this->getParametersString($class, $methodName);
+        $str .= "\n <div class='apiMethod'>- <b>$moduleName.$methodName </b>" . $params . "";
+        $str .= '<small>';
+
+        if ($outputExampleUrls) {
+            // we prefix all URLs with $prefixUrls
+            // used when we include this output in the Piwik official documentation for example
+            $str .= "<span class=\"example\">";
+            $exampleUrl = $this->getExampleUrl($class, $methodName, $parametersToSet);
+            if ($exampleUrl !== false) {
+                $lastNUrls = '';
+                if (preg_match('/(&period)|(&date)/', $exampleUrl)) {
+                    $exampleUrlRss = $prefixUrls . $this->getExampleUrl($class, $methodName, array('date' => 'last10', 'period' => 'day') + $parametersToSet);
+                    $lastNUrls = ",	RSS of the last <a target=_blank href='$exampleUrlRss&format=rss$token_auth&translateColumnNames=1'>10 days</a>";
+                }
+                $exampleUrl = $prefixUrls . $exampleUrl;
+                $str .= " [ Example in
+									<a target=_blank href='$exampleUrl&format=xml$token_auth'>XML</a>,
+									<a target=_blank href='$exampleUrl&format=JSON$token_auth'>Json</a>,
+									<a target=_blank href='$exampleUrl&format=Tsv$token_auth&translateColumnNames=1'>Tsv (Excel)</a>
+									$lastNUrls
+									]";
+            } else {
+                $str .= " [ No example available ]";
+            }
+            $str .= "</span>";
+        }
+
+        $str .= '</small>';
+        $str .= "</div>\n";
+
+        return $str;
+    }
 }
diff --git a/core/API/Proxy.php b/core/API/Proxy.php
index d3e1fbad3ff15cf26813d22c7d93d305a74cad24..daaa5c9f4232c247243a3c7a5668b9c278646b41 100644
--- a/core/API/Proxy.php
+++ b/core/API/Proxy.php
@@ -24,7 +24,7 @@ use ReflectionMethod;
  *
  * It will also log the performance of API calls (time spent, parameter values, etc.) if logger available
  *
- * @method static \Piwik\API\Proxy getInstance()
+ * @method static Proxy getInstance()
  */
 class Proxy extends Singleton
 {
diff --git a/core/API/Request.php b/core/API/Request.php
index 03b555ad188fe33c6c6dca324dcb5275815cee76..64e8e054fa3dd0349e541a878e17c2c46517a055 100644
--- a/core/API/Request.php
+++ b/core/API/Request.php
@@ -70,7 +70,7 @@ use Piwik\Log;
  */
 class Request
 {
-    protected $request = null;
+    private $request = null;
 
     /**
      * Converts the supplied request string into an array of query paramater name/value
diff --git a/core/API/ResponseBuilder.php b/core/API/ResponseBuilder.php
index 17d5d488f7ad8ae9c180230be8b6524dd612cf59..401dccf96c5231899e3a65b9b03e7a114580a3cf 100644
--- a/core/API/ResponseBuilder.php
+++ b/core/API/ResponseBuilder.php
@@ -18,7 +18,6 @@ use Piwik\DataTable\Filter\PivotByDimension;
 use Piwik\DataTable\Renderer;
 use Piwik\DataTable\DataTableInterface;
 use Piwik\DataTable\Filter\ColumnDelete;
-use Piwik\Piwik;
 
 /**
  */
@@ -158,7 +157,7 @@ class ResponseBuilder
         return Renderer::formatValueXml($message);
     }
 
-    protected function handleDataTable(DataTableInterface $datatable)
+    private function handleDataTable(DataTableInterface $datatable)
     {
         $label = $this->getLabelFromRequest($this->request);
 
@@ -224,7 +223,7 @@ class ResponseBuilder
         return $this->apiRenderer->renderDataTable($datatable);
     }
 
-    protected function handleArray($array)
+    private function handleArray($array)
     {
         $firstArray = null;
         $firstKey   = null;
diff --git a/core/Access.php b/core/Access.php
index 00093e6e4f199c5a976bc9d397856c527fd0c3a6..578edaa04494828441b7c0bf0ff4ca9de47370f2 100644
--- a/core/Access.php
+++ b/core/Access.php
@@ -8,6 +8,7 @@
  */
 namespace Piwik;
 
+use Exception;
 use Piwik\Db;
 
 /**
@@ -33,29 +34,6 @@ use Piwik\Db;
  */
 class Access
 {
-    private static $instance = null;
-
-    /**
-     * Gets the singleton instance. Creates it if necessary.
-     */
-    public static function getInstance()
-    {
-        if (self::$instance == null) {
-            self::$instance = new self;
-
-            Piwik::postEvent('Access.createAccessSingleton', array(&self::$instance));
-        }
-        return self::$instance;
-    }
-
-    /**
-     * Sets the singleton instance. For testing purposes.
-     */
-    public static function setSingletonInstance($instance)
-    {
-        self::$instance = $instance;
-    }
-
     /**
      * Array of idsites available to the current user, indexed by permission level
      * @see getSitesIdWith*()
@@ -100,6 +78,29 @@ class Access
      */
     private $auth = null;
 
+    private static $instance = null;
+
+    /**
+     * Gets the singleton instance. Creates it if necessary.
+     */
+    public static function getInstance()
+    {
+        if (self::$instance == null) {
+            self::$instance = new self;
+
+            Piwik::postEvent('Access.createAccessSingleton', array(&self::$instance));
+        }
+        return self::$instance;
+    }
+
+    /**
+     * Sets the singleton instance. For testing purposes.
+     */
+    public static function setSingletonInstance($instance)
+    {
+        self::$instance = $instance;
+    }
+
     /**
      * Returns the list of the existing Access level.
      * Useful when a given API method requests a given acccess Level.
@@ -146,6 +147,14 @@ class Access
             if ($this->hasSuperUserAccess()) {
                 return $this->reloadAccessSuperUser();
             }
+        }
+
+        if ($this->hasSuperUserAccess()) {
+            return $this->reloadAccessSuperUser();
+        }
+
+        // if the Auth wasn't set, we may be in the special case of setSuperUser(), otherwise we fail TODO: docs + review
+        if ($this->auth === null) {
             return false;
         }
 
@@ -155,6 +164,7 @@ class Access
         if (!$result->wasAuthenticationSuccessful()) {
             return false;
         }
+
         $this->login = $result->getIdentity();
         $this->token_auth = $result->getTokenAuth();
 
@@ -162,21 +172,26 @@ class Access
         if ($result->hasSuperUserAccess()) {
             return $this->reloadAccessSuperUser();
         }
+
         // in case multiple calls to API using different tokens, we ensure we reset it as not SU
         $this->setSuperUserAccess(false);
 
         // we join with site in case there are rows in access for an idsite that doesn't exist anymore
         // (backward compatibility ; before we deleted the site without deleting rows in _access table)
         $accessRaw = $this->getRawSitesWithSomeViewAccess($this->login);
+
         foreach ($accessRaw as $access) {
             $this->idsitesByAccess[$access['access']][] = $access['idsite'];
         }
+
         return true;
     }
 
     public function getRawSitesWithSomeViewAccess($login)
     {
-        return Db::fetchAll(self::getSqlAccessSite("access, t2.idsite"), $login);
+        $sql = self::getSqlAccessSite("access, t2.idsite");
+
+        return Db::fetchAll($sql, $login);
     }
 
     /**
@@ -187,10 +202,11 @@ class Access
      */
     public static function getSqlAccessSite($select)
     {
-        return "SELECT " . $select . "
-				FROM " . Common::prefixTable('access') . " as t1
-				JOIN " . Common::prefixTable('site') . " as t2 USING (idsite) " .
-              " WHERE login = ?";
+        $access    = Common::prefixTable('access');
+        $siteTable = Common::prefixTable('site');
+
+        return "SELECT " . $select . " FROM " . $access . " as t1
+				JOIN " . $siteTable . " as t2 USING (idsite) WHERE login = ?";
     }
 
     /**
@@ -323,7 +339,9 @@ class Access
         if ($this->hasSuperUserAccess()) {
             return;
         }
+
         $idSitesAccessible = $this->getSitesIdWithAdminAccess();
+
         if (count($idSitesAccessible) == 0) {
             throw new NoAccessException(Piwik::translate('General_ExceptionPrivilegeAtLeastOneWebsite', array('admin')));
         }
@@ -339,7 +357,9 @@ class Access
         if ($this->hasSuperUserAccess()) {
             return;
         }
+
         $idSitesAccessible = $this->getSitesIdWithAtLeastViewAccess();
+
         if (count($idSitesAccessible) == 0) {
             throw new NoAccessException(Piwik::translate('General_ExceptionPrivilegeAtLeastOneWebsite', array('view')));
         }
@@ -357,8 +377,10 @@ class Access
         if ($this->hasSuperUserAccess()) {
             return;
         }
+
         $idSites = $this->getIdSites($idSites);
         $idSitesAccessible = $this->getSitesIdWithAdminAccess();
+
         foreach ($idSites as $idsite) {
             if (!in_array($idsite, $idSitesAccessible)) {
                 throw new NoAccessException(Piwik::translate('General_ExceptionPrivilegeAccessWebsite', array("'admin'", $idsite)));
@@ -378,8 +400,10 @@ class Access
         if ($this->hasSuperUserAccess()) {
             return;
         }
+
         $idSites = $this->getIdSites($idSites);
         $idSitesAccessible = $this->getSitesIdWithAtLeastViewAccess();
+
         foreach ($idSites as $idsite) {
             if (!in_array($idsite, $idSitesAccessible)) {
                 throw new NoAccessException(Piwik::translate('General_ExceptionPrivilegeAccessWebsite', array("'view'", $idsite)));
@@ -399,11 +423,41 @@ class Access
         }
 
         $idSites = Site::getIdSitesFromIdSitesString($idSites);
+
         if (empty($idSites)) {
             throw new NoAccessException("The parameter 'idSite=' is missing from the request.");
         }
+
         return $idSites;
     }
+
+    /**
+     * Executes a callback with superuser privileges, making sure those privileges are rescinded
+     * before this method exits. Privileges will be rescinded even if an exception is thrown.
+     *
+     * @param callback $function The callback to execute. Should accept no arguments.
+     * @return mixed The result of `$function`.
+     * @throws Exception rethrows any exceptions thrown by `$function`.
+     * @api
+     */
+    public static function doAsSuperUser($function)
+    {
+        $isSuperUser = self::getInstance()->hasSuperUserAccess();
+
+        self::getInstance()->setSuperUserAccess(true);
+
+        try {
+            $result = $function();
+        } catch (Exception $ex) {
+            self::getInstance()->setSuperUserAccess($isSuperUser);
+
+            throw $ex;
+        }
+
+        self::getInstance()->setSuperUserAccess($isSuperUser);
+
+        return $result;
+    }
 }
 
 /**
diff --git a/core/Archive.php b/core/Archive.php
index 65b5b915324871f3c8e212c261e798f38645bdff..7101850c1d90891b9a5b246dc7d98c8159709997 100644
--- a/core/Archive.php
+++ b/core/Archive.php
@@ -197,18 +197,23 @@ class Archive
     {
         $websiteIds = Site::getIdSitesFromIdSitesString($idSites, $_restrictSitesToLogin);
 
-        $timezone = count($websiteIds) == 1 ? Site::getTimezoneFor($websiteIds[0]) : false;
+        $timezone = false;
+        if (count($websiteIds) == 1) {
+            $timezone = Site::getTimezoneFor($websiteIds[0]);
+        }
 
         if (Period::isMultiplePeriod($strDate, $period)) {
-            $oPeriod = PeriodFactory::build($period, $strDate, $timezone);
+            $oPeriod    = PeriodFactory::build($period, $strDate, $timezone);
             $allPeriods = $oPeriod->getSubperiods();
         } else {
-            $oPeriod = PeriodFactory::makePeriodFromQueryParams($timezone, $period, $strDate);
+            $oPeriod    = PeriodFactory::makePeriodFromQueryParams($timezone, $period, $strDate);
             $allPeriods = array($oPeriod);
         }
-        $segment = new Segment($segment, $websiteIds);
-        $idSiteIsAll = $idSites == self::REQUEST_ALL_WEBSITES_FLAG;
+
+        $segment        = new Segment($segment, $websiteIds);
+        $idSiteIsAll    = $idSites == self::REQUEST_ALL_WEBSITES_FLAG;
         $isMultipleDate = Period::isMultiplePeriod($strDate, $period);
+
         return Archive::factory($segment, $allPeriods, $websiteIds, $idSiteIsAll, $isMultipleDate, $skipAggregationOfSubTables);
     }
 
@@ -239,9 +244,11 @@ class Archive
     {
         $forceIndexedBySite = false;
         $forceIndexedByDate = false;
+
         if ($idSiteIsAll || count($idSites) > 1) {
             $forceIndexedBySite = true;
         }
+
         if (count($periods) > 1 || $isMultipleDate) {
             $forceIndexedByDate = true;
         }
@@ -265,7 +272,7 @@ class Archive
      *
      * @param string|array $names One or more archive names, eg, `'nb_visits'`, `'Referrers_distinctKeywords'`,
      *                            etc.
-     * @return false|numeric|array `false` if there is no data to return, a single numeric value if we're not querying
+     * @return false|integer|array `false` if there is no data to return, a single numeric value if we're not querying
      *                             for multiple sites/periods, or an array if multiple sites, periods or names are
      *                             queried for.
      */
@@ -406,9 +413,11 @@ class Archive
     private function getRequestedPlugins($archiveNames)
     {
         $result = array();
+
         foreach ($archiveNames as $name) {
             $result[] = self::getPluginForReport($name);
         }
+
         return array_unique($result);
     }
 
@@ -436,6 +445,7 @@ class Archive
      * @param int|null $idSubtable See {@link getDataTableExpanded()}
      * @param bool $skipAggregationOfSubTables Whether or not we should skip the aggregation of all sub-tables and only aggregate parent DataTable.
      * @param int|null $depth See {@link getDataTableExpanded()}
+     * @throws \Exception
      * @return DataTable|DataTable\Map See {@link getDataTable()} and
      *                                 {@link getDataTableExpanded()} for more
      *                                 information
@@ -445,9 +455,10 @@ class Archive
     {
         Piwik::checkUserHasViewAccess($idSite);
 
-        if($skipAggregationOfSubTables && ($expanded || $idSubtable)) {
+        if ($skipAggregationOfSubTables && ($expanded || $idSubtable)) {
             throw new \Exception("Not expected to skipAggregationOfSubTables when expanded=1 or idSubtable is set.");
         }
+
         $archive = Archive::build($idSite, $period, $date, $segment, $_restrictSitesToLogin = false, $skipAggregationOfSubTables);
         if ($idSubtable === false) {
             $idSubtable = null;
@@ -495,6 +506,7 @@ class Archive
             $archiveNames, $archiveDataType, $this->params->getIdSites(), $this->params->getPeriods(), $defaultRow = null);
 
         $archiveIds = $this->getArchiveIds($archiveNames);
+
         if (empty($archiveIds)) {
             return $result;
         }
@@ -532,7 +544,7 @@ class Archive
 
         // figure out which archives haven't been processed (if an archive has been processed,
         // then we have the archive IDs in $this->idarchives)
-        $doneFlags = array();
+        $doneFlags     = array();
         $archiveGroups = array();
         foreach ($plugins as $plugin) {
             $doneFlag = $this->getDoneStringForPlugin($plugin);
@@ -541,7 +553,7 @@ class Archive
             if (!isset($this->idarchives[$doneFlag])) {
                 $archiveGroup = $this->getArchiveGroupOfPlugin($plugin);
 
-                if($archiveGroup == self::ARCHIVE_ALL_PLUGINS_FLAG) {
+                if ($archiveGroup == self::ARCHIVE_ALL_PLUGINS_FLAG) {
                     $archiveGroup = reset($plugins);
                 }
                 $archiveGroups[] = $archiveGroup;
@@ -559,19 +571,7 @@ class Archive
             }
         }
 
-        // order idarchives by the table month they belong to
-        $idArchivesByMonth = array();
-        foreach (array_keys($doneFlags) as $doneFlag) {
-            if (empty($this->idarchives[$doneFlag])) {
-                continue;
-            }
-
-            foreach ($this->idarchives[$doneFlag] as $dateRange => $idarchives) {
-                foreach ($idarchives as $id) {
-                    $idArchivesByMonth[$dateRange][] = $id;
-                }
-            }
-        }
+        $idArchivesByMonth = $this->getIdArchivesByMonth($doneFlags);
 
         return $idArchivesByMonth;
     }
@@ -800,9 +800,29 @@ class Archive
 
             $idArchive = $archiveLoader->prepareArchive($plugin);
 
-            if($idArchive) {
+            if ($idArchive) {
                 $this->idarchives[$doneFlag][$periodString][] = $idArchive;
             }
         }
     }
+
+    private function getIdArchivesByMonth($doneFlags)
+    {
+        // order idarchives by the table month they belong to
+        $idArchivesByMonth = array();
+
+        foreach (array_keys($doneFlags) as $doneFlag) {
+            if (empty($this->idarchives[$doneFlag])) {
+                continue;
+            }
+
+            foreach ($this->idarchives[$doneFlag] as $dateRange => $idarchives) {
+                foreach ($idarchives as $id) {
+                    $idArchivesByMonth[$dateRange][] = $id;
+                }
+            }
+        }
+
+        return $idArchivesByMonth;
+    }
 }
diff --git a/core/Archive/DataCollection.php b/core/Archive/DataCollection.php
index 89b435f9dcd96f0c89d552d81893a36faf70cd02..efd63cd925b3fa4cc6e3a0c110da2a3ba2551bbf 100644
--- a/core/Archive/DataCollection.php
+++ b/core/Archive/DataCollection.php
@@ -188,6 +188,7 @@ class DataCollection
                 $this->putRowInIndex($result, $indexKeys, $row, $idSite, $period);
             }
         }
+
         return $result;
     }
 
@@ -208,6 +209,7 @@ class DataCollection
             $this->dataNames, $this->dataType, $this->sitesId, $this->periods, $this->defaultRow);
 
         $index = $this->getIndexedArray($resultIndices);
+
         return $dataTableFactory->make($index, $resultIndices);
     }
 
@@ -249,6 +251,7 @@ class DataCollection
         $dataTableFactory->useSubtable($idSubTable);
 
         $index = $this->getIndexedArray($resultIndices);
+
         return $dataTableFactory->make($index, $resultIndices);
     }
 
diff --git a/core/Archive/DataTableFactory.php b/core/Archive/DataTableFactory.php
index 41806c62f967d0bbba56e56fb358e4330a0b5645..71eaa7a8c1b8db33f11be4dde542617a69c4ebab 100644
--- a/core/Archive/DataTableFactory.php
+++ b/core/Archive/DataTableFactory.php
@@ -154,6 +154,7 @@ class DataTableFactory
         }
 
         $this->transformMetadata($dataTable);
+
         return $dataTable;
     }
 
diff --git a/core/ArchiveProcessor.php b/core/ArchiveProcessor.php
index 2df309d69c50bbeb536725ce3953f712a13f25c3..71e90cde23aa3a93f107d98523d4e6b3a8b096f0 100644
--- a/core/ArchiveProcessor.php
+++ b/core/ArchiveProcessor.php
@@ -79,12 +79,12 @@ class ArchiveProcessor
     /**
      * @var \Piwik\DataAccess\ArchiveWriter
      */
-    protected $archiveWriter;
+    private $archiveWriter;
 
     /**
      * @var \Piwik\DataAccess\LogAggregator
      */
-    protected $logAggregator;
+    private $logAggregator;
 
     /**
      * @var Archive
@@ -94,14 +94,14 @@ class ArchiveProcessor
     /**
      * @var Parameters
      */
-    protected $params;
+    private $params;
 
     /**
      * @var int
      */
-    protected $numberOfVisits = false;
+    private $numberOfVisits = false;
 
-    protected $numberOfVisitsConverted = false;
+    private $numberOfVisitsConverted = false;
 
     /**
      * If true, unique visitors are not calculated when we are aggregating data for multiple sites.
@@ -125,11 +125,12 @@ class ArchiveProcessor
 
     protected function getArchive()
     {
-        if(empty($this->archive)) {
+        if (empty($this->archive)) {
             $subPeriods = $this->params->getSubPeriods();
-            $idSites = $this->params->getIdSites();
+            $idSites    = $this->params->getIdSites();
             $this->archive = Archive::factory($this->params->getSegment(), $subPeriods, $idSites);
         }
+
         return $this->archive;
     }
 
@@ -208,6 +209,7 @@ class ArchiveProcessor
         if (!is_array($recordNames)) {
             $recordNames = array($recordNames);
         }
+
         $nameToCount = array();
         foreach ($recordNames as $recordName) {
             $latestUsedTableId = Manager::getInstance()->getMostRecentTableId();
@@ -218,7 +220,7 @@ class ArchiveProcessor
             $nameToCount[$recordName]['level0'] = $rowsCount;
 
             $rowsCountRecursive = $rowsCount;
-            if($this->isAggregateSubTables()) {
+            if ($this->isAggregateSubTables()) {
                 $rowsCountRecursive = $table->getRowsCountRecursive();
             }
             $nameToCount[$recordName]['recursive'] = $rowsCountRecursive;
@@ -271,7 +273,7 @@ class ArchiveProcessor
 
     public function getNumberOfVisits()
     {
-        if($this->numberOfVisits === false) {
+        if ($this->numberOfVisits === false) {
             throw new Exception("visits should have been set here");
         }
         return $this->numberOfVisits;
@@ -343,7 +345,7 @@ class ArchiveProcessor
      */
     protected function aggregateDataTableRecord($name, $columnsAggregationOperation = null, $columnsToRenameAfterAggregation = null)
     {
-        if($this->isAggregateSubTables()) {
+        if ($this->isAggregateSubTables()) {
             // By default we shall aggregate all sub-tables.
             $dataTable = $this->getArchive()->getDataTableExpanded($name, $idSubTable = null, $depth = null, $addMetadataSubtableId = false);
         } else {
@@ -440,15 +442,18 @@ class ArchiveProcessor
     protected function getAggregatedDataTableMap($data, $columnsAggregationOperation)
     {
         $table = new DataTable();
+
         if (!empty($columnsAggregationOperation)) {
             $table->setMetadata(DataTable::COLUMN_AGGREGATION_OPS_METADATA_NAME, $columnsAggregationOperation);
         }
+
         if ($data instanceof DataTable\Map) {
             // as $date => $tableToSum
             $this->aggregatedDataTableMapsAsOne($data, $table);
         } else {
             $table->addDataTable($data, $this->isAggregateSubTables());
         }
+
         return $table;
     }
 
@@ -460,7 +465,7 @@ class ArchiveProcessor
     protected function aggregatedDataTableMapsAsOne(Map $map, DataTable $aggregated)
     {
         foreach ($map->getDataTables() as $tableToAggregate) {
-            if($tableToAggregate instanceof Map) {
+            if ($tableToAggregate instanceof Map) {
                 $this->aggregatedDataTableMapsAsOne($tableToAggregate, $aggregated);
             } else {
                 $aggregated->addDataTable($tableToAggregate, $this->isAggregateSubTables());
@@ -477,6 +482,7 @@ class ArchiveProcessor
         if (is_null($columnsToRenameAfterAggregation)) {
             $columnsToRenameAfterAggregation = self::$columnsToRenameAfterAggregation;
         }
+
         foreach ($columnsToRenameAfterAggregation as $oldName => $newName) {
             $table->renameColumn($oldName, $newName, $this->isAggregateSubTables());
         }
@@ -487,6 +493,7 @@ class ArchiveProcessor
         if (!is_array($columns)) {
             $columns = array($columns);
         }
+
         $operationForColumn = $this->getOperationForColumns($columns, $operationToApply);
 
         $dataTable = $this->getArchive()->getDataTableFromNumeric($columns);
@@ -497,7 +504,7 @@ class ArchiveProcessor
         }
 
         $rowMetrics = $results->getFirstRow();
-        if($rowMetrics === false) {
+        if ($rowMetrics === false) {
             $rowMetrics = new Row;
         }
         $this->enrichWithUniqueVisitorsMetric($rowMetrics);
@@ -510,6 +517,7 @@ class ArchiveProcessor
                 $metrics[$name] = 0;
             }
         }
+
         return $metrics;
     }
 
diff --git a/core/ArchiveProcessor/Loader.php b/core/ArchiveProcessor/Loader.php
index a4ffa4d12eb4a52f20113a18abbe87e460d9e802..b684d8fee1aa9540c174cc8db1d5997d959a0be1 100644
--- a/core/ArchiveProcessor/Loader.php
+++ b/core/ArchiveProcessor/Loader.php
@@ -10,7 +10,6 @@ namespace Piwik\ArchiveProcessor;
 use Piwik\Archive;
 use Piwik\ArchiveProcessor;
 use Piwik\Config;
-use Piwik\DataAccess\ArchivePurger;
 use Piwik\DataAccess\ArchiveSelector;
 use Piwik\Date;
 use Piwik\Period;
@@ -82,6 +81,7 @@ class Loader
      * Prepares the core metrics if needed.
      *
      * @param $visits
+     * @return array
      */
     protected function prepareCoreMetricsArchive($visits, $visitsConverted)
     {
@@ -102,12 +102,14 @@ class Loader
             $visits = $metrics['nb_visits'];
             $visitsConverted = $metrics['nb_visits_converted'];
         }
+
         return array($visits, $visitsConverted);
     }
 
     protected function prepareAllPluginsArchive($visits, $visitsConverted)
     {
         $pluginsArchiver = new PluginsArchiver($this->params, $this->isArchiveTemporary());
+
         if ($this->mustProcessVisitCount($visits)
             || $this->doesRequestedPluginIncludeVisitsSummary()
         ) {
@@ -115,9 +117,11 @@ class Loader
             $visits = $metrics['nb_visits'];
             $visitsConverted = $metrics['nb_visits_converted'];
         }
+
         if ($this->isThereSomeVisits($visits)) {
             $pluginsArchiver->callAggregateAllPlugins($visits, $visitsConverted);
         }
+
         $idArchive = $pluginsArchiver->finalizeArchive();
 
         return array($idArchive, $visits);
@@ -136,11 +140,13 @@ class Loader
     {
         $period = $this->params->getPeriod()->getLabel();
         $debugSetting = 'always_archive_data_period'; // default
+
         if ($period == 'day') {
             $debugSetting = 'always_archive_data_day';
         } elseif ($period == 'range') {
             $debugSetting = 'always_archive_data_range';
         }
+
         return (bool) Config::getInstance()->Debug[$debugSetting];
     }
 
@@ -162,9 +168,11 @@ class Loader
         }
 
         $idAndVisits = ArchiveSelector::getArchiveIdAndVisits($this->params, $minDatetimeArchiveProcessedUTC);
+
         if (!$idAndVisits) {
             return $noArchiveFound;
         }
+
         return $idAndVisits;
     }
 
@@ -183,19 +191,27 @@ class Loader
             // Permanent archive
             return $endDateTimestamp;
         }
+
+        $dateStart = $this->params->getDateStart();
+        $period    = $this->params->getPeriod();
+        $segment   = $this->params->getSegment();
+        $site      = $this->params->getSite();
+
         // Temporary archive
-        return Rules::getMinTimeProcessedForTemporaryArchive($this->params->getDateStart(), $this->params->getPeriod(), $this->params->getSegment(), $this->params->getSite());
+        return Rules::getMinTimeProcessedForTemporaryArchive($dateStart, $period, $segment, $site);
     }
 
     protected static function determineIfArchivePermanent(Date $dateEnd)
     {
         $now = time();
         $endTimestampUTC = strtotime($dateEnd->getDateEndUTC());
+
         if ($endTimestampUTC <= $now) {
             // - if the period we are looking for is finished, we look for a ts_archived that
             //   is greater than the last day of the archive
             return $endTimestampUTC;
         }
+
         return false;
     }
 
@@ -204,6 +220,7 @@ class Loader
         if (is_null($this->temporaryArchive)) {
             throw new \Exception("getMinTimeArchiveProcessed() should be called prior to isArchiveTemporary()");
         }
+
         return $this->temporaryArchive;
     }
 
diff --git a/core/ArchiveProcessor/Parameters.php b/core/ArchiveProcessor/Parameters.php
index 79cb1c719685fafe90ae19e3f3b7f2a06c684905..1528d8210c7964ac7683ed51cc06ef39a237a896 100644
--- a/core/ArchiveProcessor/Parameters.php
+++ b/core/ArchiveProcessor/Parameters.php
@@ -91,7 +91,7 @@ class Parameters
      */
     public function getSubPeriods()
     {
-        if($this->getPeriod()->getLabel() == 'day') {
+        if ($this->getPeriod()->getLabel() == 'day') {
             return array( $this->getPeriod() );
         }
         return $this->getPeriod()->getSubperiods();
diff --git a/core/ArchiveProcessor/PluginsArchiver.php b/core/ArchiveProcessor/PluginsArchiver.php
index 10f61287ed737bc84389d0768b0d34cc04b2c05e..2986d05dd3d34bdad76d113895b9105a8cc1d1bd 100644
--- a/core/ArchiveProcessor/PluginsArchiver.php
+++ b/core/ArchiveProcessor/PluginsArchiver.php
@@ -56,7 +56,7 @@ class PluginsArchiver
      */
     public function callAggregateCoreMetrics()
     {
-        if($this->isSingleSiteDayArchive) {
+        if ($this->isSingleSiteDayArchive) {
             $metrics = $this->aggregateDayVisitsMetrics();
         } else {
             $metrics = $this->aggregateMultipleVisitsMetrics();
@@ -92,11 +92,11 @@ class PluginsArchiver
             /** @var Archiver $archiver */
             $archiver = new $archiverClass($this->archiveProcessor);
 
-            if(!$archiver->isEnabled()) {
+            if (!$archiver->isEnabled()) {
                 continue;
             }
-            if($this->shouldProcessReportsForPlugin($pluginName)) {
-                if($this->isSingleSiteDayArchive) {
+            if ($this->shouldProcessReportsForPlugin($pluginName)) {
+                if ($this->isSingleSiteDayArchive) {
                     $archiver->aggregateDayReport();
                 } else {
                     $archiver->aggregateMultipleReports();
diff --git a/core/ArchiveProcessor/Rules.php b/core/ArchiveProcessor/Rules.php
index a64a4f81ad2ce4a9f2d9a6b9c344db9ac854515b..31b2fc380aa8cbcb0fd6053eaa870eea18e8e828 100644
--- a/core/ArchiveProcessor/Rules.php
+++ b/core/ArchiveProcessor/Rules.php
@@ -33,8 +33,6 @@ class Rules
 
     const FLAG_TABLE_PURGED = 'lastPurge_';
 
-    public static $purgeOutdatedArchivesIsDisabled = false;
-
     /** Flag that will forcefully disable the archiving process (used in tests only) */
     public static $archivingDisabledByTests = false;
 
@@ -129,16 +127,6 @@ class Rules
         return $doneFlags;
     }
 
-    public static function disablePurgeOutdatedArchives()
-    {
-        self::$purgeOutdatedArchivesIsDisabled = true;
-    }
-
-    public static function enablePurgeOutdatedArchives()
-    {
-        self::$purgeOutdatedArchivesIsDisabled = false;
-    }
-
     /**
      * Given a monthly archive table, will delete all reports that are now outdated,
      * or reports that ended with an error
@@ -148,9 +136,6 @@ class Rules
      */
     public static function shouldPurgeOutdatedArchives(Date $date)
     {
-        if (self::$purgeOutdatedArchivesIsDisabled) {
-            return false;
-        }
         $key = self::FLAG_TABLE_PURGED . "blob_" . $date->toString('Y_m');
         $timestamp = Option::get($key);
 
@@ -222,7 +207,7 @@ class Rules
     {
         $uiSettingIsEnabled = Controller::isGeneralSettingsAdminEnabled();
 
-        if($uiSettingIsEnabled) {
+        if ($uiSettingIsEnabled) {
             $timeToLive = Option::get(self::OPTION_TODAY_ARCHIVE_TTL);
             if ($timeToLive !== false) {
                 return $timeToLive;
@@ -266,7 +251,7 @@ class Rules
     {
         $uiSettingIsEnabled = Controller::isGeneralSettingsAdminEnabled();
 
-        if($uiSettingIsEnabled) {
+        if ($uiSettingIsEnabled) {
             $browserArchivingEnabled = Option::get(self::OPTION_BROWSER_TRIGGER_ARCHIVING);
             if ($browserArchivingEnabled !== false) {
                 return (bool)$browserArchivingEnabled;
diff --git a/core/AssetManager.php b/core/AssetManager.php
index 1badba4d9e676f84b2dd9bcf2cf16519f51e38a0..6759facb2b573f1ed0c66210d7cb1d7f24ba488e 100644
--- a/core/AssetManager.php
+++ b/core/AssetManager.php
@@ -37,7 +37,7 @@ use Piwik\Translate;
  * the global option 'disable_merged_assets'. See the documentation in the global
  * config for more information.
  *
- * @method static \Piwik\AssetManager getInstance()
+ * @method static AssetManager getInstance()
  */
 class AssetManager extends Singleton
 {
@@ -72,7 +72,7 @@ class AssetManager extends Singleton
         $this->minimalStylesheetFetcher =  new StaticUIAssetFetcher(array('plugins/Morpheus/stylesheets/base.less', 'plugins/Morpheus/stylesheets/general/_forms.less'), array(), $this->theme);
 
         $theme = Manager::getInstance()->getThemeEnabled();
-        if(!empty($theme)) {
+        if (!empty($theme)) {
             $this->theme = new Theme();
         }
     }
@@ -206,7 +206,7 @@ class AssetManager extends Singleton
             $pluginName = $plugin->getPluginName();
             $pluginIsCore = Manager::getInstance()->isPluginBundledWithCore($pluginName);
 
-            if(($pluginIsCore && $core) || (!$pluginIsCore && !$core))
+            if (($pluginIsCore && $core) || (!$pluginIsCore && !$core))
                 $loadedPlugins[] = $pluginName;
         }
 
@@ -220,12 +220,12 @@ class AssetManager extends Singleton
     {
         $assetsToRemove = array($this->getMergedStylesheetAsset());
 
-        if($pluginName) {
+        if ($pluginName) {
 
-            if($this->pluginContainsJScriptAssets($pluginName)) {
+            if ($this->pluginContainsJScriptAssets($pluginName)) {
 
                 PiwikConfig::getInstance()->init();
-                if(Manager::getInstance()->isPluginBundledWithCore($pluginName)) {
+                if (Manager::getInstance()->isPluginBundledWithCore($pluginName)) {
 
                     $assetsToRemove[] = $this->getMergedCoreJSAsset();
 
@@ -347,13 +347,13 @@ class AssetManager extends Singleton
 
         $plugin = Manager::getInstance()->getLoadedPlugin($pluginName);
 
-        if($plugin->isTheme()) {
+        if ($plugin->isTheme()) {
 
             $theme = Manager::getInstance()->getTheme($pluginName);
 
             $javaScriptFiles = $theme->getJavaScriptFiles();
 
-            if(!empty($javaScriptFiles))
+            if (!empty($javaScriptFiles))
                 $assets = array_merge($assets, $javaScriptFiles);
         }
 
diff --git a/core/AssetManager/UIAssetCatalog.php b/core/AssetManager/UIAssetCatalog.php
index d8a45f89646d927cabbf93dd60b189aed506b370..826259ecb3725cee3f147d776133946abcbb7b45 100644
--- a/core/AssetManager/UIAssetCatalog.php
+++ b/core/AssetManager/UIAssetCatalog.php
@@ -40,7 +40,7 @@ class UIAssetCatalog
     {
         $location = $uiAsset->getAbsoluteLocation();
 
-        if(!$this->assetAlreadyInCatalog($location)) {
+        if (!$this->assetAlreadyInCatalog($location)) {
             $this->existingAssetLocations[] = $location;
             $this->uiAssets[] = $uiAsset;
         }
diff --git a/core/AssetManager/UIAssetFetcher.php b/core/AssetManager/UIAssetFetcher.php
index 955ced51a75b3ef99fbab9c859896024266d8972..3bd34c118e60f9f127164d82365ca01e41b97814 100644
--- a/core/AssetManager/UIAssetFetcher.php
+++ b/core/AssetManager/UIAssetFetcher.php
@@ -56,7 +56,7 @@ abstract class UIAssetFetcher
      */
     public function getCatalog()
     {
-        if($this->catalog == null)
+        if ($this->catalog == null)
             $this->createCatalog();
 
         return $this->catalog;
diff --git a/core/AssetManager/UIAssetFetcher/JScriptUIAssetFetcher.php b/core/AssetManager/UIAssetFetcher/JScriptUIAssetFetcher.php
index a5ab3d096d5a745c2824647c241aba6c290a8498..5600068e44d79d2416e2cd366b53376b8fbaf7f4 100644
--- a/core/AssetManager/UIAssetFetcher/JScriptUIAssetFetcher.php
+++ b/core/AssetManager/UIAssetFetcher/JScriptUIAssetFetcher.php
@@ -18,7 +18,7 @@ class JScriptUIAssetFetcher extends UIAssetFetcher
     protected function retrieveFileLocations()
     {
 
-        if(!empty($this->plugins)) {
+        if (!empty($this->plugins)) {
 
             /**
              * Triggered when gathering the list of all JavaScript files needed by Piwik
@@ -53,14 +53,14 @@ class JScriptUIAssetFetcher extends UIAssetFetcher
     protected function addThemeFiles()
     {
         $theme = $this->getTheme();
-        if(!$theme) {
+        if (!$theme) {
             return;
         }
-        if(in_array($theme->getThemeName(), $this->plugins)) {
+        if (in_array($theme->getThemeName(), $this->plugins)) {
 
             $jsInThemes = $this->getTheme()->getJavaScriptFiles();
 
-            if(!empty($jsInThemes)) {
+            if (!empty($jsInThemes)) {
 
                 foreach($jsInThemes as $jsFile) {
 
diff --git a/core/AssetManager/UIAssetFetcher/StylesheetUIAssetFetcher.php b/core/AssetManager/UIAssetFetcher/StylesheetUIAssetFetcher.php
index 47a78a47cae02138a4cedb18d5ecf74b8991cf89..47ac94d04b27f6d094878365e99df87307d29246 100644
--- a/core/AssetManager/UIAssetFetcher/StylesheetUIAssetFetcher.php
+++ b/core/AssetManager/UIAssetFetcher/StylesheetUIAssetFetcher.php
@@ -18,7 +18,6 @@ class StylesheetUIAssetFetcher extends UIAssetFetcher
         $theme = $this->getTheme();
         $themeName = $theme->getThemeName();
 
-        $themeName = $this->getTheme()->getThemeName();
         $order = array(
             'libs/',
             'plugins/CoreHome/stylesheets/color_manager.css', // must be before other Piwik stylesheets
@@ -72,7 +71,7 @@ class StylesheetUIAssetFetcher extends UIAssetFetcher
     protected function addThemeFiles()
     {
         $theme = $this->getTheme();
-        if(!$theme) {
+        if (!$theme) {
             return;
         }
         $themeStylesheet = $this->getTheme()->getStylesheet();
diff --git a/core/AssetManager/UIAssetMerger.php b/core/AssetManager/UIAssetMerger.php
index 8850de512b45939fd33a6888f661820bd4b8233b..42b5ce0cfee25954d9fe6301801eada6c8ef8d51 100644
--- a/core/AssetManager/UIAssetMerger.php
+++ b/core/AssetManager/UIAssetMerger.php
@@ -48,7 +48,7 @@ abstract class UIAssetMerger
 
     public function generateFile()
     {
-        if(!$this->shouldGenerate())
+        if (!$this->shouldGenerate())
             return;
 
         $this->mergedContent = $this->getMergedAssets();
@@ -138,8 +138,9 @@ abstract class UIAssetMerger
      */
     private function shouldGenerate()
     {
-        if(!$this->mergedAsset->exists())
+        if (!$this->mergedAsset->exists()) {
             return true;
+        }
 
         return !$this->isFileUpToDate();
     }
@@ -162,19 +163,11 @@ abstract class UIAssetMerger
         return false;
     }
 
-    /**
-     * @return boolean
-     */
-    private function isMergedAssetsDisabled()
-    {
-        return AssetManager::getInstance()->isMergedAssetsDisabled();
-    }
-
     private function adjustPaths()
     {
         $theme = $this->assetFetcher->getTheme();
         // During installation theme is not yet ready
-        if($theme) {
+        if ($theme) {
             $this->mergedContent = $this->assetFetcher->getTheme()->rewriteAssetsPathToTheme($this->mergedContent);
         }
     }
@@ -189,7 +182,7 @@ abstract class UIAssetMerger
      */
     protected function getCacheBusterValue()
     {
-        if(empty($this->cacheBusterValue))
+        if (empty($this->cacheBusterValue))
             $this->cacheBusterValue = $this->generateCacheBuster();
 
         return $this->cacheBusterValue;
@@ -199,12 +192,4 @@ abstract class UIAssetMerger
     {
         $this->mergedContent = $this->getPreamble() . $this->mergedContent;
     }
-
-    /**
-     * @return boolean
-     */
-    private function shouldCompareExistingVersion()
-    {
-        return $this->isMergedAssetsDisabled();
-    }
 }
diff --git a/core/AssetManager/UIAssetMerger/JScriptUIAssetMerger.php b/core/AssetManager/UIAssetMerger/JScriptUIAssetMerger.php
index bfb2442279f30e73a35c0637df79ae857be5b7ed..935018c580b94c9fe0ad88d9c0ca407660d18b4e 100644
--- a/core/AssetManager/UIAssetMerger/JScriptUIAssetMerger.php
+++ b/core/AssetManager/UIAssetMerger/JScriptUIAssetMerger.php
@@ -57,7 +57,7 @@ class JScriptUIAssetMerger extends UIAssetMerger
     {
         $plugins = $this->getPlugins();
 
-        if(!empty($plugins)) {
+        if (!empty($plugins)) {
 
             /**
              * Triggered after all the JavaScript files Piwik uses are minified and merged into a
diff --git a/core/AssetManager/UIAssetMinifier.php b/core/AssetManager/UIAssetMinifier.php
index 5f738092cc486eeba4faafcdd903bfefa9835f85..07dd3c769dcfa70b22966f6fab5e38d0e9a1c0c3 100644
--- a/core/AssetManager/UIAssetMinifier.php
+++ b/core/AssetManager/UIAssetMinifier.php
@@ -36,6 +36,7 @@ class UIAssetMinifier extends Singleton
     public function isMinifiedJs($content)
     {
         $lineCount = substr_count($content, "\n");
+
         if ($lineCount == 0) {
             return true;
         }
diff --git a/core/Auth.php b/core/Auth.php
index 5c858010c46df411434b77d6a8cccfa93f171fa4..8e3a1e28e98646bd0aaa44620e9b53536d050a94 100644
--- a/core/Auth.php
+++ b/core/Auth.php
@@ -12,20 +12,39 @@ namespace Piwik;
 use Exception;
 
 /**
- * Base for authentication implementations. Plugins that provide Auth implementations
- * must provide a class that implements this interface. Additionally, an instance
- * of that class must be set in the {@link \Piwik\Registry} class with the 'auth'
- * key during the {@link Request.initAuthenticationObject} event.
+ * Base interface for authentication implementations.
+ *
+ * Plugins that provide Auth implementations must provide a class that implements
+ * this interface. Additionally, an instance of that class must be set in the
+ * {@link \Piwik\Registry} class with the 'auth' key during the
+ * [Request.initAuthenticationObject](http://developer.piwik.org/api-reference/events#requestinitauthenticationobject)
+ * event.
  *
  * Authentication implementations must support authentication via username and
  * clear-text password and authentication via username and token auth. They can
  * additionally support authentication via username and an MD5 hash of a password. If
- * they don't support it, then formless authentication will fail.
+ * they don't support it, then [formless authentication](http://piwik.org/faq/how-to/faq_30/) will fail.
  *
  * Derived implementations should favor authenticating by password over authenticating
  * by token auth. That is to say, if a token auth and a password are set, password
  * authentication should be used.
  *
+ * ### Examples
+ *
+ * **How an Auth implementation will be used**
+ *
+ *     // authenticating by password
+ *     $auth = \Piwik\Registry::get('auth');
+ *     $auth->setLogin('user');
+ *     $auth->setPassword('password');
+ *     $result = $auth->authenticate();
+ *
+ *     // authenticating by token auth
+ *     $auth = \Piwik\Registry::get('auth');
+ *     $auth->setLogin('user');
+ *     $auth->setTokenAuth('...');
+ *     $result = $auth->authenticate();
+ *
  * @api
  */
 interface Auth
@@ -59,7 +78,7 @@ interface Auth
      * uses an MD5 hash of a user's password.
      *
      * @return string
-     * @throws Exception if the token auth cannot be calculated at the current time.
+     * @throws Exception if the token auth secret does not exist or cannot be obtained.
      */
     public function getTokenAuthSecret();
 
@@ -95,6 +114,9 @@ interface Auth
      * {@link Piwik\Plugins\Login\SessionInitializer::getHashTokenAuth()} method.
      *
      * @return AuthResult
+     * @throws Exception if the Auth implementation has an invalid state (ie, no login
+     *                   was specified). Note: implementations are not **required** to throw
+     *                   exceptions for invalid state, but they are allowed to.
      */
     public function authenticate();
 }
diff --git a/core/BaseFactory.php b/core/BaseFactory.php
index 6f09f952efdbe74225dce4aade4f5864d5844a51..0bc8716eb2c03552018a830fb6f7a3efba90a79f 100644
--- a/core/BaseFactory.php
+++ b/core/BaseFactory.php
@@ -9,7 +9,6 @@
 namespace Piwik;
 
 use Exception;
-use Piwik\Common;
 
 /**
  * Base class for all factory types.
diff --git a/core/CacheFile.php b/core/CacheFile.php
index 9eb0587595219483a264d52d55275e264ec14677..48a23004bf3521a93264f7c2ca6883ac8f3ad41d 100644
--- a/core/CacheFile.php
+++ b/core/CacheFile.php
@@ -25,11 +25,7 @@ class CacheFile
     /**
      * @var string
      */
-    protected $cachePath;
-    /**
-     * @var
-     */
-    protected $cachePrefix;
+    private $cachePath;
 
     /**
      * Minimum enforced TTL in seconds
@@ -67,11 +63,12 @@ class CacheFile
         if (empty($id)) {
             return false;
         }
+
         $id = $this->cleanupId($id);
 
         $cache_complete = false;
-        $content = '';
-        $expires_on = false;
+        $content        = '';
+        $expires_on     = false;
 
         // We are assuming that most of the time cache will exists
         $cacheFilePath = $this->cachePath . $id . '.php';
@@ -88,6 +85,7 @@ class CacheFile
             ) {
                 return false;
             }
+
             return $content;
         }
 
@@ -104,6 +102,7 @@ class CacheFile
         if (!Filesystem::isValidFilename($id)) {
             throw new Exception("Invalid cache ID request $id");
         }
+
         return $id;
     }
 
@@ -120,25 +119,23 @@ class CacheFile
         if (empty($id)) {
             return false;
         }
+
         if (!is_dir($this->cachePath)) {
             Filesystem::mkdir($this->cachePath);
         }
+
         if (!is_writable($this->cachePath)) {
             return false;
         }
-        $id = $this->cleanupId($id);
 
+        $id = $this->cleanupId($id);
         $id = $this->cachePath . $id . '.php';
 
         if (is_object($content)) {
             throw new \Exception('You cannot use the CacheFile to cache an object, only arrays, strings and numbers.');
         }
 
-        $cache_literal = "<" . "?php\n";
-        $cache_literal .= "$" . "content   = " . var_export($content, true) . ";\n";
-        $cache_literal .= "$" . "expires_on   = " . $this->getExpiresTime() . ";\n";
-        $cache_literal .= "$" . "cache_complete   = true;\n";
-        $cache_literal .= "?" . ">";
+        $cache_literal = $this->buildCacheLiteral($content);
 
         // Write cache to a temp file, then rename it, overwriting the old cache
         // On *nix systems this should guarantee atomicity
@@ -162,6 +159,7 @@ class CacheFile
 
             return true;
         }
+
         return false;
     }
 
@@ -176,14 +174,17 @@ class CacheFile
         if (empty($id)) {
             return false;
         }
+
         $id = $this->cleanupId($id);
 
         $filename = $this->cachePath . $id . '.php';
+
         if (file_exists($filename)) {
             $this->opCacheInvalidate($filename);
             @unlink($filename);
             return true;
         }
+
         return false;
     }
 
@@ -218,8 +219,19 @@ class CacheFile
                 @opcache_invalidate($filepath, $force = true);
             }
             if (function_exists('apc_delete_file')) {
-                apc_delete_file($filepath);
+                @apc_delete_file($filepath);
             }
         }
     }
+
+    private function buildCacheLiteral($content)
+    {
+        $cache_literal  = "<" . "?php\n";
+        $cache_literal .= "$" . "content   = " . var_export($content, true) . ";\n";
+        $cache_literal .= "$" . "expires_on   = " . $this->getExpiresTime() . ";\n";
+        $cache_literal .= "$" . "cache_complete   = true;\n";
+        $cache_literal .= "?" . ">";
+
+        return $cache_literal;
+    }
 }
diff --git a/core/CliMulti.php b/core/CliMulti.php
index 21e0ee0b0dd773b29cbe5b479653ad2e103e004a..6de96af5b01e90b6598e2c99736db779ca3be91c 100644
--- a/core/CliMulti.php
+++ b/core/CliMulti.php
@@ -58,13 +58,15 @@ class CliMulti {
     public function request(array $piwikUrls)
     {
         $chunks = array($piwikUrls);
-        if($this->concurrentProcessesLimit) {
+        if ($this->concurrentProcessesLimit) {
             $chunks = array_chunk( $piwikUrls, $this->concurrentProcessesLimit);
         }
+
         $results = array();
         foreach($chunks as $urlsChunk) {
             $results = array_merge($results, $this->requestUrls($urlsChunk));
         }
+
         return $results;
     }
 
@@ -89,17 +91,22 @@ class CliMulti {
     private function start($piwikUrls)
     {
         foreach ($piwikUrls as $index => $url) {
-            $cmdId  = $this->generateCommandId($url) . $index;
-            $output = new Output($cmdId);
+            $cmdId = $this->generateCommandId($url) . $index;
+            $this->executeUrlCommand($cmdId, $url);
+        }
+    }
 
-            if ($this->supportsAsync) {
-                $this->executeAsyncCli($url, $output, $cmdId);
-            } else {
-                $this->executeNotAsyncHttp($url, $output);
-            }
+    private function executeUrlCommand($cmdId, $url)
+    {
+        $output = new Output($cmdId);
 
-            $this->outputs[] = $output;
+        if ($this->supportsAsync) {
+            $this->executeAsyncCli($url, $output, $cmdId);
+        } else {
+            $this->executeNotAsyncHttp($url, $output);
         }
+
+        $this->outputs[] = $output;
     }
 
     private function buildCommand($hostname, $query, $outputFile)
@@ -192,7 +199,7 @@ class CliMulti {
         $timeOneWeekAgo = strtotime('-1 week');
 
         $files = _glob(self::getTmpPath() . '/*');
-        if(empty($files)) {
+        if (empty($files)) {
             return;
         }
 
diff --git a/core/CliMulti/CliPhp.php b/core/CliMulti/CliPhp.php
index df82e05376787703b51b4f3c9dd31c219a455eae..9ee5b191b1b7c50af37bcfb852d795c9b77cd1d1 100644
--- a/core/CliMulti/CliPhp.php
+++ b/core/CliMulti/CliPhp.php
@@ -18,12 +18,12 @@ class CliPhp
     {
         if (defined('PHP_BINARY')) {
 
-            if($this->isValidPhpType(PHP_BINARY)) {
-                return PHP_BINARY . ' -q';
+            if ($this->isHhvmBinary(PHP_BINARY)) {
+                return PHP_BINARY . ' --php';
             }
 
-            if($this->isHhvmBinary(PHP_BINARY)) {
-                return PHP_BINARY . ' --php';
+            if ($this->isValidPhpType(PHP_BINARY)) {
+                return PHP_BINARY . ' -q';
             }
         }
 
diff --git a/core/CliMulti/Process.php b/core/CliMulti/Process.php
index e8dfb662a4ab4261e27ffa2234c88bfd38d5650e..15dc539e59c7b67c315fc243e66575c20d268cef 100644
--- a/core/CliMulti/Process.php
+++ b/core/CliMulti/Process.php
@@ -154,7 +154,7 @@ class Process
             return false;
         }
 
-        if(!self::isProcFSMounted()) {
+        if (!self::isProcFSMounted()) {
             return false;
         }
 
@@ -169,11 +169,11 @@ class Process
     {
         $uname = @shell_exec('uname -a');
 
-        if(empty($uname)) {
+        if (empty($uname)) {
             $uname = php_uname();
         }
 
-        if(strpos($uname, 'synology') !== false) {
+        if (strpos($uname, 'synology') !== false) {
             return true;
         }
         return false;
@@ -208,12 +208,12 @@ class Process
      */
     private static function isProcFSMounted()
     {
-        if(is_resource(@fopen('/proc', 'r'))) {
+        if (is_resource(@fopen('/proc', 'r'))) {
             return true;
         }
         // Testing if /proc is a resource with @fopen fails on systems with open_basedir set.
         // by using stat we not only test the existance of /proc but also confirm it's a 'proc' filesystem
-        $type = shell_exec('stat -f -c "%T" /proc 2>/dev/null');
+        $type = @shell_exec('stat -f -c "%T" /proc 2>/dev/null');
         return strpos($type, 'proc') === 0;
     }
 
diff --git a/core/Columns/Updater.php b/core/Columns/Updater.php
index 2dd6e4040e8e55ea5552092c580803f04eab0167..1bc53607ca27a9983d2ced5b487f2dcea9e82f8b 100644
--- a/core/Columns/Updater.php
+++ b/core/Columns/Updater.php
@@ -87,17 +87,17 @@ class Updater extends \Piwik\Updates
 
         $changingColumns = array();
 
-        foreach (VisitDimension::getAllDimensions() as $dimension) {
+        foreach (self::getVisitDimensions() as $dimension) {
             $updates         = self::getUpdatesForDimension($dimension, 'log_visit.', $visitColumns, $conversionColumns);
             $changingColumns = self::mixinUpdates($changingColumns, $updates);
         }
 
-        foreach (ActionDimension::getAllDimensions() as $dimension) {
+        foreach (self::getActionDimensions() as $dimension) {
             $updates         = self::getUpdatesForDimension($dimension, 'log_link_visit_action.', $actionColumns);
             $changingColumns = self::mixinUpdates($changingColumns, $updates);
         }
 
-        foreach (ConversionDimension::getAllDimensions() as $dimension) {
+        foreach (self::getConversionDimensions() as $dimension) {
             $updates         = self::getUpdatesForDimension($dimension, 'log_conversion.', $conversionColumns);
             $changingColumns = self::mixinUpdates($changingColumns, $updates);
         }
@@ -167,15 +167,15 @@ class Updater extends \Piwik\Updates
         $actionColumns     = DbHelper::getTableColumns(Common::prefixTable('log_link_visit_action'));
         $conversionColumns = DbHelper::getTableColumns(Common::prefixTable('log_conversion'));
 
-        foreach (VisitDimension::getAllDimensions() as $dimension) {
+        foreach (self::getVisitDimensions() as $dimension) {
             $versions = self::mixinVersions($dimension, 'log_visit.', $visitColumns, $versions);
         }
 
-        foreach (ActionDimension::getAllDimensions() as $dimension) {
+        foreach (self::getActionDimensions() as $dimension) {
             $versions = self::mixinVersions($dimension, 'log_link_visit_action.', $actionColumns, $versions);
         }
 
-        foreach (ConversionDimension::getAllDimensions() as $dimension) {
+        foreach (self::getConversionDimensions() as $dimension) {
             $versions = self::mixinVersions($dimension, 'log_conversion.', $conversionColumns, $versions);
         }
 
@@ -327,4 +327,25 @@ class Updater extends \Piwik\Updates
 
         return array();
     }
+
+    private static function getVisitDimensions()
+    {
+        return VisitDimension::getAllDimensions();
+    }
+
+    /**
+     * @return mixed|Dimension[]
+     */
+    private static function getActionDimensions()
+    {
+        return ActionDimension::getAllDimensions();
+    }
+
+    /**
+     * @return mixed|Dimension[]
+     */
+    private static function getConversionDimensions()
+    {
+        return ConversionDimension::getAllDimensions();
+    }
 }
diff --git a/core/Common.php b/core/Common.php
index d9ddf0be25609755ba881902a74043d835571f6b..5c1391bfdb65414abf1f8949e58c1e65a39f91b7 100644
--- a/core/Common.php
+++ b/core/Common.php
@@ -362,10 +362,13 @@ class Common
      */
     private static function undoMagicQuotes($value)
     {
-        return version_compare(PHP_VERSION, '5.4', '<')
-            && get_magic_quotes_gpc()
-            ? stripslashes($value)
-            : $value;
+        if (version_compare(PHP_VERSION, '5.4', '<') &&
+            get_magic_quotes_gpc()) {
+
+            $value = stripslashes($value);
+        }
+
+        return $value;
     }
 
     /**
@@ -375,8 +378,7 @@ class Common
      */
     public static function sanitizeLineBreaks($value)
     {
-        $value = str_replace(array("\n", "\r", "\0"), '', $value);
-        return $value;
+        return str_replace(array("\n", "\r", "\0"), '', $value);
     }
 
     /**
@@ -406,6 +408,7 @@ class Common
         if (is_null($requestArrayToUse)) {
             $requestArrayToUse = $_GET + $_POST;
         }
+
         $varDefault = self::sanitizeInputValues($varDefault);
         if ($varType === 'int') {
             // settype accepts only integer
@@ -469,6 +472,7 @@ class Common
             }
             settype($value, $varType);
         }
+
         return $value;
     }
 
@@ -496,14 +500,17 @@ class Common
     public static function hash($str, $raw_output = false)
     {
         static $hashAlgorithm = null;
+
         if (is_null($hashAlgorithm)) {
             $hashAlgorithm = @Config::getInstance()->General['hash_algorithm'];
         }
 
         if ($hashAlgorithm) {
             $hash = @hash($hashAlgorithm, $str, $raw_output);
-            if ($hash !== false)
+            if ($hash !== false) {
+
                 return $hash;
+            }
         }
 
         return md5($str, $raw_output);
@@ -520,7 +527,7 @@ class Common
     public static function getRandomString($length = 16, $alphabet = "abcdefghijklmnoprstuvwxyz0123456789")
     {
         $chars = $alphabet;
-        $str = '';
+        $str   = '';
 
         list($usec, $sec) = explode(" ", microtime());
         $seed = ((float)$sec + (float)$usec) * 100000;
@@ -530,6 +537,7 @@ class Common
             $rand_key = mt_rand(0, strlen($chars) - 1);
             $str .= substr($chars, $rand_key, 1);
         }
+
         return str_shuffle($str);
     }
 
@@ -571,6 +579,7 @@ class Common
         ) {
             throw new Exception("visitorId is expected to be a " . Tracker::LENGTH_HEX_ID_STRING . " hex char string");
         }
+
         return self::hex2bin($id);
     }
 
@@ -584,6 +593,7 @@ class Common
     {
         require_once PIWIK_INCLUDE_PATH . '/libs/PiwikTracker/PiwikTracker.php';
         $userIdHashed = \PiwikTracker::getUserIdHashed($userId);
+
         return self::convertVisitorIdToBin($userIdHashed);
     }
 
@@ -730,6 +740,7 @@ class Common
         if ($includeInternalCodes) {
             return array_merge($countriesList, $extras);
         }
+
         return $countriesList;
     }
 
@@ -1054,7 +1065,7 @@ class Common
     public static function sendHeader($header, $replace = true)
     {
         // don't send header in CLI mode
-        if(!Common::isPhpCliMode() and !headers_sent()) {
+        if (!Common::isPhpCliMode() and !headers_sent()) {
             header($header, $replace);
         }
     }
diff --git a/core/Config.php b/core/Config.php
index 9d6326bb2e76dea8cbb6e291d86cde6adfd30c0a..749c585647c96bf65b1bd90d328fc22a5071f380 100644
--- a/core/Config.php
+++ b/core/Config.php
@@ -36,7 +36,7 @@ use Exception;
  *     Config::getInstance()->MySection = array('myoption' => 1);
  *     Config::getInstance()->forceSave();
  *
- * @method static \Piwik\Config getInstance()
+ * @method static Config getInstance()
  */
 class Config extends Singleton
 {
@@ -416,9 +416,9 @@ class Config extends Singleton
 
         $section = $this->getFromGlobalConfig($name);
         $sectionCommon = $this->getFromCommonConfig($name);
-        if(empty($section) && !empty($sectionCommon)) {
+        if (empty($section) && !empty($sectionCommon)) {
             $section = $sectionCommon;
-        } elseif(!empty($section) && !empty($sectionCommon)) {
+        } elseif (!empty($section) && !empty($sectionCommon)) {
             $section = $this->array_merge_recursive_distinct($section, $sectionCommon);
         }
 
@@ -459,6 +459,7 @@ class Config extends Singleton
                 $user['bridge'] = 1;
                 return $user;
             }
+
         } catch (Exception $e) {}
 
         return array();
@@ -559,7 +560,7 @@ class Config extends Singleton
         }
 
         // If there is a common.config.ini.php, this will ensure config.ini.php does not duplicate its values
-        if(!empty($configCommon)) {
+        if (!empty($configCommon)) {
             $configGlobal = $this->array_merge_recursive_distinct($configGlobal, $configCommon);
         }
 
diff --git a/core/Console.php b/core/Console.php
index 03f9df438dc0c5d38ead6f91bcc2eb3b49e8b439..423c06d7713efddaa670a3a1addce4d4c3d28105 100644
--- a/core/Console.php
+++ b/core/Console.php
@@ -40,6 +40,7 @@ class Console extends Application
     {
         $this->initPiwikHost($input);
         $this->initConfig($output);
+
         try {
             self::initPlugins();
         } catch(\Exception $e) {
@@ -51,16 +52,24 @@ class Console extends Application
         $commands = $this->getAvailableCommands();
 
         foreach ($commands as $command) {
-            if (!class_exists($command)) {
-                Log::warning(sprintf('Cannot add command %s, class does not exist', $command));
-            } elseif (!is_subclass_of($command, 'Piwik\Plugin\ConsoleCommand')) {
-                Log::warning(sprintf('Cannot add command %s, class does not extend Piwik\Plugin\ConsoleCommand', $command));
-            } else {
-                $this->add(new $command);
-            }
+            $this->addCommandIfExists($command);
         }
 
-        return parent::doRun($input, $output);
+        $self = $this;
+        return Access::doAsSuperUser(function () use ($input, $output, $self) {
+            return call_user_func(array($self, 'Symfony\Component\Console\Application::doRun'), $input, $output);
+        });
+    }
+
+    private function addCommandIfExists($command)
+    {
+        if (!class_exists($command)) {
+            Log::warning(sprintf('Cannot add command %s, class does not exist', $command));
+        } elseif (!is_subclass_of($command, 'Piwik\Plugin\ConsoleCommand')) {
+            Log::warning(sprintf('Cannot add command %s, class does not extend Piwik\Plugin\ConsoleCommand', $command));
+        } else {
+            $this->add(new $command);
+        }
     }
 
     /**
@@ -128,9 +137,11 @@ class Console extends Application
     protected function initConfig(OutputInterface $output)
     {
         $config = Config::getInstance();
+
         try {
             $config->checkLocalConfigFound();
             return $config;
+
         } catch (\Exception $e) {
             $output->writeln($e->getMessage() . "\n");
         }
@@ -151,6 +162,8 @@ class Console extends Application
             $extra = new \Piwik\Plugins\EnterpriseAdmin\EnterpriseAdmin();
             $extra->addConsoleCommands($commands);
         }
+
         return $commands;
     }
+
 }
diff --git a/core/Cookie.php b/core/Cookie.php
index d081ec944e79e3a3ba01c2cc4108792f4a8f1cb9..993d97f1e29170ab171c49c2dd2cc8bd34d47f28 100644
--- a/core/Cookie.php
+++ b/core/Cookie.php
@@ -200,12 +200,14 @@ class Cookie
     private function extractSignedContent($content)
     {
         $signature = substr($content, -40);
+
         if (substr($content, -43, 3) == self::VALUE_SEPARATOR . '_=' &&
             $signature == sha1(substr($content, 0, -40) . SettingsPiwik::getSalt())
         ) {
             // strip trailing: VALUE_SEPARATOR '_=' signature"
             return substr($content, 0, -43);
         }
+
         return false;
     }
 
@@ -218,6 +220,7 @@ class Cookie
     protected function loadContentFromCookie()
     {
         $cookieStr = $this->extractSignedContent($_COOKIE[$this->name]);
+
         if ($cookieStr === false) {
             return;
         }
@@ -255,6 +258,7 @@ class Cookie
     protected function generateContentString()
     {
         $cookieStr = '';
+
         foreach ($this->value as $name => $value) {
             if (!is_numeric($value)) {
                 $value = base64_encode(safe_serialize($value));
@@ -335,6 +339,7 @@ class Cookie
             $this->value[$name] = $value;
             return;
         }
+
         $this->value[$this->keyStore][$name] = $value;
     }
 
@@ -347,14 +352,19 @@ class Cookie
     public function get($name)
     {
         $name = self::escapeValue($name);
-        if ($this->keyStore === false) {
-            return isset($this->value[$name])
-                ? self::escapeValue($this->value[$name])
-                : false;
+        if (false === $this->keyStore) {
+            if (isset($this->value[$name])) {
+                return self::escapeValue($this->value[$name]);
+            }
+
+            return false;
+        }
+
+        if (isset($this->value[$this->keyStore][$name])) {
+            return self::escapeValue($this->value[$this->keyStore][$name]);
         }
-        return isset($this->value[$this->keyStore][$name])
-            ? self::escapeValue($this->value[$this->keyStore][$name])
-            : false;
+
+        return false;
     }
 
     /**
@@ -364,8 +374,9 @@ class Cookie
      */
     public function __toString()
     {
-        $str = 'COOKIE ' . $this->name . ', rows count: ' . count($this->value) . ', cookie size = ' . strlen($this->generateContentString()) . " bytes\n";
+        $str  = 'COOKIE ' . $this->name . ', rows count: ' . count($this->value) . ', cookie size = ' . strlen($this->generateContentString()) . " bytes\n";
         $str .= var_export($this->value, $return = true);
+
         return $str;
     }
 
diff --git a/core/CronArchive.php b/core/CronArchive.php
index 442480051ba9161a28e3c2b22278a99f5c5c0131..47fbd7d3dfaa839b53d8c3c6730b46c5db061a9c 100644
--- a/core/CronArchive.php
+++ b/core/CronArchive.php
@@ -181,6 +181,13 @@ class CronArchive
      */
     public $concurrentRequestsPerWebsite = false;
 
+    private $websitesWithVisitsSinceLastRun = 0;
+    private $skippedPeriodsArchivesWebsite = 0;
+    private $skippedDayArchivesWebsites = 0;
+    private $skipped = 0;
+    private $processed = 0;
+    private $archivedPeriodsArchivesWebsite = 0;
+
     /**
      * Returns the option name of the option that stores the time core:archive was last executed.
      *
@@ -212,10 +219,13 @@ class CronArchive
      */
     public function main()
     {
-        $this->init();
-        $this->run();
-        $this->runScheduledTasks();
-        $this->end();
+        $self = $this;
+        Access::doAsSuperUser(function () use ($self) {
+            $self->init();
+            $self->run();
+            $self->runScheduledTasks();
+            $self->end();
+        });
     }
 
     public function init()
@@ -225,7 +235,6 @@ class CronArchive
         $this->initTokenAuth();
         $this->initCheckCli();
         $this->initStateFromParameters();
-        Piwik::setUserHasSuperUserAccess(true);
 
         $this->logInitInfo();
         $this->checkPiwikUrlIsValid();
@@ -234,10 +243,10 @@ class CronArchive
         // record archiving start time
         Option::set(self::OPTION_ARCHIVING_STARTED_TS, time());
 
-        $this->segments = $this->initSegmentsToArchive();
+        $this->segments    = $this->initSegmentsToArchive();
         $this->allWebsites = APISitesManager::getInstance()->getAllSitesId();
 
-        if(!empty($this->shouldArchiveOnlySpecificPeriods)) {
+        if (!empty($this->shouldArchiveOnlySpecificPeriods)) {
             $this->log("- Will process the following periods: " . implode(", ", $this->shouldArchiveOnlySpecificPeriods) . " (--force-periods)");
         }
 
@@ -279,13 +288,6 @@ class CronArchive
         $this->runScheduledTasks();
     }
 
-    private $websitesWithVisitsSinceLastRun = 0;
-    private $skippedPeriodsArchivesWebsite = 0;
-    private $skippedDayArchivesWebsites = 0;
-    private $skipped = 0;
-    private $processed = 0;
-    private $archivedPeriodsArchivesWebsite = 0;
-
     /**
      * Main function, runs archiving on all websites with new activity
      */
@@ -310,7 +312,7 @@ class CronArchive
             }
 
             $skipWebsiteForced = in_array($idSite, $this->shouldSkipSpecifiedSites);
-            if($skipWebsiteForced) {
+            if ($skipWebsiteForced) {
                 $this->log("Skipped website id $idSite, found in --skip-idsites ");
                 $this->skipped++;
                 continue;
@@ -380,6 +382,7 @@ class CronArchive
             // do not logError since errors are already in stderr
             $this->log("Error: " . $error);
         }
+
         $summary = count($this->errors) . " total errors during this script execution, please investigate and try and fix these errors.";
         $this->logFatalError($summary);
     }
@@ -402,9 +405,11 @@ class CronArchive
         $this->log("Starting Scheduled tasks... ");
 
         $tasksOutput = $this->request("?module=API&method=CoreAdminHome.runScheduledTasks&format=csv&convertToUnicode=0&token_auth=" . $this->token_auth);
+
         if ($tasksOutput == \Piwik\DataTable\Renderer\Csv::NO_DATA_AVAILABLE) {
             $tasksOutput = " No task to run";
         }
+
         $this->log($tasksOutput);
         $this->log("done");
         $this->logSection("");
@@ -415,6 +420,7 @@ class CronArchive
         $timerWebsite = new Timer;
 
         $lastTimestampWebsiteProcessedPeriods = $lastTimestampWebsiteProcessedDay = false;
+
         if ($this->archiveAndRespectTTL) {
             Option::clearCachedOption($this->lastRunKey($idSite, "periods"));
             $lastTimestampWebsiteProcessedPeriods = Option::get($this->lastRunKey($idSite, "periods"));
@@ -433,6 +439,7 @@ class CronArchive
         if ($this->processPeriodsMaximumEverySeconds > 10 * 60) {
             $secondsSinceLastExecution += 5 * 60;
         }
+
         $shouldArchivePeriods = $secondsSinceLastExecution > $this->processPeriodsMaximumEverySeconds;
         if (empty($lastTimestampWebsiteProcessedPeriods)) {
             // 2) OR always if script never executed for this website before
@@ -455,7 +462,7 @@ class CronArchive
         }
 
         $websiteIdIsForced = in_array($idSite, $this->shouldArchiveSpecifiedSites);
-        if($websiteIdIsForced) {
+        if ($websiteIdIsForced) {
             $shouldArchivePeriods = true;
         }
 
@@ -492,7 +499,7 @@ class CronArchive
         }
 
         $shouldProceed = $this->processArchiveDays($idSite, $lastTimestampWebsiteProcessedDay, $shouldArchivePeriods, $timerWebsite);
-        if(!$shouldProceed) {
+        if (!$shouldProceed) {
             return false;
         }
 
@@ -508,7 +515,7 @@ class CronArchive
         $success = true;
         foreach (array('week', 'month', 'year') as $period) {
 
-            if(!$this->shouldProcessPeriod($period)) {
+            if (!$this->shouldProcessPeriod($period)) {
                 // if any period was skipped, we do not mark the Periods archiving as successful
                 $success = false;
                 continue;
@@ -521,6 +528,7 @@ class CronArchive
         if ($success) {
             Option::set($this->lastRunKey($idSite, "periods"), time());
         }
+
         $this->archivedPeriodsArchivesWebsite++;
 
         $requestsWebsite = $this->requests - $requestsBefore;
@@ -568,9 +576,11 @@ class CronArchive
     private function initSegmentsToArchive()
     {
         $segments = \Piwik\SettingsPiwik::getKnownSegmentsToArchive();
+
         if (empty($segments)) {
             return array();
         }
+
         $this->log("- Will pre-process " . count($segments) . " Segments for each website and each period: " . implode(", ", $segments));
         return $segments;
     }
@@ -603,7 +613,7 @@ class CronArchive
         // when some data was purged from this website
         // we make sure we query all previous days/weeks/months
         $processDaysSince = $lastTimestampWebsiteProcessedDay;
-        if($this->isOldReportInvalidatedForWebsite($idSite)
+        if ($this->isOldReportInvalidatedForWebsite($idSite)
             // when --force-all-websites option,
             // also forces to archive last52 days to be safe
             || $this->shouldArchiveAllSites) {
@@ -634,7 +644,7 @@ class CronArchive
         $this->processed++;
 
         // If there is no visit today and we don't need to process this website, we can skip remaining archives
-        if ($visitsToday == 0
+        if (0 == $visitsToday
             && !$shouldArchivePeriods
         ) {
             $this->log("Skipped website id $idSite, no visit today, " . $timerWebsite->__toString());
@@ -642,7 +652,7 @@ class CronArchive
             return false;
         }
 
-        if ($visitsLastDays == 0
+        if (0 == $visitsLastDays
             && !$shouldArchivePeriods
             && $this->shouldArchiveAllSites
         ) {
@@ -662,7 +672,7 @@ class CronArchive
     private function getSegmentsForSite($idSite)
     {
         $segmentsAllSites = $this->segments;
-        $segmentsThisSite = \Piwik\SettingsPiwik::getKnownSegmentsToArchiveForSite($idSite);
+        $segmentsThisSite = SettingsPiwik::getKnownSegmentsToArchiveForSite($idSite);
         if (!empty($segmentsThisSite)) {
             $this->log("Will pre-process the following " . count($segmentsThisSite) . " Segments for this website (id = $idSite): " . implode(", ", $segmentsThisSite));
         }
@@ -731,7 +741,7 @@ class CronArchive
         }
 
         // we have already logged the daily archive above
-        if($period != "day") {
+        if ($period != "day") {
             $this->logArchivedWebsite($idSite, $period, $date, $visitsInLastPeriods, $visitsLastPeriod, $timer);
         }
 
@@ -744,7 +754,7 @@ class CronArchive
     private function logSection($title = "")
     {
         $this->log("---------------------------");
-        if(!empty($title)) {
+        if (!empty($title)) {
             $this->log($title);
         }
     }
@@ -788,7 +798,7 @@ class CronArchive
     {
         $url = $this->piwikUrl . $url . self::APPEND_TO_API_REQUEST;
 
-        if($this->shouldStartProfiler) {
+        if ($this->shouldStartProfiler) {
             $url .= "&xhprof=2";
         }
 
@@ -851,6 +861,7 @@ class CronArchive
         if (Common::isPhpCliMode()) {
             return;
         }
+
         $token_auth = Common::getRequestVar('token_auth', '', 'string');
         if ($token_auth !== $this->token_auth
             || strlen($token_auth) != 32
@@ -892,7 +903,7 @@ class CronArchive
         $this->shouldArchiveOnlySitesWithTrafficSince = $this->isShouldArchiveAllSitesWithTrafficSince();
         $this->shouldArchiveOnlySpecificPeriods = $this->getPeriodsToProcess();
 
-        if($this->shouldArchiveOnlySitesWithTrafficSince === false) {
+        if ($this->shouldArchiveOnlySitesWithTrafficSince === false) {
             // force-all-periods is not set here
             if (empty($this->lastSuccessRunTimestamp)) {
                 // First time we run the script
@@ -905,7 +916,7 @@ class CronArchive
             // force-all-periods is set here
             $this->archiveAndRespectTTL = false;
 
-            if($this->shouldArchiveOnlySitesWithTrafficSince === true) {
+            if ($this->shouldArchiveOnlySitesWithTrafficSince === true) {
                 // force-all-periods without value
                 $this->shouldArchiveOnlySitesWithTrafficSince = self::ARCHIVE_SITES_WITH_TRAFFIC_SINCE;
             }
@@ -935,7 +946,7 @@ class CronArchive
      */
     public function initWebsiteIds()
     {
-        if(count($this->shouldArchiveSpecifiedSites) > 0) {
+        if (count($this->shouldArchiveSpecifiedSites) > 0) {
             $this->log("- Will process " . count($this->shouldArchiveSpecifiedSites) . " websites (--force-idsites)");
 
             return $this->shouldArchiveSpecifiedSites;
@@ -955,11 +966,14 @@ class CronArchive
 
     private function initTokenAuth()
     {
-        $superUser = Db::get()->fetchRow("SELECT login, token_auth
-                                          FROM " . Common::prefixTable("user") . "
-                                          WHERE superuser_access = 1
-                                          ORDER BY date_registered ASC");
-        $this->token_auth = $superUser['token_auth'];
+        $token = '';
+
+        /**
+         * @ignore
+         */
+        Piwik::postEvent('CronArchive.getTokenAuth', array(&$token));
+        
+        $this->token_auth = $token;
     }
 
     private function initPiwikHost($piwikUrl = false)
@@ -978,12 +992,12 @@ class CronArchive
             $this->logFatalErrorUrlExpected();
         }
 
-        if(!\Piwik\UrlHelper::isLookLikeUrl($piwikUrl)) {
+        if (!\Piwik\UrlHelper::isLookLikeUrl($piwikUrl)) {
             // try adding http:// in case it's missing
             $piwikUrl = "http://" . $piwikUrl;
         }
 
-        if(!\Piwik\UrlHelper::isLookLikeUrl($piwikUrl)) {
+        if (!\Piwik\UrlHelper::isLookLikeUrl($piwikUrl)) {
             $this->logFatalErrorUrlExpected();
         }
 
@@ -1099,12 +1113,14 @@ class CronArchive
         $websiteDayHasFinishedSinceLastRun = APISitesManager::getInstance()->getSitesIdFromTimezones($timezones);
         $websiteDayHasFinishedSinceLastRun = array_diff($websiteDayHasFinishedSinceLastRun, $websiteIds);
         $this->websiteDayHasFinishedSinceLastRun = $websiteDayHasFinishedSinceLastRun;
+
         if (count($websiteDayHasFinishedSinceLastRun) > 0) {
             $ids = !empty($websiteDayHasFinishedSinceLastRun) ? ", IDs: " . implode(", ", $websiteDayHasFinishedSinceLastRun) : "";
             $this->log("- Will process " . count($websiteDayHasFinishedSinceLastRun)
                 . " other websites because the last time they were archived was on a different day (in the website's timezone) "
                 . $ids);
         }
+
         return $websiteDayHasFinishedSinceLastRun;
     }
 
@@ -1170,6 +1186,7 @@ class CronArchive
         $this->log("WARNING: Automatically increasing --force-timeout-for-periods from {$this->forceTimeoutPeriod} to "
             . $this->todayArchiveTimeToLive
             . " to match the cache timeout for Today's report specified in Piwik UI > Settings > General Settings");
+
         return $this->todayArchiveTimeToLive;
     }
 
@@ -1178,11 +1195,13 @@ class CronArchive
         if (empty($this->shouldArchiveAllPeriodsSince)) {
             return false;
         }
+
         if (is_numeric($this->shouldArchiveAllPeriodsSince)
             && $this->shouldArchiveAllPeriodsSince > 1
         ) {
             return (int)$this->shouldArchiveAllPeriodsSince;
         }
+
         return true;
     }
 
@@ -1192,6 +1211,7 @@ class CronArchive
     protected function removeWebsiteFromInvalidatedWebsites($idSite)
     {
         $websiteIdsInvalidated = APICoreAdminHome::getWebsiteIdsToInvalidate();
+
         if (count($websiteIdsInvalidated)) {
             $found = array_search($idSite, $websiteIdsInvalidated);
             if ($found !== false) {
@@ -1209,25 +1229,29 @@ class CronArchive
 
     private function getVisitsLastPeriodFromApiResponse($stats)
     {
-        if(empty($stats)) {
+        if (empty($stats)) {
             return 0;
         }
+
         $today = end($stats);
+
         return $today['nb_visits'];
     }
 
     private function getVisitsFromApiResponse($stats)
     {
-        if(empty($stats)) {
+        if (empty($stats)) {
             return 0;
         }
+
         $visits = 0;
         foreach($stats as $metrics) {
-            if(empty($metrics['nb_visits'])) {
+            if (empty($metrics['nb_visits'])) {
                 continue;
             }
             $visits += $metrics['nb_visits'];
         }
+
         return $visits;
     }
 
@@ -1240,9 +1264,11 @@ class CronArchive
     private function getApiDateParameter($idSite, $period, $lastTimestampWebsiteProcessed = false)
     {
         $dateRangeForced = $this->getDateRangeToProcess();
-        if(!empty($dateRangeForced)) {
+
+        if (!empty($dateRangeForced)) {
             return $dateRangeForced;
         }
+
         return $this->getDateLastN($idSite, $period, $lastTimestampWebsiteProcessed);
     }
 
@@ -1256,7 +1282,7 @@ class CronArchive
      */
     private function logArchivedWebsite($idSite, $period, $date, $visitsInLastPeriods, $visitsToday, Timer $timer)
     {
-        if(substr($date, 0, 4) === 'last') {
+        if (substr($date, 0, 4) === 'last') {
             $visitsInLastPeriods = (int)$visitsInLastPeriods . " visits in last " . $date . " " . $period . "s, ";
             $thisPeriod = $period == "day" ? "today" : "this " . $period;
             $visitsInLastPeriod = (int)$visitsToday . " visits " . $thisPeriod . ", ";
@@ -1276,9 +1302,11 @@ class CronArchive
         if (empty($this->restrictToDateRange)) {
             return false;
         }
+
         if (strpos($this->restrictToDateRange, ',') === false) {
             throw new Exception("--force-date-range expects a date range ie. YYYY-MM-DD,YYYY-MM-DD");
         }
+
         return $this->restrictToDateRange;
     }
 
@@ -1289,6 +1317,7 @@ class CronArchive
     {
         $this->restrictToPeriods = array_intersect($this->restrictToPeriods, $this->getDefaultPeriodsToProcess());
         $this->restrictToPeriods = array_intersect($this->restrictToPeriods, PeriodFactory::getPeriodsEnabledForAPI());
+
         return $this->restrictToPeriods;
     }
 
@@ -1311,9 +1340,10 @@ class CronArchive
 
     private function shouldProcessPeriod($period)
     {
-        if(empty($this->shouldArchiveOnlySpecificPeriods)) {
+        if (empty($this->shouldArchiveOnlySpecificPeriods)) {
             return true;
         }
+
         return in_array($period, $this->shouldArchiveOnlySpecificPeriods);
     }
 
@@ -1344,6 +1374,7 @@ class CronArchive
         if (!empty($this->dateLastForced)) {
             $dateLast = $this->dateLastForced;
         }
+
         return "last" . $dateLast;
     }
 
@@ -1352,9 +1383,10 @@ class CronArchive
      */
     private function getConcurrentRequestsPerWebsite()
     {
-        if ($this->concurrentRequestsPerWebsite !== false) {
+        if (false !== $this->concurrentRequestsPerWebsite) {
             return $this->concurrentRequestsPerWebsite;
         }
+
         return self::MAX_CONCURRENT_API_REQUESTS;
     }
 }
diff --git a/core/DataAccess/ArchivePurger.php b/core/DataAccess/ArchivePurger.php
index 94e1622376c983234b3865819662a37eb83f3377..d795ee6fba16c7c4986597ae699ff8162b676dfc 100644
--- a/core/DataAccess/ArchivePurger.php
+++ b/core/DataAccess/ArchivePurger.php
@@ -31,16 +31,7 @@ class ArchivePurger
              * Select the archives that have already been invalidated and have been since re-processed.
              * It purges records for each distinct { archive name (includes segment hash) , idsite, date, period } tuple.
              */
-            $query = '
-                SELECT t1.idarchive FROM `' . $archiveTable . '` t1
-                INNER JOIN `' . $archiveTable . '` t2
-                    ON t1.name = t2.name AND t1.idsite=t2.idsite
-                    AND t1.date1=t2.date1 AND t1.date2=t2.date2 AND t1.period=t2.period
-                WHERE t1.value = ' . ArchiveWriter::DONE_INVALIDATED . '
-                AND t2.value IN(' . ArchiveWriter::DONE_OK . ', ' . ArchiveWriter::DONE_OK_TEMPORARY . ')
-                AND t1.ts_archived < t2.ts_archived AND t1.name LIKE \'done%\'';
-
-            $result = Db::fetchAll($query);
+            $result = self::getModel()->purgeInvalidatedArchiveTable($archiveTable);
 
             if (count($result) > 0) {
                 $archiveIds = array_map(
@@ -59,36 +50,39 @@ class ArchivePurger
         }
     }
 
+    private static function getModel()
+    {
+        return new Model();
+    }
 
     public static function purgeOutdatedArchives(Date $dateStart)
     {
         $purgeArchivesOlderThan = Rules::shouldPurgeOutdatedArchives($dateStart);
+
         if (!$purgeArchivesOlderThan) {
             return;
         }
 
         $idArchivesToDelete = self::getTemporaryArchiveIdsOlderThan($dateStart, $purgeArchivesOlderThan);
+
         if (!empty($idArchivesToDelete)) {
             self::deleteArchiveIds($dateStart, $idArchivesToDelete);
         }
+
         self::deleteArchivesWithPeriodRange($dateStart);
 
         Log::debug("Purging temporary archives: done [ purged archives older than %s in %s ] [Deleted IDs: %s]",
-            $purgeArchivesOlderThan,
-            $dateStart->toString("Y-m"),
-            implode(',', $idArchivesToDelete));
+                   $purgeArchivesOlderThan,
+                   $dateStart->toString("Y-m"),
+                   implode(',', $idArchivesToDelete));
     }
 
     protected static function getTemporaryArchiveIdsOlderThan(Date $date, $purgeArchivesOlderThan)
     {
-        $query = "SELECT idarchive
-                FROM " . ArchiveTableCreator::getNumericTable($date) . "
-                WHERE name LIKE 'done%'
-                    AND ((  value = " . ArchiveWriter::DONE_OK_TEMPORARY . "
-                            AND ts_archived < ?)
-                         OR value = " . ArchiveWriter::DONE_ERROR . ")";
-
-        $result = Db::fetchAll($query, array($purgeArchivesOlderThan));
+        $archiveTable = ArchiveTableCreator::getNumericTable($date);
+
+        $result = self::getModel()->getTemporaryArchivesOlderThan($archiveTable, $purgeArchivesOlderThan);
+
         $idArchivesToDelete = array();
         if (!empty($result)) {
             foreach ($result as $row) {
@@ -104,36 +98,25 @@ class ArchivePurger
      */
     protected static function deleteArchivesWithPeriodRange(Date $date)
     {
-        $query = "DELETE FROM %s WHERE period = ? AND ts_archived < ?";
-
-        $yesterday = Date::factory('yesterday')->getDateTime();
-        $bind = array(Piwik::$idPeriods['range'], $yesterday);
         $numericTable = ArchiveTableCreator::getNumericTable($date);
-        Db::query(sprintf($query, $numericTable), $bind);
+        $blobTable    = ArchiveTableCreator::getBlobTable($date);
+        $yesterday    = Date::factory('yesterday')->getDateTime();
+
         Log::debug("Purging Custom Range archives: done [ purged archives older than %s from %s / blob ]",
-            $yesterday,
-            $numericTable);
-        try {
-            Db::query(sprintf($query, ArchiveTableCreator::getBlobTable($date)), $bind);
-        } catch (Exception $e) {
-            // Individual blob tables could be missing
-        }
+                   $yesterday, $numericTable);
+
+        self::getModel()->deleteArchivesWithPeriodRange($numericTable, $blobTable, Piwik::$idPeriods['range'], $yesterday);
     }
 
     protected static function deleteArchiveIds(Date $date, $idArchivesToDelete)
     {
-        $batches = array_chunk($idArchivesToDelete, 1000);
-        foreach ($batches as $idsToDelete) {
-            $query = "DELETE FROM %s WHERE idarchive IN (" . implode(',', $idsToDelete) . ")";
+        $batches      = array_chunk($idArchivesToDelete, 1000);
+        $numericTable = ArchiveTableCreator::getNumericTable($date);
+        $blobTable    = ArchiveTableCreator::getBlobTable($date);
 
-            Db::query(sprintf($query, ArchiveTableCreator::getNumericTable($date)));
-            try {
-                Db::query(sprintf($query, ArchiveTableCreator::getBlobTable($date)));
-            } catch (Exception $e) {
-                // Individual blob tables could be missing
-            }
+        foreach ($batches as $idsToDelete) {
+            self::getModel()->deleteArchiveIds($numericTable, $blobTable, $idsToDelete);
         }
-
     }
 
 }
diff --git a/core/DataAccess/ArchiveSelector.php b/core/DataAccess/ArchiveSelector.php
index 5a715e69396e8b7d3e0887a44ed97c769baaa808..a342257eca4eb1714643489357890a2e2efc58ad 100644
--- a/core/DataAccess/ArchiveSelector.php
+++ b/core/DataAccess/ArchiveSelector.php
@@ -14,10 +14,8 @@ use Piwik\ArchiveProcessor;
 use Piwik\Common;
 use Piwik\Date;
 use Piwik\Db;
-use Piwik\Log;
 use Piwik\Period;
 use Piwik\Period\Range;
-use Piwik\Piwik;
 use Piwik\Segment;
 
 /**
@@ -40,40 +38,36 @@ class ArchiveSelector
 
     const NB_VISITS_CONVERTED_RECORD_LOOKED_UP = "nb_visits_converted";
 
+    private static function getModel()
+    {
+        return new Model();
+    }
+
     public static function getArchiveIdAndVisits(ArchiveProcessor\Parameters $params, $minDatetimeArchiveProcessedUTC)
     {
-        $dateStart = $params->getPeriod()->getDateStart();
-        $bindSQL = array($params->getSite()->getId(),
-                         $dateStart->toString('Y-m-d'),
-                         $params->getPeriod()->getDateEnd()->toString('Y-m-d'),
-                         $params->getPeriod()->getId(),
-        );
-
-        $timeStampWhere = '';
+        $idSite       = $params->getSite()->getId();
+        $period       = $params->getPeriod()->getId();
+        $dateStart    = $params->getPeriod()->getDateStart();
+        $dateStartIso = $dateStart->toString('Y-m-d');
+        $dateEndIso   = $params->getPeriod()->getDateEnd()->toString('Y-m-d');
+
+        $numericTable = ArchiveTableCreator::getNumericTable($dateStart);
+
+        $minDatetimeIsoArchiveProcessedUTC = null;
         if ($minDatetimeArchiveProcessedUTC) {
-            $timeStampWhere = " AND ts_archived >= ? ";
-            $bindSQL[] = Date::factory($minDatetimeArchiveProcessedUTC)->getDatetime();
+            $minDatetimeIsoArchiveProcessedUTC = Date::factory($minDatetimeArchiveProcessedUTC)->getDatetime();
         }
 
         $requestedPlugin = $params->getRequestedPlugin();
-        $segment = $params->getSegment();
+        $segment         = $params->getSegment();
         $isSkipAggregationOfSubTables = $params->isSkipAggregationOfSubTables();
-
         $plugins = array("VisitsSummary", $requestedPlugin);
-        $sqlWhereArchiveName = self::getNameCondition($plugins, $segment, $isSkipAggregationOfSubTables);
-
-        $sqlQuery = "	SELECT idarchive, value, name, date1 as startDate
-						FROM " . ArchiveTableCreator::getNumericTable($dateStart) . "``
-						WHERE idsite = ?
-							AND date1 = ?
-							AND date2 = ?
-							AND period = ?
-							AND ( ($sqlWhereArchiveName)
-								  OR name = '" . self::NB_VISITS_RECORD_LOOKED_UP . "'
-								  OR name = '" . self::NB_VISITS_CONVERTED_RECORD_LOOKED_UP . "')
-							$timeStampWhere
-						ORDER BY idarchive DESC";
-        $results = Db::fetchAll($sqlQuery, $bindSQL);
+
+        $doneFlags      = self::getDoneFlags($plugins, $segment, $isSkipAggregationOfSubTables);
+        $possibleValues = self::getPossibleValues();
+
+        $results = self::getModel()->getArchiveIdAndVisits($numericTable, $idSite, $period, $dateStartIso, $dateEndIso, $minDatetimeIsoArchiveProcessedUTC, $doneFlags, $possibleValues);
+
         if (empty($results)) {
             return false;
         }
@@ -83,9 +77,8 @@ class ArchiveSelector
 
         list($visits, $visitsConverted) = self::getVisitsMetricsFromResults($idArchive, $idArchiveVisitsSummary, $results);
 
-        if ($visits === false
-            && $idArchive === false
-        ) {
+        if (false === $visits && false === $idArchive) {
+
             return false;
         }
 
@@ -96,9 +89,11 @@ class ArchiveSelector
     {
         $visits = $visitsConverted = false;
         $archiveWithVisitsMetricsWasFound = ($idArchiveVisitsSummary !== false);
+
         if ($archiveWithVisitsMetricsWasFound) {
             $visits = $visitsConverted = 0;
         }
+
         foreach ($results as $result) {
             if (in_array($result['idarchive'], array($idArchive, $idArchiveVisitsSummary))) {
                 $value = (int)$result['value'];
@@ -114,6 +109,7 @@ class ArchiveSelector
                 }
             }
         }
+
         return array($visits, $visitsConverted);
     }
 
@@ -121,6 +117,7 @@ class ArchiveSelector
     {
         $idArchive = false;
         $namesRequestedPlugin = Rules::getDoneFlags(array($requestedPlugin), $segment, $isSkipAggregationOfSubTables);
+
         foreach ($results as $result) {
             if ($idArchive === false
                 && in_array($result['name'], $namesRequestedPlugin)
@@ -129,6 +126,7 @@ class ArchiveSelector
                 break;
             }
         }
+
         return $idArchive;
     }
 
@@ -150,7 +148,7 @@ class ArchiveSelector
      */
     public static function getArchiveIds($siteIds, $periods, $segment, $plugins, $isSkipAggregationOfSubTables = false)
     {
-        if(empty($siteIds)) {
+        if (empty($siteIds)) {
             throw new \Exception("Website IDs could not be read from the request, ie. idSite=");
         }
 
@@ -200,8 +198,10 @@ class ArchiveSelector
 
             $sql = sprintf($getArchiveIdsSql, $table, $dateCondition);
 
+            $archiveIds = Db::fetchAll($sql, $bind);
+
             // get the archive IDs
-            foreach (Db::fetchAll($sql, $bind) as $row) {
+            foreach ($archiveIds as $row) {
                 $archiveName = $row['name'];
 
                 //FIXMEA duplicate with Archive.php
@@ -251,18 +251,23 @@ class ArchiveSelector
         // get data from every table we're querying
         $rows = array();
         foreach ($archiveIds as $period => $ids) {
+
             if (empty($ids)) {
                 throw new Exception("Unexpected: id archive not found for period '$period' '");
             }
+
             // $period = "2009-01-04,2009-01-04",
             $date = Date::factory(substr($period, 0, 10));
+
             if ($archiveDataType == 'numeric') {
                 $table = ArchiveTableCreator::getNumericTable($date);
             } else {
                 $table = ArchiveTableCreator::getBlobTable($date);
             }
-            $sql = sprintf($getValuesSql, $table, implode(',', $ids));
+
+            $sql      = sprintf($getValuesSql, $table, implode(',', $ids));
             $dataRows = Db::fetchAll($sql, $bind);
+
             foreach ($dataRows as $row) {
                 $rows[] = $row;
             }
@@ -281,13 +286,44 @@ class ArchiveSelector
      * @return string
      */
     private static function getNameCondition(array $plugins, Segment $segment, $isSkipAggregationOfSubTables)
+    {
+        // the flags used to tell how the archiving process for a specific archive was completed,
+        // if it was completed
+        $doneFlags    = self::getDoneFlags($plugins, $segment, $isSkipAggregationOfSubTables);
+        $allDoneFlags = "'" . implode("','", $doneFlags) . "'";
+
+        $possibleValues = self::getPossibleValues();
+
+        // create the SQL to find archives that are DONE
+        return "((name IN ($allDoneFlags)) AND (value IN (" . implode(',', $possibleValues) . ")))";
+    }
+
+    /**
+     * Returns the SQL condition used to find successfully completed archives that
+     * this instance is querying for.
+     *
+     * @param array $plugins
+     * @param Segment $segment
+     * @param bool $isSkipAggregationOfSubTables
+     * @return string
+     */
+    private static function getDoneFlags(array $plugins, Segment $segment, $isSkipAggregationOfSubTables)
     {
         // the flags used to tell how the archiving process for a specific archive was completed,
         // if it was completed
         $doneFlags = Rules::getDoneFlags($plugins, $segment, $isSkipAggregationOfSubTables);
 
-        $allDoneFlags = "'" . implode("','", $doneFlags) . "'";
+        return $doneFlags;
+    }
 
+    /**
+     * Returns the SQL condition used to find successfully completed archives that
+     * this instance is querying for.
+     *
+     * @return string
+     */
+    private static function getPossibleValues()
+    {
         $possibleValues = array(ArchiveWriter::DONE_OK, ArchiveWriter::DONE_OK_TEMPORARY);
 
         if (!Rules::isRequestAuthorizedToArchive()) {
@@ -295,9 +331,7 @@ class ArchiveSelector
             $possibleValues[] = ArchiveWriter::DONE_INVALIDATED;
         }
 
-        // create the SQL to find archives that are DONE
-        return "((name IN ($allDoneFlags)) AND " .
-        " (value IN (" . implode(',', $possibleValues) . ")))";
+        return $possibleValues;
     }
 
 }
diff --git a/core/DataAccess/ArchiveTableCreator.php b/core/DataAccess/ArchiveTableCreator.php
index 67abd2b1237eca4fa39c749d5795f81a5a0f47fa..230c7da05a08a9ac7862448300fb8ed3936cb5fb 100644
--- a/core/DataAccess/ArchiveTableCreator.php
+++ b/core/DataAccess/ArchiveTableCreator.php
@@ -9,7 +9,6 @@
 
 namespace Piwik\DataAccess;
 
-use Exception;
 use Piwik\Common;
 use Piwik\Date;
 use Piwik\Db;
@@ -18,8 +17,7 @@ use Piwik\DbHelper;
 class ArchiveTableCreator
 {
     const NUMERIC_TABLE = "numeric";
-
-    const BLOB_TABLE = "blob";
+    const BLOB_TABLE    = "blob";
 
     public static $tablesAlreadyInstalled = null;
 
@@ -38,7 +36,9 @@ class ArchiveTableCreator
         $tableNamePrefix = "archive_" . $type;
         $tableName = $tableNamePrefix . "_" . $date->toString('Y_m');
         $tableName = Common::prefixTable($tableName);
+
         self::createArchiveTablesIfAbsent($tableName, $tableNamePrefix);
+
         return $tableName;
     }
 
@@ -49,24 +49,16 @@ class ArchiveTableCreator
         }
 
         if (!in_array($tableName, self::$tablesAlreadyInstalled)) {
-            $db  = Db::get();
-            $sql = DbHelper::getTableCreateSql($tableNamePrefix);
-
-            // replace table name template by real name
-            $tableNamePrefix = Common::prefixTable($tableNamePrefix);
-            $sql = str_replace($tableNamePrefix, $tableName, $sql);
-            try {
-                $db->query($sql);
-            } catch (Exception $e) {
-                // accept mysql error 1050: table already exists, throw otherwise
-                if (!$db->isErrNo($e, '1050')) {
-                    throw $e;
-                }
-            }
+            self::getModel()->createArchiveTable($tableName, $tableNamePrefix);
             self::$tablesAlreadyInstalled[] = $tableName;
         }
     }
 
+    private static function getModel()
+    {
+        return new Model();
+    }
+
     public static function clear()
     {
         self::$tablesAlreadyInstalled = null;
@@ -89,6 +81,7 @@ class ArchiveTableCreator
         }
 
         $archiveTables = array();
+
         foreach (self::$tablesAlreadyInstalled as $table) {
             if (strpos($table, 'archive_numeric_') !== false
                 || strpos($table, 'archive_blob_') !== false
@@ -96,13 +89,15 @@ class ArchiveTableCreator
                 $archiveTables[] = $table;
             }
         }
+
         return $archiveTables;
     }
 
     public static function getDateFromTableName($tableName)
     {
         $tableName = Common::unprefixTable($tableName);
-        $date = str_replace(array('archive_numeric_', 'archive_blob_'), '', $tableName);
+        $date      = str_replace(array('archive_numeric_', 'archive_blob_'), '', $tableName);
+
         return $date;
     }
 
@@ -111,9 +106,11 @@ class ArchiveTableCreator
         if (strpos($tableName, 'archive_numeric_') !== false) {
             return self::NUMERIC_TABLE;
         }
+
         if (strpos($tableName, 'archive_blob_') !== false) {
             return self::BLOB_TABLE;
         }
+
         return false;
     }
 }
diff --git a/core/DataAccess/ArchiveWriter.php b/core/DataAccess/ArchiveWriter.php
index 70f2159b67dd5a4e058ec0e47c218e5fe9c969e2..1ea6b0d08c26a5622eaa4a29f62f75f28de7441c 100644
--- a/core/DataAccess/ArchiveWriter.php
+++ b/core/DataAccess/ArchiveWriter.php
@@ -23,7 +23,6 @@ use Piwik\Period;
  */
 class ArchiveWriter
 {
-    const PREFIX_SQL_LOCK = "locked_";
     /**
      * Flag stored at the end of the archiving
      *
@@ -64,9 +63,10 @@ class ArchiveWriter
     public function __construct(ArchiveProcessor\Parameters $params, $isArchiveTemporary)
     {
         $this->idArchive = false;
-        $this->idSite = $params->getSite()->getId();
-        $this->segment = $params->getSegment();
-        $this->period = $params->getPeriod();
+        $this->idSite    = $params->getSite()->getId();
+        $this->segment   = $params->getSegment();
+        $this->period    = $params->getPeriod();
+
         $idSites = array($this->idSite);
         $this->doneFlag = Rules::getDoneStringFlagFor($idSites, $this->segment, $this->period->getLabel(), $params->getRequestedPlugin(), $params->isSkipAggregationOfSubTables());
         $this->isArchiveTemporary = $isArchiveTemporary;
@@ -92,7 +92,7 @@ class ArchiveWriter
                     $newName = $name . '_' . $id;
                 }
 
-                $value = $this->compress($value);
+                $value   = $this->compress($value);
                 $clean[] = array($newName, $value);
             }
             $this->insertBulkRecords($clean);
@@ -108,6 +108,7 @@ class ArchiveWriter
         if ($this->idArchive === false) {
             throw new Exception("Must call allocateNewArchiveId() first");
         }
+
         return $this->idArchive;
     }
 
@@ -119,7 +120,11 @@ class ArchiveWriter
 
     public function finalizeArchive()
     {
-        $this->deletePreviousArchiveStatus();
+        $numericTable = $this->getTableNumeric();
+        $idArchive    = $this->getIdArchive();
+
+        $this->getModel()->deletePreviousArchiveStatus($numericTable, $idArchive, $this->doneFlag);
+
         $this->logArchiveStatusAsFinal();
     }
 
@@ -128,28 +133,8 @@ class ArchiveWriter
         if (Db::get()->hasBlobDataType()) {
             return gzcompress($data);
         }
-        return $data;
-    }
-
-    protected function getArchiveLockName()
-    {
-        $numericTable = $this->getTableNumeric();
-        $dbLockName = "allocateNewArchiveId.$numericTable";
-        return $dbLockName;
-    }
-
-    protected function acquireArchiveTableLock()
-    {
-        $dbLockName = $this->getArchiveLockName();
-        if (Db::getDbLock($dbLockName, $maxRetries = 30) === false) {
-            throw new Exception("allocateNewArchiveId: Cannot get named lock $dbLockName.");
-        }
-    }
 
-    protected function releaseArchiveTableLock()
-    {
-        $dbLockName = $this->getArchiveLockName();
-        Db::releaseDbLock($dbLockName);
+        return $data;
     }
 
     protected function allocateNewArchiveId()
@@ -171,56 +156,31 @@ class ArchiveWriter
     {
         $numericTable = $this->getTableNumeric();
         $idSite = $this->idSite;
+        $date = date("Y-m-d H:i:s");
 
-        $this->acquireArchiveTableLock();
+        $id = $this->getModel()->insertNewArchiveId($numericTable, $idSite, $date);
 
-        $locked = self::PREFIX_SQL_LOCK . Common::generateUniqId();
-        $date = date("Y-m-d H:i:s");
-        $insertSql = "INSERT INTO $numericTable "
-            . " SELECT IFNULL( MAX(idarchive), 0 ) + 1,
-								'" . $locked . "',
-								" . (int)$idSite . ",
-								'" . $date . "',
-								'" . $date . "',
-								0,
-								'" . $date . "',
-								0 "
-            . " FROM $numericTable as tb1";
-        Db::get()->exec($insertSql);
-
-        $this->releaseArchiveTableLock();
-
-        $selectIdSql = "SELECT idarchive FROM $numericTable WHERE name = ? LIMIT 1";
-        $id = Db::get()->fetchOne($selectIdSql, $locked);
         return $id;
     }
 
-    protected function logArchiveStatusAsIncomplete()
+    private function getModel()
     {
-        $statusWhileProcessing = self::DONE_ERROR;
-        $this->insertRecord($this->doneFlag, $statusWhileProcessing);
+        return new Model();
     }
 
-    protected function deletePreviousArchiveStatus()
+    protected function logArchiveStatusAsIncomplete()
     {
-        // without advisory lock here, the DELETE would acquire Exclusive Lock
-        $this->acquireArchiveTableLock();
-
-        Db::query("DELETE FROM " . $this->getTableNumeric() . "
-					WHERE idarchive = ? AND (name = '" . $this->doneFlag
-                    . "' OR name LIKE '" . self::PREFIX_SQL_LOCK . "%')",
-            array($this->getIdArchive())
-        );
-
-        $this->releaseArchiveTableLock();
+        $this->insertRecord($this->doneFlag, self::DONE_ERROR);
     }
 
     protected function logArchiveStatusAsFinal()
     {
         $status = self::DONE_OK;
+
         if ($this->isArchiveTemporary) {
             $status = self::DONE_OK_TEMPORARY;
         }
+
         $this->insertRecord($this->doneFlag, $status);
     }
 
@@ -233,27 +193,37 @@ class ArchiveWriter
             foreach ($records as $record) {
                 $this->insertRecord($record[0], $record[1]);
             }
+
             return true;
         }
+
         $bindSql = $this->getInsertRecordBind();
-        $values = array();
+        $values  = array();
 
         $valueSeen = false;
         foreach ($records as $record) {
             // don't record zero
-            if (empty($record[1])) continue;
+            if (empty($record[1])) {
+                continue;
+            }
 
-            $bind = $bindSql;
-            $bind[] = $record[0]; // name
-            $bind[] = $record[1]; // value
+            $bind     = $bindSql;
+            $bind[]   = $record[0]; // name
+            $bind[]   = $record[1]; // value
             $values[] = $bind;
 
             $valueSeen = $record[1];
         }
-        if (empty($values)) return true;
+
+        if (empty($values)) {
+            return true;
+        }
 
         $tableName = $this->getTableNameToInsert($valueSeen);
-        BatchInsert::tableInsertBatch($tableName, $this->getInsertFields(), $values);
+        $fields    = $this->getInsertFields();
+
+        BatchInsert::tableInsertBatch($tableName, $fields, $values);
+
         return true;
     }
 
@@ -272,15 +242,11 @@ class ArchiveWriter
         }
 
         $tableName = $this->getTableNameToInsert($value);
+        $fields    = $this->getInsertFields();
+        $record    = $this->getInsertRecordBind();
+
+        $this->getModel()->insertRecord($tableName, $fields, $record, $name, $value);
 
-        // duplicate idarchives are Ignored, see https://github.com/piwik/piwik/issues/987
-        $query = "INSERT IGNORE INTO " . $tableName . "
-					(" . implode(", ", $this->getInsertFields()) . ")
-					VALUES (?,?,?,?,?,?,?,?)";
-        $bindSql = $this->getInsertRecordBind();
-        $bindSql[] = $name;
-        $bindSql[] = $value;
-        Db::query($query, $bindSql);
         return true;
     }
 
@@ -299,6 +265,7 @@ class ArchiveWriter
         if (is_numeric($value)) {
             return $this->getTableNumeric();
         }
+
         return ArchiveTableCreator::getBlobTable($this->dateStart);
     }
 
diff --git a/core/DataAccess/LogAggregator.php b/core/DataAccess/LogAggregator.php
index 95a7603176a7e3b4ad05fa0931ee3d396a3e37ee..83946b1f6fad37a58d7424a799d00b065cd32aad 100644
--- a/core/DataAccess/LogAggregator.php
+++ b/core/DataAccess/LogAggregator.php
@@ -292,52 +292,61 @@ class LogAggregator
         $tableName = self::LOG_VISIT_TABLE;
         $availableMetrics = $this->getVisitsMetricFields();
 
-        $select = $this->getSelectStatement($dimensions, $tableName, $additionalSelects, $availableMetrics, $metrics);
-        $from = array($tableName);
-        $where = $this->getWhereStatement($tableName, self::VISIT_DATETIME_FIELD, $where);
+        $select  = $this->getSelectStatement($dimensions, $tableName, $additionalSelects, $availableMetrics, $metrics);
+        $from    = array($tableName);
+        $where   = $this->getWhereStatement($tableName, self::VISIT_DATETIME_FIELD, $where);
         $groupBy = $this->getGroupByStatement($dimensions, $tableName);
         $orderBy = false;
 
         if ($rankingQuery) {
             $orderBy = '`' . Metrics::INDEX_NB_VISITS . '` DESC';
         }
+
         $query = $this->generateQuery($select, $from, $where, $groupBy, $orderBy);
 
         if ($rankingQuery) {
             unset($availableMetrics[Metrics::INDEX_MAX_ACTIONS]);
             $sumColumns = array_keys($availableMetrics);
+
             if ($metrics) {
                 $sumColumns = array_intersect($sumColumns, $metrics);
             }
+
             $rankingQuery->addColumn($sumColumns, 'sum');
             if ($this->isMetricRequested(Metrics::INDEX_MAX_ACTIONS, $metrics)) {
                 $rankingQuery->addColumn(Metrics::INDEX_MAX_ACTIONS, 'max');
             }
+
             return $rankingQuery->execute($query['sql'], $query['bind']);
         }
+
         return $this->getDb()->query($query['sql'], $query['bind']);
     }
 
     protected function getSelectsMetrics($metricsAvailable, $metricsRequested = false)
     {
         $selects = array();
+
         foreach ($metricsAvailable as $metricId => $statement) {
             if ($this->isMetricRequested($metricId, $metricsRequested)) {
-                $aliasAs = $this->getSelectAliasAs($metricId);
+                $aliasAs   = $this->getSelectAliasAs($metricId);
                 $selects[] = $statement . $aliasAs;
             }
         }
+
         return $selects;
     }
 
     protected function getSelectStatement($dimensions, $tableName, $additionalSelects, array $availableMetrics, $requestedMetrics = false)
     {
         $dimensionsToSelect = $this->getDimensionsToSelect($dimensions, $additionalSelects);
+
         $selects = array_merge(
             $this->getSelectDimensions($dimensionsToSelect, $tableName),
             $this->getSelectsMetrics($availableMetrics, $requestedMetrics),
             !empty($additionalSelects) ? $additionalSelects : array()
         );
+
         $select = implode(self::FIELDS_SEPARATOR, $selects);
         return $select;
     }
@@ -354,6 +363,7 @@ class LogAggregator
         if (empty($additionalSelects)) {
             return $dimensions;
         }
+
         $dimensionsToSelect = array();
         foreach ($dimensions as $selectAs => $dimension) {
             $asAlias = $this->getSelectAliasAs($dimension);
@@ -363,6 +373,7 @@ class LogAggregator
                 }
             }
         }
+
         $dimensionsToSelect = array_unique($dimensionsToSelect);
         return $dimensionsToSelect;
     }
@@ -381,6 +392,7 @@ class LogAggregator
     {
         foreach ($dimensions as $selectAs => &$field) {
             $selectAsString = $field;
+
             if (!is_numeric($selectAs)) {
                 $selectAsString = $selectAs;
             } else {
@@ -389,16 +401,18 @@ class LogAggregator
                     $selectAsString = $appendSelectAs = false;
                 }
             }
+
             $isKnownField = !in_array($field, array('referrer_data'));
-            if ($selectAsString == $field
-                && $isKnownField
-            ) {
+
+            if ($selectAsString == $field && $isKnownField) {
                 $field = $this->prefixColumn($field, $tableName);
             }
+
             if ($appendSelectAs && $selectAsString) {
                 $field = $this->prefixColumn($field, $tableName) . $this->getSelectAliasAs($selectAsString);
             }
         }
+
         return $dimensions;
     }
 
@@ -421,7 +435,7 @@ class LogAggregator
     protected function isFieldFunctionOrComplexExpression($field)
     {
         return strpos($field, "(") !== false
-        || strpos($field, "CASE") !== false;
+            || strpos($field, "CASE") !== false;
     }
 
     protected function getSelectAliasAs($metricId)
@@ -432,7 +446,7 @@ class LogAggregator
     protected function isMetricRequested($metricId, $metricsRequested)
     {
         return $metricsRequested === false
-        || in_array($metricId, $metricsRequested);
+            || in_array($metricId, $metricsRequested);
     }
 
     protected function getWhereStatement($tableName, $datetimeField, $extraWhere = false)
@@ -440,17 +454,20 @@ class LogAggregator
         $where = "$tableName.$datetimeField >= ?
 				AND $tableName.$datetimeField <= ?
 				AND $tableName.idsite IN (". Common::getSqlStringFieldsArray($this->sites) . ")";
+
         if (!empty($extraWhere)) {
             $extraWhere = sprintf($extraWhere, $tableName, $tableName);
-            $where .= ' AND ' . $extraWhere;
+            $where     .= ' AND ' . $extraWhere;
         }
+
         return $where;
     }
 
     protected function getGroupByStatement($dimensions, $tableName)
     {
         $dimensions = $this->getSelectDimensions($dimensions, $tableName, $appendSelectAs = false);
-        $groupBy = implode(", ", $dimensions);
+        $groupBy    = implode(", ", $dimensions);
+
         return $groupBy;
     }
 
@@ -464,6 +481,7 @@ class LogAggregator
     {
         $bind = array($this->dateStart->getDateStartUTC(), $this->dateEnd->getDateEndUTC());
         $bind = array_merge($bind, $this->sites);
+
         return $bind;
     }
 
@@ -494,7 +512,7 @@ class LogAggregator
      *
      * @param string $dimension One or more **log\_conversion\_item** columns to group aggregated data by.
      *                          Eg, `'idaction_sku'` or `'idaction_sku, idaction_category'`.
-     * @return Zend_Db_Statement A statement object that can be used to iterate through the query's
+     * @return \Zend_Db_Statement A statement object that can be used to iterate through the query's
      *                           result set. See [above](#queryEcommerceItems-result-set) to learn more
      *                           about what this query selects.
      * @api
@@ -624,9 +642,9 @@ class LogAggregator
         $tableName = self::LOG_ACTIONS_TABLE;
         $availableMetrics = $this->getActionsMetricFields();
 
-        $select = $this->getSelectStatement($dimensions, $tableName, $additionalSelects, $availableMetrics, $metrics);
-        $from = array($tableName);
-        $where = $this->getWhereStatement($tableName, self::ACTION_DATETIME_FIELD, $where);
+        $select  = $this->getSelectStatement($dimensions, $tableName, $additionalSelects, $availableMetrics, $metrics);
+        $from    = array($tableName);
+        $where   = $this->getWhereStatement($tableName, self::ACTION_DATETIME_FIELD, $where);
         $groupBy = $this->getGroupByStatement($dimensions, $tableName);
         $orderBy = false;
 
@@ -638,12 +656,14 @@ class LogAggregator
 
             foreach ($joinLogActionOnColumn as $i => $joinColumn) {
                 $tableAlias = 'log_action' . ($multiJoin ? $i + 1 : '');
+
                 if (strpos($joinColumn, ' ') === false) {
                     $joinOn = $tableAlias . '.idaction = ' . $tableName . '.' . $joinColumn;
                 } else {
-                    // more complex join column like IF(...)
+                    // more complex join column like if (...)
                     $joinOn = $tableAlias . '.idaction = ' . $joinColumn;
                 }
+
                 $from[] = array(
                     'table'      => 'log_action',
                     'tableAlias' => $tableAlias,
@@ -663,7 +683,9 @@ class LogAggregator
             if ($metrics) {
                 $sumColumns = array_intersect($sumColumns, $metrics);
             }
+
             $rankingQuery->addColumn($sumColumns, 'sum');
+
             return $rankingQuery->execute($query['sql'], $query['bind']);
         }
 
@@ -733,21 +755,22 @@ class LogAggregator
      * @param bool|string $where An optional SQL expression used in the SQL's **WHERE** clause.
      * @param array $additionalSelects Additional SELECT fields that are not included in the group by
      *                                 clause. These can be aggregate expressions, eg, `SUM(somecol)`.
-     * @return Zend_Db_Statement
+     * @return \Zend_Db_Statement
      */
     public function queryConversionsByDimension($dimensions = array(), $where = false, $additionalSelects = array())
     {
         $dimensions = array_merge(array(self::IDGOAL_FIELD), $dimensions);
+        $tableName  = self::LOG_CONVERSION_TABLE;
         $availableMetrics = $this->getConversionsMetricFields();
-        $tableName = self::LOG_CONVERSION_TABLE;
 
         $select = $this->getSelectStatement($dimensions, $tableName, $additionalSelects, $availableMetrics);
 
-        $from = array($tableName);
-        $where = $this->getWhereStatement($tableName, self::CONVERSION_DATETIME_FIELD, $where);
+        $from    = array($tableName);
+        $where   = $this->getWhereStatement($tableName, self::CONVERSION_DATETIME_FIELD, $where);
         $groupBy = $this->getGroupByStatement($dimensions, $tableName);
         $orderBy = false;
-        $query = $this->generateQuery($select, $from, $where, $groupBy, $orderBy);
+        $query   = $this->generateQuery($select, $from, $where, $groupBy, $orderBy);
+
         return $this->getDb()->query($query['sql'], $query['bind']);
     }
 
@@ -824,14 +847,16 @@ class LogAggregator
     {
         $selects = array();
         $extraCondition = '';
+
         if ($restrictToReturningVisitors) {
             // extra condition for the SQL SELECT that makes sure only returning visits are counted
             // when creating the 'days since last visit' report
             $extraCondition = 'and log_visit.visitor_returning = 1';
-            $extraSelect = "sum(case when log_visit.visitor_returning = 0 then 1 else 0 end) "
-                . " as `" . $selectColumnPrefix . 'General_NewVisits' . "`";
+            $extraSelect    = "sum(case when log_visit.visitor_returning = 0 then 1 else 0 end) "
+                            . " as `" . $selectColumnPrefix . 'General_NewVisits' . "`";
             $selects[] = $extraSelect;
         }
+
         foreach ($ranges as $gap) {
             if (count($gap) == 2) {
                 $lowerBound = $gap[0];
@@ -840,12 +865,11 @@ class LogAggregator
                 $selectAs = "$selectColumnPrefix$lowerBound-$upperBound";
 
                 $selects[] = "sum(case when $table.$column between $lowerBound and $upperBound $extraCondition" .
-                    " then 1 else 0 end) as `$selectAs`";
+                             " then 1 else 0 end) as `$selectAs`";
             } else {
                 $lowerBound = $gap[0];
 
-                $selectAs = $selectColumnPrefix . ($lowerBound + 1) . urlencode('+');
-
+                $selectAs  = $selectColumnPrefix . ($lowerBound + 1) . urlencode('+');
                 $selects[] = "sum(case when $table.$column > $lowerBound $extraCondition then 1 else 0 end) as `$selectAs`";
             }
         }
@@ -869,6 +893,7 @@ class LogAggregator
     public static function makeArrayOneColumn($row, $columnName, $lookForThisPrefix = false)
     {
         $cleanRow = array();
+
         foreach ($row as $label => $count) {
             if (empty($lookForThisPrefix)
                 || strpos($label, $lookForThisPrefix) === 0
@@ -877,6 +902,7 @@ class LogAggregator
                 $cleanRow[$cleanLabel] = array($columnName => $count);
             }
         }
+
         return $cleanRow;
     }
 
diff --git a/core/DataAccess/Model.php b/core/DataAccess/Model.php
new file mode 100644
index 0000000000000000000000000000000000000000..facaa5dd9741ab9d4b18f821a5966e6d8f95575c
--- /dev/null
+++ b/core/DataAccess/Model.php
@@ -0,0 +1,229 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\DataAccess;
+
+use Exception;
+use Piwik\Common;
+use Piwik\Db;
+use Piwik\DbHelper;
+
+/**
+ * Cleans up outdated archives
+ *
+ * @package Piwik\DataAccess
+ */
+class Model
+{
+    const PREFIX_SQL_LOCK = "locked_";
+
+    public function purgeInvalidatedArchiveTable($archiveTable)
+    {
+        /**
+         * Select the archives that have already been invalidated and have been since re-processed.
+         * It purges records for each distinct { archive name (includes segment hash) , idsite, date, period } tuple.
+         */
+        $query = 'SELECT t1.idarchive FROM `' . $archiveTable . '` t1
+                  INNER JOIN `' . $archiveTable . '` t2
+                      ON t1.name = t2.name AND t1.idsite=t2.idsite
+                      AND t1.date1=t2.date1 AND t1.date2=t2.date2 AND t1.period=t2.period
+                  WHERE t1.value = ' . ArchiveWriter::DONE_INVALIDATED . '
+                  AND t2.value IN(' . ArchiveWriter::DONE_OK . ', ' . ArchiveWriter::DONE_OK_TEMPORARY . ')
+                  AND t1.ts_archived < t2.ts_archived AND t1.name LIKE \'done%\'';
+
+        $result = Db::fetchAll($query);
+
+        return $result;
+    }
+
+    public function getTemporaryArchivesOlderThan($archiveTable, $purgeArchivesOlderThan)
+    {
+        $query = "SELECT idarchive FROM " . $archiveTable . "
+                  WHERE name LIKE 'done%'
+                    AND ((  value = " . ArchiveWriter::DONE_OK_TEMPORARY . "
+                            AND ts_archived < ?)
+                         OR value = " . ArchiveWriter::DONE_ERROR . ")";
+
+        return Db::fetchAll($query, array($purgeArchivesOlderThan));
+    }
+
+    /*
+     * Deleting "Custom Date Range" reports, since they can be re-processed and would take up un-necessary space
+     */
+    public function deleteArchivesWithPeriodRange($numericTable, $blobTable, $range, $date)
+    {
+        $query = "DELETE FROM %s WHERE period = ? AND ts_archived < ?";
+        $bind  = array($range, $date);
+
+        Db::query(sprintf($query, $numericTable), $bind);
+
+        try {
+            Db::query(sprintf($query, $blobTable), $bind);
+        } catch (Exception $e) {
+            // Individual blob tables could be missing
+        }
+    }
+
+    public function deleteArchiveIds($numericTable, $blobTable, $idsToDelete)
+    {
+        $query = "DELETE FROM %s WHERE idarchive IN (" . implode(',', $idsToDelete) . ")";
+
+        Db::query(sprintf($query, $numericTable));
+
+        try {
+            Db::query(sprintf($query, $blobTable));
+        } catch (Exception $e) {
+            // Individual blob tables could be missing
+        }
+    }
+
+    public function getArchiveIdAndVisits($numericTable, $idSite, $period, $dateStartIso, $dateEndIso, $minDatetimeIsoArchiveProcessedUTC, $doneFlags, $possibleValues)
+    {
+        $bindSQL = array($idSite,
+            $dateStartIso,
+            $dateEndIso,
+            $period,
+        );
+
+        $timeStampWhere = '';
+        if ($minDatetimeIsoArchiveProcessedUTC) {
+            $timeStampWhere = " AND ts_archived >= ? ";
+            $bindSQL[]      = $minDatetimeIsoArchiveProcessedUTC;
+        }
+
+        $sqlWhereArchiveName = self::getNameCondition($doneFlags, $possibleValues);
+
+        $sqlQuery = "SELECT idarchive, value, name, date1 as startDate FROM $numericTable
+                     WHERE idsite = ?
+                         AND date1 = ?
+                         AND date2 = ?
+                         AND period = ?
+                         AND ( ($sqlWhereArchiveName)
+                               OR name = '" . ArchiveSelector::NB_VISITS_RECORD_LOOKED_UP . "'
+                               OR name = '" . ArchiveSelector::NB_VISITS_CONVERTED_RECORD_LOOKED_UP . "')
+                         $timeStampWhere
+                     ORDER BY idarchive DESC";
+        $results = Db::fetchAll($sqlQuery, $bindSQL);
+
+        return $results;
+    }
+
+    public function createArchiveTable($tableName, $tableNamePrefix)
+    {
+        $db  = Db::get();
+        $sql = DbHelper::getTableCreateSql($tableNamePrefix);
+
+        // replace table name template by real name
+        $tableNamePrefix = Common::prefixTable($tableNamePrefix);
+        $sql = str_replace($tableNamePrefix, $tableName, $sql);
+
+        try {
+            $db->query($sql);
+        } catch (Exception $e) {
+            // accept mysql error 1050: table already exists, throw otherwise
+            if (!$db->isErrNo($e, '1050')) {
+                throw $e;
+            }
+        }
+    }
+
+    /**
+     * Locks the archive table to generate a new archive ID.
+     *
+     * We lock to make sure that
+     * if several archiving processes are running at the same time (for different websites and/or periods)
+     * then they will each use a unique archive ID.
+     *
+     * @return int
+     */
+    public function insertNewArchiveId($numericTable, $idSite, $date)
+    {
+        $this->acquireArchiveTableLock($numericTable);
+
+        $locked = self::PREFIX_SQL_LOCK . Common::generateUniqId();
+
+        $insertSql = "INSERT INTO $numericTable "
+            . " SELECT IFNULL( MAX(idarchive), 0 ) + 1,
+                                '" . $locked . "',
+                                " . (int)$idSite . ",
+                                '" . $date . "',
+                                '" . $date . "',
+                                0,
+                                '" . $date . "',
+                                0 "
+            . " FROM $numericTable as tb1";
+        Db::get()->exec($insertSql);
+
+        $this->releaseArchiveTableLock($numericTable);
+
+        $selectIdSql = "SELECT idarchive FROM $numericTable WHERE name = ? LIMIT 1";
+        $id = Db::get()->fetchOne($selectIdSql, $locked);
+        return $id;
+    }
+
+    public function deletePreviousArchiveStatus($numericTable, $archiveId, $doneFlag)
+    {
+        // without advisory lock here, the DELETE would acquire Exclusive Lock
+        $this->acquireArchiveTableLock($numericTable);
+
+        Db::query("DELETE FROM $numericTable WHERE idarchive = ? AND (name = '" . $doneFlag
+                . "' OR name LIKE '" . self::PREFIX_SQL_LOCK . "%')",
+            array($archiveId)
+        );
+
+        $this->releaseArchiveTableLock($numericTable);
+    }
+
+    public function insertRecord($tableName, $fields, $record, $name, $value)
+    {
+        // duplicate idarchives are Ignored, see https://github.com/piwik/piwik/issues/987
+        $query = "INSERT IGNORE INTO " . $tableName . " (" . implode(", ", $fields) . ")
+                  VALUES (?,?,?,?,?,?,?,?)";
+
+        $bindSql   = $record;
+        $bindSql[] = $name;
+        $bindSql[] = $value;
+
+        Db::query($query, $bindSql);
+
+        return true;
+    }
+
+    /**
+     * Returns the SQL condition used to find successfully completed archives that
+     * this instance is querying for.
+     */
+    private static function getNameCondition($doneFlags, $possibleValues)
+    {
+        $allDoneFlags = "'" . implode("','", $doneFlags) . "'";
+
+        // create the SQL to find archives that are DONE
+        return "((name IN ($allDoneFlags)) AND (value IN (" . implode(',', $possibleValues) . ")))";
+    }
+
+    protected function acquireArchiveTableLock($numericTable)
+    {
+        $dbLockName = $this->getArchiveLockName($numericTable);
+
+        if (Db::getDbLock($dbLockName, $maxRetries = 30) === false) {
+            throw new Exception("allocateNewArchiveId: Cannot get named lock $dbLockName.");
+        }
+    }
+
+    protected function releaseArchiveTableLock($numericTable)
+    {
+        $dbLockName = $this->getArchiveLockName($numericTable);
+        Db::releaseDbLock($dbLockName);
+    }
+
+    protected function getArchiveLockName($numericTable)
+    {
+        return "allocateNewArchiveId.$numericTable";
+    }
+
+}
diff --git a/core/DataArray.php b/core/DataArray.php
index 042d5ae9619d13324a7f7e328077bd8a75484e90..04c98971259e73c17da451657c547d704e64c137 100644
--- a/core/DataArray.php
+++ b/core/DataArray.php
@@ -108,7 +108,7 @@ class DataArray
 
         // In case the existing Row had no action metrics (eg. Custom Variable XYZ with "visit" scope)
         // but the new Row has action metrics (eg. same Custom Variable XYZ this time with a "page" scope)
-        if(!isset($oldRowToUpdate[Metrics::INDEX_MAX_ACTIONS])) {
+        if (!isset($oldRowToUpdate[Metrics::INDEX_MAX_ACTIONS])) {
             $toZero = array(Metrics::INDEX_MAX_ACTIONS,
                             Metrics::INDEX_SUM_VISIT_LENGTH,
                             Metrics::INDEX_BOUNCE_COUNT,
@@ -247,8 +247,8 @@ class DataArray
         $oldRowToUpdate[Metrics::INDEX_EVENT_MAX_EVENT_VALUE] = round(max($newRowToAdd[Metrics::INDEX_EVENT_MAX_EVENT_VALUE], $oldRowToUpdate[Metrics::INDEX_EVENT_MAX_EVENT_VALUE]), self::EVENT_VALUE_PRECISION);
 
         // Update minimum only if it is set
-        if($newRowToAdd[Metrics::INDEX_EVENT_MIN_EVENT_VALUE] !== false) {
-            if($oldRowToUpdate[Metrics::INDEX_EVENT_MIN_EVENT_VALUE] === false) {
+        if ($newRowToAdd[Metrics::INDEX_EVENT_MIN_EVENT_VALUE] !== false) {
+            if ($oldRowToUpdate[Metrics::INDEX_EVENT_MIN_EVENT_VALUE] === false) {
                 $oldRowToUpdate[Metrics::INDEX_EVENT_MIN_EVENT_VALUE] = round($newRowToAdd[Metrics::INDEX_EVENT_MIN_EVENT_VALUE], self::EVENT_VALUE_PRECISION);
             } else {
                 $oldRowToUpdate[Metrics::INDEX_EVENT_MIN_EVENT_VALUE] = round(min($newRowToAdd[Metrics::INDEX_EVENT_MIN_EVENT_VALUE], $oldRowToUpdate[Metrics::INDEX_EVENT_MIN_EVENT_VALUE]), self::EVENT_VALUE_PRECISION);
@@ -360,7 +360,7 @@ class DataArray
 
             // if there are no "visit" column, we force one to prevent future complications
             // eg. This helps the setDefaultColumnsToDisplay() call
-            if(!isset($values[Metrics::INDEX_NB_VISITS])) {
+            if (!isset($values[Metrics::INDEX_NB_VISITS])) {
                 $values[Metrics::INDEX_NB_VISITS] = 0;
             }
         }
diff --git a/core/DataTable.php b/core/DataTable.php
index bc5a57cff664988a623f4b8dac84f609b690f4a2..4d308f7d21c914bfeca5168babd5a933468320c0 100644
--- a/core/DataTable.php
+++ b/core/DataTable.php
@@ -469,11 +469,13 @@ class DataTable implements DataTableInterface, \IteratorAggregate, \ArrayAccess
      * metadata can be used to specify a different type of operation.
      *
      * @param \Piwik\DataTable $tableToSum
+     * @param bool $doAggregateSubTables
+     * @throws Exception
      */
     public function addDataTable(DataTable $tableToSum, $doAggregateSubTables = true)
     {
-        if($tableToSum instanceof Simple) {
-            if($tableToSum->getRowsCount() > 1) {
+        if ($tableToSum instanceof Simple) {
+            if ($tableToSum->getRowsCount() > 1) {
                 throw new Exception("Did not expect a Simple table with more than one row in addDataTable()");
             }
             $row = $tableToSum->getFirstRow();
@@ -897,7 +899,7 @@ class DataTable implements DataTableInterface, \IteratorAggregate, \ArrayAccess
         foreach ($this->getRows() as $row) {
             $row->renameColumn($oldName, $newName);
 
-            if($doRenameColumnsOfSubTables) {
+            if ($doRenameColumnsOfSubTables) {
                 if (($idSubDataTable = $row->getIdSubDataTable()) !== null) {
                     Manager::getInstance()->getTable($idSubDataTable)->renameColumn($oldName, $newName);
                 }
@@ -1602,7 +1604,7 @@ class DataTable implements DataTableInterface, \IteratorAggregate, \ArrayAccess
         } else {
             $rowFound->sumRow($row, $copyMeta = true, $this->getMetadata(self::COLUMN_AGGREGATION_OPS_METADATA_NAME));
 
-            if($doAggregateSubTables) {
+            if ($doAggregateSubTables) {
                 // if the row to add has a subtable whereas the current row doesn't
                 // we simply add it (cloning the subtable)
                 // if the row has the subtable already
diff --git a/core/DataTable/Filter/AddColumnsProcessedMetricsGoal.php b/core/DataTable/Filter/AddColumnsProcessedMetricsGoal.php
index 742f1aef6ddb5f357fa3b0cb0bc76714aa2f0f2b..963ac9acbde6321bb693c7fe639781bead51e660 100644
--- a/core/DataTable/Filter/AddColumnsProcessedMetricsGoal.php
+++ b/core/DataTable/Filter/AddColumnsProcessedMetricsGoal.php
@@ -8,12 +8,10 @@
  */
 namespace Piwik\DataTable\Filter;
 
-use Exception;
 use Piwik\DataTable;
 use Piwik\DataTable\Row;
 use Piwik\Metrics;
 use Piwik\Piwik;
-use Piwik\Tracker\GoalManager;
 
 /**
  * Adds goal related metrics to a {@link DataTable} using metrics that already exist.
diff --git a/core/DataTable/Filter/BeautifyRangeLabels.php b/core/DataTable/Filter/BeautifyRangeLabels.php
index 534f484bff1aebca0160eea7ef816df4fa001a3a..bf5e8d65d9ff28dbb8d6f435686adeb28a2670e3 100644
--- a/core/DataTable/Filter/BeautifyRangeLabels.php
+++ b/core/DataTable/Filter/BeautifyRangeLabels.php
@@ -65,7 +65,7 @@ class BeautifyRangeLabels extends ColumnCallbackReplace
         parent::__construct($table, 'label', array($this, 'beautify'), array());
 
         $this->labelSingular = $labelSingular;
-        $this->labelPlural = $labelPlural;
+        $this->labelPlural   = $labelPlural;
     }
 
     /**
diff --git a/core/DataTable/Filter/CalculateEvolutionFilter.php b/core/DataTable/Filter/CalculateEvolutionFilter.php
index 80f789919e6d65b1d46d7abd4e2cc8f5859be4a9..0ef6a30a2fadceff2f14e2ee831008c4df234d8a 100755
--- a/core/DataTable/Filter/CalculateEvolutionFilter.php
+++ b/core/DataTable/Filter/CalculateEvolutionFilter.php
@@ -121,6 +121,7 @@ class CalculateEvolutionFilter extends ColumnCallbackAddColumnPercentage
     {
         $value = self::getPercentageValue($value, $divisor, $this->quotientPrecision);
         $value = self::appendPercentSign($value);
+
         return $value;
     }
 
@@ -152,6 +153,7 @@ class CalculateEvolutionFilter extends ColumnCallbackAddColumnPercentage
         if ($appendPercentSign) {
             $number = self::appendPercentSign($number);
         }
+
         return $number;
     }
 
@@ -165,6 +167,7 @@ class CalculateEvolutionFilter extends ColumnCallbackAddColumnPercentage
         if ($number > 0) {
             $number = '+' . $number;
         }
+
         return $number;
     }
 
diff --git a/core/DataTable/Filter/ColumnCallbackAddColumnQuotient.php b/core/DataTable/Filter/ColumnCallbackAddColumnQuotient.php
index 5cc83d8e3d2c3ec9e20ae4bf325179ea7cc72204..81d8eadf047e4b2aa22711049d2301a01ea8c9f3 100644
--- a/core/DataTable/Filter/ColumnCallbackAddColumnQuotient.php
+++ b/core/DataTable/Filter/ColumnCallbackAddColumnQuotient.php
@@ -109,6 +109,7 @@ class ColumnCallbackAddColumnQuotient extends BaseFilter
         if ($divisor > 0 && $value > 0) {
             $quotient = round($value / $divisor, $this->quotientPrecision);
         }
+
         return $quotient;
     }
 
diff --git a/core/DataTable/Filter/ColumnCallbackAddMetadata.php b/core/DataTable/Filter/ColumnCallbackAddMetadata.php
index e89000f8fdc6b99b893a0a1c3734078ac0191524..c7945839cb3283f04c2df44e783b1f454ba06308 100644
--- a/core/DataTable/Filter/ColumnCallbackAddMetadata.php
+++ b/core/DataTable/Filter/ColumnCallbackAddMetadata.php
@@ -48,12 +48,12 @@ class ColumnCallbackAddMetadata extends BaseFilter
         if (!is_array($columnsToRead)) {
             $columnsToRead = array($columnsToRead);
         }
-        $this->columnsToRead = $columnsToRead;
 
-        $this->functionToApply = $functionToApply;
+        $this->columnsToRead      = $columnsToRead;
+        $this->functionToApply    = $functionToApply;
         $this->functionParameters = $functionParameters;
-        $this->metadataToAdd = $metadataToAdd;
-        $this->applyToSummaryRow = $applyToSummaryRow;
+        $this->metadataToAdd      = $metadataToAdd;
+        $this->applyToSummaryRow  = $applyToSummaryRow;
     }
 
     /**
diff --git a/core/DataTable/Filter/ColumnCallbackDeleteRow.php b/core/DataTable/Filter/ColumnCallbackDeleteRow.php
index 189fbd3b814de902674913fe572d2d75f2adf5b2..414bf71e8a8bb519d17a2adf9fb893c96813cb1a 100644
--- a/core/DataTable/Filter/ColumnCallbackDeleteRow.php
+++ b/core/DataTable/Filter/ColumnCallbackDeleteRow.php
@@ -25,7 +25,6 @@ use Piwik\DataTable\BaseFilter;
  */
 class ColumnCallbackDeleteRow extends BaseFilter
 {
-    private $columnToFilter;
     private $function;
     private $functionParams;
 
diff --git a/core/DataTable/Filter/ColumnCallbackReplace.php b/core/DataTable/Filter/ColumnCallbackReplace.php
index e33dfa9a147b6070de57b60e29b684a268851011..ca53405d7e80ca9d9941f1eecbb36c6440a7f929 100644
--- a/core/DataTable/Filter/ColumnCallbackReplace.php
+++ b/core/DataTable/Filter/ColumnCallbackReplace.php
@@ -54,14 +54,14 @@ class ColumnCallbackReplace extends BaseFilter
                                 $extraColumnParameters = array())
     {
         parent::__construct($table);
-        $this->functionToApply = $functionToApply;
+        $this->functionToApply    = $functionToApply;
         $this->functionParameters = $functionParameters;
 
         if (!is_array($columnsToFilter)) {
             $columnsToFilter = array($columnsToFilter);
         }
 
-        $this->columnsToFilter = $columnsToFilter;
+        $this->columnsToFilter       = $columnsToFilter;
         $this->extraColumnParameters = $extraColumnParameters;
     }
 
@@ -73,6 +73,7 @@ class ColumnCallbackReplace extends BaseFilter
     public function filter($table)
     {
         foreach ($table->getRows() as $row) {
+
             $extraColumnParameters = array();
             foreach ($this->extraColumnParameters as $columnName) {
                 $extraColumnParameters[] = $row->getColumn($columnName);
@@ -86,9 +87,11 @@ class ColumnCallbackReplace extends BaseFilter
                 }
 
                 $parameters = array_merge(array($value), $extraColumnParameters);
+
                 if (!is_null($this->functionParameters)) {
                     $parameters = array_merge($parameters, $this->functionParameters);
                 }
+
                 $newValue = call_user_func_array($this->functionToApply, $parameters);
                 $this->setElementToReplace($row, $column, $newValue);
                 $this->filterSubTable($row);
diff --git a/core/DataTable/Filter/ColumnDelete.php b/core/DataTable/Filter/ColumnDelete.php
index 5aac6d44a63e54ebbca7797c3457cdc391ace6f1..743f5afd8632bc642056bf8206e79f1399f46c98 100644
--- a/core/DataTable/Filter/ColumnDelete.php
+++ b/core/DataTable/Filter/ColumnDelete.php
@@ -91,6 +91,7 @@ class ColumnDelete extends BaseFilter
      * See {@link ColumnDelete}.
      *
      * @param DataTable $table
+     * @return DataTable
      */
     public function filter($table)
     {
diff --git a/core/DataTable/Filter/GroupBy.php b/core/DataTable/Filter/GroupBy.php
index 8633fb2e9d54df4ddf5e2557bbd41a25b4fc58b3..b899bb9059b8d7610f0854b15267bff7cfe322fe 100755
--- a/core/DataTable/Filter/GroupBy.php
+++ b/core/DataTable/Filter/GroupBy.php
@@ -59,9 +59,9 @@ class GroupBy extends BaseFilter
     {
         parent::__construct($table);
 
-        $this->groupByColumn = $groupByColumn;
+        $this->groupByColumn  = $groupByColumn;
         $this->reduceFunction = $reduceFunction;
-        $this->parameters = $parameters;
+        $this->parameters     = $parameters;
     }
 
     /**
@@ -82,7 +82,7 @@ class GroupBy extends BaseFilter
 
             // reduce the group by column of this row
             $groupByColumnValue = $row->getColumn($this->groupByColumn);
-            $parameters = array_merge(array($groupByColumnValue), $this->parameters);
+            $parameters   = array_merge(array($groupByColumnValue), $this->parameters);
             $groupByValue = call_user_func_array($this->reduceFunction, $parameters);
 
             if (!isset($groupByRows[$groupByValue])) {
diff --git a/core/DataTable/Filter/Limit.php b/core/DataTable/Filter/Limit.php
index 5cf848a50eef018579831464ef5fdf2dabe5bbd4..415be296020ec1464f311826ed15b945fdff8dff 100644
--- a/core/DataTable/Filter/Limit.php
+++ b/core/DataTable/Filter/Limit.php
@@ -34,9 +34,9 @@ class Limit extends BaseFilter
     public function __construct($table, $offset, $limit = -1, $keepSummaryRow = false)
     {
         parent::__construct($table);
-        $this->offset = $offset;
 
-        $this->limit = $limit;
+        $this->offset = $offset;
+        $this->limit  = $limit;
         $this->keepSummaryRow = $keepSummaryRow;
     }
 
diff --git a/core/DataTable/Filter/Sort.php b/core/DataTable/Filter/Sort.php
index 683e93cffe9f766f7d5ab919a9fdbd89630d67cf..9df22502887258ba8ed4ab17026a04e9a8b7151f 100644
--- a/core/DataTable/Filter/Sort.php
+++ b/core/DataTable/Filter/Sort.php
@@ -38,11 +38,13 @@ class Sort extends BaseFilter
     public function __construct($table, $columnToSort, $order = 'desc', $naturalSort = true, $recursiveSort = false)
     {
         parent::__construct($table);
+
         if ($recursiveSort) {
             $table->enableRecursiveSort();
         }
+
         $this->columnToSort = $columnToSort;
-        $this->naturalSort = $naturalSort;
+        $this->naturalSort  = $naturalSort;
         $this->setOrder($order);
     }
 
@@ -55,10 +57,10 @@ class Sort extends BaseFilter
     {
         if ($order == 'asc') {
             $this->order = 'asc';
-            $this->sign = 1;
+            $this->sign  = 1;
         } else {
             $this->order = 'desc';
-            $this->sign = -1;
+            $this->sign  = -1;
         }
     }
 
@@ -225,17 +227,21 @@ class Sort extends BaseFilter
         if ($table instanceof Simple) {
             return;
         }
+
         if (empty($this->columnToSort)) {
             return;
         }
+
         $rows = $table->getRows();
         if (count($rows) == 0) {
             return;
         }
+
         $row = current($rows);
         if ($row === false) {
             return;
         }
+
         $this->columnToSort = $this->selectColumnToSort($row);
 
         $value = $row->getColumn($this->columnToSort);
@@ -248,6 +254,7 @@ class Sort extends BaseFilter
                 $methodToUse = "sortString";
             }
         }
+
         $table->sort(array($this, $methodToUse), $this->columnToSort);
     }
 }
diff --git a/core/DataTable/Filter/Truncate.php b/core/DataTable/Filter/Truncate.php
index 192d85b82fdf38bcac8154c7c5b3e76c4d6daa52..120fc377601f770d896dfc9b8811131be4343e85 100644
--- a/core/DataTable/Filter/Truncate.php
+++ b/core/DataTable/Filter/Truncate.php
@@ -89,9 +89,10 @@ class Truncate extends BaseFilter
             return;
         }
 
-        $rows = $table->getRows();
-        $count = $table->getRowsCount();
+        $rows   = $table->getRows();
+        $count  = $table->getRowsCount();
         $newRow = new Row(array(Row::COLUMNS => array('label' => DataTable::LABEL_SUMMARY_ROW)));
+
         for ($i = $this->truncateAfter; $i < $count; $i++) {
             if (!isset($rows[$i])) {
                 // case when the last row is a summary row, it is not indexed by $cout but by DataTable::ID_SUMMARY_ROW
diff --git a/core/DataTable/Manager.php b/core/DataTable/Manager.php
index c19060b803175f65192a13e88a5d4e020a9e8c8d..d225b8fb87a3ad6e3e0899ec4065ae39defc18aa 100644
--- a/core/DataTable/Manager.php
+++ b/core/DataTable/Manager.php
@@ -63,6 +63,7 @@ class Manager extends Singleton
         if (!isset($this->tables[$idTable])) {
             throw new TableNotFoundException(sprintf("This report has been reprocessed since your last click. To see this error less often, please increase the timeout value in seconds in Settings > General Settings. (error: id %s not found).", $idTable));
         }
+
         return $this->tables[$idTable];
     }
 
@@ -86,6 +87,7 @@ class Manager extends Singleton
                 $this->deleteTable($id);
             }
         }
+
         if ($deleteWhenIdTableGreaterThan == 0) {
             $this->tables = array();
             $this->nextTableId = 1;
diff --git a/core/DataTable/Map.php b/core/DataTable/Map.php
index dd8bec7ca5b6d9dbed57556375ac857762d31608..8795eac13423b6507fb2ab47f050a0e2ff64223b 100644
--- a/core/DataTable/Map.php
+++ b/core/DataTable/Map.php
@@ -246,12 +246,14 @@ class Map implements DataTableInterface
     public function getColumn($name)
     {
         $values = array();
+
         foreach ($this->getDataTables() as $table) {
             $moreValues = $table->getColumn($name);
             foreach ($moreValues as &$value) {
                 $values[] = $value;
             }
         }
+
         return $values;
     }
 
diff --git a/core/DataTable/Renderer.php b/core/DataTable/Renderer.php
index 5705b3e205289dd9aade20705f39c6cb94f098c8..f825739611ce1887c831dad84aec619cb2f330a5 100644
--- a/core/DataTable/Renderer.php
+++ b/core/DataTable/Renderer.php
@@ -161,13 +161,16 @@ abstract class Renderer extends BaseFactory
     {
         $className = ucfirst(strtolower($id));
         $className = 'Piwik\DataTable\Renderer\\' . $className;
+
         return $className;
     }
 
     protected static function getInvalidClassIdExceptionMessage($id)
     {
         $availableRenderers = implode(', ', self::getRenderers());
-        return Piwik::translate('General_ExceptionInvalidRendererFormat', array(self::getClassNameFromClassId($id), $availableRenderers));
+        $klassName = self::getClassNameFromClassId($id);
+
+        return Piwik::translate('General_ExceptionInvalidRendererFormat', array($klassName, $availableRenderers));
     }
 
     /**
@@ -187,12 +190,15 @@ abstract class Renderer extends BaseFactory
                 $value = @mb_convert_encoding($value, 'UTF-8', 'UTF-8');
             }
             $value = htmlspecialchars($value, ENT_COMPAT, 'UTF-8');
+
             $htmlentities = array("&nbsp;", "&iexcl;", "&cent;", "&pound;", "&curren;", "&yen;", "&brvbar;", "&sect;", "&uml;", "&copy;", "&ordf;", "&laquo;", "&not;", "&shy;", "&reg;", "&macr;", "&deg;", "&plusmn;", "&sup2;", "&sup3;", "&acute;", "&micro;", "&para;", "&middot;", "&cedil;", "&sup1;", "&ordm;", "&raquo;", "&frac14;", "&frac12;", "&frac34;", "&iquest;", "&Agrave;", "&Aacute;", "&Acirc;", "&Atilde;", "&Auml;", "&Aring;", "&AElig;", "&Ccedil;", "&Egrave;", "&Eacute;", "&Ecirc;", "&Euml;", "&Igrave;", "&Iacute;", "&Icirc;", "&Iuml;", "&ETH;", "&Ntilde;", "&Ograve;", "&Oacute;", "&Ocirc;", "&Otilde;", "&Ouml;", "&times;", "&Oslash;", "&Ugrave;", "&Uacute;", "&Ucirc;", "&Uuml;", "&Yacute;", "&THORN;", "&szlig;", "&agrave;", "&aacute;", "&acirc;", "&atilde;", "&auml;", "&aring;", "&aelig;", "&ccedil;", "&egrave;", "&eacute;", "&ecirc;", "&euml;", "&igrave;", "&iacute;", "&icirc;", "&iuml;", "&eth;", "&ntilde;", "&ograve;", "&oacute;", "&ocirc;", "&otilde;", "&ouml;", "&divide;", "&oslash;", "&ugrave;", "&uacute;", "&ucirc;", "&uuml;", "&yacute;", "&thorn;", "&yuml;", "&euro;");
-            $xmlentities = array("&#162;", "&#163;", "&#164;", "&#165;", "&#166;", "&#167;", "&#168;", "&#169;", "&#170;", "&#171;", "&#172;", "&#173;", "&#174;", "&#175;", "&#176;", "&#177;", "&#178;", "&#179;", "&#180;", "&#181;", "&#182;", "&#183;", "&#184;", "&#185;", "&#186;", "&#187;", "&#188;", "&#189;", "&#190;", "&#191;", "&#192;", "&#193;", "&#194;", "&#195;", "&#196;", "&#197;", "&#198;", "&#199;", "&#200;", "&#201;", "&#202;", "&#203;", "&#204;", "&#205;", "&#206;", "&#207;", "&#208;", "&#209;", "&#210;", "&#211;", "&#212;", "&#213;", "&#214;", "&#215;", "&#216;", "&#217;", "&#218;", "&#219;", "&#220;", "&#221;", "&#222;", "&#223;", "&#224;", "&#225;", "&#226;", "&#227;", "&#228;", "&#229;", "&#230;", "&#231;", "&#232;", "&#233;", "&#234;", "&#235;", "&#236;", "&#237;", "&#238;", "&#239;", "&#240;", "&#241;", "&#242;", "&#243;", "&#244;", "&#245;", "&#246;", "&#247;", "&#248;", "&#249;", "&#250;", "&#251;", "&#252;", "&#253;", "&#254;", "&#255;", "&#8364;");
-            $value = str_replace($htmlentities, $xmlentities, $value);
+            $xmlentities  = array("&#162;", "&#163;", "&#164;", "&#165;", "&#166;", "&#167;", "&#168;", "&#169;", "&#170;", "&#171;", "&#172;", "&#173;", "&#174;", "&#175;", "&#176;", "&#177;", "&#178;", "&#179;", "&#180;", "&#181;", "&#182;", "&#183;", "&#184;", "&#185;", "&#186;", "&#187;", "&#188;", "&#189;", "&#190;", "&#191;", "&#192;", "&#193;", "&#194;", "&#195;", "&#196;", "&#197;", "&#198;", "&#199;", "&#200;", "&#201;", "&#202;", "&#203;", "&#204;", "&#205;", "&#206;", "&#207;", "&#208;", "&#209;", "&#210;", "&#211;", "&#212;", "&#213;", "&#214;", "&#215;", "&#216;", "&#217;", "&#218;", "&#219;", "&#220;", "&#221;", "&#222;", "&#223;", "&#224;", "&#225;", "&#226;", "&#227;", "&#228;", "&#229;", "&#230;", "&#231;", "&#232;", "&#233;", "&#234;", "&#235;", "&#236;", "&#237;", "&#238;", "&#239;", "&#240;", "&#241;", "&#242;", "&#243;", "&#244;", "&#245;", "&#246;", "&#247;", "&#248;", "&#249;", "&#250;", "&#251;", "&#252;", "&#253;", "&#254;", "&#255;", "&#8364;");
+            $value        = str_replace($htmlentities, $xmlentities, $value);
+
         } elseif ($value === false) {
             $value = 0;
         }
+
         return $value;
     }
 
diff --git a/core/DataTable/Renderer/Console.php b/core/DataTable/Renderer/Console.php
index 88161165fc6ef45c7baf42bd64a62fe9a630c77f..0e1c127fb140f3a6186f4ffb0fca9243d9882d98 100644
--- a/core/DataTable/Renderer/Console.php
+++ b/core/DataTable/Renderer/Console.php
@@ -142,7 +142,7 @@ class Console extends Renderer
             foreach ($metadata as $id => $metadataIn) {
                 $output .= "<br />";
                 $output .= $prefix . " <b>$id</b><br />";
-                if(is_array($metadataIn)) {
+                if (is_array($metadataIn)) {
                     foreach ($metadataIn as $name => $value) {
                         $output .= $prefix . $prefix . "$name => $value";
                     }
diff --git a/core/DataTable/Renderer/Json.php b/core/DataTable/Renderer/Json.php
index 8fea38a6586575c489bbbcceefc41e3754f40a65..f53ea60e67f52e250e422f79f54fe51fc730032b 100644
--- a/core/DataTable/Renderer/Json.php
+++ b/core/DataTable/Renderer/Json.php
@@ -11,7 +11,6 @@ namespace Piwik\DataTable\Renderer;
 use Piwik\Common;
 use Piwik\DataTable\Renderer;
 use Piwik\DataTable;
-use Piwik\ProxyHttp;
 
 /**
  * JSON export.
diff --git a/core/DataTable/Row.php b/core/DataTable/Row.php
index 72e6d67b6c52cb5bb6359b1bdc62b2d82af01ed6..07946adfd10baa9f912f649ff856c6a2384ddb39 100644
--- a/core/DataTable/Row.php
+++ b/core/DataTable/Row.php
@@ -183,7 +183,7 @@ class Row implements \ArrayAccess, \IteratorAggregate
         if (isset($this->c[self::COLUMNS][$oldName])) {
             $this->c[self::COLUMNS][$newName] = $this->c[self::COLUMNS][$oldName];
         }
-        // outside the if() since we want to delete nulled columns
+        // outside the if () since we want to delete nulled columns
         unset($this->c[self::COLUMNS][$oldName]);
     }
 
@@ -500,9 +500,10 @@ class Row implements \ArrayAccess, \IteratorAggregate
      *
      * @param \Piwik\DataTable\Row $rowToSum The row to sum to this row.
      * @param bool $enableCopyMetadata Whether metadata should be copied or not.
-     * @param array $aggregationOperations for columns that should not be summed, determine which
+     * @param array|bool $aggregationOperations for columns that should not be summed, determine which
      *                                     aggregation should be used (min, max). format:
      *                                     `array('column name' => 'function name')`
+     * @throws Exception
      */
     public function sumRow(Row $rowToSum, $enableCopyMetadata = true, $aggregationOperations = false)
     {
@@ -528,7 +529,7 @@ class Row implements \ArrayAccess, \IteratorAggregate
             if ($columnToSumName == Metrics::INDEX_MAX_ACTIONS) {
                 $operation = 'max';
             }
-            if(empty($operation)) {
+            if (empty($operation)) {
                 throw new Exception("Unknown aggregation operation for column $columnToSumName.");
             }
 
diff --git a/core/Date.php b/core/Date.php
index c5b4cd7af6766a3b1a8e6d70eb1fbb4df2b968a6..5b8e0fab6e01504348d2885c92fdc1a35fcaa6f9 100644
--- a/core/Date.php
+++ b/core/Date.php
@@ -273,15 +273,16 @@ class Date
         // Unit tests pass (@see Date.test.php) but I'm pretty sure this is not the right way to do it
         date_default_timezone_set($this->timezone);
         $dtzone = timezone_open('UTC');
-        $time = date('r', $this->timestamp);
-        $dtime = date_create($time);
+        $time   = date('r', $this->timestamp);
+        $dtime  = date_create($time);
+
         date_timezone_set($dtime, $dtzone);
-        $dateWithTimezone = date_format($dtime, 'r');
+        $dateWithTimezone    = date_format($dtime, 'r');
         $dateWithoutTimezone = substr($dateWithTimezone, 0, -6);
-        $timestamp = strtotime($dateWithoutTimezone);
+        $timestamp           = strtotime($dateWithoutTimezone);
         date_default_timezone_set('UTC');
 
-        return (int)$timestamp;
+        return (int) $timestamp;
     }
 
     /**
diff --git a/core/Db.php b/core/Db.php
index e845a5ab6e5b4c70162cc99ace8639818d0d0d04..52c454e3333ed84dadc287bafb7da4811d9c3fe7 100644
--- a/core/Db.php
+++ b/core/Db.php
@@ -141,6 +141,7 @@ class Db
         }
 
         $profiler->queryEnd($q);
+
         return $return;
     }
 
@@ -271,7 +272,7 @@ class Db
      *
      * @param string $table The name of the table to delete from. Must be prefixed (see {@link Piwik\Common::prefixTable()}).
      * @param string $where The where clause of the query. Must include the WHERE keyword.
-     * @param $orderBy The column to order by and the order by direction, eg, `idvisit ASC`.
+     * @param string $orderBy The column to order by and the order by direction, eg, `idvisit ASC`.
      * @param int $maxRowsPerQuery The maximum number of rows to delete per `DELETE` query.
      * @param array $parameters Parameters to bind for each query.
      * @return int The total number of rows deleted.
@@ -279,13 +280,13 @@ class Db
     public static function deleteAllRows($table, $where, $orderBy, $maxRowsPerQuery = 100000, $parameters = array())
     {
         $orderByClause = $orderBy ? "ORDER BY $orderBy" : "";
-        $sql = "DELETE FROM $table
-                $where
-                $orderByClause
+
+        $sql = "DELETE FROM $table $where $orderByClause
                 LIMIT " . (int)$maxRowsPerQuery;
 
         // delete rows w/ a limit
         $totalRowsDeleted = 0;
+
         do {
             $rowsDeleted = self::query($sql, $parameters)->rowCount();
 
@@ -308,6 +309,7 @@ class Db
     public static function optimizeTables($tables)
     {
         $optimize = Config::getInstance()->General['enable_sql_optimize_queries'];
+
         if (empty($optimize)) {
             return;
         }
@@ -315,13 +317,14 @@ class Db
         if (empty($tables)) {
             return false;
         }
+
         if (!is_array($tables)) {
             $tables = array($tables);
         }
 
         // filter out all InnoDB tables
         $myisamDbTables = array();
-        foreach (Db::fetchAll("SHOW TABLE STATUS") as $row) {
+        foreach (self::getTableStatus() as $row) {
             if (strtolower($row['Engine']) == 'myisam'
                 && in_array($row['Name'], $tables)
             ) {
@@ -337,6 +340,11 @@ class Db
         return self::query("OPTIMIZE TABLE " . implode(',', $myisamDbTables));
     }
 
+    private static function getTableStatus()
+    {
+        return Db::fetchAll("SHOW TABLE STATUS");
+    }
+
     /**
      * Drops the supplied table or tables.
      *
@@ -397,6 +405,7 @@ class Db
         if (!is_array($tablesToRead)) {
             $tablesToRead = array($tablesToRead);
         }
+
         if (!is_array($tablesToWrite)) {
             $tablesToWrite = array($tablesToWrite);
         }
@@ -405,6 +414,7 @@ class Db
         foreach ($tablesToWrite as $table) {
             $lockExprs[] = $table . " WRITE";
         }
+
         foreach ($tablesToRead as $table) {
             $lockExprs[] = $table . " READ";
         }
@@ -466,6 +476,7 @@ class Db
     public static function segmentedFetchFirst($sql, $first, $last, $step, $params = array())
     {
         $result = false;
+
         if ($step > 0) {
             for ($i = $first; $result === false && $i <= $last; $i += $step) {
                 $result = self::fetchOne($sql, array_merge($params, array($i, $i + $step)));
@@ -475,6 +486,7 @@ class Db
                 $result = self::fetchOne($sql, array_merge($params, array($i, $i + $step)));
             }
         }
+
         return $result;
     }
 
@@ -502,6 +514,7 @@ class Db
     public static function segmentedFetchOne($sql, $first, $last, $step, $params = array())
     {
         $result = array();
+
         if ($step > 0) {
             for ($i = $first; $i <= $last; $i += $step) {
                 $result[] = self::fetchOne($sql, array_merge($params, array($i, $i + $step)));
@@ -511,6 +524,7 @@ class Db
                 $result[] = self::fetchOne($sql, array_merge($params, array($i, $i + $step)));
             }
         }
+
         return $result;
     }
 
@@ -539,17 +553,19 @@ class Db
     public static function segmentedFetchAll($sql, $first, $last, $step, $params = array())
     {
         $result = array();
+
         if ($step > 0) {
             for ($i = $first; $i <= $last; $i += $step) {
                 $currentParams = array_merge($params, array($i, $i + $step));
-                $result = array_merge($result, self::fetchAll($sql, $currentParams));
+                $result        = array_merge($result, self::fetchAll($sql, $currentParams));
             }
         } else {
             for ($i = $first; $i >= $last; $i += $step) {
                 $currentParams = array_merge($params, array($i, $i + $step));
-                $result = array_merge($result, self::fetchAll($sql, $currentParams));
+                $result        = array_merge($result, self::fetchAll($sql, $currentParams));
             }
         }
+
         return $result;
     }
 
@@ -623,6 +639,7 @@ class Db
             }
             $maxRetries--;
         }
+
         return false;
     }
 
diff --git a/core/Db/Adapter.php b/core/Db/Adapter.php
index 342a320d723c38d58b29d7940521d9e92e7af7a2..5ddd529caa00d8d18a8c3672541ec91ba6135111 100644
--- a/core/Db/Adapter.php
+++ b/core/Db/Adapter.php
@@ -38,7 +38,7 @@ class Adapter
         }
 
         $className = self::getAdapterClassName($adapterName);
-        $adapter = new $className($dbInfos);
+        $adapter   = new $className($dbInfos);
 
         if ($connect) {
             $adapter->getConnection();
diff --git a/core/Db/Adapter/Mysqli.php b/core/Db/Adapter/Mysqli.php
index c864d057b01736e3efd626500d3ce560a3e13dd1..fa74f35c9d23b03b3ee01acc6b9f260eabd7a73b 100644
--- a/core/Db/Adapter/Mysqli.php
+++ b/core/Db/Adapter/Mysqli.php
@@ -56,8 +56,9 @@ class Mysqli extends Zend_Db_Adapter_Mysqli implements AdapterInterface
      */
     public function checkServerVersion()
     {
-        $serverVersion = $this->getServerVersion();
+        $serverVersion   = $this->getServerVersion();
         $requiredVersion = Config::getInstance()->General['minimum_mysql_version'];
+
         if (version_compare($serverVersion, $requiredVersion) === -1) {
             throw new Exception(Piwik::translate('General_ExceptionDatabaseVersion', array('MySQL', $serverVersion, $requiredVersion)));
         }
@@ -72,6 +73,7 @@ class Mysqli extends Zend_Db_Adapter_Mysqli implements AdapterInterface
     {
         $serverVersion = $this->getServerVersion();
         $clientVersion = $this->getClientVersion();
+
         // incompatible change to DECIMAL implementation in 5.0.3
         if (version_compare($serverVersion, '5.0.3') >= 0
             && version_compare($clientVersion, '5.0.3') < 0
@@ -168,10 +170,12 @@ class Mysqli extends Zend_Db_Adapter_Mysqli implements AdapterInterface
     public function getClientVersion()
     {
         $this->_connect();
-        $version = $this->_connection->server_version;
-        $major = (int)($version / 10000);
-        $minor = (int)($version % 10000 / 100);
+
+        $version  = $this->_connection->server_version;
+        $major    = (int)($version / 10000);
+        $minor    = (int)($version % 10000 / 100);
         $revision = (int)($version % 100);
+
         return $major . '.' . $minor . '.' . $revision;
     }
 }
diff --git a/core/Db/Adapter/Pdo/Mssql.php b/core/Db/Adapter/Pdo/Mssql.php
index fd0248958e568f2ff0c9cfaff676819ecd7ad2bb..ab032e145d06f837928d5cf05000e4e34d97b72b 100644
--- a/core/Db/Adapter/Pdo/Mssql.php
+++ b/core/Db/Adapter/Pdo/Mssql.php
@@ -66,7 +66,7 @@ class Mssql extends Zend_Db_Adapter_Pdo_Mssql implements AdapterInterface
 
         try {
             $serverName = $this->_config["host"];
-            $database = $this->_config["dbname"];
+            $database   = $this->_config["dbname"];
             if (is_null($database)) {
                 $database = 'master';
             }
@@ -134,8 +134,9 @@ class Mssql extends Zend_Db_Adapter_Pdo_Mssql implements AdapterInterface
      */
     public function checkServerVersion()
     {
-        $serverVersion = $this->getServerVersion();
+        $serverVersion   = $this->getServerVersion();
         $requiredVersion = Config::getInstance()->General['minimum_mssql_version'];
+
         if (version_compare($serverVersion, $requiredVersion) === -1) {
             throw new Exception(Piwik::translate('General_ExceptionDatabaseVersion', array('MSSQL', $serverVersion, $requiredVersion)));
         }
@@ -149,7 +150,7 @@ class Mssql extends Zend_Db_Adapter_Pdo_Mssql implements AdapterInterface
     public function getServerVersion()
     {
         try {
-            $stmt = $this->query("SELECT CAST(SERVERPROPERTY('productversion') as VARCHAR) as productversion");
+            $stmt   = $this->query("SELECT CAST(SERVERPROPERTY('productversion') as VARCHAR) as productversion");
             $result = $stmt->fetchAll(Zend_Db::FETCH_NUM);
             if (count($result)) {
                 return $result[0][0];
@@ -169,6 +170,7 @@ class Mssql extends Zend_Db_Adapter_Pdo_Mssql implements AdapterInterface
     {
         $serverVersion = $this->getServerVersion();
         $clientVersion = $this->getClientVersion();
+
         if (version_compare($serverVersion, '10') >= 0
             && version_compare($clientVersion, '10') < 0
         ) {
@@ -224,6 +226,7 @@ class Mssql extends Zend_Db_Adapter_Pdo_Mssql implements AdapterInterface
         if (preg_match('/(?:\[|\s)([0-9]{4})(?:\]|\s)/', $e->getMessage(), $match)) {
             return $match[1] == $errno;
         }
+
         return false;
     }
 
diff --git a/core/Db/Adapter/Pdo/Mysql.php b/core/Db/Adapter/Pdo/Mysql.php
index 59c3880bc9a577306f0d1b9d32fd343db62d374c..3ed5ae9c0f65b062879925d926ef1e703b5a0b98 100644
--- a/core/Db/Adapter/Pdo/Mysql.php
+++ b/core/Db/Adapter/Pdo/Mysql.php
@@ -92,8 +92,9 @@ class Mysql extends Zend_Db_Adapter_Pdo_Mysql implements AdapterInterface
      */
     public function checkServerVersion()
     {
-        $serverVersion = $this->getServerVersion();
+        $serverVersion   = $this->getServerVersion();
         $requiredVersion = Config::getInstance()->General['minimum_mysql_version'];
+
         if (version_compare($serverVersion, $requiredVersion) === -1) {
             throw new Exception(Piwik::translate('General_ExceptionDatabaseVersion', array('MySQL', $serverVersion, $requiredVersion)));
         }
@@ -108,6 +109,7 @@ class Mysql extends Zend_Db_Adapter_Pdo_Mysql implements AdapterInterface
     {
         $serverVersion = $this->getServerVersion();
         $clientVersion = $this->getClientVersion();
+
         // incompatible change to DECIMAL implementation in 5.0.3
         if (version_compare($serverVersion, '5.0.3') >= 0
             && version_compare($clientVersion, '5.0.3') < 0
@@ -159,6 +161,7 @@ class Mysql extends Zend_Db_Adapter_Pdo_Mysql implements AdapterInterface
         if (preg_match('/(?:\[|\s)([0-9]{4})(?:\]|\s)/', $e->getMessage(), $match)) {
             return $match[1] == $errno;
         }
+
         return false;
     }
 
@@ -170,9 +173,11 @@ class Mysql extends Zend_Db_Adapter_Pdo_Mysql implements AdapterInterface
     public function isConnectionUTF8()
     {
         $charsetInfo = $this->fetchAll('SHOW VARIABLES LIKE ?', array('character_set_connection'));
+
         if (empty($charsetInfo)) {
             return false;
         }
+
         $charset = $charsetInfo[0]['Value'];
         return $charset === 'utf8';
     }
diff --git a/core/Db/Adapter/Pdo/Pgsql.php b/core/Db/Adapter/Pdo/Pgsql.php
index c68280fe28227f73cdff3f20d89c124d99a23e69..0a37ab2dc92103978dff34394baaaba2cd2db984 100644
--- a/core/Db/Adapter/Pdo/Pgsql.php
+++ b/core/Db/Adapter/Pdo/Pgsql.php
@@ -47,6 +47,7 @@ class Pgsql extends Zend_Db_Adapter_Pdo_Pgsql implements AdapterInterface
     {
         $databaseVersion = $this->getServerVersion();
         $requiredVersion = Config::getInstance()->General['minimum_pgsql_version'];
+
         if (version_compare($databaseVersion, $requiredVersion) === -1) {
             throw new Exception(Piwik::translate('General_ExceptionDatabaseVersion', array('PostgreSQL', $databaseVersion, $requiredVersion)));
         }
@@ -146,6 +147,7 @@ class Pgsql extends Zend_Db_Adapter_Pdo_Pgsql implements AdapterInterface
         if (preg_match('/([0-9]{2}[0-9P][0-9]{2})/', $e->getMessage(), $match)) {
             return $match[1] == $map[$errno];
         }
+
         return false;
     }
 
diff --git a/core/Db/BatchInsert.php b/core/Db/BatchInsert.php
index 858dad4e38e8c8f0604ce80497405c020f7cee2d..f6e7a223c78c9f5d001a096a35db250871715a77 100644
--- a/core/Db/BatchInsert.php
+++ b/core/Db/BatchInsert.php
@@ -33,13 +33,12 @@ class BatchInsert
     public static function tableInsertBatchIterate($tableName, $fields, $values, $ignoreWhenDuplicate = true)
     {
         $fieldList = '(' . join(',', $fields) . ')';
-        $ignore = $ignoreWhenDuplicate ? 'IGNORE' : '';
+        $ignore    = $ignoreWhenDuplicate ? 'IGNORE' : '';
 
         foreach ($values as $row) {
-            $query = "INSERT $ignore
-					INTO " . $tableName . "
-					$fieldList
-					VALUES (" . Common::getSqlStringFieldsArray($row) . ")";
+            $query = "INSERT $ignore INTO " . $tableName . "
+					  $fieldList
+					  VALUES (" . Common::getSqlStringFieldsArray($row) . ")";
             Db::query($query, $row);
         }
     }
@@ -123,7 +122,7 @@ class BatchInsert
     {
         // Chroot environment: prefix the path with the absolute chroot path
         $chrootPath = Config::getInstance()->General['absolute_chroot_path'];
-        if(!empty($chrootPath)) {
+        if (!empty($chrootPath)) {
             $filePath = $chrootPath . $filePath;
         }
 
@@ -172,7 +171,8 @@ class BatchInsert
 		 * @see http://bugs.php.net/bug.php?id=54158
 		 */
         $openBaseDir = ini_get('open_basedir');
-        $safeMode = ini_get('safe_mode');
+        $safeMode    = ini_get('safe_mode');
+
         if (empty($openBaseDir) && empty($safeMode)) {
             // php 5.x - LOAD DATA LOCAL INFILE is disabled if open_basedir restrictions or safe_mode enabled
             $keywords[] = 'LOCAL ';
@@ -199,9 +199,11 @@ class BatchInsert
                 $exceptions[] = "\n  Try #" . (count($exceptions) + 1) . ': ' . $queryStart . ": " . $message;
             }
         }
+
         if (count($exceptions)) {
             throw new Exception(implode(",", $exceptions));
         }
+
         return false;
     }
 
@@ -218,8 +220,8 @@ class BatchInsert
         // Set up CSV delimiters, quotes, etc
         $delim = $fileSpec['delim'];
         $quote = $fileSpec['quote'];
-        $eol = $fileSpec['eol'];
-        $null = $fileSpec['null'];
+        $eol   = $fileSpec['eol'];
+        $null  = $fileSpec['null'];
         $escapespecial_cb = $fileSpec['escapespecial_cb'];
 
         $fp = @fopen($filePath, 'wb');
@@ -246,6 +248,7 @@ class BatchInsert
                 throw new Exception('Error writing to the tmp file ' . $filePath);
             }
         }
+
         fclose($fp);
 
         @chmod($filePath, 0777);
diff --git a/core/Db/Schema.php b/core/Db/Schema.php
index e210de5835258e2c1411d15f2abaf66e3ac29d8a..796e71dca5b384175572ac445afb75e421779a32 100644
--- a/core/Db/Schema.php
+++ b/core/Db/Schema.php
@@ -38,7 +38,7 @@ class Schema extends Singleton
     private static function getSchemaClassName($schemaName)
     {
         // Upgrade from pre 2.0.4
-        if(strtolower($schemaName) == 'myisam'
+        if (strtolower($schemaName) == 'myisam'
             || empty($schemaName)) {
             $schemaName = self::DEFAULT_SCHEMA;
         }
@@ -116,11 +116,11 @@ class Schema extends Singleton
      */
     private function loadSchema()
     {
-        $config = Config::getInstance();
-        $dbInfos = $config->database;
+        $config     = Config::getInstance();
+        $dbInfos    = $config->database;
         $schemaName = trim($dbInfos['schema']);
 
-        $className = self::getSchemaClassName($schemaName);
+        $className    = self::getSchemaClassName($schemaName);
         $this->schema = new $className();
     }
 
@@ -134,6 +134,7 @@ class Schema extends Singleton
         if ($this->schema === null) {
             $this->loadSchema();
         }
+
         return $this->schema;
     }
 
diff --git a/core/Db/Schema/Mysql.php b/core/Db/Schema/Mysql.php
index 43a42f167d1adc256224d030ab5b244ca37567bf..eb8c1f71f13cc82b720ff43a7e5241f47e3de8fe 100644
--- a/core/Db/Schema/Mysql.php
+++ b/core/Db/Schema/Mysql.php
@@ -20,6 +20,8 @@ use Piwik\DbHelper;
  */
 class Mysql implements SchemaInterface
 {
+    private $tablesInstalled = null;
+
     /**
      * Is this MySQL storage engine available?
      *
@@ -58,216 +60,213 @@ class Mysql implements SchemaInterface
         $prefixTables = $this->getTablePrefix();
 
         $tables = array(
-            'user'                  => "CREATE TABLE {$prefixTables}user (
-						  login VARCHAR(100) NOT NULL,
-						  password CHAR(32) NOT NULL,
-						  alias VARCHAR(45) NOT NULL,
-						  email VARCHAR(100) NOT NULL,
-						  token_auth CHAR(32) NOT NULL,
-						  superuser_access TINYINT(2) unsigned NOT NULL DEFAULT '0',
-						  date_registered TIMESTAMP NULL,
-						  PRIMARY KEY(login),
-						  UNIQUE KEY uniq_keytoken(token_auth)
-						) ENGINE=$engine DEFAULT CHARSET=utf8
-			",
-
-            'access'                => "CREATE TABLE {$prefixTables}access (
-						  login VARCHAR(100) NOT NULL,
-						  idsite INTEGER UNSIGNED NOT NULL,
-						  access VARCHAR(10) NULL,
-						  PRIMARY KEY(login, idsite)
-						) ENGINE=$engine DEFAULT CHARSET=utf8
-			",
-
-            'site'                  => "CREATE TABLE {$prefixTables}site (
-						  idsite INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,
-						  name VARCHAR(90) NOT NULL,
-						  main_url VARCHAR(255) NOT NULL,
-  						  ts_created TIMESTAMP NULL,
-  						  ecommerce TINYINT DEFAULT 0,
-  						  sitesearch TINYINT DEFAULT 1,
-  						  sitesearch_keyword_parameters TEXT NOT NULL,
-  						  sitesearch_category_parameters TEXT NOT NULL,
-  						  timezone VARCHAR( 50 ) NOT NULL,
-  						  currency CHAR( 3 ) NOT NULL,
-  						  excluded_ips TEXT NOT NULL,
-  						  excluded_parameters TEXT NOT NULL,
-  						  excluded_user_agents TEXT NOT NULL,
-  						  `group` VARCHAR(250) NOT NULL,
-  						  `type` VARCHAR(255) NOT NULL,
-  						  keep_url_fragment TINYINT NOT NULL DEFAULT 0,
-						  PRIMARY KEY(idsite)
-						) ENGINE=$engine DEFAULT CHARSET=utf8
-			",
-
-            'site_url'              => "CREATE TABLE {$prefixTables}site_url (
-							  idsite INTEGER(10) UNSIGNED NOT NULL,
-							  url VARCHAR(255) NOT NULL,
-							  PRIMARY KEY(idsite, url)
-						) ENGINE=$engine DEFAULT CHARSET=utf8
-			",
-
-            'goal'                  => "	CREATE TABLE `{$prefixTables}goal` (
-							  `idsite` int(11) NOT NULL,
-							  `idgoal` int(11) NOT NULL,
-							  `name` varchar(50) NOT NULL,
-							  `match_attribute` varchar(20) NOT NULL,
-							  `pattern` varchar(255) NOT NULL,
-							  `pattern_type` varchar(10) NOT NULL,
-							  `case_sensitive` tinyint(4) NOT NULL,
-							  `allow_multiple` tinyint(4) NOT NULL,
-							  `revenue` float NOT NULL,
-							  `deleted` tinyint(4) NOT NULL default '0',
-							  PRIMARY KEY  (`idsite`,`idgoal`)
-							) ENGINE=$engine DEFAULT CHARSET=utf8
-			",
-
-            'logger_message'        => "CREATE TABLE {$prefixTables}logger_message (
-									  idlogger_message INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
+            'user'    => "CREATE TABLE {$prefixTables}user (
+                          login VARCHAR(100) NOT NULL,
+                          password CHAR(32) NOT NULL,
+                          alias VARCHAR(45) NOT NULL,
+                          email VARCHAR(100) NOT NULL,
+                          token_auth CHAR(32) NOT NULL,
+                          superuser_access TINYINT(2) unsigned NOT NULL DEFAULT '0',
+                          date_registered TIMESTAMP NULL,
+                            PRIMARY KEY(login),
+                            UNIQUE KEY uniq_keytoken(token_auth)
+                          ) ENGINE=$engine DEFAULT CHARSET=utf8
+            ",
+
+            'access'  => "CREATE TABLE {$prefixTables}access (
+                          login VARCHAR(100) NOT NULL,
+                          idsite INTEGER UNSIGNED NOT NULL,
+                          access VARCHAR(10) NULL,
+                            PRIMARY KEY(login, idsite)
+                          ) ENGINE=$engine DEFAULT CHARSET=utf8
+            ",
+
+            'site'    => "CREATE TABLE {$prefixTables}site (
+                          idsite INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+                          name VARCHAR(90) NOT NULL,
+                          main_url VARCHAR(255) NOT NULL,
+                            ts_created TIMESTAMP NULL,
+                            ecommerce TINYINT DEFAULT 0,
+                            sitesearch TINYINT DEFAULT 1,
+                            sitesearch_keyword_parameters TEXT NOT NULL,
+                            sitesearch_category_parameters TEXT NOT NULL,
+                            timezone VARCHAR( 50 ) NOT NULL,
+                            currency CHAR( 3 ) NOT NULL,
+                            excluded_ips TEXT NOT NULL,
+                            excluded_parameters TEXT NOT NULL,
+                            excluded_user_agents TEXT NOT NULL,
+                            `group` VARCHAR(250) NOT NULL,
+                            `type` VARCHAR(255) NOT NULL,
+                            keep_url_fragment TINYINT NOT NULL DEFAULT 0,
+                              PRIMARY KEY(idsite)
+                            ) ENGINE=$engine DEFAULT CHARSET=utf8
+            ",
+
+            'site_url'    => "CREATE TABLE {$prefixTables}site_url (
+                              idsite INTEGER(10) UNSIGNED NOT NULL,
+                              url VARCHAR(255) NOT NULL,
+                                PRIMARY KEY(idsite, url)
+                              ) ENGINE=$engine DEFAULT CHARSET=utf8
+            ",
+
+            'goal'       => "CREATE TABLE `{$prefixTables}goal` (
+                              `idsite` int(11) NOT NULL,
+                              `idgoal` int(11) NOT NULL,
+                              `name` varchar(50) NOT NULL,
+                              `match_attribute` varchar(20) NOT NULL,
+                              `pattern` varchar(255) NOT NULL,
+                              `pattern_type` varchar(10) NOT NULL,
+                              `case_sensitive` tinyint(4) NOT NULL,
+                              `allow_multiple` tinyint(4) NOT NULL,
+                              `revenue` float NOT NULL,
+                              `deleted` tinyint(4) NOT NULL default '0',
+                                PRIMARY KEY  (`idsite`,`idgoal`)
+                              ) ENGINE=$engine DEFAULT CHARSET=utf8
+            ",
+
+            'logger_message'      => "CREATE TABLE {$prefixTables}logger_message (
+                                      idlogger_message INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
                                       tag VARCHAR(50) NULL,
-									  timestamp TIMESTAMP NULL,
+                                      timestamp TIMESTAMP NULL,
                                       level VARCHAR(16) NULL,
-									  message TEXT NULL,
-									  PRIMARY KEY(idlogger_message)
-									) ENGINE=$engine DEFAULT CHARSET=utf8
-			",
-
-            'log_action'            => "CREATE TABLE {$prefixTables}log_action (
-									  idaction INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,
-									  name TEXT,
-									  hash INTEGER(10) UNSIGNED NOT NULL,
-  									  type TINYINT UNSIGNED NULL,
-  									  url_prefix TINYINT(2) NULL,
-									  PRIMARY KEY(idaction),
-									  INDEX index_type_hash (type, hash)
-						) ENGINE=$engine DEFAULT CHARSET=utf8
-			",
-
-            'log_visit'             => "CREATE TABLE {$prefixTables}log_visit (
-							  idvisit INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,
-							  idsite INTEGER(10) UNSIGNED NOT NULL,
-							  idvisitor BINARY(8) NOT NULL,
-							  visit_last_action_time DATETIME NOT NULL,
-							  config_id BINARY(8) NOT NULL,
-							  location_ip VARBINARY(16) NOT NULL,
-							  PRIMARY KEY(idvisit),
-							  INDEX index_idsite_config_datetime (idsite, config_id, visit_last_action_time),
-							  INDEX index_idsite_datetime (idsite, visit_last_action_time),
-							  INDEX index_idsite_idvisitor (idsite, idvisitor)
-							) ENGINE=$engine DEFAULT CHARSET=utf8
-			",
+                                      message TEXT NULL,
+                                        PRIMARY KEY(idlogger_message)
+                                      ) ENGINE=$engine DEFAULT CHARSET=utf8
+            ",
+
+            'log_action'          => "CREATE TABLE {$prefixTables}log_action (
+                                      idaction INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+                                      name TEXT,
+                                      hash INTEGER(10) UNSIGNED NOT NULL,
+                                      type TINYINT UNSIGNED NULL,
+                                      url_prefix TINYINT(2) NULL,
+                                        PRIMARY KEY(idaction),
+                                        INDEX index_type_hash (type, hash)
+                                      ) ENGINE=$engine DEFAULT CHARSET=utf8
+            ",
+
+            'log_visit'   => "CREATE TABLE {$prefixTables}log_visit (
+                              idvisit INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+                              idsite INTEGER(10) UNSIGNED NOT NULL,
+                              idvisitor BINARY(8) NOT NULL,
+                              visit_last_action_time DATETIME NOT NULL,
+                              config_id BINARY(8) NOT NULL,
+                              location_ip VARBINARY(16) NOT NULL,
+                                PRIMARY KEY(idvisit),
+                                INDEX index_idsite_config_datetime (idsite, config_id, visit_last_action_time),
+                                INDEX index_idsite_datetime (idsite, visit_last_action_time),
+                                INDEX index_idsite_idvisitor (idsite, idvisitor)
+                              ) ENGINE=$engine DEFAULT CHARSET=utf8
+            ",
 
             'log_conversion_item'   => "CREATE TABLE `{$prefixTables}log_conversion_item` (
-												  idsite int(10) UNSIGNED NOT NULL,
-										  		  idvisitor BINARY(8) NOT NULL,
-										          server_time DATETIME NOT NULL,
-												  idvisit INTEGER(10) UNSIGNED NOT NULL,
-												  idorder varchar(100) NOT NULL,
-
-												  idaction_sku INTEGER(10) UNSIGNED NOT NULL,
-												  idaction_name INTEGER(10) UNSIGNED NOT NULL,
-												  idaction_category INTEGER(10) UNSIGNED NOT NULL,
-												  idaction_category2 INTEGER(10) UNSIGNED NOT NULL,
-												  idaction_category3 INTEGER(10) UNSIGNED NOT NULL,
-												  idaction_category4 INTEGER(10) UNSIGNED NOT NULL,
-												  idaction_category5 INTEGER(10) UNSIGNED NOT NULL,
-												  price FLOAT NOT NULL,
-												  quantity INTEGER(10) UNSIGNED NOT NULL,
-												  deleted TINYINT(1) UNSIGNED NOT NULL,
-
-												  PRIMARY KEY(idvisit, idorder, idaction_sku),
-										          INDEX index_idsite_servertime ( idsite, server_time )
-												) ENGINE=$engine DEFAULT CHARSET=utf8
-			",
-
-            'log_conversion'        => "CREATE TABLE `{$prefixTables}log_conversion` (
-									  idvisit int(10) unsigned NOT NULL,
-									  idsite int(10) unsigned NOT NULL,
-									  idvisitor BINARY(8) NOT NULL,
-									  server_time datetime NOT NULL,
-									  idaction_url int(11) default NULL,
-									  idlink_va int(11) default NULL,
-									  idgoal int(10) NOT NULL,
-									  buster int unsigned NOT NULL,
-									  idorder varchar(100) default NULL,
-									  items SMALLINT UNSIGNED DEFAULT NULL,
-									  url text NOT NULL,
-
-									  PRIMARY KEY (idvisit, idgoal, buster),
-									  UNIQUE KEY unique_idsite_idorder (idsite, idorder),
-									  INDEX index_idsite_datetime ( idsite, server_time )
-									) ENGINE=$engine DEFAULT CHARSET=utf8
-			",
+                                        idsite int(10) UNSIGNED NOT NULL,
+                                        idvisitor BINARY(8) NOT NULL,
+                                        server_time DATETIME NOT NULL,
+                                        idvisit INTEGER(10) UNSIGNED NOT NULL,
+                                        idorder varchar(100) NOT NULL,
+                                        idaction_sku INTEGER(10) UNSIGNED NOT NULL,
+                                        idaction_name INTEGER(10) UNSIGNED NOT NULL,
+                                        idaction_category INTEGER(10) UNSIGNED NOT NULL,
+                                        idaction_category2 INTEGER(10) UNSIGNED NOT NULL,
+                                        idaction_category3 INTEGER(10) UNSIGNED NOT NULL,
+                                        idaction_category4 INTEGER(10) UNSIGNED NOT NULL,
+                                        idaction_category5 INTEGER(10) UNSIGNED NOT NULL,
+                                        price FLOAT NOT NULL,
+                                        quantity INTEGER(10) UNSIGNED NOT NULL,
+                                        deleted TINYINT(1) UNSIGNED NOT NULL,
+                                          PRIMARY KEY(idvisit, idorder, idaction_sku),
+                                          INDEX index_idsite_servertime ( idsite, server_time )
+                                        ) ENGINE=$engine DEFAULT CHARSET=utf8
+            ",
+
+            'log_conversion'      => "CREATE TABLE `{$prefixTables}log_conversion` (
+                                      idvisit int(10) unsigned NOT NULL,
+                                      idsite int(10) unsigned NOT NULL,
+                                      idvisitor BINARY(8) NOT NULL,
+                                      server_time datetime NOT NULL,
+                                      idaction_url int(11) default NULL,
+                                      idlink_va int(11) default NULL,
+                                      idgoal int(10) NOT NULL,
+                                      buster int unsigned NOT NULL,
+                                      idorder varchar(100) default NULL,
+                                      items SMALLINT UNSIGNED DEFAULT NULL,
+                                      url text NOT NULL,
+                                        PRIMARY KEY (idvisit, idgoal, buster),
+                                        UNIQUE KEY unique_idsite_idorder (idsite, idorder),
+                                        INDEX index_idsite_datetime ( idsite, server_time )
+                                      ) ENGINE=$engine DEFAULT CHARSET=utf8
+            ",
 
             'log_link_visit_action' => "CREATE TABLE {$prefixTables}log_link_visit_action (
-											  idlink_va INTEGER(11) UNSIGNED NOT NULL AUTO_INCREMENT,
-									          idsite int(10) UNSIGNED NOT NULL,
-									  		  idvisitor BINARY(8) NOT NULL,
-											  idvisit INTEGER(10) UNSIGNED NOT NULL,
-											  idaction_url_ref INTEGER(10) UNSIGNED NULL DEFAULT 0,
-											  idaction_name_ref INTEGER(10) UNSIGNED NOT NULL,
-
-											  custom_float FLOAT NULL DEFAULT NULL,
-											  PRIMARY KEY(idlink_va),
-											  INDEX index_idvisit(idvisit)
-											) ENGINE=$engine DEFAULT CHARSET=utf8
-			",
-
-            'log_profiling'         => "CREATE TABLE {$prefixTables}log_profiling (
-								  query TEXT NOT NULL,
-								  count INTEGER UNSIGNED NULL,
-								  sum_time_ms FLOAT NULL,
-								  UNIQUE KEY query(query(100))
-								) ENGINE=$engine DEFAULT CHARSET=utf8
-			",
-
-            'option'                => "CREATE TABLE `{$prefixTables}option` (
-								option_name VARCHAR( 255 ) NOT NULL,
-								option_value LONGTEXT NOT NULL,
-								autoload TINYINT NOT NULL DEFAULT '1',
-								PRIMARY KEY ( option_name ),
-								INDEX autoload( autoload )
-								) ENGINE=$engine DEFAULT CHARSET=utf8
-			",
-
-            'session'               => "CREATE TABLE {$prefixTables}session (
-								id VARCHAR( 255 ) NOT NULL,
-								modified INTEGER,
-								lifetime INTEGER,
-								data TEXT,
-								PRIMARY KEY ( id )
-								) ENGINE=$engine DEFAULT CHARSET=utf8
-			",
-
-            'archive_numeric'       => "CREATE TABLE {$prefixTables}archive_numeric (
-									  idarchive INTEGER UNSIGNED NOT NULL,
-									  name VARCHAR(255) NOT NULL,
-									  idsite INTEGER UNSIGNED NULL,
-									  date1 DATE NULL,
-								  	  date2 DATE NULL,
-									  period TINYINT UNSIGNED NULL,
-								  	  ts_archived DATETIME NULL,
-								  	  value DOUBLE NULL,
-									  PRIMARY KEY(idarchive, name),
-									  INDEX index_idsite_dates_period(idsite, date1, date2, period, ts_archived),
-									  INDEX index_period_archived(period, ts_archived)
-									) ENGINE=$engine DEFAULT CHARSET=utf8
-			",
-
-            'archive_blob'          => "CREATE TABLE {$prefixTables}archive_blob (
-									  idarchive INTEGER UNSIGNED NOT NULL,
-									  name VARCHAR(255) NOT NULL,
-									  idsite INTEGER UNSIGNED NULL,
-									  date1 DATE NULL,
-									  date2 DATE NULL,
-									  period TINYINT UNSIGNED NULL,
-									  ts_archived DATETIME NULL,
-									  value MEDIUMBLOB NULL,
-									  PRIMARY KEY(idarchive, name),
-									  INDEX index_period_archived(period, ts_archived)
-									) ENGINE=$engine DEFAULT CHARSET=utf8
-			",
+                                        idlink_va INTEGER(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+                                        idsite int(10) UNSIGNED NOT NULL,
+                                        idvisitor BINARY(8) NOT NULL,
+                                        idvisit INTEGER(10) UNSIGNED NOT NULL,
+                                        idaction_url_ref INTEGER(10) UNSIGNED NULL DEFAULT 0,
+                                        idaction_name_ref INTEGER(10) UNSIGNED NOT NULL,
+                                        custom_float FLOAT NULL DEFAULT NULL,
+                                          PRIMARY KEY(idlink_va),
+                                          INDEX index_idvisit(idvisit)
+                                        ) ENGINE=$engine DEFAULT CHARSET=utf8
+            ",
+
+            'log_profiling'   => "CREATE TABLE {$prefixTables}log_profiling (
+                                  query TEXT NOT NULL,
+                                  count INTEGER UNSIGNED NULL,
+                                  sum_time_ms FLOAT NULL,
+                                    UNIQUE KEY query(query(100))
+                                  ) ENGINE=$engine DEFAULT CHARSET=utf8
+            ",
+
+            'option'        => "CREATE TABLE `{$prefixTables}option` (
+                                option_name VARCHAR( 255 ) NOT NULL,
+                                option_value LONGTEXT NOT NULL,
+                                autoload TINYINT NOT NULL DEFAULT '1',
+                                  PRIMARY KEY ( option_name ),
+                                  INDEX autoload( autoload )
+                                ) ENGINE=$engine DEFAULT CHARSET=utf8
+            ",
+
+            'session'       => "CREATE TABLE {$prefixTables}session (
+                                id VARCHAR( 255 ) NOT NULL,
+                                modified INTEGER,
+                                lifetime INTEGER,
+                                data TEXT,
+                                  PRIMARY KEY ( id )
+                                ) ENGINE=$engine DEFAULT CHARSET=utf8
+            ",
+
+            'archive_numeric'     => "CREATE TABLE {$prefixTables}archive_numeric (
+                                      idarchive INTEGER UNSIGNED NOT NULL,
+                                      name VARCHAR(255) NOT NULL,
+                                      idsite INTEGER UNSIGNED NULL,
+                                      date1 DATE NULL,
+                                      date2 DATE NULL,
+                                      period TINYINT UNSIGNED NULL,
+                                      ts_archived DATETIME NULL,
+                                      value DOUBLE NULL,
+                                        PRIMARY KEY(idarchive, name),
+                                        INDEX index_idsite_dates_period(idsite, date1, date2, period, ts_archived),
+                                        INDEX index_period_archived(period, ts_archived)
+                                      ) ENGINE=$engine DEFAULT CHARSET=utf8
+            ",
+
+            'archive_blob'        => "CREATE TABLE {$prefixTables}archive_blob (
+                                      idarchive INTEGER UNSIGNED NOT NULL,
+                                      name VARCHAR(255) NOT NULL,
+                                      idsite INTEGER UNSIGNED NULL,
+                                      date1 DATE NULL,
+                                      date2 DATE NULL,
+                                      period TINYINT UNSIGNED NULL,
+                                      ts_archived DATETIME NULL,
+                                      value MEDIUMBLOB NULL,
+                                        PRIMARY KEY(idarchive, name),
+                                        INDEX index_period_archived(period, ts_archived)
+                                      ) ENGINE=$engine DEFAULT CHARSET=utf8
+            ",
         );
+
         return $tables;
     }
 
@@ -297,17 +296,17 @@ class Mysql implements SchemaInterface
      */
     public function getTablesNames()
     {
-        $aTables = array_keys($this->getTablesCreateSql());
+        $aTables      = array_keys($this->getTablesCreateSql());
         $prefixTables = $this->getTablePrefix();
+
         $return = array();
         foreach ($aTables as $table) {
             $return[] = $prefixTables . $table;
         }
+
         return $return;
     }
 
-    private $tablesInstalled = null;
-
     /**
      * Get list of installed columns in a table
      *
@@ -317,7 +316,7 @@ class Mysql implements SchemaInterface
      */
     public function getTableColumns($tableName)
     {
-        $db = Db::get();
+        $db = $this->getDb();
 
         $allColumns = $db->fetchAll("SHOW COLUMNS FROM . $tableName");
 
@@ -340,13 +339,11 @@ class Mysql implements SchemaInterface
         if (is_null($this->tablesInstalled)
             || $forceReload === true
         ) {
-            $db = Db::get();
-            $prefixTables = $this->getTablePrefix();
 
-            // '_' matches any character; force it to be literal
-            $prefixTables = str_replace('_', '\_', $prefixTables);
+            $db = $this->getDb();
+            $prefixTables = $this->getTablePrefixEscaped();
 
-            $allTables = $db->fetchCol("SHOW TABLES LIKE '" . $prefixTables . "%'");
+            $allTables = $this->getAllExistingTables($prefixTables);
 
             // all the tables to be installed
             $allMyTables = $this->getTablesNames();
@@ -356,12 +353,13 @@ class Mysql implements SchemaInterface
 
             // at this point we have the static list of core tables, but let's add the monthly archive tables
             $allArchiveNumeric = $db->fetchCol("SHOW TABLES LIKE '" . $prefixTables . "archive_numeric%'");
-            $allArchiveBlob = $db->fetchCol("SHOW TABLES LIKE '" . $prefixTables . "archive_blob%'");
+            $allArchiveBlob    = $db->fetchCol("SHOW TABLES LIKE '" . $prefixTables . "archive_blob%'");
 
             $allTablesReallyInstalled = array_merge($tablesInstalled, $allArchiveNumeric, $allArchiveBlob);
 
             $this->tablesInstalled = $allTablesReallyInstalled;
         }
+
         return $this->tablesInstalled;
     }
 
@@ -385,6 +383,7 @@ class Mysql implements SchemaInterface
         if (is_null($dbName)) {
             $dbName = $this->getDbName();
         }
+
         Db::exec("CREATE DATABASE IF NOT EXISTS " . $dbName . " DEFAULT CHARACTER SET utf8");
     }
 
@@ -408,7 +407,7 @@ class Mysql implements SchemaInterface
         } catch (Exception $e) {
             // mysql code error 1050:table already exists
             // see bug #153 https://github.com/piwik/piwik/issues/153
-            if (!Db::get()->isErrNo($e, '1050')) {
+            if (!$this->getDb()->isErrNo($e, '1050')) {
                 throw $e;
             }
         }
@@ -428,7 +427,7 @@ class Mysql implements SchemaInterface
      */
     public function createTables()
     {
-        $db = Db::get();
+        $db = $this->getDb();
         $prefixTables = $this->getTablePrefix();
 
         $tablesAlreadyInstalled = $this->getTablesInstalled();
@@ -451,9 +450,9 @@ class Mysql implements SchemaInterface
     {
         // The anonymous user is the user that is assigned by default
         // note that the token_auth value is anonymous, which is assigned by default as well in the Login plugin
-        $db = Db::get();
+        $db = $this->getDb();
         $db->query("INSERT IGNORE INTO " . Common::prefixTable("user") . "
-					VALUES ( 'anonymous', '', 'anonymous', 'anonymous@example.org', 'anonymous', 0, '" . Date::factory('now')->getDatetime() . "' );");
+                    VALUES ( 'anonymous', '', 'anonymous', 'anonymous@example.org', 'anonymous', 0, '" . Date::factory('now')->getDatetime() . "' );");
     }
 
     /**
@@ -461,15 +460,15 @@ class Mysql implements SchemaInterface
      */
     public function truncateAllTables()
     {
-        $tablesAlreadyInstalled = $this->getTablesInstalled($forceReload = true);
-        foreach ($tablesAlreadyInstalled as $table) {
+        $tables = $this->getAllExistingTables();
+        foreach ($tables as $table) {
             Db::query("TRUNCATE `$table`");
         }
     }
 
     private function getTablePrefix()
     {
-        $dbInfos = Db::getDatabaseConfig();
+        $dbInfos      = Db::getDatabaseConfig();
         $prefixTables = $dbInfos['tables_prefix'];
 
         return $prefixTables;
@@ -478,10 +477,15 @@ class Mysql implements SchemaInterface
     private function getTableEngine()
     {
         $dbInfos = Db::getDatabaseConfig();
-        $engine = $dbInfos['type'];
+        $engine  = $dbInfos['type'];
+
         return $engine;
     }
 
+    private function getDb(){
+        return Db::get();
+    }
+
     private function getDbName()
     {
         $dbInfos = Db::getDatabaseConfig();
@@ -489,4 +493,21 @@ class Mysql implements SchemaInterface
 
         return $dbName;
     }
+
+    private function getAllExistingTables($prefixTables = false)
+    {
+        if (empty($prefixTables)) {
+            $prefixTables = $this->getTablePrefixEscaped();
+        }
+
+        return Db::get()->fetchCol("SHOW TABLES LIKE '" . $prefixTables . "%'");
+    }
+
+    private function getTablePrefixEscaped()
+    {
+        $prefixTables = $this->getTablePrefix();
+        // '_' matches any character; force it to be literal
+        $prefixTables = str_replace('_', '\_', $prefixTables);
+        return $prefixTables;
+    }
 }
diff --git a/core/DeviceDetectorCache.php b/core/DeviceDetectorCache.php
index 2c637aa95ec36017a864d245fb6a93f717022b30..ba65b82c9f639be3f99b44d4c31d61596d925182 100644
--- a/core/DeviceDetectorCache.php
+++ b/core/DeviceDetectorCache.php
@@ -32,6 +32,7 @@ class DeviceDetectorCache extends CacheFile implements \DeviceDetector\Cache\Cac
         if (empty($id)) {
             return false;
         }
+
         $id = $this->cleanupId($id);
 
         if (array_key_exists($id, self::$staticCache)) {
diff --git a/core/Error.php b/core/Error.php
index f7decbbc163529966c622cd24e71937045f2497e..c56e3301a7705f23685d570cf208b6437bb00c51 100644
--- a/core/Error.php
+++ b/core/Error.php
@@ -8,11 +8,6 @@
  */
 namespace Piwik;
 
-use Piwik\Common;
-use Piwik\Log;
-use Piwik\Piwik;
-use Piwik\Version;
-
 require_once PIWIK_INCLUDE_PATH . '/core/Log.php';
 
 /**
diff --git a/core/EventDispatcher.php b/core/EventDispatcher.php
index d9d26b437763b494eeed05480c4e18e64e05c187..d343da8bebe2f261dad95756bc9d1a2809ecd8fe 100644
--- a/core/EventDispatcher.php
+++ b/core/EventDispatcher.php
@@ -48,7 +48,7 @@ class EventDispatcher extends Singleton
     /**
      * Plugin\Manager instance used to get list of loaded plugins.
      *
-     * @var Piwik\Plugin\Manager
+     * @var \Piwik\Plugin\Manager
      */
     private $pluginManager;
 
diff --git a/core/ExceptionHandler.php b/core/ExceptionHandler.php
index 0e526225d59c3e1b6307f798a863c3a293e0c6e5..8566385070453de3f741dc1d361f375f44a7af87 100644
--- a/core/ExceptionHandler.php
+++ b/core/ExceptionHandler.php
@@ -9,7 +9,6 @@
 namespace Piwik;
 
 use Piwik\API\ResponseBuilder;
-use Piwik\Common;
 use Piwik\Plugin;
 
 /**
diff --git a/core/Filechecks.php b/core/Filechecks.php
index 33d0ed06964834d1516b096c1ac64c2093b2d6ee..3dc6d53195b677316029a2fd5e04c34564ffa120 100644
--- a/core/Filechecks.php
+++ b/core/Filechecks.php
@@ -43,7 +43,7 @@ class Filechecks
                 $directoryToCheck = PIWIK_USER_PATH . $directoryToCheck;
             }
 
-            if(strpos($directoryToCheck, '/tmp/') !== false) {
+            if (strpos($directoryToCheck, '/tmp/') !== false) {
                 $directoryToCheck = SettingsPiwik::rewriteTmpPathWithInstanceId($directoryToCheck);
             }
 
@@ -87,9 +87,9 @@ class Filechecks
             $directoryList = "<code>chown -R ". self::getUserAndGroup() ." " . $realpath . "</code><br />" . $directoryList;
         }
 
-        if(function_exists('shell_exec')) {
+        if (function_exists('shell_exec')) {
             $currentUser = self::getUser();
-            if(!empty($currentUser)) {
+            if (!empty($currentUser)) {
                 $optionalUserInfo = " (running as user '" . $currentUser . "')";
             }
         }
@@ -211,13 +211,13 @@ class Filechecks
     private static function getUserAndGroup()
     {
         $user = self::getUser();
-        if(!function_exists('shell_exec')) {
+        if (!function_exists('shell_exec')) {
             return $user . ':' . $user;
         }
 
         $group = trim(shell_exec('groups '. $user .' | cut -f3 -d" "'));
 
-        if(empty($group)) {
+        if (empty($group)) {
             $group = 'www-data';
         }
         return $user . ':' . $group;
@@ -225,7 +225,7 @@ class Filechecks
 
     private static function getUser()
     {
-        if(!function_exists('shell_exec')) {
+        if (!function_exists('shell_exec')) {
             return 'www-data';
         }
         return trim(shell_exec('whoami'));
diff --git a/core/FrontController.php b/core/FrontController.php
index a50fb152ca3f98c558cb04f626d58974a107fab1..ce39922a2ee3b08f98d158caa2ed689df55c750b 100644
--- a/core/FrontController.php
+++ b/core/FrontController.php
@@ -57,6 +57,7 @@ use Piwik\Plugins\CoreHome\Controller as CoreHomeController;
 class FrontController extends Singleton
 {
     const DEFAULT_MODULE = 'CoreHome';
+
     /**
      * Set to false and the Front Controller will not dispatch the request
      *
@@ -153,7 +154,8 @@ class FrontController extends Singleton
             return array(new CoreHomeController(), 'renderReportWidget');
         }
 
-        if (!empty($action) && 'menu' === substr($action, 0, 4)) {
+        if (!empty($action) && Report::PREFIX_ACTION_IN_MENU === substr($action, 0, strlen(Report
+            ::PREFIX_ACTION_IN_MENU))) {
             $reportAction = lcfirst(substr($action, 4)); // menuGetPageUrls => getPageUrls
             $report       = Report::factory($module, $reportAction);
 
@@ -508,22 +510,22 @@ class FrontController extends Singleton
     protected function handleSSLRedirection()
     {
         // Specifically disable for the opt out iframe
-        if(Piwik::getModule() == 'CoreAdminHome' && Piwik::getAction() == 'optOut') {
+        if (Piwik::getModule() == 'CoreAdminHome' && Piwik::getAction() == 'optOut') {
             return;
         }
         // Disable Https for VisitorGenerator
-        if(Piwik::getModule() == 'VisitorGenerator') {
+        if (Piwik::getModule() == 'VisitorGenerator') {
             return;
         }
-        if(Common::isPhpCliMode()) {
+        if (Common::isPhpCliMode()) {
             return;
         }
         // Only enable this feature after Piwik is already installed
-        if(!SettingsPiwik::isPiwikInstalled()) {
+        if (!SettingsPiwik::isPiwikInstalled()) {
             return;
         }
         // proceed only when force_ssl = 1
-        if(!SettingsPiwik::isHttpsForced()) {
+        if (!SettingsPiwik::isHttpsForced()) {
             return;
         }
         Url::redirectToHttps();
diff --git a/core/Http.php b/core/Http.php
index 537330716ab6fcb113b793a9f90a89fa862cb8f3..3643fc8553765cc07dbd50985aac51af6df290e9 100644
--- a/core/Http.php
+++ b/core/Http.php
@@ -165,7 +165,7 @@ class Http
         $aUrl = trim($aUrl);
 
         // other result data
-        $status = null;
+        $status  = null;
         $headers = array();
 
         if ($method == 'socket') {
@@ -183,7 +183,7 @@ class Http
                 throw new Exception('Invalid protocol/scheme: ' . $url['scheme']);
             }
             $host = $url['host'];
-            $port = isset($url['port)']) ? $url['port'] : 80;
+            $port = isset($url['port']) ? $url['port'] : 80;
             $path = isset($url['path']) ? $url['path'] : '/';
             if (isset($url['query'])) {
                 $path .= '?' . $url['query'];
diff --git a/core/IP.php b/core/IP.php
index 52f5f7c23ff88c70cd67557042fc76db0c2b8478..691bc7442c19762df0a61e3a4793ae570d202139 100644
--- a/core/IP.php
+++ b/core/IP.php
@@ -370,7 +370,7 @@ class IP
     {
         $proxyIps = array();
         $config = Config::getInstance()->General;
-        if(isset($config['proxy_ips'])) {
+        if (isset($config['proxy_ips'])) {
             $proxyIps = $config['proxy_ips'];
         }
         if (!is_array($proxyIps)) {
diff --git a/core/Log.php b/core/Log.php
index a860dd19893ad23772d4860d66fda5ddd352220a..b3421d13e1ae44f6bfc799a77409129a55b1875f 100644
--- a/core/Log.php
+++ b/core/Log.php
@@ -452,7 +452,7 @@ class Log extends Singleton
         if ($level == self::ERROR) {
             $message = $this->getMessageFormattedScreen($level, $tag, $datetime, $message);
             $this->writeErrorToStandardErrorOutput($message);
-            if(!isset($this->writers['screen'])) {
+            if (!isset($this->writers['screen'])) {
                 echo $message;
             }
         }
@@ -599,7 +599,7 @@ class Log extends Singleton
      */
     private function writeErrorToStandardErrorOutput($message)
     {
-        if(defined('PIWIK_TEST_MODE')) {
+        if (defined('PIWIK_TEST_MODE')) {
             // do not log on stderr during tests (prevent display of errors in CI output)
             return;
         }
diff --git a/core/Mail.php b/core/Mail.php
index d26b08b1544f738cb2f37f1e559bb71f45d7ba45..179b1221ab31a946b61ba1c165be28fafa92bdd6 100644
--- a/core/Mail.php
+++ b/core/Mail.php
@@ -34,9 +34,13 @@ class Mail extends Zend_Mail
     public function setDefaultFromPiwik()
     {
         $customLogo = new CustomLogo();
-        $fromEmailName = $customLogo->isEnabled()
-            ? Piwik::translate('CoreHome_WebAnalyticsReports')
-            : Piwik::translate('ScheduledReports_PiwikReports');
+
+        if ($customLogo->isEnabled()) {
+            $fromEmailName = Piwik::translate('CoreHome_WebAnalyticsReports');
+        } else {
+            $fromEmailName = Piwik::translate('ScheduledReports_PiwikReports');
+        }
+
         $fromEmailAddress = Config::getInstance()->General['noreply_email_address'];
         $this->setFrom($fromEmailAddress, $fromEmailName);
     }
@@ -77,20 +81,29 @@ class Mail extends Zend_Mail
     private function initSmtpTransport()
     {
         $mailConfig = Config::getInstance()->mail;
+
         if (empty($mailConfig['host'])
             || $mailConfig['transport'] != 'smtp'
         ) {
             return;
         }
+
         $smtpConfig = array();
-        if (!empty($mailConfig['type']))
+        if (!empty($mailConfig['type'])) {
             $smtpConfig['auth'] = strtolower($mailConfig['type']);
-        if (!empty($mailConfig['username']))
+        }
+
+        if (!empty($mailConfig['username'])) {
             $smtpConfig['username'] = $mailConfig['username'];
-        if (!empty($mailConfig['password']))
+        }
+
+        if (!empty($mailConfig['password'])) {
             $smtpConfig['password'] = $mailConfig['password'];
-        if (!empty($mailConfig['encryption']))
+        }
+
+        if (!empty($mailConfig['encryption'])) {
             $smtpConfig['ssl'] = $mailConfig['encryption'];
+        }
 
         $tr = new \Zend_Mail_Transport_Smtp($mailConfig['host'], $smtpConfig);
         Mail::setDefaultTransport($tr);
@@ -112,12 +125,12 @@ class Mail extends Zend_Mail
      */
     protected function parseDomainPlaceholderAsPiwikHostName($email)
     {
-        $hostname = Config::getInstance()->mail['defaultHostnameIfEmpty'];
+        $hostname  = Config::getInstance()->mail['defaultHostnameIfEmpty'];
         $piwikHost = Url::getCurrentHost($hostname);
 
         // If known Piwik URL, use it instead of "localhost"
         $piwikUrl = SettingsPiwik::getPiwikUrl();
-        $url = parse_url($piwikUrl);
+        $url      = parse_url($piwikUrl);
         if ($this->isHostDefinedAndNotLocal($url)) {
             $piwikHost = $url['host'];
         }
diff --git a/core/Menu/Group.php b/core/Menu/Group.php
index 17e7c9bc5ca7ca2c52d35a42e91baa51ef9b8a51..90e063e2648efe9691ffea87413ea1a5acdcc61e 100644
--- a/core/Menu/Group.php
+++ b/core/Menu/Group.php
@@ -18,8 +18,8 @@ class Group
     public function add($subTitleMenu, $url, $tooltip = false)
     {
         $this->items[] = array(
-            'name' => $subTitleMenu,
-            'url'  => $url,
+            'name'    => $subTitleMenu,
+            'url'     => $url,
             'tooltip' => $tooltip
         );;
     }
diff --git a/core/Menu/MenuAbstract.php b/core/Menu/MenuAbstract.php
index 1fe1152c98e38ffca391eee2601919fcb1299cfd..0d77ff21d0efc6e11182f51715fa3b5cced047a1 100644
--- a/core/Menu/MenuAbstract.php
+++ b/core/Menu/MenuAbstract.php
@@ -9,7 +9,6 @@
 namespace Piwik\Menu;
 
 use Piwik\Common;
-use Piwik\Log;
 use Piwik\Plugins\SitesManager\API;
 use Piwik\Singleton;
 use Piwik\Plugin\Manager as PluginManager;
@@ -104,7 +103,7 @@ abstract class MenuAbstract extends Singleton
     public function addItem($menuName, $subMenuName, $url, $order = 50, $tooltip = false)
     {
         // make sure the idSite value used is numeric (hack-y fix for #3426)
-        if (!is_numeric(Common::getRequestVar('idSite', false))) {
+        if (isset($url['idSite']) && !is_numeric($url['idSite'])) {
             $idSites = API::getInstance()->getSitesIdWithAtLeastViewAccess();
             $url['idSite'] = reset($idSites);
         }
@@ -215,8 +214,8 @@ abstract class MenuAbstract extends Singleton
     {
         foreach ($this->edits as $edit) {
             $mainMenuToEdit = $edit[0];
-            $subMenuToEdit = $edit[1];
-            $newUrl = $edit[2];
+            $subMenuToEdit  = $edit[1];
+            $newUrl         = $edit[2];
 
             if ($subMenuToEdit === null) {
                 $menuDataToEdit = @$this->menu[$mainMenuToEdit];
@@ -236,14 +235,14 @@ abstract class MenuAbstract extends Singleton
     {
         foreach($this->menuEntriesToRemove as $menuToDelete) {
 
-            if(empty($menuToDelete[1])) {
+            if (empty($menuToDelete[1])) {
                 // Delete Main Menu
-                if(isset($this->menu[$menuToDelete[0]])) {
+                if (isset($this->menu[$menuToDelete[0]])) {
                     unset($this->menu[$menuToDelete[0]]);
                 }
             } else {
                 // Delete Sub Menu
-                if(isset($this->menu[$menuToDelete[0]][$menuToDelete[1]])) {
+                if (isset($this->menu[$menuToDelete[0]][$menuToDelete[1]])) {
                     unset($this->menu[$menuToDelete[0]][$menuToDelete[1]]);
                 }
             }
@@ -256,9 +255,10 @@ abstract class MenuAbstract extends Singleton
     {
         foreach ($this->renames as $rename) {
             $mainMenuOriginal = $rename[0];
-            $subMenuOriginal = $rename[1];
-            $mainMenuRenamed = $rename[2];
-            $subMenuRenamed = $rename[3];
+            $subMenuOriginal  = $rename[1];
+            $mainMenuRenamed  = $rename[2];
+            $subMenuRenamed   = $rename[3];
+
             // Are we changing a submenu?
             if (!empty($subMenuOriginal)) {
                 if (isset($this->menu[$mainMenuOriginal][$subMenuOriginal])) {
diff --git a/core/Menu/MenuAdmin.php b/core/Menu/MenuAdmin.php
index 5c814b6706014781c5cf5ba1e89ff1aeb38146f4..13e84805967c0eed3b95c608614e15e98f99462b 100644
--- a/core/Menu/MenuAdmin.php
+++ b/core/Menu/MenuAdmin.php
@@ -45,7 +45,9 @@ class MenuAdmin extends MenuAbstract
      */
     public static function addEntry($adminMenuName, $url, $displayedForCurrentUser = true, $order = 20)
     {
-        self::getInstance()->add('General_Settings', $adminMenuName, $url, $displayedForCurrentUser, $order);
+        if ($displayedForCurrentUser) {
+            self::getInstance()->addItem('General_Settings', $adminMenuName, $url, $order);
+        }
     }
 
     /**
@@ -59,7 +61,7 @@ class MenuAdmin extends MenuAbstract
      */
     public function addDevelopmentItem($menuName, $url, $order = 50, $tooltip = false)
     {
-        $this->add('CoreAdminHome_MenuDevelopment', $menuName, $url, true, $order, $tooltip);
+        $this->addItem('CoreAdminHome_MenuDevelopment', $menuName, $url, $order, $tooltip);
     }
 
     /**
@@ -73,7 +75,7 @@ class MenuAdmin extends MenuAbstract
      */
     public function addDiagnosticItem($menuName, $url, $order = 50, $tooltip = false)
     {
-        $this->add('CoreAdminHome_MenuDiagnostic', $menuName, $url, true, $order, $tooltip);
+        $this->addItem('CoreAdminHome_MenuDiagnostic', $menuName, $url, $order, $tooltip);
     }
 
     /**
@@ -87,7 +89,7 @@ class MenuAdmin extends MenuAbstract
      */
     public function addPlatformItem($menuName, $url, $order = 50, $tooltip = false)
     {
-        $this->add('CorePluginsAdmin_MenuPlatform', $menuName, $url, true, $order, $tooltip);
+        $this->addItem('CorePluginsAdmin_MenuPlatform', $menuName, $url, $order, $tooltip);
     }
 
     /**
@@ -101,7 +103,7 @@ class MenuAdmin extends MenuAbstract
      */
     public function addSettingsItem($menuName, $url, $order = 50, $tooltip = false)
     {
-        $this->add('General_Settings', $menuName, $url, true, $order, $tooltip);
+        $this->addItem('General_Settings', $menuName, $url, $order, $tooltip);
     }
 
     /**
@@ -115,7 +117,7 @@ class MenuAdmin extends MenuAbstract
      */
     public function addManageItem($menuName, $url, $order = 50, $tooltip = false)
     {
-        $this->add('CoreAdminHome_MenuManage', $menuName, $url, true, $order, $tooltip);
+        $this->addItem('CoreAdminHome_MenuManage', $menuName, $url, $order, $tooltip);
     }
 
     /**
diff --git a/core/Menu/MenuMain.php b/core/Menu/MenuMain.php
index 5f27f3229e2d28af05c90417bbf6cabafa790b96..adb6b538e992e52d529ce66c350d68300564a410 100644
--- a/core/Menu/MenuMain.php
+++ b/core/Menu/MenuMain.php
@@ -11,7 +11,7 @@ namespace Piwik\Menu;
 /**
  * @deprecated since 2.4.0
  * @see MenuReporting
- * @method static \Piwik\Menu\MenuMain getInstance()
+ * @method static MenuMain getInstance()
  * @ignore
  */
 class MenuMain extends MenuReporting
diff --git a/core/Menu/MenuReporting.php b/core/Menu/MenuReporting.php
index 28fddd8313a69c1be4e7814f3d7d96521b88288b..ac35151bcb773b89d03978763973794642c0e1d4 100644
--- a/core/Menu/MenuReporting.php
+++ b/core/Menu/MenuReporting.php
@@ -45,7 +45,7 @@ class MenuReporting extends MenuAbstract
      */
     public function addVisitorsItem($menuName, $url, $order = 50, $tooltip = false)
     {
-        $this->add('General_Visitors', $menuName, $url, true, $order, $tooltip);
+        $this->addItem('General_Visitors', $menuName, $url, $order, $tooltip);
     }
 
     /**
@@ -59,7 +59,7 @@ class MenuReporting extends MenuAbstract
      */
     public function addActionsItem($menuName, $url, $order = 50, $tooltip = false)
     {
-        $this->add('General_Actions', $menuName, $url, true, $order, $tooltip);
+        $this->addItem('General_Actions', $menuName, $url, $order, $tooltip);
     }
 
     /**
@@ -88,7 +88,7 @@ class MenuReporting extends MenuAbstract
      */
     public function addReferrersItem($menuName, $url, $order = 50, $tooltip = false)
     {
-        $this->add('Referrers_Referrers', $menuName, $url, true, $order, $tooltip);
+        $this->addItem('Referrers_Referrers', $menuName, $url, $order, $tooltip);
     }
 
     /**
diff --git a/core/Menu/MenuUser.php b/core/Menu/MenuUser.php
index ad9b195d46b402c652b162988a880f67cadf36a1..758ac3d578c5877050b8d421ad600ff0052621ad 100755
--- a/core/Menu/MenuUser.php
+++ b/core/Menu/MenuUser.php
@@ -26,7 +26,7 @@ namespace Piwik\Menu;
  *         );
  *     }
  *
- * @method static \Piwik\Menu\MenuUser getInstance()
+ * @method static MenuUser getInstance()
  */
 class MenuUser extends MenuAbstract
 {
@@ -42,7 +42,7 @@ class MenuUser extends MenuAbstract
      */
     public function addManageItem($menuName, $url, $order = 50, $tooltip = false)
     {
-        $this->add('CoreAdminHome_MenuManage', $menuName, $url, true, $order, $tooltip);
+        $this->addItem('CoreAdminHome_MenuManage', $menuName, $url, $order, $tooltip);
     }
 
     /**
@@ -56,7 +56,7 @@ class MenuUser extends MenuAbstract
      */
     public function addPlatformItem($menuName, $url, $order = 50, $tooltip = false)
     {
-        $this->add('CorePluginsAdmin_MenuPlatform', $menuName, $url, true, $order, $tooltip);
+        $this->addItem('CorePluginsAdmin_MenuPlatform', $menuName, $url, $order, $tooltip);
     }
 
     /**
diff --git a/core/Metrics.php b/core/Metrics.php
index 03b9e2e0946cabc5f909bfa49f5a805610909108..0f8baf5a10f7403eb6aac173cba32d6f530c07c1 100644
--- a/core/Metrics.php
+++ b/core/Metrics.php
@@ -175,9 +175,11 @@ class Metrics
     public static function getVisitsMetricNames()
     {
         $names = array();
+
         foreach (self::$metricsAggregatedFromLogs as $metricId) {
             $names[$metricId] = self::$mappingFromIdToName[$metricId];
         }
+
         return $names;
     }
 
diff --git a/core/Metrics/Processed.php b/core/Metrics/Processed.php
index bbc638828a90d9bd7a74658eb158ace5c199e400..0e6b7c969be13bcbed478d8486ff89264906ac15 100644
--- a/core/Metrics/Processed.php
+++ b/core/Metrics/Processed.php
@@ -11,8 +11,6 @@ namespace Piwik\Metrics;
 use Piwik\Metrics;
 use Piwik\DataTable\Row;
 use Piwik\DataTable;
-use Piwik\Piwik;
-use Piwik\Tracker\GoalManager;
 
 class Processed extends Base
 {
diff --git a/core/MetricsFormatter.php b/core/MetricsFormatter.php
index 8c58215e301c4f54102f68e59c3453fa6ffa53b1..855466352586da20400308252405090630363b78 100644
--- a/core/MetricsFormatter.php
+++ b/core/MetricsFormatter.php
@@ -61,10 +61,10 @@ class MetricsFormatter
 
         // Display 01:45:17 time format
         if ($displayTimeAsSentence === false) {
-            $hours = floor($numberOfSeconds / 3600);
+            $hours   = floor($numberOfSeconds / 3600);
             $minutes = floor(($reminder = ($numberOfSeconds - $hours * 3600)) / 60);
             $seconds = floor($reminder - $minutes * 60);
-            $time = sprintf("%02s", $hours) . ':' . sprintf("%02s", $minutes) . ':' . sprintf("%02s", $seconds);
+            $time    = sprintf("%02s", $hours) . ':' . sprintf("%02s", $minutes) . ':' . sprintf("%02s", $seconds);
             $centiSeconds = ($numberOfSeconds * 100) % 100;
             if ($centiSeconds) {
                 $time .= '.' . sprintf("%02s", $centiSeconds);
@@ -76,19 +76,19 @@ class MetricsFormatter
         }
         $secondsInYear = 86400 * 365.25;
 
-        $years = floor($numberOfSeconds / $secondsInYear);
+        $years      = floor($numberOfSeconds / $secondsInYear);
         $minusYears = $numberOfSeconds - $years * $secondsInYear;
-        $days = floor($minusYears / 86400);
+        $days       = floor($minusYears / 86400);
 
         $minusDays = $numberOfSeconds - $days * 86400;
-        $hours = floor($minusDays / 3600);
+        $hours     = floor($minusDays / 3600);
 
         $minusDaysAndHours = $minusDays - $hours * 3600;
         $minutes = floor($minusDaysAndHours / 60);
 
-        $seconds = $minusDaysAndHours - $minutes * 60;
+        $seconds   = $minusDaysAndHours - $minutes * 60;
         $precision = ($seconds > 0 && $seconds < 0.01 ? 3 : 2);
-        $seconds = round($seconds, $precision);
+        $seconds   = round($seconds, $precision);
 
         if ($years > 0) {
             $return = sprintf(Piwik::translate('General_YearsDays'), $years, $days);
@@ -109,6 +109,7 @@ class MetricsFormatter
         if ($isHtml) {
             return str_replace(' ', '&nbsp;', $return);
         }
+
         return $return;
     }
 
@@ -134,6 +135,7 @@ class MetricsFormatter
                 break;
             }
         }
+
         return round($size, $precision) . " " . $currentUnit;
     }
 
@@ -175,6 +177,7 @@ class MetricsFormatter
                 $value = sprintf("%01." . $precision . "f", $value);
             }
         }
+
         $prettyMoney = $currencyBefore . $space . $value . $currencyAfter;
         return $prettyMoney;
     }
@@ -196,16 +199,19 @@ class MetricsFormatter
             $timeAsSentence = (substr($columnName, -16) == '_time_generation');
             return self::getPrettyTimeFromSeconds($value, $timeAsSentence);
         }
+
         // Add revenue symbol to revenues
         if (strpos($columnName, 'revenue') !== false && strpos($columnName, 'evolution') === false) {
             return self::getPrettyMoney($value, $idSite, $isHtml);
         }
+
         // Add % symbol to rates
         if (strpos($columnName, '_rate') !== false) {
             if (strpos($value, "%") === false) {
                 return $value . "%";
             }
         }
+
         return $value;
     }
 
@@ -217,12 +223,14 @@ class MetricsFormatter
      */
     public static function getCurrencySymbol($idSite)
     {
-        $symbols = MetricsFormatter::getCurrencyList();
-        $site = new Site($idSite);
+        $symbols  = MetricsFormatter::getCurrencyList();
+        $site     = new Site($idSite);
         $currency = $site->getCurrency();
+
         if (isset($symbols[$currency])) {
             return $symbols[$currency][0];
         }
+
         return '';
     }
 
@@ -235,10 +243,12 @@ class MetricsFormatter
     public static function getCurrencyList()
     {
         static $currenciesList = null;
+
         if (is_null($currenciesList)) {
             require_once PIWIK_INCLUDE_PATH . '/core/DataFiles/Currencies.php';
             $currenciesList = $GLOBALS['Piwik_CurrencyList'];
         }
+
         return $currenciesList;
     }
 }
diff --git a/core/Nonce.php b/core/Nonce.php
index 3937c4f94b030c3d338714314fa07da793bfe5af..1b64b87933ffdf5d467310bb06be2bdf53dbdfb9 100644
--- a/core/Nonce.php
+++ b/core/Nonce.php
@@ -160,7 +160,7 @@ class Nonce
      * @param string $nonceName The nonce's unique ID. See {@link getNonce()}.
      * @param string|null $nonce The nonce from the client. If `null`, the value from the
      *                           **nonce** query parameter is used.
-     * @throws Exception if the nonce is invalid. See {@link verifyNonce()}.
+     * @throws \Exception if the nonce is invalid. See {@link verifyNonce()}.
      */
     public static function checkNonce($nonceName, $nonce = null)
     {
diff --git a/core/Option.php b/core/Option.php
index c2c7816bbab33e00f63389bc064a13ee03aa7e03..c4410520eab49e07614cb5fc1d93a284b2c36cb3 100644
--- a/core/Option.php
+++ b/core/Option.php
@@ -68,7 +68,7 @@ class Option
      */
     public static function set($name, $value, $autoload = 0)
     {
-        return self::getInstance()->setValue($name, $value, $autoload);
+        self::getInstance()->setValue($name, $value, $autoload);
     }
 
     /**
@@ -79,7 +79,7 @@ class Option
      */
     public static function delete($name, $value = null)
     {
-        return self::getInstance()->deleteValue($name, $value);
+        self::getInstance()->deleteValue($name, $value);
     }
 
     /**
@@ -91,7 +91,7 @@ class Option
      */
     public static function deleteLike($namePattern, $value = null)
     {
-        return self::getInstance()->deleteNameLike($namePattern, $value);
+        self::getInstance()->deleteNameLike($namePattern, $value);
     }
 
     public static function clearCachedOption($name)
@@ -162,12 +162,13 @@ class Option
         if (isset($this->all[$name])) {
             return $this->all[$name];
         }
-        $value = Db::fetchOne('SELECT option_value ' .
-            'FROM `' . Common::prefixTable('option') . '` ' .
-            'WHERE option_name = ?', $name);
+        $value = Db::fetchOne('SELECT option_value FROM `' . Common::prefixTable('option') . '` ' .
+                              'WHERE option_name = ?', $name);
+
         if ($value === false) {
             return false;
         }
+
         $this->all[$name] = $value;
         return $value;
     }
@@ -184,11 +185,11 @@ class Option
 
     protected function deleteValue($name, $value)
     {
-        $sql = 'DELETE FROM `' . Common::prefixTable('option') . '` WHERE option_name = ?';
+        $sql    = 'DELETE FROM `' . Common::prefixTable('option') . '` WHERE option_name = ?';
         $bind[] = $name;
 
         if (isset($value)) {
-            $sql .= ' AND option_value = ?';
+            $sql   .= ' AND option_value = ?';
             $bind[] = $value;
         }
 
@@ -199,11 +200,11 @@ class Option
 
     protected function deleteNameLike($name, $value = null)
     {
-        $sql = 'DELETE FROM `' . Common::prefixTable('option') . '` WHERE option_name LIKE ?';
+        $sql    = 'DELETE FROM `' . Common::prefixTable('option') . '` WHERE option_name LIKE ?';
         $bind[] = $name;
 
         if (isset($value)) {
-            $sql .= ' AND option_value = ?';
+            $sql   .= ' AND option_value = ?';
             $bind[] = $value;
         }
 
@@ -214,7 +215,7 @@ class Option
 
     protected function getNameLike($name)
     {
-        $sql = 'SELECT option_name, option_value FROM `' . Common::prefixTable('option') . '` WHERE option_name LIKE ?';
+        $sql  = 'SELECT option_name, option_value FROM `' . Common::prefixTable('option') . '` WHERE option_name LIKE ?';
         $bind = array($name);
 
         $result = array();
@@ -235,9 +236,8 @@ class Option
             return;
         }
 
-        $all = Db::fetchAll('SELECT option_value, option_name
-								FROM `' . Common::prefixTable('option') . '`
-								WHERE autoload = 1');
+        $all = Db::fetchAll('SELECT option_value, option_name FROM `' . Common::prefixTable('option') . '`
+                             WHERE autoload = 1');
         foreach ($all as $option) {
             $this->all[$option['option_name']] = $option['option_value'];
         }
diff --git a/core/Period.php b/core/Period.php
index 6898020ce704ca4447a79d9dc01105e41f67aba8..1e3f188b5ed5bd901107decacf00eb781b7e4fde 100644
--- a/core/Period.php
+++ b/core/Period.php
@@ -100,16 +100,20 @@ abstract class Period
     public function getDateStart()
     {
         $this->generate();
+
         if (count($this->subperiods) == 0) {
             return $this->getDate();
         }
+
         $periods = $this->getSubperiods();
+
         /** @var $currentPeriod Period */
         $currentPeriod = $periods[0];
         while ($currentPeriod->getNumberOfSubperiods() > 0) {
-            $periods = $currentPeriod->getSubperiods();
+            $periods       = $currentPeriod->getSubperiods();
             $currentPeriod = $periods[0];
         }
+
         return $currentPeriod->getDate();
     }
 
@@ -121,16 +125,20 @@ abstract class Period
     public function getDateEnd()
     {
         $this->generate();
+
         if (count($this->subperiods) == 0) {
             return $this->getDate();
         }
+
         $periods = $this->getSubperiods();
+
         /** @var $currentPeriod Period */
         $currentPeriod = $periods[count($periods) - 1];
         while ($currentPeriod->getNumberOfSubperiods() > 0) {
-            $periods = $currentPeriod->getSubperiods();
+            $periods       = $currentPeriod->getSubperiods();
             $currentPeriod = $periods[count($periods) - 1];
         }
+
         return $currentPeriod->getDate();
     }
 
@@ -212,10 +220,12 @@ abstract class Period
     public function toString($format = "Y-m-d")
     {
         $this->generate();
+
         $dateString = array();
         foreach ($this->subperiods as $period) {
             $dateString[] = $period->toString($format);
         }
+
         return $dateString;
     }
 
@@ -259,6 +269,9 @@ abstract class Period
      */
     public function getRangeString()
     {
-        return $this->getDateStart()->toString("Y-m-d") . "," . $this->getDateEnd()->toString("Y-m-d");
+        $dateStart = $this->getDateStart();
+        $dateEnd   = $this->getDateEnd();
+
+        return $dateStart->toString("Y-m-d") . "," . $dateEnd->toString("Y-m-d");
     }
 }
diff --git a/core/Period/Day.php b/core/Period/Day.php
index 5f64627e45a6c1c758052140a09f135fd32380f7..b8212844cde18a498a08e7b17bcfd1ab0a8a52fb 100644
--- a/core/Period/Day.php
+++ b/core/Period/Day.php
@@ -37,8 +37,10 @@ class Day extends Period
     public function getLocalizedShortString()
     {
         //"Mon 15 Aug"
-        $date = $this->getDateStart();
-        $out = $date->getLocalized(Piwik::translate('CoreHome_ShortDateFormat'));
+        $date     = $this->getDateStart();
+        $template = Piwik::translate('CoreHome_ShortDateFormat');
+
+        $out = $date->getLocalized($template);
         return $out;
     }
 
@@ -50,8 +52,9 @@ class Day extends Period
     public function getLocalizedLongString()
     {
         //"Mon 15 Aug"
-        $date = $this->getDateStart();
+        $date     = $this->getDateStart();
         $template = Piwik::translate('CoreHome_DateFormat');
+
         $out = $date->getLocalized($template);
         return $out;
     }
diff --git a/core/Period/Factory.php b/core/Period/Factory.php
index b49095653119d34b0f6c57352d9ce5f8b064dee6..05303f40df787d0dd19a95a5d617b39cabff9672 100644
--- a/core/Period/Factory.php
+++ b/core/Period/Factory.php
@@ -60,7 +60,7 @@ class Factory
 
     public static function checkPeriodIsEnabled($period)
     {
-        if(!self::isPeriodEnabledForAPI($period)) {
+        if (!self::isPeriodEnabledForAPI($period)) {
             self::throwExceptionInvalidPeriod($period);
         }
     }
diff --git a/core/Period/Month.php b/core/Period/Month.php
index 167280f15b99ea2bfe0a9db0e5ab0d23b035a46a..46091809804958d54ed29f05f98874730cc60e2d 100644
--- a/core/Period/Month.php
+++ b/core/Period/Month.php
@@ -60,6 +60,7 @@ class Month extends Period
         if ($this->subperiodsProcessed) {
             return;
         }
+
         parent::generate();
 
         $date = $this->date;
diff --git a/core/Period/Range.php b/core/Period/Range.php
index 2ea6ab1792ba365f51ec54e1b8046669df35d859..36692dc0de2ba102809b5f17a3cf8f9fedb1fa47 100644
--- a/core/Period/Range.php
+++ b/core/Period/Range.php
@@ -45,12 +45,14 @@ class Range extends Period
     public function __construct($strPeriod, $strDate, $timezone = 'UTC', $today = false)
     {
         $this->strPeriod = $strPeriod;
-        $this->strDate = $strDate;
+        $this->strDate   = $strDate;
+        $this->timezone  = $timezone;
         $this->defaultEndDate = null;
-        $this->timezone = $timezone;
+
         if ($today === false) {
             $today = Date::factory('now', $this->timezone);
         }
+
         $this->today = $today;
     }
 
@@ -63,10 +65,12 @@ class Range extends Period
     {
         //"30 Dec 08 - 26 Feb 09"
         $dateStart = $this->getDateStart();
-        $dateEnd = $this->getDateEnd();
-        $template = Piwik::translate('CoreHome_ShortDateFormatWithYear');
+        $dateEnd   = $this->getDateEnd();
+        $template  = Piwik::translate('CoreHome_ShortDateFormatWithYear');
+
         $shortDateStart = $dateStart->getLocalized($template);
-        $shortDateEnd = $dateEnd->getLocalized($template);
+        $shortDateEnd   = $dateEnd->getLocalized($template);
+
         $out = "$shortDateStart - $shortDateEnd";
         return $out;
     }
@@ -90,9 +94,11 @@ class Range extends Period
     public function getDateStart()
     {
         $dateStart = parent::getDateStart();
+
         if (empty($dateStart)) {
             throw new Exception("Specified date range is invalid.");
         }
+
         return $dateStart;
     }
 
@@ -203,10 +209,12 @@ class Range extends Period
         } else {
             throw new Exception(Piwik::translate('General_ExceptionInvalidDateRange', array($this->strDate, ' \'lastN\', \'previousN\', \'YYYY-MM-DD,YYYY-MM-DD\'')));
         }
+
         if ($this->strPeriod != 'range') {
             $this->fillArraySubPeriods($startDate, $endDate, $this->strPeriod);
             return;
         }
+
         $this->processOptimalSubperiods($startDate, $endDate);
         // When period=range, we want End Date to be the actual specified end date,
         // rather than the end of the month / week / whatever is used for processing this range
@@ -223,9 +231,11 @@ class Range extends Period
     public static function parseDateRange($dateString)
     {
         $matched = preg_match('/^([0-9]{4}-[0-9]{1,2}-[0-9]{1,2}),(([0-9]{4}-[0-9]{1,2}-[0-9]{1,2})|today|now|yesterday)$/D', trim($dateString), $regs);
+
         if (empty($matched)) {
             return false;
         }
+
         return $regs;
     }
 
@@ -241,6 +251,7 @@ class Range extends Period
         if (!is_null($this->endDate)) {
             return $this->endDate;
         }
+
         return parent::getDateEnd();
     }
 
@@ -425,7 +436,7 @@ class Range extends Period
      * @param int $lastN The number of periods of type `$period` that the result range should
      *                   span.
      * @param string $endDate The desired end date of the range.
-     * @param Site $site The site whose timezone should be used.
+     * @param \Piwik\Site $site The site whose timezone should be used.
      * @return string The date range string, eg, `'2012-01-02,2013-01-02'`.
      * @api
      */
@@ -434,6 +445,7 @@ class Range extends Period
         $last30Relative = new Range($period, $lastN, $site->getTimezone());
         $last30Relative->setDefaultEndDate(Date::factory($endDate));
         $date = $last30Relative->getDateStart()->toString() . "," . $last30Relative->getDateEnd()->toString();
+
         return $date;
     }
 
diff --git a/core/Period/Week.php b/core/Period/Week.php
index f7b72649432b5b9d1af374a2ff5378c9c00e785e..23f7ab32b669817549453dcf198064c67f285e50 100644
--- a/core/Period/Week.php
+++ b/core/Period/Week.php
@@ -26,7 +26,7 @@ class Week extends Period
     {
         //"30 Dec - 6 Jan 09"
         $dateStart = $this->getDateStart();
-        $dateEnd = $this->getDateEnd();
+        $dateEnd   = $this->getDateEnd();
 
         $string = Piwik::translate('CoreHome_ShortWeekFormat');
         $string = self::getTranslatedRange($string, $dateStart, $dateEnd);
@@ -42,6 +42,7 @@ class Week extends Period
     {
         $format = Piwik::translate('CoreHome_LongWeekFormat');
         $string = self::getTranslatedRange($format, $this->getDateStart(), $this->getDateEnd());
+
         return Piwik::translate('CoreHome_PeriodWeek') . " " . $string;
     }
 
@@ -58,6 +59,7 @@ class Week extends Period
         $string = $dateStart->getLocalized($string);
         $string = str_replace('To%', '%', $string);
         $string = $dateEnd->getLocalized($string);
+
         return $string;
     }
 
@@ -68,10 +70,11 @@ class Week extends Period
      */
     public function getPrettyString()
     {
-        $out = Piwik::translate('General_DateRangeFromTo',
-            array($this->getDateStart()->toString(),
-                  $this->getDateEnd()->toString())
-        );
+        $dateStart = $this->getDateStart();
+        $dateEnd   = $this->getDateEnd();
+
+        $out = Piwik::translate('General_DateRangeFromTo', array($dateStart->toString(), $dateEnd->toString()));
+
         return $out;
     }
 
@@ -83,6 +86,7 @@ class Week extends Period
         if ($this->subperiodsProcessed) {
             return;
         }
+
         parent::generate();
         $date = $this->date;
 
diff --git a/core/Period/Year.php b/core/Period/Year.php
index 3582161e3a17d16e9ec97424b71ffaf0cf6df491..cb2d202ff7f9dbc01fab7211966e2e233982b65a 100644
--- a/core/Period/Year.php
+++ b/core/Period/Year.php
@@ -58,6 +58,7 @@ class Year extends Period
         if ($this->subperiodsProcessed) {
             return;
         }
+
         parent::generate();
 
         $year = $this->date->toString("Y");
@@ -78,10 +79,12 @@ class Year extends Period
     function toString($format = 'ignored')
     {
         $this->generate();
+
         $stringMonth = array();
         foreach ($this->subperiods as $month) {
             $stringMonth[] = $month->getDateStart()->toString("Y") . "-" . $month->getDateStart()->toString("m") . "-01";
         }
+
         return $stringMonth;
     }
 }
diff --git a/core/Piwik.php b/core/Piwik.php
index c00d5e42e9b63594feb77c96cdc6381859b13676..16f50f387faee4f6336241eec2a8d52953a971f0 100644
--- a/core/Piwik.php
+++ b/core/Piwik.php
@@ -9,7 +9,6 @@
 namespace Piwik;
 
 use Exception;
-use Piwik\Common;
 use Piwik\Db\Adapter;
 use Piwik\Db\Schema;
 use Piwik\Db;
@@ -135,7 +134,7 @@ class Piwik
         // changes made to this code should be mirrored in plugins/CoreAdminHome/javascripts/jsTrackingGenerator.js var generateJsCode
         $jsCode = file_get_contents(PIWIK_INCLUDE_PATH . "/plugins/Morpheus/templates/javascriptCode.tpl");
         $jsCode = htmlentities($jsCode);
-        if(substr($piwikUrl, 0, 4) !== 'http') {
+        if (substr($piwikUrl, 0, 4) !== 'http') {
             $piwikUrl = 'http://' . $piwikUrl;
         }
         preg_match('~^(http|https)://(.*)$~D', $piwikUrl, $matches);
@@ -428,7 +427,10 @@ class Piwik
      * Helper method user to set the current as superuser.
      * This should be used with great care as this gives the user all permissions.
      *
+     * This method is deprecated, use {@link Access::doAsSuperUser()} instead.
+     *
      * @param bool $bool true to set current user as Super User
+     * @deprecated
      */
     public static function setUserHasSuperUserAccess($bool = true)
     {
@@ -889,4 +891,4 @@ class Piwik
 
         return $result;
     }
-}
\ No newline at end of file
+}
diff --git a/core/Plugin.php b/core/Plugin.php
index 8839a962122c382215c2f16fcbaed70223158f30..55a70ab501bc83df99286fa0a22a4ce72c9954ab 100644
--- a/core/Plugin.php
+++ b/core/Plugin.php
@@ -354,7 +354,7 @@ class Plugin
         if ($this->cache->has()) {
             $components = $this->cache->get();
 
-            if($this->includeComponents($components)) {
+            if ($this->includeComponents($components)) {
                 return $components;
             } else {
                 // problem including one cached file, refresh cache
diff --git a/core/Plugin/ComponentFactory.php b/core/Plugin/ComponentFactory.php
index 68415e939762840b7231d07bc203f8869f58da33..9cb9cd1c1b31ec4027f3bcfd9cb488502777d083 100644
--- a/core/Plugin/ComponentFactory.php
+++ b/core/Plugin/ComponentFactory.php
@@ -74,7 +74,7 @@ class ComponentFactory
      * @param callback $predicate
      * @return mixed The component that satisfies $predicate or null if not found.
      */
-    public static function getComponentIf($componentTypeClass, $pluginName, $predicate)
+    public static function getComponentif ($componentTypeClass, $pluginName, $predicate)
     {
         $pluginManager = PluginManager::getInstance();
 
diff --git a/core/Plugin/ConsoleCommand.php b/core/Plugin/ConsoleCommand.php
index 884b6f60ee2e3cab63b7f3c84a04596c641e32cf..29e2fc65f6c6fb422c7fa54d93e2d283bdf0871d 100644
--- a/core/Plugin/ConsoleCommand.php
+++ b/core/Plugin/ConsoleCommand.php
@@ -8,7 +8,6 @@
  */
 namespace Piwik\Plugin;
 
-use Piwik\Common;
 use Symfony\Component\Console\Command\Command as SymfonyCommand;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
diff --git a/core/Plugin/Controller.php b/core/Plugin/Controller.php
index 3ebad0f1eda42ee437889b0a9f702b61e7c4d796..0342e34724246897c6e7072f440285a30f2e5284 100644
--- a/core/Plugin/Controller.php
+++ b/core/Plugin/Controller.php
@@ -834,32 +834,10 @@ abstract class Controller
     public function redirectToIndex($moduleToRedirect, $actionToRedirect, $websiteId = null, $defaultPeriod = null,
                                     $defaultDate = null, $parameters = array())
     {
-
-        $userPreferences = new UserPreferences();
-
-        if (empty($websiteId)) {
-            $websiteId = $userPreferences->getDefaultWebsiteId();
-        }
-        if (empty($defaultDate)) {
-            $defaultDate = $userPreferences->getDefaultDate();
-        }
-        if (empty($defaultPeriod)) {
-            $defaultPeriod = $userPreferences->getDefaultPeriod();
-        }
-        $parametersString = '';
-        if (!empty($parameters)) {
-            $parametersString = '&' . Url::getQueryStringFromParameters($parameters);
-        }
-
-        if ($websiteId) {
-            $url = "index.php?module=" . $moduleToRedirect
-                . "&action=" . $actionToRedirect
-                . "&idSite=" . $websiteId
-                . "&period=" . $defaultPeriod
-                . "&date=" . $defaultDate
-                . $parametersString;
-            Url::redirectToUrl($url);
-            exit;
+        try {
+            $this->doRedirectToUrl($moduleToRedirect, $actionToRedirect, $websiteId, $defaultPeriod, $defaultDate, $parameters);
+        } catch(Exception $e) {
+            // no website ID to default to, so could not redirect
         }
 
         if (Piwik::hasUserSuperUserAccess()) {
@@ -881,6 +859,7 @@ abstract class Controller
         exit;
     }
 
+
     /**
      * Checks that the token_auth in the URL matches the currently logged-in user's token_auth.
      *
@@ -897,7 +876,7 @@ abstract class Controller
         $tokenRequest = Common::getRequestVar('token_auth', false);
         $tokenUser = Piwik::getCurrentUserTokenAuth();
 
-        if(empty($tokenRequest) && empty($tokenUser)) {
+        if (empty($tokenRequest) && empty($tokenUser)) {
             return; // UI tests
         }
 
@@ -1000,4 +979,28 @@ abstract class Controller
 				Please check that you are logged in Piwik and have permission to access the specified website.");
         }
     }
+
+    /**
+     * @param $moduleToRedirect
+     * @param $actionToRedirect
+     * @param $websiteId
+     * @param $defaultPeriod
+     * @param $defaultDate
+     * @param $parameters
+     * @throws Exception
+     */
+    private function doRedirectToUrl($moduleToRedirect, $actionToRedirect, $websiteId, $defaultPeriod, $defaultDate, $parameters)
+    {
+        $menu = new Menu();
+
+        $parameters = array_merge(
+            $menu->urlForDefaultUserParams($websiteId, $defaultPeriod, $defaultDate),
+            $parameters
+        );
+        $queryParams = !empty($parameters) ? '&' . Url::getQueryStringFromParameters($parameters) : '';
+        $url = "index.php?module=%s&action=%s";
+        $url = sprintf($url, $moduleToRedirect, $actionToRedirect);
+        $url = $url . $queryParams;
+        Url::redirectToUrl($url);
+    }
 }
diff --git a/core/Plugin/ControllerAdmin.php b/core/Plugin/ControllerAdmin.php
index b18fe67de67787a5317e78700844a2730490e00e..e563e759f96eb6532847e95fef6fb03a297bcb72 100644
--- a/core/Plugin/ControllerAdmin.php
+++ b/core/Plugin/ControllerAdmin.php
@@ -43,6 +43,7 @@ abstract class ControllerAdmin extends Controller
     private static function notifyAnyInvalidPlugin()
     {
         $missingPlugins = \Piwik\Plugin\Manager::getInstance()->getMissingPlugins();
+
         if (empty($missingPlugins)) {
             return;
         }
@@ -50,9 +51,11 @@ abstract class ControllerAdmin extends Controller
         if (!Piwik::hasUserSuperUserAccess()) {
             return;
         }
+
         $pluginsLink = Url::getCurrentQueryStringWithParametersModified(array(
             'module' => 'CorePluginsAdmin', 'action' => 'plugins'
         ));
+
         $invalidPluginsWarning = Piwik::translate('CoreAdminHome_InvalidPluginsWarning', array(
                 self::getPiwikVersion(),
                 '<strong>' . implode('</strong>,&nbsp;<strong>', $missingPlugins) . '</strong>'))
@@ -167,8 +170,10 @@ abstract class ControllerAdmin extends Controller
         $view->currentAdminMenuName = MenuAdmin::getInstance()->getCurrentAdminMenuName();
 
         $view->isDataPurgeSettingsEnabled = self::isDataPurgeSettingsEnabled();
-        $view->enableFrames = PiwikConfig::getInstance()->General['enable_framed_settings'];
-        if (!$view->enableFrames) {
+        $enableFrames = PiwikConfig::getInstance()->General['enable_framed_settings'];
+        $view->enableFrames = $enableFrames;
+
+        if (!$enableFrames) {
             $view->setXFrameOptions('sameorigin');
         }
 
@@ -192,6 +197,7 @@ abstract class ControllerAdmin extends Controller
         $view->adminMenu = $adminMenu;
 
         $notifications = $view->notifications;
+
         if (empty($notifications)) {
             $view->notifications = NotificationManager::getAllNotificationsToDisplay();
             NotificationManager::cancelAllNonPersistent();
diff --git a/core/Plugin/Manager.php b/core/Plugin/Manager.php
index eb234c1b6cdc79614f0181701a6d270d010691e4..da2ba679df34b24c0b9fee03ba475b37e945150b 100644
--- a/core/Plugin/Manager.php
+++ b/core/Plugin/Manager.php
@@ -10,8 +10,6 @@
 namespace Piwik\Plugin;
 
 use Piwik\Cache\PersistentCache;
-use Piwik\Cache\PluginAwareStaticCache;
-use Piwik\Cache\StaticCache;
 use Piwik\CacheFile;
 use Piwik\Common;
 use Piwik\Config as PiwikConfig;
@@ -38,7 +36,7 @@ require_once PIWIK_INCLUDE_PATH . '/core/EventDispatcher.php';
 /**
  * The singleton that manages plugin loading/unloading and installation/uninstallation.
  *
- * @method static \Piwik\Plugin\Manager getInstance()
+ * @method static Manager getInstance()
  */
 class Manager extends Singleton
 {
@@ -166,7 +164,7 @@ class Manager extends Singleton
     public function isPluginOfficialAndNotBundledWithCore($pluginName)
     {
         static $gitModules;
-        if(empty($gitModules)) {
+        if (empty($gitModules)) {
             $gitModules = file_get_contents(PIWIK_INCLUDE_PATH . '/.gitmodules');
         }
         // All submodules are officially maintained plugins
@@ -541,7 +539,7 @@ class Manager extends Singleton
         $listPlugins = array_unique($listPlugins);
         foreach ($listPlugins as $pluginName) {
             // Hide plugins that are never going to be used
-            if($this->isPluginBogus($pluginName)) {
+            if ($this->isPluginBogus($pluginName)) {
                 continue;
             }
 
@@ -609,15 +607,15 @@ class Manager extends Singleton
 
     protected function isPluginThirdPartyAndBogus($pluginName)
     {
-        if($this->isPluginBundledWithCore($pluginName)) {
+        if ($this->isPluginBundledWithCore($pluginName)) {
             return false;
         }
-        if($this->isPluginBogus($pluginName)) {
+        if ($this->isPluginBogus($pluginName)) {
             return true;
         }
 
         $path = $this->getPluginsDirectory() . $pluginName;
-        if(!$this->isManifestFileFound($path)) {
+        if (!$this->isManifestFileFound($path)) {
             return true;
         }
         return false;
@@ -773,7 +771,7 @@ class Manager extends Singleton
         $plugins = $this->getLoadedPlugins();
         $enabled = $this->getActivatedPlugins();
 
-        if(empty($enabled)) {
+        if (empty($enabled)) {
             return array();
         }
         $enabled = array_combine($enabled, $enabled);
diff --git a/core/Plugin/Menu.php b/core/Plugin/Menu.php
index 6d2bdefccd28908042c9da8ed2c7a72b82a37deb..0cdc1878df6f93ccf52dcb98a4dd55609cabef58 100644
--- a/core/Plugin/Menu.php
+++ b/core/Plugin/Menu.php
@@ -14,6 +14,7 @@ use Piwik\Menu\MenuReporting;
 use Piwik\Menu\MenuTop;
 use Piwik\Menu\MenuUser;
 use Piwik\Plugin\Manager as PluginManager;
+use Piwik\Plugins\UsersManager\UserPreferences;
 
 /**
  * Base class of all plugin menu providers. Plugins that define their own menu items can extend this class to easily
@@ -105,8 +106,8 @@ class Menu
      * @param  string $module            The name of the module/plugin the action belongs to. The module name is case sensitive.
      * @param  string $controllerAction  The name of the action that should be executed within your controller
      * @param  array  $additionalParams  Optional URL parameters that will be appended to the URL
-     * @return array|null   Returns null if the given module is either not installed or not activated. Returns the URL
-     *                      to the given module action otherwise.
+     * @return array|null   Returns null if the given module is either not installed or not activated. Returns the array
+     *                      of query parameter names and values to the given module action otherwise.
      *
      * @since 2.7.0
      * // not API for now
@@ -129,6 +130,80 @@ class Menu
         return $params;
     }
 
+    /**
+     * Generates a URL to the given action of the current module, and it will also append some URL query parameters from the
+     * User preferences: idSite, period, date. If you do not need the parameters idSite, period and date to be generated
+     * use {@link urlForAction()} instead.
+     *
+     * @param  string $controllerAction  The name of the action that should be executed within your controller
+     * @param  array  $additionalParams  Optional URL parameters that will be appended to the URL
+     * @return array   Returns the array of query parameter names and values to the given module action and idSite date and period.
+     *
+     */
+    protected function urlForActionWithDefaultUserParams($controllerAction, $additionalParams = array())
+    {
+        $urlModuleAction = $this->urlForAction($controllerAction);
+        return array_merge(
+            $urlModuleAction,
+            $this->urlForDefaultUserParams(),
+            $additionalParams
+        );
+    }
+
+    /**
+     * Generates a URL to the given action of the given module, and it will also append some URL query parameters from the
+     * User preferences: idSite, period, date. If you do not need the parameters idSite, period and date to be generated
+     * use {@link urlForModuleAction()} instead.
+     *
+     * @param  string $module            The name of the module/plugin the action belongs to. The module name is case sensitive.
+     * @param  string $controllerAction  The name of the action that should be executed within your controller
+     * @param  array  $additionalParams  Optional URL parameters that will be appended to the URL
+     * @return array|null   Returns the array of query parameter names and values to the given module action and idSite date and period.
+     *                      Returns null if the module or action is invalid.
+     *
+     */
+    protected function urlForModuleActionWithDefaultUserParams($module, $controllerAction, $additionalParams = array())
+    {
+        $urlModuleAction = $this->urlForModuleAction($module, $controllerAction);
+        return array_merge(
+            $urlModuleAction,
+            $this->urlForDefaultUserParams(),
+            $additionalParams
+        );
+    }
+
+    /**
+     * Returns the &idSite=X&period=Y&date=Z query string fragment,
+     * fetched from current logged-in user's preferences.
+     *
+     * @param bool $websiteId
+     * @param bool $defaultPeriod
+     * @param bool $defaultDate
+     * @return string eg '&idSite=1&period=week&date=today'
+     * @throws \Exception in case a website was not specified and a default website id could not be found
+     */
+    public function urlForDefaultUserParams($websiteId = false, $defaultPeriod = false, $defaultDate = false)
+    {
+        $userPreferences = new UserPreferences();
+        if (empty($websiteId)) {
+            $websiteId = $userPreferences->getDefaultWebsiteId();
+        }
+        if (empty($websiteId)) {
+            throw new \Exception("A website ID was not specified and a website to default to could not be found.");
+        }
+        if (empty($defaultDate)) {
+            $defaultDate = $userPreferences->getDefaultDate();
+        }
+        if (empty($defaultPeriod)) {
+            $defaultPeriod = $userPreferences->getDefaultPeriod();
+        }
+        return array(
+            'idSite' => $websiteId,
+            'period' => $defaultPeriod,
+            'date'   => $defaultDate,
+        );
+    }
+
     /**
      * Configures the reporting menu which should only contain links to reports of a specific site such as
      * "Search Engines", "Page Titles" or "Locations & Provider".
diff --git a/core/Plugin/MetadataLoader.php b/core/Plugin/MetadataLoader.php
index 25f48ce0a095d78d713db1af3b6213a0b03b8da9..34bb90dcdcf021a3dc85721939d3e0949d89bcbc 100644
--- a/core/Plugin/MetadataLoader.php
+++ b/core/Plugin/MetadataLoader.php
@@ -101,6 +101,7 @@ class MetadataLoader
         ) {
             throw new Exception("Invalid JSON file: $path");
         }
+
         return $info;
     }
 }
diff --git a/core/Plugin/Report.php b/core/Plugin/Report.php
index 6d950babd2b5482b440b6093b138247b23e88f8e..c30e731d4627a205024b8416e868431cb1a1ac2c 100644
--- a/core/Plugin/Report.php
+++ b/core/Plugin/Report.php
@@ -41,6 +41,12 @@ class Report
      */
     const COMPONENT_SUBNAMESPACE = 'Reports';
 
+    /**
+     * When added to the menu, a given report eg 'getCampaigns'
+     * will be routed as &action=menuGetCampaigns
+     */
+    const PREFIX_ACTION_IN_MENU = 'menu';
+
     /**
      * The name of the module which is supposed to be equal to the name of the plugin. The module is detected
      * automatically.
@@ -328,11 +334,12 @@ class Report
     {
         if ($this->menuTitle) {
             $action = $this->getMenuControllerAction();
-            $menu->add($this->category,
-                       $this->menuTitle,
-                       array('module' => $this->module, 'action' => $action),
-                       $this->isEnabled(),
-                       $this->order);
+            if ($this->isEnabled()) {
+                $menu->addItem($this->category,
+                               $this->menuTitle,
+                               array('module' => $this->module, 'action' => $action),
+                               $this->order);
+            }
         }
     }
 
@@ -710,7 +717,7 @@ class Report
 
     private function getMenuControllerAction()
     {
-        return 'menu' . ucfirst($this->action);
+        return self::PREFIX_ACTION_IN_MENU . ucfirst($this->action);
     }
 
     private function getSubtableApiMethod()
@@ -731,7 +738,7 @@ class Report
      */
     public static function getForDimension(Dimension $dimension)
     {
-        return ComponentFactory::getComponentIf(__CLASS__, $dimension->getModule(), function (Report $report) use ($dimension) {
+        return ComponentFactory::getComponentif (__CLASS__, $dimension->getModule(), function (Report $report) use ($dimension) {
             return !$report->isSubtableReport()
                 && $report->getDimension()
                 && $report->getDimension()->getId() == $dimension->getId();
diff --git a/core/Plugin/ViewDataTable.php b/core/Plugin/ViewDataTable.php
index d7f72028cf5d404273b0cf1d194923491ef9ec05..4f3b854127f2fac99547933a45dad33a87cb265a 100644
--- a/core/Plugin/ViewDataTable.php
+++ b/core/Plugin/ViewDataTable.php
@@ -275,11 +275,11 @@ abstract class ViewDataTable implements ViewInterface
 
     protected function assignRelatedReportsTitle()
     {
-        if(!empty($this->config->related_reports_title)) {
+        if (!empty($this->config->related_reports_title)) {
             // title already assigned by a plugin
             return;
         }
-        if(count($this->config->related_reports) == 1) {
+        if (count($this->config->related_reports) == 1) {
             $this->config->related_reports_title = Piwik::translate('General_RelatedReport') . ':';
         } else {
             $this->config->related_reports_title = Piwik::translate('General_RelatedReports') . ':';
diff --git a/core/Plugin/Visualization.php b/core/Plugin/Visualization.php
index e82a8d7f7397f3c9d1d33474c027b7bad09adf17..e7e79c62e2beef67bf3b9efd89a221379a9b66c8 100644
--- a/core/Plugin/Visualization.php
+++ b/core/Plugin/Visualization.php
@@ -498,6 +498,7 @@ class Visualization extends ViewDataTable
             'filter_excludelowpop',
             'filter_excludelowpop_value',
         );
+
         foreach ($deleteFromJavascriptVariables as $name) {
             if (isset($javascriptVariablesToSet[$name])) {
                 unset($javascriptVariablesToSet[$name]);
diff --git a/core/Profiler.php b/core/Profiler.php
index 7468b1f5d669e0fc7ffca43602fcca1a23450b59..2b92583d89d5ff07218f9ff42f53a44c2ce30240 100644
--- a/core/Profiler.php
+++ b/core/Profiler.php
@@ -143,7 +143,7 @@ class Profiler
     {
         $totalTime = self::getDbElapsedSecs();
         $queryCount = Profiler::getQueryCount();
-        if($queryCount > 0) {
+        if ($queryCount > 0) {
             Log::debug(sprintf("Total queries = %d (total sql time = %.2fs)", $queryCount, $totalTime));
         }
     }
@@ -234,7 +234,7 @@ class Profiler
 
         $currentGitBranch = SettingsPiwik::getCurrentGitBranch();
         $profilerNamespace = "piwik";
-        if($currentGitBranch != 'master') {
+        if ($currentGitBranch != 'master') {
             $profilerNamespace .= "." . $currentGitBranch;
         }
 
@@ -326,7 +326,7 @@ class Profiler
     {
         $runIds = file_get_contents( self::getPathToXHProfRunIds() );
         $array = json_decode($runIds, $assoc = true);
-        if(!is_array($array)) {
+        if (!is_array($array)) {
             $array = array();
         }
         return $array;
diff --git a/core/ProxyHttp.php b/core/ProxyHttp.php
index a1e7fda32c41c5aea78f2d1c29fbd65ff01b0207..69f7144b44b4b315b2b6cc8dfa40934e62df60cf 100644
--- a/core/ProxyHttp.php
+++ b/core/ProxyHttp.php
@@ -233,6 +233,7 @@ class ProxyHttp
             // FastCGI
             $key = 'Status:';
         }
+
         Common::sendHeader($key . ' ' . $status);
     }
 
diff --git a/core/RankingQuery.php b/core/RankingQuery.php
index f40ae1273e39aeb191e59bedfa4911b28d1a4842..f44845f07535435f69dfc2646b0f11b89da849b6 100644
--- a/core/RankingQuery.php
+++ b/core/RankingQuery.php
@@ -215,7 +215,7 @@ class RankingQuery
     public function execute($innerQuery, $bind = array())
     {
         $query = $this->generateQuery($innerQuery);
-        $data = Db::fetchAll($query, $bind);
+        $data  = Db::fetchAll($query, $bind);
 
         if ($this->columnToMarkExcludedRows !== false) {
             // split the result into the regular result and the rows with special treatment
diff --git a/core/Registry.php b/core/Registry.php
index a3383a84c0789b2b033ceb17fda59c00afb26e66..5022bf09e24a42410c5a5431f2566a70bd10a452 100644
--- a/core/Registry.php
+++ b/core/Registry.php
@@ -11,7 +11,8 @@ namespace Piwik;
 /**
  * Registry class.
  *
- * @method static \Piwik\Registry getInstance()
+ * @method static Registry getInstance()
+ * @api
  */
 class Registry extends Singleton
 {
diff --git a/core/ReportRenderer/Csv.php b/core/ReportRenderer/Csv.php
index 23ace2ac4d4b219c8c3ce754b89cbcb5bade8699..94eca5172a605f3cd5a1c599d9610f7780ede8a8 100644
--- a/core/ReportRenderer/Csv.php
+++ b/core/ReportRenderer/Csv.php
@@ -105,7 +105,7 @@ class Csv extends ReportRenderer
         );
 
         $reportData = $csvRenderer->render($processedReport);
-        if(empty($reportData)) {
+        if (empty($reportData)) {
             $reportData = Piwik::translate('CoreHome_ThereIsNoDataForThisReport');
         }
 
diff --git a/core/ScheduledTask.php b/core/ScheduledTask.php
index 15b702dab862333e5d4f348f2fd19142fdd07c4e..d570f5bea2e65b600c2f1a2e2602b2afd823e17a 100644
--- a/core/ScheduledTask.php
+++ b/core/ScheduledTask.php
@@ -77,6 +77,7 @@ class ScheduledTask
      *                                          should be executed and how long before the next execution.
      * @param int $priority The priority of the task. Tasks with a higher priority will be executed first.
      *                      Tasks with low priority will be executed last.
+     * @throws Exception
      */
     public function __construct($objectInstance, $methodName, $methodParameter, $scheduledTime,
                                 $priority = self::NORMAL_PRIORITY)
diff --git a/core/ScheduledTime.php b/core/ScheduledTime.php
index f221a82a43e528596f248d9dedf8d7a9e83f393b..3da4afe98baae790a10b5bd9f5998786eb09612b 100644
--- a/core/ScheduledTime.php
+++ b/core/ScheduledTime.php
@@ -183,7 +183,7 @@ abstract class ScheduledTime
      * and a string description of the day within the period to execute the task on.
      *
      * @param string $periodType The scheduled period type. Can be `'hourly'`, `'daily'`, `'weekly'`, or `'monthly'`.
-     * @param string|int|false $periodDay A string describing the day within the scheduled period to execute
+     * @param bool|false|int|string $periodDay A string describing the day within the scheduled period to execute
      *                                    the task on. Only valid for week and month periods.
      *
      *                                    If `'weekly'` is supplied for `$periodType`, this should be a day
@@ -192,6 +192,7 @@ abstract class ScheduledTime
      *                                    If `'monthly'` is supplied for `$periodType`, this can be a numeric
      *                                    day in the month or a day in one week of the month. For example,
      *                                    `12`, `23`, `'first sunday'` or `'fourth tuesday'`.
+     * @throws Exception
      * @api
      */
     public static function factory($periodType, $periodDay = false)
@@ -203,13 +204,13 @@ abstract class ScheduledTime
                 return new Daily();
             case 'weekly':
                 $result = new Weekly();
-                if($periodDay !== false) {
+                if ($periodDay !== false) {
                     $result->setDay($periodDay);
                 }
                 return $result;
             case 'monthly':
                 $result = new Monthly($periodDay);
-                if($periodDay !== false) {
+                if ($periodDay !== false) {
                     if (is_int($periodDay)) {
                         $result->setDay($periodDay);
                     } else {
diff --git a/core/ScheduledTime/Monthly.php b/core/ScheduledTime/Monthly.php
index d4900530e8d397d5e91e564f2a842880437c78fb..84189f9badc345bf4d6154e52243c11c6d28006c 100644
--- a/core/ScheduledTime/Monthly.php
+++ b/core/ScheduledTime/Monthly.php
@@ -46,7 +46,6 @@ class Monthly extends ScheduledTime
         $day = Weekly::getDayIntFromString($dayNumberString) % 7;
 
         // get week number
-        $week = false;
         $weekNumberString = strtolower($weekNumberString);
         if (isset(self::$weekNumberStringToInt[$weekNumberString])) {
             $week = self::$weekNumberStringToInt[$weekNumberString];
diff --git a/core/Segment.php b/core/Segment.php
index e12b165028c1290bb0679243119f23cb5ade9d42..420946794da028e8890c7906058a82399dd74d75 100644
--- a/core/Segment.php
+++ b/core/Segment.php
@@ -70,6 +70,7 @@ class Segment
      * @param string $segmentCondition The segment condition, eg, `'browserCode=ff;countryCode=CA'`.
      * @param array $idSites The list of sites the segment will be used with. Some segments are
      *                       dependent on the site, such as goal segments.
+     * @throws Exception
      */
     public function __construct($segmentCondition, $idSites)
     {
@@ -99,7 +100,7 @@ class Segment
         // As a preventive measure, we restrict the filter size to a safe limit
         $string = substr($string, 0, self::SEGMENT_TRUNCATE_LIMIT);
 
-        $this->string = $string;
+        $this->string  = $string;
         $this->idSites = $idSites;
         $segment = new SegmentExpression($string);
         $this->segment = $segment;
@@ -117,6 +118,7 @@ class Segment
             $expression[SegmentExpression::INDEX_OPERAND] = $cleanedExpression;
             $cleanedExpressions[] = $expression;
         }
+
         $segment->setSubExpressionsAfterCleanup($cleanedExpressions);
     }
 
@@ -155,10 +157,10 @@ class Segment
                 throw new Exception("You do not have enough permission to access the segment " . $name);
             }
 
-            if($matchType != SegmentExpression::MATCH_IS_NOT_NULL_NOR_EMPTY
+            if ($matchType != SegmentExpression::MATCH_IS_NOT_NULL_NOR_EMPTY
                 && $matchType != SegmentExpression::MATCH_IS_NULL_OR_EMPTY) {
 
-                if(isset($segment['sqlFilterValue'])) {
+                if (isset($segment['sqlFilterValue'])) {
                     $value = call_user_func($segment['sqlFilterValue'], $value);
                 }
 
diff --git a/core/SegmentExpression.php b/core/SegmentExpression.php
index 682aa201d0189d7dcb47938de796c4a9d8fac38f..cbd2a3eb9e1ff2e8acdf8a7e24c49380e91b5204 100644
--- a/core/SegmentExpression.php
+++ b/core/SegmentExpression.php
@@ -84,7 +84,7 @@ class SegmentExpression
             }
 
             $leftMember = $matches[1];
-            $operation = $matches[2];
+            $operation  = $matches[2];
             $valueRightMember = urldecode($matches[3]);
 
             // is null / is not null
@@ -138,6 +138,7 @@ class SegmentExpression
             if ($operand[1] !== null) {
                 $this->valuesBind[] = $operand[1];
             }
+
             $operand = $operand[0];
             $sqlSubExpressions[] = array(
                 self::INDEX_BOOL_OPERATOR => $operator,
@@ -161,9 +162,9 @@ class SegmentExpression
      */
     protected function getSqlMatchFromDefinition($def, &$availableTables)
     {
-        $field = $def[0];
+        $field     = $def[0];
         $matchType = $def[1];
-        $value = $def[2];
+        $value     = $def[2];
 
         $alsoMatchNULLValues = false;
         switch ($matchType) {
@@ -188,22 +189,22 @@ class SegmentExpression
                 break;
             case self::MATCH_CONTAINS:
                 $sqlMatch = 'LIKE';
-                $value = '%' . $this->escapeLikeString($value) . '%';
+                $value    = '%' . $this->escapeLikeString($value) . '%';
                 break;
             case self::MATCH_DOES_NOT_CONTAIN:
                 $sqlMatch = 'NOT LIKE';
-                $value = '%' . $this->escapeLikeString($value) . '%';
+                $value    = '%' . $this->escapeLikeString($value) . '%';
                 $alsoMatchNULLValues = true;
                 break;
 
             case self::MATCH_IS_NOT_NULL_NOR_EMPTY:
                 $sqlMatch = 'IS NOT NULL AND (' . $field . ' <> \'\' OR ' . $field . ' = 0)';
-                $value = null;
+                $value    = null;
                 break;
 
             case self::MATCH_IS_NULL_OR_EMPTY:
                 $sqlMatch = 'IS NULL OR ' . $field . ' = \'\' ';
-                $value = null;
+                $value    = null;
                 break;
 
             case self::MATCH_ACTIONS_CONTAINS:
@@ -212,7 +213,7 @@ class SegmentExpression
                 // it can be used internally to inject sub-expressions into the query.
                 // see Segment::getCleanedExpression()
                 $sqlMatch = 'IN (' . $value['SQL'] . ')';
-                $value = $this->escapeLikeString($value['bind']);
+                $value    = $this->escapeLikeString($value['bind']);
                 break;
             default:
                 throw new Exception("Filter contains the match type '" . $matchType . "' which is not supported");
diff --git a/core/Session/SaveHandler/DbTable.php b/core/Session/SaveHandler/DbTable.php
index 249faca6e1af9df1108d9c01180e7b762a6f0d1c..74fc5e388b6c641ed993ad609ee5437451a97222 100644
--- a/core/Session/SaveHandler/DbTable.php
+++ b/core/Session/SaveHandler/DbTable.php
@@ -119,8 +119,7 @@ class DbTable implements Zend_Session_SaveHandler_Interface
      */
     public function destroy($id)
     {
-        $sql = 'DELETE FROM ' . $this->config['name']
-            . ' WHERE ' . $this->config['primary'] . ' = ?';
+        $sql = 'DELETE FROM ' . $this->config['name'] . ' WHERE ' . $this->config['primary'] . ' = ?';
 
         Db::get()->query($sql, array($id));
 
diff --git a/core/SettingsPiwik.php b/core/SettingsPiwik.php
index 4e83190e703da42a1d6753d0a0638088d53f8a09..26949c560a2d5c59b22caf72fbee613067b782a9 100644
--- a/core/SettingsPiwik.php
+++ b/core/SettingsPiwik.php
@@ -179,7 +179,7 @@ class SettingsPiwik
             $url = $currentUrl;
         }
 
-        if(ProxyHttp::isHttps()) {
+        if (ProxyHttp::isHttps()) {
             $url = str_replace("http://", "https://", $url);
         }
         return $url;
@@ -195,7 +195,7 @@ class SettingsPiwik
         $exists = file_exists($config);
 
         // Piwik is installed if the config file is found
-        if(!$exists) {
+        if (!$exists) {
             return false;
         }
 
@@ -205,12 +205,12 @@ class SettingsPiwik
         if (array_key_exists('installation_in_progress', $general)) {
             $isInstallationInProgress = (bool) $general['installation_in_progress'];
         }
-        if($isInstallationInProgress) {
+        if ($isInstallationInProgress) {
             return false;
         }
 
         // Check that the database section is really set, ie. file is not empty
-        if(empty(Config::getInstance()->database['username'])) {
+        if (empty(Config::getInstance()->database['username'])) {
             return false;
         }
         return true;
@@ -297,6 +297,8 @@ class SettingsPiwik
      * this will return false..
      *
      * @param $piwikServerUrl
+     * @param bool $acceptInvalidSSLCertificates
+     * @throws Exception
      * @return bool
      */
     public static function checkPiwikServerWorking($piwikServerUrl, $acceptInvalidSSLCertificates = false)
@@ -337,7 +339,7 @@ class SettingsPiwik
     public static function getCurrentGitBranch()
     {
         $file = PIWIK_INCLUDE_PATH . '/.git/HEAD';
-        if(!file_exists($file)) {
+        if (!file_exists($file)) {
             return '';
         }
         $firstLineOfGitHead = file($file);
@@ -385,19 +387,19 @@ class SettingsPiwik
     protected static function getPiwikInstanceId()
     {
         // until Piwik is installed, we use hostname as instance_id
-        if(!self::isPiwikInstalled()
+        if (!self::isPiwikInstalled()
             && Common::isPhpCliMode()) {
             // enterprise:install use case
             return Config::getHostname();
         }
 
         // config.ini.php not ready yet, instance_id will not be set
-        if(!Config::getInstance()->existsLocalConfig()) {
+        if (!Config::getInstance()->existsLocalConfig()) {
             return false;
         }
 
         $instanceId = @Config::getInstance()->General['instance_id'];
-        if(!empty($instanceId)) {
+        if (!empty($instanceId)) {
             return $instanceId;
         }
 
diff --git a/core/Site.php b/core/Site.php
index 7efeee77ef1ba2f72c8329d61d20d9897f36a575..96b7316b76e9ce7cfadae02a67b857d126d56da4 100644
--- a/core/Site.php
+++ b/core/Site.php
@@ -94,7 +94,7 @@ class Site
      */
     protected static function setSite($idSite, $infoSite)
     {
-        if(empty($idSite) || empty($infoSite)) {
+        if (empty($idSite) || empty($infoSite)) {
             throw new Exception("An unexpected website was found, check idSite in the request.");
         }
 
@@ -361,7 +361,7 @@ class Site
             return API::getInstance()->getSitesIdWithAtLeastViewAccess($_restrictSitesToLogin);
         }
 
-        if(is_bool($ids)) {
+        if (is_bool($ids)) {
             return array();
         }
         if (!is_array($ids)) {
@@ -406,7 +406,7 @@ class Site
             $site = API::getInstance()->getSiteFromId($idsite);
             self::setSite($idsite, $site);
         }
-        if($field) {
+        if ($field) {
             return self::$infoSites[$idsite][$field];
         }
         return self::$infoSites[$idsite];
diff --git a/core/Theme.php b/core/Theme.php
index b0fe5abecba9864b0253997b81bb5a0251f843b0..f7f85a52919ae5a4dce3321ab1d9b8402487c713 100644
--- a/core/Theme.php
+++ b/core/Theme.php
@@ -64,7 +64,7 @@ class Theme
             return false;
         }
         $jsFiles = $info['javascript'];
-        if(!is_array($jsFiles)) {
+        if (!is_array($jsFiles)) {
             $jsFiles = array($jsFiles);
         }
         foreach($jsFiles as &$jsFile) {
@@ -107,18 +107,18 @@ class Theme
 
         // Basic health check, we dont replace if not starting with plugins/
         $posPluginsInPath = strpos($pathAsset, 'plugins');
-        if( $posPluginsInPath !== 0) {
+        if ( $posPluginsInPath !== 0) {
             return $source;
         }
 
         // or if it's already rewritten
-        if(strpos($pathAsset, $this->themeName) !== false) {
+        if (strpos($pathAsset, $this->themeName) !== false) {
             return $source;
         }
 
         $pathPluginName = substr($pathAsset, strlen('plugins/'));
         $nextSlash = strpos($pathPluginName, '/');
-        if($nextSlash === false) {
+        if ($nextSlash === false) {
             return $source;
         }
         $pathPluginName = substr($pathPluginName, 0, $nextSlash);
@@ -133,11 +133,11 @@ class Theme
         // Strip trailing query string
         $fileToCheck = $overridingAsset;
         $queryStringPos = strpos($fileToCheck, '?');
-        if( $queryStringPos !== false) {
+        if ( $queryStringPos !== false) {
             $fileToCheck = substr($fileToCheck, 0, $queryStringPos);
         }
 
-        if(file_exists($fileToCheck)) {
+        if (file_exists($fileToCheck)) {
             return str_replace($pathAsset, $overridingAsset, $source);
         }
         return $source;
diff --git a/core/Tracker.php b/core/Tracker.php
index 733f23d8a32e93552e6c0e3b3980d5a1ef3ecea8..3aa27237a12e193d89076aa81f9b6a640b8cae25 100644
--- a/core/Tracker.php
+++ b/core/Tracker.php
@@ -221,7 +221,7 @@ class Tracker
      */
     public function main($args = null)
     {
-        if(!SettingsPiwik::isPiwikInstalled()) {
+        if (!SettingsPiwik::isPiwikInstalled()) {
             return $this->handleEmptyRequest();
         }
         try {
@@ -468,7 +468,7 @@ class Tracker
             Common::sendHeader('Content-Type: text/html; charset=utf-8');
             echo $this->getMessageFromException($e);
         } else {
-            $this->outputTransparentGif();
+            $this->outputTransparentGif ();
         }
         exit;
     }
@@ -516,7 +516,7 @@ class Tracker
         }
         switch ($this->getState()) {
             case self::STATE_LOGGING_DISABLE:
-                $this->outputTransparentGif();
+                $this->outputTransparentGif ();
                 Common::printDebug("Logging disabled, display transparent logo");
                 break;
 
@@ -528,7 +528,7 @@ class Tracker
             case self::STATE_NOSCRIPT_REQUEST:
             case self::STATE_NOTHING_TO_NOTICE:
             default:
-                $this->outputTransparentGif();
+                $this->outputTransparentGif ();
                 Common::printDebug("Nothing to notice => default behaviour");
                 break;
         }
@@ -663,7 +663,7 @@ class Tracker
         return $visit;
     }
 
-    protected function outputTransparentGif()
+    protected function outputTransparentGif ()
     {
         if (isset($GLOBALS['PIWIK_TRACKER_DEBUG'])
             && $GLOBALS['PIWIK_TRACKER_DEBUG']
@@ -717,7 +717,7 @@ class Tracker
 
     protected function handleEmptyRequest(Request $request = null)
     {
-        if(is_null($request)) {
+        if (is_null($request)) {
             $request = new Request($_GET + $_POST);
         }
         $countParameters = $request->getParamsCount();
diff --git a/core/Tracker/Action.php b/core/Tracker/Action.php
index 6175d86e59a41bbf318931077197b78d39225b88..6df6f64cfcc3f0c570488686e4e147afc05b6a4b 100644
--- a/core/Tracker/Action.php
+++ b/core/Tracker/Action.php
@@ -22,32 +22,50 @@ use Piwik\Tracker;
  */
 abstract class Action
 {
-    const TYPE_PAGE_URL = 1;
-    const TYPE_OUTLINK = 2;
-    const TYPE_DOWNLOAD = 3;
+    const TYPE_PAGE_URL   = 1;
+    const TYPE_OUTLINK    = 2;
+    const TYPE_DOWNLOAD   = 3;
     const TYPE_PAGE_TITLE = 4;
-    const TYPE_ECOMMERCE_ITEM_SKU = 5;
+    const TYPE_ECOMMERCE_ITEM_SKU  = 5;
     const TYPE_ECOMMERCE_ITEM_NAME = 6;
     const TYPE_ECOMMERCE_ITEM_CATEGORY = 7;
     const TYPE_SITE_SEARCH = 8;
 
-    const TYPE_EVENT = 10; // Alias TYPE_EVENT_CATEGORY
+    const TYPE_EVENT          = 10; // Alias TYPE_EVENT_CATEGORY
     const TYPE_EVENT_CATEGORY = 10;
-    const TYPE_EVENT_ACTION = 11;
-    const TYPE_EVENT_NAME = 12;
+    const TYPE_EVENT_ACTION   = 11;
+    const TYPE_EVENT_NAME     = 12;
 
-    const TYPE_CONTENT = 13; // Alias TYPE_CONTENT_NAME
-    const TYPE_CONTENT_NAME = 13;
-    const TYPE_CONTENT_PIECE = 14;
-    const TYPE_CONTENT_TARGET = 15;
+    const TYPE_CONTENT             = 13; // Alias TYPE_CONTENT_NAME
+    const TYPE_CONTENT_NAME        = 13;
+    const TYPE_CONTENT_PIECE       = 14;
+    const TYPE_CONTENT_TARGET      = 15;
     const TYPE_CONTENT_INTERACTION = 16;
 
     const DB_COLUMN_CUSTOM_FLOAT = 'custom_float';
 
     private static $factoryPriority = array(
-        self::TYPE_PAGE_URL, self::TYPE_CONTENT, self::TYPE_SITE_SEARCH, self::TYPE_EVENT, self::TYPE_OUTLINK, self::TYPE_DOWNLOAD
+        self::TYPE_PAGE_URL,
+        self::TYPE_CONTENT,
+        self::TYPE_SITE_SEARCH,
+        self::TYPE_EVENT,
+        self::TYPE_OUTLINK,
+        self::TYPE_DOWNLOAD
     );
 
+    /**
+     * Public so that events listener can access it
+     *
+     * @var Request
+     */
+    public $request;
+
+    private $idLinkVisitAction;
+    private $actionIdsCached = array();
+    private $actionName;
+    private $actionType;
+    private $actionUrl;
+
     /**
      * Makes the correct Action object based on the request.
      *
@@ -102,7 +120,7 @@ abstract class Action
         $instances = array();
 
         foreach ($actions as $action) {
-            /** @var \Piwik\Tracker\Action $instance */
+            /** @var \Piwik\Tracker\Action $action */
             if ($action::shouldHandle($request)) {
                 $instances[] = new $action($request);
             }
@@ -111,19 +129,6 @@ abstract class Action
         return $instances;
     }
 
-    /**
-     * Public so that events listener can access it
-     *
-     * @var Request
-     */
-    public $request;
-
-    private $idLinkVisitAction;
-    private $actionIdsCached = array();
-    private $actionName;
-    private $actionType;
-    private $actionUrl;
-
     public function __construct($type, Request $request)
     {
         $this->actionType = $type;
@@ -152,8 +157,7 @@ abstract class Action
 
     public function getCustomVariables()
     {
-        $customVariables = $this->request->getCustomVariables($scope = 'page');
-        return $customVariables;
+        return $this->request->getCustomVariables($scope = 'page');
     }
 
     // custom_float column
@@ -164,8 +168,7 @@ abstract class Action
 
     protected function setActionName($name)
     {
-        $name = PageUrl::cleanupString((string)$name);
-        $this->actionName = $name;
+        $this->actionName = PageUrl::cleanupString((string)$name);
     }
 
     protected function setActionUrl($url)
@@ -178,8 +181,7 @@ abstract class Action
             Common::printDebug(' After is "' . $url . '"');
         }
 
-        $url = PageUrl::getUrlIfLookValid($url);
-        $this->actionUrl = $url;
+        $this->actionUrl = PageUrl::getUrlIfLookValid($url);
     }
 
     abstract protected function getActionsToLookup();
@@ -187,11 +189,13 @@ abstract class Action
     protected function getUrlAndType()
     {
         $url = $this->getActionUrl();
+
         if (!empty($url)) {
             // normalize urls by stripping protocol and www
             $url = PageUrl::normalizeUrl($url);
             return array($url['url'], self::TYPE_PAGE_URL, $url['prefixId']);
         }
+
         return false;
     }
 
@@ -214,9 +218,11 @@ abstract class Action
 
     public function getIdActionName()
     {
-        if(!isset($this->actionIdsCached['idaction_name'])) {
+        if (!isset($this->actionIdsCached['idaction_name'])) {
+
             return false;
         }
+
         return $this->actionIdsCached['idaction_name'];
     }
 
@@ -230,24 +236,17 @@ abstract class Action
         return $this->idLinkVisitAction;
     }
 
-    public function writeDebugInfo()
-    {
-        $type = self::getTypeAsString($this->getActionType());
-        Common::printDebug("Action is a $type,
-                Action name =  " . $this->getActionName() . ",
-                Action URL = " . $this->getActionUrl());
-        return true;
-    }
-
     public static function getTypeAsString($type)
     {
-        $class = new \ReflectionClass("\\Piwik\\Tracker\\Action");
+        $class     = new \ReflectionClass("\\Piwik\\Tracker\\Action");
         $constants = $class->getConstants();
 
         $typeId = array_search($type, $constants);
-        if($typeId === false) {
+
+        if (false === $typeId) {
             throw new Exception("Unexpected action type " . $type);
         }
+
         return str_replace('TYPE_', '', $typeId);
     }
 
@@ -262,24 +261,27 @@ abstract class Action
      */
     public function loadIdsFromLogActionTable()
     {
-        if(!empty($this->actionIdsCached)) {
+        if (!empty($this->actionIdsCached)) {
             return;
         }
 
-        $actions    = $this->getActionsToLookup();
+        /** @var ActionDimension[] $dimensions */
         $dimensions = ActionDimension::getAllDimensions();
+        $actions    = $this->getActionsToLookup();
 
         foreach ($dimensions as $dimension) {
             $value = $dimension->onLookupAction($this->request, $this);
 
-            if ($value !== false) {
+            if (false !== $value) {
                 $field = $dimension->getColumnName();
 
                 if (empty($field)) {
-                    throw new Exception('Dimension ' . get_class($dimension) . ' does not define a field name');
+                    $dimensionClass = get_class($dimension);
+                    throw new Exception('Dimension ' . $dimensionClass . ' does not define a field name');
                 }
 
-                $actions[$field] = array($value, $dimension->getActionId());
+                $actionId        = $dimension->getActionId();
+                $actions[$field] = array($value, $actionId);
                 Common::printDebug("$field = $value");
             }
         }
@@ -316,6 +318,7 @@ abstract class Action
             'idaction_name_ref' => $idReferrerActionName
         );
 
+        /** @var ActionDimension[] $dimensions */
         $dimensions = ActionDimension::getAllDimensions();
 
         foreach ($dimensions as $dimension) {
@@ -347,18 +350,15 @@ abstract class Action
         }
 
         $visitAction = array_merge($visitAction, $customVariables);
-        $fields      = implode(", ", array_keys($visitAction));
-        $bind        = array_values($visitAction);
-        $values      = Common::getSqlStringFieldsArray($visitAction);
 
-        $sql = "INSERT INTO " . Common::prefixTable('log_link_visit_action') . " ($fields) VALUES ($values)";
-        Tracker::getDatabase()->query($sql, $bind);
+        $this->idLinkVisitAction = $this->getModel()->createAction($visitAction);
 
-        $this->idLinkVisitAction = Tracker::getDatabase()->lastInsertId();
         $visitAction['idlink_va'] = $this->idLinkVisitAction;
 
         Common::printDebug("Inserted new action:");
-        Common::printDebug($visitAction);
+        $visitActionDebug = $visitAction;
+        $visitActionDebug['idvisitor'] = bin2hex($visitActionDebug['idvisitor']);
+        Common::printDebug($visitActionDebug);
 
         /**
          * Triggered after successfully persisting a [visit action entity](/guides/persistence-and-the-mysql-backend#visit-actions).
@@ -370,13 +370,31 @@ abstract class Action
         Piwik::postEvent('Tracker.recordAction', array($trackerAction = $this, $visitAction));
     }
 
+    public function writeDebugInfo()
+    {
+        $type = self::getTypeAsString($this->getActionType());
+        $name = $this->getActionName();
+        $url  = $this->getActionUrl();
+
+        Common::printDebug("Action is a $type,
+                Action name =  " . $name . ",
+                Action URL = " . $url);
+
+        return true;
+    }
+
+    private function getModel()
+    {
+        return new Model();
+    }
+
     /**
      * @return bool
      */
-    protected function isActionHasActionName()
+    private function isActionHasActionName()
     {
-        return in_array($this->getActionType(), array(self::TYPE_PAGE_TITLE,
-                                                      self::TYPE_PAGE_URL,
-                                                      self::TYPE_SITE_SEARCH));
+        $types = array(self::TYPE_PAGE_TITLE, self::TYPE_PAGE_URL, self::TYPE_SITE_SEARCH);
+
+        return in_array($this->getActionType(), $types);
     }
 }
diff --git a/core/Tracker/ActionPageview.php b/core/Tracker/ActionPageview.php
index fa3d0146dc526613c879ec47a53ce21c2cad47c3..9088fc543a19a52e9033e7705137f2e805946716 100644
--- a/core/Tracker/ActionPageview.php
+++ b/core/Tracker/ActionPageview.php
@@ -38,7 +38,7 @@ class ActionPageview extends Action
     {
         return array(
             'idaction_name' => array($this->getActionName(), Action::TYPE_PAGE_TITLE),
-            'idaction_url' => $this->getUrlAndType()
+            'idaction_url'  => $this->getUrlAndType()
         );
     }
 
@@ -55,22 +55,38 @@ class ActionPageview extends Action
     private function cleanupActionName($actionName)
     {
         // get the delimiter, by default '/'; BC, we read the old action_category_delimiter first (see #1067)
-        $actionCategoryDelimiter = isset(Config::getInstance()->General['action_category_delimiter'])
-            ? Config::getInstance()->General['action_category_delimiter']
-            : Config::getInstance()->General['action_url_category_delimiter'];
+        $actionCategoryDelimiter = $this->getActionCategoryDelimiter();
 
         // create an array of the categories delimited by the delimiter
         $split = explode($actionCategoryDelimiter, $actionName);
+        $split = $this->trimEveryCategory($split);
+        $split = $this->removeEmptyCategories($split);
 
-        // trim every category
-        $split = array_map('trim', $split);
+        return $this->rebuildNameOfCleanedCategories($actionCategoryDelimiter, $split);
+    }
+
+    private function rebuildNameOfCleanedCategories($actionCategoryDelimiter, $split)
+    {
+        return implode($actionCategoryDelimiter, $split);
+    }
 
-        // remove empty categories
-        $split = array_filter($split, 'strlen');
+    private function removeEmptyCategories($split)
+    {
+        return array_filter($split, 'strlen');
+    }
+
+    private function trimEveryCategory($split)
+    {
+        return array_map('trim', $split);
+    }
+
+    private function getActionCategoryDelimiter()
+    {
+        if (isset(Config::getInstance()->General['action_category_delimiter'])) {
+            return Config::getInstance()->General['action_category_delimiter'];
+        }
 
-        // rebuild the name from the array of cleaned categories
-        $actionName = implode($actionCategoryDelimiter, $split);
-        return $actionName;
+        return Config::getInstance()->General['action_url_category_delimiter'];
     }
 
 }
diff --git a/core/Tracker/Cache.php b/core/Tracker/Cache.php
index 0217b175de1b3ae70bf3ac198e13d6e770c934b0..b8f0413c63cc686e6fb541f1425f41f3b5a72b24 100644
--- a/core/Tracker/Cache.php
+++ b/core/Tracker/Cache.php
@@ -8,6 +8,7 @@
  */
 namespace Piwik\Tracker;
 
+use Piwik\Access;
 use Piwik\ArchiveProcessor\Rules;
 use Piwik\CacheFile;
 use Piwik\Common;
@@ -45,56 +46,54 @@ class Cache
      */
     static function getCacheWebsiteAttributes($idSite)
     {
-        if($idSite == 'all') {
+        if ('all' == $idSite) {
             return array();
         }
+
         $idSite = (int)$idSite;
-        if($idSite <= 0) {
+        if ($idSite <= 0) {
             return array();
         }
 
-        $cache = self::getInstance();
-        if (($cacheContent = $cache->get($idSite)) !== false) {
+        $cache        = self::getInstance();
+        $cacheContent = $cache->get($idSite);
+
+        if (false !== $cacheContent) {
             return $cacheContent;
         }
 
         Tracker::initCorePiwikInTrackerMode();
 
-        // save current user privilege and temporarily assume Super User privilege
-        $isSuperUser = Piwik::hasUserSuperUserAccess();
-        Piwik::setUserHasSuperUserAccess();
-
         $content = array();
-
-        /**
-         * Triggered to get the attributes of a site entity that might be used by the
-         * Tracker.
-         *
-         * Plugins add new site attributes for use in other tracking events must
-         * use this event to put those attributes in the Tracker Cache.
-         *
-         * **Example**
-         *
-         *     public function getSiteAttributes($content, $idSite)
-         *     {
-         *         $sql = "SELECT info FROM " . Common::prefixTable('myplugin_extra_site_info') . " WHERE idsite = ?";
-         *         $content['myplugin_site_data'] = Db::fetchOne($sql, array($idSite));
-         *     }
-         *
-         * @param array &$content Array mapping of site attribute names with values.
-         * @param int $idSite The site ID to get attributes for.
-         */
-        Piwik::postEvent('Tracker.Cache.getSiteAttributes', array(&$content, $idSite));
-        Common::printDebug("Website $idSite tracker cache was re-created.");
-
-        // restore original user privilege
-        Piwik::setUserHasSuperUserAccess($isSuperUser);
+        Access::doAsSuperUser(function () use (&$content, $idSite) {
+            /**
+             * Triggered to get the attributes of a site entity that might be used by the
+             * Tracker.
+             *
+             * Plugins add new site attributes for use in other tracking events must
+             * use this event to put those attributes in the Tracker Cache.
+             *
+             * **Example**
+             *
+             *     public function getSiteAttributes($content, $idSite)
+             *     {
+             *         $sql = "SELECT info FROM " . Common::prefixTable('myplugin_extra_site_info') . " WHERE idsite = ?";
+             *         $content['myplugin_site_data'] = Db::fetchOne($sql, array($idSite));
+             *     }
+             *
+             * @param array &$content Array mapping of site attribute names with values.
+             * @param int $idSite The site ID to get attributes for.
+             */
+            Piwik::postEvent('Tracker.Cache.getSiteAttributes', array(&$content, $idSite));
+            Common::printDebug("Website $idSite tracker cache was re-created.");
+        });
 
         // if nothing is returned from the plugins, we don't save the content
         // this is not expected: all websites are expected to have at least one URL
         if (!empty($content)) {
             $cache->set($idSite, $content);
         }
+
         return $content;
     }
 
@@ -114,10 +113,12 @@ class Cache
      */
     public static function getCacheGeneral()
     {
-        $cache = self::getInstance();
+        $cache   = self::getInstance();
         $cacheId = 'general';
 
-        if (($cacheContent = $cache->get($cacheId)) !== false) {
+        $cacheContent = $cache->get($cacheId);
+
+        if (false !== $cacheContent) {
             return $cacheContent;
         }
 
@@ -161,9 +162,10 @@ class Cache
      */
     public static function setCacheGeneral($value)
     {
-        $cache = self::getInstance();
+        $cache   = self::getInstance();
         $cacheId = 'general';
         $cache->set($cacheId, $value);
+
         return true;
     }
 
@@ -177,6 +179,7 @@ class Cache
         if (!is_array($idSites)) {
             $idSites = array($idSites);
         }
+
         foreach ($idSites as $idSite) {
             self::deleteCacheWebsiteAttributes($idSite);
             self::getCacheWebsiteAttributes($idSite);
diff --git a/core/Tracker/Db.php b/core/Tracker/Db.php
index 4ce13a08918739ec10b6bf5bf67a93f0d66259f3..1fe081daac1d1c96727ccab6e59fd8d0f8bd805e 100644
--- a/core/Tracker/Db.php
+++ b/core/Tracker/Db.php
@@ -77,10 +77,14 @@ abstract class Db
      */
     protected function recordQueryProfile($query, $timer)
     {
-        if (!isset($this->queriesProfiling[$query])) $this->queriesProfiling[$query] = array('sum_time_ms' => 0, 'count' => 0);
-        $time = $timer->getTimeMs(2);
+        if (!isset($this->queriesProfiling[$query])) {
+            $this->queriesProfiling[$query] = array('sum_time_ms' => 0, 'count' => 0);
+        }
+
+        $time  = $timer->getTimeMs(2);
         $time += $this->queriesProfiling[$query]['sum_time_ms'];
         $count = $this->queriesProfiling[$query]['count'] + 1;
+
         $this->queriesProfiling[$query] = array('sum_time_ms' => $time, 'count' => $count);
     }
 
@@ -97,13 +101,12 @@ abstract class Db
         self::$profiling = false;
 
         foreach ($this->queriesProfiling as $query => $info) {
-            $time = $info['sum_time_ms'];
+            $time  = $info['sum_time_ms'];
             $count = $info['count'];
 
             $queryProfiling = "INSERT INTO " . Common::prefixTable('log_profiling') . "
 						(query,count,sum_time_ms) VALUES (?,$count,$time)
-						ON DUPLICATE KEY
-							UPDATE count=count+$count,sum_time_ms=sum_time_ms+$time";
+						ON DUPLICATE KEY UPDATE count=count+$count,sum_time_ms=sum_time_ms+$time";
             $this->query($queryProfiling, array($query));
         }
 
diff --git a/core/Tracker/Db/Mysqli.php b/core/Tracker/Db/Mysqli.php
index 78e2d9ee291efac3c65b0b2d03e186e7a7f645c4..945255168371ff8696b5863fbe9eacb1d29d33c2 100644
--- a/core/Tracker/Db/Mysqli.php
+++ b/core/Tracker/Db/Mysqli.php
@@ -73,7 +73,14 @@ class Mysqli extends Db
             $timer = $this->initProfiler();
         }
 
-        $this->connection = mysqli_connect($this->host, $this->username, $this->password, $this->dbname, $this->port, $this->socket);
+        $this->connection = mysqli_init();
+
+        // Make sure MySQL returns all matched rows on update queries including
+        // rows that actually didn't have to be updated because the values didn't
+        // change. This matches common behaviour among other database systems.
+        // See #6296 why this is important in tracker
+        $flags = MYSQLI_CLIENT_FOUND_ROWS;
+        mysqli_real_connect($this->connection, $this->host, $this->username, $this->password, $this->dbname, $this->port, $this->socket, $flags);
         if (!$this->connection || mysqli_connect_errno()) {
             throw new DbException("Connect failed: " . mysqli_connect_error());
         }
@@ -205,8 +212,8 @@ class Mysqli extends Db
             return $result;
         } catch (Exception $e) {
             throw new DbException("Error query: " . $e->getMessage() . "
-								In query: $query
-								Parameters: " . var_export($parameters, true));
+                                   In query: $query
+                                   Parameters: " . var_export($parameters, true));
         }
     }
 
@@ -278,57 +285,58 @@ class Mysqli extends Db
         return mysqli_affected_rows($this->connection);
     }
 
-	/**
-	 * Start Transaction
-	 * @return string TransactionID
-	 */
-
-	public function beginTransaction()
-	{
-		if(!$this->activeTransaction === false ) {
-			return;
-		}
-
-		if( $this->connection->autocommit(false) ) {
-			$this->activeTransaction = uniqid();
-			return $this->activeTransaction;
-		}
-	}
-
-	/**
-	 * Commit Transaction
-	 * @param string TransactionID from beginTransaction
-	 */
-
-	public function commit($xid)
-	{
-		if($this->activeTransaction !=  $xid || $this->activeTransaction === false  ) {
-
-			return;
-		}
-		$this->activeTransaction = false;
-
-		if(!$this->connection->commit() ) {
-			throw new DbException("Commit failed");
-		}
-		$this->connection->autocommit(true);
-	}
-
-	/**
-	 * Rollback Transaction
-	 * @param string TransactionID from beginTransaction
-	 */
-
-	public function rollBack($xid)
-	{
-		if($this->activeTransaction !=  $xid || $this->activeTransaction === false  ) {
-			return;
-		}
-		$this->activeTransaction = false;
-
-		if(!$this->connection->rollback() ) {
-			throw new DbException("Rollback failed");
-		}
-		$this->connection->autocommit(true);
-	}
+    /**
+     * Start Transaction
+     * @return string TransactionID
+     */
+    public function beginTransaction()
+    {
+        if (!$this->activeTransaction === false ) {
+            return;
+        }
+
+        if ( $this->connection->autocommit(false) ) {
+            $this->activeTransaction = uniqid();
+            return $this->activeTransaction;
+        }
+    }
+
+    /**
+     * Commit Transaction
+     * @param $xid
+     * @throws DbException
+     * @internal param TransactionID $string from beginTransaction
+     */
+    public function commit($xid)
+    {
+        if ($this->activeTransaction !=  $xid || $this->activeTransaction === false  ) {
+
+            return;
+        }
+        $this->activeTransaction = false;
+
+        if (!$this->connection->commit() ) {
+            throw new DbException("Commit failed");
+        }
+        $this->connection->autocommit(true);
+    }
+
+    /**
+     * Rollback Transaction
+     * @param $xid
+     * @throws DbException
+     * @internal param TransactionID $string from beginTransaction
+     */
+    public function rollBack($xid)
+    {
+        if ($this->activeTransaction !=  $xid || $this->activeTransaction === false  ) {
+            return;
+        }
+        $this->activeTransaction = false;
+
+        if (!$this->connection->rollback() ) {
+            throw new DbException("Rollback failed");
+        }
+        $this->connection->autocommit(true);
+    }
 }
diff --git a/core/Tracker/Db/Pdo/Mysql.php b/core/Tracker/Db/Pdo/Mysql.php
index a2f5a79b2cbbe3c5f1318e65e041750791089e25..1cb72c11a6df85687aaac2912ccf88febcffeec5 100644
--- a/core/Tracker/Db/Pdo/Mysql.php
+++ b/core/Tracker/Db/Pdo/Mysql.php
@@ -68,8 +68,17 @@ class Mysql extends Db
             $timer = $this->initProfiler();
         }
 
-        $this->connection = @new PDO($this->dsn, $this->username, $this->password, $config = array());
-        $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+        // Make sure MySQL returns all matched rows on update queries including
+        // rows that actually didn't have to be updated because the values didn't
+        // change. This matches common behaviour among other database systems.
+        // See #6296 why this is important in tracker
+        $config = array(
+            PDO::MYSQL_ATTR_FOUND_ROWS => true,
+            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
+        );
+
+        $this->connection = @new PDO($this->dsn, $this->username, $this->password, $config);
+
         // we may want to setAttribute(PDO::ATTR_TIMEOUT ) to a few seconds (default is 60) in case the DB is locked
         // the piwik.php would stay waiting for the database... bad!
         // we delete the password from this object "just in case" it could be printed
@@ -195,8 +204,8 @@ class Mysql extends Db
             return $sth;
         } catch (PDOException $e) {
             throw new DbException("Error query: " . $e->getMessage() . "
-								In query: $query
-								Parameters: " . var_export($parameters, true));
+                                In query: $query
+                                Parameters: " . var_export($parameters, true));
         }
     }
 
@@ -237,54 +246,55 @@ class Mysql extends Db
         return $queryResult->rowCount();
     }
 
-	/**
-	 * Start Transaction
-	 * @return string TransactionID
-	 */
-
-	public function beginTransaction()
-	{
-		if(!$this->activeTransaction === false ) {
-			return;
-		}
-
-		if( $this->connection->beginTransaction() ) {
-			$this->activeTransaction = uniqid();
-			return $this->activeTransaction;
-		}
-	}
-
-	/**
-	 * Commit Transaction
-	 * @param string TransactionID from beginTransaction
-	 */
+    /**
+     * Start Transaction
+     * @return string TransactionID
+     */
+    public function beginTransaction()
+    {
+        if (!$this->activeTransaction === false ) {
+            return;
+        }
 
-	public function commit($xid)
-	{
-		if($this->activeTransaction != $xid || $this->activeTransaction === false ) {
-			return;
-		}
-		$this->activeTransaction = false;
+        if ( $this->connection->beginTransaction() ) {
+            $this->activeTransaction = uniqid();
+            return $this->activeTransaction;
+        }
+    }
 
-		if(!$this->connection->commit() ) {
-			throw new DbException("Commit failed");
-		}
-	}
+    /**
+     * Commit Transaction
+     * @param $xid
+     * @throws DbException
+     * @internal param TransactionID $string from beginTransaction
+     */
+    public function commit($xid)
+    {
+        if ($this->activeTransaction != $xid || $this->activeTransaction === false ) {
+            return;
+        }
+        $this->activeTransaction = false;
 
-	/**
-	 * Rollback Transaction
-	 * @param string TransactionID from beginTransaction
-	 */
+        if (!$this->connection->commit() ) {
+            throw new DbException("Commit failed");
+        }
+    }
 
-	public function rollBack($xid)
-	{
-		if($this->activeTransaction != $xid || $this->activeTransaction === false ) {
-			return;
-		}
-		$this->activeTransaction = false;
+    /**
+     * Rollback Transaction
+     * @param $xid
+     * @throws DbException
+     * @internal param TransactionID $string from beginTransaction
+     */
+    public function rollBack($xid)
+    {
+        if ($this->activeTransaction != $xid || $this->activeTransaction === false ) {
+            return;
+        }
+        $this->activeTransaction = false;
 
-		if(!$this->connection->rollBack() ) {
-			throw new DbException("Rollback failed");
-		}
-	}
+        if (!$this->connection->rollBack() ) {
+            throw new DbException("Rollback failed");
+        }
+    }
 }
diff --git a/core/Tracker/GoalManager.php b/core/Tracker/GoalManager.php
index 1a0944ad9a58cf53484f00b5f41b5b0fbd941810..69639fd1c63b7b42ac875dc19633ab8aefe58631 100644
--- a/core/Tracker/GoalManager.php
+++ b/core/Tracker/GoalManager.php
@@ -34,6 +34,25 @@ class GoalManager
     const REVENUE_PRECISION = 2;
 
     const MAXIMUM_PRODUCT_CATEGORIES = 5;
+
+    // In the GET items parameter, each item has the following array of information
+    const INDEX_ITEM_SKU = 0;
+    const INDEX_ITEM_NAME = 1;
+    const INDEX_ITEM_CATEGORY = 2;
+    const INDEX_ITEM_PRICE = 3;
+    const INDEX_ITEM_QUANTITY = 4;
+
+    // Used in the array of items, internally to this class
+    const INTERNAL_ITEM_SKU = 0;
+    const INTERNAL_ITEM_NAME = 1;
+    const INTERNAL_ITEM_CATEGORY = 2;
+    const INTERNAL_ITEM_CATEGORY2 = 3;
+    const INTERNAL_ITEM_CATEGORY3 = 4;
+    const INTERNAL_ITEM_CATEGORY4 = 5;
+    const INTERNAL_ITEM_CATEGORY5 = 6;
+    const INTERNAL_ITEM_PRICE = 7;
+    const INTERNAL_ITEM_QUANTITY = 8;
+
     public $idGoal;
     public $requestIsEcommerce;
     private $isGoalAnOrder;
@@ -65,7 +84,7 @@ class GoalManager
         $this->idGoal  = $request->getParam('idgoal');
 
         $this->isGoalAnOrder = !empty($this->orderId);
-        $this->requestIsEcommerce = ($this->idGoal == 0);
+        $this->requestIsEcommerce = (0 == $this->idGoal);
     }
 
     public function isGoalAnOrder()
@@ -87,30 +106,36 @@ class GoalManager
     public static function getGoalDefinitions($idSite)
     {
         $websiteAttributes = Cache::getCacheWebsiteAttributes($idSite);
+
         if (isset($websiteAttributes['goals'])) {
             return $websiteAttributes['goals'];
         }
+
         return array();
     }
 
     public static function getGoalDefinition($idSite, $idGoal)
     {
         $goals = self::getGoalDefinitions($idSite);
+
         foreach ($goals as $goal) {
             if ($goal['idgoal'] == $idGoal) {
                 return $goal;
             }
         }
+
         throw new Exception('Goal not found');
     }
 
     public static function getGoalIds($idSite)
     {
-        $goals = self::getGoalDefinitions($idSite);
+        $goals   = self::getGoalDefinitions($idSite);
         $goalIds = array();
+
         foreach ($goals as $goal) {
             $goalIds[] = $goal['idgoal'];
         }
+
         return $goalIds;
     }
 
@@ -131,14 +156,15 @@ class GoalManager
         $decodedActionUrl = $action->getActionUrl();
         $actionType = $action->getActionType();
         $goals = $this->getGoalDefinitions($idSite);
+
         foreach ($goals as $goal) {
             $attribute = $goal['match_attribute'];
             // if the attribute to match is not the type of the current action
-            if (   (($attribute == 'url' || $attribute == 'title') && $actionType != Action::TYPE_PAGE_URL)
-                || ($attribute == 'file' && $actionType != Action::TYPE_DOWNLOAD)
-                || ($attribute == 'external_website' && $actionType != Action::TYPE_OUTLINK)
-                || ($attribute == 'manually')
-                || in_array($attribute, array('event_action', 'event_name', 'event_category')) && $actionType != Action::TYPE_EVENT
+            if ((($attribute == 'url' || $attribute == 'title') && $actionType != Action::TYPE_PAGE_URL)
+              || ($attribute == 'file' && $actionType != Action::TYPE_DOWNLOAD)
+              || ($attribute == 'external_website' && $actionType != Action::TYPE_OUTLINK)
+              || ($attribute == 'manually')
+              || in_array($attribute, array('event_action', 'event_name', 'event_category')) && $actionType != Action::TYPE_EVENT
             ) {
                 continue;
             }
@@ -169,23 +195,33 @@ class GoalManager
                 $this->convertedGoals[] = $goal;
             }
         }
+
         return count($this->convertedGoals) > 0;
     }
 
+    public function isManualGoalConversion()
+    {
+        return $this->idGoal > 0;
+    }
+
     public function detectGoalId($idSite)
     {
         if (!Common::isGoalPluginEnabled()) {
             return false;
         }
+
         $goals = $this->getGoalDefinitions($idSite);
+
         if (!isset($goals[$this->idGoal])) {
             return false;
         }
+
         $goal = $goals[$this->idGoal];
 
-        $url = $this->request->getParam('url');
+        $url         = $this->request->getParam('url');
         $goal['url'] = PageUrl::excludeQueryParametersFromUrl($url, $idSite);
         $this->convertedGoals[] = $goal;
+
         return true;
     }
 
@@ -199,18 +235,7 @@ class GoalManager
      */
     public function recordGoals(Visitor $visitor, $visitorInformation, $visitCustomVariables, $action)
     {
-        $goal = array(
-            'idvisit'     => $visitorInformation['idvisit'],
-            'idvisitor'   => $visitorInformation['idvisitor'],
-            'server_time' => Tracker::getDatetimeFromTimestamp($visitorInformation['visit_last_action_time'])
-        );
-
-        foreach (VisitDimension::getAllDimensions() as $dimension) {
-            $value = $dimension->onAnyGoalConversion($this->request, $visitor, $action);
-            if (false !== $value) {
-                $goal[$dimension->getColumnName()] = $value;
-            }
-        }
+        $goal = $this->getGoalFromVisitor($visitor, $visitorInformation, $action);
 
         // Copy Custom Variables from Visit row to the Goal conversion
         // Otherwise, set the Custom Variables found in the cookie sent with this request
@@ -249,6 +274,7 @@ class GoalManager
         if (round($revenue) == $revenue) {
             return $revenue;
         }
+
         return round($revenue, self::REVENUE_PRECISION);
     }
 
@@ -291,7 +317,8 @@ class GoalManager
 
         // INSERT or Sync items in the Cart / Order for this visit & order
         $items = $this->getEcommerceItemsFromRequest();
-        if ($items === false) {
+
+        if (false === $items) {
             return;
         }
 
@@ -303,12 +330,7 @@ class GoalManager
         $conversion['items'] = $itemsCount;
 
         if ($this->isThereExistingCartInVisit) {
-            $updateWhere = array(
-                'idvisit' => $visitInformation['idvisit'],
-                'idgoal'  => self::IDGOAL_CART,
-                'buster'  => 0,
-            );
-            $recorded = $this->updateExistingConversion($conversion, $updateWhere);
+            $recorded = $this->getModel()->updateConversion($visitInformation['idvisit'], self::IDGOAL_CART, $conversion);
         } else {
             $recorded = $this->insertNewConversion($conversion, $visitInformation);
         }
@@ -338,12 +360,15 @@ class GoalManager
     private function getEcommerceItemsFromRequest()
     {
         $items = Common::unsanitizeInputValue($this->request->getParam('ec_items'));
+
         if (empty($items)) {
             Common::printDebug("There are no Ecommerce items in the request");
             // we still record an Ecommerce order without any item in it
             return array();
         }
+
         $items = Common::json_decode($items, $assoc = true);
+
         if (!is_array($items)) {
             Common::printDebug("Error while json_decode the Ecommerce items = " . var_export($items, true));
             return false;
@@ -368,23 +393,11 @@ class GoalManager
             $itemInCartBySku[$item[0]] = $item;
         }
 
-        // Select all items currently in the Cart if any
-        $sql = "SELECT idaction_sku, idaction_name, idaction_category, idaction_category2, idaction_category3, idaction_category4, idaction_category5, price, quantity, deleted, idorder as idorder_original_value
-				FROM " . Common::prefixTable('log_conversion_item') . "
-				WHERE idvisit = ?
-					AND (idorder = ? OR idorder = ?)";
+        $itemsInDb = $this->getModel()->getAllItemsCurrentlyInTheCart($goal, self::ITEM_IDORDER_ABANDONED_CART);
 
-        $bind = array($goal['idvisit'],
-                      isset($goal['idorder']) ? $goal['idorder'] : self::ITEM_IDORDER_ABANDONED_CART,
-                      self::ITEM_IDORDER_ABANDONED_CART
-        );
-
-        $itemsInDb = Tracker::getDatabase()->fetchAll($sql, $bind);
-
-        Common::printDebug("Items found in current cart, for conversion_item (visit,idorder)=" . var_export($bind, true));
-        Common::printDebug($itemsInDb);
         // Look at which items need to be deleted, which need to be added or updated, based on the SKU
         $skuFoundInDb = $itemsToUpdate = array();
+
         foreach ($itemsInDb as $itemInDb) {
             $skuFoundInDb[] = $itemInDb['idaction_sku'];
 
@@ -435,27 +448,10 @@ class GoalManager
                 $itemsToInsert[] = $item;
             }
         }
+
         $this->insertEcommerceItems($goal, $itemsToInsert);
     }
 
-    // In the GET items parameter, each item has the following array of information
-    const INDEX_ITEM_SKU = 0;
-    const INDEX_ITEM_NAME = 1;
-    const INDEX_ITEM_CATEGORY = 2;
-    const INDEX_ITEM_PRICE = 3;
-    const INDEX_ITEM_QUANTITY = 4;
-
-    // Used in the array of items, internally to this class
-    const INTERNAL_ITEM_SKU = 0;
-    const INTERNAL_ITEM_NAME = 1;
-    const INTERNAL_ITEM_CATEGORY = 2;
-    const INTERNAL_ITEM_CATEGORY2 = 3;
-    const INTERNAL_ITEM_CATEGORY3 = 4;
-    const INTERNAL_ITEM_CATEGORY4 = 5;
-    const INTERNAL_ITEM_CATEGORY5 = 6;
-    const INTERNAL_ITEM_PRICE = 7;
-    const INTERNAL_ITEM_QUANTITY = 8;
-
     /**
      * Reads items from the request, then looks up the names from the lookup table
      * and returns a clean array of items ready for the database.
@@ -468,9 +464,10 @@ class GoalManager
         // Clean up the items array
         $cleanedItems = array();
         foreach ($items as $item) {
-            $name = $category = $category2 = $category3 = $category4 = $category5 = false;
-            $price = 0;
+            $name     = $category = $category2 = $category3 = $category4 = $category5 = false;
+            $price    = 0;
             $quantity = 1;
+
             // items are passed in the request as an array: ( $sku, $name, $category, $price, $quantity )
             if (empty($item[self::INDEX_ITEM_SKU])) {
                 continue;
@@ -562,6 +559,7 @@ class GoalManager
             $item[5] = $actionsLookedUp[$index * $columnsInEachRow + 5];
             $item[6] = $actionsLookedUp[$index * $columnsInEachRow + 6];
         }
+
         return $cleanedItems;
     }
 
@@ -579,29 +577,23 @@ class GoalManager
         if (empty($itemsToUpdate)) {
             return;
         }
+
         Common::printDebug("Goal data used to update ecommerce items:");
         Common::printDebug($goal);
 
         foreach ($itemsToUpdate as $item) {
             $newRow = $this->getItemRowEnriched($goal, $item);
             Common::printDebug($newRow);
-            $updateParts = $sqlBind = array();
-            foreach ($newRow as $name => $value) {
-                $updateParts[] = $name . " = ?";
-                $sqlBind[] = $value;
-            }
-            $sql = 'UPDATE ' . Common::prefixTable('log_conversion_item') . "
-					SET " . implode($updateParts, ', ') . "
-						WHERE idvisit = ?
-							AND idorder = ?
-							AND idaction_sku = ?";
-            $sqlBind[] = $newRow['idvisit'];
-            $sqlBind[] = $item['idorder_original_value'];
-            $sqlBind[] = $newRow['idaction_sku'];
-            Tracker::getDatabase()->query($sql, $sqlBind);
+
+            $this->getModel()->updateEcommerceItem($item['idorder_original_value'], $newRow);
         }
     }
 
+    private function getModel()
+    {
+        return new Model();
+    }
+
     /**
      * Inserts in the cart in the DB the new items
      * that were not previously in the cart
@@ -616,27 +608,17 @@ class GoalManager
         if (empty($itemsToInsert)) {
             return;
         }
+
         Common::printDebug("Ecommerce items that are added to the cart/order");
         Common::printDebug($itemsToInsert);
 
-        $sql = "INSERT INTO " . Common::prefixTable('log_conversion_item') . "
-					(idaction_sku, idaction_name, idaction_category, idaction_category2, idaction_category3, idaction_category4, idaction_category5, price, quantity, deleted,
-					idorder, idsite, idvisitor, server_time, idvisit)
-					VALUES ";
-        $i = 0;
-        $bind = array();
+        $items = array();
+
         foreach ($itemsToInsert as $item) {
-            if ($i > 0) {
-                $sql .= ',';
-            }
-            $newRow = array_values($this->getItemRowEnriched($goal, $item));
-            $sql .= " ( " . Common::getSqlStringFieldsArray($newRow) . " ) ";
-            $i++;
-            $bind = array_merge($bind, $newRow);
-        }
-        Tracker::getDatabase()->query($sql, $bind);
-        Common::printDebug($sql);
-        Common::printDebug($bind);
+            $items[] = $this->getItemRowEnriched($goal, $item);
+        }
+
+        $this->getModel()->createEcommerceItems($items);
     }
 
     protected function getItemRowEnriched($goal, $item)
@@ -685,7 +667,7 @@ class GoalManager
             Common::printDebug("- Goal " . $convertedGoal['idgoal'] . " matched. Recording...");
             $conversion = $goal;
             $conversion['idgoal'] = $convertedGoal['idgoal'];
-            $conversion['url'] = $convertedGoal['url'];
+            $conversion['url']    = $convertedGoal['url'];
 
             if (!is_null($action)) {
                 $conversion['idaction_url'] = $action->getIdActionUrl();
@@ -741,15 +723,9 @@ class GoalManager
         $newGoalDebug['idvisitor'] = bin2hex($newGoalDebug['idvisitor']);
         Common::printDebug($newGoalDebug);
 
-        $fields = implode(", ", array_keys($conversion));
-        $bindFields = Common::getSqlStringFieldsArray($conversion);
-        $sql = 'INSERT IGNORE INTO ' . Common::prefixTable('log_conversion') . "
-                ($fields) VALUES ($bindFields) ";
-        $bind = array_values($conversion);
-        $result = Tracker::getDatabase()->query($sql, $bind);
+        $wasInserted = $this->getModel()->createConversion($conversion);
 
-        // If a record was inserted, we return true
-        return Tracker::getDatabase()->rowCount($result) > 0;
+        return $wasInserted;
     }
 
     /**
@@ -772,30 +748,6 @@ class GoalManager
         );
     }
 
-    protected function updateExistingConversion($newGoal, $updateWhere)
-    {
-        $updateParts = $sqlBind = $updateWhereParts = array();
-        foreach ($newGoal as $name => $value) {
-            $updateParts[] = $name . " = ?";
-            $sqlBind[] = $value;
-        }
-        foreach ($updateWhere as $name => $value) {
-            $updateWhereParts[] = $name . " = ?";
-            $sqlBind[] = $value;
-        }
-        $sql = 'UPDATE  ' . Common::prefixTable('log_conversion') . "
-					SET " . implode($updateParts, ', ') . "
-						WHERE " . implode($updateWhereParts, ' AND ');
-
-        try {
-            Tracker::getDatabase()->query($sql, $sqlBind);
-        } catch(Exception $e){
-            Common::printDebug("There was an error while updating the Conversion: " . $e->getMessage());
-            return false;
-        }
-        return true;
-    }
-
     /**
      * @param $goal
      * @param $pattern_type
@@ -842,6 +794,7 @@ class GoalManager
                 throw new Exception(Piwik::translate('General_ExceptionInvalidGoalPattern', array($pattern_type)));
                 break;
         }
+
         return $match;
     }
 
@@ -859,7 +812,7 @@ class GoalManager
         foreach ($dimensions as $dimension) {
             $value = $dimension->$hook($this->request, $visitor, $action, $this);
 
-            if ($value !== false) {
+            if (false !== $value) {
                 $fieldName = $dimension->getColumnName();
                 $visitor->setVisitorColumn($fieldName, $value);
 
@@ -869,4 +822,24 @@ class GoalManager
 
         return $valuesToUpdate;
     }
+
+    private function getGoalFromVisitor(Visitor $visitor, $visitorInformation, $action)
+    {
+        $goal = array(
+            'idvisit'     => $visitorInformation['idvisit'],
+            'idvisitor'   => $visitorInformation['idvisitor'],
+            'server_time' => Tracker::getDatetimeFromTimestamp($visitorInformation['visit_last_action_time'])
+        );
+
+        $visitDimensions = VisitDimension::getAllDimensions();
+
+        foreach ($visitDimensions as $dimension) {
+            $value = $dimension->onAnyGoalConversion($this->request, $visitor, $action);
+            if (false !== $value) {
+                $goal[$dimension->getColumnName()] = $value;
+            }
+        }
+
+        return $goal;
+    }
 }
diff --git a/core/Tracker/Model.php b/core/Tracker/Model.php
new file mode 100644
index 0000000000000000000000000000000000000000..090cd8be596384c162eae09d14d8d03802928697
--- /dev/null
+++ b/core/Tracker/Model.php
@@ -0,0 +1,383 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Tracker;
+
+use Exception;
+use PDOStatement;
+use Piwik\Common;
+use Piwik\Tracker;
+use Piwik\Tracker\Db\DbException;
+
+class Model
+{
+
+    public function createAction($visitAction)
+    {
+        $fields = implode(", ", array_keys($visitAction));
+        $values = Common::getSqlStringFieldsArray($visitAction);
+        $table  = Common::prefixTable('log_link_visit_action');
+
+        $sql  = "INSERT INTO $table ($fields) VALUES ($values)";
+        $bind = array_values($visitAction);
+
+        $db = $this->getDb();
+        $db->query($sql, $bind);
+
+        $id = $db->lastInsertId();
+
+        return $id;
+    }
+
+    public function createConversion($conversion)
+    {
+        $fields     = implode(", ", array_keys($conversion));
+        $bindFields = Common::getSqlStringFieldsArray($conversion);
+        $table      = Common::prefixTable('log_conversion');
+
+        $sql    = "INSERT IGNORE INTO $table ($fields) VALUES ($bindFields) ";
+        $bind   = array_values($conversion);
+
+        $db     = $this->getDb();
+        $result = $db->query($sql, $bind);
+
+        // If a record was inserted, we return true
+        return $db->rowCount($result) > 0;
+    }
+
+    public function updateConversion($idVisit, $idGoal, $newConversion)
+    {
+        $updateWhere = array(
+            'idvisit' => $idVisit,
+            'idgoal'  => $idGoal,
+            'buster'  => 0,
+        );
+
+        $updateParts = $sqlBind = $updateWhereParts = array();
+
+        foreach ($newConversion as $name => $value) {
+            $updateParts[] = $name . " = ?";
+            $sqlBind[]     = $value;
+        }
+
+        foreach ($updateWhere as $name => $value) {
+            $updateWhereParts[] = $name . " = ?";
+            $sqlBind[]          = $value;
+        }
+
+        $parts = implode($updateParts, ', ');
+        $table = Common::prefixTable('log_conversion');
+
+        $sql   = "UPDATE $table SET $parts WHERE " . implode($updateWhereParts, ' AND ');
+
+        try {
+            $this->getDb()->query($sql, $sqlBind);
+        } catch(Exception $e){
+            Common::printDebug("There was an error while updating the Conversion: " . $e->getMessage());
+
+            return false;
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Loads the Ecommerce items from the request and records them in the DB
+     *
+     * @param array $goal
+     * @param int   $defaultIdOrder
+     * @throws Exception
+     * @return array
+     */
+    public function getAllItemsCurrentlyInTheCart($goal, $defaultIdOrder)
+    {
+        $sql = "SELECT idaction_sku, idaction_name, idaction_category, idaction_category2, idaction_category3, idaction_category4, idaction_category5, price, quantity, deleted, idorder as idorder_original_value
+				FROM " . Common::prefixTable('log_conversion_item') . "
+				WHERE idvisit = ? AND (idorder = ? OR idorder = ?)";
+
+        $bind = array(
+            $goal['idvisit'],
+            isset($goal['idorder']) ? $goal['idorder'] : $defaultIdOrder,
+            $defaultIdOrder
+        );
+
+        $itemsInDb = $this->getDb()->fetchAll($sql, $bind);
+
+        Common::printDebug("Items found in current cart, for conversion_item (visit,idorder)=" . var_export($bind, true));
+        Common::printDebug($itemsInDb);
+
+        return $itemsInDb;
+    }
+
+    public function createEcommerceItems($ecommerceItems)
+    {
+        $sql = "INSERT INTO " . Common::prefixTable('log_conversion_item');
+        $i    = 0;
+        $bind = array();
+
+        foreach ($ecommerceItems as $item) {
+
+            if ($i === 0) {
+                $fields = implode(', ', array_keys($item));
+                $sql   .= ' (' . $fields . ') VALUES ';
+            } elseif ($i > 0) {
+                $sql   .= ',';
+            }
+
+            $newRow = array_values($item);
+            $sql   .= " ( " . Common::getSqlStringFieldsArray($newRow) . " ) ";
+            $bind   = array_merge($bind, $newRow);
+            $i++;
+        }
+
+        $this->getDb()->query($sql, $bind);
+
+        Common::printDebug($sql);
+        Common::printDebug($bind);
+    }
+
+    public function createNewIdAction($name, $type, $urlPrefix)
+    {
+        $table = Common::prefixTable('log_action');
+        $sql   = "INSERT INTO $table (name, hash, type, url_prefix) VALUES (?,CRC32(?),?,?)";
+
+        $db = $this->getDb();
+        $db->query($sql, array($name, $name, $type, $urlPrefix));
+
+        $actionId = $db->lastInsertId();
+
+        return $actionId;
+    }
+
+    private function getSqlSelectActionId()
+    {
+        $sql = "SELECT idaction, type, name FROM " . Common::prefixTable('log_action')
+            . "  WHERE ( hash = CRC32(?) AND name = ? AND type = ? ) ";
+
+        return $sql;
+    }
+
+    public function getIdActionMatchingNameAndType($name, $type)
+    {
+        $sql  = $this->getSqlSelectActionId();
+        $bind = array($name, $name, $type);
+
+        $idAction = $this->getDb()->fetchOne($sql, $bind);
+
+        return $idAction;
+    }
+
+    public function getIdsAction($actionsNameAndType)
+    {
+        $sql  = $this->getSqlSelectActionId();
+        $bind = array();
+
+        $i = 0;
+        foreach ($actionsNameAndType as $actionNameType) {
+            $name = $actionNameType['name'];
+
+            if (empty($name)) {
+                continue;
+            }
+
+            if ($i > 0) {
+                $sql .= " OR ( hash = CRC32(?) AND name = ? AND type = ? ) ";
+            }
+
+            $bind[] = $name;
+            $bind[] = $name;
+            $bind[] = $actionNameType['type'];
+            $i++;
+        }
+
+        // Case URL & Title are empty
+        if (empty($bind)) {
+            return false;
+        }
+
+        $actionIds = $this->getDb()->fetchAll($sql, $bind);
+
+        return $actionIds;
+    }
+
+    public function updateEcommerceItem($originalIdOrder, $newItem)
+    {
+        $updateParts = $sqlBind = array();
+        foreach ($newItem as $name => $value) {
+            $updateParts[] = $name . " = ?";
+            $sqlBind[]     = $value;
+        }
+
+        $parts = implode($updateParts, ', ');
+        $table = Common::prefixTable('log_conversion_item');
+
+        $sql = "UPDATE $table SET $parts WHERE idvisit = ? AND idorder = ? AND idaction_sku = ?";
+
+        $sqlBind[] = $newItem['idvisit'];
+        $sqlBind[] = $originalIdOrder;
+        $sqlBind[] = $newItem['idaction_sku'];
+
+        $this->getDb()->query($sql, $sqlBind);
+    }
+
+    public function createVisit($visit)
+    {
+        $fields = array_keys($visit);
+        $fields = implode(", ", $fields);
+        $values = Common::getSqlStringFieldsArray($visit);
+        $table  = Common::prefixTable('log_visit');
+
+        $sql  = "INSERT INTO $table ($fields) VALUES ($values)";
+        $bind = array_values($visit);
+
+        $db = $this->getDb();
+        $db->query($sql, $bind);
+
+        return $db->lastInsertId();
+    }
+
+    public function updateVisit($idSite, $idVisit, $valuesToUpdate)
+    {
+        list($updateParts, $sqlBind) = $this->visitFieldsToQuery($valuesToUpdate);
+
+        $parts = implode($updateParts, ', ');
+        $table = Common::prefixTable('log_visit');
+
+        $sqlQuery = "UPDATE $table SET $parts WHERE idsite = ? AND idvisit = ?";
+
+        $sqlBind[] = $idSite;
+        $sqlBind[] = $idVisit;
+
+        $db          = $this->getDb();
+        $result      = $db->query($sqlQuery, $sqlBind);
+        $wasInserted = $db->rowCount($result) != 0;
+
+        if (!$wasInserted) {
+            Common::printDebug("Visitor with this idvisit wasn't found in the DB.");
+            Common::printDebug("$sqlQuery --- ");
+            Common::printDebug($sqlBind);
+        }
+
+        return $wasInserted;
+    }
+
+    public function findVisitor($idSite, $configId, $idVisitor, $fieldsToRead, $numCustomVarsToRead, $shouldMatchOneFieldOnly, $isVisitorIdToLookup, $timeLookBack, $timeLookAhead)
+    {
+        $selectCustomVariables = '';
+
+        if ($numCustomVarsToRead) {
+            for ($index = 1; $index <= $numCustomVarsToRead; $index++) {
+                $selectCustomVariables .= ', custom_var_k' . $index . ', custom_var_v' . $index;
+            }
+        }
+
+        $selectFields = implode(', ', $fieldsToRead);
+
+        $select = "SELECT $selectFields $selectCustomVariables ";
+        $from   = "FROM " . Common::prefixTable('log_visit');
+
+        // Two use cases:
+        // 1) there is no visitor ID so we try to match only on config_id (heuristics)
+        // 		Possible causes of no visitor ID: no browser cookie support, direct Tracking API request without visitor ID passed,
+        //        importing server access logs with import_logs.py, etc.
+        // 		In this case we use config_id heuristics to try find the visitor in tahhhe past. There is a risk to assign
+        // 		this page view to the wrong visitor, but this is better than creating artificial visits.
+        // 2) there is a visitor ID and we trust it (config setting trust_visitors_cookies, OR it was set using &cid= in tracking API),
+        //      and in these cases, we force to look up this visitor id
+        $whereCommon = "visit_last_action_time >= ? AND visit_last_action_time <= ? AND idsite = ?";
+        $bindSql = array(
+            $timeLookBack,
+            $timeLookAhead,
+            $idSite
+        );
+
+        if ($shouldMatchOneFieldOnly) {
+            if ($isVisitorIdToLookup) {
+                $whereCommon .= ' AND idvisitor = ?';
+                $bindSql[]    = $idVisitor;
+            } else {
+                $whereCommon .= ' AND config_id = ?';
+                $bindSql[]    = $configId;
+            }
+
+            $sql = "$select $from
+                    WHERE " . $whereCommon . "
+                    ORDER BY visit_last_action_time DESC
+                    LIMIT 1";
+        } // We have a config_id AND a visitor_id. We match on either of these.
+        // 		Why do we also match on config_id?
+        //		we do not trust the visitor ID only. Indeed, some browsers, or browser addons,
+        // 		cause the visitor id from the 1st party cookie to be different on each page view!
+        // 		It is not acceptable to create a new visit every time such browser does a page view,
+        // 		so we also backup by searching for matching config_id.
+        // We use a UNION here so that each sql query uses its own INDEX
+        else {
+            // will use INDEX index_idsite_config_datetime (idsite, config_id, visit_last_action_time)
+            $where       = ' AND config_id = ? AND user_id IS NULL ';
+            $bindSql[]   = $configId;
+            $sqlConfigId = "$select ,
+                0 as priority
+                $from
+                WHERE $whereCommon $where
+                ORDER BY visit_last_action_time DESC
+                LIMIT 1
+            ";
+            // will use INDEX index_idsite_idvisitor (idsite, idvisitor)
+            $bindSql[] = $timeLookBack;
+            $bindSql[] = $timeLookAhead;
+            $bindSql[] = $idSite;
+            $where     = ' AND idvisitor = ?';
+            $bindSql[] = $idVisitor;
+            $sqlVisitorId = "$select ,
+                1 as priority
+                $from
+                WHERE $whereCommon $where
+                ORDER BY visit_last_action_time DESC
+                LIMIT 1
+            ";
+
+            // We join both queries and favor the one matching the visitor_id if it did match
+            $sql = " ( $sqlConfigId )
+                UNION
+                ( $sqlVisitorId )
+                ORDER BY priority DESC
+                LIMIT 1";
+        }
+
+        $visitRow = $this->getDb()->fetch($sql, $bindSql);
+
+        return $visitRow;
+    }
+
+    private function visitFieldsToQuery($valuesToUpdate)
+    {
+        $updateParts = array();
+        $sqlBind     = array();
+
+        foreach ($valuesToUpdate as $name => $value) {
+            // Case where bind parameters don't work
+            if ($value === $name . ' + 1') {
+                //$name = 'visit_total_events'
+                //$value = 'visit_total_events + 1';
+                $updateParts[] = " $name = $value ";
+            } else {
+                $updateParts[] = $name . " = ?";
+                $sqlBind[]     = $value;
+            }
+        }
+
+        return array($updateParts, $sqlBind);
+    }
+
+    private function getDb()
+    {
+        return Tracker::getDatabase();
+    }
+
+}
diff --git a/core/Tracker/PageUrl.php b/core/Tracker/PageUrl.php
index 1d8486eda05788772a502a5c1657f558f9dca3a3..ae55b48aac3169e8abd3bb72e9131fdfe2e45831 100644
--- a/core/Tracker/PageUrl.php
+++ b/core/Tracker/PageUrl.php
@@ -49,17 +49,22 @@ class PageUrl
 
         if (empty($parsedUrl['query'])) {
             if (empty($parsedUrl['fragment'])) {
+
                 return UrlHelper::getParseUrlReverse($parsedUrl);
             }
+
             // Exclude from the hash tag as well
             $queryParameters = UrlHelper::getArrayFromQueryString($parsedUrl['fragment']);
             $parsedUrl['fragment'] = UrlHelper::getQueryStringWithExcludedParameters($queryParameters, $parametersToExclude);
             $url = UrlHelper::getParseUrlReverse($parsedUrl);
+
             return $url;
         }
+
         $queryParameters = UrlHelper::getArrayFromQueryString($parsedUrl['query']);
         $parsedUrl['query'] = UrlHelper::getQueryStringWithExcludedParameters($queryParameters, $parametersToExclude);
         $url = UrlHelper::getParseUrlReverse($parsedUrl);
+
         return $url;
     }
 
@@ -79,17 +84,15 @@ class PageUrl
         );
 
         $website = Cache::getCacheWebsiteAttributes($idSite);
-        $excludedParameters = isset($website['excluded_parameters'])
-            ? $website['excluded_parameters']
-            : array();
+        $excludedParameters = self::getExcludedParametersFromWebsite($website);
 
         if (!empty($excludedParameters)) {
             Common::printDebug('Excluding parameters "' . implode(',', $excludedParameters) . '" from URL');
         }
 
         $parametersToExclude = array_merge($excludedParameters,
-            self::$queryParametersToExclude,
-            $campaignTrackingParameters);
+                                           self::$queryParametersToExclude,
+                                           $campaignTrackingParameters);
 
         $parametersToExclude = array_map('strtolower', $parametersToExclude);
         return $parametersToExclude;
@@ -152,6 +155,7 @@ class PageUrl
         if (empty($parsedUrl)) {
             return $parsedUrl;
         }
+
         if (!empty($parsedUrl['host'])) {
             $parsedUrl['host'] = mb_strtolower($parsedUrl['host'], 'UTF-8');
         }
@@ -174,19 +178,24 @@ class PageUrl
     public static function convertMatrixUrl($originalUrl)
     {
         $posFirstSemiColon = strpos($originalUrl, ";");
-        if ($posFirstSemiColon === false) {
+
+        if (false === $posFirstSemiColon) {
             return $originalUrl;
         }
+
         $posQuestionMark = strpos($originalUrl, "?");
-        $replace = ($posQuestionMark === false);
+        $replace = (false === $posQuestionMark);
+
         if ($posQuestionMark > $posFirstSemiColon) {
             $originalUrl = substr_replace($originalUrl, ";", $posQuestionMark, 1);
             $replace = true;
         }
+
         if ($replace) {
             $originalUrl = substr_replace($originalUrl, "?", strpos($originalUrl, ";"), 1);
             $originalUrl = str_replace(";", "&", $originalUrl);
         }
+
         return $originalUrl;
     }
 
@@ -214,6 +223,7 @@ class PageUrl
                 $value = urlencode(mb_convert_encoding($decoded, 'UTF-8', $encoding));
             }
         }
+
         return $value;
     }
 
@@ -226,6 +236,7 @@ class PageUrl
                 $value = PageUrl::reencodeParameterValue($value, $encoding);
             }
         }
+
         return $queryParameters;
     }
 
@@ -247,12 +258,13 @@ class PageUrl
     {
         // if query params are encoded w/ non-utf8 characters (due to browser bug or whatever),
         // encode to UTF-8.
-        if ($encoding !== false
-            && strtolower($encoding) != 'utf-8'
+        if (false !== $encoding
+            && 'utf-8' != strtolower($encoding)
             && function_exists('mb_check_encoding')
         ) {
             $queryParameters = PageUrl::reencodeParametersArray($queryParameters, $encoding);
         }
+
         return $queryParameters;
     }
 
@@ -261,6 +273,7 @@ class PageUrl
         $url = Common::unsanitizeInputValue($url);
         $url = PageUrl::cleanupString($url);
         $url = PageUrl::convertMatrixUrl($url);
+
         return $url;
     }
 
@@ -274,6 +287,7 @@ class PageUrl
     public static function reconstructNormalizedUrl($url, $prefixId)
     {
         $map = array_flip(self::$urlPrefixMap);
+
         if ($prefixId !== null && isset($map[$prefixId])) {
             $fullUrl = $map[$prefixId] . $url;
         } else {
@@ -283,7 +297,8 @@ class PageUrl
         // Clean up host & hash tags, for URLs
         $parsedUrl = @parse_url($fullUrl);
         $parsedUrl = PageUrl::cleanupHostAndHashTag($parsedUrl);
-        $url = UrlHelper::getParseUrlReverse($parsedUrl);
+        $url       = UrlHelper::getParseUrlReverse($parsedUrl);
+
         if (!empty($url)) {
             return $url;
         }
@@ -302,12 +317,14 @@ class PageUrl
     {
         foreach (self::$urlPrefixMap as $prefix => $id) {
             if (strtolower(substr($url, 0, strlen($prefix))) == $prefix) {
+
                 return array(
                     'url'      => substr($url, strlen($prefix)),
                     'prefixId' => $id
                 );
             }
         }
+
         return array('url' => $url, 'prefixId' => null);
     }
 
@@ -317,10 +334,20 @@ class PageUrl
 
         if (!UrlHelper::isLookLikeUrl($url)) {
             Common::printDebug("WARNING: URL looks invalid and is discarded");
-            $url = false;
-            return $url;
+
+            return false;
         }
+
         return $url;
     }
+
+    private static function getExcludedParametersFromWebsite($website)
+    {
+        if (isset($website['excluded_parameters'])) {
+            return $website['excluded_parameters'];
+        }
+
+        return array();
+    }
 }
 
diff --git a/core/Tracker/Request.php b/core/Tracker/Request.php
index b34ee88709477a15245967d56b0705d5fe1d826f..212abbd0d2670d2c9a71322de4f79dd2935a97f0 100644
--- a/core/Tracker/Request.php
+++ b/core/Tracker/Request.php
@@ -138,10 +138,12 @@ class Request
         if (!$this->isTimestampValid($cookieFirstVisitTimestamp)) {
             $cookieFirstVisitTimestamp = $this->getCurrentTimestamp();
         }
+
         $daysSinceFirstVisit = round(($this->getCurrentTimestamp() - $cookieFirstVisitTimestamp) / 86400, $precision = 0);
         if ($daysSinceFirstVisit < 0) {
             $daysSinceFirstVisit = 0;
         }
+
         return $daysSinceFirstVisit;
     }
 
@@ -152,12 +154,14 @@ class Request
     {
         $daysSinceLastOrder = false;
         $lastOrderTimestamp = $this->getParam('_ects');
+
         if ($this->isTimestampValid($lastOrderTimestamp)) {
             $daysSinceLastOrder = round(($this->getCurrentTimestamp() - $lastOrderTimestamp) / 86400, $precision = 0);
             if ($daysSinceLastOrder < 0) {
                 $daysSinceLastOrder = 0;
             }
         }
+
         return $daysSinceLastOrder;
     }
 
@@ -168,12 +172,14 @@ class Request
     {
         $daysSinceLastVisit = 0;
         $lastVisitTimestamp = $this->getParam('_viewts');
+
         if ($this->isTimestampValid($lastVisitTimestamp)) {
             $daysSinceLastVisit = round(($this->getCurrentTimestamp() - $lastVisitTimestamp) / 86400, $precision = 0);
             if ($daysSinceLastVisit < 0) {
                 $daysSinceLastVisit = 0;
             }
         }
+
         return $daysSinceLastVisit;
     }
 
@@ -297,6 +303,7 @@ class Request
         if (!isset($supportedParams[$name])) {
             throw new Exception("Requested parameter $name is not a known Tracking API Parameter.");
         }
+
         $paramDefaultValue = $supportedParams[$name][0];
         $paramType = $supportedParams[$name][1];
 
@@ -318,7 +325,7 @@ class Request
     protected function isTimestampValid($time)
     {
         return $time <= $this->getCurrentTimestamp()
-        && $time > $this->getCurrentTimestamp() - 10 * 365 * 86400;
+            && $time > $this->getCurrentTimestamp() - 10 * 365 * 86400;
     }
 
     public function getIdSite()
@@ -338,9 +345,11 @@ class Request
          *                      request.
          */
         Piwik::postEvent('Tracker.Request.getIdSite', array(&$idSite, $this->params));
+
         if ($idSite <= 0) {
             throw new Exception('Invalid idSite: \'' . $idSite . '\'');
         }
+
         return $idSite;
     }
 
@@ -359,9 +368,11 @@ class Request
         }
 
         $customVar = Common::unsanitizeInputValues(Common::getRequestVar($parameter, '', 'json', $this->params));
+
         if (!is_array($customVar)) {
             return array();
         }
+
         $customVariables = array();
         $maxCustomVars = CustomVariables::getMaxCustomVariables();
         foreach ($customVar as $id => $keyValue) {
@@ -374,13 +385,14 @@ class Request
                 Common::printDebug("Invalid custom variables detected (id=$id)");
                 continue;
             }
+
             if (strlen($keyValue[1]) == 0) {
                 $keyValue[1] = "";
             }
             // We keep in the URL when Custom Variable have empty names
             // and values, as it means they can be deleted server side
 
-            $key = self::truncateCustomVariable($keyValue[0]);
+            $key   = self::truncateCustomVariable($keyValue[0]);
             $value = self::truncateCustomVariable($keyValue[1]);
             $customVariables['custom_var_k' . $id] = $key;
             $customVariables['custom_var_v' . $id] = $value;
@@ -407,6 +419,7 @@ class Request
         if (!$this->shouldUseThirdPartyCookie()) {
             return;
         }
+
         Common::printDebug("We manage the cookie...");
 
         $cookie = $this->makeThirdPartyCookie();
@@ -455,7 +468,7 @@ class Request
 
         // If User ID is set it takes precedence
         $userId = $this->getForcedUserId();
-        if($userId) {
+        if ($userId) {
             $userIdHashed = $this->getUserIdHashed($userId);
             $idVisitor = $this->truncateIdAsVisitorId($userIdHashed);
             Common::printDebug("Request will be recorded for this user_id = " . $userId . " (idvisitor = $idVisitor)");
@@ -502,6 +515,7 @@ class Request
                 return $binVisitorId;
             }
         }
+
         return false;
     }
 
@@ -512,6 +526,7 @@ class Request
         } else {
             $ipString = IP::getIpFromHeader();
         }
+
         $ip = IP::P2N($ipString);
         return $ip;
     }
@@ -536,10 +551,11 @@ class Request
     public function getForcedUserId()
     {
         $userId = $this->getParam('uid');
-        if(strlen($userId) > 0) {
+        if (strlen($userId) > 0) {
             return $userId;
         }
-        return null;
+
+        return false;
     }
 
     public function getForcedVisitorId()
@@ -572,6 +588,7 @@ class Request
         ) {
             return (int)$generationTime;
         }
+
         return false;
     }
 
@@ -590,8 +607,8 @@ class Request
      * @param $userId
      * @return string
      */
-    private function getUserIdHashed($userId)
+    public function getUserIdHashed($userId)
     {
-        return sha1($userId);
+        return substr( sha1( $userId ), 0, 16);
     }
 }
diff --git a/core/Tracker/TableLogAction.php b/core/Tracker/TableLogAction.php
index c547d742b80f87591c7cbaa13dbe3e5c6fb43d85..4f4849a3526baff23bfd4a1d6981c0061da3a230 100644
--- a/core/Tracker/TableLogAction.php
+++ b/core/Tracker/TableLogAction.php
@@ -36,34 +36,21 @@ class TableLogAction
     {
         // Add url prefix if not set
         foreach($actionsNameAndType as &$action) {
-            if(count($action) == 2) {
+            if (2 == count($action)) {
                 $action[] = null;
             }
         }
+
         $actionIds = self::queryIdsAction($actionsNameAndType);
 
         list($queriedIds, $fieldNamesToInsert) = self::processIdsToInsert($actionsNameAndType, $actionIds);
 
         $insertedIds = self::insertNewIdsAction($actionsNameAndType, $fieldNamesToInsert);
-
-        $queriedIds = $queriedIds + $insertedIds;
+        $queriedIds  = $queriedIds + $insertedIds;
 
         return $queriedIds;
     }
 
-    /**
-     * @param $name
-     * @param $type
-     * @return string
-     */
-    private static function getIdActionMatchingNameAndType($name, $type)
-    {
-        $sql = TableLogAction::getSqlSelectActionId();
-        $bind = array($name, $name, $type);
-        $idAction = \Piwik\Db::fetchOne($sql, $bind);
-        return $idAction;
-    }
-
     /**
      * @param $matchType
      * @param $actionType
@@ -75,6 +62,7 @@ class TableLogAction
         // now, we handle the cases =@ (contains) and !@ (does not contain)
         // build the expression based on the match type
         $sql = 'SELECT idaction FROM ' . Common::prefixTable('log_action') . ' WHERE %s AND type = ' . $actionType . ' )';
+
         switch ($matchType) {
             case '=@':
                 // use concat to make sure, no %s occurs because some plugins use %s in their sql
@@ -87,61 +75,45 @@ class TableLogAction
                 throw new \Exception("This match type $matchType is not available for action-segments.");
                 break;
         }
+
         $sql = sprintf($sql, $where);
-        return $sql;
-    }
 
-    private static function getSqlSelectActionId()
-    {
-        $sql = "SELECT idaction, type, name
-                        FROM " . Common::prefixTable('log_action')
-            . "  WHERE "
-            . "		( hash = CRC32(?) AND name = ? AND type = ? ) ";
         return $sql;
     }
 
     private static function insertNewIdsAction($actionsNameAndType, $fieldNamesToInsert)
     {
-        $sql = "INSERT INTO " . Common::prefixTable('log_action') .
-            "( name, hash, type, url_prefix ) VALUES (?,CRC32(?),?,?)";
         // Then, we insert all new actions in the lookup table
         $inserted = array();
+
         foreach ($fieldNamesToInsert as $fieldName) {
             list($name, $type, $urlPrefix) = $actionsNameAndType[$fieldName];
 
-            Tracker::getDatabase()->query($sql, array($name, $name, $type, $urlPrefix));
-            $actionId = Tracker::getDatabase()->lastInsertId();
-
-            $inserted[$fieldName] = $actionId;
+            $actionId = self::getModel()->createNewIdAction($name, $type, $urlPrefix);
 
             Common::printDebug("Recorded a new action (" . Action::getTypeAsString($type) . ") in the lookup table: " . $name . " (idaction = " . $actionId . ")");
+
+            $inserted[$fieldName] = $actionId;
         }
+
         return $inserted;
     }
 
+    private static function getModel()
+    {
+        return new Model();
+    }
+
     private static function queryIdsAction($actionsNameAndType)
     {
-        $sql = TableLogAction::getSqlSelectActionId();
-        $bind = array();
-        $i = 0;
+        $toQuery = array();
         foreach ($actionsNameAndType as &$actionNameType) {
             list($name, $type, $urlPrefix) = $actionNameType;
-            if (empty($name)) {
-                continue;
-            }
-            if ($i > 0) {
-                $sql .= " OR ( hash = CRC32(?) AND name = ? AND type = ? ) ";
-            }
-            $bind[] = $name;
-            $bind[] = $name;
-            $bind[] = $type;
-            $i++;
+            $toQuery[] = array('name' => $name, 'type' => $type);
         }
-        // Case URL & Title are empty
-        if (empty($bind)) {
-            return false;
-        }
-        $actionIds = Tracker::getDatabase()->fetchAll($sql, $bind);
+
+        $actionIds = self::getModel()->getIdsAction($toQuery);
+
         return $actionIds;
     }
 
@@ -150,6 +122,7 @@ class TableLogAction
         // For the Actions found in the lookup table, add the idaction in the array,
         // If not found in lookup table, queue for INSERT
         $fieldNamesToInsert = $fieldNameToActionId = array();
+
         foreach ($actionsNameAndType as $fieldName => &$actionNameType) {
             @list($name, $type, $urlPrefix) = $actionNameType;
             if (empty($name)) {
@@ -172,6 +145,7 @@ class TableLogAction
                 $fieldNamesToInsert[] = $fieldName;
             }
         }
+
         return array($fieldNameToActionId, $fieldNamesToInsert);
     }
 
@@ -197,12 +171,13 @@ class TableLogAction
             // for urls trim protocol and www because it is not recorded in the db
             $valueToMatch = preg_replace('@^http[s]?://(www\.)?@i', '', $valueToMatch);
         }
+
         $valueToMatch = Common::sanitizeInputValue(Common::unsanitizeInputValue($valueToMatch));
 
         if ($matchType == SegmentExpression::MATCH_EQUAL
             || $matchType == SegmentExpression::MATCH_NOT_EQUAL
         ) {
-            $idAction = self::getIdActionMatchingNameAndType($valueToMatch, $actionType);
+            $idAction = self::getModel()->getIdActionMatchingNameAndType($valueToMatch, $actionType);
             // if the action is not found, we hack -100 to ensure it tries to match against an integer
             // otherwise binding idaction_name to "false" returns some rows for some reasons (in case &segment=pageTitle==Větrnásssssss)
             if (empty($idAction)) {
@@ -214,6 +189,7 @@ class TableLogAction
         // "name contains $string" match can match several idaction so we cannot return yet an idaction
         // special case
         $sql = TableLogAction::getSelectQueryWhereNameContains($matchType, $actionType);
+
         return array(
             // mark that the returned value is an sql-expression instead of a literal value
             'SQL'  => $sql,
@@ -229,15 +205,16 @@ class TableLogAction
     private static function guessActionTypeFromSegment($segmentName)
     {
         $exactMatch = array(
-            'eventAction' => Action::TYPE_EVENT_ACTION,
-            'eventCategory' => Action::TYPE_EVENT_CATEGORY,
-            'eventName' => Action::TYPE_EVENT_NAME,
-            'contentPiece' => Action::TYPE_CONTENT_PIECE,
-            'contentTarget' => Action::TYPE_CONTENT_TARGET,
-            'contentName' => Action::TYPE_CONTENT_NAME,
+            'eventAction'        => Action::TYPE_EVENT_ACTION,
+            'eventCategory'      => Action::TYPE_EVENT_CATEGORY,
+            'eventName'          => Action::TYPE_EVENT_NAME,
+            'contentPiece'       => Action::TYPE_CONTENT_PIECE,
+            'contentTarget'      => Action::TYPE_CONTENT_TARGET,
+            'contentName'        => Action::TYPE_CONTENT_NAME,
             'contentInteraction' => Action::TYPE_CONTENT_INTERACTION,
         );
-        if(!empty($exactMatch[$segmentName])) {
+
+        if (!empty($exactMatch[$segmentName])) {
             return $exactMatch[$segmentName];
         }
 
diff --git a/core/Tracker/Visit.php b/core/Tracker/Visit.php
index 90b58a88b068e845a3f81b930b08d84b1cebf83a..0ce45c3659de613e5fa195c4b579123dd5287a5d 100644
--- a/core/Tracker/Visit.php
+++ b/core/Tracker/Visit.php
@@ -109,8 +109,9 @@ class Visit implements VisitInterface
         $visitIsConverted = false;
         $action = null;
 
-        $requestIsManualGoalConversion = ($this->goalManager->idGoal > 0);
+        $isManualGoalConversion = $this->goalManager->isManualGoalConversion();
         $requestIsEcommerce = $this->goalManager->requestIsEcommerce;
+
         if ($requestIsEcommerce) {
             $someGoalsConverted = true;
 
@@ -118,23 +119,26 @@ class Visit implements VisitInterface
             if ($this->goalManager->isGoalAnOrder()) {
                 $visitIsConverted = true;
             }
-        } // this request is from the JS call to piwikTracker.trackGoal()
-        elseif ($requestIsManualGoalConversion) {
+
+        } elseif ($isManualGoalConversion) {
+            // this request is from the JS call to piwikTracker.trackGoal()
             $someGoalsConverted = $this->goalManager->detectGoalId($this->request->getIdSite());
-            $visitIsConverted = $someGoalsConverted;
+            $visitIsConverted   = $someGoalsConverted;
+
             // if we find a idgoal in the URL, but then the goal is not valid, this is most likely a fake request
             if (!$someGoalsConverted) {
                 Common::printDebug('Invalid goal tracking request for goal id = ' . $this->goalManager->idGoal);
                 return;
             }
-        } // normal page view, potentially triggering a URL matching goal
-        else {
+
+        } else {
+            // normal page view, potentially triggering a URL matching goal
             $action = Action::factory($this->request);
 
             $action->writeDebugInfo();
 
             $someGoalsConverted = $this->goalManager->detectGoalsMatchingUrl($this->request->getIdSite(), $action);
-            $visitIsConverted = $someGoalsConverted;
+            $visitIsConverted   = $someGoalsConverted;
 
             $action->loadIdsFromLogActionTable();
         }
@@ -153,6 +157,7 @@ class Visit implements VisitInterface
         if (!$isLastActionInTheSameVisit) {
             Common::printDebug("Visitor detected, but last action was more than 30 minutes ago...");
         }
+
         // Known visit when:
         // ( - the visitor has the Piwik cookie with the idcookie ID used by Piwik to match the visitor
         //   OR
@@ -165,12 +170,15 @@ class Visit implements VisitInterface
         ) {
             $idReferrerActionUrl  = $this->visitorInfo['visit_exit_idaction_url'];
             $idReferrerActionName = $this->visitorInfo['visit_exit_idaction_name'];
+
             try {
                 $this->goalManager->detectIsThereExistingCartInVisit($this->visitorInfo);
                 $this->handleExistingVisit($visitor, $action, $visitIsConverted);
+
                 if (!is_null($action)) {
                     $action->record($visitor, $idReferrerActionUrl, $idReferrerActionName);
                 }
+
             } catch (VisitorNotFoundInDb $e) {
 
                 // There is an edge case when:
@@ -179,7 +187,7 @@ class Visit implements VisitInterface
                 //   because the UPDATE didn't affect any rows (one row was found, but not updated since no field changed)
                 // - the exception is caught here and will result in a new visit incorrectly
                 // In this case, we cancel the current conversion to be recorded:
-                if ($requestIsManualGoalConversion
+                if ($isManualGoalConversion
                     || $requestIsEcommerce
                 ) {
                     $someGoalsConverted = $visitIsConverted = false;
@@ -239,8 +247,7 @@ class Visit implements VisitInterface
 
         // TODO we should not have to sync this->visitorInfo and $visitor columns.
         // TODO it should be its own dimension
-        $this->visitorInfo['time_spent_ref_action'] = $this->getTimeSpentReferrerAction();
-        $visitor->setVisitorColumn('time_spent_ref_action', $this->visitorInfo['time_spent_ref_action']);
+        $this->setVisitorColumn($visitor, 'time_spent_ref_action', $this->getTimeSpentReferrerAction());
 
         // update visitorInfo
         foreach ($valuesToUpdate as $name => $value) {
@@ -262,8 +269,7 @@ class Visit implements VisitInterface
 
         $this->updateExistingVisit($valuesToUpdate);
 
-        $this->visitorInfo['visit_last_action_time'] = $this->request->getCurrentTimestamp();
-        $visitor->setVisitorColumn('visit_last_action_time', $this->visitorInfo['visit_last_action_time']);
+        $this->setVisitorColumn($visitor, 'visit_last_action_time', $this->request->getCurrentTimestamp());
     }
 
     /**
@@ -275,8 +281,8 @@ class Visit implements VisitInterface
         if ($timeSpent < 0) {
             $timeSpent = 0;
         }
-        $visitStandardLength = Config::getInstance()->Tracker['visit_standard_length'];
-        if($timeSpent > $visitStandardLength) {
+        $visitStandardLength = $this->getVisitStandardLength();
+        if ($timeSpent > $visitStandardLength) {
             $timeSpent = $visitStandardLength;
         }
         return $timeSpent;
@@ -297,15 +303,7 @@ class Visit implements VisitInterface
     {
         Common::printDebug("New Visit (IP = " . IP::N2P($this->getVisitorIp()) . ")");
 
-        $this->visitorInfo = $this->getNewVisitorInformation($visitor);
-
-        // Add Custom variable key,value to the visitor array
-        $this->visitorInfo = array_merge($this->visitorInfo, $this->visitorCustomVariables);
-
-        $visitor->clearVisitorInfo();
-        foreach ($this->visitorInfo as $key => $value) {
-            $visitor->setVisitorColumn($key, $value);
-        }
+        $this->setNewVisitorInformation($visitor);
 
         $dimensions = $this->getAllVisitDimensions();
 
@@ -329,15 +327,16 @@ class Visit implements VisitInterface
 
         $this->printVisitorInformation();
 
-        $idVisit = $this->insertNewVisit( $this->visitorInfo );
+        $idVisit = $this->insertNewVisit($this->visitorInfo);
 
-        $this->visitorInfo['idvisit'] = $idVisit;
-        $this->visitorInfo['visit_first_action_time'] = $this->request->getCurrentTimestamp();
-        $this->visitorInfo['visit_last_action_time'] = $this->request->getCurrentTimestamp();
+        $this->setVisitorColumn($visitor, 'idvisit', $idVisit);
+        $this->setVisitorColumn($visitor, 'visit_first_action_time', $this->request->getCurrentTimestamp());
+        $this->setVisitorColumn($visitor, 'visit_last_action_time', $this->request->getCurrentTimestamp());
+    }
 
-        $visitor->setVisitorColumn('idvisit', $this->visitorInfo['idvisit']);
-        $visitor->setVisitorColumn('visit_first_action_time', $this->visitorInfo['visit_first_action_time']);
-        $visitor->setVisitorColumn('visit_last_action_time', $this->visitorInfo['visit_last_action_time']);
+    private function getModel()
+    {
+        return new Model();
     }
 
     /**
@@ -353,7 +352,7 @@ class Visit implements VisitInterface
 
         // If the visitor had a first party ID cookie, then we use this value
         if (!empty($this->visitorInfo['idvisitor'])
-            && strlen($this->visitorInfo['idvisitor']) == Tracker::LENGTH_BINARY_ID
+            && Tracker::LENGTH_BINARY_ID == strlen($this->visitorInfo['idvisitor'])
         ) {
             return $this->visitorInfo['idvisitor'];
         }
@@ -366,8 +365,7 @@ class Visit implements VisitInterface
      */
     public static function generateUniqueVisitorId()
     {
-        $uniqueId = substr(Common::generateUniqId(), 0, Tracker::LENGTH_HEX_ID_STRING);
-        return $uniqueId;
+        return substr(Common::generateUniqId(), 0, Tracker::LENGTH_HEX_ID_STRING);
     }
 
     /**
@@ -387,9 +385,10 @@ class Visit implements VisitInterface
      */
     protected function getSettingsObject()
     {
-        if(is_null($this->userSettings)) {
+        if (is_null($this->userSettings)) {
             $this->userSettings = new Settings( $this->request, $this->getVisitorIp() );
         }
+
         return $this->userSettings;
     }
 
@@ -410,33 +409,26 @@ class Visit implements VisitInterface
     public static function isHostKnownAliasHost($urlHost, $idSite)
     {
         $websiteData = Cache::getCacheWebsiteAttributes($idSite);
+
         if (isset($websiteData['hosts'])) {
             $canonicalHosts = array();
             foreach ($websiteData['hosts'] as $host) {
-                $canonicalHosts[] = str_replace('www.', '', mb_strtolower($host, 'UTF-8'));
+                $canonicalHosts[] = self::toCanonicalHost($host);
             }
-            $canonicalHost = str_replace('www.', '', mb_strtolower($urlHost, 'UTF-8'));
+
+            $canonicalHost = self::toCanonicalHost($urlHost);
             if (in_array($canonicalHost, $canonicalHosts)) {
                 return true;
             }
         }
+
         return false;
     }
 
-    /**
-     * @return mixed
-     */
-    protected function insertNewVisit($visit)
+    private static function toCanonicalHost($host)
     {
-        $fields = implode(", ", array_keys($visit));
-        $values = Common::getSqlStringFieldsArray($visit);
-
-        $sql = "INSERT INTO " . Common::prefixTable('log_visit') . " ($fields) VALUES ($values)";
-        $bind = array_values($visit);
-        Tracker::getDatabase()->query($sql, $bind);
-
-        $idVisit = Tracker::getDatabase()->lastInsertId();
-        return $idVisit;
+        $hostLower = mb_strtolower($host, 'UTF-8');
+        return str_replace('www.', '', $hostLower);
     }
 
     /**
@@ -445,45 +437,32 @@ class Visit implements VisitInterface
      */
     protected function updateExistingVisit($valuesToUpdate)
     {
-        $sqlQuery = "UPDATE " . Common::prefixTable('log_visit') . "
-                    SET %s
-                    WHERE idsite = ?
-                        AND idvisit = ?";
-        // build sql query
-        $updateParts = $sqlBind = array();
-        foreach ($valuesToUpdate as $name => $value) {
-            // Case where bind parameters don't work
-            if(strpos($value, $name) !== false) {
-                //$name = 'visit_total_events'
-                //$value = 'visit_total_events + 1';
-                $updateParts[] = " $name = $value ";
-            } else {
-                $updateParts[] = $name . " = ?";
-                $sqlBind[] = $value;
-            }
-        }
-        $sqlQuery = sprintf($sqlQuery, implode($updateParts, ', ') );
-        array_push($sqlBind, $this->request->getIdSite(), (int)$this->visitorInfo['idvisit']);
+        $idSite  = $this->request->getIdSite();
+        $idVisit = (int) $this->visitorInfo['idvisit'];
 
-        $result = Tracker::getDatabase()->query($sqlQuery, $sqlBind);
+        $wasInserted = $this->getModel()->updateVisit($idSite, $idVisit, $valuesToUpdate);
 
         // Debug output
         if (isset($valuesToUpdate['idvisitor'])) {
             $valuesToUpdate['idvisitor'] = bin2hex($valuesToUpdate['idvisitor']);
         }
-        Common::printDebug('Updating existing visit: ' . var_export($valuesToUpdate, true));
 
-        if (Tracker::getDatabase()->rowCount($result) == 0) {
-            Common::printDebug("Visitor with this idvisit wasn't found in the DB.");
-            Common::printDebug("$sqlQuery --- ");
-            Common::printDebug($sqlBind);
+        if ($wasInserted) {
+            Common::printDebug('Updated existing visit: ' . var_export($valuesToUpdate, true));
+        } else {
             throw new VisitorNotFoundInDb(
                 "The visitor with idvisitor=" . bin2hex($this->visitorInfo['idvisitor']) . " and idvisit=" . $this->visitorInfo['idvisit']
                 . " wasn't found in the DB, we fallback to a new visitor");
         }
     }
 
-    protected function printVisitorInformation()
+    private function setVisitorColumn(Visitor $visitor, $key, $value)
+    {
+        $this->visitorInfo[$key] = $value;
+        $visitor->setVisitorColumn($key, $value);
+    }
+
+    private function printVisitorInformation()
     {
         $debugVisitInfo = $this->visitorInfo;
         $debugVisitInfo['idvisitor'] = bin2hex($debugVisitInfo['idvisitor']);
@@ -491,13 +470,22 @@ class Visit implements VisitInterface
         Common::printDebug($debugVisitInfo);
     }
 
-    protected function getNewVisitorInformation($visitor)
+    private function setNewVisitorInformation(Visitor $visitor)
     {
-        return array(
-            'idvisitor'   => $this->getVisitorIdcookie($visitor),
-            'config_id'   => $this->getSettingsObject()->getConfigId(),
-            'location_ip' => $this->getVisitorIp(),
-        );
+        $idVisitor = $this->getVisitorIdcookie($visitor);
+        $visitorIp = $this->getVisitorIp();
+        $configId  = $this->getSettingsObject()->getConfigId();
+
+        $this->visitorInfo = array();
+        $visitor->clearVisitorInfo();
+
+        $this->setVisitorColumn($visitor, 'idvisitor', $idVisitor);
+        $this->setVisitorColumn($visitor, 'config_id', $configId);
+        $this->setVisitorColumn($visitor, 'location_ip', $visitorIp);
+
+        foreach ($this->visitorCustomVariables as $key => $value) {
+            $this->setVisitorColumn($visitor, $key, $value);
+        }
     }
 
     /**
@@ -508,15 +496,11 @@ class Visit implements VisitInterface
      * @param $visitIsConverted
      * @return array
      */
-    protected function getExistingVisitFieldsToUpdate($visitor, $action, $visitIsConverted)
+    private function getExistingVisitFieldsToUpdate($visitor, $action, $visitIsConverted)
     {
         $valuesToUpdate = array();
 
-        // Might update the idvisitor when it was forced or overwritten for this visit
-        if (strlen($this->visitorInfo['idvisitor']) == Tracker::LENGTH_BINARY_ID) {
-            $valuesToUpdate['idvisitor'] = $this->visitorInfo['idvisitor'];
-            $visitor->setVisitorColumn('idvisitor', $this->visitorInfo['idvisitor']);
-        }
+        $valuesToUpdate = $this->setIdVisitorForExistingVisit($visitor, $valuesToUpdate);
 
         $dimensions     = $this->getAllVisitDimensions();
         $valuesToUpdate = $this->triggerHookOnDimensions($dimensions, 'onExistingVisit', $visitor, $action, $valuesToUpdate);
@@ -526,8 +510,7 @@ class Visit implements VisitInterface
         }
 
         // Custom Variables overwrite previous values on each page view
-        $valuesToUpdate = array_merge($valuesToUpdate, $this->visitorCustomVariables);
-        return $valuesToUpdate;
+        return array_merge($valuesToUpdate, $this->visitorCustomVariables);
     }
 
     /**
@@ -567,7 +550,44 @@ class Visit implements VisitInterface
         foreach($dimensions as $dimension) {
             $dimensionNames[] = $dimension->getColumnName();
         }
+
         Common::printDebug("Following dimensions have been collected from plugins: " . implode(", ", $dimensionNames));
+
         return $dimensions;
     }
+
+    private function getVisitStandardLength()
+    {
+        return Config::getInstance()->Tracker['visit_standard_length'];
+    }
+
+    /**
+     * @param $visitor
+     * @param $valuesToUpdate
+     * @return mixed
+     */
+    private function setIdVisitorForExistingVisit($visitor, $valuesToUpdate)
+    {
+        // Might update the idvisitor when it was forced or overwritten for this visit
+        if (strlen($this->visitorInfo['idvisitor']) == Tracker::LENGTH_BINARY_ID) {
+            $binIdVisitor = $this->visitorInfo['idvisitor'];
+            $visitor->setVisitorColumn('idvisitor', $binIdVisitor);
+            $valuesToUpdate['idvisitor'] = $binIdVisitor;
+        }
+
+        // User ID takes precedence and overwrites idvisitor value
+        $userId = $this->request->getForcedUserId();
+        if ($userId) {
+            $userIdHash   = $this->request->getUserIdHashed($userId);
+            $binIdVisitor = Common::hex2bin($userIdHash);
+            $visitor->setVisitorColumn('idvisitor', $binIdVisitor);
+            $valuesToUpdate['idvisitor'] = $binIdVisitor;
+        }
+        return $valuesToUpdate;
+    }
+
+    protected function insertNewVisit($visit)
+    {
+        return $this->getModel()->createVisit($visit);
+    }
 }
diff --git a/core/Tracker/VisitExcluded.php b/core/Tracker/VisitExcluded.php
index 586c874a0c74351f00289937e37fcb394eca900a..48eb1e3db75e72434ef30299ca9c0303d84b5a02 100644
--- a/core/Tracker/VisitExcluded.php
+++ b/core/Tracker/VisitExcluded.php
@@ -8,7 +8,6 @@
  */
 namespace Piwik\Tracker;
 
-use DeviceDetector\Parser\Bot;
 use Piwik\Common;
 use Piwik\Config;
 use Piwik\DeviceDetectorFactory;
@@ -27,16 +26,16 @@ class VisitExcluded
      */
     public function __construct(Request $request, $ip = false, $userAgent = false)
     {
-        if ($ip === false) {
+        if (false === $ip) {
             $ip = $request->getIp();
         }
 
-        if ($userAgent === false) {
+        if (false === $userAgent) {
             $userAgent = $request->getUserAgent();
         }
 
-        $this->request = $request;
-        $this->idSite = $request->getIdSite();
+        $this->request   = $request;
+        $this->idSite    = $request->getIdSite();
         $this->userAgent = $userAgent;
         $this->ip = $ip;
     }
@@ -200,6 +199,7 @@ class VisitExcluded
             Common::printDebug('Piwik ignore cookie was found, visit not tracked.');
             return true;
         }
+
         return false;
     }
 
@@ -211,12 +211,14 @@ class VisitExcluded
     protected function isVisitorIpExcluded()
     {
         $websiteAttributes = Cache::getCacheWebsiteAttributes($this->idSite);
+
         if (!empty($websiteAttributes['excluded_ips'])) {
             if (IP::isIpInRange($this->ip, $websiteAttributes['excluded_ips'])) {
                 Common::printDebug('Visitor IP ' . IP::N2P($this->ip) . ' is excluded from being tracked');
                 return true;
             }
         }
+
         return false;
     }
 
@@ -232,6 +234,7 @@ class VisitExcluded
     protected function isUserAgentExcluded()
     {
         $websiteAttributes = Cache::getCacheWebsiteAttributes($this->idSite);
+
         if (!empty($websiteAttributes['excluded_user_agents'])) {
             foreach ($websiteAttributes['excluded_user_agents'] as $excludedUserAgent) {
                 // if the excluded user agent string part is in this visit's user agent, this visit should be excluded
@@ -240,6 +243,7 @@ class VisitExcluded
                 }
             }
         }
+
         return false;
     }
 
@@ -254,12 +258,14 @@ class VisitExcluded
         $spamHosts = explode(",", $spamHosts);
 
         $referrerUrl = $this->request->getParam('urlref');
+
         foreach($spamHosts as $spamHost) {
-            if( strpos($referrerUrl, $spamHost) !== false) {
+            if ( strpos($referrerUrl, $spamHost) !== false) {
                 Common::printDebug('Referrer URL is a known spam: ' . $spamHost);
                 return true;
             }
         }
+
         return false;
     }
 }
diff --git a/core/Tracker/Visitor.php b/core/Tracker/Visitor.php
index b4120781516bc9ae02b536ea08b470bbe6241e4e..afec61849e74f42c0d445f151c5e368291d9ac19 100644
--- a/core/Tracker/Visitor.php
+++ b/core/Tracker/Visitor.php
@@ -25,9 +25,9 @@ class Visitor
     public function __construct(Request $request, $configId, $visitorInfo = array(), $customVariables = null)
     {
         $this->request = $request;
+        $this->configId = $configId;
         $this->visitorInfo = $visitorInfo;
         $this->customVariables = $customVariables;
-        $this->configId = $configId;
     }
 
     /**
@@ -41,119 +41,35 @@ class Visitor
     {
         $this->setIsVisitorKnown(false);
 
-        $configId = $this->configId;
-
+        $configId  = $this->configId;
+        $idSite    = $this->request->getIdSite();
         $idVisitor = $this->request->getVisitorId();
+
         $isVisitorIdToLookup = !empty($idVisitor);
 
         if ($isVisitorIdToLookup) {
             $this->visitorInfo['idvisitor'] = $idVisitor;
-            Common::printDebug("Matching visitors with: visitorId=" . bin2hex($this->visitorInfo['idvisitor']) . " OR configId=" . bin2hex($configId));
+            Common::printDebug("Matching visitors with: visitorId=" . bin2hex($idVisitor) . " OR configId=" . bin2hex($configId));
         } else {
             Common::printDebug("Visitor doesn't have the piwik cookie...");
         }
 
-        $selectCustomVariables = '';
-        // No custom var were found in the request, so let's copy the previous one in a potential conversion later
+        $numCustomVarsToRead = 0;
         if (!$this->customVariables) {
-            $maxCustomVariables = CustomVariables::getMaxCustomVariables();
-
-            for ($index = 1; $index <= $maxCustomVariables; $index++) {
-                $selectCustomVariables .= ', custom_var_k' . $index . ', custom_var_v' . $index;
-            }
+            // No custom var were found in the request, so let's copy the previous one in a potential conversion later
+            $numCustomVarsToRead = CustomVariables::getMaxCustomVariables();
         }
 
-        $persistedVisitAttributes = self::getVisitFieldsPersist();
-        array_unshift($persistedVisitAttributes, 'visit_first_action_time');
-        array_unshift($persistedVisitAttributes, 'visit_last_action_time');
-        $persistedVisitAttributes = array_unique($persistedVisitAttributes);
-
-        $selectFields = implode(", ", $persistedVisitAttributes);
-
-        $select = "SELECT
-                        $selectFields
-                        $selectCustomVariables
-        ";
-        $from = "FROM " . Common::prefixTable('log_visit');
-
+        $persistedVisitAttributes = $this->getVisitFieldsPersist();
+        $shouldMatchOneFieldOnly  = $this->shouldLookupOneVisitorFieldOnly($isVisitorIdToLookup);
         list($timeLookBack, $timeLookAhead) = $this->getWindowLookupThisVisit();
 
-        $shouldMatchOneFieldOnly = $this->shouldLookupOneVisitorFieldOnly($isVisitorIdToLookup);
-
-        // Two use cases:
-        // 1) there is no visitor ID so we try to match only on config_id (heuristics)
-        // 		Possible causes of no visitor ID: no browser cookie support, direct Tracking API request without visitor ID passed,
-        //        importing server access logs with import_logs.py, etc.
-        // 		In this case we use config_id heuristics to try find the visitor in tahhhe past. There is a risk to assign
-        // 		this page view to the wrong visitor, but this is better than creating artificial visits.
-        // 2) there is a visitor ID and we trust it (config setting trust_visitors_cookies, OR it was set using &cid= in tracking API),
-        //      and in these cases, we force to look up this visitor id
-        $whereCommon = "visit_last_action_time >= ? AND visit_last_action_time <= ? AND idsite = ?";
-        $bindSql = array(
-            $timeLookBack,
-            $timeLookAhead,
-            $this->request->getIdSite()
-        );
-
-        if ($shouldMatchOneFieldOnly) {
-            if ($isVisitorIdToLookup) {
-                $whereCommon .= ' AND idvisitor = ?';
-                $bindSql[] = $this->visitorInfo['idvisitor'];
-            } else {
-                $whereCommon .= ' AND config_id = ?';
-                $bindSql[] = $configId;
-            }
-
-            $sql = "$select
-            $from
-            WHERE " . $whereCommon . "
-            ORDER BY visit_last_action_time DESC
-            LIMIT 1";
-        } // We have a config_id AND a visitor_id. We match on either of these.
-        // 		Why do we also match on config_id?
-        //		we do not trust the visitor ID only. Indeed, some browsers, or browser addons,
-        // 		cause the visitor id from the 1st party cookie to be different on each page view!
-        // 		It is not acceptable to create a new visit every time such browser does a page view,
-        // 		so we also backup by searching for matching config_id.
-        // We use a UNION here so that each sql query uses its own INDEX
-        else {
-            // will use INDEX index_idsite_config_datetime (idsite, config_id, visit_last_action_time)
-            $where = ' AND config_id = ?';
-            $bindSql[] = $configId;
-            $sqlConfigId = "$select ,
-                0 as priority
-                $from
-                WHERE $whereCommon $where
-                ORDER BY visit_last_action_time DESC
-                LIMIT 1
-            ";
-            // will use INDEX index_idsite_idvisitor (idsite, idvisitor)
-            $bindSql[] = $timeLookBack;
-            $bindSql[] = $timeLookAhead;
-            $bindSql[] = $this->request->getIdSite();
-            $where = ' AND idvisitor = ?';
-            $bindSql[] = $this->visitorInfo['idvisitor'];
-            $sqlVisitorId = "$select ,
-                1 as priority
-                $from
-                WHERE $whereCommon $where
-                ORDER BY visit_last_action_time DESC
-                LIMIT 1
-            ";
-
-            // We join both queries and favor the one matching the visitor_id if it did match
-            $sql = " ( $sqlConfigId )
-                UNION
-                ( $sqlVisitorId )
-                ORDER BY priority DESC
-                LIMIT 1";
-        }
-
-        $visitRow = Tracker::getDatabase()->fetch($sql, $bindSql);
+        $model    = $this->getModel();
+        $visitRow = $model->findVisitor($idSite, $configId, $idVisitor, $persistedVisitAttributes, $numCustomVarsToRead, $shouldMatchOneFieldOnly, $isVisitorIdToLookup, $timeLookBack, $timeLookAhead);
 
         $isNewVisitForced = $this->request->getParam('new_visit');
         $isNewVisitForced = !empty($isNewVisitForced);
-        $enforceNewVisit = $isNewVisitForced || Config::getInstance()->Debug['tracker_always_new_visitor'];
+        $enforceNewVisit  = $isNewVisitForced || Config::getInstance()->Debug['tracker_always_new_visitor'];
 
         if (!$enforceNewVisit
             && $visitRow
@@ -161,17 +77,16 @@ class Visitor
         ) {
 
             // These values will be used throughout the request
-            foreach($persistedVisitAttributes as $field) {
+            foreach ($persistedVisitAttributes as $field) {
                 $this->visitorInfo[$field] = $visitRow[$field];
             }
 
-            $this->visitorInfo['visit_last_action_time'] = strtotime($visitRow['visit_last_action_time']);
+            $this->visitorInfo['visit_last_action_time']  = strtotime($visitRow['visit_last_action_time']);
             $this->visitorInfo['visit_first_action_time'] = strtotime($visitRow['visit_first_action_time']);
 
             // Custom Variables copied from Visit in potential later conversion
-            if (!empty($selectCustomVariables)) {
-                $maxCustomVariables = CustomVariables::getMaxCustomVariables();
-                for ($i = 1; $i <= $maxCustomVariables; $i++) {
+            if (!empty($numCustomVarsToRead)) {
+                for ($i = 1; $i <= $numCustomVarsToRead; $i++) {
                     if (isset($visitRow['custom_var_k' . $i])
                         && strlen($visitRow['custom_var_k' . $i])
                     ) {
@@ -192,7 +107,6 @@ class Visitor
                     last action = " . date("r", $this->visitorInfo['visit_last_action_time']) . ",
                     first action = " . date("r", $this->visitorInfo['visit_first_action_time']) . ",
                     visit_goal_buyer' = " . $this->visitorInfo['visit_goal_buyer'] . ")");
-            //Common::printDebug($this->visitorInfo);
         } else {
             Common::printDebug("The visitor was not matched with an existing visitor...");
         }
@@ -209,16 +123,16 @@ class Visitor
      */
     protected function getWindowLookupThisVisit()
     {
-        $visitStandardLength = Config::getInstance()->Tracker['visit_standard_length'];
+        $visitStandardLength    = Config::getInstance()->Tracker['visit_standard_length'];
         $lookBackNSecondsCustom = Config::getInstance()->Tracker['window_look_back_for_visitor'];
 
         $lookAheadNSeconds = $visitStandardLength;
-        $lookBackNSeconds = $visitStandardLength;
+        $lookBackNSeconds  = $visitStandardLength;
         if ($lookBackNSecondsCustom > $lookBackNSeconds) {
             $lookBackNSeconds = $lookBackNSecondsCustom;
         }
 
-        $timeLookBack = date('Y-m-d H:i:s', $this->request->getCurrentTimestamp() - $lookBackNSeconds);
+        $timeLookBack  = date('Y-m-d H:i:s', $this->request->getCurrentTimestamp() - $lookBackNSeconds);
         $timeLookAhead = date('Y-m-d H:i:s', $this->request->getCurrentTimestamp() + $lookAheadNSeconds);
 
         return array($timeLookBack, $timeLookAhead);
@@ -226,27 +140,38 @@ class Visitor
 
     protected function shouldLookupOneVisitorFieldOnly($isVisitorIdToLookup)
     {
+        $isForcedUserIdMustMatch = (false !== $this->request->getForcedUserId());
+
+        if ($isForcedUserIdMustMatch) {
+            // if &iud was set, we must try and match both idvisitor and config_id
+            return false;
+        }
+
         // This setting would be enabled for Intranet websites, to ensure that visitors using all the same computer config, same IP
         // are not counted as 1 visitor. In this case, we want to enforce and trust the visitor ID from the cookie.
         $trustCookiesOnly = Config::getInstance()->Tracker['trust_visitors_cookies'];
+        if ($isVisitorIdToLookup && $trustCookiesOnly) {
+            return true;
+        }
 
         // If a &cid= was set, we force to select this visitor (or create a new one)
         $isForcedVisitorIdMustMatch = ($this->request->getForcedVisitorId() != null);
 
-        // if &iud was set, we force to select this visitor (or create new one)
-        $isForcedUserIdMustMatch = ($this->request->getForcedUserId() !== null);
+        if ($isForcedVisitorIdMustMatch) {
+            return true;
+        }
 
-        $shouldMatchOneFieldOnly = (($isVisitorIdToLookup && $trustCookiesOnly)
-            || $isForcedVisitorIdMustMatch
-            || $isForcedUserIdMustMatch
-            || !$isVisitorIdToLookup);
-        return $shouldMatchOneFieldOnly;
+        if (!$isVisitorIdToLookup ) {
+            return true;
+        }
+
+        return false;
     }
 
     /**
      * @return array
      */
-    public static function getVisitFieldsPersist()
+    private function getVisitFieldsPersist()
     {
         $fields = array(
             'idvisitor',
@@ -296,6 +221,10 @@ class Visitor
          */
         Piwik::postEvent('Tracker.getVisitFieldsToPersist', array(&$fields));
 
+        array_unshift($fields, 'visit_first_action_time');
+        array_unshift($fields, 'visit_last_action_time');
+        $fields = array_unique($fields);
+
         return $fields;
     }
 
@@ -332,4 +261,9 @@ class Visitor
     {
         return $this->visitorKnown = $isVisitorKnown;
     }
+
+    private function getModel()
+    {
+        return new Model();
+    }
 }
diff --git a/core/Translate.php b/core/Translate.php
index 34bd35ba1223c8359deda10cdd737bee68f073a4..65381c0a2da811ec4d1144c1c275dfd3484b5a36 100644
--- a/core/Translate.php
+++ b/core/Translate.php
@@ -68,7 +68,7 @@ class Translate
 
     private static function loadCoreTranslationFile($language)
     {
-        if(empty($language)) {
+        if (empty($language)) {
             return;
         }
         $path = PIWIK_INCLUDE_PATH . '/lang/' . $language . '.json';
@@ -174,7 +174,7 @@ class Translate
         }
 
         $js = 'var translations = ' . Common::json_encode($clientSideTranslations) . ';';
-        $js .= "\n" . 'if(typeof(piwik_translations) == \'undefined\') { var piwik_translations = new Object; }' .
+        $js .= "\n" . 'if (typeof(piwik_translations) == \'undefined\') { var piwik_translations = new Object; }' .
             'for(var i in translations) { piwik_translations[i] = translations[i];} ';
         return $js;
     }
diff --git a/core/Translate/Validate/NoScripts.php b/core/Translate/Validate/NoScripts.php
index 0ee0fc9a57ca656b1cc5278bd323758a9082f223..e7f032ff55d2155d931b4607a7a3ef642be56b4b 100644
--- a/core/Translate/Validate/NoScripts.php
+++ b/core/Translate/Validate/NoScripts.php
@@ -28,12 +28,14 @@ class NoScripts extends ValidateAbstract
         // check if any translation contains restricted script tags
         $serializedStrings = serialize($translations);
         $invalids = array("<script", 'document.', 'javascript:', 'src=', 'background=', 'onload=');
+
         foreach ($invalids as $invalid) {
             if (stripos($serializedStrings, $invalid) !== false) {
                 $this->message = 'script tags restricted for language files';
                 return false;
             }
         }
+
         return true;
     }
 }
diff --git a/core/Translate/Writer.php b/core/Translate/Writer.php
index 617b8b95526a3994629ed47867e6456f9fc0f362..c43beca189934bcfd6db7c58044811440fe48b54 100644
--- a/core/Translate/Writer.php
+++ b/core/Translate/Writer.php
@@ -71,7 +71,7 @@ class Writer
     protected $filterMessages = array();
 
     const UNFILTERED = 'unfiltered';
-    const FILTERED = 'filtered';
+    const FILTERED   = 'filtered';
 
     protected $currentState = self::UNFILTERED;
 
@@ -152,12 +152,14 @@ class Writer
     public function getTranslations($lang)
     {
         $path = $this->getTranslationPathBaseDirectory('lang', $lang);
+
         if (!is_readable($path)) {
             return array();
         }
 
         $data = file_get_contents($path);
         $translations = json_decode($data, true);
+
         return $translations;
     }
 
diff --git a/core/Twig.php b/core/Twig.php
index b0707350c49d7d6626772509d56e3f96eaadd2d5..2e0ef95844671f3e65c11cf0abcc7701c852fd27 100755
--- a/core/Twig.php
+++ b/core/Twig.php
@@ -46,7 +46,7 @@ class Twig
 		$loaders = array();
 
 		//create loader for custom theme to overwrite twig templates
-		if($theme && $theme->getPluginName() != \Piwik\Plugin\Manager::DEFAULT_THEME) {
+		if ($theme && $theme->getPluginName() != \Piwik\Plugin\Manager::DEFAULT_THEME) {
 			$customLoader = $this->getCustomThemeLoader($theme);
 			if ($customLoader) {
 				//make it possible to overwrite plugin templates
@@ -187,7 +187,7 @@ class Twig
 	 * @return \Twig_Loader_Filesystem
 	 */
 	protected function getCustomThemeLoader(Plugin $theme){
-		if(!file_exists(sprintf("%s/plugins/%s/templates/", PIWIK_INCLUDE_PATH, $theme->getPluginName()))){
+		if (!file_exists(sprintf("%s/plugins/%s/templates/", PIWIK_INCLUDE_PATH, $theme->getPluginName()))){
 			return false;
 		}
 		$themeLoader = new Twig_Loader_Filesystem(array(
diff --git a/core/Unzip.php b/core/Unzip.php
index 5b5495c4e4f5ffdbb57b4a3263989696b29819d8..547a1a84a5a5dd06422b5920a9fd6aa90df58b69 100644
--- a/core/Unzip.php
+++ b/core/Unzip.php
@@ -4,19 +4,17 @@
  *
  * @link http://piwik.org
  * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
  */
 
 namespace Piwik;
 
-use Piwik\Unzip\Gzip;
-use Piwik\Unzip\PclZip;
-use Piwik\Unzip\Tar;
-use Piwik\Unzip\ZipArchive;
+use Piwik\Decompress\Gzip;
+use Piwik\Decompress\PclZip;
+use Piwik\Decompress\Tar;
+use Piwik\Decompress\ZipArchive;
 
 /**
- * Unzip wrapper around ZipArchive and PclZip
- *
+ * Factory for Decompress adapters.
  */
 class Unzip
 {
@@ -25,7 +23,7 @@ class Unzip
      *
      * @param string $name Name of unarchiver
      * @param string $filename Name of .zip archive
-     * @return \Piwik\Unzip\UncompressInterface
+     * @return \Piwik\Decompress\DecompressInterface
      */
     public static function factory($name, $filename)
     {
diff --git a/core/Unzip/Gzip.php b/core/Unzip/Gzip.php
deleted file mode 100755
index 16f08abf0ad5e83fd5c911cf710a6ead3d53769c..0000000000000000000000000000000000000000
--- a/core/Unzip/Gzip.php
+++ /dev/null
@@ -1,81 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-
-namespace Piwik\Unzip;
-
-/**
- * Unzip implementation for .gz files.
- *
- */
-class Gzip implements UncompressInterface
-{
-    /**
-     * Name of .gz file.
-     *
-     * @var string
-     */
-    private $filename = null;
-
-    /**
-     * Error string.
-     *
-     * @var string
-     */
-    private $error = null;
-
-    /**
-     * Constructor.
-     *
-     * @param string $filename Name of .gz file.
-     */
-    public function __construct($filename)
-    {
-        $this->filename = $filename;
-    }
-
-    /**
-     * Extracts the contents of the .gz file to $pathExtracted.
-     *
-     * @param string $pathExtracted Must be file, not directory.
-     * @return bool true if successful, false if otherwise.
-     */
-    public function extract($pathExtracted)
-    {
-        $file = gzopen($this->filename, 'r');
-        if ($file === false) {
-            $this->error = "gzopen failed";
-            return false;
-        }
-
-        $output = fopen($pathExtracted, 'w');
-        while (!feof($file)) {
-            fwrite($output, fread($file, 1024 * 1024));
-        }
-        fclose($output);
-
-        $success = gzclose($file);
-        if ($success === false) {
-            $this->error = "gzclose failed";
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Get error status string for the latest error.
-     *
-     * @return string
-     */
-    public function errorInfo()
-    {
-        return $this->error;
-    }
-}
-
diff --git a/core/Unzip/PclZip.php b/core/Unzip/PclZip.php
deleted file mode 100644
index b0ce4b3a75bb2269b64f5a3e25ebe2ba8bbbaa3c..0000000000000000000000000000000000000000
--- a/core/Unzip/PclZip.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Unzip;
-
-/**
- * @see libs/PclZip
- */
-require_once PIWIK_INCLUDE_PATH . '/libs/PclZip/pclzip.lib.php';
-
-/**
- * Unzip wrapper around PclZip
- *
- */
-class PclZip implements UncompressInterface
-{
-    /**
-     * @var PclZip
-     */
-    private $pclzip;
-    /**
-     * @var string
-     */
-    public $filename;
-
-    /**
-     * Constructor
-     *
-     * @param string $filename Name of the .zip archive
-     */
-    public function __construct($filename)
-    {
-        $this->pclzip = new \PclZip($filename);
-        $this->filename = $filename;
-    }
-
-    /**
-     * Extract files from archive to target directory
-     *
-     * @param string $pathExtracted Absolute path of target directory
-     * @return mixed  Array of filenames if successful; or 0 if an error occurred
-     */
-    public function extract($pathExtracted)
-    {
-        $pathExtracted = str_replace('\\', '/', $pathExtracted);
-        $list = $this->pclzip->listContent();
-        if (empty($list)) {
-            return 0;
-        }
-
-        foreach ($list as $entry) {
-            $filename = str_replace('\\', '/', $entry['stored_filename']);
-            $parts = explode('/', $filename);
-
-            if (!strncmp($filename, '/', 1) ||
-                array_search('..', $parts) !== false ||
-                strpos($filename, ':') !== false
-            ) {
-                return 0;
-            }
-        }
-
-        // PCLZIP_CB_PRE_EXTRACT callback returns 0 to skip, 1 to resume, or 2 to abort
-        return $this->pclzip->extract(
-            PCLZIP_OPT_PATH, $pathExtracted,
-            PCLZIP_OPT_STOP_ON_ERROR,
-            PCLZIP_OPT_REPLACE_NEWER,
-            PCLZIP_CB_PRE_EXTRACT, function ($p_event, &$p_header) use ($pathExtracted) {
-                return strncmp($p_header['filename'], $pathExtracted, strlen($pathExtracted)) ? 0 : 1;
-            }
-        );
-    }
-
-    /**
-     * Get error status string for the latest error
-     *
-     * @return string
-     */
-    public function errorInfo()
-    {
-        return $this->pclzip->errorInfo(true);
-    }
-}
diff --git a/core/Unzip/Tar.php b/core/Unzip/Tar.php
deleted file mode 100755
index 2c87882611cd884bae3536112fea7e846f369b2e..0000000000000000000000000000000000000000
--- a/core/Unzip/Tar.php
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Unzip;
-
-use Archive_Tar;
-
-/**
- * @see libs/Archive_Tar
- */
-require_once PIWIK_INCLUDE_PATH . '/libs/Archive_Tar/Tar.php';
-
-/**
- * Unzip implementation for Archive_Tar PEAR lib.
- *
- */
-class Tar implements UncompressInterface
-{
-    /**
-     * Archive_Tar instance.
-     *
-     * @var Archive_Tar
-     */
-    private $tarArchive = null;
-
-    /**
-     * Constructor.
-     *
-     * @param string $filename Path to tar file.
-     * @param string|null $compression Either 'gz', 'bz2' or null for no compression.
-     */
-    public function __construct($filename, $compression = null)
-    {
-        $this->tarArchive = new Archive_Tar($filename, $compression);
-    }
-
-    /**
-     * Extracts the contents of the tar file to $pathExtracted.
-     *
-     * @param string $pathExtracted Directory to extract into.
-     * @return bool true if successful, false if otherwise.
-     */
-    public function extract($pathExtracted)
-    {
-        return $this->tarArchive->extract($pathExtracted);
-    }
-
-    /**
-     * Extracts one file held in a tar archive and returns the deflated file
-     * as a string.
-     *
-     * @param string $inArchivePath Path to file in the tar archive.
-     * @return bool true if successful, false if otherwise.
-     */
-    public function extractInString($inArchivePath)
-    {
-        return $this->tarArchive->extractInString($inArchivePath);
-    }
-
-    /**
-     * Lists the files held in the tar archive.
-     *
-     * @return array List of paths describing everything held in the tar archive.
-     */
-    public function listContent()
-    {
-        return $this->tarArchive->listContent();
-    }
-
-    /**
-     * Get error status string for the latest error.
-     *
-     * @return string
-     */
-    public function errorInfo()
-    {
-        return $this->tarArchive->error_object->getMessage();
-    }
-}
diff --git a/core/Unzip/UncompressInterface.php b/core/Unzip/UncompressInterface.php
deleted file mode 100644
index 072f476bb4291636929d9688d65c43e99ef65fbb..0000000000000000000000000000000000000000
--- a/core/Unzip/UncompressInterface.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-
-namespace Piwik\Unzip;
-
-/**
- * Unzip interface
- *
- */
-interface UncompressInterface
-{
-    /**
-     * Constructor
-     *
-     * @param string $filename Name of the .zip archive
-     */
-    public function __construct($filename);
-
-    /**
-     * Extract files from archive to target directory
-     *
-     * @param string $pathExtracted Absolute path of target directory
-     * @return mixed  Array of filenames if successful; or 0 if an error occurred
-     */
-    public function extract($pathExtracted);
-
-    /**
-     * Get error status string for the latest error
-     *
-     * @return string
-     */
-    public function errorInfo();
-}
diff --git a/core/Unzip/ZipArchive.php b/core/Unzip/ZipArchive.php
deleted file mode 100644
index c8d7edd87443f143c40dcd0827aadabc889148ea..0000000000000000000000000000000000000000
--- a/core/Unzip/ZipArchive.php
+++ /dev/null
@@ -1,133 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Unzip;
-
-use Exception;
-
-/**
- * Unzip wrapper around ZipArchive
- *
- */
-class ZipArchive implements UncompressInterface
-{
-    /**
-     * @var \ZipArchive
-     */
-    private $ziparchive;
-    /**
-     * @var string
-     */
-    public $filename;
-
-    /**
-     * Constructor
-     *
-     * @param string $filename Name of the .zip archive
-     * @throws Exception
-     */
-    public function __construct($filename)
-    {
-        $this->filename = $filename;
-        $this->ziparchive = new \ZipArchive;
-        if ($this->ziparchive->open($filename) !== true) {
-            throw new Exception('Error opening ' . $filename);
-        }
-    }
-
-    /**
-     * Extract files from archive to target directory
-     *
-     * @param string $pathExtracted Absolute path of target directory
-     * @return mixed  Array of filenames if successful; or 0 if an error occurred
-     */
-    public function extract($pathExtracted)
-    {
-        if (substr($pathExtracted, -1) !== '/') {
-            $pathExtracted .= '/';
-        }
-
-        $fileselector = array();
-        $list = array();
-        $count = $this->ziparchive->numFiles;
-        if ($count === 0) {
-            return 0;
-        }
-
-        for ($i = 0; $i < $count; $i++) {
-            $entry = $this->ziparchive->statIndex($i);
-
-            $filename = str_replace('\\', '/', $entry['name']);
-            $parts = explode('/', $filename);
-
-            if (!strncmp($filename, '/', 1) ||
-                array_search('..', $parts) !== false ||
-                strpos($filename, ':') !== false
-            ) {
-                return 0;
-            }
-            $fileselector[] = $entry['name'];
-            $list[] = array(
-                'filename'        => $pathExtracted . $entry['name'],
-                'stored_filename' => $entry['name'],
-                'size'            => $entry['size'],
-                'compressed_size' => $entry['comp_size'],
-                'mtime'           => $entry['mtime'],
-                'index'           => $i,
-                'crc'             => $entry['crc'],
-            );
-        }
-
-        $res = $this->ziparchive->extractTo($pathExtracted, $fileselector);
-        if ($res === false)
-            return 0;
-        return $list;
-    }
-
-    /**
-     * Get error status string for the latest error
-     *
-     * @return string
-     */
-    public function errorInfo()
-    {
-        static $statusStrings = array(
-            \ZipArchive::ER_OK          => 'No error',
-            \ZipArchive::ER_MULTIDISK   => 'Multi-disk zip archives not supported',
-            \ZipArchive::ER_RENAME      => 'Renaming temporary file failed',
-            \ZipArchive::ER_CLOSE       => 'Closing zip archive failed',
-            \ZipArchive::ER_SEEK        => 'Seek error',
-            \ZipArchive::ER_READ        => 'Read error',
-            \ZipArchive::ER_WRITE       => 'Write error',
-            \ZipArchive::ER_CRC         => 'CRC error',
-            \ZipArchive::ER_ZIPCLOSED   => 'Containing zip archive was closed',
-            \ZipArchive::ER_NOENT       => 'No such file',
-            \ZipArchive::ER_EXISTS      => 'File already exists',
-            \ZipArchive::ER_OPEN        => 'Can\'t open file',
-            \ZipArchive::ER_TMPOPEN     => 'Failure to create temporary file',
-            \ZipArchive::ER_ZLIB        => 'Zlib error',
-            \ZipArchive::ER_MEMORY      => 'Malloc failure',
-            \ZipArchive::ER_CHANGED     => 'Entry has been changed',
-            \ZipArchive::ER_COMPNOTSUPP => 'Compression method not supported',
-            \ZipArchive::ER_EOF         => 'Premature EOF',
-            \ZipArchive::ER_INVAL       => 'Invalid argument',
-            \ZipArchive::ER_NOZIP       => 'Not a zip archive',
-            \ZipArchive::ER_INTERNAL    => 'Internal error',
-            \ZipArchive::ER_INCONS      => 'Zip archive inconsistent',
-            \ZipArchive::ER_REMOVE      => 'Can\'t remove file',
-            \ZipArchive::ER_DELETED     => 'Entry has been deleted',
-        );
-
-        if (isset($statusStrings[$this->ziparchive->status])) {
-            $statusString = $statusStrings[$this->ziparchive->status];
-        } else {
-            $statusString = 'Unknown status';
-        }
-        return $statusString . '(' . $this->ziparchive->status . ')';
-    }
-}
diff --git a/core/UpdateCheck.php b/core/UpdateCheck.php
index 228ac23a856d45bbfffb0a3a8fa4b73d88d0b8ac..43639da9dc10fbf4099cc416040ed005403417ec 100644
--- a/core/UpdateCheck.php
+++ b/core/UpdateCheck.php
@@ -36,7 +36,7 @@ class UpdateCheck
      */
     public static function check($force = false, $interval = null)
     {
-        if(!self::isAutoUpdateEnabled()) {
+        if (!self::isAutoUpdateEnabled()) {
             return;
         }
 
diff --git a/core/Updater.php b/core/Updater.php
index 1527da723a9ec778daa025c994a5e1cc14969915..0069d1b71bcddcb70b1ced4256e52eeb101f5017 100644
--- a/core/Updater.php
+++ b/core/Updater.php
@@ -355,6 +355,7 @@ class Updater
      * @param string $updateSql Update SQL query.
      * @param int|false $errorToIgnore A MySQL error code to ignore.
      * @param string $file The Update file that's calling this method.
+     * @throws UpdaterErrorException
      */
     public static function handleQueryError($e, $updateSql, $errorToIgnore, $file)
     {
@@ -371,6 +372,7 @@ class Updater
      *
      * @param int $error
      * @param int|int[] $errorCodesToIgnore
+     * @return boolean
      */
     public static function isDbErrorOneOf($error, $errorCodesToIgnore)
     {
diff --git a/core/Updates/0.2.34.php b/core/Updates/0.2.34.php
deleted file mode 100644
index 5bdf982d8c0bf43a0af1ac0d5dbae535c48e2b8a..0000000000000000000000000000000000000000
--- a/core/Updates/0.2.34.php
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-
-namespace Piwik\Updates;
-
-use Piwik\Piwik;
-use Piwik\Plugins\SitesManager\API;
-use Piwik\Tracker\Cache;
-use Piwik\Updates;
-
-/**
- */
-class Updates_0_2_34 extends Updates
-{
-    static function update()
-    {
-        // force regeneration of cache files following #648
-        Piwik::setUserHasSuperUserAccess();
-        $allSiteIds = API::getInstance()->getAllSitesId();
-        Cache::regenerateCacheWebsiteAttributes($allSiteIds);
-    }
-}
diff --git a/core/Updates/0.6.2.php b/core/Updates/0.6.2.php
deleted file mode 100644
index 0fd9651736c9e4a87cfc946f3560994e4bb98986..0000000000000000000000000000000000000000
--- a/core/Updates/0.6.2.php
+++ /dev/null
@@ -1,47 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-
-namespace Piwik\Updates;
-
-use Piwik\Filesystem;
-use Piwik\Piwik;
-use Piwik\Plugins\SitesManager\API;
-use Piwik\Tracker\Cache;
-use Piwik\Updates;
-
-/**
- */
-class Updates_0_6_2 extends Updates
-{
-    static function update()
-    {
-        $obsoleteFiles = array(
-            PIWIK_INCLUDE_PATH . '/core/Db/Mysqli.php',
-        );
-        foreach ($obsoleteFiles as $obsoleteFile) {
-            if (file_exists($obsoleteFile)) {
-                @unlink($obsoleteFile);
-            }
-        }
-
-        $obsoleteDirectories = array(
-            PIWIK_INCLUDE_PATH . '/core/Db/Pdo',
-        );
-        foreach ($obsoleteDirectories as $dir) {
-            if (file_exists($dir)) {
-                Filesystem::unlinkRecursive($dir, true);
-            }
-        }
-
-        // force regeneration of cache files
-        Piwik::setUserHasSuperUserAccess();
-        $allSiteIds = API::getInstance()->getAllSitesId();
-        Cache::regenerateCacheWebsiteAttributes($allSiteIds);
-    }
-}
diff --git a/core/Updates/2.0-a17.php b/core/Updates/2.0-a17.php
index 2df452c1abed5fb9a173b798b757f4ace9c56f88..5d6514359629472cfafe197e11d502f28b695b75 100644
--- a/core/Updates/2.0-a17.php
+++ b/core/Updates/2.0-a17.php
@@ -35,7 +35,7 @@ class Updates_2_0_a17 extends Updates
             }
 
         }
-        if(!empty($errors)) {
+        if (!empty($errors)) {
             throw new \Exception("Warnings during the update: <br>" . implode("<br>", $errors));
         }
    }
diff --git a/core/Updates/2.0-b13.php b/core/Updates/2.0-b13.php
index 78cc791566ada02b4b514b73b2138e51c9cd3b3b..a5e9546b9065247020d29258fa49899251572071 100644
--- a/core/Updates/2.0-b13.php
+++ b/core/Updates/2.0-b13.php
@@ -35,7 +35,7 @@ class Updates_2_0_b13 extends Updates
             }
 
         }
-        if(!empty($errors)) {
+        if (!empty($errors)) {
             throw new \Exception("Warnings during the update: <br>" . implode("<br>", $errors));
         }
    }
diff --git a/core/Updates/2.0.3-b7.php b/core/Updates/2.0.3-b7.php
index f3fa6a34aac4288d9ff75eb461c413148607094c..add119e462cb16bcbe11f340ecc5bb73ae1033d1 100644
--- a/core/Updates/2.0.3-b7.php
+++ b/core/Updates/2.0.3-b7.php
@@ -56,7 +56,7 @@ class Updates_2_0_3_b7 extends Updates
             }
 
         }
-        if(!empty($errors)) {
+        if (!empty($errors)) {
             throw new \Exception("Warnings during the update: <br>" . implode("<br>", $errors));
         }
     }
diff --git a/core/Updates/2.1.1-b11.php b/core/Updates/2.1.1-b11.php
index 45b781a1cf868e8c945b5cfbe9725493055622ae..3fa0364e73d4026a103945a96bade144de636050 100644
--- a/core/Updates/2.1.1-b11.php
+++ b/core/Updates/2.1.1-b11.php
@@ -41,17 +41,14 @@ class Updates_2_1_1_b11 extends Updates
         // returning visit segment
         foreach ($archiveNumericTables as $table) {
             // get archives w/ *._returning
-            $sql = "SELECT idarchive, idsite, period, date1, date2
-                      FROM $table
-                     WHERE name IN ('" . implode("','", $returningMetrics) . "')
-                  GROUP BY idarchive";
+            $sql = "SELECT idarchive, idsite, period, date1, date2 FROM $table
+                    WHERE name IN ('" . implode("','", $returningMetrics) . "')
+                    GROUP BY idarchive";
             $idArchivesWithReturning = Db::fetchAll($sql);
 
             // get archives for visitssummary returning visitor segment
-            $sql = "SELECT idarchive, idsite, period, date1, date2
-                      FROM $table
-                     WHERE name = ?
-                  GROUP BY idarchive";
+            $sql = "SELECT idarchive, idsite, period, date1, date2 FROM $table
+                    WHERE name = ?  GROUP BY idarchive";
             $visitSummaryReturningSegmentDone = Rules::getDoneFlagArchiveContainsOnePlugin(
                 new Segment(VisitFrequencyApi::RETURNING_VISITOR_SEGMENT, $idSites = array()), 'VisitsSummary');
             $idArchivesWithVisitReturningSegment = Db::fetchAll($sql, array($visitSummaryReturningSegmentDone));
diff --git a/core/Updates/2.4.0-b1.php b/core/Updates/2.4.0-b1.php
index a0f6d64f65984f036ec2628d61af78d357305c29..cc0d615d54317f16e1a485ddbb6b2805b30a9c03 100644
--- a/core/Updates/2.4.0-b1.php
+++ b/core/Updates/2.4.0-b1.php
@@ -8,9 +8,6 @@
  */
 namespace Piwik\Updates;
 
-use Faker\Provider\File;
-use Piwik\Filesystem;
-use Piwik\Plugins\Installation\ServerFilesGenerator;
 use Piwik\Updates;
 
 class Updates_2_4_0_b1 extends Updates
diff --git a/core/Url.php b/core/Url.php
index 32ea140f2079f3c3a1365ca3d6b313ba36b7e195..1ed77f5fa5033a9e38f449fffbad36d16f867b26 100644
--- a/core/Url.php
+++ b/core/Url.php
@@ -10,12 +10,7 @@ namespace Piwik;
 
 use Exception;
 
-use Piwik\Config;
-use Piwik\Common;
-use Piwik\IP;
-use Piwik\ProxyHttp;
 use Piwik\Session;
-use Piwik\UrlHelper;
 
 /**
  * Provides URL related helper methods.
@@ -232,18 +227,18 @@ class Url
 
         $trustedHosts = self::getTrustedHosts();
 
+        // Only punctuation we allow is '[', ']', ':', '.', '_' and '-'
+        $hostLength = strlen($host);
+        if ($hostLength !== strcspn($host, '`~!@#$%^&*()+={}\\|;"\'<>,?/ ')) {
+            return false;
+        }
+
         // if no trusted hosts, just assume it's valid
         if (empty($trustedHosts)) {
             self::saveTrustedHostnameInConfig($host);
             return true;
         }
 
-        // Only punctuation we allow is '[', ']', ':', '.' and '-'
-        $hostLength = strlen($host);
-        if ($hostLength !== strcspn($host, '`~!@#$%^&*()_+={}\\|;"\'<>,?/ ')) {
-            return false;
-        }
-
         foreach ($trustedHosts as &$trustedHost) {
             $trustedHost = preg_quote($trustedHost);
         }
@@ -346,7 +341,7 @@ class Url
         $hostHeaders = array();
 
         $config = Config::getInstance()->General;
-        if(isset($config['proxy_host_headers'])) {
+        if (isset($config['proxy_host_headers'])) {
             $hostHeaders = $config['proxy_host_headers'];
         }
 
@@ -473,6 +468,7 @@ class Url
      * Redirects the user to the specified URL.
      *
      * @param string $url
+     * @throws Exception
      * @api
      */
     public static function redirectToUrl($url)
@@ -490,7 +486,7 @@ class Url
             echo "Invalid URL to redirect to.";
         }
 
-        if(Common::isPhpCliMode()) {
+        if (Common::isPhpCliMode()) {
             throw new Exception("If you were using a browser, Piwik would redirect you to this URL: $url \n\n");
         }
         exit;
@@ -501,7 +497,7 @@ class Url
      */
     public static function redirectToHttps()
     {
-        if(ProxyHttp::isHttps()) {
+        if (ProxyHttp::isHttps()) {
             return;
         }
         $url = self::getCurrentUrl();
diff --git a/core/Version.php b/core/Version.php
index 94c6da9cb7e45801b001c6b56dd0c618fdc705b3..cf2377419e12ad06bb6015fae5e6276157d86a45 100644
--- a/core/Version.php
+++ b/core/Version.php
@@ -21,5 +21,5 @@ final class Version
      * The current Piwik version.
      * @var string
      */
-    const VERSION = '2.8.0-b1';
+    const VERSION = '2.9.0-b1';
 }
diff --git a/core/View.php b/core/View.php
index bc02e4c7924a2ef15697461e2b6b5a5f3f020f5b..6200a2311307bf7ced719cc92418ae784a661ab6 100644
--- a/core/View.php
+++ b/core/View.php
@@ -9,12 +9,8 @@
 namespace Piwik;
 
 use Exception;
-use Piwik\Access;
 use Piwik\AssetManager\UIAssetCacheBuster;
-use Piwik\Common;
 use Piwik\Plugins\UsersManager\API as APIUsersManager;
-use Piwik\SettingsPiwik;
-use Piwik\Version;
 use Piwik\View\ViewInterface;
 use Twig_Environment;
 
diff --git a/core/View/ReportsByDimension.php b/core/View/ReportsByDimension.php
index e1cb058459354af9a2bc2b61d0ed8ee86e8f6249..dbb59be930b26705b2c10b3141511b76595e5afa 100644
--- a/core/View/ReportsByDimension.php
+++ b/core/View/ReportsByDimension.php
@@ -104,10 +104,10 @@ class ReportsByDimension extends View
         // display it initially
         $categories = $this->dimensionCategories;
         if (!empty($categories)) {
-            $firstCategory = reset($categories);
+            $firstCategory   = reset($categories);
             $firstReportInfo = reset($firstCategory);
 
-            $oldGet = $_GET;
+            $oldGet  = $_GET;
             $oldPost = $_POST;
 
             foreach ($firstReportInfo['params'] as $key => $value) {
@@ -120,7 +120,7 @@ class ReportsByDimension extends View
             $action = $firstReportInfo['params']['action'];
             $this->firstReport = FrontController::getInstance()->fetchDispatch($module, $action);
 
-            $_GET = $oldGet;
+            $_GET  = $oldGet;
             $_POST = $oldPost;
         }
 
diff --git a/core/ViewDataTable/Config.php b/core/ViewDataTable/Config.php
index 2bd748d3e4ff09fee2d4045851da21617652d645..1706e4b15f454b163c04f5c7c786f30fd3dc2663 100644
--- a/core/ViewDataTable/Config.php
+++ b/core/ViewDataTable/Config.php
@@ -598,7 +598,7 @@ class Config
         // don't add the related report if it references this report
         if ($this->controllerName == $module
             && $this->controllerAction == $action) {
-            if(empty($queryParams)) {
+            if (empty($queryParams)) {
                 return;
             }
         }
diff --git a/core/ViewDataTable/Manager.php b/core/ViewDataTable/Manager.php
index 19e2335ce1d137b6840c72aac9e67e3e5d0c57d4..5d056506574d2f6fbee754a6f3e0ef6b45d9474c 100644
--- a/core/ViewDataTable/Manager.php
+++ b/core/ViewDataTable/Manager.php
@@ -156,46 +156,7 @@ class Manager
     {
         $result = array();
 
-        // add normal view icons (eg, normal table, all columns, goals)
-        $normalViewIcons = array(
-            'class'   => 'tableAllColumnsSwitch',
-            'buttons' => array(),
-        );
-
-        if ($view->config->show_table) {
-            $normalViewIcons['buttons'][] = static::getFooterIconFor(HtmlTable::ID);
-        }
-
-        if ($view->config->show_table_all_columns) {
-            $normalViewIcons['buttons'][] = static::getFooterIconFor(HtmlTable\AllColumns::ID);
-        }
-
-        if ($view->config->show_goals) {
-            $goalButton = static::getFooterIconFor(Goals::ID);
-            if (Common::getRequestVar('idGoal', false) == 'ecommerceOrder') {
-                $goalButton['icon'] = 'plugins/Morpheus/images/ecommerceOrder.gif';
-            }
-
-            $normalViewIcons['buttons'][] = $goalButton;
-        }
-
-        if ($view->config->show_ecommerce) {
-            $normalViewIcons['buttons'][] = array(
-                'id'    => 'ecommerceOrder',
-                'title' => Piwik::translate('General_EcommerceOrders'),
-                'icon'  => 'plugins/Morpheus/images/ecommerceOrder.gif',
-                'text'  => Piwik::translate('General_EcommerceOrders')
-            );
-
-            $normalViewIcons['buttons'][] = array(
-                'id'    => 'ecommerceAbandonedCart',
-                'title' => Piwik::translate('General_AbandonedCarts'),
-                'icon'  => 'plugins/Morpheus/images/ecommerceAbandonedCart.gif',
-                'text'  => Piwik::translate('General_AbandonedCarts')
-            );
-        }
-
-        $normalViewIcons['buttons'] = array_filter($normalViewIcons['buttons']);
+        $normalViewIcons = self::getNormalViewIcons($view);
 
         if (!empty($normalViewIcons['buttons'])) {
             $result[] = $normalViewIcons;
@@ -207,25 +168,7 @@ class Manager
             'buttons' => array(),
         );
 
-        // add graph views
-        $graphViewIcons = array(
-            'class'   => 'tableGraphViews tableGraphCollapsed',
-            'buttons' => array(),
-        );
-
-        if ($view->config->show_all_views_icons) {
-            if ($view->config->show_bar_chart) {
-                $graphViewIcons['buttons'][] = static::getFooterIconFor(Bar::ID);
-            }
-
-            if ($view->config->show_pie_chart) {
-                $graphViewIcons['buttons'][] = static::getFooterIconFor(Pie::ID);
-            }
-
-            if ($view->config->show_tag_cloud) {
-                $graphViewIcons['buttons'][] = static::getFooterIconFor(Cloud::ID);
-            }
-        }
+        $graphViewIcons = self::getGraphViewIcons($view);
 
         $nonCoreVisualizations = static::getNonCoreViewDataTables();
 
@@ -331,4 +274,75 @@ class Manager
     {
         return sprintf('viewDataTableParameters_%s_%s', $login, $controllerAction);
     }
+
+    private static function getNormalViewIcons(ViewDataTable $view)
+    {
+        // add normal view icons (eg, normal table, all columns, goals)
+        $normalViewIcons = array(
+            'class'   => 'tableAllColumnsSwitch',
+            'buttons' => array(),
+        );
+
+        if ($view->config->show_table) {
+            $normalViewIcons['buttons'][] = static::getFooterIconFor(HtmlTable::ID);
+        }
+
+        if ($view->config->show_table_all_columns) {
+            $normalViewIcons['buttons'][] = static::getFooterIconFor(HtmlTable\AllColumns::ID);
+        }
+
+        if ($view->config->show_goals) {
+            $goalButton = static::getFooterIconFor(Goals::ID);
+            if (Common::getRequestVar('idGoal', false) == 'ecommerceOrder') {
+                $goalButton['icon'] = 'plugins/Morpheus/images/ecommerceOrder.gif';
+            }
+
+            $normalViewIcons['buttons'][] = $goalButton;
+        }
+
+        if ($view->config->show_ecommerce) {
+            $normalViewIcons['buttons'][] = array(
+                'id' => 'ecommerceOrder',
+                'title' => Piwik::translate('General_EcommerceOrders'),
+                'icon' => 'plugins/Morpheus/images/ecommerceOrder.gif',
+                'text' => Piwik::translate('General_EcommerceOrders')
+            );
+
+            $normalViewIcons['buttons'][] = array(
+                'id' => 'ecommerceAbandonedCart',
+                'title' => Piwik::translate('General_AbandonedCarts'),
+                'icon' => 'plugins/Morpheus/images/ecommerceAbandonedCart.gif',
+                'text' => Piwik::translate('General_AbandonedCarts')
+            );
+        }
+
+        $normalViewIcons['buttons'] = array_filter($normalViewIcons['buttons']);
+
+        return $normalViewIcons;
+    }
+
+    private static function getGraphViewIcons(ViewDataTable $view)
+    {
+        // add graph views
+        $graphViewIcons = array(
+            'class'   => 'tableGraphViews tableGraphCollapsed',
+            'buttons' => array(),
+        );
+
+        if ($view->config->show_all_views_icons) {
+            if ($view->config->show_bar_chart) {
+                $graphViewIcons['buttons'][] = static::getFooterIconFor(Bar::ID);
+            }
+
+            if ($view->config->show_pie_chart) {
+                $graphViewIcons['buttons'][] = static::getFooterIconFor(Pie::ID);
+            }
+
+            if ($view->config->show_tag_cloud) {
+                $graphViewIcons['buttons'][] = static::getFooterIconFor(Cloud::ID);
+            }
+        }
+
+        return $graphViewIcons;
+    }
 }
diff --git a/core/ViewDataTable/Request.php b/core/ViewDataTable/Request.php
index 94938899443aab7eefa2bf2589eecc5d2ea0be7b..352ce25899cac6ef39eb10f8212e62cc4b825b0d 100644
--- a/core/ViewDataTable/Request.php
+++ b/core/ViewDataTable/Request.php
@@ -119,8 +119,8 @@ class Request
         if (isset($_GET[$nameVar])) {
             return Common::sanitizeInputValue($_GET[$nameVar]);
         }
-        $default = $this->getDefault($nameVar);
-        return $default;
+
+        return $this->getDefault($nameVar);
     }
 
     /**
diff --git a/core/Visualization/Sparkline.php b/core/Visualization/Sparkline.php
index 8a7b4063423c7cb4f7fc0f9ea1a3d6dd3c690a9c..642c1325cb00755799ef0f2fd429f7bf1ecc88b7 100644
--- a/core/Visualization/Sparkline.php
+++ b/core/Visualization/Sparkline.php
@@ -32,6 +32,7 @@ class Sparkline implements ViewInterface
     public static $enableSparklineImages = true;
 
     private static $colorNames = array('backgroundColor', 'lineColor', 'minPointColor', 'lastPointColor', 'maxPointColor');
+    private $values = array();
 
     /**
      * Width of the sparkline
@@ -60,7 +61,6 @@ class Sparkline implements ViewInterface
      */
     public function setHeight($height)
     {
-
         if (!is_numeric($height) || $height <= 0) {
             return;
         }
@@ -74,7 +74,6 @@ class Sparkline implements ViewInterface
      */
     public function setWidth($width)
     {
-
         if (!is_numeric($width) || $width <= 0) {
             return;
         }
@@ -110,7 +109,9 @@ class Sparkline implements ViewInterface
 
         $min = $max = $last = null;
         $i = 0;
-        $toRemove = array('%', str_replace('%s', '', Piwik::translate('General_Seconds')));
+        $seconds  = Piwik::translate('General_Seconds');
+        $toRemove = array('%', str_replace('%s', '', $seconds));
+
         foreach ($this->values as $value) {
             // 50% and 50s should be plotted as 50
             $value = str_replace($toRemove, '', $value);
@@ -158,6 +159,7 @@ class Sparkline implements ViewInterface
     private function setSparklineColors($sparkline)
     {
         $colors = Common::getRequestVar('colors', false, 'json');
+
         if (empty($colors)) { // quick fix so row evolution sparklines will have color in widgetize's iframes
             $colors = array(
                 'backgroundColor' => '#ffffff',
diff --git a/core/dispatch.php b/core/dispatch.php
index f18b73f0bde174b4244e5ef589cbda23c737bb14..133f26f3550b5549f71e3fa162cb79e4b10e2a99 100644
--- a/core/dispatch.php
+++ b/core/dispatch.php
@@ -24,7 +24,7 @@ if (!defined('PIWIK_ENABLE_ERROR_HANDLER') || PIWIK_ENABLE_ERROR_HANDLER) {
 
 FrontController::setUpSafeMode();
 
-if(!defined('PIWIK_ENABLE_DISPATCH')) {
+if (!defined('PIWIK_ENABLE_DISPATCH')) {
     define('PIWIK_ENABLE_DISPATCH', true);
 }
 
@@ -33,7 +33,7 @@ if (PIWIK_ENABLE_DISPATCH) {
     $controller->init();
     $response = $controller->dispatch();
 
-    if(is_array($response)) {
+    if (is_array($response)) {
         var_export($response);
     } elseif (!is_null($response)) {
         echo $response;
diff --git a/core/testMinimumPhpVersion.php b/core/testMinimumPhpVersion.php
index bce404c9e6240a72290a99180e3d44481bce7fcd..3dd3defd3e0691e195e54668c47f897437243447 100644
--- a/core/testMinimumPhpVersion.php
+++ b/core/testMinimumPhpVersion.php
@@ -129,7 +129,7 @@ if (!function_exists('Piwik_ExitWithMessage')) {
         $message = str_replace("\t", "", $message);
         $message = strip_tags($message);
 
-        if($isCli) {
+        if ($isCli) {
             echo $message;
         } else {
             echo $headerPage . $content . $footerPage;
diff --git a/libs/Archive_Tar/Tar.php b/libs/Archive_Tar/Tar.php
deleted file mode 100755
index 167a485b50f3bce74034d085b911612bf5479c42..0000000000000000000000000000000000000000
--- a/libs/Archive_Tar/Tar.php
+++ /dev/null
@@ -1,1993 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * File::CSV
- *
- * PHP versions 4 and 5
- *
- * Copyright (c) 1997-2008,
- * Vincent Blavet <vincent@phpconcept.net>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *     * Redistributions of source code must retain the above copyright notice,
- *       this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @category  File_Formats
- * @package   Archive_Tar
- * @author    Vincent Blavet <vincent@phpconcept.net>
- * @copyright 1997-2010 The Authors
- * @license   http://www.opensource.org/licenses/bsd-license.php New BSD License
- * @version   CVS: $Id$
- * @link      http://pear.php.net/package/Archive_Tar
- */
-
-require_once __DIR__ . "/../PEAR.php";
-
-define('ARCHIVE_TAR_ATT_SEPARATOR', 90001);
-define('ARCHIVE_TAR_END_BLOCK', pack("a512", ''));
-
-/**
-* Creates a (compressed) Tar archive
-*
-* @package Archive_Tar
-* @author  Vincent Blavet <vincent@phpconcept.net>
-* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
-* @version $Revision$
-*/
-class Archive_Tar extends PEAR
-{
-    /**
-    * @var string Name of the Tar
-    */
-    var $_tarname='';
-
-    /**
-    * @var boolean if true, the Tar file will be gzipped
-    */
-    var $_compress=false;
-
-    /**
-    * @var string Type of compression : 'none', 'gz' or 'bz2'
-    */
-    var $_compress_type='none';
-
-    /**
-    * @var string Explode separator
-    */
-    var $_separator=' ';
-
-    /**
-    * @var file descriptor
-    */
-    var $_file=0;
-
-    /**
-    * @var string Local Tar name of a remote Tar (http:// or ftp://)
-    */
-    var $_temp_tarname='';
-
-    /**
-    * @var string regular expression for ignoring files or directories
-    */
-    var $_ignore_regexp='';
-
-    /**
-     * @var object PEAR_Error object
-     */
-    var $error_object=null; 
-
-    // {{{ constructor
-    /**
-    * Archive_Tar Class constructor. This flavour of the constructor only
-    * declare a new Archive_Tar object, identifying it by the name of the
-    * tar file.
-    * If the compress argument is set the tar will be read or created as a
-    * gzip or bz2 compressed TAR file.
-    *
-    * @param string $p_tarname  The name of the tar archive to create
-    * @param string $p_compress can be null, 'gz' or 'bz2'. This
-    *               parameter indicates if gzip or bz2 compression
-    *               is required.  For compatibility reason the
-    *               boolean value 'true' means 'gz'.
-    *
-    * @access public
-    */
-    function Archive_Tar($p_tarname, $p_compress = null)
-    {
-        $this->PEAR();
-        $this->_compress = false;
-        $this->_compress_type = 'none';
-        if (($p_compress === null) || ($p_compress == '')) {
-            if (@file_exists($p_tarname)) {
-                if ($fp = @fopen($p_tarname, "rb")) {
-                    // look for gzip magic cookie
-                    $data = fread($fp, 2);
-                    fclose($fp);
-                    if ($data == "\37\213") {
-                        $this->_compress = true;
-                        $this->_compress_type = 'gz';
-                        // No sure it's enought for a magic code ....
-                    } elseif ($data == "BZ") {
-                        $this->_compress = true;
-                        $this->_compress_type = 'bz2';
-                    }
-                }
-            } else {
-                // probably a remote file or some file accessible
-                // through a stream interface
-                if (substr($p_tarname, -2) == 'gz') {
-                    $this->_compress = true;
-                    $this->_compress_type = 'gz';
-                } elseif ((substr($p_tarname, -3) == 'bz2') ||
-                          (substr($p_tarname, -2) == 'bz')) {
-                    $this->_compress = true;
-                    $this->_compress_type = 'bz2';
-                }
-            }
-        } else {
-            if (($p_compress === true) || ($p_compress == 'gz')) {
-                $this->_compress = true;
-                $this->_compress_type = 'gz';
-            } else if ($p_compress == 'bz2') {
-                $this->_compress = true;
-                $this->_compress_type = 'bz2';
-            } else {
-                $this->_error("Unsupported compression type '$p_compress'\n".
-                    "Supported types are 'gz' and 'bz2'.\n");
-                return false;
-            }
-        }
-        $this->_tarname = $p_tarname;
-        if ($this->_compress) { // assert zlib or bz2 extension support
-            if ($this->_compress_type == 'gz')
-                $extname = 'zlib';
-            else if ($this->_compress_type == 'bz2')
-                $extname = 'bz2';
-
-            if (!extension_loaded($extname)) {
-                PEAR::loadExtension($extname);
-            }
-            if (!extension_loaded($extname)) {
-                $this->_error("The extension '$extname' couldn't be found.\n".
-                    "Please make sure your version of PHP was built ".
-                    "with '$extname' support.\n");
-                return false;
-            }
-        }
-    }
-    // }}}
-
-    // {{{ destructor
-    function _Archive_Tar()
-    {
-        $this->_close();
-        // ----- Look for a local copy to delete
-        if ($this->_temp_tarname != '')
-            @unlink($this->_temp_tarname);
-        $this->_PEAR();
-    }
-    // }}}
-
-    // {{{ create()
-    /**
-    * This method creates the archive file and add the files / directories
-    * that are listed in $p_filelist.
-    * If a file with the same name exist and is writable, it is replaced
-    * by the new tar.
-    * The method return false and a PEAR error text.
-    * The $p_filelist parameter can be an array of string, each string
-    * representing a filename or a directory name with their path if
-    * needed. It can also be a single string with names separated by a
-    * single blank.
-    * For each directory added in the archive, the files and
-    * sub-directories are also added.
-    * See also createModify() method for more details.
-    *
-    * @param array $p_filelist An array of filenames and directory names, or a
-    *              single string with names separated by a single
-    *              blank space.
-    *
-    * @return true on success, false on error.
-    * @see    createModify()
-    * @access public
-    */
-    function create($p_filelist)
-    {
-        return $this->createModify($p_filelist, '', '');
-    }
-    // }}}
-
-    // {{{ add()
-    /**
-    * This method add the files / directories that are listed in $p_filelist in
-    * the archive. If the archive does not exist it is created.
-    * The method return false and a PEAR error text.
-    * The files and directories listed are only added at the end of the archive,
-    * even if a file with the same name is already archived.
-    * See also createModify() method for more details.
-    *
-    * @param array $p_filelist An array of filenames and directory names, or a
-    *              single string with names separated by a single
-    *              blank space.
-    *
-    * @return true on success, false on error.
-    * @see    createModify()
-    * @access public
-    */
-    function add($p_filelist)
-    {
-        return $this->addModify($p_filelist, '', '');
-    }
-    // }}}
-
-    // {{{ extract()
-    function extract($p_path='', $p_preserve=false)
-    {
-        return $this->extractModify($p_path, '', $p_preserve);
-    }
-    // }}}
-
-    // {{{ listContent()
-    function listContent()
-    {
-        $v_list_detail = array();
-
-        if ($this->_openRead()) {
-            if (!$this->_extractList('', $v_list_detail, "list", '', '')) {
-                unset($v_list_detail);
-                $v_list_detail = 0;
-            }
-            $this->_close();
-        }
-
-        return $v_list_detail;
-    }
-    // }}}
-
-    // {{{ createModify()
-    /**
-    * This method creates the archive file and add the files / directories
-    * that are listed in $p_filelist.
-    * If the file already exists and is writable, it is replaced by the
-    * new tar. It is a create and not an add. If the file exists and is
-    * read-only or is a directory it is not replaced. The method return
-    * false and a PEAR error text.
-    * The $p_filelist parameter can be an array of string, each string
-    * representing a filename or a directory name with their path if
-    * needed. It can also be a single string with names separated by a
-    * single blank.
-    * The path indicated in $p_remove_dir will be removed from the
-    * memorized path of each file / directory listed when this path
-    * exists. By default nothing is removed (empty path '')
-    * The path indicated in $p_add_dir will be added at the beginning of
-    * the memorized path of each file / directory listed. However it can
-    * be set to empty ''. The adding of a path is done after the removing
-    * of path.
-    * The path add/remove ability enables the user to prepare an archive
-    * for extraction in a different path than the origin files are.
-    * See also addModify() method for file adding properties.
-    *
-    * @param array  $p_filelist   An array of filenames and directory names,
-    *                             or a single string with names separated by
-    *                             a single blank space.
-    * @param string $p_add_dir    A string which contains a path to be added
-    *                             to the memorized path of each element in
-    *                             the list.
-    * @param string $p_remove_dir A string which contains a path to be
-    *                             removed from the memorized path of each
-    *                             element in the list, when relevant.
-    *
-    * @return boolean true on success, false on error.
-    * @access public
-    * @see addModify()
-    */
-    function createModify($p_filelist, $p_add_dir, $p_remove_dir='')
-    {
-        $v_result = true;
-
-        if (!$this->_openWrite())
-            return false;
-
-        if ($p_filelist != '') {
-            if (is_array($p_filelist))
-                $v_list = $p_filelist;
-            elseif (is_string($p_filelist))
-                $v_list = explode($this->_separator, $p_filelist);
-            else {
-                $this->_cleanFile();
-                $this->_error('Invalid file list');
-                return false;
-            }
-
-            $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir);
-        }
-
-        if ($v_result) {
-            $this->_writeFooter();
-            $this->_close();
-        } else
-            $this->_cleanFile();
-
-        return $v_result;
-    }
-    // }}}
-
-    // {{{ addModify()
-    /**
-    * This method add the files / directories listed in $p_filelist at the
-    * end of the existing archive. If the archive does not yet exists it
-    * is created.
-    * The $p_filelist parameter can be an array of string, each string
-    * representing a filename or a directory name with their path if
-    * needed. It can also be a single string with names separated by a
-    * single blank.
-    * The path indicated in $p_remove_dir will be removed from the
-    * memorized path of each file / directory listed when this path
-    * exists. By default nothing is removed (empty path '')
-    * The path indicated in $p_add_dir will be added at the beginning of
-    * the memorized path of each file / directory listed. However it can
-    * be set to empty ''. The adding of a path is done after the removing
-    * of path.
-    * The path add/remove ability enables the user to prepare an archive
-    * for extraction in a different path than the origin files are.
-    * If a file/dir is already in the archive it will only be added at the
-    * end of the archive. There is no update of the existing archived
-    * file/dir. However while extracting the archive, the last file will
-    * replace the first one. This results in a none optimization of the
-    * archive size.
-    * If a file/dir does not exist the file/dir is ignored. However an
-    * error text is send to PEAR error.
-    * If a file/dir is not readable the file/dir is ignored. However an
-    * error text is send to PEAR error.
-    *
-    * @param array  $p_filelist   An array of filenames and directory
-    *                             names, or a single string with names
-    *                             separated by a single blank space.
-    * @param string $p_add_dir    A string which contains a path to be
-    *                             added to the memorized path of each
-    *                             element in the list.
-    * @param string $p_remove_dir A string which contains a path to be
-    *                             removed from the memorized path of
-    *                             each element in the list, when
-    *                             relevant.
-    *
-    * @return true on success, false on error.
-    * @access public
-    */
-    function addModify($p_filelist, $p_add_dir, $p_remove_dir='')
-    {
-        $v_result = true;
-
-        if (!$this->_isArchive())
-            $v_result = $this->createModify($p_filelist, $p_add_dir,
-                                            $p_remove_dir);
-        else {
-            if (is_array($p_filelist))
-                $v_list = $p_filelist;
-            elseif (is_string($p_filelist))
-                $v_list = explode($this->_separator, $p_filelist);
-            else {
-                $this->_error('Invalid file list');
-                return false;
-            }
-
-            $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir);
-        }
-
-        return $v_result;
-    }
-    // }}}
-
-    // {{{ addString()
-    /**
-    * This method add a single string as a file at the
-    * end of the existing archive. If the archive does not yet exists it
-    * is created.
-    *
-    * @param string $p_filename A string which contains the full
-    *                           filename path that will be associated
-    *                           with the string.
-    * @param string $p_string   The content of the file added in
-    *                           the archive.
-    * @param int    $p_datetime A custom date/time (unix timestamp)
-    *                           for the file (optional).
-    *
-    * @return true on success, false on error.
-    * @access public
-    */
-    function addString($p_filename, $p_string, $p_datetime = false)
-    {
-        $v_result = true;
-
-        if (!$this->_isArchive()) {
-            if (!$this->_openWrite()) {
-                return false;
-            }
-            $this->_close();
-        }
-
-        if (!$this->_openAppend())
-            return false;
-
-        // Need to check the get back to the temporary file ? ....
-        $v_result = $this->_addString($p_filename, $p_string, $p_datetime);
-
-        $this->_writeFooter();
-
-        $this->_close();
-
-        return $v_result;
-    }
-    // }}}
-
-    // {{{ extractModify()
-    /**
-    * This method extract all the content of the archive in the directory
-    * indicated by $p_path. When relevant the memorized path of the
-    * files/dir can be modified by removing the $p_remove_path path at the
-    * beginning of the file/dir path.
-    * While extracting a file, if the directory path does not exists it is
-    * created.
-    * While extracting a file, if the file already exists it is replaced
-    * without looking for last modification date.
-    * While extracting a file, if the file already exists and is write
-    * protected, the extraction is aborted.
-    * While extracting a file, if a directory with the same name already
-    * exists, the extraction is aborted.
-    * While extracting a directory, if a file with the same name already
-    * exists, the extraction is aborted.
-    * While extracting a file/directory if the destination directory exist
-    * and is write protected, or does not exist but can not be created,
-    * the extraction is aborted.
-    * If after extraction an extracted file does not show the correct
-    * stored file size, the extraction is aborted.
-    * When the extraction is aborted, a PEAR error text is set and false
-    * is returned. However the result can be a partial extraction that may
-    * need to be manually cleaned.
-    *
-    * @param string  $p_path        The path of the directory where the
-    *                               files/dir need to by extracted.
-    * @param string  $p_remove_path Part of the memorized path that can be
-    *                               removed if present at the beginning of
-    *                               the file/dir path.
-    * @param boolean $p_preserve    Preserve user/group ownership of files
-    *
-    * @return boolean true on success, false on error.
-    * @access public
-    * @see    extractList()
-    */
-    function extractModify($p_path, $p_remove_path, $p_preserve=false)
-    {
-        $v_result = true;
-        $v_list_detail = array();
-
-        if ($v_result = $this->_openRead()) {
-            $v_result = $this->_extractList($p_path, $v_list_detail,
-                "complete", 0, $p_remove_path, $p_preserve);
-            $this->_close();
-        }
-
-        return $v_result;
-    }
-    // }}}
-
-    // {{{ extractInString()
-    /**
-    * This method extract from the archive one file identified by $p_filename.
-    * The return value is a string with the file content, or NULL on error.
-    *
-    * @param string $p_filename The path of the file to extract in a string.
-    *
-    * @return a string with the file content or NULL.
-    * @access public
-    */
-    function extractInString($p_filename)
-    {
-        if ($this->_openRead()) {
-            $v_result = $this->_extractInString($p_filename);
-            $this->_close();
-        } else {
-            $v_result = null;
-        }
-
-        return $v_result;
-    }
-    // }}}
-
-    // {{{ extractList()
-    /**
-    * This method extract from the archive only the files indicated in the
-    * $p_filelist. These files are extracted in the current directory or
-    * in the directory indicated by the optional $p_path parameter.
-    * If indicated the $p_remove_path can be used in the same way as it is
-    * used in extractModify() method.
-    *
-    * @param array   $p_filelist    An array of filenames and directory names,
-    *                               or a single string with names separated
-    *                               by a single blank space.
-    * @param string  $p_path        The path of the directory where the
-    *                               files/dir need to by extracted.
-    * @param string  $p_remove_path Part of the memorized path that can be
-    *                               removed if present at the beginning of
-    *                               the file/dir path.
-    * @param boolean $p_preserve    Preserve user/group ownership of files
-    *
-    * @return true on success, false on error.
-    * @access public
-    * @see    extractModify()
-    */
-    function extractList($p_filelist, $p_path='', $p_remove_path='', $p_preserve=false)
-    {
-        $v_result = true;
-        $v_list_detail = array();
-
-        if (is_array($p_filelist))
-            $v_list = $p_filelist;
-        elseif (is_string($p_filelist))
-            $v_list = explode($this->_separator, $p_filelist);
-        else {
-            $this->_error('Invalid string list');
-            return false;
-        }
-
-        if ($v_result = $this->_openRead()) {
-            $v_result = $this->_extractList($p_path, $v_list_detail, "partial",
-                $v_list, $p_remove_path, $p_preserve);
-            $this->_close();
-        }
-
-        return $v_result;
-    }
-    // }}}
-
-    // {{{ setAttribute()
-    /**
-    * This method set specific attributes of the archive. It uses a variable
-    * list of parameters, in the format attribute code + attribute values :
-    * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ',');
-    *
-    * @param mixed $argv variable list of attributes and values
-    *
-    * @return true on success, false on error.
-    * @access public
-    */
-    function setAttribute()
-    {
-        $v_result = true;
-
-        // ----- Get the number of variable list of arguments
-        if (($v_size = func_num_args()) == 0) {
-            return true;
-        }
-
-        // ----- Get the arguments
-        $v_att_list = &func_get_args();
-
-        // ----- Read the attributes
-        $i=0;
-        while ($i<$v_size) {
-
-            // ----- Look for next option
-            switch ($v_att_list[$i]) {
-                // ----- Look for options that request a string value
-                case ARCHIVE_TAR_ATT_SEPARATOR :
-                    // ----- Check the number of parameters
-                    if (($i+1) >= $v_size) {
-                        $this->_error('Invalid number of parameters for '
-						              .'attribute ARCHIVE_TAR_ATT_SEPARATOR');
-                        return false;
-                    }
-
-                    // ----- Get the value
-                    $this->_separator = $v_att_list[$i+1];
-                    $i++;
-                break;
-
-                default :
-                    $this->_error('Unknow attribute code '.$v_att_list[$i].'');
-                    return false;
-            }
-
-            // ----- Next attribute
-            $i++;
-        }
-
-        return $v_result;
-    }
-    // }}}
-
-    // {{{ setIgnoreRegexp()
-    /**
-    * This method sets the regular expression for ignoring files and directories
-    * at import, for example:
-    * $arch->setIgnoreRegexp("#CVS|\.svn#");
-    *
-    * @param string $regexp regular expression defining which files or directories to ignore
-    *
-    * @access public
-    */
-    function setIgnoreRegexp($regexp)
-    {
-    	$this->_ignore_regexp = $regexp;
-    }
-    // }}}
-
-    // {{{ setIgnoreList()
-    /**
-    * This method sets the regular expression for ignoring all files and directories
-    * matching the filenames in the array list at import, for example:
-    * $arch->setIgnoreList(array('CVS', '.svn', 'bin/tool'));
-    *
-    * @param array $list a list of file or directory names to ignore
-    *
-    * @access public
-    */
-    function setIgnoreList($list)
-    {
-    	$regexp = str_replace(array('#', '.', '^', '$'), array('\#', '\.', '\^', '\$'), $list);
-    	$regexp = '#/'.join('$|/', $list).'#';
-    	$this->setIgnoreRegexp($regexp);
-    }
-    // }}}
-
-    // {{{ _error()
-    function _error($p_message)
-    {
-        $this->error_object = &$this->raiseError($p_message); 
-    }
-    // }}}
-
-    // {{{ _warning()
-    function _warning($p_message)
-    {
-        $this->error_object = &$this->raiseError($p_message); 
-    }
-    // }}}
-
-    // {{{ _isArchive()
-    function _isArchive($p_filename=null)
-    {
-        if ($p_filename == null) {
-            $p_filename = $this->_tarname;
-        }
-        clearstatcache();
-        return @is_file($p_filename) && !@is_link($p_filename);
-    }
-    // }}}
-
-    // {{{ _openWrite()
-    function _openWrite()
-    {
-        if ($this->_compress_type == 'gz' && function_exists('gzopen'))
-            $this->_file = @gzopen($this->_tarname, "wb9");
-        else if ($this->_compress_type == 'bz2' && function_exists('bzopen'))
-            $this->_file = @bzopen($this->_tarname, "w");
-        else if ($this->_compress_type == 'none')
-            $this->_file = @fopen($this->_tarname, "wb");
-        else {
-            $this->_error('Unknown or missing compression type ('
-			              .$this->_compress_type.')');
-            return false;
-        }
-
-        if ($this->_file == 0) {
-            $this->_error('Unable to open in write mode \''
-			              .$this->_tarname.'\'');
-            return false;
-        }
-
-        return true;
-    }
-    // }}}
-
-    // {{{ _openRead()
-    function _openRead()
-    {
-        if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') {
-
-          // ----- Look if a local copy need to be done
-          if ($this->_temp_tarname == '') {
-              $this->_temp_tarname = uniqid('tar').'.tmp';
-              if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
-                $this->_error('Unable to open in read mode \''
-				              .$this->_tarname.'\'');
-                $this->_temp_tarname = '';
-                return false;
-              }
-              if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
-                $this->_error('Unable to open in write mode \''
-				              .$this->_temp_tarname.'\'');
-                $this->_temp_tarname = '';
-                return false;
-              }
-              while ($v_data = @fread($v_file_from, 1024))
-                  @fwrite($v_file_to, $v_data);
-              @fclose($v_file_from);
-              @fclose($v_file_to);
-          }
-
-          // ----- File to open if the local copy
-          $v_filename = $this->_temp_tarname;
-
-        } else
-          // ----- File to open if the normal Tar file
-          $v_filename = $this->_tarname;
-
-        if ($this->_compress_type == 'gz' && function_exists('gzopen'))
-            $this->_file = @gzopen($v_filename, "rb");
-        else if ($this->_compress_type == 'bz2' && function_exists('bzopen'))
-            $this->_file = @bzopen($v_filename, "r");
-        else if ($this->_compress_type == 'none')
-            $this->_file = @fopen($v_filename, "rb");
-        else {
-            $this->_error('Unknown or missing compression type ('
-			              .$this->_compress_type.')');
-            return false;
-        }
-
-        if ($this->_file == 0) {
-            $this->_error('Unable to open in read mode \''.$v_filename.'\'');
-            return false;
-        }
-
-        return true;
-    }
-    // }}}
-
-    // {{{ _openReadWrite()
-    function _openReadWrite()
-    {
-        if ($this->_compress_type == 'gz')
-            $this->_file = @gzopen($this->_tarname, "r+b");
-        else if ($this->_compress_type == 'bz2') {
-            $this->_error('Unable to open bz2 in read/write mode \''
-			              .$this->_tarname.'\' (limitation of bz2 extension)');
-            return false;
-        } else if ($this->_compress_type == 'none')
-            $this->_file = @fopen($this->_tarname, "r+b");
-        else {
-            $this->_error('Unknown or missing compression type ('
-			              .$this->_compress_type.')');
-            return false;
-        }
-
-        if ($this->_file == 0) {
-            $this->_error('Unable to open in read/write mode \''
-			              .$this->_tarname.'\'');
-            return false;
-        }
-
-        return true;
-    }
-    // }}}
-
-    // {{{ _close()
-    function _close()
-    {
-        //if (isset($this->_file)) {
-        if (is_resource($this->_file)) {
-            if ($this->_compress_type == 'gz')
-                @gzclose($this->_file);
-            else if ($this->_compress_type == 'bz2')
-                @bzclose($this->_file);
-            else if ($this->_compress_type == 'none')
-                @fclose($this->_file);
-            else
-                $this->_error('Unknown or missing compression type ('
-				              .$this->_compress_type.')');
-
-            $this->_file = 0;
-        }
-
-        // ----- Look if a local copy need to be erase
-        // Note that it might be interesting to keep the url for a time : ToDo
-        if ($this->_temp_tarname != '') {
-            @unlink($this->_temp_tarname);
-            $this->_temp_tarname = '';
-        }
-
-        return true;
-    }
-    // }}}
-
-    // {{{ _cleanFile()
-    function _cleanFile()
-    {
-        $this->_close();
-
-        // ----- Look for a local copy
-        if ($this->_temp_tarname != '') {
-            // ----- Remove the local copy but not the remote tarname
-            @unlink($this->_temp_tarname);
-            $this->_temp_tarname = '';
-        } else {
-            // ----- Remove the local tarname file
-            @unlink($this->_tarname);
-        }
-        $this->_tarname = '';
-
-        return true;
-    }
-    // }}}
-
-    // {{{ _writeBlock()
-    function _writeBlock($p_binary_data, $p_len=null)
-    {
-      if (is_resource($this->_file)) {
-          if ($p_len === null) {
-              if ($this->_compress_type == 'gz')
-                  @gzputs($this->_file, $p_binary_data);
-              else if ($this->_compress_type == 'bz2')
-                  @bzwrite($this->_file, $p_binary_data);
-              else if ($this->_compress_type == 'none')
-                  @fputs($this->_file, $p_binary_data);
-              else
-                  $this->_error('Unknown or missing compression type ('
-				                .$this->_compress_type.')');
-          } else {
-              if ($this->_compress_type == 'gz')
-                  @gzputs($this->_file, $p_binary_data, $p_len);
-              else if ($this->_compress_type == 'bz2')
-                  @bzwrite($this->_file, $p_binary_data, $p_len);
-              else if ($this->_compress_type == 'none')
-                  @fputs($this->_file, $p_binary_data, $p_len);
-              else
-                  $this->_error('Unknown or missing compression type ('
-				                .$this->_compress_type.')');
-
-          }
-      }
-      return true;
-    }
-    // }}}
-
-    // {{{ _readBlock()
-    function _readBlock()
-    {
-      $v_block = null;
-      if (is_resource($this->_file)) {
-          if ($this->_compress_type == 'gz')
-              $v_block = @gzread($this->_file, 512);
-          else if ($this->_compress_type == 'bz2')
-              $v_block = @bzread($this->_file, 512);
-          else if ($this->_compress_type == 'none')
-              $v_block = @fread($this->_file, 512);
-          else
-              $this->_error('Unknown or missing compression type ('
-			                .$this->_compress_type.')');
-      }
-      return $v_block;
-    }
-    // }}}
-
-    // {{{ _jumpBlock()
-    function _jumpBlock($p_len=null)
-    {
-      if (is_resource($this->_file)) {
-          if ($p_len === null)
-              $p_len = 1;
-
-          if ($this->_compress_type == 'gz') {
-              @gzseek($this->_file, gztell($this->_file)+($p_len*512));
-          }
-          else if ($this->_compress_type == 'bz2') {
-              // ----- Replace missing bztell() and bzseek()
-              for ($i=0; $i<$p_len; $i++)
-                  $this->_readBlock();
-          } else if ($this->_compress_type == 'none')
-              @fseek($this->_file, $p_len*512, SEEK_CUR);
-          else
-              $this->_error('Unknown or missing compression type ('
-			                .$this->_compress_type.')');
-
-      }
-      return true;
-    }
-    // }}}
-
-    // {{{ _writeFooter()
-    function _writeFooter()
-    {
-      if (is_resource($this->_file)) {
-          // ----- Write the last 0 filled block for end of archive
-          $v_binary_data = pack('a1024', '');
-          $this->_writeBlock($v_binary_data);
-      }
-      return true;
-    }
-    // }}}
-
-    // {{{ _addList()
-    function _addList($p_list, $p_add_dir, $p_remove_dir)
-    {
-      $v_result=true;
-      $v_header = array();
-
-      // ----- Remove potential windows directory separator
-      $p_add_dir = $this->_translateWinPath($p_add_dir);
-      $p_remove_dir = $this->_translateWinPath($p_remove_dir, false);
-
-      if (!$this->_file) {
-          $this->_error('Invalid file descriptor');
-          return false;
-      }
-
-      if (sizeof($p_list) == 0)
-          return true;
-
-      foreach ($p_list as $v_filename) {
-          if (!$v_result) {
-              break;
-          }
-
-        // ----- Skip the current tar name
-        if ($v_filename == $this->_tarname)
-            continue;
-
-        if ($v_filename == '')
-            continue;
-
-       	// ----- ignore files and directories matching the ignore regular expression
-       	if ($this->_ignore_regexp && preg_match($this->_ignore_regexp, '/'.$v_filename)) {
-            $this->_warning("File '$v_filename' ignored");
-       	    continue;
-       	}
-
-        if (!file_exists($v_filename) && !is_link($v_filename)) {
-            $this->_warning("File '$v_filename' does not exist");
-            continue;
-        }
-
-        // ----- Add the file or directory header
-        if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir))
-            return false;
-
-        if (@is_dir($v_filename) && !@is_link($v_filename)) {
-            if (!($p_hdir = opendir($v_filename))) {
-                $this->_warning("Directory '$v_filename' can not be read");
-                continue;
-            }
-            while (false !== ($p_hitem = readdir($p_hdir))) {
-                if (($p_hitem != '.') && ($p_hitem != '..')) {
-                    if ($v_filename != ".")
-                        $p_temp_list[0] = $v_filename.'/'.$p_hitem;
-                    else
-                        $p_temp_list[0] = $p_hitem;
-
-                    $v_result = $this->_addList($p_temp_list,
-					                            $p_add_dir,
-												$p_remove_dir);
-                }
-            }
-
-            unset($p_temp_list);
-            unset($p_hdir);
-            unset($p_hitem);
-        }
-      }
-
-      return $v_result;
-    }
-    // }}}
-
-    // {{{ _addFile()
-    function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir)
-    {
-      if (!$this->_file) {
-          $this->_error('Invalid file descriptor');
-          return false;
-      }
-
-      if ($p_filename == '') {
-          $this->_error('Invalid file name');
-          return false;
-      }
-
-      // ----- Calculate the stored filename
-      $p_filename = $this->_translateWinPath($p_filename, false);;
-      $v_stored_filename = $p_filename;
-      if (strcmp($p_filename, $p_remove_dir) == 0) {
-          return true;
-      }
-      if ($p_remove_dir != '') {
-          if (substr($p_remove_dir, -1) != '/')
-              $p_remove_dir .= '/';
-
-          if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir)
-              $v_stored_filename = substr($p_filename, strlen($p_remove_dir));
-      }
-      $v_stored_filename = $this->_translateWinPath($v_stored_filename);
-      if ($p_add_dir != '') {
-          if (substr($p_add_dir, -1) == '/')
-              $v_stored_filename = $p_add_dir.$v_stored_filename;
-          else
-              $v_stored_filename = $p_add_dir.'/'.$v_stored_filename;
-      }
-
-      $v_stored_filename = $this->_pathReduction($v_stored_filename);
-
-      if ($this->_isArchive($p_filename)) {
-          if (($v_file = @fopen($p_filename, "rb")) == 0) {
-              $this->_warning("Unable to open file '".$p_filename
-			                  ."' in binary read mode");
-              return true;
-          }
-
-          if (!$this->_writeHeader($p_filename, $v_stored_filename))
-              return false;
-
-          while (($v_buffer = fread($v_file, 512)) != '') {
-              $v_binary_data = pack("a512", "$v_buffer");
-              $this->_writeBlock($v_binary_data);
-          }
-
-          fclose($v_file);
-
-      } else {
-          // ----- Only header for dir
-          if (!$this->_writeHeader($p_filename, $v_stored_filename))
-              return false;
-      }
-
-      return true;
-    }
-    // }}}
-
-    // {{{ _addString()
-    function _addString($p_filename, $p_string, $p_datetime = false)
-    {
-      if (!$this->_file) {
-          $this->_error('Invalid file descriptor');
-          return false;
-      }
-
-      if ($p_filename == '') {
-          $this->_error('Invalid file name');
-          return false;
-      }
-
-      // ----- Calculate the stored filename
-      $p_filename = $this->_translateWinPath($p_filename, false);;
-      
-      // ----- If datetime is not specified, set current time
-      if ($p_datetime === false) {
-          $p_datetime = time();
-      }
-
-      if (!$this->_writeHeaderBlock($p_filename, strlen($p_string),
-                                    $p_datetime, 384, "", 0, 0))
-          return false;
-
-      $i=0;
-      while (($v_buffer = substr($p_string, (($i++)*512), 512)) != '') {
-          $v_binary_data = pack("a512", $v_buffer);
-          $this->_writeBlock($v_binary_data);
-      }
-
-      return true;
-    }
-    // }}}
-
-    // {{{ _writeHeader()
-    function _writeHeader($p_filename, $p_stored_filename)
-    {
-        if ($p_stored_filename == '')
-            $p_stored_filename = $p_filename;
-        $v_reduce_filename = $this->_pathReduction($p_stored_filename);
-
-        if (strlen($v_reduce_filename) > 99) {
-          if (!$this->_writeLongHeader($v_reduce_filename))
-            return false;
-        }
-
-        $v_info = lstat($p_filename);
-        $v_uid = sprintf("%07s", DecOct($v_info[4]));
-        $v_gid = sprintf("%07s", DecOct($v_info[5]));
-        $v_perms = sprintf("%07s", DecOct($v_info['mode'] & 000777));
-
-        $v_mtime = sprintf("%011s", DecOct($v_info['mtime']));
-
-        $v_linkname = '';
-
-        if (@is_link($p_filename)) {
-          $v_typeflag = '2';
-          $v_linkname = readlink($p_filename);
-          $v_size = sprintf("%011s", DecOct(0));
-        } elseif (@is_dir($p_filename)) {
-          $v_typeflag = "5";
-          $v_size = sprintf("%011s", DecOct(0));
-        } else {
-          $v_typeflag = '0';
-          clearstatcache();
-          $v_size = sprintf("%011s", DecOct($v_info['size']));
-        }
-
-        $v_magic = 'ustar ';
-
-        $v_version = ' ';
-        
-        if (function_exists('posix_getpwuid'))
-        {
-          $userinfo = posix_getpwuid($v_info[4]);
-          $groupinfo = posix_getgrgid($v_info[5]);
-          
-          $v_uname = $userinfo['name'];
-          $v_gname = $groupinfo['name'];
-        }
-        else
-        {
-          $v_uname = '';
-          $v_gname = '';
-        }
-
-        $v_devmajor = '';
-
-        $v_devminor = '';
-
-        $v_prefix = '';
-
-        $v_binary_data_first = pack("a100a8a8a8a12a12",
-		                            $v_reduce_filename, $v_perms, $v_uid,
-									$v_gid, $v_size, $v_mtime);
-        $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
-		                           $v_typeflag, $v_linkname, $v_magic,
-								   $v_version, $v_uname, $v_gname,
-								   $v_devmajor, $v_devminor, $v_prefix, '');
-
-        // ----- Calculate the checksum
-        $v_checksum = 0;
-        // ..... First part of the header
-        for ($i=0; $i<148; $i++)
-            $v_checksum += ord(substr($v_binary_data_first,$i,1));
-        // ..... Ignore the checksum value and replace it by ' ' (space)
-        for ($i=148; $i<156; $i++)
-            $v_checksum += ord(' ');
-        // ..... Last part of the header
-        for ($i=156, $j=0; $i<512; $i++, $j++)
-            $v_checksum += ord(substr($v_binary_data_last,$j,1));
-
-        // ----- Write the first 148 bytes of the header in the archive
-        $this->_writeBlock($v_binary_data_first, 148);
-
-        // ----- Write the calculated checksum
-        $v_checksum = sprintf("%06s ", DecOct($v_checksum));
-        $v_binary_data = pack("a8", $v_checksum);
-        $this->_writeBlock($v_binary_data, 8);
-
-        // ----- Write the last 356 bytes of the header in the archive
-        $this->_writeBlock($v_binary_data_last, 356);
-
-        return true;
-    }
-    // }}}
-
-    // {{{ _writeHeaderBlock()
-    function _writeHeaderBlock($p_filename, $p_size, $p_mtime=0, $p_perms=0,
-	                           $p_type='', $p_uid=0, $p_gid=0)
-    {
-        $p_filename = $this->_pathReduction($p_filename);
-
-        if (strlen($p_filename) > 99) {
-          if (!$this->_writeLongHeader($p_filename))
-            return false;
-        }
-
-        if ($p_type == "5") {
-          $v_size = sprintf("%011s", DecOct(0));
-        } else {
-          $v_size = sprintf("%011s", DecOct($p_size));
-        }
-
-        $v_uid = sprintf("%07s", DecOct($p_uid));
-        $v_gid = sprintf("%07s", DecOct($p_gid));
-        $v_perms = sprintf("%07s", DecOct($p_perms & 000777));
-
-        $v_mtime = sprintf("%11s", DecOct($p_mtime));
-
-        $v_linkname = '';
-
-        $v_magic = 'ustar ';
-
-        $v_version = ' ';
-
-        if (function_exists('posix_getpwuid'))
-        {
-          $userinfo = posix_getpwuid($p_uid);
-          $groupinfo = posix_getgrgid($p_gid);
-          
-          $v_uname = $userinfo['name'];
-          $v_gname = $groupinfo['name'];
-        }
-        else
-        {
-          $v_uname = '';
-          $v_gname = '';
-        }
-        
-        $v_devmajor = '';
-
-        $v_devminor = '';
-
-        $v_prefix = '';
-
-        $v_binary_data_first = pack("a100a8a8a8a12A12",
-		                            $p_filename, $v_perms, $v_uid, $v_gid,
-									$v_size, $v_mtime);
-        $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
-		                           $p_type, $v_linkname, $v_magic,
-								   $v_version, $v_uname, $v_gname,
-								   $v_devmajor, $v_devminor, $v_prefix, '');
-
-        // ----- Calculate the checksum
-        $v_checksum = 0;
-        // ..... First part of the header
-        for ($i=0; $i<148; $i++)
-            $v_checksum += ord(substr($v_binary_data_first,$i,1));
-        // ..... Ignore the checksum value and replace it by ' ' (space)
-        for ($i=148; $i<156; $i++)
-            $v_checksum += ord(' ');
-        // ..... Last part of the header
-        for ($i=156, $j=0; $i<512; $i++, $j++)
-            $v_checksum += ord(substr($v_binary_data_last,$j,1));
-
-        // ----- Write the first 148 bytes of the header in the archive
-        $this->_writeBlock($v_binary_data_first, 148);
-
-        // ----- Write the calculated checksum
-        $v_checksum = sprintf("%06s ", DecOct($v_checksum));
-        $v_binary_data = pack("a8", $v_checksum);
-        $this->_writeBlock($v_binary_data, 8);
-
-        // ----- Write the last 356 bytes of the header in the archive
-        $this->_writeBlock($v_binary_data_last, 356);
-
-        return true;
-    }
-    // }}}
-
-    // {{{ _writeLongHeader()
-    function _writeLongHeader($p_filename)
-    {
-        $v_size = sprintf("%11s ", DecOct(strlen($p_filename)));
-
-        $v_typeflag = 'L';
-
-        $v_linkname = '';
-
-        $v_magic = '';
-
-        $v_version = '';
-
-        $v_uname = '';
-
-        $v_gname = '';
-
-        $v_devmajor = '';
-
-        $v_devminor = '';
-
-        $v_prefix = '';
-
-        $v_binary_data_first = pack("a100a8a8a8a12a12",
-		                            '././@LongLink', 0, 0, 0, $v_size, 0);
-        $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
-		                           $v_typeflag, $v_linkname, $v_magic,
-								   $v_version, $v_uname, $v_gname,
-								   $v_devmajor, $v_devminor, $v_prefix, '');
-
-        // ----- Calculate the checksum
-        $v_checksum = 0;
-        // ..... First part of the header
-        for ($i=0; $i<148; $i++)
-            $v_checksum += ord(substr($v_binary_data_first,$i,1));
-        // ..... Ignore the checksum value and replace it by ' ' (space)
-        for ($i=148; $i<156; $i++)
-            $v_checksum += ord(' ');
-        // ..... Last part of the header
-        for ($i=156, $j=0; $i<512; $i++, $j++)
-            $v_checksum += ord(substr($v_binary_data_last,$j,1));
-
-        // ----- Write the first 148 bytes of the header in the archive
-        $this->_writeBlock($v_binary_data_first, 148);
-
-        // ----- Write the calculated checksum
-        $v_checksum = sprintf("%06s ", DecOct($v_checksum));
-        $v_binary_data = pack("a8", $v_checksum);
-        $this->_writeBlock($v_binary_data, 8);
-
-        // ----- Write the last 356 bytes of the header in the archive
-        $this->_writeBlock($v_binary_data_last, 356);
-
-        // ----- Write the filename as content of the block
-        $i=0;
-        while (($v_buffer = substr($p_filename, (($i++)*512), 512)) != '') {
-            $v_binary_data = pack("a512", "$v_buffer");
-            $this->_writeBlock($v_binary_data);
-        }
-
-        return true;
-    }
-    // }}}
-
-    // {{{ _readHeader()
-    function _readHeader($v_binary_data, &$v_header)
-    {
-        if (strlen($v_binary_data)==0) {
-            $v_header['filename'] = '';
-            return true;
-        }
-
-        if (strlen($v_binary_data) != 512) {
-            $v_header['filename'] = '';
-            $this->_error('Invalid block size : '.strlen($v_binary_data));
-            return false;
-        }
-
-        if (!is_array($v_header)) {
-            $v_header = array();
-        }
-        // ----- Calculate the checksum
-        $v_checksum = 0;
-        // ..... First part of the header
-        for ($i=0; $i<148; $i++)
-            $v_checksum+=ord(substr($v_binary_data,$i,1));
-        // ..... Ignore the checksum value and replace it by ' ' (space)
-        for ($i=148; $i<156; $i++)
-            $v_checksum += ord(' ');
-        // ..... Last part of the header
-        for ($i=156; $i<512; $i++)
-           $v_checksum+=ord(substr($v_binary_data,$i,1));
-
-        if (version_compare(PHP_VERSION,"5.5.0-dev")<0) {
-            $fmt = "a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/" .
-                   "a8checksum/a1typeflag/a100link/a6magic/a2version/" .
-                   "a32uname/a32gname/a8devmajor/a8devminor/a131prefix";
-        } else {
-            $fmt = "Z100filename/Z8mode/Z8uid/Z8gid/Z12size/Z12mtime/" .
-                   "Z8checksum/Z1typeflag/Z100link/Z6magic/Z2version/" .
-                   "Z32uname/Z32gname/Z8devmajor/Z8devminor/Z131prefix";
-        }
-        $v_data = unpack($fmt, $v_binary_data);
-
-        if (strlen($v_data["prefix"]) > 0) {
-            $v_data["filename"] = "$v_data[prefix]/$v_data[filename]";
-        }
-
-        // ----- Extract the checksum
-        $v_header['checksum'] = OctDec(trim($v_data['checksum']));
-        if ($v_header['checksum'] != $v_checksum) {
-            $v_header['filename'] = '';
-
-            // ----- Look for last block (empty block)
-            if (($v_checksum == 256) && ($v_header['checksum'] == 0))
-                return true;
-
-            $this->_error('Invalid checksum for file "'.$v_data['filename']
-			              .'" : '.$v_checksum.' calculated, '
-						  .$v_header['checksum'].' expected');
-            return false;
-        }
-
-        // ----- Extract the properties
-        $v_header['filename'] = $v_data['filename'];
-        if ($this->_maliciousFilename($v_header['filename'])) {
-            $this->_error('Malicious .tar detected, file "' . $v_header['filename'] .
-                '" will not install in desired directory tree');
-            return false;
-        }
-        $v_header['mode'] = OctDec(trim($v_data['mode']));
-        $v_header['uid'] = OctDec(trim($v_data['uid']));
-        $v_header['gid'] = OctDec(trim($v_data['gid']));
-        $v_header['size'] = OctDec(trim($v_data['size']));
-        $v_header['mtime'] = OctDec(trim($v_data['mtime']));
-        if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
-          $v_header['size'] = 0;
-        }
-        $v_header['link'] = trim($v_data['link']);
-        /* ----- All these fields are removed form the header because
-		they do not carry interesting info
-        $v_header[magic] = trim($v_data[magic]);
-        $v_header[version] = trim($v_data[version]);
-        $v_header[uname] = trim($v_data[uname]);
-        $v_header[gname] = trim($v_data[gname]);
-        $v_header[devmajor] = trim($v_data[devmajor]);
-        $v_header[devminor] = trim($v_data[devminor]);
-        */
-
-        return true;
-    }
-    // }}}
-
-    // {{{ _maliciousFilename()
-    /**
-     * Detect and report a malicious file name
-     *
-     * @param string $file
-     *
-     * @return bool
-     * @access private
-     */
-    function _maliciousFilename($file)
-    {
-        if (strpos($file, '/../') !== false) {
-            return true;
-        }
-        if (strpos($file, '../') === 0) {
-            return true;
-        }
-        return false;
-    }
-    // }}}
-
-    // {{{ _readLongHeader()
-    function _readLongHeader(&$v_header)
-    {
-      $v_filename = '';
-      $n = floor($v_header['size']/512);
-      for ($i=0; $i<$n; $i++) {
-        $v_content = $this->_readBlock();
-        $v_filename .= $v_content;
-      }
-      if (($v_header['size'] % 512) != 0) {
-        $v_content = $this->_readBlock();
-        $v_filename .= trim($v_content);
-      }
-
-      // ----- Read the next header
-      $v_binary_data = $this->_readBlock();
-
-      if (!$this->_readHeader($v_binary_data, $v_header))
-        return false;
-
-      $v_filename = trim($v_filename);
-      $v_header['filename'] = $v_filename;
-        if ($this->_maliciousFilename($v_filename)) {
-            $this->_error('Malicious .tar detected, file "' . $v_filename .
-                '" will not install in desired directory tree');
-            return false;
-      }
-
-      return true;
-    }
-    // }}}
-
-    // {{{ _extractInString()
-    /**
-    * This method extract from the archive one file identified by $p_filename.
-    * The return value is a string with the file content, or null on error.
-    *
-    * @param string $p_filename The path of the file to extract in a string.
-    *
-    * @return a string with the file content or null.
-    * @access private
-    */
-    function _extractInString($p_filename)
-    {
-        $v_result_str = "";
-
-        While (strlen($v_binary_data = $this->_readBlock()) != 0)
-        {
-          if (!$this->_readHeader($v_binary_data, $v_header))
-            return null;
-
-          if ($v_header['filename'] == '')
-            continue;
-
-          // ----- Look for long filename
-          if ($v_header['typeflag'] == 'L') {
-            if (!$this->_readLongHeader($v_header))
-              return null;
-          }
-
-          if ($v_header['filename'] == $p_filename) {
-              if ($v_header['typeflag'] == "5") {
-                  $this->_error('Unable to extract in string a directory '
-				                .'entry {'.$v_header['filename'].'}');
-                  return null;
-              } else {
-                  $n = floor($v_header['size']/512);
-                  for ($i=0; $i<$n; $i++) {
-                      $v_result_str .= $this->_readBlock();
-                  }
-                  if (($v_header['size'] % 512) != 0) {
-                      $v_content = $this->_readBlock();
-                      $v_result_str .= substr($v_content, 0,
-					                          ($v_header['size'] % 512));
-                  }
-                  return $v_result_str;
-              }
-          } else {
-              $this->_jumpBlock(ceil(($v_header['size']/512)));
-          }
-        }
-
-        return null;
-    }
-    // }}}
-
-    // {{{ _extractList()
-    function _extractList($p_path, &$p_list_detail, $p_mode,
-                          $p_file_list, $p_remove_path, $p_preserve=false)
-    {
-    $v_result=true;
-    $v_nb = 0;
-    $v_extract_all = true;
-    $v_listing = false;
-
-    $p_path = $this->_translateWinPath($p_path, false);
-    if ($p_path == '' || (substr($p_path, 0, 1) != '/'
-	    && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))) {
-      $p_path = "./".$p_path;
-    }
-    $p_remove_path = $this->_translateWinPath($p_remove_path);
-
-    // ----- Look for path to remove format (should end by /)
-    if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/'))
-      $p_remove_path .= '/';
-    $p_remove_path_size = strlen($p_remove_path);
-
-    switch ($p_mode) {
-      case "complete" :
-        $v_extract_all = true;
-        $v_listing = false;
-      break;
-      case "partial" :
-          $v_extract_all = false;
-          $v_listing = false;
-      break;
-      case "list" :
-          $v_extract_all = false;
-          $v_listing = true;
-      break;
-      default :
-        $this->_error('Invalid extract mode ('.$p_mode.')');
-        return false;
-    }
-
-    clearstatcache();
-
-    while (strlen($v_binary_data = $this->_readBlock()) != 0)
-    {
-      $v_extract_file = FALSE;
-      $v_extraction_stopped = 0;
-
-      if (!$this->_readHeader($v_binary_data, $v_header))
-        return false;
-
-      if ($v_header['filename'] == '') {
-        continue;
-      }
-
-      // ----- Look for long filename
-      if ($v_header['typeflag'] == 'L') {
-        if (!$this->_readLongHeader($v_header))
-          return false;
-      }
-
-      if ((!$v_extract_all) && (is_array($p_file_list))) {
-        // ----- By default no unzip if the file is not found
-        $v_extract_file = false;
-
-        for ($i=0; $i<sizeof($p_file_list); $i++) {
-          // ----- Look if it is a directory
-          if (substr($p_file_list[$i], -1) == '/') {
-            // ----- Look if the directory is in the filename path
-            if ((strlen($v_header['filename']) > strlen($p_file_list[$i]))
-			    && (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
-				    == $p_file_list[$i])) {
-              $v_extract_file = true;
-              break;
-            }
-          }
-
-          // ----- It is a file, so compare the file names
-          elseif ($p_file_list[$i] == $v_header['filename']) {
-            $v_extract_file = true;
-            break;
-          }
-        }
-      } else {
-        $v_extract_file = true;
-      }
-
-      // ----- Look if this file need to be extracted
-      if (($v_extract_file) && (!$v_listing))
-      {
-        if (($p_remove_path != '')
-            && (substr($v_header['filename'].'/', 0, $p_remove_path_size)
-			    == $p_remove_path)) {
-          $v_header['filename'] = substr($v_header['filename'],
-		                                 $p_remove_path_size);
-          if( $v_header['filename'] == '' ){
-            continue;
-          }
-        }
-        if (($p_path != './') && ($p_path != '/')) {
-          while (substr($p_path, -1) == '/')
-            $p_path = substr($p_path, 0, strlen($p_path)-1);
-
-          if (substr($v_header['filename'], 0, 1) == '/')
-              $v_header['filename'] = $p_path.$v_header['filename'];
-          else
-            $v_header['filename'] = $p_path.'/'.$v_header['filename'];
-        }
-        if (file_exists($v_header['filename'])) {
-          if (   (@is_dir($v_header['filename']))
-		      && ($v_header['typeflag'] == '')) {
-            $this->_error('File '.$v_header['filename']
-			              .' already exists as a directory');
-            return false;
-          }
-          if (   ($this->_isArchive($v_header['filename']))
-		      && ($v_header['typeflag'] == "5")) {
-            $this->_error('Directory '.$v_header['filename']
-			              .' already exists as a file');
-            return false;
-          }
-          if (!is_writeable($v_header['filename'])) {
-            $this->_error('File '.$v_header['filename']
-			              .' already exists and is write protected');
-            return false;
-          }
-          if (filemtime($v_header['filename']) > $v_header['mtime']) {
-            // To be completed : An error or silent no replace ?
-          }
-        }
-
-        // ----- Check the directory availability and create it if necessary
-        elseif (($v_result
-		         = $this->_dirCheck(($v_header['typeflag'] == "5"
-				                    ?$v_header['filename']
-									:dirname($v_header['filename'])))) != 1) {
-            $this->_error('Unable to create path for '.$v_header['filename']);
-            return false;
-        }
-
-        if ($v_extract_file) {
-          if ($v_header['typeflag'] == "5") {
-            if (!@file_exists($v_header['filename'])) {
-                if (!@mkdir($v_header['filename'], 0777)) {
-                    $this->_error('Unable to create directory {'
-					              .$v_header['filename'].'}');
-                    return false;
-                }
-            }
-          } elseif ($v_header['typeflag'] == "2") {
-              if (@file_exists($v_header['filename'])) {
-                  @unlink($v_header['filename']);
-              }
-              if (!@symlink($v_header['link'], $v_header['filename'])) {
-                  $this->_error('Unable to extract symbolic link {'
-                                .$v_header['filename'].'}');
-                  return false;
-              }
-          } else {
-              if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
-                  $this->_error('Error while opening {'.$v_header['filename']
-				                .'} in write binary mode');
-                  return false;
-              } else {
-                  $n = floor($v_header['size']/512);
-                  for ($i=0; $i<$n; $i++) {
-                      $v_content = $this->_readBlock();
-                      fwrite($v_dest_file, $v_content, 512);
-                  }
-            if (($v_header['size'] % 512) != 0) {
-              $v_content = $this->_readBlock();
-              fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
-            }
-
-            @fclose($v_dest_file);
-            
-            if ($p_preserve) {
-                @chown($v_header['filename'], $v_header['uid']);
-                @chgrp($v_header['filename'], $v_header['gid']);
-            }
-
-            // ----- Change the file mode, mtime
-            @touch($v_header['filename'], $v_header['mtime']);
-            if ($v_header['mode'] & 0111) {
-                // make file executable, obey umask
-                $mode = fileperms($v_header['filename']) | (~umask() & 0111);
-                @chmod($v_header['filename'], $mode);
-            }
-          }
-
-          // ----- Check the file size
-          clearstatcache();
-          if (!is_file($v_header['filename'])) {
-              $this->_error('Extracted file '.$v_header['filename']
-                            .'does not exist. Archive may be corrupted.');
-              return false;
-          }
-          
-          $filesize = filesize($v_header['filename']);
-          if ($filesize != $v_header['size']) {
-              $this->_error('Extracted file '.$v_header['filename']
-                            .' does not have the correct file size \''
-                            .$filesize
-                            .'\' ('.$v_header['size']
-                            .' expected). Archive may be corrupted.');
-              return false;
-          }
-          }
-        } else {
-          $this->_jumpBlock(ceil(($v_header['size']/512)));
-        }
-      } else {
-          $this->_jumpBlock(ceil(($v_header['size']/512)));
-      }
-
-      /* TBC : Seems to be unused ...
-      if ($this->_compress)
-        $v_end_of_file = @gzeof($this->_file);
-      else
-        $v_end_of_file = @feof($this->_file);
-        */
-
-      if ($v_listing || $v_extract_file || $v_extraction_stopped) {
-        // ----- Log extracted files
-        if (($v_file_dir = dirname($v_header['filename']))
-		    == $v_header['filename'])
-          $v_file_dir = '';
-        if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == ''))
-          $v_file_dir = '/';
-
-        $p_list_detail[$v_nb++] = $v_header;
-        if (is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) {
-            return true;
-        }
-      }
-    }
-
-        return true;
-    }
-    // }}}
-
-    // {{{ _openAppend()
-    function _openAppend()
-    {
-        if (filesize($this->_tarname) == 0)
-          return $this->_openWrite();
-
-        if ($this->_compress) {
-            $this->_close();
-
-            if (!@rename($this->_tarname, $this->_tarname.".tmp")) {
-                $this->_error('Error while renaming \''.$this->_tarname
-				              .'\' to temporary file \''.$this->_tarname
-							  .'.tmp\'');
-                return false;
-            }
-
-            if ($this->_compress_type == 'gz')
-                $v_temp_tar = @gzopen($this->_tarname.".tmp", "rb");
-            elseif ($this->_compress_type == 'bz2')
-                $v_temp_tar = @bzopen($this->_tarname.".tmp", "r");
-
-            if ($v_temp_tar == 0) {
-                $this->_error('Unable to open file \''.$this->_tarname
-				              .'.tmp\' in binary read mode');
-                @rename($this->_tarname.".tmp", $this->_tarname);
-                return false;
-            }
-
-            if (!$this->_openWrite()) {
-                @rename($this->_tarname.".tmp", $this->_tarname);
-                return false;
-            }
-
-            if ($this->_compress_type == 'gz') {
-                $end_blocks = 0;
-                
-                while (!@gzeof($v_temp_tar)) {
-                    $v_buffer = @gzread($v_temp_tar, 512);
-                    if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
-                        $end_blocks++;
-                        // do not copy end blocks, we will re-make them
-                        // after appending
-                        continue;
-                    } elseif ($end_blocks > 0) {
-                        for ($i = 0; $i < $end_blocks; $i++) {
-                            $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
-                        }
-                        $end_blocks = 0;
-                    }
-                    $v_binary_data = pack("a512", $v_buffer);
-                    $this->_writeBlock($v_binary_data);
-                }
-
-                @gzclose($v_temp_tar);
-            }
-            elseif ($this->_compress_type == 'bz2') {
-                $end_blocks = 0;
-                
-                while (strlen($v_buffer = @bzread($v_temp_tar, 512)) > 0) {
-                    if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
-                        $end_blocks++;
-                        // do not copy end blocks, we will re-make them
-                        // after appending
-                        continue;
-                    } elseif ($end_blocks > 0) {
-                        for ($i = 0; $i < $end_blocks; $i++) {
-                            $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
-                        }
-                        $end_blocks = 0;
-                    }
-                    $v_binary_data = pack("a512", $v_buffer);
-                    $this->_writeBlock($v_binary_data);
-                }
-
-                @bzclose($v_temp_tar);
-            }
-
-            if (!@unlink($this->_tarname.".tmp")) {
-                $this->_error('Error while deleting temporary file \''
-				              .$this->_tarname.'.tmp\'');
-            }
-
-        } else {
-            // ----- For not compressed tar, just add files before the last
-			//       one or two 512 bytes block
-            if (!$this->_openReadWrite())
-               return false;
-
-            clearstatcache();
-            $v_size = filesize($this->_tarname);
-
-            // We might have zero, one or two end blocks.
-            // The standard is two, but we should try to handle
-            // other cases.
-            fseek($this->_file, $v_size - 1024);
-            if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
-                fseek($this->_file, $v_size - 1024);
-            }
-            elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
-                fseek($this->_file, $v_size - 512);
-            }
-        }
-
-        return true;
-    }
-    // }}}
-
-    // {{{ _append()
-    function _append($p_filelist, $p_add_dir='', $p_remove_dir='')
-    {
-        if (!$this->_openAppend())
-            return false;
-
-        if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir))
-           $this->_writeFooter();
-
-        $this->_close();
-
-        return true;
-    }
-    // }}}
-
-    // {{{ _dirCheck()
-
-    /**
-     * Check if a directory exists and create it (including parent
-     * dirs) if not.
-     *
-     * @param string $p_dir directory to check
-     *
-     * @return bool true if the directory exists or was created
-     */
-    function _dirCheck($p_dir)
-    {
-        clearstatcache();
-        if ((@is_dir($p_dir)) || ($p_dir == ''))
-            return true;
-
-        $p_parent_dir = dirname($p_dir);
-
-        if (($p_parent_dir != $p_dir) &&
-            ($p_parent_dir != '') &&
-            (!$this->_dirCheck($p_parent_dir)))
-             return false;
-
-        if (!@mkdir($p_dir, 0777)) {
-            $this->_error("Unable to create directory '$p_dir'");
-            return false;
-        }
-
-        return true;
-    }
-
-    // }}}
-
-    // {{{ _pathReduction()
-
-    /**
-     * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar",
-     * rand emove double slashes.
-     *
-     * @param string $p_dir path to reduce
-     *
-     * @return string reduced path
-     *
-     * @access private
-     *
-     */
-    function _pathReduction($p_dir)
-    {
-        $v_result = '';
-
-        // ----- Look for not empty path
-        if ($p_dir != '') {
-            // ----- Explode path by directory names
-            $v_list = explode('/', $p_dir);
-
-            // ----- Study directories from last to first
-            for ($i=sizeof($v_list)-1; $i>=0; $i--) {
-                // ----- Look for current path
-                if ($v_list[$i] == ".") {
-                    // ----- Ignore this directory
-                    // Should be the first $i=0, but no check is done
-                }
-                else if ($v_list[$i] == "..") {
-                    // ----- Ignore it and ignore the $i-1
-                    $i--;
-                }
-                else if (   ($v_list[$i] == '')
-				         && ($i!=(sizeof($v_list)-1))
-						 && ($i!=0)) {
-                    // ----- Ignore only the double '//' in path,
-                    // but not the first and last /
-                } else {
-                    $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?'/'
-					            .$v_result:'');
-                }
-            }
-        }
-        
-        if (defined('OS_WINDOWS') && OS_WINDOWS) {
-            $v_result = strtr($v_result, '\\', '/');
-        }
-        
-        return $v_result;
-    }
-
-    // }}}
-
-    // {{{ _translateWinPath()
-    function _translateWinPath($p_path, $p_remove_disk_letter=true)
-    {
-      if (defined('OS_WINDOWS') && OS_WINDOWS) {
-          // ----- Look for potential disk letter
-          if (   ($p_remove_disk_letter)
-		      && (($v_position = strpos($p_path, ':')) != false)) {
-              $p_path = substr($p_path, $v_position+1);
-          }
-          // ----- Change potential windows directory separator
-          if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) {
-              $p_path = strtr($p_path, '\\', '/');
-          }
-      }
-      return $p_path;
-    }
-    // }}}
-
-}
-?>
diff --git a/libs/PiwikTracker/PiwikTracker.php b/libs/PiwikTracker/PiwikTracker.php
index 8605e38e1f5a5b41cd6800c834950573566e0d18..15e3b8420c209a9f273427be36b2cd5c45fedfcc 100644
--- a/libs/PiwikTracker/PiwikTracker.php
+++ b/libs/PiwikTracker/PiwikTracker.php
@@ -1063,6 +1063,8 @@ class PiwikTracker
     /**
      * Hash function used internally by Piwik to hash a User ID into the Visitor ID.
      *
+     * Note: matches implementation of Tracker\Request->getUserIdHashed()
+     *
      * @param $id
      * @return string
      */
@@ -1071,7 +1073,6 @@ class PiwikTracker
         return substr( sha1( $id ), 0, 16);
     }
 
-
     /**
      * Forces the requests to be recorded for the specified Visitor ID.
      * Note: it is recommended to use ->setUserId($userId); instead.
diff --git a/libs/README.md b/libs/README.md
index 959d38e4b900072fa0f001a799918b294c62e5e9..8d7c7d8e6e74b2afb1aa7a82af344143f294aa19 100644
--- a/libs/README.md
+++ b/libs/README.md
@@ -17,8 +17,6 @@ third-party libraries:
    - The bug #4206 (GD with JIS-mapped Japanese Font Support) was fixed in this
      commit: https://github.com/piwik/piwik/commit/516c13d9b13ca3b908575eb809f7ad9d9397f0e1
      Changed files: class/pImage.class.php class/pDraw.class.php
- * PclZip/
-   - in r1960, ignore touch() - utime failed warning
  * PEAR/, PEAR.php
    - in r2419, add static keyword to isError and raiseError as it throws notices
      in HTML_Quickform2
diff --git a/misc/phpstorm-codestyles/Piwik_codestyle.xml b/misc/phpstorm-codestyles/Piwik_codestyle.xml
index 0fd9a921b5248da8b4e4e7023673eef4e45b980a..ed09f367d723f1b12d996a287d931435412ba5a4 100644
--- a/misc/phpstorm-codestyles/Piwik_codestyle.xml
+++ b/misc/phpstorm-codestyles/Piwik_codestyle.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="UTF-8"?>
 <code_scheme name="Piwik-codestyle">
   <option name="LINE_SEPARATOR" value="&#10;" />
   <option name="RIGHT_MARGIN" value="160" />
@@ -24,136 +23,6 @@
           <order>BREADTH_FIRST</order>
         </group>
       </groups>
-      <rules>
-        <rule>
-          <match>
-            <CONST />
-          </match>
-        </rule>
-        <rule>
-          <match>
-            <AND>
-              <FIELD />
-              <PUBLIC />
-              <STATIC />
-            </AND>
-          </match>
-        </rule>
-        <rule>
-          <match>
-            <AND>
-              <FIELD />
-              <PROTECTED />
-              <STATIC />
-            </AND>
-          </match>
-        </rule>
-        <rule>
-          <match>
-            <AND>
-              <FIELD />
-              <PRIVATE />
-              <STATIC />
-            </AND>
-          </match>
-        </rule>
-        <rule>
-          <match>
-            <AND>
-              <FIELD />
-              <PUBLIC />
-            </AND>
-          </match>
-        </rule>
-        <rule>
-          <match>
-            <AND>
-              <FIELD />
-              <PROTECTED />
-            </AND>
-          </match>
-        </rule>
-        <rule>
-          <match>
-            <AND>
-              <FIELD />
-              <PRIVATE />
-            </AND>
-          </match>
-        </rule>
-        <rule>
-          <match>
-            <CONSTRUCTOR />
-          </match>
-        </rule>
-        <rule>
-          <match>
-            <AND>
-              <METHOD />
-              <PUBLIC />
-              <STATIC />
-            </AND>
-          </match>
-        </rule>
-        <rule>
-          <match>
-            <AND>
-              <METHOD />
-              <PROTECTED />
-              <STATIC />
-            </AND>
-          </match>
-        </rule>
-        <rule>
-          <match>
-            <AND>
-              <METHOD />
-              <PRIVATE />
-              <STATIC />
-            </AND>
-          </match>
-        </rule>
-        <rule>
-          <match>
-            <AND>
-              <METHOD />
-              <PUBLIC />
-            </AND>
-          </match>
-        </rule>
-        <rule>
-          <match>
-            <AND>
-              <METHOD />
-              <PROTECTED />
-            </AND>
-          </match>
-        </rule>
-        <rule>
-          <match>
-            <AND>
-              <METHOD />
-              <PRIVATE />
-            </AND>
-          </match>
-        </rule>
-        <rule>
-          <match>
-            <TRAIT />
-          </match>
-        </rule>
-        <rule>
-          <match>
-            <INTERFACE />
-          </match>
-        </rule>
-        <rule>
-          <match>
-            <CLASS />
-          </match>
-        </rule>
-      </rules>
     </arrangement>
   </codeStyleSettings>
-</code_scheme>
-
+</code_scheme>
\ No newline at end of file
diff --git a/misc/proxy-hide-piwik-url/piwik.php b/misc/proxy-hide-piwik-url/piwik.php
index 80721cd6ea38b8c2ddf800b837bb90ecdb7c6a5d..d1c9e9ca3c29c795bd666493471cdae94221ae63 100644
--- a/misc/proxy-hide-piwik-url/piwik.php
+++ b/misc/proxy-hide-piwik-url/piwik.php
@@ -76,7 +76,7 @@ if (empty($_GET)) {
 $url = sprintf("%spiwik.php?cip=%s&token_auth=%s&", $PIWIK_URL, getVisitIp(), $TOKEN_AUTH);
 
 foreach ($_GET as $key => $value) {
-    $url .= $key . '=' . urlencode($value) . '&';
+    $url .= urlencode($key ). '=' . urlencode($value) . '&';
 }
 sendHeader("Content-Type: image/gif");
 $stream_options = array('http' => array(
diff --git a/plugins/API/API.php b/plugins/API/API.php
index 00758ca6bb6f96a8607e15fc610e9b9e4f2df52a..c65c04fffe8236642857921c8187953f01b7710e 100644
--- a/plugins/API/API.php
+++ b/plugins/API/API.php
@@ -259,7 +259,7 @@ class API extends \Piwik\Plugin\API
             SegmentExpression::MATCH_IS_NULL_OR_EMPTY,
             SegmentExpression::MATCH_NOT_EQUAL,
         );
-        if(in_array($matchType, $acceptedMatches)) {
+        if (in_array($matchType, $acceptedMatches)) {
             return $value;
         }
         $message = "Invalid Segment match type: try using 'userId' segment with one of the following match types: %s.";
@@ -524,7 +524,7 @@ class API extends \Piwik\Plugin\API
      */
     public function getSuggestedValuesForSegment($segmentName, $idSite)
     {
-        if(empty(Config::getInstance()->General['enable_segment_suggested_values'])) {
+        if (empty(Config::getInstance()->General['enable_segment_suggested_values'])) {
             return array();
         }
         Piwik::checkUserHasViewAccess($idSite);
@@ -549,7 +549,7 @@ class API extends \Piwik\Plugin\API
         }
 
         // if period=range is disabled, do not proceed
-        if(!Period\Factory::isPeriodEnabledForAPI('range')) {
+        if (!Period\Factory::isPeriodEnabledForAPI('range')) {
             return array();
         }
 
diff --git a/plugins/API/Controller.php b/plugins/API/Controller.php
index 9a6b3fc5e7b40723faba25e5d5d3d76be8ea5c68..18e39d58a2f34da3dd28da405236ca38df30b507 100644
--- a/plugins/API/Controller.php
+++ b/plugins/API/Controller.php
@@ -60,7 +60,7 @@ class Controller extends \Piwik\Plugin\Controller
         foreach ($segments as $segment) {
             // Eg. Event Value is a metric, not in the Visit metric category,
             // we make sure it is displayed along with the Events dimensions
-            if($segment['type'] == 'metric' && $segment['category'] != Piwik::translate('General_Visit')) {
+            if ($segment['type'] == 'metric' && $segment['category'] != Piwik::translate('General_Visit')) {
                 $segment['type'] = 'dimension';
             }
 
diff --git a/plugins/API/RowEvolution.php b/plugins/API/RowEvolution.php
index 7a5290c44fdd824740adedbd4147ddadb1254018..b57a788050d54e553497ee5cf85e1fc1c228866e 100644
--- a/plugins/API/RowEvolution.php
+++ b/plugins/API/RowEvolution.php
@@ -279,7 +279,7 @@ class RowEvolution
         // note: some reports should not be filtered with AddColumnProcessedMetrics
         // specifically, reports without the Metrics::INDEX_NB_VISITS metric such as Goals.getVisitsUntilConversion & Goal.getDaysToConversion
         // this is because the AddColumnProcessedMetrics filter removes all datable rows lacking this metric
-        if( isset($metadata['metrics']['nb_visits'])
+        if ( isset($metadata['metrics']['nb_visits'])
             && !empty($label)) {
             $parameters['filter_add_columns_when_show_all_columns'] = '1';
         }
@@ -430,7 +430,7 @@ class RowEvolution
                         $labelRow, $apiModule, $apiAction, $labelUseAbsoluteUrl);
 
                     $prettyLabel = $labelRow->getColumn('label_html');
-                    if($prettyLabel !== false) {
+                    if ($prettyLabel !== false) {
                         $actualLabels[$labelIdx] = $prettyLabel;
                     }
 
diff --git a/plugins/Actions/Actions/ActionSiteSearch.php b/plugins/Actions/Actions/ActionSiteSearch.php
index 9631aa0473ffda07bbf41757d6c064bc2cf97909..d19cfaa6fc71ac0942b926ed2e25c803d017e1ba 100644
--- a/plugins/Actions/Actions/ActionSiteSearch.php
+++ b/plugins/Actions/Actions/ActionSiteSearch.php
@@ -73,7 +73,7 @@ class ActionSiteSearch extends Action
     {
         $siteSearch = $this->detectSiteSearch($this->originalUrl);
 
-        if(empty($siteSearch)) {
+        if (empty($siteSearch)) {
             return false;
         }
 
@@ -169,10 +169,10 @@ class ActionSiteSearch extends Action
             // @see excludeQueryParametersFromUrl()
             // Excluded the detected parameters from the URL
             $parametersToExclude = array($categoryParameterRaw, $keywordParameterRaw);
-            if(isset($parsedUrl['query'])) {
+            if (isset($parsedUrl['query'])) {
                 $parsedUrl['query'] = UrlHelper::getQueryStringWithExcludedParameters(UrlHelper::getArrayFromQueryString($parsedUrl['query']), $parametersToExclude);
             }
-            if(isset($parsedUrl['fragment'])) {
+            if (isset($parsedUrl['fragment'])) {
                 $parsedUrl['fragment'] = UrlHelper::getQueryStringWithExcludedParameters(UrlHelper::getArrayFromQueryString($parsedUrl['fragment']), $parametersToExclude);
             }
         }
diff --git a/plugins/Actions/Archiver.php b/plugins/Actions/Archiver.php
index 14d42147444f3fdac34d2eb6600298af9dd68538..67408ced64aba07a08a384a04ac981f3ad211777 100644
--- a/plugins/Actions/Archiver.php
+++ b/plugins/Actions/Archiver.php
@@ -241,7 +241,7 @@ class Archiver extends \Piwik\Plugin\Archiver
         // 1) No result Keywords
         // 2) For each page view, count number of times the referrer page was a Site Search
         if ($this->isSiteSearchEnabled()) {
-                $this->updateQuerySelectFromForSiteSearch($select, $from);
+            $this->updateQuerySelectFromForSiteSearch($select, $from);
         }
 
         $this->archiveDayQueryProcess($select, $from, $where, $orderBy, $groupBy, "idaction_name", $rankingQuery);
diff --git a/plugins/Annotations/AnnotationList.php b/plugins/Annotations/AnnotationList.php
index 89a5b9131f1dad15601b8731bd40c4428f834d95..cf068e6f35e889f0d1dcd44ba62b6904a8a4f843 100755
--- a/plugins/Annotations/AnnotationList.php
+++ b/plugins/Annotations/AnnotationList.php
@@ -331,7 +331,7 @@ class AnnotationList
 
             if ($serialized !== false) {
                 $result[$id] = @unserialize($serialized);
-                if(empty($result[$id])) {
+                if (empty($result[$id])) {
                     // in case unserialize failed
                     $result[$id] = array();
                 }
diff --git a/plugins/Contents/Controller.php b/plugins/Contents/Controller.php
index daf319bb535a683791f2977b059a1746aeba959c..5785ba478c5d81e6ae147cd398d8b40fcb20118d 100644
--- a/plugins/Contents/Controller.php
+++ b/plugins/Contents/Controller.php
@@ -27,7 +27,7 @@ class Controller extends \Piwik\Plugin\Controller
             $reportsView->addReport(
                 $report->getCategory(),
                 $report->getName(),
-                'Contents.menu' . ucfirst($report->getAction())
+                'Contents.' . Report::PREFIX_ACTION_IN_MENU . ucfirst($report->getAction())
             );
         }
 
diff --git a/plugins/Contents/tests/ContentsTest.php b/plugins/Contents/tests/ContentsTest.php
index 2bd9549502ea338ca076642876343df82f0322b4..68875db127c9428f67db148bf204798d3fbfaee1 100644
--- a/plugins/Contents/tests/ContentsTest.php
+++ b/plugins/Contents/tests/ContentsTest.php
@@ -36,7 +36,7 @@ class ContentsTest extends IntegrationTestCase
             'Contents.getContentPieces',
             'Actions.get',
             'Actions.getPageUrls',
-            //'Live.getLastVisitsDetails'
+            'Live.getLastVisitsDetails'
         );
     }
 
@@ -55,7 +55,7 @@ class ContentsTest extends IntegrationTestCase
         $dayPeriod = 'day';
         $periods = array($dayPeriod, 'month');
 
-        $apisToTest = array('Contents', 'Actions.getPageUrls'); // , 'Live.getLastVisitsDetails'
+        $apisToTest = array('Contents', 'Actions.getPageUrls', 'Live.getLastVisitsDetails');
         $result = array(
             array($apiToCallProcessedReportMetadata, array(
                 'idSite'       => $idSite1,
diff --git a/plugins/Contents/tests/expected/test_Contents__Actions.getPageUrls_day.xml b/plugins/Contents/tests/expected/test_Contents__Actions.getPageUrls_day.xml
index c1e492c05ad7e70025c56ac29bc0de765d19fc84..fde347f2b53dc66196772a7ea0e6d522367e707d 100644
--- a/plugins/Contents/tests/expected/test_Contents__Actions.getPageUrls_day.xml
+++ b/plugins/Contents/tests/expected/test_Contents__Actions.getPageUrls_day.xml
@@ -5,18 +5,18 @@
 		<nb_visits>2</nb_visits>
 		<nb_uniq_visitors>2</nb_uniq_visitors>
 		<nb_hits>2</nb_hits>
-		<sum_time_spent>0</sum_time_spent>
+		<sum_time_spent>540</sum_time_spent>
 		<nb_hits_with_time_generation>2</nb_hits_with_time_generation>
 		<min_time_generation>0.333</min_time_generation>
 		<max_time_generation>0.333</max_time_generation>
 		<entry_nb_uniq_visitors>2</entry_nb_uniq_visitors>
 		<entry_nb_visits>2</entry_nb_visits>
 		<entry_nb_actions>2</entry_nb_actions>
-		<entry_sum_visit_length>2</entry_sum_visit_length>
+		<entry_sum_visit_length>542</entry_sum_visit_length>
 		<entry_bounce_count>2</entry_bounce_count>
 		<exit_nb_uniq_visitors>2</exit_nb_uniq_visitors>
 		<exit_nb_visits>2</exit_nb_visits>
-		<avg_time_on_page>0</avg_time_on_page>
+		<avg_time_on_page>270</avg_time_on_page>
 		<bounce_rate>100%</bounce_rate>
 		<exit_rate>100%</exit_rate>
 		<avg_time_generation>0.333</avg_time_generation>
diff --git a/plugins/Contents/tests/expected/test_Contents__Actions.getPageUrls_month.xml b/plugins/Contents/tests/expected/test_Contents__Actions.getPageUrls_month.xml
index 56760f4816e6fa769fae9b6c5eef29ed97ab764c..3dc775d40a8885e1c31b84093d990294ea6b06a2 100644
--- a/plugins/Contents/tests/expected/test_Contents__Actions.getPageUrls_month.xml
+++ b/plugins/Contents/tests/expected/test_Contents__Actions.getPageUrls_month.xml
@@ -4,19 +4,19 @@
 		<label>/page</label>
 		<nb_visits>2</nb_visits>
 		<nb_hits>2</nb_hits>
-		<sum_time_spent>0</sum_time_spent>
+		<sum_time_spent>540</sum_time_spent>
 		<nb_hits_with_time_generation>2</nb_hits_with_time_generation>
 		<min_time_generation>0.333</min_time_generation>
 		<max_time_generation>0.333</max_time_generation>
 		<entry_nb_visits>2</entry_nb_visits>
 		<entry_nb_actions>2</entry_nb_actions>
-		<entry_sum_visit_length>2</entry_sum_visit_length>
+		<entry_sum_visit_length>542</entry_sum_visit_length>
 		<entry_bounce_count>2</entry_bounce_count>
 		<exit_nb_visits>2</exit_nb_visits>
 		<sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
 		<sum_daily_entry_nb_uniq_visitors>2</sum_daily_entry_nb_uniq_visitors>
 		<sum_daily_exit_nb_uniq_visitors>2</sum_daily_exit_nb_uniq_visitors>
-		<avg_time_on_page>0</avg_time_on_page>
+		<avg_time_on_page>270</avg_time_on_page>
 		<bounce_rate>100%</bounce_rate>
 		<exit_rate>100%</exit_rate>
 		<avg_time_generation>0.333</avg_time_generation>
diff --git a/plugins/Contents/tests/expected/test_Contents__Live.getLastVisitsDetails_day.xml b/plugins/Contents/tests/expected/test_Contents__Live.getLastVisitsDetails_day.xml
index 6a083ba44892e9e18b3e2bec7f95c082d9b31303..989f816722569544d52920872adc903958cc58b6 100644
--- a/plugins/Contents/tests/expected/test_Contents__Live.getLastVisitsDetails_day.xml
+++ b/plugins/Contents/tests/expected/test_Contents__Live.getLastVisitsDetails_day.xml
@@ -1,450 +1,9 @@
 <?xml version="1.0" encoding="utf-8" ?>
 <result>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>6</idVisit>
-		<visitIp>156.5.3.2</visitIp>
-		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>91</visitDuration>
-		<visitDurationPretty>1 min 31s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>flash, java</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
-				<pluginName>flash</pluginName>
-			</row>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
-				<pluginName>java</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>4</idVisit>
-		<visitIp>156.5.3.2</visitIp>
-		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>61</visitDuration>
-		<visitDurationPretty>1 min 1s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>flash, java</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
-				<pluginName>flash</pluginName>
-			</row>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
-				<pluginName>java</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>5</idVisit>
-		<visitIp>156.5.3.2</visitIp>
-		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>1</visitDuration>
-		<visitDurationPretty>1s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>flash, java</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
-				<pluginName>flash</pluginName>
-			</row>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
-				<pluginName>java</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>2</idVisit>
-		<visitIp>156.5.3.2</visitIp>
-		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>121</visitDuration>
-		<visitDurationPretty>2 min 1s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>flash, java</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
-				<pluginName>flash</pluginName>
-			</row>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
-				<pluginName>java</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>3</idVisit>
-		<visitIp>156.5.3.2</visitIp>
-		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>0</visitDuration>
-		<visitDurationPretty>0s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>flash, java</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
-				<pluginName>flash</pluginName>
-			</row>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
-				<pluginName>java</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
 	<row>
 		<idSite>1</idSite>
 		<idVisit>1</idVisit>
 		<visitIp>156.5.3.2</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -469,6 +28,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -479,8 +39,8 @@
 		<visitEcommerceStatusIcon />
 		<daysSinceFirstVisit>0</daysSinceFirstVisit>
 		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>1</visitDuration>
-		<visitDurationPretty>1s</visitDurationPretty>
+		<visitDuration>271</visitDuration>
+		<visitDurationPretty>4 min 31s</visitDurationPretty>
 		<customVariables>
 		</customVariables>
 		<deviceType>Desktop</deviceType>
@@ -542,179 +102,22 @@
 	</row>
 	<row>
 		<idSite>1</idSite>
-		<idVisit>13</idVisit>
-		<visitIp>111.1.1.1</visitIp>
-		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>91</visitDuration>
-		<visitDurationPretty>1 min 31s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>director</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/director.gif</pluginIcon>
-				<pluginName>director</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>8</idVisit>
+		<idVisit>2</idVisit>
 		<visitIp>111.1.1.1</visitIp>
-		<userId />
 		
 		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>181</visitDuration>
-		<visitDurationPretty>3 min 1s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>director</plugins>
-		<pluginsIcons>
 			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/director.gif</pluginIcon>
-				<pluginName>director</pluginName>
+				<type>action</type>
+				<url>http://www.example.org/page</url>
+				<pageTitle>Ads</pageTitle>
+				<pageIdAction>2</pageIdAction>
+				
+				<pageId>13</pageId>
+				<generationTime>0.33s</generationTime>
+				<timeSpent>0</timeSpent>
+				<timeSpentPretty>0s</timeSpentPretty>
+				<icon />
 			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>11</idVisit>
-		<visitIp>111.1.1.1</visitIp>
-		<userId />
-		
-		<actionDetails>
 		</actionDetails>
 		<goalConversions>0</goalConversions>
 		<siteCurrency>USD</siteCurrency>
@@ -724,91 +127,8 @@
 		
 		
 		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>0</visitDuration>
-		<visitDurationPretty>0s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>director</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/director.gif</pluginIcon>
-				<pluginName>director</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>12</idVisit>
-		<visitIp>111.1.1.1</visitIp>
+		<actions>1</actions>
 		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -819,8 +139,8 @@
 		<visitEcommerceStatusIcon />
 		<daysSinceFirstVisit>0</daysSinceFirstVisit>
 		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>0</visitDuration>
-		<visitDurationPretty>0s</visitDurationPretty>
+		<visitDuration>271</visitDuration>
+		<visitDurationPretty>4 min 31s</visitDurationPretty>
 		<customVariables>
 		</customVariables>
 		<deviceType>Desktop</deviceType>
diff --git a/plugins/Contents/tests/expected/test_Contents__Live.getLastVisitsDetails_month.xml b/plugins/Contents/tests/expected/test_Contents__Live.getLastVisitsDetails_month.xml
index 6a083ba44892e9e18b3e2bec7f95c082d9b31303..989f816722569544d52920872adc903958cc58b6 100644
--- a/plugins/Contents/tests/expected/test_Contents__Live.getLastVisitsDetails_month.xml
+++ b/plugins/Contents/tests/expected/test_Contents__Live.getLastVisitsDetails_month.xml
@@ -1,450 +1,9 @@
 <?xml version="1.0" encoding="utf-8" ?>
 <result>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>6</idVisit>
-		<visitIp>156.5.3.2</visitIp>
-		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>91</visitDuration>
-		<visitDurationPretty>1 min 31s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>flash, java</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
-				<pluginName>flash</pluginName>
-			</row>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
-				<pluginName>java</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>4</idVisit>
-		<visitIp>156.5.3.2</visitIp>
-		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>61</visitDuration>
-		<visitDurationPretty>1 min 1s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>flash, java</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
-				<pluginName>flash</pluginName>
-			</row>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
-				<pluginName>java</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>5</idVisit>
-		<visitIp>156.5.3.2</visitIp>
-		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>1</visitDuration>
-		<visitDurationPretty>1s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>flash, java</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
-				<pluginName>flash</pluginName>
-			</row>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
-				<pluginName>java</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>2</idVisit>
-		<visitIp>156.5.3.2</visitIp>
-		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>121</visitDuration>
-		<visitDurationPretty>2 min 1s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>flash, java</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
-				<pluginName>flash</pluginName>
-			</row>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
-				<pluginName>java</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>3</idVisit>
-		<visitIp>156.5.3.2</visitIp>
-		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>0</visitDuration>
-		<visitDurationPretty>0s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>flash, java</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
-				<pluginName>flash</pluginName>
-			</row>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
-				<pluginName>java</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
 	<row>
 		<idSite>1</idSite>
 		<idVisit>1</idVisit>
 		<visitIp>156.5.3.2</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -469,6 +28,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -479,8 +39,8 @@
 		<visitEcommerceStatusIcon />
 		<daysSinceFirstVisit>0</daysSinceFirstVisit>
 		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>1</visitDuration>
-		<visitDurationPretty>1s</visitDurationPretty>
+		<visitDuration>271</visitDuration>
+		<visitDurationPretty>4 min 31s</visitDurationPretty>
 		<customVariables>
 		</customVariables>
 		<deviceType>Desktop</deviceType>
@@ -542,179 +102,22 @@
 	</row>
 	<row>
 		<idSite>1</idSite>
-		<idVisit>13</idVisit>
-		<visitIp>111.1.1.1</visitIp>
-		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>91</visitDuration>
-		<visitDurationPretty>1 min 31s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>director</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/director.gif</pluginIcon>
-				<pluginName>director</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>8</idVisit>
+		<idVisit>2</idVisit>
 		<visitIp>111.1.1.1</visitIp>
-		<userId />
 		
 		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>181</visitDuration>
-		<visitDurationPretty>3 min 1s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>director</plugins>
-		<pluginsIcons>
 			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/director.gif</pluginIcon>
-				<pluginName>director</pluginName>
+				<type>action</type>
+				<url>http://www.example.org/page</url>
+				<pageTitle>Ads</pageTitle>
+				<pageIdAction>2</pageIdAction>
+				
+				<pageId>13</pageId>
+				<generationTime>0.33s</generationTime>
+				<timeSpent>0</timeSpent>
+				<timeSpentPretty>0s</timeSpentPretty>
+				<icon />
 			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>11</idVisit>
-		<visitIp>111.1.1.1</visitIp>
-		<userId />
-		
-		<actionDetails>
 		</actionDetails>
 		<goalConversions>0</goalConversions>
 		<siteCurrency>USD</siteCurrency>
@@ -724,91 +127,8 @@
 		
 		
 		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>0</visitDuration>
-		<visitDurationPretty>0s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>director</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/director.gif</pluginIcon>
-				<pluginName>director</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>12</idVisit>
-		<visitIp>111.1.1.1</visitIp>
+		<actions>1</actions>
 		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -819,8 +139,8 @@
 		<visitEcommerceStatusIcon />
 		<daysSinceFirstVisit>0</daysSinceFirstVisit>
 		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>0</visitDuration>
-		<visitDurationPretty>0s</visitDurationPretty>
+		<visitDuration>271</visitDuration>
+		<visitDurationPretty>4 min 31s</visitDurationPretty>
 		<customVariables>
 		</customVariables>
 		<deviceType>Desktop</deviceType>
diff --git a/plugins/Contents/tests/expected/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml b/plugins/Contents/tests/expected/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml
index dfd70cba41e3e52c693c1f1700b1b74b7e08b56c..989f816722569544d52920872adc903958cc58b6 100644
--- a/plugins/Contents/tests/expected/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml
+++ b/plugins/Contents/tests/expected/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml
@@ -2,99 +2,22 @@
 <result>
 	<row>
 		<idSite>1</idSite>
-		<idVisit>6</idVisit>
+		<idVisit>1</idVisit>
 		<visitIp>156.5.3.2</visitIp>
-		<userId />
 		
 		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>91</visitDuration>
-		<visitDurationPretty>1 min 31s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>flash, java</plugins>
-		<pluginsIcons>
 			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
-				<pluginName>flash</pluginName>
-			</row>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
-				<pluginName>java</pluginName>
+				<type>action</type>
+				<url>http://www.example.org/page</url>
+				<pageTitle>Ads</pageTitle>
+				<pageIdAction>2</pageIdAction>
+				
+				<pageId>1</pageId>
+				<generationTime>0.33s</generationTime>
+				<timeSpent>0</timeSpent>
+				<timeSpentPretty>0s</timeSpentPretty>
+				<icon />
 			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>5</idVisit>
-		<visitIp>156.5.3.2</visitIp>
-		<userId />
-		
-		<actionDetails>
 		</actionDetails>
 		<goalConversions>0</goalConversions>
 		<siteCurrency>USD</siteCurrency>
@@ -104,7 +27,8 @@
 		
 		
 		<searches>0</searches>
-		<actions>0</actions>
+		<actions>1</actions>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -115,8 +39,8 @@
 		<visitEcommerceStatusIcon />
 		<daysSinceFirstVisit>0</daysSinceFirstVisit>
 		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>1</visitDuration>
-		<visitDurationPretty>1s</visitDurationPretty>
+		<visitDuration>271</visitDuration>
+		<visitDurationPretty>4 min 31s</visitDurationPretty>
 		<customVariables>
 		</customVariables>
 		<deviceType>Desktop</deviceType>
@@ -178,95 +102,22 @@
 	</row>
 	<row>
 		<idSite>1</idSite>
-		<idVisit>13</idVisit>
+		<idVisit>2</idVisit>
 		<visitIp>111.1.1.1</visitIp>
-		<userId />
 		
 		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>91</visitDuration>
-		<visitDurationPretty>1 min 31s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>director</plugins>
-		<pluginsIcons>
 			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/director.gif</pluginIcon>
-				<pluginName>director</pluginName>
+				<type>action</type>
+				<url>http://www.example.org/page</url>
+				<pageTitle>Ads</pageTitle>
+				<pageIdAction>2</pageIdAction>
+				
+				<pageId>13</pageId>
+				<generationTime>0.33s</generationTime>
+				<timeSpent>0</timeSpent>
+				<timeSpentPretty>0s</timeSpentPretty>
+				<icon />
 			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>12</idVisit>
-		<visitIp>111.1.1.1</visitIp>
-		<userId />
-		
-		<actionDetails>
 		</actionDetails>
 		<goalConversions>0</goalConversions>
 		<siteCurrency>USD</siteCurrency>
@@ -276,7 +127,8 @@
 		
 		
 		<searches>0</searches>
-		<actions>0</actions>
+		<actions>1</actions>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -287,8 +139,8 @@
 		<visitEcommerceStatusIcon />
 		<daysSinceFirstVisit>0</daysSinceFirstVisit>
 		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>0</visitDuration>
-		<visitDurationPretty>0s</visitDurationPretty>
+		<visitDuration>271</visitDuration>
+		<visitDurationPretty>4 min 31s</visitDurationPretty>
 		<customVariables>
 		</customVariables>
 		<deviceType>Desktop</deviceType>
diff --git a/plugins/Contents/tests/expected/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml b/plugins/Contents/tests/expected/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml
index bed0f8ffd99cfd090bee2c6c9a88b0eae4d24350..989f816722569544d52920872adc903958cc58b6 100644
--- a/plugins/Contents/tests/expected/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml
+++ b/plugins/Contents/tests/expected/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml
@@ -2,99 +2,22 @@
 <result>
 	<row>
 		<idSite>1</idSite>
-		<idVisit>4</idVisit>
+		<idVisit>1</idVisit>
 		<visitIp>156.5.3.2</visitIp>
-		<userId />
 		
 		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>61</visitDuration>
-		<visitDurationPretty>1 min 1s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>flash, java</plugins>
-		<pluginsIcons>
 			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
-				<pluginName>flash</pluginName>
-			</row>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
-				<pluginName>java</pluginName>
+				<type>action</type>
+				<url>http://www.example.org/page</url>
+				<pageTitle>Ads</pageTitle>
+				<pageIdAction>2</pageIdAction>
+				
+				<pageId>1</pageId>
+				<generationTime>0.33s</generationTime>
+				<timeSpent>0</timeSpent>
+				<timeSpentPretty>0s</timeSpentPretty>
+				<icon />
 			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>2</idVisit>
-		<visitIp>156.5.3.2</visitIp>
-		<userId />
-		
-		<actionDetails>
 		</actionDetails>
 		<goalConversions>0</goalConversions>
 		<siteCurrency>USD</siteCurrency>
@@ -104,95 +27,8 @@
 		
 		
 		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>121</visitDuration>
-		<visitDurationPretty>2 min 1s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>flash, java</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
-				<pluginName>flash</pluginName>
-			</row>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
-				<pluginName>java</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>3</idVisit>
-		<visitIp>156.5.3.2</visitIp>
+		<actions>1</actions>
 		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -203,8 +39,8 @@
 		<visitEcommerceStatusIcon />
 		<daysSinceFirstVisit>0</daysSinceFirstVisit>
 		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>0</visitDuration>
-		<visitDurationPretty>0s</visitDurationPretty>
+		<visitDuration>271</visitDuration>
+		<visitDurationPretty>4 min 31s</visitDurationPretty>
 		<customVariables>
 		</customVariables>
 		<deviceType>Desktop</deviceType>
@@ -266,95 +102,22 @@
 	</row>
 	<row>
 		<idSite>1</idSite>
-		<idVisit>8</idVisit>
+		<idVisit>2</idVisit>
 		<visitIp>111.1.1.1</visitIp>
-		<userId />
 		
 		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>181</visitDuration>
-		<visitDurationPretty>3 min 1s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>director</plugins>
-		<pluginsIcons>
 			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/director.gif</pluginIcon>
-				<pluginName>director</pluginName>
+				<type>action</type>
+				<url>http://www.example.org/page</url>
+				<pageTitle>Ads</pageTitle>
+				<pageIdAction>2</pageIdAction>
+				
+				<pageId>13</pageId>
+				<generationTime>0.33s</generationTime>
+				<timeSpent>0</timeSpent>
+				<timeSpentPretty>0s</timeSpentPretty>
+				<icon />
 			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>9</idVisit>
-		<visitIp>111.1.1.1</visitIp>
-		<userId />
-		
-		<actionDetails>
 		</actionDetails>
 		<goalConversions>0</goalConversions>
 		<siteCurrency>USD</siteCurrency>
@@ -364,91 +127,8 @@
 		
 		
 		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>0</visitDuration>
-		<visitDurationPretty>0s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>director</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/director.gif</pluginIcon>
-				<pluginName>director</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>10</idVisit>
-		<visitIp>111.1.1.1</visitIp>
+		<actions>1</actions>
 		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -459,8 +139,8 @@
 		<visitEcommerceStatusIcon />
 		<daysSinceFirstVisit>0</daysSinceFirstVisit>
 		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>0</visitDuration>
-		<visitDurationPretty>0s</visitDurationPretty>
+		<visitDuration>271</visitDuration>
+		<visitDurationPretty>4 min 31s</visitDurationPretty>
 		<customVariables>
 		</customVariables>
 		<deviceType>Desktop</deviceType>
diff --git a/plugins/Contents/tests/expected/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml b/plugins/Contents/tests/expected/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml
index 9595395b50c3befcac40bdabbc309faee9053546..989f816722569544d52920872adc903958cc58b6 100644
--- a/plugins/Contents/tests/expected/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml
+++ b/plugins/Contents/tests/expected/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml
@@ -1,450 +1,9 @@
 <?xml version="1.0" encoding="utf-8" ?>
 <result>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>6</idVisit>
-		<visitIp>156.5.3.2</visitIp>
-		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>91</visitDuration>
-		<visitDurationPretty>1 min 31s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>flash, java</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
-				<pluginName>flash</pluginName>
-			</row>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
-				<pluginName>java</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>4</idVisit>
-		<visitIp>156.5.3.2</visitIp>
-		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>61</visitDuration>
-		<visitDurationPretty>1 min 1s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>flash, java</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
-				<pluginName>flash</pluginName>
-			</row>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
-				<pluginName>java</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>5</idVisit>
-		<visitIp>156.5.3.2</visitIp>
-		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>1</visitDuration>
-		<visitDurationPretty>1s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>flash, java</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
-				<pluginName>flash</pluginName>
-			</row>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
-				<pluginName>java</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>2</idVisit>
-		<visitIp>156.5.3.2</visitIp>
-		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>121</visitDuration>
-		<visitDurationPretty>2 min 1s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>flash, java</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
-				<pluginName>flash</pluginName>
-			</row>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
-				<pluginName>java</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>3</idVisit>
-		<visitIp>156.5.3.2</visitIp>
-		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>0</visitDuration>
-		<visitDurationPretty>0s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>flash, java</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
-				<pluginName>flash</pluginName>
-			</row>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
-				<pluginName>java</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
 	<row>
 		<idSite>1</idSite>
 		<idVisit>1</idVisit>
 		<visitIp>156.5.3.2</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -469,6 +28,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -479,8 +39,8 @@
 		<visitEcommerceStatusIcon />
 		<daysSinceFirstVisit>0</daysSinceFirstVisit>
 		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>1</visitDuration>
-		<visitDurationPretty>1s</visitDurationPretty>
+		<visitDuration>271</visitDuration>
+		<visitDurationPretty>4 min 31s</visitDurationPretty>
 		<customVariables>
 		</customVariables>
 		<deviceType>Desktop</deviceType>
@@ -542,179 +102,22 @@
 	</row>
 	<row>
 		<idSite>1</idSite>
-		<idVisit>13</idVisit>
-		<visitIp>111.1.1.1</visitIp>
-		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>91</visitDuration>
-		<visitDurationPretty>1 min 31s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>director</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/director.gif</pluginIcon>
-				<pluginName>director</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>8</idVisit>
+		<idVisit>2</idVisit>
 		<visitIp>111.1.1.1</visitIp>
-		<userId />
 		
 		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>181</visitDuration>
-		<visitDurationPretty>3 min 1s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>director</plugins>
-		<pluginsIcons>
 			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/director.gif</pluginIcon>
-				<pluginName>director</pluginName>
+				<type>action</type>
+				<url>http://www.example.org/page</url>
+				<pageTitle>Ads</pageTitle>
+				<pageIdAction>2</pageIdAction>
+				
+				<pageId>13</pageId>
+				<generationTime>0.33s</generationTime>
+				<timeSpent>0</timeSpent>
+				<timeSpentPretty>0s</timeSpentPretty>
+				<icon />
 			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>12</idVisit>
-		<visitIp>111.1.1.1</visitIp>
-		<userId />
-		
-		<actionDetails>
 		</actionDetails>
 		<goalConversions>0</goalConversions>
 		<siteCurrency>USD</siteCurrency>
@@ -724,91 +127,8 @@
 		
 		
 		<searches>0</searches>
-		<actions>0</actions>
-		<visitorType>new</visitorType>
-		<visitorTypeIcon />
-		<visitConverted>0</visitConverted>
-		<visitConvertedIcon />
-		<visitCount>1</visitCount>
-		
-		<visitEcommerceStatus>none</visitEcommerceStatus>
-		<visitEcommerceStatusIcon />
-		<daysSinceFirstVisit>0</daysSinceFirstVisit>
-		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>0</visitDuration>
-		<visitDurationPretty>0s</visitDurationPretty>
-		<customVariables>
-		</customVariables>
-		<deviceType>Desktop</deviceType>
-		<events>0</events>
-		<provider>Unknown</provider>
-		<providerName>Unknown</providerName>
-		<providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
-		<referrerType>direct</referrerType>
-		<referrerTypeName>Direct Entry</referrerTypeName>
-		<referrerName />
-		<referrerKeyword />
-		<referrerKeywordPosition />
-		<referrerUrl />
-		<referrerSearchEngineUrl />
-		<referrerSearchEngineIcon />
-		<continent>Europe</continent>
-		<continentCode>eur</continentCode>
-		<country>France</country>
-		<countryCode>fr</countryCode>
-		<countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
-		<region />
-		<regionCode />
-		<city />
-		<location>France</location>
-		<latitude />
-		<longitude />
-		<operatingSystem>Windows XP</operatingSystem>
-		<operatingSystemCode>WXP</operatingSystemCode>
-		<operatingSystemShortName>Win XP</operatingSystemShortName>
-		<operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
-		<browserFamily>gecko</browserFamily>
-		<browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
-		<browserName>Firefox 3.6</browserName>
-		<browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
-		<browserCode>FF</browserCode>
-		<browserVersion>3.6</browserVersion>
-		<screenType>normal</screenType>
-		<resolution>1024x768</resolution>
-		<screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
-		<plugins>director</plugins>
-		<pluginsIcons>
-			<row>
-				<pluginIcon>plugins/UserSettings/images/plugins/director.gif</pluginIcon>
-				<pluginName>director</pluginName>
-			</row>
-		</pluginsIcons>
-		<visitLocalTime>12:34:06</visitLocalTime>
-		<visitLocalHour>12</visitLocalHour>
-		<daysSinceLastVisit>0</daysSinceLastVisit>
-		
-		
-		
-		
-		
-	</row>
-	<row>
-		<idSite>1</idSite>
-		<idVisit>9</idVisit>
-		<visitIp>111.1.1.1</visitIp>
+		<actions>1</actions>
 		<userId />
-		
-		<actionDetails>
-		</actionDetails>
-		<goalConversions>0</goalConversions>
-		<siteCurrency>USD</siteCurrency>
-		<siteCurrencySymbol>$</siteCurrencySymbol>
-		
-		
-		
-		
-		<searches>0</searches>
-		<actions>0</actions>
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -819,8 +139,8 @@
 		<visitEcommerceStatusIcon />
 		<daysSinceFirstVisit>0</daysSinceFirstVisit>
 		<daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
-		<visitDuration>0</visitDuration>
-		<visitDurationPretty>0s</visitDurationPretty>
+		<visitDuration>271</visitDuration>
+		<visitDurationPretty>4 min 31s</visitDurationPretty>
 		<customVariables>
 		</customVariables>
 		<deviceType>Desktop</deviceType>
diff --git a/plugins/CoreAdminHome/API.php b/plugins/CoreAdminHome/API.php
index 530cc101561f8b79d3dbc35db36a9ca4e128997b..a25a522cb4c539f80e67c9e8b5ba7acfc78927bf 100644
--- a/plugins/CoreAdminHome/API.php
+++ b/plugins/CoreAdminHome/API.php
@@ -66,19 +66,23 @@ class API extends \Piwik\Plugin\API
     public function invalidateArchivedReports($idSites, $dates, $period = false)
     {
         $idSites = Site::getIdSitesFromIdSitesString($idSites);
+
         if (empty($idSites)) {
             throw new Exception("Specify a value for &idSites= as a comma separated list of website IDs, for which your token_auth has 'admin' permission");
         }
+
         Piwik::checkUserHasAdminAccess($idSites);
 
-        if(!empty($period)) {
+        if (!empty($period)) {
             $period = Period\Factory::build($period, Date::today());
         }
 
         // Ensure the specified dates are valid
         $toInvalidate = $invalidDates = array();
+
         $dates = explode(',', trim($dates));
         $dates = array_unique($dates);
+
         foreach ($dates as $theDate) {
             $theDate = trim($theDate);
             try {
@@ -141,7 +145,7 @@ class API extends \Piwik\Plugin\API
             }
         }
 
-        if(empty($minDate)) {
+        if (empty($minDate)) {
             throw new Exception("Check the 'dates' parameter is a valid date.");
         }
 
@@ -169,7 +173,7 @@ class API extends \Piwik\Plugin\API
             $sql = implode(" OR ", $sql);
 
             $sqlPeriod = "";
-            if($invalidateForPeriod) {
+            if ($invalidateForPeriod) {
                 $sqlPeriod = " AND period = ? ";
                 $bind[] = $invalidateForPeriod;
             }
diff --git a/plugins/CoreAdminHome/Controller.php b/plugins/CoreAdminHome/Controller.php
index 6b672d07e8bc0ecc4c14856bbf0756b8b3848818..d1278607fdf7fb57e56a950a5f4ce463d4839fcd 100644
--- a/plugins/CoreAdminHome/Controller.php
+++ b/plugins/CoreAdminHome/Controller.php
@@ -278,7 +278,7 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
         $successLogo    = $logo->copyUploadedLogoToFilesystem();
         $successFavicon = $logo->copyUploadedFaviconToFilesystem();
 
-        if($successLogo || $successFavicon) {
+        if ($successLogo || $successFavicon) {
             return '1';
         }
         return '0';
@@ -291,7 +291,7 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
 
     private function saveGeneralSettings()
     {
-        if(!self::isGeneralSettingsAdminEnabled()) {
+        if (!self::isGeneralSettingsAdminEnabled()) {
             // General settings + Beta channel + SMTP settings is disabled
             return;
         }
@@ -339,7 +339,7 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
     {
         // Whether to display or not the general settings (cron, beta, smtp)
         $view->isGeneralSettingsAdminEnabled = self::isGeneralSettingsAdminEnabled();
-        if($view->isGeneralSettingsAdminEnabled) {
+        if ($view->isGeneralSettingsAdminEnabled) {
             $this->displayWarningIfConfigFileNotWritable();
         }
 
diff --git a/plugins/CoreAdminHome/CustomLogo.php b/plugins/CoreAdminHome/CustomLogo.php
index fe7e78ac6eb8f92dd1361e742a511bb1637ef52f..eda7ef06383f94d40940516eb9c79951e2086ed3 100644
--- a/plugins/CoreAdminHome/CustomLogo.php
+++ b/plugins/CoreAdminHome/CustomLogo.php
@@ -88,7 +88,7 @@ class CustomLogo
      */
     public function isCustomLogoWritable()
     {
-        if(Config::getInstance()->General['enable_custom_logo_check'] == 0) {
+        if (Config::getInstance()->General['enable_custom_logo_check'] == 0) {
             return true;
         }
         $pathUserLogo = $this->getPathUserLogo();
@@ -196,7 +196,7 @@ class CustomLogo
                 $image = imagecreatefrompng($file);
                 break;
             case 'image/gif':
-                $image = imagecreatefromgif($file);
+                $image = imagecreatefromgif ($file);
                 break;
             default:
                 return false;
diff --git a/plugins/CoreAdminHome/Tasks.php b/plugins/CoreAdminHome/Tasks.php
index 461ca5ca5240140d2262464a94a14ab8c9b29c6e..d633b9fd5d68efc5e2e033185c69d2d39c673266 100644
--- a/plugins/CoreAdminHome/Tasks.php
+++ b/plugins/CoreAdminHome/Tasks.php
@@ -35,7 +35,7 @@ class Tasks extends \Piwik\Plugin\Tasks
             list($year, $month) = explode('_', $date);
 
             // Somehow we may have archive tables created with older dates, prevent exception from being thrown
-            if($year > 1990) {
+            if ($year > 1990) {
                 ArchivePurger::purgeOutdatedArchives(Date::factory("$year-$month-15"));
             }
         }
diff --git a/plugins/CoreConsole/Commands/GenerateCommand.php b/plugins/CoreConsole/Commands/GenerateCommand.php
index e8661f028ea4ca676a9bb026ba4c19c16567a334..9fe95c06d3bebabb1591d3255d6e511d98a8ed4e 100644
--- a/plugins/CoreConsole/Commands/GenerateCommand.php
+++ b/plugins/CoreConsole/Commands/GenerateCommand.php
@@ -34,7 +34,9 @@ class GenerateCommand extends GeneratePluginBase
 
         $exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExampleCommand';
         $replace       = array(
+            'ExampleCommandDescription' => $commandName,
             'ExampleCommand' => $pluginName,
+            'examplecommand:helloworld' => strtolower($pluginName) . ':' . $this->buildCommandName($commandName),
             'examplecommand' => strtolower($pluginName),
             'HelloWorld'     => $commandName,
             'helloworld'     => strtolower($commandName)
@@ -49,6 +51,15 @@ class GenerateCommand extends GeneratePluginBase
         ));
     }
 
+    /**
+     * Convert MyComponentName => my-component-name
+     * @param  string $commandNameCamelCase
+     * @return string
+     */
+    protected function buildCommandName($commandNameCamelCase)
+    {
+        return strtolower(preg_replace('/([a-zA-Z])(?=[A-Z])/', '$1-', $commandNameCamelCase));
+    }
     /**
      * @param InputInterface $input
      * @param OutputInterface $output
@@ -64,12 +75,16 @@ class GenerateCommand extends GeneratePluginBase
                 throw new \InvalidArgumentException('You have to enter a command name');
             }
 
+            if (!ctype_alnum($testname)) {
+                throw new \InvalidArgumentException('Only alphanumeric characters are allowed as a command name. Use CamelCase if the name of your command contains multiple words.');
+            }
+
             return $testname;
         };
 
         if (empty($testname)) {
             $dialog   = $this->getHelperSet()->get('dialog');
-            $testname = $dialog->askAndValidate($output, 'Enter the name of the command: ', $validate);
+            $testname = $dialog->askAndValidate($output, 'Enter the name of the command (CamelCase): ', $validate);
         } else {
             $validate($testname);
         }
diff --git a/plugins/CoreConsole/Commands/GenerateTest.php b/plugins/CoreConsole/Commands/GenerateTest.php
index a9ace19a8b8d2aaf33e43269e865ac48d3b29845..ff68eec784b9ad5b5494a7ec6a5632bf796a7ddb 100644
--- a/plugins/CoreConsole/Commands/GenerateTest.php
+++ b/plugins/CoreConsole/Commands/GenerateTest.php
@@ -42,7 +42,7 @@ class GenerateTest extends GeneratePluginBase
          );
 
         $testClass  = $this->getTestClass($testType);
-        if(!empty($testClass)) {
+        if (!empty($testClass)) {
             $replace['\PHPUnit_Framework_TestCase'] = $testClass;
 
         }
@@ -167,7 +167,7 @@ class GenerateTest extends GeneratePluginBase
      */
     protected function getTestFilesWhitelist($testType)
     {
-        if('Integration' == $testType) {
+        if ('Integration' == $testType) {
             return array(
                 '/.gitignore',
                 '/tests',
diff --git a/plugins/CoreConsole/TravisYmlView.php b/plugins/CoreConsole/TravisYmlView.php
index cb4fabfda2662cfa3ec74ceb017aa57256338347..a89b5f1df52f7c03301c10ae01dccec97e0f5b63 100644
--- a/plugins/CoreConsole/TravisYmlView.php
+++ b/plugins/CoreConsole/TravisYmlView.php
@@ -89,6 +89,7 @@ class TravisYmlView extends View
         $this->pluginName = $pluginName;
 
         $customTravisBuildSteps = array();
+
         foreach (self::$travisYmlExtendableSectionNames as $name) {
             $customTravisBuildSteps[$name] = array();
 
@@ -102,6 +103,7 @@ class TravisYmlView extends View
                 $customTravisBuildSteps[$name]['after'] = $this->changeIndent(file_get_contents($afterStepsTemplate), '  ');
             }
         }
+
         $this->customTravisBuildSteps = $customTravisBuildSteps;
     }
 
@@ -160,12 +162,14 @@ class TravisYmlView extends View
         preg_match_all("/^[a-zA-Z_]+:/m", $yamlText, $allMatches, PREG_OFFSET_CAPTURE);
 
         $result = array();
+
         foreach ($allMatches[0] as $match) {
             $matchLength = strlen($match[0]);
             $sectionName = substr($match[0], 0, $matchLength - 1);
 
             $result[$sectionName] = $match[1] + $matchLength;
         }
+
         return $result;
     }
 
@@ -206,6 +210,7 @@ class TravisYmlView extends View
             $testsToExclude[] = array('php' => '5.4',
                                       'env' => 'TEST_SUITE=PluginTests MYSQL_ADAPTER=PDO_MYSQL TEST_AGAINST_CORE=latest_stable');
         }
+
         if ($this->isTargetPluginContainsUITests()) {
             $testsToRun[] = array('name' => 'UITests',
                                   'vars' => "MYSQL_ADAPTER=PDO_MYSQL");
diff --git a/plugins/CoreHome/Columns/UserId.php b/plugins/CoreHome/Columns/UserId.php
index 146a7ea4c68a1e2d1d6264b0b10cdb8bf537e39b..55fea6b5173fe6345efde2730c5510a5268eeabe 100644
--- a/plugins/CoreHome/Columns/UserId.php
+++ b/plugins/CoreHome/Columns/UserId.php
@@ -48,12 +48,7 @@ class UserId extends VisitDimension
      */
     public function onExistingVisit(Request $request, Visitor $visitor, $action)
     {
-        $forcedUserId = $request->getForcedUserId();
-        if ($forcedUserId) {
-            return $forcedUserId;
-        }
-
-        return false;
+        return $request->getForcedUserId();
     }
 
 }
\ No newline at end of file
diff --git a/plugins/CoreHome/Columns/VisitGoalBuyer.php b/plugins/CoreHome/Columns/VisitGoalBuyer.php
index 1fcf91cb965b85c2b944d65988b774097e1a7a4d..8867efd70848a27d5dfad7a7c73dc46a4880cc8d 100644
--- a/plugins/CoreHome/Columns/VisitGoalBuyer.php
+++ b/plugins/CoreHome/Columns/VisitGoalBuyer.php
@@ -72,7 +72,7 @@ class VisitGoalBuyer extends VisitDimension
         // Ecommerce buyer status
         $visitEcommerceStatus = $this->getBuyerType($request, $goalBuyer);
 
-        if($visitEcommerceStatus != self::TYPE_BUYER_NONE
+        if ($visitEcommerceStatus != self::TYPE_BUYER_NONE
             // only update if the value has changed (prevents overwriting the value in case a request has
             // updated it in the meantime)
             && $visitEcommerceStatus != $goalBuyer) {
diff --git a/plugins/CoreHome/Controller.php b/plugins/CoreHome/Controller.php
index b0d3770cbe12e344b98c4dac97f20d759d745009..387c31e9e9a221b2a22d84d36745186a7329ffd8 100644
--- a/plugins/CoreHome/Controller.php
+++ b/plugins/CoreHome/Controller.php
@@ -103,9 +103,11 @@ class Controller extends \Piwik\Plugin\Controller
         ) {
             $module = 'MultiSites';
         }
+
         if ($defaultReport == Piwik::getLoginPluginName()) {
             $module = Piwik::getLoginPluginName();
         }
+
         $idSite = Common::getRequestVar('idSite', false, 'int');
         parent::redirectToIndex($module, $action, $idSite);
     }
@@ -113,10 +115,12 @@ class Controller extends \Piwik\Plugin\Controller
     public function showInContext()
     {
         $controllerName = Common::getRequestVar('moduleToLoad');
-        $actionName = Common::getRequestVar('actionToLoad', 'index');
+        $actionName     = Common::getRequestVar('actionToLoad', 'index');
+
         if ($actionName == 'showInContext') {
             throw new Exception("Preventing infinite recursion...");
         }
+
         $view = $this->getDefaultIndexView();
         $view->content = FrontController::getInstance()->fetchDispatch($controllerName, $actionName);
         return $view->render();
@@ -146,12 +150,16 @@ class Controller extends \Piwik\Plugin\Controller
         ) {
             return;
         }
+
         $websiteId = Common::getRequestVar('idSite', false, 'int');
+
         if ($websiteId) {
+
             $website = new Site($websiteId);
-            $datetimeCreationDate = $website->getCreationDate()->getDatetime();
+            $datetimeCreationDate      = $website->getCreationDate()->getDatetime();
             $creationDateLocalTimezone = Date::factory($datetimeCreationDate, $website->getTimezone())->toString('Y-m-d');
-            $todayLocalTimezone = Date::factory('now', $website->getTimezone())->toString('Y-m-d');
+            $todayLocalTimezone        = Date::factory('now', $website->getTimezone())->toString('Y-m-d');
+
             if ($creationDateLocalTimezone == $todayLocalTimezone) {
                 Piwik::redirectToModule('CoreHome', 'index',
                     array('date'   => 'today',
diff --git a/plugins/CoreHome/CoreHome.php b/plugins/CoreHome/CoreHome.php
index 187f356c5e5e9928cc511e1d31a27e6df96cc473..f833b1e5cc8c838359d499ce93022a0872caf606 100644
--- a/plugins/CoreHome/CoreHome.php
+++ b/plugins/CoreHome/CoreHome.php
@@ -69,6 +69,7 @@ class CoreHome extends \Piwik\Plugin
         $stylesheets[] = "plugins/CoreHome/angularjs/enrichedheadline/enrichedheadline.directive.less";
         $stylesheets[] = "plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.less";
         $stylesheets[] = "plugins/CoreHome/angularjs/dialogtoggler/ngdialog.less";
+        $stylesheets[] = "plugins/CoreHome/angularjs/notification/notification.directive.less";
     }
 
     public function getJsFiles(&$jsFiles)
@@ -149,6 +150,9 @@ class CoreHome extends \Piwik\Plugin
         $jsFiles[] = "plugins/CoreHome/angularjs/dialogtoggler/dialogtoggler.directive.js";
         $jsFiles[] = "plugins/CoreHome/angularjs/dialogtoggler/dialogtoggler.controller.js";
         $jsFiles[] = "plugins/CoreHome/angularjs/dialogtoggler/dialogtoggler-urllistener.service.js";
+
+        $jsFiles[] = "plugins/CoreHome/angularjs/notification/notification.controller.js";
+        $jsFiles[] = "plugins/CoreHome/angularjs/notification/notification.directive.js";
     }
 
     public function getClientSideTranslationKeys(&$translationKeys)
diff --git a/plugins/CoreHome/DataTableRowAction/RowEvolution.php b/plugins/CoreHome/DataTableRowAction/RowEvolution.php
index 915139d30000fcf0d8ddd6e95314469270b362f1..b0922f05bfbce38bb1e873caebc1ea248f2c2b2e 100644
--- a/plugins/CoreHome/DataTableRowAction/RowEvolution.php
+++ b/plugins/CoreHome/DataTableRowAction/RowEvolution.php
@@ -86,7 +86,7 @@ class RowEvolution
         if (empty($this->apiMethod)) throw new Exception("Parameter apiMethod not set.");
 
         $this->label = ResponseBuilder::getLabelFromRequest($_GET);
-        if(!is_array($this->label)) {
+        if (!is_array($this->label)) {
             throw new Exception("Expected label to be an array, got instead: " . $this->label);
         }
         $this->label = $this->label[0];
@@ -337,7 +337,7 @@ class RowEvolution
         $labelPretty = $dataTableMap->getColumn('label_html');
         $labelPretty = array_filter($labelPretty, 'strlen');
         $labelPretty = current($labelPretty);
-        if(!empty($labelPretty)) {
+        if (!empty($labelPretty)) {
             return $labelPretty;
         }
         return $rowLabel;
diff --git a/plugins/CoreHome/Visitor.php b/plugins/CoreHome/Visitor.php
index 688d1c8bb62c1ce387d6542949b6a1c8b6e6b57d..35b64b3d30eb099e77aed4928bf1a3b0ba6d6120 100644
--- a/plugins/CoreHome/Visitor.php
+++ b/plugins/CoreHome/Visitor.php
@@ -102,10 +102,10 @@ class Visitor
     function getUserId()
     {
         if (isset($this->details['user_id'])
-            && !is_null($this->details['user_id'])) {
+            && strlen($this->details['user_id']) > 0) {
             return $this->details['user_id'];
         }
-        return false;
+        return null;
     }
 
 }
\ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/common/directives/translate.js b/plugins/CoreHome/angularjs/common/directives/translate.js
index 4cc20e83b3d88da0465320c35b872eb1b7d962e8..5a9588f7c6f31fab33ca9d85ac056890f3c7f751 100644
--- a/plugins/CoreHome/angularjs/common/directives/translate.js
+++ b/plugins/CoreHome/angularjs/common/directives/translate.js
@@ -12,6 +12,8 @@
  * within the sprintf args. Using the filter, this is not possible w/o manually sanitizing
  * and creating trusted HTML, which is not as safe.
  *
+ * Note: nesting this directive is not supported.
+ *
  * Usage:
  * <span piwik-translate="Plugin_TranslationToken">
  *     first arg::<strong>second arg</strong>::{{ unsafeDataThatWillBeSanitized }}
@@ -22,10 +24,8 @@
 
     function piwikTranslate() {
         return {
+            priority: 1,
             restrict: 'A',
-            scope: {
-                piwikTranslate: '@'
-            },
             compile: function(element, attrs) {
                 var parts = element.html().split('::'),
                     translated = _pk_translate(attrs.piwikTranslate, parts);
diff --git a/plugins/CoreHome/angularjs/common/services/piwik-api.js b/plugins/CoreHome/angularjs/common/services/piwik-api.js
index 7b15c48fa8ab7a5ae34993cff601b191b4a1cc19..80ac84312d956f628ec047f86471676d1d9dd67b 100644
--- a/plugins/CoreHome/angularjs/common/services/piwik-api.js
+++ b/plugins/CoreHome/angularjs/common/services/piwik-api.js
@@ -44,7 +44,9 @@
         }
 
         function createResponseErrorNotification(response, options) {
-            if (response.message) {
+            if (response.message
+                && options.createErrorNotification
+            ) {
                 var UI = require('piwik/UI');
                 var notification = new UI.Notification();
                 notification.show(response.message, {
@@ -66,6 +68,10 @@
                 options = {};
             }
 
+            if (options.createErrorNotification === undefined) {
+                options.createErrorNotification = true;
+            }
+
             var deferred = $q.defer(),
                 requestPromise = deferred.promise;
 
@@ -271,7 +277,7 @@
              * @deprecated
              */
             abort: abort,
-            abortAll: abortAll,
+            abortAll: abortAll
         };
     }
 })();
\ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/notification/notification.controller.js b/plugins/CoreHome/angularjs/notification/notification.controller.js
new file mode 100644
index 0000000000000000000000000000000000000000..645cc13e594c7587f995cc750e45f571c4851562
--- /dev/null
+++ b/plugins/CoreHome/angularjs/notification/notification.controller.js
@@ -0,0 +1,34 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+(function () {
+    angular.module('piwikApp').controller('NotificationController', NotificationController);
+
+    NotificationController.$inject = ['piwikApi'];
+
+    function NotificationController(piwikApi) {
+        /**
+         * Marks a persistent notification as read so it will not reappear on the next page
+         * load.
+         */
+        this.markNotificationAsRead = function () {
+            var notificationId = this.notificationId;
+            if (!notificationId) {
+                return;
+            }
+
+            piwikApi.post(
+                { // GET params
+                    module: 'CoreHome',
+                    action: 'markNotificationAsRead'
+                },
+                { // POST params
+                    notificationId: notificationId
+                }
+            );
+        };
+    }
+})();
\ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/notification/notification.directive.html b/plugins/CoreHome/angularjs/notification/notification.directive.html
new file mode 100644
index 0000000000000000000000000000000000000000..a643be8a3b3da2df52f46e0bd4ac28843c9efdfc
--- /dev/null
+++ b/plugins/CoreHome/angularjs/notification/notification.directive.html
@@ -0,0 +1,8 @@
+<div class="notification system">
+    <button type="button" class="close" data-dismiss="alert" ng-if="!noclear" ng-click="notification.markNotificationAsRead()">&times;</button>
+    <strong ng-if="title">{{ title }}</strong>
+
+    <!-- ng-transclude causes directive child elements to be added here -->
+    <div ng-transclude style="display:inline-block"></div>
+
+</div>
\ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/notification/notification.directive.js b/plugins/CoreHome/angularjs/notification/notification.directive.js
new file mode 100644
index 0000000000000000000000000000000000000000..167c61575b317e3835f83d738ea9a2542af70eac
--- /dev/null
+++ b/plugins/CoreHome/angularjs/notification/notification.directive.js
@@ -0,0 +1,95 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+/**
+ * Directive to show a notification.
+ *
+ * Note: using this directive is preferred over the Notification class (which uses jquery
+ * exclusively).
+ *
+ * Supports the following attributes:
+ *
+ * * **context**: Either 'success', 'error', 'info', 'warning'
+ * * **type**: Either 'toast', 'persistent', 'transient'
+ * * **noclear**: If truthy, no clear button is displayed. For persistent notifications, has no effect.
+ *
+ * Usage:
+ *
+ *     <div piwik-notification context="success" type="persistent" noclear="true">
+ *         <strong>Info: </strong>My notification message.
+ *     </div>
+ */
+(function () {
+    angular.module('piwikApp').directive('piwikNotification', piwikNotification);
+
+    piwikNotification.$inject = ['piwik', '$timeout'];
+
+    function piwikNotification(piwik, $timeout) {
+        return {
+            restrict: 'A',
+            scope: {
+                notificationId: '@?',
+                title: '@?notificationTitle', // TODO: shouldn't need this since the title can be specified within
+                                              //       HTML of the node that uses the directive.
+                context: '@?',
+                type: '@?',
+                noclear: '=?'
+            },
+            transclude: true,
+            templateUrl: 'plugins/CoreHome/angularjs/notification/notification.directive.html?cb=' + piwik.cacheBuster,
+            controller: 'NotificationController',
+            controllerAs: 'notification',
+            link: function (scope, element, attrs) {
+                if (scope.context) {
+                    element.children('.notification').addClass('notification-' + scope.context);
+                }
+
+                if (scope.type == 'persistent') {
+                    // otherwise it is never possible to dismiss the notification
+                    scope.noclear = false;
+                }
+
+                if (scope.notificationId) {
+                    closeExistingNotificationHavingSameIdIfNeeded();
+                }
+
+                if ('toast' == scope.type) {
+                    addToastEvent();
+                }
+
+                if (!scope.noclear) {
+                    addCloseEvent();
+                }
+
+                function closeExistingNotificationHavingSameIdIfNeeded() {
+                    // TODO: instead of doing a global query for notification, there should be a notification-container
+                    //       directive that manages notifications.
+                    var existingNode = angular.element('.system.notification[notification-id=' + attrs.id + ']');
+                    if (existingNode && existingNode.length) {
+                        existingNode.remove();
+                    }
+                }
+
+                function addToastEvent() {
+                    $timeout(function () {
+                        element.fadeOut('slow', function() {
+                            element.remove();
+                        });
+                    }, 12 * 1000);
+                }
+
+                function addCloseEvent() {
+                    element.on('click', '.close', function (event) {
+                        if (event && event.delegateTarget) {
+                            angular.element(event.delegateTarget).remove();
+                        }
+                    });
+                }
+            }
+        };
+    }
+})();
\ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/notification/notification.directive.less b/plugins/CoreHome/angularjs/notification/notification.directive.less
new file mode 100644
index 0000000000000000000000000000000000000000..bc3c5e3f5fd6922bde7bec2b6c56240022c6e9d4
--- /dev/null
+++ b/plugins/CoreHome/angularjs/notification/notification.directive.less
@@ -0,0 +1,84 @@
+.system.notification {
+  color: #9b7a44;
+  float: none;
+
+  padding: 15px 35px 15px 15px;
+  text-shadow: 0 1px 0 rgba(255,255,255,.5);
+  background-color: #ffffe0;
+  border: 1px solid #e6db55;
+  border-radius: 3px;
+  font-size: 14px;
+  margin: 0px;
+  margin-bottom: 16px;
+
+  a {
+    color: #9b7a44;
+    text-decoration: underline;
+  }
+
+  .close {
+    position: relative;
+    top: -5px;
+    right: -28px;
+    line-height: 20px;
+  }
+
+  button.close {
+    padding: 0;
+    cursor: pointer;
+    background: transparent;
+    border: 0;
+    -webkit-appearance: none;
+  }
+  .close {
+    float: right;
+    font-size: 20px;
+    font-weight: bold;
+    line-height: 20px;
+    color: #000000;
+    text-shadow: 0 1px 0 #ffffff;
+    opacity: 0.2;
+    filter: alpha(opacity=20);
+  }
+
+  &.notification-success {
+    background-color: #dff0d8;
+    border-color: #c3d6b7;
+    color: #468847;
+
+    a {
+      color: #468847
+    }
+  }
+  &.notification-danger,
+  &.notification-error {
+    background-color: #f2dede;
+    border-color: #d5bfc4;
+    color: #b94a48;
+
+    a {
+      color: #b94a48
+    }
+  }
+  &.notification-info {
+    background-color: #d9edf7;
+    border-color: #a7d3e3;
+    color: #3a87ad;
+
+    a {
+      color: #3a87ad
+    }
+  }
+
+  &.notification-block {
+    padding-top: 14px;
+    padding-bottom: 14px;
+  }
+  &.notification-block > p,
+  &.notification-block > ul {
+    margin-bottom: 0;
+  }
+  &.notification-block p + p {
+    margin-top: 5px;
+  }
+}
\ No newline at end of file
diff --git a/plugins/CoreHome/javascripts/notification.js b/plugins/CoreHome/javascripts/notification.js
index 7bd92042a5f21a1a4ff583c74d87a47a66e24eb9..266477446e619cd938980b0e6e4a5ef01c042bbe 100644
--- a/plugins/CoreHome/javascripts/notification.js
+++ b/plugins/CoreHome/javascripts/notification.js
@@ -50,26 +50,8 @@
             options = {};
         }
 
-        if ('persistent' == options.type) {
-            // otherwise it is never possible to dismiss the notification
-            options.noclear = false;
-        }
-
-        closeExistingNotificationHavingSameIdIfNeeded(options);
-
-        var template          = generateNotificationHtmlMarkup(options, message);
-        var $notificationNode = placeNotification(template, options);
-        this.$node = $notificationNode;
-
-        if ('persistent' == options.type) {
-            addPersistentEvent($notificationNode);
-        } else if ('toast' == options.type) {
-            addToastEvent($notificationNode);
-        }
-
-        if (!options.noclear) {
-            addCloseEvent($notificationNode);
-        }
+        var template = generateNotificationHtmlMarkup(options, message);
+        this.$node   = placeNotification(template, options);
     };
 
     Notification.prototype.scrollToNotification = function () {
@@ -80,69 +62,37 @@
 
     exports.Notification = Notification;
 
-    function closeExistingNotificationHavingSameIdIfNeeded(options)
-    {
-        if (!options.id) {
-            return;
-        }
-
-        var $existingNode = $('.system.notification[data-id=' + options.id + ']');
-        if ($existingNode && $existingNode.length) {
-            $existingNode.remove();
-        }
-    }
-
     function generateNotificationHtmlMarkup(options, message) {
-        var template = buildNotificationStart(options);
-
-        if (!options.noclear) {
-            template += buildClearButton();
-        }
-
-        if (options.title) {
-            template += buildTitle(options);
-        }
-
-        template += message;
-        template += buildNotificationEnd();
-
-        return template;
-    }
-
-    function buildNotificationStart(options) {
-        var template = '<div class="notification system';
-
-        if (options.context) {
-            template += ' notification-' + options.context;
-        }
-
-        template += '"';
-
-        if (options.id) {
-            template += ' data-id="' + options.id + '"';
+        var attributeMapping = {
+                id: 'notification-id',
+                title: 'notification-title',
+                context: 'context',
+                type: 'type',
+                noclear: 'noclear'
+            },
+            html = '<div piwik-notification';
+
+        for (var key in attributeMapping) {
+            if (attributeMapping.hasOwnProperty(key)
+                && options[key]
+            ) {
+                html += ' ' + attributeMapping[key] + '="' + options[key].toString().replace(/"/g, "&quot;") + '"';
+            }
         }
 
-        template += '>';
-
-        return template;
-    }
-
-    function buildNotificationEnd() {
-        return '</div>';
-    }
-
-    function buildClearButton() {
-        return '<button type="button" class="close" data-dismiss="alert">&times;</button>';
-    }
+        html += '>' + message + '</div>';
 
-    function buildTitle(options) {
-        return '<strong>' + options.title + '</strong> ';
+        return html;
     }
 
     function placeNotification(template, options) {
-
         var $notificationNode = $(template);
 
+        // compile the template in angular
+        angular.element(document).injector().invoke(function ($compile, $rootScope) {
+            $compile($notificationNode)($rootScope.$new(true));
+        });
+
         if (options.style) {
             $notificationNode.css(options.style);
         }
@@ -158,41 +108,4 @@
 
         return $notificationNode;
     }
-
-    function addToastEvent($notificationNode)
-    {
-        setTimeout(function () {
-            $notificationNode.fadeOut( 'slow', function() {
-                $notificationNode.remove();
-                $notificationNode = null;
-            });
-        }, 12 * 1000);
-    }
-
-    function addCloseEvent($notificationNode) {
-        $notificationNode.on('click', '.close', function (event) {
-            if (event && event.delegateTarget) {
-                $(event.delegateTarget).remove();
-            }
-        });
-    };
-
-    function addPersistentEvent($notificationNode) {
-        var notificationId = $notificationNode.data('id');
-
-        if (!notificationId) {
-            return;
-        }
-
-        $notificationNode.on('click', '.close', function (event) {
-            var ajaxHandler = new ajaxHelper();
-            ajaxHandler.addParams({
-                module: 'CoreHome',
-                action: 'markNotificationAsRead'
-            }, 'GET');
-            ajaxHandler.addParams({notificationId: notificationId}, 'POST');
-            ajaxHandler.send(true);
-        });
-    };
-
 })(jQuery, require);
\ No newline at end of file
diff --git a/plugins/CoreHome/stylesheets/notification.less b/plugins/CoreHome/stylesheets/notification.less
index 23b29e1fe42070e316b0efb2e88241c415788212..36f7085f6f8263d1d8c8950a547446d05ebdd4ec 100644
--- a/plugins/CoreHome/stylesheets/notification.less
+++ b/plugins/CoreHome/stylesheets/notification.less
@@ -5,89 +5,4 @@
   .notification {
     margin: 10px;
   }
-}
-
-.system.notification {
-  color: #9b7a44;
-  float: none;
-
-  padding: 15px 35px 15px 15px;
-  text-shadow: 0 1px 0 rgba(255,255,255,.5);
-  background-color: #ffffe0;
-  border: 1px solid #e6db55;
-  border-radius: 3px;
-  font-size: 14px;
-  margin: 0px;
-  margin-bottom: 16px;
-
-  a {
-    color: #9b7a44;
-    text-decoration: underline;
-  }
-
-  .close {
-    position: relative;
-    top: -5px;
-    right: -28px;
-    line-height: 20px;
-  }
-
-  button.close {
-    padding: 0;
-    cursor: pointer;
-    background: transparent;
-    border: 0;
-    -webkit-appearance: none;
-  }
-  .close {
-    float: right;
-    font-size: 20px;
-    font-weight: bold;
-    line-height: 20px;
-    color: #000000;
-    text-shadow: 0 1px 0 #ffffff;
-    opacity: 0.2;
-    filter: alpha(opacity=20);
-  }
-
-  &.notification-success {
-    background-color: #dff0d8;
-    border-color: #c3d6b7;
-    color: #468847;
-
-    a {
-      color: #468847
-    }
-  }
-  &.notification-danger,
-  &.notification-error {
-    background-color: #f2dede;
-    border-color: #d5bfc4;
-    color: #b94a48;
-
-    a {
-      color: #b94a48
-    }
-  }
-  &.notification-info {
-    background-color: #d9edf7;
-    border-color: #a7d3e3;
-    color: #3a87ad;
-
-    a {
-      color: #3a87ad
-    }
-  }
-
-  &.notification-block {
-    padding-top: 14px;
-    padding-bottom: 14px;
-  }
-  &.notification-block > p,
-  &.notification-block > ul {
-    margin-bottom: 0;
-  }
-  &.notification-block p + p {
-    margin-top: 5px;
-  }
-}
+}
\ No newline at end of file
diff --git a/plugins/CoreHome/templates/_topBarTopMenu.twig b/plugins/CoreHome/templates/_topBarTopMenu.twig
index 5f5831237aa12e0907242e7cdb4693d373fab5d4..fc09b62f78f9f1f3ca99d66fcff275cbdbe1b542 100644
--- a/plugins/CoreHome/templates/_topBarTopMenu.twig
+++ b/plugins/CoreHome/templates/_topBarTopMenu.twig
@@ -36,17 +36,8 @@
              menu-title="{{ helloAlias|trim }}"
              piwik-menudropdown>
 
-            {% if userLogin != 'anonymous' %}
-                {% if isAdminLayout is defined and currentModule == 'UsersManager' and currentAction == 'userSettings' %}
-                    <a class="item active" href="index.php?module=CoreAdminHome">{{ 'General_Settings'|translate }}</a>
-                {% else %}
-                    <a class="item" href="index.php?module=CoreAdminHome">{{ 'General_Settings'|translate }}</a>
-                {% endif %}
-            {% endif %}
-
             {% for lev1UserLabel,lev1UserMenu in userMenu if lev1UserLabel|slice(0,1) != '_' %}
-
-                {% if userLogin != 'anonymous' or not loop.first %}
+                {% if not loop.first %}
                     <hr class="item separator"/>
                 {% endif %}
 
diff --git a/plugins/CorePluginsAdmin/Controller.php b/plugins/CorePluginsAdmin/Controller.php
index 01c28378578f3cb388b6ae5608e9ab293bd8479a..70942c7715bc8668512a01b0780a75adad5b4080 100644
--- a/plugins/CorePluginsAdmin/Controller.php
+++ b/plugins/CorePluginsAdmin/Controller.php
@@ -293,7 +293,7 @@ class Controller extends Plugin\ControllerAdmin
 
                 $suffix = Piwik::translate('CorePluginsAdmin_PluginNotWorkingAlternative');
                 // If the plugin has been renamed, we do not show message to ask user to update plugin
-                if($pluginName != Request::renameModule($pluginName)) {
+                if ($pluginName != Request::renameModule($pluginName)) {
                     $suffix = "You may uninstall the plugin or manually delete the files in piwik/plugins/$pluginName/";
                 }
 
@@ -359,7 +359,7 @@ class Controller extends Plugin\ControllerAdmin
             return $message;
         }
 
-        if(Common::isPhpCliMode()) {
+        if (Common::isPhpCliMode()) {
             Piwik_ExitWithMessage("Error:" . var_export($lastError, true));
         }
 
diff --git a/plugins/CorePluginsAdmin/PluginInstaller.php b/plugins/CorePluginsAdmin/PluginInstaller.php
index 58fd074909b5ea1d23198f05de75d0e5d7e1a034..8bb9c475d07be1d8d067af4b2944f46271a6af2c 100644
--- a/plugins/CorePluginsAdmin/PluginInstaller.php
+++ b/plugins/CorePluginsAdmin/PluginInstaller.php
@@ -155,7 +155,7 @@ class PluginInstaller
     private function makeSureThereAreNoMissingRequirements($metadata)
     {
         $requires = array();
-        if(!empty($metadata->require)) {
+        if (!empty($metadata->require)) {
             $requires = (array) $metadata->require;
         }
 
diff --git a/plugins/CorePluginsAdmin/UpdateCommunication.php b/plugins/CorePluginsAdmin/UpdateCommunication.php
index ad6c570e7e7450c381c9d0aed2da38f6fb799e90..3ed004993f5b937a2819879760b0f9c05e23eba9 100644
--- a/plugins/CorePluginsAdmin/UpdateCommunication.php
+++ b/plugins/CorePluginsAdmin/UpdateCommunication.php
@@ -109,34 +109,8 @@ class UpdateCommunication
             $hasPluginUpdate = $hasPluginUpdate || !$plugin['isTheme'];
         }
 
-        $subject  = Piwik::translate('CoreUpdater_NotificationSubjectAvailablePluginUpdate');
-        $message  = Piwik::translate('ScheduledReports_EmailHello');
-        $message .= "\n\n";
-        $message .= Piwik::translate('CoreUpdater_ThereIsNewPluginVersionAvailableForUpdate');
-        $message .= "\n\n";
-
-        foreach ($pluginsToBeNotified as $plugin) {
-            $message .= sprintf(' * %s %s', $plugin['name'], $plugin['latestVersion']);
-            $message .= "\n";
-        }
-
-        $message .= "\n";
-
-        $host = SettingsPiwik::getPiwikUrl();
-        if ($hasThemeUpdate) {
-            $message .= Piwik::translate('CoreUpdater_NotificationClickToUpdateThemes') . "\n";
-            $message .= $host. 'index.php?module=CorePluginsAdmin&action=themes';
-        }
-        if ($hasPluginUpdate) {
-            if ($hasThemeUpdate) {
-                $message .= "\n\n";
-            }
-            $message .= Piwik::translate('CoreUpdater_NotificationClickToUpdatePlugins') . "\n";
-            $message .= $host. 'index.php?module=CorePluginsAdmin&action=plugins';
-        }
-
-        $message .= "\n\n";
-        $message .= Piwik::translate('Installation_HappyAnalysing');
+        $subject = Piwik::translate('CoreUpdater_NotificationSubjectAvailablePluginUpdate');
+        $message = $this->buildNotificationMessage($pluginsToBeNotified, $hasThemeUpdate, $hasPluginUpdate);
 
         $this->sendEmailNotification($subject, $message);
     }
@@ -161,24 +135,24 @@ class UpdateCommunication
         }
     }
 
-    private function setHasLatestUpdateNotificationReceived($plugin)
+    protected function setHasLatestUpdateNotificationReceived($plugin)
     {
         $latestVersion = $this->getLatestVersion($plugin);
 
         Option::set($this->getNotificationSentOptionName($plugin), $latestVersion);
     }
 
-    private function getLatestVersionSent($plugin)
+    protected function getLatestVersionSent($plugin)
     {
         return Option::get($this->getNotificationSentOptionName($plugin));
     }
 
-    private function getLatestVersion($plugin)
+    protected function getLatestVersion($plugin)
     {
         return $plugin['latestVersion'];
     }
 
-    private function hasNotificationAlreadyReceived($plugin)
+    protected function hasNotificationAlreadyReceived($plugin)
     {
         $latestVersion   = $this->getLatestVersion($plugin);
         $lastVersionSent = $this->getLatestVersionSent($plugin);
@@ -192,7 +166,7 @@ class UpdateCommunication
         return false;
     }
 
-    private function getNotificationSentOptionName($plugin)
+    protected function getNotificationSentOptionName($plugin)
     {
         return 'last_update_communication_sent_plugin_' . $plugin['name'];
     }
@@ -207,4 +181,39 @@ class UpdateCommunication
 
         return $plugins;
     }
+
+    protected function buildNotificationMessage($pluginsToBeNotified, $hasThemeUpdate, $hasPluginUpdate)
+    {
+        $message  = Piwik::translate('ScheduledReports_EmailHello');
+        $message .= "\n\n";
+        $message .= Piwik::translate('CoreUpdater_ThereIsNewPluginVersionAvailableForUpdate');
+        $message .= "\n\n";
+
+        foreach ($pluginsToBeNotified as $plugin) {
+            $message .= sprintf(' * %s %s', $plugin['name'], $plugin['latestVersion']);
+            $message .= "\n";
+        }
+
+        $message .= "\n";
+
+        $host = SettingsPiwik::getPiwikUrl();
+
+        if ($hasThemeUpdate) {
+            $message .= Piwik::translate('CoreUpdater_NotificationClickToUpdateThemes') . "\n";
+            $message .= $host . 'index.php?module=CorePluginsAdmin&action=themes';
+        }
+
+        if ($hasPluginUpdate) {
+            if ($hasThemeUpdate) {
+                $message .= "\n\n";
+            }
+            $message .= Piwik::translate('CoreUpdater_NotificationClickToUpdatePlugins') . "\n";
+            $message .= $host . 'index.php?module=CorePluginsAdmin&action=plugins';
+        }
+
+        $message .= "\n\n";
+        $message .= Piwik::translate('Installation_HappyAnalysing');
+
+        return $message;
+    }
 }
diff --git a/plugins/CoreUpdater/Commands/Update.php b/plugins/CoreUpdater/Commands/Update.php
index e5a0e39d33ff6c7dccd0a0f133e3aa9790db96c4..108281c4607520a7d1e5297f26e8a2629d3d9b98 100644
--- a/plugins/CoreUpdater/Commands/Update.php
+++ b/plugins/CoreUpdater/Commands/Update.php
@@ -40,7 +40,7 @@ class Update extends ConsoleCommand
         try {
             $this->makeUpdate($input, $output, $doDryRun);
 
-            if(!$doDryRun) {
+            if (!$doDryRun) {
                 $this->writeSuccessMessage($output, array("Piwik has been successfully updated!"));
             }
 
diff --git a/plugins/CoreUpdater/Controller.php b/plugins/CoreUpdater/Controller.php
index 1d1d689b56c51b7a3c2fdf179c939aba49308c11..cc27c3e9aa4a518c0f3c249ef467787b6ab47872 100644
--- a/plugins/CoreUpdater/Controller.php
+++ b/plugins/CoreUpdater/Controller.php
@@ -327,11 +327,11 @@ class Controller extends \Piwik\Plugin\Controller
 
         $doExecuteUpdates = Common::getRequestVar('updateCorePlugins', 0, 'integer') == 1;
 
-        if(is_null($doDryRun)) {
+        if (is_null($doDryRun)) {
             $doDryRun = !$doExecuteUpdates;
         }
 
-        if($doDryRun) {
+        if ($doDryRun) {
             $viewWelcome->queries = $updater->getSqlQueriesToExecute();
             $viewWelcome->isMajor = $updater->hasMajorDbUpdate();
             $this->doWelcomeUpdates($viewWelcome, $componentsWithUpdateFile);
diff --git a/plugins/CoreUpdater/UpdateCommunication.php b/plugins/CoreUpdater/UpdateCommunication.php
index 5a113f74d53364b03e2729b80f565b6c42ab614a..cd52e80a3ef64fbed49beb3dc9dacadb26123c55 100644
--- a/plugins/CoreUpdater/UpdateCommunication.php
+++ b/plugins/CoreUpdater/UpdateCommunication.php
@@ -76,7 +76,7 @@ class UpdateCommunication
         $this->sendEmailNotification($subject, $message);
     }
 
-    private function isVersionLike($latestVersion)
+    protected function isVersionLike($latestVersion)
     {
         return strlen($latestVersion) < 18;
     }
@@ -101,7 +101,7 @@ class UpdateCommunication
         }
     }
 
-    private function isNewVersionAvailable()
+    protected function isNewVersionAvailable()
     {
         UpdateCheck::check();
 
@@ -119,7 +119,7 @@ class UpdateCommunication
         return $hasUpdate;
     }
 
-    private function hasNotificationAlreadyReceived()
+    protected function hasNotificationAlreadyReceived()
     {
         $latestVersion   = $this->getLatestVersion();
         $lastVersionSent = $this->getLatestVersionSent();
diff --git a/plugins/CustomVariables/Archiver.php b/plugins/CustomVariables/Archiver.php
index 241e2772a0a5ba211abbae293866f33e39a9151d..47e1363dc4e3b52026887ad0e672addc59ce018d 100644
--- a/plugins/CustomVariables/Archiver.php
+++ b/plugins/CustomVariables/Archiver.php
@@ -39,7 +39,7 @@ class Archiver extends \Piwik\Plugin\Archiver
     {
         parent::__construct($processor);
 
-        if($processor->getParams()->getSite()->isEcommerceEnabled()) {
+        if ($processor->getParams()->getSite()->isEcommerceEnabled()) {
             $this->maximumRowsInDataTableLevelZero = self::MAX_ROWS_WHEN_ECOMMERCE;
             $this->maximumRowsInSubDataTable = self::MAX_ROWS_WHEN_ECOMMERCE;
         } else {
diff --git a/plugins/CustomVariables/tests/ModelTest.php b/plugins/CustomVariables/tests/ModelTest.php
index bfca81c777c003f20bb43b45b6ef79fc3c253a95..3ed82f552a734800d03505760f3a87c5d9cf7deb 100644
--- a/plugins/CustomVariables/tests/ModelTest.php
+++ b/plugins/CustomVariables/tests/ModelTest.php
@@ -7,16 +7,36 @@
  */
 
 namespace Piwik\Plugins\CustomVariables\tests;
+use Piwik\Common;
 use Piwik\Db;
+use Piwik\DbHelper;
 use Piwik\Plugins\CustomVariables\Model;
 
 /**
  * @group CustomVariables
  * @group ModelTest
  * @group Database
+ * @group CustomVariables_ModelTest
  */
 class ModelTest extends \DatabaseTestCase
 {
+    private static $cvarScopes = array('log_link_visit_action', 'log_visit', 'log_conversion');
+
+    public function setUp()
+    {
+        // do not call parent::setUp() since it expects database to be created,
+        // but DB for this test is removed in tearDown
+
+        self::$fixture->performSetUp();
+    }
+
+    public function tearDown()
+    {
+        parent::tearDown();
+
+        self::$fixture->performTearDown();
+    }
+
     /**
      * @expectedException \Exception
      */
@@ -35,7 +55,7 @@ class ModelTest extends \DatabaseTestCase
 
     public function testGetAllScopes()
     {
-        $this->assertEquals(array('log_link_visit_action', 'log_visit', 'log_conversion'), Model::getScopes());
+        $this->assertEquals(self::$cvarScopes, Model::getScopes());
     }
 
     public function test_Install_Uninstall()
diff --git a/plugins/CustomVariables/tests/expected/test_CustomVariablesIntegrationTest__Live.getLastVisitsDetails_day.xml b/plugins/CustomVariables/tests/expected/test_CustomVariablesIntegrationTest__Live.getLastVisitsDetails_day.xml
index 6626b1a24dc79921d1bab7b1931671706e293fd2..2e53cbf4d8ecd7e8cf81fd88e1b6373b38465a01 100644
--- a/plugins/CustomVariables/tests/expected/test_CustomVariablesIntegrationTest__Live.getLastVisitsDetails_day.xml
+++ b/plugins/CustomVariables/tests/expected/test_CustomVariablesIntegrationTest__Live.getLastVisitsDetails_day.xml
@@ -69,7 +69,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
diff --git a/plugins/CustomVariables/tests/processed/test_CustomVariablesIntegrationTest__Live.getLastVisitsDetails_day.xml b/plugins/CustomVariables/tests/processed/test_CustomVariablesIntegrationTest__Live.getLastVisitsDetails_day.xml
index 6626b1a24dc79921d1bab7b1931671706e293fd2..2e53cbf4d8ecd7e8cf81fd88e1b6373b38465a01 100644
--- a/plugins/CustomVariables/tests/processed/test_CustomVariablesIntegrationTest__Live.getLastVisitsDetails_day.xml
+++ b/plugins/CustomVariables/tests/processed/test_CustomVariablesIntegrationTest__Live.getLastVisitsDetails_day.xml
@@ -69,7 +69,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
diff --git a/plugins/Dashboard/Controller.php b/plugins/Dashboard/Controller.php
index 5e319ddb2500d224e713abca7cbbc9bb0e5c10c2..c7a89a75a5d86d82634a1368c966e5963c627064 100644
--- a/plugins/Dashboard/Controller.php
+++ b/plugins/Dashboard/Controller.php
@@ -104,38 +104,13 @@ class Controller extends \Piwik\Plugin\Controller
             $session->dashboardLayout = $layout;
             $session->setExpirationSeconds(1800);
         } else {
-            $this->saveLayoutForUser(Piwik::getCurrentUserLogin(), $idDashboard, $layout);
+            $this->getModel()->updateLayoutForUser(Piwik::getCurrentUserLogin(), $idDashboard, $layout);
         }
     }
 
-    /**
-     * Records the layout in the DB for the given user.
-     *
-     * @param string $login
-     * @param int $idDashboard
-     * @param string $layout
-     */
-    protected function saveLayoutForUser($login, $idDashboard, $layout)
-    {
-        $paramsBind = array($login, $idDashboard, $layout, $layout);
-        $query = sprintf('INSERT INTO %s (login, iddashboard, layout) VALUES (?,?,?) ON DUPLICATE KEY UPDATE layout=?',
-            Common::prefixTable('user_dashboard'));
-        Db::query($query, $paramsBind);
-    }
-
-    /**
-     * Updates the name of a dashboard
-     *
-     * @param string $login
-     * @param int $idDashboard
-     * @param string $name
-     */
-    protected function updateDashboardName($login, $idDashboard, $name)
+    private function getModel()
     {
-        $paramsBind = array($name, $login, $idDashboard);
-        $query = sprintf('UPDATE %s SET name = ? WHERE login = ? AND iddashboard = ?',
-            Common::prefixTable('user_dashboard'));
-        Db::query($query, $paramsBind);
+        return new Model();
     }
 
     /**
@@ -153,9 +128,7 @@ class Controller extends \Piwik\Plugin\Controller
 
         // first layout can't be removed
         if ($idDashboard != 1) {
-            $query = sprintf('DELETE FROM %s WHERE iddashboard = ? AND login = ?',
-                Common::prefixTable('user_dashboard'));
-            Db::query($query, array($idDashboard, Piwik::getCurrentUserLogin()));
+            $this->getModel()->deleteDashboardForUser($idDashboard, Piwik::getCurrentUserLogin());
         }
     }
 
@@ -171,7 +144,7 @@ class Controller extends \Piwik\Plugin\Controller
             return '[]';
         }
 
-        $login = Piwik::getCurrentUserLogin();
+        $login      = Piwik::getCurrentUserLogin();
         $dashboards = $this->dashboard->getAllDashboards($login);
 
         Json::sendHeaderJSON();
@@ -189,38 +162,22 @@ class Controller extends \Piwik\Plugin\Controller
         if (Piwik::isUserIsAnonymous()) {
             return '0';
         }
-        $user = Piwik::getCurrentUserLogin();
-        $nextId = $this->getNextIdDashboard($user);
 
-        $name = urldecode(Common::getRequestVar('name', '', 'string'));
-        $type = urldecode(Common::getRequestVar('type', 'default', 'string'));
+        $name   = urldecode(Common::getRequestVar('name', '', 'string'));
+        $type   = urldecode(Common::getRequestVar('type', 'default', 'string'));
         $layout = '{}';
+        $login  = Piwik::getCurrentUserLogin();
 
         if ($type == 'default') {
             $layout = $this->dashboard->getDefaultLayout();
         }
 
-        $query = sprintf('INSERT INTO %s (login, iddashboard, name, layout) VALUES (?, ?, ?, ?)',
-            Common::prefixTable('user_dashboard'));
-        Db::query($query, array($user, $nextId, $name, $layout));
+        $nextId = $this->getModel()->createNewDashboardForUser($login, $name, $layout);
 
         Json::sendHeaderJSON();
         return Common::json_encode($nextId);
     }
 
-    private function getNextIdDashboard($login)
-    {
-        $nextIdQuery = sprintf('SELECT MAX(iddashboard)+1 FROM %s WHERE login = ?',
-            Common::prefixTable('user_dashboard'));
-        $nextId = Db::fetchOne($nextIdQuery, array($login));
-
-        if (empty($nextId)) {
-            $nextId = 1;
-            return $nextId;
-        }
-        return $nextId;
-    }
-
     public function copyDashboardToUser()
     {
         $this->checkTokenInUrl();
@@ -228,18 +185,16 @@ class Controller extends \Piwik\Plugin\Controller
         if (!Piwik::hasUserSuperUserAccess()) {
             return '0';
         }
+
         $login = Piwik::getCurrentUserLogin();
-        $name = urldecode(Common::getRequestVar('name', '', 'string'));
-        $user = urldecode(Common::getRequestVar('user', '', 'string'));
+        $name  = urldecode(Common::getRequestVar('name', '', 'string'));
+        $user  = urldecode(Common::getRequestVar('user', '', 'string'));
         $idDashboard = Common::getRequestVar('dashboardId', 0, 'int');
+
         $layout = $this->dashboard->getLayoutForUser($login, $idDashboard);
 
         if ($layout !== false) {
-            $nextId = $this->getNextIdDashboard($user);
-
-            $query = sprintf('INSERT INTO %s (login, iddashboard, name, layout) VALUES (?, ?, ?, ?)',
-                Common::prefixTable('user_dashboard'));
-            Db::query($query, array($user, $nextId, $name, $layout));
+            $nextId = $this->getModel()->createNewDashboardForUser($user, $name, $layout);
 
             Json::sendHeaderJSON();
             return Common::json_encode($nextId);
@@ -255,17 +210,18 @@ class Controller extends \Piwik\Plugin\Controller
     {
         $this->checkTokenInUrl();
 
-        $layout = Common::unsanitizeInputValue(Common::getRequestVar('layout'));
+        $layout      = Common::unsanitizeInputValue(Common::getRequestVar('layout'));
         $idDashboard = Common::getRequestVar('idDashboard', 1, 'int');
-        $name = Common::getRequestVar('name', '', 'string');
+        $name        = Common::getRequestVar('name', '', 'string');
+
         if (Piwik::isUserIsAnonymous()) {
             $session = new SessionNamespace("Dashboard");
             $session->dashboardLayout = $layout;
             $session->setExpirationSeconds(1800);
         } else {
-            $this->saveLayoutForUser(Piwik::getCurrentUserLogin(), $idDashboard, $layout);
+            $this->getModel()->updateLayoutForUser(Piwik::getCurrentUserLogin(), $idDashboard, $layout);
             if (!empty($name)) {
-                $this->updateDashboardName(Piwik::getCurrentUserLogin(), $idDashboard, $name);
+                $this->getModel()->updateDashboardName(Piwik::getCurrentUserLogin(), $idDashboard, $name);
             }
         }
     }
@@ -279,10 +235,7 @@ class Controller extends \Piwik\Plugin\Controller
 
         if (Piwik::hasUserSuperUserAccess()) {
             $layout = Common::unsanitizeInputValue(Common::getRequestVar('layout'));
-            $paramsBind = array('', '1', $layout, $layout);
-            $query = sprintf('INSERT INTO %s (login, iddashboard, layout) VALUES (?,?,?) ON DUPLICATE KEY UPDATE layout=?',
-                Common::prefixTable('user_dashboard'));
-            Db::query($query, $paramsBind);
+            $this->getModel()->createOrUpdateDashboard('', '1', $layout);
         }
     }
 
diff --git a/plugins/Dashboard/Dashboard.php b/plugins/Dashboard/Dashboard.php
index cb545465ff215f99e053c88bd2434d06544aa84d..1ff5a98182fbc209f41164b169bb518005c9f257 100644
--- a/plugins/Dashboard/Dashboard.php
+++ b/plugins/Dashboard/Dashboard.php
@@ -10,7 +10,6 @@ namespace Piwik\Plugins\Dashboard;
 
 use Piwik\Common;
 use Piwik\Db;
-use Piwik\DbHelper;
 use Piwik\Piwik;
 use Piwik\WidgetsList;
 
@@ -42,10 +41,7 @@ class Dashboard extends \Piwik\Plugin
      */
     public function getLayoutForUser($login, $idDashboard)
     {
-        $paramsBind = array($login, $idDashboard);
-        $query = sprintf('SELECT layout FROM %s WHERE login = ? AND iddashboard = ?',
-            Common::prefixTable('user_dashboard'));
-        $return = Db::fetchAll($query, $paramsBind);
+        $return = $this->getModel()->getLayoutForUser($login, $idDashboard);
 
         if (count($return) == 0) {
             return false;
@@ -54,6 +50,11 @@ class Dashboard extends \Piwik\Plugin
         return $return[0]['layout'];
     }
 
+    private function getModel()
+    {
+        return new Model();
+    }
+
     public function getDefaultLayout()
     {
         $defaultLayout = $this->getLayoutForUser('', 1);
@@ -107,9 +108,7 @@ class Dashboard extends \Piwik\Plugin
 
     public function getAllDashboards($login)
     {
-        $dashboards = Db::fetchAll('SELECT iddashboard, name, layout
-                                      FROM ' . Common::prefixTable('user_dashboard') .
-            ' WHERE login = ? ORDER BY iddashboard', array($login));
+        $dashboards = $this->getModel()->getAllDashboardsForUser($login);
 
         $nameless = 1;
         foreach ($dashboards as &$dashboard) {
@@ -219,23 +218,17 @@ class Dashboard extends \Piwik\Plugin
 
     public function deleteDashboardLayout($userLogin)
     {
-        Db::query('DELETE FROM ' . Common::prefixTable('user_dashboard') . ' WHERE login = ?', array($userLogin));
+        $this->getModel()->deleteAllLayoutsForUser($userLogin);
     }
 
     public function install()
     {
-        $dashboard = "login VARCHAR( 100 ) NOT NULL ,
-					  iddashboard INT NOT NULL ,
-					  name VARCHAR( 100 ) NULL DEFAULT NULL ,
-					  layout TEXT NOT NULL,
-					  PRIMARY KEY ( login , iddashboard )";
-
-        DbHelper::createTable('user_dashboard', $dashboard);
+        Model::install();
     }
 
     public function uninstall()
     {
-        Db::dropTables(Common::prefixTable('user_dashboard'));
+        Model::uninstall();
     }
 
     public function getClientSideTranslationKeys(&$translationKeys)
diff --git a/plugins/Dashboard/Menu.php b/plugins/Dashboard/Menu.php
index 2ee0521623026145354bf34dc2f47ac26be6545c..f90c117e109b447c499dfde7a9d1625e6cc1cffb 100644
--- a/plugins/Dashboard/Menu.php
+++ b/plugins/Dashboard/Menu.php
@@ -41,11 +41,9 @@ class Menu extends \Piwik\Plugin\Menu
     {
         $userPreferences = new UserPreferences();
         $idSite = $userPreferences->getDefaultWebsiteId();
-
         $tooltip = Piwik::translate('Dashboard_TopLinkTooltip', Site::getNameFor($idSite));
 
-        $urlParams = $this->urlForModuleAction('CoreHome', 'index', array('idSite' => $idSite)) ;
-
+        $urlParams = $this->urlForModuleActionWithDefaultUserParams('CoreHome', 'index') ;
         $menu->addItem('Dashboard_Dashboard', null, $urlParams, 1, $tooltip);
     }
 }
diff --git a/plugins/Dashboard/Model.php b/plugins/Dashboard/Model.php
new file mode 100644
index 0000000000000000000000000000000000000000..39dcb065571add0153d099a1e99a542c466bd364
--- /dev/null
+++ b/plugins/Dashboard/Model.php
@@ -0,0 +1,147 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link     http://piwik.org
+ * @license  http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+namespace Piwik\Plugins\Dashboard;
+
+use Piwik\Common;
+use Piwik\Db;
+use Piwik\DbHelper;
+
+class Model
+{
+    private static $rawPrefix = 'user_dashboard';
+    private $table;
+
+    public function __construct()
+    {
+        $this->table = Common::prefixTable(self::$rawPrefix);
+    }
+
+    /**
+     * Returns the layout in the DB for the given user, or false if the layout has not been set yet.
+     * Parameters must be checked BEFORE this function call
+     *
+     * @param string $login
+     * @param int $idDashboard
+     *
+     * @return bool|string
+     */
+    public function getLayoutForUser($login, $idDashboard)
+    {
+        $query   = sprintf('SELECT layout FROM %s WHERE login = ? AND iddashboard = ?',
+                           $this->table);
+        $bind    = array($login, $idDashboard);
+        $layouts = Db::fetchAll($query, $bind);
+
+        return $layouts;
+    }
+
+    public function getAllDashboardsForUser($login)
+    {
+        $dashboards = Db::fetchAll('SELECT iddashboard, name, layout FROM ' . $this->table .
+                                   ' WHERE login = ? ORDER BY iddashboard', array($login));
+
+        return $dashboards;
+    }
+
+    public function deleteAllLayoutsForUser($userLogin)
+    {
+        Db::query('DELETE FROM ' . $this->table . ' WHERE login = ?', array($userLogin));
+    }
+
+    /**
+     * Updates the name of a dashboard
+     *
+     * @param string $login
+     * @param int $idDashboard
+     * @param string $name
+     */
+    public function updateDashboardName($login, $idDashboard, $name)
+    {
+        $bind  = array($name, $login, $idDashboard);
+        $query = sprintf('UPDATE %s SET name = ? WHERE login = ? AND iddashboard = ?', $this->table);
+        Db::query($query, $bind);
+    }
+
+    /**
+     * Removes the dashboard with the given id
+     */
+    public function deleteDashboardForUser($idDashboard, $login)
+    {
+        $query = sprintf('DELETE FROM %s WHERE iddashboard = ? AND login = ?', $this->table);
+        Db::query($query, array($idDashboard, $login));
+    }
+
+    /**
+     * Creates a new dashboard for the current user
+     * User needs to be logged in
+     */
+    public function createNewDashboardForUser($login, $name, $layout)
+    {
+        $nextId = $this->getNextIdDashboard($login);
+
+        $query = sprintf('INSERT INTO %s (login, iddashboard, name, layout) VALUES (?, ?, ?, ?)', $this->table);
+        $bind  = array($login, $nextId, $name, $layout);
+        Db::query($query, $bind);
+
+        return $nextId;
+    }
+
+    /**
+     * Saves the layout as default
+     */
+    public function createOrUpdateDashboard($login, $idDashboard, $layout)
+    {
+        $bind   = array($login, $idDashboard, $layout, $layout);
+        $query  = sprintf('INSERT INTO %s (login, iddashboard, layout) VALUES (?,?,?) ON DUPLICATE KEY UPDATE layout=?',
+                          $this->table);
+        Db::query($query, $bind);
+    }
+
+    private function getNextIdDashboard($login)
+    {
+        $nextIdQuery = sprintf('SELECT MAX(iddashboard)+1 FROM %s WHERE login = ?', $this->table);
+        $nextId      = Db::fetchOne($nextIdQuery, array($login));
+
+        if (empty($nextId)) {
+            $nextId = 1;
+        }
+
+        return $nextId;
+    }
+
+    /**
+     * Records the layout in the DB for the given user.
+     *
+     * @param string $login
+     * @param int $idDashboard
+     * @param string $layout
+     */
+    public function updateLayoutForUser($login, $idDashboard, $layout)
+    {
+        $bind  = array($login, $idDashboard, $layout, $layout);
+        $query = sprintf('INSERT INTO %s (login, iddashboard, layout) VALUES (?,?,?) ON DUPLICATE KEY UPDATE layout=?',
+                         $this->table);
+        Db::query($query, $bind);
+    }
+
+    public static function install()
+    {
+        $dashboard = "login VARCHAR( 100 ) NOT NULL ,
+					  iddashboard INT NOT NULL ,
+					  name VARCHAR( 100 ) NULL DEFAULT NULL ,
+					  layout TEXT NOT NULL,
+					  PRIMARY KEY ( login , iddashboard )";
+
+        DbHelper::createTable(self::$rawPrefix, $dashboard);
+    }
+
+    public static function uninstall()
+    {
+        Db::dropTables(Common::prefixTable(self::$rawPrefix));
+    }
+}
diff --git a/plugins/DevicesDetection/functions.php b/plugins/DevicesDetection/functions.php
index 1112be30502ff6618a67e2de97b3c27a638cf14c..12f18b19d171d753620e3dd8a5e8aeb1609332d6 100644
--- a/plugins/DevicesDetection/functions.php
+++ b/plugins/DevicesDetection/functions.php
@@ -179,7 +179,7 @@ function getOSFamilyFullNameExtended($label)
         return 'Bot';
     }
     $label = OperatingSystemParser::getOsFamily($label);
-    if($label !== false) {
+    if ($label !== false) {
         return $label;
     }
     return Piwik::translate('General_Unknown');
@@ -292,4 +292,4 @@ function getBrowserEngineName($engineName) {
         return $engineName;
     }
     return Piwik::translate('General_Unknown');
-}
\ No newline at end of file
+}
diff --git a/plugins/Events/API.php b/plugins/Events/API.php
index 361f0ef965ff886063e56a8c9bd8060dde4d21f7..890979db2c73109e469ebda5f640c83e2aa7c0ba 100644
--- a/plugins/Events/API.php
+++ b/plugins/Events/API.php
@@ -94,7 +94,7 @@ class API extends \Piwik\Plugin\API
      */
     public function getDefaultSecondaryDimension($apiMethod)
     {
-        if(isset($this->defaultMappingApiToSecondaryDimension[$apiMethod])) {
+        if (isset($this->defaultMappingApiToSecondaryDimension[$apiMethod])) {
             return $this->defaultMappingApiToSecondaryDimension[$apiMethod];
         }
         return false;
@@ -106,11 +106,11 @@ class API extends \Piwik\Plugin\API
             $secondaryDimension = $this->getDefaultSecondaryDimension($apiMethod);
         }
         $record = $this->mappingApiToRecord[$apiMethod];
-        if(!is_array($record)) {
+        if (!is_array($record)) {
             return $record;
         }
         // when secondaryDimension is incorrectly set
-        if(empty($record[$secondaryDimension])) {
+        if (empty($record[$secondaryDimension])) {
             return key($record);
         }
         return $record[$secondaryDimension];
@@ -124,7 +124,7 @@ class API extends \Piwik\Plugin\API
     public function getSecondaryDimensions($apiMethod)
     {
         $records = $this->mappingApiToRecord[$apiMethod];
-        if(!is_array($records)) {
+        if (!is_array($records)) {
             return false;
         }
         return array_keys($records);
diff --git a/plugins/Events/Archiver.php b/plugins/Events/Archiver.php
index 02fe3a8d83689e6fb101e34f8dafb43548704834..eb33d4899fee28bdb350884c3aabd449caa04570 100644
--- a/plugins/Events/Archiver.php
+++ b/plugins/Events/Archiver.php
@@ -225,7 +225,7 @@ class Archiver extends \Piwik\Plugin\Archiver
      */
     protected function getDataArray($name)
     {
-        if(empty($this->arrays[$name])) {
+        if (empty($this->arrays[$name])) {
             $this->arrays[$name] = new DataArray();
         }
         return $this->arrays[$name];
diff --git a/plugins/Events/Events.php b/plugins/Events/Events.php
index 3d335bd229f9ee955a0aa84bf98b2b5dd062e6df..6a55588af44138c8aceae95ff9287be3c8fc3843 100644
--- a/plugins/Events/Events.php
+++ b/plugins/Events/Events.php
@@ -184,7 +184,7 @@ class Events extends \Piwik\Plugin
 
     private function addRelatedReports($view, $secondaryDimension)
     {
-        if(empty($secondaryDimension)) {
+        if (empty($secondaryDimension)) {
             // eg. Row Evolution
             return;
         }
@@ -194,7 +194,7 @@ class Events extends \Piwik\Plugin
         $apiMethod = $view->requestConfig->getApiMethodToRequest();
         $secondaryDimensions = API::getInstance()->getSecondaryDimensions($apiMethod);
 
-        if(empty($secondaryDimensions)) {
+        if (empty($secondaryDimensions)) {
             return;
         }
 
@@ -205,7 +205,7 @@ class Events extends \Piwik\Plugin
             . Piwik::translate('Events_SwitchToSecondaryDimension', '');
 
         foreach($secondaryDimensions as $dimension) {
-            if($dimension == $secondaryDimension) {
+            if ($dimension == $secondaryDimension) {
                 // don't show as related report the currently selected dimension
                 continue;
             }
diff --git a/plugins/ExampleCommand/Commands/HelloWorld.php b/plugins/ExampleCommand/Commands/HelloWorld.php
index 5c0d415dcd9c6e02454039627849134974d9c4a3..d8dc781e3f1e1e37c54e267a46bab436b96f7500 100644
--- a/plugins/ExampleCommand/Commands/HelloWorld.php
+++ b/plugins/ExampleCommand/Commands/HelloWorld.php
@@ -15,18 +15,36 @@ use Symfony\Component\Console\Input\InputOption;
 use Symfony\Component\Console\Output\OutputInterface;
 
 /**
+ * This class lets you define a new command. To read more about commands have a look at our Piwik Console guide on
+ * http://developer.piwik.org/guides/piwik-on-the-command-line
+ *
+ * As Piwik Console is based on the Symfony Console you might also want to have a look at
+ * http://symfony.com/doc/current/components/console/index.html
  */
 class HelloWorld extends ConsoleCommand
 {
+
+    /**
+     * This methods allows you to configure your command. Here you can define the name and description of your command
+     * as well as all options and arguments you expect when executing it.
+     */
     protected function configure()
     {
         $this->setName('examplecommand:helloworld');
-        $this->setDescription('ExampleCommand');
+        $this->setDescription('ExampleCommandDescription');
         $this->addOption('name', null, InputOption::VALUE_REQUIRED, 'Your name:');
     }
 
     /**
-     * Execute command like: ./console examplecommand:helloworld --name="The Piwik Team"
+     * The actual task is defined in this method. Here you can access any option or argument that was defined on the
+     * command line via $input and write anything to the console via $output argument.
+     * In case anything went wrong during the execution you should throw an exception to make sure the user will get a
+     * useful error message and to make sure the command does not exit with the status code 0.
+     *
+     * Ideally, the actual command is quite short as it acts like a controller. It should only receive the input values,
+     * execute the task by calling a method of another class and output any useful information.
+     *
+     * Execute the command like: ./console examplecommand:helloworld --name="The Piwik Team"
      */
     protected function execute(InputInterface $input, OutputInterface $output)
     {
diff --git a/plugins/ExampleRssWidget/RssRenderer.php b/plugins/ExampleRssWidget/RssRenderer.php
index 254a30ce6f8cf31dc7e09ea0a05d42514069f3e8..7990b1acb8d021c935c95d2eb9af7d30884c74f6 100644
--- a/plugins/ExampleRssWidget/RssRenderer.php
+++ b/plugins/ExampleRssWidget/RssRenderer.php
@@ -54,7 +54,7 @@ class RssRenderer
         $i = 0;
 
         $items = array();
-        if(!empty($rss->channel->item)) {
+        if (!empty($rss->channel->item)) {
             $items = $rss->channel->item;
         }
         foreach ($items as $post) {
diff --git a/plugins/ExampleUI/templates/notifications.twig b/plugins/ExampleUI/templates/notifications.twig
index 2212ead3d9550cd068f032831ec102a410aa2b69..1058a50a61dbe842c7e3b6a85f7dab2e689cb579 100644
--- a/plugins/ExampleUI/templates/notifications.twig
+++ b/plugins/ExampleUI/templates/notifications.twig
@@ -4,6 +4,11 @@
     <h2>Inline notification example:</h2>
 
     <div style="display:inline-block;margin-top:10px;" id="exampleUI_notifications">
-        {{ 'This is an example for an inline notification. Have you noticed the success message disappeared after a few seconds?'|notification({'placeAt': '#exampleUI_notifications', 'title': 'Info: ', 'noclear': true, 'context': 'info'}) }}
+        <div piwik-notification
+             notification-title="Info:"
+             noclear="true"
+             context="info">
+            This is an example for an inline notification. Have you noticed the success message disappeared after a few seconds?
+        </div>
     </div>
 {% endblock %}
\ No newline at end of file
diff --git a/plugins/Goals/API.php b/plugins/Goals/API.php
index 176cafad24d3400c8de0832a16d20e177da6e477..c76054aab9974eb1f9a694496b7c62bb35d389d7 100644
--- a/plugins/Goals/API.php
+++ b/plugins/Goals/API.php
@@ -54,14 +54,15 @@ class API extends \Piwik\Plugin\API
         //TODO calls to this function could be cached as static
         // would help UI at least, since some UI requests would call this 2-3 times..
         $idSite = Site::getIdSitesFromIdSitesString($idSite);
+
         if (empty($idSite)) {
             return array();
         }
+
         Piwik::checkUserHasViewAccess($idSite);
-        $goals = Db::fetchAll("SELECT *
-								FROM " . Common::prefixTable('goal') . "
-								WHERE idsite IN (" . implode(", ", $idSite) . ")
-									AND deleted = 0");
+
+        $goals = $this->getModel()->getActiveGoals($idSite);
+
         $cleanedGoals = array();
         foreach ($goals as &$goal) {
             if ($goal['match_attribute'] == 'manually') {
@@ -71,6 +72,7 @@ class API extends \Piwik\Plugin\API
             }
             $cleanedGoals[$goal['idgoal']] = $goal;
         }
+
         return $cleanedGoals;
     }
 
@@ -91,35 +93,33 @@ class API extends \Piwik\Plugin\API
     public function addGoal($idSite, $name, $matchAttribute, $pattern, $patternType, $caseSensitive = false, $revenue = false, $allowMultipleConversionsPerVisit = false)
     {
         Piwik::checkUserHasAdminAccess($idSite);
+
         $this->checkPatternIsValid($patternType, $pattern, $matchAttribute);
-        $name = $this->checkName($name);
+        $name    = $this->checkName($name);
         $pattern = $this->checkPattern($pattern);
 
-        // save in db
-        $db = Db::get();
-        $idGoal = $db->fetchOne("SELECT max(idgoal) + 1
-								FROM " . Common::prefixTable('goal') . "
-								WHERE idsite = ?", $idSite);
-        if ($idGoal == false) {
-            $idGoal = 1;
-        }
-        $db->insert(Common::prefixTable('goal'),
-            array(
-                 'idsite'          => $idSite,
-                 'idgoal'          => $idGoal,
-                 'name'            => $name,
-                 'match_attribute' => $matchAttribute,
-                 'pattern'         => $pattern,
-                 'pattern_type'    => $patternType,
-                 'case_sensitive'  => (int)$caseSensitive,
-                 'allow_multiple'  => (int)$allowMultipleConversionsPerVisit,
-                 'revenue'         => (float)$revenue,
-                 'deleted'         => 0,
-            ));
+        $goal = array(
+            'name'            => $name,
+            'match_attribute' => $matchAttribute,
+            'pattern'         => $pattern,
+            'pattern_type'    => $patternType,
+            'case_sensitive'  => (int)$caseSensitive,
+            'allow_multiple'  => (int)$allowMultipleConversionsPerVisit,
+            'revenue'         => (float)$revenue,
+            'deleted'         => 0,
+        );
+
+        $idGoal = $this->getModel()->createGoalForSite($idSite, $goal);
+
         Cache::regenerateCacheWebsiteAttributes($idSite);
         return $idGoal;
     }
 
+    private function getModel()
+    {
+        return new Model();
+    }
+
     /**
      * Updates a Goal description.
      * Will not update or re-process the conversions already recorded
@@ -139,21 +139,21 @@ class API extends \Piwik\Plugin\API
     public function updateGoal($idSite, $idGoal, $name, $matchAttribute, $pattern, $patternType, $caseSensitive = false, $revenue = false, $allowMultipleConversionsPerVisit = false)
     {
         Piwik::checkUserHasAdminAccess($idSite);
-        $name = $this->checkName($name);
+
+        $name    = $this->checkName($name);
         $pattern = $this->checkPattern($pattern);
         $this->checkPatternIsValid($patternType, $pattern, $matchAttribute);
-        Db::get()->update(Common::prefixTable('goal'),
-            array(
-                 'name'            => $name,
-                 'match_attribute' => $matchAttribute,
-                 'pattern'         => $pattern,
-                 'pattern_type'    => $patternType,
-                 'case_sensitive'  => (int)$caseSensitive,
-                 'allow_multiple'  => (int)$allowMultipleConversionsPerVisit,
-                 'revenue'         => (float)$revenue,
-            ),
-            "idsite = '$idSite' AND idgoal = '$idGoal'"
-        );
+
+        $this->getModel()->updateGoal($idSite, $idGoal, array(
+            'name'            => $name,
+            'match_attribute' => $matchAttribute,
+            'pattern'         => $pattern,
+            'pattern_type'    => $patternType,
+            'case_sensitive'  => (int) $caseSensitive,
+            'allow_multiple'  => (int) $allowMultipleConversionsPerVisit,
+            'revenue'         => (float) $revenue,
+        ));
+
         Cache::regenerateCacheWebsiteAttributes($idSite);
     }
 
@@ -188,12 +188,10 @@ class API extends \Piwik\Plugin\API
     public function deleteGoal($idSite, $idGoal)
     {
         Piwik::checkUserHasAdminAccess($idSite);
-        Db::query("UPDATE " . Common::prefixTable('goal') . "
-										SET deleted = 1
-										WHERE idsite = ?
-											AND idgoal = ?",
-            array($idSite, $idGoal));
-        Db::deleteAllRows(Common::prefixTable("log_conversion"), "WHERE idgoal = ? AND idsite = ?", "idvisit", 100000, array($idGoal, $idSite));
+
+        $this->getModel()->deleteGoal($idSite, $idGoal);
+        $this->getModel()->deleteGoalConversions($idSite, $idGoal);
+
         Cache::regenerateCacheWebsiteAttributes($idSite);
     }
 
@@ -204,11 +202,13 @@ class API extends \Piwik\Plugin\API
     protected function getItems($recordName, $idSite, $period, $date, $abandonedCarts, $segment)
     {
         Piwik::checkUserHasViewAccess($idSite);
+
         $recordNameFinal = $recordName;
         if ($abandonedCarts) {
             $recordNameFinal = Archiver::getItemRecordNameAbandonedCart($recordName);
         }
-        $archive = Archive::build($idSite, $period, $date, $segment);
+
+        $archive   = Archive::build($idSite, $period, $date, $segment);
         $dataTable = $archive->getDataTable($recordNameFinal);
 
         $dataTable->filter('Sort', array(Metrics::INDEX_ECOMMERCE_ITEM_REVENUE));
@@ -250,6 +250,7 @@ class API extends \Piwik\Plugin\API
             }
             return;
         }
+
         $rowNotDefined = $dataTable->getRowFromLabel(\Piwik\Plugins\CustomVariables\Archiver::LABEL_CUSTOM_VALUE_NOT_DEFINED);
         if ($rowNotDefined) {
             $rowNotDefined->setColumn('label', $notDefinedStringPretty);
diff --git a/plugins/Goals/Controller.php b/plugins/Goals/Controller.php
index f5a3f1f735fd61bfd3309a11178755c318ba3e0a..e7af6d6243d4ccc2c6038499fd603afbee070200 100644
--- a/plugins/Goals/Controller.php
+++ b/plugins/Goals/Controller.php
@@ -98,7 +98,7 @@ class Controller extends \Piwik\Plugin\Controller
     {
         $saveGET = $_GET;
         $filterEcommerce = Common::getRequestVar('filterEcommerce', self::ECOMMERCE_LOG_SHOW_ORDERS, 'int');
-        if($filterEcommerce == self::ECOMMERCE_LOG_SHOW_ORDERS) {
+        if ($filterEcommerce == self::ECOMMERCE_LOG_SHOW_ORDERS) {
             $segment = urlencode('visitEcommerceStatus==ordered,visitEcommerceStatus==orderedThenAbandonedCart');
         } else {
             $segment = urlencode('visitEcommerceStatus==abandonedCart,visitEcommerceStatus==orderedThenAbandonedCart');
@@ -458,7 +458,7 @@ class Controller extends \Piwik\Plugin\Controller
             foreach ($allReports as $category => $reports) {
                 $categoryText = Piwik::translate('Goals_ViewGoalsBy', $category);
                 foreach ($reports as $report) {
-                    if(empty($report['viewDataTable'])) {
+                    if (empty($report['viewDataTable'])) {
                         $report['viewDataTable'] = 'tableGoals';
                     }
                     $customParams['viewDataTable'] = $report['viewDataTable'];
diff --git a/plugins/Goals/Goals.php b/plugins/Goals/Goals.php
index 39a7c0b2dcb53758c29ec4cb65dd46f986c3e713..381c37f7eebb51be6b8e529ceea31459194c0512 100644
--- a/plugins/Goals/Goals.php
+++ b/plugins/Goals/Goals.php
@@ -135,7 +135,8 @@ class Goals extends \Piwik\Plugin
      */
     public function deleteSiteGoals($idSite)
     {
-        Db::query("DELETE FROM " . Common::prefixTable('goal') . " WHERE idsite = ? ", array($idSite));
+        $model = new Model();
+        $model->deleteGoalsForSite($idSite);
     }
 
     /**
diff --git a/plugins/Goals/Model.php b/plugins/Goals/Model.php
new file mode 100644
index 0000000000000000000000000000000000000000..2b35f7947d0d40abc4956847baffe8088a945864
--- /dev/null
+++ b/plugins/Goals/Model.php
@@ -0,0 +1,95 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Goals;
+
+use Piwik\Common;
+use Piwik\Db;
+
+class Model
+{
+    private static $rawPrefix = 'goal';
+    private $table;
+
+    public function __construct()
+    {
+        $this->table = Common::prefixTable(self::$rawPrefix);
+    }
+
+    private function getNextIdGoal($idSite)
+    {
+        $db     = $this->getDb();
+        $idGoal = $db->fetchOne("SELECT max(idgoal) + 1 FROM " . $this->table . "
+                                 WHERE idsite = ?", $idSite);
+
+        if (empty($idGoal)) {
+            $idGoal = 1;
+        }
+
+        return $idGoal;
+    }
+
+    public function createGoalForSite($idSite, $goal)
+    {
+        $db     = $this->getDb();
+        $goalId = $this->getNextIdGoal($idSite);
+
+        $goal['idgoal'] = $goalId;
+        $goal['idsite'] = $idSite;
+
+        $db->insert($this->table, $goal);
+
+        return $goalId;
+    }
+
+    public function updateGoal($idSite, $idGoal, $goal)
+    {
+        $idSite = (int) $idSite;
+        $idGoal = (int) $idGoal;
+
+        $db = $this->getDb();
+        $db->update($this->table, $goal, "idsite = '$idSite' AND idgoal = '$idGoal'");
+    }
+
+    // actually this should be in a log_conversion model
+    public function deleteGoalConversions($idSite, $idGoal)
+    {
+        $table = Common::prefixTable("log_conversion");
+
+        Db::deleteAllRows($table, "WHERE idgoal = ? AND idsite = ?", "idvisit", 100000, array($idGoal, $idSite));
+    }
+
+    public function getActiveGoals($idSite)
+    {
+        $idSite = array_map('intval', $idSite);
+        $goals  = Db::fetchAll("SELECT * FROM " . $this->table . "
+                                WHERE idsite IN (" . implode(", ", $idSite) . ")
+                                      AND deleted = 0");
+
+        return $goals;
+    }
+
+    public function deleteGoalsForSite($idSite)
+    {
+        Db::query("DELETE FROM " . $this->table . " WHERE idsite = ? ", array($idSite));
+    }
+
+    public function deleteGoal($idSite, $idGoal)
+    {
+        $query = "UPDATE " . $this->table . " SET deleted = 1
+                  WHERE idsite = ? AND idgoal = ?";
+        $bind  = array($idSite, $idGoal);
+
+        Db::query($query, $bind);
+    }
+
+    private function getDb()
+    {
+        return Db::get();
+    }
+}
diff --git a/plugins/Goals/Visualizations/Goals.php b/plugins/Goals/Visualizations/Goals.php
index 0b8c2c5365523f9c60fe344a7b925922edd14617..9808621b145a569ef8bc0c1e1b3f4c04b7aa3d9d 100644
--- a/plugins/Goals/Visualizations/Goals.php
+++ b/plugins/Goals/Visualizations/Goals.php
@@ -31,7 +31,7 @@ class Goals extends HtmlTable
     {
         parent::beforeLoadDataTable();
 
-        if($this->config->disable_subtable_when_show_goals) {
+        if ($this->config->disable_subtable_when_show_goals) {
             $this->config->subtable_controller_action = null;
         }
 
diff --git a/plugins/Goals/tests/APITest.php b/plugins/Goals/tests/APITest.php
index 0f393385d953cb6ed5ed7029e53bc3249ba70792..3263bc4972a78dd9a99bea28260d4482907d9956 100644
--- a/plugins/Goals/tests/APITest.php
+++ b/plugins/Goals/tests/APITest.php
@@ -8,6 +8,7 @@
 
 namespace Piwik\Plugins\Goals\tests;
 use Piwik\Access;
+use Piwik\Piwik;
 use Piwik\Plugins\Goals\API;
 use Piwik\Tests\Fixture;
 
@@ -31,6 +32,9 @@ class APITest extends \DatabaseTestCase
         parent::setUp();
         $this->api = API::getInstance();
 
+        Fixture::createAccessInstance();
+        Piwik::setUserHasSuperUserAccess();
+
         Fixture::createWebsite('2014-01-01 00:00:00');
         Fixture::createWebsite('2014-01-01 00:00:00');
     }
diff --git a/plugins/ImageGraph/StaticGraph/GridGraph.php b/plugins/ImageGraph/StaticGraph/GridGraph.php
index 3eeb1393db470a920c7d2779ddabb85e8a4d3235..4ffde4c2c478dafed3e957eba8532d21ff0ef6e2 100644
--- a/plugins/ImageGraph/StaticGraph/GridGraph.php
+++ b/plugins/ImageGraph/StaticGraph/GridGraph.php
@@ -419,11 +419,11 @@ abstract class GridGraph extends StaticGraph
     // see https://github.com/piwik/piwik/issues/3396
 //	protected function displayMinMaxValues()
 //	{
-//		if($displayMinMax)
+//		if ($displayMinMax)
 //		{
 //			// when plotting multiple metrics, display min & max on both series
 //			// to fix: in vertical bars, labels are hidden when multiple metrics are plotted, hence the restriction on count($this->ordinateSeries) == 1
-//			if($this->multipleMetrics && count($this->ordinateSeries) == 1)
+//			if ($this->multipleMetrics && count($this->ordinateSeries) == 1)
 //			{
 //				$colorIndex = 1;
 //				foreach($this->ordinateSeries as $column => $data)
@@ -467,13 +467,13 @@ abstract class GridGraph extends StaticGraph
 //		$maxValueIndex = 0;
 //		foreach($data as $index => $value)
 //		{
-//			if($value > $maxValue)
+//			if ($value > $maxValue)
 //			{
 //				$maxValue = $value;
 //				$maxValueIndex = $index;
 //			}
 //
-//			if($value < $minValue)
+//			if ($value < $minValue)
 //			{
 //				$minValue = $value;
 //				$minValueIndex = $index;
diff --git a/plugins/Installation/Controller.php b/plugins/Installation/Controller.php
index d3da5402f01dfbbef799b262a0b62586f5e59b5a..574af47ad7edf36070a12e96d0965c291e8967bc 100644
--- a/plugins/Installation/Controller.php
+++ b/plugins/Installation/Controller.php
@@ -84,7 +84,7 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
         // Delete merged js/css files to force regenerations based on updated activated plugin list
         Filesystem::deleteAllCacheOnUpdate();
 
-        if(empty($message)) {
+        if (empty($message)) {
             $this->checkPiwikIsNotInstalled();
         }
         $view = new View(
@@ -196,14 +196,16 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
             $view->tablesInstalled     = implode(', ', $tablesInstalled);
             $view->someTablesInstalled = true;
 
-            Access::getInstance();
-            Piwik::setUserHasSuperUserAccess();
-            if ($this->hasEnoughTablesToReuseDb($tablesInstalled) &&
-                count(APISitesManager::getInstance()->getAllSitesId()) > 0 &&
-                count(APIUsersManager::getInstance()->getUsers()) > 0
-            ) {
-                $view->showReuseExistingTables = true;
-            }
+            $self = $this;
+            Access::doAsSuperUser(function () use ($self, $tablesInstalled, $view) {
+                Access::getInstance();
+                if ($self->hasEnoughTablesToReuseDb($tablesInstalled) &&
+                    count(APISitesManager::getInstance()->getAllSitesId()) > 0 &&
+                    count(APIUsersManager::getInstance()->getUsers()) > 0
+                ) {
+                    $view->showReuseExistingTables = true;
+                }
+            });
         } else {
 
             DbHelper::createTables();
@@ -234,7 +236,7 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
         );
 
         $result = $this->updateComponents();
-        if($result === false) {
+        if ($result === false) {
             $this->redirectToNextStep('tablesCreation');
         }
 
@@ -258,8 +260,11 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
     {
         $this->checkPiwikIsNotInstalled();
 
-        $this->initObjectsToCallAPI();
-        if(count(APIUsersManager::getInstance()->getUsersHavingSuperUserAccess()) > 0) {
+        $superUserAlreadyExists = Access::doAsSuperUser(function () {
+            return count(APIUsersManager::getInstance()->getUsersHavingSuperUserAccess()) > 0;
+        });
+
+        if ($superUserAlreadyExists) {
             $this->redirectToNextStep('setupSuperUser');
         }
 
@@ -301,9 +306,11 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
     {
         $this->checkPiwikIsNotInstalled();
 
-        $this->initObjectsToCallAPI();
+        $siteIdsCount = Access::doAsSuperUser(function () {
+            return count(APISitesManager::getInstance()->getAllSitesId());
+        });
 
-        if(count(APISitesManager::getInstance()->getAllSitesId()) > 0) {
+        if ($siteIdsCount > 0) {
             // if there is a already a website, skip this step and trackingCode step
             $this->redirectToNextStep('trackingCode');
         }
@@ -317,12 +324,15 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
         $form = new FormFirstWebsiteSetup();
 
         if ($form->validate()) {
-            $name = Common::unsanitizeInputValue($form->getSubmitValue('siteName'));
+            $name = Common::sanitizeInputValue($form->getSubmitValue('siteName'));
             $url = Common::unsanitizeInputValue($form->getSubmitValue('url'));
             $ecommerce = (int)$form->getSubmitValue('ecommerce');
 
             try {
-                $result = APISitesManager::getInstance()->addSite($name, $url, $ecommerce);
+                $result = Access::doAsSuperUser(function () use ($name, $url, $ecommerce) {
+                    return APISitesManager::getInstance()->addSite($name, $url, $ecommerce);
+                });
+
                 $params = array(
                     'site_idSite' => $result,
                     'site_name' => urlencode($name)
@@ -336,7 +346,7 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
         }
 
         // Display previous step success message, when current step form was not submitted yet
-        if(count($form->getErrorMessages()) == 0) {
+        if (count($form->getErrorMessages()) == 0) {
             $view->displayGeneralSetupSuccess = true;
         }
 
@@ -463,14 +473,6 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
         return Common::getRequestVar($name, false, 'string');
     }
 
-    /**
-     * Instantiate access and log objects
-     */
-    private function initObjectsToCallAPI()
-    {
-        Piwik::setUserHasSuperUserAccess();
-    }
-
     /**
      * Write configuration file from session-store
      */
@@ -513,7 +515,7 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
 
     private function checkPiwikIsNotInstalled()
     {
-        if(!SettingsPiwik::isPiwikInstalled()) {
+        if (!SettingsPiwik::isPiwikInstalled()) {
             return;
         }
         \Piwik\Plugins\Login\Controller::clearSession();
@@ -633,13 +635,12 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
 
     private function createSuperUser($login, $password, $email)
     {
-        $this->initObjectsToCallAPI();
-
-        $api = APIUsersManager::getInstance();
-        $api->addUser($login, $password, $email);
-
-        $this->initObjectsToCallAPI();
-        $api->setSuperUserAccess($login, true);
+        $self = $this;
+        Access::doAsSuperUser(function () use ($self, $login, $password, $email) {
+            $api = APIUsersManager::getInstance();
+            $api->addUser($login, $password, $email);
+            $api->setSuperUserAccess($login, true);
+        });
     }
 
     private function hasEnoughTablesToReuseDb($tablesInstalled)
@@ -658,7 +659,7 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
     private function deleteConfigFileIfNeeded()
     {
         $config = Config::getInstance();
-        if($config->existsLocalConfig()) {
+        if ($config->existsLocalConfig()) {
             $config->deleteLocalConfig();
         }
     }
@@ -702,16 +703,16 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
     protected function updateComponents()
     {
         Access::getInstance();
-        Piwik::setUserHasSuperUserAccess();
 
-        $updater = new Updater();
-        $componentsWithUpdateFile = CoreUpdater::getComponentUpdates($updater);
+        return Access::doAsSuperUser(function () {
+            $updater = new Updater();
+            $componentsWithUpdateFile = CoreUpdater::getComponentUpdates($updater);
 
-        if (empty($componentsWithUpdateFile)) {
-            return false;
-        }
-        $result = CoreUpdater::updateComponents($updater, $componentsWithUpdateFile);
-        return $result;
+            if (empty($componentsWithUpdateFile)) {
+                return false;
+            }
+            $result = CoreUpdater::updateComponents($updater, $componentsWithUpdateFile);
+            return $result;
+        });
     }
-
 }
diff --git a/plugins/Installation/FormFirstWebsiteSetup.php b/plugins/Installation/FormFirstWebsiteSetup.php
index 83c68bea3462e9598a38267880029b50c9eb48d8..924c711a30f908eaa4776d6b1abfd6df9ab1afd3 100644
--- a/plugins/Installation/FormFirstWebsiteSetup.php
+++ b/plugins/Installation/FormFirstWebsiteSetup.php
@@ -12,6 +12,8 @@ namespace Piwik\Plugins\Installation;
 use HTML_QuickForm2_DataSource_Array;
 use HTML_QuickForm2_Factory;
 use HTML_QuickForm2_Rule;
+use Piwik\Log;
+use Piwik\Access;
 use Piwik\Piwik;
 use Piwik\Plugins\SitesManager\API;
 use Piwik\QuickForm2;
@@ -31,7 +33,7 @@ class FormFirstWebsiteSetup extends QuickForm2
         HTML_QuickForm2_Factory::registerRule('checkTimezone', 'Piwik\Plugins\Installation\Rule_isValidTimezone');
 
         $urlExample = 'http://example.org';
-        $javascriptOnClickUrlExample = "javascript:if(this.value=='$urlExample'){this.value='http://';} this.style.color='black';";
+        $javascriptOnClickUrlExample = "javascript:if (this.value=='$urlExample'){this.value='http://';} this.style.color='black';";
 
         $timezones = API::getInstance()->getTimezonesList();
         $timezones = array_merge(array('No timezone' => Piwik::translate('SitesManager_SelectACity')), $timezones);
@@ -79,7 +81,9 @@ class Rule_isValidTimezone extends HTML_QuickForm2_Rule
         try {
             $timezone = $this->owner->getValue();
             if (!empty($timezone)) {
-                API::getInstance()->setDefaultTimezone($timezone);
+                Access::doAsSuperUser(function () use ($timezone) {
+                    API::getInstance()->setDefaultTimezone($timezone);
+                });
             }
         } catch (\Exception $e) {
             return false;
diff --git a/plugins/Installation/ServerFilesGenerator.php b/plugins/Installation/ServerFilesGenerator.php
index 5ce2abf844f5f0beb3a45aa2e6c94e8c073f9968..9551340e4ac51ac392bae89b4d6a6e86b45053d3 100644
--- a/plugins/Installation/ServerFilesGenerator.php
+++ b/plugins/Installation/ServerFilesGenerator.php
@@ -18,7 +18,7 @@ class ServerFilesGenerator
      */
     public static function createHtAccessFiles()
     {
-        if(!SettingsServer::isApache()) {
+        if (!SettingsServer::isApache()) {
             return;
         }
         $denyAll = self::getDenyAllHtaccessContent();
diff --git a/plugins/Installation/SystemCheck.php b/plugins/Installation/SystemCheck.php
index f6d8c42e028ff146819e2b09af85917bc20599b0..29f87f2415ce0d0ee81887703bd86476e2c928c2 100644
--- a/plugins/Installation/SystemCheck.php
+++ b/plugins/Installation/SystemCheck.php
@@ -140,7 +140,7 @@ class SystemCheck
         }
 
         $sessionAutoStarted = (int)ini_get('session.auto_start');
-        if($sessionAutoStarted) {
+        if ($sessionAutoStarted) {
             $infos['missing_desired_functions'][] = 'session.auto_start';
         }
 
diff --git a/plugins/LanguagesManager/API.php b/plugins/LanguagesManager/API.php
index e95931ae8721ca6246b91b23178da654fdb207ae..e715770279574f9824139946f754947ed1fddc58 100644
--- a/plugins/LanguagesManager/API.php
+++ b/plugins/LanguagesManager/API.php
@@ -9,7 +9,6 @@
  */
 namespace Piwik\Plugins\LanguagesManager;
 
-use Piwik\Common;
 use Piwik\Db;
 use Piwik\Filesystem;
 use Piwik\Piwik;
@@ -229,12 +228,20 @@ class API extends \Piwik\Plugin\API
      */
     public function getLanguageForUser($login)
     {
-        if($login == 'anonymous') {
+        if ($login == 'anonymous') {
             return false;
         }
+
         Piwik::checkUserHasSuperUserAccessOrIsTheUser($login);
-        return Db::fetchOne('SELECT language FROM ' . Common::prefixTable('user_language') .
-            ' WHERE login = ? ', array($login));
+
+        $lang = $this->getModel()->getLanguageForUser($login);
+
+        return $lang;
+    }
+
+    private function getModel()
+    {
+        return new Model();
     }
 
     /**
@@ -248,15 +255,13 @@ class API extends \Piwik\Plugin\API
     {
         Piwik::checkUserHasSuperUserAccessOrIsTheUser($login);
         Piwik::checkUserIsNotAnonymous();
+
         if (!$this->isLanguageAvailable($languageCode)) {
             return false;
         }
-        $paramsBind = array($login, $languageCode, $languageCode);
-        Db::query('INSERT INTO ' . Common::prefixTable('user_language') .
-            ' (login, language)
-                VALUES (?,?)
-            ON DUPLICATE KEY UPDATE language=?',
-            $paramsBind);
+
+        $this->getModel()->setLanguageForUser($login, $languageCode);
+
         return true;
     }
 
diff --git a/plugins/LanguagesManager/Commands/CompareKeys.php b/plugins/LanguagesManager/Commands/CompareKeys.php
index 088bb492aeb12ae2f89c262f7d271bc5c9c4c647..821342a90c63538f65a703cd723827ff9107671e 100644
--- a/plugins/LanguagesManager/Commands/CompareKeys.php
+++ b/plugins/LanguagesManager/Commands/CompareKeys.php
@@ -62,7 +62,7 @@ class CompareKeys extends ConsoleCommand
         {
             if (!empty($englishFromOTrance[$category])) {
                 foreach ($englishFromOTrance[$category] as $key => $value) {
-                    if(!array_key_exists($category, $availableTranslations) || !array_key_exists($key, $availableTranslations[$category])) {
+                    if (!array_key_exists($category, $availableTranslations) || !array_key_exists($key, $availableTranslations[$category])) {
                         $unnecessary[] = sprintf('%s_%s', $category, $key);
                         continue;
                     } else if (html_entity_decode($availableTranslations[$category][$key]) != html_entity_decode($englishFromOTrance[$category][$key])) {
@@ -73,7 +73,7 @@ class CompareKeys extends ConsoleCommand
             }
             if (!empty($availableTranslations[$category])) {
                 foreach ($availableTranslations[$category] as $key => $value) {
-                    if(!array_key_exists($category, $englishFromOTrance) || !array_key_exists($key, $englishFromOTrance[$category])) {
+                    if (!array_key_exists($category, $englishFromOTrance) || !array_key_exists($key, $englishFromOTrance[$category])) {
                         $missing[] = sprintf('%s_%s', $category, $key);
                         continue;
                     }
diff --git a/plugins/LanguagesManager/LanguagesManager.php b/plugins/LanguagesManager/LanguagesManager.php
index 66fba008e59e361ededd3871e22c146f8ac41c04..6a0fcf10e14d8b23a6308813b4efc08ef2299a57 100644
--- a/plugins/LanguagesManager/LanguagesManager.php
+++ b/plugins/LanguagesManager/LanguagesManager.php
@@ -14,7 +14,6 @@ use Piwik\Common;
 use Piwik\Config;
 use Piwik\Cookie;
 use Piwik\Db;
-use Piwik\DbHelper;
 use Piwik\Piwik;
 use Piwik\Translate;
 use Piwik\View;
@@ -102,7 +101,8 @@ class LanguagesManager extends \Piwik\Plugin
 
     public function deleteUserLanguage($userLogin)
     {
-        Db::query('DELETE FROM ' . Common::prefixTable('user_language') . ' WHERE login = ?', $userLogin);
+        $model = new Model();
+        $model->deleteUserLanguage($userLogin);
     }
 
     /**
@@ -110,10 +110,7 @@ class LanguagesManager extends \Piwik\Plugin
      */
     public function install()
     {
-        $userLanguage = "login VARCHAR( 100 ) NOT NULL ,
-					     language VARCHAR( 10 ) NOT NULL ,
-					     PRIMARY KEY ( login )";
-        DbHelper::createTable('user_language', $userLanguage);
+        Model::install();
     }
 
     /**
@@ -121,7 +118,7 @@ class LanguagesManager extends \Piwik\Plugin
      */
     public function uninstall()
     {
-        Db::dropTables(Common::prefixTable('user_language'));
+        Model::uninstall();
     }
 
     /**
diff --git a/plugins/LanguagesManager/Model.php b/plugins/LanguagesManager/Model.php
new file mode 100644
index 0000000000000000000000000000000000000000..e40452c1344897f199aa2e716def0cba7b912ef9
--- /dev/null
+++ b/plugins/LanguagesManager/Model.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ *
+ */
+namespace Piwik\Plugins\LanguagesManager;
+
+use Piwik\Common;
+use Piwik\Db;
+use Piwik\DbHelper;
+
+class Model
+{
+    private static $rawPrefix = 'user_language';
+    private $table;
+
+    public function __construct()
+    {
+        $this->table = Common::prefixTable(self::$rawPrefix);
+    }
+
+    public function deleteUserLanguage($userLogin)
+    {
+        Db::query('DELETE FROM ' . $this->table . ' WHERE login = ?', $userLogin);
+    }
+
+    /**
+     * Returns the language for the user
+     *
+     * @param string $userLogin
+     * @return string
+     */
+    public function getLanguageForUser($userLogin)
+    {
+        return Db::fetchOne('SELECT language FROM ' . $this->table .
+                            ' WHERE login = ? ', array($userLogin));
+    }
+
+    /**
+     * Sets the language for the user
+     *
+     * @param string $login
+     * @param string $languageCode
+     * @return bool
+     */
+    public function setLanguageForUser($login, $languageCode)
+    {
+        $query = 'INSERT INTO ' . $this->table .
+                 ' (login, language) VALUES (?,?) ON DUPLICATE KEY UPDATE language=?';
+        $bind  = array($login, $languageCode, $languageCode);
+        Db::query($query, $bind);
+
+        return true;
+    }
+
+    public static function install()
+    {
+        $userLanguage = "login VARCHAR( 100 ) NOT NULL ,
+					     language VARCHAR( 10 ) NOT NULL ,
+					     PRIMARY KEY ( login )";
+        DbHelper::createTable(self::$rawPrefix, $userLanguage);
+    }
+
+    public static function uninstall()
+    {
+        Db::dropTables(Common::prefixTable(self::$rawPrefix));
+    }
+}
diff --git a/plugins/Live/API.php b/plugins/Live/API.php
index c2acabb6191fa4f025550919ae0497b9459d890f..d15cca9e36c0b435104118e81b2eab1a0a76aad2 100644
--- a/plugins/Live/API.php
+++ b/plugins/Live/API.php
@@ -306,7 +306,7 @@ class API extends \Piwik\Plugin\API
                 $cities[$countryCode] = array();
             }
             $city = $visit->getColumn('city');
-            if(!empty($city)) {
+            if (!empty($city)) {
                 $cities[$countryCode][] = $city;
             }
         }
@@ -325,7 +325,7 @@ class API extends \Piwik\Plugin\API
                                    'nb_visits'  => $nbVisits,
                                    'flag'       => \Piwik\Plugins\UserCountry\getFlagFromCode($countryCode),
                                    'prettyName' => \Piwik\Plugins\UserCountry\countryTranslate($countryCode));
-            if(!empty($cities[$countryCode])) {
+            if (!empty($cities[$countryCode])) {
                 $countryInfo['cities'] = array_unique($cities[$countryCode]);
             }
             $result['countries'][] = $countryInfo;
@@ -476,8 +476,7 @@ class API extends \Piwik\Plugin\API
         $segment = new Segment($segment, $idSite);
         $queryInfo = $segment->getSelectQuery($select, $from, $where, $whereBind, $orderBy, $groupBy);
 
-        $sql = "SELECT sub.idvisitor, sub.visit_last_action_time
-                  FROM ({$queryInfo['sql']}) as sub
+        $sql = "SELECT sub.idvisitor, sub.visit_last_action_time FROM ({$queryInfo['sql']}) as sub
                  WHERE $visitLastActionTimeCondition
                  LIMIT 1";
         $bind = array_merge($queryInfo['bind'], array($visitLastActionTime));
@@ -589,7 +588,7 @@ class API extends \Piwik\Plugin\API
                 $visitorDetailsArray['serverTimestamp'] = $visitorDetailsArray['lastActionTimestamp'];
 
                 $dateTimeVisit = Date::factory($visitorDetailsArray['lastActionTimestamp'], $timezone);
-                if($dateTimeVisit) {
+                if ($dateTimeVisit) {
                     $visitorDetailsArray['serverTimePretty'] = $dateTimeVisit->getLocalized('%time%');
                     $visitorDetailsArray['serverDatePretty'] = $dateTimeVisit->getLocalized(Piwik::translate('CoreHome_ShortDateFormat'));
                 }
@@ -703,8 +702,7 @@ class API extends \Piwik\Plugin\API
 
         // Group by idvisit so that a visitor converting 2 goals only appears once
         $sql = "
-			SELECT sub.*
-			FROM (
+			SELECT sub.* FROM (
 				" . $subQuery['sql'] . "
 				$sqlLimit
 			) AS sub
diff --git a/plugins/Live/Visitor.php b/plugins/Live/Visitor.php
index ae01ed4e1840a749061652a15b466182fcc2572a..55fd3fed8344eb7ef3b4e951c650657b2ce6195a 100644
--- a/plugins/Live/Visitor.php
+++ b/plugins/Live/Visitor.php
@@ -309,7 +309,7 @@ class Visitor implements VisitorInterface
 
             } elseif ($actionDetail['type'] == Action::TYPE_EVENT_CATEGORY) {
                 // Handle Event
-                if(strlen($actionDetail['pageTitle']) > 0) {
+                if (strlen($actionDetail['pageTitle']) > 0) {
                     $actionDetail['eventName'] = $actionDetail['pageTitle'];
                 }
 
@@ -322,8 +322,8 @@ class Visitor implements VisitorInterface
             }
 
             // Event value / Generation time
-            if($actionDetail['type'] == Action::TYPE_EVENT_CATEGORY) {
-                if(strlen($actionDetail['custom_float']) > 0) {
+            if ($actionDetail['type'] == Action::TYPE_EVENT_CATEGORY) {
+                if (strlen($actionDetail['custom_float']) > 0) {
                     $actionDetail['eventValue'] = round($actionDetail['custom_float'], self::EVENT_VALUE_PRECISION);
                 }
             } elseif ($actionDetail['custom_float'] > 0) {
diff --git a/plugins/Live/VisitorLog.php b/plugins/Live/VisitorLog.php
index 2afc67349bcfb0f77eff5d70639b762d601277ad..054b2f50ae5d46324ec7347ea9df464f5d9a858d 100644
--- a/plugins/Live/VisitorLog.php
+++ b/plugins/Live/VisitorLog.php
@@ -105,7 +105,7 @@ class VisitorLog extends Visualization
                                        && $filterEcommerce == \Piwik\Plugins\Goals\Controller::ECOMMERCE_LOG_SHOW_ORDERS;
                             $isAbandonedCart = $action['type'] == 'ecommerceAbandonedCart'
                                        && $filterEcommerce == \Piwik\Plugins\Goals\Controller::ECOMMERCE_LOG_SHOW_ABANDONED_CARTS;
-                            if($isAbandonedCart || $isEcommerceOrder) {
+                            if ($isAbandonedCart || $isEcommerceOrder) {
                                 return true;
                             }
                         }
diff --git a/plugins/Login/Controller.php b/plugins/Login/Controller.php
index 82ae9ccab26e4fd99359bb4466970629610d93d2..62c8b407407bbdaa1357ccf9ba8c69082a88ff0a 100644
--- a/plugins/Login/Controller.php
+++ b/plugins/Login/Controller.php
@@ -9,6 +9,7 @@
 namespace Piwik\Plugins\Login;
 
 use Exception;
+use Piwik\Access;
 use Piwik\Auth as AuthInterface;
 use Piwik\Common;
 use Piwik\Config;
@@ -278,7 +279,7 @@ class Controller extends \Piwik\Plugin\Controller
             // have to do this as super user since redirectToIndex checks if there's a default website ID for
             // the current user and if not, doesn't redirect to the requested action. TODO: this behavior is wrong. somehow.
             $self = $this;
-            Piwik::doAsSuperUser(function () use ($self) {
+            Access::doAsSuperUser(function () use ($self) {
                 $self->redirectToIndex(Piwik::getLoginPluginName(), 'resetPasswordSuccess');
             });
             return null;
@@ -330,4 +331,4 @@ class Controller extends \Piwik\Plugin\Controller
             Url::redirectToUrl($logoutUrl);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/plugins/Login/Login.php b/plugins/Login/Login.php
index 4c33579176850611c9b2ecdb0643ce824522bd3a..8b65e2e1751fb3e377f37fdd479d911280932213 100644
--- a/plugins/Login/Login.php
+++ b/plugins/Login/Login.php
@@ -85,7 +85,7 @@ class Login extends \Piwik\Plugin
      */
     public static function initAuthenticationFromCookie(\Piwik\Auth $auth, $activateCookieAuth)
     {
-        if(self::isModuleIsAPI() && !$activateCookieAuth) {
+        if (self::isModuleIsAPI() && !$activateCookieAuth) {
             return;
         }
 
diff --git a/plugins/Login/PasswordResetter.php b/plugins/Login/PasswordResetter.php
index 479a8a10a33ef858758d5ebd54d883b540f2e124..d2631abdf980b6dda30bc37c088690a87a9c0fb3 100644
--- a/plugins/Login/PasswordResetter.php
+++ b/plugins/Login/PasswordResetter.php
@@ -8,6 +8,7 @@
 namespace Piwik\Plugins\Login;
 
 use Exception;
+use Piwik\Access;
 use Piwik\Common;
 use Piwik\Config;
 use Piwik\IP;
@@ -209,7 +210,7 @@ class PasswordResetter
 
         // reset password of user
         $usersManager = $this->usersManagerApi;
-        Piwik::doAsSuperUser(function () use ($usersManager, $user, $resetPassword) {
+        Access::doAsSuperUser(function () use ($usersManager, $user, $resetPassword) {
             $usersManager->updateUser(
                 $user['login'], $resetPassword, $email = false, $alias = false, $isPasswordHashed = true);
         });
@@ -359,7 +360,7 @@ class PasswordResetter
     protected function getUserInformation($loginOrMail)
     {
         $usersManager = $this->usersManagerApi;
-        return Piwik::doAsSuperUser(function () use ($loginOrMail, $usersManager) {
+        return Access::doAsSuperUser(function () use ($loginOrMail, $usersManager) {
             $user = null;
             if ($usersManager->userExists($loginOrMail)) {
                 $user = $usersManager->getUser($loginOrMail);
diff --git a/plugins/Login/SessionInitializer.php b/plugins/Login/SessionInitializer.php
index 1ede89c63904dced1c374de01989b8bbd1365e0d..cd41b36295e47a7264deb0f73064fe0afb76961f 100644
--- a/plugins/Login/SessionInitializer.php
+++ b/plugins/Login/SessionInitializer.php
@@ -14,6 +14,7 @@ use Piwik\AuthResult;
 use Piwik\Config;
 use Piwik\Cookie;
 use Piwik\Db;
+use Piwik\Log;
 use Piwik\Piwik;
 use Piwik\Plugins\UsersManager\API as UsersManagerAPI;
 use Piwik\ProxyHttp;
@@ -135,7 +136,17 @@ class SessionInitializer
      */
     protected function doAuthenticateSession(AuthInterface $auth)
     {
-        $tokenAuth = $this->usersManagerAPI->getTokenAuth($auth->getLogin(), $auth->getTokenAuthSecret());
+        $login = $auth->getLogin();
+        $tokenAuthSecret = null;
+
+        try {
+            $tokenAuthSecret = $auth->getTokenAuthSecret();
+        } catch (Exception $ex) {
+            Log::debug("SessionInitializer::doAuthenticateSession: token_auth secret for %s not avaialble before user"
+                     . " is authenticated.", $login);
+        }
+
+        $tokenAuth = empty($tokenAuthSecret) ? null : $this->usersManagerAPI->getTokenAuth($login, $tokenAuthSecret);
 
         /**
          * @deprecated Create a custom SessionInitializer instead.
diff --git a/plugins/MultiSites/API.php b/plugins/MultiSites/API.php
index 41031fae8f19c7f5dafec58be2d5f92a91c174f1..ea393414f7b83505015f61978b720a228addeabd 100755
--- a/plugins/MultiSites/API.php
+++ b/plugins/MultiSites/API.php
@@ -346,7 +346,7 @@ class API extends \Piwik\Plugin\API
     {
         $metrics = self::$baseMetrics;
 
-        if(Common::isActionsPluginEnabled()) {
+        if (Common::isActionsPluginEnabled()) {
             $metrics[self::NB_PAGEVIEWS_LABEL] = array(
                 self::METRIC_TRANSLATION_KEY        => 'General_ColumnPageviews',
                 self::METRIC_EVOLUTION_COL_NAME_KEY => 'pageviews_evolution',
diff --git a/plugins/MultiSites/Menu.php b/plugins/MultiSites/Menu.php
index 5059cfc09dc2094a71a0bc4ce7d2763506ae5d8c..8860eacec097b63b0a8b395869a6db6e6b2cbfed 100644
--- a/plugins/MultiSites/Menu.php
+++ b/plugins/MultiSites/Menu.php
@@ -15,7 +15,7 @@ class Menu extends \Piwik\Plugin\Menu
 {
     public function configureTopMenu(MenuTop $menu)
     {
-        $urlParams = $this->urlForAction('index', array('segment' => false));
+        $urlParams = $this->urlForActionWithDefaultUserParams('index', array('segment' => false, 'idSite' => false));
         $tooltip   = Piwik::translate('MultiSites_TopLinkTooltip');
 
         $menu->add('General_MultiSitesSummary', null, $urlParams, true, 3, $tooltip);
diff --git a/plugins/PrivacyManager/DoNotTrackHeaderChecker.php b/plugins/PrivacyManager/DoNotTrackHeaderChecker.php
index b857debf853db5a2ebe8e2afbcf71ddc08029f4b..14938f426e4461c409a762a942255e127dc7a5f5 100644
--- a/plugins/PrivacyManager/DoNotTrackHeaderChecker.php
+++ b/plugins/PrivacyManager/DoNotTrackHeaderChecker.php
@@ -26,7 +26,7 @@ class DoNotTrackHeaderChecker
      */
     public function checkHeaderInTracker(&$exclude)
     {
-        if($exclude) {
+        if ($exclude) {
             Common::printDebug("Visit is already excluded, no need to check DoNotTrack support.");
             return;
         }
diff --git a/plugins/PrivacyManager/LogDataPurger.php b/plugins/PrivacyManager/LogDataPurger.php
index 2ec73deb81d9676903a9359eced830bf23e301dc..6fe1381c502a795d201f3dadbeb3e9f6bf201c03 100755
--- a/plugins/PrivacyManager/LogDataPurger.php
+++ b/plugins/PrivacyManager/LogDataPurger.php
@@ -173,7 +173,7 @@ class LogDataPurger
     private function getLogTableDeleteCount($table, $maxIdVisit)
     {
         $sql = "SELECT COUNT(*) FROM $table WHERE idvisit <= ?";
-        return (int)Db::fetchOne($sql, array($maxIdVisit));
+        return (int) Db::fetchOne($sql, array($maxIdVisit));
     }
 
     private function createTempTable()
diff --git a/plugins/PrivacyManager/ReportsPurger.php b/plugins/PrivacyManager/ReportsPurger.php
index a35169e6efaf49222b133c9ecafbd87a95f33162..9889c00e9d72530385fd551919d94666c4801891 100755
--- a/plugins/PrivacyManager/ReportsPurger.php
+++ b/plugins/PrivacyManager/ReportsPurger.php
@@ -260,12 +260,11 @@ class ReportsPurger
     {
         $maxIdArchive = Db::fetchOne("SELECT MAX(idarchive) FROM $table");
 
-        $sql = "SELECT COUNT(*)
-				  FROM $table
-				 WHERE name NOT IN ('" . implode("','", $this->metricsToKeep) . "')
-				   AND name NOT LIKE 'done%'
-				   AND idarchive >= ?
-				   AND idarchive < ?";
+        $sql = "SELECT COUNT(*) FROM $table
+                 WHERE name NOT IN ('" . implode("','", $this->metricsToKeep) . "')
+                   AND name NOT LIKE 'done%'
+                   AND idarchive >= ?
+                   AND idarchive < ?";
 
         $segments = Db::segmentedFetchOne($sql, 0, $maxIdArchive, self::$selectSegmentSize);
         return array_sum($segments);
@@ -275,11 +274,10 @@ class ReportsPurger
     {
         $maxIdArchive = Db::fetchOne("SELECT MAX(idarchive) FROM $table");
 
-        $sql = "SELECT COUNT(*)
-				  FROM $table
-				 WHERE " . $this->getBlobTableWhereExpr($oldNumericTables, $table) . "
-				   AND idarchive >= ?
-				   AND idarchive < ?";
+        $sql = "SELECT COUNT(*) FROM $table
+                 WHERE " . $this->getBlobTableWhereExpr($oldNumericTables, $table) . "
+                   AND idarchive >= ?
+                   AND idarchive < ?";
 
         $segments = Db::segmentedFetchOne($sql, 0, $maxIdArchive, self::$selectSegmentSize);
         return array_sum($segments);
@@ -325,12 +323,11 @@ class ReportsPurger
 
             $maxIdArchive = Db::fetchOne("SELECT MAX(idarchive) FROM $table");
 
-            $sql = "SELECT idarchive
-					  FROM $table
-					 WHERE name != 'done'
-					   AND name LIKE 'done_%.%'
-					   AND idarchive >= ?
-					   AND idarchive < ?";
+            $sql = "SELECT idarchive FROM $table
+                     WHERE name != 'done'
+                       AND name LIKE 'done_%.%'
+                       AND idarchive >= ?
+                       AND idarchive < ?";
 
             if (is_null($this->segmentArchiveIds)) {
                 $this->segmentArchiveIds = array();
diff --git a/plugins/Referrers/Columns/Base.php b/plugins/Referrers/Columns/Base.php
index de871401b386359bf0b2590c948f406b1872a10a..a69fcc54bfe3639fd3d4b6104cb476738d0ca2e6 100644
--- a/plugins/Referrers/Columns/Base.php
+++ b/plugins/Referrers/Columns/Base.php
@@ -244,14 +244,14 @@ abstract class Base extends VisitDimension
 
     protected function detectCampaignKeywordFromReferrerUrl()
     {
-        if(!empty($this->nameReferrerAnalyzed)
+        if (!empty($this->nameReferrerAnalyzed)
             && !empty($this->keywordReferrerAnalyzed)) {
             // keyword is already set, we skip
             return true;
         }
 
         // Set the Campaign keyword to the keyword found in the Referrer URL if any
-        if(!empty($this->nameReferrerAnalyzed)) {
+        if (!empty($this->nameReferrerAnalyzed)) {
             $referrerUrlInfo = UrlHelper::extractSearchEngineInformationFromUrl($this->referrerUrl);
             if (!empty($referrerUrlInfo['keywords'])) {
                 $this->keywordReferrerAnalyzed = $referrerUrlInfo['keywords'];
@@ -270,7 +270,7 @@ abstract class Base extends VisitDimension
                 $parsedAdsenseReferrerUrl = parse_url($value);
                 if (!empty($parsedAdsenseReferrerUrl['host'])) {
 
-                    if(empty($this->nameReferrerAnalyzed)) {
+                    if (empty($this->nameReferrerAnalyzed)) {
                         $type = $this->getParameterValueFromReferrerUrl('ad_type');
                         $type = $type ? " ($type)" : '';
                         $this->nameReferrerAnalyzed = self::LABEL_ADWORDS_NAME . $type;
@@ -304,7 +304,7 @@ abstract class Base extends VisitDimension
             return false;
         }
         // if we detected a campaign but there is still no keyword set, we set the keyword to the Referrer host
-        if(empty($this->keywordReferrerAnalyzed)) {
+        if (empty($this->keywordReferrerAnalyzed)) {
             $this->keywordReferrerAnalyzed = $this->referrerHost;
         }
 
diff --git a/plugins/Referrers/Controller.php b/plugins/Referrers/Controller.php
index e683cb7f9ef99112086806c55de33cfbb1025aa5..f01c61f64703dda1bcf9da03c30c43905890e2ad 100644
--- a/plugins/Referrers/Controller.php
+++ b/plugins/Referrers/Controller.php
@@ -332,7 +332,7 @@ function DisplayTopKeywords($url = "")
 	$url = empty($url) ? "http://". $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"] : $url;
 	$api = "' . $api . '&url=" . urlencode($url);
 	$keywords = @unserialize(file_get_contents($api));
-	if($keywords === false || isset($keywords["result"])) {
+	if ($keywords === false || isset($keywords["result"])) {
 		// DEBUG ONLY: uncomment for troubleshooting an empty output (the URL output reveals the token_auth)
 		// echo "Error while fetching the <a href=\'$api\'>Top Keywords from Piwik</a>";
 		return;
@@ -344,7 +344,7 @@ function DisplayTopKeywords($url = "")
 	foreach($keywords as $keyword) {
 		$output .= "<li>". $keyword . "</li>";
 	}
-	if(empty($keywords)) { $output .= "Nothing yet..."; }
+	if (empty($keywords)) { $output .= "Nothing yet..."; }
 	$output .= "</ul>";
 	echo $output;
 }
diff --git a/plugins/Referrers/functions.php b/plugins/Referrers/functions.php
index 8f7a4023dfbbf6231f773cf7ddd5c6cbbfc2de52..e0fee308336f492e8f7c90b6f11fe14424415a64 100644
--- a/plugins/Referrers/functions.php
+++ b/plugins/Referrers/functions.php
@@ -39,7 +39,7 @@ function getSocialMainUrl($url)
     $social  = getSocialNetworkFromDomain($url);
     foreach (Common::getSocialUrls() as $domain => $name) {
 
-        if($name == $social) {
+        if ($name == $social) {
 
             return $domain;
         }
@@ -57,7 +57,7 @@ function getSocialNetworkFromDomain($url)
 {
     foreach (Common::getSocialUrls() as $domain => $name) {
 
-        if(preg_match('/(^|[\.\/])'.$domain.'([\.\/]|$)/', $url)) {
+        if (preg_match('/(^|[\.\/])'.$domain.'([\.\/]|$)/', $url)) {
 
             return $name;
         }
diff --git a/plugins/ScheduledReports/API.php b/plugins/ScheduledReports/API.php
index 3ea8a05c28b4883282bf85d28b4ecbfe0eaf11fd..a42b5bb209ad90fb0593051079757546d9859ebd 100644
--- a/plugins/ScheduledReports/API.php
+++ b/plugins/ScheduledReports/API.php
@@ -53,6 +53,9 @@ class API extends \Piwik\Plugin\API
 
     const REPORT_TRUNCATE = 23;
 
+    // static cache storing reports
+    public static $cache = array();
+
     /**
      * Creates a new report and schedules it.
      *
@@ -84,29 +87,20 @@ class API extends \Piwik\Plugin\API
         // validation of requested reports
         $reports = self::validateRequestedReports($idSite, $reportType, $reports);
 
-        $db = Db::get();
-        $idReport = $db->fetchOne("SELECT max(idreport) + 1 FROM " . Common::prefixTable('report'));
-
-        if ($idReport == false) {
-            $idReport = 1;
-        }
-
-        $db->insert(Common::prefixTable('report'),
-            array(
-                 'idreport'    => $idReport,
-                 'idsite'      => $idSite,
-                 'login'       => $currentUser,
-                 'description' => $description,
-                 'idsegment'   => $idSegment,
-                 'period'      => $period,
-                 'hour'        => $hour,
-                 'type'        => $reportType,
-                 'format'      => $reportFormat,
-                 'parameters'  => $parameters,
-                 'reports'     => $reports,
-                 'ts_created'  => Date::now()->getDatetime(),
-                 'deleted'     => 0,
-            ));
+        $idReport = $this->getModel()->createReport(array(
+             'idsite'      => $idSite,
+             'login'       => $currentUser,
+             'description' => $description,
+             'idsegment'   => $idSegment,
+             'period'      => $period,
+             'hour'        => $hour,
+             'type'        => $reportType,
+             'format'      => $reportFormat,
+             'parameters'  => $parameters,
+             'reports'     => $reports,
+             'ts_created'  => Date::now()->getDatetime(),
+             'deleted'     => 0,
+        ));
 
         return $idReport;
     }
@@ -130,7 +124,7 @@ class API extends \Piwik\Plugin\API
         Piwik::checkUserHasViewAccess($idSite);
 
         $scheduledReports = $this->getReports($idSite, $periodSearch = false, $idReport);
-        $report = reset($scheduledReports);
+        $report   = reset($scheduledReports);
         $idReport = $report['idreport'];
 
         $currentUser = Piwik::getCurrentUserLogin();
@@ -144,19 +138,16 @@ class API extends \Piwik\Plugin\API
         // validation of requested reports
         $reports = self::validateRequestedReports($idSite, $reportType, $reports);
 
-        Db::get()->update(Common::prefixTable('report'),
-            array(
-                 'description' => $description,
-                 'idsegment'   => $idSegment,
-                 'period'      => $period,
-                 'hour'        => $hour,
-                 'type'        => $reportType,
-                 'format'      => $reportFormat,
-                 'parameters'  => $parameters,
-                 'reports'     => $reports,
-            ),
-            "idreport = '$idReport'"
-        );
+        $this->getModel()->updateReport($idReport, array(
+            'description' => $description,
+            'idsegment'   => $idSegment,
+            'period'      => $period,
+            'hour'        => $hour,
+            'type'        => $reportType,
+            'format'      => $reportFormat,
+            'parameters'  => $parameters,
+            'reports'     => $reports,
+        ));
 
         self::$cache = array();
     }
@@ -172,18 +163,13 @@ class API extends \Piwik\Plugin\API
         $report = reset($APIScheduledReports);
         Piwik::checkUserHasSuperUserAccessOrIsTheUser($report['login']);
 
-        Db::get()->update(Common::prefixTable('report'),
-            array(
-                 'deleted' => 1,
-            ),
-            "idreport = '$idReport'"
-        );
+        $this->getModel()->updateReport($idReport, array(
+            'deleted' => 1,
+        ));
+
         self::$cache = array();
     }
 
-    // static cache storing reports
-    public static $cache = array();
-
     /**
      * Returns the list of reports matching the passed parameters
      *
@@ -198,6 +184,7 @@ class API extends \Piwik\Plugin\API
     public function getReports($idSite = false, $period = false, $idReport = false, $ifSuperUserReturnOnlySuperUserReports = false, $idSegment = false)
     {
         Piwik::checkUserHasSomeViewAccess();
+
         $cacheKey = (int)$idSite . '.' . (string)$period . '.' . (int)$idReport . '.' . (int)$ifSuperUserReturnOnlySuperUserReports;
         if (isset(self::$cache[$cacheKey])) {
             return self::$cache[$cacheKey];
@@ -427,7 +414,7 @@ class API extends \Piwik\Plugin\API
             array(&$reportRenderer, $reportType, $outputType, $report)
         );
 
-        if(is_null($reportRenderer)) {
+        if (is_null($reportRenderer)) {
             throw new Exception("A report renderer was not supplied in the event " . self::GET_RENDERER_INSTANCE_EVENT);
         }
 
@@ -556,10 +543,8 @@ class API extends \Piwik\Plugin\API
         );
 
         // Update flag in DB
-        Db::get()->update(Common::prefixTable('report'),
-            array('ts_last_sent' => Date::now()->getDatetime()),
-            "idreport = " . $report['idreport']
-        );
+        $now = Date::now()->getDatetime();
+        $this->getModel()->updateReport($report['idreport'], array('ts_last_sent' => $now));
 
         // If running from piwik.php with debug, do not delete the PDF after sending the email
         if (!isset($GLOBALS['PIWIK_TRACKER_DEBUG']) || !$GLOBALS['PIWIK_TRACKER_DEBUG']) {
@@ -567,6 +552,11 @@ class API extends \Piwik\Plugin\API
         }
     }
 
+    private function getModel()
+    {
+        return new Model();
+    }
+
     private static function getReportSubjectAndReportTitle($websiteName, $reports)
     {
         // if the only report is "All websites", we don't display the site name
diff --git a/plugins/ScheduledReports/Model.php b/plugins/ScheduledReports/Model.php
new file mode 100644
index 0000000000000000000000000000000000000000..01507f65f9c41aaf2be2fd3dfe271688ac913d05
--- /dev/null
+++ b/plugins/ScheduledReports/Model.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\ScheduledReports;
+
+use Piwik\Common;
+use Piwik\Db;
+use Piwik\DbHelper;
+use Piwik\ReportRenderer;
+use Piwik\Translate;
+
+class Model
+{
+    private static $rawPrefix = 'report';
+    private $table;
+
+    public function __construct()
+    {
+        $this->table = Common::prefixTable(self::$rawPrefix);
+    }
+
+    public function deleteUserReportForSite($userLogin, $idSite)
+    {
+        $query = 'DELETE FROM ' . $this->table . ' WHERE login = ? and idsite = ?';
+        $bind  = array($userLogin, $idSite);
+        Db::query($query, $bind);
+    }
+
+    public function deleteAllReportForUser($userLogin)
+    {
+        Db::query('DELETE FROM ' . $this->table . ' WHERE login = ?', $userLogin);
+    }
+
+    public function updateReport($idReport, $report)
+    {
+        $idReport = (int) $idReport;
+
+        $this->getDb()->update($this->table, $report, "idreport = " . $idReport);
+    }
+
+    public function createReport($report)
+    {
+        $nextId = $this->getNextReportId();
+        $report['idreport'] = $nextId;
+
+        $this->getDb()->insert($this->table, $report);
+
+        return $nextId;
+    }
+
+    private function getNextReportId()
+    {
+        $db = $this->getDb();
+        $idReport = $db->fetchOne("SELECT max(idreport) + 1 FROM " . $this->table);
+
+        if ($idReport == false) {
+            $idReport = 1;
+        }
+
+        return $idReport;
+    }
+
+    private function getDb()
+    {
+        return Db::get();
+    }
+
+    public static function install()
+    {
+        $reportTable = "`idreport` INT(11) NOT NULL AUTO_INCREMENT,
+					    `idsite` INTEGER(11) NOT NULL,
+					    `login` VARCHAR(100) NOT NULL,
+					    `description` VARCHAR(255) NOT NULL,
+					    `idsegment` INT(11),
+					    `period` VARCHAR(10) NOT NULL,
+					    `hour` tinyint NOT NULL default 0,
+					    `type` VARCHAR(10) NOT NULL,
+					    `format` VARCHAR(10) NOT NULL,
+					    `reports` TEXT NOT NULL,
+					    `parameters` TEXT NULL,
+					    `ts_created` TIMESTAMP NULL,
+					    `ts_last_sent` TIMESTAMP NULL,
+					    `deleted` tinyint(4) NOT NULL default 0,
+					    PRIMARY KEY (`idreport`)";
+
+        DbHelper::createTable(self::$rawPrefix, $reportTable);
+    }
+}
diff --git a/plugins/ScheduledReports/ScheduledReports.php b/plugins/ScheduledReports/ScheduledReports.php
index ca5ebb9b418474cf8784ea26de0b3988fd8f5d74..e59e9140abad99fcbeb38040ce2a782084932b06 100644
--- a/plugins/ScheduledReports/ScheduledReports.php
+++ b/plugins/ScheduledReports/ScheduledReports.php
@@ -9,9 +9,7 @@
 namespace Piwik\Plugins\ScheduledReports;
 
 use Exception;
-use Piwik\Common;
 use Piwik\Db;
-use Piwik\DbHelper;
 use Piwik\Mail;
 use Piwik\Piwik;
 use Piwik\Plugins\MobileMessaging\MobileMessaging;
@@ -469,27 +467,27 @@ class ScheduledReports extends \Piwik\Plugin
 
         $reportsNeedSegment = array();
 
-        if(!$updatedSegment['enable_all_users']) {
+        if (!$updatedSegment['enable_all_users']) {
             // which reports would become invisible to other users?
             foreach($reportsUsingSegment as $report) {
-                if($report['login'] == Piwik::getCurrentUserLogin()) {
+                if ($report['login'] == Piwik::getCurrentUserLogin()) {
                     continue;
                 }
                 $reportsNeedSegment[] = $report;
             }
         }
 
-        if($updatedSegment['enable_only_idsite']) {
+        if ($updatedSegment['enable_only_idsite']) {
             // which reports from other websites are set to use this segment restricted to one website?
             foreach($reportsUsingSegment as $report) {
-                if($report['idsite'] == $updatedSegment['enable_only_idsite']) {
+                if ($report['idsite'] == $updatedSegment['enable_only_idsite']) {
                     continue;
                 }
                 $reportsNeedSegment[] = $report;
             }
         }
 
-        if(empty($reportsNeedSegment)) {
+        if (empty($reportsNeedSegment)) {
             return;
         }
 
@@ -526,7 +524,7 @@ class ScheduledReports extends \Piwik\Plugin
 
     public function deleteUserReport($userLogin)
     {
-        Db::query('DELETE FROM ' . Common::prefixTable('report') . ' WHERE login = ?', $userLogin);
+        $this->getModel()->deleteAllReportForUser($userLogin);
     }
 
     public function deleteUserReportForSites($userLogin, $idSites)
@@ -535,33 +533,21 @@ class ScheduledReports extends \Piwik\Plugin
             return;
         }
 
-        $table = Common::prefixTable('report');
+        $model = $this->getModel();
 
         foreach ($idSites as $idSite) {
-            Db::query('DELETE FROM ' . $table . ' WHERE login = ? and idsite = ?',
-                      array($userLogin, $idSite));
+            $model->deleteUserReportForSite($userLogin, $idSite);
         }
     }
 
+    private function getModel()
+    {
+        return new Model();
+    }
+
     public function install()
     {
-        $reportTable = "`idreport` INT(11) NOT NULL AUTO_INCREMENT,
-					    `idsite` INTEGER(11) NOT NULL,
-					    `login` VARCHAR(100) NOT NULL,
-					    `description` VARCHAR(255) NOT NULL,
-					    `idsegment` INT(11),
-					    `period` VARCHAR(10) NOT NULL,
-					    `hour` tinyint NOT NULL default 0,
-					    `type` VARCHAR(10) NOT NULL,
-					    `format` VARCHAR(10) NOT NULL,
-					    `reports` TEXT NOT NULL,
-					    `parameters` TEXT NULL,
-					    `ts_created` TIMESTAMP NULL,
-					    `ts_last_sent` TIMESTAMP NULL,
-					    `deleted` tinyint(4) NOT NULL default 0,
-					    PRIMARY KEY (`idreport`)";
-
-        DbHelper::createTable('report', $reportTable);
+        Model::install();
     }
 
     private static function checkAdditionalEmails($additionalEmails)
diff --git a/plugins/SegmentEditor/API.php b/plugins/SegmentEditor/API.php
index 98b752cc2aea949b899861a508e092767514c94c..699ad3a4eae2ca5014f5b5b94aa65c15fae43ae6 100644
--- a/plugins/SegmentEditor/API.php
+++ b/plugins/SegmentEditor/API.php
@@ -103,6 +103,7 @@ class API extends \Piwik\Plugin\API
         if (empty($segment)) {
             throw new Exception("Requested segment not found");
         }
+
         return $segment;
     }
 
@@ -128,7 +129,7 @@ class API extends \Piwik\Plugin\API
 
     public function isUserCanAddNewSegment($idSite)
     {
-        if(Piwik::isUserIsAnonymous()) {
+        if (Piwik::isUserIsAnonymous()) {
             return false;
         }
 
@@ -145,13 +146,13 @@ class API extends \Piwik\Plugin\API
 
     protected function checkUserCanEditOrDeleteSegment($segment)
     {
-        if(Piwik::hasUserSuperUserAccess()) {
+        if (Piwik::hasUserSuperUserAccess()) {
             return;
         }
 
         $this->checkUserIsNotAnonymous();
 
-        if($segment['login'] != Piwik::getCurrentUserLogin()) {
+        if ($segment['login'] != Piwik::getCurrentUserLogin()) {
             throw new Exception($this->getMessageCannotEditSegmentCreatedBySuperUser());
         }
     }
@@ -177,11 +178,16 @@ class API extends \Piwik\Plugin\API
          */
         Piwik::postEvent('SegmentEditor.deactivate', array($idSegment));
 
-        $db = Db::get();
-        $db->delete(Common::prefixTable('segment'), 'idsegment = ' . $idSegment);
+        $this->getModel()->deleteSegment($idSegment);
+
         return true;
     }
 
+    private function getModel()
+    {
+        return new Model();
+    }
+
     /**
      * Modifies an existing stored segment.
      *
@@ -201,9 +207,9 @@ class API extends \Piwik\Plugin\API
 
         $idSite = $this->checkIdSite($idSite);
         $this->checkSegmentName($name);
-        $definition = $this->checkSegmentValue($definition, $idSite);
+        $definition      = $this->checkSegmentValue($definition, $idSite);
         $enabledAllUsers = $this->checkEnabledAllUsers($enabledAllUsers);
-        $autoArchive = $this->checkAutoArchive($autoArchive, $idSite);
+        $autoArchive     = $this->checkAutoArchive($autoArchive, $idSite);
 
         $bind = array(
             'name'               => $name,
@@ -224,11 +230,8 @@ class API extends \Piwik\Plugin\API
          */
         Piwik::postEvent('SegmentEditor.update', array($idSegment, $bind));
 
-        $db = Db::get();
-        $db->update(Common::prefixTable("segment"),
-            $bind,
-            "idsegment = $idSegment"
-        );
+        $this->getModel()->updateSegment($idSegment, $bind);
+
         return true;
     }
 
@@ -252,7 +255,6 @@ class API extends \Piwik\Plugin\API
         $enabledAllUsers = $this->checkEnabledAllUsers($enabledAllUsers);
         $autoArchive = $this->checkAutoArchive($autoArchive, $idSite);
 
-        $db = Db::get();
         $bind = array(
             'name'               => $name,
             'definition'         => $definition,
@@ -263,8 +265,10 @@ class API extends \Piwik\Plugin\API
             'ts_created'         => Date::now()->getDatetime(),
             'deleted'            => 0,
         );
-        $db->insert(Common::prefixTable("segment"), $bind);
-        return $db->lastInsertId();
+
+        $id = $this->getModel()->createSegment($bind);
+
+        return $id;
     }
 
     /**
@@ -277,12 +281,12 @@ class API extends \Piwik\Plugin\API
     public function get($idSegment)
     {
         Piwik::checkUserHasSomeViewAccess();
+
         if (!is_numeric($idSegment)) {
             throw new Exception("idSegment should be numeric.");
         }
-        $segment = Db::get()->fetchRow("SELECT * " .
-            " FROM " . Common::prefixTable("segment") .
-            " WHERE idsegment = ?", $idSegment);
+
+        $segment = $this->getModel()->getSegment($idSegment);
 
         if (empty($segment)) {
             return false;
@@ -300,6 +304,7 @@ class API extends \Piwik\Plugin\API
         if ($segment['deleted']) {
             throw new Exception("This segment is marked as deleted. ");
         }
+
         return $segment;
     }
 
@@ -319,7 +324,7 @@ class API extends \Piwik\Plugin\API
 
         $userLogin = Piwik::getCurrentUserLogin();
 
-        $model = new Model();
+        $model = $this->getModel();
         if (empty($idSite)) {
             $segments = $model->getAllSegments($userLogin);
         } else {
diff --git a/plugins/SegmentEditor/Model.php b/plugins/SegmentEditor/Model.php
index 54c0e07ddfe0bf5722f5e122cea59f9a8810f8e9..8bfcc957ae6893c905765ae636bd6bb78440f214 100644
--- a/plugins/SegmentEditor/Model.php
+++ b/plugins/SegmentEditor/Model.php
@@ -10,12 +10,21 @@ namespace Piwik\Plugins\SegmentEditor;
 
 use Piwik\Common;
 use Piwik\Db;
+use Piwik\DbHelper;
 
 /**
  * The SegmentEditor Model lets you persist and read custom Segments from the backend without handling any logic.
  */
 class Model
 {
+    private static $rawPrefix = 'segment';
+    private $table;
+
+    public function __construct()
+    {
+        $this->table = Common::prefixTable(self::$rawPrefix);
+    }
+
     /**
      * Returns all stored segments.
      *
@@ -36,7 +45,7 @@ class Model
         $sql = $this->buildQuerySortedByName("($whereIdSite enable_only_idsite = 0)
                                               AND deleted = 0 AND auto_archive = 1");
 
-        $segments = Db::get()->fetchAll($sql, $bind);
+        $segments = $this->getDb()->fetchAll($sql, $bind);
 
         return $segments;
     }
@@ -52,7 +61,7 @@ class Model
         $bind = array($userLogin);
         $sql  = $this->buildQuerySortedByName('deleted = 0 AND (enable_all_users = 1 OR login = ?)');
 
-        $segments = Db::get()->fetchAll($sql, $bind);
+        $segments = $this->getDb()->fetchAll($sql, $bind);
 
         return $segments;
     }
@@ -70,16 +79,69 @@ class Model
         $sql  = $this->buildQuerySortedByName('(enable_only_idsite = ? OR enable_only_idsite = 0)
                                                AND deleted = 0
                                                AND (enable_all_users = 1 OR login = ?)');
-        $segments = Db::get()->fetchAll($sql, $bind);
+        $segments = $this->getDb()->fetchAll($sql, $bind);
 
         return $segments;
     }
 
+    public function deleteSegment($idSegment)
+    {
+        $db = $this->getDb();
+        $db->delete($this->table, 'idsegment = ' . (int) $idSegment);
+    }
+
+    public function updateSegment($idSegment, $segment)
+    {
+        $idSegment = (int) $idSegment;
+
+        $db = $this->getDb();
+        $db->update($this->table, $segment, "idsegment = $idSegment");
+
+        return true;
+    }
+
+    public function createSegment($segment)
+    {
+        $db = $this->getDb();
+        $db->insert($this->table, $segment);
+        $id = $db->lastInsertId();
+
+        return $id;
+    }
+
+    public function getSegment($idSegment)
+    {
+        $db = $this->getDb();
+        $segment = $db->fetchRow("SELECT * FROM " . $this->table . " WHERE idsegment = ?", $idSegment);
+
+        return $segment;
+    }
+
+    private function getDb()
+    {
+        return Db::get();
+    }
+
     private function buildQuerySortedByName($where)
     {
-        $sql = "SELECT * FROM " . Common::prefixTable("segment") .
-               " WHERE $where ORDER BY name ASC";
+        return "SELECT * FROM " . $this->table . " WHERE $where ORDER BY name ASC";
+    }
+
+    public static function install()
+    {
+        $segmentTable = "`idsegment` INT(11) NOT NULL AUTO_INCREMENT,
+					     `name` VARCHAR(255) NOT NULL,
+					     `definition` TEXT NOT NULL,
+					     `login` VARCHAR(100) NOT NULL,
+					     `enable_all_users` tinyint(4) NOT NULL default 0,
+					     `enable_only_idsite` INTEGER(11) NULL,
+					     `auto_archive` tinyint(4) NOT NULL default 0,
+					     `ts_created` TIMESTAMP NULL,
+					     `ts_last_edit` TIMESTAMP NULL,
+					     `deleted` tinyint(4) NOT NULL default 0,
+					     PRIMARY KEY (`idsegment`)";
 
-        return $sql;
+        DbHelper::createTable(self::$rawPrefix, $segmentTable);
     }
+
 }
diff --git a/plugins/SegmentEditor/SegmentEditor.php b/plugins/SegmentEditor/SegmentEditor.php
index bd957c54c011dd57278fd0426beade837b968f8e..aef619156dd85281c28cd4a5c9b815dbf980a1b8 100644
--- a/plugins/SegmentEditor/SegmentEditor.php
+++ b/plugins/SegmentEditor/SegmentEditor.php
@@ -67,27 +67,17 @@ class SegmentEditor extends \Piwik\Plugin
     {
         $model = new Model();
         $segmentToAutoArchive = $model->getSegmentsToAutoArchive($idSite);
+
         foreach ($segmentToAutoArchive as $segmentInfo) {
             $segments[] = $segmentInfo['definition'];
         }
+
         $segments = array_unique($segments);
     }
 
     public function install()
     {
-        $segmentTable = "`idsegment` INT(11) NOT NULL AUTO_INCREMENT,
-					     `name` VARCHAR(255) NOT NULL,
-					     `definition` TEXT NOT NULL,
-					     `login` VARCHAR(100) NOT NULL,
-					     `enable_all_users` tinyint(4) NOT NULL default 0,
-					     `enable_only_idsite` INTEGER(11) NULL,
-					     `auto_archive` tinyint(4) NOT NULL default 0,
-					     `ts_created` TIMESTAMP NULL,
-					     `ts_last_edit` TIMESTAMP NULL,
-					     `deleted` tinyint(4) NOT NULL default 0,
-					     PRIMARY KEY (`idsegment`)";
-
-        DbHelper::createTable('segment', $segmentTable);
+        Model::install();
     }
 
     public function getJsFiles(&$jsFiles)
diff --git a/plugins/SitesManager/API.php b/plugins/SitesManager/API.php
index 5b856cd862a04f3ad077a56d3f9cec500c645d54..1bb4d4b304b6e8769fc9a4d433f6c0508ce88717 100644
--- a/plugins/SitesManager/API.php
+++ b/plugins/SitesManager/API.php
@@ -143,11 +143,9 @@ class API extends \Piwik\Plugin\API
     public function getSitesFromGroup($group)
     {
         Piwik::checkUserHasSuperUserAccess();
-        $group = trim($group);
 
-        $sites = Db::get()->fetchAll("SELECT *
-    									FROM " . Common::prefixTable("site") . "
-    								   WHERE `group` = ?", $group);
+        $group = trim($group);
+        $sites = $this->getModel()->getSitesFromGroup($group);
 
         Site::setSitesFromArray($sites);
         return $sites;
@@ -162,12 +160,10 @@ class API extends \Piwik\Plugin\API
     public function getSitesGroups()
     {
         Piwik::checkUserHasSuperUserAccess();
-        $groups = Db::get()->fetchAll("SELECT DISTINCT `group` FROM " . Common::prefixTable("site"));
-        $cleanedGroups = array();
-        foreach ($groups as $group) {
-            $cleanedGroups[] = $group['group'];
-        }
-        $cleanedGroups = array_map('trim', $cleanedGroups);
+
+        $groups = $this->getModel()->getSitesGroups();
+        $cleanedGroups = array_map('trim', $groups);
+
         return $cleanedGroups;
     }
 
@@ -219,12 +215,15 @@ class API extends \Piwik\Plugin\API
     public function getAllSites()
     {
         Piwik::checkUserHasSuperUserAccess();
-        $sites = Db::get()->fetchAll("SELECT * FROM " . Common::prefixTable("site") . " ORDER BY idsite ASC");
+
+        $sites  = $this->getModel()->getAllSites();
         $return = array();
         foreach ($sites as $site) {
             $return[$site['idsite']] = $site;
         }
+
         Site::setSitesFromArray($return);
+
         return $return;
     }
 
@@ -258,24 +257,16 @@ class API extends \Piwik\Plugin\API
 
         if (empty($timestamp)) $timestamp = time();
 
-        $time = Date::factory((int)$timestamp)->getDatetime();
-        $result = Db::fetchAll("
-            SELECT
-                idsite
-            FROM
-                " . Common::prefixTable('site') . " s
-            WHERE EXISTS (
-                SELECT 1
-                FROM " . Common::prefixTable('log_visit') . " v
-                WHERE v.idsite = s.idsite
-                AND visit_last_action_time > ?
-                AND visit_last_action_time <= ?
-                LIMIT 1)
-        ", array($time, $now = Date::now()->addHour(1)->getDatetime()));
+        $time   = Date::factory((int)$timestamp)->getDatetime();
+        $now    = Date::now()->addHour(1)->getDatetime();
+
+        $result = $this->getModel()->getSitesWithVisits($time, $now);
+
         $idSites = array();
         foreach ($result as $idSite) {
             $idSites[] = $idSite['idsite'];
         }
+
         return $idSites;
     }
 
@@ -291,9 +282,11 @@ class API extends \Piwik\Plugin\API
         $sitesId = $this->getSitesIdWithAdminAccess();
         $sites = $this->getSitesFromIds($sitesId);
 
-        if ($fetchAliasUrls)
-            foreach ($sites as &$site)
+        if ($fetchAliasUrls) {
+            foreach ($sites as &$site) {
                 $site['alias_urls'] = API::getInstance()->getSiteUrlsFromId($site['idsite']);
+            }
+        }
 
         return $sites;
     }
@@ -373,10 +366,12 @@ class API extends \Piwik\Plugin\API
             }
 
             $accessRaw = Access::getInstance()->getRawSitesWithSomeViewAccess($_restrictSitesToLogin);
-            $sitesId = array();
+            $sitesId   = array();
+
             foreach ($accessRaw as $access) {
                 $sitesId[] = $access['idsite'];
             }
+
             return $sitesId;
         } else {
             return Access::getInstance()->getSitesIdWithAtLeastViewAccess();
@@ -407,6 +402,7 @@ class API extends \Piwik\Plugin\API
         } else {
             $urlBis = str_replace('://', '://www.', $url);
         }
+
         return array($url, $urlBis);
     }
 
@@ -420,28 +416,12 @@ class API extends \Piwik\Plugin\API
     {
         $url = $this->removeTrailingSlash($url);
         list($url, $urlBis) = $this->getNormalizedUrls($url);
+
         if (Piwik::hasUserSuperUserAccess()) {
-            $ids = Db::get()->fetchAll(
-                'SELECT idsite
-                FROM ' . Common::prefixTable('site') . '
-					WHERE (main_url = ? OR main_url = ?) ' .
-                'UNION
-                SELECT idsite
-                FROM ' . Common::prefixTable('site_url') . '
-					WHERE (url = ? OR url = ?) ', array($url, $urlBis, $url, $urlBis));
+            $ids   = $this->getModel()->getAllSitesIdFromSiteUrl($url, $urlBis);
         } else {
             $login = Piwik::getCurrentUserLogin();
-            $ids = Db::get()->fetchAll(
-                'SELECT idsite
-                FROM ' . Common::prefixTable('site') . '
-					WHERE (main_url = ? OR main_url = ?)' .
-                'AND idsite IN (' . Access::getSqlAccessSite('idsite') . ') ' .
-                'UNION
-                SELECT idsite
-                FROM ' . Common::prefixTable('site_url') . '
-					WHERE (url = ? OR url = ?)' .
-                'AND idsite IN (' . Access::getSqlAccessSite('idsite') . ')',
-                array($url, $urlBis, $login, $url, $urlBis, $login));
+            $ids   = $this->getModel()->getSitesIdFromSiteUrlHavingAccess($url, $urlBis, $login);
         }
 
         return $ids;
@@ -457,18 +437,17 @@ class API extends \Piwik\Plugin\API
     public function getSitesIdFromTimezones($timezones)
     {
         Piwik::checkUserHasSuperUserAccess();
+
         $timezones = Piwik::getArrayFromApiParameter($timezones);
         $timezones = array_unique($timezones);
-        $ids = Db::get()->fetchAll(
-            'SELECT idsite
-            FROM ' . Common::prefixTable('site') . '
-					WHERE timezone IN (' . Common::getSqlStringFieldsArray($timezones) . ')
-					ORDER BY idsite ASC',
-            $timezones);
+
+        $ids = $this->getModel()->getSitesFromTimezones($timezones);
+
         $return = array();
         foreach ($ids as $id) {
             $return[] = $id['idsite'];
         }
+
         return $return;
     }
 
@@ -538,9 +517,7 @@ class API extends \Piwik\Plugin\API
         }
         $this->checkValidCurrency($currency);
 
-        $db = Db::get();
-
-        $url = $urls[0];
+        $url  = $urls[0];
         $urls = array_slice($urls, 1);
 
         $bind = array('name'     => $siteName,
@@ -549,31 +526,31 @@ class API extends \Piwik\Plugin\API
         );
 
         $bind['excluded_ips'] = $this->checkAndReturnExcludedIps($excludedIps);
-        $bind['excluded_parameters'] = $this->checkAndReturnCommaSeparatedStringList($excludedQueryParameters);
+        $bind['excluded_parameters']  = $this->checkAndReturnCommaSeparatedStringList($excludedQueryParameters);
         $bind['excluded_user_agents'] = $this->checkAndReturnCommaSeparatedStringList($excludedUserAgents);
-        $bind['keep_url_fragment'] = $keepURLFragments;
-        $bind['timezone'] = $timezone;
-        $bind['currency'] = $currency;
-        $bind['ecommerce'] = (int)$ecommerce;
+        $bind['keep_url_fragment']    = $keepURLFragments;
+        $bind['timezone']   = $timezone;
+        $bind['currency']   = $currency;
+        $bind['ecommerce']  = (int)$ecommerce;
         $bind['sitesearch'] = $siteSearch;
-        $bind['sitesearch_keyword_parameters'] = $searchKeywordParameters;
+        $bind['sitesearch_keyword_parameters']  = $searchKeywordParameters;
         $bind['sitesearch_category_parameters'] = $searchCategoryParameters;
-        $bind['ts_created'] = !is_null($startDate)
-            ? Date::factory($startDate)->getDatetime()
-            : Date::now()->getDatetime();
+
+        if (is_null($startDate)) {
+            $bind['ts_created'] = Date::now()->getDatetime();
+        } else {
+            $bind['ts_created'] = Date::factory($startDate)->getDatetime();
+        }
+
         $bind['type'] = $this->checkAndReturnType($type);
 
-        if (!empty($group)
-            && Piwik::hasUserSuperUserAccess()
-        ) {
+        if (!empty($group) && Piwik::hasUserSuperUserAccess()) {
             $bind['group'] = trim($group);
         } else {
             $bind['group'] = "";
         }
 
-        $db->insert(Common::prefixTable("site"), $bind);
-
-        $idSite = $db->lastInsertId();
+        $idSite = $this->getModel()->createSite($bind);
 
         $this->insertSiteUrls($idSite, $urls);
 
@@ -588,7 +565,7 @@ class API extends \Piwik\Plugin\API
          */
         Piwik::postEvent('SitesManager.addSite.end', array($idSite));
 
-        return (int)$idSite;
+        return (int) $idSite;
     }
 
     private function postUpdateWebsite($idSite)
@@ -619,16 +596,7 @@ class API extends \Piwik\Plugin\API
             throw new Exception(Piwik::translate("SitesManager_ExceptionDeleteSite"));
         }
 
-        $db = Db::get();
-
-        $db->query("DELETE FROM " . Common::prefixTable("site") . "
-					WHERE idsite = ?", $idSite);
-
-        $db->query("DELETE FROM " . Common::prefixTable("site_url") . "
-					WHERE idsite = ?", $idSite);
-
-        $db->query("DELETE FROM " . Common::prefixTable("access") . "
-					WHERE idsite = ?", $idSite);
+        $this->getModel()->deleteSite($idSite);
 
         // we do not delete logs here on purpose (you can run these queries on the log_ tables to delete all data)
         Cache::deleteCacheWebsiteAttributes($idSite);
@@ -682,12 +650,14 @@ class API extends \Piwik\Plugin\API
 
     private function checkAndReturnType($type)
     {
-        if(empty($type)) {
+        if (empty($type)) {
             $type = Site::DEFAULT_SITE_TYPE;
         }
-        if(!is_string($type)) {
+
+        if (!is_string($type)) {
             throw new Exception("Invalid website type $type");
         }
+
         return $type;
     }
 
@@ -704,14 +674,17 @@ class API extends \Piwik\Plugin\API
         if (empty($excludedIps)) {
             return '';
         }
+
         $ips = explode(',', $excludedIps);
         $ips = array_map('trim', $ips);
         $ips = array_filter($ips, 'strlen');
+
         foreach ($ips as $ip) {
             if (!$this->isValidIp($ip)) {
                 throw new Exception(Piwik::translate('SitesManager_ExceptionInvalidIPFormat', array($ip, "1.2.3.4, 1.2.3.*, or 1.2.3.4/5")));
             }
         }
+
         $ips = implode(',', $ips);
         return $ips;
     }
@@ -756,7 +729,7 @@ class API extends \Piwik\Plugin\API
         $urls = $this->cleanParameterUrls($urls);
         $this->checkUrls($urls);
 
-        $this->deleteSiteAliasUrls($idSite);
+        $this->getModel()->deleteSiteAliasUrls($idSite);
         $this->insertSiteUrls($idSite, $urls);
         $this->postUpdateWebsite($idSite);
 
@@ -1131,17 +1104,15 @@ class API extends \Piwik\Plugin\API
         $bind['sitesearch_category_parameters'] = $searchCategoryParameters;
         $bind['type'] = $this->checkAndReturnType($type);
 
-        $db = Db::get();
-        $db->update(Common::prefixTable("site"),
-            $bind,
-            "idsite = $idSite"
-        );
+        $this->getModel()->updateSite($bind, $idSite);
 
         // we now update the main + alias URLs
-        $this->deleteSiteAliasUrls($idSite);
+        $this->getModel()->deleteSiteAliasUrls($idSite);
+
         if (count($urls) > 1) {
             $this->addSiteAliasUrls($idSite, array_slice($urls, 1));
         }
+
         $this->postUpdateWebsite($idSite);
     }
 
@@ -1158,14 +1129,9 @@ class API extends \Piwik\Plugin\API
         $idSites = Site::getIdSitesFromIdSitesString($idSites);
         Piwik::checkUserHasAdminAccess($idSites);
 
-        // Update piwik_site.ts_created
-        $query = "UPDATE " . Common::prefixTable("site") .
-            " SET ts_created = ?" .
-            " WHERE idsite IN ( " . implode(",", $idSites) . " )
-					AND ts_created > ?";
         $minDateSql = $minDate->subDay(1)->getDatetime();
-        $bind = array($minDateSql, $minDateSql);
-        Db::query($query, $bind);
+
+        $this->getModel()->updateSiteCreatedTime($idSites, $minDateSql);
     }
 
     private function checkAndReturnCommaSeparatedStringList($parameters)
@@ -1296,12 +1262,8 @@ class API extends \Piwik\Plugin\API
     public function getUniqueSiteTimezones()
     {
         Piwik::checkUserHasSuperUserAccess();
-        $results = Db::fetchAll("SELECT distinct timezone FROM " . Common::prefixTable('site'));
-        $timezones = array();
-        foreach ($results as $result) {
-            $timezones[] = $result['timezone'];
-        }
-        return $timezones;
+
+        return $this->getModel()->getUniqueSiteTimezones();
     }
 
     /**
@@ -1311,14 +1273,9 @@ class API extends \Piwik\Plugin\API
     private function insertSiteUrls($idSite, $urls)
     {
         if (count($urls) != 0) {
-            $db = Db::get();
             foreach ($urls as $url) {
                 try {
-                    $db->insert(Common::prefixTable("site_url"), array(
-                                                                      'idsite' => $idSite,
-                                                                      'url'    => $url
-                                                                 )
-                    );
+                    $this->getModel()->insertSiteUrl($idSite, $url);
                 } catch(Exception $e) {
                     // See bug #4149
                 }
@@ -1326,16 +1283,6 @@ class API extends \Piwik\Plugin\API
         }
     }
 
-    /**
-     * Delete all the alias URLs for the given idSite.
-     */
-    private function deleteSiteAliasUrls($idsite)
-    {
-        $db = Db::get();
-        $db->query("DELETE FROM " . Common::prefixTable("site_url") . "
-					WHERE idsite = ?", $idsite);
-    }
-
     /**
      * Remove the final slash in the URLs if found
      *
@@ -1350,6 +1297,7 @@ class API extends \Piwik\Plugin\API
         ) {
             $url = substr($url, 0, strlen($url) - 1);
         }
+
         return $url;
     }
 
@@ -1404,6 +1352,7 @@ class API extends \Piwik\Plugin\API
         if (empty($searchKeywordParameters)) {
             $searchKeywordParameters = '';
         }
+
         if (empty($searchCategoryParameters)) {
             $searchCategoryParameters = '';
         }
@@ -1439,9 +1388,10 @@ class API extends \Piwik\Plugin\API
         if (!is_array($urls)) {
             $urls = array($urls);
         }
-        $urls = array_filter($urls);
 
+        $urls = array_filter($urls);
         $urls = array_map('urldecode', $urls);
+
         foreach ($urls as &$url) {
             $url = $this->removeTrailingSlash($url);
             if (strpos($url, 'http') !== 0) {
@@ -1450,6 +1400,7 @@ class API extends \Piwik\Plugin\API
             $url = trim($url);
             $url = Common::sanitizeInputValue($url);
         }
+
         $urls = array_unique($urls);
         return $urls;
     }
@@ -1489,30 +1440,9 @@ class API extends \Piwik\Plugin\API
             return array();
         }
 
-        $ids_str = '';
-        foreach ($ids as $id_val) {
-            $ids_str .= $id_val . ' , ';
-        }
-        $ids_str .= $id_val;
-
-        $db = Db::get();
-        $bind = array('%' . $pattern . '%', 'http%' . $pattern . '%', '%' . $pattern . '%');
+        $limit = SettingsPiwik::getWebsitesCountToDisplay();
+        $sites = $this->getModel()->getPatternMatchSites($ids, $pattern, $limit);
 
-        // Also match the idsite
-        $where = '';
-        if (is_numeric($pattern)) {
-            $bind[] = $pattern;
-            $where = 'OR  s.idsite = ?';
-        }
-        $sites = $db->fetchAll("SELECT idsite, name, main_url, `group`
-								FROM " . Common::prefixTable('site') . " s
-								WHERE (		s.name like ?
-										OR 	s.main_url like ?
-										OR 	s.`group` like ?
-										 $where )
-									AND idsite in ($ids_str)
-								LIMIT " . SettingsPiwik::getWebsitesCountToDisplay(),
-            $bind);
         return $sites;
     }
 
diff --git a/plugins/SitesManager/Model.php b/plugins/SitesManager/Model.php
index 207f59bdfd1965ba4a3349c75addd3901247d4e3..971844c40b0a634d69ca87dafcf4850802101ef2 100644
--- a/plugins/SitesManager/Model.php
+++ b/plugins/SitesManager/Model.php
@@ -8,13 +8,172 @@
  */
 namespace Piwik\Plugins\SitesManager;
 
+use Piwik\Access;
+use Piwik\Date;
 use Piwik\Db;
 use Piwik\Common;
 use Exception;
-use Piwik\Site;
 
 class Model
 {
+    private static $rawPrefix = 'site';
+    private $table;
+
+    public function __construct()
+    {
+        $this->table = Common::prefixTable(self::$rawPrefix);
+    }
+
+    public function createSite($site)
+    {
+        $db = $this->getDb();
+        $db->insert($this->table, $site);
+
+        $idSite = $db->lastInsertId();
+
+        return $idSite;
+    }
+
+    /**
+     * Returns all websites belonging to the specified group
+     * @param string $group Group name
+     * @return array of sites
+     */
+    public function getSitesFromGroup($group)
+    {
+        $sites = $this->getDb()->fetchAll("SELECT * FROM " . $this->table . "
+                                           WHERE `group` = ?", $group);
+
+        return $sites;
+    }
+
+    /**
+     * Returns the list of website groups, including the empty group
+     * if no group were specified for some websites
+     *
+     * @return array of group names strings
+     */
+    public function getSitesGroups()
+    {
+        $groups = $this->getDb()->fetchAll("SELECT DISTINCT `group` FROM " . $this->table);
+
+        $cleanedGroups = array();
+        foreach ($groups as $group) {
+            $cleanedGroups[] = $group['group'];
+        }
+
+        return $cleanedGroups;
+    }
+
+    /**
+     * Returns all websites
+     *
+     * @return array The list of websites, indexed by idsite
+     */
+    public function getAllSites()
+    {
+        $sites = $this->getDb()->fetchAll("SELECT * FROM " . $this->table . " ORDER BY idsite ASC");
+
+        return $sites;
+    }
+
+    /**
+     * Returns the list of the website IDs that received some visits since the specified timestamp.
+     *
+     * @param \Piwik\Date $time
+     * @param \Piwik\Date $now
+     * @return array The list of website IDs
+     */
+    public function getSitesWithVisits($time, $now)
+    {
+        $sites = Db::fetchAll("
+            SELECT idsite FROM " . $this->table . " s
+            WHERE EXISTS (
+                SELECT 1
+                FROM " . Common::prefixTable('log_visit') . " v
+                WHERE v.idsite = s.idsite
+                AND visit_last_action_time > ?
+                AND visit_last_action_time <= ?
+                LIMIT 1)
+        ", array($time, $now));
+
+        return $sites;
+    }
+
+
+    /**
+     * Returns the list of websites ID associated with a URL.
+     *
+     * @param string $url
+     * @param string $urlBis
+     * @return array list of websites ID
+     */
+    public function getAllSitesIdFromSiteUrl($url, $urlBis)
+    {
+        $siteUrlTable = Common::prefixTable('site_url');
+
+        $ids = $this->getDb()->fetchAll(
+            'SELECT idsite FROM ' . $this->table . '
+                    WHERE (main_url = ? OR main_url = ?) ' .
+            'UNION
+                SELECT idsite FROM ' . $siteUrlTable . '
+                    WHERE (url = ? OR url = ?) ', array($url, $urlBis, $url, $urlBis));
+
+        return $ids;
+    }
+
+    /**
+     * Returns the list of websites ID associated with a URL.
+     *
+     * @param string $url
+     * @return array list of websites ID
+     */
+    public function getSitesIdFromSiteUrlHavingAccess($url, $urlBis, $login)
+    {
+        $siteUrlTable  = Common::prefixTable('site_url');
+        $sqlAccessSite = Access::getSqlAccessSite('idsite');
+
+        $ids = $this->getDb()->fetchAll(
+            'SELECT idsite
+                FROM ' . $this->table . '
+                    WHERE (main_url = ? OR main_url = ?)' .
+            'AND idsite IN (' . $sqlAccessSite . ') ' .
+            'UNION
+                SELECT idsite
+                FROM ' . $siteUrlTable . '
+                    WHERE (url = ? OR url = ?)' .
+            'AND idsite IN (' . $sqlAccessSite . ')',
+            array($url, $urlBis, $login, $url, $urlBis, $login));
+
+        return $ids;
+    }
+
+    /**
+     * Returns all websites with a timezone matching one the specified timezones
+     *
+     * @param array $timezones
+     * @return array
+     * @ignore
+     */
+    public function getSitesFromTimezones($timezones)
+    {
+        $query = 'SELECT idsite FROM ' . $this->table . '
+                  WHERE timezone IN (' . Common::getSqlStringFieldsArray($timezones) . ')
+                  ORDER BY idsite ASC';
+        $sites = $this->getDb()->fetchAll($query, $timezones);
+
+        return $sites;
+    }
+
+    public function deleteSite($idSite)
+    {
+        $db = $this->getDb();
+
+        $db->query("DELETE FROM " . $this->table . " WHERE idsite = ?", $idSite);
+        $db->query("DELETE FROM " . Common::prefixTable("site_url") . " WHERE idsite = ?", $idSite);
+        $db->query("DELETE FROM " . Common::prefixTable("access") . " WHERE idsite = ?", $idSite);
+    }
+
     /**
      * Returns the list of websites from the ID array in parameters.
      *
@@ -36,11 +195,10 @@ class Model
 
         $idSites = array_map('intval', $idSites);
 
-        $db    = Db::get();
-        $sites = $db->fetchAll("SELECT *
-								FROM " . Common::prefixTable("site") . "
-								WHERE idsite IN (" . implode(", ", $idSites) . ")
-								ORDER BY idsite ASC $limit");
+        $db    = $this->getDb();
+        $sites = $db->fetchAll("SELECT * FROM " . $this->table . "
+                                WHERE idsite IN (" . implode(", ", $idSites) . ")
+                                ORDER BY idsite ASC $limit");
 
         return $sites;
     }
@@ -54,9 +212,8 @@ class Model
      */
     public function getSiteFromId($idSite)
     {
-        $site = Db::get()->fetchRow("SELECT *
-    								FROM " . Common::prefixTable("site") . "
-    								WHERE idsite = ?", $idSite);
+        $site = $this->getDb()->fetchRow("SELECT * FROM " . $this->table . "
+                                          WHERE idsite = ?", $idSite);
 
         return $site;
     }
@@ -69,11 +226,13 @@ class Model
      */
     public function getSitesId()
     {
-        $result = Db::fetchAll("SELECT idsite FROM " . Common::prefixTable('site'));
+        $result  = Db::fetchAll("SELECT idsite FROM " . Common::prefixTable('site'));
+
         $idSites = array();
         foreach ($result as $idSite) {
             $idSites[] = $idSite['idsite'];
         }
+
         return $idSites;
     }
 
@@ -87,7 +246,6 @@ class Model
     public function getSiteUrlsFromId($idSite)
     {
         $urls = $this->getAliasSiteUrlsFromId($idSite);
-
         $site = $this->getSiteFromId($idSite);
 
         if (empty($site)) {
@@ -106,14 +264,119 @@ class Model
      */
     public function getAliasSiteUrlsFromId($idSite)
     {
-        $db = Db::get();
-        $result = $db->fetchAll("SELECT url
-								FROM " . Common::prefixTable("site_url") . "
-								WHERE idsite = ?", $idSite);
+        $db     = $this->getDb();
+        $result = $db->fetchAll("SELECT url FROM " . Common::prefixTable("site_url") . "
+                                WHERE idsite = ?", $idSite);
         $urls = array();
         foreach ($result as $url) {
             $urls[] = $url['url'];
         }
+
         return $urls;
     }
+
+    public function updateSite($site, $idSite)
+    {
+        $idSite = (int) $idSite;
+
+        $db = $this->getDb();
+        $db->update($this->table, $site, "idsite = $idSite");
+    }
+
+    /**
+     * Returns the list of unique timezones from all configured sites.
+     *
+     * @return array ( string )
+     */
+    public function getUniqueSiteTimezones()
+    {
+        $results = Db::fetchAll("SELECT distinct timezone FROM " . $this->table);
+
+        $timezones = array();
+        foreach ($results as $result) {
+            $timezones[] = $result['timezone'];
+        }
+
+        return $timezones;
+    }
+
+    /**
+     * Updates the field ts_created for the specified websites.
+     *
+     * @param $idSites int Id Site to update ts_created
+     * @param string Date to set as creation date.
+     *
+     * @ignore
+     */
+    public function updateSiteCreatedTime($idSites, $minDateSql)
+    {
+        $idSites   = array_map('intval', $idSites);
+
+        $query = "UPDATE " . $this->table . " SET ts_created = ?" .
+                " WHERE idsite IN ( " . implode(",", $idSites) . " ) AND ts_created > ?";
+
+        $bind  = array($minDateSql, $minDateSql);
+
+        Db::query($query, $bind);
+    }
+
+    /**
+     * Insert the list of alias URLs for the website.
+     * The URLs must not exist already for this website!
+     */
+    public function insertSiteUrl($idSite, $url)
+    {
+        $db = $this->getDb();
+        $db->insert(Common::prefixTable("site_url"), array(
+                'idsite' => (int) $idSite,
+                'url'    => $url
+            )
+        );
+    }
+
+    public function getPatternMatchSites($ids, $pattern, $limit)
+    {
+        $ids_str = '';
+        foreach ($ids as $id_val) {
+            $ids_str .= (int) $id_val . ' , ';
+        }
+        $ids_str .= (int) $id_val;
+
+        $bind = array('%' . $pattern . '%', 'http%' . $pattern . '%', '%' . $pattern . '%');
+
+        // Also match the idsite
+        $where = '';
+        if (is_numeric($pattern)) {
+            $bind[] = $pattern;
+            $where  = 'ORs s.idsite = ?';
+        }
+
+        $query = "SELECT idsite, name, main_url, `group`
+                  FROM " . $this->table . " s
+                  WHERE (    s.name like ?
+                          OR s.main_url like ?
+                          OR s.`group` like ?
+                          $where )
+                     AND idsite in ($ids_str)
+                 LIMIT " . (int) $limit;
+
+        $db    = $this->getDb();
+        $sites = $db->fetchAll($query, $bind);
+
+        return $sites;
+    }
+
+    /**
+     * Delete all the alias URLs for the given idSite.
+     */
+    public function deleteSiteAliasUrls($idsite)
+    {
+        $db = $this->getDb();
+        $db->query("DELETE FROM " . Common::prefixTable("site_url") . " WHERE idsite = ?", $idsite);
+    }
+
+    private function getDb()
+    {
+        return Db::get();
+    }
 }
diff --git a/plugins/Transitions/API.php b/plugins/Transitions/API.php
index faeddf9f0b66ac54c856205a8af44b60b8fbaaa9..32abffdc06e690d5b98c1ec05b1a1902dfa85c97 100644
--- a/plugins/Transitions/API.php
+++ b/plugins/Transitions/API.php
@@ -172,7 +172,6 @@ class API extends \Piwik\Plugin\API
      */
     private function addInternalReferrers($logAggregator, &$report, $idaction, $actionType, $limitBeforeGrouping)
     {
-
         $data = $this->queryInternalReferrers($idaction, $actionType, $logAggregator, $limitBeforeGrouping);
 
         if ($data['pageviews'] == 0) {
@@ -198,7 +197,6 @@ class API extends \Piwik\Plugin\API
      */
     private function addFollowingActions($logAggregator, &$report, $idaction, $actionType, $limitBeforeGrouping, $includeLoops = false)
     {
-
         $data = $this->queryFollowingActions(
             $idaction, $actionType, $logAggregator, $limitBeforeGrouping, $includeLoops);
 
@@ -225,7 +223,7 @@ class API extends \Piwik\Plugin\API
         if ($actionType != 'title') {
             // specific setup for page urls
             $types[Action::TYPE_PAGE_URL] = 'followingPages';
-            $dimension = 'IF( idaction_url IS NULL, idaction_name, idaction_url )';
+            $dimension = 'if ( idaction_url IS NULL, idaction_name, idaction_url )';
             // site search referrers are logged with url=NULL
             // when we find one, we have to join on name
             $joinLogActionColumn = $dimension;
@@ -408,7 +406,7 @@ class API extends \Piwik\Plugin\API
         if ($dimension == 'idaction_url_ref') {
             // site search referrers are logged with url_ref=NULL
             // when we find one, we have to join on name_ref
-            $dimension = 'IF( idaction_url_ref IS NULL, idaction_name_ref, idaction_url_ref )';
+            $dimension = 'if ( idaction_url_ref IS NULL, idaction_name_ref, idaction_url_ref )';
             $joinLogActionOn = $dimension;
         } else {
             $joinLogActionOn = $dimension;
@@ -514,7 +512,6 @@ class API extends \Piwik\Plugin\API
      */
     private function addExternalReferrers($logAggregator, &$report, $idaction, $actionType, $limitBeforeGrouping)
     {
-
         $data = $this->queryExternalReferrers(
             $idaction, $actionType, $logAggregator, $limitBeforeGrouping);
 
diff --git a/plugins/UserCountry/Controller.php b/plugins/UserCountry/Controller.php
index 483b2d844f05112055297ab95ed3155c7909e6d9..a6ed712dbe76658cf00eb2201becf6e323dd2d10 100644
--- a/plugins/UserCountry/Controller.php
+++ b/plugins/UserCountry/Controller.php
@@ -369,7 +369,7 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
 
     private function dieIfGeolocationAdminIsDisabled()
     {
-        if(!UserCountry::isGeoLocationAdminEnabled()) {
+        if (!UserCountry::isGeoLocationAdminEnabled()) {
             throw new \Exception('Geo location setting page has been disabled.');
         }
     }
diff --git a/plugins/UsersManager/API.php b/plugins/UsersManager/API.php
index 61b26323da2d524e59c20320a64bae7ed861584d..7a1c9faf7a8aed4ba59e45db195c5924c65d402d 100644
--- a/plugins/UsersManager/API.php
+++ b/plugins/UsersManager/API.php
@@ -318,7 +318,7 @@ class API extends \Piwik\Plugin\API
      *
      * @exception in case of an invalid parameter
      */
-    public function addUser($userLogin, $password, $email, $alias = false)
+    public function addUser($userLogin, $password, $email, $alias = false, $_isPasswordHashed = false)
     {
         Piwik::checkUserHasSuperUserAccess();
 
@@ -326,10 +326,15 @@ class API extends \Piwik\Plugin\API
         $this->checkEmail($email);
 
         $password = Common::unsanitizeInputValue($password);
-        UsersManager::checkPassword($password);
+        if (!$_isPasswordHashed) {
+            UsersManager::checkPassword($password);
+
+            $passwordTransformed = UsersManager::getPasswordHash($password);
+        } else {
+            $passwordTransformed = $password;
+        }
 
         $alias = $this->getCleanAlias($alias, $userLogin);
-        $passwordTransformed = UsersManager::getPasswordHash($password);
 
         $token_auth = $this->getTokenAuth($userLogin, $passwordTransformed);
 
@@ -435,7 +440,7 @@ class API extends \Piwik\Plugin\API
             $this->checkEmail($email);
         }
 
-        $alias = $this->getCleanAlias($alias, $userLogin);
+        $alias      = $this->getCleanAlias($alias, $userLogin);
         $token_auth = $this->getTokenAuth($userLogin, $password);
 
         $this->model->updateUser($userLogin, $password, $email, $alias, $token_auth);
diff --git a/plugins/UsersManager/Controller.php b/plugins/UsersManager/Controller.php
index 56974b1efc30b8722d708598dfdf667b40268b48..d22240b977c495e3fe4222d7689b64b62a6b2226 100644
--- a/plugins/UsersManager/Controller.php
+++ b/plugins/UsersManager/Controller.php
@@ -177,7 +177,7 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
         );
 
         // assertion
-        if(count($dates) != count($mappingDatesToPeriods)) {
+        if (count($dates) != count($mappingDatesToPeriods)) {
             throw new Exception("some metadata is missing in getDefaultDates()");
         }
 
@@ -251,7 +251,7 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
         Piwik::checkUserIsNotAnonymous();
 
         $salt = Common::getRequestVar('ignoreSalt', false, 'string');
-        if($salt !== $this->getIgnoreCookieSalt()) {
+        if ($salt !== $this->getIgnoreCookieSalt()) {
             throw new Exception("Not authorized");
         }
 
diff --git a/plugins/UsersManager/Menu.php b/plugins/UsersManager/Menu.php
index 8335d97305c1fcd09fa189a1e821450db2b16a80..88aeb051f5b8cb79b561d8bb80ccd5f38bfc24ad 100644
--- a/plugins/UsersManager/Menu.php
+++ b/plugins/UsersManager/Menu.php
@@ -9,6 +9,7 @@
 namespace Piwik\Plugins\UsersManager;
 
 use Piwik\Menu\MenuAdmin;
+use Piwik\Menu\MenuUser;
 use Piwik\Piwik;
 
 class Menu extends \Piwik\Plugin\Menu
@@ -20,4 +21,11 @@ class Menu extends \Piwik\Plugin\Menu
             $menu->addManageItem('UsersManager_MenuUserSettings', $this->urlForAction('userSettings'), $order = 3);
         }
     }
+
+    public function configureUserMenu(MenuUser $menu)
+    {
+        if (!Piwik::isUserIsAnonymous()) {
+            $menu->addItem('', 'General_Settings', $this->urlForAction('index'), 0);
+        }
+    }
 }
diff --git a/plugins/UsersManager/Model.php b/plugins/UsersManager/Model.php
index 872d693ee6d6006711c80ac4b813c2c70d1f27b4..3d62ca61fd8e43265503e4331c279e81b0a493d1 100644
--- a/plugins/UsersManager/Model.php
+++ b/plugins/UsersManager/Model.php
@@ -26,6 +26,14 @@ use Piwik\Piwik;
  */
 class Model
 {
+    private static $rawPrefix = 'user';
+    private $table;
+
+    public function __construct()
+    {
+        $this->table = Common::prefixTable(self::$rawPrefix);
+    }
+
     /**
      * Returns the list of all the users
      *
@@ -39,13 +47,12 @@ class Model
 
         if (!empty($userLogins)) {
             $where = 'WHERE login IN (' . Common::getSqlStringFieldsArray($userLogins) . ')';
-            $bind = $userLogins;
+            $bind  = $userLogins;
         }
 
-        $users = Db::get()->fetchAll("SELECT *
-                                      FROM " . Common::prefixTable("user") . "
-                                      $where
-                                      ORDER BY login ASC", $bind);
+        $users = $this->getDb()->fetchAll("SELECT * FROM " . $this->table . "
+                                           $where
+                                           ORDER BY login ASC", $bind);
 
         return $users;
     }
@@ -57,9 +64,8 @@ class Model
      */
     public function getUsersLogin()
     {
-        $users = Db::get()->fetchAll("SELECT login
-                                      FROM " . Common::prefixTable("user") . "
-                                      ORDER BY login ASC");
+        $users = $this->getDb()->fetchAll("SELECT login FROM " . $this->table . " ORDER BY login ASC");
+
         $return = array();
         foreach ($users as $login) {
             $return[] = $login['login'];
@@ -70,10 +76,9 @@ class Model
 
     public function getUsersSitesFromAccess($access)
     {
-        $users = Db::get()->fetchAll("SELECT login,idsite
-                                      FROM " . Common::prefixTable("access")
-                                  . " WHERE access = ?
-                                      ORDER BY login, idsite", $access);
+        $users = $this->getDb()->fetchAll("SELECT login,idsite FROM " . Common::prefixTable("access")
+                                        . " WHERE access = ?
+                                            ORDER BY login, idsite", $access);
 
         $return = array();
         foreach ($users as $user) {
@@ -85,9 +90,8 @@ class Model
 
     public function getUsersAccessFromSite($idSite)
     {
-        $users = Db::get()->fetchAll("SELECT login,access
-                                      FROM " . Common::prefixTable("access")
-                                  . " WHERE idsite = ?", $idSite);
+        $users = $this->getDb()->fetchAll("SELECT login,access FROM " . Common::prefixTable("access")
+                                        . " WHERE idsite = ?", $idSite);
 
         $return = array();
         foreach ($users as $user) {
@@ -99,9 +103,9 @@ class Model
 
     public function getUsersLoginWithSiteAccess($idSite, $access)
     {
-        $users = Db::get()->fetchAll("SELECT login
-                                      FROM " . Common::prefixTable("access")
-                                  . " WHERE idsite = ? AND access = ?", array($idSite, $access));
+        $users = $this->getDb()->fetchAll("SELECT login
+                                           FROM " . Common::prefixTable("access")
+                                       . " WHERE idsite = ? AND access = ?", array($idSite, $access));
 
         $logins = array();
         foreach ($users as $user) {
@@ -129,9 +133,8 @@ class Model
      */
     public function getSitesAccessFromUser($userLogin)
     {
-        $users = Db::get()->fetchAll("SELECT idsite,access
-                                      FROM " . Common::prefixTable("access")
-                                  . " WHERE login = ?", $userLogin);
+        $users = $this->getDb()->fetchAll("SELECT idsite,access FROM " . Common::prefixTable("access")
+                                        . " WHERE login = ?", $userLogin);
 
         $return = array();
         foreach ($users as $user) {
@@ -146,23 +149,20 @@ class Model
 
     public function getUser($userLogin)
     {
-        return Db::get()->fetchRow("SELECT *
-                                    FROM " . Common::prefixTable("user")
-                                . " WHERE login = ?", $userLogin);
+        return $this->getDb()->fetchRow("SELECT * FROM " . $this->table
+                                     . " WHERE login = ?", $userLogin);
     }
 
     public function getUserByEmail($userEmail)
     {
-        return Db::get()->fetchRow("SELECT *
-                                    FROM " . Common::prefixTable("user")
-                                . " WHERE email = ?", $userEmail);
+        return $this->getDb()->fetchRow("SELECT * FROM " . $this->table
+                                      . " WHERE email = ?", $userEmail);
     }
 
     public function getUserByTokenAuth($tokenAuth)
     {
-        return Db::get()->fetchRow('SELECT *
-                                    FROM ' . Common::prefixTable('user') . '
-					                WHERE token_auth = ?', $tokenAuth);
+        return $this->getDb()->fetchRow('SELECT * FROM ' . $this->table . '
+					                     WHERE token_auth = ?', $tokenAuth);
     }
 
     public function addUser($userLogin, $passwordTransformed, $email, $alias, $tokenAuth, $dateRegistered)
@@ -177,12 +177,12 @@ class Model
             'superuser_access' => 0
         );
 
-        Db::get()->insert(Common::prefixTable("user"), $user);
+        $this->getDb()->insert($this->table, $user);
     }
 
     public function setSuperUserAccess($userLogin, $hasSuperUserAccess)
     {
-        Db::get()->update(Common::prefixTable("user"),
+        $this->getDb()->update($this->table,
             array(
                 'superuser_access' => $hasSuperUserAccess ? 1 : 0
             ),
@@ -192,17 +192,17 @@ class Model
 
     public function getUsersHavingSuperUserAccess()
     {
-        $users = Db::get()->fetchAll("SELECT login, email
-                                      FROM " . Common::prefixTable("user") . "
-                                      WHERE superuser_access = 1
-                                      ORDER BY date_registered ASC");
+        $users = $this->getDb()->fetchAll("SELECT login, email
+                                           FROM " . Common::prefixTable("user") . "
+                                           WHERE superuser_access = 1
+                                           ORDER BY date_registered ASC");
 
         return $users;
     }
 
     public function updateUser($userLogin, $password, $email, $alias, $tokenAuth)
     {
-        Db::get()->update(Common::prefixTable("user"),
+        $this->getDb()->update($this->table,
             array(
                  'password'   => $password,
                  'alias'      => $alias,
@@ -215,24 +215,22 @@ class Model
 
     public function userExists($userLogin)
     {
-        $count = Db::get()->fetchOne("SELECT count(*)
-                                      FROM " . Common::prefixTable("user") . "
-                                      WHERE login = ?", $userLogin);
+        $count = $this->getDb()->fetchOne("SELECT count(*) FROM " . $this->table . "
+                                           WHERE login = ?", $userLogin);
         return $count != 0;
     }
 
     public function userEmailExists($userEmail)
     {
-        $count = Db::get()->fetchOne("SELECT count(*)
-                                      FROM " . Common::prefixTable("user") . "
-                                      WHERE email = ?", $userEmail);
+        $count = $this->getDb()->fetchOne("SELECT count(*) FROM " . $this->table . "
+                                           WHERE email = ?", $userEmail);
         return $count != 0;
     }
 
     public function addUserAccess($userLogin, $access, $idSites)
     {
         foreach ($idSites as $idsite) {
-            Db::get()->insert(Common::prefixTable("access"),
+            $this->getDb()->insert(Common::prefixTable("access"),
                 array("idsite" => $idsite,
                       "login"  => $userLogin,
                       "access" => $access)
@@ -242,7 +240,7 @@ class Model
 
     public function deleteUserOnly($userLogin)
     {
-        Db::get()->query("DELETE FROM " . Common::prefixTable("user") . " WHERE login = ?", $userLogin);
+        $this->getDb()->query("DELETE FROM " . $this->table . " WHERE login = ?", $userLogin);
 
         /**
          * Triggered after a user has been deleted.
@@ -258,12 +256,12 @@ class Model
     public function deleteUserAccess($userLogin, $idSites = null)
     {
         if (is_null($idSites)) {
-            Db::get()->query("DELETE FROM " . Common::prefixTable("access") .
+            $this->getDb()->query("DELETE FROM " . Common::prefixTable("access") .
                 " WHERE login = ?",
                 array($userLogin));
         } else {
             foreach ($idSites as $idsite) {
-                Db::get()->query("DELETE FROM " . Common::prefixTable("access") .
+                $this->getDb()->query("DELETE FROM " . Common::prefixTable("access") .
                     " WHERE idsite = ? AND login = ?",
                     array($idsite, $userLogin)
                 );
@@ -271,4 +269,9 @@ class Model
         }
     }
 
+    private function getDb()
+    {
+        return Db::get();
+    }
+
 }
diff --git a/plugins/UsersManager/UsersManager.php b/plugins/UsersManager/UsersManager.php
index b2c4b2e8f3e2e8bb7a39d953f0366a186bf730d9..cdc383d041711750d509e03087c8299459ae5c84 100644
--- a/plugins/UsersManager/UsersManager.php
+++ b/plugins/UsersManager/UsersManager.php
@@ -34,7 +34,8 @@ class UsersManager extends \Piwik\Plugin
             'SitesManager.deleteSite.end'            => 'deleteSite',
             'Tracker.Cache.getSiteAttributes'        => 'recordAdminUsersInCache',
             'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
-            'Platform.initialized'                   => 'onPlatformInitialized'
+            'Platform.initialized'                   => 'onPlatformInitialized',
+            'CronArchive.getTokenAuth'               => 'getCronArchiveTokenAuth'
         );
     }
 
@@ -62,9 +63,22 @@ class UsersManager extends \Piwik\Plugin
         foreach ($users as $user) {
             $tokens[] = $user['token_auth'];
         }
+
         $attributes['admin_token_auth'] = $tokens;
     }
 
+    public function getCronArchiveTokenAuth(&$token)
+    {
+        $model      = new Model();
+        $superUsers = $model->getUsersHavingSuperUserAccess();
+
+        if (!empty($superUsers)) {
+            $superUser = array_shift($superUsers);
+
+            $token = $superUser['token_auth'];
+        }
+    }
+
     /**
      * Delete user preferences associated with a particular site
      */
@@ -105,7 +119,9 @@ class UsersManager extends \Piwik\Plugin
         ) {
             return true;
         }
+
         $l = strlen($input);
+
         return $l >= self::PASSWORD_MIN_LENGTH && $l <= self::PASSWORD_MAX_LENGTH;
     }
 
diff --git a/plugins/VisitorGenerator b/plugins/VisitorGenerator
index 90327ea31c298d17cf14312d4eeefad7228c54a4..5d6355fcb38e7b8964d697da3cf9e2d201bf2245 160000
--- a/plugins/VisitorGenerator
+++ b/plugins/VisitorGenerator
@@ -1 +1 @@
-Subproject commit 90327ea31c298d17cf14312d4eeefad7228c54a4
+Subproject commit 5d6355fcb38e7b8964d697da3cf9e2d201bf2245
diff --git a/plugins/VisitsSummary/Controller.php b/plugins/VisitsSummary/Controller.php
index 903b2477cf5ecd203bd04b080cedc0f4d55223d5..63fe8ef2050431fec2914156432bf41f987c5c70 100644
--- a/plugins/VisitsSummary/Controller.php
+++ b/plugins/VisitsSummary/Controller.php
@@ -159,7 +159,7 @@ class Controller extends \Piwik\Plugin\Controller
         $view->maxActions = (int)$dataRow->getColumn('max_actions');
         $view->nbActionsPerVisit = $dataRow->getColumn('nb_actions_per_visit');
 
-        if(Common::isActionsPluginEnabled()) {
+        if (Common::isActionsPluginEnabled()) {
             $view->showActionsPluginReports = true;
             $dataTableActions = APIActions::getInstance()->get($idSite, Common::getRequestVar('period'), Common::getRequestVar('date'),
                 \Piwik\API\Request::getRawSegmentFromRequest());
diff --git a/tests/PHPUnit/Core/AssetManagerTest.php b/tests/PHPUnit/Core/AssetManagerTest.php
index 2e2f27f498adc7495f56c3ec90aeccc47cfdcc83..85fc6d9764cd2a9a60010ec139e71728372dcc5e 100644
--- a/tests/PHPUnit/Core/AssetManagerTest.php
+++ b/tests/PHPUnit/Core/AssetManagerTest.php
@@ -420,7 +420,7 @@ class AssetManagerTest extends PHPUnit_Framework_TestCase
         return
             '<script type="text/javascript">' . PHP_EOL .
             'var translations = [];' . PHP_EOL .
-            'if(typeof(piwik_translations) == \'undefined\') { var piwik_translations = new Object; }for(var i in translations) { piwik_translations[i] = translations[i];} ' . PHP_EOL .
+            'if (typeof(piwik_translations) == \'undefined\') { var piwik_translations = new Object; }for(var i in translations) { piwik_translations[i] = translations[i];} ' . PHP_EOL .
             '</script>';
     }
 
diff --git a/tests/PHPUnit/Core/Unzip/relative.zip b/tests/PHPUnit/Core/Http/fixture.zip
similarity index 100%
rename from tests/PHPUnit/Core/Unzip/relative.zip
rename to tests/PHPUnit/Core/Http/fixture.zip
diff --git a/tests/PHPUnit/Core/HttpTest.php b/tests/PHPUnit/Core/HttpTest.php
index 36af08b943d31b99fb07a7229bfdb83f3b769952..af2711c530c4d71b79637bd4668412023d42242e 100644
--- a/tests/PHPUnit/Core/HttpTest.php
+++ b/tests/PHPUnit/Core/HttpTest.php
@@ -19,9 +19,9 @@ class HttpTest extends PHPUnit_Framework_TestCase
     public function getMethodsToTest()
     {
         return array(
-            array('curl'),
-            array('fopen'),
-            array('socket'),
+            'curl' => array('curl'),
+            'fopen' => array('fopen'),
+            'socket' => array('socket'),
         );
     }
 
@@ -33,7 +33,7 @@ class HttpTest extends PHPUnit_Framework_TestCase
     public function testFetchRemoteFile($method)
     {
         $this->assertNotNull(Http::getTransportMethod());
-        $result = Http::sendHttpRequestBy($method, 'http://localhost/piwik.js', 30);
+        $result = Http::sendHttpRequestBy($method, Fixture::getRootUrl() . 'piwik.js', 30);
         $this->assertTrue(strpos($result, 'Piwik') !== false);
     }
 
@@ -43,7 +43,7 @@ class HttpTest extends PHPUnit_Framework_TestCase
     public function testFetchApiLatestVersion()
     {
         $destinationPath = PIWIK_USER_PATH . '/tmp/latest/LATEST';
-        Http::fetchRemoteFile('http://localhost/', $destinationPath, 3);
+        Http::fetchRemoteFile(Fixture::getRootUrl(), $destinationPath, 3);
         $this->assertFileExists($destinationPath);
         $this->assertGreaterThan(0, filesize($destinationPath));
     }
@@ -54,7 +54,7 @@ class HttpTest extends PHPUnit_Framework_TestCase
     public function testFetchLatestZip()
     {
         $destinationPath = PIWIK_USER_PATH . '/tmp/latest/latest.zip';
-        Http::fetchRemoteFile('http://localhost/tests/PHPUnit/Core/Unzip/relative.zip', $destinationPath, 3, 30);
+        Http::fetchRemoteFile(Fixture::getRootUrl() . 'tests/PHPUnit/Core/Http/fixture.zip', $destinationPath, 3, 30);
         $this->assertFileExists($destinationPath);
         $this->assertGreaterThan(0, filesize($destinationPath));
     }
@@ -100,7 +100,7 @@ class HttpTest extends PHPUnit_Framework_TestCase
 
         $result = Http::sendHttpRequestBy(
             $method,
-            'http://localhost/tests/PHPUnit/Core/Unzip/relative.zip',
+            Fixture::getRootUrl() . 'tests/PHPUnit/Core/Http/fixture.zip',
             30,
             $userAgent = null,
             $destinationPath = null,
diff --git a/tests/PHPUnit/Core/Unzip/empty.zip b/tests/PHPUnit/Core/Unzip/empty.zip
deleted file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/tests/PHPUnit/Core/Unzip/test.gz b/tests/PHPUnit/Core/Unzip/test.gz
deleted file mode 100755
index 113cbed07f15e555920c15ac10317e8645b15d47..0000000000000000000000000000000000000000
Binary files a/tests/PHPUnit/Core/Unzip/test.gz and /dev/null differ
diff --git a/tests/PHPUnit/Core/Unzip/test.tar.gz b/tests/PHPUnit/Core/Unzip/test.tar.gz
deleted file mode 100755
index b9cc91965d020c8931877d861539a57ab2226514..0000000000000000000000000000000000000000
Binary files a/tests/PHPUnit/Core/Unzip/test.tar.gz and /dev/null differ
diff --git a/tests/PHPUnit/Core/Unzip/zaabs.zip b/tests/PHPUnit/Core/Unzip/zaabs.zip
deleted file mode 100644
index c5517f940ddd3335a5fe9f49ab51ad8c4d4f29a5..0000000000000000000000000000000000000000
Binary files a/tests/PHPUnit/Core/Unzip/zaabs.zip and /dev/null differ
diff --git a/tests/PHPUnit/Core/Unzip/zaatt.zip b/tests/PHPUnit/Core/Unzip/zaatt.zip
deleted file mode 100644
index 91e0c4864a3d68c86e22057070cbf72aa41afd47..0000000000000000000000000000000000000000
Binary files a/tests/PHPUnit/Core/Unzip/zaatt.zip and /dev/null differ
diff --git a/tests/PHPUnit/Core/UnzipTest.php b/tests/PHPUnit/Core/UnzipTest.php
deleted file mode 100644
index 12f754c8b7c2970fb3d22509d0d15e518670f6a6..0000000000000000000000000000000000000000
--- a/tests/PHPUnit/Core/UnzipTest.php
+++ /dev/null
@@ -1,217 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-use Piwik\Unzip\Gzip;
-use Piwik\Unzip;
-use Piwik\Unzip\PclZip;
-use Piwik\Unzip\Tar;
-use Piwik\Unzip\ZipArchive;
-
-class UnzipTest extends PHPUnit_Framework_TestCase
-{
-    /**
-     * @group Core
-     */
-    public function testRelativePath()
-    {
-        clearstatcache();
-        $extractDir = PIWIK_USER_PATH . '/tmp/latest/';
-        $test = 'relative';
-        $filename = dirname(__FILE__) . '/Unzip/' . $test . '.zip';
-
-        if (class_exists('ZipArchive', false)) {
-            $unzip = Unzip::factory('ZipArchive', $filename);
-            $res = $unzip->extract($extractDir);
-            $this->assertEquals(1, count($res));
-            $this->assertFileExists($extractDir . $test . '.txt');
-            $this->assertFileNotExists(dirname(__FILE__) . '/' . $test . '.txt');
-            $this->assertFileNotExists(dirname(__FILE__) . '/../../tests/' . $test . '.txt');
-            unlink($extractDir . $test . '.txt');
-
-            $unzip = new ZipArchive($filename);
-            $res = $unzip->extract($extractDir);
-            $this->assertEquals(1, count($res));
-            $this->assertFileExists($extractDir . $test . '.txt');
-            $this->assertFileNotExists(dirname(__FILE__) . '/' . $test . '.txt');
-            $this->assertFileNotExists(dirname(__FILE__) . '/../../tests/' . $test . '.txt');
-            unlink($extractDir . $test . '.txt');
-        }
-
-        $unzip = Unzip::factory('PclZip', $filename);
-        $res = $unzip->extract($extractDir);
-        $this->assertEquals(1, count($res));
-        $this->assertFileExists($extractDir . $test . '.txt');
-        $this->assertFileNotExists(dirname(__FILE__) . '/' . $test . '.txt');
-        $this->assertFileNotExists(dirname(__FILE__) . '/../../tests/' . $test . '.txt');
-        unlink($extractDir . $test . '.txt');
-
-        $unzip = new PclZip($filename);
-        $res = $unzip->extract($extractDir);
-        $this->assertEquals(1, count($res));
-        $this->assertFileExists($extractDir . $test . '.txt');
-        $this->assertFileNotExists(dirname(__FILE__) . '/' . $test . '.txt');
-        $this->assertFileNotExists(dirname(__FILE__) . '/../../tests/' . $test . '.txt');
-        unlink($extractDir . $test . '.txt');
-    }
-
-    /**
-     * @group Core
-     */
-    public function testRelativePathAttack()
-    {
-        clearstatcache();
-        $extractDir = PIWIK_USER_PATH . '/tmp/latest/';
-        $test = 'zaatt';
-        $filename = dirname(__FILE__) . '/Unzip/' . $test . '.zip';
-
-        if (class_exists('ZipArchive', false)) {
-            $unzip = new ZipArchive($filename);
-            $res = $unzip->extract($extractDir);
-            $this->assertEquals(0, $res);
-            $this->assertFileNotExists($extractDir . $test . '.txt');
-            $this->assertFileNotExists($extractDir . '../' . $test . '.txt');
-            $this->assertFileNotExists(dirname(__FILE__) . '/' . $test . '.txt');
-            $this->assertFileNotExists(dirname(__FILE__) . '/../' . $test . '.txt');
-            $this->assertFileNotExists(dirname(__FILE__) . '/../../' . $test . '.txt');
-        }
-
-        $unzip = new PclZip($filename);
-        $res = $unzip->extract($extractDir);
-        $this->assertEquals(0, $res);
-        $this->assertFileNotExists($extractDir . $test . '.txt');
-        $this->assertFileNotExists($extractDir . '../' . $test . '.txt');
-        $this->assertFileNotExists(dirname(__FILE__) . '/' . $test . '.txt');
-        $this->assertFileNotExists(dirname(__FILE__) . '/../' . $test . '.txt');
-        $this->assertFileNotExists(dirname(__FILE__) . '/../../' . $test . '.txt');
-    }
-
-    /**
-     * @group Core
-     */
-    public function testAbsolutePathAttack()
-    {
-        clearstatcache();
-        $extractDir = PIWIK_USER_PATH . '/tmp/latest/';
-        $test = 'zaabs';
-        $filename = dirname(__FILE__) . '/Unzip/' . $test . '.zip';
-
-        if (class_exists('ZipArchive', false)) {
-            $unzip = new ZipArchive($filename);
-            $res = $unzip->extract($extractDir);
-            $this->assertEquals(0, $res);
-            $this->assertFileNotExists($extractDir . $test . '.txt');
-            $this->assertFileNotExists(dirname(__FILE__) . '/' . $test . '.txt');
-        }
-
-        $unzip = new PclZip($filename);
-        $res = $unzip->extract($extractDir);
-        $this->assertEquals(0, $res);
-        $this->assertFileNotExists($extractDir . $test . '.txt');
-        $this->assertFileNotExists(dirname(__FILE__) . '/' . $test . '.txt');
-    }
-
-    /**
-     * @group Core
-     */
-    public function testUnzipErrorInfo()
-    {
-        clearstatcache();
-        $filename = dirname(__FILE__) . '/Unzip/zaabs.zip';
-
-        $unzip = new ZipArchive($filename);
-        $this->assertContains('No error', $unzip->errorInfo());
-    }
-
-    /**
-     * @group Core
-     */
-    public function testUnzipEmptyFile()
-    {
-        clearstatcache();
-        $filename = dirname(__FILE__) . '/Unzip/empty.zip';
-        $extractDir = PIWIK_USER_PATH . '/tmp/latest/';
-
-        $unzip = new ZipArchive($filename);
-        $res = $unzip->extract($extractDir);
-        $this->assertEquals(0, $res);
-    }
-
-    /**
-     * @group Core
-     */
-    public function testUnzipNotExistingFile()
-    {
-        clearstatcache();
-        $filename = dirname(__FILE__) . '/Unzip/NotExisting.zip';
-
-        try {
-            new ZipArchive($filename);
-        } catch (Exception $e) {
-            return;
-        }
-        $this->fail('Exception not raised');
-    }
-
-    /**
-     * @group Core
-     */
-    public function testUnzipInvalidFile2()
-    {
-        clearstatcache();
-        $extractDir = PIWIK_USER_PATH . '/tmp/latest/';
-        $filename = dirname(__FILE__) . '/Unzip/NotExisting.zip';
-
-        $unzip = new PclZip($filename);
-        $res = $unzip->extract($extractDir);
-        $this->assertEquals(0, $res);
-
-        $this->assertContains('PCLZIP_ERR_MISSING_FILE', $unzip->errorInfo());
-    }
-
-    /**
-     * @group Core
-     */
-    public function testGzipFile()
-    {
-        $extractDir = PIWIK_USER_PATH . '/tmp/latest/';
-        $extractFile = $extractDir . 'testgz.txt';
-        $filename = dirname(__FILE__) . '/Unzip/test.gz';
-
-        $unzip = new Gzip($filename);
-        $res = $unzip->extract($extractFile);
-        $this->assertTrue($res);
-
-        $this->assertFileContentsEquals('TESTSTRING', $extractFile);
-    }
-
-    /**
-     * @group Core
-     */
-    public function testTarGzFile()
-    {
-        $extractDir = PIWIK_USER_PATH . '/tmp/latest/';
-        $filename = dirname(__FILE__) . '/Unzip/test.tar.gz';
-
-        $unzip = new Tar($filename, 'gz');
-        $res = $unzip->extract($extractDir);
-        $this->assertTrue($res);
-
-        $this->assertFileContentsEquals('TESTDATA', $extractDir . 'tarout1.txt');
-        $this->assertFileContentsEquals('MORETESTDATA', $extractDir . 'tardir/tarout2.txt');
-    }
-
-    private function assertFileContentsEquals($expectedContent, $path)
-    {
-        $this->assertTrue(file_exists($path));
-
-        $fd = fopen($path, 'rb');
-        $actualContent = fread($fd, filesize($path));
-        fclose($fd);
-
-        $this->assertEquals($expectedContent, $actualContent);
-    }
-}
diff --git a/tests/PHPUnit/DatabaseTestCase.php b/tests/PHPUnit/DatabaseTestCase.php
index ef247e0f1e86e8ada54e3b9d14e681d9e5ba8c9d..715571eba45848b36824b933d159a5b95837e422 100644
--- a/tests/PHPUnit/DatabaseTestCase.php
+++ b/tests/PHPUnit/DatabaseTestCase.php
@@ -5,8 +5,10 @@
  * @link http://piwik.org
  * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
  */
+use Piwik\Config;
 use Piwik\Db;
 use Piwik\Tests\Fixture;
+use Piwik\Tests\IntegrationTestCase;
 
 /**
  * Tests extending DatabaseTestCase are much slower to run: the setUp will
@@ -16,12 +18,48 @@ use Piwik\Tests\Fixture;
  * then test it.
  *
  */
-class DatabaseTestCase extends PHPUnit_Framework_TestCase
+class DatabaseTestCase extends IntegrationTestCase
 {
     /**
      * @var Fixture
      */
-    protected $fixture = null;
+    public static $fixture;
+    public static $tableData;
+
+    /**
+     * Implementation details:
+     *
+     * To increase speed of tests, database setup is done once in setUpBeforeClass.
+     * Afterwards, the content of the tables is stored in a static class variable,
+     * self::$tableData. Before each individual test, the database tables are
+     * truncated and the data in self::$tableData is restored.
+     *
+     * If your test modifies table columns, you will need to recreate the database
+     * completely. This can be accomplished by:
+     *
+     *     public function setUp()
+     *     {
+     *         self::$fixture->performSetUp();
+     *     }
+     *
+     *     public function tearDown()
+     *     {
+     *         parent::tearDown();
+     *         self::$fixture->performTearDown();
+     *     }
+     */
+    public static function setUpBeforeClass()
+    {
+        static::configureFixture(static::$fixture);
+        parent::setUpBeforeClass();
+
+        self::$tableData = self::getDbTablesWithData();
+    }
+
+    public static function tearDownAfterClass()
+    {
+        self::$tableData = array();
+    }
 
     /**
      * Setup the database and create the base tables for all tests
@@ -30,9 +68,11 @@ class DatabaseTestCase extends PHPUnit_Framework_TestCase
     {
         parent::setUp();
 
-        $this->fixture = new Fixture();
-        $this->configureFixture();
-        $this->fixture->performSetUp();
+        Config::getInstance()->setTestEnvironment();
+
+        if (!empty(self::$tableData)) {
+            self::restoreDbTables(self::$tableData);
+        }
     }
 
     /**
@@ -40,14 +80,17 @@ class DatabaseTestCase extends PHPUnit_Framework_TestCase
      */
     public function tearDown()
     {
+        self::$fixture->clearInMemoryCaches();
+
         parent::tearDown();
-        $this->fixture->performTearDown();
     }
 
-    protected function configureFixture()
+    protected static function configureFixture($fixture)
     {
-        $this->fixture->loadTranslations = false;
-        $this->fixture->createSuperUser = false;
-        $this->fixture->configureComponents = false;
+        $fixture->loadTranslations = false;
+        $fixture->createSuperUser = false;
+        $fixture->configureComponents = false;
     }
 }
+
+DatabaseTestCase::$fixture = new Fixture();
\ No newline at end of file
diff --git a/tests/PHPUnit/Fixture.php b/tests/PHPUnit/Fixture.php
index f625f98001d06d85c747cecaffbf4766c04896fc..cc72b8498d836ea6334474e833b77aa15c5a7024 100644
--- a/tests/PHPUnit/Fixture.php
+++ b/tests/PHPUnit/Fixture.php
@@ -185,7 +185,7 @@ class Fixture extends PHPUnit_Framework_Assert
         static::createAccessInstance();
 
         // We need to be SU to create websites for tests
-        Piwik::setUserHasSuperUserAccess();
+        Access::getInstance()->setSuperUserAccess();
 
         Cache::deleteTrackerCache();
 
@@ -275,6 +275,11 @@ class Fixture extends PHPUnit_Framework_Assert
             $this->dropDatabase();
         }
 
+        $this->clearInMemoryCaches();
+    }
+
+    public function clearInMemoryCaches()
+    {
         DataTableManager::getInstance()->deleteAll();
         Option::clearCache();
         Site::clearCache();
@@ -291,7 +296,7 @@ class Fixture extends PHPUnit_Framework_Assert
         Config::unsetInstance();
 
         \Piwik\Config::getInstance()->Plugins; // make sure Plugins exists in a config object for next tests that use Plugin\Manager
-                                               // since Plugin\Manager uses getFromGlobalConfig which doesn't init the config object
+        // since Plugin\Manager uses getFromGlobalConfig which doesn't init the config object
     }
 
     public static function loadAllPlugins($testEnvironment = null, $testCaseClass = false, $extraPluginsToLoad = array())
diff --git a/tests/PHPUnit/Fixtures/FewVisitsWithSetVisitorIdAndUserId.php b/tests/PHPUnit/Fixtures/FewVisitsWithSetVisitorIdAndUserId.php
index 30accf676deff468e75d529384866484ed890cfc..f0395054609576715c623b7af3818a2378868e87 100644
--- a/tests/PHPUnit/Fixtures/FewVisitsWithSetVisitorIdAndUserId.php
+++ b/tests/PHPUnit/Fixtures/FewVisitsWithSetVisitorIdAndUserId.php
@@ -80,12 +80,20 @@ class FewVisitsWithSetVisitorId extends Fixture
 
     private function trackVisits_setUserId()
     {
+        $userId = self::USER_ID_EXAMPLE_COM;
         // total = 2 visitors, 3 page views
         $t = self::getTracker($this->idSite, $this->dateTime, $defaultInit = true);
 
         // First, some basic tests
         $this->settingInvalidUserIdShouldThrow($t);
 
+        // We create a visit with no User ID.
+        // When User ID  will be set below, then it will UPDATE this visit here that starts without UserID
+        $t->setForceVisitDateTime(Date::factory($this->dateTime)->addHour(1.9)->getDatetime());
+        $t->setVisitorId('6be121d126d93581');
+        $t->setUrl('http://example.org/no-user-id-set-but-should-appear-in-user-id-visit');
+        self::checkResponse($t->doTrackPageView('no User Id set but it should appear in '. $userId .'!'));
+
         // A NEW VISIT
         // Setting both Visitor ID and User ID
         // -> User ID takes precedence
@@ -98,22 +106,21 @@ class FewVisitsWithSetVisitorId extends Fixture
         $this->assertEquals($generatedVisitorId, $t->getVisitorId());
 
         // Set User ID
-        $userId = self::USER_ID_EXAMPLE_COM;
         $t->setUserId($userId);
-        $this->assertEquals($userId, $t->getUserId());
 
         // User ID takes precedence over any previously set Visitor ID
-        $hashUserId = $t->getUserIdHashed($userId);
-        $this->assertEquals($hashUserId, $t->getVisitorId());
+        $this->assertEquals($t->getUserIdHashed($userId), $t->getVisitorId());
+        $this->assertEquals('9395988394d4568d', $t->getVisitorId());
+        $this->assertEquals($userId, $t->getUserId());
 
         // Track a pageview with this user id
         self::checkResponse($t->doTrackPageView('incredible title!'));
 
         // Track another pageview
         $t->setForceVisitDateTime(Date::factory($this->dateTime)->addHour(2.1)->getDatetime());
+        $this->assertEquals($userId, $t->getUserId());
         self::checkResponse($t->doTrackPageView('second page'));
 
-
         // A NEW VISIT WITH A SET USER ID
         // Change User ID -> This will create a new visit
         $t->setForceVisitDateTime(Date::factory($this->dateTime)->addHour(2.2)->getDatetime());
diff --git a/tests/PHPUnit/Fixtures/SqlDump.php b/tests/PHPUnit/Fixtures/SqlDump.php
index 7aea83b781bb18ad04c6db98b3332b06b5c208af..06c094de036eaf73df4a8df73f97d9cdbd57a826 100644
--- a/tests/PHPUnit/Fixtures/SqlDump.php
+++ b/tests/PHPUnit/Fixtures/SqlDump.php
@@ -7,6 +7,7 @@
  */
 namespace Piwik\Tests\Fixtures;
 
+use Piwik\Access;
 use Piwik\ArchiveProcessor\Rules;
 use Piwik\Config;
 use Piwik\Db;
@@ -79,7 +80,7 @@ class SqlDump extends Fixture
         Rules::setBrowserTriggerArchiving(true);
 
         // reload access
-        Piwik::setUserHasSuperUserAccess();
+        Access::getInstance()->reloadAccess();
 
         $this->getTestEnvironment()->configOverride = array(
             'database' => array(
diff --git a/tests/PHPUnit/Integration/ArchiveInvalidationTest.php b/tests/PHPUnit/Integration/ArchiveInvalidationTest.php
index a45aaac72c107b90e41c6c3b227388f74a745540..1d04920a8c56d4178c20c73ef4499667b2758f60 100644
--- a/tests/PHPUnit/Integration/ArchiveInvalidationTest.php
+++ b/tests/PHPUnit/Integration/ArchiveInvalidationTest.php
@@ -86,7 +86,6 @@ class ArchiveInvalidationTest extends IntegrationTestCase
 
         $this->invalidateTestArchives();
         $this->runApiTests($api, $params);
-
     }
 
     /**
diff --git a/tests/PHPUnit/Integration/Core/AccessTest.php b/tests/PHPUnit/Integration/Core/AccessTest.php
index 06a9b4a036769534b3d0d05433f93cdff30d39c8..ec1eb9bd29800c9c4fb7ffbff567a4ac522a3bb9 100644
--- a/tests/PHPUnit/Integration/Core/AccessTest.php
+++ b/tests/PHPUnit/Integration/Core/AccessTest.php
@@ -11,7 +11,6 @@ use Piwik\AuthResult;
 /**
  * Class Core_AccessTest
  *
- * @group Core_AccessTest
  * @group Core
  */
 class Core_AccessTest extends DatabaseTestCase
@@ -308,4 +307,58 @@ class Core_AccessTest extends DatabaseTestCase
         $this->assertTrue($access->reloadAccess($mock));
         $this->assertFalse($access->hasSuperUserAccess());
     }
+
+    public function test_doAsSuperUser_ChangesSuperUserAccessCorrectly()
+    {
+        Access::getInstance()->setSuperUserAccess(false);
+
+        $this->assertFalse(Access::getInstance()->hasSuperUserAccess());
+
+        Access::doAsSuperUser(function () {
+            Core_AccessTest::assertTrue(Access::getInstance()->hasSuperUserAccess());
+        });
+
+        $this->assertFalse(Access::getInstance()->hasSuperUserAccess());
+    }
+
+    public function test_doAsSuperUser_RemovesSuperUserAccess_IfExceptionThrown()
+    {
+        Access::getInstance()->setSuperUserAccess(false);
+
+        $this->assertFalse(Access::getInstance()->hasSuperUserAccess());
+
+        try {
+            Access::doAsSuperUser(function () {
+                throw new Exception();
+            });
+
+            $this->fail("Exception was not propagated by doAsSuperUser.");
+        } catch (Exception $ex)
+        {
+            // pass
+        }
+
+        $this->assertFalse(Access::getInstance()->hasSuperUserAccess());
+    }
+
+    public function test_doAsSuperUser_ReturnsCallbackResult()
+    {
+        $result = Access::doAsSuperUser(function () {
+            return 24;
+        });
+        $this->assertEquals(24, $result);
+    }
+
+    public function test_reloadAccess_DoesNotRemoveSuperUserAccess_IfUsedInDoAsSuperUser()
+    {
+        Access::getInstance()->setSuperUserAccess(false);
+
+        Access::doAsSuperUser(function () {
+            $access = Access::getInstance();
+
+            Core_AccessTest::assertTrue($access->hasSuperUserAccess());
+            $access->reloadAccess();
+            Core_AccessTest::assertTrue($access->hasSuperUserAccess());
+        });
+    }
 }
\ No newline at end of file
diff --git a/tests/PHPUnit/Integration/Core/CronArchive/SharedSiteIdsTest.php b/tests/PHPUnit/Integration/Core/CronArchive/SharedSiteIdsTest.php
index 5183177aa93ced8ee0987afbc95911d9c6704a06..eca1d85aeab1594b603a1037fe70744fa674f8e5 100644
--- a/tests/PHPUnit/Integration/Core/CronArchive/SharedSiteIdsTest.php
+++ b/tests/PHPUnit/Integration/Core/CronArchive/SharedSiteIdsTest.php
@@ -10,6 +10,7 @@ use Piwik\CronArchive\SharedSiteIds;
 
 /**
  * @group Core
+ * @group SharedSiteIdsTest
  */
 class SharedSiteIdsTest extends DatabaseTestCase
 {
@@ -21,7 +22,6 @@ class SharedSiteIdsTest extends DatabaseTestCase
     public function setUp()
     {
         parent::setUp();
-        $this->fixture->performSetUp(true);
 
         $this->sharedSiteIds = new SharedSiteIds(array(1,2,5,9));
     }
diff --git a/tests/PHPUnit/Integration/Core/LogTest.php b/tests/PHPUnit/Integration/Core/LogTest.php
index f7d35e451b334d8e1430ae38aa1f3214515697b9..a3923183ae4a6f0d11e51e6a6feb60c44a93d8ba 100644
--- a/tests/PHPUnit/Integration/Core/LogTest.php
+++ b/tests/PHPUnit/Integration/Core/LogTest.php
@@ -31,9 +31,9 @@ class Core_LogTest extends DatabaseTestCase
         'screen' => 'dummy error message<br />
  <br />
  --&gt; To temporarily debug this error further, set const PIWIK_PRINT_ERROR_BACKTRACE=true; in index.php',
-        'file' => '[Core_LogTest] LogTest.php(161): dummy error message
+        'file' => '[Core_LogTest] LogTest.php(165): dummy error message
   dummy backtrace',
-        'database' => '[Core_LogTest] LogTest.php(161): dummy error message
+        'database' => '[Core_LogTest] LogTest.php(165): dummy error message
 dummy backtrace'
     );
 
@@ -55,6 +55,8 @@ dummy backtrace'
 
     public static function setUpBeforeClass()
     {
+        parent::setUpBeforeClass();
+
         Error::setErrorHandler();
         ExceptionHandler::setUp();
     }
@@ -63,6 +65,8 @@ dummy backtrace'
     {
         restore_error_handler();
         restore_exception_handler();
+
+        parent::tearDownAfterClass();
     }
 
     public function setUp()
diff --git a/tests/PHPUnit/Integration/Core/OptionTest.php b/tests/PHPUnit/Integration/Core/OptionTest.php
index c926e1c808140962907f7928d863dc615ba3cb71..41a12df3fd6e368069b4443795032174f05fd7b5 100644
--- a/tests/PHPUnit/Integration/Core/OptionTest.php
+++ b/tests/PHPUnit/Integration/Core/OptionTest.php
@@ -13,6 +13,7 @@ use Piwik\Option;
  * Class Core_OptionTest
  *
  * @group Core
+ * @group Core_OptionTest
  */
 class Core_OptionTest extends DatabaseTestCase
 {
diff --git a/tests/PHPUnit/Integration/Core/SegmentTest.php b/tests/PHPUnit/Integration/Core/SegmentTest.php
index ce7a0c363f82350689cf4b0aa3c9100b73d8583f..3fddab94b27907341d57224752fb1afd991added 100644
--- a/tests/PHPUnit/Integration/Core/SegmentTest.php
+++ b/tests/PHPUnit/Integration/Core/SegmentTest.php
@@ -8,8 +8,10 @@
 use Piwik\Access;
 use Piwik\Common;
 use Piwik\Segment;
-use Piwik\Tests\Fixture;
 
+/**
+ * @group SegmentTest
+ */
 class SegmentTest extends DatabaseTestCase
 {
     public function setUp()
@@ -20,14 +22,11 @@ class SegmentTest extends DatabaseTestCase
         $pseudoMockAccess = new FakeAccess;
         FakeAccess::$superUser = true;
         Access::setSingletonInstance($pseudoMockAccess);
-
-        Fixture::loadAllPlugins();
     }
 
     public function tearDown()
     {
         parent::tearDown();
-        Fixture::unloadAllPlugins();
     }
 
     protected function _filterWhitsSpaces($valueToFilter)
diff --git a/tests/PHPUnit/Integration/Core/Tracker/DbTest.php b/tests/PHPUnit/Integration/Core/Tracker/DbTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..ef738d55151027245afbae565131437cbd7cb0e0
--- /dev/null
+++ b/tests/PHPUnit/Integration/Core/Tracker/DbTest.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+use Piwik\Common;
+use Piwik\Db;
+
+/**
+ * Tracker DB test
+ *
+ * @group Core
+ * @group TrackerDbTest
+ */
+class Core_Tracker_DbTest extends DatabaseTestCase
+{
+    public function test_rowCount_whenUpdating_returnsAllMatchedRowsNotOnlyUpdatedRows()
+    {
+        $db = \Piwik\Tracker::getDatabase();
+        // insert one record
+        $db->query("INSERT INTO `" . Common::prefixTable('option') . "` VALUES ('rowid', '1', false)");
+
+        // We will now UPDATE this table and check rowCount() value
+        $sqlUpdate = "UPDATE `" . Common::prefixTable('option') . "` SET option_value = 2";
+
+        // when no record was updated, return 0
+        $result = $db->query($sqlUpdate . " WHERE option_name = 'NOT FOUND'");
+        $this->assertSame(0, $db->rowCount($result));
+
+        // when one record was found and updated, returns 1
+        $result = $db->query($sqlUpdate . " WHERE option_name = 'rowid'");
+        $this->assertSame(1, $db->rowCount($result));
+
+        // when one record was found but NOT actually updated (as values have not changed), we make sure to return 1
+        // testing for MYSQLI_CLIENT_FOUND_ROWS and MYSQL_ATTR_FOUND_ROWS
+        $result = $db->query($sqlUpdate . " WHERE option_name = 'rowid'");
+        $this->assertSame(1, $db->rowCount($result));
+    }
+
+}
\ No newline at end of file
diff --git a/tests/PHPUnit/Integration/Core/TrackerTest.php b/tests/PHPUnit/Integration/Core/TrackerTest.php
index ad2810f7898e36b62b7d2b80db249b11fcb4d161..a5eb8cbcb8bbc00b3af6b218784277eae91ba2e3 100644
--- a/tests/PHPUnit/Integration/Core/TrackerTest.php
+++ b/tests/PHPUnit/Integration/Core/TrackerTest.php
@@ -16,13 +16,12 @@ class Core_TrackerTest extends DatabaseTestCase
     public function setUp()
     {
         parent::setUp();
-        \Piwik\Piwik::setUserHasSuperUserAccess(true);
         Fixture::createWebsite('2014-02-04');
     }
 
-    protected function configureFixture()
+    protected static function configureFixture($fixture)
     {
-        $this->fixture->createSuperUser = true;
+        $fixture->createSuperUser = true;
     }
 
     /**
diff --git a/tests/PHPUnit/Integration/ManyVisitorsOneWebsiteTest.php b/tests/PHPUnit/Integration/ManyVisitorsOneWebsiteTest.php
index a7f41f6b3be43a5db2f51dbcdb0a294eb5fb4773..c7f3d9ca0039f7b931c950d8b6fe8889bcaac2a3 100755
--- a/tests/PHPUnit/Integration/ManyVisitorsOneWebsiteTest.php
+++ b/tests/PHPUnit/Integration/ManyVisitorsOneWebsiteTest.php
@@ -108,6 +108,7 @@ class ManyVisitorsOneWebsiteTest extends IntegrationTestCase
 
         // Randomly fails on 5.3
         if(!self::isPhpVersion53()) {
+
             $apiToTest[] = array('Live.getLastVisitsDetails', array(
                 'idSite'                 => $idSite,
                 'date'                   => $dateString,
@@ -140,7 +141,11 @@ class ManyVisitorsOneWebsiteTest extends IntegrationTestCase
                 'date'                   => $dateString,
                 'periods'                => 'month',
                 'testSuffix'             => '_Live.getLastVisitsDetails_sortByIdVisitAsc',
-                'otherRequestParameters' => array('filter_sort_order' => 'asc', 'filter_sort_column' => 'idVisit', 'filter_limit' => 7)
+                'otherRequestParameters' => array('filter_sort_order' => 'asc',
+                                                  'filter_sort_column' => 'idVisit',
+                                                  'filter_limit' => 7,
+                                                  'hideColumns' => 'latitude,longitude' // Mysqli has troubles with lat/long rounding
+                )
             ));
         }
 
diff --git a/tests/PHPUnit/Integration/PivotByQueryParamTest.php b/tests/PHPUnit/Integration/PivotByQueryParamTest.php
index b668a68f7ad4728e2f119be6222a54ee8c80d6d5..7e579f4b5efbb8c905838eefb6a05619cdc01d40 100644
--- a/tests/PHPUnit/Integration/PivotByQueryParamTest.php
+++ b/tests/PHPUnit/Integration/PivotByQueryParamTest.php
@@ -43,7 +43,7 @@ class PivotByQueryParamTest extends IntegrationTestCase
         ));
     }
 
-    public function test_PivotBySubtableDimension_CreatesCorrectPivotTable_WhenEntireHirearchyIsNotLoaded()
+    public function test_PivotBySubtableDimension_WhenEntireHirearchyIsNotLoaded()
     {
         $this->assertApiResponseEqualsExpected("Referrers.getKeywords", array(
             'idSite' => self::$fixture->idSite,
@@ -186,4 +186,4 @@ class PivotByQueryParamTest extends IntegrationTestCase
     }
 }
 
-PivotByQueryParamTest::$fixture = new ManyVisitsWithMockLocationProvider();
\ No newline at end of file
+PivotByQueryParamTest::$fixture = new ManyVisitsWithMockLocationProvider();
diff --git a/tests/PHPUnit/Integration/PrivacyManagerTest.php b/tests/PHPUnit/Integration/PrivacyManagerTest.php
index b78a93d32ab7d8f57564fea42485efd04bc6854e..c229f08d8c3a2d60a95c7e3e7c468bc0a31ee036 100644
--- a/tests/PHPUnit/Integration/PrivacyManagerTest.php
+++ b/tests/PHPUnit/Integration/PrivacyManagerTest.php
@@ -71,15 +71,9 @@ class PrivacyManagerTest extends IntegrationTestCase
     {
         parent::setUpBeforeClass();
 
-        // Temporarily disable the purge of old archives so that getNumeric('nb_visits')
-        // in _addReportData does not trigger the data purge of data we've just imported
-        \Piwik\ArchiveProcessor\Rules::disablePurgeOutdatedArchives();
-
         self::_addLogData();
         self::_addReportData();
 
-        \Piwik\ArchiveProcessor\Rules::enablePurgeOutdatedArchives();
-
         self::$dbData = self::getDbTablesWithData();
     }
 
diff --git a/tests/PHPUnit/Integration/expected/test_AutoSuggestAPITest__Live.getLastVisitsDetails_range.xml b/tests/PHPUnit/Integration/expected/test_AutoSuggestAPITest__Live.getLastVisitsDetails_range.xml
index ef32d680f81888b683a134b40e1ff8c5240a6aba..32e753a325b7efbec888a5be7f87ae9da07f19c0 100644
--- a/tests/PHPUnit/Integration/expected/test_AutoSuggestAPITest__Live.getLastVisitsDetails_range.xml
+++ b/tests/PHPUnit/Integration/expected/test_AutoSuggestAPITest__Live.getLastVisitsDetails_range.xml
@@ -4,7 +4,6 @@
 		<idSite>1</idSite>
 		<idVisit>35</idVisit>
 		<visitIp>194.57.91.215</visitIp>
-		<userId>userid.email@example.org</userId>
 		
 		<actionDetails>
 			<row>
@@ -33,7 +32,8 @@
 		
 		
 		
-
+		
+		<userId>userid.email@example.org</userId>
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -111,7 +111,6 @@
 		<idSite>1</idSite>
 		<idVisit>18</idVisit>
 		<visitIp>1.2.4.8</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -181,7 +180,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -267,7 +267,6 @@
 		<idSite>1</idSite>
 		<idVisit>17</idVisit>
 		<visitIp>1.2.4.8</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -306,7 +305,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -392,7 +392,6 @@
 		<idSite>1</idSite>
 		<idVisit>16</idVisit>
 		<visitIp>1.2.4.7</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -445,7 +444,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -531,7 +531,6 @@
 		<idSite>1</idSite>
 		<idVisit>15</idVisit>
 		<visitIp>1.2.4.7</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -570,7 +569,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -656,7 +656,6 @@
 		<idSite>1</idSite>
 		<idVisit>14</idVisit>
 		<visitIp>1.2.4.6</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -726,7 +725,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -812,7 +812,6 @@
 		<idSite>1</idSite>
 		<idVisit>13</idVisit>
 		<visitIp>1.2.4.6</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -851,7 +850,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -937,7 +937,6 @@
 		<idSite>1</idSite>
 		<idVisit>12</idVisit>
 		<visitIp>1.2.4.5</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -990,7 +989,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -1076,7 +1076,6 @@
 		<idSite>1</idSite>
 		<idVisit>11</idVisit>
 		<visitIp>1.2.4.5</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -1115,7 +1114,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -1201,7 +1201,6 @@
 		<idSite>1</idSite>
 		<idVisit>10</idVisit>
 		<visitIp>1.2.4.4</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -1271,7 +1270,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -1357,7 +1357,6 @@
 		<idSite>1</idSite>
 		<idVisit>9</idVisit>
 		<visitIp>1.2.4.4</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -1396,7 +1395,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -1482,7 +1482,6 @@
 		<idSite>1</idSite>
 		<idVisit>8</idVisit>
 		<visitIp>1.2.4.3</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -1535,7 +1534,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -1621,7 +1621,6 @@
 		<idSite>1</idSite>
 		<idVisit>30</idVisit>
 		<visitIp>113.62.1.1</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -1674,7 +1673,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -1752,7 +1752,6 @@
 		<idSite>1</idSite>
 		<idVisit>7</idVisit>
 		<visitIp>1.2.4.3</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -1791,7 +1790,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -1877,7 +1877,6 @@
 		<idSite>1</idSite>
 		<idVisit>29</idVisit>
 		<visitIp>113.62.1.1</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -1916,7 +1915,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -2002,7 +2002,6 @@
 		<idSite>1</idSite>
 		<idVisit>6</idVisit>
 		<visitIp>1.2.4.2</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -2072,7 +2071,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -2158,7 +2158,6 @@
 		<idSite>1</idSite>
 		<idVisit>28</idVisit>
 		<visitIp>2001:db8:85a3::8a2e:370:7334</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -2228,7 +2227,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -2306,7 +2306,6 @@
 		<idSite>1</idSite>
 		<idVisit>5</idVisit>
 		<visitIp>1.2.4.2</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -2345,7 +2344,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -2431,7 +2431,6 @@
 		<idSite>1</idSite>
 		<idVisit>27</idVisit>
 		<visitIp>2001:db8:85a3::8a2e:370:7334</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -2470,7 +2469,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -2556,7 +2556,6 @@
 		<idSite>1</idSite>
 		<idVisit>4</idVisit>
 		<visitIp>1.2.4.1</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -2609,7 +2608,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -2695,7 +2695,6 @@
 		<idSite>1</idSite>
 		<idVisit>22</idVisit>
 		<visitIp>::ffff:137.82.130.49</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -2748,7 +2747,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -2834,7 +2834,6 @@
 		<idSite>1</idSite>
 		<idVisit>26</idVisit>
 		<visitIp>137.82.0.0</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -2887,7 +2886,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -2965,7 +2965,6 @@
 		<idSite>1</idSite>
 		<idVisit>34</idVisit>
 		<visitIp>103.29.196.229</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -3018,7 +3017,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -3104,7 +3104,6 @@
 		<idSite>1</idSite>
 		<idVisit>3</idVisit>
 		<visitIp>1.2.4.1</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -3143,7 +3142,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -3229,7 +3229,6 @@
 		<idSite>1</idSite>
 		<idVisit>21</idVisit>
 		<visitIp>::ffff:137.82.130.49</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -3268,7 +3267,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -3354,7 +3354,6 @@
 		<idSite>1</idSite>
 		<idVisit>25</idVisit>
 		<visitIp>137.82.0.0</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -3393,7 +3392,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -3479,7 +3479,6 @@
 		<idSite>1</idSite>
 		<idVisit>33</idVisit>
 		<visitIp>103.29.196.229</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -3518,7 +3517,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -3604,7 +3604,6 @@
 		<idSite>1</idSite>
 		<idVisit>2</idVisit>
 		<visitIp>1.2.4.0</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -3674,7 +3673,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -3760,7 +3760,6 @@
 		<idSite>1</idSite>
 		<idVisit>20</idVisit>
 		<visitIp>194.57.91.215</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -3830,7 +3829,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -3916,7 +3916,6 @@
 		<idSite>1</idSite>
 		<idVisit>24</idVisit>
 		<visitIp>137.82.130.0</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -3986,7 +3985,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -4064,7 +4064,6 @@
 		<idSite>1</idSite>
 		<idVisit>32</idVisit>
 		<visitIp>151.100.101.92</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -4134,7 +4133,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -4220,7 +4220,6 @@
 		<idSite>1</idSite>
 		<idVisit>1</idVisit>
 		<visitIp>1.2.4.0</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -4259,7 +4258,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -4345,7 +4345,6 @@
 		<idSite>1</idSite>
 		<idVisit>19</idVisit>
 		<visitIp>194.57.91.215</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -4384,7 +4383,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -4470,7 +4470,6 @@
 		<idSite>1</idSite>
 		<idVisit>23</idVisit>
 		<visitIp>137.82.130.0</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -4509,7 +4508,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -4595,7 +4595,6 @@
 		<idSite>1</idSite>
 		<idVisit>31</idVisit>
 		<visitIp>151.100.101.92</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -4634,7 +4633,8 @@
 		
 		
 		
-
+		
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
diff --git a/tests/PHPUnit/Integration/expected/test_CustomEvents__Live.getLastVisitsDetails_day.xml b/tests/PHPUnit/Integration/expected/test_CustomEvents__Live.getLastVisitsDetails_day.xml
index 2c741a31b0f055701cd2d58e55c2cd18cb7fe88d..e058d9fe14cc0e1e21b064a3ffa0fbd4898e6295 100644
--- a/tests/PHPUnit/Integration/expected/test_CustomEvents__Live.getLastVisitsDetails_day.xml
+++ b/tests/PHPUnit/Integration/expected/test_CustomEvents__Live.getLastVisitsDetails_day.xml
@@ -26,7 +26,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -128,7 +128,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -298,7 +298,7 @@
 		
 		<searches>0</searches>
 		<actions>6</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -400,7 +400,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -737,7 +737,7 @@
 		
 		<searches>0</searches>
 		<actions>15</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -839,7 +839,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -937,7 +937,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -1103,7 +1103,7 @@
 		
 		<searches>0</searches>
 		<actions>6</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -1201,7 +1201,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -1534,7 +1534,7 @@
 		
 		<searches>0</searches>
 		<actions>15</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
diff --git a/tests/PHPUnit/Integration/expected/test_CustomEvents__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/Integration/expected/test_CustomEvents__Live.getLastVisitsDetails_month.xml
index 2c741a31b0f055701cd2d58e55c2cd18cb7fe88d..e058d9fe14cc0e1e21b064a3ffa0fbd4898e6295 100644
--- a/tests/PHPUnit/Integration/expected/test_CustomEvents__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/Integration/expected/test_CustomEvents__Live.getLastVisitsDetails_month.xml
@@ -26,7 +26,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -128,7 +128,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -298,7 +298,7 @@
 		
 		<searches>0</searches>
 		<actions>6</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -400,7 +400,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -737,7 +737,7 @@
 		
 		<searches>0</searches>
 		<actions>15</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -839,7 +839,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -937,7 +937,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -1103,7 +1103,7 @@
 		
 		<searches>0</searches>
 		<actions>6</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -1201,7 +1201,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -1534,7 +1534,7 @@
 		
 		<searches>0</searches>
 		<actions>15</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
diff --git a/tests/PHPUnit/Integration/expected/test_ImportLogs__Live.getLastVisitsDetails_range.xml b/tests/PHPUnit/Integration/expected/test_ImportLogs__Live.getLastVisitsDetails_range.xml
index dfb3d767360bd4c1abb532b397d3b5dbbf5af927..979dcb11467e4e344251594ca9b84fa0c36ab8e7 100644
--- a/tests/PHPUnit/Integration/expected/test_ImportLogs__Live.getLastVisitsDetails_range.xml
+++ b/tests/PHPUnit/Integration/expected/test_ImportLogs__Live.getLastVisitsDetails_range.xml
@@ -42,7 +42,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>returning</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -180,7 +180,7 @@
 		
 		<searches>0</searches>
 		<actions>2</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>returning</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -289,7 +289,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>returning</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -439,7 +439,7 @@
 		
 		<searches>0</searches>
 		<actions>2</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>returning</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -554,7 +554,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>returning</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>0</visitConverted>
@@ -680,7 +680,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -813,7 +813,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>returning</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -935,7 +935,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>returning</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -1049,7 +1049,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>returning</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -1218,7 +1218,7 @@
 		
 		<searches>0</searches>
 		<actions>3</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -1336,7 +1336,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>returning</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -1462,7 +1462,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -1750,7 +1750,7 @@
 		
 		<searches>0</searches>
 		<actions>10</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -1862,7 +1862,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -1979,7 +1979,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>returning</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -2112,7 +2112,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -2237,7 +2237,7 @@
 		
 		<searches>0</searches>
 		<actions>2</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -2369,7 +2369,7 @@
 		
 		<searches>0</searches>
 		<actions>3</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -2477,7 +2477,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -2585,7 +2585,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -2683,7 +2683,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -2791,7 +2791,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -2899,7 +2899,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -3007,7 +3007,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -3111,7 +3111,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -3215,7 +3215,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -3319,7 +3319,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -3423,7 +3423,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -3527,7 +3527,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -3631,7 +3631,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -3735,7 +3735,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -3839,7 +3839,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -3943,7 +3943,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -4047,7 +4047,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -4151,7 +4151,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -4255,7 +4255,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -4359,7 +4359,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -4463,7 +4463,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -4567,7 +4567,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -4671,7 +4671,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
diff --git a/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByIdVisitAsc__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByIdVisitAsc__Live.getLastVisitsDetails_month.xml
index 050f358af479ef0d25af9128ac1abbc850c102c6..314b95c25ad478044f3ae822bdf81242b81d5074 100644
--- a/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByIdVisitAsc__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByIdVisitAsc__Live.getLastVisitsDetails_month.xml
@@ -43,7 +43,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -101,8 +101,6 @@
 		<regionCode>P3</regionCode>
 		<city>Stratford-upon-Avon</city>
 		<location>Stratford-upon-Avon, Warwickshire, United Kingdom</location>
-		<latitude>123.456001</latitude>
-		<longitude>21.320999</longitude>
 		<visitLocalTime>12:34:06</visitLocalTime>
 		<visitLocalHour>12</visitLocalHour>
 		<daysSinceLastVisit>0</daysSinceLastVisit>
@@ -199,7 +197,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -257,8 +255,6 @@
 		<regionCode>P3</regionCode>
 		<city>Stratford-upon-Avon</city>
 		<location>Stratford-upon-Avon, Warwickshire, United Kingdom</location>
-		<latitude>123.456001</latitude>
-		<longitude>21.320999</longitude>
 		<visitLocalTime>12:34:06</visitLocalTime>
 		<visitLocalHour>12</visitLocalHour>
 		<daysSinceLastVisit>10</daysSinceLastVisit>
@@ -324,7 +320,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -382,8 +378,6 @@
 		<regionCode>A6</regionCode>
 		<city>Besançon</city>
 		<location>Besançon, Franche-Comte, France</location>
-		<latitude>47.249001</latitude>
-		<longitude>6.018000</longitude>
 		<visitLocalTime>12:34:06</visitLocalTime>
 		<visitLocalHour>12</visitLocalHour>
 		<daysSinceLastVisit>0</daysSinceLastVisit>
@@ -480,7 +474,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -538,8 +532,6 @@
 		<regionCode>A6</regionCode>
 		<city>Besançon</city>
 		<location>Besançon, Franche-Comte, France</location>
-		<latitude>47.249001</latitude>
-		<longitude>6.018000</longitude>
 		<visitLocalTime>12:34:06</visitLocalTime>
 		<visitLocalHour>12</visitLocalHour>
 		<daysSinceLastVisit>10</daysSinceLastVisit>
@@ -605,7 +597,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -663,8 +655,6 @@
 		<regionCode>BC</regionCode>
 		<city>Vancouver</city>
 		<location>Vancouver, British Columbia, Canada</location>
-		<latitude>49.250000</latitude>
-		<longitude>-123.133003</longitude>
 		<visitLocalTime>12:34:06</visitLocalTime>
 		<visitLocalHour>12</visitLocalHour>
 		<daysSinceLastVisit>0</daysSinceLastVisit>
@@ -761,7 +751,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -819,8 +809,6 @@
 		<regionCode>BC</regionCode>
 		<city>Vancouver</city>
 		<location>Vancouver, British Columbia, Canada</location>
-		<latitude>49.250000</latitude>
-		<longitude>-123.133003</longitude>
 		<visitLocalTime>12:34:06</visitLocalTime>
 		<visitLocalHour>12</visitLocalHour>
 		<daysSinceLastVisit>10</daysSinceLastVisit>
@@ -878,7 +866,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -936,8 +924,6 @@
 		<regionCode />
 		<city />
 		<location>Italy</location>
-		<latitude />
-		<longitude />
 		<visitLocalTime>12:34:06</visitLocalTime>
 		<visitLocalHour>12</visitLocalHour>
 		<daysSinceLastVisit>0</daysSinceLastVisit>
diff --git a/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByIdVisit__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByIdVisit__Live.getLastVisitsDetails_month.xml
index 6f86215248d94c969dd2179bd1659e3db5220fea..3b6d2c7b2d31b79d6c2360302a170fa88dfd4410 100644
--- a/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByIdVisit__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByIdVisit__Live.getLastVisitsDetails_month.xml
@@ -181,7 +181,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -306,7 +306,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -445,7 +445,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -570,7 +570,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -726,7 +726,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -851,7 +851,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
diff --git a/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByVisitCount__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByVisitCount__Live.getLastVisitsDetails_month.xml
index e9caa3ba66c5f44f180abeaa5c6191fa782efbfb..bf27da99957a429626d6ac7858e4431281973ffe 100644
--- a/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByVisitCount__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByVisitCount__Live.getLastVisitsDetails_month.xml
@@ -74,7 +74,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -199,7 +199,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -355,7 +355,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -494,7 +494,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -619,7 +619,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -744,7 +744,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
diff --git a/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortDesc__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortDesc__Live.getLastVisitsDetails_month.xml
index 6f86215248d94c969dd2179bd1659e3db5220fea..3b6d2c7b2d31b79d6c2360302a170fa88dfd4410 100644
--- a/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortDesc__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortDesc__Live.getLastVisitsDetails_month.xml
@@ -181,7 +181,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -306,7 +306,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -445,7 +445,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -570,7 +570,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -726,7 +726,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -851,7 +851,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
diff --git a/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest__Live.getLastVisitsDetails_month.xml
index fc8478d9b33eaf6f3d550206957adcdf1553776e..d4f1c0f44f39f98d8479cb1d38e88c9773eaba86 100644
--- a/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/Integration/expected/test_ManyVisitorsOneWebsiteTest__Live.getLastVisitsDetails_month.xml
@@ -181,7 +181,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -306,7 +306,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -445,7 +445,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -570,7 +570,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -726,7 +726,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -851,7 +851,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -990,7 +990,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -1115,7 +1115,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -1271,7 +1271,7 @@
 		
 		
 		
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
diff --git a/tests/PHPUnit/Integration/expected/test_OneVisitorTwoVisits_withCookieSupport__Live.getLastVisitsDetails_day.xml b/tests/PHPUnit/Integration/expected/test_OneVisitorTwoVisits_withCookieSupport__Live.getLastVisitsDetails_day.xml
index d8a06d259e0814b52889aa9d43306b265eab682f..dca93d3104e7d56189cec2595766e0889c666373 100644
--- a/tests/PHPUnit/Integration/expected/test_OneVisitorTwoVisits_withCookieSupport__Live.getLastVisitsDetails_day.xml
+++ b/tests/PHPUnit/Integration/expected/test_OneVisitorTwoVisits_withCookieSupport__Live.getLastVisitsDetails_day.xml
@@ -36,7 +36,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>returning</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -224,7 +224,7 @@
 		
 		<searches>1</searches>
 		<actions>8</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
diff --git a/tests/PHPUnit/Integration/expected/test_OneVisitor_NoKeywordSpecified__Live.getLastVisitsDetails_day.xml b/tests/PHPUnit/Integration/expected/test_OneVisitor_NoKeywordSpecified__Live.getLastVisitsDetails_day.xml
index d6cf0ea497ffcd121913da84dac7fed3c65d13ee..5fde4bea232fd8a3c48e5f22acdb9bee6856c664 100644
--- a/tests/PHPUnit/Integration/expected/test_OneVisitor_NoKeywordSpecified__Live.getLastVisitsDetails_day.xml
+++ b/tests/PHPUnit/Integration/expected/test_OneVisitor_NoKeywordSpecified__Live.getLastVisitsDetails_day.xml
@@ -4,7 +4,6 @@
 		<idSite>1</idSite>
 		<idVisit>2</idVisit>
 		<visitIp>156.5.0.0</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -24,6 +23,7 @@
 		
 		
 		
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -101,7 +101,6 @@
 		<idSite>1</idSite>
 		<idVisit>1</idVisit>
 		<visitIp>156.5.0.0</visitIp>
-		<userId />
 		
 		<actionDetails>
 			<row>
@@ -131,6 +130,7 @@
 		
 		
 		
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
diff --git a/tests/PHPUnit/Integration/expected/test_OneVisitor_SeveralDays_ImportedInRandomOrderTest_shouldShowOneVisit_InEachOfThreeDays__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/Integration/expected/test_OneVisitor_SeveralDays_ImportedInRandomOrderTest_shouldShowOneVisit_InEachOfThreeDays__Live.getLastVisitsDetails_month.xml
index d40e18c7d9cc56226a03594f1cda9be38cda998b..eda23c25e715259447a0806926f9629b749ad506 100644
--- a/tests/PHPUnit/Integration/expected/test_OneVisitor_SeveralDays_ImportedInRandomOrderTest_shouldShowOneVisit_InEachOfThreeDays__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/Integration/expected/test_OneVisitor_SeveralDays_ImportedInRandomOrderTest_shouldShowOneVisit_InEachOfThreeDays__Live.getLastVisitsDetails_month.xml
@@ -30,7 +30,7 @@
 		<lastActionDateTime>2013-04-07 10:00:00</lastActionDateTime>
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -123,7 +123,7 @@
 		<lastActionDateTime>2013-04-06 11:00:00</lastActionDateTime>
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -216,7 +216,7 @@
 		<lastActionDateTime>2013-04-05 12:00:00</lastActionDateTime>
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
diff --git a/tests/PHPUnit/Integration/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_CreatesCorrectPivotTable_WhenEntireHirearchyIsNotLoaded__Referrers.getKeywords_week.xml b/tests/PHPUnit/Integration/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_WhenEntireHirearchyIsNotLoaded__Referrers.getKeywords_week.xml
similarity index 100%
rename from tests/PHPUnit/Integration/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_CreatesCorrectPivotTable_WhenEntireHirearchyIsNotLoaded__Referrers.getKeywords_week.xml
rename to tests/PHPUnit/Integration/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_WhenEntireHirearchyIsNotLoaded__Referrers.getKeywords_week.xml
diff --git a/tests/PHPUnit/Integration/expected/test_TimezonesTest__Live.getLastVisitsDetails_day.xml b/tests/PHPUnit/Integration/expected/test_TimezonesTest__Live.getLastVisitsDetails_day.xml
index 35533fdac6f32afac9899091d394c1e037540f05..ea4cebdafe863eb811a673facc8bdec5fe0efcdf 100644
--- a/tests/PHPUnit/Integration/expected/test_TimezonesTest__Live.getLastVisitsDetails_day.xml
+++ b/tests/PHPUnit/Integration/expected/test_TimezonesTest__Live.getLastVisitsDetails_day.xml
@@ -25,7 +25,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
diff --git a/tests/PHPUnit/Integration/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_and_graph__ScheduledReports.generateReport_month.original.html b/tests/PHPUnit/Integration/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_and_graph__ScheduledReports.generateReport_month.original.html
index 25de6d905786d2015f960482b8a94b5a71f3e27e..8f057be5e7da938c9121f474278c50883555b371 100644
--- a/tests/PHPUnit/Integration/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_and_graph__ScheduledReports.generateReport_month.original.html
+++ b/tests/PHPUnit/Integration/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_and_graph__ScheduledReports.generateReport_month.original.html
@@ -143,6 +143,16 @@
                 <a href="#Actions_getDownloads" style="text-decoration:none; color: rgb(68,68,68);">
                     Downloads
                 </a>
+            </li>
+                    <li>
+                <a href="#Contents_getContentNames" style="text-decoration:none; color: rgb(68,68,68);">
+                    Content Name
+                </a>
+            </li>
+                    <li>
+                <a href="#Contents_getContentPieces" style="text-decoration:none; color: rgb(68,68,68);">
+                    Content Piece
+                </a>
             </li>
                     <li>
                 <a href="#Events_getCategory" style="text-decoration:none; color: rgb(68,68,68);">
@@ -438,7 +448,7 @@
                                                                 <td style="font-size: 11pt; border-bottom: 1px solid rgb(231,231,231); padding: 5px 0 5px 5px;">
                                                                                                                                                                         Users                                                                                                                        </td>
                                             <td style="font-size: 11pt; border-bottom: 1px solid rgb(231,231,231); padding: 5px 0 5px 5px;">
-                                                                                                1
+                                                                                                0
                                                                                     </td>
                                     </tr>
                             
@@ -3705,6 +3715,16 @@
     Downloads
 </h2>
 
+    There is no data for this report.
+<h2 id="Contents_getContentNames" style="color: rgb(126,115,99); font-size: 11pt;">
+    Content Name
+</h2>
+
+    There is no data for this report.
+<h2 id="Contents_getContentPieces" style="color: rgb(126,115,99); font-size: 11pt;">
+    Content Piece
+</h2>
+
     There is no data for this report.
 <h2 id="Events_getCategory" style="color: rgb(126,115,99); font-size: 11pt;">
     Event Categories
diff --git a/tests/PHPUnit/Integration/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_month.original.pdf b/tests/PHPUnit/Integration/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_month.original.pdf
index 5fecafa3697b33829a433ff4a7d32c4f65e76309..7891c7d5ca81b8bb7d192678110ae18739417f34 100644
Binary files a/tests/PHPUnit/Integration/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_month.original.pdf and b/tests/PHPUnit/Integration/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_month.original.pdf differ
diff --git a/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__Live.getLastVisitsDetails_month.xml
index 1946cec5ba97237a2f2ebab8a8b38cda03699933..cc28b360a0c13cc0967aad92997eb6f8f887179d 100644
--- a/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__Live.getLastVisitsDetails_month.xml
@@ -16,7 +16,7 @@
 		</actionDetails>
 		<lastActionDateTime>2010-03-06 11:22:33</lastActionDateTime>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 	</row>
 	<row>
 		<idVisit>2</idVisit>
@@ -45,19 +45,30 @@
 		</actionDetails>
 		<lastActionDateTime>2010-03-06 11:28:33</lastActionDateTime>
 		<actions>2</actions>
-		<userId>0</userId>
+		<userId />
 	</row>
 	<row>
 		<idVisit>3</idVisit>
 		<visitorId>9395988394d4568d</visitorId>
 		<actionDetails>
+			<row>
+				<type>action</type>
+				<url>http://example.org/no-user-id-set-but-should-appear-in-user-id-visit</url>
+				<pageTitle>no User Id set but it should appear in email@example.com!</pageTitle>
+				<pageIdAction>6</pageIdAction>
+				<serverTimePretty>Sat 6 Mar 13:16:33</serverTimePretty>
+				<pageId>4</pageId>
+				<timeSpent>360</timeSpent>
+				<timeSpentPretty>6 min 0s</timeSpentPretty>
+				<icon />
+			</row>
 			<row>
 				<type>action</type>
 				<url>http://example.org/index.htm</url>
 				<pageTitle>incredible title!</pageTitle>
 				<pageIdAction>2</pageIdAction>
 				<serverTimePretty>Sat 6 Mar 13:22:33</serverTimePretty>
-				<pageId>4</pageId>
+				<pageId>5</pageId>
 				<timeSpent>360</timeSpent>
 				<timeSpentPretty>6 min 0s</timeSpentPretty>
 				<icon />
@@ -68,12 +79,12 @@
 				<pageTitle>second page</pageTitle>
 				<pageIdAction>2</pageIdAction>
 				<serverTimePretty>Sat 6 Mar 13:28:33</serverTimePretty>
-				<pageId>5</pageId>
+				<pageId>6</pageId>
 				<icon />
 			</row>
 		</actionDetails>
 		<lastActionDateTime>2010-03-06 13:28:33</lastActionDateTime>
-		<actions>2</actions>
+		<actions>3</actions>
 		<userId>email@example.com</userId>
 	</row>
 	<row>
@@ -86,7 +97,7 @@
 				<pageTitle>a new user id was set -&gt; new visit</pageTitle>
 				<pageIdAction>2</pageIdAction>
 				<serverTimePretty>Sat 6 Mar 13:34:33</serverTimePretty>
-				<pageId>6</pageId>
+				<pageId>7</pageId>
 				<icon />
 			</row>
 		</actionDetails>
@@ -102,9 +113,9 @@
 				<type>action</type>
 				<url>http://example.org/home</url>
 				<pageTitle>same user id was set -&gt; this is the same unique user</pageTitle>
-				<pageIdAction>8</pageIdAction>
+				<pageIdAction>10</pageIdAction>
 				<serverTimePretty>Sat 6 Mar 16:22:33</serverTimePretty>
-				<pageId>7</pageId>
+				<pageId>8</pageId>
 				<timeSpent>360</timeSpent>
 				<timeSpentPretty>6 min 0s</timeSpentPretty>
 				<icon />
@@ -113,9 +124,9 @@
 				<type>action</type>
 				<url>http://example.org/home</url>
 				<pageTitle>second pageview - by this user id</pageTitle>
-				<pageIdAction>8</pageIdAction>
+				<pageIdAction>10</pageIdAction>
 				<serverTimePretty>Sat 6 Mar 16:28:33</serverTimePretty>
-				<pageId>8</pageId>
+				<pageId>9</pageId>
 				<icon />
 			</row>
 			<row>
@@ -157,15 +168,15 @@
 				<type>action</type>
 				<url>http://example.org/home</url>
 				<pageTitle>pageview - should not be tracked by our user id but in a new visit</pageTitle>
-				<pageIdAction>8</pageIdAction>
+				<pageIdAction>10</pageIdAction>
 				<serverTimePretty>Sat 6 Mar 16:28:33</serverTimePretty>
-				<pageId>9</pageId>
+				<pageId>10</pageId>
 				<icon />
 			</row>
 		</actionDetails>
 		<lastActionDateTime>2010-03-06 16:28:33</lastActionDateTime>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 	</row>
 	<row>
 		<idVisit>7</idVisit>
@@ -177,7 +188,7 @@
 				<pageTitle>Page view by email@example.com</pageTitle>
 				<pageIdAction>2</pageIdAction>
 				<serverTimePretty>Sun 14 Mar 11:22:33</serverTimePretty>
-				<pageId>10</pageId>
+				<pageId>11</pageId>
 				<icon />
 			</row>
 		</actionDetails>
@@ -195,7 +206,7 @@
 				<pageTitle>A page view by new-user-id@one-weeklater</pageTitle>
 				<pageIdAction>2</pageIdAction>
 				<serverTimePretty>Sun 14 Mar 11:46:33</serverTimePretty>
-				<pageId>11</pageId>
+				<pageId>12</pageId>
 				<icon />
 			</row>
 		</actionDetails>
diff --git a/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__VisitsSummary.get_day.xml b/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__VisitsSummary.get_day.xml
index 4a8baf7fc310decd23eb2dca0dcc88b35425d296..ca85e8dedebac3ef7da39382a1bcfe610b0f4632 100644
--- a/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__VisitsSummary.get_day.xml
+++ b/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__VisitsSummary.get_day.xml
@@ -3,12 +3,12 @@
 	<nb_uniq_visitors>5</nb_uniq_visitors>
 	<nb_users>2</nb_users>
 	<nb_visits>6</nb_visits>
-	<nb_actions>9</nb_actions>
+	<nb_actions>10</nb_actions>
 	<nb_visits_converted>1</nb_visits_converted>
 	<bounce_count>3</bounce_count>
-	<sum_visit_length>1623</sum_visit_length>
-	<max_actions>2</max_actions>
+	<sum_visit_length>1983</sum_visit_length>
+	<max_actions>3</max_actions>
 	<bounce_rate>50%</bounce_rate>
-	<nb_actions_per_visit>1.5</nb_actions_per_visit>
-	<avg_time_on_site>271</avg_time_on_site>
+	<nb_actions_per_visit>1.7</nb_actions_per_visit>
+	<avg_time_on_site>331</avg_time_on_site>
 </result>
\ No newline at end of file
diff --git a/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__VisitsSummary.get_month.xml b/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__VisitsSummary.get_month.xml
index 94ed6f59e05e0e08fff104dc8d2249d7c3df486e..7731535795426ac8e138dca89a94bbb58d26249b 100644
--- a/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__VisitsSummary.get_month.xml
+++ b/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__VisitsSummary.get_month.xml
@@ -3,12 +3,12 @@
 	<nb_uniq_visitors>6</nb_uniq_visitors>
 	<nb_users>3</nb_users>
 	<nb_visits>8</nb_visits>
-	<nb_actions>11</nb_actions>
+	<nb_actions>12</nb_actions>
 	<nb_visits_converted>1</nb_visits_converted>
 	<bounce_count>5</bounce_count>
-	<sum_visit_length>1623</sum_visit_length>
-	<max_actions>2</max_actions>
+	<sum_visit_length>1983</sum_visit_length>
+	<max_actions>3</max_actions>
 	<bounce_rate>63%</bounce_rate>
-	<nb_actions_per_visit>1.4</nb_actions_per_visit>
-	<avg_time_on_site>203</avg_time_on_site>
+	<nb_actions_per_visit>1.5</nb_actions_per_visit>
+	<avg_time_on_site>248</avg_time_on_site>
 </result>
\ No newline at end of file
diff --git a/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__VisitsSummary.get_week.xml b/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__VisitsSummary.get_week.xml
index 4a8baf7fc310decd23eb2dca0dcc88b35425d296..ca85e8dedebac3ef7da39382a1bcfe610b0f4632 100644
--- a/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__VisitsSummary.get_week.xml
+++ b/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__VisitsSummary.get_week.xml
@@ -3,12 +3,12 @@
 	<nb_uniq_visitors>5</nb_uniq_visitors>
 	<nb_users>2</nb_users>
 	<nb_visits>6</nb_visits>
-	<nb_actions>9</nb_actions>
+	<nb_actions>10</nb_actions>
 	<nb_visits_converted>1</nb_visits_converted>
 	<bounce_count>3</bounce_count>
-	<sum_visit_length>1623</sum_visit_length>
-	<max_actions>2</max_actions>
+	<sum_visit_length>1983</sum_visit_length>
+	<max_actions>3</max_actions>
 	<bounce_rate>50%</bounce_rate>
-	<nb_actions_per_visit>1.5</nb_actions_per_visit>
-	<avg_time_on_site>271</avg_time_on_site>
+	<nb_actions_per_visit>1.7</nb_actions_per_visit>
+	<avg_time_on_site>331</avg_time_on_site>
 </result>
\ No newline at end of file
diff --git a/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__VisitsSummary.get_year.xml b/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__VisitsSummary.get_year.xml
index 107fa6ae8aef2b799212ce9bb7caed9d7197bbbb..84850ee827e073c38ac01eb3d231498aaf72d41d 100644
--- a/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__VisitsSummary.get_year.xml
+++ b/tests/PHPUnit/Integration/expected/test_UserId_VisitorId__VisitsSummary.get_year.xml
@@ -1,12 +1,12 @@
 <?xml version="1.0" encoding="utf-8" ?>
 <result>
 	<nb_visits>8</nb_visits>
-	<nb_actions>11</nb_actions>
+	<nb_actions>12</nb_actions>
 	<nb_visits_converted>1</nb_visits_converted>
 	<bounce_count>5</bounce_count>
-	<sum_visit_length>1623</sum_visit_length>
-	<max_actions>2</max_actions>
+	<sum_visit_length>1983</sum_visit_length>
+	<max_actions>3</max_actions>
 	<bounce_rate>63%</bounce_rate>
-	<nb_actions_per_visit>1.4</nb_actions_per_visit>
-	<avg_time_on_site>203</avg_time_on_site>
+	<nb_actions_per_visit>1.5</nb_actions_per_visit>
+	<avg_time_on_site>248</avg_time_on_site>
 </result>
\ No newline at end of file
diff --git a/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems_LiveEcommerceStatusOrdered__Live.getLastVisitsDetails_day.xml b/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems_LiveEcommerceStatusOrdered__Live.getLastVisitsDetails_day.xml
index df83d3ad4d9f64f8856f2b70c34e0cfc11eb5a48..f45437858dcc1b545ca283bbc269965cbb204e6f 100644
--- a/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems_LiveEcommerceStatusOrdered__Live.getLastVisitsDetails_day.xml
+++ b/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems_LiveEcommerceStatusOrdered__Live.getLastVisitsDetails_day.xml
@@ -51,7 +51,7 @@
 		
 		<searches>0</searches>
 		<actions>0</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -262,7 +262,7 @@
 		
 		<searches>0</searches>
 		<actions>3</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
diff --git a/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems__Live.getLastVisitsDetails_day.xml b/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems__Live.getLastVisitsDetails_day.xml
index db2945b307cac91708f4c406139823c874bc8167..37e6dd50a1dc4c482d4920c39969ff0520705055 100644
--- a/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems__Live.getLastVisitsDetails_day.xml
+++ b/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems__Live.getLastVisitsDetails_day.xml
@@ -127,7 +127,7 @@
 		
 		<searches>0</searches>
 		<actions>3</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>returningCustomer</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>0</visitConverted>
@@ -457,7 +457,7 @@
 		
 		<searches>0</searches>
 		<actions>6</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>returning</visitorType>
 		<visitorTypeIcon>plugins/Live/images/returningVisitor.gif</visitorTypeIcon>
 		<visitConverted>1</visitConverted>
@@ -677,7 +677,7 @@
 		
 		<searches>0</searches>
 		<actions>4</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
diff --git a/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems_scheduled_report_in_html_tables_and_graph__ScheduledReports.generateReport_week.original.html b/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems_scheduled_report_in_html_tables_and_graph__ScheduledReports.generateReport_week.original.html
index b92f3087c5eea105509c70343ad844eda82392f1..401a3a99bbf6c5f07a6e1332732cb89f59792b54 100644
--- a/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems_scheduled_report_in_html_tables_and_graph__ScheduledReports.generateReport_week.original.html
+++ b/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems_scheduled_report_in_html_tables_and_graph__ScheduledReports.generateReport_week.original.html
@@ -188,6 +188,16 @@
                 <a href="#Actions_getDownloads" style="text-decoration:none; color: rgb(68,68,68);">
                     Downloads
                 </a>
+            </li>
+                    <li>
+                <a href="#Contents_getContentNames" style="text-decoration:none; color: rgb(68,68,68);">
+                    Content Name
+                </a>
+            </li>
+                    <li>
+                <a href="#Contents_getContentPieces" style="text-decoration:none; color: rgb(68,68,68);">
+                    Content Piece
+                </a>
             </li>
                     <li>
                 <a href="#Events_getCategory" style="text-decoration:none; color: rgb(68,68,68);">
@@ -498,7 +508,7 @@
                                                                 <td style="font-size: 11pt; border-bottom: 1px solid rgb(231,231,231); padding: 5px 0 5px 5px;">
                                                                                                                                                                         Users                                                                                                                        </td>
                                             <td style="font-size: 11pt; border-bottom: 1px solid rgb(231,231,231); padding: 5px 0 5px 5px;">
-                                                                                                1
+                                                                                                0
                                                                                     </td>
                                     </tr>
                             
@@ -4806,6 +4816,16 @@
     Downloads
 </h2>
 
+    There is no data for this report.
+<h2 id="Contents_getContentNames" style="color: rgb(126,115,99); font-size: 11pt;">
+    Content Name
+</h2>
+
+    There is no data for this report.
+<h2 id="Contents_getContentPieces" style="color: rgb(126,115,99); font-size: 11pt;">
+    Content Piece
+</h2>
+
     There is no data for this report.
 <h2 id="Events_getCategory" style="color: rgb(126,115,99); font-size: 11pt;">
     Event Categories
diff --git a/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_week.original.pdf b/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_week.original.pdf
index 0bb4a30c1767307a2a0b817f1882bc9395092609..e8e37848fd2f107a6b9e3ad041a811634a3f2642 100644
Binary files a/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_week.original.pdf and b/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_week.original.pdf differ
diff --git a/tests/PHPUnit/Integration/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__Live.getLastVisitsDetails_range.xml b/tests/PHPUnit/Integration/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__Live.getLastVisitsDetails_range.xml
index b5052f4f745d49c04e6f615880101afb597f371b..38191d26d91a0103f76d4d0270cf945b010b07a3 100644
--- a/tests/PHPUnit/Integration/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__Live.getLastVisitsDetails_range.xml
+++ b/tests/PHPUnit/Integration/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__Live.getLastVisitsDetails_range.xml
@@ -25,7 +25,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>0</visitConverted>
@@ -140,7 +140,7 @@
 		
 		<searches>0</searches>
 		<actions>1</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
@@ -311,7 +311,7 @@
 		
 		<searches>0</searches>
 		<actions>3</actions>
-		<userId>0</userId>
+		<userId />
 		<visitorType>new</visitorType>
 		<visitorTypeIcon />
 		<visitConverted>1</visitConverted>
diff --git a/tests/PHPUnit/Integration/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__Live.getVisitorProfile.xml b/tests/PHPUnit/Integration/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__Live.getVisitorProfile.xml
index 0725631cd965055be6e6e210ea7a03b3ff5ef687..ff0e385988a3541085cc5e831467eb5aea8424ba 100644
--- a/tests/PHPUnit/Integration/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__Live.getVisitorProfile.xml
+++ b/tests/PHPUnit/Integration/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__Live.getVisitorProfile.xml
@@ -68,7 +68,7 @@
 			
 			<searches>0</searches>
 			<actions>1</actions>
-			<userId>0</userId>
+			<userId />
 			<visitorType>new</visitorType>
 			<visitorTypeIcon />
 			<visitConverted>0</visitConverted>
@@ -184,7 +184,7 @@
 			
 			<searches>0</searches>
 			<actions>1</actions>
-			<userId>0</userId>
+			<userId />
 			<visitorType>new</visitorType>
 			<visitorTypeIcon />
 			<visitConverted>1</visitConverted>
diff --git a/tests/PHPUnit/IntegrationTestCase.php b/tests/PHPUnit/IntegrationTestCase.php
index ae8a674ed2e636d47ed754a1dbfa94639612cbaf..d5d78128a4552d64a401f45533c00e87f4bc11fd 100755
--- a/tests/PHPUnit/IntegrationTestCase.php
+++ b/tests/PHPUnit/IntegrationTestCase.php
@@ -414,10 +414,6 @@ abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase
     {
         $testConfig = new ApiTestConfig($params);
 
-        // make sure that the reports we process here are not directly deleted in ArchiveProcessor/PluginsArchiver
-        // (because we process reports in the past, they would sometimes be invalid, and would have been deleted)
-        \Piwik\ArchiveProcessor\Rules::disablePurgeOutdatedArchives();
-
         $testName = 'test_' . static::getOutputPrefix();
         $this->missingExpectedFiles = array();
         $this->comparisonFailures = array();
@@ -440,9 +436,6 @@ abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase
             $this->_testApiUrl($testName . $testConfig->testSuffix, $apiId, $requestUrl, $testConfig->compareAgainst, $testConfig->xmlFieldsToRemove, $params);
         }
 
-        // Restore normal purge behavior
-        \Piwik\ArchiveProcessor\Rules::enablePurgeOutdatedArchives();
-
         // change the language back to en
         if ($this->lastLanguage != 'en') {
             $this->changeLanguage('en');
@@ -525,7 +518,6 @@ abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase
      */
     protected static function restoreDbTables($tables)
     {
-        // truncate existing tables
         DbHelper::truncateAllTables();
 
         // insert data
diff --git a/tests/PHPUnit/TestingEnvironment.php b/tests/PHPUnit/TestingEnvironment.php
index ba15855f61cbaf794d00ed13bd63285633007a72..0c5ddbc69e2fcb317e00478482438963f8d9520c 100644
--- a/tests/PHPUnit/TestingEnvironment.php
+++ b/tests/PHPUnit/TestingEnvironment.php
@@ -88,7 +88,7 @@ class Piwik_TestingEnvironment
             if (isset($_SERVER['QUERY_STRING'])
                 && !$this->dontUseTestConfig
             ) {
-                \Piwik\Log::verbose("Test Environment Variables for (%s):\n%s", $_SERVER['QUERY_STRING'], print_r($this->behaviorOverrideProperties, true));
+                @\Piwik\Log::verbose("Test Environment Variables for (%s):\n%s", $_SERVER['QUERY_STRING'], print_r($this->behaviorOverrideProperties, true));
             }
         } catch (Exception $ex) {
             // ignore
diff --git a/tests/PHPUnit/UI b/tests/PHPUnit/UI
index d67cb0957de65891ab2e5b6fe12e04cdd35e1bfd..d98325f48a495a6d5d71cb1ffed231f6834f30bb 160000
--- a/tests/PHPUnit/UI
+++ b/tests/PHPUnit/UI
@@ -1 +1 @@
-Subproject commit d67cb0957de65891ab2e5b6fe12e04cdd35e1bfd
+Subproject commit d98325f48a495a6d5d71cb1ffed231f6834f30bb
diff --git a/tests/PHPUnit/bootstrap.php b/tests/PHPUnit/bootstrap.php
index dc16386563641a42d73c8d9a8101a5317298c05c..2fd701a0e87e9728e0bed7abf37f76788ad6dba3 100644
--- a/tests/PHPUnit/bootstrap.php
+++ b/tests/PHPUnit/bootstrap.php
@@ -34,8 +34,9 @@ require_once file_exists(PIWIK_INCLUDE_PATH . '/vendor/autoload.php')
 require_once PIWIK_INCLUDE_PATH . '/libs/upgradephp/upgrade.php';
 require_once PIWIK_INCLUDE_PATH . '/core/testMinimumPhpVersion.php';
 require_once PIWIK_INCLUDE_PATH . '/core/FrontController.php';
-require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/DatabaseTestCase.php';
+require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/Fixture.php';
 require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/IntegrationTestCase.php';
+require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/DatabaseTestCase.php';
 require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/ConsoleCommandTestCase.php';
 require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/FakeAccess.php';
 require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/MockPiwikOption.php';
@@ -49,8 +50,6 @@ if (getenv('PIWIK_USE_XHPROF') == 1) {
 }
 
 // require test fixtures
-require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/Fixture.php';
-
 $fixturesToLoad = array(
     '/tests/PHPUnit/Fixtures/*.php',
     '/tests/PHPUnit/UI/Fixtures/*.php',
diff --git a/tests/PHPUnit/proxy/includes.php b/tests/PHPUnit/proxy/includes.php
index 858ae485d20ae74fdca4e65dca9ad2581804fa85..b813fd21ad0575de52b4dec5631bd4c3e99d4c1b 100644
--- a/tests/PHPUnit/proxy/includes.php
+++ b/tests/PHPUnit/proxy/includes.php
@@ -28,7 +28,3 @@ require_once $vendorDirectory . '/piwik/device-detector/DeviceDetector.php';
 
 \Piwik\SettingsServer::setMaxExecutionTime(0);
 
-// Make sure Data processed in cron core:archive command is not being purged instantly (useful for: Integration/ArchiveCronTest)
-if(\Piwik\SettingsServer::isArchivePhpTriggered()) {
-    \Piwik\ArchiveProcessor\Rules::disablePurgeOutdatedArchives();
-}
\ No newline at end of file
diff --git a/tests/resources/staticFileServer.php b/tests/resources/staticFileServer.php
index 5907c169e3e61f188a17f4bf0a432a51895d4b19..6ad277863e3bca23b28c966d5be743eba8d3c994 100644
--- a/tests/resources/staticFileServer.php
+++ b/tests/resources/staticFileServer.php
@@ -15,7 +15,7 @@ use Piwik\ProxyHttp;
 define('PIWIK_DOCUMENT_ROOT', dirname(__FILE__).'/../../');
 if(file_exists(PIWIK_DOCUMENT_ROOT . '/bootstrap.php'))
 {
-	require_once PIWIK_DOCUMENT_ROOT . '/bootstrap.php';
+    require_once PIWIK_DOCUMENT_ROOT . '/bootstrap.php';
 }
 
 error_reporting(E_ALL|E_NOTICE);
@@ -25,11 +25,11 @@ error_reporting(E_ALL|E_NOTICE);
 
 if(!defined('PIWIK_USER_PATH'))
 {
-	define('PIWIK_USER_PATH', PIWIK_DOCUMENT_ROOT);
+    define('PIWIK_USER_PATH', PIWIK_DOCUMENT_ROOT);
 }
 if(!defined('PIWIK_INCLUDE_PATH'))
 {
-	define('PIWIK_INCLUDE_PATH', PIWIK_DOCUMENT_ROOT);
+    define('PIWIK_INCLUDE_PATH', PIWIK_DOCUMENT_ROOT);
 }
 
 require_once PIWIK_INCLUDE_PATH . '/libs/upgradephp/upgrade.php';