From c1264ec0476fc2e88c29d052e2018990458f814d Mon Sep 17 00:00:00 2001 From: diosmosis <benaka@piwik.pro> Date: Thu, 6 Nov 2014 11:00:10 -0800 Subject: [PATCH] Moved processed metrics computation to DataTableGenericFilter, removed new filters & implemented as methods in Report to avoid confusion regarding re-use, allow adding processed metrics as DataTable metadata and use this to rewrite AddProcessedMetrics filter, correct name of Metrics::getMappingFromIdToName function, added placeholder AggregatedMetric class for future, revise Metric/ProcessedMetric hierarchy (add methods for translation/etc.), allow .get API methods to use metadata to automatically figure out which columns to select, get EcommerceOrderWithItemsTest to pass. --- core/API/DataTableGenericFilter.php | 64 ++++++++++- core/API/ResponseBuilder.php | 10 +- core/DataTable.php | 5 + .../Filter/AddColumnsProcessedMetrics.php | 29 ++--- .../Filter/ComputeProcessedMetrics.php | 66 ----------- .../Filter/FormatProcessedMetrics.php | 65 ----------- core/DataTable/Filter/PivotByDimension.php | 2 +- core/DataTable/Filter/Sort.php | 2 +- core/Metrics.php | 8 +- core/Metrics/Processed.php | 7 +- core/Plugin/AggregatedMetric.php | 18 +++ core/Plugin/ComponentFactory.php | 2 +- core/Plugin/Metric.php | 33 ++++++ core/Plugin/ProcessedMetric.php | 14 +-- core/Plugin/Report.php | 107 +++++++++++++++++- plugins/API/API.php | 16 +-- plugins/API/ProcessedReport.php | 2 + plugins/CoreHome/Metrics/ActionsPerVisit.php | 16 ++- .../CoreHome/Metrics/AverageTimeOnSite.php | 15 ++- plugins/CoreHome/Metrics/BounceRate.php | 15 ++- plugins/CoreHome/Metrics/ConversionRate.php | 46 ++++++++ .../Metrics/BounceRateReturning.php | 11 ++ plugins/VisitsSummary/API.php | 10 +- ...t_ImportLogs__VisitFrequency.get_month.xml | 2 +- ...t_ImportLogs__VisitFrequency.get_range.xml | 2 +- ...st_ImportLogs__VisitsSummary.get_month.xml | 2 +- ...singLogReplay__VisitsSummary.get_month.xml | 2 +- ...Test_sitesGroup__VisitsSummary.get_day.xml | 2 +- ...st_sitesGroup__VisitsSummary.get_month.xml | 2 +- ...rceOrderWithItems_API_get__API.get_day.xml | 2 +- ...ceOrderWithItems_API_get__API.get_week.xml | 2 +- ...ntAbandonedCart__VisitsSummary.get_day.xml | 2 +- ...onvertedGoalId1__VisitsSummary.get_day.xml | 2 +- ...nvertedGoalId1__VisitsSummary.get_week.xml | 2 +- ...tConvertGoalId1__VisitsSummary.get_day.xml | 2 +- ...entNewVisitors__VisitsSummary.get_week.xml | 2 +- ...mentNoEcommerce__VisitsSummary.get_day.xml | 2 +- ...onExistingGoal__VisitsSummary.get_week.xml | 2 +- ...rderedSomething__VisitsSummary.get_day.xml | 2 +- ...tPageTitleMatch__VisitsSummary.get_day.xml | 2 +- ...rningCustomers__VisitsSummary.get_week.xml | 2 +- ...urningVisitors__VisitsSummary.get_week.xml | 2 +- ...sConvertedGoal__VisitsSummary.get_week.xml | 2 +- ...dConvertedGoal__VisitsSummary.get_week.xml | 2 +- ...eOrderWithItems__VisitsSummary.get_day.xml | 4 +- ...edReports.generateReport_week.original.csv | 8 +- ...dReports.generateReport_week.original.html | 24 ++-- ...edReports.generateReport_week.original.pdf | Bin 527977 -> 525106 bytes .../test_noVisit__VisitFrequency.get_day.xml | 2 +- tests/PHPUnit/Unit/MetricsTest.php | 2 +- 50 files changed, 406 insertions(+), 239 deletions(-) delete mode 100644 core/DataTable/Filter/ComputeProcessedMetrics.php delete mode 100644 core/DataTable/Filter/FormatProcessedMetrics.php create mode 100644 core/Plugin/AggregatedMetric.php create mode 100644 plugins/CoreHome/Metrics/ConversionRate.php diff --git a/core/API/DataTableGenericFilter.php b/core/API/DataTableGenericFilter.php index 681c1a12f8..9cb7599147 100644 --- a/core/API/DataTableGenericFilter.php +++ b/core/API/DataTableGenericFilter.php @@ -12,6 +12,8 @@ use Exception; use Piwik\Common; use Piwik\DataTable\Filter\AddColumnsProcessedMetricsGoal; use Piwik\DataTable; +use Piwik\Plugin\ProcessedMetric; +use Piwik\Plugin\Report; class DataTableGenericFilter { @@ -22,14 +24,22 @@ class DataTableGenericFilter */ private $disabledFilters = array(); + /** + * TODO + * + * @var Report|null- + */ + private $report; + /** * Constructor * * @param $request */ - function __construct($request) + function __construct($request, $report = null) { $this->request = $request; + $this->report = $report; } /** @@ -105,7 +115,7 @@ class DataTableGenericFilter 'filter_offset' => array('integer', '0'), 'filter_limit' => array('integer'), 'keep_summary_row' => array('integer', '0'), - )), + )) ); } @@ -126,6 +136,8 @@ class DataTableGenericFilter return; } + $computed = $this->computeProcessedMetricsIfNeeded($datatable); + $genericFilters = self::getGenericFiltersInformation(); $filterApplied = false; @@ -164,6 +176,52 @@ class DataTableGenericFilter $filterApplied = true; } } + + if (!$computed) { + $this->computeProcessedMetrics($datatable); + } + return $filterApplied; } -} + + private function computeProcessedMetricsIfNeeded(DataTable $dataTable) + { + if (!$this->doesColumnQueryParamReferenceProcessedMetric()) { + return false; + } + + $this->computeProcessedMetrics($dataTable); + + return true; + } + + private function computeProcessedMetrics(DataTable $dataTable) + { + if (empty($this->report)) { + return; + } + + $this->report->computeProcessedMetrics($dataTable); + } + + private function doesColumnQueryParamReferenceProcessedMetric() + { + $columnQueryParameters = array( + 'filter_column', + 'filter_column_recursive', + 'filter_excludelowpop', + 'filter_sort_column' + ); + + foreach ($columnQueryParameters as $queryParamName) { + $queryParamValue = Common::getRequestVar($queryParamName, false); + if (!empty($queryParamValue) + && ProcessedMetric::isProcessedMetric($queryParamValue) // TODO + ) { + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/core/API/ResponseBuilder.php b/core/API/ResponseBuilder.php index b2e8bd9aea..49cb4c2f51 100644 --- a/core/API/ResponseBuilder.php +++ b/core/API/ResponseBuilder.php @@ -169,6 +169,7 @@ class ResponseBuilder private function handleDataTable(DataTableInterface $datatable) { $label = $this->getLabelFromRequest($this->request); + $report = Report::factory($this->apiModule, $this->apiMethod); // handle pivot by dimension filter $pivotBy = Common::getRequestVar('pivotBy', false, 'string', $this->request); @@ -195,14 +196,9 @@ class ResponseBuilder $datatable = $genericFilter->calculate($datatable); } - $report = Report::factory($this->apiModule, $this->apiMethod); - if (!empty($report)) { - $datatable->filter('ComputeProcessedMetrics', array($report)); - } - // if the flag disable_generic_filters is defined we skip the generic filters if (0 == Common::getRequestVar('disable_generic_filters', '0', 'string', $this->request)) { - $genericFilter = new DataTableGenericFilter($this->request); + $genericFilter = new DataTableGenericFilter($this->request, $report); if (!empty($label)) { $genericFilter->disableFilters(array('Limit', 'Truncate')); } @@ -243,7 +239,7 @@ class ResponseBuilder if (!($this->apiRenderer instanceof Original) && !empty($report) ) { - $datatable->filter('FormatProcessedMetrics', array($report)); + $datatable->filter(array($report, 'formatProcessedMetrics')); } return $this->apiRenderer->renderDataTable($datatable); diff --git a/core/DataTable.php b/core/DataTable.php index 4d308f7d21..089f1a63fa 100644 --- a/core/DataTable.php +++ b/core/DataTable.php @@ -199,6 +199,11 @@ class DataTable implements DataTableInterface, \IteratorAggregate, \ArrayAccess /** The original label of the Summary Row. */ const LABEL_SUMMARY_ROW = -1; + /** + * TODO + */ + const EXTRA_PROCESSED_METRICS_METADATA_NAME = 'extra_processed_metrics'; + /** * Maximum nesting level. */ diff --git a/core/DataTable/Filter/AddColumnsProcessedMetrics.php b/core/DataTable/Filter/AddColumnsProcessedMetrics.php index f3d8191b1f..06cdc154ea 100644 --- a/core/DataTable/Filter/AddColumnsProcessedMetrics.php +++ b/core/DataTable/Filter/AddColumnsProcessedMetrics.php @@ -12,6 +12,10 @@ use Piwik\DataTable\BaseFilter; use Piwik\DataTable\Row; use Piwik\DataTable; use Piwik\Metrics; +use Piwik\Plugins\CoreHome\Metrics\ActionsPerVisit; +use Piwik\Plugins\CoreHome\Metrics\AverageTimeOnSite; +use Piwik\Plugins\CoreHome\Metrics\BounceRate; +use Piwik\Plugins\CoreHome\Metrics\ConversionRate; /** * Adds processed metrics columns to a {@link DataTable} using metrics that already exist. @@ -65,25 +69,14 @@ class AddColumnsProcessedMetrics extends BaseFilter $this->deleteRowsWithNoVisit($table); } - $metrics = new Metrics\Processed(); - - foreach ($table->getRows() as $row) { - $this->tryToAddColumn($row, 'conversion_rate', array($metrics, 'getConversionRate')); - $this->tryToAddColumn($row, 'nb_actions_per_visit', array($metrics, 'getActionsPerVisit')); - $this->tryToAddColumn($row, 'avg_time_on_site', array($metrics, 'getAvgTimeOnSite')); - $this->tryToAddColumn($row, 'bounce_rate', array($metrics, 'getBounceRate')); + $extraProcessedMetrics = $table->getMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME); - $this->filterSubTable($row); - } - } + $extraProcessedMetrics[] = new ConversionRate(); + $extraProcessedMetrics[] = new ActionsPerVisit(); + $extraProcessedMetrics[] = new AverageTimeOnSite(); + $extraProcessedMetrics[] = new BounceRate(); - private function tryToAddColumn(Row $row, $column, $callable) - { - try { - $row->addColumn($column, $callable); - } catch (\Exception $e) { - - } + $table->setMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME, $extraProcessedMetrics); } private function deleteRowsWithNoVisit(DataTable $table) @@ -102,4 +95,4 @@ class AddColumnsProcessedMetrics extends BaseFilter } } } -} +} \ No newline at end of file diff --git a/core/DataTable/Filter/ComputeProcessedMetrics.php b/core/DataTable/Filter/ComputeProcessedMetrics.php deleted file mode 100644 index d463212368..0000000000 --- a/core/DataTable/Filter/ComputeProcessedMetrics.php +++ /dev/null @@ -1,66 +0,0 @@ -<?php -/** - * Piwik - free/libre analytics platform - * - * @link http://piwik.org - * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later - * - */ -namespace Piwik\DataTable\Filter; - -use Exception; -use Piwik\DataTable\BaseFilter; -use Piwik\DataTable; -use Piwik\Plugin\ProcessedMetric; -use Piwik\Plugin\Report; - -/** - * TODO - */ -class ComputeProcessedMetrics extends BaseFilter -{ - /** - * TODO - * - * @var Report - */ - private $report; - - /** - * Constructor. - * - * @param DataTable $table The table that will be filtered. - * @param Report $report The report metadata. - */ - public function __construct($table, Report $report) - { - parent::__construct($table); - - $this->report = $report; - } - - /** - * Executes the filter. See {@link ComputeProcessedMetrics}. - * - * @param DataTable $table - */ - public function filter($table) - { - $processedMetrics = $this->report->processedMetrics; - if (!is_array($processedMetrics)) { - return; - } - - foreach ($table->getRows() as $row) { - /** @var ProcessedMetric $processedMetric */ // TODO: should remove this and if below eventually. - foreach ($processedMetrics as $processedMetric) { - if ($processedMetric instanceof ProcessedMetric) { - $processedMetricName = $processedMetric->getName(); - if ($row->getColumn($processedMetricName) === false) { - $row->addColumn($processedMetricName, $processedMetric->compute($row)); - } - } - } - } - } -} \ No newline at end of file diff --git a/core/DataTable/Filter/FormatProcessedMetrics.php b/core/DataTable/Filter/FormatProcessedMetrics.php deleted file mode 100644 index d612ecaedd..0000000000 --- a/core/DataTable/Filter/FormatProcessedMetrics.php +++ /dev/null @@ -1,65 +0,0 @@ -<?php -/** - * Piwik - free/libre analytics platform - * - * @link http://piwik.org - * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later - * - */ -namespace Piwik\DataTable\Filter; - -use Exception; -use Piwik\DataTable\BaseFilter; -use Piwik\DataTable; -use Piwik\Plugin\ProcessedMetric; -use Piwik\Plugin\Report; - -/** - * TODO - */ -class FormatProcessedMetrics extends BaseFilter -{ - /** - * TODO - */ - private $report; - - /** - * Constructor. - *TODO modify - * @param DataTable $table The table that will be filtered. - */ - public function __construct($table, Report $report) - { - parent::__construct($table); - - $this->report = $report; - } - - /** - * Executes the filter. See {@link ComputeProcessedMetrics}. - * - * @param DataTable $table - */ - public function filter($table) - { - $processedMetrics = $this->report->processedMetrics; - if (empty($processedMetrics)) { - return; - } - - foreach ($table->getRows() as $row) { - foreach ($processedMetrics as $processedMetric) { - if (!($processedMetric instanceof ProcessedMetric)) { - continue; - } - - $name = $processedMetric->getName(); - $columnValue = $row->getColumn($name); - if ($columnValue !== false) { - $row->setColumn($name, $processedMetric->format($columnValue)); - } - } - } - } -} \ No newline at end of file diff --git a/core/DataTable/Filter/PivotByDimension.php b/core/DataTable/Filter/PivotByDimension.php index ce3ac98ec5..61e68423e8 100644 --- a/core/DataTable/Filter/PivotByDimension.php +++ b/core/DataTable/Filter/PivotByDimension.php @@ -161,7 +161,7 @@ class PivotByDimension extends BaseFilter $this->pivotByColumnLimit = $pivotByColumnLimit ?: self::getDefaultColumnLimit(); $this->isFetchingBySegmentEnabled = $isFetchingBySegmentEnabled; - $namesToId = Metrics::getMappingFromIdToName(); + $namesToId = Metrics::getMappingFromNameToId(); $this->metricIndexValue = isset($namesToId[$this->pivotColumn]) ? $namesToId[$this->pivotColumn] : null; $this->setPivotByDimension($pivotByDimension); diff --git a/core/DataTable/Filter/Sort.php b/core/DataTable/Filter/Sort.php index 9df2250288..6ffe33bced 100644 --- a/core/DataTable/Filter/Sort.php +++ b/core/DataTable/Filter/Sort.php @@ -192,7 +192,7 @@ class Sort extends BaseFilter return $this->columnToSort; } - $columnIdToName = Metrics::getMappingFromIdToName(); + $columnIdToName = Metrics::getMappingFromNameToId(); // sorting by "nb_visits" but the index is Metrics::INDEX_NB_VISITS in the table if (isset($columnIdToName[$this->columnToSort])) { $column = $columnIdToName[$this->columnToSort]; diff --git a/core/Metrics.php b/core/Metrics.php index 0f8baf5a10..01e2e66ca2 100644 --- a/core/Metrics.php +++ b/core/Metrics.php @@ -183,10 +183,12 @@ class Metrics return $names; } - // TODO: this method is named wrong - public static function getMappingFromIdToName() + public static function getMappingFromNameToId() { - $idToName = array_flip(self::$mappingFromIdToName); + static $idToName = null; + if ($idToName === null) { + $idToName = array_flip(self::$mappingFromIdToName); + } return $idToName; } diff --git a/core/Metrics/Processed.php b/core/Metrics/Processed.php index 0e6b7c969b..5fe38e9363 100644 --- a/core/Metrics/Processed.php +++ b/core/Metrics/Processed.php @@ -4,7 +4,6 @@ * * @link http://piwik.org * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later - * */ namespace Piwik\Metrics; @@ -12,6 +11,7 @@ use Piwik\Metrics; use Piwik\DataTable\Row; use Piwik\DataTable; +// TODO: this class should be removed class Processed extends Base { @@ -60,9 +60,8 @@ class Processed extends Base return $this->invalidDivision; } - $bounceRate = round(100 * $this->getColumn($row, Metrics::INDEX_BOUNCE_COUNT) / $nbVisits, $this->roundPrecision); + $bounceRate = round($this->getColumn($row, Metrics::INDEX_BOUNCE_COUNT) / $nbVisits, $this->roundPrecision); - return $bounceRate . "%"; + return $bounceRate; } - } \ No newline at end of file diff --git a/core/Plugin/AggregatedMetric.php b/core/Plugin/AggregatedMetric.php new file mode 100644 index 0000000000..5bdf8d4e1e --- /dev/null +++ b/core/Plugin/AggregatedMetric.php @@ -0,0 +1,18 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +namespace Piwik\Plugin; + +use Piwik\DataTable\Row; + +/** + * TODO + */ +abstract class AggregatedMetric extends Metric +{ + // stub, to be filled out later +} \ No newline at end of file diff --git a/core/Plugin/ComponentFactory.php b/core/Plugin/ComponentFactory.php index 9cb9cd1c1b..68415e9397 100644 --- a/core/Plugin/ComponentFactory.php +++ b/core/Plugin/ComponentFactory.php @@ -74,7 +74,7 @@ class ComponentFactory * @param callback $predicate * @return mixed The component that satisfies $predicate or null if not found. */ - public static function getComponentif ($componentTypeClass, $pluginName, $predicate) + public static function getComponentIf($componentTypeClass, $pluginName, $predicate) { $pluginManager = PluginManager::getInstance(); diff --git a/core/Plugin/Metric.php b/core/Plugin/Metric.php index 09c8d2298e..3728dacac5 100644 --- a/core/Plugin/Metric.php +++ b/core/Plugin/Metric.php @@ -8,6 +8,7 @@ namespace Piwik\Plugin; use Piwik\DataTable\Row; +use Piwik\Metrics; /** * TODO @@ -45,4 +46,36 @@ abstract class Metric * TODO */ abstract public function getName(); + + /** + * TODO + */ + abstract public function getTranslatedName(); + + /** + * TODO + */ + public function format($value) + { + return $value; + } + + /** + * TODO + */ + public function getColumn(Row $row, $columnName, $mappingIdToName = null) + { + if (empty($mappingIdToName)) { + $mappingIdToName = Metrics::getMappingFromNameToId(); + } + + $value = $row->getColumn($columnName); + if ($value === false + && isset($mappingIdToName[$columnName]) + ) { + $value = $row->getColumn($mappingIdToName[$columnName]); + } + + return $value; + } } \ No newline at end of file diff --git a/core/Plugin/ProcessedMetric.php b/core/Plugin/ProcessedMetric.php index 9fcf1f5767..da0fdbea0f 100644 --- a/core/Plugin/ProcessedMetric.php +++ b/core/Plugin/ProcessedMetric.php @@ -12,7 +12,7 @@ use Piwik\DataTable\Row; /** * TODO */ -abstract class ProcessedMetric +abstract class ProcessedMetric extends Metric { /** * The sub-namespace name in a plugin where Report components are stored. @@ -42,18 +42,10 @@ abstract class ProcessedMetric /** * TODO */ - abstract public function getName(); - - /** - * TODO - */ - public function format($value) - { - return $value; - } + abstract public function compute(Row $row); /** * TODO */ - abstract public function compute(Row $row); + abstract public function getDependenctMetrics(); } \ No newline at end of file diff --git a/core/Plugin/Report.php b/core/Plugin/Report.php index 4f8e357624..76e8f66f45 100644 --- a/core/Plugin/Report.php +++ b/core/Plugin/Report.php @@ -367,6 +367,33 @@ class Report return $this->getMetricTranslations($this->metrics); } + /** + * TODO + */ + public function getMetricsRequiredForReport($allColumns = null, $restrictToColumns = null) + { + if (empty($allColumns)) { + $allColumns = $this->metrics; + } + + if (empty($restrictToColumns)) { + return $allColumns; + } else { + $processedMetricsById = $this->getProcessedMetricsById(); + $metricsSet = array_flip($allColumns); + + $metrics = array(); + foreach ($restrictToColumns as $column) { + if (isset($processedMetricsById[$column])) { + $metrics = array_merge($metrics, $processedMetricsById[$column]->getDependenctMetrics()); + } else if (isset($metricsSet[$column])) { // TODO: this may cause regression w/ #2531, check? + $metrics[] = $column; + } + } + return array_unique($metrics); + } + } + /** * Returns an array of supported processed metrics and their corresponding translations. Eg * `array('nb_visits' => 'Visits')`. By default the given {@link $processedMetrics} are used and their @@ -655,6 +682,70 @@ class Report return Request::processRequest($module . '.' . $action, $paramOverride); } + /** + * TODO + * TODO: recursion (+ for format) + */ + public function computeProcessedMetrics(DataTable $dataTable) + { + $processedMetrics = $this->getProcessedMetricsFor($dataTable); + if (empty($processedMetrics)) { + return; + } + + foreach ($dataTable->getRows() as $row) { + /** @var ProcessedMetric $processedMetric */ + foreach ($processedMetrics as $name => $processedMetric) { + if ($row->getColumn($name) === false) { // do not compute the metric if it has been computed already + $row->addColumn($name, $processedMetric->compute($row)); + } + } + } + } + + /** + * TODO + * + * @return ProcessedMetric[] + */ + public function getProcessedMetricsFor(DataTable $dataTable) + { + $dataTableProcessedMetrics = $dataTable->getMetadata(DataTable::EXTRA_PROCESSED_METRICS_METADATA_NAME) ?: array(); + + $processedMetrics = $this->processedMetrics ?: array(); + $processedMetrics = array_merge($processedMetrics, $dataTableProcessedMetrics); + + $result = array(); + foreach ($processedMetrics as $metric) { + if (!($metric instanceof ProcessedMetric)) { + continue; + } + + $result[$metric->getName()] = $metric; + } + return $result; + } + + /** + * TODO + */ + public function formatProcessedMetrics(DataTable $dataTable) + { + $processedMetrics = $this->getProcessedMetricsFor($dataTable); + if (empty($processedMetrics)) { + return; + } + + foreach ($dataTable->getRows() as $row) { + foreach ($processedMetrics as $name => $processedMetric) { + $columnValue = $row->getColumn($name); + if ($columnValue !== false) { + $row->setColumn($name, $processedMetric->format($columnValue)); + } + } + } + } + /** * Get an instance of a specific report belonging to the given module and having the given action. * @param string $module @@ -751,10 +842,24 @@ class Report */ public static function getForDimension(Dimension $dimension) { - return ComponentFactory::getComponentif (__CLASS__, $dimension->getModule(), function (Report $report) use ($dimension) { + return ComponentFactory::getComponentIf(__CLASS__, $dimension->getModule(), function (Report $report) use ($dimension) { return !$report->isSubtableReport() && $report->getDimension() && $report->getDimension()->getId() == $dimension->getId(); }); } + + /** + * @return ProcessedMetric[] + */ + private function getProcessedMetricsById() + { + $result = array(); + foreach ($this->processedMetrics as $processedMetric) { + if ($processedMetric instanceof ProcessedMetric) { // instanceof check for backwards compatibility + $result[$processedMetric->getName()] = $processedMetric; + } + } + return $result; + } } diff --git a/plugins/API/API.php b/plugins/API/API.php index 405d5d7b3a..9d7d364187 100644 --- a/plugins/API/API.php +++ b/plugins/API/API.php @@ -22,7 +22,6 @@ use Piwik\Period; use Piwik\Period\Range; use Piwik\Piwik; use Piwik\Plugin\Dimension\VisitDimension; -use Piwik\Plugin\Report; use Piwik\Plugins\CoreAdminHome\CustomLogo; use Piwik\SegmentExpression; use Piwik\Translate; @@ -363,8 +362,7 @@ class API extends \Piwik\Plugin\API */ public function get($idSite, $period, $date, $segment = false, $columns = false) { - $columnsToShow = Piwik::getArrayFromApiParameter($columns); - $columns = array(); + $columns = Piwik::getArrayFromApiParameter($columns); // build columns map for faster checks later on $columnsMap = array(); @@ -374,7 +372,6 @@ class API extends \Piwik\Plugin\API // find out which columns belong to which plugin $columnsByPlugin = array(); - $allColumns = array(); $meta = \Piwik\Plugins\API\API::getInstance()->getReportMetadata($idSite, $period, $date); foreach ($meta as $reportMeta) { // scan all *.get reports @@ -391,7 +388,6 @@ class API extends \Piwik\Plugin\API || empty($columnsMap) ) { $columnsByPlugin[$plugin][] = $column; - $allColumns[] = $column; } } } @@ -403,10 +399,11 @@ class API extends \Piwik\Plugin\API foreach ($columnsByPlugin as $plugin => $columns) { // load the data $className = Request::getClassNameAPI($plugin); - $params['columns'] = ""; + $params['columns'] = implode(',', $columns); $dataTable = Proxy::getInstance()->call($className, 'get', $params); // make sure the table has all columns + /* TODO: keep removed? $array = ($dataTable instanceof DataTable\Map ? $dataTable->getDataTables() : array($dataTable)); foreach ($array as $table) { // we don't support idSites=all&date=DATE1,DATE2 @@ -422,7 +419,7 @@ class API extends \Piwik\Plugin\API } } } - } + }*/ // merge reports if ($mergedDataTable === false) { @@ -431,11 +428,6 @@ class API extends \Piwik\Plugin\API $this->mergeDataTables($mergedDataTable, $dataTable); } } - - if (!empty($columnsToShow)) { - $mergedDataTable->filter('ColumnDelete', array(array(), $columnsToShow)); - } - return $mergedDataTable; } diff --git a/plugins/API/ProcessedReport.php b/plugins/API/ProcessedReport.php index 040e2b768d..f3be5e3359 100644 --- a/plugins/API/ProcessedReport.php +++ b/plugins/API/ProcessedReport.php @@ -448,6 +448,8 @@ class ProcessedReport throw new Exception("API returned an error: " . $e->getMessage() . " at " . basename($e->getFile()) . ":" . $e->getLine() . "\n"); } + $dataTable->filter(array(Report::factory($apiModule, $apiAction), 'formatProcessedMetrics')); + list($newReport, $columns, $rowsMetadata, $totals) = $this->handleTableReport($idSite, $dataTable, $reportMetadata, $showRawMetrics); foreach ($columns as &$name) { diff --git a/plugins/CoreHome/Metrics/ActionsPerVisit.php b/plugins/CoreHome/Metrics/ActionsPerVisit.php index cd6e357a2a..a19fda80de 100644 --- a/plugins/CoreHome/Metrics/ActionsPerVisit.php +++ b/plugins/CoreHome/Metrics/ActionsPerVisit.php @@ -10,6 +10,7 @@ namespace Piwik\Plugins\CoreHome\Metrics; use Piwik\DataTable\Row; use Piwik\Piwik; use Piwik\Plugin\ProcessedMetric; +use Piwik\Translate; /** * TODO @@ -23,6 +24,19 @@ class ActionsPerVisit extends ProcessedMetric public function compute(Row $row) { - return Piwik::getQuotientSafe($row->getColumn('nb_actions'), $row->getColumn('nb_visits'), $precision = 1); + $actions = $this->getColumn($row, 'nb_actions'); + $visits = $this->getColumn($row, 'nb_visits'); + + return Piwik::getQuotientSafe($actions, $visits, $precision = 2); + } + + public function getTranslatedName() + { + return Piwik::translate('General_ColumnActionsPerVisit'); + } + + public function getDependenctMetrics() + { + return array('nb_actions', 'nb_visits'); } } \ No newline at end of file diff --git a/plugins/CoreHome/Metrics/AverageTimeOnSite.php b/plugins/CoreHome/Metrics/AverageTimeOnSite.php index dda436140c..bdeea363ea 100644 --- a/plugins/CoreHome/Metrics/AverageTimeOnSite.php +++ b/plugins/CoreHome/Metrics/AverageTimeOnSite.php @@ -23,6 +23,19 @@ class AverageTimeOnSite extends ProcessedMetric public function compute(Row $row) { - return Piwik::getQuotientSafe($row->getColumn('sum_visit_length'), $row->getColumn('nb_visits'), $precision = 0); + $sumVisitLength = $this->getColumn($row, 'sum_visit_length'); + $nbVisits = $this->getColumn($row, 'nb_visits'); + + return Piwik::getQuotientSafe($sumVisitLength, $nbVisits, $precision = 0); + } + + public function getTranslatedName() + { + return Piwik::translate('General_ColumnAvgTimeOnSite'); + } + + public function getDependenctMetrics() + { + return array('sum_visit_length', 'nb_visits'); } } \ No newline at end of file diff --git a/plugins/CoreHome/Metrics/BounceRate.php b/plugins/CoreHome/Metrics/BounceRate.php index cd1dfca671..4fb79a52c7 100644 --- a/plugins/CoreHome/Metrics/BounceRate.php +++ b/plugins/CoreHome/Metrics/BounceRate.php @@ -21,6 +21,16 @@ class BounceRate extends ProcessedMetric return 'bounce_rate'; } + public function getTranslatedName() + { + return Piwik::translate('General_ColumnBounceRate'); + } + + public function getDependenctMetrics() + { + return array('bounce_count', 'nb_visits'); + } + public function format($value) { return ($value * 100) . '%'; @@ -28,6 +38,9 @@ class BounceRate extends ProcessedMetric public function compute(Row $row) { - return Piwik::getQuotientSafe($row->getColumn('bounce_count'), $row->getColumn('nb_visits'), $precision = 2); + $bounceCount = $this->getColumn($row, 'bounce_count'); + $visits = $this->getColumn($row, 'nb_visits'); + + return Piwik::getQuotientSafe($bounceCount, $visits, $precision = 4); } } \ No newline at end of file diff --git a/plugins/CoreHome/Metrics/ConversionRate.php b/plugins/CoreHome/Metrics/ConversionRate.php new file mode 100644 index 0000000000..c98915a26f --- /dev/null +++ b/plugins/CoreHome/Metrics/ConversionRate.php @@ -0,0 +1,46 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +namespace Piwik\Plugins\CoreHome\Metrics; + +use Piwik\DataTable\Row; +use Piwik\Piwik; +use Piwik\Plugin\ProcessedMetric; + +/** + * TODO + */ +class ConversionRate extends ProcessedMetric +{ + public function getName() + { + return 'conversion_rate'; + } + + public function getTranslatedName() + { + return Piwik::translate('General_ColumnConversionRate'); + } + + public function getDependenctMetrics() + { + return array('nb_visits_converted', 'nb_visits'); + } + + public function format($value) + { + return ($value * 100) . '%'; + } + + public function compute(Row $row) + { + $nbVisitsConverted = $this->getColumn($row, 'nb_visits_converted'); + $nbVisits = $this->getColumn($row, 'nb_visits'); + + return Piwik::getQuotientSafe($nbVisitsConverted, $nbVisits, $precision = 4); + } +} \ No newline at end of file diff --git a/plugins/VisitFrequency/Metrics/BounceRateReturning.php b/plugins/VisitFrequency/Metrics/BounceRateReturning.php index 4137a999a5..d8f572c3a4 100644 --- a/plugins/VisitFrequency/Metrics/BounceRateReturning.php +++ b/plugins/VisitFrequency/Metrics/BounceRateReturning.php @@ -9,6 +9,7 @@ namespace Piwik\Plugins\VisitFrequency\Metrics; use Exception; use Piwik\DataTable\Row; +use Piwik\Piwik; use Piwik\Plugin\ProcessedMetric; /** @@ -21,6 +22,11 @@ class BounceRateReturning extends ProcessedMetric return 'bounce_rate_returning'; } + public function getTranslatedName() + { + return Piwik::translate('VisitFrequency_ColumnBounceRateForReturningVisits'); + } + public function format($value) { return ($value * 100) . '%'; @@ -30,4 +36,9 @@ class BounceRateReturning extends ProcessedMetric { // empty (metric is not computed, it is copied from segmented report) } + + public function getDependenctMetrics() + { + return array(); + } } \ No newline at end of file diff --git a/plugins/VisitsSummary/API.php b/plugins/VisitsSummary/API.php index 681b2d05a8..81fd49f8df 100644 --- a/plugins/VisitsSummary/API.php +++ b/plugins/VisitsSummary/API.php @@ -9,8 +9,10 @@ namespace Piwik\Plugins\VisitsSummary; use Piwik\Archive; +use Piwik\Common; use Piwik\MetricsFormatter; use Piwik\Piwik; +use Piwik\Plugin\Report; use Piwik\SettingsPiwik; /** @@ -21,12 +23,16 @@ use Piwik\SettingsPiwik; */ class API extends \Piwik\Plugin\API { - public function get($idSite, $period, $date, $segment = false) + public function get($idSite, $period, $date, $segment = false, $columns = false) { Piwik::checkUserHasViewAccess($idSite); $archive = Archive::build($idSite, $period, $date, $segment); - $columns = $this->getCoreColumns($period); + $columns = Piwik::getArrayFromApiParameter($columns); + + $report = Report::factory("VisitsSummary", "get"); + $columns = $report->getMetricsRequiredForReport($this->getCoreColumns($period), $columns); + $dataTable = $archive->getDataTableFromNumeric($columns); return $dataTable; } diff --git a/tests/PHPUnit/System/expected/test_ImportLogs__VisitFrequency.get_month.xml b/tests/PHPUnit/System/expected/test_ImportLogs__VisitFrequency.get_month.xml index b876004aa6..3633fe5914 100644 --- a/tests/PHPUnit/System/expected/test_ImportLogs__VisitFrequency.get_month.xml +++ b/tests/PHPUnit/System/expected/test_ImportLogs__VisitFrequency.get_month.xml @@ -8,7 +8,7 @@ <bounce_count_returning>1</bounce_count_returning> <sum_visit_length_returning>0</sum_visit_length_returning> <max_actions_returning>1</max_actions_returning> + <bounce_rate_returning>100%</bounce_rate_returning> <nb_actions_per_visit_returning>1</nb_actions_per_visit_returning> <avg_time_on_site_returning>0</avg_time_on_site_returning> - <bounce_rate_returning>100%</bounce_rate_returning> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ImportLogs__VisitFrequency.get_range.xml b/tests/PHPUnit/System/expected/test_ImportLogs__VisitFrequency.get_range.xml index 4ae0deec01..f301254690 100644 --- a/tests/PHPUnit/System/expected/test_ImportLogs__VisitFrequency.get_range.xml +++ b/tests/PHPUnit/System/expected/test_ImportLogs__VisitFrequency.get_range.xml @@ -6,7 +6,7 @@ <bounce_count_returning>8</bounce_count_returning> <sum_visit_length_returning>115</sum_visit_length_returning> <max_actions_returning>2</max_actions_returning> + <bounce_rate_returning>80%</bounce_rate_returning> <nb_actions_per_visit_returning>1.2</nb_actions_per_visit_returning> <avg_time_on_site_returning>12</avg_time_on_site_returning> - <bounce_rate_returning>80%</bounce_rate_returning> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ImportLogs__VisitsSummary.get_month.xml b/tests/PHPUnit/System/expected/test_ImportLogs__VisitsSummary.get_month.xml index 07e3a2a444..327d564f47 100644 --- a/tests/PHPUnit/System/expected/test_ImportLogs__VisitsSummary.get_month.xml +++ b/tests/PHPUnit/System/expected/test_ImportLogs__VisitsSummary.get_month.xml @@ -8,7 +8,7 @@ <bounce_count>25</bounce_count> <sum_visit_length>305</sum_visit_length> <max_actions>3</max_actions> + <bounce_rate>93%</bounce_rate> <nb_actions_per_visit>1.1</nb_actions_per_visit> <avg_time_on_site>11</avg_time_on_site> - <bounce_rate>93%</bounce_rate> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ImportLogs_siteIdTwo_TrackedUsingLogReplay__VisitsSummary.get_month.xml b/tests/PHPUnit/System/expected/test_ImportLogs_siteIdTwo_TrackedUsingLogReplay__VisitsSummary.get_month.xml index e58092a648..b0e66b9280 100644 --- a/tests/PHPUnit/System/expected/test_ImportLogs_siteIdTwo_TrackedUsingLogReplay__VisitsSummary.get_month.xml +++ b/tests/PHPUnit/System/expected/test_ImportLogs_siteIdTwo_TrackedUsingLogReplay__VisitsSummary.get_month.xml @@ -8,7 +8,7 @@ <bounce_count>1</bounce_count> <sum_visit_length>0</sum_visit_length> <max_actions>1</max_actions> + <bounce_rate>100%</bounce_rate> <nb_actions_per_visit>1</nb_actions_per_visit> <avg_time_on_site>0</avg_time_on_site> - <bounce_rate>100%</bounce_rate> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_MultipleSitesArchivingTest_sitesGroup__VisitsSummary.get_day.xml b/tests/PHPUnit/System/expected/test_MultipleSitesArchivingTest_sitesGroup__VisitsSummary.get_day.xml index fae1924b03..64e9c36af1 100644 --- a/tests/PHPUnit/System/expected/test_MultipleSitesArchivingTest_sitesGroup__VisitsSummary.get_day.xml +++ b/tests/PHPUnit/System/expected/test_MultipleSitesArchivingTest_sitesGroup__VisitsSummary.get_day.xml @@ -8,7 +8,7 @@ <bounce_count>5</bounce_count> <sum_visit_length>0</sum_visit_length> <max_actions>1</max_actions> + <bounce_rate>100%</bounce_rate> <nb_actions_per_visit>1</nb_actions_per_visit> <avg_time_on_site>0</avg_time_on_site> - <bounce_rate>100%</bounce_rate> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_MultipleSitesArchivingTest_sitesGroup__VisitsSummary.get_month.xml b/tests/PHPUnit/System/expected/test_MultipleSitesArchivingTest_sitesGroup__VisitsSummary.get_month.xml index fae1924b03..64e9c36af1 100644 --- a/tests/PHPUnit/System/expected/test_MultipleSitesArchivingTest_sitesGroup__VisitsSummary.get_month.xml +++ b/tests/PHPUnit/System/expected/test_MultipleSitesArchivingTest_sitesGroup__VisitsSummary.get_month.xml @@ -8,7 +8,7 @@ <bounce_count>5</bounce_count> <sum_visit_length>0</sum_visit_length> <max_actions>1</max_actions> + <bounce_rate>100%</bounce_rate> <nb_actions_per_visit>1</nb_actions_per_visit> <avg_time_on_site>0</avg_time_on_site> - <bounce_rate>100%</bounce_rate> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_API_get__API.get_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_API_get__API.get_day.xml index 81ecc67c50..ebf215db8e 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_API_get__API.get_day.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_API_get__API.get_day.xml @@ -2,6 +2,6 @@ <result> <nb_visits>3</nb_visits> <nb_visits_converted>2</nb_visits_converted> - <avg_time_on_site>1801</avg_time_on_site> <nb_pageviews>13</nb_pageviews> + <avg_time_on_site>1801</avg_time_on_site> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_API_get__API.get_week.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_API_get__API.get_week.xml index 00706ea24a..3194b95fa1 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_API_get__API.get_week.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_API_get__API.get_week.xml @@ -2,6 +2,6 @@ <result> <nb_visits>5</nb_visits> <nb_visits_converted>4</nb_visits_converted> - <avg_time_on_site>1369</avg_time_on_site> <nb_pageviews>16</nb_pageviews> + <avg_time_on_site>1369</avg_time_on_site> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentAbandonedCart__VisitsSummary.get_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentAbandonedCart__VisitsSummary.get_day.xml index c909a67f09..2ecf693474 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentAbandonedCart__VisitsSummary.get_day.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentAbandonedCart__VisitsSummary.get_day.xml @@ -8,7 +8,7 @@ <bounce_count>0</bounce_count> <sum_visit_length>4682</sum_visit_length> <max_actions>6</max_actions> + <bounce_rate>0%</bounce_rate> <nb_actions_per_visit>4.5</nb_actions_per_visit> <avg_time_on_site>2341</avg_time_on_site> - <bounce_rate>0%</bounce_rate> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentConvertedGoalId1__VisitsSummary.get_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentConvertedGoalId1__VisitsSummary.get_day.xml index c48c13a998..a9d2095dfb 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentConvertedGoalId1__VisitsSummary.get_day.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentConvertedGoalId1__VisitsSummary.get_day.xml @@ -8,7 +8,7 @@ <bounce_count>0</bounce_count> <sum_visit_length>721</sum_visit_length> <max_actions>4</max_actions> + <bounce_rate>0%</bounce_rate> <nb_actions_per_visit>4</nb_actions_per_visit> <avg_time_on_site>721</avg_time_on_site> - <bounce_rate>0%</bounce_rate> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentConvertedGoalId1__VisitsSummary.get_week.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentConvertedGoalId1__VisitsSummary.get_week.xml index c48c13a998..a9d2095dfb 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentConvertedGoalId1__VisitsSummary.get_week.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentConvertedGoalId1__VisitsSummary.get_week.xml @@ -8,7 +8,7 @@ <bounce_count>0</bounce_count> <sum_visit_length>721</sum_visit_length> <max_actions>4</max_actions> + <bounce_rate>0%</bounce_rate> <nb_actions_per_visit>4</nb_actions_per_visit> <avg_time_on_site>721</avg_time_on_site> - <bounce_rate>0%</bounce_rate> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentDidNotConvertGoalId1__VisitsSummary.get_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentDidNotConvertGoalId1__VisitsSummary.get_day.xml index c909a67f09..2ecf693474 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentDidNotConvertGoalId1__VisitsSummary.get_day.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentDidNotConvertGoalId1__VisitsSummary.get_day.xml @@ -8,7 +8,7 @@ <bounce_count>0</bounce_count> <sum_visit_length>4682</sum_visit_length> <max_actions>6</max_actions> + <bounce_rate>0%</bounce_rate> <nb_actions_per_visit>4.5</nb_actions_per_visit> <avg_time_on_site>2341</avg_time_on_site> - <bounce_rate>0%</bounce_rate> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentNewVisitors__VisitsSummary.get_week.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentNewVisitors__VisitsSummary.get_week.xml index c48c13a998..a9d2095dfb 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentNewVisitors__VisitsSummary.get_week.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentNewVisitors__VisitsSummary.get_week.xml @@ -8,7 +8,7 @@ <bounce_count>0</bounce_count> <sum_visit_length>721</sum_visit_length> <max_actions>4</max_actions> + <bounce_rate>0%</bounce_rate> <nb_actions_per_visit>4</nb_actions_per_visit> <avg_time_on_site>721</avg_time_on_site> - <bounce_rate>0%</bounce_rate> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentNoEcommerce__VisitsSummary.get_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentNoEcommerce__VisitsSummary.get_day.xml index c48c13a998..a9d2095dfb 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentNoEcommerce__VisitsSummary.get_day.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentNoEcommerce__VisitsSummary.get_day.xml @@ -8,7 +8,7 @@ <bounce_count>0</bounce_count> <sum_visit_length>721</sum_visit_length> <max_actions>4</max_actions> + <bounce_rate>0%</bounce_rate> <nb_actions_per_visit>4</nb_actions_per_visit> <avg_time_on_site>721</avg_time_on_site> - <bounce_rate>0%</bounce_rate> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentNoVisit_HaveConvertedNonExistingGoal__VisitsSummary.get_week.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentNoVisit_HaveConvertedNonExistingGoal__VisitsSummary.get_week.xml index f8181af56d..32b66284be 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentNoVisit_HaveConvertedNonExistingGoal__VisitsSummary.get_week.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentNoVisit_HaveConvertedNonExistingGoal__VisitsSummary.get_week.xml @@ -8,7 +8,7 @@ <bounce_count>0</bounce_count> <sum_visit_length>0</sum_visit_length> <max_actions>0</max_actions> + <bounce_rate>0%</bounce_rate> <nb_actions_per_visit>0</nb_actions_per_visit> <avg_time_on_site>0</avg_time_on_site> - <bounce_rate>0%</bounce_rate> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentOrderedSomething__VisitsSummary.get_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentOrderedSomething__VisitsSummary.get_day.xml index 6b178d1ed5..44b18e613c 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentOrderedSomething__VisitsSummary.get_day.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentOrderedSomething__VisitsSummary.get_day.xml @@ -8,7 +8,7 @@ <bounce_count>0</bounce_count> <sum_visit_length>3961</sum_visit_length> <max_actions>6</max_actions> + <bounce_rate>0%</bounce_rate> <nb_actions_per_visit>6</nb_actions_per_visit> <avg_time_on_site>3961</avg_time_on_site> - <bounce_rate>0%</bounce_rate> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentPageTitleMatch__VisitsSummary.get_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentPageTitleMatch__VisitsSummary.get_day.xml index c48c13a998..a9d2095dfb 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentPageTitleMatch__VisitsSummary.get_day.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentPageTitleMatch__VisitsSummary.get_day.xml @@ -8,7 +8,7 @@ <bounce_count>0</bounce_count> <sum_visit_length>721</sum_visit_length> <max_actions>4</max_actions> + <bounce_rate>0%</bounce_rate> <nb_actions_per_visit>4</nb_actions_per_visit> <avg_time_on_site>721</avg_time_on_site> - <bounce_rate>0%</bounce_rate> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentReturningCustomers__VisitsSummary.get_week.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentReturningCustomers__VisitsSummary.get_week.xml index 4a69adcaa0..fc0095a9b6 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentReturningCustomers__VisitsSummary.get_week.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentReturningCustomers__VisitsSummary.get_week.xml @@ -8,7 +8,7 @@ <bounce_count>1</bounce_count> <sum_visit_length>2165</sum_visit_length> <max_actions>3</max_actions> + <bounce_rate>33.33%</bounce_rate> <nb_actions_per_visit>2</nb_actions_per_visit> <avg_time_on_site>722</avg_time_on_site> - <bounce_rate>33%</bounce_rate> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentReturningVisitors__VisitsSummary.get_week.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentReturningVisitors__VisitsSummary.get_week.xml index 6b178d1ed5..44b18e613c 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentReturningVisitors__VisitsSummary.get_week.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentReturningVisitors__VisitsSummary.get_week.xml @@ -8,7 +8,7 @@ <bounce_count>0</bounce_count> <sum_visit_length>3961</sum_visit_length> <max_actions>6</max_actions> + <bounce_rate>0%</bounce_rate> <nb_actions_per_visit>6</nb_actions_per_visit> <avg_time_on_site>3961</avg_time_on_site> - <bounce_rate>0%</bounce_rate> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentVisitHasConvertedGoal__VisitsSummary.get_week.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentVisitHasConvertedGoal__VisitsSummary.get_week.xml index c48c13a998..a9d2095dfb 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentVisitHasConvertedGoal__VisitsSummary.get_week.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentVisitHasConvertedGoal__VisitsSummary.get_week.xml @@ -8,7 +8,7 @@ <bounce_count>0</bounce_count> <sum_visit_length>721</sum_visit_length> <max_actions>4</max_actions> + <bounce_rate>0%</bounce_rate> <nb_actions_per_visit>4</nb_actions_per_visit> <avg_time_on_site>721</avg_time_on_site> - <bounce_rate>0%</bounce_rate> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentVisitHasNotOrderedAndConvertedGoal__VisitsSummary.get_week.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentVisitHasNotOrderedAndConvertedGoal__VisitsSummary.get_week.xml index c48c13a998..a9d2095dfb 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentVisitHasNotOrderedAndConvertedGoal__VisitsSummary.get_week.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentVisitHasNotOrderedAndConvertedGoal__VisitsSummary.get_week.xml @@ -8,7 +8,7 @@ <bounce_count>0</bounce_count> <sum_visit_length>721</sum_visit_length> <max_actions>4</max_actions> + <bounce_rate>0%</bounce_rate> <nb_actions_per_visit>4</nb_actions_per_visit> <avg_time_on_site>721</avg_time_on_site> - <bounce_rate>0%</bounce_rate> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__VisitsSummary.get_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__VisitsSummary.get_day.xml index 0902118d1a..bd9117bce7 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__VisitsSummary.get_day.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__VisitsSummary.get_day.xml @@ -8,7 +8,7 @@ <bounce_count>0</bounce_count> <sum_visit_length>5403</sum_visit_length> <max_actions>6</max_actions> - <nb_actions_per_visit>4.3</nb_actions_per_visit> - <avg_time_on_site>1801</avg_time_on_site> <bounce_rate>0%</bounce_rate> + <nb_actions_per_visit>4.33</nb_actions_per_visit> + <avg_time_on_site>1801</avg_time_on_site> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_csv__ScheduledReports.generateReport_week.original.csv b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_csv__ScheduledReports.generateReport_week.original.csv index 0939181278..ad3cd28109 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_csv__ScheduledReports.generateReport_week.original.csv +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_csv__ScheduledReports.generateReport_week.original.csv @@ -4,8 +4,8 @@ Piwik test,5,16,16,$ 13361.11,5,4,$ 13351.11,100%,100%,100%,100%,100%,100%,100% Piwik test,2,1,1,$ 250,1,0,$ 0,100%,100%,100%,100%,100%,0,0 Visits Summary -nb_uniq_visitors,nb_users,nb_visits,nb_actions,max_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate -1,0,5,16,6,3.2,00:22:49,0.2% +nb_uniq_visitors,nb_users,nb_visits,nb_actions,max_actions,bounce_rate,nb_actions_per_visit,avg_time_on_site +1,0,5,16,6,20%,3.2,00:22:49 Visits by Server Time label,nb_visits,nb_actions,revenue,nb_actions_per_visit,avg_time_on_site,bounce_rate @@ -484,8 +484,8 @@ New visits,1 365+ days,0 Returning Visits -nb_uniq_visitors_returning,nb_users_returning,nb_visits_returning,nb_actions_returning,nb_visits_converted_returning,sum_visit_length_returning,max_actions_returning,nb_actions_per_visit_returning,avg_time_on_site_returning,bounce_rate_returning -1,0,4,12,3,6126,6,3,00:25:32,0.25% +nb_uniq_visitors_returning,nb_users_returning,nb_visits_returning,nb_actions_returning,nb_visits_converted_returning,sum_visit_length_returning,max_actions_returning,bounce_rate_returning,nb_actions_per_visit_returning,avg_time_on_site_returning +1,0,4,12,3,6126,6,25%,3,00:25:32 Provider label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_week.original.html b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_week.original.html index f0a2507dcf..dbe23a2221 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_week.original.html +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_week.original.html @@ -551,25 +551,25 @@ <tr style="background-color: rgb(249,250,250)"> <td style="font-size: 11pt; border-bottom: 1px solid rgb(231,231,231); padding: 5px 0 5px 5px;"> - Actions per Visit </td> + Bounce Rate </td> <td style="font-size: 11pt; border-bottom: 1px solid rgb(231,231,231); padding: 5px 0 5px 5px;"> - 3.2 + 20% </td> </tr> <tr style=""> <td style="font-size: 11pt; border-bottom: 1px solid rgb(231,231,231); padding: 5px 0 5px 5px;"> - Avg. Visit Duration (in seconds) </td> + Actions per Visit </td> <td style="font-size: 11pt; border-bottom: 1px solid rgb(231,231,231); padding: 5px 0 5px 5px;"> - 00:22:49 + 3.2 </td> </tr> <tr style="background-color: rgb(249,250,250)"> <td style="font-size: 11pt; border-bottom: 1px solid rgb(231,231,231); padding: 5px 0 5px 5px;"> - Bounce Rate </td> + Avg. Time on Website </td> <td style="font-size: 11pt; border-bottom: 1px solid rgb(231,231,231); padding: 5px 0 5px 5px;"> - 0.2% + 00:22:49 </td> </tr> </tbody> @@ -6482,25 +6482,25 @@ <tr style="background-color: rgb(249,250,250)"> <td style="font-size: 11pt; border-bottom: 1px solid rgb(231,231,231); padding: 5px 0 5px 5px;"> - Avg. Actions per Returning Visit </td> + Bounce Rate for Returning Visits </td> <td style="font-size: 11pt; border-bottom: 1px solid rgb(231,231,231); padding: 5px 0 5px 5px;"> - 3 + 25% </td> </tr> <tr style=""> <td style="font-size: 11pt; border-bottom: 1px solid rgb(231,231,231); padding: 5px 0 5px 5px;"> - Avg. Duration of a Returning Visit (in sec) </td> + Avg. Actions per Returning Visit </td> <td style="font-size: 11pt; border-bottom: 1px solid rgb(231,231,231); padding: 5px 0 5px 5px;"> - 00:25:32 + 3 </td> </tr> <tr style="background-color: rgb(249,250,250)"> <td style="font-size: 11pt; border-bottom: 1px solid rgb(231,231,231); padding: 5px 0 5px 5px;"> - Bounce Rate for Returning Visits </td> + Avg. Duration of a Returning Visit (in sec) </td> <td style="font-size: 11pt; border-bottom: 1px solid rgb(231,231,231); padding: 5px 0 5px 5px;"> - 0.25% + 00:25:32 </td> </tr> </tbody> diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_week.original.pdf b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_week.original.pdf index 3db8e7ed770c4ed225c87091b08c556f0397bc20..fbfae51937bd72976b27399f655d34a16b2e0b5c 100644 GIT binary patch delta 14766 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 E0aUJ&!T<mO delta 17697 zcmZvC2RzmP_rDR>mX(#r-rehNGa6QAwkXLc8ObW+CbNv}o1N@zvNzd6vUey_Bt>TZ zUsRvpH~t<EkKXU|I_G)D>zwmC@0W`GxjrUv6{e}-FbIUKEZ1EpM+-As3b%x16Sc?* z1jEKXoS(Q(<7tIy&PqD2Y;@-FvKfMt3LC`j;_<f?*0fumWb*Zf8W+1<AMT7{ZXd9$ zWeb^@)TrikHXed5AtFt~Y0rmc`i4)p)5<j#Ff?UZjbXJgZa;ZX8mEfVLTE^jH#e?t zy-794t!<ghOIv*9#LDtq<>V|<O9+~F@{l;0#7VB09@=Ik_~L2!6^2jQFM|y=PLZ)r z(Gr^`M=0LV`(fX~q2p?LXQjy--n8WKj2Dl}I+dn*@n%r^arOQ_>)TpOANQCUj2+cE z7A|GoY)u-*VT)ukr8{9-pAGjH3@?`Ymv13(MGNa!FWt_QUVlgl|N1y#7zZl~S=Dh9 zPfzCGsQDT6$Tl{$)uCk>0r=zuH`->4w4aeCsB|iSbyN7kGz*Kkt}UI^j|*{=?il&D zT|oCF^N~!>FSf645x-vr9?29OeodS$8i=`N*TDCPEEA_KZ2kR#@#5`74w8AHJ^jFT z11d%{%Ig|m>Mx#8vRsMfG!R#@md_hXihcC3cb9;yuIopIAy1_TF)o|kGum>M=A_bQ z?!c-nq1o97HrC_h-w1Dz=Set(gpzYFHu25PTy7JX574MqoOE^_^jw^B$#ghh^=0-; z`D8)g_KuYtE_^Q2EZE*o<2LOGuCVEie5pO_Nt4xcEKfN^rcSy<5MT7k=@sJm&~)W; z%6XRO=rQKWot2u@Yx(BT0luffH$E7tsc@kLE<{BrFUdr#xrcpPAbVfEf{0$`vJMC{ z`k+8P_HD7RF*zj}>F_L%U`jSiMw2J2_Z<a?Pn7${jxkQ!-CUS(^qdDitT|YBo5uIc zSC48F5=MRRvS9jj$^||$PP&no6nffol}se%Dmnz^_iJerq;8kxoPe^g8yR24rj=^7 zI<|ke(6PKYKOR9r+HRmCkSB7XAZLZvp$Jd+XkjwQHs`vTN^j*_N?d%-nnjJ?it=V@ zze2|1bM8u<akS=0XGlPNio<A|P-m2RXN2k%TPx_72bx@%%8KR*cMMN{Ag%dT{^(fw zD5*qvgD}-@iJ#Ato(K2rnP&9K*wvRc`8qzqFpJ2FCDw|MzuwuC!`^Vcnm*n~A#SwH zoA5ZLo;Qo^+pYIAjA1lNr@0WdHN45cG{Oq<SLQ!P;vSrdm-0@L{l1v5KqT|Rt~9_@ zEA^5+p32>X@3@*zrgg+CoxyjFt{PD3ipRqzPjTk6za8iE2@t?fH4#LIM6l#Yp52tC zBPAOaF(zi@Z|;ws5@$VoTJrHamvB5EOy4<hRR%^ym;buVKdZoafAKt(DXkP?K|tct z?)_`gIO-^td`W{%buLm${WN1Ai?nAmFKSIB3XeTl@3?<F`gO$99NF_djq_yMB$4un zm*{}@rYQ1bAD1KK=Pw=?yL={IdUSg7ruu478I?f3W!Fun3HQqo{V~nCmk(YRUJ>)4 zs+{7RCt{vV{-xV!&UA8H`_t(+Xyg2cB7`MKzqDPPzD^^xu7bbtCRy4<LGNR)T9}_E zwMSZ?XO1_sc>InYv0QFbZJxJ2wY6;&>#do)vr{oTXOXK4pQ{RxtKq^wN=aoMa{!xF zFq@J{u==eTXi293H>iBRDY2q?CUR9i>I2dtBm0NMz{Gu><Ok+;pH01uBUaipO1L+l zB<JA__{7FUO3j@=Yg(WhX-do6>;$hb%pirY3#>A#8Po<QHu#LkH~Tyu!Aie=Ji_v< zm@bF8h~a^QyUha!Iw?q&86EpM9hCVxw+j)Sojo<3`1OV3w$B4Y8im<k-lvlyq%1Ed zrDQI;TgY~z2zK5Au6O2o=JAw`q2uqkU1;9u;etlUy|MyLI%0kma+e*`W)Oa?C%z%` zNu0}DHel4l=+^d+=pw8^2sWEhK$`?dEHZ7d%y6Z$Q`Pa;Q??@1S%WEI6pFwxa`^<G z0-u6)1{Y~CV+AwPEETESqiXS?a>hSLL|cg>oUDp>kSV)?tDDum%{?^z1p%8>HU*cK z5l&y9*P!X%3Gvc?ie^oUnk7@h{!I8VlM0=*5<G9m+0Sv=*^hk6LQ^<BYEfR43S(za zyIIEzSMX?wxHQU}oqem>yfzIb3&A(}j2kzno}PHP0n*3K?UEoGL#TfIb6$4Z{9x|r zMUAwiXQ!Itbj#&h?_X4LAtw)pzFUo8#I@xpBeaAO8)~_q#vxj4^lEayXn7k;@nuSg zCuT-Jh%y-KFJ-cxk;br>44k_%{5+Gjl=pR%nAazs@^-1tr)dU*8&71j9^Q~$r=6IZ zk|R2^m4#d3>iVWVs&IK#bR1f0YbzajJZSaRa^Ba^k1k!<yDMF;dV{5rB)5`D#*Y#g zkl-Fq&yXc#wqf>3*1VL~rMf8cTEO|6YL~bPXtIk$<;>R^tv`DHm_06b^H$C95SI}> z&6PG`=g7T9rjq1|hE!I0-NF*33J80tJ;7(0uHZgXnVk+b3GVq9t2f@=rlq}QPeaQc zLMI*17jg_}9mVX>^=N;Jg4$Vb@Q9}3hT^!`_*oIA&JptFnY{48{)8L3DHBg;xcDNr zZk78B<?7Tf<y(C?+oZ4y?G}6+8Db~|X_A#V15rsxlfLfkqEd6Ly!=OmccLTO%;v*c z_*dYw`Oi)_e(w|S9*rB%J^FatcY!~fDz*FpA38NNMhB{-d{0H~S;jTf$#wrdoUOMV z+J$YAR4eXsq{~eH70?AT3dc4s7?8>0qh^F3z%hL8+Qm6mXIYjdc-OI{%^~CC%`y&` zLVv8Cyo_M-&%E8V9p(M5aXIf@V-)P6Rb-U+8{>wEyb{h;MTVqDQiXmuu{+^$Y-UYr zExy<Nzb;+whPtpV?CT4jHEY3DGQFoCFIh>GidQ}3SRVoF4>A^6kWYfa7aH@mP8G>= znoTz>FMFELq)uRmUf=uh&alj^bv^p)r6!RkhVt@O28I!`UNw4_i}r-7b{92P1m8;E zCXYBypVjd);8_*HX=?LKZ@c5^*wf@(&MnQB;(Q9*89S*vNLlmEd|cUmoH&*oQ;v8i zKcJ-UwLSq!HTBPs9lkbl$K8DdlHYO1K5FNhTPJ_61_#Tji7B>ImpFLbP|6%EwIrgW zl0UpFd+pw>bWa4pUgT0g5#!f^2kR%_@-KReL4%FF^)#br#LRpu>Q++Q+Sr93lKHqD zxHKgkfBPvx*lc;s`QmrCad|pq*v@VpGIy1GueQJYnvj&2yGDB_IbJnHGsOj1jry~$ z>$k!mm62%x^%~t)Jksb6t9|t#eJdGO@6fq?Y21BPTW=_TB{8{gMETjd=Py49tej*r z^*wW1^y}O5J3FObXP!}FWWRVRyL87jX-;IXI>d$FZqxKw_7KE**9B`hHz^mkEiV^M zGxU({qP8@NG)8>~w|KlE<>mg6uWc+zVrz;Ir-)*1C(x20(+2h&W3XGt(QztfrGrA# zRC9w1@n)Y9J=D(;3-N_nzQ(UFgxl9W>HU@b*@cvBoGs~WSL6F(zE)Vw!)^5ujycio zyb~4#mLJYPDvwgc<!We+m^iq*yRr%j|G?|seIDx;V~ctI>xG*oo$C_;JNpoU4=?GG z;^z^;z=GYtB*he;GAZ`r+c$_P!Y92bxFVF$I&OEnE>f1;)<fSREHp`88K-#E*LnMk zCH}ZNutjx!1G0IKgl>=H)oS^w+{d4fMH1&?5*(bU73<H*%H0{03BL1-(KMz0Ve*-( z;Z?78X{8?oUQL$?ZrY5LKWfh5TxSh-KBZWChkc@C(?V&fwIDR+F{4HNPihs4H_9ba z`l35HBozM75N)J(cN}%RWwf3M-@_ZgwMn{Yd~!JU!+b{EM%aAcNO7y}$x%nPQux+a zPc93}XV+p+UgkySAyv4nNmlA0qOQrWV$oNa;>5Gl?1eIMeLpzAPGjHa&a}G6vevjW zwD#N*XlgJgtUM)Z2~lL&Uc;U5fB1FniMsgWlSpFO$2O0on$e%$eLj0X;}RC74S$_S z?_c#$sI5|Dkutk!$E>j>>eL&(5A}TlzAKbszO=;l>2R}W(VF7Er)v82*qPl=*Iqa4 zugV>Mz3lp-jQ-)h(-i}+8|<v=rOGKA&wo@rS8hD|rQ3EH11Gf)va~BN!A-}GUu4b= zQyB9XC{En#nJ6p1R(xEA>GcE<f|qmr=r&66v-#j6wUcKj7xSd_B1=V-cF5Wt;%}$c z?#y3E^_X~7_rzm@?6b>;=lmQ%EdIj7iFT|`^yJ*C2p?bmywlzm0<fkPW$or&q}(fN zU&Q$>r=G8G6!B!vL!HEZx%O<;&|+2A5AJZyyD}QCx=C-Tiz&(wEuo9nyuzig-t%$C zYCcf3JwdcXEcW{O4w9|JE8(hZti3{&o<GCYr~Gxjyei~J9{yqr@X7O*D|B<>F`k|> znkKd{vyTufd{;MHN{;k{Ub@8^lXcDgLR~nk8NqF$XZZw7B*9m?aTWK!(UUic7~bz- z5_#O-H9a#dpy{q$7jbiGT(7?jRvPca_MG{B42=|<OV9Od3Fm)~v(;)wU^P>>_?2J( z*l2&KFm`_VxhAz8>AFZl0Sm_+0;5IE2t%>EiVIXdSN-QCmX0S}FFUSoiPEDdLJh6o z@|nB~pDGNNmoW<#kyOXsYCbl1>^{FP>09m}AwtK3*o(DIvB_Om@2)YIjTm;klDbi# z6)>xLk~}5oS<v9QdnQTI_V2NkdFnlZ#9B1S@-xKQ_Bkgh&BGnO#5`uVE?^x_vQaF! zJ{gg^c2+p-p_iA!dTrhHT(SJ&I+gnqr6L+tmd|vJb}PGQ-Uu7$WZ`ChK7RRb{jqMG zw0faD^T-S4kqn&TrD@IcKFzmkn)uwltDHs*42+rId`YCDl9pB?vb`pt{A596>|F?1 zZ*xM!w9NZ(@p#QsABmeU=f@6~HKn&!e&i)YrV3Ch6X`B|f3<!0l18o%mAVF9Pe`6a z_8XqS<tNXi1<4H(85l*DaWMI!SvW#Ig-mZsuVR2qJB!f*$N1h%d1fi$`KGbo)8_`0 zY;oM?eFW^r@3d0`=k6%+o(ec0`CP7ejexJgSzT|}MCFoR?ni317~Kf79Dvat!SyNN zr(kDuM8lxWg{f4GLeMoE#=HecW_!wwhdfN;$j7^+7pk>7*_gL-a9@__f2xQ!`$;ty z$GTLb*(y*mhW5N;jWy~|UuOTZnGvBrS=P;Dy|(-m=^&<6^s&9`moI5()cd@*9+7Du z+}&@;Utrt3sJWBjZ57&6cXMX^+=wxC&D%88C8!N`joJ$PWwLP6q>igQFTCx2iwoE` zTg%4K)CqSj-<TRiTF>CJR%4mC89NhgX5Nftlh(OdI8Z0B>oE#j+dsKA<Hj*?YFv+U zA%gXbf(SC~#3^`kX69Wn>2%pR&ZO<q6Q&DZTw>BG0+eP8Ms5lk(sCG?@Drw)R!}i% zenHyn`$SD?IfQ)C2~z><vtrU2g0$xQL@hwP0En5^I7TD4OM0jJdP-M)bKShGi?55- zs1H2=M6FY;fEe}M+ROU!KJkqKV5wK4{6f~HI9rn)$5Et*bQSZLQ^@V47l}Rd^<lhr zj8DYC+bzecr%7)$e)V;HdOOFk{chB;^2XKP{N6Jo9<ZHNX>JewOo?f+Q^)2*j4w3W z;P9yiQ9Ua~_>WfhrwqQO)V*x9SX;R8{6}~d+2wv{c3R!9#66+yY`!GibNn`&muE0e zXe)H#&Y+t4%Z5eDSTm16efgT$m<_gG{du-80n_4_*N8N{=kPuL2|}w`dNM6WC62nF zMTDy7pPYt`z;VBbBzs-ADJ<-6?BAT=v%?{j0aJ#A;Fk#e5`*7k;FqL)%8+#9Ck_VX z`rqT>eY}h{yE0?j@bsH45!ds~bjd}9MKJQlM&D}+WKF(j$w<wqTCWiiGC%_#oW4fJ zLPgr>9dwq<k1MQchC6JQ!iSPs{0iBXEQfbZAr#EQSF*HHEY+)X5)*%Xc-^+LG%!*B zt;SPhr^Mxh+*s_LgkQKyQcn97;qP{`@M|iZPfe#^?+KMpyVq92hf_P_j7FzTH`SOp zO!i)u^@$;WsEdCQQwu}7w@!b~Q(tFYasIqMwSCEcb-0}szWC`jKEr6LK1+foUeRlF zIsQg}cQohZX_z*%X<=FL7=AZxn-crpaPmpst(AdFSHiXFxCRp(azl}EP#eGd-1h7g zSzJAx;TgC7%H2UpaEUXq!jR<bd$}%v#QjdNP4rc##h+Nab1U9&o~&d$ba;$R+~q*k zM@C2}^lJ!>IkR7EvHD<t+J-VCmonw~<K0?^H!9!Eh07LmHzEYfsq)F($Kv`X!s-H& zuMc^iG@(y5>oCmd#<7v42v|C{`X^Wo&8sbUtuM_yEU($qzHNF=nTP8mWxgRpYOmWj zSi9tLxXanaiH9{<{@aT3R`m{THN<nfUZiL5vRX90OZR?Gdls?V*6^f??s6yeVtD;I z!3zu0^pYZ}R<0NC$ki5dZ1L>=93h@mTOoPvv#95rl1b?oc$yU#iMB@)m1UY6eC4AM zvHKvTv?Q<m#Z0YFzv+&+PqBYfFeAn3`1JO8^BOUUVH&~Mb6Te=2wxXU^*&EiJ$}J6 z(AbUMDK^3OyrNZaUZ31U%aKI6xd_)+f^2S(@dxT*B~DaM*K}3Bi{6IlIR!=dYSm=h zbLqTW{`y8}P5Kln569cXAGMfOVo!#3O@Dl?XNVxh!_nz+%>)yr$;pD~#U8p{!FPJ| zu_Ys%&q|9Py;@{H)|f7(rC{rKM=P?cg)O|o#;1;qxT*e=uQL5->etdu(`v9c(eo^x zEsdS@@X1xLfyHys<LY0EN-OCtxBA9tn$Jo*AuCxYKTbtE3W(wQqBs2WURSf8x-b-@ z8km2&{H$vNEe8ADg}SP9YW^25!*(;#ZBD9BE%L+R#wl|`5;>#KG@8iD(YL;nE$5NN zi73>vEE+jVeMj_Y7(U~1H?~K14SiU$2}>_7!z|u+lychKiL1PP8ZKE}9;Ek)K9%u% z0Bl71bW~7qUC#}2+<eSpMdwRuNn88OV4c<{c1?O;qp#^WF;wzxBdUUX=bRVQYE!P3 zToH4xCJG6-UKzM}(NWduO8nJ~a{|lDDMYoGJk`Zzt70eU_h_9)pEF5X*t=6W)yrk& ziE&qvRPsqy@oltIBo?Fl$FAJ7hYt*$AopzYpP=`In6xfT7~!0nro8mS-8cN{*Pa<2 zbGoH=fxG;C{Y5;raSD%y)3R-B_WTCqhV5v@qVEmh%uTxnHN_{PpYyKXw9S_=vQZ6G z4>L}AGOI9sPw9y)mCrX7o4cjndDLR!eDay?wtbiRt_XRgq$w(HxXeiRPna6o*goo0 zcBK4{r_R=?7n8)5m3vN7(?|#4Xq$|_zPahhu)TO!+S6*rq=t}VbR6>%wdqlkIo+7d zq$7f=dU!H*I^mHdzTQFKd}y&fuTQ&I+Jo>rZSV)JypcuS@0)^sw!A&L)QkNZvd`*j z#N%w4C3E`S(chKRRxX~s$}6%d{0_ga>Bgh@&}@bO{c#Ci9No5PMtomD2YsDhx`l#P zf88VA4|<h8IW6*XBp>;mZrGo_xr-te99DO7QTyyC!GC&k!^erI>i%AxdKx8LQ*?yd zje_kvwe5@M(8)kqWxYGP4r%4A4+~5AE}(yTz_R>Z2%o;GjxPN$QRpZ@TUPdJu|Gf1 zdQm?@mF3Og#s{1yrHXr38AqbYGqG!W%3>TH<89rG!tNsXw9;!k+!+~COXzEG)x7${ za0xsKNXcE35MlSoTruJ8_i+=gJ%rUUdYYb(2+HO4M~y$})-_EzlD~=f854Q_Iktkh z+xK&}R(r&Z-r~#JK_-$L`IyBihoAmg?!r#I49@AB?^?ikc(;%QWS^fNqdoaI=W_#( z9!yC{+)7#Cy&+H6QeDXlL|>Db^-sz2pQAm|s2|whmatc^n7JIH0abGE;y<?#)IDJE zL*&{Q0!idllv~tG^oxK}TO0X8rfTBFs9Hbv4Iy`)T(K2@`j^PIw`Og9Lhh;oTENcb zbNF&!9AZ7ye6hH85Xr}K)AlR+i7nmd7WI^_4ZY*fi)*!pVy<<~DDr=Lb`J2oeq`1$ zC1|5sto5CtQFffwX>_W=-l}7&*!Ch`Pc{C9iz_L|xH0*8KKE3CC(0;42KJ#0DWA|~ z>ZA+J8yAg?n^FnZihG4kWix1y9}%=~zrte9;@YSBp^rb?hUa^`CX%0F`zmZ{)FXcF zJMjcBM~wuTSW~CfkcYf`PO9L2CncN6Q#6`s6y^huYKVR7LaS5Oj=fNUn#gu9P>vZB zUP!5ZGxT9bCjOf1AoKBvt2aA`3xx*Myw0a=9CNL|p@a7p@S;*|yv4q!{;IM5LPOCI z_V|6A#)8ir(`&j@yUz-QhIo-n49psGB4-#l^DhethkkXQ4YpC8m6TgDn&n<jUs`{- ziM(e&?kjIO6fFEv`Kebr_RC4H+tCID47r{vCg!}-D))l)E^jwYO>u=rmNUwJ%d4F% zFvi8`1VpcQ9_yN~u8N%UkgjFPc-|-;XS_5iU_5*lir(f=j94Zw42@QtjlaM2>)VT6 zDfL?6E6KNC-_(A&WF(zcT(W!BzpKAmKUeRH=K0H8cZV?dbN0R<*R87ub_Lfu+U*jH z*93?!e3_$d2?;Pw-e%^j?7V<?F@xO3=SD*A;Utg;W5$_F7Is!n)?5e)Eb5=JV>!{& zf&G1A8*ZmACt7s0m~Z@a%v;}~JGaTGUlI~gMV)Ha%KwsRbKmw%qzGXrvQPc$(-eH{ z$@hZG-ILL=sbXP(vJzURnUS7;_Hu+~KUD?RTESW=@alErwV;!=xICBAGkfM|EJbeW z_m)&g@Xht&V)T1gZq@IMPk)<S*peX-$z6@{F8tX@4;6K2CPKHDm_7b(0r~dAMMX$W zaOvsuP@(i(yUqUFx<lVS`w>;k&s;}1*JPcHj%xOseV8#<c2`ZQ0@L8yuM@^=D%#$A zgTkC|aOa($((HC2rU6&tDQeOeGI!y<W<G|yW6C&#K%8mIW}GMyfh<^h`(oQb5}kgl zVma3$)|C|VjZ8yisp$Exw&{lB$^z_r3!&Wut6|6P*ogbNSto_saWSg->`wfbBJ_QI z<&$KR%`<eDb(Ocy)wyZkyX$J-=~>eLWhG=o!YPraW&Rh%T4XG4_p;Tul1*VJE`{*w z`;t@R{4t(MZ@;@|E^x}lE8bp^2(Ravs!Ou!lEtmv{+Zul*wUO=RVw3TBYH9=tGM@v z73GghnF7*EOGMs#y@N&K+XY5?RC7g6D?ejNUR5Uw1fF>{E;mIdymJK^EK?E-u{`0x zq(V3`z&iDYDTDm^XWUgeWvlw|OAC869>c!A1smtPyaI~ne*HRESyH{nz+wAyWr}bT zO2hov-4b5k%UoMtrZuy2b#hQ0FLE<{+LF>WxOX7fIsU@WYEM}4?Ap^B(T?)a^efUL z1T%L{!sDx&Tz(~rXD3U_$QU-!v=TU&7|$e4sfWIl`GAv_G5LlQU$)2!VE8&HYF^&> z=y|a%;*r<N=?FIr9Va8EnmR*uDfCSga^=1^!N}m-ui+bO?#|)Ek2?jXpNg}Pk`Qo` z1(mmrdyc}mkI5&rNuV!2B$js9(e7DV;qiRHbxP%xc_?i<@?<JYt5Tzoty1B4pGO#t zu?&Yh{wvS3txD)uaCD~ACn`!Zo6UT<E|{{-{}M=Swyg}x*x;{Pen~@c$KUj|goYJm z&+<gQWZ9Hy9KrGQY+cd4_)8%!C$?^BeDBn3*q5ZC{H(!Ts8LBzG&8N|?8QazG?EdS z(S+E#qRu^sSdX^L4ARoiCnq^|b+{USq9~-hbW@?mlgU^LM_8RMQXE<mVoFdb!)BK= zXi|AvG+%y1pH=Gf+&1?o%!d6~!gsCcc*$lOBlOmI;iAWE@*<gu=o<2evq`)g#~7U* z-4?Cn<K7!eGi8dk{EQhx)6C);*G0Ar+!rGV6ukuLskR41oFS^mlRr}71n4LSs~iXG zC^_v4_PXNSaa&n?F~=GPPp4S&@XFr~8XC%ve$8DUD)NO~=RK$Jnx$0}?<2RBFV0ji zjl+KgRq);S!9BUxY4OZva^AmCDW5q^{9^5>D23dWw{N><E^N6v+_unY5A}Xbv&iiu z{V8nQxRT;se&It$=GZHO4s;0>C4B8A)(c*SeJHme-ta=4#%PzrCSl%fhwh+UCpcnA z$oMqD%EyrBHXH<`ZZRj%O9hawqC&U6#wC@u*UJ)6@%$<#fHsu4ED3T~AJd9^@!j_1 z2>tnJDdppM9$qGKBNvR+d6M`*-q@_@u9lm^k56DOO?31QY=@8uMMfh}o^u%<z4wY+ z<?{5>CxzZyRXB$vQf_6^+eYd(Ecxxx?UJ9&t-p_u6X;_sIrPX*R%R}9M6-k<w91~C z%O>BUC78IyLBP-GEL5`bg4f`~ryNPT^-%ZkF5{U<nJ1rVY>RrSJ1dCb-zu-n(`k5+ zVRwigkhcW5-cWmJlSka}^?AROBjka|IqzQX3Rc<c1SdOjDRqPunls0f<rWD?(h@WL z`%bMGh{+|lp)}$d&KN-+cp7H2zNaBTJNug$c$tnQpBp>|Ts@r?!Z%|=7<^^om{!|j zZ%9H0=N*rCeZp=7+izoc;iC$Xor%1G<JZG4u6*Sxo*)$S#FYyUAX-G^-`w%#rsE_c zSXD4}{8m<m>sZZN$Lj73XWwh+^<r;xw&jk2%!a4ENE8$fWKVr{?K|Ui=kZ?u<>}9H zSH#y`csPXRakr3S#~LP2y-d<8T~6(|rv@RY@qOn|w|Q(V=&C;#shf*WLtUa3-SRsX zyC)Z1g3~8Fhe;rJ`?svoPj4#LExEZrW5?(zJshE*$KgJ1R-Kw`AbjA{?iumn)xh?S zjJ4;u_1gMfbLiK3FC(FpC*lY*f}i5_yVq+bTdK#qd=vyOY)iTHd+%Xy8VlTFzNZ@I z8s`2mo#Wz_!CQt7VN!$-?0W0<bSzf`2+_1ZZ*j1Nbw?3+RfX-$baX73$mkZdKDu#= zRj7T@CGGAiu66xJUwx2;{B>ugIO^$A8tSgeOdZ=cgQel88l(;P$iHyBmXqo?;WzJB zzs&ymuCVBtdS`|o_pLeDCUk4v?|adF8?C|$uG(G3F+U492a$>p2vl|OC)SyDD1SDs zlxHJ9r2MJxTICt*s*jMAX8L186*Nz-`JJoIouj97UOj=c>!PDD5562^6t@0W5-}C% z!Efwla&dj<lH}I_-HKLbseV;{a|uzMa-Q;Ie(!DN=?SVoWjGtqPwz32>#tDDD1G<H z=(2Q5bFGX#rsX^!uGb}IB_C&`7|W&|9cL847rvv_UHKy<c;!K2Z&Z*YwQ6d2{tM;w zV)C}|PZlo|a3rGydCd{+dn}G+*ZSWWRJy<9sWk}G6W(cTCNef`ZwMVK=3-9;3M&=E z3u2Y)v<hM`Nson3!C51%{Wu;u^OS1NPC@q}I9#h{ZZ~sw<}WKHaiQ*&aOFjPbT>2# zJN5>1u<VIQR-SvmG8XDlZbjMuSa+I(5$lVSzFg!d+HPFMO%2>PT``N82*gr&=-FCJ z5ECfto^w^rbNnF^2`d^47v%ZOeDkzMtMi~Fvr#~6*PiO+GP0{O>P}~-(Pe{^XT_5T zE?g#Fps3s&)Ib7$1GF|J-^z+Zrn7b7M0ud}3cIg)L=CS$o8ALNThXS4yb<gRCr*@d z?R<`5SVhH<Btm<Ioy5-7p7DqA&T7!WR#T84ch3!5!rh)5xnkyqVO>%$-QP$eF0N2D z^cc+V>>-7*dKOpnw*8%nx<YG|W)yh6ja>;y?w;yU;WwYv`t(4mmY6b}SDd~ggm7i7 zjNtma3W<x+{a>pFi3&Oz6TY8%`63X<D_<kP=qBLE>>>ZQFLgay-VB7S!fjY`rgP7~ zFmQyOhwwVWPc|uAn6^7%ea#spPsjLmIw#6C_q(ynZ=kc^^VyrP*PE+d77@E4Kid@P z`-2a)IxilPW?(a0c(q1P$Lo<C$1BB4QuJRdeRYFvuj;YQk9M{&zj&DMY%PSNq-XZ# zt)FBbhsCWGPbq)X1ApKiP~aFYl_#DIJujfEeHE|j+;3q+9o=|=s{=w`L@CYq)mFQb zvt1byH`6(IF3K`ght?!XP`JawR-WjAQpEIf5N&nh*SEora;aHYW1pHVr4kUZG#2sD z!R$}x-s24vHP>iW3FEGh46M$<$qzU=;+@SG+&a6~kh0oDn?9U5iek^%S}7NVQQP@F z?-M%=Zl<<F7>WoJOhc64c6bgCOwh+YiQbH_d%`&1!nClfYo-1+kvZAO^1R?u<N1ku z97!s1N-K}eJnmipz^uB|sxw<4n3osAIG=z!w}mevxv40nCX*0oo`-uQigUc$_Yx<W z=p=rkocGeZ;LzMhNbffUrmF>v>k?&L9D)4<=k~tF**q5QXLOX)(kV-d+pySMyg#Ea zYi<-aq~S5JXe@B&OzQr`FzadkMJC2zg;lNI>ef%5%nT1hzgqQ8zRu3N?5k`hq$h3| z4SM<47w0Mmr~LTd)_YEKHv-pTf(+*DwJMOi^Fi_B?Z~Tw^`F~2$6L=x6%UFj-IeaH zzw}y00)J;%0e$Yv$0x&ADvRDY4pYxL)K%CxuDlrLuS3a9^ZKX4>qf%$KvkVlvHf_d zRdVA~e8+d%3E?_?$`Agkxlm`3r8=%l>Tfkf(#bDyTpoa>fA^>xc^pZLqq&i8Q!~h2 zW)!Bkv5>ahu3MH9F>E~YF!$two4te@-K#c}JZR11bk2`Ya7#}8>gH~azowmB(3atC z@4bJl-W+ZUf0*#r=?o>Fvy;jAj90>(akgJ4toCYrQYP7^K{b0zfn}`X_FS@;dDT)e zf!e!ngxu7!QgvEOHOFZGBb<9jmMo3KkAa#`Nj48HHom*M>I89#I4ZUT$z8rFzdb1N z(rtF7AwRn^IW;d>r(+yrse!9;B-v)FOr34<bfsx9{a!^Ssw74ApqhW-O1;I^wjx@A zSqr}?{rS+xpnGDy+>3aOB_p#R5jrfy8ZrmfJ+1Mv;#_)SoWqvi&VgeZc1cSlx!F>B z3va_;5=glE9$unhaYfimrdRf9V9)|%J+~{>#Cy2Qi8LlxNBf(U^c>VPsthH)RU8^f zUWZ?U%<%QPeHK6MD0_}ONXg=KF(pyNgI<m9-5y(}7&SsK8$~j``A|P8DSAG~>JlEj z>#V6isYBalw^#XNT)oVRk0~<x5^g!(Hf)l{VWvj@<!5J2FOpwd*bJ^Fxla;NBg~uI z&OtlzokNCT?v^X7aTrY$!Owfr&h3Lim4r!raE#F0XsdXdR^-W0cozG`B0YQ&e}xP0 z{qELM9#8URY&U1xhmCu$7f404s48r4e}LAhmie2v&tc?XL%3Gz8Qp{nyXr!GU+!Kj z`mDrA*-xP-zM?uC>MXC@j4{ml<ftN~jCt3P`24Z|olgc!=|oAhZH&>cj992tO{r%z zRPU@VZc#lZxk+Nu=w%oNf8k#jx}{v1HXzAPtk{TEOLmaT%d}=G56<`*n7XOY8|y(j z+T&50g&0prB~iouVpxlktM>@LYPA-))!hpX@Cas{e`~!rCU9cSD}A~5^mJ{Y@$+H9 zUy0=++R)(mHtjR1<Y)WWi47k~b9V?5FEKS&e7kfxN>X?(zXRK1sgoE@jQyxD`+BEm zsWp|%XT3*osQ^0d#ZKT(m+yCr#eKm;<it+Mya&bU$F<@jxalO5vo}{kFEuBlzmzlP z`PLK?x!^npPgRZz`|+j2Pe?bFV5a4vhqF?kq&jisnOLuUA=`p`YQt3KCFUlxBx=?7 zM0HmuG)(4|<m(XaQc*d0r@gy#@XMP$9bcb2%C_Y?=QiK}@qIU?#{SG@CSvvW^iR#t z&sAC)qGhFIeQ?&tSP5`Z^FI{Nx7Nu|LRaDvnmaEn3$m{2@Yf49tdCp`-5YJH?LZJ{ z5<DZ4E(>E&T5CERT{@}Fw;uW^Rv^BBx0RbGV%Pu5eSG`3!50j2$&q%fs_7o<pH&Dn ztSFj^^qrmKSao-HH$SV|QHt!ME-#wLe#>F<i*%l=`}iG)tL7lHYjabU35yh`aM0Di z?PVBYe@Zo}A=?>Q@KGaCjEds6E_tYMdg2@$vM17;!LqukU<$u>`GH9FO+J%fmJ)mG zH^z3q75psMn#s4Nq+0t-(3>>)()_~vtTgGk9?QL;p!HNA?(z%c;$#j!(jsB=H<V?B zJ9diu8P;>(;+$*+SKn;Rka~w`MqOvYi3{)C?dK_pB~tKu-+j@0#|eQDb(o~eV{cWi zbgIzwutr_3&wfJHFcjLyAI>>D%5pAVZiaGeHuYmdb>wLRSw?cx6Y~LXc1)_h*<&IR z(%NA-Xma-Gd*?Qzm`ZM5s;{5#iF#^_bDR<GwWN$pN0Z@->Ip*oh(F^yZa_}qr7R!@ zgh+h&O$bYQt_6gY5D&G0P)3dqoWzSifiU1dgFl@UqVO;a$kk(5E)05~^C6zq8sblg zj(jt~k8ibxSmKkdA(Z=2x+Dk~7Y17nnC=sT?_~(pK2kZ{1~N#9r?UCY#E-|?LL>-b z`%upKceapzLfAf3`IsH#A|as!{<H(+IwAbGCel0L-iFKJk4dq2AYO!seQQifurMy{ zf#DDFdybGMLgWF)hr19tLVW$*->USEA-S*zHv8gfTp*jjZ7vsch5RBU#2k1<f`D>i zvHQw=@J#n13wV)xf2`(nhrA`k|GfVPiUiFCgB}>|gU|AVFyS{mAs_!(PKtw&65*%4 z{zQRP0t0vtJn+SDcth6lRNlWmD5v*<<PqXOJ^aIo=k$Y+{Eq(t>Q8*V?;p<B{t!!| z-=T-%<M0qT5%j<l=W?3I5KY2Au2jcDh>7qfK@h6_`0EqHpa;IN;K63v;H6U_(fGiS z-wy3>s4*dQ-)ks-H6Fr>PkIJnB89`bV6Z=%aW4WwgTE673Bo^ma$p7ro;Ms4j^7RY zZ7=`693?&}62SULKql~|;gC1w@F<88A^v(Kcr=ZHP!i%pq9L$-lM%rD{Y~DtSc4F6 zjsFu_VDvE}LiB%@pz#G(5EJ~qc2@ZRT*k3Pn_pugX(u2cJWfD}PYH)G;_Krfa`?Rj z2pQN8D3>-qIT8}Z0sG$@Ji+jNq10=P4Fm+l|H;)Q0FzdIA!k6a&m=-l{uiGZd`=QX zU_Um7c<twq2ROt&F4q}lI2Q)>=Mlk$!Tfmy`2_v*h~mOZ{CPxkVgHI@xWIklZv-qC z_OBTD(<Ti1R}cmRFMma065!>pFbvKG{tEh69)<u*{~;j3HvNZy0x$m|fW!oXzjeYu z<^j1sFIez`{PQ9KOn@B(4LBzOOaQFE*(87oFzmsLtZaE-DkSX~UcMe=_@gWcC+#0( zbqhBqE|`P_zB~(5Bw+(s#$-d#9DkNI9W7kIGVC|xA7(f{I2&S%cgh0HG%p|m!v8Y= zao`X0AEVD(+;!qIhT-4U0U>B5L<P^C4LN~7H3~L=@de~GXbcY75FtD~2XYO+l?~y+ zm*qhC02TEDP)TwDwSNC8H1~j)A_qL%<^!zNX@C`x1F+QdAYwpZ;=iS;Jg{^l7s7?- z&4+M;rNUf@EdF6WpknfXfaVP3IDRc3!U~o=@*slv-2y;806doeXPxCDff<1<!A*kO z1owov&S;uBTG)YrVd41m`M)L1@UQbBeE6z@101RXpyEL>L=_)h0IYK?gunp$KmjoK zbs=!Vq!3VNih<X4QxHn(e<9NffpBgS5Ed%}Y#_E2_!Gqt5rAM<1PUZ?0-}uHC<3Md z1T3H`6a(DRmw&_1SqzpcN)E!nR`M4swFImm_!{*R!VaW9>@Tgn1ZwQ}Mb%3W0$unL zU?rA9uHrGJ0A`{L!g<I%r&7RSRR+A+D}^BNJ7o|_fF@f8;-FmtM8LMH;@ip~Quyt1 zP?2Eo%7LQ7eh}}va<Cp&3E?;dDO>>{*((8LNd-g#pI3PRxwcOwt_HRNNZ-F`i<N)T z9I60X-x!26rWQmfuo^-Kl#NvZA-|fxvAA9h;m0f0Kp4PMTs4r4s{z*W)PSv`s67b7 zl^P%*-}zTyz6OB4s)e9|0Dmp;iMI}zm0t^}4~8LR_~#&V!P0ImkOEnJ4ez&~%6jz& z`B+g0G?di?4WPo9@hlAx4#4YH4>rxY0r-DVSO+i@4F`FGY5*{w8viP<YXE8h79&2Z z@nC(U0U{gI1n_W;zwwU$U1@3rlFP6DN~$ygN#W)LkAj<k6~4_tim4f_&o>`faj_X# zA^!?k(YsH5_6ouSY$JLFc!^p7Z_q0c6UUYV?_RwEylpKY%`UY7+|^ca07<kS6i;9a z5D04p0(7mA)A-%i13R@_fq-rs03Y9{HnbhUoM;2QjO~Co84&PJ?FSh))CMf~?EY)H zX*<w>={Q)5YX<@e9YBDm1FY|M9Qb3}0l@V;0r<i`wXE}i%F+pVk9Psyl>N<f=z<6U zfBHKC?{F93HSPjbRQG}JPrCqbL^t3)y{~tz8zKaFb-Dqs@oV7aL^rU3rVm0!bNAm; zJoy@AKxYqFJ!n>GufdaD4+IXR`(6XgnI3>?*aI-n_8#Q=^BzFW?*&wmUO)wys({y_ z7r5-x2eM^rpSsxxu?JM6K0uA{2ZRIg**=IiUZMX0#`+C_0VSh~zf%R)kH0;LvSU9G zXc+*6gYLB54`IW1|6US)3j}xvfI!Jxu<knmVFnsL>{CIBtKjVhfaQ{d2X&Az0Gx6e z1lI5lLRj!Cg9p)29|XLh>!{#|1_5u`&_Tmt83HOPhXL=wnE`TlKXS7}fOl~iXtNmx z+78<Hm63yldNB-^>PEm4d<2L}j6#q=;KBZL_$YuO9|Z!WV+Y{Yqkw8W2B-&Kf>Pe^ zOA=$iyqF1K!-1DoW8jHu5{xcS#}CZ^JoeX6r*Q}`-eBS&*K)_fW`fSBf=5n(V}ot- zfND1ZG#E~TZnm)x__yQI;8!OPbU`QoVpU8+F!=7N11i<jZ!Bee)D)09Xqqw82TO}n z0C0SI-{fgfFV|)u?0?VD--jd?hVPk%aQ}{^<P4anI^IFpPX9SNFPVY!5B6uWkd@v4 zzf<<tZ&ARo2>h{GNGBn(ymuDjPYWh1y){S*2*&0bn9z~<v)>>rV5Bnq2I0V=z%jr7 z!)3=svHvglf436*2mJoeUm5}lg`tnqBrsrJ_+LICi`pMG4$-jt6UV<agv9>f0e)!z zQ-XvdkT7KVvF{)!aA+iO@qb025^xFVAsDCx5{5cTL+y_-|H@*Z*rPNg;*jf52`m<V zpcnUlzC+<qIOebtI1IZ#l>MUwE&)gW_US*Dpl~D<eS{B*lsLkNLc+nk_8%V54+XKr zVvY!7QAa#MKw(EbLBO$p0{nl*AP{gA7#IIjvj2cUOF$1t8i7XPkcT}+0EdqVW0CtK z=Rbf*FrXgF6e!r%BTA46@W=GSvIq?3w=uZ?vl@wl?N7%4DnX&ZALb9y&{*^l8U_L8 z)qnX=5^(5Y#V83h>Ypg=#~%ehn6>{=jDjPPhogW(Ade&=Fz-kbqR>Z^8ihHU)MzLI zhWp1FU;-M7IidtDfjQza8V*0=F&c$I9NtbeTH;6^q0v~xpDMxqt$ZjN1IHdN6AToF zIviFE6m=xwFfhP*DEt@+i6gm%LBQbuZt*cF6obHPZ9y1tDC7}`FevPP&--U*Fc=K- zUkuPrpa}ROJ_J$%cDR}mAh_^D6^THD52$^-{Y>~93<L%Sn!&${5g0fMc_^Pi8vku? z|09b*0i=J727F)}4%4tu?EmOE=mZE1R^o_-7%cj5#P^HzaI^pob+{rCSa3UW*kjP8 zk%yy&h2fC<-+})dY9NdSH#di95}<b;p`kH{J;uV}|1>&)g22K-;vJR+-QfTa`2Sz{ zu?Y13XZF9wAmN9T8-YcFEIZ7HlGy(k|5p~2<Pqo4h<^;+k3Ry7#vVTE5P$-1gAM_L zeLA8T3q2ZEEJEUc_IMuzfyJT@H&Y~_<KTxZ1VrTF><8TjiaM12fCgIKzXl?q5-{`; zJ_*F(+yZ=P=x@FM*NMU54#gbWV^Cpe%n<_-*u(7s3C;lYp{)ZnIQr1O0~+$*Ee7!i zMD+eW$^OsZTtGrWH68H;C2@56Kq3A=wExePg2L?InEa~)4TS;!4--KLIYL8#8<WF) zsKd<%3<DU%5n0TU`~at_#NSckzfKH@prIXBf&uOE2n~C<(IBB<8aNVaEd2jNLmsLU z90)%abHo#HL3MbD0Vn^_$bcjCNMt~+9!WURY!6os5_Dh~0(ZzeaFw-x1NP58fg7zO z`2m9+X}16nb9ib4H0=I;-M@ICO8({>?(bL(lYk#SZILhu<l%`5(7<_n1Q3flVl*6f zc$7fG;73|8=)YjBJOT(u9}OWKdo<LDgPXg5y#o#IuXq1B2U6=O4FyW^;QaZ&vV(!6 z=m_Kf&L8#|35Or$LmgFu1V`XuSrqjDB7^($RRWsXk!*#b5Qk?{@Iin&nja`Iog7wz zKH5KEU>H6eX&elFWQN@DWq<4QzlH=F>;GB(*Jun#|HFzgM~-qN49uyA6~i#7{fan< z|Nkk$0M5gJ;DA3$lQ^1iV7fcXhdi1ySoHs#8<f943MCNWvk*T)M8*N8!86+S_WR$R tAf^Ym-*%Sv;0+`=cmp@`6nCA>9G%=8Ei5U(myQGmLBYp&LE|FD{{vZEMfm^# diff --git a/tests/PHPUnit/System/expected/test_noVisit__VisitFrequency.get_day.xml b/tests/PHPUnit/System/expected/test_noVisit__VisitFrequency.get_day.xml index 937fbcb558..c415099916 100644 --- a/tests/PHPUnit/System/expected/test_noVisit__VisitFrequency.get_day.xml +++ b/tests/PHPUnit/System/expected/test_noVisit__VisitFrequency.get_day.xml @@ -8,7 +8,7 @@ <bounce_count_returning>0</bounce_count_returning> <sum_visit_length_returning>0</sum_visit_length_returning> <max_actions_returning>0</max_actions_returning> + <bounce_rate_returning>0%</bounce_rate_returning> <nb_actions_per_visit_returning>0</nb_actions_per_visit_returning> <avg_time_on_site_returning>0</avg_time_on_site_returning> - <bounce_rate_returning>0%</bounce_rate_returning> </result> \ No newline at end of file diff --git a/tests/PHPUnit/Unit/MetricsTest.php b/tests/PHPUnit/Unit/MetricsTest.php index 610e1cf459..20202232ef 100644 --- a/tests/PHPUnit/Unit/MetricsTest.php +++ b/tests/PHPUnit/Unit/MetricsTest.php @@ -39,7 +39,7 @@ class Core_MetricsTest extends \PHPUnit_Framework_TestCase */ public function testGetMappingFromIdToName() { - $mapping = Metrics::getMappingFromIdToName(); + $mapping = Metrics::getMappingFromNameToId(); $expectedMapping = array( 'nb_uniq_visitors' => 1, 'nb_visits' => 2, -- GitLab