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

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordiosmosis <benaka@piwik.pro>2015-03-11 14:31:07 +0300
committerdiosmosis <benaka@piwik.pro>2015-03-11 14:31:07 +0300
commita1388b84ba44fb67b21b735ffe3b38060c0e94f9 (patch)
tree83ce5c30f2816be5d0ec380f91d56885d367f17c /plugins
parent070135f195694a52552d3bafb687c7fcf7f6988c (diff)
Refactor AttributeHistoricalDataWithLocations for clarity, fixing IntegrationTestCase issue and fixing changes to RawLog...
Diffstat (limited to 'plugins')
-rw-r--r--plugins/UserCountry/Commands/AttributeHistoricalDataWithLocations.php287
-rw-r--r--plugins/UserCountry/tests/System/AttributeHistoricalDataWithLocationsTest.php14
-rw-r--r--plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getCity_month.xml168
-rw-r--r--plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getContinent_month.xml80
-rw-r--r--plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getCountry_month.xml202
-rw-r--r--plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getRegion_month.xml154
6 files changed, 672 insertions, 233 deletions
diff --git a/plugins/UserCountry/Commands/AttributeHistoricalDataWithLocations.php b/plugins/UserCountry/Commands/AttributeHistoricalDataWithLocations.php
index bf1d2aabc2..dc2221573f 100644
--- a/plugins/UserCountry/Commands/AttributeHistoricalDataWithLocations.php
+++ b/plugins/UserCountry/Commands/AttributeHistoricalDataWithLocations.php
@@ -14,6 +14,7 @@ use Piwik\Plugin\ConsoleCommand;
use Piwik\Plugins\UserCountry\VisitorGeolocator;
use Piwik\Plugins\UserCountry\LocationProvider;
use Piwik\DataAccess\RawLogFetcher;
+use Piwik\Timer;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -22,18 +23,24 @@ use Symfony\Component\Console\Output\OutputInterface;
class AttributeHistoricalDataWithLocations extends ConsoleCommand
{
const DATES_RANGE_ARGUMENT = 'dates-range';
-
const PERCENT_STEP_ARGUMENT = 'percent-step';
-
const PERCENT_STEP_ARGUMENT_DEFAULT = 5;
-
const PROVIDER_ARGUMENT = 'provider';
-
- const SEGMENT_LIMIT_OPTION = 'segmentLimit';
-
+ const SEGMENT_LIMIT_OPTION = 'segment-limit';
const SEGMENT_LIMIT_OPTION_DEFAULT = 1000;
/**
+ * @var string[]
+ */
+ private static $logVisitFieldsToUpdate = array(
+ 'location_country' => LocationProvider::COUNTRY_CODE_KEY,
+ 'location_region' => LocationProvider::REGION_CODE_KEY,
+ 'location_city' => LocationProvider::CITY_NAME_KEY,
+ 'location_latitude' => LocationProvider::LATITUDE_KEY,
+ 'location_longitude' => LocationProvider::LONGITUDE_KEY
+ );
+
+ /**
* @var RawLogFetcher
*/
protected $fetcher;
@@ -46,7 +53,7 @@ class AttributeHistoricalDataWithLocations extends ConsoleCommand
/**
* @var VisitorGeolocator
*/
- protected $locationFetcher;
+ protected $visitorGeolocator;
/**
* @var int
@@ -59,9 +66,9 @@ class AttributeHistoricalDataWithLocations extends ConsoleCommand
private $amountOfVisits;
/**
- * @var int
+ * @var Timer
*/
- private $start;
+ private $timer;
/**
* @var int
@@ -69,54 +76,29 @@ class AttributeHistoricalDataWithLocations extends ConsoleCommand
private $percentStep;
/**
- * @var array
+ * @var int
*/
- private $percentConfirmed = array();
+ private $processedPercent = 0;
- /**
- * @var array
- */
- protected $logVisitFieldsToUpdate = array(
- 'location_country' => LocationProvider::COUNTRY_CODE_KEY,
- 'location_region' => LocationProvider::REGION_CODE_KEY,
- 'location_city' => LocationProvider::CITY_NAME_KEY,
- 'location_latitude' => LocationProvider::LATITUDE_KEY,
- 'location_longitude' => LocationProvider::LONGITUDE_KEY
- );
+ public function __construct(RawLogFetcher $fetcher = null, RawLogUpdater $updater = null)
+ {
+ parent::__construct();
+
+ $this->fetcher = $fetcher ?: new RawLogFetcher();
+ $this->updater = $updater ?: new RawLogUpdater();
+ }
protected function configure()
{
$this->setName('usercountry:attribute');
- $this->addArgument(
- self::DATES_RANGE_ARGUMENT,
- InputArgument::REQUIRED,
- 'Attribute visits from this dates.'
- );
-
- $this->addArgument(
- self::PERCENT_STEP_ARGUMENT,
- InputArgument::OPTIONAL,
- 'How often command should write about current state.',
- self::PERCENT_STEP_ARGUMENT_DEFAULT
- );
-
- $this->addArgument(
- self::PROVIDER_ARGUMENT,
- InputArgument::OPTIONAL,
- 'Provider id which should be used to attribute visits. If empty then Piwik will use default provider.'
- );
-
- $this->addOption(
- self::SEGMENT_LIMIT_OPTION,
- null,
- InputOption::VALUE_OPTIONAL,
- 'Number of segments in single iteration.',
- self::SEGMENT_LIMIT_OPTION_DEFAULT
- );
-
- $this->fetcher = new RawLogFetcher();
- $this->updater = new RawLogUpdater();
+ $this->addArgument(self::DATES_RANGE_ARGUMENT, InputArgument::REQUIRED, 'Attribute visits in this date range. Eg, 2012-01-01,2013-01-01');
+ $this->addArgument(self::PERCENT_STEP_ARGUMENT, InputArgument::OPTIONAL,
+ 'How often to display the command progress. A status update will be printed after N percent of visits are processed, '
+ . 'where N is the value of this option.', self::PERCENT_STEP_ARGUMENT_DEFAULT);
+ $this->addArgument(self::PROVIDER_ARGUMENT, InputArgument::OPTIONAL, 'Provider id which should be used to attribute visits. If empty then'
+ . ' Piwik will use the currently configured provider. If no provider is configured, the default provider is used.');
+ $this->addOption(self::SEGMENT_LIMIT_OPTION, null, InputOption::VALUE_OPTIONAL, 'Number of visits to process at a time.', self::SEGMENT_LIMIT_OPTION_DEFAULT);
}
/**
@@ -126,96 +108,65 @@ class AttributeHistoricalDataWithLocations extends ConsoleCommand
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
- $from = $this->getDateArgument($input, self::DATES_RANGE_ARGUMENT, 0);
- $to = $this->getDateArgument($input, self::DATES_RANGE_ARGUMENT, 1);
- $segmentLimit = $input->getOption(self::SEGMENT_LIMIT_OPTION);
+ list($from, $to) = $this->getDateRangeToAttribute($input);
+
+ $this->visitorGeolocator = $this->createGeolocator($input);
$this->percentStep = $this->getPercentStep($input);
$this->amountOfVisits = $this->fetcher->countVisitsWithDatesLimit($from, $to);
- if (!$from || !$to) {
- $output->writeln(
- sprintf('Invalid from [%s] or to [%s].',
- $from, $to
- )
- );
-
- return 1;
- }
-
- $providerId = $input->getArgument(self::PROVIDER_ARGUMENT);
- $this->locationFetcher = new VisitorGeolocator(LocationProvider::getProviderById($providerId) ?: null);
-
$output->writeln(
sprintf('Re-attribution for date range: %s to %s. %d visits to process with provider "%s".',
- $from, $to, $this->amountOfVisits, $this->locationFetcher->getProvider()->getId()
- )
+ $from, $to, $this->amountOfVisits, $this->visitorGeolocator->getProvider()->getId())
);
- $this->start = time();
- $lastId = 0;
- $visitFields = array_merge(
- array('idvisit', 'location_ip'),
- array_keys($this->logVisitFieldsToUpdate)
- );
+ $this->timer = new Timer();
- do {
- $logs = $this->fetcher->getVisitsWithDatesLimit($from, $to, $visitFields, $lastId, $segmentLimit);
- if (!empty($logs)) {
- $lastId = $logs[count($logs) - 1]['idvisit'];
- }
+ $this->processSpecifiedLogsInChunks($output, $from, $to, $input->getOption(self::SEGMENT_LIMIT_OPTION));
- /**
- * @var array $row
- */
- foreach ($logs as $row) {
- if (!$this->isRowComplete($output, $row)) {
- continue;
- }
+ $output->writeln("Completed. <comment>" . $this->timer->__toString() . "</comment>");
- $idVisit = $row['idvisit'];
- $ip = IPUtils::binaryToStringIP($row['location_ip']);
- $values = $this->parseRowIntoValues($row, $ip);
+ return 0;
+ }
- ++$this->processed;
- $this->trackProgress($output);
+ protected function processSpecifiedLogsInChunks(OutputInterface $output, $from, $to, $segmentLimit)
+ {
+ $visitFieldsToSelect = array_merge(array('idvisit', 'location_ip'), array_keys(self::$logVisitFieldsToUpdate));
- if ($this->shouldSkipAttribution($output, $values, (string) $idVisit, $ip)) {
- continue;
- }
+ $lastId = 0;
+ do {
+ $logs = $this->fetcher->getVisitsWithDatesLimit($from, $to, $visitFieldsToSelect, $lastId, $segmentLimit);
+ if (!empty($logs)) {
+ $lastId = $logs[count($logs) - 1]['idvisit'];
- if ($output->getVerbosity() > OutputInterface::VERBOSITY_NORMAL) {
- $output->writeln(
- sprintf('Updating visit with idvisit = %s and ip = %s.', (string) $idVisit, $ip)
- );
- }
+ $this->reattributeVisitLogs($output, $logs);
+ }
+ } while (count($logs) == $segmentLimit);
+ }
- $this->updater->updateVisits($values, $idVisit);
- $this->updater->updateConversions($values, $idVisit);
+ protected function reattributeVisitLogs(OutputInterface $output, $logRows)
+ {
+ foreach ($logRows as $row) {
+ if (!$this->isRowComplete($output, $row)) {
+ continue;
}
- } while (count($logs) == $segmentLimit);
+ $location = $this->getVisitLocation($row);
+ $valuesToUpdate = $this->getValuesToUpdate($row, $location);
- $output->writeln(sprintf('Completed in %d seconds.', time() - $this->start));
+ $this->onVisitProcessed($output);
- return 0;
- }
+ $idVisit = $row['idvisit'];
- /**
- * @param InputInterface $input
- * @param string $name
- * @param int $index
- * @return string
- */
- protected function getDateArgument(InputInterface $input, $name, $index)
- {
- $option = explode(',', $input->getArgument($name));
+ if (empty($valuesToUpdate)) {
+ $this->writeIfVerbose($output, 'Nothing to update for idvisit = ' . $idVisit . '. Existing location info is same as geolocated.');
+ } else {
+ $this->writeIfVerbose($output, 'Updating visit with idvisit = ' . $idVisit . '.');
- if (!isset($option[$index])) {
- return false;
+ $this->updater->updateVisits($valuesToUpdate, $idVisit);
+ $this->updater->updateConversions($valuesToUpdate, $idVisit);
+ }
}
-
- return date('Y-m-d', strtotime($option[$index]));
}
/**
@@ -239,51 +190,52 @@ class AttributeHistoricalDataWithLocations extends ConsoleCommand
}
/**
- * Parse row into proper values. (only if provider found difference)
+ * Returns location log values that are different than the values currently in a log row.
*
- * @param array $row
- * @param string $ip
- * @return array
+ * @param array $row The visit row.
+ * @param array $location The location information.
+ * @return array The location properties to update.
*/
- protected function parseRowIntoValues(array $row, $ip)
+ protected function getValuesToUpdate(array $row, $location)
{
- $location = $this->locationFetcher->getLocation(array('ip' => $ip));
-
- $values = array();
- foreach ($this->logVisitFieldsToUpdate as $column => $locationKey) {
+ $valuesToUpdate = array();
+ foreach (self::$logVisitFieldsToUpdate as $column => $locationKey) {
if (empty($location[$locationKey])) {
continue;
}
- $locationAttribute = $location[$locationKey];
+ $locationPropertyValue = $location[$locationKey];
+ $existingPropertyValue = $row[$column];
if ($locationKey === LocationProvider::COUNTRY_CODE_KEY) {
- if (strtolower($locationAttribute) != strtolower($row[$column])) {
- $values[$column] = strtolower($locationAttribute);
+ if (strtolower($locationPropertyValue) != strtolower($existingPropertyValue)) {
+ $valuesToUpdate[$column] = strtolower($locationPropertyValue);
}
} else {
- if ($locationAttribute != $row[$column]) {
- $values[$column] = $locationAttribute;
+ if ($locationPropertyValue != $existingPropertyValue) {
+ $valuesToUpdate[$column] = $locationPropertyValue;
}
}
}
- return $values;
+ return $valuesToUpdate;
}
/**
* Print information about progress.
* @param OutputInterface $output
*/
- protected function trackProgress(OutputInterface $output)
+ protected function onVisitProcessed(OutputInterface $output)
{
+ ++$this->processed;
+
$percent = ceil($this->processed / $this->amountOfVisits * 100);
- if (!in_array($percent, $this->percentConfirmed, true) && $percent % $this->percentStep === 0) {
- $output->writeln(
- sprintf('%d%% processed. [in %d seconds]', $percent, time() - $this->start)
- );
+ if ($percent > $this->processedPercent
+ && $percent % $this->percentStep === 0
+ ) {
+ $output->writeln(sprintf('%d%% processed. <comment>%s</comment>', $percent, $this->timer->__toString()));
- $this->percentConfirmed[] = $percent;
+ $this->processedPercent = $percent;
}
}
@@ -296,19 +248,13 @@ class AttributeHistoricalDataWithLocations extends ConsoleCommand
protected function isRowComplete(OutputInterface $output, array $row)
{
if (empty($row['idvisit'])) {
- if ($output->getVerbosity() > OutputInterface::VERBOSITY_NORMAL) {
- $output->writeln('Empty idvisit field. Skipping...');
- }
+ $this->writeIfVerbose($output, 'Empty idvisit field. Skipping...');
return false;
}
if (empty($row['location_ip'])) {
- if ($output->getVerbosity() > OutputInterface::VERBOSITY_NORMAL) {
- $output->writeln(
- sprintf('Empty location_ip field for idvisit = %s. Skipping...', (string) $row['idvisit'])
- );
- }
+ $this->writeIfVerbose($output, sprintf('Empty location_ip field for idvisit = %s. Skipping...', (string) $row['idvisit']));
return false;
}
@@ -316,26 +262,37 @@ class AttributeHistoricalDataWithLocations extends ConsoleCommand
return true;
}
- /**
- * Check if given visit should be re attributed.
- * @param OutputInterface $output
- * @param array $values
- * @param string $idVisit
- * @param string $ip
- * @return bool
- */
- protected function shouldSkipAttribution(OutputInterface $output, array $values, $idVisit, $ip)
+ private function getVisitLocation($row)
{
- if (empty($values)) {
- if ($output->getVerbosity() > OutputInterface::VERBOSITY_NORMAL) {
- $output->writeln(
- sprintf('Visit with idvisit = %s and ip = %s is attributed. Skipping...', $idVisit, $ip)
- );
- }
+ $ip = IPUtils::binaryToStringIP($row['location_ip']);
+ $location = $this->visitorGeolocator->getLocation(array('ip' => $ip));
+ return $location;
+ }
- return true;
+ private function getDateRangeToAttribute(InputInterface $input)
+ {
+ $dateRangeString = $input->getArgument(self::DATES_RANGE_ARGUMENT);
+
+ $dates = explode(',', $dateRangeString);
+ $dates = array_map(array('Piwik\Date', 'factory'), $dates);
+
+ if (count($dates) != 2) {
+ throw new \InvalidArgumentException('Invalid date range supplied: ' . $dateRangeString);
}
- return false;
+ return $dates;
+ }
+
+ private function createGeolocator(InputInterface $input)
+ {
+ $providerId = $input->getArgument(self::PROVIDER_ARGUMENT);
+ return new VisitorGeolocator(LocationProvider::getProviderById($providerId) ?: null);
+ }
+
+ private function writeIfVerbose(OutputInterface $output, $message)
+ {
+ if ($output->getVerbosity() > OutputInterface::VERBOSITY_NORMAL) {
+ $output->writeln($message);
+ }
}
-}
+} \ No newline at end of file
diff --git a/plugins/UserCountry/tests/System/AttributeHistoricalDataWithLocationsTest.php b/plugins/UserCountry/tests/System/AttributeHistoricalDataWithLocationsTest.php
index 844d42f9e5..ec35e4657c 100644
--- a/plugins/UserCountry/tests/System/AttributeHistoricalDataWithLocationsTest.php
+++ b/plugins/UserCountry/tests/System/AttributeHistoricalDataWithLocationsTest.php
@@ -10,10 +10,12 @@ namespace Piwik\Plugins\UserCountry\Test\Integration;
use Piwik\Common;
use Piwik\Db;
+use Piwik\Network\IPUtils;
use Piwik\Piwik;
use Piwik\Plugins\UserCountry\Commands\AttributeHistoricalDataWithLocations;
use Piwik\Tests\Fixtures\ManyVisitsWithGeoIP;
use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
+use Piwik\Translate;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;
@@ -55,6 +57,8 @@ class AttributeHistoricalDataWithLocationsTest extends IntegrationTestCase
Db::query($sql);
}
+
+ self::$fixture->setLocationProvider('GeoIPCity.dat');
}
/**
@@ -66,11 +70,13 @@ class AttributeHistoricalDataWithLocationsTest extends IntegrationTestCase
$this->executeCommand(null);
}
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage General_ExceptionInvalidDateFormat
+ */
public function testExecute_ShouldReturnMessage_IfDatesAreInvalid()
{
- $this->assertEquals(
- 'Invalid from [1970-01-01] or to [].' . "\n", $this->executeCommand('test')
- );
+ $this->executeCommand('test');
}
public function testExecute_ShouldReturnEmptyWorkingProcessLogs_IfThereIsNoData()
@@ -90,7 +96,7 @@ class AttributeHistoricalDataWithLocationsTest extends IntegrationTestCase
$result
);
- $this->assertRegExp('/100% processed. \[in [(0-9)+] seconds\]/', $result);
+ $this->assertRegExp('/100% processed. Time elapsed: [0-9.]+s/', $result);
$queryParams = array(
'idSite' => self::$fixture->idSite,
diff --git a/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getCity_month.xml b/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getCity_month.xml
index 23c40113d8..4618daf140 100644
--- a/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getCity_month.xml
+++ b/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getCity_month.xml
@@ -1,34 +1,166 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <label>Unknown</label>
- <nb_visits>35</nb_visits>
- <nb_actions>61</nb_actions>
+ <label>General_Unknown</label>
+ <nb_visits>22</nb_visits>
+ <nb_actions>39</nb_actions>
<max_actions>3</max_actions>
- <sum_visit_length>21437</sum_visit_length>
- <bounce_count>18</bounce_count>
+ <sum_visit_length>13871</sum_visit_length>
+ <bounce_count>11</bounce_count>
<goals>
<row idgoal='1'>
- <nb_conversions>35</nb_conversions>
- <nb_visits_converted>35</nb_visits_converted>
- <revenue>175</revenue>
+ <nb_conversions>22</nb_conversions>
+ <nb_visits_converted>22</nb_visits_converted>
+ <revenue>110</revenue>
</row>
<row idgoal='2'>
- <nb_conversions>17</nb_conversions>
- <nb_visits_converted>17</nb_visits_converted>
- <revenue>85</revenue>
+ <nb_conversions>11</nb_conversions>
+ <nb_visits_converted>11</nb_visits_converted>
+ <revenue>55</revenue>
</row>
</goals>
- <nb_conversions>52</nb_conversions>
- <revenue>260</revenue>
- <sum_daily_nb_uniq_visitors>18</sum_daily_nb_uniq_visitors>
- <sum_daily_nb_users>1</sum_daily_nb_users>
- <city_name>Unknown</city_name>
+ <nb_conversions>33</nb_conversions>
+ <revenue>165</revenue>
+ <sum_daily_nb_uniq_visitors>11</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>0</sum_daily_nb_users>
+ <city_name>General_Unknown</city_name>
<city>xx</city>
<region>xx</region>
<country>xx</country>
- <country_name>Unknown</country_name>
- <region_name>Unknown</region_name>
+ <country_name>General_Unknown</country_name>
+ <region_name>General_Unknown</region_name>
<logo>plugins/UserCountry/images/flags/xx.png</logo>
</row>
+ <row>
+ <label>Vancouver, British Columbia, UserCountry_country_ca</label>
+ <nb_visits>6</nb_visits>
+ <nb_actions>10</nb_actions>
+ <max_actions>3</max_actions>
+ <sum_visit_length>3783</sum_visit_length>
+ <bounce_count>3</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>6</nb_conversions>
+ <nb_visits_converted>6</nb_visits_converted>
+ <revenue>30</revenue>
+ </row>
+ <row idgoal='2'>
+ <nb_conversions>3</nb_conversions>
+ <nb_visits_converted>3</nb_visits_converted>
+ <revenue>15</revenue>
+ </row>
+ </goals>
+ <nb_conversions>9</nb_conversions>
+ <revenue>45</revenue>
+ <sum_daily_nb_uniq_visitors>3</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>0</sum_daily_nb_users>
+ <lat>49.25</lat>
+ <long>-123.133</long>
+ <segment>city==Vancouver;regionCode==BC;countryCode==ca</segment>
+ <city_name>Vancouver</city_name>
+ <region>BC</region>
+ <country>ca</country>
+ <country_name>UserCountry_country_ca</country_name>
+ <region_name>British Columbia</region_name>
+ <logo>plugins/UserCountry/images/flags/ca.png</logo>
+ </row>
+ <row>
+ <label>Besançon, Franche-Comte, UserCountry_country_fr</label>
+ <nb_visits>3</nb_visits>
+ <nb_actions>5</nb_actions>
+ <max_actions>3</max_actions>
+ <sum_visit_length>1261</sum_visit_length>
+ <bounce_count>2</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>3</nb_conversions>
+ <nb_visits_converted>3</nb_visits_converted>
+ <revenue>15</revenue>
+ </row>
+ <row idgoal='2'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>5</revenue>
+ </row>
+ </goals>
+ <nb_conversions>4</nb_conversions>
+ <revenue>20</revenue>
+ <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>1</sum_daily_nb_users>
+ <lat>47.249</lat>
+ <long>6.018</long>
+ <segment>city==Besan%C3%A7on;regionCode==A6;countryCode==fr</segment>
+ <city_name>Besançon</city_name>
+ <region>A6</region>
+ <country>fr</country>
+ <country_name>UserCountry_country_fr</country_name>
+ <region_name>Franche-Comte</region_name>
+ <logo>plugins/UserCountry/images/flags/fr.png</logo>
+ </row>
+ <row>
+ <label>Lhasa, General_Unknown, UserCountry_country_ti</label>
+ <nb_visits>2</nb_visits>
+ <nb_actions>3</nb_actions>
+ <max_actions>2</max_actions>
+ <sum_visit_length>1261</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>2</nb_conversions>
+ <nb_visits_converted>2</nb_visits_converted>
+ <revenue>10</revenue>
+ </row>
+ <row idgoal='2'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>5</revenue>
+ </row>
+ </goals>
+ <nb_conversions>3</nb_conversions>
+ <revenue>15</revenue>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>0</sum_daily_nb_users>
+ <lat>29.65</lat>
+ <long>91.1</long>
+ <segment>city==Lhasa;regionCode==1;countryCode==ti</segment>
+ <city_name>Lhasa</city_name>
+ <region>1</region>
+ <country>ti</country>
+ <country_name>UserCountry_country_ti</country_name>
+ <region_name>General_Unknown</region_name>
+ <logo>plugins/UserCountry/images/flags/ti.png</logo>
+ </row>
+ <row>
+ <label>Rome, Lazio, UserCountry_country_it</label>
+ <nb_visits>2</nb_visits>
+ <nb_actions>4</nb_actions>
+ <max_actions>3</max_actions>
+ <sum_visit_length>1261</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>2</nb_conversions>
+ <nb_visits_converted>2</nb_visits_converted>
+ <revenue>10</revenue>
+ </row>
+ <row idgoal='2'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>5</revenue>
+ </row>
+ </goals>
+ <nb_conversions>3</nb_conversions>
+ <revenue>15</revenue>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>0</sum_daily_nb_users>
+ <lat>41.9</lat>
+ <long>12.483</long>
+ <segment>city==Rome;regionCode==07;countryCode==it</segment>
+ <city_name>Rome</city_name>
+ <region>07</region>
+ <country>it</country>
+ <country_name>UserCountry_country_it</country_name>
+ <region_name>Lazio</region_name>
+ <logo>plugins/UserCountry/images/flags/it.png</logo>
+ </row>
</result> \ No newline at end of file
diff --git a/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getContinent_month.xml b/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getContinent_month.xml
index 5882ac249d..37261de820 100644
--- a/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getContinent_month.xml
+++ b/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getContinent_month.xml
@@ -1,28 +1,78 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <label>North America</label>
- <nb_visits>35</nb_visits>
- <nb_actions>61</nb_actions>
+ <label>UserCountry_continent_asi</label>
+ <nb_visits>22</nb_visits>
+ <nb_actions>38</nb_actions>
<max_actions>3</max_actions>
- <sum_visit_length>21437</sum_visit_length>
- <bounce_count>18</bounce_count>
+ <sum_visit_length>13871</sum_visit_length>
+ <bounce_count>11</bounce_count>
<goals>
<row idgoal='1'>
- <nb_conversions>35</nb_conversions>
- <nb_visits_converted>35</nb_visits_converted>
- <revenue>175</revenue>
+ <nb_conversions>22</nb_conversions>
+ <nb_visits_converted>22</nb_visits_converted>
+ <revenue>110</revenue>
</row>
<row idgoal='2'>
- <nb_conversions>17</nb_conversions>
- <nb_visits_converted>17</nb_visits_converted>
- <revenue>85</revenue>
+ <nb_conversions>11</nb_conversions>
+ <nb_visits_converted>11</nb_visits_converted>
+ <revenue>55</revenue>
</row>
</goals>
- <nb_conversions>52</nb_conversions>
- <revenue>260</revenue>
- <sum_daily_nb_uniq_visitors>18</sum_daily_nb_uniq_visitors>
+ <nb_conversions>33</nb_conversions>
+ <revenue>165</revenue>
+ <sum_daily_nb_uniq_visitors>11</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>0</sum_daily_nb_users>
+ <code>UserCountry_continent_asi</code>
+ </row>
+ <row>
+ <label>UserCountry_continent_amn</label>
+ <nb_visits>8</nb_visits>
+ <nb_actions>14</nb_actions>
+ <max_actions>3</max_actions>
+ <sum_visit_length>5044</sum_visit_length>
+ <bounce_count>4</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>8</nb_conversions>
+ <nb_visits_converted>8</nb_visits_converted>
+ <revenue>40</revenue>
+ </row>
+ <row idgoal='2'>
+ <nb_conversions>4</nb_conversions>
+ <nb_visits_converted>4</nb_visits_converted>
+ <revenue>20</revenue>
+ </row>
+ </goals>
+ <nb_conversions>12</nb_conversions>
+ <revenue>60</revenue>
+ <sum_daily_nb_uniq_visitors>4</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>0</sum_daily_nb_users>
+ <code>UserCountry_continent_amn</code>
+ </row>
+ <row>
+ <label>UserCountry_continent_eur</label>
+ <nb_visits>5</nb_visits>
+ <nb_actions>9</nb_actions>
+ <max_actions>3</max_actions>
+ <sum_visit_length>2522</sum_visit_length>
+ <bounce_count>3</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>5</nb_conversions>
+ <nb_visits_converted>5</nb_visits_converted>
+ <revenue>25</revenue>
+ </row>
+ <row idgoal='2'>
+ <nb_conversions>2</nb_conversions>
+ <nb_visits_converted>2</nb_visits_converted>
+ <revenue>10</revenue>
+ </row>
+ </goals>
+ <nb_conversions>7</nb_conversions>
+ <revenue>35</revenue>
+ <sum_daily_nb_uniq_visitors>3</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>1</sum_daily_nb_users>
- <code>North America</code>
+ <code>UserCountry_continent_eur</code>
</row>
</result> \ No newline at end of file
diff --git a/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getCountry_month.xml b/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getCountry_month.xml
index ee389b9ac8..70c2dc42e3 100644
--- a/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getCountry_month.xml
+++ b/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getCountry_month.xml
@@ -1,28 +1,202 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <label>United States</label>
- <nb_visits>35</nb_visits>
- <nb_actions>61</nb_actions>
+ <label>UserCountry_country_cn</label>
+ <nb_visits>18</nb_visits>
+ <nb_actions>32</nb_actions>
<max_actions>3</max_actions>
- <sum_visit_length>21437</sum_visit_length>
- <bounce_count>18</bounce_count>
+ <sum_visit_length>11349</sum_visit_length>
+ <bounce_count>9</bounce_count>
<goals>
<row idgoal='1'>
- <nb_conversions>35</nb_conversions>
- <nb_visits_converted>35</nb_visits_converted>
- <revenue>175</revenue>
+ <nb_conversions>18</nb_conversions>
+ <nb_visits_converted>18</nb_visits_converted>
+ <revenue>90</revenue>
</row>
<row idgoal='2'>
- <nb_conversions>17</nb_conversions>
- <nb_visits_converted>17</nb_visits_converted>
- <revenue>85</revenue>
+ <nb_conversions>9</nb_conversions>
+ <nb_visits_converted>9</nb_visits_converted>
+ <revenue>45</revenue>
</row>
</goals>
- <nb_conversions>52</nb_conversions>
- <revenue>260</revenue>
- <sum_daily_nb_uniq_visitors>18</sum_daily_nb_uniq_visitors>
+ <nb_conversions>27</nb_conversions>
+ <revenue>135</revenue>
+ <sum_daily_nb_uniq_visitors>9</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>0</sum_daily_nb_users>
+ <code>cn</code>
+ <logo>plugins/UserCountry/images/flags/cn.png</logo>
+ <segment>countryCode==cn</segment>
+ <logoWidth>16</logoWidth>
+ <logoHeight>11</logoHeight>
+ </row>
+ <row>
+ <label>UserCountry_country_ca</label>
+ <nb_visits>6</nb_visits>
+ <nb_actions>10</nb_actions>
+ <max_actions>3</max_actions>
+ <sum_visit_length>3783</sum_visit_length>
+ <bounce_count>3</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>6</nb_conversions>
+ <nb_visits_converted>6</nb_visits_converted>
+ <revenue>30</revenue>
+ </row>
+ <row idgoal='2'>
+ <nb_conversions>3</nb_conversions>
+ <nb_visits_converted>3</nb_visits_converted>
+ <revenue>15</revenue>
+ </row>
+ </goals>
+ <nb_conversions>9</nb_conversions>
+ <revenue>45</revenue>
+ <sum_daily_nb_uniq_visitors>3</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>0</sum_daily_nb_users>
+ <code>ca</code>
+ <logo>plugins/UserCountry/images/flags/ca.png</logo>
+ <segment>countryCode==ca</segment>
+ <logoWidth>16</logoWidth>
+ <logoHeight>11</logoHeight>
+ </row>
+ <row>
+ <label>UserCountry_country_fr</label>
+ <nb_visits>3</nb_visits>
+ <nb_actions>5</nb_actions>
+ <max_actions>3</max_actions>
+ <sum_visit_length>1261</sum_visit_length>
+ <bounce_count>2</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>3</nb_conversions>
+ <nb_visits_converted>3</nb_visits_converted>
+ <revenue>15</revenue>
+ </row>
+ <row idgoal='2'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>5</revenue>
+ </row>
+ </goals>
+ <nb_conversions>4</nb_conversions>
+ <revenue>20</revenue>
+ <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>1</sum_daily_nb_users>
+ <code>fr</code>
+ <logo>plugins/UserCountry/images/flags/fr.png</logo>
+ <segment>countryCode==fr</segment>
+ <logoWidth>16</logoWidth>
+ <logoHeight>11</logoHeight>
+ </row>
+ <row>
+ <label>UserCountry_country_id</label>
+ <nb_visits>2</nb_visits>
+ <nb_actions>3</nb_actions>
+ <max_actions>2</max_actions>
+ <sum_visit_length>1261</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>2</nb_conversions>
+ <nb_visits_converted>2</nb_visits_converted>
+ <revenue>10</revenue>
+ </row>
+ <row idgoal='2'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>5</revenue>
+ </row>
+ </goals>
+ <nb_conversions>3</nb_conversions>
+ <revenue>15</revenue>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>0</sum_daily_nb_users>
+ <code>id</code>
+ <logo>plugins/UserCountry/images/flags/id.png</logo>
+ <segment>countryCode==id</segment>
+ <logoWidth>16</logoWidth>
+ <logoHeight>11</logoHeight>
+ </row>
+ <row>
+ <label>UserCountry_country_it</label>
+ <nb_visits>2</nb_visits>
+ <nb_actions>4</nb_actions>
+ <max_actions>3</max_actions>
+ <sum_visit_length>1261</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>2</nb_conversions>
+ <nb_visits_converted>2</nb_visits_converted>
+ <revenue>10</revenue>
+ </row>
+ <row idgoal='2'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>5</revenue>
+ </row>
+ </goals>
+ <nb_conversions>3</nb_conversions>
+ <revenue>15</revenue>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>0</sum_daily_nb_users>
+ <code>it</code>
+ <logo>plugins/UserCountry/images/flags/it.png</logo>
+ <segment>countryCode==it</segment>
+ <logoWidth>16</logoWidth>
+ <logoHeight>11</logoHeight>
+ </row>
+ <row>
+ <label>UserCountry_country_ti</label>
+ <nb_visits>2</nb_visits>
+ <nb_actions>3</nb_actions>
+ <max_actions>2</max_actions>
+ <sum_visit_length>1261</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>2</nb_conversions>
+ <nb_visits_converted>2</nb_visits_converted>
+ <revenue>10</revenue>
+ </row>
+ <row idgoal='2'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>5</revenue>
+ </row>
+ </goals>
+ <nb_conversions>3</nb_conversions>
+ <revenue>15</revenue>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>0</sum_daily_nb_users>
+ <code>ti</code>
+ <logo>plugins/UserCountry/images/flags/ti.png</logo>
+ <segment>countryCode==ti</segment>
+ <logoWidth>16</logoWidth>
+ <logoHeight>11</logoHeight>
+ </row>
+ <row>
+ <label>UserCountry_country_us</label>
+ <nb_visits>2</nb_visits>
+ <nb_actions>4</nb_actions>
+ <max_actions>3</max_actions>
+ <sum_visit_length>1261</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>2</nb_conversions>
+ <nb_visits_converted>2</nb_visits_converted>
+ <revenue>10</revenue>
+ </row>
+ <row idgoal='2'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>5</revenue>
+ </row>
+ </goals>
+ <nb_conversions>3</nb_conversions>
+ <revenue>15</revenue>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>0</sum_daily_nb_users>
<code>us</code>
<logo>plugins/UserCountry/images/flags/us.png</logo>
<segment>countryCode==us</segment>
diff --git a/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getRegion_month.xml b/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getRegion_month.xml
index bb934e5ce6..378d5e701f 100644
--- a/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getRegion_month.xml
+++ b/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData_IfThereAreData__UserCountry.getRegion_month.xml
@@ -1,32 +1,152 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <label>Unknown</label>
- <nb_visits>35</nb_visits>
- <nb_actions>61</nb_actions>
+ <label>General_Unknown</label>
+ <nb_visits>22</nb_visits>
+ <nb_actions>39</nb_actions>
<max_actions>3</max_actions>
- <sum_visit_length>21437</sum_visit_length>
- <bounce_count>18</bounce_count>
+ <sum_visit_length>13871</sum_visit_length>
+ <bounce_count>11</bounce_count>
<goals>
<row idgoal='1'>
- <nb_conversions>35</nb_conversions>
- <nb_visits_converted>35</nb_visits_converted>
- <revenue>175</revenue>
+ <nb_conversions>22</nb_conversions>
+ <nb_visits_converted>22</nb_visits_converted>
+ <revenue>110</revenue>
</row>
<row idgoal='2'>
- <nb_conversions>17</nb_conversions>
- <nb_visits_converted>17</nb_visits_converted>
- <revenue>85</revenue>
+ <nb_conversions>11</nb_conversions>
+ <nb_visits_converted>11</nb_visits_converted>
+ <revenue>55</revenue>
</row>
</goals>
- <nb_conversions>52</nb_conversions>
- <revenue>260</revenue>
- <sum_daily_nb_uniq_visitors>18</sum_daily_nb_uniq_visitors>
- <sum_daily_nb_users>1</sum_daily_nb_users>
+ <nb_conversions>33</nb_conversions>
+ <revenue>165</revenue>
+ <sum_daily_nb_uniq_visitors>11</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>0</sum_daily_nb_users>
<region>xx</region>
<country>xx</country>
- <country_name>Unknown</country_name>
- <region_name>Unknown</region_name>
+ <country_name>General_Unknown</country_name>
+ <region_name>General_Unknown</region_name>
<logo>plugins/UserCountry/images/flags/xx.png</logo>
</row>
+ <row>
+ <label>British Columbia, UserCountry_country_ca</label>
+ <nb_visits>6</nb_visits>
+ <nb_actions>10</nb_actions>
+ <max_actions>3</max_actions>
+ <sum_visit_length>3783</sum_visit_length>
+ <bounce_count>3</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>6</nb_conversions>
+ <nb_visits_converted>6</nb_visits_converted>
+ <revenue>30</revenue>
+ </row>
+ <row idgoal='2'>
+ <nb_conversions>3</nb_conversions>
+ <nb_visits_converted>3</nb_visits_converted>
+ <revenue>15</revenue>
+ </row>
+ </goals>
+ <nb_conversions>9</nb_conversions>
+ <revenue>45</revenue>
+ <sum_daily_nb_uniq_visitors>3</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>0</sum_daily_nb_users>
+ <segment>regionCode==BC;countryCode==ca</segment>
+ <region>BC</region>
+ <country>ca</country>
+ <country_name>UserCountry_country_ca</country_name>
+ <region_name>British Columbia</region_name>
+ <logo>plugins/UserCountry/images/flags/ca.png</logo>
+ </row>
+ <row>
+ <label>Franche-Comte, UserCountry_country_fr</label>
+ <nb_visits>3</nb_visits>
+ <nb_actions>5</nb_actions>
+ <max_actions>3</max_actions>
+ <sum_visit_length>1261</sum_visit_length>
+ <bounce_count>2</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>3</nb_conversions>
+ <nb_visits_converted>3</nb_visits_converted>
+ <revenue>15</revenue>
+ </row>
+ <row idgoal='2'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>5</revenue>
+ </row>
+ </goals>
+ <nb_conversions>4</nb_conversions>
+ <revenue>20</revenue>
+ <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>1</sum_daily_nb_users>
+ <segment>regionCode==A6;countryCode==fr</segment>
+ <region>A6</region>
+ <country>fr</country>
+ <country_name>UserCountry_country_fr</country_name>
+ <region_name>Franche-Comte</region_name>
+ <logo>plugins/UserCountry/images/flags/fr.png</logo>
+ </row>
+ <row>
+ <label>General_Unknown, UserCountry_country_ti</label>
+ <nb_visits>2</nb_visits>
+ <nb_actions>3</nb_actions>
+ <max_actions>2</max_actions>
+ <sum_visit_length>1261</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>2</nb_conversions>
+ <nb_visits_converted>2</nb_visits_converted>
+ <revenue>10</revenue>
+ </row>
+ <row idgoal='2'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>5</revenue>
+ </row>
+ </goals>
+ <nb_conversions>3</nb_conversions>
+ <revenue>15</revenue>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>0</sum_daily_nb_users>
+ <segment>regionCode==1;countryCode==ti</segment>
+ <region>1</region>
+ <country>ti</country>
+ <country_name>UserCountry_country_ti</country_name>
+ <region_name>General_Unknown</region_name>
+ <logo>plugins/UserCountry/images/flags/ti.png</logo>
+ </row>
+ <row>
+ <label>Lazio, UserCountry_country_it</label>
+ <nb_visits>2</nb_visits>
+ <nb_actions>4</nb_actions>
+ <max_actions>3</max_actions>
+ <sum_visit_length>1261</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>2</nb_conversions>
+ <nb_visits_converted>2</nb_visits_converted>
+ <revenue>10</revenue>
+ </row>
+ <row idgoal='2'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>5</revenue>
+ </row>
+ </goals>
+ <nb_conversions>3</nb_conversions>
+ <revenue>15</revenue>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>0</sum_daily_nb_users>
+ <segment>regionCode==07;countryCode==it</segment>
+ <region>07</region>
+ <country>it</country>
+ <country_name>UserCountry_country_it</country_name>
+ <region_name>Lazio</region_name>
+ <logo>plugins/UserCountry/images/flags/it.png</logo>
+ </row>
</result> \ No newline at end of file