diff --git a/.travis.yml b/.travis.yml
index 5a28f29340a49b10579e8234725664ce74692e1c..0ade48a0fe60c7945dc67787859ede5bcd91ea5d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,9 +12,10 @@ env:
     - TEST_SUITE=PluginTests
     - TEST_SUITE=CoreTests
     - TEST_SUITE=IntegrationTests
+    #- TEST_DIR=UI
   global:
     secure: "AMhZmPZx4SUcuZRBzGHlQPxzM4D8FvFB3UThDa52gbi9KIBrwcumzV2VGi6B\n5fgjwtB4XTE1In7qhY2HMikPWBmWYYOQ5QcMPJsqqHt4iMmahx8WKzne6NOk\nNpqAuje/fulNGeP2LJZi0nrub3Fh4VwXaOvpNloKNQN/2JuqPtM="
-  
+
 # Run PHP 5.4 for aa tests to generate
 # code coverage.
 
diff --git a/core/AssetManager.php b/core/AssetManager.php
index 086f538a3f5933898fbf24b883b89b67f7301d9d..541157dc2f3decbe62680cacbe92fb3f413abdd5 100644
--- a/core/AssetManager.php
+++ b/core/AssetManager.php
@@ -284,6 +284,7 @@ class AssetManager
             'plugins/Zeitgeist/stylesheets/',
             'plugins/',
             'plugins/Dashboard/stylesheets/dashboard.less',
+            'tests/',
         );
 
         return self::prioritySort($priorityCssOrdered, $cssFiles);
@@ -380,6 +381,7 @@ class AssetManager
             'plugins/Zeitgeist/javascripts/',
             'plugins/CoreHome/javascripts/broadcast.js',
             'plugins/',
+            'tests/',
         );
 
         return self::prioritySort($priorityJsOrdered, $jsFiles);
diff --git a/core/DataTable/Filter/Limit.php b/core/DataTable/Filter/Limit.php
index 5d751ddbc47532a16481fb165d747828a59a8c7d..e040244a0be7b9db6de6f60208ad0d15a2507476 100644
--- a/core/DataTable/Filter/Limit.php
+++ b/core/DataTable/Filter/Limit.php
@@ -29,14 +29,11 @@ class Limit extends Filter
      * @param int $limit           Number of rows to keep (specify -1 to keep all rows)
      * @param bool $keepSummaryRow  Whether to keep the summary row or not.
      */
-    public function __construct($table, $offset, $limit = null, $keepSummaryRow = false)
+    public function __construct($table, $offset, $limit = -1, $keepSummaryRow = false)
     {
         parent::__construct($table);
         $this->offset = $offset;
 
-        if (is_null($limit)) {
-            $limit = -1;
-        }
         $this->limit = $limit;
         $this->keepSummaryRow = $keepSummaryRow;
     }
diff --git a/core/ViewDataTable.php b/core/ViewDataTable.php
index a07f79054290453b2407011c32f9041111caca9d..533cef4bb2dedce2b34f8e3c800822c778801bb8 100644
--- a/core/ViewDataTable.php
+++ b/core/ViewDataTable.php
@@ -318,9 +318,6 @@ class ViewDataTable
             'filter_excludelowpop_value',
             'filter_pattern',
             'filter_column',
-            'filter_limit',
-            'filter_sort_column',
-            'filter_sort_order',
         );
 
         if ($this->visualizationClass) {
@@ -706,7 +703,13 @@ class ViewDataTable
             $requestArray['expanded'] = 1;
         }
 
-        $requestArray = array_merge($requestArray, $this->viewProperties['request_parameters_to_modify']);
+        $requestArray = array_merge($requestArray, $this->request_parameters_to_modify);
+
+        if (!empty($requestArray['filter_limit'])
+            && $requestArray['filter_limit'] === 0
+        ) {
+            unset($requestArray['filter_limit']);
+        }
 
         return $requestArray;
     }
@@ -1060,10 +1063,6 @@ class ViewDataTable
         if (!PluginsManager::getInstance()->isPluginActivated('Goals')) {
             $this->viewProperties['show_goals'] = false;
         }
-
-        if ($this->viewProperties['filter_limit'] == 0) {
-            $this->viewProperties['filter_limit'] = false;
-        }
     }
 
     protected function buildView()
@@ -1105,12 +1104,132 @@ class ViewDataTable
         $view->javascriptVariablesToSet = $this->getJavascriptVariablesToSet();
         $view->clientSidePropertiesToSet = $this->getClientSidePropertiesToSet();
         $view->properties = $this->viewProperties; // TODO: should be $this. need to move non-view properties from the class
+        $view->footerIcons = $this->getFooterIconsToShow();
 
-        $nonCoreVisualizations = DataTableVisualization::getNonCoreVisualizations();
-        $view->nonCoreVisualizations = DataTableVisualization::getVisualizationInfoFor($nonCoreVisualizations);
         $this->view = $view;
     }
 
+    private function getFooterIconsToShow()
+    {
+        $result = array();
+
+        // add normal view icons (eg, normal table, all columns, goals)
+        $normalViewIcons = array(
+            'class' => 'tableAllColumnsSwitch',
+            'buttons' => array(),
+        );
+
+        if ($this->show_table) {
+            $normalViewIcons['buttons'][] = array(
+                'format' => 'table',
+                'var' => 'table',
+                'title' => Piwik_Translate('General_DisplaySimpleTable'),
+                'icon' => 'plugins/Zeitgeist/images/table.png',
+            );
+        }
+
+        if ($this->show_table_all_columns) {
+            $normalViewIcons['buttons'][] = array(
+                'format' => 'tableAllColumns',
+                'var' => 'tableAllColumns',
+                'title' => Piwik_Translate('General_DisplayTableWithMoreMetrics'),
+                'icon' => 'plugins/Zeitgeist/images/table_more.png'
+            );
+        }
+
+        if ($this->show_goals) {
+            if (Common::getRequestVar('idGoal', false) == 'ecommerceOrder') {
+                $icon = 'plugins/Zeitgeist/images/ecommerceOrder.gif';
+            } else {
+                $icon = 'plugins/Zeitgeist/images/goal.png';
+            }
+            
+            $normalViewIcons['buttons'][] = array(
+                'format' => 'tableGoals',
+                'var' => 'tableGoals',
+                'title' => Piwik_Translate('General_DisplayTableWithGoalMetrics'),
+                'icon' => $icon
+            );
+        }
+
+        if ($this->show_ecommerce) {
+            $normalViewIcons['buttons'][] = array(
+                'format' => 'ecommerceOrder',
+                'var' => 'ecommerceOrder',
+                'title' => Piwik_Translate('General_EcommerceOrders'),
+                'icon' => 'plugins/Zeitgeist/images/ecommerceOrder.gif',
+                'text' => Piwik_Translate('General_EcommerceOrders')
+            );
+
+            $normalViewIcons['buttons'][] = array(
+                'format' => 'ecommerceAbandonedCart',
+                'var' => 'ecommerceAbandonedCart',
+                'title' => Piwik_Translate('General_AbandonedCarts'),
+                'icon' => 'plugins/Zeitgeist/images/ecommerceAbandonedCart.gif',
+                'text' => Piwik_Translate('General_AbandonedCarts')
+            );
+        }
+
+        if (!empty($normalViewIcons['buttons'])) {
+            $result[] = $normalViewIcons;
+        }
+
+        // add graph views
+        $graphViewIcons = array(
+            'class' => 'tableGraphViews tableGraphCollapsed',
+            'buttons' => array(),
+        );
+
+        if ($this->show_all_views_icons) {
+            if ($this->show_bar_chart) {
+                $graphViewIcons['buttons'][] = array(
+                    'format' => 'graphVerticalBar',
+                    'var' => 'graphVerticalBar', // TODO: is var actually used anywhere?
+                    'title' => Piwik_Translate('General_VBarGraph'),
+                    'icon' => 'plugins/Zeitgeist/images/chart_bar.png'
+                );
+            }
+
+            if ($this->show_pie_chart) {
+                $graphViewIcons['buttons'][] = array(
+                    'format' => 'graphPie',
+                    'var' => 'graphPie',
+                    'title' => Piwik_Translate('General_Piechart'),
+                    'icon' => 'plugins/Zeitgeist/images/chart_pie.png'
+                );
+            }
+
+            if ($this->show_tag_cloud) {
+                $graphViewIcons['buttons'][] = array(
+                    'format' => 'cloud',
+                    'var' => 'cloud',
+                    'title' => Piwik_Translate('General_TagCloud'),
+                    'icon' => 'plugins/Zeitgeist/images/tagcloud.png'
+                );
+            }
+
+            if ($this->show_non_core_visualizations) {
+                $nonCoreVisualizations = DataTableVisualization::getNonCoreVisualizations();
+                $nonCoreVisualizationInfo = DataTableVisualization::getVisualizationInfoFor($nonCoreVisualizations);
+
+                foreach ($nonCoreVisualizationInfo as $format => $info) {
+                    $graphViewIcons['buttons'][] = array(
+                        'format' => $format,
+                        'var' => $format,
+                        'title' => Piwik_Translate($info['title']),
+                        'icon' => $info['icon']
+                    );
+                }
+            }
+        }
+
+        if (!empty($graphViewIcons['buttons'])) {
+            $result[] = $graphViewIcons;
+        }
+
+        return $result;
+    }
+
     public function getDefaultDataTableCssClass()
     {
         return 'dataTableViz' . Piwik::getUnnamespacedClassName($this->visualizationClass);
@@ -1141,4 +1260,4 @@ class ViewDataTable
     {
         return is_bool($value) ? (int)$value : $value;
     }
-}
+}
\ No newline at end of file
diff --git a/core/Visualization/Graph.php b/core/Visualization/Graph.php
index 45f328bed45f6d8c55a829b60fd881140bd2aa5b..efd9d27a3409d1d4374838a4506b0b0d71e876d5 100644
--- a/core/Visualization/Graph.php
+++ b/core/Visualization/Graph.php
@@ -79,6 +79,13 @@ abstract class Graph extends DataTableVisualization
             $view->translations['nb_conversions'] = Piwik_Translate('Goals_ColumnConversions');
             $view->translations['revenue'] = Piwik_Translate('General_TotalRevenue');
         }
+
+        $view->request_parameters_to_modify['filter_limit'] = false;
+        $view->request_parameters_to_modify['filter_offset'] = false;
+
+        if ($view->visualization_properties->max_graph_elements) {
+            $view->request_parameters_to_modify['filter_truncate'] = $view->visualization_properties->max_graph_elements - 1;
+        }
     }
 
     public static function getDefaultPropertyValues()
diff --git a/plugins/Annotations/stylesheets/annotations.less b/plugins/Annotations/stylesheets/annotations.less
index 6de537dc9d1dd8d988d46cd1209b79e677fcf4d0..3a01ca398d60ae093ff04588298a1acd90337387 100755
--- a/plugins/Annotations/stylesheets/annotations.less
+++ b/plugins/Annotations/stylesheets/annotations.less
@@ -9,6 +9,7 @@
 
 .evolution-annotations > span {
     position: absolute;
+    top:10px;
 }
 
 .annotation-manager {
diff --git a/plugins/CoreHome/javascripts/broadcast.js b/plugins/CoreHome/javascripts/broadcast.js
index 7b0a3bfe240be23dc7a6c2b8ac74c8022a66c89d..761404efbd3a15df8e9ff394341ad69c6b0423d4 100644
--- a/plugins/CoreHome/javascripts/broadcast.js
+++ b/plugins/CoreHome/javascripts/broadcast.js
@@ -394,16 +394,13 @@ var broadcast = {
             }
         }
 
-        var ajaxRequest = {
-            type: 'POST',
-            url: urlAjax,
-            dataType: 'html',
-            async: true,
-            error: broadcast.customAjaxHandleError,	// Callback when the request fails
-            success: sectionLoaded, // Callback when the request succeeds
-            data: {}
-        };
-        globalAjaxQueue.push($.ajax(ajaxRequest));
+        var ajax = new ajaxHelper();
+        ajax.setUrl(urlAjax);
+        ajax.setErrorCallback(broadcast.customAjaxHandleError);
+        ajax.setCallback(sectionLoaded);
+        ajax.setFormat('html');
+        ajax.send();
+
         return false;
     },
 
diff --git a/plugins/CoreHome/javascripts/dataTable.js b/plugins/CoreHome/javascripts/dataTable.js
index 05fa11b55bef18a6973ba92806b966d1cd36bc6c..6831a6a215d61c1a1cec9ca26fdf2c94f55138d0 100644
--- a/plugins/CoreHome/javascripts/dataTable.js
+++ b/plugins/CoreHome/javascripts/dataTable.js
@@ -714,8 +714,6 @@ dataTable.prototype =
                 // we only reset the limit filter, in case switch to table view from cloud view where limit is custom set to 30
                 // this value is stored in config file General->datatable_default_limit but this is more an edge case so ok to set it to 10
 
-                self.setActiveIcon(this, domElem);
-
                 var viewDataTable = $(this).attr('format');
                 self.param.viewDataTable = viewDataTable;
 
@@ -735,7 +733,6 @@ dataTable.prototype =
         $('.tableGraphViews a', domElem)
             .click(function () {
                 var viewDataTable = $(this).attr('format');
-                self.setActiveIcon(this, domElem);
 
                 var filters = self.resetAllFilters();
                 self.param.flat = filters.flat;
@@ -778,8 +775,7 @@ dataTable.prototype =
                         $(this).show('fast', function () {self.graphViewStartingThreads--});
                     }
                     else if (self.graphViewEnabled) {
-                        //set footer arrow position
-                        $('.dataTableFooterActiveItem', domElem).animate({left: $(this).parent().position().left + i * (this.offsetWidth + 1)}, "fast", function () {self.graphViewStartingThreads--});
+                        self.graphViewStartingThreads--;
                     }
                 });
                 self.exportToFormatHide(domElem);
@@ -792,10 +788,6 @@ dataTable.prototype =
                         //hide other icons
                         $(this).hide('fast');
                     }
-                    else if (self.graphViewEnabled) {
-                        //set footer arrow position
-                        $('.dataTableFooterActiveItem', domElem).animate({left: $(this).parent().position().left}, "fast");
-                    }
                 });
                 $(this).removeClass('tableIconsGroupActive');
             }
@@ -805,7 +797,7 @@ dataTable.prototype =
         self.exportToFormat = null;
         $('.exportToFormatIcons a', domElem).click(function () {
             self.exportToFormat = {};
-            self.exportToFormat.lastActiveIcon = self.setActiveIcon(this, domElem);
+            self.exportToFormat.lastActiveIcon = this;
             self.exportToFormat.target = $(this).parent().siblings('.exportToFormatItems').show('fast');
             self.exportToFormat.obj = $(this).hide();
         });
@@ -892,12 +884,6 @@ dataTable.prototype =
                 return str;
             }
         );
-
-        // Initialize arrow footer to correct icon
-        $('.dataTableFooterWrap a.tableIcon', domElem).each(function () {
-            if (self.jsViewDataTable == $(this).attr('var')) self.setActiveIcon(this, domElem);
-        });
-
     },
 
     exportToFormatHide: function (domElem, noAnimation) {
@@ -1060,30 +1046,6 @@ dataTable.prototype =
         }
     },
 
-    //footer arrow position handler
-    setActiveIcon: function (obj, domElem) {
-        if (!obj) return false;
-
-        var lastActiveIcon = this.lastActiveIcon;
-
-        if (lastActiveIcon) {
-            $(lastActiveIcon).removeClass("activeIcon");
-        }
-
-        $(obj).addClass("activeIcon");
-        this.lastActiveIcon = obj;
-
-        var target = $('.dataTableFooterActiveItem', domElem);
-
-        //set arrow position with delay (for ajax widget loading)
-        setTimeout(function () {
-            target.css({left: $(obj).position().left});
-        }, 100);
-
-        return lastActiveIcon;
-
-    },
-
     // Tell parent widget that the parameters of this table was updated,
     notifyWidgetParametersChange: function (domWidget, parameters) {
         var widget = $(domWidget).parents('[widgetId]');
@@ -1603,7 +1565,6 @@ actionDataTable.prototype =
     onClickSort: dataTable.prototype.onClickSort,
     truncate: dataTable.prototype.truncate,
     handleOffsetInformation: dataTable.prototype.handleOffsetInformation,
-    setActiveIcon: dataTable.prototype.setActiveIcon,
     resetAllFilters: dataTable.prototype.resetAllFilters,
     restoreAllFilters: dataTable.prototype.restoreAllFilters,
     exportToFormatHide: dataTable.prototype.exportToFormatHide,
diff --git a/plugins/CoreHome/stylesheets/coreHome.less b/plugins/CoreHome/stylesheets/coreHome.less
index 2c82ad95b4f7a91c9bc3e0e275f4cf1326a1fa8b..71a130f9996a7baaada5a83e5befbcab0a801112 100644
--- a/plugins/CoreHome/stylesheets/coreHome.less
+++ b/plugins/CoreHome/stylesheets/coreHome.less
@@ -40,7 +40,6 @@ h3 {
 .pageWrap {
   border-left: 1px solid #DDDDDD;
   border-right: 1px solid #DDDDDD;
-  max-height: 681px;
   min-height: 10px;
   overflow: visible;
   padding: 15px 15px 0;
diff --git a/plugins/CoreHome/stylesheets/dataTable/_dataTable.less b/plugins/CoreHome/stylesheets/dataTable/_dataTable.less
index 6083dd1ccaf8d13a163b2b6546391ba36393e50a..4b2cd407d0ff6b4e156b2cbf871b9cb1d26fc72d 100644
--- a/plugins/CoreHome/stylesheets/dataTable/_dataTable.less
+++ b/plugins/CoreHome/stylesheets/dataTable/_dataTable.less
@@ -286,6 +286,11 @@ table.dataTable img {
   background: #e9e8e1;
 }
 
+.tableIconsGroup > span > span {
+    position:relative;
+    float:left;
+}
+
 .dataTableFooterActiveItem {
   position: absolute;
   top: -6px;
diff --git a/plugins/CoreHome/templates/_dataTableFooter.twig b/plugins/CoreHome/templates/_dataTableFooter.twig
index 3a800944c99a5c9c5682274777cab3757afd7463..1655c5d18e35bbb84029552121e7c597bf97bf41 100644
--- a/plugins/CoreHome/templates/_dataTableFooter.twig
+++ b/plugins/CoreHome/templates/_dataTableFooter.twig
@@ -26,68 +26,27 @@
     {% if properties.show_footer_icons %}
         <div class="dataTableFooterIcons">
             <div class="dataTableFooterWrap" var="{{ javascriptVariablesToSet.viewDataTable }}">
-                {% if properties.show_active_view_icon %}
-                    <img src="plugins/Zeitgeist/images/data_table_footer_active_item.png" class="dataTableFooterActiveItem"/>
-                {% endif %}
+                {% for footerIconGroup in footerIcons %}
                 <div class="tableIconsGroup">
-            	<span class="tableAllColumnsSwitch">
-                    {% if properties.show_table %}
-                        <a class="tableIcon" format="table" var="table">
-                            <img title="{{ 'General_DisplaySimpleTable'|translate }}" src="plugins/Zeitgeist/images/table.png"/>
-                        </a>
-                    {% endif %}
-                    {% if properties.show_table_all_columns %}
-                        <a class="tableIcon" format="tableAllColumns" var="tableAllColumns">
-                            <img title="{{ 'General_DisplayTableWithMoreMetrics'|translate }}" src="plugins/Zeitgeist/images/table_more.png"/>
-                        </a>
-                    {% endif %}
-                    {% if properties.show_goals %}
-                        <a class="tableIcon" format="tableGoals" var="tableGoals">
-                            <img title="{{ 'General_DisplayTableWithGoalMetrics'|translate }}"
-                                 src="plugins/Zeitgeist/images/{% if javascriptVariablesToSet.idGoal is defined and javascriptVariablesToSet.idGoal=='ecommerceOrder' %}ecommerceOrder.gif{% else %}goal.png{% endif %}"/>
-                        </a>
-                    {% endif %}
-                    {% if properties.show_ecommerce %}
-                        <a class="tableIcon" format="ecommerceOrder" var="ecommerceOrder">
-                            <img title="{{ 'General_EcommerceOrders'|translate }}" src="plugins/Zeitgeist/images/ecommerceOrder.gif" />
-                            <span>{{ 'General_EcommerceOrders'|translate }}</span>
-                        </a>
-                        <a class="tableIcon" format="ecommerceAbandonedCart" var="ecommerceAbandonedCart">
-                            <img title="{{ 'General_AbandonedCarts'|translate }}" src="plugins/Zeitgeist/images/ecommerceAbandonedCart.gif" />
-                            <span>{{ 'General_AbandonedCarts'|translate }}</span>
-                        </a>
-                    {% endif %}
-                </span>
+                    <span class="{{ footerIconGroup.class }}">
+                    {% for footerIcon in footerIconGroup.buttons %}
+                        <span>
+                            {% if properties.show_active_view_icon and javascriptVariablesToSet.viewDataTable == footerIcon.format %}
+                            <img src="plugins/Zeitgeist/images/data_table_footer_active_item.png" class="dataTableFooterActiveItem"/>
+                            {% endif %}
+                            <a class="tableIcon {% if javascriptVariablesToSet.viewDataTable == footerIcon.format %}activeIcon{% endif %}" format="{{ footerIcon.format }}" var="{{ footerIcon.var }}">
+                                <img width="16" height="16" title="{{ footerIcon.title }}" src="{{ footerIcon.icon }}"/>
+                                {% if footerIcon.text is defined %}<span>{{ footerIcon.text }}</span>{% endif %}
+                            </a>
+                        </span>
+                    {% endfor %}
+                    </span>
                 </div>
-                {% if properties.show_all_views_icons %}
+                {% endfor %}
                 <div class="tableIconsGroup">
-            	    <span class="tableGraphViews tableGraphCollapsed">
-                    {% if properties.show_bar_chart %}
-                        <a class="tableIcon" format="graphVerticalBar" var="graphVerticalBar">
-                            <img width="16" height="16" src="plugins/Zeitgeist/images/chart_bar.png" title="{{ 'General_VBarGraph'|translate }}"/>
-                        </a>
-                    {% endif %}
-                    {% if properties.show_pie_chart %}
-                        <a class="tableIcon" format="graphPie" var="graphPie">
-                            <img width="16" height="16" src="plugins/Zeitgeist/images/chart_pie.png" title="{{ 'General_Piechart'|translate }}"/>
-                        </a>
-                    {% endif %}
-                    {% if properties.show_tag_cloud %}
-                        <a class="tableIcon" format="cloud" var="cloud">
-                            <img width="16" height="16" src="plugins/Zeitgeist/images/tagcloud.png" title="{{ 'General_TagCloud'|translate }}"/>
-                        </a>
-                    {% endif %}
-                    {% if properties.show_non_core_visualizations %}
-                        {% for format, info in nonCoreVisualizations %}
-                        <a class="tableIcon" format="{{ format }}" var="{{ format }}">
-                            <img width="16" height="16" src="{{ info.table_icon }}" title="{{ info.title|translate }}"/>
-                        </a>
-                        {% endfor %}
+                    {% if footerIcons is empty %}
+                    <img src="plugins/Zeitgeist/images/data_table_footer_active_item.png" class="dataTableFooterActiveItem"/>
                     {% endif %}
-				    </span>
-                </div>
-                {% endif %}
-                <div class="tableIconsGroup">
                     <span class="exportToFormatIcons">
                         <a class="tableIcon" var="export">
                             <img width="16" height="16" src="plugins/Zeitgeist/images/export.png" title="{{ 'General_ExportThisReport'|translate }}"/>
diff --git a/plugins/CoreVisualizations/JqplotDataGenerator.php b/plugins/CoreVisualizations/JqplotDataGenerator.php
index 9642aabf1b256acc217e8f87de0c744878bf9b38..6de29e226b43867d5180eadabb827aed5373ca25 100644
--- a/plugins/CoreVisualizations/JqplotDataGenerator.php
+++ b/plugins/CoreVisualizations/JqplotDataGenerator.php
@@ -83,16 +83,6 @@ class JqplotDataGenerator
      */
     public function generate($dataTable)
     {
-        if (!empty($this->properties['visualization_properties']->max_graph_elements)) {
-            $offsetStartSummary = $this->properties['visualization_properties']->max_graph_elements - 1;
-            $sortColumn = !empty($this->properties['filter_sort_column'])
-                ? $this->properties['filter_sort_column']
-                : Metrics::INDEX_NB_VISITS;
-
-            $dataTable->filter(
-                'AddSummaryRow', array($offsetStartSummary, Piwik_Translate('General_Others'), $sortColumn));
-        }
-
         if ($dataTable->getRowsCount() > 0) {
             // if addTotalRow was called in GenerateGraphHTML, add a row containing totals of
             // different metrics
diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable.php b/plugins/CoreVisualizations/Visualizations/HtmlTable.php
index 614721b686bba328444540c8192cbad9eb3d3d05..e7c86e6b0561c96a5d4f81875c3e9f586f7abcf4 100644
--- a/plugins/CoreVisualizations/Visualizations/HtmlTable.php
+++ b/plugins/CoreVisualizations/Visualizations/HtmlTable.php
@@ -87,6 +87,9 @@ class HtmlTable extends DataTableVisualization
 
     static public $clientSideParameters = array(
         'search_recursive',
+        'filter_limit',
+        'filter_sort_column',
+        'filter_sort_order',
     );
 
     static public $clientSideProperties = array(
diff --git a/plugins/CoreVisualizations/Visualizations/JqplotGraph.php b/plugins/CoreVisualizations/Visualizations/JqplotGraph.php
index 567eb00571a13a6028944075266d1458e9f5cfef..71a9ef9b2c84c08042c4e9f323725f9a6aee450a 100644
--- a/plugins/CoreVisualizations/Visualizations/JqplotGraph.php
+++ b/plugins/CoreVisualizations/Visualizations/JqplotGraph.php
@@ -46,13 +46,8 @@ class JqplotGraph extends Graph
      */
     public function __construct($view)
     {
-        // Graphs require the full dataset, so no filters
-        $this->request_parameters_to_modify['disable_generic_filters'] = true;
+        parent::__construct($view);
         
-        // the queued filters will be manually applied later. This is to ensure that filtering using search
-        // will be done on the table before the labels are enhanced (see ReplaceColumnNames)
-        $this->request_parameters_to_modify['disable_queued_filters'] = true;
-
         // do not sort if sorted column was initially "label" or eg. it would make "Visits by Server time" not pretty
         if ($view->filter_sort_column != 'label') {
             $columns = $view->columns_to_display;
diff --git a/plugins/Zeitgeist/javascripts/ajaxHelper.js b/plugins/Zeitgeist/javascripts/ajaxHelper.js
index f12d451bbe8f7bdf32ee5b1f106b6bd25ddf7a8d..b3915f589730af547f1ecba73f3bd5f9a73821db 100644
--- a/plugins/Zeitgeist/javascripts/ajaxHelper.js
+++ b/plugins/Zeitgeist/javascripts/ajaxHelper.js
@@ -11,19 +11,32 @@
  * @type {Array} array holding XhrRequests with automatic cleanup
  */
 var globalAjaxQueue = [];
+globalAjaxQueue.active = 0;
 
 /**
- * Extend Array.push with automatic cleanup for finished requests
- *
- * @return {Object}
+ * Removes all finished requests from the queue.
+ * 
+ * @return {void}
  */
-globalAjaxQueue.push = function () {
-    // cleanup ajax queue
+globalAjaxQueue.clean = function () {
     for (var i = this.length; i--;) {
         if (!this[i] || this[i].readyState == 4) {
             this.splice(i, 1);
         }
     }
+};
+
+/**
+ * Extend Array.push with automatic cleanup for finished requests
+ *
+ * @return {Object}
+ */
+globalAjaxQueue.push = function () {
+    this.active += arguments.length;
+
+    // cleanup ajax queue
+    this.clean();
+
     // call original array push
     return Array.prototype.push.apply(this, arguments);
 };
@@ -40,6 +53,8 @@ globalAjaxQueue.abort = function () {
     }
     // remove all elements from array
     this.splice(0, this.length);
+
+    this.active = 0;
 };
 
 /**
@@ -85,6 +100,13 @@ function ajaxHelper() {
      */
     this.getParams =      {};
 
+    /**
+     * Base URL used in the AJAX request. Can be set by setUrl.
+     * @type {String}
+     * @see ajaxHelper.setUrl
+     */
+    this.getUrl = 'index.php?';
+
     /**
      * Params to be passed as GET params
      * @type {Object}
@@ -119,6 +141,10 @@ function ajaxHelper() {
      * @return {void}
      */
     this.addParams = function (params, type) {
+        if (typeof params == 'string') {
+            params = broadcast.getValuesFromUrl(params);
+        }
+
         for (var key in params) {
             if(type.toLowerCase() == 'get') {
                 this.getParams[key] = params[key];
@@ -128,6 +154,15 @@ function ajaxHelper() {
         }
     };
     
+    /**
+     * Sets the base URL to use in the AJAX request.
+     * 
+     * @param {string} url
+     */
+    this.setUrl = function (url) {
+        this.getUrl = url;
+    };
+
     /**
      * Gets this helper instance ready to send a bulk request. Each argument to this
      * function is a single request to use.
@@ -300,7 +335,10 @@ function ajaxHelper() {
 
         var parameters = this._mixinDefaultGetParams(this.getParams);
 
-        var url = 'index.php?';
+        var url = this.getUrl;
+        if (url[url.length - 1] != '?') {
+            url += '&';
+        }
 
         // we took care of encoding &segment properly already, so we don't use $.param for it ($.param URL encodes the values)
         if(parameters['segment']) {
@@ -328,10 +366,17 @@ function ajaxHelper() {
                         $(that.errorElement).html(response.message).fadeIn();
                         piwikHelper.lazyScrollTo(that.errorElement, 250);
                     }
-                    return;
+                } else {
+                    that.callback(response);
                 }
 
-                that.callback(response);
+                --globalAjaxQueue.active;
+                var piwik = window.piwik;
+                if (piwik
+                    && piwik.ajaxRequestFinished
+                ) {
+                    piwik.ajaxRequestFinished();
+                }
             },
             data:     this._mixinDefaultPostParams(this.postParams)
         };
diff --git a/tests/PHPUnit/Integration/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_only__PDFReports.generateReport_month.original.html b/tests/PHPUnit/Integration/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_only__PDFReports.generateReport_month.original.html
index f93a03e8e899551a6dfe14d417c9f2b086d4c013..177fbdd63a1c247acec24ae327c8fd9ff1b4b279 100644
--- a/tests/PHPUnit/Integration/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_only__PDFReports.generateReport_month.original.html
+++ b/tests/PHPUnit/Integration/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_only__PDFReports.generateReport_month.original.html
@@ -291,7 +291,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Website&nbsp;&nbsp;
@@ -374,7 +374,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="VisitsSummary_get" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -383,7 +383,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Name&nbsp;&nbsp;
@@ -452,7 +452,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="VisitTime_getVisitInformationPerServerTime" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -461,7 +461,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Server time&nbsp;&nbsp;
@@ -1041,7 +1041,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="VisitTime_getVisitInformationPerLocalTime" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -1050,7 +1050,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Local time&nbsp;&nbsp;
@@ -1630,7 +1630,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="VisitTime_getByDayOfWeek" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -1639,7 +1639,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Day of the week&nbsp;&nbsp;
@@ -1828,7 +1828,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="Actions_get" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -1837,7 +1837,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Name&nbsp;&nbsp;
@@ -1922,7 +1922,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="Actions_getPageUrls" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -1931,7 +1931,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Page URL&nbsp;&nbsp;
@@ -2059,7 +2059,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="Actions_getEntryPageUrls" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -2068,7 +2068,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Page URL&nbsp;&nbsp;
@@ -2119,7 +2119,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="Actions_getExitPageUrls" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -2128,7 +2128,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Page URL&nbsp;&nbsp;
@@ -2179,7 +2179,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="Actions_getPageTitles" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -2188,7 +2188,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Page Name&nbsp;&nbsp;
@@ -2308,7 +2308,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="Actions_getEntryPageTitles" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -2317,7 +2317,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Page Name&nbsp;&nbsp;
@@ -2364,7 +2364,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="Actions_getExitPageTitles" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -2373,7 +2373,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Page Name&nbsp;&nbsp;
@@ -2420,7 +2420,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="Actions_getOutlinks" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -2439,7 +2439,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Referrer Type&nbsp;&nbsp;
@@ -2513,7 +2513,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="Referers_getAll" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -2522,7 +2522,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Referrer&nbsp;&nbsp;
@@ -2573,7 +2573,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="Referers_getKeywords" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -2587,7 +2587,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Website&nbsp;&nbsp;
@@ -2638,7 +2638,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="Referers_getSearchEngines" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -2662,7 +2662,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Name&nbsp;&nbsp;
@@ -2707,7 +2707,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="Goals_getVisitsUntilConversion" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -2726,7 +2726,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Country&nbsp;&nbsp;
@@ -2779,7 +2779,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="UserCountry_getContinent" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -2788,7 +2788,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Continent&nbsp;&nbsp;
@@ -2839,7 +2839,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="UserCountry_getRegion" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -2848,7 +2848,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Region&nbsp;&nbsp;
@@ -2901,7 +2901,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="UserCountry_getCity" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -2910,7 +2910,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;City&nbsp;&nbsp;
@@ -2963,7 +2963,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="CustomVariables_getCustomVariables" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -2977,7 +2977,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Visit duration&nbsp;&nbsp;
@@ -3070,7 +3070,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="VisitorInterest_getNumberOfVisitsPerPage" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -3079,7 +3079,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Pages per visit&nbsp;&nbsp;
@@ -3172,7 +3172,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="VisitorInterest_getNumberOfVisitsByVisitCount" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -3181,7 +3181,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Visits by Visit Number&nbsp;&nbsp;
@@ -3351,7 +3351,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="VisitorInterest_getNumberOfVisitsByDaysSinceLast" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -3360,7 +3360,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Visits by days since last visit&nbsp;&nbsp;
@@ -3493,7 +3493,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="VisitFrequency_get" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -3502,7 +3502,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Name&nbsp;&nbsp;
@@ -3563,7 +3563,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="Provider_getProvider" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -3572,7 +3572,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Provider&nbsp;&nbsp;
@@ -3625,7 +3625,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="DevicesDetection_getType" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -3634,7 +3634,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Device type&nbsp;&nbsp;
@@ -3687,7 +3687,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="DevicesDetection_getBrand" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -3696,7 +3696,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Device brand&nbsp;&nbsp;
@@ -3749,7 +3749,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="DevicesDetection_getModel" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -3758,7 +3758,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Device model&nbsp;&nbsp;
@@ -3809,7 +3809,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="DevicesDetection_getOsFamilies" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -3818,7 +3818,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Operating System families&nbsp;&nbsp;
@@ -3871,7 +3871,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="DevicesDetection_getOsVersions" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -3880,7 +3880,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Operating System versions&nbsp;&nbsp;
@@ -3933,7 +3933,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="DevicesDetection_getBrowserFamilies" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -3942,7 +3942,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Browsers families&nbsp;&nbsp;
@@ -4020,7 +4020,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="DevicesDetection_getBrowserVersions" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -4029,7 +4029,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Browser versions&nbsp;&nbsp;
@@ -4107,7 +4107,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="UserSettings_getResolution" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -4116,7 +4116,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Resolution&nbsp;&nbsp;
@@ -4190,7 +4190,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="UserSettings_getBrowser" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -4199,7 +4199,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Browser&nbsp;&nbsp;
@@ -4277,7 +4277,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="UserSettings_getBrowserVersion" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -4286,7 +4286,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Browser version&nbsp;&nbsp;
@@ -4364,7 +4364,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="UserSettings_getBrowserType" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -4373,7 +4373,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Browser family&nbsp;&nbsp;
@@ -4447,7 +4447,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="UserSettings_getPlugin" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -4456,7 +4456,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Plugin&nbsp;&nbsp;
@@ -4602,7 +4602,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="UserSettings_getWideScreen" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -4611,7 +4611,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Type of screen&nbsp;&nbsp;
@@ -4689,7 +4689,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="UserSettings_getOS" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -4698,7 +4698,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Operating system&nbsp;&nbsp;
@@ -4751,7 +4751,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="UserSettings_getConfiguration" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -4760,7 +4760,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Configuration&nbsp;&nbsp;
@@ -4834,7 +4834,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="UserSettings_getOSFamily" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -4843,7 +4843,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Operating system family&nbsp;&nbsp;
@@ -4896,7 +4896,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="UserSettings_getMobileVsDesktop" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -4905,7 +4905,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Mobile vs Desktop&nbsp;&nbsp;
@@ -4983,7 +4983,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 <h2 id="UserSettings_getLanguage" style="color: rgb(126,115,99); font-size: 11pt;">
@@ -4992,7 +4992,7 @@
 
     
     
-            <table style="border-collapse:collapse; margin-left: 5px">
+            <table style="border-collapse:collapse; margin-left: 5px;">
             <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;">
                             <th style="padding: 6px 0;">
                     &nbsp;Language&nbsp;&nbsp;
@@ -5043,7 +5043,7 @@
                         </tbody>
         </table>
         <br/>
-    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop">
+    <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop">
         Back to top
     </a>
 </body>
diff --git a/tests/PHPUnit/IntegrationTestCase.php b/tests/PHPUnit/IntegrationTestCase.php
index cfcf72c5810d4caa6171e8ae74cea45f24b5d317..ed567452ae9aedeaf8b2ce2125be7af0d5581b17 100755
--- a/tests/PHPUnit/IntegrationTestCase.php
+++ b/tests/PHPUnit/IntegrationTestCase.php
@@ -635,7 +635,7 @@ abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase
                                         $abandonedCarts = false, $idGoal = false, $apiModule = false, $apiAction = false,
                                         $otherRequestParameters = array(), $supertableApi = false, $fileExtension = false)
     {
-        list($pathProcessed, $pathExpected) = $this->getProcessedAndExpectedDirs();
+        list($pathProcessed, $pathExpected) = self::getProcessedAndExpectedDirs();
 
         if ($periods === false) {
             $periods = 'day';
@@ -866,9 +866,9 @@ abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase
         return $input;
     }
 
-    protected function getProcessedAndExpectedDirs()
+    protected static function getProcessedAndExpectedDirs()
     {
-        $path = $this->getPathToTestDirectory();
+        $path = self::getPathToTestDirectory();
         return array($path . '/processed/', $path . '/expected/');
     }
 
@@ -879,7 +879,7 @@ abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase
             $filename .= ".$format";
         }
 
-        list($processedDir, $expectedDir) = $this->getProcessedAndExpectedDirs();
+        list($processedDir, $expectedDir) = self::getProcessedAndExpectedDirs();
 
         return array($processedDir . $filename, $expectedDir . $filename);
     }
@@ -1062,9 +1062,9 @@ abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase
     }
 
     /**
-     * Path where expected/processed output files are stored. Can be overridden.
+     * Path where expected/processed output files are stored.
      */
-    public function getPathToTestDirectory()
+    public static function getPathToTestDirectory()
     {
         return dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Integration';
     }
diff --git a/tests/PHPUnit/Plugins/SegmentEditorTest.php b/tests/PHPUnit/Plugins/SegmentEditorTest.php
index 696f19bcbc333017fe6aaecc2feecfdca86b3af6..12f7cc713856dcd5a5953dea49e6b79ef087983c 100644
--- a/tests/PHPUnit/Plugins/SegmentEditorTest.php
+++ b/tests/PHPUnit/Plugins/SegmentEditorTest.php
@@ -140,6 +140,11 @@ class SegmentEditorTest extends DatabaseTestCase
         );
 
         $newSegment = API::getInstance()->get($idSegment2);
+
+        // avoid test failures for when ts_created/ts_last_edit are different by between 1/2 secs
+        $this->removeSecondsFromSegmentInfo($updatedSegment);
+        $this->removeSecondsFromSegmentInfo($newSegment);
+
         $this->assertEquals($newSegment, $updatedSegment);
 
         // Check the other segmenet was not updated
@@ -164,4 +169,14 @@ class SegmentEditorTest extends DatabaseTestCase
         // and this should work
         API::getInstance()->get($idSegment1);
     }
+
+    private function removeSecondsFromSegmentInfo(&$segmentInfo)
+    {
+        $timestampProperties = array('ts_last_edit', 'ts_created');
+        foreach ($timestampProperties as $propertyName) {
+            if (isset($segmentInfo[$propertyName])) {
+                $segmentInfo[$propertyName] = substr($segmentInfo[$propertyName], 0, strlen($segmentInfo[$propertyName] - 2));
+            }
+        }
+    }
 }
diff --git a/tests/PHPUnit/TestingEnvironment.php b/tests/PHPUnit/TestingEnvironment.php
index 99d2822ef6fedd1c221d21aa41d2a07ceff5f9b7..171ce749010e84236265309f571760c22dcaed1a 100644
--- a/tests/PHPUnit/TestingEnvironment.php
+++ b/tests/PHPUnit/TestingEnvironment.php
@@ -23,5 +23,12 @@ class Piwik_TestingEnvironment
         Piwik_AddAction('FrontController.dispatch', function() {
             \Piwik\Plugins\CoreVisualizations\Visualizations\Cloud::$debugDisableShuffle = true;
         });
+        Piwik_AddAction('AssetManager.getCssFiles', function(&$cssFiles) {
+            $cssFiles[] = 'tests/resources/screenshot-override/override.css';
+        });
+        Piwik_AddAction('AssetManager.getJsFiles', function(&$jsFiles) {
+            $jsFiles[] = 'tests/resources/screenshot-override/jquery.waitforimages.js';
+            $jsFiles[] = 'tests/resources/screenshot-override/override.js';
+        });
     }
 }
\ No newline at end of file
diff --git a/tests/PHPUnit/UI/UIIntegrationTest.php b/tests/PHPUnit/UI/UIIntegrationTest.php
index 7d63301b8e8d15669a6bd1b711e3f0f12d5583ca..b1b95e0df67f48f27ec1f0d99e32eaabe40d17cc 100644
--- a/tests/PHPUnit/UI/UIIntegrationTest.php
+++ b/tests/PHPUnit/UI/UIIntegrationTest.php
@@ -13,7 +13,7 @@ use Piwik\Plugins\VisitsSummary\API;
 /**
  * Tests UI code by grabbing screenshots of webpages and comparing with expected files.
  * 
- * Uses cutycapt.
+ * Uses slimerjs or phantomjs.
  * 
  * TODO:
  * - allow instrumentation javascript to be injected before screenshot is taken (so we can, say,
@@ -22,10 +22,9 @@ use Piwik\Plugins\VisitsSummary\API;
 class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase
 {
     const IMAGE_TYPE = 'png';
-    const CUTYCAPT_DELAY = 1000;
+    const CAPTURE_PROGRAM = 'phantomjs';
     
     public static $fixture = null; // initialized below class definition
-    private static $useXvfb = false;
     
     public static function createAccessInstance()
     {
@@ -35,11 +34,18 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase
     
     public static function setUpBeforeClass()
     {
-        if (self::isXvfbAvailable()) {
-            self::$useXvfb = true;
-        } else if (!self::isCutyCaptAvailable()) {
-            self::markTestSkipped("cutycapt is not available, skipping UI integration tests. "
-                                . "(install with 'sudo apt-get intsall cutycapt')");
+        if (!self::isXvfbAvailable()) {
+            self::markTestSkipped("xvfb is not available, skipping UI integration tests. (install with 'sudo apt-get install xvfb')");
+        } else if (self::CAPTURE_PROGRAM == 'slimerjs'
+                   && !self::isSlimerJsAvailable()
+        ) {
+            self::markTestSkipped("slimerjs is not available, skipping UI integration tests. "
+                                . "(install by downloading http://slimerjs.org/download.html)");
+        } else if (self::CAPTURE_PROGRAM == 'phantomjs'
+                   && !self::isPhantomJsAvailable()
+        ) {
+            self::markTestSkipped("phantomjs is not available, skipping UI integration tests. "
+                                . "(install by downloading http://phantomjs.org/download.html)");
         }
         
         parent::setUpBeforeClass();
@@ -48,10 +54,35 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase
         
         // launch archiving so tests don't run out of time
         API::getInstance()->get(self::$fixture->idSite, 'year', '2012-08-09');
+
+        // make sure processed & expected dirs exist
+        list($processedDir, $expectedDir) = self::getProcessedAndExpectedDirs();
+        if (!is_dir($processedDir)) {
+            mkdir($processedDir);
+        }
+        if (!is_dir($expectedDir)) {
+            mkdir($expectedDir);
+        }
+
+        // run slimerjs/phantomjs w/ all urls so we only invoke it once
+        $urls = array();
+        foreach (self::getUrlsForTesting() as $testInfo) {
+            list($name, $urlQuery) = $testInfo;
+
+            list($processedScreenshotPath, $expectedScreenshotPath) = self::getProcessedAndExpectedScreenshotPaths($name);
+            $urls[] = array($processedScreenshotPath, self::getProxyUrl() . $urlQuery);
+        }
+        
+        echo "Generating screenshots...\n";
+        self::runCaptureProgram($urls);
     }
     
     public static function tearDownAfterClass()
     {
+        if (file_exists("C:\\nppdf32Log\\debuglog.txt")) { // remove slimerjs oddity
+            unlink("C:\\nppdf32Log\\debuglog.txt");
+        }
+
         if (!Zend_Registry::get('db')) {
             Piwik::createDatabaseObject();
         }
@@ -63,14 +94,6 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase
     {
         parent::setUp();
         
-        list($processedDir, $expectedDir) = $this->getProcessedAndExpectedDirs();
-        if (!is_dir($processedDir)) {
-            mkdir($processedDir);
-        }
-        if (!is_dir($expectedDir)) {
-            mkdir($expectedDir);
-        }
-        
         if (!Zend_Registry::get('db')) {
             Piwik::createDatabaseObject();
         }
@@ -84,7 +107,7 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase
         \Zend_Registry::set('db', false);
     }
     
-    public function getUrlsForTesting()
+    public static function getUrlsForTesting()
     {
         $generalParams = 'idSite=1&period=week&date=2012-08-09';
         $evolutionParams = 'idSite=1&period=day&date=2012-08-11&evolution_day_last_n=30';
@@ -196,33 +219,26 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase
      */
     public function testUIUrl($name, $urlQuery)
     {
-        list($processedDir, $expectedDir) = $this->getProcessedAndExpectedDirs();
-        
-        $processedScreenshotPath = $processedDir . "$name." . self::IMAGE_TYPE;
-        $expectedScreenshotPath = $expectedDir . "$name." . self::IMAGE_TYPE;
-        
-        // run cutycapt w/ url and output to /processed-ui-screenshots/$name.svg
-        $this->runCutyCapt($urlQuery, $processedScreenshotPath);
+        list($processedScreenshotPath, $expectedScreenshotPath) = self::getProcessedAndExpectedScreenshotPaths($name);
         
         // compare processed w/ expected
         $this->compareScreenshot($name, $expectedScreenshotPath, $processedScreenshotPath, $urlQuery);
     }
     
-    private function runCutyCapt($urlQuery, $processedPath)
+    private static function runCaptureProgram($urlInfo)
     {
-        $url = self::getProxyUrl() . $urlQuery;
-        
-        $cmd = "cutycapt --url=\"$url\" --out=\"$processedPath\" --min-width=1366 --delay=".self::CUTYCAPT_DELAY." 2>&1";
-        if (self::$useXvfb) {
-            $cmd = 'xvfb-run --server-args="-screen 0, 1024x768x24" ' . $cmd;
-        }
+        file_put_contents(PIWIK_INCLUDE_PATH . '/tmp/urls.txt', json_encode($urlInfo));
+        $cmd = self::CAPTURE_PROGRAM . " \"" . PIWIK_INCLUDE_PATH . "/tests/resources/screenshot-capture/capture.js\" 2>&1";
+        $cmd = 'xvfb-run --server-args="-screen 0, 1024x768x24" ' . $cmd;
         
         exec($cmd, $output, $result);
-        
-        if ($result !== 0) {
-            throw new Exception("cutycapt failed: " . implode("\n", $output) . "\n\ncommand used: $cmd");
+        $output = implode("\n", $output);
+        if ($result !== 0
+            || strpos($output, "ERROR") !== false
+        ) {
+            echo self::CAPTURE_PROGRAM . " failed: " . $output . "\n\ncommand used: $cmd\n";
+            throw new Exception("phantomjs failed");
         }
-
         return $output;
     }
     
@@ -241,21 +257,40 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase
         $this->assertTrue($expected == $processed, "screenshot compare failed for '$processedPath'");
     }
     
-    private static function isCutyCaptAvailable()
+    private static function isSlimerJsAvailable()
     {
-        exec("cutycapt --help 2>&1", $output, $result);
-        return $result === 0 || $result === 1;
+        return self::isProgramAvailable('slimerjs');
+    }
+
+    private static function isPhantomJsAvailable()
+    {
+        return self::isProgramAvailable('phantomjs');
     }
     
     private static function isXvfbAvailable()
     {
-        exec("xvfb-run --help 2>&1", $output, $result);
+        return self::isProgramAvailable('xvfb-run');
+    }
+
+    private static function isProgramAvailable($name)
+    {
+        exec($name . ' --help 2>&1', $output, $result);
         return $result === 0 || $result === 1;
     }
+
+    private static function getProcessedAndExpectedScreenshotPaths($name)
+    {
+        list($processedDir, $expectedDir) = self::getProcessedAndExpectedDirs();
+
+        $processedScreenshotPath = $processedDir . "$name." . self::IMAGE_TYPE;
+        $expectedScreenshotPath = $expectedDir . "$name." . self::IMAGE_TYPE;
+
+        return array($processedScreenshotPath, $expectedScreenshotPath);
+    }
     
-    protected function getProcessedAndExpectedDirs()
+    protected static function getProcessedAndExpectedDirs()
     {
-        $path = $this->getPathToTestDirectory() . '/../UI';
+        $path = self::getPathToTestDirectory() . '/../UI';
         return array($path . '/processed-ui-screenshots/', $path . '/expected-ui-screenshots/');
     }
     
@@ -265,4 +300,4 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase
     }
 }
 
-Test_Piwik_Integration_UIIntegrationTest::$fixture = new Test_Piwik_Fixture_ManySitesImportedLogsWithXssAttempts();
+Test_Piwik_Integration_UIIntegrationTest::$fixture = new Test_Piwik_Fixture_ManySitesImportedLogsWithXssAttempts();
\ No newline at end of file
diff --git a/tests/resources/screenshot-capture/capture.js b/tests/resources/screenshot-capture/capture.js
new file mode 100644
index 0000000000000000000000000000000000000000..34ac2f8068100e0bbb25dbb75566b31638ea5174
--- /dev/null
+++ b/tests/resources/screenshot-capture/capture.js
@@ -0,0 +1,126 @@
+var fs = require('fs');
+var app = typeof slimer === 'undefined' ? phantom : slimer;
+var readFileSync = fs.readFileSync || fs.read;
+
+var PageRenderer = function() {
+    this.start = new Date();
+
+    this.urlIndex = 0;
+    this.urls = JSON.parse(readFileSync('../../tmp/urls.txt'));
+
+    this.webpage = require('webpage').create();
+    this.outputPath = '';
+    this.url = '';
+
+    this._setupWebpageEvents();
+    this._setScriptTimeout();
+};
+
+PageRenderer.prototype = {
+    renderAll: function () {
+        this._saveCurrentUrl();
+    },
+
+    _saveCurrentUrl: function () {
+        if (this.urlIndex >= this.urls.length) {
+            app.exit();
+            return;
+        }
+
+        this.outputPath = this.urls[this.urlIndex][0];
+        this.url = this.urls[this.urlIndex][1];
+
+        console.log("SAVING " + this.url + " at " + this._getElapsedExecutionTime());
+
+        this.webpage.viewportSize = {width:1350, height:768};
+        this.webpage.open(this.url);
+
+        this._setPageTimeouts();
+    },
+
+    _setPageTimeouts: function () {
+        var url = this.url, self = this;
+        this.webpage.onLoadFinished = function () {
+            // check that we're still on the same url
+            if (url != self.url) {
+                return;
+            }
+
+            // in case there are no ajax requests, try triggering after a sec
+            setTimeout(function () {
+                if (url == self.url) {
+                    self.webpage.evaluate(function () {
+                        window.piwik.ajaxRequestFinished();
+                    });
+                }
+            }, 1000)
+
+            // only allowed at most one minute to load
+            setTimeout(function () {
+                if (url == self.url) {
+                    self.webpage.evaluate(function () {
+                        window.piwik._triggerRenderInsane();
+                    });
+                }
+            }, 1000 * 60);
+        };
+    },
+
+    _setupWebpageEvents: function () {
+        this.webpage.onError = function (message) {
+            console.log("Webpage error: " + message);
+        };
+
+        var self = this;
+        this.webpage.onConsoleMessage = function (message) {
+            if (message == "__AJAX_DONE__") {
+                try {
+                    self._setCorrectViewportSize();
+                    self.webpage.render(self.outputPath);
+
+                    self._renderNextUrl();
+                } catch (e) {
+                    console.log("ERROR: " + e.message);
+                    app.exit(1);
+                }
+            } else {
+                console.log("LOGGED: " + message);
+            }
+        };
+    },
+
+    _renderNextUrl: function () {
+        ++this.urlIndex;
+        this._saveCurrentUrl();
+    },
+
+    _setCorrectViewportSize: function () {
+        this.webpage.viewportSize = {width:1350, height:768};
+        var height = Math.max(768, this.webpage.evaluate(function() {
+            return document.body.offsetHeight;
+        }));
+        this.webpage.viewportSize = {width:1350, height: height};
+    },
+
+    _getElapsedExecutionTime: function () {
+        var now = new Date(),
+            elapsed = now.getTime() - this.start.getTime();
+
+        return (elapsed / 1000.0) + "s";
+    },
+
+    _setScriptTimeout: function () {
+        setTimeout(function() {
+            console.log("ERROR: Timed out!");
+            app.exit(1);
+        }, Math.max(1000 * 15 * this.urls.length, 1000 * 60 * 5));
+    },
+};
+
+try {
+    var renderer = new PageRenderer();
+    renderer.renderAll();
+} catch (e) {
+    console.log("ERROR: " + e.message);
+    app.exit(1);
+}
\ No newline at end of file
diff --git a/tests/resources/screenshot-override/jquery.waitforimages.js b/tests/resources/screenshot-override/jquery.waitforimages.js
new file mode 100644
index 0000000000000000000000000000000000000000..eba523b8bb459fd2c380b0437c9ba90676a6709e
--- /dev/null
+++ b/tests/resources/screenshot-override/jquery.waitforimages.js
@@ -0,0 +1,136 @@
+/*! waitForImages jQuery Plugin - v1.5.0 - 2013-07-20
+* https://github.com/alexanderdickson/waitForImages
+* Copyright (c) 2013 Alex Dickson; Licensed MIT */
+;(function ($) {
+    // Namespace all events.
+    var eventNamespace = 'waitForImages';
+
+    // CSS properties which contain references to images.
+    $.waitForImages = {
+        hasImageProperties: ['backgroundImage', 'listStyleImage', 'borderImage', 'borderCornerImage', 'cursor']
+    };
+
+    // Custom selector to find `img` elements that have a valid `src` attribute and have not already loaded.
+    $.expr[':'].uncached = function (obj) {
+        // Ensure we are dealing with an `img` element with a valid `src` attribute.
+        if (!$(obj).is('img[src!=""]')) {
+            return false;
+        }
+
+        // Firefox's `complete` property will always be `true` even if the image has not been downloaded.
+        // Doing it this way works in Firefox.
+        var img = new Image();
+        img.src = obj.src;
+        return !img.complete;
+    };
+
+    $.fn.waitForImages = function (finishedCallback, eachCallback, waitForAll) {
+
+        var allImgsLength = 0;
+        var allImgsLoaded = 0;
+
+        // Handle options object.
+        if ($.isPlainObject(arguments[0])) {
+            waitForAll = arguments[0].waitForAll;
+            eachCallback = arguments[0].each;
+			// This must be last as arguments[0]
+			// is aliased with finishedCallback.
+            finishedCallback = arguments[0].finished;
+        }
+
+        // Handle missing callbacks.
+        finishedCallback = finishedCallback || $.noop;
+        eachCallback = eachCallback || $.noop;
+
+        // Convert waitForAll to Boolean
+        waitForAll = !! waitForAll;
+
+        // Ensure callbacks are functions.
+        if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) {
+            throw new TypeError('An invalid callback was supplied.');
+        }
+
+        return this.each(function () {
+            // Build a list of all imgs, dependent on what images will be considered.
+            var obj = $(this);
+            var allImgs = [];
+            // CSS properties which may contain an image.
+            var hasImgProperties = $.waitForImages.hasImageProperties || [];
+            // To match `url()` references.
+            // Spec: http://www.w3.org/TR/CSS2/syndata.html#value-def-uri
+            var matchUrl = /url\(\s*(['"]?)(.*?)\1\s*\)/g;
+
+            if (waitForAll) {
+
+                // Get all elements (including the original), as any one of them could have a background image.
+                obj.find('*').addBack().each(function () {
+                    var element = $(this);
+
+                    // If an `img` element, add it. But keep iterating in case it has a background image too.
+                    if (element.is('img:uncached')) {
+                        allImgs.push({
+                            src: element.attr('src'),
+                            element: element[0]
+                        });
+                    }
+
+                    $.each(hasImgProperties, function (i, property) {
+                        var propertyValue = element.css(property);
+                        var match;
+
+                        // If it doesn't contain this property, skip.
+                        if (!propertyValue) {
+                            return true;
+                        }
+
+                        // Get all url() of this element.
+                        while (match = matchUrl.exec(propertyValue)) {
+                            allImgs.push({
+                                src: match[2],
+                                element: element[0]
+                            });
+                        }
+                    });
+                });
+            } else {
+                // For images only, the task is simpler.
+                obj.find('img:uncached')
+                    .each(function () {
+                    allImgs.push({
+                        src: this.src,
+                        element: this
+                    });
+                });
+            }
+
+            allImgsLength = allImgs.length;
+            allImgsLoaded = 0;
+
+            // If no images found, don't bother.
+            if (allImgsLength === 0) {
+                finishedCallback.call(obj[0]);
+            }
+
+            $.each(allImgs, function (i, img) {
+
+                var image = new Image();
+
+                // Handle the image loading and error with the same callback.
+                $(image).on('load.' + eventNamespace + ' error.' + eventNamespace, function (event) {
+                    allImgsLoaded++;
+
+                    // If an error occurred with loading the image, set the third argument accordingly.
+                    eachCallback.call(img.element, allImgsLoaded, allImgsLength, event.type == 'load');
+
+                    if (allImgsLoaded == allImgsLength) {
+                        finishedCallback.call(obj[0]);
+                        return false;
+                    }
+
+                });
+
+                image.src = img.src;
+            });
+        });
+    };
+}(jQuery));
diff --git a/tests/resources/screenshot-override/open_sans.woff b/tests/resources/screenshot-override/open_sans.woff
new file mode 100644
index 0000000000000000000000000000000000000000..55b25f867099eb26c436b1c9fecff14a51290d46
Binary files /dev/null and b/tests/resources/screenshot-override/open_sans.woff differ
diff --git a/tests/resources/screenshot-override/open_sans_b.woff b/tests/resources/screenshot-override/open_sans_b.woff
new file mode 100644
index 0000000000000000000000000000000000000000..27619e7cea1c29f9d71567b78470fdd705c174dc
Binary files /dev/null and b/tests/resources/screenshot-override/open_sans_b.woff differ
diff --git a/tests/resources/screenshot-override/open_sans_bi.woff b/tests/resources/screenshot-override/open_sans_bi.woff
new file mode 100644
index 0000000000000000000000000000000000000000..e12c3a9f273c2f0e4952293bb852406c2ab1eb0a
Binary files /dev/null and b/tests/resources/screenshot-override/open_sans_bi.woff differ
diff --git a/tests/resources/screenshot-override/open_sans_i.woff b/tests/resources/screenshot-override/open_sans_i.woff
new file mode 100644
index 0000000000000000000000000000000000000000..cedefb8f6ff406c6b77e75ae55ee88e2bd88dc17
Binary files /dev/null and b/tests/resources/screenshot-override/open_sans_i.woff differ
diff --git a/tests/resources/screenshot-override/override.css b/tests/resources/screenshot-override/override.css
new file mode 100644
index 0000000000000000000000000000000000000000..8bc65e63d38884ded4d8af5e7fc6ef32b41d673f
--- /dev/null
+++ b/tests/resources/screenshot-override/override.css
@@ -0,0 +1,28 @@
+@font-face {
+  font-family: 'Open Sans';
+  font-style: normal;
+  font-weight: 400;
+  src: url(tests/resources/screenshot-override/open_sans.woff) format('woff');
+}
+@font-face {
+  font-family: 'Open Sans';
+  font-style: normal;
+  font-weight: 700;
+  src: url(tests/resources/screenshot-override/open_sans_b.woff) format('woff');
+}
+@font-face {
+  font-family: 'Open Sans';
+  font-style: italic;
+  font-weight: 400;
+  src: url(tests/resources/screenshot-override/open_sans_i.woff) format('woff');
+}
+@font-face {
+  font-family: 'Open Sans';
+  font-style: italic;
+  font-weight: 700;
+  src: url(tests/resources/screenshot-override/open_sans_bi.woff) format('woff');
+}
+
+* {
+    font-family: 'Open Sans';
+}
\ No newline at end of file
diff --git a/tests/resources/screenshot-override/override.js b/tests/resources/screenshot-override/override.js
new file mode 100644
index 0000000000000000000000000000000000000000..c354d5ca132786ffb87ee854d9328b666db4c0cb
--- /dev/null
+++ b/tests/resources/screenshot-override/override.js
@@ -0,0 +1,41 @@
+(function ($) {
+
+    var DEBUG_LOGGING = true;
+    
+    if (DEBUG_LOGGING) {
+        var log = function(message) {
+            console.log(message);
+        };
+    } else {
+        var log = function() {};
+    }
+
+    var triggerRenderInsane = function () {
+        console.log("__AJAX_DONE__");
+    };
+    
+    var triggerRender = function () {
+        if (window.globalAjaxQueue.active === 0) { // sanity check
+            triggerRenderInsane();
+        }
+    };
+
+    var triggerRenderIfNoAjax = function () {
+        setTimeout(function () { // allow other javascript to execute in case they execute ajax/add images/set the src of images
+            if (window.globalAjaxQueue.active === 0) {
+                $('body').waitForImages({
+                    waitForAll: true,
+                    finished: function () {
+                        // wait some more to make sure other javascript is executed & the last image is rendered
+                        setTimeout(triggerRender, 1000);
+                    },
+                });
+            }
+        }, 1);
+    };
+
+    window.piwik = window.piwik || {};
+    window.piwik.ajaxRequestFinished = triggerRenderIfNoAjax;
+    window.piwik._triggerRenderInsane = triggerRenderInsane;
+
+}(jQuery));
\ No newline at end of file
diff --git a/tests/travis/prepare.sh b/tests/travis/prepare.sh
index b45bbe7039f32c9e9dbf87274a1670f66b44a9cc..04f50f03548fe2dc4bb2b42844f9c66a88ef0107 100755
--- a/tests/travis/prepare.sh
+++ b/tests/travis/prepare.sh
@@ -4,6 +4,20 @@ set -e
 # Install XMLStarlet
 sudo apt-get install -qq xmlstarlet
 
+# Install phantomjs 1.9.1 for UI tests
+if [ "$TEST_DIR" = "UI" ];
+then
+    cd tmp
+    wget "https://phantomjs.googlecode.com/files/phantomjs-1.9.1-linux-x86_64.tar.bz2" -O phantomjs.tar.bz2
+    tar xvjf phantomjs.tar.bz2
+    cd phantomjs*
+    export PATH=$PATH:`pwd`/bin
+    cd ../..
+
+    echo "Using phantomjs version:"
+    phantomjs --version
+fi
+
 # Copy Piwik configuration
 echo "Install config.ini.php"
 cp ./tests/PHPUnit/config.ini.travis.php ./config/config.ini.php
diff --git a/tests/travis/upload_artifacts.sh b/tests/travis/upload_artifacts.sh
index 1d829c4ca5b0fd5ed26edd707ccc6a3d4fa4a0bb..84cbab9efeb33454e1bd385a15a36442d634ec51 100755
--- a/tests/travis/upload_artifacts.sh
+++ b/tests/travis/upload_artifacts.sh
@@ -1,16 +1,30 @@
-if [ "$TEST_SUITE" != "IntegrationTests" ];
+#!/bin/bash
+
+if [ "$TEST_SUITE" = "IntegrationTests" ];
 then
-    echo "No artifacts for $TEST_SUITE tests.";
-    exit;
-fi
+    url="http://builds-artifacts.piwik.org/upload.php?auth_key=$ARTIFACTS_PASS&artifact_name=processed&branch=$TRAVIS_BRANCH&build_id=$TRAVIS_JOB_NUMBER"
+
+    echo "Uploading artifacts for $TEST_SUITE..."
 
-url="http://builds-artifacts.piwik.org/upload.php?auth_key=$ARTIFACTS_PASS&artifact_name=processed&branch=$TRAVIS_BRANCH&build_id=$TRAVIS_JOB_NUMBER"
+    cd ./tests/PHPUnit/Integration
 
-echo "Uploading artifacts for $TEST_SUITE..."
+    # upload processed tarball
+    tar -cjf processed.tar.bz2 processed --exclude='.gitkeep'
+    curl -X POST --data-binary @processed.tar.bz2 "$url"
+else
+    if [ "$TEST_DIR" = "UI" ];
+    then
+        url="http://builds-artifacts.piwik.org/upload.php?auth_key=$ARTIFACTS_PASS&artifact_name=processed-ui-screenshots&branch=$TRAVIS_BRANCH&build_id=$TRAVIS_JOB_NUMBER"
 
-cd ./tests/PHPUnit/Integration
+        echo "Uploading artifacts for $TEST_DIR..."
 
-# upload processed tarball
-tar -cjf processed.tar.bz2 processed --exclude='.gitkeep'
-curl -X POST --data-binary @processed.tar.bz2 "$url"
+        cd ./tests/PHPUnit/UI
 
+        # upload processed tarball
+        tar -cjf processed-ui-screenshots.tar.bz2 processed-ui-screenshots --exclude='.gitkeep'
+        curl -X POST --data-binary @processed-ui-screenshots.tar.bz2 "$url"
+    else
+        echo "No artifacts for $TEST_SUITE tests."
+        exit
+    fi
+fi
\ No newline at end of file