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:
authorThomas Steur <thomas.steur@gmail.com>2016-04-06 06:29:18 +0300
committerThomas Steur <thomas.steur@gmail.com>2016-04-06 06:29:18 +0300
commit3eb0cf055146c0b77b592cf9ef4bf2eb2e2f1ca3 (patch)
tree99817781db0a0626fa4d14f96697f6e04e66f983
parent1854f5c456a76af807431d52bcb19ad207ba658e (diff)
parent0f38083969261b95a00c59f1f5596d35365506cd (diff)
Merge branch 'master' into 3.0-m03
Conflicts: core/Version.php core/WidgetsList.php plugins/CustomDimensions plugins/Goals/templates/getGoalReportView.twig plugins/Goals/templates/getOverviewView.twig tests/UI/expected-ui-screenshots
-rw-r--r--CHANGELOG.md13
-rw-r--r--HIRING.md18
-rw-r--r--README.md4
-rw-r--r--composer.lock40
-rw-r--r--config/global.ini.php6
-rw-r--r--core/Access.php13
-rw-r--r--core/Archive.php12
-rw-r--r--core/ArchiveProcessor/Rules.php20
-rw-r--r--core/AssetManager.php13
-rw-r--r--core/BaseFactory.php7
-rw-r--r--core/DataAccess/LogQueryBuilder.php35
-rw-r--r--core/Segment.php7
-rw-r--r--core/SettingsServer.php1
-rw-r--r--core/Tracker/PageUrl.php19
-rw-r--r--core/Tracker/Visit.php2
-rwxr-xr-xcore/Twig.php117
-rw-r--r--core/Unzip.php4
-rw-r--r--core/UpdateCheck.php3
-rw-r--r--core/Updates/2.16.1-b3.php25
-rw-r--r--js/README.md8
-rw-r--r--js/piwik.js240
-rw-r--r--lang/el.json6
-rw-r--r--lang/fi.json20
-rw-r--r--lang/ko.json4
-rw-r--r--lang/nb.json1
-rw-r--r--lang/pl.json1
-rw-r--r--lang/ru.json15
-rw-r--r--lang/sq.json2
-rw-r--r--lang/sr.json2
-rw-r--r--lang/sv.json2
-rw-r--r--lang/tr.json2
-rw-r--r--libs/Zend/Validate/Hostname.php142
-rw-r--r--misc/cron/archive.php24
m---------misc/log-analytics0
-rw-r--r--piwik.js95
-rw-r--r--plugins/API/lang/fi.json6
-rw-r--r--plugins/API/lang/ru.json5
-rw-r--r--plugins/Actions/lang/fi.json5
-rw-r--r--plugins/Actions/lang/ru.json4
-rw-r--r--plugins/Contents/lang/ru.json6
-rw-r--r--plugins/CoreAdminHome/lang/ru.json13
-rw-r--r--plugins/CoreAdminHome/templates/trackingCodeGenerator.twig1
-rw-r--r--plugins/CoreHome/Columns/VisitorReturning.php8
-rw-r--r--plugins/CoreHome/angularjs/common/services/piwik-api.js2
-rw-r--r--plugins/CoreHome/angularjs/siteselector/siteselector.directive.less2
-rw-r--r--plugins/CoreHome/lang/fi.json11
-rw-r--r--plugins/CoreHome/lang/ko.json1
-rw-r--r--plugins/CoreHome/lang/ru.json8
-rw-r--r--plugins/CoreHome/stylesheets/dataTable/_reportDocumentation.less2
-rw-r--r--plugins/CoreHome/templates/_dataTableCell.twig15
-rw-r--r--plugins/CorePluginsAdmin/lang/ru.json11
-rw-r--r--plugins/CoreUpdater/lang/fi.json10
-rw-r--r--plugins/CoreUpdater/lang/ru.json8
-rw-r--r--plugins/CoreVisualizations/CoreVisualizations.php20
-rw-r--r--plugins/CoreVisualizations/Visualizations/HtmlTable.php19
-rw-r--r--plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php10
-rw-r--r--plugins/CoreVisualizations/Visualizations/HtmlTable/PivotBy.php36
m---------plugins/CustomDimensions0
-rw-r--r--plugins/CustomVariables/lang/fi.json6
-rw-r--r--plugins/CustomVariables/lang/ru.json16
-rw-r--r--plugins/DBStats/lang/fi.json1
-rw-r--r--plugins/Dashboard/lang/fi.json2
-rw-r--r--plugins/Dashboard/lang/lt.json2
-rw-r--r--plugins/Dashboard/lang/ru.json2
-rw-r--r--plugins/DevicePlugins/lang/fi.json2
-rw-r--r--plugins/DevicePlugins/lang/ru.json2
-rw-r--r--plugins/DevicesDetection/images/browsers/AT.gifbin0 -> 1087 bytes
-rw-r--r--plugins/DevicesDetection/images/browsers/KY.gifbin0 -> 614 bytes
-rw-r--r--plugins/DevicesDetection/images/browsers/OT.gifbin0 -> 1025 bytes
-rw-r--r--plugins/DevicesDetection/images/browsers/SP.gifbin0 -> 990 bytes
-rw-r--r--plugins/DevicesDetection/images/browsers/SS.gifbin0 -> 595 bytes
-rw-r--r--plugins/Diagnostics/lang/fi.json6
-rw-r--r--plugins/Diagnostics/lang/nb.json6
-rw-r--r--plugins/Diagnostics/lang/ru.json8
-rw-r--r--plugins/Ecommerce/lang/fi.json8
-rw-r--r--plugins/Events/Events.php3
-rw-r--r--plugins/Events/lang/ru.json2
-rw-r--r--plugins/Feedback/lang/fi.json8
-rw-r--r--plugins/Feedback/lang/ru.json4
-rw-r--r--plugins/Goals/API.php1
-rw-r--r--plugins/Goals/Pages.php3
-rw-r--r--plugins/Goals/lang/el.json2
-rw-r--r--plugins/Goals/lang/en.json1
-rw-r--r--plugins/Goals/lang/lt.json2
-rw-r--r--plugins/Goals/lang/nb.json1
-rw-r--r--plugins/Goals/lang/ru.json5
-rw-r--r--plugins/Goals/tests/Integration/APITest.php7
-rw-r--r--plugins/ImageGraph/lang/fi.json3
-rw-r--r--plugins/Installation/ServerFilesGenerator.php16
-rw-r--r--plugins/Installation/lang/fi.json14
-rw-r--r--plugins/Live/lang/fi.json4
-rw-r--r--plugins/Live/lang/nb.json1
-rw-r--r--plugins/Live/stylesheets/live.less4
-rw-r--r--plugins/Live/templates/_dataTableViz_visitorLog.twig7
-rw-r--r--plugins/Live/templates/getLastVisitsStart.twig35
-rw-r--r--plugins/Live/tests/Integration/ModelTest.php9
-rw-r--r--plugins/Login/lang/en.json2
m---------plugins/LoginHttpAuth0
-rw-r--r--plugins/MobileAppMeasurable/lang/fi.json7
-rw-r--r--plugins/PrivacyManager/lang/fi.json7
-rw-r--r--plugins/PrivacyManager/lang/nb.json2
-rw-r--r--plugins/Provider/lang/fi.json4
m---------plugins/QueuedTracking0
-rw-r--r--plugins/Referrers/lang/fi.json2
-rw-r--r--plugins/SEO/lang/fi.json1
m---------plugins/SecurityInfo0
-rw-r--r--plugins/SegmentEditor/lang/fi.json9
-rw-r--r--plugins/SitesManager/API.php4
-rw-r--r--plugins/SitesManager/Controller.php1
-rw-r--r--plugins/SitesManager/Menu.php1
-rw-r--r--plugins/SitesManager/Model.php34
-rw-r--r--plugins/SitesManager/angularjs/sites-manager/multiline-field.directive.html1
-rw-r--r--plugins/SitesManager/angularjs/sites-manager/sites-manager-site.controller.js9
-rw-r--r--plugins/SitesManager/angularjs/sites-manager/sites-manager.controller.js19
-rw-r--r--plugins/SitesManager/lang/el.json2
-rw-r--r--plugins/SitesManager/lang/ru.json4
-rw-r--r--plugins/SitesManager/templates/dialogs/dialogs.html1
-rw-r--r--plugins/SitesManager/templates/dialogs/edit-dialog.html1
-rw-r--r--plugins/SitesManager/templates/displayJavascriptCode.twig1
-rw-r--r--plugins/SitesManager/templates/help/timezone-help.html3
-rw-r--r--plugins/SitesManager/templates/index.html8
-rw-r--r--plugins/SitesManager/templates/siteWithoutData.twig4
-rw-r--r--plugins/SitesManager/templates/sites-list/site-fields.html2
m---------plugins/TasksTimetable0
-rw-r--r--plugins/Transitions/API.php6
-rw-r--r--plugins/Transitions/lang/fi.json1
m---------plugins/TreemapVisualization0
-rw-r--r--plugins/UserCountry/Commands/AttributeHistoricalDataWithLocations.php4
-rw-r--r--plugins/UserCountry/lang/fi.json1
-rw-r--r--plugins/UserCountry/lang/nb.json2
-rw-r--r--plugins/UserCountryMap/lang/fi.json5
-rw-r--r--plugins/UserLanguage/lang/fi.json3
-rw-r--r--plugins/UsersManager/Model.php105
-rw-r--r--plugins/UsersManager/lang/fi.json12
-rw-r--r--plugins/UsersManager/tests/Integration/APITest.php11
-rw-r--r--plugins/VisitFrequency/Controller.php1
-rw-r--r--plugins/VisitFrequency/lang/fi.json2
-rw-r--r--plugins/VisitTime/lang/fi.json1
-rw-r--r--plugins/VisitorInterest/lang/fi.json1
-rw-r--r--plugins/VisitsSummary/lang/fi.json1
-rw-r--r--plugins/WebsiteMeasurable/lang/fi.json7
-rw-r--r--tests/PHPUnit/Integration/EmailValidatorTest.php59
-rw-r--r--tests/PHPUnit/Integration/JsProxyTest.php4
-rw-r--r--tests/PHPUnit/Integration/ReleaseCheckListTest.php15
-rw-r--r--tests/PHPUnit/Integration/SegmentTest.php128
-rw-r--r--tests/PHPUnit/System/TransitionsTest.php21
-rw-r--r--tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageTitle_day.xml117
-rw-r--r--tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageUrl_day.xml112
-rw-r--r--tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml2
-rw-r--r--tests/PHPUnit/Unit/DeprecatedMethodsTest.php3
-rw-r--r--tests/PHPUnit/Unit/UrlHelperTest.php9
m---------tests/UI/expected-ui-screenshots0
-rw-r--r--tests/UI/specs/UIIntegration_spec.js6
-rw-r--r--tests/javascript/index.php112
-rw-r--r--tests/javascript/piwiktest.js1
m---------tests/travis0
156 files changed, 1620 insertions, 580 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index df034f4ea8..a85c7e5a16 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -44,6 +44,19 @@ This is a changelog for Piwik platform developers. All changes for our HTTP API'
### New features
* New method `setIsWritableByCurrentUser` for `SystemSetting` to change the writable permission for certain system settings via DI.
+ * JS Tracker: `setDomains` function now supports page wildcards matching eg. `example.com/index*` which can be useful when [tracking a group of pages within a domain in a separate website in Piwik](http://developer.piwik.org/guides/tracking-javascript-guide#tracking-a-group-of-pages-in-a-separate-website)
+ * To customise the list of URL query parameters to be removed from your URLs, you can now define and overwrite `url_query_parameter_to_exclude_from_url` INI setting in your `config.ini.php` file. By default, the following query string parameters will be removed: `gclid, fb_xd_fragment, fb_comment_id, phpsessid, jsessionid, sessionid, aspsessionid, doing_wp_cron, sid`.
+
+### Deprecations
+* The following PHP functions have been deprecated and will be removed in Piwik 3.0:
+ * `SettingsServer::isApache()`
+
+### New guides
+ * JavaScript Tracker: [Measuring domains and/or sub-domains](http://developer.piwik.org/guides/tracking-javascript-guide#measuring-domains-andor-sub-domains)
+
+### Internal change
+ * Tracking API: by default, when tracking a Page URL, Piwik will now remove the URL query string parameter `sid` if it is found.
+ * In the JavaScript tracker, the function `setDomains` will not anymore attempt to set a cookie path. Learn more about [configuring the tracker correctly](http://developer.piwik.org/guides/tracking-javascript-guide#tracking-one-domain) when tracking one or several domains and/or paths.
## Piwik 2.16.0
diff --git a/HIRING.md b/HIRING.md
new file mode 100644
index 0000000000..4eaefa80fd
--- /dev/null
+++ b/HIRING.md
@@ -0,0 +1,18 @@
+# We are hiring engineers to build an awesome product and platform used by millions of people
+
+Are you ready for a new challenge? Or maybe you know someone who is looking for a change? We have some exciting problems to solve and are looking for senior developers to work with us and our community on our open source Piwik Analytics platform. Piwik is used by more than one million websites all over the world. It is deployed on more than 300.000 servers and some users track more than 1 billion actions per month.
+
+## What is it like to work on Piwik?
+
+We develop this software using modern PHP, MySQL, Redis, AngularJS and more. We provide several kind of APIs and a plugin architecture to allow developers to extend and change Piwik to their needs. However, we would not be Piwik if we stopped at this point! We want to turn Piwik into an even more awesome product and platform.
+You can imagine there is a lot to do and many challenges to face!
+
+While one part is to always make Piwik scale better and to improve UI and UX, we also want to provide simple APIs to make the life of developers as pleasant as possible. We aim to solve things the right way and our thousands of unit, integration, system, JavaScript and screenshot tests help us to innovate and to not be afraid of change. We like clean code and constant improvements.
+
+The Piwik team lives in New Zealand, Europe (Poland, Germany) and in the U.S. We do the vast majority of our collaboration online. Our values include being open, transparent and sharing knowledge. For this we use tools like GitHub and Slack to communicate and Quake servers to take our minds off complex challenges. We are a small, flexible team, so when you come aboard, you will play an integral part in engineering and have a big impact on the product loved by so many people. You’ll help to create a welcoming environment for new contributors and set an example with your development practices and communications skills.
+
+## Apply now, or spread the word!
+
+If you have strong skills in PHP send us an email with your CV and tell us a little about yourself and your experience in engineering complex applications.
+
+[Apply for a job here http://piwik.org/jobs/](http://piwik.org/jobs/) and if you’re maybe not the right candidate, contribute to the project by sharing this blog post and by sending it to your friends!
diff --git a/README.md b/README.md
index aec6448c3d..6ef7604077 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[![Build Status](https://travis-ci.org/piwik/piwik.svg?branch=master)](https://travis-ci.org/piwik/piwik)
[![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/piwik/piwik.svg)](https://scrutinizer-ci.com/g/piwik/piwik?branch=master)
-[![Code Coverage](https://scrutinizer-ci.com/g/piwik/piwik/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/piwik/piwik/?branch=master)
+[![Code Coverage](https://scrutinizer-ci.com/g/piwik/piwik/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/piwik/piwik/?branch=master "Unit tests code coverage. Does not include coverage of integration tests, system tests or UI screenshot tests.")
[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/piwik/piwik.svg)](http://isitmaintained.com/project/piwik/piwik "Average time to resolve an issue")
[![Percentage of issues still open](http://isitmaintained.com/badge/open/piwik/piwik.svg)](http://isitmaintained.com/project/piwik/piwik "Percentage of issues still open")
[![Dependency Status](https://gemnasium.com/piwik/piwik.svg)](https://gemnasium.com/piwik/piwik)
@@ -39,7 +39,7 @@ Piwik is released under the GPL v3 (or later) license, see [misc/gpl-3.0.txt](mi
Are you looking for a new challenge? We are currently seeking a software engineer or software developer who is passionate about data processing, security, privacy, the open source and free/libre philosophy and usable interface design.
-[View Job Description](https://piwik.org/blog/2015/01/piwik-expanding-seeking-talented-software-engineer-new-zealand-poland/) - [Apply online](http://piwik.org/jobs/)
+[View Job Description](https://piwik.org/blog/2016/01/piwik-expanding-seeking-talented-software-engineer-new-zealand-poland/) - [Apply online](http://piwik.org/jobs/)
This is for a full time position to work on the open source Piwik platform, either remotely or we can help the right candidate relocate to beautiful New Zealand (Wellington) or Poland (Wroclaw).
diff --git a/composer.lock b/composer.lock
index e880b46091..cc8ce0bd49 100644
--- a/composer.lock
+++ b/composer.lock
@@ -823,16 +823,16 @@
},
{
"name": "piwik/device-detector",
- "version": "3.6.0",
+ "version": "3.6.1",
"source": {
"type": "git",
"url": "https://github.com/piwik/device-detector.git",
- "reference": "8c2fcfce34d8bd25d8db9c48e67fabb65c5497ae"
+ "reference": "4f4c2b0ce412fb1b8f679a7c82190783ba697d4c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/piwik/device-detector/zipball/8c2fcfce34d8bd25d8db9c48e67fabb65c5497ae",
- "reference": "8c2fcfce34d8bd25d8db9c48e67fabb65c5497ae",
+ "url": "https://api.github.com/repos/piwik/device-detector/zipball/4f4c2b0ce412fb1b8f679a7c82190783ba697d4c",
+ "reference": "4f4c2b0ce412fb1b8f679a7c82190783ba697d4c",
"shasum": ""
},
"require": {
@@ -870,7 +870,7 @@
"parser",
"useragent"
],
- "time": "2016-03-02 22:20:49"
+ "time": "2016-03-31 20:28:09"
},
{
"name": "piwik/ini",
@@ -939,16 +939,16 @@
},
{
"name": "piwik/piwik-php-tracker",
- "version": "1.0.1",
+ "version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/piwik/piwik-php-tracker.git",
- "reference": "ac3e26bb3e2c8a428ccbf6ca663c2ef37fa47a5e"
+ "reference": "f026613f8137c014030c96a22491ede5f5f1676b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/piwik/piwik-php-tracker/zipball/ac3e26bb3e2c8a428ccbf6ca663c2ef37fa47a5e",
- "reference": "ac3e26bb3e2c8a428ccbf6ca663c2ef37fa47a5e",
+ "url": "https://api.github.com/repos/piwik/piwik-php-tracker/zipball/f026613f8137c014030c96a22491ede5f5f1676b",
+ "reference": "f026613f8137c014030c96a22491ede5f5f1676b",
"shasum": ""
},
"type": "library",
@@ -975,20 +975,20 @@
"piwik",
"tracker"
],
- "time": "2015-11-11 02:55:37"
+ "time": "2016-01-12 21:44:22"
},
{
"name": "piwik/referrer-spam-blacklist",
- "version": "1.0.7",
+ "version": "1.0.8",
"source": {
"type": "git",
"url": "https://github.com/piwik/referrer-spam-blacklist.git",
- "reference": "85db74cfc7249cb34ff59eba22edeb6704fd69b8"
+ "reference": "665ad115eb85a94210beecb13c57806ff474364f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/piwik/referrer-spam-blacklist/zipball/85db74cfc7249cb34ff59eba22edeb6704fd69b8",
- "reference": "85db74cfc7249cb34ff59eba22edeb6704fd69b8",
+ "url": "https://api.github.com/repos/piwik/referrer-spam-blacklist/zipball/665ad115eb85a94210beecb13c57806ff474364f",
+ "reference": "665ad115eb85a94210beecb13c57806ff474364f",
"shasum": ""
},
"type": "library",
@@ -997,20 +997,20 @@
"Public Domain"
],
"description": "Community-contributed list of referrer spammers",
- "time": "2016-01-05 17:31:58"
+ "time": "2016-03-22 18:43:29"
},
{
"name": "piwik/searchengine-and-social-list",
- "version": "1.1",
+ "version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/piwik/searchengine-and-social-list.git",
- "reference": "5b6763e77dadf24e579f03a7a0e79f1827b5db8a"
+ "reference": "276e03a2f0dfe1559f57d6e2cba9258305ecdba5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/piwik/searchengine-and-social-list/zipball/5b6763e77dadf24e579f03a7a0e79f1827b5db8a",
- "reference": "5b6763e77dadf24e579f03a7a0e79f1827b5db8a",
+ "url": "https://api.github.com/repos/piwik/searchengine-and-social-list/zipball/276e03a2f0dfe1559f57d6e2cba9258305ecdba5",
+ "reference": "276e03a2f0dfe1559f57d6e2cba9258305ecdba5",
"shasum": ""
},
"type": "library",
@@ -1019,7 +1019,7 @@
"Public Domain"
],
"description": "Search engine and social network definitions used by Piwik",
- "time": "2015-11-16 22:24:23"
+ "time": "2016-02-17 06:55:15"
},
{
"name": "psr/log",
diff --git a/config/global.ini.php b/config/global.ini.php
index fd9ef2d649..9967c31da7 100644
--- a/config/global.ini.php
+++ b/config/global.ini.php
@@ -345,7 +345,7 @@ login_password_recovery_email_address = "password-recovery@{DOMAIN}"
; name that appears as a Sender in the password recovery email
login_password_recovery_email_name = Piwik
-; email address that appears as a Repy-to in the password recovery email
+; email address that appears as a Reply-to in the password recovery email
; if specified, {DOMAIN} will be replaced by the current Piwik domain
login_password_recovery_replyto_email_address = "no-reply@{DOMAIN}"
; name that appears as a Reply-to in the password recovery email
@@ -623,6 +623,10 @@ window_look_back_for_visitor = 0
; visitors that stay on the website and view only one page will be considered as time on site of 0 second
default_time_one_page_visit = 0
+; Comma separated list of URL query string variable names that will be removed from your tracked URLs
+; By default, Piwik will remove the most common parameters which are known to change often (eg. session ID parameters)
+url_query_parameter_to_exclude_from_url = "gclid,fb_xd_fragment,fb_comment_id,phpsessid,jsessionid,sessionid,aspsessionid,doing_wp_cron,sid"
+
; if set to 1, Piwik attempts a "best guess" at the visitor's country of
; origin when the preferred language tag omits region information.
; The mapping is defined in core/DataFiles/LanguageToCountry.php,
diff --git a/core/Access.php b/core/Access.php
index 881810bfca..c8b9bafea0 100644
--- a/core/Access.php
+++ b/core/Access.php
@@ -10,6 +10,7 @@ namespace Piwik;
use Exception;
use Piwik\Container\StaticContainer;
+use Piwik\Plugins\SitesManager\API as SitesManagerApi;
/**
* Singleton that manages user access to Piwik resources.
@@ -145,7 +146,7 @@ class Access
$this->login = null;
// if the Auth wasn't set, we may be in the special case of setSuperUser(), otherwise we fail TODO: docs + review
- if ($this->auth === null) {
+ if (!isset($this->auth)) {
return false;
}
@@ -207,7 +208,8 @@ class Access
if ($this->hasSuperUserAccess) {
if (empty($this->idsitesByAccess['superuser'])) {
try {
- $allSitesId = Plugins\SitesManager\API::getInstance()->getAllSitesId();
+ $api = SitesManagerApi::getInstance();
+ $allSitesId = $api->getAllSitesId();
} catch (\Exception $e) {
$allSitesId = array();
}
@@ -460,17 +462,18 @@ class Access
{
$isSuperUser = self::getInstance()->hasSuperUserAccess();
- self::getInstance()->setSuperUserAccess(true);
+ $access = self::getInstance();
+ $access->setSuperUserAccess(true);
try {
$result = $function();
} catch (Exception $ex) {
- self::getInstance()->setSuperUserAccess($isSuperUser);
+ $access->setSuperUserAccess($isSuperUser);
throw $ex;
}
- self::getInstance()->setSuperUserAccess($isSuperUser);
+ $access->setSuperUserAccess($isSuperUser);
return $result;
}
diff --git a/core/Archive.php b/core/Archive.php
index 2efe230318..8bddda0922 100644
--- a/core/Archive.php
+++ b/core/Archive.php
@@ -646,7 +646,7 @@ class Archive
$doneFlags = array();
$archiveGroups = array();
foreach ($plugins as $plugin) {
- $doneFlag = $this->getDoneStringForPlugin($plugin);
+ $doneFlag = $this->getDoneStringForPlugin($plugin, $this->params->getIdSites());
$doneFlags[$doneFlag] = true;
if (!isset($this->idarchives[$doneFlag])) {
@@ -731,7 +731,7 @@ class Archive
// initialize archive ID cache for each report
foreach ($plugins as $plugin) {
- $doneFlag = $this->getDoneStringForPlugin($plugin);
+ $doneFlag = $this->getDoneStringForPlugin($plugin, $this->params->getIdSites());
$this->initializeArchiveIdCache($doneFlag);
}
@@ -749,10 +749,10 @@ class Archive
* @param string $plugin
* @return string
*/
- private function getDoneStringForPlugin($plugin)
+ private function getDoneStringForPlugin($plugin, $idSites)
{
return Rules::getDoneStringFlagFor(
- $this->params->getIdSites(),
+ $idSites,
$this->params->getSegment(),
$this->getPeriodLabel(),
$plugin
@@ -893,9 +893,11 @@ class Archive
$periodString = $period->getRangeString();
+ $idSites = array($site->getId());
+
// process for each plugin as well
foreach ($archiveGroups as $plugin) {
- $doneFlag = $this->getDoneStringForPlugin($plugin);
+ $doneFlag = $this->getDoneStringForPlugin($plugin, $idSites);
$this->initializeArchiveIdCache($doneFlag);
$idArchive = $archiveLoader->prepareArchive($plugin);
diff --git a/core/ArchiveProcessor/Rules.php b/core/ArchiveProcessor/Rules.php
index 0ec92f7590..7f37b3250c 100644
--- a/core/ArchiveProcessor/Rules.php
+++ b/core/ArchiveProcessor/Rules.php
@@ -172,20 +172,21 @@ class Rules
|| $generalConfig['archiving_range_force_on_browser_request'] != false
) {
return false;
- } else {
- Log::debug("Not forcing archiving for range period.");
}
+
+ Log::debug("Not forcing archiving for range period.");
+ $processOneReportOnly = false;
+
+ } else {
+ $processOneReportOnly = !self::shouldProcessReportsAllPlugins($idSites, $segment, $periodLabel);
}
- $processOneReportOnly = !self::shouldProcessReportsAllPlugins($idSites, $segment, $periodLabel);
- $isArchivingDisabled = !self::isRequestAuthorizedToArchive() || self::$archivingDisabledByTests;
+ $isArchivingEnabled = self::isRequestAuthorizedToArchive() && !self::$archivingDisabledByTests;
- if ($processOneReportOnly
- && $periodLabel != 'range'
- ) {
+ if ($processOneReportOnly) {
// When there is a segment, we disable archiving when browser_archiving_disabled_enforce applies
if (!$segment->isEmpty()
- && $isArchivingDisabled
+ && !$isArchivingEnabled
&& $generalConfig['browser_archiving_disabled_enforce']
&& !SettingsServer::isArchivePhpTriggered() // Only applies when we are not running core:archive command
) {
@@ -196,7 +197,8 @@ class Rules
// Always allow processing one report
return false;
}
- return $isArchivingDisabled;
+
+ return !$isArchivingEnabled;
}
public static function isRequestAuthorizedToArchive()
diff --git a/core/AssetManager.php b/core/AssetManager.php
index 407a2058c0..54c09515f5 100644
--- a/core/AssetManager.php
+++ b/core/AssetManager.php
@@ -123,7 +123,7 @@ class AssetManager extends Singleton
$this->getMergedCoreJSAsset()->delete();
$this->getMergedNonCoreJSAsset()->delete();
- $result .= $this->getIndividualJsIncludes();
+ $result .= $this->getIndividualCoreAndNonCoreJsIncludes();
} else {
$result .= sprintf(self::JS_IMPORT_DIRECTIVE, self::GET_CORE_JS_MODULE_ACTION);
$result .= sprintf(self::JS_IMPORT_DIRECTIVE, self::GET_NON_CORE_JS_MODULE_ACTION);
@@ -290,7 +290,7 @@ class AssetManager extends Singleton
*
* @return string
*/
- private function getIndividualJsIncludes()
+ private function getIndividualCoreAndNonCoreJsIncludes()
{
return
$this->getIndividualJsIncludesFromAssetFetcher($this->getCoreJScriptFetcher()) .
@@ -305,7 +305,9 @@ class AssetManager extends Singleton
{
$jsIncludeString = '';
- foreach ($assetFetcher->getCatalog()->getAssets() as $jsFile) {
+ $assets = $assetFetcher->getCatalog()->getAssets();
+
+ foreach ($assets as $jsFile) {
$jsFile->validateFile();
$jsIncludeString = $jsIncludeString . sprintf(self::JS_IMPORT_DIRECTIVE, $jsFile->getRelativeLocation());
}
@@ -339,10 +341,11 @@ class AssetManager extends Singleton
return false;
}
- $plugin = Manager::getInstance()->getLoadedPlugin($pluginName);
+ $pluginManager = Manager::getInstance();
+ $plugin = $pluginManager->getLoadedPlugin($pluginName);
if ($plugin->isTheme()) {
- $theme = Manager::getInstance()->getTheme($pluginName);
+ $theme = $pluginManager->getTheme($pluginName);
$javaScriptFiles = $theme->getJavaScriptFiles();
diff --git a/core/BaseFactory.php b/core/BaseFactory.php
index 24425c8fee..32b4090bc2 100644
--- a/core/BaseFactory.php
+++ b/core/BaseFactory.php
@@ -34,13 +34,18 @@ abstract class BaseFactory
$className = static::getClassNameFromClassId($classId);
if (!class_exists($className)) {
- Common::sendHeader('Content-Type: text/plain; charset=utf-8');
+ self::sendPlainHeader();
throw new Exception(static::getInvalidClassIdExceptionMessage($classId));
}
return new $className;
}
+ private static function sendPlainHeader()
+ {
+ Common::sendHeader('Content-Type: text/plain; charset=utf-8');
+ }
+
/**
* Should return a class name based on the class's associated string ID.
*/
diff --git a/core/DataAccess/LogQueryBuilder.php b/core/DataAccess/LogQueryBuilder.php
index b0f2b73ad0..c65f36bf10 100644
--- a/core/DataAccess/LogQueryBuilder.php
+++ b/core/DataAccess/LogQueryBuilder.php
@@ -16,7 +16,7 @@ use Piwik\Segment\SegmentExpression;
class LogQueryBuilder
{
public function getSelectQueryString(SegmentExpression $segmentExpression, $select, $from, $where, $bind, $groupBy,
- $orderBy, $limit)
+ $orderBy, $limitAndOffset)
{
if (!is_array($from)) {
$from = array($from);
@@ -43,11 +43,11 @@ class LogQueryBuilder
if ($useSpecialConversionGroupBy) {
$innerGroupBy = "CONCAT(log_conversion.idvisit, '_' , log_conversion.idgoal, '_', log_conversion.buster)";
- $sql = $this->buildWrappedSelectQuery($select, $from, $where, $groupBy, $orderBy, $limit, $innerGroupBy);
+ $sql = $this->buildWrappedSelectQuery($select, $from, $where, $groupBy, $orderBy, $limitAndOffset, $innerGroupBy);
} elseif ($joinWithSubSelect) {
- $sql = $this->buildWrappedSelectQuery($select, $from, $where, $groupBy, $orderBy, $limit);
+ $sql = $this->buildWrappedSelectQuery($select, $from, $where, $groupBy, $orderBy, $limitAndOffset);
} else {
- $sql = $this->buildSelectQuery($select, $from, $where, $groupBy, $orderBy, $limit);
+ $sql = $this->buildSelectQuery($select, $from, $where, $groupBy, $orderBy, $limitAndOffset);
}
return array(
'sql' => $sql,
@@ -249,12 +249,12 @@ class LogQueryBuilder
* @param string $where
* @param string $groupBy
* @param string $orderBy
- * @param string $limit
+ * @param string $limitAndOffset
* @param null|string $innerGroupBy If given, this inner group by will be used. If not, we try to detect one
* @throws Exception
* @return string
*/
- private function buildWrappedSelectQuery($select, $from, $where, $groupBy, $orderBy, $limit, $innerGroupBy = null)
+ private function buildWrappedSelectQuery($select, $from, $where, $groupBy, $orderBy, $limitAndOffset, $innerGroupBy = null)
{
$matchTables = "(log_visit|log_conversion_item|log_conversion|log_action)";
preg_match_all("/". $matchTables ."\.[a-z0-9_\*]+/", $select, $matches);
@@ -271,7 +271,7 @@ class LogQueryBuilder
$innerFrom = $from;
$innerWhere = $where;
- $innerLimit = $limit;
+ $innerLimitAndOffset = $limitAndOffset;
if (!isset($innerGroupBy) && in_array('log_visit', $matchesFrom[1])) {
$innerGroupBy = "log_visit.idvisit";
@@ -280,16 +280,16 @@ class LogQueryBuilder
}
$innerOrderBy = "NULL";
- if ($innerLimit && $orderBy) {
+ if ($innerLimitAndOffset && $orderBy) {
// only When LIMITing we can apply to the inner query the same ORDER BY as the parent query
$innerOrderBy = $orderBy;
}
- if ($innerLimit) {
+ if ($innerLimitAndOffset) {
// When LIMITing, no need to GROUP BY (GROUPing by is done before the LIMIT which is super slow when large amount of rows is matched)
$innerGroupBy = false;
}
- $innerQuery = $this->buildSelectQuery($innerSelect, $innerFrom, $innerWhere, $innerGroupBy, $innerOrderBy, $innerLimit);
+ $innerQuery = $this->buildSelectQuery($innerSelect, $innerFrom, $innerWhere, $innerGroupBy, $innerOrderBy, $innerLimitAndOffset);
$select = preg_replace('/'.$matchTables.'\./', 'log_inner.', $select);
$from = "
@@ -299,7 +299,9 @@ class LogQueryBuilder
$where = false;
$orderBy = preg_replace('/'.$matchTables.'\./', 'log_inner.', $orderBy);
$groupBy = preg_replace('/'.$matchTables.'\./', 'log_inner.', $groupBy);
- $query = $this->buildSelectQuery($select, $from, $where, $groupBy, $orderBy, $limit);
+
+ $outerLimitAndOffset = null;
+ $query = $this->buildSelectQuery($select, $from, $where, $groupBy, $orderBy, $outerLimitAndOffset);
return $query;
}
@@ -312,10 +314,10 @@ class LogQueryBuilder
* @param string $where where clause
* @param string $groupBy group by clause
* @param string $orderBy order by clause
- * @param string|int $limit limit by clause eg '5' for Limit 5 Offset 0 or '10, 5' for Limit 5 Offset 10
+ * @param string|int $limitAndOffset limit by clause eg '5' for Limit 5 Offset 0 or '10, 5' for Limit 5 Offset 10
* @return string
*/
- private function buildSelectQuery($select, $from, $where, $groupBy, $orderBy, $limit)
+ private function buildSelectQuery($select, $from, $where, $groupBy, $orderBy, $limitAndOffset)
{
$sql = "
SELECT
@@ -341,11 +343,16 @@ class LogQueryBuilder
$orderBy";
}
- $sql = $this->appendLimitClauseToQuery($sql, $limit);
+ $sql = $this->appendLimitClauseToQuery($sql, $limitAndOffset);
return $sql;
}
+ /**
+ * @param $sql
+ * @param $limit LIMIT clause eg. "10, 50" (offset 10, limit 50)
+ * @return string
+ */
private function appendLimitClauseToQuery($sql, $limit)
{
$limitParts = explode(',', (string) $limit);
diff --git a/core/Segment.php b/core/Segment.php
index d9f8d163c6..0ba687740e 100644
--- a/core/Segment.php
+++ b/core/Segment.php
@@ -299,12 +299,13 @@ class Segment
{
$segmentExpression = $this->segmentExpression;
- if ($offset > 0) {
- $limit = (int) $offset . ', ' . (int) $limit;
+ $limitAndOffset = null;
+ if($limit > 0) {
+ $limitAndOffset = (int) $offset . ', ' . (int) $limit;
}
return $this->segmentQueryBuilder->getSelectQueryString($segmentExpression, $select, $from, $where, $bind,
- $groupBy, $orderBy, $limit);
+ $groupBy, $orderBy, $limitAndOffset);
}
/**
diff --git a/core/SettingsServer.php b/core/SettingsServer.php
index d84e3ff483..06432a5dfb 100644
--- a/core/SettingsServer.php
+++ b/core/SettingsServer.php
@@ -76,6 +76,7 @@ class SettingsServer
*
* @return bool
* @api
+ * @deprecated
*/
public static function isApache()
{
diff --git a/core/Tracker/PageUrl.php b/core/Tracker/PageUrl.php
index 5083ecdf50..2e5ad45d82 100644
--- a/core/Tracker/PageUrl.php
+++ b/core/Tracker/PageUrl.php
@@ -28,10 +28,6 @@ class PageUrl
'https://' => 2
);
- protected static $queryParametersToExclude = array('gclid', 'fb_xd_fragment', 'fb_comment_id',
- 'phpsessid', 'jsessionid', 'sessionid', 'aspsessionid',
- 'doing_wp_cron', 'sid');
-
/**
* Given the Input URL, will exclude all query parameters set for this site
*
@@ -87,7 +83,7 @@ class PageUrl
$excludedParameters = self::getExcludedParametersFromWebsite($website);
$parametersToExclude = array_merge($excludedParameters,
- self::$queryParametersToExclude,
+ self::getUrlParameterNamesToExcludeFromUrl(),
$campaignTrackingParameters);
/**
@@ -107,6 +103,19 @@ class PageUrl
}
/**
+ * Returns the list of URL query parameters that should be removed from the tracked URL query string.
+ *
+ * @return array
+ */
+ protected static function getUrlParameterNamesToExcludeFromUrl()
+ {
+ $paramsToExclude = Config::getInstance()->Tracker['url_query_parameter_to_exclude_from_url'];
+ $paramsToExclude = explode(",", $paramsToExclude);
+ $paramsToExclude = array_map('trim', $paramsToExclude);
+ return $paramsToExclude;
+ }
+
+ /**
* Returns true if URL fragments should be removed for a specific site,
* false if otherwise.
*
diff --git a/core/Tracker/Visit.php b/core/Tracker/Visit.php
index 80d8d13613..f4485f52fb 100644
--- a/core/Tracker/Visit.php
+++ b/core/Tracker/Visit.php
@@ -365,7 +365,7 @@ class Visit implements VisitInterface
return $this->userSettings;
}
- // is the referrer host any of the registered URLs for this website?
+ // is the host any of the registered URLs for this website?
public static function isHostKnownAliasHost($urlHost, $idSite)
{
$websiteData = Cache::getCacheWebsiteAttributes($idSite);
diff --git a/core/Twig.php b/core/Twig.php
index c3b6ba7414..9f17e0b218 100755
--- a/core/Twig.php
+++ b/core/Twig.php
@@ -23,6 +23,85 @@ use Twig_SimpleFilter;
use Twig_SimpleFunction;
use Twig_SimpleTest;
+function piwik_filter_truncate($string, $size)
+{
+ if (strlen($string) < $size) {
+ return $string;
+ } else {
+ $array = str_split($string, $size);
+ return array_shift($array) . "...";
+ }
+}
+
+function piwik_format_number($string, $minFractionDigits, $maxFractionDigits)
+{
+ $formatter = NumberFormatter::getInstance();
+ return $formatter->format($string, $minFractionDigits, $maxFractionDigits);
+}
+
+function piwik_fix_lbrace($string)
+{
+ $chars = array('{', '&#x7B;', '&#123;', '&lcub;', '&lbrace;', '&#x0007B;');
+
+ static $search;
+ static $replace;
+
+ if (!isset($search)) {
+ $search = array_map(function ($val) { return $val . $val; }, $chars);
+ }
+ if (!isset($replace)) {
+ $replace = array_map(function ($val) { return $val . '&#8291;' . $val; }, $chars);
+ }
+
+ return str_replace($search, $replace, $string);
+}
+
+function piwik_escape_filter(Twig_Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false) {
+
+ $string = twig_escape_filter($env, $string, $strategy, $charset, $autoescape);
+
+ switch ($strategy) {
+ case 'html':
+ case 'html_attr':
+ return piwik_fix_lbrace($string);
+ case 'url':
+ $encoded = rawurlencode('{');
+ return str_replace('{{', $encoded . $encoded, $string);
+ case 'css':
+ case 'js':
+ default:
+ return $string;
+ }
+}
+
+function piwik_format_money($amount, $idSite)
+{
+ $currencySymbol = Site::getCurrencySymbolFor($idSite);
+ $numberFormatter = NumberFormatter::getInstance();
+ return $numberFormatter->formatCurrency($amount, $currencySymbol, GoalManager::REVENUE_PRECISION);
+}
+
+class PiwikTwigFilterExtension extends \Twig_Extension
+{
+ public function getFilters()
+ {
+ return array(
+ new Twig_SimpleFilter('e', '\Piwik\piwik_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
+ new Twig_SimpleFilter('escape', '\Piwik\piwik_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe'))
+ );
+ }
+
+ /**
+ * Returns the name of the extension.
+ *
+ * @return string The extension name
+ */
+ public function getName()
+ {
+ return 'escaper2';
+ }
+}
+
/**
* Twig class
*
@@ -84,8 +163,8 @@ class Twig
$this->addFilter_money();
$this->addFilter_truncate();
$this->addFilter_notification();
- $this->addFilter_percentage();
$this->addFilter_percent();
+ $this->addFilter_percentage();
$this->addFilter_percentEvolution();
$this->addFilter_piwikProAdLink();
$this->addFilter_piwikProOnPremisesAdLink();
@@ -109,6 +188,8 @@ class Twig
$this->addTest_false();
$this->addTest_true();
$this->addTest_emptyString();
+
+ $this->twig->addExtension(new PiwikTwigFilterExtension());
}
private function addTest_false()
@@ -287,7 +368,9 @@ class Twig
$string = str_replace('+', '%2B', $string);
$string = str_replace('&nbsp;', html_entity_decode('&nbsp;'), $string);
- return SafeDecodeLabel::decodeLabelSafe($string);
+ $string = SafeDecodeLabel::decodeLabelSafe($string);
+
+ return piwik_fix_lbrace($string);
}, array('is_safe' => array('all')));
$this->twig->addFilter($rawSafeDecoded);
@@ -304,7 +387,8 @@ class Twig
protected function addFilter_percentage()
{
$percentage = new Twig_SimpleFilter('percentage', function ($string, $totalValue, $precision = 1) {
- return NumberFormatter::getInstance()->formatPercent(Piwik::getPercentageSafe($string, $totalValue, $precision), $precision);
+ $formatter = NumberFormatter::getInstance();
+ return $formatter->formatPercent(Piwik::getPercentageSafe($string, $totalValue, $precision), $precision);
});
$this->twig->addFilter($percentage);
}
@@ -312,7 +396,8 @@ class Twig
protected function addFilter_percent()
{
$percentage = new Twig_SimpleFilter('percent', function ($string, $precision = 1) {
- return NumberFormatter::getInstance()->formatPercent($string, $precision);
+ $formatter = NumberFormatter::getInstance();
+ return $formatter->formatPercent($string, $precision);
});
$this->twig->addFilter($percentage);
}
@@ -320,7 +405,8 @@ class Twig
protected function addFilter_percentEvolution()
{
$percentage = new Twig_SimpleFilter('percentEvolution', function ($string) {
- return NumberFormatter::getInstance()->formatPercentEvolution($string);
+ $formatter = NumberFormatter::getInstance();
+ return $formatter->formatPercentEvolution($string);
});
$this->twig->addFilter($percentage);
}
@@ -371,7 +457,7 @@ class Twig
protected function addFilter_number()
{
$formatter = new Twig_SimpleFilter('number', function ($string, $minFractionDigits = 0, $maxFractionDigits = 0) {
- return NumberFormatter::getInstance()->format($string, $minFractionDigits, $maxFractionDigits);
+ return piwik_format_number($string, $minFractionDigits, $maxFractionDigits);
});
$this->twig->addFilter($formatter);
}
@@ -379,27 +465,20 @@ class Twig
protected function addFilter_truncate()
{
$truncateFilter = new Twig_SimpleFilter('truncate', function ($string, $size) {
- if (strlen($string) < $size) {
- return $string;
- } else {
- $array = str_split($string, $size);
- return array_shift($array) . "...";
- }
+ return piwik_filter_truncate($string, $size);
});
$this->twig->addFilter($truncateFilter);
}
protected function addFilter_money()
{
- $formatter = $this->formatter;
- $moneyFilter = new Twig_SimpleFilter('money', function ($amount) use ($formatter) {
+ $moneyFilter = new Twig_SimpleFilter('money', function ($amount) {
if (func_num_args() != 2) {
throw new Exception('the money modifier expects one parameter: the idSite.');
}
$idSite = func_get_args();
$idSite = $idSite[1];
- $currencySymbol = Site::getCurrencySymbolFor($idSite);
- return NumberFormatter::getInstance()->formatCurrency($amount, $currencySymbol, GoalManager::REVENUE_PRECISION);
+ return piwik_format_money($amount, $idSite);
});
$this->twig->addFilter($moneyFilter);
}
@@ -445,7 +524,8 @@ class Twig
private function addPluginNamespaces(Twig_Loader_Filesystem $loader)
{
- $plugins = \Piwik\Plugin\Manager::getInstance()->getAllPluginsNames();
+ $pluginManager = \Piwik\Plugin\Manager::getInstance();
+ $plugins = $pluginManager->getAllPluginsNames();
foreach ($plugins as $name) {
$path = sprintf("%s/plugins/%s/templates/", PIWIK_INCLUDE_PATH, $name);
if (is_dir($path)) {
@@ -461,7 +541,8 @@ class Twig
*/
private function addCustomPluginNamespaces(Twig_Loader_Filesystem $loader, $pluginName)
{
- $plugins = \Piwik\Plugin\Manager::getInstance()->getAllPluginsNames();
+ $pluginManager = \Piwik\Plugin\Manager::getInstance();
+ $plugins = $pluginManager->getAllPluginsNames();
foreach ($plugins as $name) {
$path = sprintf("%s/plugins/%s/templates/plugins/%s/", PIWIK_INCLUDE_PATH, $pluginName, $name);
if (is_dir($path)) {
diff --git a/core/Unzip.php b/core/Unzip.php
index ffef2add15..af1c14a815 100644
--- a/core/Unzip.php
+++ b/core/Unzip.php
@@ -33,15 +33,19 @@ class Unzip
return new ZipArchive($filename);
}
break;
+
case 'tar.gz':
return new Tar($filename, 'gz');
+
case 'tar.bz2':
return new Tar($filename, 'bz2');
+
case 'gz':
if (function_exists('gzopen')) {
return new Gzip($filename);
}
break;
+
case 'PclZip':
default:
return new PclZip($filename);
diff --git a/core/UpdateCheck.php b/core/UpdateCheck.php
index b176ed87c3..e2ce130c4a 100644
--- a/core/UpdateCheck.php
+++ b/core/UpdateCheck.php
@@ -68,7 +68,8 @@ class UpdateCheck
*/
private static function getLatestAvailableVersionNumber()
{
- $channel = StaticContainer::get('\Piwik\Plugin\ReleaseChannels')->getActiveReleaseChannel();
+ $releaseChannels = StaticContainer::get('\Piwik\Plugin\ReleaseChannels');
+ $channel = $releaseChannels->getActiveReleaseChannel();
$url = $channel->getUrlToCheckForLatestAvailableVersion();
try {
diff --git a/core/Updates/2.16.1-b3.php b/core/Updates/2.16.1-b3.php
new file mode 100644
index 0000000000..cb46053660
--- /dev/null
+++ b/core/Updates/2.16.1-b3.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Updates;
+
+use Piwik\Plugins\Installation\ServerFilesGenerator;
+use Piwik\Updates;
+use Piwik\Updater;
+
+/**
+ */
+class Updates_2_16_1_b3 extends Updates
+{
+ public function doUpdate(Updater $updater)
+ {
+ // added .eot whitelisted file for apache webserver
+ ServerFilesGenerator::deleteHtAccessFiles();
+ ServerFilesGenerator::createHtAccessFiles();
+ }
+} \ No newline at end of file
diff --git a/js/README.md b/js/README.md
index 1d409cebff..9556dc402e 100644
--- a/js/README.md
+++ b/js/README.md
@@ -31,13 +31,13 @@ The js/ folder contains:
## Deployment
-* piwik.js is minified using YUICompressor 2.4.2.
+* piwik.js is minified using YUICompressor 2.4.7.
To install YUICompressor run:
```bash
$ cd /path/to/piwik/js/
- $ wget http://www.julienlecomte.net/yuicompressor/yuicompressor-2.4.2.zip
- $ unzip yuicompressor-2.4.2.zip
+ $ wget https://github.com/downloads/yui/yuicompressor/yuicompressor-2.4.7.zip
+ $ unzip yuicompressor-2.4.7.zip
```
To compress the code containing the evil "eval", either apply the patch from
@@ -46,7 +46,7 @@ The js/ folder contains:
```bash
$ cd /path/to/piwik/js/
- $ sed '/<DEBUG>/,/<\/DEBUG>/d' < piwik.js | sed 's/eval/replacedEvilString/' | java -jar yuicompressor-2.4.2/build/yuicompressor-2.4.2.jar --type js --line-break 1000 | sed 's/replacedEvilString/eval/' | sed 's/^[/][*]/\/*!/' > piwik-min.js && cp piwik-min.js ../piwik.js
+ $ sed '/<DEBUG>/,/<\/DEBUG>/d' < piwik.js | sed 's/eval/replacedEvilString/' | java -jar yuicompressor-2.4.7/build/yuicompressor-2.4.7.jar --type js --line-break 1000 | sed 's/replacedEvilString/eval/' | sed 's/^[/][*]/\/*!/' > piwik-min.js && cp piwik-min.js ../piwik.js
```
This will generate the minify /path/to/piwik/js/piwik-min.js and copy it to
diff --git a/js/piwik.js b/js/piwik.js
index cd00196bd2..aa3d2f8921 100644
--- a/js/piwik.js
+++ b/js/piwik.js
@@ -1068,10 +1068,6 @@ if (typeof window.Piwik !== 'object') {
/* performance timing */
performanceAlias = windowAlias.performance || windowAlias.mozPerformance || windowAlias.msPerformance || windowAlias.webkitPerformance,
- /* DOM Ready */
- hasLoaded = false,
- registeredOnLoadHandlers = [],
-
/* encode */
encodeWrapper = windowAlias.encodeURIComponent,
@@ -1247,72 +1243,6 @@ if (typeof window.Piwik !== 'object') {
}
/*
- * Handler for onload event
- */
- function loadHandler() {
- var i;
-
- if (!hasLoaded) {
- hasLoaded = true;
- executePluginMethod('load');
- for (i = 0; i < registeredOnLoadHandlers.length; i++) {
- registeredOnLoadHandlers[i]();
- }
- }
-
- return true;
- }
-
- /*
- * Add onload or DOM ready handler
- */
- function addReadyListener() {
- var _timer;
-
- if (documentAlias.addEventListener) {
- addEventListener(documentAlias, 'DOMContentLoaded', function ready() {
- documentAlias.removeEventListener('DOMContentLoaded', ready, false);
- loadHandler();
- });
- } else if (documentAlias.attachEvent) {
- documentAlias.attachEvent('onreadystatechange', function ready() {
- if (documentAlias.readyState === 'complete') {
- documentAlias.detachEvent('onreadystatechange', ready);
- loadHandler();
- }
- });
-
- if (documentAlias.documentElement.doScroll && windowAlias === windowAlias.top) {
- (function ready() {
- if (!hasLoaded) {
- try {
- documentAlias.documentElement.doScroll('left');
- } catch (error) {
- setTimeout(ready, 0);
-
- return;
- }
- loadHandler();
- }
- }());
- }
- }
-
- // sniff for older WebKit versions
- if ((new RegExp('WebKit')).test(navigatorAlias.userAgent)) {
- _timer = setInterval(function () {
- if (hasLoaded || /loaded|complete/.test(documentAlias.readyState)) {
- clearInterval(_timer);
- loadHandler();
- }
- }, 10);
- }
-
- // fallback
- addEventListener(windowAlias, 'load', loadHandler, false);
- }
-
- /*
* Load JavaScript file (asynchronously)
*/
function loadScript(src, onLoad) {
@@ -3112,7 +3042,7 @@ if (typeof window.Piwik !== 'object') {
function isSitePath (path, pathAlias)
{
- var matchesAnyPath = (!pathAlias || pathAlias === '/');
+ var matchesAnyPath = (!pathAlias || pathAlias === '/' || pathAlias === '/*');
if (matchesAnyPath) {
return true;
@@ -3129,6 +3059,26 @@ if (typeof window.Piwik !== 'object') {
pathAlias = String(pathAlias).toLowerCase();
path = String(path).toLowerCase();
+ // wildcard path support
+ if(stringEndsWith(pathAlias, '*')) {
+ // remove the final '*' before comparing
+ pathAlias = pathAlias.slice(0, -1);
+
+ // Note: this is almost duplicated from just few lines above
+ matchesAnyPath = (!pathAlias || pathAlias === '/');
+
+ if (matchesAnyPath) {
+ return true;
+ }
+
+ if (path === pathAlias) {
+ return true;
+ }
+
+ // wildcard match
+ return path.indexOf(pathAlias) === 0;
+ }
+
// we need to append slashes so /foobarbaz won't match a site /foobar
if (!stringEndsWith(path, '/')) {
path += '/';
@@ -3141,6 +3091,15 @@ if (typeof window.Piwik !== 'object') {
return path.indexOf(pathAlias) === 0;
}
+ /**
+ * Whether the specified domain name and path belong to any of the alias domains (eg. set via setDomains).
+ *
+ * Note: this function is used to determine whether a click on a URL will be considered an "Outlink".
+ *
+ * @param host
+ * @param path
+ * @returns {boolean}
+ */
function isSiteHostPath(host, path)
{
var i,
@@ -4497,7 +4456,9 @@ if (typeof window.Piwik !== 'object') {
'contentImpressions'
);
- requests.push(request);
+ if (request) {
+ requests.push(request);
+ }
}
return requests;
@@ -4689,7 +4650,7 @@ if (typeof window.Piwik !== 'object') {
} else if (windowAlias.addEventListener) {
windowAlias.addEventListener('load', callback);
} else if (windowAlias.attachEvent) {
- windowAlias.attachEvent('onLoad', callback);
+ windowAlias.attachEvent('onload', callback);
}
}
@@ -4698,18 +4659,61 @@ if (typeof window.Piwik !== 'object') {
var loaded = false;
if (documentAlias.attachEvent) {
- loaded = documentAlias.readyState === "complete";
+ loaded = documentAlias.readyState === 'complete';
} else {
- loaded = documentAlias.readyState !== "loading";
+ loaded = documentAlias.readyState !== 'loading';
}
if (loaded) {
callback();
- } else if (documentAlias.addEventListener) {
- documentAlias.addEventListener('DOMContentLoaded', callback);
+ return;
+ }
+
+ var _timer;
+
+ if (documentAlias.addEventListener) {
+ addEventListener(documentAlias, 'DOMContentLoaded', function ready() {
+ documentAlias.removeEventListener('DOMContentLoaded', ready, false);
+ if (!loaded) {
+ loaded = true;
+ callback();
+ }
+ });
} else if (documentAlias.attachEvent) {
- documentAlias.attachEvent('onreadystatechange', callback);
+ documentAlias.attachEvent('onreadystatechange', function ready() {
+ if (documentAlias.readyState === 'complete') {
+ documentAlias.detachEvent('onreadystatechange', ready);
+ if (!loaded) {
+ loaded = true;
+ callback();
+ }
+ }
+ });
+
+ if (documentAlias.documentElement.doScroll && windowAlias === windowAlias.top) {
+ (function ready() {
+ if (!loaded) {
+ try {
+ documentAlias.documentElement.doScroll('left');
+ } catch (error) {
+ setTimeout(ready, 0);
+
+ return;
+ }
+ loaded = true;
+ callback();
+ }
+ }());
+ }
}
+
+ // fallback
+ addEventListener(windowAlias, 'load', function () {
+ if (!loaded) {
+ loaded = true;
+ callback();
+ }
+ }, false);
}
/*
@@ -4946,60 +4950,6 @@ if (typeof window.Piwik !== 'object') {
});
}
- /**
- * Note: While we check whether the user is on a configHostAlias path we do not check whether the user is
- * actually on the configHostAlias domain. This is already done where this method is called and for
- * simplicity we do not check this again.
- *
- * Also we currently assume that all configHostAlias domains start with the same wild card of '*.', '.' or
- * none. Eg either all like '*.piwik.org' or '.piwik.org' or 'piwik.org'. Piwik always adds '*.' so it
- * should be fine.
- */
- function findConfigCookiePathToUse(configHostAlias, currentUrl)
- {
- var aliasPath = getPathName(configHostAlias);
- var currentPath = getPathName(currentUrl);
-
- if (!aliasPath || aliasPath === '/' || !currentPath || currentPath === '/') {
- // no path set that would be useful for cookiePath
- return;
- }
-
- var aliasDomain = domainFixup(configHostAlias);
-
- if (isSiteHostPath(aliasDomain, '/')) {
- // there is another configHostsAlias having same domain that allows all paths
- // eg this alias is for piwik.org/support but there is another alias allowing
- // piwik.org
- return;
- }
-
- if (stringEndsWith(aliasPath, '/')) {
- aliasPath = removeCharactersFromEndOfString(aliasPath, 1);
- }
-
- // eg if we're in the case of "apache.piwik/foo/bar" we check whether there is maybe
- // also a config alias allowing "apache.piwik/foo". In this case we're not allowed to set
- // the cookie for "/foo/bar" but "/foo"
- var pathAliasParts = aliasPath.split('/');
- var i;
- for (i = 2; i < pathAliasParts.length; i++) {
- var lessRestrctivePath = pathAliasParts.slice(0, i).join('/');
- if (isSiteHostPath(aliasDomain, lessRestrctivePath)) {
- aliasPath = lessRestrctivePath;
- break;
- }
- }
-
- if (!isSitePath(currentPath, aliasPath)) {
- // current path of current URL does not match the alias
- // eg user is on piwik.org/demo but configHostAlias is for piwik.org/support
- return;
- }
-
- return aliasPath;
- }
-
/*
* Browser features (plugins, resolution, cookies)
*/
@@ -5578,10 +5528,8 @@ if (typeof window.Piwik !== 'object') {
* case all links that don't go to '*.piwik.org/subsite1/ *' would be treated as outlinks.
* For example a link to 'piwik.org/' or 'piwik.org/subsite2' both would be treated as outlinks.
*
- * We might automatically set a cookieConfigPath to avoid creating several cookies under one domain
- * if there is a hostAlias defined with a path. Say a user is visiting 'http://piwik.org/subsite1'
- * and '.piwik.org/subsite1' is set as a hostsAlias. Piwik will automatically use '/subsite1' as
- * cookieConfigPath.
+ * Also supports page wildcard, eg 'piwik.org/index*'. In this case all links
+ * that don't go to piwik.org/index* would be treated as outlinks.
*
* @param string|array hostsAlias
*/
@@ -5593,15 +5541,6 @@ if (typeof window.Piwik !== 'object') {
if (Object.prototype.hasOwnProperty.call(configHostsAlias, i)
&& isSameHost(domainAlias, domainFixup(String(configHostsAlias[i])))) {
hasDomainAliasAlready = true;
-
- if (!configCookiePath) {
- var path = findConfigCookiePathToUse(configHostsAlias[i], locationHrefAlias);
- if (path) {
- this.setCookiePath(path);
- }
-
- break;
- }
}
}
@@ -5878,15 +5817,11 @@ if (typeof window.Piwik !== 'object') {
enableLinkTracking: function (enable) {
linkTrackingEnabled = true;
- if (hasLoaded) {
- // the load event has already fired, add the click listeners now
- addClickListeners(enable);
- } else {
- // defer until page has loaded
- registeredOnLoadHandlers.push(function () {
+ trackCallback(function () {
+ trackCallbackOnReady(function () {
addClickListeners(enable);
});
- }
+ });
},
/**
@@ -6447,7 +6382,6 @@ if (typeof window.Piwik !== 'object') {
// initialize the Piwik singleton
addEventListener(windowAlias, 'beforeunload', beforeUnloadHandler, false);
- addReadyListener();
Date.prototype.getTimeAlias = Date.prototype.getTime;
diff --git a/lang/el.json b/lang/el.json
index fcceae2a81..c141191e32 100644
--- a/lang/el.json
+++ b/lang/el.json
@@ -62,11 +62,11 @@
"ColumnNbActions": "Δραστηριότητες",
"ColumnNbActionsDocumentation": "Ο αριθμός των δραστηριοτήτων που έγιναν από τους επισκέπτες σας. Οι δραστηριότητες μπορεί να είναι προβολές σελίδων, λήψεις ή εξωτερικοί σύνδεσμοι.",
"ColumnNbUniqVisitors": "Μοναδικοί επισκέπτες",
- "ColumnNbUniqVisitorsDocumentation": "Ο αριθμός των μη διπλών επισκεπτών που έρχονται στην ιστοσελίδα. Κάθε χρήστης καταγράφετε μόνο μια φορά, ακόμα και αν επισκέπτεται την ιστοσελίδα περισσότερες φορές τη μέρα.",
+ "ColumnNbUniqVisitorsDocumentation": "Ο αριθμός των μη διπλών επισκεπτών που έρχονται στην ιστοσελίδα. Κάθε χρήστης καταγράφεται μόνο μια φορά, ακόμα και αν επισκέπτεται την ιστοσελίδα περισσότερες φορές τη μέρα.",
"ColumnNbUsers": "Χρήστες",
"ColumnNbUsersDocumentation": "Ο αριθμός χρηστών που έχουν κάνει είσοδο στον ιστοτόπο σας. Είναι ο αριθμός των μοναδικών ενεργών χρηστών που έχουν καθορισμένο αναγνωριστικό χρήστη (μέσω της συνάρτησης παρακολούθησης 'setUserId').",
"ColumnNbVisits": "Επισκέψεις",
- "ColumnNbVisitsDocumentation": "Αν ένας επισκέπτης έρθει στην ιστοσελίδα για πρώτη φορά ή αν επισκέπτεται μια σελίδα για περισσότερο από 30 λεπτά μετά την τελευταία προβολή σελίδας, αυτό θα καταγράφετε ως νέα επίσκεψη.",
+ "ColumnNbVisitsDocumentation": "Αν ένας επισκέπτης έρθει στην ιστοσελίδα για πρώτη φορά ή αν επισκέπτεται μια σελίδα για περισσότερο από 30 λεπτά μετά την τελευταία προβολή σελίδας, αυτό θα καταγράφεται ως νέα επίσκεψη.",
"ColumnPageBounceRateDocumentation": "Το ποσοστό των επισκέψεων που ξεκίνησαν σε αυτή τη σελίδα και άφησαν την ιστοσελίδα αμέσως.",
"ColumnPageviews": "Προβολές σελίδων",
"ColumnPageviewsDocumentation": "Οι επισκέψεις αυτής της σελίδας.",
@@ -77,7 +77,7 @@
"ColumnUniqueEntrances": "Μοναδικές είσοδοι",
"ColumnUniqueExits": "Μοναδικές έξοδοι",
"ColumnUniquePageviews": "Μοναδικές προβολές σελίδων",
- "ColumnUniquePageviewsDocumentation": "Ο αριθμός των επισκέψεων που περιελάμβαναν αυτή τη σελίδα. Αν μια σελίδα προβλήθηκε πολλές φορές σε μια επίσκεψη, καταγράφετε μόνο μια φορά..",
+ "ColumnUniquePageviewsDocumentation": "Ο αριθμός των επισκέψεων που περιελάμβαναν αυτή την σελίδα. Αν μια σελίδα προβλήθηκε πολλές φορές σε μια επίσκεψη, καταγράφεται μόνο μια φορά.",
"ColumnValuePerVisit": "Τιμή ανά Επίσκεψη",
"ColumnViewedAfterSearch": "Πατημένο στα αποτελέσματα αναζήτησης",
"ColumnViewedAfterSearchDocumentation": "Ο αριθμός των επισκέψεων σε αυτή τη σελίδα, έπειτα από αναζήτηση ενός επισκέπτη στην ιστοσελίδα σας και αφού στη συνέχεια έκανε κλικ σε αυτή τη σελίδα από τα αποτελέσματα αναζήτησης.",
diff --git a/lang/fi.json b/lang/fi.json
index 715c3afc41..a864ac39be 100644
--- a/lang/fi.json
+++ b/lang/fi.json
@@ -1,5 +1,7 @@
{
"General": {
+ "12HourClock": "12-tuntinen kello",
+ "24HourClock": "24-tuntinen kello",
"AbandonedCarts": "Hylätyt ostoskorit",
"AboutPiwikX": "Tietoja Piwikistä %s",
"Action": "Toiminto",
@@ -10,6 +12,7 @@
"AllWebsitesDashboard": "Kaikkien verkkosivujen työpöytä",
"And": "ja",
"API": "API",
+ "Apply": "Käytä",
"ArchivingInlineHelp": "Keskikokoisilla ja vilkkailla sivulla on suositeltavaa kieltää arkistointi selaimesta. Parempi vaihtoehto on käyttää cron-työtä arkistointiin joka tunti.",
"ArchivingTriggerDescription": "Suositeltavaa suuremmissa Piwik-asennuksissa. Sinun täytyy %1$sasentaa cron-työ%2$s, jotta raportit käsitellään oikein.",
"AuthenticationMethodSmtp": "SMTP:n autentikointimenetelmä",
@@ -23,6 +26,7 @@
"CannotUnzipFile": "Ei voi purkaa tiedostoa %1$s: %2$s",
"ChangePassword": "Vaihda salasana",
"ChangeTagCloudView": "Voit katsoa raporttia myös muissa muodoissa. Käytä nappuloita raportin alareunassa.",
+ "ChooseDate": "Valitse päivä, nyt valittu päivä: %s",
"ChooseLanguage": "Valitse kieli",
"ChoosePeriod": "Valitse aikaväli",
"ClickHere": "Klikkaa tästä lisätietoja.",
@@ -81,6 +85,8 @@
"ConfigFileIsNotWritable": "Piwikin asetustiedostoon %1$s ei voi kirjoittaa. Kaikkia muutoksia ei voi tallentaa. %2$s Muuta tiedoston oikeuksia niin, että kirjoittaminen on sallittua.",
"Continue": "Jatka",
"ContinueToPiwik": "Jatka Piwikiin",
+ "CurrentlyUsingUnsecureHttp": "Käytät Piwikiä epäturvallisen HTTP:n yli. Suosittelemme säätämään Piwikin käyttämään SSL:ää (HTTPS).",
+ "CreatedByUser": "luoja %s",
"CurrentMonth": "Tämä kuukausi",
"CurrentWeek": "Tämä viikko",
"CurrentYear": "Tämä vuosi",
@@ -94,6 +100,7 @@
"Date": "Päiväys",
"DateRange": "Aikaväli:",
"DateRangeFrom": "Alkaen",
+ "DateRangeInPeriodList": "päiväysalue",
"DateRangeTo": "Mihin",
"DaysHours": "%1$s päivää %2$s tuntia",
"DaysSinceFirstVisit": "Päiviä ensimmäisestä käynnistä",
@@ -221,6 +228,7 @@
"Name": "Nimi",
"NbActions": "Toimintojen määrä",
"NbSearches": "Sisäisten hakujen määrä",
+ "NeedMoreHelp": "Tarvitsetko lisää apua?",
"Never": "Ei koskaan",
"NewReportsWillBeProcessedByCron": "Kun Piwikin arkistointia ei käynnistetä selaimesta, uudet raportit luodaan cronilla.",
"NewUpdatePiwikX": "Uusi päivitys: Piwik %s",
@@ -233,6 +241,7 @@
"NotDefined": "%s ei ole määritetty.",
"Note": "Huomio",
"NotInstalled": "Ei asennettu",
+ "NotRecommended": "ei suositella",
"NotValid": "%s on virheellinen",
"NumberOfVisits": "Käyntien lukumäärä",
"NUsers": "%s käyttäjää",
@@ -256,6 +265,7 @@
"OperationNotEquals": "Ei täsmää",
"OptionalSmtpPort": "Valinnainen. Oletus 25 salaamattomalle ja TLS:lle ja 465 SSL:lle.",
"Options": "Asetukset",
+ "Or": "tai",
"OrCancel": "tai %1$s peruuta %2$s",
"Others": "Muut",
"Outlink": "Lähtevä linkki",
@@ -283,10 +293,13 @@
"Price": "Hinta",
"ProductConversionRate": "Tuotteen konversiot",
"ProductRevenue": "Tuotteiden tulot",
+ "Measurable": "Mitattava",
+ "Measurables": "Mitattavat",
"PurchasedProducts": "Ostetut tuotteet",
"Quantity": "Määrä",
"RangeReports": "Oma aikaväli",
"ReadThisToLearnMore": "%1$sLue täältä lisätietoa.%2$s",
+ "Recommended": "Suositeltu",
"RecordsToPlot": "Piirrettävät tietueet",
"Refresh": "Päivitä",
"RefreshPage": "Päivitä sivu",
@@ -297,6 +310,7 @@
"ReportGeneratedFrom": "Tämä raportti on luotu %s:n tiedoista.",
"ReportRatioTooltip": "'%1$s' kuvaa %2$s :ta %3$s %4$s :ssa %5$s:n kanssa.",
"Reports": "Raportit",
+ "ReportsContainingTodayWillBeProcessedAtMostEvery": "Arkistoi enintään joka X sekunti",
"ReportsWillBeProcessedAtMostEveryHour": "Raportit päivitetään enintään kerran tunnissa.",
"RequestTimedOut": "Pyyntö osoitteeseen %s aikakatkaistiin. Ole hyvä ja yritä uudelleen.",
"Required": "%s vaaditaan",
@@ -334,10 +348,14 @@
"TagCloud": "Avainsanapilvi",
"Tax": "Verot",
"TimeAgo": "%s sitten",
+ "TimeFormat": "Aikamuoto",
"TimeOnPage": "Aika sivulla",
"Total": "Yhteensä",
"TotalRatioTooltip": "Tämä on %1$s kaikista %2$s %3$s.",
"TotalRevenue": "Tulot yhteensä",
+ "TrackingScopeAction": "Toiminto",
+ "TrackingScopePage": "Sivu",
+ "TrackingScopeVisit": "Käynti",
"TransitionsRowActionTooltip": "Näe mitä kävijät tekivät ennen ja jälkeen tällä sivulla käymistä",
"TransitionsRowActionTooltipTitle": "Avaa muutokset",
"TranslatorName": "<a href=\"http:\/\/olli.jarva.fi\/\">Olli Jarva<\/a>",
@@ -363,6 +381,7 @@
"Visitors": "Kävijät",
"VisitsWith": "Käynnit %s:n kanssa",
"VisitorSettings": "Kävijöiden asetukset",
+ "VisitType": "Käyntityyppi",
"VisitTypeExample": "Voit esimerkiksi valita kaikki kävijät jotka palasivat sivulle ja ostivat edellisellä käynnillä. Esimerkki pyynnöstä on %s",
"Warning": "Varoitus",
"WarningPhpVersionXIsTooOld": "Käyttämäsi PHP versio %s on ohittanut EOL (End of Life) ajankohdan. Suosittelemme vakavasti ohjelmiston päivittämistä uudempaan versioon, sillä käyttämäsi versio voi altistaa sivuston tietoturva-aukoille ja virheille, jotka ovat korjattu PHP:n uudemmissa versioissa.",
@@ -384,6 +403,7 @@
"YearsDays": "%1$s vuotta %2$s päivää",
"Yes": "Kyllä",
"YouAreCurrentlyUsing": "Käytät Piwik %s:ää",
+ "YouAreViewingDemoShortMessage": "Katsot Piwikin demoversiota",
"YouMustBeLoggedIn": "Sinun täytyy kirjautua sisään ennen tämän toiminnallisuuden käyttämistä.",
"YourChangesHaveBeenSaved": "Muutokset on tallennettu"
},
diff --git a/lang/ko.json b/lang/ko.json
index 615e8bf383..761a278d51 100644
--- a/lang/ko.json
+++ b/lang/ko.json
@@ -27,6 +27,7 @@
"CannotUnzipFile": "%1$s 파일의 압축을 풀 수 없습니다: %2$s",
"ChangePassword": "비밀번호 변경",
"ChangeTagCloudView": "태그 클라우드가 아닌 다른 방법으로 보고서를 볼 수 있습니다. 보고서의 아래쪽에있는 컨트롤을 사용하세요.",
+ "ChooseDate": "날짜를 선택하세요, 현재 선택된 날짜는 %s",
"ChooseLanguage": "언어 선택",
"ChoosePeriod": "기간 선택",
"ClickHere": "자세한 내용은 이곳을 클릭하세요.",
@@ -84,6 +85,7 @@
"Continue": "계속",
"ContinueToPiwik": "Piwik 계속 하기",
"CurrentlyUsingUnsecureHttp": "현재 위험할 수 있는 불안전한 HTTP를 통해 Piwik를 이용하고 있습니다. 우리는 SSL (HTTPS)를 설치하여 보안을 향상시킬 것을 추천합니다.",
+ "CreatedByUser": "%s가 만듬",
"CurrentMonth": "이번달",
"CurrentWeek": "이번주",
"CurrentYear": "올해",
@@ -242,6 +244,7 @@
"OperationDoesNotContain": "포함하지 않기",
"OptionalSmtpPort": "옵션입니다. 비 암호화 및 TLS SMTP는 25가 SSL SMTP는 465이 기본입니다.",
"Options": "설정",
+ "Or": "혹은",
"OrCancel": "또는 %1$s 취소 %2$s",
"Others": "기타",
"Outlink": "외부링크",
@@ -298,6 +301,7 @@
"Save": "저장",
"SaveImageOnYourComputer": "이미지를 저장하려면 이미지를 오른쪽으로 클릭하여 \"다른 이름으로 그림 저장...\"을 선택합니다",
"Search": "검색",
+ "SearchNoResults": "결과 없음",
"SeeAll": "다 보기",
"SeeTheOfficialDocumentationForMoreInformation": "자세한 내용은 %1$s 공식 문서 %2$s를 참조하세요.",
"SelectYesIfYouWantToSendEmailsViaServer": "로컬 mail() 함수 대신 메일서버를 통해 이메일을 보낼 경우, \"예\"를 선택합니다",
diff --git a/lang/nb.json b/lang/nb.json
index c20d68cb56..c307c41792 100644
--- a/lang/nb.json
+++ b/lang/nb.json
@@ -231,6 +231,7 @@
"Name": "Navn",
"NbActions": "Antall handlinger",
"NbSearches": "Antall interne søk",
+ "NeedMoreHelp": "Trenger du mer hjelp?",
"Never": "Aldri",
"NewReportsWillBeProcessedByCron": "Hvis Piwik-arkivering ikke blir utløst av nettleseren, så vil nye rapporter bli prosessert ved hjelp av crontab.",
"NewUpdatePiwikX": "Ny utgave: Piwik %s",
diff --git a/lang/pl.json b/lang/pl.json
index b908e83f8e..72fc354356 100644
--- a/lang/pl.json
+++ b/lang/pl.json
@@ -13,6 +13,7 @@
"AllWebsitesDashboard": "Tablica analiz wszystkich stron",
"And": "i",
"API": "API",
+ "Apply": "Zastosuj",
"ArchivingInlineHelp": "Dla serwisów o średnim i wysokim natężeniu ruchu, zalecane jest wyłączenie archiwizacji danych Piwik podczas przeglądania raportów w przeglądarce. Zamiast tego zaleca się skonfigurowanie żądania cron, by przetwarzanie raportów Piwik następowało co godzinę.",
"ArchivingTriggerDescription": "Zalecany dla większych instalacji Piwik, musisz %1$sskonfigurować crona%2$s do przetwarzania raportów automatycznie.",
"AuthenticationMethodSmtp": "Metoda uwierzytelnienie dla SMTP",
diff --git a/lang/ru.json b/lang/ru.json
index 79d4aed2c4..9ec7aa55b0 100644
--- a/lang/ru.json
+++ b/lang/ru.json
@@ -1,5 +1,7 @@
{
"General": {
+ "12HourClock": "12-часовой формат времени",
+ "24HourClock": "24-часовой формат времени",
"AbandonedCarts": "Нереализованные покупки",
"AboutPiwikX": "О Piwik %s",
"Action": "Действие",
@@ -25,6 +27,7 @@
"CannotUnzipFile": "Не могу распаковать файл %1$s: %2$s",
"ChangePassword": "Изменить пароль",
"ChangeTagCloudView": "Учтите, что Вы можете просматривать отчет не только через облако тегов. Используйте элементы управления внизу отчета для переключения вариантов просмотра.",
+ "ChooseDate": "Выбор даты, сейчас выбрана дата %s",
"ChooseLanguage": "Выбрать язык",
"ChoosePeriod": "Выбрать период",
"ClickHere": "Нажмите здесь, чтобы узнать больше",
@@ -83,6 +86,8 @@
"ConfigFileIsNotWritable": "Файл конфигурации Piwik %1$s закрыт для записи, ваши изменения не будут сохранены. %2$s Пожалуйста, измените разрешения конфигурационного файла и разрешите запись в него.",
"Continue": "Продолжить",
"ContinueToPiwik": "Перейти к Piwik",
+ "CurrentlyUsingUnsecureHttp": "В данный момент вы используете Piwik через небезопасное соединение HTTP, что может быть рискованно. Мы рекомендуем настроить Piwik на использование SSL (HTTPS) для повышения уровня безопасности.",
+ "CreatedByUser": "сделано %s",
"CurrentMonth": "Текущий месяц",
"CurrentWeek": "Текущая неделя",
"CurrentYear": "Текущий год",
@@ -225,6 +230,7 @@
"Name": "Имя",
"NbActions": "Количество действий",
"NbSearches": "Количество обращений к внутреннему поиску",
+ "NeedMoreHelp": "Нужна помощь?",
"Never": "Никогда",
"NewReportsWillBeProcessedByCron": "Если архивирование Piwik не провоцируется браузером, новые отчеты производятся с помощью crontab-задач.",
"NewUpdatePiwikX": "Новое обновление: Piwik %s",
@@ -259,8 +265,11 @@
"OperationIsNot": "Не",
"OperationLessThan": "Меньше чем",
"OperationNotEquals": "Не равно",
+ "OperationStartsWith": "Начинается с",
+ "OperationEndsWith": "Заканчивается с",
"OptionalSmtpPort": "Необязательно. По умолчанию используется 25 для незашифрованного и TLS SMTP соединения, и 465 для SSL SMTP.",
"Options": "Настройки",
+ "Or": "или",
"OrCancel": "или %1$s отмените %2$s",
"Others": "Другие",
"Outlink": "Исходящая ссылка",
@@ -289,6 +298,8 @@
"Price": "Цена",
"ProductConversionRate": "Конверсия для товара",
"ProductRevenue": "Прибыль с товара",
+ "Measurable": "Единица измерения",
+ "Measurables": "Единицы измерения",
"PurchasedProducts": "Купленные товары",
"Quantity": "Количество",
"RangeReports": "Другие периоды",
@@ -349,6 +360,9 @@
"TotalRatioTooltip": "Это %1$s из всех %2$s %3$s.",
"TotalRevenue": "Общая прибыль",
"TotalVisitsPageviewsActionsRevenue": "(Всего: %1$s визиты, %2$s просмотры страниц, %3$s действия, %4$s выручка)",
+ "TrackingScopeAction": "Действие",
+ "TrackingScopePage": "Страница",
+ "TrackingScopeVisit": "Посещение",
"TransitionsRowActionTooltip": "Посмотрите, что посетители делали до и после просмотра этой страницы",
"TransitionsRowActionTooltipTitle": "Открыть переходы",
"TranslatorName": "Ademaro, Joker Interactive, Важенин Илья (компания Codax), Nelde Maxim, Andrey, Vadim Nekhai, UptimePal",
@@ -383,6 +397,7 @@
"WarningFileIntegrityNoManifestDeployingFromGit": "Если вы делаете деплой Piwik из Git, это сообщение является нормальным.",
"WarningFileIntegrityNoMd5file": "Проверка целостности не может быть проведена из-за отсутствия функции md5_file().",
"WarningPasswordStored": "%1$sВнимание:%2$s Этот пароль будет сохранен в конфигурационном файле на сервере в незашифрованном виде, и будет виден любому, кто имеет доступ к файловой системе сервера.",
+ "WarningDebugOnDemandEnabled": "Режим слежения за %1$s включен. Из соображений безопасности он должен быть включен только в небольшой период времени. Чтобы отключить его, установите %2$s на %3$s в %4$s",
"Website": "Сайт",
"Weekly": "Еженедельно",
"WeeklyReport": "еженедельно",
diff --git a/lang/sq.json b/lang/sq.json
index 175075db1d..c071259db9 100644
--- a/lang/sq.json
+++ b/lang/sq.json
@@ -208,6 +208,7 @@
"NoDataForGraph": "Pa të dhëna për këtë grafik",
"NoDataForTagCloud": "Pa të dhëna për këtë re etiketash.",
"NotDefined": "%s pa u përkufizuar",
+ "NotRecommended": "jo e këshillueshme",
"NotValid": "%s nuk është e vlefshme",
"NumberOfVisits": "Numër vizitash",
"NVisits": "%s vizita",
@@ -273,6 +274,7 @@
"Total": "Gjithsej",
"TotalRevenue": "Të ardhura Gjithsej",
"TotalVisitsPageviewsActionsRevenue": "(Gjithsej: %1$s vizita, %2$s parje faqesh, %3$s veprime, %4$s të ardhura)",
+ "TrackingScopePage": "Faqe",
"TranslatorName": "Besnik Bleta",
"UniquePurchases": "Blerje Unike",
"Unknown": "I panjohur",
diff --git a/lang/sr.json b/lang/sr.json
index 578d418821..b32a676c9b 100644
--- a/lang/sr.json
+++ b/lang/sr.json
@@ -351,7 +351,7 @@
"TotalVisitsPageviewsActionsRevenue": "(Ukupno poseta %1$s, prikaza %2$s, akcija %3$s, zarada %4$s)",
"TransitionsRowActionTooltip": "Pogledajte šta su posetioci radili pre i posle posete ovoj stranici",
"TransitionsRowActionTooltipTitle": "Otvori tranzicije",
- "TranslatorName": "Petar Benke, Branislav Maksin, Nikola Stojković",
+ "TranslatorName": "<a href=\"https:\/\/www.linkedin.com\/in\/petar-benke-905a02b8\">Petar Benke<\/a>, Branislav Maksin, Nikola Stojković",
"UniquePurchases": "Jedinstvene porudžbine",
"Unknown": "Nepoznato",
"Upload": "Okači",
diff --git a/lang/sv.json b/lang/sv.json
index 9628ac2bf3..312eb24a1b 100644
--- a/lang/sv.json
+++ b/lang/sv.json
@@ -366,7 +366,7 @@
"TrackingScopeVisit": "Besök",
"TransitionsRowActionTooltip": "Se vad besökarna gjorde före och efter att ha tittat på den här sidan",
"TransitionsRowActionTooltipTitle": "Öppna övergångar",
- "TranslatorName": "Sökmotoroptimering.se, Kampanjjakt.se, Fredrik Astrom, Tony",
+ "TranslatorName": "Sökmotoroptimering.se, Kampanjjakt.se, Fredrik Astrom, Tony, <a href=\"http:\/\/www.kb.se\/\">National Library of Sweden<\/a>, <a href=\"https:\/\/www.facebook.com\/Rabattkod-147619931946607\">Yegane Shirazi<\/a>",
"UniquePurchases": "Unika beställningar",
"Unknown": "Okänt",
"Upload": "Ladda upp",
diff --git a/lang/tr.json b/lang/tr.json
index 219a429305..faa035cf35 100644
--- a/lang/tr.json
+++ b/lang/tr.json
@@ -285,7 +285,7 @@
"TrackingScopePage": "Sayfa",
"TrackingScopeVisit": "Ziyaret",
"TransitionsRowActionTooltipTitle": "Açık Geçişler",
- "TranslatorName": "Fabian Becker, Emre Yazici, Emre Saraçoğlu, Uğur Eskici, Umut ARICAN",
+ "TranslatorName": "Fabian Becker, Emre Yazici, Emre Saraçoğlu, Uğur Eskici, <a href=\"https:\/\/sourceforge.net\/u\/umutarcn\/profile\/\">Umut ARICAN<\/a>",
"UniquePurchases": "Tekil Satın Alımlar",
"Unknown": "Bilinmeyen",
"Upload": "Yükle",
diff --git a/libs/Zend/Validate/Hostname.php b/libs/Zend/Validate/Hostname.php
index cd5db5abcb..49e72dd1aa 100644
--- a/libs/Zend/Validate/Hostname.php
+++ b/libs/Zend/Validate/Hostname.php
@@ -57,6 +57,7 @@ class Zend_Validate_Hostname extends Zend_Validate_Abstract
const LOCAL_NAME_NOT_ALLOWED = 'hostnameLocalNameNotAllowed';
const UNDECIPHERABLE_TLD = 'hostnameUndecipherableTld';
const UNKNOWN_TLD = 'hostnameUnknownTld';
+ const VALID_UNICODE_DOMAIN = '/^[\p{L}\p{M}]{1,63}$/iu';
/**
* @var array
@@ -201,16 +202,7 @@ class Zend_Validate_Hostname extends Zend_Validate_Abstract
'villas', 'vin', 'vip', 'virgin', 'vision', 'vista', 'vistaprint', 'viva', 'vlaanderen', 'vn', 'vodka', 'vote',
'voting', 'voto', 'voyage', 'vu', 'wales', 'walter', 'wang', 'wanggou', 'watch', 'watches', 'webcam', 'weber',
'website', 'wed', 'wedding', 'weir', 'wf', 'whoswho', 'wien', 'wiki', 'williamhill', 'win', 'windows', 'wine',
- 'wme', 'work', 'works', 'world', 'ws', 'wtc', 'wtf', 'xbox', 'xerox', 'xin', 'कॉम', '佛山', '慈善', '集团',
- '在线', '한국', '点看', 'คอม', 'ভারত', '八卦', 'موقع', '公益', '公司', '移动', '我爱你', 'москва', 'қаз', 'онлайн',
- 'сайт', 'срб', 'бел', 'קום', '时尚', '淡马锡', 'орг', 'नेट', '삼성', 'சிங்கப்பூர்', '商标', '商店', '商城', 'дети',
- 'мкд', 'ポイント', '新闻', '工行', 'كوم', '中文网', '中信', '中国', '中國', '娱乐', '谷歌', 'భారత్', 'ලංකා', 'ભારત',
- 'भारत', '网店', 'संगठन', '餐厅', '网络', 'ком', 'укр', '香港', '诺基亚', '飞利浦', '台湾', '台灣', '手表', '手机',
- 'мон', 'الجزائر', 'عمان', 'ارامكو', 'ایران', 'امارات', 'بازار', 'الاردن', 'موبايلي', 'بھارت', 'المغرب',
- 'السعودية', 'سودان', 'همراه', 'عراق', 'مليسيا', '닷컴', '政府', 'شبكة', 'بيتك', 'გე', '机构', '组织机构',
- '健康', 'ไทย', 'سورية', 'рус', 'рф', '珠宝', 'تونس', '大拿', 'みんな', 'グーグル', 'ελ', '世界', 'ਭਾਰਤ', '网址',
- '닷넷', 'コム', '游戏', 'vermögensberater', 'vermögensberatung', '企业', '信息', 'مصر', 'قطر', '广东', 'இலங்கை',
- 'இந்தியா', 'հայ', '新加坡', 'فلسطين', '政务', 'xperia', 'xxx', 'xyz', 'yachts', 'yamaxun', 'yandex', 'ye',
+ 'wme', 'work', 'works', 'world', 'ws', 'wtc', 'wtf', 'xbox', 'xerox', 'xin', 'xperia', 'xxx', 'xyz', 'yachts', 'yamaxun', 'yandex', 'ye',
'yodobashi', 'yoga', 'yokohama', 'youtube', 'yt', 'za', 'zara', 'zero', 'zip', 'zm', 'zone', 'zuerich', 'zw'
);
@@ -371,9 +363,135 @@ class Zend_Validate_Hostname extends Zend_Validate_Abstract
'ایران' => array(1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'),
'中国' => 'Hostname/Cn.php',
'公司' => 'Hostname/Cn.php',
- '网络' => 'Hostname/Cn.php'
+ '网络' => 'Hostname/Cn.php',
+ 'कॉम' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'セール' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '佛山' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '慈善' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '集团' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '在线' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '한국' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '点看' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'คอม' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'ভারত' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '八卦' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'موقع' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '公益' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '公司' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '移动' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '我爱你' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'москва' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'қаз' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'онлайн' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'сайт' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '联通' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'срб' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'бел' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'קום' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '时尚' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '淡马锡' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'ファッション' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'орг' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'नेट' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'ストア' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '삼성' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'சிங்கப்பூர்' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '商标' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '商店' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '商城' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'дети' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'мкд' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'ею' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'ポイント' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '新闻' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '工行' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'كوم' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '中文网' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '中信' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '中国' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '中國' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '娱乐' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '谷歌' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'భారత్' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'ලංකා' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '购物' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'クラウド' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'ભારત' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'भारत' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '网店' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'संगठन' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '餐厅' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '网络' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'ком' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'укр' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '香港' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '诺基亚' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '食品' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '飞利浦' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '台湾' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '台灣' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '手表' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '手机' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'мон' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'الجزائر' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'عمان' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'ارامكو' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'ایران' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'امارات' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'بازار' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'الاردن' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'موبايلي' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'بھارت' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'المغرب' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'السعودية' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'سودان' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'همراه' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'عراق' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'مليسيا' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '澳門' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '닷컴' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '政府' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'شبكة' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'بيتك' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'გე' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '机构' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '组织机构' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '健康' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'ไทย' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'سورية' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'рус' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'рф' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '珠宝' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'تونس' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '大拿' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'みんな' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'グーグル' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'ελ' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '世界' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '書籍' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'ਭਾਰਤ' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '网址' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '닷넷' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'コム' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '游戏' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'VERMöGENSBERATER' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'VERMöGENSBERATUNG' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '企业' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '信息' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '嘉里大酒店' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'مصر' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'قطر' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '广东' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'இலங்கை' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'இந்தியா' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'հայ' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '新加坡' => array(1 => self::VALID_UNICODE_DOMAIN),
+ 'فلسطين' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '政务' => array(1 => self::VALID_UNICODE_DOMAIN),
+ '家電' => array(1 => self::VALID_UNICODE_DOMAIN),
);
+
protected $_idnLength = array(
'BIZ' => array(5 => 17, 11 => 15, 12 => 20),
'CN' => array(1 => 20),
@@ -744,7 +862,7 @@ class Zend_Validate_Hostname extends Zend_Validate_Abstract
// Check for URI Syntax (RFC3986)
if ($this->_options['allow'] & self::ALLOW_URI) {
- if (preg_match("/^([a-zA-Z0-9-._~!$&\'()*+,;=]|%[[:xdigit:]]{2}){1,254}$/i", $value)) {
+ if (preg_match("/^([a-zA-Z0-9-._~!$&'()*+,;=]|%[[:xdigit:]]{2}){1,254}$/i", $value)) {
return true;
} else {
$this->_error(self::INVALID_URI);
diff --git a/misc/cron/archive.php b/misc/cron/archive.php
index f719a2d3d4..0bc4daa1f1 100644
--- a/misc/cron/archive.php
+++ b/misc/cron/archive.php
@@ -22,18 +22,19 @@ define('PIWIK_ENABLE_SESSION_START', false);
require_once PIWIK_INCLUDE_PATH . '/core/Common.php';
-if (!empty($_SERVER['argv'][0])) {
- $callee = $_SERVER['argv'][0];
-} else {
- $callee = '';
-}
+if (Piwik\Common::isPhpCliMode()) {
+ require_once PIWIK_INCLUDE_PATH . "/core/bootstrap.php";
+
+ $console = new Piwik\Console();
-if (false !== strpos($callee, 'archive.php')) {
+ // manipulate command line arguments so CoreArchiver command will be executed
+ $script = array_shift($_SERVER['argv']);
$piwikHome = PIWIK_INCLUDE_PATH;
+
echo "
-------------------------------------------------------
Using this 'archive.php' script is no longer recommended.
-Please use '/path/to/php $piwikHome/console core:archive " . implode('', array_slice($_SERVER['argv'], 1)) . "' instead.
+Please use '/path/to/php $piwikHome/console core:archive " . implode(' ', $_SERVER['argv']) . "' instead.
To get help use '/path/to/php $piwikHome/console core:archive --help'
See also: http://piwik.org/docs/setup-auto-archiving/
@@ -41,16 +42,7 @@ If you cannot use the console because it requires CLI
try 'php archive.php --url=http://your.piwik/path'
-------------------------------------------------------
\n\n";
-}
-
-if (Piwik\Common::isPhpCliMode()) {
- require_once PIWIK_INCLUDE_PATH . "/core/bootstrap.php";
-
- $console = new Piwik\Console();
-
- // manipulate command line arguments so CoreArchiver command will be executed
- $script = array_shift($_SERVER['argv']);
array_unshift($_SERVER['argv'], 'core:archive');
array_unshift($_SERVER['argv'], $script);
diff --git a/misc/log-analytics b/misc/log-analytics
-Subproject f15f7271439380dbc7366aa117d3c8add358c26
+Subproject 45b09932404359f98bd44b43b09ea162bd0e3ca
diff --git a/piwik.js b/piwik.js
index 550e6053ab..b0d1b1abbe 100644
--- a/piwik.js
+++ b/piwik.js
@@ -1,4 +1,4 @@
-/*!
+/*!!
* Piwik - free/libre analytics platform
*
* JavaScript tracking client
@@ -9,7 +9,7 @@
* @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD-3-Clause
*/
if(typeof JSON2!=="object"&&typeof window.JSON==="object"&&window.JSON.stringify&&window.JSON.parse){JSON2=window.JSON}else{(function(){var a={};
-/*! JSON v3.3.2 | http://bestiejs.github.io/json3 | Copyright 2012-2014, Kit Cambridge | http://kit.mit-license.org */
+/*!! JSON v3.3.2 | http://bestiejs.github.io/json3 | Copyright 2012-2014, Kit Cambridge | http://kit.mit-license.org */
(function(){var c=typeof define==="function"&&define.amd;var e={"function":true,object:true};var h=e[typeof a]&&a&&!a.nodeType&&a;var i=e[typeof window]&&window||this,b=h&&e[typeof module]&&module&&!module.nodeType&&typeof global=="object"&&global;if(b&&(b.global===b||b.window===b||b.self===b)){i=b}function j(ab,V){ab||(ab=i.Object());V||(V=i.Object());var K=ab.Number||i.Number,R=ab.String||i.String,x=ab.Object||i.Object,S=ab.Date||i.Date,T=ab.SyntaxError||i.SyntaxError,aa=ab.TypeError||i.TypeError,J=ab.Math||i.Math,Y=ab.JSON||i.JSON;
if(typeof Y=="object"&&Y){V.stringify=Y.stringify;V.parse=Y.parse}var n=x.prototype,u=n.toString,r,m,L;var B=new S(-3509827334573292);try{B=B.getUTCFullYear()==-109252&&B.getUTCMonth()===0&&B.getUTCDate()===1&&B.getUTCHours()==10&&B.getUTCMinutes()==37&&B.getUTCSeconds()==6&&B.getUTCMilliseconds()==708}catch(v){}function o(ac){if(o[ac]!==L){return o[ac]}var ad;if(ac=="bug-string-char-index"){ad="a"[0]!="a"}else{if(ac=="json"){ad=o("json-stringify")&&o("json-parse")}else{var ak,ah='{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}';if(ac=="json-stringify"){var ai=V.stringify,aj=typeof ai=="function"&&B;if(aj){(ak=function(){return 1}).toJSON=ak;try{aj=ai(0)==="0"&&ai(new K())==="0"&&ai(new R())=='""'&&ai(u)===L&&ai(L)===L&&ai()===L&&ai(ak)==="1"&&ai([ak])=="[1]"&&ai([L])=="[null]"&&ai(null)=="null"&&ai([L,u,null])=="[null,null,null]"&&ai({a:[ak,true,false,null,"\x00\b\n\f\r\t"]})==ah&&ai(null,ak)==="1"&&ai([1,2],null,1)=="[\n 1,\n 2\n]"&&ai(new S(-8640000000000000))=='"-271821-04-20T00:00:00.000Z"'&&ai(new S(8640000000000000))=='"+275760-09-13T00:00:00.000Z"'&&ai(new S(-62198755200000))=='"-000001-01-01T00:00:00.000Z"'&&ai(new S(-1))=='"1969-12-31T23:59:59.999Z"'
}catch(ae){aj=false}}ad=aj}if(ac=="json-parse"){var ag=V.parse;if(typeof ag=="function"){try{if(ag("0")===0&&!ag(false)){ak=ag(ah);var af=ak.a.length==5&&ak.a[0]===1;if(af){try{af=!ag('"\t"')}catch(ae){}if(af){try{af=ag("01")!==1}catch(ae){}}if(af){try{af=ag("1.")!==1}catch(ae){}}}}}catch(ae){af=false}}ad=af}}}return o[ac]=!!ad}if(!o("json")){var U="[object Function]",Q="[object Date]",N="[object Number]",O="[object String]",E="[object Array]",A="[object Boolean]";var F=o("bug-string-char-index");if(!B){var s=J.floor;var Z=[0,31,59,90,120,151,181,212,243,273,304,334];var D=function(ac,ad){return Z[ad]+365*(ac-1970)+s((ac-1969+(ad=+(ad>1)))/4)-s((ac-1901+ad)/100)+s((ac-1601+ad)/400)}}if(!(r=n.hasOwnProperty)){r=function(ae){var ac={},ad;if((ac.__proto__=null,ac.__proto__={toString:1},ac).toString!=u){r=function(ah){var ag=this.__proto__,af=ah in (this.__proto__=null,this);this.__proto__=ag;return af}}else{ad=ac.constructor;r=function(ag){var af=(this.constructor||ad).prototype;return ag in this&&!(ag in af&&this[ag]===af[ag])
@@ -18,50 +18,49 @@ var I="000000";var t=function(ac,ad){return(I+(ad||0)).slice(-ac)};var z="\\u00"
}else{at=null}}else{if(typeof at.toJSON=="function"&&((ae!=N&&ae!=O&&ae!=E)||r.call(at,"toJSON"))){at=at.toJSON(ai)}}}if(ag){at=ag.call(aA,ai,at)}if(at===null){return"null"}ae=u.call(at);if(ae==A){return""+at}else{if(ae==N){return at>-1/0&&at<1/0?""+at:"null"}else{if(ae==O){return C(""+at)}}}if(typeof at=="object"){for(af=aj.length;af--;){if(aj[af]===at){throw aa()}}aj.push(at);ar=[];av=ac;ac+=ax;if(ae==E){for(ah=0,af=at.length;ah<af;ah++){ad=p(ah,at,ag,al,ax,ac,aj);ar.push(ad===L?"null":ad)}ao=ar.length?(ax?"[\n"+ac+ar.join(",\n"+ac)+"\n"+av+"]":("["+ar.join(",")+"]")):"[]"}else{m(al||at,function(aC){var aB=p(aC,at,ag,al,ax,ac,aj);if(aB!==L){ar.push(C(aC)+":"+(ax?" ":"")+aB)}});ao=ar.length?(ax?"{\n"+ac+ar.join(",\n"+ac)+"\n"+av+"}":("{"+ar.join(",")+"}")):"{}"}aj.pop();return ao}};V.stringify=function(ac,ae,af){var ad,al,aj,ai;if(e[typeof ae]&&ae){if((ai=u.call(ae))==U){al=ae}else{if(ai==E){aj={};for(var ah=0,ag=ae.length,ak;ah<ag;ak=ae[ah++],((ai=u.call(ak)),ai==O||ai==N)&&(aj[ak]=1)){}}}}if(af){if((ai=u.call(af))==N){if((af-=af%1)>0){for(ad="",af>10&&(af=10);
ad.length<af;ad+=" "){}}}else{if(ai==O){ad=af.length<=10?af:af.slice(0,10)}}}return p("",(ak={},ak[""]=ac,ak),al,aj,ad,"",[])}}if(!o("json-parse")){var M=R.fromCharCode;var l={92:"\\",34:'"',47:"/",98:"\b",116:"\t",110:"\n",102:"\f",114:"\r"};var G,X;var H=function(){G=X=null;throw T()};var y=function(){var ah=X,af=ah.length,ag,ae,ac,ai,ad;while(G<af){ad=ah.charCodeAt(G);switch(ad){case 9:case 10:case 13:case 32:G++;break;case 123:case 125:case 91:case 93:case 58:case 44:ag=F?ah.charAt(G):ah[G];G++;return ag;case 34:for(ag="@",G++;G<af;){ad=ah.charCodeAt(G);if(ad<32){H()}else{if(ad==92){ad=ah.charCodeAt(++G);switch(ad){case 92:case 34:case 47:case 98:case 116:case 110:case 102:case 114:ag+=l[ad];G++;break;case 117:ae=++G;for(ac=G+4;G<ac;G++){ad=ah.charCodeAt(G);if(!(ad>=48&&ad<=57||ad>=97&&ad<=102||ad>=65&&ad<=70)){H()}}ag+=M("0x"+ah.slice(ae,G));break;default:H()}}else{if(ad==34){break}ad=ah.charCodeAt(G);ae=G;while(ad>=32&&ad!=92&&ad!=34){ad=ah.charCodeAt(++G)}ag+=ah.slice(ae,G)}}}if(ah.charCodeAt(G)==34){G++;
return ag}H();default:ae=G;if(ad==45){ai=true;ad=ah.charCodeAt(++G)}if(ad>=48&&ad<=57){if(ad==48&&((ad=ah.charCodeAt(G+1)),ad>=48&&ad<=57)){H()}ai=false;for(;G<af&&((ad=ah.charCodeAt(G)),ad>=48&&ad<=57);G++){}if(ah.charCodeAt(G)==46){ac=++G;for(;ac<af&&((ad=ah.charCodeAt(ac)),ad>=48&&ad<=57);ac++){}if(ac==G){H()}G=ac}ad=ah.charCodeAt(G);if(ad==101||ad==69){ad=ah.charCodeAt(++G);if(ad==43||ad==45){G++}for(ac=G;ac<af&&((ad=ah.charCodeAt(ac)),ad>=48&&ad<=57);ac++){}if(ac==G){H()}G=ac}return +ah.slice(ae,G)}if(ai){H()}if(ah.slice(G,G+4)=="true"){G+=4;return true}else{if(ah.slice(G,G+5)=="false"){G+=5;return false}else{if(ah.slice(G,G+4)=="null"){G+=4;return null}}}H()}}return"$"};var W=function(ad){var ac,ae;if(ad=="$"){H()}if(typeof ad=="string"){if((F?ad.charAt(0):ad[0])=="@"){return ad.slice(1)}if(ad=="["){ac=[];for(;;ae||(ae=true)){ad=y();if(ad=="]"){break}if(ae){if(ad==","){ad=y();if(ad=="]"){H()}}else{H()}}if(ad==","){H()}ac.push(W(ad))}return ac}else{if(ad=="{"){ac={};for(;;ae||(ae=true)){ad=y();
-if(ad=="}"){break}if(ae){if(ad==","){ad=y();if(ad=="}"){H()}}else{H()}}if(ad==","||typeof ad!="string"||(F?ad.charAt(0):ad[0])!="@"||y()!=":"){H()}ac[ad.slice(1)]=W(y())}return ac}}H()}return ad};var P=function(ae,ad,af){var ac=w(ae,ad,af);if(ac===L){delete ae[ad]}else{ae[ad]=ac}};var w=function(af,ae,ag){var ad=af[ae],ac;if(typeof ad=="object"&&ad){if(u.call(ad)==E){for(ac=ad.length;ac--;){P(ad,ac,ag)}}else{m(ad,function(ah){P(ad,ah,ag)})}}return ag.call(af,ae,ad)};V.parse=function(ae,af){var ac,ad;G=0;X=""+ae;ac=W(y());if(y()!="$"){H()}G=X=null;return af&&u.call(af)==U?w((ad={},ad[""]=ac,ad),"",af):ac}}}V.runInContext=j;return V}if(h&&!c){j(i,h)}else{var f=i.JSON,k=i.JSON3,d=false;var g=j(i,(i.JSON3={noConflict:function(){if(!d){d=true;i.JSON=f;i.JSON3=k;f=k=null}return g}}));i.JSON={parse:g.parse,stringify:g.stringify}}if(c){define(function(){return g})}}).call(this);JSON2=a})()}if(typeof _paq!=="object"){_paq=[]}if(typeof window.Piwik!=="object"){window.Piwik=(function(){var l,a={},z=document,f=navigator,Q=screen,M=window,g=M.performance||M.mozPerformance||M.msPerformance||M.webkitPerformance,s=false,K=[],n=M.encodeURIComponent,L=M.decodeURIComponent,i=unescape,R,y,d;
-function k(ac){try{return L(ac)}catch(ad){return unescape(ac)}}function B(ad){var ac=typeof ad;return ac!=="undefined"}function u(ac){return typeof ac==="function"}function P(ac){return typeof ac==="object"}function q(ac){return typeof ac==="string"||ac instanceof String}function v(ad){if(!ad){return true}var ac;var ae=true;for(ac in ad){if(Object.prototype.hasOwnProperty.call(ad,ac)){ae=false}}return ae}function X(){var ac,ae,ad;for(ac=0;ac<arguments.length;ac+=1){ad=arguments[ac];ae=ad.shift();if(q(ae)){R[ae].apply(R,ad)}else{ae.apply(R,ad)}}}function ab(af,ae,ad,ac){if(af.addEventListener){af.addEventListener(ae,ad,ac);return true}if(af.attachEvent){return af.attachEvent("on"+ae,ad)}af["on"+ae]=ad}function U(ad,ag){var ac="",af,ae;for(af in a){if(Object.prototype.hasOwnProperty.call(a,af)){ae=a[af][ad];if(u(ae)){ac+=ae(ag)}}}return ac}function Y(){var ac;U("unload");if(l){do{ac=new Date()}while(ac.getTimeAlias()<l)}}function V(){var ac;if(!s){s=true;U("load");for(ac=0;ac<K.length;ac++){K[ac]()
-}}return true}function r(){var ad;if(z.addEventListener){ab(z,"DOMContentLoaded",function ac(){z.removeEventListener("DOMContentLoaded",ac,false);V()})}else{if(z.attachEvent){z.attachEvent("onreadystatechange",function ac(){if(z.readyState==="complete"){z.detachEvent("onreadystatechange",ac);V()}});if(z.documentElement.doScroll&&M===M.top){(function ac(){if(!s){try{z.documentElement.doScroll("left")}catch(ae){setTimeout(ac,0);return}V()}}())}}}if((new RegExp("WebKit")).test(f.userAgent)){ad=setInterval(function(){if(s||/loaded|complete/.test(z.readyState)){clearInterval(ad);V()}},10)}ab(M,"load",V,false)}function j(ae,ad){var ac=z.createElement("script");ac.type="text/javascript";ac.src=ae;if(ac.readyState){ac.onreadystatechange=function(){var af=this.readyState;if(af==="loaded"||af==="complete"){ac.onreadystatechange=null;ad()}}}else{ac.onload=ad}z.getElementsByTagName("head")[0].appendChild(ac)}function C(){var ac="";try{ac=M.top.document.referrer}catch(ae){if(M.parent){try{ac=M.parent.document.referrer
-}catch(ad){ac=""}}}if(ac===""){ac=z.referrer}return ac}function m(ac){var ae=new RegExp("^([a-z]+):"),ad=ae.exec(ac);return ad?ad[1]:null}function c(ac){var ae=new RegExp("^(?:(?:https?|ftp):)/*(?:[^@]+@)?([^:/#]+)"),ad=ae.exec(ac);return ad?ad[1]:ac}function O(ae,ad){var ac="[\\?&#]"+ad+"=([^&#]*)";var ag=new RegExp(ac);var af=ag.exec(ae);return af?L(af[1]):""}function x(ac){return unescape(n(ac))}function aa(ar){var ae=function(ay,ax){return(ay<<ax)|(ay>>>(32-ax))},at=function(aA){var ay="",az,ax;for(az=7;az>=0;az--){ax=(aA>>>(az*4))&15;ay+=ax.toString(16)}return ay},ah,av,au,ad=[],al=1732584193,aj=4023233417,ai=2562383102,ag=271733878,af=3285377520,aq,ap,ao,an,am,aw,ac,ak=[];ar=x(ar);ac=ar.length;for(av=0;av<ac-3;av+=4){au=ar.charCodeAt(av)<<24|ar.charCodeAt(av+1)<<16|ar.charCodeAt(av+2)<<8|ar.charCodeAt(av+3);ak.push(au)}switch(ac&3){case 0:av=2147483648;break;case 1:av=ar.charCodeAt(ac-1)<<24|8388608;break;case 2:av=ar.charCodeAt(ac-2)<<24|ar.charCodeAt(ac-1)<<16|32768;break;case 3:av=ar.charCodeAt(ac-3)<<24|ar.charCodeAt(ac-2)<<16|ar.charCodeAt(ac-1)<<8|128;
-break}ak.push(av);while((ak.length&15)!==14){ak.push(0)}ak.push(ac>>>29);ak.push((ac<<3)&4294967295);for(ah=0;ah<ak.length;ah+=16){for(av=0;av<16;av++){ad[av]=ak[ah+av]}for(av=16;av<=79;av++){ad[av]=ae(ad[av-3]^ad[av-8]^ad[av-14]^ad[av-16],1)}aq=al;ap=aj;ao=ai;an=ag;am=af;for(av=0;av<=19;av++){aw=(ae(aq,5)+((ap&ao)|(~ap&an))+am+ad[av]+1518500249)&4294967295;am=an;an=ao;ao=ae(ap,30);ap=aq;aq=aw}for(av=20;av<=39;av++){aw=(ae(aq,5)+(ap^ao^an)+am+ad[av]+1859775393)&4294967295;am=an;an=ao;ao=ae(ap,30);ap=aq;aq=aw}for(av=40;av<=59;av++){aw=(ae(aq,5)+((ap&ao)|(ap&an)|(ao&an))+am+ad[av]+2400959708)&4294967295;am=an;an=ao;ao=ae(ap,30);ap=aq;aq=aw}for(av=60;av<=79;av++){aw=(ae(aq,5)+(ap^ao^an)+am+ad[av]+3395469782)&4294967295;am=an;an=ao;ao=ae(ap,30);ap=aq;aq=aw}al=(al+aq)&4294967295;aj=(aj+ap)&4294967295;ai=(ai+ao)&4294967295;ag=(ag+an)&4294967295;af=(af+am)&4294967295}aw=at(al)+at(aj)+at(ai)+at(ag)+at(af);return aw.toLowerCase()}function T(ae,ac,ad){if(!ae){ae=""}if(!ac){ac=""}if(ae==="translate.googleusercontent.com"){if(ad===""){ad=ac
-}ac=O(ac,"u");ae=c(ac)}else{if(ae==="cc.bingj.com"||ae==="webcache.googleusercontent.com"||ae.slice(0,5)==="74.6."){ac=z.links[0].href;ae=c(ac)}}return[ae,ac,ad]}function D(ad){var ac=ad.length;if(ad.charAt(--ac)==="."){ad=ad.slice(0,ac)}if(ad.slice(0,2)==="*."){ad=ad.slice(1)}if(ad.indexOf("/")!==-1){ad=ad.substr(0,ad.indexOf("/"))}return ad}function Z(ad){ad=ad&&ad.text?ad.text:ad;if(!q(ad)){var ac=z.getElementsByTagName("title");if(ac&&B(ac[0])){ad=ac[0].text}}return ad}function H(ac){if(!ac){return[]}if(!B(ac.children)&&B(ac.childNodes)){return ac.children}if(B(ac.children)){return ac.children}return[]}function N(ad,ac){if(!ad||!ac){return false}if(ad.contains){return ad.contains(ac)}if(ad===ac){return true}if(ad.compareDocumentPosition){return !!(ad.compareDocumentPosition(ac)&16)}return false}function E(ae,af){if(ae&&ae.indexOf){return ae.indexOf(af)}if(!B(ae)||ae===null){return -1}if(!ae.length){return -1}var ac=ae.length;if(ac===0){return -1}var ad=0;while(ad<ac){if(ae[ad]===af){return ad
-}ad++}return -1}function J(ad,ac){ad=String(ad);return ad.indexOf(ac,ad.length-ac.length)!==-1}function t(ad,ac){ad=String(ad);return ad.indexOf(ac)!==-1}function e(ad,ac){ad=String(ad);return ad.substr(0,ad.length-ac)}function h(ae){if(!ae){return false}function ac(ag,ah){if(M.getComputedStyle){return z.defaultView.getComputedStyle(ag,null)[ah]}if(ag.currentStyle){return ag.currentStyle[ah]}}function af(ag){ag=ag.parentNode;while(ag){if(ag===z){return true}ag=ag.parentNode}return false}function ad(ai,ao,ag,al,aj,am,ak){var ah=ai.parentNode,an=1;if(!af(ai)){return false}if(9===ah.nodeType){return true}if("0"===ac(ai,"opacity")||"none"===ac(ai,"display")||"hidden"===ac(ai,"visibility")){return false}if(!B(ao)||!B(ag)||!B(al)||!B(aj)||!B(am)||!B(ak)){ao=ai.offsetTop;aj=ai.offsetLeft;al=ao+ai.offsetHeight;ag=aj+ai.offsetWidth;am=ai.offsetWidth;ak=ai.offsetHeight}if(ae===ai&&(0===ak||0===am)&&"hidden"===ac(ai,"overflow")){return false}if(ah){if(("hidden"===ac(ah,"overflow")||"scroll"===ac(ah,"overflow"))){if(aj+an>ah.offsetWidth+ah.scrollLeft||aj+am-an<ah.scrollLeft||ao+an>ah.offsetHeight+ah.scrollTop||ao+ak-an<ah.scrollTop){return false
-}}if(ai.offsetParent===ah){aj+=ah.offsetLeft;ao+=ah.offsetTop}return ad(ah,ao,ag,al,aj,am,ak)}return true}return ad(ae)}var W={htmlCollectionToArray:function(ae){var ac=[],ad;if(!ae||!ae.length){return ac}for(ad=0;ad<ae.length;ad++){ac.push(ae[ad])}return ac},find:function(ac){if(!document.querySelectorAll||!ac){return[]}var ad=document.querySelectorAll(ac);return this.htmlCollectionToArray(ad)},findMultiple:function(ae){if(!ae||!ae.length){return[]}var ad,af;var ac=[];for(ad=0;ad<ae.length;ad++){af=this.find(ae[ad]);ac=ac.concat(af)}ac=this.makeNodesUnique(ac);return ac},findNodesByTagName:function(ad,ac){if(!ad||!ac||!ad.getElementsByTagName){return[]}var ae=ad.getElementsByTagName(ac);return this.htmlCollectionToArray(ae)},makeNodesUnique:function(ac){var ah=[].concat(ac);ac.sort(function(aj,ai){if(aj===ai){return 0}var al=E(ah,aj);var ak=E(ah,ai);if(al===ak){return 0}return al>ak?-1:1});if(ac.length<=1){return ac}var ad=0;var af=0;var ag=[];var ae;ae=ac[ad++];while(ae){if(ae===ac[ad]){af=ag.push(ad)
-}ae=ac[ad++]||null}while(af--){ac.splice(ag[af],1)}return ac},getAttributeValueFromNode:function(ag,ae){if(!this.hasNodeAttribute(ag,ae)){return}if(ag&&ag.getAttribute){return ag.getAttribute(ae)}if(!ag||!ag.attributes){return}var af=(typeof ag.attributes[ae]);if("undefined"===af){return}if(ag.attributes[ae].value){return ag.attributes[ae].value}if(ag.attributes[ae].nodeValue){return ag.attributes[ae].nodeValue}var ad;var ac=ag.attributes;if(!ac){return}for(ad=0;ad<ac.length;ad++){if(ac[ad].nodeName===ae){return ac[ad].nodeValue}}return null},hasNodeAttributeWithValue:function(ad,ac){var ae=this.getAttributeValueFromNode(ad,ac);return !!ae},hasNodeAttribute:function(ae,ac){if(ae&&ae.hasAttribute){return ae.hasAttribute(ac)}if(ae&&ae.attributes){var ad=(typeof ae.attributes[ac]);return"undefined"!==ad}return false},hasNodeCssClass:function(ae,ac){if(ae&&ac&&ae.className){var ad=typeof ae.className==="string"?ae.className.split(" "):[];if(-1!==E(ad,ac)){return true}}return false},findNodesHavingAttribute:function(ag,ae,ac){if(!ac){ac=[]
-}if(!ag||!ae){return ac}var af=H(ag);if(!af||!af.length){return ac}var ad,ah;for(ad=0;ad<af.length;ad++){ah=af[ad];if(this.hasNodeAttribute(ah,ae)){ac.push(ah)}ac=this.findNodesHavingAttribute(ah,ae,ac)}return ac},findFirstNodeHavingAttribute:function(ae,ad){if(!ae||!ad){return}if(this.hasNodeAttribute(ae,ad)){return ae}var ac=this.findNodesHavingAttribute(ae,ad);if(ac&&ac.length){return ac[0]}},findFirstNodeHavingAttributeWithValue:function(af,ae){if(!af||!ae){return}if(this.hasNodeAttributeWithValue(af,ae)){return af}var ac=this.findNodesHavingAttribute(af,ae);if(!ac||!ac.length){return}var ad;for(ad=0;ad<ac.length;ad++){if(this.getAttributeValueFromNode(ac[ad],ae)){return ac[ad]}}},findNodesHavingCssClass:function(ag,af,ac){if(!ac){ac=[]}if(!ag||!af){return ac}if(ag.getElementsByClassName){var ah=ag.getElementsByClassName(af);return this.htmlCollectionToArray(ah)}var ae=H(ag);if(!ae||!ae.length){return[]}var ad,ai;for(ad=0;ad<ae.length;ad++){ai=ae[ad];if(this.hasNodeCssClass(ai,af)){ac.push(ai)
-}ac=this.findNodesHavingCssClass(ai,af,ac)}return ac},findFirstNodeHavingClass:function(ae,ad){if(!ae||!ad){return}if(this.hasNodeCssClass(ae,ad)){return ae}var ac=this.findNodesHavingCssClass(ae,ad);if(ac&&ac.length){return ac[0]}},isLinkElement:function(ad){if(!ad){return false}var ac=String(ad.nodeName).toLowerCase();var af=["a","area"];var ae=E(af,ac);return ae!==-1},setAnyAttribute:function(ad,ac,ae){if(!ad||!ac){return}if(ad.setAttribute){ad.setAttribute(ac,ae)}else{ad[ac]=ae}}};var p={CONTENT_ATTR:"data-track-content",CONTENT_CLASS:"piwikTrackContent",CONTENT_NAME_ATTR:"data-content-name",CONTENT_PIECE_ATTR:"data-content-piece",CONTENT_PIECE_CLASS:"piwikContentPiece",CONTENT_TARGET_ATTR:"data-content-target",CONTENT_TARGET_CLASS:"piwikContentTarget",CONTENT_IGNOREINTERACTION_ATTR:"data-content-ignoreinteraction",CONTENT_IGNOREINTERACTION_CLASS:"piwikContentIgnoreInteraction",location:undefined,findContentNodes:function(){var ad="."+this.CONTENT_CLASS;var ac="["+this.CONTENT_ATTR+"]";
-var ae=W.findMultiple([ad,ac]);return ae},findContentNodesWithinNode:function(af){if(!af){return[]}var ad=W.findNodesHavingCssClass(af,this.CONTENT_CLASS);var ac=W.findNodesHavingAttribute(af,this.CONTENT_ATTR);if(ac&&ac.length){var ae;for(ae=0;ae<ac.length;ae++){ad.push(ac[ae])}}if(W.hasNodeAttribute(af,this.CONTENT_ATTR)){ad.push(af)}else{if(W.hasNodeCssClass(af,this.CONTENT_CLASS)){ad.push(af)}}ad=W.makeNodesUnique(ad);return ad},findParentContentNode:function(ad){if(!ad){return}var ae=ad;var ac=0;while(ae&&ae!==z&&ae.parentNode){if(W.hasNodeAttribute(ae,this.CONTENT_ATTR)){return ae}if(W.hasNodeCssClass(ae,this.CONTENT_CLASS)){return ae}ae=ae.parentNode;if(ac>1000){break}ac++}},findPieceNode:function(ad){var ac;ac=W.findFirstNodeHavingAttribute(ad,this.CONTENT_PIECE_ATTR);if(!ac){ac=W.findFirstNodeHavingClass(ad,this.CONTENT_PIECE_CLASS)}if(ac){return ac}return ad},findTargetNodeNoDefault:function(ac){if(!ac){return}var ad=W.findFirstNodeHavingAttributeWithValue(ac,this.CONTENT_TARGET_ATTR);
-if(ad){return ad}ad=W.findFirstNodeHavingAttribute(ac,this.CONTENT_TARGET_ATTR);if(ad){return ad}ad=W.findFirstNodeHavingClass(ac,this.CONTENT_TARGET_CLASS);if(ad){return ad}},findTargetNode:function(ac){var ad=this.findTargetNodeNoDefault(ac);if(ad){return ad}return ac},findContentName:function(ad){if(!ad){return}var ag=W.findFirstNodeHavingAttributeWithValue(ad,this.CONTENT_NAME_ATTR);if(ag){return W.getAttributeValueFromNode(ag,this.CONTENT_NAME_ATTR)}var ac=this.findContentPiece(ad);if(ac){return this.removeDomainIfIsInLink(ac)}if(W.hasNodeAttributeWithValue(ad,"title")){return W.getAttributeValueFromNode(ad,"title")}var ae=this.findPieceNode(ad);if(W.hasNodeAttributeWithValue(ae,"title")){return W.getAttributeValueFromNode(ae,"title")}var af=this.findTargetNode(ad);if(W.hasNodeAttributeWithValue(af,"title")){return W.getAttributeValueFromNode(af,"title")}},findContentPiece:function(ad){if(!ad){return}var af=W.findFirstNodeHavingAttributeWithValue(ad,this.CONTENT_PIECE_ATTR);if(af){return W.getAttributeValueFromNode(af,this.CONTENT_PIECE_ATTR)
-}var ac=this.findPieceNode(ad);var ae=this.findMediaUrlInNode(ac);if(ae){return this.toAbsoluteUrl(ae)}},findContentTarget:function(ae){if(!ae){return}var af=this.findTargetNode(ae);if(W.hasNodeAttributeWithValue(af,this.CONTENT_TARGET_ATTR)){return W.getAttributeValueFromNode(af,this.CONTENT_TARGET_ATTR)}var ad;if(W.hasNodeAttributeWithValue(af,"href")){ad=W.getAttributeValueFromNode(af,"href");return this.toAbsoluteUrl(ad)}var ac=this.findPieceNode(ae);if(W.hasNodeAttributeWithValue(ac,"href")){ad=W.getAttributeValueFromNode(ac,"href");return this.toAbsoluteUrl(ad)}},isSameDomain:function(ac){if(!ac||!ac.indexOf){return false}if(0===ac.indexOf(this.getLocation().origin)){return true}var ad=ac.indexOf(this.getLocation().host);if(8>=ad&&0<=ad){return true}return false},removeDomainIfIsInLink:function(ae){var ad="^https?://[^/]+";var ac="^.*//[^/]+";if(ae&&ae.search&&-1!==ae.search(new RegExp(ad))&&this.isSameDomain(ae)){ae=ae.replace(new RegExp(ac),"");if(!ae){ae="/"}}return ae},findMediaUrlInNode:function(ag){if(!ag){return
-}var ae=["img","embed","video","audio"];var ac=ag.nodeName.toLowerCase();if(-1!==E(ae,ac)&&W.findFirstNodeHavingAttributeWithValue(ag,"src")){var af=W.findFirstNodeHavingAttributeWithValue(ag,"src");return W.getAttributeValueFromNode(af,"src")}if(ac==="object"&&W.hasNodeAttributeWithValue(ag,"data")){return W.getAttributeValueFromNode(ag,"data")}if(ac==="object"){var ah=W.findNodesByTagName(ag,"param");if(ah&&ah.length){var ad;for(ad=0;ad<ah.length;ad++){if("movie"===W.getAttributeValueFromNode(ah[ad],"name")&&W.hasNodeAttributeWithValue(ah[ad],"value")){return W.getAttributeValueFromNode(ah[ad],"value")}}}var ai=W.findNodesByTagName(ag,"embed");if(ai&&ai.length){return this.findMediaUrlInNode(ai[0])}}},trim:function(ac){if(ac&&String(ac)===ac){return ac.replace(/^\s+|\s+$/g,"")}return ac},isOrWasNodeInViewport:function(ah){if(!ah||!ah.getBoundingClientRect||ah.nodeType!==1){return true}var ag=ah.getBoundingClientRect();var af=z.documentElement||{};var ae=ag.top<0;if(ae&&ah.offsetTop){ae=(ah.offsetTop+ag.height)>0
-}var ad=af.clientWidth;if(M.innerWidth&&ad>M.innerWidth){ad=M.innerWidth}var ac=af.clientHeight;if(M.innerHeight&&ac>M.innerHeight){ac=M.innerHeight}return((ag.bottom>0||ae)&&ag.right>0&&ag.left<ad&&((ag.top<ac)||ae))},isNodeVisible:function(ad){var ac=h(ad);var ae=this.isOrWasNodeInViewport(ad);return ac&&ae},buildInteractionRequestParams:function(ac,ad,ae,af){var ag="";if(ac){ag+="c_i="+n(ac)}if(ad){if(ag){ag+="&"}ag+="c_n="+n(ad)}if(ae){if(ag){ag+="&"}ag+="c_p="+n(ae)}if(af){if(ag){ag+="&"}ag+="c_t="+n(af)}return ag},buildImpressionRequestParams:function(ac,ad,ae){var af="c_n="+n(ac)+"&c_p="+n(ad);if(ae){af+="&c_t="+n(ae)}return af},buildContentBlock:function(ae){if(!ae){return}var ac=this.findContentName(ae);var ad=this.findContentPiece(ae);var af=this.findContentTarget(ae);ac=this.trim(ac);ad=this.trim(ad);af=this.trim(af);return{name:ac||"Unknown",piece:ad||"Unknown",target:af||""}},collectContent:function(af){if(!af||!af.length){return[]}var ae=[];var ac,ad;for(ac=0;ac<af.length;
-ac++){ad=this.buildContentBlock(af[ac]);if(B(ad)){ae.push(ad)}}return ae},setLocation:function(ac){this.location=ac},getLocation:function(){var ac=this.location||M.location;if(!ac.origin){ac.origin=ac.protocol+"//"+ac.hostname+(ac.port?":"+ac.port:"")}return ac},toAbsoluteUrl:function(ad){if((!ad||String(ad)!==ad)&&ad!==""){return ad}if(""===ad){return this.getLocation().href}if(ad.search(/^\/\//)!==-1){return this.getLocation().protocol+ad}if(ad.search(/:\/\//)!==-1){return ad}if(0===ad.indexOf("#")){return this.getLocation().origin+this.getLocation().pathname+ad}if(0===ad.indexOf("?")){return this.getLocation().origin+this.getLocation().pathname+ad}if(0===ad.search("^[a-zA-Z]{2,11}:")){return ad}if(ad.search(/^\//)!==-1){return this.getLocation().origin+ad}var ac="(.*/)";var ae=this.getLocation().origin+this.getLocation().pathname.match(new RegExp(ac))[0];return ae+ad},isUrlToCurrentDomain:function(ad){var ae=this.toAbsoluteUrl(ad);if(!ae){return false}var ac=this.getLocation().origin;
-if(ac===ae){return true}if(0===String(ae).indexOf(ac)){if(":"===String(ae).substr(ac.length,1)){return false}return true}return false},setHrefAttribute:function(ad,ac){if(!ad||!ac){return}W.setAnyAttribute(ad,"href",ac)},shouldIgnoreInteraction:function(ae){var ad=W.hasNodeAttribute(ae,this.CONTENT_IGNOREINTERACTION_ATTR);var ac=W.hasNodeCssClass(ae,this.CONTENT_IGNOREINTERACTION_CLASS);return ad||ac}};function G(ad,ag){if(ag){return ag}if(t(ad,"?")){var af=ad.indexOf("?");ad=ad.slice(0,af)}if(J(ad,"piwik.php")){ad=e(ad,"piwik.php".length)}else{if(J(ad,".php")){var ac=ad.lastIndexOf("/");var ae=1;ad=ad.slice(0,ac+ae)}}if(J(ad,"/js/")){ad=e(ad,"js/".length)}return ad}function F(ai){var ak="Piwik_Overlay";var ad=new RegExp("index\\.php\\?module=Overlay&action=startOverlaySession&idSite=([0-9]+)&period=([^&]+)&date=([^&]+)(&segment=.*)?$");var ae=ad.exec(z.referrer);if(ae){var ag=ae[1];if(ag!==String(ai)){return false}var ah=ae[2],ac=ae[3],af=ae[4];if(!af){af=""}else{if(af.indexOf("&segment=")===0){af=af.substr("&segment=".length)
-}}M.name=ak+"###"+ah+"###"+ac+"###"+af}var aj=M.name.split("###");return aj.length===4&&aj[0]===ak}function S(ad,aj,af){var ai=M.name.split("###"),ah=ai[1],ac=ai[2],ag=ai[3],ae=G(ad,aj);j(ae+"plugins/Overlay/client/client.js?v=1",function(){Piwik_Overlay_Client.initialize(ae,af,ah,ac,ag)})}function o(){if(B(M.frameElement)){return(M.frameElement&&String(M.frameElement.nodeName).toLowerCase()==="iframe")}try{return M.self!==M.top}catch(ac){return true}}function I(bL,bF){var bB=T(z.domain,M.location.href,C()),cj=D(bB[0]),bl=k(bB[1]),a0=k(bB[2]),ch=false,bP="GET",cv=bP,aq="application/x-www-form-urlencoded; charset=UTF-8",b1=aq,am=bL||"",bg="",cn="",bD=bF||"",a9="",bm="",aK,aW=z.title,cs=["7z","aac","apk","arc","arj","asf","asx","avi","azw3","bin","csv","deb","dmg","doc","docx","epub","exe","flv","gif","gz","gzip","hqx","ibooks","jar","jpg","jpeg","js","mobi","mp2","mp3","mp4","mpg","mpeg","mov","movie","msi","msp","odb","odf","odg","ods","odt","ogg","ogv","pdf","phps","png","ppt","pptx","qt","qtm","ra","ram","rar","rpm","sea","sit","tar","tbz","tbz2","bz","bz2","tgz","torrent","txt","wav","wma","wmv","wpd","xls","xlsx","xml","z","zip"],ai=[cj],ba=[],bj=[],aN=[],bh=500,ca,aL,bp,bn,ac,bX=["pk_campaign","piwik_campaign","utm_campaign","utm_source","utm_medium"],bf=["pk_kwd","piwik_kwd","utm_term"],aX="_pk_",cl,a2,aY=false,cf,aU,a6,cb=33955200000,bV=1800000,cr=15768000000,aI=true,bT=0,bo=false,ax=false,bI,bt={},bS={},aZ={},a5=200,co={},ct={},bH=[],bM=false,b4=false,ad=false,cu=false,av=false,aT=o(),cm=null,bJ,ay,bb,bE=aa,a1;
-function cy(cI,cF,cE,cH,cD,cG){if(aY){return}var cC;if(cE){cC=new Date();cC.setTime(cC.getTime()+cE)}z.cookie=cI+"="+n(cF)+(cE?";expires="+cC.toGMTString():"")+";path="+(cH||"/")+(cD?";domain="+cD:"")+(cG?";secure":"")}function al(cE){if(aY){return 0}var cC=new RegExp("(^|;)[ ]*"+cE+"=([^;]*)"),cD=cC.exec(z.cookie);return cD?L(cD[2]):0}function bz(cC){var cD;if(bn){cD=new RegExp("#.*");return cC.replace(cD,"")}return cC}function bs(cE,cC){var cF=m(cC),cD;if(cF){return cC}if(cC.slice(0,1)==="/"){return m(cE)+"://"+c(cE)+cC}cE=bz(cE);cD=cE.indexOf("?");if(cD>=0){cE=cE.slice(0,cD)}cD=cE.lastIndexOf("/");if(cD!==cE.length-1){cE=cE.slice(0,cD+1)}return cE+cC}function b8(cE,cC){var cD;cE=String(cE).toLowerCase();cC=String(cC).toLowerCase();if(cE===cC){return true}if(cC.slice(0,1)==="."){if(cE===cC.slice(1)){return true}cD=cE.length-cC.length;if((cD>0)&&(cE.slice(cD)===cC)){return true}}return false}function bR(cC){var cD=document.createElement("a");if(cC.indexOf("//")!==0&&cC.indexOf("http")!==0){cC="http://"+cC
-}cD.href=p.toAbsoluteUrl(cC);if(cD.pathname){return cD.pathname}return""}function aJ(cD,cC){var cE=(!cC||cC==="/");if(cE){return true}if(cD===cC){return true}if(!cD){return false}cC=String(cC).toLowerCase();cD=String(cD).toLowerCase();if(!J(cD,"/")){cD+="/"}if(!J(cC,"/")){cC+="/"}return cD.indexOf(cC)===0}function af(cG,cI){var cD,cC,cE,cF,cH;for(cD=0;cD<ai.length;cD++){cF=D(ai[cD]);cH=bR(ai[cD]);if(b8(cG,cF)&&aJ(cI,cH)){return true}}return false}function aC(cF){var cD,cC,cE;for(cD=0;cD<ai.length;cD++){cC=D(ai[cD].toLowerCase());if(cF===cC){return true}if(cC.slice(0,1)==="."){if(cF===cC.slice(1)){return true}cE=cF.length-cC.length;if((cE>0)&&(cF.slice(cE)===cC)){return true}}}return false}function bW(cC,cE){var cD=new Image(1,1);cD.onload=function(){y=0;if(typeof cE==="function"){cE()}};cD.src=am+(am.indexOf("?")<0?"?":"&")+cC}function cq(cD,cG,cC){if(!B(cC)||null===cC){cC=true}try{var cF=M.XMLHttpRequest?new M.XMLHttpRequest():M.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):null;
-cF.open("POST",am,true);cF.onreadystatechange=function(){if(this.readyState===4&&!(this.status>=200&&this.status<300)&&cC){bW(cD,cG)}else{if(typeof cG==="function"){cG()}}};cF.setRequestHeader("Content-Type",b1);cF.send(cD)}catch(cE){if(cC){bW(cD,cG)}}}function bN(cD){var cC=new Date();var cE=cC.getTime()+cD;if(!l||cE>l){l=cE}}function bU(cC){if(bJ||!aL){return}bJ=setTimeout(function cD(){bJ=null;if(!aT){aT=(!z.hasFocus||z.hasFocus())}if(!aT){bU(aL);return}if(bp()){return}var cE=new Date(),cF=aL-(cE.getTime()-cm);cF=Math.min(aL,cF);bU(cF)},cC||aL)}function bi(){if(!bJ){return}clearTimeout(bJ);bJ=null}function aQ(){aT=true;if(bp()){return}bU()}function aj(){bi()}function cA(){if(av||!aL){return}av=true;ab(M,"focus",aQ);ab(M,"blur",aj);bU()}function b5(cG){var cD=new Date();var cC=cD.getTime();cm=cC;if(b4&&cC<b4){var cE=b4-cC;setTimeout(cG,cE);bN(cE+50);b4+=50;return}if(b4===false){var cF=800;b4=cC+cF}cG()}function be(cD,cC,cE){if(!cf&&cD){b5(function(){if(cv==="POST"){cq(cD,cE)}else{bW(cD,cE)
-}bN(cC)})}if(!av){cA()}else{bU()}}function bQ(cC){if(cf){return false}return(cC&&cC.length)}function cz(cE,cC){if(!bQ(cE)){return}var cD='{"requests":["?'+cE.join('","?')+'"]}';b5(function(){cq(cD,null,false);bN(cC)})}function aA(cC){return aX+cC+"."+bD+"."+a1}function bC(){if(aY){return"0"}if(!B(f.cookieEnabled)){var cC=aA("testcookie");cy(cC,"1");return al(cC)==="1"?"1":"0"}return f.cookieEnabled?"1":"0"}function aV(){a1=bE((cl||cj)+(a2||"/")).slice(0,4)}function bu(){var cD=aA("cvar"),cC=al(cD);if(cC.length){cC=JSON2.parse(cC);if(P(cC)){return cC}}return{}}function b6(){if(ax===false){ax=bu()}}function cg(){return bE((f.userAgent||"")+(f.platform||"")+JSON2.stringify(ct)+(new Date()).getTime()+Math.random()).slice(0,16)}function cd(){var cE=new Date(),cC=Math.round(cE.getTime()/1000),cD=aA("id"),cH=al(cD),cG,cF;if(cH){cG=cH.split(".");cG.unshift("0");if(bm.length){cG[1]=bm}return cG}if(bm.length){cF=bm}else{if("0"===bC()){cF=""}else{cF=cg()}}cG=["1",cF,cC,0,cC,"",""];return cG}function aE(){var cJ=cd(),cF=cJ[0],cG=cJ[1],cD=cJ[2],cC=cJ[3],cH=cJ[4],cE=cJ[5];
-if(!B(cJ[6])){cJ[6]=""}var cI=cJ[6];return{newVisitor:cF,uuid:cG,createTs:cD,visitCount:cC,currentVisitTs:cH,lastVisitTs:cE,lastEcommerceOrderTs:cI}}function ap(){var cF=new Date(),cD=cF.getTime(),cG=aE().createTs;var cC=parseInt(cG,10);var cE=(cC*1000)+cb-cD;return cE}function at(cC){if(!bD){return}var cE=new Date(),cD=Math.round(cE.getTime()/1000);if(!B(cC)){cC=aE()}var cF=cC.uuid+"."+cC.createTs+"."+cC.visitCount+"."+cD+"."+cC.lastVisitTs+"."+cC.lastEcommerceOrderTs;cy(aA("id"),cF,ap(),a2,cl)}function bk(){var cC=al(aA("ref"));if(cC.length){try{cC=JSON2.parse(cC);if(P(cC)){return cC}}catch(cD){}}return["","",0,""]}function bv(cE,cD,cC){cy(cE,"",-86400,cD,cC)}function a7(cD){var cC="testvalue";cy("test",cC,10000,null,cD);if(al("test")===cC){bv("test",null,cD);return true}return false}function an(){var cE=aY;aY=false;var cC=["id","ses","cvar","ref"];var cD,cF;for(cD=0;cD<cC.length;cD++){cF=aA(cC[cD]);if(0!==al(cF)){bv(cF,a2,cl)}}aY=cE}function bA(cC){bD=cC;at()}function cB(cG){if(!cG||!P(cG)){return
-}var cF=[];var cE;for(cE in cG){if(Object.prototype.hasOwnProperty.call(cG,cE)){cF.push(cE)}}var cH={};cF.sort();var cC=cF.length;var cD;for(cD=0;cD<cC;cD++){cH[cF[cD]]=cG[cF[cD]]}return cH}function bK(){cy(aA("ses"),"*",bV,a2,cl)}function bY(cE,cZ,c0,cF){var cY,cD=new Date(),cM=Math.round(cD.getTime()/1000),cJ,cX,cG=1024,c5,cN,cV=ax,cH=aA("ses"),cT=aA("ref"),cQ=aA("cvar"),cR=al(cH),cW=bk(),c2=aK||bl,cK,cC;if(aY){an()}if(cf){return""}var cS=aE();if(!B(cF)){cF=""}var cP=z.characterSet||z.charset;if(!cP||cP.toLowerCase()==="utf-8"){cP=null}cK=cW[0];cC=cW[1];cJ=cW[2];cX=cW[3];if(!cR){var c1=bV/1000;if(!cS.lastVisitTs||(cM-cS.lastVisitTs)>c1){cS.visitCount++;cS.lastVisitTs=cS.currentVisitTs}if(!a6||!cK.length){for(cY in bX){if(Object.prototype.hasOwnProperty.call(bX,cY)){cK=O(c2,bX[cY]);if(cK.length){break}}}for(cY in bf){if(Object.prototype.hasOwnProperty.call(bf,cY)){cC=O(c2,bf[cY]);if(cC.length){break}}}}c5=c(a0);cN=cX.length?c(cX):"";if(c5.length&&!aC(c5)&&(!a6||!cN.length||aC(cN))){cX=a0
-}if(cX.length||cK.length){cJ=cM;cW=[cK,cC,cJ,bz(cX.slice(0,cG))];cy(cT,JSON2.stringify(cW),cr,a2,cl)}}cE+="&idsite="+bD+"&rec=1&r="+String(Math.random()).slice(2,8)+"&h="+cD.getHours()+"&m="+cD.getMinutes()+"&s="+cD.getSeconds()+"&url="+n(bz(c2))+(a0.length?"&urlref="+n(bz(a0)):"")+((a9&&a9.length)?"&uid="+n(a9):"")+"&_id="+cS.uuid+"&_idts="+cS.createTs+"&_idvc="+cS.visitCount+"&_idn="+cS.newVisitor+(cK.length?"&_rcn="+n(cK):"")+(cC.length?"&_rck="+n(cC):"")+"&_refts="+cJ+"&_viewts="+cS.lastVisitTs+(String(cS.lastEcommerceOrderTs).length?"&_ects="+cS.lastEcommerceOrderTs:"")+(String(cX).length?"&_ref="+n(bz(cX.slice(0,cG))):"")+(cP?"&cs="+n(cP):"")+"&send_image=0";for(cY in ct){if(Object.prototype.hasOwnProperty.call(ct,cY)){cE+="&"+cY+"="+ct[cY]}}var c4=[];if(cZ){for(cY in cZ){if(Object.prototype.hasOwnProperty.call(cZ,cY)&&/^dimension\d+$/.test(cY)){var cI=cY.replace("dimension","");c4.push(parseInt(cI,10));c4.push(String(cI));cE+="&"+cY+"="+cZ[cY];delete cZ[cY]}}}if(cZ&&v(cZ)){cZ=null
-}for(cY in aZ){if(Object.prototype.hasOwnProperty.call(aZ,cY)){var cO=(-1===c4.indexOf(cY));if(cO){cE+="&dimension"+cY+"="+aZ[cY]}}}if(cZ){cE+="&data="+n(JSON2.stringify(cZ))}else{if(ac){cE+="&data="+n(JSON2.stringify(ac))}}function cL(c6,c7){var c8=JSON2.stringify(c6);if(c8.length>2){return"&"+c7+"="+n(c8)}return""}var c3=cB(bt);var cU=cB(bS);cE+=cL(c3,"cvar");cE+=cL(cU,"e_cvar");if(ax){cE+=cL(ax,"_cvar");for(cY in cV){if(Object.prototype.hasOwnProperty.call(cV,cY)){if(ax[cY][0]===""||ax[cY][1]===""){delete ax[cY]}}}if(bo){cy(cQ,JSON2.stringify(ax),bV,a2,cl)}}if(aI){if(bT){cE+="&gt_ms="+bT}else{if(g&&g.timing&&g.timing.requestStart&&g.timing.responseEnd){cE+="&gt_ms="+(g.timing.responseEnd-g.timing.requestStart)}}}cS.lastEcommerceOrderTs=B(cF)&&String(cF).length?cF:cS.lastEcommerceOrderTs;at(cS);bK();cE+=U(c0);if(cn.length){cE+="&"+cn}if(u(bI)){cE=bI(cE)}return cE}bp=function aM(){var cC=new Date();if(cm+aL<=cC.getTime()){var cD=bY("ping=1",null,"ping");be(cD,bh);return true}return false
-};function a3(cF,cE,cJ,cG,cC,cM){var cH="idgoal=0",cI,cD=new Date(),cK=[],cL;if(String(cF).length){cH+="&ec_id="+n(cF);cI=Math.round(cD.getTime()/1000)}cH+="&revenue="+cE;if(String(cJ).length){cH+="&ec_st="+cJ}if(String(cG).length){cH+="&ec_tx="+cG}if(String(cC).length){cH+="&ec_sh="+cC}if(String(cM).length){cH+="&ec_dt="+cM}if(co){for(cL in co){if(Object.prototype.hasOwnProperty.call(co,cL)){if(!B(co[cL][1])){co[cL][1]=""}if(!B(co[cL][2])){co[cL][2]=""}if(!B(co[cL][3])||String(co[cL][3]).length===0){co[cL][3]=0}if(!B(co[cL][4])||String(co[cL][4]).length===0){co[cL][4]=1}cK.push(co[cL])}}cH+="&ec_items="+n(JSON2.stringify(cK))}cH=bY(cH,ac,"ecommerce",cI);be(cH,bh)}function bw(cC,cG,cF,cE,cD,cH){if(String(cC).length&&B(cG)){a3(cC,cG,cF,cE,cD,cH)}}function a4(cC){if(B(cC)){a3("",cC,"","","","")}}function bx(cD,cE){var cC=bY("action_name="+n(Z(cD||aW)),cE,"log");be(cC,bh)}function aG(cE,cD){var cF,cC="(^| )(piwik[_-]"+cD;if(cE){for(cF=0;cF<cE.length;cF++){cC+="|"+cE[cF]}}cC+=")( |$)";return new RegExp(cC)
-}function aB(cC){return(am&&cC&&0===String(cC).indexOf(am))}function bZ(cG,cC,cH,cD){if(aB(cC)){return 0}var cF=aG(bj,"download"),cE=aG(aN,"link"),cI=new RegExp("\\.("+cs.join("|")+")([?&#]|$)","i");if(cE.test(cG)){return"link"}if(cD||cF.test(cG)||cI.test(cC)){return"download"}if(cH){return 0}return"link"}function ag(cD){var cC;cC=cD.parentNode;while(cC!==null&&B(cC)){if(W.isLinkElement(cD)){break}cD=cC;cC=cD.parentNode}return cD}function cw(cH){cH=ag(cH);if(!W.hasNodeAttribute(cH,"href")){return}if(!B(cH.href)){return}var cG=W.getAttributeValueFromNode(cH,"href");if(aB(cG)){return}var cD=cH.pathname||bR(cH.href);var cI=cH.hostname||c(cH.href);var cJ=cI.toLowerCase();var cE=cH.href.replace(cI,cJ);var cF=new RegExp("^(javascript|vbscript|jscript|mocha|livescript|ecmascript|mailto|tel):","i");if(!cF.test(cE)){var cC=bZ(cH.className,cE,af(cJ,cD),W.hasNodeAttribute(cH,"download"));if(cC){return{type:cC,href:cE}}}}function aw(cC,cD,cE,cF){var cG=p.buildInteractionRequestParams(cC,cD,cE,cF);if(!cG){return
-}return bY(cG,null,"contentInteraction")}function cc(cE,cF,cJ,cC,cD){if(!B(cE)){return}if(aB(cE)){return cE}var cH=p.toAbsoluteUrl(cE);var cG="redirecturl="+n(cH)+"&";cG+=aw(cF,cJ,cC,(cD||cE));var cI="&";if(am.indexOf("?")<0){cI="?"}return am+cI+cG}function aR(cC,cD){if(!cC||!cD){return false}var cE=p.findTargetNode(cC);if(p.shouldIgnoreInteraction(cE)){return false}cE=p.findTargetNodeNoDefault(cC);if(cE&&!N(cE,cD)){return false}return true}function b0(cE,cD,cG){if(!cE){return}var cC=p.findParentContentNode(cE);if(!cC){return}if(!aR(cC,cE)){return}var cF=p.buildContentBlock(cC);if(!cF){return}if(!cF.target&&cG){cF.target=cG}return p.buildInteractionRequestParams(cD,cF.name,cF.piece,cF.target)}function aD(cD){if(!bH||!bH.length){return false}var cC,cE;for(cC=0;cC<bH.length;cC++){cE=bH[cC];if(cE&&cE.name===cD.name&&cE.piece===cD.piece&&cE.target===cD.target){return true}}return false}function bd(cF){if(!cF){return false}var cI=p.findTargetNode(cF);if(!cI||p.shouldIgnoreInteraction(cI)){return false
-}var cJ=cw(cI);if(cu&&cJ&&cJ.type){return false}if(W.isLinkElement(cI)&&W.hasNodeAttributeWithValue(cI,"href")){var cC=String(W.getAttributeValueFromNode(cI,"href"));if(0===cC.indexOf("#")){return false}if(aB(cC)){return true}if(!p.isUrlToCurrentDomain(cC)){return false}var cG=p.buildContentBlock(cF);if(!cG){return}var cE=cG.name;var cK=cG.piece;var cH=cG.target;if(!W.hasNodeAttributeWithValue(cI,p.CONTENT_TARGET_ATTR)||cI.wasContentTargetAttrReplaced){cI.wasContentTargetAttrReplaced=true;cH=p.toAbsoluteUrl(cC);W.setAnyAttribute(cI,p.CONTENT_TARGET_ATTR,cH)}var cD=cc(cC,"click",cE,cK,cH);p.setHrefAttribute(cI,cD);return true}return false}function au(cD){if(!cD||!cD.length){return}var cC;for(cC=0;cC<cD.length;cC++){bd(cD[cC])}}function aF(cC){return function(cD){if(!cC){return}var cG=p.findParentContentNode(cC);var cH;if(cD){cH=cD.target||cD.srcElement}if(!cH){cH=cC}if(!aR(cG,cH)){return}bN(bh);if(W.isLinkElement(cC)&&W.hasNodeAttributeWithValue(cC,"href")&&W.hasNodeAttributeWithValue(cC,p.CONTENT_TARGET_ATTR)){var cE=W.getAttributeValueFromNode(cC,"href");
-if(!aB(cE)&&cC.wasContentTargetAttrReplaced){W.setAnyAttribute(cC,p.CONTENT_TARGET_ATTR,"")}}var cL=cw(cC);if(ad&&cL&&cL.type){return cL.type}if(bd(cG)){return"href"}var cI=p.buildContentBlock(cG);if(!cI){return}var cF=cI.name;var cM=cI.piece;var cK=cI.target;var cJ=aw("click",cF,cM,cK);be(cJ,bh);return cJ}}function by(cE){if(!cE||!cE.length){return}var cC,cD;for(cC=0;cC<cE.length;cC++){cD=p.findTargetNode(cE[cC]);if(cD&&!cD.contentInteractionTrackingSetupDone){cD.contentInteractionTrackingSetupDone=true;ab(cD,"click",aF(cD))}}}function a8(cE,cF){if(!cE||!cE.length){return[]}var cC,cD;for(cC=0;cC<cE.length;cC++){if(aD(cE[cC])){cE.splice(cC,1);cC--}else{bH.push(cE[cC])}}if(!cE||!cE.length){return[]}au(cF);by(cF);var cG=[];for(cC=0;cC<cE.length;cC++){cD=bY(p.buildImpressionRequestParams(cE[cC].name,cE[cC].piece,cE[cC].target),undefined,"contentImpressions");cG.push(cD)}return cG}function b3(cD){var cC=p.collectContent(cD);return a8(cC,cD)}function aP(cD){if(!cD||!cD.length){return[]}var cC;
-for(cC=0;cC<cD.length;cC++){if(!p.isNodeVisible(cD[cC])){cD.splice(cC,1);cC--}}if(!cD||!cD.length){return[]}return b3(cD)}function ao(cE,cC,cD){var cF=p.buildImpressionRequestParams(cE,cC,cD);return bY(cF,null,"contentImpression")}function cx(cF,cD){if(!cF){return}var cC=p.findParentContentNode(cF);var cE=p.buildContentBlock(cC);if(!cE){return}if(!cD){cD="Unknown"}return aw(cD,cE.name,cE.piece,cE.target)}function ce(cD,cF,cC,cE){return"e_c="+n(cD)+"&e_a="+n(cF)+(B(cC)?"&e_n="+n(cC):"")+(B(cE)?"&e_v="+n(cE):"")}function ah(cE,cG,cC,cF,cH){if(String(cE).length===0||String(cG).length===0){return false}var cD=bY(ce(cE,cG,cC,cF),cH,"event");be(cD,bh)}function bG(cC,cF,cD,cG){var cE=bY("search="+n(cC)+(cF?"&search_cat="+n(cF):"")+(B(cD)?"&search_count="+cD:""),cG,"sitesearch");be(cE,bh)}function ci(cC,cF,cE){var cD=bY("idgoal="+cC+(cF?"&revenue="+cF:""),cE,"goal");be(cD,bh)}function cp(cF,cC,cJ,cI,cE){var cH=cC+"="+n(bz(cF));var cD=b0(cE,"click",cF);if(cD){cH+="&"+cD}var cG=bY(cH,cJ,"link");be(cG,(cI?0:bh),cI)
-}function bq(cD,cC){if(cD!==""){return cD+cC.charAt(0).toUpperCase()+cC.slice(1)}return cC}function bO(cH){var cG,cC,cF=["","webkit","ms","moz"],cE;if(!aU){for(cC=0;cC<cF.length;cC++){cE=cF[cC];if(Object.prototype.hasOwnProperty.call(z,bq(cE,"hidden"))){if(z[bq(cE,"visibilityState")]==="prerender"){cG=true}break}}}if(cG){ab(z,cE+"visibilitychange",function cD(){z.removeEventListener(cE+"visibilitychange",cD,false);cH()});return}cH()}function ar(cC){if(z.readyState==="complete"){cC()}else{if(M.addEventListener){M.addEventListener("load",cC)}else{if(M.attachEvent){M.attachEvent("onLoad",cC)}}}}function aS(cD){var cC=false;if(z.attachEvent){cC=z.readyState==="complete"}else{cC=z.readyState!=="loading"}if(cC){cD()}else{if(z.addEventListener){z.addEventListener("DOMContentLoaded",cD)}else{if(z.attachEvent){z.attachEvent("onreadystatechange",cD)}}}}function b9(cC){var cD=cw(cC);if(cD&&cD.type){cD.href=k(cD.href);cp(cD.href,cD.type,undefined,null,cC)}}function b2(){return z.all&&!z.addEventListener
-}function ck(cC){var cE=cC.which;var cD=(typeof cC.button);if(!cE&&cD!=="undefined"){if(b2()){if(cC.button&1){cE=1}else{if(cC.button&2){cE=3}else{if(cC.button&4){cE=2}}}}else{if(cC.button===0||cC.button==="0"){cE=1}else{if(cC.button&1){cE=2}else{if(cC.button&2){cE=3}}}}}return cE}function br(cC){switch(ck(cC)){case 1:return"left";case 2:return"middle";case 3:return"right"}}function aH(cC){return cC.target||cC.srcElement}function ak(cC){return function(cF){cF=cF||M.event;var cE=br(cF);var cG=aH(cF);if(cF.type==="click"){var cD=false;if(cC&&cE==="middle"){cD=true}if(cG&&!cD){b9(cG)}}else{if(cF.type==="mousedown"){if(cE==="middle"&&cG){ay=cE;bb=cG}else{ay=bb=null}}else{if(cF.type==="mouseup"){if(cE===ay&&cG===bb){b9(cG)}ay=bb=null}else{if(cF.type==="contextmenu"){b9(cG)}}}}}}function ae(cD,cC){ab(cD,"click",ak(cC),false);if(cC){ab(cD,"mouseup",ak(cC),false);ab(cD,"mousedown",ak(cC),false);ab(cD,"contextmenu",ak(cC),false)}}function bc(cD){if(!ad){ad=true;var cE,cC=aG(ba,"ignore"),cF=z.links;
-if(cF){for(cE=0;cE<cF.length;cE++){if(!cC.test(cF[cE].className)){ae(cF[cE],cD)}}}}}function az(cE,cG,cH){if(bM){return true}bM=true;var cI=false;var cF,cD;function cC(){cI=true}ar(function(){function cJ(cL){setTimeout(function(){if(!bM){return}cI=false;cH.trackVisibleContentImpressions();cJ(cL)},cL)}function cK(cL){setTimeout(function(){if(!bM){return}if(cI){cI=false;cH.trackVisibleContentImpressions()}cK(cL)},cL)}if(cE){cF=["scroll","resize"];for(cD=0;cD<cF.length;cD++){if(z.addEventListener){z.addEventListener(cF[cD],cC)}else{M.attachEvent("on"+cF[cD],cC)}}cK(100)}if(cG&&cG>0){cG=parseInt(cG,10);cJ(cG)}})}function aO(cG,cI){var cH=bR(cG);var cF=bR(cI);if(!cH||cH==="/"||!cF||cF==="/"){return}var cE=D(cG);if(af(cE,"/")){return}if(J(cH,"/")){cH=e(cH,1)}var cJ=cH.split("/");var cD;for(cD=2;cD<cJ.length;cD++){var cC=cJ.slice(0,cD).join("/");if(af(cE,cC)){cH=cC;break}}if(!aJ(cF,cH)){return}return cH}function b7(){var cE,cG,cH={pdf:"application/pdf",qt:"video/quicktime",realp:"audio/x-pn-realaudio-plugin",wma:"application/x-mplayer2",dir:"application/x-director",fla:"application/x-shockwave-flash",java:"application/x-java-vm",gears:"application/x-googlegears",ag:"application/x-silverlight"},cD=M.devicePixelRatio||1;
-if(!((new RegExp("MSIE")).test(f.userAgent))){if(f.mimeTypes&&f.mimeTypes.length){for(cE in cH){if(Object.prototype.hasOwnProperty.call(cH,cE)){cG=f.mimeTypes[cH[cE]];ct[cE]=(cG&&cG.enabledPlugin)?"1":"0"}}}if(typeof navigator.javaEnabled!=="unknown"&&B(f.javaEnabled)&&f.javaEnabled()){ct.java="1"}if(u(M.GearsFactory)){ct.gears="1"}ct.cookie=bC()}var cF=parseInt(Q.width,10)*cD;var cC=parseInt(Q.height,10)*cD;ct.res=parseInt(cF,10)+"x"+parseInt(cC,10)}b7();aV();at();return{getVisitorId:function(){return aE().uuid},getVisitorInfo:function(){return cd()},getAttributionInfo:function(){return bk()},getAttributionCampaignName:function(){return bk()[0]},getAttributionCampaignKeyword:function(){return bk()[1]},getAttributionReferrerTimestamp:function(){return bk()[2]},getAttributionReferrerUrl:function(){return bk()[3]},setTrackerUrl:function(cC){am=cC},getTrackerUrl:function(){return am},getSiteId:function(){return bD},setSiteId:function(cC){bA(cC)},setUserId:function(cC){if(!B(cC)||!cC.length){return
-}a9=cC;bm=bE(a9).substr(0,16)},getUserId:function(){return a9},setCustomData:function(cC,cD){if(P(cC)){ac=cC}else{if(!ac){ac={}}ac[cC]=cD}},getCustomData:function(){return ac},setCustomRequestProcessing:function(cC){bI=cC},appendToTrackingUrl:function(cC){cn=cC},getRequest:function(cC){return bY(cC)},addPlugin:function(cC,cD){a[cC]=cD},setCustomDimension:function(cC,cD){cC=parseInt(cC,10);if(cC>0){if(!B(cD)){cD=""}if(!q(cD)){cD=String(cD)}aZ[cC]=cD}},getCustomDimension:function(cC){cC=parseInt(cC,10);if(cC>0&&Object.prototype.hasOwnProperty.call(aZ,cC)){return aZ[cC]}},deleteCustomDimension:function(cC){cC=parseInt(cC,10);if(cC>0){delete aZ[cC]}},setCustomVariable:function(cD,cC,cG,cE){var cF;if(!B(cE)){cE="visit"}if(!B(cC)){return}if(!B(cG)){cG=""}if(cD>0){cC=!q(cC)?String(cC):cC;cG=!q(cG)?String(cG):cG;cF=[cC.slice(0,a5),cG.slice(0,a5)];if(cE==="visit"||cE===2){b6();ax[cD]=cF}else{if(cE==="page"||cE===3){bt[cD]=cF}else{if(cE==="event"){bS[cD]=cF}}}}},getCustomVariable:function(cD,cE){var cC;
-if(!B(cE)){cE="visit"}if(cE==="page"||cE===3){cC=bt[cD]}else{if(cE==="event"){cC=bS[cD]}else{if(cE==="visit"||cE===2){b6();cC=ax[cD]}}}if(!B(cC)||(cC&&cC[0]==="")){return false}return cC},deleteCustomVariable:function(cC,cD){if(this.getCustomVariable(cC,cD)){this.setCustomVariable(cC,"","",cD)}},storeCustomVariablesInCookie:function(){bo=true},setLinkTrackingTimer:function(cC){bh=cC},setDownloadExtensions:function(cC){if(q(cC)){cC=cC.split("|")}cs=cC},addDownloadExtensions:function(cD){var cC;if(q(cD)){cD=cD.split("|")}for(cC=0;cC<cD.length;cC++){cs.push(cD[cC])}},removeDownloadExtensions:function(cE){var cD,cC=[];if(q(cE)){cE=cE.split("|")}for(cD=0;cD<cs.length;cD++){if(E(cE,cs[cD])===-1){cC.push(cs[cD])}}cs=cC},setDomains:function(cC){ai=q(cC)?[cC]:cC;var cE=false,cD;for(cD in ai){if(Object.prototype.hasOwnProperty.call(ai,cD)&&b8(cj,D(String(ai[cD])))){cE=true;if(!a2){var cF=aO(ai[cD],bl);if(cF){this.setCookiePath(cF)}break}}}if(!cE){ai.push(cj)}},setIgnoreClasses:function(cC){ba=q(cC)?[cC]:cC
-},setRequestMethod:function(cC){cv=cC||bP},setRequestContentType:function(cC){b1=cC||aq},setReferrerUrl:function(cC){a0=cC},setCustomUrl:function(cC){aK=bs(bl,cC)},setDocumentTitle:function(cC){aW=cC},setAPIUrl:function(cC){bg=cC},setDownloadClasses:function(cC){bj=q(cC)?[cC]:cC},setLinkClasses:function(cC){aN=q(cC)?[cC]:cC},setCampaignNameKey:function(cC){bX=q(cC)?[cC]:cC},setCampaignKeywordKey:function(cC){bf=q(cC)?[cC]:cC},discardHashTag:function(cC){bn=cC},setCookieNamePrefix:function(cC){aX=cC;ax=bu()},setCookieDomain:function(cC){var cD=D(cC);if(a7(cD)){cl=cD;aV()}},setCookiePath:function(cC){a2=cC;aV()},setVisitorCookieTimeout:function(cC){cb=cC*1000},setSessionCookieTimeout:function(cC){bV=cC*1000},setReferralCookieTimeout:function(cC){cr=cC*1000},setConversionAttributionFirstReferrer:function(cC){a6=cC},disableCookies:function(){aY=true;ct.cookie="0";if(bD){an()}},deleteCookies:function(){an()},setDoNotTrack:function(cD){var cC=f.doNotTrack||f.msDoNotTrack;cf=cD&&(cC==="yes"||cC==="1");
-if(cf){this.disableCookies()}},addListener:function(cD,cC){ae(cD,cC)},enableLinkTracking:function(cC){cu=true;if(s){bc(cC)}else{K.push(function(){bc(cC)})}},enableJSErrorTracking:function(){if(ch){return}ch=true;var cC=M.onerror;M.onerror=function(cH,cF,cE,cG,cD){bO(function(){var cI="JavaScript Errors";var cJ=cF+":"+cE;if(cG){cJ+=":"+cG}ah(cI,cJ,cH)});if(cC){return cC(cH,cF,cE,cG,cD)}return false}},disablePerformanceTracking:function(){aI=false},setGenerationTimeMs:function(cC){bT=parseInt(cC,10)},enableHeartBeatTimer:function(cC){cC=Math.max(cC,1);aL=(cC||15)*1000;if(cm!==null){cA()}},killFrame:function(){if(M.location!==M.top.location){M.top.location=M.location}},redirectFile:function(cC){if(M.location.protocol==="file:"){M.location=cC}},setCountPreRendered:function(cC){aU=cC},trackGoal:function(cC,cE,cD){bO(function(){ci(cC,cE,cD)})},trackLink:function(cD,cC,cF,cE){bO(function(){cp(cD,cC,cF,cE)})},trackPageView:function(cC,cD){bH=[];if(F(bD)){bO(function(){S(am,bg,bD)})}else{bO(function(){bx(cC,cD)
-})}},trackAllContentImpressions:function(){if(F(bD)){return}bO(function(){aS(function(){var cC=p.findContentNodes();var cD=b3(cC);cz(cD,bh)})})},trackVisibleContentImpressions:function(cC,cD){if(F(bD)){return}if(!B(cC)){cC=true}if(!B(cD)){cD=750}az(cC,cD,this);bO(function(){ar(function(){var cE=p.findContentNodes();var cF=aP(cE);cz(cF,bh)})})},trackContentImpression:function(cE,cC,cD){if(F(bD)){return}if(!cE){return}cC=cC||"Unknown";bO(function(){var cF=ao(cE,cC,cD);be(cF,bh)})},trackContentImpressionsWithinNode:function(cC){if(F(bD)||!cC){return}bO(function(){if(bM){ar(function(){var cD=p.findContentNodesWithinNode(cC);var cE=aP(cD);cz(cE,bh)})}else{aS(function(){var cD=p.findContentNodesWithinNode(cC);var cE=b3(cD);cz(cE,bh)})}})},trackContentInteraction:function(cE,cF,cC,cD){if(F(bD)){return}if(!cE||!cF){return}cC=cC||"Unknown";bO(function(){var cG=aw(cE,cF,cC,cD);be(cG,bh)})},trackContentInteractionNode:function(cD,cC){if(F(bD)||!cD){return}bO(function(){var cE=cx(cD,cC);be(cE,bh)})
-},logAllContentBlocksOnPage:function(){var cD=p.findContentNodes();var cC=p.collectContent(cD);if(console!==undefined&&console&&console.log){console.log(cC)}},trackEvent:function(cD,cF,cC,cE,cG){bO(function(){ah(cD,cF,cC,cE,cG)})},trackSiteSearch:function(cC,cE,cD,cF){bO(function(){bG(cC,cE,cD,cF)})},setEcommerceView:function(cF,cC,cE,cD){if(!B(cE)||!cE.length){cE=""}else{if(cE instanceof Array){cE=JSON2.stringify(cE)}}bt[5]=["_pkc",cE];if(B(cD)&&String(cD).length){bt[2]=["_pkp",cD]}if((!B(cF)||!cF.length)&&(!B(cC)||!cC.length)){return}if(B(cF)&&cF.length){bt[3]=["_pks",cF]}if(!B(cC)||!cC.length){cC=""}bt[4]=["_pkn",cC]},addEcommerceItem:function(cG,cC,cE,cD,cF){if(cG.length){co[cG]=[cG,cC,cE,cD,cF]}},trackEcommerceOrder:function(cC,cG,cF,cE,cD,cH){bw(cC,cG,cF,cE,cD,cH)},trackEcommerceCartUpdate:function(cC){a4(cC)}}}function A(){return{push:X}}function b(ah,ag){var ai={};var ae,af;for(ae=0;ae<ag.length;ae++){var ac=ag[ae];ai[ac]=1;for(af=0;af<ah.length;af++){if(ah[af]&&ah[af][0]){var ad=ah[af][0];
-if(ac===ad){X(ah[af]);delete ah[af];if(ai[ad]>1){if(console!==undefined&&console&&console.error){console.error("The method "+ad+' is registered more than once in "paq" variable. Only the last call has an effect. Please have a look at the multiple Piwik trackers documentation: http://developer.piwik.org/guides/tracking-javascript-guide#multiple-piwik-trackers')}}ai[ad]++}}}}return ah}ab(M,"beforeunload",Y,false);r();Date.prototype.getTimeAlias=Date.prototype.getTime;R=new I();var w=["disableCookies","setTrackerUrl","setAPIUrl","setCookiePath","setCookieDomain","setDomains","setUserId","setSiteId","enableLinkTracking"];_paq=b(_paq,w);for(y=0;y<_paq.length;y++){if(_paq[y]){X(_paq[y])}}_paq=new A();d={addPlugin:function(ac,ad){a[ac]=ad},getTracker:function(ac,ad){if(!B(ad)){ad=this.getAsyncTracker().getSiteId()}if(!B(ac)){ac=this.getAsyncTracker().getTrackerUrl()}return new I(ac,ad)},getAsyncTracker:function(){return R}};if(typeof define==="function"&&define.amd){define("piwik",[],function(){return d
-})}return d}())}if(window&&window.piwikAsyncInit){window.piwikAsyncInit()}(function(){var a=(typeof AnalyticsTracker);if(a==="undefined"){AnalyticsTracker=window.Piwik}}());if(typeof piwik_log!=="function"){piwik_log=function(b,f,d,g){function a(h){try{if(window["piwik_"+h]){return window["piwik_"+h]}}catch(i){}return}var c,e=window.Piwik.getTracker(d,f);e.setDocumentTitle(b);e.setCustomData(g);c=a("tracker_pause");if(c){e.setLinkTrackingTimer(c)}c=a("download_extensions");if(c){e.setDownloadExtensions(c)}c=a("hosts_alias");if(c){e.setDomains(c)}c=a("ignore_classes");if(c){e.setIgnoreClasses(c)}e.trackPageView();if(a("install_tracker")){piwik_track=function(i,k,j,h){e.setSiteId(k);e.setTrackerUrl(j);e.trackLink(i,h)};e.enableLinkTracking()}};
-/*! @license-end */
+if(ad=="}"){break}if(ae){if(ad==","){ad=y();if(ad=="}"){H()}}else{H()}}if(ad==","||typeof ad!="string"||(F?ad.charAt(0):ad[0])!="@"||y()!=":"){H()}ac[ad.slice(1)]=W(y())}return ac}}H()}return ad};var P=function(ae,ad,af){var ac=w(ae,ad,af);if(ac===L){delete ae[ad]}else{ae[ad]=ac}};var w=function(af,ae,ag){var ad=af[ae],ac;if(typeof ad=="object"&&ad){if(u.call(ad)==E){for(ac=ad.length;ac--;){P(ad,ac,ag)}}else{m(ad,function(ah){P(ad,ah,ag)})}}return ag.call(af,ae,ad)};V.parse=function(ae,af){var ac,ad;G=0;X=""+ae;ac=W(y());if(y()!="$"){H()}G=X=null;return af&&u.call(af)==U?w((ad={},ad[""]=ac,ad),"",af):ac}}}V.runInContext=j;return V}if(h&&!c){j(i,h)}else{var f=i.JSON,k=i.JSON3,d=false;var g=j(i,(i.JSON3={noConflict:function(){if(!d){d=true;i.JSON=f;i.JSON3=k;f=k=null}return g}}));i.JSON={parse:g.parse,stringify:g.stringify}}if(c){define(function(){return g})}}).call(this);JSON2=a})()}if(typeof _paq!=="object"){_paq=[]}if(typeof window.Piwik!=="object"){window.Piwik=(function(){var l,a={},x=document,f=navigator,N=screen,J=window,g=J.performance||J.mozPerformance||J.msPerformance||J.webkitPerformance,n=J.encodeURIComponent,I=J.decodeURIComponent,i=unescape,O,w,d;
+function k(Y){try{return I(Y)}catch(Z){return unescape(Y)}}function z(Z){var Y=typeof Z;return Y!=="undefined"}function s(Y){return typeof Y==="function"}function M(Y){return typeof Y==="object"}function q(Y){return typeof Y==="string"||Y instanceof String}function t(Z){if(!Z){return true}var Y;var aa=true;for(Y in Z){if(Object.prototype.hasOwnProperty.call(Z,Y)){aa=false}}return aa}function T(){var Y,aa,Z;for(Y=0;Y<arguments.length;Y+=1){Z=arguments[Y];aa=Z.shift();if(q(aa)){O[aa].apply(O,Z)}else{aa.apply(O,Z)}}}function W(ab,aa,Z,Y){if(ab.addEventListener){ab.addEventListener(aa,Z,Y);return true}if(ab.attachEvent){return ab.attachEvent("on"+aa,Z)}ab["on"+aa]=Z}function R(Z,ac){var Y="",ab,aa;for(ab in a){if(Object.prototype.hasOwnProperty.call(a,ab)){aa=a[ab][Z];if(s(aa)){Y+=aa(ac)}}}return Y}function U(){var Y;R("unload");if(l){do{Y=new Date()}while(Y.getTimeAlias()<l)}}function j(aa,Z){var Y=x.createElement("script");Y.type="text/javascript";Y.src=aa;if(Y.readyState){Y.onreadystatechange=function(){var ab=this.readyState;
+if(ab==="loaded"||ab==="complete"){Y.onreadystatechange=null;Z()}}}else{Y.onload=Z}x.getElementsByTagName("head")[0].appendChild(Y)}function A(){var Y="";try{Y=J.top.document.referrer}catch(aa){if(J.parent){try{Y=J.parent.document.referrer}catch(Z){Y=""}}}if(Y===""){Y=x.referrer}return Y}function m(Y){var aa=new RegExp("^([a-z]+):"),Z=aa.exec(Y);return Z?Z[1]:null}function c(Y){var aa=new RegExp("^(?:(?:https?|ftp):)/*(?:[^@]+@)?([^:/#]+)"),Z=aa.exec(Y);return Z?Z[1]:Y}function L(aa,Z){var Y="[\\?&#]"+Z+"=([^&#]*)";var ac=new RegExp(Y);var ab=ac.exec(aa);return ab?I(ab[1]):""}function v(Y){return unescape(n(Y))}function V(an){var aa=function(au,at){return(au<<at)|(au>>>(32-at))},ao=function(aw){var au="",av,at;for(av=7;av>=0;av--){at=(aw>>>(av*4))&15;au+=at.toString(16)}return au},ad,aq,ap,Z=[],ah=1732584193,af=4023233417,ae=2562383102,ac=271733878,ab=3285377520,am,al,ak,aj,ai,ar,Y,ag=[];an=v(an);Y=an.length;for(aq=0;aq<Y-3;aq+=4){ap=an.charCodeAt(aq)<<24|an.charCodeAt(aq+1)<<16|an.charCodeAt(aq+2)<<8|an.charCodeAt(aq+3);
+ag.push(ap)}switch(Y&3){case 0:aq=2147483648;break;case 1:aq=an.charCodeAt(Y-1)<<24|8388608;break;case 2:aq=an.charCodeAt(Y-2)<<24|an.charCodeAt(Y-1)<<16|32768;break;case 3:aq=an.charCodeAt(Y-3)<<24|an.charCodeAt(Y-2)<<16|an.charCodeAt(Y-1)<<8|128;break}ag.push(aq);while((ag.length&15)!==14){ag.push(0)}ag.push(Y>>>29);ag.push((Y<<3)&4294967295);for(ad=0;ad<ag.length;ad+=16){for(aq=0;aq<16;aq++){Z[aq]=ag[ad+aq]}for(aq=16;aq<=79;aq++){Z[aq]=aa(Z[aq-3]^Z[aq-8]^Z[aq-14]^Z[aq-16],1)}am=ah;al=af;ak=ae;aj=ac;ai=ab;for(aq=0;aq<=19;aq++){ar=(aa(am,5)+((al&ak)|(~al&aj))+ai+Z[aq]+1518500249)&4294967295;ai=aj;aj=ak;ak=aa(al,30);al=am;am=ar}for(aq=20;aq<=39;aq++){ar=(aa(am,5)+(al^ak^aj)+ai+Z[aq]+1859775393)&4294967295;ai=aj;aj=ak;ak=aa(al,30);al=am;am=ar}for(aq=40;aq<=59;aq++){ar=(aa(am,5)+((al&ak)|(al&aj)|(ak&aj))+ai+Z[aq]+2400959708)&4294967295;ai=aj;aj=ak;ak=aa(al,30);al=am;am=ar}for(aq=60;aq<=79;aq++){ar=(aa(am,5)+(al^ak^aj)+ai+Z[aq]+3395469782)&4294967295;ai=aj;aj=ak;ak=aa(al,30);al=am;am=ar}ah=(ah+am)&4294967295;
+af=(af+al)&4294967295;ae=(ae+ak)&4294967295;ac=(ac+aj)&4294967295;ab=(ab+ai)&4294967295}ar=ao(ah)+ao(af)+ao(ae)+ao(ac)+ao(ab);return ar.toLowerCase()}function Q(aa,Y,Z){if(!aa){aa=""}if(!Y){Y=""}if(aa==="translate.googleusercontent.com"){if(Z===""){Z=Y}Y=L(Y,"u");aa=c(Y)}else{if(aa==="cc.bingj.com"||aa==="webcache.googleusercontent.com"||aa.slice(0,5)==="74.6."){Y=x.links[0].href;aa=c(Y)}}return[aa,Y,Z]}function B(Z){var Y=Z.length;if(Z.charAt(--Y)==="."){Z=Z.slice(0,Y)}if(Z.slice(0,2)==="*."){Z=Z.slice(1)}if(Z.indexOf("/")!==-1){Z=Z.substr(0,Z.indexOf("/"))}return Z}function X(Z){Z=Z&&Z.text?Z.text:Z;if(!q(Z)){var Y=x.getElementsByTagName("title");if(Y&&z(Y[0])){Z=Y[0].text}}return Z}function F(Y){if(!Y){return[]}if(!z(Y.children)&&z(Y.childNodes)){return Y.children}if(z(Y.children)){return Y.children}return[]}function K(Z,Y){if(!Z||!Y){return false}if(Z.contains){return Z.contains(Y)}if(Z===Y){return true}if(Z.compareDocumentPosition){return !!(Z.compareDocumentPosition(Y)&16)}return false
+}function C(aa,ab){if(aa&&aa.indexOf){return aa.indexOf(ab)}if(!z(aa)||aa===null){return -1}if(!aa.length){return -1}var Y=aa.length;if(Y===0){return -1}var Z=0;while(Z<Y){if(aa[Z]===ab){return Z}Z++}return -1}function H(Z,Y){Z=String(Z);return Z.indexOf(Y,Z.length-Y.length)!==-1}function r(Z,Y){Z=String(Z);return Z.indexOf(Y)!==-1}function e(Z,Y){Z=String(Z);return Z.substr(0,Z.length-Y)}function h(aa){if(!aa){return false}function Y(ac,ad){if(J.getComputedStyle){return x.defaultView.getComputedStyle(ac,null)[ad]}if(ac.currentStyle){return ac.currentStyle[ad]}}function ab(ac){ac=ac.parentNode;while(ac){if(ac===x){return true}ac=ac.parentNode}return false}function Z(ae,ak,ac,ah,af,ai,ag){var ad=ae.parentNode,aj=1;if(!ab(ae)){return false}if(9===ad.nodeType){return true}if("0"===Y(ae,"opacity")||"none"===Y(ae,"display")||"hidden"===Y(ae,"visibility")){return false}if(!z(ak)||!z(ac)||!z(ah)||!z(af)||!z(ai)||!z(ag)){ak=ae.offsetTop;af=ae.offsetLeft;ah=ak+ae.offsetHeight;ac=af+ae.offsetWidth;
+ai=ae.offsetWidth;ag=ae.offsetHeight}if(aa===ae&&(0===ag||0===ai)&&"hidden"===Y(ae,"overflow")){return false}if(ad){if(("hidden"===Y(ad,"overflow")||"scroll"===Y(ad,"overflow"))){if(af+aj>ad.offsetWidth+ad.scrollLeft||af+ai-aj<ad.scrollLeft||ak+aj>ad.offsetHeight+ad.scrollTop||ak+ag-aj<ad.scrollTop){return false}}if(ae.offsetParent===ad){af+=ad.offsetLeft;ak+=ad.offsetTop}return Z(ad,ak,ac,ah,af,ai,ag)}return true}return Z(aa)}var S={htmlCollectionToArray:function(aa){var Y=[],Z;if(!aa||!aa.length){return Y}for(Z=0;Z<aa.length;Z++){Y.push(aa[Z])}return Y},find:function(Y){if(!document.querySelectorAll||!Y){return[]}var Z=document.querySelectorAll(Y);return this.htmlCollectionToArray(Z)},findMultiple:function(aa){if(!aa||!aa.length){return[]}var Z,ab;var Y=[];for(Z=0;Z<aa.length;Z++){ab=this.find(aa[Z]);Y=Y.concat(ab)}Y=this.makeNodesUnique(Y);return Y},findNodesByTagName:function(Z,Y){if(!Z||!Y||!Z.getElementsByTagName){return[]}var aa=Z.getElementsByTagName(Y);return this.htmlCollectionToArray(aa)
+},makeNodesUnique:function(Y){var ad=[].concat(Y);Y.sort(function(af,ae){if(af===ae){return 0}var ah=C(ad,af);var ag=C(ad,ae);if(ah===ag){return 0}return ah>ag?-1:1});if(Y.length<=1){return Y}var Z=0;var ab=0;var ac=[];var aa;aa=Y[Z++];while(aa){if(aa===Y[Z]){ab=ac.push(Z)}aa=Y[Z++]||null}while(ab--){Y.splice(ac[ab],1)}return Y},getAttributeValueFromNode:function(ac,aa){if(!this.hasNodeAttribute(ac,aa)){return}if(ac&&ac.getAttribute){return ac.getAttribute(aa)}if(!ac||!ac.attributes){return}var ab=(typeof ac.attributes[aa]);if("undefined"===ab){return}if(ac.attributes[aa].value){return ac.attributes[aa].value}if(ac.attributes[aa].nodeValue){return ac.attributes[aa].nodeValue}var Z;var Y=ac.attributes;if(!Y){return}for(Z=0;Z<Y.length;Z++){if(Y[Z].nodeName===aa){return Y[Z].nodeValue}}return null},hasNodeAttributeWithValue:function(Z,Y){var aa=this.getAttributeValueFromNode(Z,Y);return !!aa},hasNodeAttribute:function(aa,Y){if(aa&&aa.hasAttribute){return aa.hasAttribute(Y)}if(aa&&aa.attributes){var Z=(typeof aa.attributes[Y]);
+return"undefined"!==Z}return false},hasNodeCssClass:function(aa,Y){if(aa&&Y&&aa.className){var Z=typeof aa.className==="string"?aa.className.split(" "):[];if(-1!==C(Z,Y)){return true}}return false},findNodesHavingAttribute:function(ac,aa,Y){if(!Y){Y=[]}if(!ac||!aa){return Y}var ab=F(ac);if(!ab||!ab.length){return Y}var Z,ad;for(Z=0;Z<ab.length;Z++){ad=ab[Z];if(this.hasNodeAttribute(ad,aa)){Y.push(ad)}Y=this.findNodesHavingAttribute(ad,aa,Y)}return Y},findFirstNodeHavingAttribute:function(aa,Z){if(!aa||!Z){return}if(this.hasNodeAttribute(aa,Z)){return aa}var Y=this.findNodesHavingAttribute(aa,Z);if(Y&&Y.length){return Y[0]}},findFirstNodeHavingAttributeWithValue:function(ab,aa){if(!ab||!aa){return}if(this.hasNodeAttributeWithValue(ab,aa)){return ab}var Y=this.findNodesHavingAttribute(ab,aa);if(!Y||!Y.length){return}var Z;for(Z=0;Z<Y.length;Z++){if(this.getAttributeValueFromNode(Y[Z],aa)){return Y[Z]}}},findNodesHavingCssClass:function(ac,ab,Y){if(!Y){Y=[]}if(!ac||!ab){return Y}if(ac.getElementsByClassName){var ad=ac.getElementsByClassName(ab);
+return this.htmlCollectionToArray(ad)}var aa=F(ac);if(!aa||!aa.length){return[]}var Z,ae;for(Z=0;Z<aa.length;Z++){ae=aa[Z];if(this.hasNodeCssClass(ae,ab)){Y.push(ae)}Y=this.findNodesHavingCssClass(ae,ab,Y)}return Y},findFirstNodeHavingClass:function(aa,Z){if(!aa||!Z){return}if(this.hasNodeCssClass(aa,Z)){return aa}var Y=this.findNodesHavingCssClass(aa,Z);if(Y&&Y.length){return Y[0]}},isLinkElement:function(Z){if(!Z){return false}var Y=String(Z.nodeName).toLowerCase();var ab=["a","area"];var aa=C(ab,Y);return aa!==-1},setAnyAttribute:function(Z,Y,aa){if(!Z||!Y){return}if(Z.setAttribute){Z.setAttribute(Y,aa)}else{Z[Y]=aa}}};var p={CONTENT_ATTR:"data-track-content",CONTENT_CLASS:"piwikTrackContent",CONTENT_NAME_ATTR:"data-content-name",CONTENT_PIECE_ATTR:"data-content-piece",CONTENT_PIECE_CLASS:"piwikContentPiece",CONTENT_TARGET_ATTR:"data-content-target",CONTENT_TARGET_CLASS:"piwikContentTarget",CONTENT_IGNOREINTERACTION_ATTR:"data-content-ignoreinteraction",CONTENT_IGNOREINTERACTION_CLASS:"piwikContentIgnoreInteraction",location:undefined,findContentNodes:function(){var Z="."+this.CONTENT_CLASS;
+var Y="["+this.CONTENT_ATTR+"]";var aa=S.findMultiple([Z,Y]);return aa},findContentNodesWithinNode:function(ab){if(!ab){return[]}var Z=S.findNodesHavingCssClass(ab,this.CONTENT_CLASS);var Y=S.findNodesHavingAttribute(ab,this.CONTENT_ATTR);if(Y&&Y.length){var aa;for(aa=0;aa<Y.length;aa++){Z.push(Y[aa])}}if(S.hasNodeAttribute(ab,this.CONTENT_ATTR)){Z.push(ab)}else{if(S.hasNodeCssClass(ab,this.CONTENT_CLASS)){Z.push(ab)}}Z=S.makeNodesUnique(Z);return Z},findParentContentNode:function(Z){if(!Z){return}var aa=Z;var Y=0;while(aa&&aa!==x&&aa.parentNode){if(S.hasNodeAttribute(aa,this.CONTENT_ATTR)){return aa}if(S.hasNodeCssClass(aa,this.CONTENT_CLASS)){return aa}aa=aa.parentNode;if(Y>1000){break}Y++}},findPieceNode:function(Z){var Y;Y=S.findFirstNodeHavingAttribute(Z,this.CONTENT_PIECE_ATTR);if(!Y){Y=S.findFirstNodeHavingClass(Z,this.CONTENT_PIECE_CLASS)}if(Y){return Y}return Z},findTargetNodeNoDefault:function(Y){if(!Y){return}var Z=S.findFirstNodeHavingAttributeWithValue(Y,this.CONTENT_TARGET_ATTR);
+if(Z){return Z}Z=S.findFirstNodeHavingAttribute(Y,this.CONTENT_TARGET_ATTR);if(Z){return Z}Z=S.findFirstNodeHavingClass(Y,this.CONTENT_TARGET_CLASS);if(Z){return Z}},findTargetNode:function(Y){var Z=this.findTargetNodeNoDefault(Y);if(Z){return Z}return Y},findContentName:function(Z){if(!Z){return}var ac=S.findFirstNodeHavingAttributeWithValue(Z,this.CONTENT_NAME_ATTR);if(ac){return S.getAttributeValueFromNode(ac,this.CONTENT_NAME_ATTR)}var Y=this.findContentPiece(Z);if(Y){return this.removeDomainIfIsInLink(Y)}if(S.hasNodeAttributeWithValue(Z,"title")){return S.getAttributeValueFromNode(Z,"title")}var aa=this.findPieceNode(Z);if(S.hasNodeAttributeWithValue(aa,"title")){return S.getAttributeValueFromNode(aa,"title")}var ab=this.findTargetNode(Z);if(S.hasNodeAttributeWithValue(ab,"title")){return S.getAttributeValueFromNode(ab,"title")}},findContentPiece:function(Z){if(!Z){return}var ab=S.findFirstNodeHavingAttributeWithValue(Z,this.CONTENT_PIECE_ATTR);if(ab){return S.getAttributeValueFromNode(ab,this.CONTENT_PIECE_ATTR)
+}var Y=this.findPieceNode(Z);var aa=this.findMediaUrlInNode(Y);if(aa){return this.toAbsoluteUrl(aa)}},findContentTarget:function(aa){if(!aa){return}var ab=this.findTargetNode(aa);if(S.hasNodeAttributeWithValue(ab,this.CONTENT_TARGET_ATTR)){return S.getAttributeValueFromNode(ab,this.CONTENT_TARGET_ATTR)}var Z;if(S.hasNodeAttributeWithValue(ab,"href")){Z=S.getAttributeValueFromNode(ab,"href");return this.toAbsoluteUrl(Z)}var Y=this.findPieceNode(aa);if(S.hasNodeAttributeWithValue(Y,"href")){Z=S.getAttributeValueFromNode(Y,"href");return this.toAbsoluteUrl(Z)}},isSameDomain:function(Y){if(!Y||!Y.indexOf){return false}if(0===Y.indexOf(this.getLocation().origin)){return true}var Z=Y.indexOf(this.getLocation().host);if(8>=Z&&0<=Z){return true}return false},removeDomainIfIsInLink:function(aa){var Z="^https?://[^/]+";var Y="^.*//[^/]+";if(aa&&aa.search&&-1!==aa.search(new RegExp(Z))&&this.isSameDomain(aa)){aa=aa.replace(new RegExp(Y),"");if(!aa){aa="/"}}return aa},findMediaUrlInNode:function(ac){if(!ac){return
+}var aa=["img","embed","video","audio"];var Y=ac.nodeName.toLowerCase();if(-1!==C(aa,Y)&&S.findFirstNodeHavingAttributeWithValue(ac,"src")){var ab=S.findFirstNodeHavingAttributeWithValue(ac,"src");return S.getAttributeValueFromNode(ab,"src")}if(Y==="object"&&S.hasNodeAttributeWithValue(ac,"data")){return S.getAttributeValueFromNode(ac,"data")}if(Y==="object"){var ad=S.findNodesByTagName(ac,"param");if(ad&&ad.length){var Z;for(Z=0;Z<ad.length;Z++){if("movie"===S.getAttributeValueFromNode(ad[Z],"name")&&S.hasNodeAttributeWithValue(ad[Z],"value")){return S.getAttributeValueFromNode(ad[Z],"value")}}}var ae=S.findNodesByTagName(ac,"embed");if(ae&&ae.length){return this.findMediaUrlInNode(ae[0])}}},trim:function(Y){if(Y&&String(Y)===Y){return Y.replace(/^\s+|\s+$/g,"")}return Y},isOrWasNodeInViewport:function(ad){if(!ad||!ad.getBoundingClientRect||ad.nodeType!==1){return true}var ac=ad.getBoundingClientRect();var ab=x.documentElement||{};var aa=ac.top<0;if(aa&&ad.offsetTop){aa=(ad.offsetTop+ac.height)>0
+}var Z=ab.clientWidth;if(J.innerWidth&&Z>J.innerWidth){Z=J.innerWidth}var Y=ab.clientHeight;if(J.innerHeight&&Y>J.innerHeight){Y=J.innerHeight}return((ac.bottom>0||aa)&&ac.right>0&&ac.left<Z&&((ac.top<Y)||aa))},isNodeVisible:function(Z){var Y=h(Z);var aa=this.isOrWasNodeInViewport(Z);return Y&&aa},buildInteractionRequestParams:function(Y,Z,aa,ab){var ac="";if(Y){ac+="c_i="+n(Y)}if(Z){if(ac){ac+="&"}ac+="c_n="+n(Z)}if(aa){if(ac){ac+="&"}ac+="c_p="+n(aa)}if(ab){if(ac){ac+="&"}ac+="c_t="+n(ab)}return ac},buildImpressionRequestParams:function(Y,Z,aa){var ab="c_n="+n(Y)+"&c_p="+n(Z);if(aa){ab+="&c_t="+n(aa)}return ab},buildContentBlock:function(aa){if(!aa){return}var Y=this.findContentName(aa);var Z=this.findContentPiece(aa);var ab=this.findContentTarget(aa);Y=this.trim(Y);Z=this.trim(Z);ab=this.trim(ab);return{name:Y||"Unknown",piece:Z||"Unknown",target:ab||""}},collectContent:function(ab){if(!ab||!ab.length){return[]}var aa=[];var Y,Z;for(Y=0;Y<ab.length;Y++){Z=this.buildContentBlock(ab[Y]);
+if(z(Z)){aa.push(Z)}}return aa},setLocation:function(Y){this.location=Y},getLocation:function(){var Y=this.location||J.location;if(!Y.origin){Y.origin=Y.protocol+"//"+Y.hostname+(Y.port?":"+Y.port:"")}return Y},toAbsoluteUrl:function(Z){if((!Z||String(Z)!==Z)&&Z!==""){return Z}if(""===Z){return this.getLocation().href}if(Z.search(/^\/\//)!==-1){return this.getLocation().protocol+Z}if(Z.search(/:\/\//)!==-1){return Z}if(0===Z.indexOf("#")){return this.getLocation().origin+this.getLocation().pathname+Z}if(0===Z.indexOf("?")){return this.getLocation().origin+this.getLocation().pathname+Z}if(0===Z.search("^[a-zA-Z]{2,11}:")){return Z}if(Z.search(/^\//)!==-1){return this.getLocation().origin+Z}var Y="(.*/)";var aa=this.getLocation().origin+this.getLocation().pathname.match(new RegExp(Y))[0];return aa+Z},isUrlToCurrentDomain:function(Z){var aa=this.toAbsoluteUrl(Z);if(!aa){return false}var Y=this.getLocation().origin;if(Y===aa){return true}if(0===String(aa).indexOf(Y)){if(":"===String(aa).substr(Y.length,1)){return false
+}return true}return false},setHrefAttribute:function(Z,Y){if(!Z||!Y){return}S.setAnyAttribute(Z,"href",Y)},shouldIgnoreInteraction:function(aa){var Z=S.hasNodeAttribute(aa,this.CONTENT_IGNOREINTERACTION_ATTR);var Y=S.hasNodeCssClass(aa,this.CONTENT_IGNOREINTERACTION_CLASS);return Z||Y}};function E(Z,ac){if(ac){return ac}if(r(Z,"?")){var ab=Z.indexOf("?");Z=Z.slice(0,ab)}if(H(Z,"piwik.php")){Z=e(Z,"piwik.php".length)}else{if(H(Z,".php")){var Y=Z.lastIndexOf("/");var aa=1;Z=Z.slice(0,Y+aa)}}if(H(Z,"/js/")){Z=e(Z,"js/".length)}return Z}function D(ae){var ag="Piwik_Overlay";var Z=new RegExp("index\\.php\\?module=Overlay&action=startOverlaySession&idSite=([0-9]+)&period=([^&]+)&date=([^&]+)(&segment=.*)?$");var aa=Z.exec(x.referrer);if(aa){var ac=aa[1];if(ac!==String(ae)){return false}var ad=aa[2],Y=aa[3],ab=aa[4];if(!ab){ab=""}else{if(ab.indexOf("&segment=")===0){ab=ab.substr("&segment=".length)}}J.name=ag+"###"+ad+"###"+Y+"###"+ab}var af=J.name.split("###");return af.length===4&&af[0]===ag
+}function P(Z,af,ab){var ae=J.name.split("###"),ad=ae[1],Y=ae[2],ac=ae[3],aa=E(Z,af);j(aa+"plugins/Overlay/client/client.js?v=1",function(){Piwik_Overlay_Client.initialize(aa,ab,ad,Y,ac)})}function o(){if(z(J.frameElement)){return(J.frameElement&&String(J.frameElement.nodeName).toLowerCase()==="iframe")}try{return J.self!==J.top}catch(Y){return true}}function G(bG,bA){var bw=Q(x.domain,J.location.href,A()),ce=B(bw[0]),bg=k(bw[1]),aV=k(bw[2]),cc=false,bK="GET",cq=bK,am="application/x-www-form-urlencoded; charset=UTF-8",bW=am,ai=bG||"",bb="",ci="",by=bA||"",a4="",bh="",aG,aR=x.title,cn=["7z","aac","apk","arc","arj","asf","asx","avi","azw3","bin","csv","deb","dmg","doc","docx","epub","exe","flv","gif","gz","gzip","hqx","ibooks","jar","jpg","jpeg","js","mobi","mp2","mp3","mp4","mpg","mpeg","mov","movie","msi","msp","odb","odf","odg","ods","odt","ogg","ogv","pdf","phps","png","ppt","pptx","qt","qtm","ra","ram","rar","rpm","sea","sit","tar","tbz","tbz2","bz","bz2","tgz","torrent","txt","wav","wma","wmv","wpd","xls","xlsx","xml","z","zip"],ae=[ce],a5=[],be=[],aJ=[],bc=500,b5,aH,bk,bi,Y,bS=["pk_campaign","piwik_campaign","utm_campaign","utm_source","utm_medium"],ba=["pk_kwd","piwik_kwd","utm_term"],aS="_pk_",cg,aX,aT=false,ca,aP,a1,b6=33955200000,bQ=1800000,cm=15768000000,aE=true,bO=0,bj=false,at=false,bD,bo={},bN={},aU={},a0=200,cj={},co={},bC=[],bH=false,bZ=false,Z=false,cp=false,aq=false,aO=o(),ch=null,bE,au,a6,bz=V,aW;
+function ct(cD,cA,cz,cC,cy,cB){if(aT){return}var cx;if(cz){cx=new Date();cx.setTime(cx.getTime()+cz)}x.cookie=cD+"="+n(cA)+(cz?";expires="+cx.toGMTString():"")+";path="+(cC||"/")+(cy?";domain="+cy:"")+(cB?";secure":"")}function ah(cz){if(aT){return 0}var cx=new RegExp("(^|;)[ ]*"+cz+"=([^;]*)"),cy=cx.exec(x.cookie);return cy?I(cy[2]):0}function bu(cx){var cy;if(bi){cy=new RegExp("#.*");return cx.replace(cy,"")}return cx}function bn(cz,cx){var cA=m(cx),cy;if(cA){return cx}if(cx.slice(0,1)==="/"){return m(cz)+"://"+c(cz)+cx}cz=bu(cz);cy=cz.indexOf("?");if(cy>=0){cz=cz.slice(0,cy)}cy=cz.lastIndexOf("/");if(cy!==cz.length-1){cz=cz.slice(0,cy+1)}return cz+cx}function b3(cz,cx){var cy;cz=String(cz).toLowerCase();cx=String(cx).toLowerCase();if(cz===cx){return true}if(cx.slice(0,1)==="."){if(cz===cx.slice(1)){return true}cy=cz.length-cx.length;if((cy>0)&&(cz.slice(cy)===cx)){return true}}return false}function bM(cx){var cy=document.createElement("a");if(cx.indexOf("//")!==0&&cx.indexOf("http")!==0){cx="http://"+cx
+}cy.href=p.toAbsoluteUrl(cx);if(cy.pathname){return cy.pathname}return""}function aF(cy,cx){var cz=(!cx||cx==="/"||cx==="/*");if(cz){return true}if(cy===cx){return true}if(!cy){return false}cx=String(cx).toLowerCase();cy=String(cy).toLowerCase();if(H(cx,"*")){cx=cx.slice(0,-1);cz=(!cx||cx==="/");if(cz){return true}if(cy===cx){return true}return cy.indexOf(cx)===0}if(!H(cy,"/")){cy+="/"}if(!H(cx,"/")){cx+="/"}return cy.indexOf(cx)===0}function ab(cB,cD){var cy,cx,cz,cA,cC;for(cy=0;cy<ae.length;cy++){cA=B(ae[cy]);cC=bM(ae[cy]);if(b3(cB,cA)&&aF(cD,cC)){return true}}return false}function ay(cA){var cy,cx,cz;for(cy=0;cy<ae.length;cy++){cx=B(ae[cy].toLowerCase());if(cA===cx){return true}if(cx.slice(0,1)==="."){if(cA===cx.slice(1)){return true}cz=cA.length-cx.length;if((cz>0)&&(cA.slice(cz)===cx)){return true}}}return false}function bR(cx,cz){var cy=new Image(1,1);cy.onload=function(){w=0;if(typeof cz==="function"){cz()}};cy.src=ai+(ai.indexOf("?")<0?"?":"&")+cx}function cl(cy,cB,cx){if(!z(cx)||null===cx){cx=true
+}try{var cA=J.XMLHttpRequest?new J.XMLHttpRequest():J.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):null;cA.open("POST",ai,true);cA.onreadystatechange=function(){if(this.readyState===4&&!(this.status>=200&&this.status<300)&&cx){bR(cy,cB)}else{if(typeof cB==="function"){cB()}}};cA.setRequestHeader("Content-Type",bW);cA.send(cy)}catch(cz){if(cx){bR(cy,cB)}}}function bI(cy){var cx=new Date();var cz=cx.getTime()+cy;if(!l||cz>l){l=cz}}function bP(cx){if(bE||!aH){return}bE=setTimeout(function cy(){bE=null;if(!aO){aO=(!x.hasFocus||x.hasFocus())}if(!aO){bP(aH);return}if(bk()){return}var cz=new Date(),cA=aH-(cz.getTime()-ch);cA=Math.min(aH,cA);bP(cA)},cx||aH)}function bd(){if(!bE){return}clearTimeout(bE);bE=null}function aL(){aO=true;if(bk()){return}bP()}function af(){bd()}function cv(){if(aq||!aH){return}aq=true;W(J,"focus",aL);W(J,"blur",af);bP()}function b0(cB){var cy=new Date();var cx=cy.getTime();ch=cx;if(bZ&&cx<bZ){var cz=bZ-cx;setTimeout(cB,cz);bI(cz+50);bZ+=50;return}if(bZ===false){var cA=800;
+bZ=cx+cA}cB()}function a9(cy,cx,cz){if(!ca&&cy){b0(function(){if(cq==="POST"){cl(cy,cz)}else{bR(cy,cz)}bI(cx)})}if(!aq){cv()}else{bP()}}function bL(cx){if(ca){return false}return(cx&&cx.length)}function cu(cz,cx){if(!bL(cz)){return}var cy='{"requests":["?'+cz.join('","?')+'"]}';b0(function(){cl(cy,null,false);bI(cx)})}function aw(cx){return aS+cx+"."+by+"."+aW}function bx(){if(aT){return"0"}if(!z(f.cookieEnabled)){var cx=aw("testcookie");ct(cx,"1");return ah(cx)==="1"?"1":"0"}return f.cookieEnabled?"1":"0"}function aQ(){aW=bz((cg||ce)+(aX||"/")).slice(0,4)}function bp(){var cy=aw("cvar"),cx=ah(cy);if(cx.length){cx=JSON2.parse(cx);if(M(cx)){return cx}}return{}}function b1(){if(at===false){at=bp()}}function cb(){return bz((f.userAgent||"")+(f.platform||"")+JSON2.stringify(co)+(new Date()).getTime()+Math.random()).slice(0,16)}function b8(){var cz=new Date(),cx=Math.round(cz.getTime()/1000),cy=aw("id"),cC=ah(cy),cB,cA;if(cC){cB=cC.split(".");cB.unshift("0");if(bh.length){cB[1]=bh}return cB}if(bh.length){cA=bh
+}else{if("0"===bx()){cA=""}else{cA=cb()}}cB=["1",cA,cx,0,cx,"",""];return cB}function aA(){var cE=b8(),cA=cE[0],cB=cE[1],cy=cE[2],cx=cE[3],cC=cE[4],cz=cE[5];if(!z(cE[6])){cE[6]=""}var cD=cE[6];return{newVisitor:cA,uuid:cB,createTs:cy,visitCount:cx,currentVisitTs:cC,lastVisitTs:cz,lastEcommerceOrderTs:cD}}function al(){var cA=new Date(),cy=cA.getTime(),cB=aA().createTs;var cx=parseInt(cB,10);var cz=(cx*1000)+b6-cy;return cz}function ao(cx){if(!by){return}var cz=new Date(),cy=Math.round(cz.getTime()/1000);if(!z(cx)){cx=aA()}var cA=cx.uuid+"."+cx.createTs+"."+cx.visitCount+"."+cy+"."+cx.lastVisitTs+"."+cx.lastEcommerceOrderTs;ct(aw("id"),cA,al(),aX,cg)}function bf(){var cx=ah(aw("ref"));if(cx.length){try{cx=JSON2.parse(cx);if(M(cx)){return cx}}catch(cy){}}return["","",0,""]}function bq(cz,cy,cx){ct(cz,"",-86400,cy,cx)}function a2(cy){var cx="testvalue";ct("test",cx,10000,null,cy);if(ah("test")===cx){bq("test",null,cy);return true}return false}function aj(){var cz=aT;aT=false;var cx=["id","ses","cvar","ref"];
+var cy,cA;for(cy=0;cy<cx.length;cy++){cA=aw(cx[cy]);if(0!==ah(cA)){bq(cA,aX,cg)}}aT=cz}function bv(cx){by=cx;ao()}function cw(cB){if(!cB||!M(cB)){return}var cA=[];var cz;for(cz in cB){if(Object.prototype.hasOwnProperty.call(cB,cz)){cA.push(cz)}}var cC={};cA.sort();var cx=cA.length;var cy;for(cy=0;cy<cx;cy++){cC[cA[cy]]=cB[cA[cy]]}return cC}function bF(){ct(aw("ses"),"*",bQ,aX,cg)}function bT(cz,cU,cV,cA){var cT,cy=new Date(),cH=Math.round(cy.getTime()/1000),cE,cS,cB=1024,c0,cI,cQ=at,cC=aw("ses"),cO=aw("ref"),cL=aw("cvar"),cM=ah(cC),cR=bf(),cX=aG||bg,cF,cx;if(aT){aj()}if(ca){return""}var cN=aA();if(!z(cA)){cA=""}var cK=x.characterSet||x.charset;if(!cK||cK.toLowerCase()==="utf-8"){cK=null}cF=cR[0];cx=cR[1];cE=cR[2];cS=cR[3];if(!cM){var cW=bQ/1000;if(!cN.lastVisitTs||(cH-cN.lastVisitTs)>cW){cN.visitCount++;cN.lastVisitTs=cN.currentVisitTs}if(!a1||!cF.length){for(cT in bS){if(Object.prototype.hasOwnProperty.call(bS,cT)){cF=L(cX,bS[cT]);if(cF.length){break}}}for(cT in ba){if(Object.prototype.hasOwnProperty.call(ba,cT)){cx=L(cX,ba[cT]);
+if(cx.length){break}}}}c0=c(aV);cI=cS.length?c(cS):"";if(c0.length&&!ay(c0)&&(!a1||!cI.length||ay(cI))){cS=aV}if(cS.length||cF.length){cE=cH;cR=[cF,cx,cE,bu(cS.slice(0,cB))];ct(cO,JSON2.stringify(cR),cm,aX,cg)}}cz+="&idsite="+by+"&rec=1&r="+String(Math.random()).slice(2,8)+"&h="+cy.getHours()+"&m="+cy.getMinutes()+"&s="+cy.getSeconds()+"&url="+n(bu(cX))+(aV.length?"&urlref="+n(bu(aV)):"")+((a4&&a4.length)?"&uid="+n(a4):"")+"&_id="+cN.uuid+"&_idts="+cN.createTs+"&_idvc="+cN.visitCount+"&_idn="+cN.newVisitor+(cF.length?"&_rcn="+n(cF):"")+(cx.length?"&_rck="+n(cx):"")+"&_refts="+cE+"&_viewts="+cN.lastVisitTs+(String(cN.lastEcommerceOrderTs).length?"&_ects="+cN.lastEcommerceOrderTs:"")+(String(cS).length?"&_ref="+n(bu(cS.slice(0,cB))):"")+(cK?"&cs="+n(cK):"")+"&send_image=0";for(cT in co){if(Object.prototype.hasOwnProperty.call(co,cT)){cz+="&"+cT+"="+co[cT]}}var cZ=[];if(cU){for(cT in cU){if(Object.prototype.hasOwnProperty.call(cU,cT)&&/^dimension\d+$/.test(cT)){var cD=cT.replace("dimension","");
+cZ.push(parseInt(cD,10));cZ.push(String(cD));cz+="&"+cT+"="+cU[cT];delete cU[cT]}}}if(cU&&t(cU)){cU=null}for(cT in aU){if(Object.prototype.hasOwnProperty.call(aU,cT)){var cJ=(-1===cZ.indexOf(cT));if(cJ){cz+="&dimension"+cT+"="+aU[cT]}}}if(cU){cz+="&data="+n(JSON2.stringify(cU))}else{if(Y){cz+="&data="+n(JSON2.stringify(Y))}}function cG(c1,c2){var c3=JSON2.stringify(c1);if(c3.length>2){return"&"+c2+"="+n(c3)}return""}var cY=cw(bo);var cP=cw(bN);cz+=cG(cY,"cvar");cz+=cG(cP,"e_cvar");if(at){cz+=cG(at,"_cvar");for(cT in cQ){if(Object.prototype.hasOwnProperty.call(cQ,cT)){if(at[cT][0]===""||at[cT][1]===""){delete at[cT]}}}if(bj){ct(cL,JSON2.stringify(at),bQ,aX,cg)}}if(aE){if(bO){cz+="&gt_ms="+bO}else{if(g&&g.timing&&g.timing.requestStart&&g.timing.responseEnd){cz+="&gt_ms="+(g.timing.responseEnd-g.timing.requestStart)}}}cN.lastEcommerceOrderTs=z(cA)&&String(cA).length?cA:cN.lastEcommerceOrderTs;ao(cN);bF();cz+=R(cV);if(ci.length){cz+="&"+ci}if(s(bD)){cz=bD(cz)}return cz}bk=function aI(){var cx=new Date();
+if(ch+aH<=cx.getTime()){var cy=bT("ping=1",null,"ping");a9(cy,bc);return true}return false};function aY(cA,cz,cE,cB,cx,cH){var cC="idgoal=0",cD,cy=new Date(),cF=[],cG;if(String(cA).length){cC+="&ec_id="+n(cA);cD=Math.round(cy.getTime()/1000)}cC+="&revenue="+cz;if(String(cE).length){cC+="&ec_st="+cE}if(String(cB).length){cC+="&ec_tx="+cB}if(String(cx).length){cC+="&ec_sh="+cx}if(String(cH).length){cC+="&ec_dt="+cH}if(cj){for(cG in cj){if(Object.prototype.hasOwnProperty.call(cj,cG)){if(!z(cj[cG][1])){cj[cG][1]=""}if(!z(cj[cG][2])){cj[cG][2]=""}if(!z(cj[cG][3])||String(cj[cG][3]).length===0){cj[cG][3]=0}if(!z(cj[cG][4])||String(cj[cG][4]).length===0){cj[cG][4]=1}cF.push(cj[cG])}}cC+="&ec_items="+n(JSON2.stringify(cF))}cC=bT(cC,Y,"ecommerce",cD);a9(cC,bc)}function br(cx,cB,cA,cz,cy,cC){if(String(cx).length&&z(cB)){aY(cx,cB,cA,cz,cy,cC)}}function aZ(cx){if(z(cx)){aY("",cx,"","","","")}}function bs(cy,cz){var cx=bT("action_name="+n(X(cy||aR)),cz,"log");a9(cx,bc)}function aC(cz,cy){var cA,cx="(^| )(piwik[_-]"+cy;
+if(cz){for(cA=0;cA<cz.length;cA++){cx+="|"+cz[cA]}}cx+=")( |$)";return new RegExp(cx)}function ax(cx){return(ai&&cx&&0===String(cx).indexOf(ai))}function bU(cB,cx,cC,cy){if(ax(cx)){return 0}var cA=aC(be,"download"),cz=aC(aJ,"link"),cD=new RegExp("\\.("+cn.join("|")+")([?&#]|$)","i");if(cz.test(cB)){return"link"}if(cy||cA.test(cB)||cD.test(cx)){return"download"}if(cC){return 0}return"link"}function ac(cy){var cx;cx=cy.parentNode;while(cx!==null&&z(cx)){if(S.isLinkElement(cy)){break}cy=cx;cx=cy.parentNode}return cy}function cr(cC){cC=ac(cC);if(!S.hasNodeAttribute(cC,"href")){return}if(!z(cC.href)){return}var cB=S.getAttributeValueFromNode(cC,"href");if(ax(cB)){return}var cy=cC.pathname||bM(cC.href);var cD=cC.hostname||c(cC.href);var cE=cD.toLowerCase();var cz=cC.href.replace(cD,cE);var cA=new RegExp("^(javascript|vbscript|jscript|mocha|livescript|ecmascript|mailto|tel):","i");if(!cA.test(cz)){var cx=bU(cC.className,cz,ab(cE,cy),S.hasNodeAttribute(cC,"download"));if(cx){return{type:cx,href:cz}
+}}}function ar(cx,cy,cz,cA){var cB=p.buildInteractionRequestParams(cx,cy,cz,cA);if(!cB){return}return bT(cB,null,"contentInteraction")}function b7(cz,cA,cE,cx,cy){if(!z(cz)){return}if(ax(cz)){return cz}var cC=p.toAbsoluteUrl(cz);var cB="redirecturl="+n(cC)+"&";cB+=ar(cA,cE,cx,(cy||cz));var cD="&";if(ai.indexOf("?")<0){cD="?"}return ai+cD+cB}function aM(cx,cy){if(!cx||!cy){return false}var cz=p.findTargetNode(cx);if(p.shouldIgnoreInteraction(cz)){return false}cz=p.findTargetNodeNoDefault(cx);if(cz&&!K(cz,cy)){return false}return true}function bV(cz,cy,cB){if(!cz){return}var cx=p.findParentContentNode(cz);if(!cx){return}if(!aM(cx,cz)){return}var cA=p.buildContentBlock(cx);if(!cA){return}if(!cA.target&&cB){cA.target=cB}return p.buildInteractionRequestParams(cy,cA.name,cA.piece,cA.target)}function az(cy){if(!bC||!bC.length){return false}var cx,cz;for(cx=0;cx<bC.length;cx++){cz=bC[cx];if(cz&&cz.name===cy.name&&cz.piece===cy.piece&&cz.target===cy.target){return true}}return false}function a8(cA){if(!cA){return false
+}var cD=p.findTargetNode(cA);if(!cD||p.shouldIgnoreInteraction(cD)){return false}var cE=cr(cD);if(cp&&cE&&cE.type){return false}if(S.isLinkElement(cD)&&S.hasNodeAttributeWithValue(cD,"href")){var cx=String(S.getAttributeValueFromNode(cD,"href"));if(0===cx.indexOf("#")){return false}if(ax(cx)){return true}if(!p.isUrlToCurrentDomain(cx)){return false}var cB=p.buildContentBlock(cA);if(!cB){return}var cz=cB.name;var cF=cB.piece;var cC=cB.target;if(!S.hasNodeAttributeWithValue(cD,p.CONTENT_TARGET_ATTR)||cD.wasContentTargetAttrReplaced){cD.wasContentTargetAttrReplaced=true;cC=p.toAbsoluteUrl(cx);S.setAnyAttribute(cD,p.CONTENT_TARGET_ATTR,cC)}var cy=b7(cx,"click",cz,cF,cC);p.setHrefAttribute(cD,cy);return true}return false}function ap(cy){if(!cy||!cy.length){return}var cx;for(cx=0;cx<cy.length;cx++){a8(cy[cx])}}function aB(cx){return function(cy){if(!cx){return}var cB=p.findParentContentNode(cx);var cC;if(cy){cC=cy.target||cy.srcElement}if(!cC){cC=cx}if(!aM(cB,cC)){return}bI(bc);if(S.isLinkElement(cx)&&S.hasNodeAttributeWithValue(cx,"href")&&S.hasNodeAttributeWithValue(cx,p.CONTENT_TARGET_ATTR)){var cz=S.getAttributeValueFromNode(cx,"href");
+if(!ax(cz)&&cx.wasContentTargetAttrReplaced){S.setAnyAttribute(cx,p.CONTENT_TARGET_ATTR,"")}}var cG=cr(cx);if(Z&&cG&&cG.type){return cG.type}if(a8(cB)){return"href"}var cD=p.buildContentBlock(cB);if(!cD){return}var cA=cD.name;var cH=cD.piece;var cF=cD.target;var cE=ar("click",cA,cH,cF);a9(cE,bc);return cE}}function bt(cz){if(!cz||!cz.length){return}var cx,cy;for(cx=0;cx<cz.length;cx++){cy=p.findTargetNode(cz[cx]);if(cy&&!cy.contentInteractionTrackingSetupDone){cy.contentInteractionTrackingSetupDone=true;W(cy,"click",aB(cy))}}}function a3(cz,cA){if(!cz||!cz.length){return[]}var cx,cy;for(cx=0;cx<cz.length;cx++){if(az(cz[cx])){cz.splice(cx,1);cx--}else{bC.push(cz[cx])}}if(!cz||!cz.length){return[]}ap(cA);bt(cA);var cB=[];for(cx=0;cx<cz.length;cx++){cy=bT(p.buildImpressionRequestParams(cz[cx].name,cz[cx].piece,cz[cx].target),undefined,"contentImpressions");if(cy){cB.push(cy)}}return cB}function bY(cy){var cx=p.collectContent(cy);return a3(cx,cy)}function aK(cy){if(!cy||!cy.length){return[]
+}var cx;for(cx=0;cx<cy.length;cx++){if(!p.isNodeVisible(cy[cx])){cy.splice(cx,1);cx--}}if(!cy||!cy.length){return[]}return bY(cy)}function ak(cz,cx,cy){var cA=p.buildImpressionRequestParams(cz,cx,cy);return bT(cA,null,"contentImpression")}function cs(cA,cy){if(!cA){return}var cx=p.findParentContentNode(cA);var cz=p.buildContentBlock(cx);if(!cz){return}if(!cy){cy="Unknown"}return ar(cy,cz.name,cz.piece,cz.target)}function b9(cy,cA,cx,cz){return"e_c="+n(cy)+"&e_a="+n(cA)+(z(cx)?"&e_n="+n(cx):"")+(z(cz)?"&e_v="+n(cz):"")}function ad(cz,cB,cx,cA,cC){if(String(cz).length===0||String(cB).length===0){return false}var cy=bT(b9(cz,cB,cx,cA),cC,"event");a9(cy,bc)}function bB(cx,cA,cy,cB){var cz=bT("search="+n(cx)+(cA?"&search_cat="+n(cA):"")+(z(cy)?"&search_count="+cy:""),cB,"sitesearch");a9(cz,bc)}function cd(cx,cA,cz){var cy=bT("idgoal="+cx+(cA?"&revenue="+cA:""),cz,"goal");a9(cy,bc)}function ck(cA,cx,cE,cD,cz){var cC=cx+"="+n(bu(cA));var cy=bV(cz,"click",cA);if(cy){cC+="&"+cy}var cB=bT(cC,cE,"link");
+a9(cB,(cD?0:bc),cD)}function bl(cy,cx){if(cy!==""){return cy+cx.charAt(0).toUpperCase()+cx.slice(1)}return cx}function bJ(cC){var cB,cx,cA=["","webkit","ms","moz"],cz;if(!aP){for(cx=0;cx<cA.length;cx++){cz=cA[cx];if(Object.prototype.hasOwnProperty.call(x,bl(cz,"hidden"))){if(x[bl(cz,"visibilityState")]==="prerender"){cB=true}break}}}if(cB){W(x,cz+"visibilitychange",function cy(){x.removeEventListener(cz+"visibilitychange",cy,false);cC()});return}cC()}function an(cx){if(x.readyState==="complete"){cx()}else{if(J.addEventListener){J.addEventListener("load",cx)}else{if(J.attachEvent){J.attachEvent("onload",cx)}}}}function aN(cA){var cx=false;if(x.attachEvent){cx=x.readyState==="complete"}else{cx=x.readyState!=="loading"}if(cx){cA();return}var cz;if(x.addEventListener){W(x,"DOMContentLoaded",function cy(){x.removeEventListener("DOMContentLoaded",cy,false);if(!cx){cx=true;cA()}})}else{if(x.attachEvent){x.attachEvent("onreadystatechange",function cy(){if(x.readyState==="complete"){x.detachEvent("onreadystatechange",cy);
+if(!cx){cx=true;cA()}}});if(x.documentElement.doScroll&&J===J.top){(function cy(){if(!cx){try{x.documentElement.doScroll("left")}catch(cB){setTimeout(cy,0);return}cx=true;cA()}}())}}}W(J,"load",function(){if(!cx){cx=true;cA()}},false)}function b4(cx){var cy=cr(cx);if(cy&&cy.type){cy.href=k(cy.href);ck(cy.href,cy.type,undefined,null,cx)}}function bX(){return x.all&&!x.addEventListener}function cf(cx){var cz=cx.which;var cy=(typeof cx.button);if(!cz&&cy!=="undefined"){if(bX()){if(cx.button&1){cz=1}else{if(cx.button&2){cz=3}else{if(cx.button&4){cz=2}}}}else{if(cx.button===0||cx.button==="0"){cz=1}else{if(cx.button&1){cz=2}else{if(cx.button&2){cz=3}}}}}return cz}function bm(cx){switch(cf(cx)){case 1:return"left";case 2:return"middle";case 3:return"right"}}function aD(cx){return cx.target||cx.srcElement}function ag(cx){return function(cA){cA=cA||J.event;var cz=bm(cA);var cB=aD(cA);if(cA.type==="click"){var cy=false;if(cx&&cz==="middle"){cy=true}if(cB&&!cy){b4(cB)}}else{if(cA.type==="mousedown"){if(cz==="middle"&&cB){au=cz;
+a6=cB}else{au=a6=null}}else{if(cA.type==="mouseup"){if(cz===au&&cB===a6){b4(cB)}au=a6=null}else{if(cA.type==="contextmenu"){b4(cB)}}}}}}function aa(cy,cx){W(cy,"click",ag(cx),false);if(cx){W(cy,"mouseup",ag(cx),false);W(cy,"mousedown",ag(cx),false);W(cy,"contextmenu",ag(cx),false)}}function a7(cy){if(!Z){Z=true;var cz,cx=aC(a5,"ignore"),cA=x.links;if(cA){for(cz=0;cz<cA.length;cz++){if(!cx.test(cA[cz].className)){aa(cA[cz],cy)}}}}}function av(cz,cB,cC){if(bH){return true}bH=true;var cD=false;var cA,cy;function cx(){cD=true}an(function(){function cE(cG){setTimeout(function(){if(!bH){return}cD=false;cC.trackVisibleContentImpressions();cE(cG)},cG)}function cF(cG){setTimeout(function(){if(!bH){return}if(cD){cD=false;cC.trackVisibleContentImpressions()}cF(cG)},cG)}if(cz){cA=["scroll","resize"];for(cy=0;cy<cA.length;cy++){if(x.addEventListener){x.addEventListener(cA[cy],cx)}else{J.attachEvent("on"+cA[cy],cx)}}cF(100)}if(cB&&cB>0){cB=parseInt(cB,10);cE(cB)}})}function b2(){var cz,cB,cC={pdf:"application/pdf",qt:"video/quicktime",realp:"audio/x-pn-realaudio-plugin",wma:"application/x-mplayer2",dir:"application/x-director",fla:"application/x-shockwave-flash",java:"application/x-java-vm",gears:"application/x-googlegears",ag:"application/x-silverlight"},cy=J.devicePixelRatio||1;
+if(!((new RegExp("MSIE")).test(f.userAgent))){if(f.mimeTypes&&f.mimeTypes.length){for(cz in cC){if(Object.prototype.hasOwnProperty.call(cC,cz)){cB=f.mimeTypes[cC[cz]];co[cz]=(cB&&cB.enabledPlugin)?"1":"0"}}}if(typeof navigator.javaEnabled!=="unknown"&&z(f.javaEnabled)&&f.javaEnabled()){co.java="1"}if(s(J.GearsFactory)){co.gears="1"}co.cookie=bx()}var cA=parseInt(N.width,10)*cy;var cx=parseInt(N.height,10)*cy;co.res=parseInt(cA,10)+"x"+parseInt(cx,10)}b2();aQ();ao();return{getVisitorId:function(){return aA().uuid},getVisitorInfo:function(){return b8()},getAttributionInfo:function(){return bf()},getAttributionCampaignName:function(){return bf()[0]},getAttributionCampaignKeyword:function(){return bf()[1]},getAttributionReferrerTimestamp:function(){return bf()[2]},getAttributionReferrerUrl:function(){return bf()[3]},setTrackerUrl:function(cx){ai=cx},getTrackerUrl:function(){return ai},getSiteId:function(){return by},setSiteId:function(cx){bv(cx)},setUserId:function(cx){if(!z(cx)||!cx.length){return
+}a4=cx;bh=bz(a4).substr(0,16)},getUserId:function(){return a4},setCustomData:function(cx,cy){if(M(cx)){Y=cx}else{if(!Y){Y={}}Y[cx]=cy}},getCustomData:function(){return Y},setCustomRequestProcessing:function(cx){bD=cx},appendToTrackingUrl:function(cx){ci=cx},getRequest:function(cx){return bT(cx)},addPlugin:function(cx,cy){a[cx]=cy},setCustomDimension:function(cx,cy){cx=parseInt(cx,10);if(cx>0){if(!z(cy)){cy=""}if(!q(cy)){cy=String(cy)}aU[cx]=cy}},getCustomDimension:function(cx){cx=parseInt(cx,10);if(cx>0&&Object.prototype.hasOwnProperty.call(aU,cx)){return aU[cx]}},deleteCustomDimension:function(cx){cx=parseInt(cx,10);if(cx>0){delete aU[cx]}},setCustomVariable:function(cy,cx,cB,cz){var cA;if(!z(cz)){cz="visit"}if(!z(cx)){return}if(!z(cB)){cB=""}if(cy>0){cx=!q(cx)?String(cx):cx;cB=!q(cB)?String(cB):cB;cA=[cx.slice(0,a0),cB.slice(0,a0)];if(cz==="visit"||cz===2){b1();at[cy]=cA}else{if(cz==="page"||cz===3){bo[cy]=cA}else{if(cz==="event"){bN[cy]=cA}}}}},getCustomVariable:function(cy,cz){var cx;
+if(!z(cz)){cz="visit"}if(cz==="page"||cz===3){cx=bo[cy]}else{if(cz==="event"){cx=bN[cy]}else{if(cz==="visit"||cz===2){b1();cx=at[cy]}}}if(!z(cx)||(cx&&cx[0]==="")){return false}return cx},deleteCustomVariable:function(cx,cy){if(this.getCustomVariable(cx,cy)){this.setCustomVariable(cx,"","",cy)}},storeCustomVariablesInCookie:function(){bj=true},setLinkTrackingTimer:function(cx){bc=cx},setDownloadExtensions:function(cx){if(q(cx)){cx=cx.split("|")}cn=cx},addDownloadExtensions:function(cy){var cx;if(q(cy)){cy=cy.split("|")}for(cx=0;cx<cy.length;cx++){cn.push(cy[cx])}},removeDownloadExtensions:function(cz){var cy,cx=[];if(q(cz)){cz=cz.split("|")}for(cy=0;cy<cn.length;cy++){if(C(cz,cn[cy])===-1){cx.push(cn[cy])}}cn=cx},setDomains:function(cx){ae=q(cx)?[cx]:cx;var cz=false,cy;for(cy in ae){if(Object.prototype.hasOwnProperty.call(ae,cy)&&b3(ce,B(String(ae[cy])))){cz=true}}if(!cz){ae.push(ce)}},setIgnoreClasses:function(cx){a5=q(cx)?[cx]:cx},setRequestMethod:function(cx){cq=cx||bK},setRequestContentType:function(cx){bW=cx||am
+},setReferrerUrl:function(cx){aV=cx},setCustomUrl:function(cx){aG=bn(bg,cx)},setDocumentTitle:function(cx){aR=cx},setAPIUrl:function(cx){bb=cx},setDownloadClasses:function(cx){be=q(cx)?[cx]:cx},setLinkClasses:function(cx){aJ=q(cx)?[cx]:cx},setCampaignNameKey:function(cx){bS=q(cx)?[cx]:cx},setCampaignKeywordKey:function(cx){ba=q(cx)?[cx]:cx},discardHashTag:function(cx){bi=cx},setCookieNamePrefix:function(cx){aS=cx;at=bp()},setCookieDomain:function(cx){var cy=B(cx);if(a2(cy)){cg=cy;aQ()}},setCookiePath:function(cx){aX=cx;aQ()},setVisitorCookieTimeout:function(cx){b6=cx*1000},setSessionCookieTimeout:function(cx){bQ=cx*1000},setReferralCookieTimeout:function(cx){cm=cx*1000},setConversionAttributionFirstReferrer:function(cx){a1=cx},disableCookies:function(){aT=true;co.cookie="0";if(by){aj()}},deleteCookies:function(){aj()},setDoNotTrack:function(cy){var cx=f.doNotTrack||f.msDoNotTrack;ca=cy&&(cx==="yes"||cx==="1");if(ca){this.disableCookies()}},addListener:function(cy,cx){aa(cy,cx)},enableLinkTracking:function(cx){cp=true;
+bJ(function(){aN(function(){a7(cx)})})},enableJSErrorTracking:function(){if(cc){return}cc=true;var cx=J.onerror;J.onerror=function(cC,cA,cz,cB,cy){bJ(function(){var cD="JavaScript Errors";var cE=cA+":"+cz;if(cB){cE+=":"+cB}ad(cD,cE,cC)});if(cx){return cx(cC,cA,cz,cB,cy)}return false}},disablePerformanceTracking:function(){aE=false},setGenerationTimeMs:function(cx){bO=parseInt(cx,10)},enableHeartBeatTimer:function(cx){cx=Math.max(cx,1);aH=(cx||15)*1000;if(ch!==null){cv()}},killFrame:function(){if(J.location!==J.top.location){J.top.location=J.location}},redirectFile:function(cx){if(J.location.protocol==="file:"){J.location=cx}},setCountPreRendered:function(cx){aP=cx},trackGoal:function(cx,cz,cy){bJ(function(){cd(cx,cz,cy)})},trackLink:function(cy,cx,cA,cz){bJ(function(){ck(cy,cx,cA,cz)})},trackPageView:function(cx,cy){bC=[];if(D(by)){bJ(function(){P(ai,bb,by)})}else{bJ(function(){bs(cx,cy)})}},trackAllContentImpressions:function(){if(D(by)){return}bJ(function(){aN(function(){var cx=p.findContentNodes();
+var cy=bY(cx);cu(cy,bc)})})},trackVisibleContentImpressions:function(cx,cy){if(D(by)){return}if(!z(cx)){cx=true}if(!z(cy)){cy=750}av(cx,cy,this);bJ(function(){an(function(){var cz=p.findContentNodes();var cA=aK(cz);cu(cA,bc)})})},trackContentImpression:function(cz,cx,cy){if(D(by)){return}if(!cz){return}cx=cx||"Unknown";bJ(function(){var cA=ak(cz,cx,cy);a9(cA,bc)})},trackContentImpressionsWithinNode:function(cx){if(D(by)||!cx){return}bJ(function(){if(bH){an(function(){var cy=p.findContentNodesWithinNode(cx);var cz=aK(cy);cu(cz,bc)})}else{aN(function(){var cy=p.findContentNodesWithinNode(cx);var cz=bY(cy);cu(cz,bc)})}})},trackContentInteraction:function(cz,cA,cx,cy){if(D(by)){return}if(!cz||!cA){return}cx=cx||"Unknown";bJ(function(){var cB=ar(cz,cA,cx,cy);a9(cB,bc)})},trackContentInteractionNode:function(cy,cx){if(D(by)||!cy){return}bJ(function(){var cz=cs(cy,cx);a9(cz,bc)})},logAllContentBlocksOnPage:function(){var cy=p.findContentNodes();var cx=p.collectContent(cy);if(console!==undefined&&console&&console.log){console.log(cx)
+}},trackEvent:function(cy,cA,cx,cz,cB){bJ(function(){ad(cy,cA,cx,cz,cB)})},trackSiteSearch:function(cx,cz,cy,cA){bJ(function(){bB(cx,cz,cy,cA)})},setEcommerceView:function(cA,cx,cz,cy){if(!z(cz)||!cz.length){cz=""}else{if(cz instanceof Array){cz=JSON2.stringify(cz)}}bo[5]=["_pkc",cz];if(z(cy)&&String(cy).length){bo[2]=["_pkp",cy]}if((!z(cA)||!cA.length)&&(!z(cx)||!cx.length)){return}if(z(cA)&&cA.length){bo[3]=["_pks",cA]}if(!z(cx)||!cx.length){cx=""}bo[4]=["_pkn",cx]},addEcommerceItem:function(cB,cx,cz,cy,cA){if(cB.length){cj[cB]=[cB,cx,cz,cy,cA]}},trackEcommerceOrder:function(cx,cB,cA,cz,cy,cC){br(cx,cB,cA,cz,cy,cC)},trackEcommerceCartUpdate:function(cx){aZ(cx)}}}function y(){return{push:T}}function b(ad,ac){var ae={};var aa,ab;for(aa=0;aa<ac.length;aa++){var Y=ac[aa];ae[Y]=1;for(ab=0;ab<ad.length;ab++){if(ad[ab]&&ad[ab][0]){var Z=ad[ab][0];if(Y===Z){T(ad[ab]);delete ad[ab];if(ae[Z]>1){if(console!==undefined&&console&&console.error){console.error("The method "+Z+' is registered more than once in "paq" variable. Only the last call has an effect. Please have a look at the multiple Piwik trackers documentation: http://developer.piwik.org/guides/tracking-javascript-guide#multiple-piwik-trackers')
+}}ae[Z]++}}}}return ad}W(J,"beforeunload",U,false);Date.prototype.getTimeAlias=Date.prototype.getTime;O=new G();var u=["disableCookies","setTrackerUrl","setAPIUrl","setCookiePath","setCookieDomain","setDomains","setUserId","setSiteId","enableLinkTracking"];_paq=b(_paq,u);for(w=0;w<_paq.length;w++){if(_paq[w]){T(_paq[w])}}_paq=new y();d={addPlugin:function(Y,Z){a[Y]=Z},getTracker:function(Y,Z){if(!z(Z)){Z=this.getAsyncTracker().getSiteId()}if(!z(Y)){Y=this.getAsyncTracker().getTrackerUrl()}return new G(Y,Z)},getAsyncTracker:function(){return O}};if(typeof define==="function"&&define.amd){define("piwik",[],function(){return d})}return d}())}if(window&&window.piwikAsyncInit){window.piwikAsyncInit()}(function(){var a=(typeof AnalyticsTracker);if(a==="undefined"){AnalyticsTracker=window.Piwik}}());if(typeof piwik_log!=="function"){piwik_log=function(b,f,d,g){function a(h){try{if(window["piwik_"+h]){return window["piwik_"+h]}}catch(i){}return}var c,e=window.Piwik.getTracker(d,f);e.setDocumentTitle(b);
+e.setCustomData(g);c=a("tracker_pause");if(c){e.setLinkTrackingTimer(c)}c=a("download_extensions");if(c){e.setDownloadExtensions(c)}c=a("hosts_alias");if(c){e.setDomains(c)}c=a("ignore_classes");if(c){e.setIgnoreClasses(c)}e.trackPageView();if(a("install_tracker")){piwik_track=function(i,k,j,h){e.setSiteId(k);e.setTrackerUrl(j);e.trackLink(i,h)};e.enableLinkTracking()}};
+/*!! @license-end */
}; \ No newline at end of file
diff --git a/plugins/API/lang/fi.json b/plugins/API/lang/fi.json
index 22e886ce2c..27db066e77 100644
--- a/plugins/API/lang/fi.json
+++ b/plugins/API/lang/fi.json
@@ -4,8 +4,12 @@
"KeepTokenSecret": "Tämä token_auth on yhtä salainen kuin salasanasi, %1$s älä jaa sitä%2$s!",
"LoadedAPIs": "Ladattiin %s APIa",
"MoreInformation": "Lisätietoa Piwikin APIsta löytyy sivulta %1$sJohdatus Piwikin APIin%2$s ja %3$sPiwikin API%4$s.",
+ "PluginDescription": "Kaikki Piwikissä olevat tiedot on saatavilla yksinkertaisten APIen kautta. Tämä lisäosa on API verkkosivuille. Tämän lisäosan kautta voit ladata tiedot xml:nä, json:na, php:nä, csv:nä jne.",
+ "ReportingApiReference": "Raportointi-API:n referenssi",
"TopLinkTooltip": "Hae analytiikkatietoja automaattisesti yksinkertaisella API:lla JSON:lla, XML:llä jne.",
"UserAuthentication": "Käyttäjän autentikointi",
- "UsingTokenAuth": "Jos haluat %1$s hakea tietoja skriptillä, crontabista jne. %2$s sinun täytyy lisätä parametri %3$s API-kutsujen osoitteisiin, jos kutsu vaatii autentikoinnin."
+ "UsingTokenAuth": "Jos haluat %1$s hakea tietoja skriptillä, crontabista jne. %2$s sinun täytyy lisätä parametri %3$s API-kutsujen osoitteisiin, jos kutsu vaatii autentikoinnin.",
+ "Glossary": "Sanasto",
+ "LearnAboutCommonlyUsedTerms": "Opi lisää yleisistä termeistä Piwikissä: %1$s ja %2$s."
}
} \ No newline at end of file
diff --git a/plugins/API/lang/ru.json b/plugins/API/lang/ru.json
index fd5378fa78..b1f33d003e 100644
--- a/plugins/API/lang/ru.json
+++ b/plugins/API/lang/ru.json
@@ -5,8 +5,11 @@
"LoadedAPIs": "%s API успешно загружен",
"MoreInformation": "Чтобы узнать больше информации о Piwik API, пожалуйста, посмотрите раздел %1$s Introduction to Piwik API %2$s в %3$s Piwik API Reference %4$s.",
"PluginDescription": "Все данные из Piwik доступны через простые API. Этот плагин является входной точкой для веб сервиса, который можно вызвать чтобы получить данные веб аналитики в xml, json, php, csv и др.",
+ "ReportingApiReference": "Сообщение справочной информации по API",
"TopLinkTooltip": "Получайте доступ к вашей веб-аналитике с помощью простого API и использования json, xml и др.",
"UserAuthentication": "Аутентификация пользователя",
- "UsingTokenAuth": "Если вам необходимо %1$s запрашивать данные в ваших скриптах, cron-задачах, или другого источника, то вам %2$s необходимо добавить следующий ключ %3$s к URL API-вызова, который требует аутентификации."
+ "UsingTokenAuth": "Если вам необходимо %1$s запрашивать данные в ваших скриптах, cron-задачах, или другого источника, то вам %2$s необходимо добавить следующий ключ %3$s к URL API-вызова, который требует аутентификации.",
+ "Glossary": "Глоссарий",
+ "LearnAboutCommonlyUsedTerms": "Изучите часто используемые термины, чтобы извлечь максимум пользы из Piwik Analytics: %1$s and %2$s."
}
} \ No newline at end of file
diff --git a/plugins/Actions/lang/fi.json b/plugins/Actions/lang/fi.json
index cb7a0a31ca..26f23e5629 100644
--- a/plugins/Actions/lang/fi.json
+++ b/plugins/Actions/lang/fi.json
@@ -2,6 +2,7 @@
"Actions": {
"AvgGenerationTimeTooltip": "Keskiarvo %1$s osumasta %2$s %3$s - %4$s",
"ColumnClickedURL": "Klikattu URL",
+ "ColumnActionURL": "Toiminnon osoite",
"ColumnClicks": "Klikkaukset",
"ColumnClicksDocumentation": "Tämän linkin klikkausten määrä.",
"ColumnDownloadURL": "Ladattu URL",
@@ -39,6 +40,7 @@
"PagesReportDocumentation": "Tämä raportti sisältää tietoa sivuista, joilla on käyty. %s Taulukko on organisoitu hierarkisesti, URL:t näytetään puurakenteena.",
"PageTitlesReportDocumentation": "Tämä raportti sisältää tietoa käytyjen sivujen otsikoista. %1$s Sivun otsikko on HTML:n %2$s-tagi, jonka useimmat selaimet näyttävät ikkunan otsikossa.",
"PageUrls": "Sivujen URL:t",
+ "PluginDescription": "Raportoi sivukatselut ja sivujen otsikot. Mahdollistaa sivun sisäisen hakukoneen mittaamisen. Seuraa automaattisesti ulospäin suuntautuvia linkkejä ja latauksia.",
"SiteSearchCategories1": "Tämä raportti listaa kategoriat jotka kävijät valitsivat.",
"SiteSearchCategories2": "Esimerkiksi e-kauppojen sivuilla on tyypillisesti \"Kategoria\"-valitsin, jolla käyttäjät voivat rajoittaa hakutuloksia.",
"SiteSearchFollowingPagesDoc": "Kun kävijät hakevat sivuiltasi, he etsivät tiettyä sivua, sisältöä, tuotetta tai palvelua. Tämä raportti listaa sivut joita klikattiin useiten haun jälkeen.",
@@ -59,6 +61,7 @@
"WidgetPageUrlsFollowingSearch": "Verkkosivuhaun tuloksena löytyneet sivut",
"WidgetSearchCategories": "Haun kategoriat",
"WidgetSearchKeywords": "Sivuhaun hakusanat",
- "WidgetSearchNoResultKeywords": "Hakusanat ilman tuloksia"
+ "WidgetSearchNoResultKeywords": "Hakusanat ilman tuloksia",
+ "ActionType": "Toiminnon tyyppi"
}
} \ No newline at end of file
diff --git a/plugins/Actions/lang/ru.json b/plugins/Actions/lang/ru.json
index 04b3e49b5e..61d49c8364 100644
--- a/plugins/Actions/lang/ru.json
+++ b/plugins/Actions/lang/ru.json
@@ -2,6 +2,7 @@
"Actions": {
"AvgGenerationTimeTooltip": "В среднем по %1$s хит(ов) %2$s между %3$s и %4$s",
"ColumnClickedURL": "URL кликов",
+ "ColumnActionURL": "URL действия",
"ColumnClicks": "Клики",
"ColumnClicksDocumentation": "Количество кликов по этой ссылке.",
"ColumnDownloadURL": "Ссылка для загрузки",
@@ -60,6 +61,7 @@
"WidgetPageUrlsFollowingSearch": "Страницы, которые нашлись в поиске",
"WidgetSearchCategories": "Категории поиска",
"WidgetSearchKeywords": "Поисковые ключевые слова сайта",
- "WidgetSearchNoResultKeywords": "Поисковые ключевые слова без результатов"
+ "WidgetSearchNoResultKeywords": "Поисковые ключевые слова без результатов",
+ "ActionType": "Тип действия"
}
} \ No newline at end of file
diff --git a/plugins/Contents/lang/ru.json b/plugins/Contents/lang/ru.json
index b4d5864720..bddfd2799c 100644
--- a/plugins/Contents/lang/ru.json
+++ b/plugins/Contents/lang/ru.json
@@ -1,5 +1,6 @@
{
"Contents": {
+ "PluginDescription": "Отслеживание контента и баннеров позволяет вам измерять эффективность (просмотры, клики, CTR) любой части контента на ваших страницах (баннер-реклама, изображение, любой элемент).",
"Impressions": "Показы",
"Interactions": "Взаимодествия",
"Interaction": "Взаимодествие",
@@ -7,6 +8,9 @@
"ContentName": "Название публикации",
"ContentPiece": "Часть публикации",
"ContentTarget": "Цель публикации",
- "Contents": "Публикации"
+ "Contents": "Публикации",
+ "InteractionsMetricDocumentation": "Сколько раз с блоком контента происходило взаимодействие (например, 'клик' по баннеру или рекламе).",
+ "ImpressionsMetricDocumentation": "Сколько раз блок контента, такой как баннер или реклама, был показан на странице.",
+ "InteractionRateMetricDocumentation": "Соотношение представления контента и взаимодействий."
}
} \ No newline at end of file
diff --git a/plugins/CoreAdminHome/lang/ru.json b/plugins/CoreAdminHome/lang/ru.json
index 92b61015dc..905ccd69c0 100644
--- a/plugins/CoreAdminHome/lang/ru.json
+++ b/plugins/CoreAdminHome/lang/ru.json
@@ -1,8 +1,10 @@
{
"CoreAdminHome": {
+ "AddNewTrustedHost": "Добавить новый доверенный хост",
"Administration": "Администрирование",
"ArchivingSettings": "Настройка архивации",
"BrandingSettings": "Настройки логотипа",
+ "ReleaseChannel": "Канал выпуска",
"ClickHereToOptIn": "Кликните, чтобы вы учитывались в аналитике.",
"ClickHereToOptOut": "Кликните, чтобы отказаться от учета вас в аналитике.",
"CustomLogoFeedbackInfo": "Если вы используйете свой логотип, вам, возможно, также понадобится скрыть ссылку %1$s в верхнем меню. Для этого просто отключите плагин Feedback (обратная связь) на странице %2$sУправление плагинами%3$s.",
@@ -20,6 +22,9 @@
"InvalidPluginsWarning": "Следующие плагины не совместимы с %1$s и не могут быть загружены: %2$s.",
"InvalidPluginsYouCanUninstall": "Вы можете обновить или удалить эти плагины на странице %1$sУправления плагинами%2$s.",
"JavaScriptTracking": "JavaScript-отслеживание",
+ "JSTracking_CampaignKwdParam": "Параметр Ключевого слова кампании",
+ "JSTracking_CampaignNameParam": "Параметр Имени кампании",
+ "JSTracking_CodeNoteBeforeClosingHead": "Удостоверьтесь, что этот код находится на каждой странице вашего вебсайта. Мы рекомендуем вставлять его сразу перед закрытием тега %1$s.",
"JSTracking_CustomCampaignQueryParam": "Использовать пользовательские имена параметров в запросе для названия кампании и ключевого слова",
"JSTracking_CustomCampaignQueryParamDesc": "Примечание: %1$sPiwik автоматически определит параметры Google Analytics.%2$s",
"JSTracking_DisableCookies": "Отключить все отслеживания cookies",
@@ -44,6 +49,7 @@
"JSTrackingIntro5": "Если вы хотите больше, чем простое отслеживание страниц, пожалуйста, ознакомьтесь с %1$sPiwik Javascript Tracking documentation%2$s для просмотра всех функций. С помощью этих функций вы можете отслеживать цели, пользовательские переменные, заказы электронной коммерции, неоформленные заказы и многое другое.",
"LogoNotWriteableInstruction": "Чтобы использовать собственное лого вместо стандартного Piwik, откройте для записи эту папку: %1$s Piwik нужен доступ на запись к вашим лого, храняшимся в файлах %2$s.",
"FileUploadDisabled": "Загрузка файлов не включена в вашей конфигурации PHP. Для загрузки другого логотипа выставите %s в php.ini и перезапустите веб-сервер.",
+ "LogoUploadFailed": "Загруженный файл не может быть обработан. Пожалуйста, проверьте, что файл имеет нужный формат.",
"LogoUpload": "Выберите лого для загрузки",
"FaviconUpload": "Выбрать Favicon для загрузки",
"LogoUploadHelp": "Пожалуйста, закачивайте файлы в %1$s форматах, минимальное ограничение по высоте – %2$s пикселей.",
@@ -53,6 +59,7 @@
"MenuDevelopment": "Разработка",
"OptOutComplete": "Исключение из политики конфиденциальности завершено; ваши посещения на данный сайт не будут учитываться системой веб аналитики. Мы уважаем ваш выбор.",
"OptOutCompleteBis": "Заметьте, что если вы очистите cookies браузера, то, скорее всего, удалится и исключительный cookie, или если вы поменяете компьютер или браузер, то необходимо будет пройти процедуру исключения снова.",
+ "OptOutDntFound": "Ваши действия не отслеживались, так как ваш браузер сообщает, что вы не хотите этого. Это настройка вашего браузера, поэтому у вас не будет возможности включить ее до тех пор, пока вы не отключите опцию \"Не отслеживать\".",
"OptOutExplanation": "Piwik – за сохранение личных данных в сети. Поэтому данная система может предложить вашим пользователям выбор исключения из политики конфиденциальности (отказ от дальнейшего сбора статистики о пользователе). Вы можете вставить следующий HTML-код на одну из ваших страниц сайта, например на страницу о гарантиях конфиденциальности.",
"OptOutExplanationBis": "Тег покаже \"iframe\", в якому міститиметься посилання для ваших відвідувачів, клацнувши на яке, вони зможуть відмовитися від потрапляння в веб-аналітику через отримання відповідного файлу cookie. %1$s Клацніть тут%2$s, щоб переглянути вміст що буде показано в \"iframe\".",
"OptOutForYourVisitors": "Исключение из политики конфиденциальности Piwik для посетителей",
@@ -67,6 +74,7 @@
"SendPluginUpdateCommunication": "Отправить email с уведомлением, когда для плагина будет доступна новая версия",
"SendPluginUpdateCommunicationHelp": "Письмо будет отправлено суперпользователю когда будет доступна новая версия плагина.",
"StableReleases": "Если Piwik является важной частью вашего бизнеса, мы рекомендуем использовать последнюю стабильную версию. Если вы используете последнюю бета версию, и вы нашли ошибку или есть предложение, пожалуйста, %1$sперейдите по ссылке%2$s.",
+ "LtsReleases": "Версии LTS (Долгосрочная поддержка) получают только исправления, касающиеся безопасности и ошибок.",
"SystemPluginSettings": "Системные настройки плагинов",
"TrackAGoal": "Отслеживать цель",
"TrackingCode": "Код отслеживания",
@@ -79,6 +87,9 @@
"YouAreOptedIn": "Статистика о вас собирается.",
"YouAreOptedOut": "Вы отказались от сбора статистических данных.",
"YouMayOptOut": "Вы можете отказаться от уникального cookie, привязанному к вашему браузеру, и идентифицирующего вас в системе аналитики данного сайта, тем самым отказавшись от любого сбора сведений о вас и их анализа на данном сайте.",
- "YouMayOptOutBis": "Снимите галочку и получите исключающий cookie для отказа сбора данных."
+ "YouMayOptOutBis": "Снимите галочку и получите исключающий cookie для отказа сбора данных.",
+ "OptingYouOut": "Отписываем вас, пожалуйста, подождите...",
+ "ProtocolNotDetectedCorrectly": "В данный момент вы просматриваете Piwik через безопасное соединение SSL (используя https), но Piwic смог обнаружить только небезопасное соединение на сервере.",
+ "ProtocolNotDetectedCorrectlySolution": "Чтобы удостовериться, что Piwic безопасно запрашивает и обрабатывает ваш контент через HTTPS, вы можете отредактировать свой файл %1$s или настроить ваши настройки прокси, или вы можете добавить линию %2$s под разделом %3$s. %4$sУзнать больше%5$s"
}
} \ No newline at end of file
diff --git a/plugins/CoreAdminHome/templates/trackingCodeGenerator.twig b/plugins/CoreAdminHome/templates/trackingCodeGenerator.twig
index 787ff4aba7..1011afa8cb 100644
--- a/plugins/CoreAdminHome/templates/trackingCodeGenerator.twig
+++ b/plugins/CoreAdminHome/templates/trackingCodeGenerator.twig
@@ -50,6 +50,7 @@
<div class="form-group">
<div class="form-help">
{{ 'CoreAdminHome_JSTracking_MergeSubdomainsDesc'|translate("x.<span class='current-site-host'>"~defaultReportSiteDomain~"</span>","y.<span class='current-site-host'>"~defaultReportSiteDomain~"</span>")|raw }}
+ {{ 'General_LearnMore'|translate(' (<a href="http://developer.piwik.org/guides/tracking-javascript-guide#measuring-domains-andor-sub-domains" rel="noreferrer" target="_blank">', '</a>)')|raw }}
</div>
<label class="checkbox">
<input type="checkbox" id="javascript-tracking-all-subdomains"/>
diff --git a/plugins/CoreHome/Columns/VisitorReturning.php b/plugins/CoreHome/Columns/VisitorReturning.php
index fc0ca345a7..3a7268052e 100644
--- a/plugins/CoreHome/Columns/VisitorReturning.php
+++ b/plugins/CoreHome/Columns/VisitorReturning.php
@@ -49,8 +49,6 @@ class VisitorReturning extends VisitDimension
*/
public function onNewVisit(Request $request, Visitor $visitor, $action)
{
- $visitCount = $request->getVisitCount();
- $daysSinceLastVisit = $request->getDaysSinceLastVisit();
$daysSinceLastOrder = $request->getDaysSinceLastOrder();
$isReturningCustomer = ($daysSinceLastOrder !== false);
@@ -59,7 +57,11 @@ class VisitorReturning extends VisitDimension
return self::IS_RETURNING_CUSTOMER;
}
- if ($visitCount > 1 || $visitor->isVisitorKnown() || $daysSinceLastVisit > 0) {
+ $visitCount = $request->getVisitCount();
+ $daysSinceFirstVisit = $request->getDaysSinceFirstVisit();
+ $daysSinceLastVisit = $request->getDaysSinceLastVisit();
+
+ if ($visitCount > 1 || $visitor->isVisitorKnown() || $daysSinceFirstVisit > 0 || $daysSinceLastVisit > 0) {
return self::IS_RETURNING;
}
diff --git a/plugins/CoreHome/angularjs/common/services/piwik-api.js b/plugins/CoreHome/angularjs/common/services/piwik-api.js
index 8bb14808c5..5257aff0c9 100644
--- a/plugins/CoreHome/angularjs/common/services/piwik-api.js
+++ b/plugins/CoreHome/angularjs/common/services/piwik-api.js
@@ -53,7 +53,7 @@ var hasBlockedContent = false;
}
function isErrorResponse(response) {
- return response && response.result == 'error';
+ return response && angular.isObject(response) && response.result == 'error';
}
function createResponseErrorNotification(response, options) {
diff --git a/plugins/CoreHome/angularjs/siteselector/siteselector.directive.less b/plugins/CoreHome/angularjs/siteselector/siteselector.directive.less
index b6e4c3d676..78dd32a862 100644
--- a/plugins/CoreHome/angularjs/siteselector/siteselector.directive.less
+++ b/plugins/CoreHome/angularjs/siteselector/siteselector.directive.less
@@ -22,7 +22,7 @@
> .siteSelector {
position: absolute;
- z-index: 9999;
+ z-index: 999;
}
a.title {
diff --git a/plugins/CoreHome/lang/fi.json b/plugins/CoreHome/lang/fi.json
index 382429907e..401eb9fdfc 100644
--- a/plugins/CoreHome/lang/fi.json
+++ b/plugins/CoreHome/lang/fi.json
@@ -3,6 +3,7 @@
"CategoryNoData": "Tässä kategoriassa ei ole tietoja. Kokeile linkkiä \"Kaikki esiintymät\".",
"CheckForUpdates": "Tarkista päivitykset",
"CheckPiwikOut": "Tutustu Piwikiin!",
+ "ClickToEditX": "Muokkaa %s klikkaamalla",
"CloseWidgetDirections": "Voit sulkea tämän widget-käyttöliittymän klikkaamalla \"X\"-ikonia käyttöliittymän yläreunassa.",
"DataForThisReportHasBeenPurged": "Tämän raportin data on yli %s kuukautta vanhaa ja on poistettu.",
"DataTableExcludeAggregateRows": "Yhdistetyt rivit ovat näkyvillä %s Piilota",
@@ -23,8 +24,10 @@
"InjectedHostSuperUserWarning": "Piwik saattaa olla väärin asennettu (esim. jos Piwik on hiljattain siirretty uuteen serveriin tai URL:ään). Voit joko %1$sklikata tästä ja lisätä %2$s ja lisätä päteväksi Piwik isäntänimeksi (jos luotat siihen)%3$s, tai %4$sklikata tästä ja %5$s siirtyäksesi Piwikiin turvallisesti%6$s.",
"InjectedHostWarningIntro": "Käytät Piwikiä osoitteesta %1$s, mutta Piwik on konfiguroitu ajettavaksi tässä osoitteessa: %2$s.",
"JavascriptDisabled": "JavaScriptin täytyy olla käytössä normaalinäkymässä.<br \/>JavaScript ei ole päällä tai ei ole tuettu selaimessasi.<br \/>Ota JavaScript käyttöön selaimesi asetuksista ja %1$syritä uudelleen%2$s.<br\/>",
+ "MainNavigation": "Päänavigointi",
"MakeADifference": "Ole mukana vaikuttamassa: %1$sTee lahjoitus%2$s Piwik 2.0 version rahoittamiseksi!",
"MakeOneTimeDonation": "Lahjoita kertasumma.",
+ "Menu": "Valikko",
"NoPrivilegesAskPiwikAdmin": "Olet kirjautuneena sisään käyttäjänä '%1$s', mutta sinulla ei ole mitään oikeuksia Piwikissä. %2$sPyydä Piwikin ylläpitäjää (klikkaa avataksesi sähköpostin)%3$s antamaan katseluoikeudet verkkosivuun.",
"OnlyForSuperUserAccess": "Tämä widget näkyy ainoastaan käyttäjille, joilla on Superkäyttäjän oikeudet.",
"PageOf": "%1$s of %2$s",
@@ -35,6 +38,7 @@
"SharePiwikShort": "Piwik! Ilmainen ja avoimen lähdekoodin verkkoanalyysi. Hallitse omaa dataasi.",
"ShareThis": "Jaa tämä",
"ShowJSCode": "Näytä lisättävä Javascript-koodi",
+ "SkipToContent": "Siirry sisältöön",
"SubscribeAndBecomePiwikSupporter": "Jatka turvalliselle luottokorttimaksusivulle (Paypal) ryhtyäksesi Piwikin tukijaksi!",
"SupportPiwik": "Tue Piwikiä!",
"TableNoData": "Ei tietoja tässä taulukossa",
@@ -45,6 +49,11 @@
"YouAreUsingTheLatestVersion": "Käytössäsi on uusin versio Piwikistä!",
"ClickRowToExpandOrContract": "Klikkaa tätä riviä avataksesi tai sulkeaksesi alataulukon.",
"UndoPivotBySubtable": "Tämä raportti on käännetty %s:llä. Kumoa kääntö",
- "PivotBySubtable": "Tämä raportti ei ole käännetty %1$s:n mukaan. Käännetty %2$s:llä."
+ "PivotBySubtable": "Tämä raportti ei ole käännetty %1$s:n mukaan. Käännetty %2$s:llä.",
+ "QuickAccessTitle": "Hae %s:llä. Käytä nuolia navigointiin. Oikotie: haku aukeaa painamalla f-näppäintä.",
+ "MenuEntries": "Valikon sisältö",
+ "Segments": "Segmentit",
+ "AdblockIsMaybeUsed": "Jos käytät mainostenestoa (ad blocker), poista se käytöstä tällä sivulla, jotta Piwik toimii ongelmitta.",
+ "ChangeCurrentWebsite": "Valitse verkkosivu, nyt valittuna %s"
}
} \ No newline at end of file
diff --git a/plugins/CoreHome/lang/ko.json b/plugins/CoreHome/lang/ko.json
index 53f815c4cc..1288435bf2 100644
--- a/plugins/CoreHome/lang/ko.json
+++ b/plugins/CoreHome/lang/ko.json
@@ -49,6 +49,7 @@
"ClickRowToExpandOrContract": "하위 테이블의 행을 확장하거나 축소하기 위해 클릭하세요.",
"UndoPivotBySubtable": "이 보고서는 %s Undo pivot에 의해 결정되었습니다.",
"PivotBySubtable": "이 보고서는 %1$s Pivot이 %2$s에 의해 결정되지 않았습니다.",
+ "QuickAccessTitle": "%s 검색. 검색 결과를 확인할 때 방향키를 사용하세요. 단축키: 'f'는 검색",
"MenuEntries": "메뉴",
"Segments": "세그멘트",
"AdblockIsMaybeUsed": "Piwik가 문제 없이 동작하기 위해서 광고 차단기능이 있는 플러그인을 꺼주시길 바랍니다.",
diff --git a/plugins/CoreHome/lang/ru.json b/plugins/CoreHome/lang/ru.json
index 4b7d9f0549..7fdd19b854 100644
--- a/plugins/CoreHome/lang/ru.json
+++ b/plugins/CoreHome/lang/ru.json
@@ -24,6 +24,7 @@
"InjectedHostSuperUserWarning": "Piwik может быть неправильно сконфигурирован (например, если Piwik был недавно перемещен на новый сервер или переехал на новый адрес). Вы также можете %1$sнажать сюда и добавить %2$s в качестве доверенного имени хоста Piwik (если вы доверяете ему)%3$s, или %4$sнажмите сюда и перейдите %5$s для безопасного доступа к Piwik%6$s.",
"InjectedHostWarningIntro": "Сейчас вы заходите в Piwik на %1$s, но Piwik был настроен на этом адресе: %2$s.",
"JavascriptDisabled": "JavaScript должен быть разрешен для корректного стандартного отображения Piwik.<br \/>Если Вы читаете это сообщение, значит JavaScript запрещен, либо не поддерживается вашим браузером.<br \/>Для использования стандартного вида, разрешите JavaScript в настройках вашего браузера, потом %1$sпопробуйте обновить страницу%2$s.<br \/>",
+ "MainNavigation": "Основная навигация",
"MakeADifference": "Внесите свой вклад: %1$sПожертвуйте сейчас%2$s для финансирования Piwik 2.0!",
"MakeOneTimeDonation": "Сделать только пожертвование (без подписки).",
"Menu": "Меню",
@@ -46,6 +47,11 @@
"ViewAllPiwikVideoTutorials": "Просмотреть все обучающие ролики про Piwik",
"WebAnalyticsReports": "Отчеты веб аналитики",
"YouAreUsingTheLatestVersion": "У вас последняя версия Piwik!",
- "ClickRowToExpandOrContract": "Нажмите на эту строку, чтобы растянуть или сжать подтаблицу."
+ "ClickRowToExpandOrContract": "Нажмите на эту строку, чтобы растянуть или сжать подтаблицу.",
+ "QuickAccessTitle": "Поиск %s. Используйте клавиши со стрелками для переходов в пределах результатов поиска. Быстрый доступ: нажмите 'f' для поиска.",
+ "MenuEntries": "Пункты меню",
+ "Segments": "Сегменты",
+ "AdblockIsMaybeUsed": "В случае, если вы используете блокировщик рекламы, пожалуйста, отключите его, чтобы убедиться, что Piwik работает без проблем.",
+ "ChangeCurrentWebsite": "Выбор вебсайта, сейчас выбран вебсайт: %s"
}
} \ No newline at end of file
diff --git a/plugins/CoreHome/stylesheets/dataTable/_reportDocumentation.less b/plugins/CoreHome/stylesheets/dataTable/_reportDocumentation.less
index 117fcf8716..6d071025f9 100644
--- a/plugins/CoreHome/stylesheets/dataTable/_reportDocumentation.less
+++ b/plugins/CoreHome/stylesheets/dataTable/_reportDocumentation.less
@@ -10,7 +10,7 @@ table.dataTable th .columnDocumentation {
border: 1px solid #e4e5e4;
padding: 5px 10px 6px 10px;
border-radius: 4px;
- z-index: 125;
+ z-index: 150;
position: absolute;
box-shadow: 0 0 4px #e4e5e4;
cursor: default;
diff --git a/plugins/CoreHome/templates/_dataTableCell.twig b/plugins/CoreHome/templates/_dataTableCell.twig
index 1bcd1bb0f2..3a54c3fac0 100644
--- a/plugins/CoreHome/templates/_dataTableCell.twig
+++ b/plugins/CoreHome/templates/_dataTableCell.twig
@@ -2,9 +2,12 @@
{% set tooltipIndex = column ~ '_tooltip' %}
{% if row.getMetadata(tooltipIndex) %}<span class="cell-tooltip" data-tooltip="{{ row.getMetadata(tooltipIndex) }}">{% endif %}
{% if not row.getIdSubDataTable() and column=='label' and row.getMetadata('url') %}
- <a rel="noreferrer" target="_blank" href='{% if row.getMetadata('url')|slice(0,4) not in ['http','ftp:'] %}http://{% endif %}{{ row.getMetadata('url')|rawSafeDecoded }}'>
+ <a rel="noreferrer"
+ target="_blank"
+ href='{% if row.getMetadata('url')|slice(0,4) not in ['http','ftp:'] %}http://{% endif %}{{ row.getMetadata('url')|rawSafeDecoded }}'>
{% if not row.getMetadata('logo') %}
- <img class="link" width="10" height="9" src="plugins/Morpheus/images/link.gif"/>
+ <img class="link" width="10" height="9"
+ src="plugins/Morpheus/images/link.gif"/>
{% endif %}
{% endif %}
@@ -19,7 +22,7 @@
{% endif %}
{% set rowPercentage = row.getColumn(column)|percentage(reportTotal, 1) %}
{% set metricTitle = translations[column]|default(column) %}
- {% set reportLabel = row.getColumn(labelColumn)|truncate(40)|raw %}
+ {% set reportLabel = row.getColumn(labelColumn)|truncate(40)|rawSafeDecoded %}
{% set reportRatioTooltip = 'General_ReportRatioTooltip'|translate(reportLabel, rowPercentage|e('html_attr'), reportTotal|e('html_attr'), metricTitle|e('html_attr'), translations[labelColumn]|default(labelColumn)|e('html_attr')) %}
@@ -30,7 +33,9 @@
{% set totalRatioTooltip = '' %}
{% endif %}
- <span class="ratio" title="{{ reportRatioTooltip|raw }} {{ totalRatioTooltip|e('html_attr') }}">&nbsp;{{ rowPercentage }}</span>
+ <span class="ratio"
+ title="{{ reportRatioTooltip|raw }} {{ totalRatioTooltip|e('html_attr') }}"
+ >&nbsp;{{ rowPercentage }}</span>
{%- endif %}
{% if column=='label' %}
@@ -42,7 +47,7 @@
{% if row.getMetadata('html_label_prefix') %}<span class='label-prefix'>{{ row.getMetadata('html_label_prefix') | raw }}&nbsp;</span>{% endif -%}
{%- if row.getMetadata('html_label_suffix') %}<span class='label-suffix'>{{ row.getMetadata('html_label_suffix') | raw }}</span>{% endif -%}
{% endif %}<span class="value">
- {%- if row.getColumn(column) %}{% if column=='label' %}{{- row.getColumn(column)|raw -}}{% else %}{{- row.getColumn(column)|number(2,0)|raw -}}{% endif %}
+ {%- if row.getColumn(column) or (column=='label' and row.getColumn(column) is same as("0")) %}{% if column=='label' %}{{- row.getColumn(column)|rawSafeDecoded -}}{% else %}{{- row.getColumn(column)|number(2,0)|raw -}}{% endif %}
{%- else -%}-
{%- endif -%}</span>
{% if column=='label' %}</span>{% endif %}
diff --git a/plugins/CorePluginsAdmin/lang/ru.json b/plugins/CorePluginsAdmin/lang/ru.json
index 0aa82140b2..405c87ac6f 100644
--- a/plugins/CorePluginsAdmin/lang/ru.json
+++ b/plugins/CorePluginsAdmin/lang/ru.json
@@ -14,12 +14,16 @@
"BackToExtendPiwik": "Вернуться к Marketplace",
"BeCarefulUsingPlugins": "Плагины, которые разработаны не командой Piwik должны использоваться с осторожностью: мы не просматриваем их.",
"BeCarefulUsingThemes": "Темы, которые разработаны не командой Piwik должны использоваться с осторожностью: мы не просматриваем их.",
+ "ByXDevelopers": "разработчиками %s",
+ "CannotInstall": "Невозможно установить (помощь)",
"Changelog": "История изменений",
"ChangeSettingsPossible": "Вы можете %1$sизменить настройки%2$s для этого плагина.",
"CorePluginTooltip": "Основные плагины не имеют версию, так как они распространяются с Piwik.",
"Deactivate": "Деактивировать",
"Developer": "Разработчик",
+ "DevelopersLearnHowToDevelopPlugins": "Разработчикам: Изучите, как вы можете расширить и настроить Piwik при помощи плагинов для %1$sразработки или тем%2$s.",
"DoMoreContactPiwikAdmins": "Для установки нового плагина или новой темы, пожалуйста свяжитесь с вашим Piwik-администратором",
+ "EmailToEnquireUpdatedVersion": "Пожалуйста, напишите на электронную почту %1$s и запросите обновленную версию %2$s.",
"FeaturedPlugin": "Набирающий популярность плагин",
"ChangeLookByManageThemes": "Вы можете изменить внешний вид Piwik: %1$sВыбор Темы%2$s.",
"GetEarlyAccessForPaidPlugins": "Примечание: в настоящее время все плагины доступны бесплатно, в будущем мы включим платные плагины на Marketplace (%1$sсвяжитесь с нами%2$s для раннего доступа).",
@@ -31,8 +35,13 @@
"InstallingPlugin": "Установка %s",
"InstallNewPlugins": "Установить новые плагины",
"InstallNewThemes": "Установить новые темы",
+ "LastCommitTime": "(последний коммит %s)",
"LastUpdated": "Последнее обновление",
"LicenseHomepage": "Дом. страница лицензии",
+ "LikeThisPlugin": "Нравится этот плагин?",
+ "ConsiderDonating": "Рассмотреть возможность пожертвования",
+ "CommunityContributedPlugin": "Это плагин, сделанный при содействии сообщества, доставленный к вам бесплатно.",
+ "ConsiderDonatingCreatorOf": "Пожалуйста, рассмотрите возможность пожертвования автору %s",
"PluginsExtendPiwik": "Плагины расширяют функциональность Piwik.",
"OncePluginIsInstalledYouMayActivateHere": "После установки плагина Вы можете активировать или деактивировать его здесь.",
"Marketplace": "Marketplace",
@@ -40,8 +49,10 @@
"MenuPlatform": "Платформа",
"MissingRequirementsNotice": "Пожалуйста, обновите %1$s %2$s до более новой версии, необходима версия %1$s %3$s.",
"MissingRequirementsPleaseInstallNotice": "Пожалуйста, установите %1$s %2$s т. к. оно требуется для %3$s.",
+ "NewVersion": "новая версия",
"NoPluginsFound": "Плагины не найдены",
"NotAllowedToBrowseMarketplacePlugins": "Можете посмотреть список плагинов, которые могут быть установлены для подстройки или расширения вашей платформы Piwik. Свяжитесь с администратором если вам потребуется установить один из них.",
+ "NotAllowedToBrowseMarketplaceThemes": "Вы можете посмотреть список тем, которые могут быть установлены для настройки внешнего вида платформы Piwik. Пожалуйста, свяжите с вашим администратором, чтобы установить любой из них.",
"NoThemesFound": "Темы не найдены",
"NoZipFileSelected": "Выберете ZIP файл",
"NumDownloadsLatestVersion": "Последняя версия скачена: %s раз",
diff --git a/plugins/CoreUpdater/lang/fi.json b/plugins/CoreUpdater/lang/fi.json
index 87b362e1e2..28915e6f2f 100644
--- a/plugins/CoreUpdater/lang/fi.json
+++ b/plugins/CoreUpdater/lang/fi.json
@@ -25,6 +25,11 @@
"HighTrafficPiwikServerEnableMaintenance": "Jos Piwik-palvelimellasi on suuria määriä liikennettä, suosittelemme %1$spoistamaan käyttäjäseurannan hetkellisesti käytöstä ja laittamaan Piwikin käyttäjäliittymän huoltotilaan%2$s.",
"IncompatbilePluginsWillBeDisabledInfo": "Huom. Osa lisäosista ei ole yhteensopivia Piwikin kanssa: %s. Nämä poistetaan käytöstä kun päivität:",
"InstallingTheLatestVersion": "Asennetaan uusinta versiota",
+ "LatestBetaRelease": "Viimeisin beta-julkaisu",
+ "LatestStableRelease": "Viimeisin vakaa julkaisu",
+ "Latest2XStableRelease": "Viimeisin vakaa 2.X",
+ "Latest2XBetaRelease": "Viimeisin beta 2.X",
+ "LtsSupportVersion": "Pitkään tuettu versio",
"MajorUpdateWarning1": "Tämä on iso päivitys! Päivityksessä kestää kauemmin kuin normaalisti.",
"MajorUpdateWarning2": "Seuraavat ohjeet ovat erityisen tärkeitä suurille asennuksille.",
"NoteForLargePiwikInstances": "Tärkeä tiedotus suurille Piwikin asennuksille",
@@ -48,6 +53,8 @@
"UpdateHasBeenCancelledExplanation": "Piwikin yhden klikkauksen päivitys on peruutettu. Jos et voi korjata alla olevaa virhettä, on suositeltavaa päivittää Piwik manuaalisesti. %1$s Ole hyvä ja tarkista %2$sPäivitysdokumentaatio%3$s",
"UpdateTitle": "Piwik › Päivitys",
"UpdateSuccessTitle": "Piwik on päivitetty onnistuneesti!",
+ "UpdateErrorTitle": "Päivitysvirhe",
+ "Updating": "Päivitetään",
"UpgradeComplete": "Päivitys valmis!",
"UpgradePiwik": "Päivitä Piwik",
"VerifyingUnpackedFiles": "Tarkistetaan purettuja tiedostoja",
@@ -56,6 +63,7 @@
"YouCanUpgradeAutomaticallyOrDownloadPackage": "Voit päivittää versioon %s automaattisesti tai ladata paketin ja asentaa sen manuaalisesti:",
"YouCouldManuallyExecuteSqlQueries": "Jos et voi käyttää komentorivin päivitysohjelmaa ja Piwikin päivitys epäonnistuu (aikakatkaisu tai jokin muu virhe), voit ajaa SQL-kyselyt itse.",
"YouMustDownloadPackageOrFixPermissions": "Piwik ei voi ylikirjoittaa nykyistä asennusta. Voit joko korjata hakemistojen\/tiedostojen oikeudet tai ladata paketin ja asentaa version %s itse:",
- "YourDatabaseIsOutOfDate": "Piwikin tietokanta on vanhentunut ja se tulee päivittää ennen jatkamista."
+ "YourDatabaseIsOutOfDate": "Piwikin tietokanta on vanhentunut ja se tulee päivittää ennen jatkamista.",
+ "ViewVersionChangelog": "katso muutostiedot tälle versiolle:"
}
} \ No newline at end of file
diff --git a/plugins/CoreUpdater/lang/ru.json b/plugins/CoreUpdater/lang/ru.json
index 30c9ab8e11..768fc2b8bc 100644
--- a/plugins/CoreUpdater/lang/ru.json
+++ b/plugins/CoreUpdater/lang/ru.json
@@ -22,8 +22,14 @@
"HelpMessageContent": "Проверьте %1$s Piwik FAQ %2$s, в котором объясняется большинство известных ошибок, которые могут случится во время обновления. %3$s Обратитесь к системному администратору – он может помочь Вам с решением проблемы на сервере или с настройками MySQL.",
"HelpMessageIntroductionWhenError": "Выше подается код ошибки ядра системы. Он поможет Вам объяснить причину ошибки, но если же Вам необходима дополнительная помощь, пожалуйста:",
"HelpMessageIntroductionWhenWarning": "Обновление завершено успешно, однако в процессе возникло несколько предупреждений. Пожалуйста, прочтите примечания ниже. Для дополнительной помощи:",
+ "HighTrafficPiwikServerEnableMaintenance": "Если вы управляете сервером Piwik с большим объемом трафика, мы рекомендуем %1$sна мгновение выключить Отслеживание посетителей и переключить Пользовательский интерфейс Piwik в режим%2$s поддержки.",
"IncompatbilePluginsWillBeDisabledInfo": "Примечание: некоторые плагины не совместимы с Piwik %s. Они будут отключены при обновлении:",
"InstallingTheLatestVersion": "Установка последней версии",
+ "LatestBetaRelease": "Последний тестовый выпуск",
+ "LatestStableRelease": "Последний стабильный выпуск",
+ "Latest2XStableRelease": "Последний стабильный 2.X",
+ "Latest2XBetaRelease": "Последний тестовый 2.X",
+ "LtsSupportVersion": "Версия Долгосрочной поддержки",
"MajorUpdateWarning1": "Это большое обновление! Может потребоваться больше времени, чем обычно.",
"MajorUpdateWarning2": "Следующий совет особенно важен для больших обновлений!",
"NoteForLargePiwikInstances": "Важное замечание для больших инсталляций Piwik",
@@ -55,6 +61,8 @@
"CloudHosting": "Облачный хостинг",
"Updating": "Обновление",
"UpdateUsingHttpsFailed": "Не удалось скачать последнюю версию Piwik по безопасному HTTPS, возникла следующая ошибка:",
+ "UpdateUsingHttpsFailedHelp": "Почему это не удалось? Загрузка последней версии Piwik (через безопасное HTTPS соединение) может потерпеть неудачу по разным причинам, например, из-за ошибки соединения, медленной скорости соединения или неправильной настройки системы. Обратите внимание, что это также может означать, что ваш сервер подвергается атаке MITM, и кто-то пытается заменить обновление на вредоносную версию Piwik.",
+ "UpdateUsingHttpsFailedHelpWhatToDo": "Рекомендуется повторить попытку загрузки, используя безопасное соединение HTTPS, так как оно предотвращает атаки MITM.",
"UsingHttps": "используется защищенное HTTPS-соединение (рекомендуется)",
"UsingHttp": "используется незащищенное HTTP-соединение",
"UpgradeComplete": "Обновление завершено!",
diff --git a/plugins/CoreVisualizations/CoreVisualizations.php b/plugins/CoreVisualizations/CoreVisualizations.php
index 9a5f88e7ec..0aec35fb3e 100644
--- a/plugins/CoreVisualizations/CoreVisualizations.php
+++ b/plugins/CoreVisualizations/CoreVisualizations.php
@@ -29,8 +29,7 @@ class CoreVisualizations extends \Piwik\Plugin
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
- 'UsersManager.deleteUser' => 'deleteUser',
- 'ViewDataTable.addViewDataTable' => 'addViewDataTable'
+ 'UsersManager.deleteUser' => 'deleteUser'
);
}
@@ -39,23 +38,6 @@ class CoreVisualizations extends \Piwik\Plugin
ViewDataTableManager::clearUserViewDataTableParameters($userLogin);
}
- public function addViewDataTable(&$viewDataTable)
- {
- // Both are the same HtmlTable, just the Pivot one has some extra logic in case Pivot is used.
- // We don't want to use the same HtmlTable twice in the UI. Therefore we always need to remove one.
- if (Common::getRequestVar('pivotBy', '')) {
- $tableToRemove = 'Visualizations\HtmlTable';
- } else {
- $tableToRemove = 'HtmlTable\PivotBy';
- }
-
- foreach ($viewDataTable as $index => $table) {
- if (Common::stringEndsWith($table, $tableToRemove)) {
- unset($viewDataTable[$index]);
- }
- }
- }
-
public function getStylesheetFiles(&$stylesheets)
{
$stylesheets[] = "plugins/CoreVisualizations/stylesheets/dataTableVisualizations.less";
diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable.php b/plugins/CoreVisualizations/Visualizations/HtmlTable.php
index 66cb4c26e9..dff8aa3e7a 100644
--- a/plugins/CoreVisualizations/Visualizations/HtmlTable.php
+++ b/plugins/CoreVisualizations/Visualizations/HtmlTable.php
@@ -70,6 +70,25 @@ class HtmlTable extends Visualization
$dataTable = $request->process();
$this->assignTemplateVar('siteSummary', $dataTable);
}
+
+ if ($this->isPivoted()) {
+ $this->config->columns_to_display = $this->dataTable->getColumns();
+ }
+ }
+
+ public function beforeGenericFiltersAreAppliedToLoadedDataTable()
+ {
+ if ($this->isPivoted()) {
+ $this->config->columns_to_display = $this->dataTable->getColumns();
+
+ $this->dataTable->applyQueuedFilters();
+ }
+
+ parent::beforeGenericFiltersAreAppliedToLoadedDataTable();
}
+ protected function isPivoted()
+ {
+ return $this->requestConfig->pivotBy || Common::getRequestVar('pivotBy', '');
+ }
}
diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php b/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php
index 5acf9b50be..959aa0d57b 100644
--- a/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php
+++ b/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php
@@ -64,4 +64,14 @@ class AllColumns extends HtmlTable
$properties->columns_to_display = $columnsToDisplay;
});
}
+
+ public function beforeLoadDataTable()
+ {
+ $this->requestConfig->request_parameters_to_modify['pivotBy'] = null; // always unset pivotBy
+ }
+
+ protected function isPivoted()
+ {
+ return false; // Pivot not supported
+ }
}
diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable/PivotBy.php b/plugins/CoreVisualizations/Visualizations/HtmlTable/PivotBy.php
deleted file mode 100644
index 1703988599..0000000000
--- a/plugins/CoreVisualizations/Visualizations/HtmlTable/PivotBy.php
+++ /dev/null
@@ -1,36 +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\Plugins\CoreVisualizations\Visualizations\HtmlTable;
-
-use Piwik\DataTable;
-use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
-use Piwik\View;
-
-/**
- * DataTable Visualization that derives from HtmlTable and sets show_extra_columns to true.
- */
-class PivotBy extends HtmlTable
-{
- public function beforeGenericFiltersAreAppliedToLoadedDataTable()
- {
- $this->config->columns_to_display = $this->dataTable->getColumns();
-
- $this->dataTable->applyQueuedFilters();
-
- parent::beforeGenericFiltersAreAppliedToLoadedDataTable();
- }
-
- public function beforeRender()
- {
- parent::beforeRender();
-
- $this->config->columns_to_display = $this->dataTable->getColumns();
- }
-}
diff --git a/plugins/CustomDimensions b/plugins/CustomDimensions
-Subproject cef5a9d43f7e26e98a33a003eb283431dfacf6d
+Subproject 212a703c5884c644cff37eea714a1be4494715c
diff --git a/plugins/CustomVariables/lang/fi.json b/plugins/CustomVariables/lang/fi.json
index 51c8ee0f1f..0dfd138a41 100644
--- a/plugins/CustomVariables/lang/fi.json
+++ b/plugins/CustomVariables/lang/fi.json
@@ -5,6 +5,10 @@
"CustomVariables": "Kustomoidut muuttujat",
"CustomVariablesReportDocumentation": "Tämä raportti sisältää tietoa kustomoiduista muuttujastasi. Voit tarkastella eri arvojen määrää klikkaamalla muuttujan nimeä. %1$s Saat lisätietoa kustomoiduista muuttujista %2$sCustom Variables%3$s-sivulta piwik.orgista (englanninkielinen)",
"ScopePage": "alueena sivu",
- "ScopeVisit": "alueena käynti"
+ "ScopeVisit": "alueena käynti",
+ "ManageDescription": "Tämä on yleiskatsaus kaikista kustomoiduista muuttujista ja niiden käytöstä verkkosivulla '%s'. Nimet on järjestetty käyttömäärien mukaan.",
+ "Index": "Indeksi",
+ "Usages": "Käytöt",
+ "Unused": "Käyttämätön"
}
} \ No newline at end of file
diff --git a/plugins/CustomVariables/lang/ru.json b/plugins/CustomVariables/lang/ru.json
index c448538e4b..82d7f8182f 100644
--- a/plugins/CustomVariables/lang/ru.json
+++ b/plugins/CustomVariables/lang/ru.json
@@ -4,7 +4,21 @@
"ColumnCustomVariableValue": "Значение пользовательской переменной",
"CustomVariables": "Пользовательские переменные",
"CustomVariablesReportDocumentation": "Этот отчет отображает информацию по вашим Пользовательским Переменным. Кликните по переменной, чтобы увидеть распределение значений. %1$s Для большей информации о Пользов. Переменных в общих чертах ознакомьтесь с %2$sдокументацией по Пользов. переменных на сайте Piwik%3$s",
+ "PluginDescription": "Пользовательские переменные - это пары (имя, значение), которые вы можете назначить для пользователей или любого их действия при помощи Javascript API. Тогда Piwik будет сообщать, сколько посещений, страниц, преобразований для каждого из этих пользовательских имен и значений. Смотрите детализацию Пользовательских переменных для каждого пользователя и действия в Журнале посещений.<br \/>Требуется для использования опции <a href=\"http:\/\/piwik.org\/docs\/ecommerce-analytics\/\">Аналитика электронной торговли<\/a>!",
"ScopePage": "scope page",
- "ScopeVisit": "scope visit"
+ "ScopeVisit": "scope visit",
+ "ManageDescription": "Этот обзор показывает все слоты для пользовательских переменных и их использование для вебсайта '%s'. Названия в пределах одного слота распределены по общей частоте использования.",
+ "ScopeX": "Выборка %s",
+ "Index": "Индекс",
+ "Usages": "Использование",
+ "Unused": "Не использовано",
+ "CreateNewSlot": "Увеличить количество доступных слотов Пользовательских переменных",
+ "UsageDetails": "%1$s посещений и %2$s действий с момента создания этого вебсайта.",
+ "CreatingCustomVariableTakesTime": "Создание нового слота пользовательских переменных может занять долгое время в зависимости от размера вашей базы данных. Поэтому, это возможно сделать только с помощью команды, которая должна выполняться в командной строке.",
+ "CurrentAvailableCustomVariables": "В данный момент вы можете использовать до %s Пользовательских переменных на сайт.",
+ "ToCreateCustomVarExecute": "Чтобы создать новый слот Пользовательских переменных, введите следующую команду во время установки Piwik:",
+ "SlotsReportIsGeneratedOverTime": "Информация для этого отчета будет заполнена со временем. Это может занять день или два, чтобы увидеть какую-либо информацию, и несколько недель, чтобы получить точный отчет.",
+ "MetricsAreOnlyAvailableForVisitScope": "Внимание: %1$s метрика доступна только для Пользовательских переменных выборки %2$s.",
+ "MetricsNotAvailableForPageScope": "Для выборки Пользовательных переменных %1$s, значение столбца для этих метрик - %2$s"
}
} \ No newline at end of file
diff --git a/plugins/DBStats/lang/fi.json b/plugins/DBStats/lang/fi.json
index edb42aeadd..9232287c22 100644
--- a/plugins/DBStats/lang/fi.json
+++ b/plugins/DBStats/lang/fi.json
@@ -10,6 +10,7 @@
"MetricDataByYear": "Metriikat vuosittain",
"MetricTables": "Metriikkataulut",
"OtherTables": "Muut taulut",
+ "PluginDescription": "Tarjoaa tietoa MySQL-tietokannan käytöstä. Saatavilla pääkäyttäjille Diagnostiikka-sivun alla.",
"ReportDataByYear": "Raporttitaulut vuosittain",
"ReportTables": "Raporttitaulut",
"RowCount": "Rivien määrä",
diff --git a/plugins/Dashboard/lang/fi.json b/plugins/Dashboard/lang/fi.json
index c888edd724..14a6dd65b1 100644
--- a/plugins/Dashboard/lang/fi.json
+++ b/plugins/Dashboard/lang/fi.json
@@ -18,8 +18,10 @@
"Maximise": "Suurenna",
"Minimise": "Pienennä",
"NotUndo": "Et voi peruuttaa tätä operaatiota.",
+ "PluginDescription": "Web-analytiikkojen työpöytä. Muokkaa työpöytääsi lisäämällä uusia osia, siirtämällä osia eri kohtiin, ja vaihtamalla työpöydän sisältöä. Jokainen käyttäjä voi hallita omaa työpöytäänsä.",
"RemoveDashboard": "Poista näkymä",
"RemoveDashboardConfirm": "Haluatko varmasti poistaa työpöydän \"%s\"?",
+ "RemoveDefaultDashboardNotPossible": "Oletustyöpöytää ei voi poistaa",
"RenameDashboard": "Uudelleenimeä näkymä",
"ResetDashboard": "Nollaa työpöytä",
"ResetDashboardConfirm": "Haluatko varmasti nollata työpöydän asettelun takaisin oletusasetuksiin?",
diff --git a/plugins/Dashboard/lang/lt.json b/plugins/Dashboard/lang/lt.json
index dc83d12c30..b7ac2a7f30 100644
--- a/plugins/Dashboard/lang/lt.json
+++ b/plugins/Dashboard/lang/lt.json
@@ -9,6 +9,7 @@
"DashboardCopied": "Esamas skydelis sėkmingai nukopijuotas pasirinktam naudotojui.",
"DashboardEmptyNotification": "Jūsų Skydelyje nėra jokių valdiklių. Pradėkite, pridėdami kelis valdiklius arba, tiesiog, atstatykite skydelį į numatytąjį valdiklių pasirinkimą.",
"DashboardName": "Skydelio pavadinimas:",
+ "DashboardOf": "%s skydelis",
"DefaultDashboard": "Numatytasis skydelis - Naudojamas numatytųjų valdiklių pasirinkimo ir stulpelių išdėstymas",
"DeleteWidgetConfirm": "Ar tikrai norite pašalinti šį valdiklį iš skydelio?",
"EmptyDashboard": "Tuščias skydelis - Parinkite savo mėgiamus valdiklius",
@@ -20,6 +21,7 @@
"PluginDescription": "Jūsų Saityno Analitikos Skydelis. Tinkinkite savo skydelį, pridėdami naujų valdiklių, vilkdami juos iš vienos vietos į kitą ir keisdami skydelio stulpelių išdėstymą. Kiekvienas naudotojas gali tvarkyti savo asmeninį pasirinktiną skydelį.",
"RemoveDashboard": "Šalinti skydelį",
"RemoveDashboardConfirm": "Ar tikrai norite pašalinti skydelį \"%s\"?",
+ "RemoveDefaultDashboardNotPossible": "Numatytasis skydelis negali būti pašalintas",
"RenameDashboard": "Pervadinti skydelį",
"ResetDashboard": "Atstatyti skydelį",
"ResetDashboardConfirm": "Ar tikrai norite atstatyti savo skydelio išdėstymą į numatytąjį Valdiklių pasirinkimą?",
diff --git a/plugins/Dashboard/lang/ru.json b/plugins/Dashboard/lang/ru.json
index 413838e418..071a954c63 100644
--- a/plugins/Dashboard/lang/ru.json
+++ b/plugins/Dashboard/lang/ru.json
@@ -18,8 +18,10 @@
"Maximise": "Развернуть",
"Minimise": "Свернуть",
"NotUndo": "Данная операция не обратима.",
+ "PluginDescription": "Ваша Панель управления веб-аналитикой. Настройте свою панель управления, добавляйте новые виджеты, перемещайте их и изменяйте расположение столбцов панели управления. Каждый пользователь может управлять своей собственной панелью управления.",
"RemoveDashboard": "Удалить панель инструментов",
"RemoveDashboardConfirm": "Вы уверены, что хотите удалить эту панель инструментов: '%s'?",
+ "RemoveDefaultDashboardNotPossible": "Панель управления по умолчанию не может быть удалена",
"RenameDashboard": "Переименовать панель инструментов",
"ResetDashboard": "Сбросить панель инструментов",
"ResetDashboardConfirm": "Вы уверены, что хотите обновить сбросить вид панели инструментов к виду по умолчанию?",
diff --git a/plugins/DevicePlugins/lang/fi.json b/plugins/DevicePlugins/lang/fi.json
index 8011625ef1..de4ac1ac6b 100644
--- a/plugins/DevicePlugins/lang/fi.json
+++ b/plugins/DevicePlugins/lang/fi.json
@@ -2,6 +2,8 @@
"DevicePlugins": {
"BrowserWithNoPluginsEnabled": "%1$s ilman liitännäisiä aktivoitu",
"BrowserWithPluginsEnabled": "%1$s liitännäisillä %2$s on aktivoitu",
+ "PluginDescription": "Lista lisäosista joita kävijöiden selaimet tukevat.",
+ "PluginDetectionDoesNotWorkInIE": "Huom. Lisäosien tunnistus ei toimi Internet Explorerissa ennen versiota 11. Tässä raportissa on mukana vain uudet IE:t ja muut selaimet.",
"WidgetPlugins": "Lista lisäosista",
"WidgetPluginsDocumentation": "Tämä raportti näyttää, mitä selainlisäosia vierailijoillasi oli käytössä. Tästä tiedosta voi olla hyötyä, kun joudut valitsemaan, miten tietoa esitetään ja välitetään vierailijoille."
}
diff --git a/plugins/DevicePlugins/lang/ru.json b/plugins/DevicePlugins/lang/ru.json
index b1ae429313..cca6f1f296 100644
--- a/plugins/DevicePlugins/lang/ru.json
+++ b/plugins/DevicePlugins/lang/ru.json
@@ -1,7 +1,9 @@
{
"DevicePlugins": {
"BrowserWithNoPluginsEnabled": "%1$s без активированных плагинов",
+ "BrowserWithPluginsEnabled": "%1$s с плагинами %2$s включен",
"PluginDescription": "Сообщает список плагинов, доступных в браузерах посетителей.",
+ "PluginDetectionDoesNotWorkInIE": "Внимание: Определение плагинов не работает в Internet Explorer до 11. Этот отчет базируется только на не-IE браузерах и новейших версиях IE.",
"WidgetPlugins": "Список плагинов",
"WidgetPluginsDocumentation": "Этот отчет показывается какие плагины посетители используют в своих браузерах. Эта информация может быть важна для того, чтобы посетители смогли видеть ваш контент должным образом."
}
diff --git a/plugins/DevicesDetection/images/browsers/AT.gif b/plugins/DevicesDetection/images/browsers/AT.gif
new file mode 100644
index 0000000000..f1d9824afd
--- /dev/null
+++ b/plugins/DevicesDetection/images/browsers/AT.gif
Binary files differ
diff --git a/plugins/DevicesDetection/images/browsers/KY.gif b/plugins/DevicesDetection/images/browsers/KY.gif
new file mode 100644
index 0000000000..9d14605aca
--- /dev/null
+++ b/plugins/DevicesDetection/images/browsers/KY.gif
Binary files differ
diff --git a/plugins/DevicesDetection/images/browsers/OT.gif b/plugins/DevicesDetection/images/browsers/OT.gif
new file mode 100644
index 0000000000..068d88fa29
--- /dev/null
+++ b/plugins/DevicesDetection/images/browsers/OT.gif
Binary files differ
diff --git a/plugins/DevicesDetection/images/browsers/SP.gif b/plugins/DevicesDetection/images/browsers/SP.gif
new file mode 100644
index 0000000000..f404825e95
--- /dev/null
+++ b/plugins/DevicesDetection/images/browsers/SP.gif
Binary files differ
diff --git a/plugins/DevicesDetection/images/browsers/SS.gif b/plugins/DevicesDetection/images/browsers/SS.gif
new file mode 100644
index 0000000000..5ea7e91ba4
--- /dev/null
+++ b/plugins/DevicesDetection/images/browsers/SS.gif
Binary files differ
diff --git a/plugins/Diagnostics/lang/fi.json b/plugins/Diagnostics/lang/fi.json
new file mode 100644
index 0000000000..28051d0630
--- /dev/null
+++ b/plugins/Diagnostics/lang/fi.json
@@ -0,0 +1,6 @@
+{
+ "Diagnostics": {
+ "ConfigFileTitle": "Asetustiedosto",
+ "Sections": "Osiot"
+ }
+} \ No newline at end of file
diff --git a/plugins/Diagnostics/lang/nb.json b/plugins/Diagnostics/lang/nb.json
new file mode 100644
index 0000000000..47a69e3d91
--- /dev/null
+++ b/plugins/Diagnostics/lang/nb.json
@@ -0,0 +1,6 @@
+{
+ "Diagnostics": {
+ "ConfigFileTitle": "Konfigurasjonsfil",
+ "Sections": "Seksjoner"
+ }
+} \ No newline at end of file
diff --git a/plugins/Diagnostics/lang/ru.json b/plugins/Diagnostics/lang/ru.json
new file mode 100644
index 0000000000..d865637b5e
--- /dev/null
+++ b/plugins/Diagnostics/lang/ru.json
@@ -0,0 +1,8 @@
+{
+ "Diagnostics": {
+ "ConfigFileTitle": "Файл конфигурации",
+ "ConfigFileIntroduction": "Здесь вы можете посмотреть конфигурацию Piwik. Если вы запускаете Piwik в среде с балансированной нагрузкой, страница может быть различной в зависимости от сервера, с которого эта страница загружается. Ряды с разными цветами фона - это измененные значения конфигурации, которые описаны, например в файле %1$s.",
+ "HideUnchanged": "Если вы хотите видеть только измененные значения, вы можете %1$sспрятать все неизмененные значения%2$s.",
+ "Sections": "Разделы"
+ }
+} \ No newline at end of file
diff --git a/plugins/Ecommerce/lang/fi.json b/plugins/Ecommerce/lang/fi.json
new file mode 100644
index 0000000000..6942b9eb21
--- /dev/null
+++ b/plugins/Ecommerce/lang/fi.json
@@ -0,0 +1,8 @@
+{
+ "Ecommerce": {
+ "PluginDescription": "E-kauppa mahdollistaa myyntiin liittyvien toimintojen seuraamisen: tuotteiden lisäämisen ostoskoriin ja ostosten tekemisen. Myös tuotteiden ja tuotekategorioiden katselu, ja hylätyt ostoskorit seurataan.",
+ "Sales": "Myynnit",
+ "SalesBy": "Myynnit %s:n mukaan",
+ "SalesAdjective": "Myynnit %s"
+ }
+} \ No newline at end of file
diff --git a/plugins/Events/Events.php b/plugins/Events/Events.php
index 06a7b5b081..15c49e87f1 100644
--- a/plugins/Events/Events.php
+++ b/plugins/Events/Events.php
@@ -144,7 +144,8 @@ class Events extends \Piwik\Plugin
$secondaryDimension = $this->getSecondaryDimensionFromRequest();
$view->config->subtable_controller_action = API::getInstance()->getActionToLoadSubtables($apiMethod, $secondaryDimension);
- if (Common::getRequestVar('pivotBy', false) === false) {
+ $pivotBy = Common::getRequestVar('pivotBy', false);
+ if (empty($pivotBy)) {
$view->config->columns_to_display = array('label', 'nb_events', 'sum_event_value');
}
diff --git a/plugins/Events/lang/ru.json b/plugins/Events/lang/ru.json
index 242b414fa2..3a8c5c6656 100644
--- a/plugins/Events/lang/ru.json
+++ b/plugins/Events/lang/ru.json
@@ -1,5 +1,6 @@
{
"Events": {
+ "PluginDescription": "Отслеживайте события и получайте отчеты об активности своих посетителей.",
"AvgEventValue": "Среднее значение события: %s",
"AvgValue": "Среднее значение",
"AvgValueDocumentation": "Среднее всех значений для этого события",
@@ -19,6 +20,7 @@
"MaxValueDocumentation": "Максимальное значения для этого события",
"MinValue": "Минимальное значение",
"MinValueDocumentation": "Минимальное значения для этого события",
+ "SecondaryDimension": "Втроричное измерение %s.",
"SwitchToSecondaryDimension": "Переключиться на %s",
"TopEvents": "Топ событий",
"TotalEvents": "Всего событий",
diff --git a/plugins/Feedback/lang/fi.json b/plugins/Feedback/lang/fi.json
index 6ab6ec2a91..f665cbf2da 100644
--- a/plugins/Feedback/lang/fi.json
+++ b/plugins/Feedback/lang/fi.json
@@ -10,6 +10,12 @@
"RateFeatureTitle": "Pidätkö ominaisuudesta '%s'? Jätä arvostelu ja kommentti",
"SendFeedback": "Lähetä palaute",
"ThankYou": "Kiitos että autat parantamaan Piwikiä!",
- "TopLinkTooltip": "Kerro meille mitä ajattelet, tai osta tukipalveluita (englanniksi)."
+ "TopLinkTooltip": "Kerro meille mitä ajattelet, tai osta tukipalveluita (englanniksi).",
+ "CommunityHelp": "Yhteisön apu",
+ "ProfessionalHelp": "Ammattilaisapu",
+ "PiwikProReviewPiwikSetup": "Piwik-asennuksesi arviointi",
+ "PiwikProPhoneEmailSupport": "Puhelin- ja sähköpostituki",
+ "PiwikProPremiumFeatures": "Premium-ominaisuudet",
+ "ContactUs": "Ota yhteyttä"
}
} \ No newline at end of file
diff --git a/plugins/Feedback/lang/ru.json b/plugins/Feedback/lang/ru.json
index e04996be0b..941b17f2d9 100644
--- a/plugins/Feedback/lang/ru.json
+++ b/plugins/Feedback/lang/ru.json
@@ -18,6 +18,7 @@
"ViewUserGuides": "Узнайте, как настроить Piwik и эффективно анализировать Ваши данные, используя %1$s руководства пользователя%2$s",
"CommunityHelp": "Помощь сообщества",
"ProfessionalHelp": "Помощь профессионала",
+ "PiwikProIntro": "Piwik PRO предоставляет экспертную поддержку и консультирование клиентам, которые размещают Piwik в своей собственной инфраструктуре.",
"PiwikProOfferIntro": "Наше предложение включает",
"PiwikProReviewPiwikSetup": "Просмотр Вашей установки Piwik",
"PiwikProOptimizationMaintenance": "Услуги оптимизации и обслуживания Piwik",
@@ -26,6 +27,7 @@
"PiwikProPremiumFeatures": "Премиальные возможности",
"PiwikProCustomDevelopment": "Услуги разработки",
"PiwikProAnalystConsulting": "Услуги аналитика-консультанта",
- "ContactUs": "Свяжитесь с нами"
+ "ContactUs": "Свяжитесь с нами",
+ "VisitTheForums": "Посетите %1$s Форумы%2$s и получите помощь от сообщества пользователей Piwik"
}
} \ No newline at end of file
diff --git a/plugins/Goals/API.php b/plugins/Goals/API.php
index 89af85f9c0..bb7da8cbae 100644
--- a/plugins/Goals/API.php
+++ b/plugins/Goals/API.php
@@ -184,6 +184,7 @@ class API extends \Piwik\Plugin\API
if ($patternType == 'exact'
&& substr($pattern, 0, 4) != 'http'
&& substr($matchAttribute, 0, 6) != 'event_'
+ && $matchAttribute != 'title'
) {
throw new Exception(Piwik::translate('Goals_ExceptionInvalidMatchingString', array("http:// or https://", "http://www.yourwebsite.com/newsletter/subscribed.html")));
}
diff --git a/plugins/Goals/Pages.php b/plugins/Goals/Pages.php
index 72db6cc21b..50e3f63e37 100644
--- a/plugins/Goals/Pages.php
+++ b/plugins/Goals/Pages.php
@@ -8,12 +8,9 @@
*/
namespace Piwik\Plugins\Goals;
-
-use Piwik\API\Request;
use Piwik\Cache;
use Piwik\Common;
use Piwik\Piwik;
-use Piwik\Plugin\Report;
use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution;
use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines;
use Piwik\Plugin\Reports;
diff --git a/plugins/Goals/lang/el.json b/plugins/Goals/lang/el.json
index 612438258b..b2cce6c204 100644
--- a/plugins/Goals/lang/el.json
+++ b/plugins/Goals/lang/el.json
@@ -66,7 +66,7 @@
"GoalsOverview": "Επισκόπηση στόχων",
"GoalsOverviewDocumentation": "Αυτό είναι μια επισκόπηση των μετατροπών των στόχων σας. Αρχικά, το διάγραμμα δείχνει το άθροισμα όλων των μετατροπών. %s Κάτω από το διάγραμμα, μπορείτε να αναφορές μετατροπής για κάθε έναν από τους στόχους. Τα μικροδιαγράμματα μπορούν να μεγεθυνθούν πατώντας επάνω τους.",
"GoalX": "Στόχος %s",
- "HelpOneConversionPerVisit": "Αν μια Σελίδα ταιριάζει, αυτός ο Στόχος ανανεώνεται ή προβάλεται περισσόερες φορές ανά Επίσκεψη και ο Στόχος θα καταγράφετε μόνο την πρώτη φορά που φορτώθηκε η σελίδα κατά την επίσκεψη.",
+ "HelpOneConversionPerVisit": "Αν μια Σελίδα ταιριάζει, αυτός ο Στόχος ανανεώνεται ή προβάλλεται περισσότερες φορές ανά Επίσκεψη και ο Στόχος θα καταγράφεται μόνο την πρώτη φορά που φορτώθηκε η σελίδα κατά την επίσκεψη.",
"IsExactly": "είναι ακριβώς %s",
"LearnMoreAboutGoalTrackingDocumentation": "Δείτε περισσότερα για την %1$sΠαρακολούθηση των Στόχων στο Piwik%2$s στην τεκμηρίωση για το χρήστη.",
"LeftInCart": "%s απομένουν στο καλάθι",
diff --git a/plugins/Goals/lang/en.json b/plugins/Goals/lang/en.json
index d5b221a3fc..2b9a79ea32 100644
--- a/plugins/Goals/lang/en.json
+++ b/plugins/Goals/lang/en.json
@@ -78,6 +78,7 @@
"NewGoalIntro": "Goal Conversion tracking is one of the most efficient ways to measure and improve your business objectives.",
"NewVisitorsConversionRateIs": "New visitors conversion rate is %s",
"NoGoalsNeedAccess": "Only an Administrator or a user with Super User access can manage Goals for a given website. Please ask your Piwik administrator to set up a Goal for your website. <br>Tracking Goals is a great way to help understand and maximize your website performance!",
+ "NoConversionsNoReportsMessage": "Reports are not displayed because there is no conversion data for the selected goal and period.",
"NeedAccess": "Only an Administrator or a user with Super User access can manage Goals for a given website.",
"Optional": "(optional)",
"OverallConversionRate": "overall conversion rate (visits with a completed goal)",
diff --git a/plugins/Goals/lang/lt.json b/plugins/Goals/lang/lt.json
index 10bcee0e28..c32adb2a5b 100644
--- a/plugins/Goals/lang/lt.json
+++ b/plugins/Goals/lang/lt.json
@@ -6,7 +6,7 @@
"BestCountries": "Jūsų geriausios konversijos šalys:",
"BestKeywords": "Jū9sų geriausi konversijos raktažodžiai:",
"BestReferrers": "Jūsų geriausios konversijos svetainės:",
- "CaseSensitive": "Linksnių atitikimas",
+ "CaseSensitive": "Raidžių dydžio sutapimas",
"ClickOutlink": "Paspauskite ant nuorodos į išorinį puslapį",
"ColumnConversions": "Konversijos",
"Contains": "turi %s",
diff --git a/plugins/Goals/lang/nb.json b/plugins/Goals/lang/nb.json
index 415c58bff0..62627850be 100644
--- a/plugins/Goals/lang/nb.json
+++ b/plugins/Goals/lang/nb.json
@@ -16,6 +16,7 @@
"ColumnConversions": "Konvertering",
"ColumnConversionsDocumentation": "Antall konverteringer for %s.",
"Contains": "inneholder %s",
+ "ConversionRate": "%s konverteringsrate",
"Conversions": "%s konverteringer",
"DaysToConv": "Dager til konvertering",
"Details": "Måldetaljer",
diff --git a/plugins/Goals/lang/ru.json b/plugins/Goals/lang/ru.json
index 52b761496a..7a3575049a 100644
--- a/plugins/Goals/lang/ru.json
+++ b/plugins/Goals/lang/ru.json
@@ -13,6 +13,7 @@
"CancelAndReturnToGoals": "Отмена и %1$sвозврат к списку целей%2$s",
"CategoryTextGeneral_Visitors": "Местоположение пользователя",
"CategoryTextReferrers_Referrers": "Источники",
+ "CategoryTextVisitsSummary_VisitsSummary": "Свойство пользователя",
"CategoryTextGeneral_Visit": "Вовлеченность",
"ChooseGoal": "Выберите цель",
"ClickOutlink": "Переходят по ссылке на внешний сайт",
@@ -76,6 +77,8 @@
"NewGoalIntro": "Отслеживание достигнутых переходов является одним из наиболее эффективных способов измерить и улучшить свои бизнес-задачи.",
"NewVisitorsConversionRateIs": "Коэффициент новых посетителей %s",
"NoGoalsNeedAccess": "Только администратор или пользователь с правами суперпользователя может добавлять цели для данного сайта. Пожалуйста, обратитесь к администратору Piwik, чтобы создать цели для вашего сайта.<br>Отслеживания целей является отличным способом, чтобы помочь понять как увеличить и максимизировать эффективность веб-сайта!",
+ "NoConversionsNoReportsMessage": "Отчеты не показаны, потому что данные преобразования для выбранных цели и периода отсутсвуют.",
+ "NeedAccess": "Только Администратор или пользователь с доступом Суперпользователя может управлять целями для данного вебсайта.",
"Optional": "(необязательно)",
"OverallConversionRate": "%s общий коэффициент конверсий (переходы с выполненной целью)",
"OverallRevenue": "%s общая прибыль",
@@ -92,6 +95,8 @@
"UpdateGoal": "Обновить цель",
"URL": "URL выглядит следующим образом:",
"ViewAndEditGoals": "Просмотреть и редактировать цели",
+ "GoalsBy": "Цели по %s",
+ "GoalsAdjective": "Цели %s",
"VisitPageTitle": "Посещают данный Заголовок страницы",
"VisitsUntilConv": "Сконвертированные посещения",
"VisitUrl": "Посещают данный URL (страницу или группу страниц)",
diff --git a/plugins/Goals/tests/Integration/APITest.php b/plugins/Goals/tests/Integration/APITest.php
index 913bebf0a6..7dcb79eef5 100644
--- a/plugins/Goals/tests/Integration/APITest.php
+++ b/plugins/Goals/tests/Integration/APITest.php
@@ -62,6 +62,13 @@ class APITest extends IntegrationTestCase
$this->assertGoal($idGoal, 'MyName', 'url', 'http://www.test.de', 'exact', 1, 50, 1);
}
+ public function test_addGoal_ShouldSucceed_IfExactPageTitle()
+ {
+ $idGoal = $this->api->addGoal($this->idSite, 'MyName', 'title', 'normal title', 'exact', true, 50, true);
+
+ $this->assertGoal($idGoal, 'MyName', 'title', 'normal title', 'exact', 1, 50, 1);
+ }
+
/**
* @expectedException \Exception
* @expectedExceptionMessage Goals_ExceptionInvalidMatchingString
diff --git a/plugins/ImageGraph/lang/fi.json b/plugins/ImageGraph/lang/fi.json
index 5dac1b5f20..06af13adfe 100644
--- a/plugins/ImageGraph/lang/fi.json
+++ b/plugins/ImageGraph/lang/fi.json
@@ -1,5 +1,6 @@
{
"ImageGraph": {
- "ColumnOrdinateMissing": "Kolumnia '%1$s' ei löydetty tässä raportissa. Kokeile mitä tahansa %2$s"
+ "ColumnOrdinateMissing": "Kolumnia '%1$s' ei löydetty tässä raportissa. Kokeile mitä tahansa %2$s",
+ "PluginDescription": "Luo kauniita staattisia PNG-kuvaajia mistä tahansa raportista."
}
} \ No newline at end of file
diff --git a/plugins/Installation/ServerFilesGenerator.php b/plugins/Installation/ServerFilesGenerator.php
index fcd780523d..927f403ccb 100644
--- a/plugins/Installation/ServerFilesGenerator.php
+++ b/plugins/Installation/ServerFilesGenerator.php
@@ -15,12 +15,10 @@ class ServerFilesGenerator
{
/**
* Generate Apache .htaccess files to restrict access
+ * .htaccess files are created on all webservers even Nginx, as sometimes Nginx knows how to handle .htaccess files
*/
public static function createHtAccessFiles()
{
- if (!SettingsServer::isApache()) {
- return;
- }
$denyAll = self::getDenyAllHtaccessContent();
$allow = self::getAllowHtaccessContent();
@@ -39,7 +37,7 @@ class ServerFilesGenerator
"</IfModule>\n\n" .
"# Allow to serve static files which are safe\n" .
- "<Files ~ \"\\.(gif|ico|jpg|png|svg|js|css|htm|html|swf|mp3|mp4|wav|ogg|avi|ttf)$\">\n" .
+ "<Files ~ \"\\.(gif|ico|jpg|png|svg|js|css|htm|html|swf|mp3|mp4|wav|ogg|avi|ttf|eot)$\">\n" .
$allow . "\n" .
"</Files>\n";
@@ -76,17 +74,17 @@ class ServerFilesGenerator
*
* Apache-specific; for IIS @see web.config
*
+ * .htaccess files are created on all webservers even Nginx, as sometimes Nginx knows how to handle .htaccess files
+ *
* @param string $path without trailing slash
* @param bool $overwrite whether to overwrite an existing file or not
* @param string $content
*/
protected static function createHtAccess($path, $overwrite = true, $content)
{
- if (SettingsServer::isApache()) {
- $file = $path . '/.htaccess';
- if ($overwrite || !file_exists($file)) {
- @file_put_contents($file, $content);
- }
+ $file = $path . '/.htaccess';
+ if ($overwrite || !file_exists($file)) {
+ @file_put_contents($file, $content);
}
}
diff --git a/plugins/Installation/lang/fi.json b/plugins/Installation/lang/fi.json
index 0a3a2579dd..25a3b390af 100644
--- a/plugins/Installation/lang/fi.json
+++ b/plugins/Installation/lang/fi.json
@@ -15,6 +15,7 @@
"DatabaseSetupLogin": "käyttäjätunnus",
"DatabaseSetupServer": "tietokantapalvelin",
"DatabaseSetupTablePrefix": "taulujen etuliite",
+ "Email": "Sähköposti",
"Extension": "lisäosa",
"Filesystem": "Tiedostojärjestelmä",
"GetInvolved": "Jos pidät näkemästäsi, myös sinä voit %1$sosallistua%2$s.",
@@ -24,6 +25,7 @@
"InstallationStatus": "Asennuksen tila",
"InsufficientPrivilegesHelp": "Voit lisätä nämä oikeudet esim. phpMyAdminilla tai ajamalla oikeat SQL-kyselyt. Jos et tiedä miten tehdä nämä asiat, pyydä järjestelmän ylläpitäjää säätämään oikeudet oikein.",
"InsufficientPrivilegesMain": "Joko tietokantaa ei ole olemassa (eikä sitä voitu luoda), tai tällä käyttäjällä ei ole tarvittavia oikeuksia. Tietokannan käyttäjällä täytyy olla seuraavat oikeudet: %s",
+ "InvalidStateError": "Virhe: Piwik on jo asennettu. %1$s Mene takaisin %2$s Piwikiin%3$s.",
"JsTagArchivingHelp1": "Kohtalaisen ja korkean liikenteen verkkosivuille on tiettyjä optimointeja, jotka tulisi tehdä, jotta Piwik voi toimia nopeammin (kuten %1$sautomaattisen arkistoinnin asettaminen%2$s).",
"JSTracking_EndNote": "Huom: Asennuksen jälkeen voit luoda omia seurantakoodeja ylläpitosivun osastolla %1$sSeurantakoodi%2$s",
"JSTracking_Intro": "Voidaksesi seurata liikennettä Piwikin avulla, sinun tulee lisätä ekstrakoodi jokaiselle verkkosivullesi.",
@@ -36,9 +38,14 @@
"NfsFilesystemWarningSuffixInstall": "Tiedostopohjaisten sessioiden käyttäminen NFS:ssä on todella hidasta, joten Piwik käyttää tietokantasessioita. Jos sinulla on monia samanaikaisia ohjauspaneelin käyttäjiä, sinun tarvitsee ehkä lisätä tietokantaserverin käyttäjäyhteyksien maksimimäärää.",
"NoConfigFound": "Piwikin asetustiedostoa ei löydy ja yrität siirtyä Piwikin sivuille.<br \/><b>  » Voit <a href='index.php'>asentaa Piwikin nyt<\/a><\/b><br \/><small>Jos asensit Piwikin aikaisemmin ja tietokannassa on jo tietoja, älä murehdi, tietoja ei hävitetä.<\/small>",
"Optional": "Optionaalinen",
+ "Password": "Salasana",
"PasswordDoNotMatch": "salasanat eivät täsmää",
+ "PasswordRepeat": "Salasana (uudelleen)",
"PercentDone": "%s %% valmiina",
+ "PiwikProAdTitle": "Edistynyt analytiikka ja palvelut",
"PleaseFixTheFollowingErrors": "Korjaa seuraavat virheet",
+ "DefaultSettings": "Oletusasetukset",
+ "DefaultSettingsHelp": "Piwikissä on oletusasetukset. Voit muuttaa asetuksia nyt tai myöhemmin hallintasivulta.",
"Requirements": "Piwikin vaatimukset",
"RestartWebServer": "Käynnistä web-palvelimesi uudelleen näiden muutosten jälkeen.",
"ReusingTables": "Taulukoiden uudelleenkäyttö",
@@ -46,15 +53,19 @@
"SeeBelowForMoreInfo": "Katso alempaa lisätietoja.",
"SetupWebsite": "Lisää verkkosivu",
"SetupWebsiteError": "Virhe verkkosivun lisäämisessä",
+ "SetupWebSiteName": "Verkkosivun nimi",
"SetupWebsiteSetupSuccess": "Sivu %s luotiin onnistuneesti!",
+ "SetupWebSiteURL": "Verkkosivun osoite",
"SiteSetup": "Luo ensimmäinen seurattava verkkosivu:",
"SiteSetupFootnote": "Huom: kun asennus on valmis, voit lisätä lisää verkkosivuja!",
"SuperUser": "Pääkäyttäjä",
+ "SuperUserLogin": "Pääkäyttäjän kirjautuminen",
"SuperUserSetupError": "Superkäyttäjää lisätessä tapahtui virhe.",
"SuperUserSetupSuccess": "Pääkäyttäjän luominen onnistui!",
"SystemCheck": "Järjestelmän asetukset",
"SystemCheckAutoUpdateHelp": "Huomioi: Piwikin yhden klikkauksen päivitys vaatii kirjoitusoikeudet Piwikin kansioon ja kansion kaikkeen sisältöön.",
"SystemCheckCreateFunctionHelp": "Piwik käyttää anonyymejä funktioita takaisinkutsuihin.",
+ "SystemCheckDatabaseExtensions": "MySQL-lisäosat",
"SystemCheckDatabaseHelp": "Piwik vaatii joko mysqli-lisäosan tai sekä PDO- että pdo_mysql-lisäosat..",
"SystemCheckDebugBacktraceHelp": "View::factory ei voi luoda näkymää kutsuvalle moduulille.",
"SystemCheckError": "Tapahtui virhe - täytyy korjata ennen jatkamista",
@@ -62,6 +73,7 @@
"SystemCheckExtensions": "Muut vaaditut lisäosat",
"SystemCheckFileIntegrity": "Tiedoston eheys",
"SystemCheckFunctions": "Vaaditut funktiot",
+ "SystemCheckFunctionHelp": "Sinun täytyy ottaa käyttöön tämä sisäänrakennettu funktio.",
"SystemCheckGDFreeType": "GD > 2.x + Freetype (grafiikka)",
"SystemCheckGDHelp": "Pienet graafit eivät toimi.",
"SystemCheckGlobHelp": "Tämä sisäänrakennettu toiminnallisuus on poistettu käytöstä palvelimellasi. Piwik yrittää emuloida toimintoa, mutta saattaa törmätä uusiin turvallisuusrajoituksiin. Suorituskyky heikkenee.",
@@ -99,6 +111,7 @@
"SystemCheckZlibHelp": "PHP pitää olla asennettuna zlib-lisäosan kanssa, --with-zlib.",
"SystemCheckCronArchiveProcess": "Arkistointityö",
"SystemCheckCronArchiveProcessCLI": "Prosessien hallinta komentoriviltä",
+ "SystemCheckUpdateHttps": "Päivitä HTTPS:n yli",
"NotSupported": "ei tuettu",
"Tables": "Luodaan taulut",
"TablesCreatedSuccess": "Taulut luotu onnistuneesti!",
@@ -109,6 +122,7 @@
"TablesUpdatedSuccess": "Tietokanta on päivitetty onnistuneesti: %1$s > %2$s!",
"TablesWarningHelp": "Valitse joko nykyisten taulujen käyttö tai luo taulut uudelleen (vanhat tiedot menetetään).",
"TablesWithSameNamesFound": "Osalla %1$s tauluista tietokannassa %2$s on sama nimi kuin tauluilla, joita Piwik yrittää luoda.",
+ "Timezone": "Verkkosivun aikavyöhyke",
"WeHopeYouWillEnjoyPiwik": "Toivomme että nautit Piwikin käytöstä yhtä paljon kuin me nautimme sen luomisesta!",
"Welcome": "Tervetuloa!",
"WelcomeHelp": "<p>Piwik on vapaan lähdekoodin verkkosivujen analysointityökalu, joka tekee kävijöiden tietojen keräämisen ja analysoinnin helpoksi.<\/p><p>Tämä prosessi on jaettu %s helppoon osaan ja vie aikaa noin viisi minuuttia.<\/p>",
diff --git a/plugins/Live/lang/fi.json b/plugins/Live/lang/fi.json
index 505ef58e1b..a273a5d133 100644
--- a/plugins/Live/lang/fi.json
+++ b/plugins/Live/lang/fi.json
@@ -31,6 +31,8 @@
"VisitorProfile": "Kävijäprofiili",
"VisitorsInRealTime": "Reaaliaikaiset kävijätiedot",
"VisitorsLastVisit": "Tämän kävijän edellinen käynti oli %s päivää sitten.",
- "VisitsFrom": "%1$s%2$s käyntiä%3$s lähteestä"
+ "VisitsFrom": "%1$s%2$s käyntiä%3$s lähteestä",
+ "OnClickPause": "%s on käynnissä. Pysäytä klikkaamalla.",
+ "OnClickStart": "%s on pysäytetty. Aloita klikkaamalla."
}
} \ No newline at end of file
diff --git a/plugins/Live/lang/nb.json b/plugins/Live/lang/nb.json
index f70474f6c6..5ac8a3275c 100644
--- a/plugins/Live/lang/nb.json
+++ b/plugins/Live/lang/nb.json
@@ -23,6 +23,7 @@
"VisitorProfile": "Besøksprofil",
"VisitorsInRealTime": "Besøkende i sanntid",
"VisitsFrom": "%1$s%2$s besøk%3$s fra",
+ "VisitSummaryWithActionDetails": "Brukte totalt %1$s%2$s på nettsiden%3$s og utførte %4$s handlinger%5$s (%6$s) over %7$s besøk%8$s.",
"OnClickPause": "%s er startet. Klikk for å sette på pause.",
"OnClickStart": "%s er stoppet. Klikk for å starte."
}
diff --git a/plugins/Live/stylesheets/live.less b/plugins/Live/stylesheets/live.less
index 7bbdde4044..bf71c90c2c 100644
--- a/plugins/Live/stylesheets/live.less
+++ b/plugins/Live/stylesheets/live.less
@@ -119,6 +119,10 @@ ol.visitorLog li {
margin-right: 4px;
}
+.visitorReferrer .visitorRank {
+ display: inline-block;
+}
+
.visitorRank {
border: 1px solid #D8D8D8;
color: #474747;
diff --git a/plugins/Live/templates/_dataTableViz_visitorLog.twig b/plugins/Live/templates/_dataTableViz_visitorLog.twig
index 5ae56c9570..37c1cac60f 100644
--- a/plugins/Live/templates/_dataTableViz_visitorLog.twig
+++ b/plugins/Live/templates/_dataTableViz_visitorLog.twig
@@ -140,8 +140,11 @@ GPS (lat/long): {{ visitor.getColumn('latitude') }},{{ visitor.getColumn('longit
{% if visitor.getColumn('provider') %}
<br/>
{{ 'Provider_ColumnProvider'|translate }}:
- <a href="{{ visitor.getColumn('providerUrl') }}" rel="noreferrer" target="_blank" class="visitorLogTooltip" title="{{ visitor.getColumn('providerName') }} {{ visitor.getColumn('providerUrl') }}" style="text-decoration:underline;">
- {{ visitor.getColumn('providerName') }}</a>
+ {% if visitor.getColumn('providerUrl') %}
+ <a href="{{ visitor.getColumn('providerUrl') }}" rel="noreferrer" target="_blank" class="visitorLogTooltip" title="{{ visitor.getColumn('providerName') }} {{ visitor.getColumn('providerUrl') }}" style="text-decoration:underline;">
+ {% endif -%}
+ {{ visitor.getColumn('providerName') }}
+ {%- if visitor.getColumn('providerUrl') %}</a>{% endif %}
{% endif %}
{% if visitor.getColumn('visitorTypeIcon') or visitor.getColumn('countryFlag') %}
<br/>
diff --git a/plugins/Live/templates/getLastVisitsStart.twig b/plugins/Live/templates/getLastVisitsStart.twig
index 59a4a1fb9d..064a3545ae 100644
--- a/plugins/Live/templates/getLastVisitsStart.twig
+++ b/plugins/Live/templates/getLastVisitsStart.twig
@@ -19,23 +19,25 @@
{% endif %}
<br />
- {% if visitor.countryFlag is defined %}&nbsp;<img src="{{ visitor.countryFlag }}" title="{{ visitor.location }}, {{ 'Provider_ColumnProvider'|translate }} {% if visitor.providerName is defined %}{{ visitor.providerName }}{% endif %}"/>{% endif %}
- {% if visitor.browserIcon is defined %}&nbsp;<img src="{{ visitor.browserIcon }}" title="{{ visitor.browser }}{% if visitor.plugins is defined %}, {{ 'General_Plugins'|translate }}: {{ visitor.plugins }}{% endif %}"/>{% endif %}
+ {% if visitor.countryFlag is defined %}&nbsp;<img src="{{ visitor.countryFlag }}" title="{{ visitor.location|e('html_attr') }}, {{ 'Provider_ColumnProvider'|translate }} {% if visitor.providerName is defined %}{{ visitor.providerName }}{% endif %}"/>{% endif %}
+ {% if visitor.browserIcon is defined %}&nbsp;<img src="{{ visitor.browserIcon }}" title="{{ visitor.browser|e('html_attr') }}{% if visitor.plugins is defined %}, {{ 'General_Plugins'|translate }}: {{ visitor.plugins }}{% endif %}"/>{% endif %}
{% if visitor.operatingSystemIcon is defined %}&nbsp;<img src="{{ visitor.operatingSystemIcon }}" title="{{ visitor.operatingSystem }}{% if visitor.resolution is defined %}, {{ visitor.resolution }}{% endif %}"/>{% endif %}
&nbsp;
{% if visitor.visitConverted %}
- <span title="{{ 'General_VisitConvertedNGoals'|translate(visitor.goalConversions) }}" class='visitorRank'>
+ <span title="{{ 'General_VisitConvertedNGoals'|translate(visitor.goalConversions) }}"
+ class='visitorRank'>
<img src="{{ visitor.visitConvertedIcon }}" />
<span class='hash'>#</span>
{{ visitor.goalConversions }}
{% if visitor.visitEcommerceStatusIcon %}
- <img src="{{ visitor.visitEcommerceStatusIcon }}" title="{{ visitor.visitEcommerceStatus }}"/>
+ <img src="{{ visitor.visitEcommerceStatusIcon }}" title="{{ visitor.visitEcommerceStatus|e('html_attr') }}"/>
{% endif %}
</span>
{% endif %}
{% if visitor.visitorTypeIcon %}
- <img src="{{ visitor.visitorTypeIcon }}" title="{{ 'General_ReturningVisitor'|translate }}"/>
+ <img src="{{ visitor.visitorTypeIcon }}"
+ title="{{ 'General_ReturningVisitor'|translate }}"/>
{% endif %}
{% if visitor.visitIp %} <span title="{% if visitor.visitorId is not empty %}{{ 'General_VisitorID'|translate }}: {{ visitor.visitorId }}{% endif %}">
@@ -46,33 +48,45 @@
{% if visitor.referrerType is defined and visitor.referrerType != 'direct' %}
{{ 'General_FromReferrer'|translate }}
{% if visitor.referrerUrl is not empty %}
- <a href="{{ visitor.referrerUrl }}" rel="noreferrer" target="_blank">
+ <a rel="noreferrer" target="_blank"
+ href="{{ visitor.referrerUrl|e('html_attr') }}">
{% endif %}
+
{% if visitor.searchEngineIcon is defined %}
<img src="{{ visitor.searchEngineIcon }}" />
{% endif %}
+
{{ visitor.referrerName }}
+
{% if visitor.referrerUrl is not empty %}
</a>
{% endif %}
+
{% if visitor.referrerKeyword is not empty %} - "{{ visitor.referrerKeyword }}"{% endif %}
+
{% set keyword %}{{ visitor.referrerKeyword }}{% endset %}
{% set searchName %}{{ visitor.referrerName }}{% endset %}
{% set position %}#{{ visitor.referrerKeywordPosition}}{% endset %}
+
{% if visitor.referrerKeywordPosition is not empty %}
- <span title='{{ 'Live_KeywordRankedOnSearchResultForThisVisitor'|translate(keyword,position,searchName) }}' class='visitorRank'>
+ <span title='{{ 'Live_KeywordRankedOnSearchResultForThisVisitor'|translate(keyword,position,searchName) }}'
+ class='visitorRank'>
<span class='hash'>#</span> {{ visitor.referrerKeywordPosition }}
</span>
{% endif %}
+
{% elseif visitor.referrerType is defined %}
{{ 'Referrers_DirectEntry'|translate }}
{% endif %}
</span></div>
- <div id="{{ visitor.idVisit }}_actions" class="settings">
- <span class="pagesTitle" title="{{ visitor.actionDetails|length }} {{ 'General_Actions'|translate }}">{{ 'General_Actions'|translate }}:</span>&nbsp;
+ <div id="{{ visitor.idVisit|e('html_attr') }}_actions" class="settings">
+ <span class="pagesTitle"
+ title="{{ visitor.actionDetails|length }} {{ 'General_Actions'|translate }}"
+ >{{ 'General_Actions'|translate }}:</span>&nbsp;
{% set col = 0 %}
{% for action in visitor.actionDetails %}
{% if loop.index <= maxPagesDisplayedByVisitor %}
+
{% if action.type == 'ecommerceOrder' or action.type == 'ecommerceAbandonedCart' %}
{% set title %}
{%- if action.type == 'ecommerceOrder' %}
@@ -104,7 +118,9 @@
{{ 'General_ColumnRevenue'|translate }}: {{ action.revenue|money(idSite)|raw }}
{% endif %}
</span>
+
{% else %}
+
{% set col = col + 1 %}
{% if col >= 9 %}
{% set col = 0 %}
@@ -136,6 +152,7 @@
{% endif %}
{% endif %}
{% endfor %}
+
{% if visitor.actionDetails|length > maxPagesDisplayedByVisitor %}
<em>({{ 'Live_MorePagesNotDisplayed'|translate }})</em>
{% endif %}
diff --git a/plugins/Live/tests/Integration/ModelTest.php b/plugins/Live/tests/Integration/ModelTest.php
index 355f1fb777..828d3865f0 100644
--- a/plugins/Live/tests/Integration/ModelTest.php
+++ b/plugins/Live/tests/Integration/ModelTest.php
@@ -53,7 +53,7 @@ class ModelTest extends IntegrationTestCase
AND log_visit.visit_last_action_time >= ?
AND log_visit.visit_last_action_time <= ?
ORDER BY idsite, visit_last_action_time DESC
- LIMIT 100
+ LIMIT 0, 100
) AS sub
GROUP BY sub.idvisit
ORDER BY sub.visit_last_action_time DESC
@@ -93,7 +93,7 @@ class ModelTest extends IntegrationTestCase
AND log_visit.visit_last_action_time >= ?
AND log_visit.visit_last_action_time <= ?
ORDER BY visit_last_action_time DESC
- LIMIT 100
+ LIMIT 0, 100
) AS sub
GROUP BY sub.idvisit
ORDER BY sub.visit_last_action_time DESC
@@ -154,7 +154,7 @@ class ModelTest extends IntegrationTestCase
$period = 'month',
$date = '2010-01-01',
$segment = 'customVariablePageName1==Test',
- $offset = 0,
+ $offset = 10,
$limit = 100,
$visitorId = 'abc',
$minTimestamp = false,
@@ -175,10 +175,9 @@ class ModelTest extends IntegrationTestCase
AND log_visit.visit_last_action_time <= ? )
AND ( log_link_visit_action.custom_var_k1 = ? )
ORDER BY idsite, visit_last_action_time DESC
- LIMIT 100
+ LIMIT 10, 100
) AS log_inner
ORDER BY idsite, visit_last_action_time DESC
- LIMIT 100
) AS sub
GROUP BY sub.idvisit
ORDER BY sub.visit_last_action_time DESC
diff --git a/plugins/Login/lang/en.json b/plugins/Login/lang/en.json
index 185de64c25..89a06ab7e0 100644
--- a/plugins/Login/lang/en.json
+++ b/plugins/Login/lang/en.json
@@ -12,7 +12,7 @@
"LoginOrEmail": "Username or E-mail",
"LoginPasswordNotCorrect": "Wrong Username and password combination.",
"LostYourPassword": "Lost your password?",
- "MailPasswordChangeBody": "Hi %1$s,\n\nA password reset request was received from %2$s. To confirm this password change so you can login with your new credentials, visit the following link:\n\n%3$s\n\nAttention: Changing the password will also change your token_auth. You can look up your new token_auth on your settings page.\n\nIf you are using your API token in any external applications or for archiving, make sure to update the token as requests to the API will fail otherwise.\n\nNote: this token will expire in 24 hours.\n\nAnd thank you for using Piwik!",
+ "MailPasswordChangeBody": "Hi %1$s,\n\nA password reset request was received from %2$s. To confirm this password change so you can login with your new credentials, visit the following link:\n\n%3$s\n\nAttention: Changing the password will also change your token_auth. You can look up your new token_auth on your settings page.\n\nIf you are using your API token_auth in any external applications or for archiving, make sure to update the token_auth as requests to the API will fail otherwise.\n\nNote: this link will expire in 24 hours.\n\nAnd thank you for using Piwik!",
"MailTopicPasswordChange": "Confirm Password Change",
"PasswordChanged": "Your password has been changed.",
"PasswordRepeat": "Password (repeat)",
diff --git a/plugins/LoginHttpAuth b/plugins/LoginHttpAuth
new file mode 160000
+Subproject 92978e17acd032cfcdfc1f4be4c40947b54b91e
diff --git a/plugins/MobileAppMeasurable/lang/fi.json b/plugins/MobileAppMeasurable/lang/fi.json
new file mode 100644
index 0000000000..8300bfb476
--- /dev/null
+++ b/plugins/MobileAppMeasurable/lang/fi.json
@@ -0,0 +1,7 @@
+{
+ "MobileAppMeasurable": {
+ "MobileApp": "Mobiili-app",
+ "MobileApps": "Mobiili-appit",
+ "MobileAppDescription": "Natiiviohjelmat iOS:llä, Androidilla tai millä tahansa muulla mobiilikäyttöjärjestelmällä"
+ }
+} \ No newline at end of file
diff --git a/plugins/PrivacyManager/lang/fi.json b/plugins/PrivacyManager/lang/fi.json
index bc8d0c0085..af20fe9d0c 100644
--- a/plugins/PrivacyManager/lang/fi.json
+++ b/plugins/PrivacyManager/lang/fi.json
@@ -2,6 +2,7 @@
"PrivacyManager": {
"AnonymizeIpDescription": "Valitse \"Kyllä\", jos et halua, että Piwik seuraa kokonaisia IP-osoitteita.",
"AnonymizeIpInlineHelp": "Poistaa viimeisen tavun vierailijoiden IP-osoitteista, mikäli paikalliset yksityiseensuojalait\/-ohjeistukset vaativat.",
+ "AnonymizeIpExtendedHelp": "Kun käyttäjät vierailevat sivullasi, Piwik ei tallenna täyttä IP-osoitetta (esim. %1$s), vaan sen sijaan osoite anonymisoidaan (esim. %2$s). IP-osoitteen anonymisointi on osa yksityisyydensuojasta määrääviä lakeja esimerkiksi Saksassa.",
"AnonymizeIpMaskLengtDescription": "Valitse, montako tavua käyttäjien IP-osoitteista piilotetaan.",
"AnonymizeIpMaskLength": "%1$s tavua - esim. %2$s",
"CannotLockSoDeleteLogActions": "log_action-taulua ei ole tyhjätty. Lisää \"LOCK TABLES\"-oikeus käyttäjälle %s.",
@@ -12,6 +13,8 @@
"DeleteDataDescription": "Voit säätää Piwikin poistamaan vanhat kävijätiedot ja\/tai luodut raportit, jotta tietokannan koko pysyy pienenä.",
"DeleteDataDescription2": "Voit valita, että etukäteen luodut raportit säilytetäänja ainoastaan käynnit, avatut sivut ja seurantalogit poistetaan. Tai raportit voidaan poistaa ja logit säilyttää.",
"DeleteDataInterval": "Poista vanhat tiedot joka",
+ "DeleteOldVisitorLogs": "Poista vanhat kävijälogit",
+ "DeleteOldArchivedReports": "Poista arkistoidut raportit",
"DeleteLogDescription2": "Kun lokeja poistetaan automaattisesti, sinun täytyy tarkistaa, että kaikki aikaisemmat päivittäiset raportit on prosessoitu, jotta tietoja ei häviä.",
"DeleteLogInfo": "Lokit seuraavista tauluista poistetaan: %s",
"DeleteLogsConfirm": "Olet ottamassa käyttöön lokitietojen poistamisen. Jos vanhat tiedot poistetaan ja raportteja ei ole vielä luotu, et näe historiatietoja. Haluatko varmasti tehdä tämän?",
@@ -24,6 +27,7 @@
"DeleteReportsInfo2": "Jos et ole ottanut käyttöön \"%s\":ää, vanhat raportit luodaan automaattisesti uudelleen tarvittaessa.",
"DeleteReportsInfo3": "Jos olet ottanut käyttöön \"%s\":n, vanhat tiedot poistetaan lopullisesti.",
"DeleteReportsOlderThan": "Poista raportit, jotka ovat vanhempia kuin",
+ "DeleteSchedulingSettings": "Ajoita vanhojen tietojen poisto",
"DeleteDataSettings": "Poista vanhat lokit ja raportit",
"DoNotTrack_Description": "\"Do not Track\" (älä seuraa) on teknologia, jolla käyttäjät voivat ilmoittaa etteivät halua tulla seuratuiksi.",
"DoNotTrack_Disable": "Poista \"Älä seuraa minua\" (\"do not track\") -tuki käytöstä",
@@ -38,15 +42,18 @@
"GeolocationAnonymizeIpNote": "Huom: Geopaikannuksella on suurin piirtein samat tulokset, kun 1 tavu on salattu. Jos 2 tavua tai enemmän on salattu, Geopaikannus on epätarkka.",
"GetPurgeEstimate": "Kokoarviot tietojen poistamisesta",
"KeepBasicMetrics": "Kerää yksinkertaiset metriikat (käynnit, sivujen katselut, kauppatiedot jne.)",
+ "KeepDataFor": "Säilytä kaikki tiedot",
"KeepReportSegments": "Säilytä alla listattujen tietojen lisäksi segmentoidut raportit",
"LastDelete": "Edellinen poistaminen oli",
"LeastDaysInput": "Päiviä täytyy olla enemmän kuin %s.",
"LeastMonthsInput": "Kuukausien lukumäärän täytyy olla suurempi kuin %s.",
"MenuPrivacySettings": "Yksityisyys",
"NextDelete": "Seuraava poistaminen on",
+ "PluginDescription": "Paranna kävijöiden yksityisyydensuojaa ja säädä Piwik-asennuksesi noudattamaan paikallista lainsäädäntöä",
"PurgeNow": "Siivoa tietokanta nyt",
"PurgeNowConfirm": "Olet poistamassa tietoja lopullisesti. Haluatko varmasti jatkaa?",
"PurgingData": "Siivotaan tietoja...",
+ "RecommendedForPrivacy": "Suositellaan yksityisyydensuojaan",
"ReportsDataSavedEstimate": "Tietokannan koko",
"SaveSettingsBeforePurge": "Olet muuttanut tietojen poistamisen asetuksia. Tallenna muutokset ennen jatkamista.",
"SeeAlsoOurOfficialGuidePrivacy": "Lue myös virallinen oppaamme: %1$sVerkkoanalyysi ja yksityisyys%2$s",
diff --git a/plugins/PrivacyManager/lang/nb.json b/plugins/PrivacyManager/lang/nb.json
index 87b96e9d56..8642afedbf 100644
--- a/plugins/PrivacyManager/lang/nb.json
+++ b/plugins/PrivacyManager/lang/nb.json
@@ -12,6 +12,8 @@
"DeleteMaxRowsNoLimit": "ingen grense",
"DeleteReportsOlderThan": "Slett rapporter eldre enn",
"DeleteDataSettings": "Slett gamle besøkslogger og -rapporter",
+ "DoNotTrack_Disable": "Deaktiver Do Not Track støtte",
+ "DoNotTrack_Enable": "Aktiver Do Not Track støtte",
"EstimatedSpaceSaved": "Estimert plassbesparelse",
"GeolocationAnonymizeIpNote": "Merk: Geoposisjonering vil ha omtrent de samme resultatene med en byte anonymisert. Med to byte eller mer, vil geoposisjonering være unøyaktig.",
"KeepDataFor": "Behold all data for",
diff --git a/plugins/Provider/lang/fi.json b/plugins/Provider/lang/fi.json
index bf079428c4..cce8a9cac5 100644
--- a/plugins/Provider/lang/fi.json
+++ b/plugins/Provider/lang/fi.json
@@ -1,7 +1,9 @@
{
"Provider": {
"ColumnProvider": "Palveluntarjoajat",
+ "PluginDescription": "Raportoi kävijöiden internetoperaattorin",
"ProviderReportDocumentation": "Tämä raportti näyttää, mitä internetin toimittajia kävijäsi käyttivät sivuillasi. Saat lisätietoja klikkaamalla toimittajan nimeä. %s Jos Piwik ei tunnista toimittajan nimeä, kävijästä näytetään IP.",
- "WidgetProviders": "Palveluntarjoajat"
+ "WidgetProviders": "Palveluntarjoajat",
+ "ProviderReportFooter": "Tuntematon toimittaja ei selvitä IP-osoitteita"
}
} \ No newline at end of file
diff --git a/plugins/QueuedTracking b/plugins/QueuedTracking
-Subproject 39b949806240c93beef5d0308988f608b643788
+Subproject a7137646fa4d738c6378686df6cd222fd291217
diff --git a/plugins/Referrers/lang/fi.json b/plugins/Referrers/lang/fi.json
index a4e985a12b..3f877a70ea 100644
--- a/plugins/Referrers/lang/fi.json
+++ b/plugins/Referrers/lang/fi.json
@@ -20,10 +20,12 @@
"EvolutionDocumentationMoreInfo": "Löydät lisätietoja erilaisista viittaustyypeistä taulun %s dokumentaatiosta.",
"Keywords": "Avainsanat",
"KeywordsReportDocumentation": "Tämä rapotti näyttää, millä hakusanoilla kävijät tulivat sivuillesi. %s Näet hakukoneiden määrän klikkaamalla hakusanaa.",
+ "PluginDescription": "Raportoi viittaajiin liittyvää tietoa: hakukoneet, hakusanat, verkkosivut, kampanjat, sosiaalisen median, suorat saapumiset.",
"Referrer": "Viittaukset",
"ReferrerName": "Viittauksen nimi",
"Referrers": "Viittaajat",
"ReferrersOverview": "Viittauksien yleiskatsaus",
+ "ReferrerTypes": "Viittaajatyypit",
"SearchEngines": "Hakukoneet",
"SearchEnginesDocumentation": "Kävijä tuli sivullesi hakukoneesta. %1$s Katso %2$s raportista lisätietoja.",
"SearchEnginesReportDocumentation": "Tämä raportti näyttää, mitkä hakukoneet viittasivat kävijöitä sivuillesi. %s Näet hakusanat klikkaamalla hakukoneen nimeä.",
diff --git a/plugins/SEO/lang/fi.json b/plugins/SEO/lang/fi.json
index 354270e2d3..02accf4536 100644
--- a/plugins/SEO/lang/fi.json
+++ b/plugins/SEO/lang/fi.json
@@ -1,5 +1,6 @@
{
"SEO": {
+ "PluginDescription": "Tämä lisäosa hakee ja näyttää SEO-tietoja: Alexan web ranking, Googlen Pagerank, indeksoitujen sivujen lukumäärän, ja takaisin osoittavien linkkien määrän valitulle sivulle.",
"AlexaRank": "Alexa-tulos",
"Bing_IndexedPages": "Bingin indeksoidut sivut",
"Dmoz": "DMOZ tulossivut",
diff --git a/plugins/SecurityInfo b/plugins/SecurityInfo
-Subproject 8647523ae5de07f5dbfc9f50476c9bb661a51b3
+Subproject 85790278f1c34d2b12c9a4d846df81daee905bb
diff --git a/plugins/SegmentEditor/lang/fi.json b/plugins/SegmentEditor/lang/fi.json
index de72617253..7aab90628c 100644
--- a/plugins/SegmentEditor/lang/fi.json
+++ b/plugins/SegmentEditor/lang/fi.json
@@ -16,10 +16,17 @@
"SegmentDisplayedAllWebsites": "kaikki sivut",
"SegmentDisplayedThisWebsiteOnly": "vain tällä verkkosivulla",
"SegmentNotApplied": "Segmenttiä '%s' ei sovelleta",
+ "SelectSegmentOfVisits": "Valitse segmentit käynnille:",
"ThisSegmentIsVisibleTo": "Tämä segmentti näytetään seuraaville:",
"VisibleToAllUsers": "kaikki käyttäjät",
"VisibleToMe": "minä",
"YouMayChangeSetting": "Vaihtoehtoisesti voit vaihtaa asetuksen tiedostosta %1$s, tai muuttaa tätä segmenttiä ja valita '%2$s'.",
- "YouMustBeLoggedInToCreateSegments": "Sinun täytyy olla sisäänkirjautuneena voidaksesi luoda tai muokata kävijäsegmenttejä."
+ "VisibleToSuperUser": "Näkyvissä sinulle, koska sinulla on pääkäyttäjän oikeudet",
+ "SharedWithYou": "Jaettu kanssasi",
+ "YouMustBeLoggedInToCreateSegments": "Sinun täytyy olla sisäänkirjautuneena voidaksesi luoda tai muokata kävijäsegmenttejä.",
+ "AddingSegmentForAllWebsitesDisabled": "Segmenttien lisääminen kaikille verkkosivuille on poistettu käytöstä.",
+ "CustomSegment": "Kustomoidut segmentit",
+ "SegmentOperatorIsNullOrEmpty": "on tyhjä",
+ "SegmentOperatorIsNotNullNorEmpty": "ei ole tyhjä"
}
} \ No newline at end of file
diff --git a/plugins/SitesManager/API.php b/plugins/SitesManager/API.php
index 739af7d5e9..d6b969f9ad 100644
--- a/plugins/SitesManager/API.php
+++ b/plugins/SitesManager/API.php
@@ -491,6 +491,7 @@ class API extends \Piwik\Plugin\API
* @param array|string $urls The URLs array must contain at least one URL called the 'main_url' ;
* if several URLs are provided in the array, they will be recorded
* as Alias URLs for this website.
+ * When calling API via HTTP specify multiple URLs via `&urls[]=http...&urls[]=http...`.
* @param int $ecommerce Is Ecommerce Reporting enabled for this website?
* @param null $siteSearch
* @param string $searchKeywordParameters Comma separated list of search keyword parameter names
@@ -767,7 +768,7 @@ class API extends \Piwik\Plugin\API
* they won't be duplicated. The 'main_url' of the website won't be affected by this method.
*
* @param int $idSite
- * @param array|string $urls
+ * @param array|string $urls When calling API via HTTP specify multiple URLs via `&urls[]=http...&urls[]=http...`.
* @return int the number of inserted URLs
*/
public function addSiteAliasUrls($idSite, $urls)
@@ -1077,6 +1078,7 @@ class API extends \Piwik\Plugin\API
* @param int $idSite website ID defining the website to edit
* @param string $siteName website name
* @param string|array $urls the website URLs
+ * When calling API via HTTP specify multiple URLs via `&urls[]=http...&urls[]=http...`.
* @param int $ecommerce Whether Ecommerce is enabled, 0 or 1
* @param null|int $siteSearch Whether site search is enabled, 0 or 1
* @param string $searchKeywordParameters Comma separated list of search keyword parameter names
diff --git a/plugins/SitesManager/Controller.php b/plugins/SitesManager/Controller.php
index fc7b7eb6e8..d64fb45fa9 100644
--- a/plugins/SitesManager/Controller.php
+++ b/plugins/SitesManager/Controller.php
@@ -63,7 +63,6 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
$response = new ResponseBuilder(Common::getRequestVar('format'));
$globalSettings = array();
-
$globalSettings['keepURLFragmentsGlobal'] = API::getInstance()->getKeepURLFragmentsGlobal();
$globalSettings['siteSpecificUserAgentExcludeEnabled'] = API::getInstance()->isSiteSpecificUserAgentExcludeEnabled();
$globalSettings['defaultCurrency'] = API::getInstance()->getDefaultCurrency();
diff --git a/plugins/SitesManager/Menu.php b/plugins/SitesManager/Menu.php
index a9e82e6024..d242a25351 100644
--- a/plugins/SitesManager/Menu.php
+++ b/plugins/SitesManager/Menu.php
@@ -44,6 +44,7 @@ class Menu extends \Piwik\Plugin\Menu
if (count($types) === 1) {
// only one type is in use, use this one for the wording
return reset($types);
+
} else {
// multiple types are activated, check whether only one is actually in use
$model = new Model();
diff --git a/plugins/SitesManager/Model.php b/plugins/SitesManager/Model.php
index 96062b608a..5e69d308e7 100644
--- a/plugins/SitesManager/Model.php
+++ b/plugins/SitesManager/Model.php
@@ -41,8 +41,9 @@ class Model
*/
public function getSitesFromGroup($group)
{
- $sites = $this->getDb()->fetchAll("SELECT * FROM " . $this->table . "
- WHERE `group` = ?", $group);
+ $db = $this->getDb();
+ $sites = $db->fetchAll("SELECT * FROM " . $this->table . "
+ WHERE `group` = ?", $group);
return $sites;
}
@@ -55,7 +56,8 @@ class Model
*/
public function getSitesGroups()
{
- $groups = $this->getDb()->fetchAll("SELECT DISTINCT `group` FROM " . $this->table);
+ $db = $this->getDb();
+ $groups = $db->fetchAll("SELECT DISTINCT `group` FROM " . $this->table);
$cleanedGroups = array();
foreach ($groups as $group) {
@@ -72,7 +74,8 @@ class Model
*/
public function getAllSites()
{
- $sites = $this->getDb()->fetchAll("SELECT * FROM " . $this->table . " ORDER BY idsite ASC");
+ $db = $this->getDb();
+ $sites = $db->fetchAll("SELECT * FROM " . $this->table . " ORDER BY idsite ASC");
return $sites;
}
@@ -111,7 +114,8 @@ class Model
{
$siteUrlTable = Common::prefixTable('site_url');
- $ids = $this->getDb()->fetchAll(
+ $db = $this->getDb();
+ $ids = $db->fetchAll(
'SELECT idsite FROM ' . $this->table . '
WHERE main_url IN ( ' . Common::getSqlStringFieldsArray($urls) . ') ' .
'UNION
@@ -137,7 +141,8 @@ class Model
$siteUrlTable = Common::prefixTable('site_url');
$sqlAccessSite = Access::getSqlAccessSite('idsite');
- $ids = $this->getDb()->fetchAll(
+ $db = $this->getDb();
+ $ids = $db->fetchAll(
'SELECT idsite
FROM ' . $this->table . '
WHERE main_url IN ( ' . Common::getSqlStringFieldsArray($urls) . ')' .
@@ -171,7 +176,8 @@ class Model
$query = 'SELECT idsite FROM ' . $this->table . '
WHERE timezone IN (' . Common::getSqlStringFieldsArray($timezones) . ')
ORDER BY idsite ASC';
- $sites = $this->getDb()->fetchAll($query, $timezones);
+ $db = $this->getDb();
+ $sites = $db->fetchAll($query, $timezones);
return $sites;
}
@@ -223,8 +229,9 @@ class Model
*/
public function getSiteFromId($idSite)
{
- $site = $this->getDb()->fetchRow("SELECT * FROM " . $this->table . "
- WHERE idsite = ?", $idSite);
+ $db = $this->getDb();
+ $site = $db->fetchRow("SELECT * FROM " . $this->table . "
+ WHERE idsite = ?", $idSite);
return $site;
}
@@ -237,7 +244,7 @@ class Model
*/
public function getSitesId()
{
- $result = Db::fetchAll("SELECT idsite FROM " . Common::prefixTable('site'));
+ $result = Db::fetchAll("SELECT idsite FROM " . Common::prefixTable('site'));
$idSites = array();
foreach ($result as $idSite) {
@@ -277,7 +284,8 @@ class Model
{
$db = $this->getDb();
$result = $db->fetchAll("SELECT url FROM " . Common::prefixTable("site_url") . "
- WHERE idsite = ?", $idSite);
+ WHERE idsite = ?", $idSite);
+
$urls = array();
foreach ($result as $url) {
$urls[] = $url['url'];
@@ -354,7 +362,9 @@ class Model
public function getUsedTypeIds()
{
$types = array();
- $rows = $this->getDb()->fetchAll("SELECT DISTINCT `type` as typeid FROM " . $this->table);
+
+ $db = $this->getDb();
+ $rows = $db->fetchAll("SELECT DISTINCT `type` as typeid FROM " . $this->table);
foreach ($rows as $row) {
$types[] = $row['typeid'];
diff --git a/plugins/SitesManager/angularjs/sites-manager/multiline-field.directive.html b/plugins/SitesManager/angularjs/sites-manager/multiline-field.directive.html
index fed8822dc1..2e1bf44bf7 100644
--- a/plugins/SitesManager/angularjs/sites-manager/multiline-field.directive.html
+++ b/plugins/SitesManager/angularjs/sites-manager/multiline-field.directive.html
@@ -3,5 +3,4 @@
rows="{{ rows }}"
ng-model="field.value"
ng-change="onChange()">
-
</textarea>
diff --git a/plugins/SitesManager/angularjs/sites-manager/sites-manager-site.controller.js b/plugins/SitesManager/angularjs/sites-manager/sites-manager-site.controller.js
index d759ec940f..0fac17cc22 100644
--- a/plugins/SitesManager/angularjs/sites-manager/sites-manager-site.controller.js
+++ b/plugins/SitesManager/angularjs/sites-manager/sites-manager-site.controller.js
@@ -135,22 +135,25 @@
"http://siteUrl2.com/"
];
$scope.site.exclude_unknown_urls = 0;
- $scope.site.keep_url_fragment = "0";
+ $scope.site.keep_url_fragment = 0;
$scope.site.excluded_ips = [];
$scope.site.excluded_parameters = [];
$scope.site.excluded_user_agents = [];
$scope.site.sitesearch_keyword_parameters = [];
$scope.site.sitesearch_category_parameters = [];
- $scope.site.sitesearch = $scope.globalSettings.searchKeywordParametersGlobal.length ? "1" : "0";
+ $scope.site.sitesearch = $scope.globalSettings.searchKeywordParametersGlobal.length ? 1 : 0;
$scope.site.timezone = $scope.globalSettings.defaultTimezone;
$scope.site.currency = $scope.globalSettings.defaultCurrency;
- $scope.site.ecommerce = "0";
+ $scope.site.ecommerce = 0;
updateSiteWithSiteSearchConfig();
};
var initExistingSite = function() {
+ $scope.site.keep_url_fragment = parseInt($scope.site.keep_url_fragment, 10);
+ $scope.site.ecommerce = parseInt($scope.site.ecommerce, 10);
+ $scope.site.sitesearch = parseInt($scope.site.sitesearch, 10);
$scope.site.excluded_ips = sitesManagerApiHelper.commaDelimitedFieldToArray($scope.site.excluded_ips);
$scope.site.excluded_parameters = sitesManagerApiHelper.commaDelimitedFieldToArray($scope.site.excluded_parameters);
$scope.site.excluded_user_agents = sitesManagerApiHelper.commaDelimitedFieldToArray($scope.site.excluded_user_agents);
diff --git a/plugins/SitesManager/angularjs/sites-manager/sites-manager.controller.js b/plugins/SitesManager/angularjs/sites-manager/sites-manager.controller.js
index b5d7ec0213..66c27a7703 100644
--- a/plugins/SitesManager/angularjs/sites-manager/sites-manager.controller.js
+++ b/plugins/SitesManager/angularjs/sites-manager/sites-manager.controller.js
@@ -118,8 +118,8 @@
var initEcommerceSelectOptions = function() {
$scope.eCommerceptions = [
- {key: '0', value: translate('SitesManager_NotAnEcommerceSite')},
- {key: '1', value: translate('SitesManager_EnableEcommerce')}
+ {key: 0, value: translate('SitesManager_NotAnEcommerceSite')},
+ {key: 1, value: translate('SitesManager_EnableEcommerce')}
];
};
@@ -189,18 +189,17 @@
var initSiteSearchSelectOptions = function() {
$scope.siteSearchOptions = [
- {key: '1', value: translate('SitesManager_EnableSiteSearch')},
- {key: '0', value: translate('SitesManager_DisableSiteSearch')}
+ {key: 1, value: translate('SitesManager_EnableSiteSearch')},
+ {key: 0, value: translate('SitesManager_DisableSiteSearch')}
];
};
var initKeepURLFragmentsList = function() {
-
- $scope.keepURLFragmentsOptions = {
- 0: ($scope.globalSettings.keepURLFragmentsGlobal ? translate('General_Yes') : translate('General_No')) + ' (' + translate('General_Default') + ')',
- 1: translate('General_Yes'),
- 2: translate('General_No')
- };
+ $scope.keepURLFragmentsOptions = [
+ {key: 0, value: ($scope.globalSettings.keepURLFragmentsGlobal ? translate('General_Yes') : translate('General_No')) + ' (' + translate('General_Default') + ')'},
+ {key: 1, value: translate('General_Yes')},
+ {key: 2, value: translate('General_No')}
+ ];
};
var addNewEntity = function () {
diff --git a/plugins/SitesManager/lang/el.json b/plugins/SitesManager/lang/el.json
index e8636db0ad..a6b2092a5a 100644
--- a/plugins/SitesManager/lang/el.json
+++ b/plugins/SitesManager/lang/el.json
@@ -11,7 +11,7 @@
"DefaultCurrencyForNewWebsites": "Προεπιλεγμένο Νόμισμα για νέες ιστοσελίδες",
"DefaultTimezoneForNewWebsites": "Προεπιλεγμένη Ζώνη ώρας για νέες ιστοσελίδες",
"DeleteConfirm": "Είστε σίγουρος ότι θέλετε να διαγράψετε την ιστοσελίδα %s?",
- "DisableSiteSearch": "Να μην καταγράφετε η Αναζήτηση Σελίδας",
+ "DisableSiteSearch": "Να μην καταγράφεται η Αναζήτηση Σελίδας",
"EcommerceHelp": "Όταν ενεργοποιηθεί, η αναφορά «Στόχοι» θα έχει ένα νέο τομέα «Ηλεκτρονικό Εμπόριο».",
"EnableEcommerce": "Το Ηλεκτρονικό Εμπόριο ενεργοποιήθηκε",
"EnableSiteSearch": "Η καταγραφή Αναζήτησης Ιστοσελίδας είναι ενεργοποιημένη",
diff --git a/plugins/SitesManager/lang/ru.json b/plugins/SitesManager/lang/ru.json
index db55be9cfc..f4b1a26d6d 100644
--- a/plugins/SitesManager/lang/ru.json
+++ b/plugins/SitesManager/lang/ru.json
@@ -1,6 +1,7 @@
{
"SitesManager": {
"AddSite": "Добавить новый сайт",
+ "AddMeasurable": "Добавить новые показатели",
"AdvancedTimezoneSupportNotFound": "Поддержка дополнительных временных зон не найдена в вашем PHP (поддерживается в PHP>=5.2). Вы все еще можете выбрать UTC вручную вместо этого.",
"AliasUrlHelp": "Рекомендуется, но необязательно, указывать все домены для сайта (каждый домен – новая линия), которые пользователи могут использовать для доступа к сайту. Псевдонимы для различных доменов сайта не будут отображаться в разделе Источики трафика > Сайты. Заметьте, что нет необходимости указывать варианты адресов с \"www\" и без него. Piwik автоматически учитывает оба.",
"ChangingYourTimezoneWillOnlyAffectDataForward": "Изменение вашего часового пояса только повлияет на то, что данные будут учитываться наперед, и никак не повлияет на существующие данные.",
@@ -64,6 +65,7 @@
"ShowTrackingTag": "Показать код",
"Sites": "Сайты",
"SiteSearchUse": "Вы можете использовать Piwik для отслеживания и отображения аналитики по тому, что ищут посетители на вашем сайте используя функционал для внутреннего поиска по сайту.",
+ "SiteWithoutDataTitle": "Ещё ни какие данные не были записаны",
"SuperUserAccessCan": "Пользователь с правами суперпользователя может также %1$sуказать общие настройки%2$s для новых веб-сайтов.",
"Timezone": "Часовой пояс",
"TrackingSiteSearch": "Отслеживать внутренний поиск по сайту",
@@ -71,6 +73,8 @@
"Urls": "URL-ы",
"UTCTimeIs": "Время UTC: %s.",
"WebsitesManagement": "Управление сайтами",
+ "XManagement": "Управление %s",
+ "ChooseMeasurableTypeHeadline": "Чтобы вы хотели измерить?",
"YouCurrentlyHaveAccessToNWebsites": "В данный момент вы имеете доступ к %s сайтам.",
"YourCurrentIpAddressIs": "Ваш IP: %s"
}
diff --git a/plugins/SitesManager/templates/dialogs/dialogs.html b/plugins/SitesManager/templates/dialogs/dialogs.html
index 476505e7bf..2f3d5d8072 100644
--- a/plugins/SitesManager/templates/dialogs/dialogs.html
+++ b/plugins/SitesManager/templates/dialogs/dialogs.html
@@ -1,3 +1,2 @@
<div ng-include="'plugins/SitesManager/templates/dialogs/edit-dialog.html'"></div>
-
<div ng-include="'plugins/SitesManager/templates/dialogs/remove-dialog.html'"></div>
diff --git a/plugins/SitesManager/templates/dialogs/edit-dialog.html b/plugins/SitesManager/templates/dialogs/edit-dialog.html
index afb9910869..1bb6067f47 100644
--- a/plugins/SitesManager/templates/dialogs/edit-dialog.html
+++ b/plugins/SitesManager/templates/dialogs/edit-dialog.html
@@ -1,5 +1,4 @@
<div class="ui-confirm" piwik-dialog="site.editDialog.show">
-
<h2>{{ site.editDialog.title }}</h2>
<input role="no" type="button" value="{{ 'General_Ok'|translate }}"/>
diff --git a/plugins/SitesManager/templates/displayJavascriptCode.twig b/plugins/SitesManager/templates/displayJavascriptCode.twig
index 9b514b69c0..05d867030e 100644
--- a/plugins/SitesManager/templates/displayJavascriptCode.twig
+++ b/plugins/SitesManager/templates/displayJavascriptCode.twig
@@ -1,6 +1,5 @@
{% extends 'admin.twig' %}
{% block content %}
-
{% include "@SitesManager/_displayJavascriptCode.twig" %}
{% endblock %} \ No newline at end of file
diff --git a/plugins/SitesManager/templates/help/timezone-help.html b/plugins/SitesManager/templates/help/timezone-help.html
index 0308b783b5..f77ad7863e 100644
--- a/plugins/SitesManager/templates/help/timezone-help.html
+++ b/plugins/SitesManager/templates/help/timezone-help.html
@@ -9,10 +9,7 @@
</span>
<br/>
-
{{ 'SitesManager_UTCTimeIs'| translate : (utcTime | date : 'yyyy-MM-dd HH:mm:ss') }}
-
<br/>
-
{{ 'SitesManager_ChangingYourTimezoneWillOnlyAffectDataForward'|translate }}
</div>
diff --git a/plugins/SitesManager/templates/index.html b/plugins/SitesManager/templates/index.html
index cfdca4a970..adedf3e644 100644
--- a/plugins/SitesManager/templates/index.html
+++ b/plugins/SitesManager/templates/index.html
@@ -1,17 +1,9 @@
<div ng-controller="SitesManagerController" class="SitesManager">
-
<div ng-include="'plugins/SitesManager/templates/sites-manager-header.html?cb=' + cacheBuster" class="sites-manager-header"></div>
-
<div ng-include="'plugins/SitesManager/templates/loading.html?cb=' + cacheBuster"></div>
-
<div ng-include="'plugins/SitesManager/templates/sites-list/add-site-link.html?cb=' + cacheBuster"></div>
-
<div ng-include="'plugins/SitesManager/templates/sites-list/add-entity-dialog.html?cb=' + cacheBuster"></div>
-
<div ng-include="'plugins/SitesManager/templates/sites-list/sites-list.html?cb=' + cacheBuster"></div>
-
<div class="bottomButtonBar" ng-include="'plugins/SitesManager/templates/sites-list/add-site-link.html?cb=' + cacheBuster"></div>
-
<div ng-include="'plugins/SitesManager/templates/global-settings.html?cb=' + cacheBuster"></div>
-
</div>
diff --git a/plugins/SitesManager/templates/siteWithoutData.twig b/plugins/SitesManager/templates/siteWithoutData.twig
index 498d2ee765..b1a659f31a 100644
--- a/plugins/SitesManager/templates/siteWithoutData.twig
+++ b/plugins/SitesManager/templates/siteWithoutData.twig
@@ -33,7 +33,7 @@
{{ 'SitesManager_SiteWithoutDataSetupTracking'|translate('<a href="' ~ linkTo({
'module': 'CoreAdminHome',
'action': 'trackingCodeGenerator',
- }) ~ '">', '</a>')|raw }}
+ }) ~ '">', "</a>")|raw }}
</p>
<p>
@@ -41,7 +41,7 @@
{{ 'SitesManager_SiteWithoutDataSetupGoals'|translate('<a href="' ~ linkTo({
'module': 'Goals',
'action': 'manage',
- }) ~ '">', '</a>')|raw }}
+ }) ~ '">', "</a>")|raw }}
</p>
{{ trackingHelp|raw }}
diff --git a/plugins/SitesManager/templates/sites-list/site-fields.html b/plugins/SitesManager/templates/sites-list/site-fields.html
index 200e935e27..2f0eaa7b76 100644
--- a/plugins/SitesManager/templates/sites-list/site-fields.html
+++ b/plugins/SitesManager/templates/sites-list/site-fields.html
@@ -94,7 +94,7 @@
<div class="form-group">
<label>{{ 'SitesManager_KeepURLFragmentsLong'|translate }}</label>
- <select ng-options="key as value for (key, value) in keepURLFragmentsOptions"
+ <select ng-options="option.key as option.value for option in keepURLFragmentsOptions"
ng-model="site.keep_url_fragment"></select>
</div>
diff --git a/plugins/TasksTimetable b/plugins/TasksTimetable
-Subproject 53ab383e4d19963441b2e8c8211fac3ac9426cb
+Subproject 8212ef0033dd2b3731fccd39c498f61d6ca8147
diff --git a/plugins/Transitions/API.php b/plugins/Transitions/API.php
index 1ab38f89ae..4304e2a281 100644
--- a/plugins/Transitions/API.php
+++ b/plugins/Transitions/API.php
@@ -222,7 +222,8 @@ class API extends \Piwik\Plugin\API
if ($actionType != 'title') {
// specific setup for page urls
$types[Action::TYPE_PAGE_URL] = 'followingPages';
- $dimension = 'if ( idaction_url IS NULL, idaction_name, idaction_url )';
+ $dimension = 'if ( %1$s.idaction_url IS NULL, %1$s.idaction_name, %1$s.idaction_url )';
+ $dimension = sprintf($dimension, 'log_link_visit_action' );
// site search referrers are logged with url=NULL
// when we find one, we have to join on name
$joinLogActionColumn = $dimension;
@@ -405,7 +406,8 @@ class API extends \Piwik\Plugin\API
if ($dimension == 'idaction_url_ref') {
// site search referrers are logged with url_ref=NULL
// when we find one, we have to join on name_ref
- $dimension = 'if ( idaction_url_ref IS NULL, idaction_name_ref, idaction_url_ref )';
+ $dimension = 'if ( %1$s.idaction_url_ref IS NULL, %1$s.idaction_name_ref, %1$s.idaction_url_ref )';
+ $dimension = sprintf($dimension, 'log_link_visit_action');
$joinLogActionOn = $dimension;
} else {
$joinLogActionOn = $dimension;
diff --git a/plugins/Transitions/lang/fi.json b/plugins/Transitions/lang/fi.json
index 246303c4df..df5c6bc3a8 100644
--- a/plugins/Transitions/lang/fi.json
+++ b/plugins/Transitions/lang/fi.json
@@ -16,6 +16,7 @@
"NoDataForAction": "%s:lle ei ole tietoja",
"NoDataForActionDetails": "Joko toiminnolle ei ole tietoja aikavälille %s tai toiminto on virheellinen.",
"OutgoingTraffic": "Lähtevä liikenne",
+ "PluginDescription": "Raportoi edellisen ja seuraavat toiminnot jokaiselle sivulle. Saatavilla \"Toiminnot\"-raportissa uuden ikonin takaa.",
"ShareOfAllPageviews": "Tällä sivulla on %1$s sivunavausta (%2$s kaikista)",
"ToFollowingPages": "Sisäisille sivuille",
"ToFollowingPagesInline": "%s sisäisille sivuille",
diff --git a/plugins/TreemapVisualization b/plugins/TreemapVisualization
-Subproject e487d14390a4b99504a38ba6237705c10317b12
+Subproject a74d9a9b29d257a00b7cb1b51f70997e45ee23c
diff --git a/plugins/UserCountry/Commands/AttributeHistoricalDataWithLocations.php b/plugins/UserCountry/Commands/AttributeHistoricalDataWithLocations.php
index 5e617f53e6..c5eaf833da 100644
--- a/plugins/UserCountry/Commands/AttributeHistoricalDataWithLocations.php
+++ b/plugins/UserCountry/Commands/AttributeHistoricalDataWithLocations.php
@@ -145,7 +145,7 @@ class AttributeHistoricalDataWithLocations extends ConsoleCommand
* Print information about progress.
* @param OutputInterface $output
*/
- protected function onVisitProcessed(OutputInterface $output)
+ public function onVisitProcessed(OutputInterface $output)
{
++$this->processed;
@@ -199,4 +199,4 @@ class AttributeHistoricalDataWithLocations extends ConsoleCommand
return $geolocator;
}
-} \ No newline at end of file
+}
diff --git a/plugins/UserCountry/lang/fi.json b/plugins/UserCountry/lang/fi.json
index 98ea0c0518..1cb6e70cb2 100644
--- a/plugins/UserCountry/lang/fi.json
+++ b/plugins/UserCountry/lang/fi.json
@@ -16,6 +16,7 @@
"country_a2": "Satelliittiyhteys",
"country_cat": "Katalaania puhuvat alueet",
"country_o1": "Muu maa",
+ "country_ti": "Tiibet",
"CurrentLocationIntro": "Tämän toteutuksen mukaan nykyinen sijaintisi on",
"DefaultLocationProviderDesc1": "Oletustoteutus arvaa käyttäjien maan kielen perusteella.",
"DefaultLocationProviderDesc2": "Tämä ei ole erityisen tarkkaa, joten %1$ssuosittelemme asentamaan ja käyttämään %2$sGeoIp:tä%3$s.%4$s",
diff --git a/plugins/UserCountry/lang/nb.json b/plugins/UserCountry/lang/nb.json
index 34b842e32d..155ec58045 100644
--- a/plugins/UserCountry/lang/nb.json
+++ b/plugins/UserCountry/lang/nb.json
@@ -1,5 +1,6 @@
{
"UserCountry": {
+ "AssumingNonApache": "Kan ikke finne apache_get_modules-funksjonen. Antar at det ikke er en Apache webserver.",
"CannotFindGeoIPDatabaseInArchive": "Kan ikke finne filen %1$s i tar-arkivet %2$s!",
"CannotListContent": "Kunne ikke vise innhold for %1$s: %2$s",
"CannotLocalizeLocalIP": "IP-adressen %s er en lokal adresse og kan ikke lokaliseres.",
@@ -24,6 +25,7 @@
"HowToInstallGeoIpPecl": "Hvordan installerer jeg GeoIP PECL-utvidelsen?",
"HowToInstallNginxModule": "Hvordan installerer jeg GeoIP-modulen for Nginx?",
"HowToSetupGeoIP_Step1": "%1$sLast ned%2$s GeoLite City-databasen fra %3$sMaxMind%4$s.",
+ "HttpServerModule": "HTTP Server-modul",
"ISPDatabase": "ISP-database",
"IWantToDownloadFreeGeoIP": "Jeg vil laste ned gratis GeoIP-database...",
"Latitude": "Breddegrad",
diff --git a/plugins/UserCountryMap/lang/fi.json b/plugins/UserCountryMap/lang/fi.json
index 9da534097e..ab377390bd 100644
--- a/plugins/UserCountryMap/lang/fi.json
+++ b/plugins/UserCountryMap/lang/fi.json
@@ -1,5 +1,6 @@
{
"UserCountryMap": {
+ "PluginDescription": "Tämä lisäosa tarjoaa käyttäjäkartan ja reaaliaikakartan. Huom: \"UserCountry\"-lisäosan täytyy olla päällä.",
"AndNOthers": "ja %s muuta",
"Cities": "Kaupunkeja",
"Countries": "Maita",
@@ -17,6 +18,8 @@
"ShowingVisits": "Geopaikannetut käynnit viimeiset",
"Unlocated": "<b>%s<\/b> %p käynneistä %c:sta ei voitu geopaikantaa.",
"VisitorMap": "Kartta kävijöistä",
- "WorldWide": "Maailmanlaajuinen"
+ "WorldWide": "Maailmanlaajuinen",
+ "WithUnknownRegion": "%s tuntemattomalta alueelta",
+ "WithUnknownCity": "%s tuntemattomista kaupungeista"
}
} \ No newline at end of file
diff --git a/plugins/UserLanguage/lang/fi.json b/plugins/UserLanguage/lang/fi.json
index 57a7794cc9..140e43780b 100644
--- a/plugins/UserLanguage/lang/fi.json
+++ b/plugins/UserLanguage/lang/fi.json
@@ -1,6 +1,7 @@
{
"UserLanguage": {
"BrowserLanguage": "Selaimen kieli",
- "LanguageCode": "Kielikoodi"
+ "LanguageCode": "Kielikoodi",
+ "PluginDescription": "Raportoi käyttäjän selaimen kieliasetukset."
}
} \ No newline at end of file
diff --git a/plugins/UsersManager/Model.php b/plugins/UsersManager/Model.php
index e6c0971867..db0285eab6 100644
--- a/plugins/UsersManager/Model.php
+++ b/plugins/UsersManager/Model.php
@@ -50,9 +50,10 @@ class Model
$bind = $userLogins;
}
- $users = $this->getDb()->fetchAll("SELECT * FROM " . $this->table . "
- $where
- ORDER BY login ASC", $bind);
+ $db = $this->getDb();
+ $users = $db->fetchAll("SELECT * FROM " . $this->table . "
+ $where
+ ORDER BY login ASC", $bind);
return $users;
}
@@ -64,7 +65,8 @@ class Model
*/
public function getUsersLogin()
{
- $users = $this->getDb()->fetchAll("SELECT login FROM " . $this->table . " ORDER BY login ASC");
+ $db = $this->getDb();
+ $users = $db->fetchAll("SELECT login FROM " . $this->table . " ORDER BY login ASC");
$return = array();
foreach ($users as $login) {
@@ -76,9 +78,10 @@ class Model
public function getUsersSitesFromAccess($access)
{
- $users = $this->getDb()->fetchAll("SELECT login,idsite FROM " . Common::prefixTable("access")
- . " WHERE access = ?
- ORDER BY login, idsite", $access);
+ $db = $this->getDb();
+ $users = $db->fetchAll("SELECT login,idsite FROM " . Common::prefixTable("access")
+ . " WHERE access = ?
+ ORDER BY login, idsite", $access);
$return = array();
foreach ($users as $user) {
@@ -90,8 +93,9 @@ class Model
public function getUsersAccessFromSite($idSite)
{
- $users = $this->getDb()->fetchAll("SELECT login,access FROM " . Common::prefixTable("access")
- . " WHERE idsite = ?", $idSite);
+ $db = $this->getDb();
+ $users = $db->fetchAll("SELECT login,access FROM " . Common::prefixTable("access")
+ . " WHERE idsite = ?", $idSite);
$return = array();
foreach ($users as $user) {
@@ -103,7 +107,8 @@ class Model
public function getUsersLoginWithSiteAccess($idSite, $access)
{
- $users = $this->getDb()->fetchAll("SELECT login
+ $db = $this->getDb();
+ $users = $db->fetchAll("SELECT login
FROM " . Common::prefixTable("access")
. " WHERE idsite = ? AND access = ?", array($idSite, $access));
@@ -133,7 +138,8 @@ class Model
*/
public function getSitesAccessFromUser($userLogin)
{
- $users = $this->getDb()->fetchAll("SELECT idsite,access FROM " . Common::prefixTable("access")
+ $db = $this->getDb();
+ $users = $db->fetchAll("SELECT idsite,access FROM " . Common::prefixTable("access")
. " WHERE login = ?", $userLogin);
$return = array();
@@ -167,12 +173,14 @@ class Model
public function getUserByEmail($userEmail)
{
- return $this->getDb()->fetchRow("SELECT * FROM " . $this->table . " WHERE email = ?", $userEmail);
+ $db = $this->getDb();
+ return $db->fetchRow("SELECT * FROM " . $this->table . " WHERE email = ?", $userEmail);
}
public function getUserByTokenAuth($tokenAuth)
{
- return $this->getDb()->fetchRow('SELECT * FROM ' . $this->table . ' WHERE token_auth = ?', $tokenAuth);
+ $db = $this->getDb();
+ return $db->fetchRow('SELECT * FROM ' . $this->table . ' WHERE token_auth = ?', $tokenAuth);
}
public function addUser($userLogin, $passwordTransformed, $email, $alias, $tokenAuth, $dateRegistered)
@@ -187,17 +195,31 @@ class Model
'superuser_access' => 0
);
- $this->getDb()->insert($this->table, $user);
+ $db = $this->getDb();
+ $db->insert($this->table, $user);
}
public function setSuperUserAccess($userLogin, $hasSuperUserAccess)
{
- $this->getDb()->update($this->table,
- array(
- 'superuser_access' => $hasSuperUserAccess ? 1 : 0
- ),
- "login = '$userLogin'"
- );
+ $this->updateUserFields($userLogin, array(
+ 'superuser_access' => $hasSuperUserAccess ? 1 : 0
+ ));
+ }
+
+ private function updateUserFields($userLogin, $fields)
+ {
+ $set = array();
+ $bind = array();
+
+ foreach ($fields as $key => $val) {
+ $set[] = "`$key` = ?";
+ $bind[] = $val;
+ }
+
+ $bind[] = $userLogin;
+
+ $db = $this->getDb();
+ $db->query(sprintf('UPDATE `%s` SET %s WHERE `login` = ?', $this->table, implode(', ', $set)), $bind);
}
/**
@@ -207,45 +229,47 @@ class Model
*/
public function getUsersHavingSuperUserAccess()
{
- $users = $this->getDb()->fetchAll("SELECT login, email, token_auth
- FROM " . Common::prefixTable("user") . "
- WHERE superuser_access = 1
- ORDER BY date_registered ASC");
+ $db = $this->getDb();
+ $users = $db->fetchAll("SELECT login, email, token_auth
+ FROM " . Common::prefixTable("user") . "
+ WHERE superuser_access = 1
+ ORDER BY date_registered ASC");
return $users;
}
public function updateUser($userLogin, $password, $email, $alias, $tokenAuth)
{
- $this->getDb()->update($this->table,
- array(
- 'password' => $password,
- 'alias' => $alias,
- 'email' => $email,
- 'token_auth' => $tokenAuth
- ),
- "login = '$userLogin'"
- );
+ $this->updateUserFields($userLogin, array(
+ 'password' => $password,
+ 'alias' => $alias,
+ 'email' => $email,
+ 'token_auth' => $tokenAuth
+ ));
}
public function userExists($userLogin)
{
- $count = $this->getDb()->fetchOne("SELECT count(*) FROM " . $this->table . " WHERE login = ?", $userLogin);
+ $db = $this->getDb();
+ $count = $db->fetchOne("SELECT count(*) FROM " . $this->table . " WHERE login = ?", $userLogin);
return $count != 0;
}
public function userEmailExists($userEmail)
{
- $count = $this->getDb()->fetchOne("SELECT count(*) FROM " . $this->table . " WHERE email = ?", $userEmail);
+ $db = $this->getDb();
+ $count = $db->fetchOne("SELECT count(*) FROM " . $this->table . " WHERE email = ?", $userEmail);
return $count != 0;
}
public function addUserAccess($userLogin, $access, $idSites)
{
+ $db = $this->getDb();
+
foreach ($idSites as $idsite) {
- $this->getDb()->insert(Common::prefixTable("access"),
+ $db->insert(Common::prefixTable("access"),
array("idsite" => $idsite,
"login" => $userLogin,
"access" => $access)
@@ -255,7 +279,8 @@ class Model
public function deleteUserOnly($userLogin)
{
- $this->getDb()->query("DELETE FROM " . $this->table . " WHERE login = ?", $userLogin);
+ $db = $this->getDb();
+ $db->query("DELETE FROM " . $this->table . " WHERE login = ?", $userLogin);
/**
* Triggered after a user has been deleted.
@@ -270,13 +295,15 @@ class Model
public function deleteUserAccess($userLogin, $idSites = null)
{
+ $db = $this->getDb();
+
if (is_null($idSites)) {
- $this->getDb()->query("DELETE FROM " . Common::prefixTable("access") .
+ $db->query("DELETE FROM " . Common::prefixTable("access") .
" WHERE login = ?",
array($userLogin));
} else {
foreach ($idSites as $idsite) {
- $this->getDb()->query("DELETE FROM " . Common::prefixTable("access") .
+ $db->query("DELETE FROM " . Common::prefixTable("access") .
" WHERE idsite = ? AND login = ?",
array($idsite, $userLogin)
);
diff --git a/plugins/UsersManager/lang/fi.json b/plugins/UsersManager/lang/fi.json
index 8a39276cae..9fb8873852 100644
--- a/plugins/UsersManager/lang/fi.json
+++ b/plugins/UsersManager/lang/fi.json
@@ -3,9 +3,11 @@
"AddUser": "Lisää uusi käyttäjä",
"Alias": "Alias",
"AllWebsites": "Kaikki sivut",
+ "AnonymousUser": "Anonyymi käyttäjä",
"AnonymousUserHasViewAccess": "Huom: käyttäjällä %1$s on %2$s pääsy tälle verkkosivulle.",
"AnonymousUserHasViewAccess2": "Analyysiraporttisi ja kävijätietosi ovat julkisia.",
"ApplyToAllWebsites": "Päivitä kaikille sivuille",
+ "ChangeAllConfirm": "Haluatko varmasti antaa käyttäjälle '%s' pääsyn kaikille verkkosivuille?",
"ChangePasswordConfirm": "Salasanan vaihtaminen vaihtaa myös käyttäjän token_auth:n. Haluatko varmasti jatkaa?",
"ClickHereToDeleteTheCookie": "Paina tästä poistaaksesi cookie",
"ClickHereToSetTheCookieOnDomain": "Paina tästä luodaksesi cookie sivulle %s",
@@ -14,6 +16,7 @@
"DeleteConfirm": "Haluatko varmasti poistaa käyttäjän %s?",
"Email": "Sähköposti",
"EmailYourAdministrator": "%1$sLähetä ylläpitäjällesi sähköpostia ongelmasta%2$s.",
+ "EnterUsernameOrEmail": "Kirjoita käyttäjätunnus tai sähköpostiosoite",
"ExceptionAccessValues": "Oikeuksien täytyy olla yksi seuraavista arvoista: [ %s ]",
"ExceptionAdminAnonymous": "Et voi sallia ylläpito-oikeuksia anonyymikäyttäjälle.",
"ExceptionDeleteDoesNotExist": "Käyttäjää '%s' ei ole eikä sitä siksi voida poistaa.",
@@ -21,14 +24,20 @@
"ExceptionEditAnonymous": "Anonyymikäyttäjää ei voi muokata tai poistaa. Se on Piwikin sisäinen tunnus käyttäjälle, joka ei ole kirjautunut sisään. Voit esimerkiksi julkaista tilastoja kaikille sallimalla anonyymikäyttäjälle katsomisoikeuden.",
"ExceptionEmailExists": "Käyttäjä sähköpostilla '%s' on jo olemassa.",
"ExceptionInvalidEmail": "Sähköposti ei ole kelvollinen.",
+ "ExceptionInvalidLoginFormat": "Käyttäjänimen pitää olla %1$s-%2$s merkkiä pitkä ja saa sisältää vain kirjaimia (ei ääkkösiä), numeroita tai '_' or '-' or '.' or '@' or '+'",
"ExceptionInvalidPassword": "Salasanan pituuden täytyy olla %1$s ja %2$s välillä.",
+ "ExceptionLoginExists": "Käyttäjätunnus '%s' on jo olemassa.",
"ExceptionPasswordMD5HashExpected": "UserManager.getTokenAuth haluaa MD5-tiivisteen salasanastasi (32 merkkiä pitkä merkkijono). Kutsu md5()-funktiota salasanallesi ennen kutsumista.",
"ExceptionRemoveSuperUserAccessOnlySuperUser": "Superkäyttäjäoikeuksien poistaminen käyttäjältä '%s' ei ole mahdollista.",
"ExceptionSuperUserAccess": "Tällä käyttäjällä on jo Superkäyttäjäoikeudet ja oikeudet muokata kaikkia verkkosivuja Piwikissä. Voit poistaa Superkäyttäjäoikeudet tältä käyttäjältä ja yrittää uudelleen.",
"ExceptionUserDoesNotExist": "Käyttäjää '%s' ei ole olemassa.",
"ExceptionYouMustGrantSuperUserAccessFirst": "Ainakin yhdellä käyttäjällä tulee olla Superkäyttäjäoikeudet. Ole hyvä ja anna toiselle käyttäjälle Superkäyttäjäoikeudet ensin.",
+ "ExceptionUserHasViewAccessAlready": "Käyttäjällä on jo pääsy sivulle.",
+ "ExceptionNoValueForUsernameOrEmail": "Kirjoita käyttäjätunnus tai sähköpostiosoite.",
"ExcludeVisitsViaCookie": "Poista käyntiesi seuraaminen cookiella",
"ForAnonymousUsersReportDateToLoadByDefault": "Lataa anonyymeille käyttäjille oletuksena",
+ "GiveViewAccess": "Anna katseluoikeus",
+ "GiveViewAccessTitle": "Anna olemassaolevalle käyttäjälle oikeus katsoa %s:n raportteja",
"IfYouWouldLikeToChangeThePasswordTypeANewOne": "Jos haluat vaihtaa salasanan, kirjoita uusi. Muuten jätä tyhjäksi.",
"InjectedHostCannotChangePwd": "Olet sivulla tällä hetkellä tuntemattoman isännän kautta (%1$s). Et voi vaihtaa salasanaasi ennen kuin tämä ongelma on korjattu.",
"LastSeen": "Nähty viimeeksi",
@@ -36,8 +45,11 @@
"MenuAnonymousUserSettings": "Anonyymin käyttäjän asetukset",
"MenuUsers": "Käyttäjät",
"MenuUserSettings": "Käyttäjäasetukset",
+ "MenuPersonal": "Henkilökohtainen",
+ "PersonalSettings": "Henkilökohtaiset asetukset",
"NoteNoAnonymousUserAccessSettingsWontBeUsed2": "Huom. et voi vaihtaa tämän osion asetuksia, koska sinulla ei ole yhtäkään sivustoa, jonka tietoja anonyymit käyttäjät pääsevät katsomaan.",
"NoUsersExist": "Yhtään käyttäjää ei ole vielä olemassa.",
+ "PluginDescription": "Käyttäjähallinta antaa sinun lisätä uusia käyttäjiä, muokata olemassaolevia käyttäjiä, antaa pääsyoikeuksia sivuille ja muokata sivuja.",
"PrivAdmin": "Hallinnointioikeus",
"PrivNone": "Ei käyttöoikeutta",
"PrivView": "Näkymä",
diff --git a/plugins/UsersManager/tests/Integration/APITest.php b/plugins/UsersManager/tests/Integration/APITest.php
index f7ab746ce6..892deedc58 100644
--- a/plugins/UsersManager/tests/Integration/APITest.php
+++ b/plugins/UsersManager/tests/Integration/APITest.php
@@ -178,6 +178,17 @@ class APITest extends IntegrationTestCase
$this->api->setUserPreference($user2, 'ohOH_myPreferenceName', 'valueForUser2');
}
+ public function test_updateUser()
+ {
+ $this->api->updateUser($this->login, 'newPassword', 'email@example.com', 'newAlias', false);
+
+ $user = $this->api->getUser($this->login);
+
+ $this->assertSame('14a88b9d2f52c55b5fbcf9c5d9c11875', $user['password']);
+ $this->assertSame('email@example.com', $user['email']);
+ $this->assertSame('newAlias', $user['alias']);
+ }
+
public function test_getSitesAccessFromUser_forSuperUser()
{
$user2 = 'userLogin2';
diff --git a/plugins/VisitFrequency/Controller.php b/plugins/VisitFrequency/Controller.php
index 8e6af9cffd..855d1286de 100644
--- a/plugins/VisitFrequency/Controller.php
+++ b/plugins/VisitFrequency/Controller.php
@@ -68,6 +68,7 @@ class Controller extends \Piwik\Plugin\Controller
);
$period = Common::getRequestVar('period', false);
+
if ($period == 'day') {
// add number of unique (returning) visitors for period=day
$selectableColumns = array_merge(
diff --git a/plugins/VisitFrequency/lang/fi.json b/plugins/VisitFrequency/lang/fi.json
index b46c8115d6..4bee78edcc 100644
--- a/plugins/VisitFrequency/lang/fi.json
+++ b/plugins/VisitFrequency/lang/fi.json
@@ -10,6 +10,8 @@
"ColumnReturningVisits": "Palaavat käynnit",
"ColumnSumVisitLengthReturning": "Palaavien käyttäjien aika yhteensä (sekunteja)",
"ColumnUniqueReturningVisitors": "Yksilölliset palaavat kävijät",
+ "ColumnReturningUsers": "Palaavat käyttäjät",
+ "PluginDescription": "Raportoi metriikat ensimmäisen kerran kävijöistä ja palaavista vierailijoista",
"ReturnActions": "%s toimintoa palaavilta käyttäjiltä",
"ReturnAverageVisitDuration": "%s keskimääräinen käynnin pituus palaaville kävijöille",
"ReturnAvgActions": "%s toimintoa \/ palaava käynti",
diff --git a/plugins/VisitTime/lang/fi.json b/plugins/VisitTime/lang/fi.json
index 14e8b8856b..1efd00df94 100644
--- a/plugins/VisitTime/lang/fi.json
+++ b/plugins/VisitTime/lang/fi.json
@@ -5,6 +5,7 @@
"DayOfWeek": "Viikonpäivä",
"LocalTime": "Käyntejä (paikallinen aika)",
"NHour": "%sh",
+ "PluginDescription": "Raportoi palvelimen ajan ja käyttäjän paikallisen ajan käynneille.",
"ServerTime": "Käyntejä (palvelimen aika)",
"SubmenuTimes": "Ajat",
"VisitsByDayOfWeek": "Käynnit viikonpäivän mukaan",
diff --git a/plugins/VisitorInterest/lang/fi.json b/plugins/VisitorInterest/lang/fi.json
index e306a04236..e196332b95 100644
--- a/plugins/VisitorInterest/lang/fi.json
+++ b/plugins/VisitorInterest/lang/fi.json
@@ -7,6 +7,7 @@
"Engagement": "Sitoutuminen",
"NPages": "%s sivua",
"OnePage": "1 sivu",
+ "PluginDescription": "Raportoi kävijöiden kiinnostuksen: käytyjen sivujen määrän, sivuilla vietetyn ajan, ajan edellisestä käynnistä jne.",
"VisitNum": "Käynnin numero",
"VisitsByDaysSinceLast": "Käynnit lajiteltuna aikavälillä edelliseen käyntiin",
"visitsByVisitCount": "Käynnit käyntinumeron mukaan",
diff --git a/plugins/VisitsSummary/lang/fi.json b/plugins/VisitsSummary/lang/fi.json
index 4df0a1d5db..0bc92bcf03 100644
--- a/plugins/VisitsSummary/lang/fi.json
+++ b/plugins/VisitsSummary/lang/fi.json
@@ -17,6 +17,7 @@
"NbUniquePageviewsDescription": "%s yksilöllistä sivunavausta",
"NbUniqueVisitors": "%s uniikia kävijää",
"NbVisitsBounced": "%s lyhyttä käyntiä (vain yksi ladattu sivu)",
+ "PluginDescription": "Raportoi yleiset analytiikkametriikat: käynnit, uniikit kävijät, toimintojen määrän jne.",
"VisitsSummary": "Yhteenveto käynneistä",
"VisitsSummaryDocumentation": "Tämä on käyntien muutoksen yleiskatsaus",
"WidgetLastVisits": "Edelliset käynnit",
diff --git a/plugins/WebsiteMeasurable/lang/fi.json b/plugins/WebsiteMeasurable/lang/fi.json
new file mode 100644
index 0000000000..e3c519b052
--- /dev/null
+++ b/plugins/WebsiteMeasurable/lang/fi.json
@@ -0,0 +1,7 @@
+{
+ "WebsiteMeasurable": {
+ "Website": "Verkkosivu",
+ "Websites": "Verkkosivut",
+ "WebsiteDescription": "Verkkosivusto on tyypillisesti kokoelma sivuja saman verkko-osoitteen alla."
+ }
+} \ No newline at end of file
diff --git a/tests/PHPUnit/Integration/EmailValidatorTest.php b/tests/PHPUnit/Integration/EmailValidatorTest.php
index 4b2e215506..22c95f86ee 100644
--- a/tests/PHPUnit/Integration/EmailValidatorTest.php
+++ b/tests/PHPUnit/Integration/EmailValidatorTest.php
@@ -8,6 +8,7 @@
namespace Piwik\Tests\Integration;
+use Piwik\Http;
use Piwik\Piwik;
/**
@@ -20,6 +21,64 @@ class EmailValidatorTest extends \PHPUnit_Framework_TestCase
return Piwik::isValidEmailString($email);
}
+ private function getAllTlds()
+ {
+ /** @var array $response */
+ $response = \Piwik\Http::sendHttpRequest("http://data.iana.org/TLD/tlds-alpha-by-domain.txt", 30, null, null, null, null, null, true);
+
+ $this->assertEquals("200", $response['status']);
+
+ $tlds = explode("\n", $response['data']);
+ foreach ($tlds as $key => $tld) {
+ if (strpos($tld, '#') !== false || $tld == "") {
+ unset($tlds[$key]);
+ }
+ }
+ return $tlds;
+ }
+
+ public function test_allCurrentTlds(){
+ $tlds = $this->getAllTlds();
+ if (count($tlds) === 0) {
+ $this->markTestSkipped("Couldn't get TLD list");
+ }
+
+ foreach ($tlds as $key => $tld) {
+ if (strpos(mb_strtolower($tld), 'xn--') !== 0) {
+ $tld = mb_strtolower($tld);
+ }
+ $email = 'test@example.' . idn_to_utf8($tld);
+ $this->assertTrue(
+ $this->isValid($email),
+ "email $email is not valid, but expected to be valid. Add this domain extension to libs/Zend/Validate/Hostname.php"
+ );
+ }
+ }
+
+ public function test_invalidTld(){
+ $tlds = [
+ strval(bin2hex(openssl_random_pseudo_bytes(64))), //generates 128 bit length string
+ '-tld-cannot-start-from-hypen',
+ 'ąęśćżźł-there-is-no-such-idn',
+ 'xn--fd67as67fdsa', //no such idn punycode
+ '!@#-inavlid-chars-in-tld',
+ 'no spaces in tld allowed',
+ 'no--double--hypens--allowed'
+ ];
+ if (count($tlds) === 0) {
+ $this->markTestSkipped("Couldn't get TLD list");
+ }
+
+ foreach ($tlds as $key => $tld) {
+ if (strpos(mb_strtolower($tld), 'xn--') !== 0) {
+ $tld = mb_strtolower($tld);
+ }
+ $this->assertFalse(
+ $this->isValid('test@example.' . idn_to_utf8($tld))
+ );
+ }
+ }
+
public function test_isValid_validStandard()
{
$this->assertTrue($this->isValid('test@example.com'));
diff --git a/tests/PHPUnit/Integration/JsProxyTest.php b/tests/PHPUnit/Integration/JsProxyTest.php
index e2a68cf4c3..0fbab1890f 100644
--- a/tests/PHPUnit/Integration/JsProxyTest.php
+++ b/tests/PHPUnit/Integration/JsProxyTest.php
@@ -31,7 +31,7 @@ class JsProxyTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($piwik_js, $fullResponse, 'script content');
}
- public function testPiwikJsNoComment()
+ public function testPiwik_WhiteLabelledJs_HasNoComment()
{
$curlHandle = curl_init();
curl_setopt($curlHandle, CURLOPT_URL, $this->getStaticSrvUrl() . '/js/tracker.php');
@@ -44,7 +44,7 @@ class JsProxyTest extends \PHPUnit_Framework_TestCase
$piwikJs = file_get_contents(PIWIK_PATH_TEST_TO_ROOT . '/piwik.js');
$piwikNoCommentJs = substr($piwikJs, strpos($piwikJs, "*/\n") + 3);
- $this->assertEquals($piwikNoCommentJs, $fullResponse, 'script content (if comment shows, $byteStart value in /js/tracker.php)');
+ $this->assertEquals($piwikNoCommentJs, trim($fullResponse), 'script content (if comment shows, $byteStart value in /js/tracker.php)');
}
public function testPiwikPhp()
diff --git a/tests/PHPUnit/Integration/ReleaseCheckListTest.php b/tests/PHPUnit/Integration/ReleaseCheckListTest.php
index fcda0177be..e416ad1602 100644
--- a/tests/PHPUnit/Integration/ReleaseCheckListTest.php
+++ b/tests/PHPUnit/Integration/ReleaseCheckListTest.php
@@ -12,6 +12,7 @@ use Exception;
use Piwik\Config;
use Piwik\Container\StaticContainer;
use Piwik\Filesystem;
+use Piwik\Http;
use Piwik\Ini\IniReader;
use Piwik\Plugin\Manager;
use Piwik\Tests\Framework\TestCase\SystemTestCase;
@@ -201,7 +202,7 @@ class ReleaseCheckListTest extends \PHPUnit_Framework_TestCase
$js = Filesystem::globr(PIWIK_INCLUDE_PATH, '*.twig');
$this->checkFilesDoNotHaveWeirdSpaces($js);
}
-
+
public function test_htmlfilesDoNotContainFakeSpaces()
{
$js = Filesystem::globr(PIWIK_INCLUDE_PATH, '*.html');
@@ -329,6 +330,18 @@ class ReleaseCheckListTest extends \PHPUnit_Framework_TestCase
$this->assertTrue(preg_match($pattern, $contents) == 0);
}
+ public function test_piwikJs_minified_isUpToDate()
+ {
+ Http::fetchRemoteFile('https://github.com/downloads/yui/yuicompressor/yuicompressor-2.4.7.zip', PIWIK_DOCUMENT_ROOT .'/tmp/yuicompressor.zip');
+ shell_exec('unzip -n '. PIWIK_DOCUMENT_ROOT .'/tmp/yuicompressor.zip');
+ shell_exec("sed '/<DEBUG>/,/<\/DEBUG>/d' < ". PIWIK_DOCUMENT_ROOT ."/js/piwik.js | sed 's/eval/replacedEvilString/' | java -jar yuicompressor-2.4.7/build/yuicompressor-2.4.7.jar --type js --line-break 1000 | sed 's/replacedEvilString/eval/' | sed 's/^[/][*]/\/*!/' > " . PIWIK_DOCUMENT_ROOT ."/piwik-minified.js");
+
+ $this->assertFileEquals(PIWIK_DOCUMENT_ROOT . '/piwik-minified.js',
+ PIWIK_DOCUMENT_ROOT . '/piwik.js',
+ 'minified /piwik.js is out of date, please re-generate the minified /piwik.js using instructions in /js/README'
+ );
+ }
+
public function testTmpDirectoryContainsGitKeep()
{
$this->assertFileExists(PIWIK_DOCUMENT_ROOT . '/tmp/.gitkeep');
diff --git a/tests/PHPUnit/Integration/SegmentTest.php b/tests/PHPUnit/Integration/SegmentTest.php
index 7041c89202..9f626e7969 100644
--- a/tests/PHPUnit/Integration/SegmentTest.php
+++ b/tests/PHPUnit/Integration/SegmentTest.php
@@ -829,9 +829,129 @@ class SegmentTest extends IntegrationTestCase
AND
( log_link_visit_action.custom_var_k1 = ? )
ORDER BY NULL
- LIMIT 33
- ) AS log_inner
- LIMIT 33",
+ LIMIT 0, 33
+ ) AS log_inner",
+ "bind" => array(1, 'Test'));
+
+ $this->assertEquals($this->removeExtraWhiteSpaces($expected), $this->removeExtraWhiteSpaces($query));
+ }
+
+
+ public function test_getSelectQuery_whenLimitAndOffset_outerQueryShouldNotHaveOffset()
+ {
+ $select = 'sum(log_visit.visit_total_time) as sum_visit_length';
+ $from = 'log_visit';
+ $where = 'log_visit.idvisit = ?';
+ $bind = array(1);
+
+ $segment = 'customVariablePageName1==Test';
+ $segment = new Segment($segment, $idSites = array());
+
+ $orderBy = false;
+ $groupBy = false;
+ $limit = 33;
+ $offset = 10;
+
+ $query = $segment->getSelectQuery($select, $from, $where, $bind, $orderBy, $groupBy, $limit, $offset);
+
+ $expected = array(
+ "sql" => "
+ SELECT
+ sum(log_inner.visit_total_time) as sum_visit_length
+ FROM
+ (
+ SELECT
+ log_visit.visit_total_time
+ FROM
+ " . Common::prefixTable('log_visit') . " AS log_visit
+ LEFT JOIN " . Common::prefixTable('log_link_visit_action') . " AS log_link_visit_action ON log_link_visit_action.idvisit = log_visit.idvisit
+ WHERE
+ ( log_visit.idvisit = ? )
+ AND
+ ( log_link_visit_action.custom_var_k1 = ? )
+ ORDER BY NULL
+ LIMIT 10, 33
+ ) AS log_inner",
+ "bind" => array(1, 'Test'));
+
+ $this->assertEquals($this->removeExtraWhiteSpaces($expected), $this->removeExtraWhiteSpaces($query));
+ }
+
+ public function test_getSelectQuery_whenOffsetIsZero()
+ {
+ $select = 'sum(log_visit.visit_total_time) as sum_visit_length';
+ $from = 'log_visit';
+ $where = 'log_visit.idvisit = ?';
+ $bind = array(1);
+
+ $segment = 'customVariablePageName1==Test';
+ $segment = new Segment($segment, $idSites = array());
+
+ $orderBy = false;
+ $groupBy = false;
+ $limit = 33;
+ $offset = 0;
+
+ $query = $segment->getSelectQuery($select, $from, $where, $bind, $orderBy, $groupBy, $limit, $offset);
+
+ $expected = array(
+ "sql" => "
+ SELECT
+ sum(log_inner.visit_total_time) as sum_visit_length
+ FROM
+ (
+ SELECT
+ log_visit.visit_total_time
+ FROM
+ " . Common::prefixTable('log_visit') . " AS log_visit
+ LEFT JOIN " . Common::prefixTable('log_link_visit_action') . " AS log_link_visit_action ON log_link_visit_action.idvisit = log_visit.idvisit
+ WHERE
+ ( log_visit.idvisit = ? )
+ AND
+ ( log_link_visit_action.custom_var_k1 = ? )
+ ORDER BY NULL
+ LIMIT 0, 33
+ ) AS log_inner",
+ "bind" => array(1, 'Test'));
+
+ $this->assertEquals($this->removeExtraWhiteSpaces($expected), $this->removeExtraWhiteSpaces($query));
+ }
+
+ public function test_getSelectQuery_whenLimitIsZero()
+ {
+ $select = 'sum(log_visit.visit_total_time) as sum_visit_length';
+ $from = 'log_visit';
+ $where = 'log_visit.idvisit = ?';
+ $bind = array(1);
+
+ $segment = 'customVariablePageName1==Test';
+ $segment = new Segment($segment, $idSites = array());
+
+ $orderBy = false;
+ $groupBy = false;
+ $limit = 0;
+ $offset = 10;
+
+ $query = $segment->getSelectQuery($select, $from, $where, $bind, $orderBy, $groupBy, $limit, $offset);
+
+ $expected = array(
+ "sql" => "
+ SELECT
+ sum(log_inner.visit_total_time) as sum_visit_length
+ FROM
+ (
+ SELECT
+ log_visit.visit_total_time
+ FROM
+ " . Common::prefixTable('log_visit') . " AS log_visit
+ LEFT JOIN " . Common::prefixTable('log_link_visit_action') . " AS log_link_visit_action ON log_link_visit_action.idvisit = log_visit.idvisit
+ WHERE
+ ( log_visit.idvisit = ? )
+ AND
+ ( log_link_visit_action.custom_var_k1 = ? )
+ GROUP BY log_visit.idvisit
+ ORDER BY NULL
+ ) AS log_inner",
"bind" => array(1, 'Test'));
$this->assertEquals($this->removeExtraWhiteSpaces($expected), $this->removeExtraWhiteSpaces($query));
@@ -1233,7 +1353,7 @@ class SegmentTest extends IntegrationTestCase
$this->assertEquals($this->removeExtraWhiteSpaces($expected), $this->removeExtraWhiteSpaces($query));
}
- // se https://github.com/piwik/piwik/issues/9194
+ // see https://github.com/piwik/piwik/issues/9194
public function test_getSelectQuery_whenQueryingLogConversionWithSegmentThatUsesLogLinkVisitActionAndLogVisit_shouldUseSubselectGroupedByIdVisitAndBuster()
{
$select = 'log_conversion.idgoal AS `idgoal`,
diff --git a/tests/PHPUnit/System/TransitionsTest.php b/tests/PHPUnit/System/TransitionsTest.php
index 3049d0f823..b319558c90 100644
--- a/tests/PHPUnit/System/TransitionsTest.php
+++ b/tests/PHPUnit/System/TransitionsTest.php
@@ -79,6 +79,27 @@ class TransitionsTest extends SystemTestCase
'limitBeforeGrouping' => 2
)
));
+
+ $return[] = array('Transitions.getTransitionsForPageUrl', array( // test w/ segment
+ 'idSite' => self::$fixture->idSite,
+ 'date' => self::$fixture->dateTime,
+ 'periods' => array('day'),
+ 'testSuffix' => '_withSegment',
+ 'segment' => 'visitConvertedGoalId!%3D2',
+ 'otherRequestParameters' => array(
+ 'pageUrl' => 'http://example.org/page/one.html',
+ 'limitBeforeGrouping' => 2
+ )
+ ));
+ $return[] = array('Transitions.getTransitionsForPageTitle', array(
+ 'idSite' => self::$fixture->idSite,
+ 'date' => self::$fixture->dateTime,
+ 'periods' => array('day'),
+ 'testSuffix' => '_withSegment',
+ 'otherRequestParameters' => array(
+ 'pageTitle' => 'page title - page/one.html',
+ )
+ ));
return $return;
}
diff --git a/tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageTitle_day.xml b/tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageTitle_day.xml
new file mode 100644
index 0000000000..26c278c975
--- /dev/null
+++ b/tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageTitle_day.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <date>Sat, Mar 6</date>
+ <previousPages>
+ <row>
+ <label>page title - the/third_page.html?foo=bar</label>
+ <referrals>3</referrals>
+ </row>
+ <row>
+ <label>page title - sub/dir/page2.html</label>
+ <referrals>2</referrals>
+ </row>
+ <row>
+ <label>page title - the/third_page.html?foo=baz#anchor1</label>
+ <referrals>1</referrals>
+ </row>
+ <row>
+ <label>page title - the/third_page.html?foo=baz#anchor2</label>
+ <referrals>1</referrals>
+ </row>
+ </previousPages>
+ <previousSiteSearches>
+ <row>
+ <label>mykwd</label>
+ <referrals>1</referrals>
+ </row>
+ <row>
+ <label>anotherkwd</label>
+ <referrals>1</referrals>
+ </row>
+ </previousSiteSearches>
+ <pageMetrics>
+ <loops>5</loops>
+ <pageviews>17</pageviews>
+ <entries>3</entries>
+ <exits>3</exits>
+ </pageMetrics>
+ <followingPages>
+ <row>
+ <label>page title - sub/dir/page2.html</label>
+ <referrals>2</referrals>
+ </row>
+ <row>
+ <label>page title - the/third_page.html?foo=bar</label>
+ <referrals>2</referrals>
+ </row>
+ <row>
+ <label>page title - the/third_page.html?foo=baz#anchor1</label>
+ <referrals>2</referrals>
+ </row>
+ <row>
+ <label>page title - the/third_page.html?foo=baz#anchor2</label>
+ <referrals>1</referrals>
+ </row>
+ <row>
+ <label>page title - page3.html</label>
+ <referrals>1</referrals>
+ </row>
+ </followingPages>
+ <followingSiteSearches>
+ <row>
+ <label>anotherkwd</label>
+ <referrals>1</referrals>
+ </row>
+ </followingSiteSearches>
+ <outlinks>
+ <row>
+ <label>http://www.anothersite.com/to/outlink/page.html</label>
+ <referrals>1</referrals>
+ </row>
+ <row>
+ <label>http://anothersite.com/to/outlink/page2.html</label>
+ <referrals>1</referrals>
+ </row>
+ </outlinks>
+ <downloads>
+ <row>
+ <label>http://example.org/downloads/33.tar.gz</label>
+ <referrals>1</referrals>
+ </row>
+ <row>
+ <label>https://example.org/downloads/35.tar.gz</label>
+ <referrals>1</referrals>
+ </row>
+ </downloads>
+ <referrers>
+ <row>
+ <label>Direct Entries</label>
+ <shortName>direct</shortName>
+ <visits>1</visits>
+ <details>
+ </details>
+ </row>
+ <row>
+ <label>From Search Engines</label>
+ <shortName>search</shortName>
+ <visits>1</visits>
+ <details>
+ <row>
+ <label>&lt;&gt;&amp;\&quot;the pdo extension is required for this adapter but the extension is not loaded</label>
+ <referrals>1</referrals>
+ </row>
+ </details>
+ </row>
+ <row>
+ <label>From Websites</label>
+ <shortName>website</shortName>
+ <visits>1</visits>
+ <details>
+ <row>
+ <label>http://www.external.com.vn/referrerPage-counted.html</label>
+ <referrals>1</referrals>
+ </row>
+ </details>
+ </row>
+ </referrers>
+</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageUrl_day.xml b/tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageUrl_day.xml
new file mode 100644
index 0000000000..865d25db4e
--- /dev/null
+++ b/tests/PHPUnit/System/expected/test_Transitions_withSegment__Transitions.getTransitionsForPageUrl_day.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <date>Sat, Mar 6</date>
+ <previousPages>
+ <row>
+ <label>example.org/the/third_page.html?foo=bar</label>
+ <referrals>3</referrals>
+ </row>
+ <row>
+ <label>example.org/sub/dir/page2.html</label>
+ <referrals>2</referrals>
+ </row>
+ <row>
+ <label>Others</label>
+ <referrals>2</referrals>
+ </row>
+ </previousPages>
+ <previousSiteSearches>
+ <row>
+ <label>anotherkwd</label>
+ <referrals>1</referrals>
+ </row>
+ </previousSiteSearches>
+ <pageMetrics>
+ <loops>2</loops>
+ <pageviews>18</pageviews>
+ <entries>4</entries>
+ <exits>7</exits>
+ </pageMetrics>
+ <followingPages>
+ <row>
+ <label>example.org/the/third_page.html?foo=baz</label>
+ <referrals>3</referrals>
+ </row>
+ <row>
+ <label>example.org/sub/dir/page2.html</label>
+ <referrals>2</referrals>
+ </row>
+ <row>
+ <label>Others</label>
+ <referrals>3</referrals>
+ </row>
+ </followingPages>
+ <followingSiteSearches>
+ <row>
+ <label>anotherkwd</label>
+ <referrals>1</referrals>
+ </row>
+ </followingSiteSearches>
+ <outlinks>
+ <row>
+ <label>http://www.anothersite.com/to/outlink/page.html</label>
+ <referrals>1</referrals>
+ </row>
+ <row>
+ <label>http://anothersite.com/to/outlink/page2.html</label>
+ <referrals>1</referrals>
+ </row>
+ </outlinks>
+ <downloads>
+ <row>
+ <label>http://example.org/downloads/33.tar.gz</label>
+ <referrals>1</referrals>
+ </row>
+ <row>
+ <label>https://example.org/downloads/35.tar.gz</label>
+ <referrals>1</referrals>
+ </row>
+ </downloads>
+ <referrers>
+ <row>
+ <label>Direct Entries</label>
+ <shortName>direct</shortName>
+ <visits>1</visits>
+ <details>
+ </details>
+ </row>
+ <row>
+ <label>From Search Engines</label>
+ <shortName>search</shortName>
+ <visits>1</visits>
+ <details>
+ <row>
+ <label>&lt;&gt;&amp;\&quot;the pdo extension is required for this adapter but the extension is not loaded</label>
+ <referrals>1</referrals>
+ </row>
+ </details>
+ </row>
+ <row>
+ <label>From Websites</label>
+ <shortName>website</shortName>
+ <visits>1</visits>
+ <details>
+ <row>
+ <label>http://www.external.com.vn/referrerPage-counted.html</label>
+ <referrals>1</referrals>
+ </row>
+ </details>
+ </row>
+ <row>
+ <label>From Campaigns</label>
+ <shortName>campaign</shortName>
+ <visits>1</visits>
+ <details>
+ <row>
+ <label>testcampaign testkeyword</label>
+ <referrals>1</referrals>
+ </row>
+ </details>
+ </row>
+ </referrers>
+</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml
index 0afffa1863..8c6340eebb 100644
--- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml
+++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml
@@ -142,7 +142,7 @@
<category>Visit</category>
<name>Device brand</name>
<segment>deviceBrand</segment>
- <acceptedValues>3Q, Acer, Ainol, Airness, Alcatel, Allview, Altech UEC, Arnova, Amazon, Amoi, Apple, Archos, ARRIS, Airties, Asus, Avvio, Audiovox, Axxion, BBK, Becker, Bird, Beetel, Bmobile, Barnes &amp; Noble, BangOlufsen, BenQ, BenQ-Siemens, Blu, Boway, bq, Brondi, Bush, CUBOT, Carrefour, Captiva, Casio, Cat, Celkon, ConCorde, Changhong, Cherry Mobile, Cricket, Crosscall, Compal, CnM, Crius Mea, CreNova, Capitel, Compaq, Coolpad, Cowon, Cube, Coby Kyros, Danew, Datang, Denver, Desay, Dbtel, DoCoMo, Dicam, Dell, DMM, Doogee, Doov, Dopod, Dune HD, E-Boda, EBEST, Ericsson, ECS, Ezio, Elephone, Easypix, Energy Sistem, Ericy, Eton, eTouch, Evertek, Ezze, Fly, Foxconn, Fujitsu, Garmin-Asus, Gateway, Gemini, Gionee, Gigabyte, Gigaset, GOCLEVER, Goly, Google, Gradiente, Grundig, Haier, Hasee, Hisense, Hi-Level, Hosin, HP, HTC, Huawei, Humax, Hyrican, Hyundai, Ikea, iBall, i-Joy, iBerry, iKoMo, i-mate, iOcean, iNew, Infinix, Innostream, Inkti, Intex, i-mobile, INQ, Intek, Inverto, iTel, Jiayu, Jolla, Karbonn, KDDI, Kingsun, Konka, Komu, Koobee, K-Touch, KT-Tech, KOPO, Koridy, Kumai, Kyocera, Kazam, Lava, Lanix, LCT, Lenovo, Lenco, Le Pan, LG, Lingwin, Loewe, Logicom, Lexibook, Majestic, Manta Multimedia, Mobistel, Mecer, Medion, MEEG, Meizu, Metz, MEU, MicroMax, Mediacom, MediaTek, Mio, Mpman, Mofut, Motorola, Microsoft, MSI, Memup, Mitsubishi, MLLED, M.T.T., MyPhone, NEC, Netgear, NGM, Nintendo, Noain, Nokia, Nomi, Nikon, Newgen, Nexian, NextBook, Onda, OnePlus, OPPO, Orange, O2, Ouki, OUYA, Opsson, Panasonic, PEAQ, Philips, Pioneer, Polaroid, Palm, phoneOne, Pantech, Point of View, PolyPad, Pomp, Positivo, Prestigio, ProScan, PULID, Qilive, Qtek, QMobile, Quechua, Overmax, Oysters, Ramos, RCA Tablets, Readboy, Rikomagic, RIM, Roku, Rover, Samsung, Sega, Sony Ericsson, Sencor, Softbank, SFR, Sagem, Sharp, Siemens, Sendo, Skyworth, Smartfren, Sony, Spice, SuperSonic, Selevision, Sanyo, Symphony, Smart, Star, Storex, Stonex, SunVan, Sumvision, Tesla, TCL, Telit, ThL, TiPhone, Tecno Mobile, Tesco, TIANYU, Telefunken, Telenor, T-Mobile, Thomson, Tolino, Toplux, Toshiba, TechnoTrend, Trevi, Tunisie Telecom, Turbo-X, TVC, TechniSat, teXet, Unowhy, Uniscope, UTStarcom, Vastking, Videocon, Vertu, Vitelcom, VK Mobile, ViewSonic, Vestel, Vivo, Voto, Voxtel, Vodafone, Vizio, Videoweb, Walton, Web TV, WellcoM, Wexler, Wiko, Wolder, Wonu, Woxter, Xiaomi, Xolo, Unknown, Yarvik, Yuandao, Yusun, Ytone, Zeemi, Zonda, Zopo, ZTE</acceptedValues>
+ <acceptedValues>3Q, Acer, Ainol, Airness, Alcatel, Allview, Altech UEC, Arnova, Amazon, Amoi, Apple, Archos, ARRIS, Airties, Asus, Avvio, Audiovox, Axxion, BBK, Becker, Bird, Beetel, Bmobile, Barnes &amp; Noble, BangOlufsen, BenQ, BenQ-Siemens, Blu, Boway, bq, Brondi, Bush, CUBOT, Carrefour, Captiva, Casio, Cat, Celkon, ConCorde, Changhong, Cherry Mobile, Cricket, Crosscall, Compal, CnM, Crius Mea, CreNova, Capitel, Compaq, Coolpad, Cowon, Cube, Coby Kyros, Danew, Datang, Denver, Desay, Dbtel, DoCoMo, Dicam, Dell, DNS, DMM, Doogee, Doov, Dopod, Dune HD, E-Boda, EBEST, Ericsson, ECS, Ezio, Elephone, Easypix, Energy Sistem, Ericy, Eton, eTouch, Evertek, Ezze, Fairphone, Fly, Foxconn, Fujitsu, Garmin-Asus, Gateway, Gemini, Gionee, Gigabyte, Gigaset, GOCLEVER, Goly, Google, Gradiente, Grundig, Haier, Hasee, Hisense, Hi-Level, Hosin, HP, HTC, Huawei, Humax, Hyrican, Hyundai, Ikea, iBall, i-Joy, iBerry, iKoMo, i-mate, iOcean, iNew, Infinix, Innostream, Inkti, Intex, i-mobile, INQ, Intek, Inverto, iTel, Jiayu, Jolla, Karbonn, KDDI, Kingsun, Konka, Komu, Koobee, K-Touch, KT-Tech, KOPO, Koridy, Kumai, Kyocera, Kazam, Lava, Lanix, LCT, Lenovo, Lenco, Le Pan, LG, Lingwin, Loewe, Logicom, Lexibook, Majestic, Manta Multimedia, Mobistel, Mecer, Medion, MEEG, Meizu, Metz, MEU, MicroMax, Mediacom, MediaTek, Mio, Mpman, Mofut, Motorola, Microsoft, MSI, Memup, Mitsubishi, MLLED, M.T.T., MyPhone, NEC, Netgear, NGM, Nintendo, Noain, Nokia, Nomi, Nikon, Newgen, Nexian, NextBook, Onda, OnePlus, OPPO, Orange, O2, Ouki, OUYA, Opsson, Panasonic, PEAQ, Philips, Pioneer, Polaroid, Palm, phoneOne, Pantech, Ployer, Point of View, PolyPad, Pomp, Positivo, Prestigio, ProScan, PULID, Qilive, Qtek, QMobile, Quechua, Overmax, Oysters, Ramos, RCA Tablets, Readboy, Rikomagic, RIM, Roku, Rover, Samsung, Sega, Sony Ericsson, Sencor, Softbank, SFR, Sagem, Sharp, Siemens, Sendo, Skyworth, Smartfren, Sony, Spice, SuperSonic, Selevision, Sanyo, Symphony, Smart, Star, Storex, Stonex, SunVan, Sumvision, Tesla, TCL, Telit, ThL, TiPhone, Tecno Mobile, Tesco, TIANYU, Telefunken, Telenor, T-Mobile, Thomson, Tolino, Toplux, Toshiba, TechnoTrend, Trevi, Tunisie Telecom, Turbo-X, TVC, TechniSat, teXet, Unowhy, Uniscope, UTStarcom, Vastking, Videocon, Vertu, Vitelcom, VK Mobile, ViewSonic, Vestel, Vivo, Voto, Voxtel, Vodafone, Vizio, Videoweb, Walton, WellcoM, Wexler, Wiko, Wolder, Wonu, Woxter, Xiaomi, Xolo, Yarvik, Yuandao, Yusun, Ytone, Zeemi, Zonda, Zopo, ZTE, Web TV, Unknown</acceptedValues>
</row>
<row>
<type>dimension</type>
diff --git a/tests/PHPUnit/Unit/DeprecatedMethodsTest.php b/tests/PHPUnit/Unit/DeprecatedMethodsTest.php
index c123378941..ff2dd4bcbd 100644
--- a/tests/PHPUnit/Unit/DeprecatedMethodsTest.php
+++ b/tests/PHPUnit/Unit/DeprecatedMethodsTest.php
@@ -23,6 +23,9 @@ class DeprecatedMethodsTest extends \PHPUnit_Framework_TestCase
{
public function test_deprecations()
{
+ $validTill = '2016-09-01';
+ $this->assertDeprecatedMethodIsRemoved('Piwik\SettingsServer', 'isApache', $validTill);
+
$validTill = '2015-03-10';
$this->assertDeprecatedMethodIsRemoved('\Piwik\Period', 'factory', $validTill);
$this->assertDeprecatedMethodIsRemoved('\Piwik\Config', 'getConfigSuperUserForBackwardCompatibility', $validTill);
diff --git a/tests/PHPUnit/Unit/UrlHelperTest.php b/tests/PHPUnit/Unit/UrlHelperTest.php
index bfdf9959aa..09aab2c2f3 100644
--- a/tests/PHPUnit/Unit/UrlHelperTest.php
+++ b/tests/PHPUnit/Unit/UrlHelperTest.php
@@ -216,6 +216,15 @@ class UrlHelperTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('segment=pageTitle!@%40Hello%20World;pageTitle!@Peace%20Love%20', UrlHelper::getQueryFromUrl('/?segment=pageTitle!@%40Hello%20World;pageTitle!@Peace%20Love%20', array()));
}
+ public function test_getQueryFromUrl_whenUrlParameterIsDuplicatedInQueryString_returnsLastFoundValue()
+ {
+ // Currently when the same parameter is used several times in the query string,
+ // only the last set value is returned by UrlHelper::getParameterFromQueryString
+ // refs https://github.com/piwik/piwik/issues/9842#issue-136043409
+ $this->assertEquals('blue', UrlHelper::getParameterFromQueryString('selected_colors=red&selected_colors=blue&par3=1', 'selected_colors'));
+ $this->assertEquals('selected_colors=red&selected_colors=blue&par3=1', UrlHelper::getQueryFromUrl('http:/mydomain.com?selected_colors=red&selected_colors=blue&par3=1', array()));
+ }
+
/**
* @group Core
*/
diff --git a/tests/UI/expected-ui-screenshots b/tests/UI/expected-ui-screenshots
-Subproject 9ca952c6485f9e0d7a890a78720ca1365aaf67f
+Subproject bceba741bd4f4fc3f34eee4476c0e50dab260f8
diff --git a/tests/UI/specs/UIIntegration_spec.js b/tests/UI/specs/UIIntegration_spec.js
index 57bdb4c97c..3c108061b3 100644
--- a/tests/UI/specs/UIIntegration_spec.js
+++ b/tests/UI/specs/UIIntegration_spec.js
@@ -237,6 +237,12 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik?
}, done);
});
+ it('should display metric tooltip correctly', function (done) {
+ expect.screenshot("metric_tooltip").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
+ page.mouseMove('[data-report="Referrers.getReferrerType"] #nb_visits .thDIV', 500);
+ }, done);
+ });
+
it('should load the referrers > search engines & keywords page correctly', function (done) {
expect.screenshot('referrers_search_engines_keywords').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
page.load("?" + urlBase + "#?" + generalParams + "&category=Referrers_Referrers&subcategory=Referrers_SubmenuSearchEngines");
diff --git a/tests/javascript/index.php b/tests/javascript/index.php
index 2e0e48723d..be9af836da 100644
--- a/tests/javascript/index.php
+++ b/tests/javascript/index.php
@@ -2243,8 +2243,8 @@ function PiwikTest() {
}
});
- test("Tracker setDomains(), isSiteHostName(), isSiteHostPath(), findConfigCookiePathToUse() and getLinkIfShouldBeProcessed()", function() {
- expect(117);
+ test("Tracker setDomains(), isSiteHostName(), isSiteHostPath(), and getLinkIfShouldBeProcessed()", function() {
+ expect(154);
var tracker = Piwik.getTracker();
var initialDomains = tracker.getDomains();
@@ -2253,12 +2253,10 @@ function PiwikTest() {
equal( typeof tracker.hook.test._isSiteHostName, 'function', "isSiteHostName" );
equal( typeof tracker.hook.test._isSiteHostPath, 'function', "isSiteHostPath" );
equal( typeof tracker.hook.test._getLinkIfShouldBeProcessed, 'function', "getLinkIfShouldBeProcessed" );
- equal( typeof tracker.hook.test._findConfigCookiePathToUse, 'function', "findConfigCookiePathToUse" );
var isSiteHostName = tracker.hook.test._isSiteHostName;
var isSiteHostPath = tracker.hook.test._isSiteHostPath;
var getLinkIfShouldBeProcessed = tracker.hook.test._getLinkIfShouldBeProcessed;
- var findConfigCookiePathToUse = tracker.hook.test._findConfigCookiePathToUse;
// tracker.setDomain()
@@ -2308,14 +2306,42 @@ function PiwikTest() {
ok( isSiteHostName('dev.piwik.org'), 'isSiteHostName("dev.piwik.org")' );
ok( !isSiteHostName('piwik.org.com'), '!isSiteHostName("piwik.org.com")');
+ // domain wildcard should not affect behavior
+ tracker.setDomains( '.piwik.net/*' );
+ ok( isSiteHostName('piwik.net'), 'isSiteHostName("piwik.net")' );
+ ok( isSiteHostName('dev.piwik.net'), 'isSiteHostName("dev.piwik.net")' );
+ ok( !isSiteHostName('piwik.net.com'), '!isSiteHostName("piwik.net.com")');
+
/**
* isSiteHostPath ()
*/
+ // various edge cases with wildcards or 'empty' paths
+ var testCases = [
+ ['piwik.org'],
+ ['piwik.org/'],
+ ['piwik.org/*'],
+ ['piwik.org/*', 'piwik.org/foo' ],
+ ['piwik.org/foo', 'piwik.org/*' ],
+ ['piwik.org/foo', 'piwik.org/*', 'piwik.org/*/bar' ],
+ ];
+ for(var i in testCases) {
+ domainTestCase = testCases[i];
+ tracker.setDomains( domainTestCase );
+
+ ok( isSiteHostPath('piwik.org', '/'), 'isSiteHostPath("piwik.org", "/") for ' + domainTestCase );
+ ok( isSiteHostPath('piwik.org', ''), 'isSiteHostPath("piwik.org", "") for ' + domainTestCase );
+ ok( isSiteHostPath('piwik.org', '*'), 'isSiteHostPath("piwik.org", "*") for ' + domainTestCase);
+ ok( isSiteHostPath('piwik.org', '/*'), 'isSiteHostPath("piwik.org", "/*") for ' + domainTestCase);
+ ok( isSiteHostPath('piwik.org', '/index'), 'isSiteHostPath("piwik.org", "/index") for ' + domainTestCase);
+ }
+
+
// with path
tracker.setDomains( '.piwik.org/path' );
ok( isSiteHostPath('piwik.org', '/path'), 'isSiteHostPath("piwik.org", "/path")' );
ok( isSiteHostPath('piwik.org', '/path/'), 'isSiteHostPath("piwik.org", "/path/")' );
+ ok( !isSiteHostPath('piwik.org', '/path.htm'), 'isSiteHostPath("piwik.org", "/path.htm")' );
ok( isSiteHostPath('piwik.org', '/path/test'), 'isSiteHostPath("piwik.org", "/path/test)' );
ok( isSiteHostPath('dev.piwik.org', '/path'), 'isSiteHostPath("dev.piwik.org", "/path")' );
ok( !isSiteHostPath('piwik.org', '/pat'), '!isSiteHostPath("piwik.org", "/pat")');
@@ -2353,12 +2379,33 @@ function PiwikTest() {
ok( isSiteHostPath('piwik.org', '/foo/bar'), 'isSiteHostPath("piwik.org", "/foo/bar")' );
ok( isSiteHostPath('piwik.org', '/bar/baz/foo'), 'isSiteHostPath("piwik.org", "/bar/baz/foo/")' );
ok( !isSiteHostPath('piwik.org', '/bar/ba'), 'isSiteHostPath("piwik.org", "/bar/ba")' );
- ok( isSiteHostPath('piwik.org', '/path/test'), 'isSiteHostPath("piwik.org", "/path/test)' );
+ ok( isSiteHostPath('piwik.org', '/path/test'), 'isSiteHostPath("piwik.org", "/path/test")' );
+ ok( isSiteHostPath('piwik.org', '/path/test.htm'), 'isSiteHostPath("piwik.org", "/path/test.htm")' );
ok( isSiteHostPath('dev.piwik.pro', '/test'), 'isSiteHostPath("dev.piwik.pro", "/test")' );
+ ok( !isSiteHostPath('dev.piwik.pro', 'something/test.htm'), 'isSiteHostPath("dev.piwik.pro", "something/test")' );
ok( !isSiteHostPath('dev.piwik.pro', '/'), 'isSiteHostPath("dev.piwik.pro", "/")' );
- ok( !isSiteHostPath('piwik.pro', '/'), 'isSiteHostPath("piwik.pro", "/")' );
ok( !isSiteHostPath('piwik.org', '/'), 'isSiteHostPath("piwik.org", "/")' );
+ ok( !isSiteHostPath('piwik.pro', '/'), 'isSiteHostPath("piwik.pro", "/")' );
+ ok( !isSiteHostPath('piwik.org', '/index.htm'), 'isSiteHostPath("piwik.org", "/index.htm")' );
ok( !isSiteHostPath('piwik.org', '/anythingelse'), 'isSiteHostPath("piwik.org", "/anythingelse")' );
+ ok( !isSiteHostPath('another.org', '/'), 'isSiteHostPath("another.org", "/")' );
+ ok( !isSiteHostPath('another.org', '/anythingelse'), 'isSiteHostPath("another.org", "/anythingelse")' );
+
+
+ // some subdirectories and some path wildcards
+ tracker.setDomains( ['piwik.org/path', 'piwik.org/path2', 'piwik.org/index*'] );
+ ok( !isSiteHostPath('piwik.org', '/another'), "isSiteHostPath('piwik.org', '/another')" );
+ ok( !isSiteHostPath('piwik.org', '/anotherindex'), "isSiteHostPath('piwik.org', '/anotherindex')" );
+ ok( !isSiteHostPath('piwik.org', '/path.html'), "isSiteHostPath('piwik.org', '/path.html')" );
+ ok( isSiteHostPath('piwik.org', '/index'), "isSiteHostPath('piwik.org', '/index')" );
+ ok( isSiteHostPath('piwik.org', '/index.htm'), "isSiteHostPath('piwik.org', '/index.htm')" );
+ ok( isSiteHostPath('piwik.org', '/index_en.htm'), "isSiteHostPath('piwik.org', '/index_en.htm')" );
+ ok( isSiteHostPath('piwik.org', '/index*page'), "isSiteHostPath('piwik.org', '/index*page')" );
+
+ tracker.setDomains( ['piwik.org/index*', 'piwik.org'] );
+ ok( isSiteHostPath('piwik.org', '/index*page'), "isSiteHostPath('piwik.org', '/index*page')" );
+ ok( isSiteHostPath('piwik.org', ''), "isSiteHostPath('piwik.org', '')" );
+ ok( isSiteHostPath('piwik.org', '/'), "isSiteHostPath('piwik.org', '/')" );
// all is compared lower case
tracker.setDomains( '.piwik.oRg/PaTh' );
@@ -2416,45 +2463,20 @@ function PiwikTest() {
"type": "link"
}, getLinkIfShouldBeProcessed(createLink('http://www.piwik.org/footer')), 'getLinkIfShouldBeProcessed http://www.piwik.org/footer and there is domain piwik.org/foo but it should be outlink as path is different')
-
- /**
- * findConfigCookiePathToUse ()
- */
-
- tracker.setDomains( ['.piwik.org', '.piwik.pro/foo/bar', '.piwik.pro/foo', '.piwik.com/test/foo', 'example.com/foo'] );
-
- equal(null, findConfigCookiePathToUse('.piwik.org/test', 'http://piwik.org/test/two'), 'findConfigCookiePathToUse no cookiePath because there is a domain alias given allowing them all');
- equal('/foo', findConfigCookiePathToUse('.piwik.pro/foo', 'http://piwik.pro/foo/bar/test'), 'findConfigCookiePathToUse should find a match');
- equal('/foo', findConfigCookiePathToUse('.piwik.pro/foo/bar/test', 'http://piwik.pro/foo/bar/test'), 'findConfigCookiePathToUse should find a less restrictive path automatically');
- equal('/foo', findConfigCookiePathToUse('.piwik.pro/foo/bar/test', 'http://piwik.pro/foo'), 'findConfigCookiePathToUse should find a less restrictive path automatically, urlPath===domainPath');
- equal('/test/bar/test', findConfigCookiePathToUse('.piwik.com/test/bar/test', 'http://piwik.com/test/bar/test/'), 'findConfigCookiePathToUse should use exactly given path if no less restrictive version is available');
- equal('/test/foo', findConfigCookiePathToUse('.piwik.com/test/foo/test', 'http://piwik.com/test/foo/test'), 'findConfigCookiePathToUse should find a less restrictive path automatically, configAlias === currentUrl');
- equal('/test/foo', findConfigCookiePathToUse('.piwik.com/test/foo', 'http://piwik.com/test/foo/test'), 'findConfigCookiePathToUse should find a less restrictive path automatically');
- equal(null, findConfigCookiePathToUse('.piwik.pro/foo', 'http://piwik.pro/test'), 'findConfigCookiePathToUse should not return a path when user is actually not on that path');
- equal(null, findConfigCookiePathToUse('.piwik.pro/foo', 'http://piwik.pro'), 'findConfigCookiePathToUse when there is no path set we cannot use a configPath');
-
/**
- * Test sets a good cookie path automatically
+ * Test that we don't set a cookie path automatically
*/
tracker.setCookiePath(null);
tracker.setDomains( ['.' + domainAlias + '/tests'] );
- equal('/tests', tracker.getConfigCookiePath()), 'should set a cookie path automatically';
+ equal(null, tracker.getConfigCookiePath(), 'should not set a cookie path automatically');
tracker.setCookiePath(null);
tracker.setDomains( ['.' + domainAlias + '/tests/javascript'] );
- equal('/tests/javascript', tracker.getConfigCookiePath()), 'should set a cookie path automatically, multiple directories';
+ equal(null, tracker.getConfigCookiePath(), 'should not set a cookie path automatically');
- tracker.setCookiePath(null);
+ tracker.setCookiePath('/path2');
tracker.setDomains( ['.' + domainAlias + '/tests/javascript', '.' + domainAlias + '/tests'] );
- equal('/tests', tracker.getConfigCookiePath()), 'should find shortest path for possible cookie path';
-
- tracker.setCookiePath(null);
- tracker.setDomains( ['.' + domainAlias + '/tests/javascript', '.example.com/tests'] );
- equal('/tests/javascript', tracker.getConfigCookiePath()), 'should not find a shorter path when no other domain matches';
-
- tracker.setCookiePath(null);
- tracker.setDomains( ['.' + domainAlias + '/another/one', '.example.org/tests/javascript', '.example.com/tests'] );
- equal(null, tracker.getConfigCookiePath()), 'should not set a path when no domain and no path matches';
+ equal('/path2', tracker.getConfigCookiePath(), 'should not set a cookie path automatically');
tracker.setCookiePath(null);
});
@@ -2515,6 +2537,24 @@ function PiwikTest() {
equal( tracker.hook.test._getCookie( cookieName ), expectedValue, 'getCookie(), setCookie()' );
});
+ test("Tracker getCookieName() contains website ID", function() {
+ expect(4);
+
+ var tracker = Piwik.getTracker();
+ tracker.setTrackerUrl("piwik.php");
+
+ tracker.setSiteId(1);
+ cookieName = tracker.hook.test._getCookieName('testing');
+ ok( cookieName.indexOf('testing.1.') != -1);
+ ok( cookieName.indexOf('testing.2.') == -1);
+
+ tracker.setSiteId(2);
+ cookieName = tracker.hook.test._getCookieName('testing-another');
+ ok( cookieName.indexOf('testing-another.2.') != -1);
+ ok( cookieName.indexOf('testing-another.1.') == -1);
+
+ });
+
test("Tracker setDownloadExtensions(), addDownloadExtensions(), setDownloadClasses(), setLinkClasses(), and getLinkType()", function() {
expect(72);
diff --git a/tests/javascript/piwiktest.js b/tests/javascript/piwiktest.js
index ff5525c47d..8430f54055 100644
--- a/tests/javascript/piwiktest.js
+++ b/tests/javascript/piwiktest.js
@@ -27,7 +27,6 @@ Piwik.addPlugin('testPlugin', {
'_getCookieName : getCookieName,' +
'_setCookie : setCookie,' +
'_getLinkIfShouldBeProcessed : getLinkIfShouldBeProcessed,' +
- '_findConfigCookiePathToUse : findConfigCookiePathToUse,' +
'_encode : encodeWrapper,' +
'_decode : decodeWrapper,' +
'_urldecode : urldecode,' +
diff --git a/tests/travis b/tests/travis
-Subproject 3e80077f810f8ab963be85fb5be032138328201
+Subproject 2551892dc296f1abc500acf7b04380689a64588