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 <tsteur@users.noreply.github.com>2016-08-28 09:33:55 +0300
committerMatthieu Aubry <mattab@users.noreply.github.com>2016-08-28 09:33:55 +0300
commit77a6412ff7a8bdb2f23fb00a2d8ce22e7a35fcee (patch)
tree32100fa64ee556f1fd125751bb7c619dc73200bf
parentba0a9d53f41a96c994d9bb1c8298d97c0400060c (diff)
Split piwik.js into multiple files and provide a merged one (#10441)
refs #6106
-rw-r--r--.gitignore1
-rw-r--r--CHANGELOG.md5
-rw-r--r--config/global.ini.php1
-rw-r--r--core/DataTable/Map.php10
-rw-r--r--core/Filechecks.php2
-rw-r--r--core/Plugin/Report.php9
-rw-r--r--core/Updates/2.16.3-b2.php28
-rw-r--r--core/Version.php2
-rw-r--r--js/README.md6
-rw-r--r--js/piwik.js2539
-rw-r--r--js/piwik.min.js71
-rw-r--r--piwik.js95
-rw-r--r--plugins/Actions/javascripts/actionsDataTable.js2
-rw-r--r--plugins/CoreHome/javascripts/dataTable.js9
-rw-r--r--plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php3
-rw-r--r--plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php6
-rw-r--r--plugins/CustomPiwikJs/.gitignore1
-rw-r--r--plugins/CustomPiwikJs/Commands/UpdateTracker.php62
-rw-r--r--plugins/CustomPiwikJs/CustomPiwikJs.php35
-rw-r--r--plugins/CustomPiwikJs/Diagnostic/PiwikJsCheck.php54
-rw-r--r--plugins/CustomPiwikJs/Exception/AccessDeniedException.php15
-rw-r--r--plugins/CustomPiwikJs/File.php75
-rw-r--r--plugins/CustomPiwikJs/Tasks.php23
-rw-r--r--plugins/CustomPiwikJs/TrackerUpdater.php78
-rw-r--r--plugins/CustomPiwikJs/TrackingCode/JsTestPluginTrackerFiles.php27
-rw-r--r--plugins/CustomPiwikJs/TrackingCode/PiwikJsManipulator.php57
-rw-r--r--plugins/CustomPiwikJs/TrackingCode/PluginTrackerFiles.php87
-rw-r--r--plugins/CustomPiwikJs/config/config.php7
-rw-r--r--plugins/CustomPiwikJs/lang/en.json7
-rw-r--r--plugins/CustomPiwikJs/tests/Framework/Mock/PluginTrackerFilesMock.php36
-rw-r--r--plugins/CustomPiwikJs/tests/Integration/FileTest.php125
-rw-r--r--plugins/CustomPiwikJs/tests/Integration/PiwikJsManipulatorTest.php73
-rw-r--r--plugins/CustomPiwikJs/tests/Integration/PluginTrackerFilesTest.php124
-rw-r--r--plugins/CustomPiwikJs/tests/Integration/TrackerUpdaterTest.php121
-rw-r--r--plugins/CustomPiwikJs/tests/System/PiwikJsContentTest.php39
-rw-r--r--plugins/CustomPiwikJs/tests/resources/MyTestTarget2.js16
-rw-r--r--plugins/CustomPiwikJs/tests/resources/test.js2
-rw-r--r--plugins/CustomPiwikJs/tests/resources/testpiwik.js6
-rw-r--r--plugins/CustomPiwikJs/tests/resources/tracker.js4
-rw-r--r--plugins/CustomPiwikJs/tests/resources/tracker.min.js2
-rw-r--r--plugins/Live/javascripts/live.js9
-rw-r--r--tests/PHPUnit/Integration/ReleaseCheckListTest.php8
m---------tests/UI/expected-ui-screenshots0
-rw-r--r--tests/angularjs/Gruntfile.js23
-rwxr-xr-xtests/angularjs/karma.conf.js4
-rw-r--r--tests/angularjs/package.json5
-rw-r--r--tests/javascript/index.php31
47 files changed, 2683 insertions, 1262 deletions
diff --git a/.gitignore b/.gitignore
index a1cd27d0cd..8a53c53e11 100644
--- a/.gitignore
+++ b/.gitignore
@@ -61,6 +61,7 @@ php_errors.log
/tests/PHPUnit/proxy/piwik.js
/tests/PHPUnit/proxy/plugins
/tests/PHPUnit/proxy/tests
+/tests/resources/piwik.test.js
/config/*.config.ini.php
/Vagrantfile
/misc/vagrant
diff --git a/CHANGELOG.md b/CHANGELOG.md
index adb48086fb..c8eec8149f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,11 @@ This is the Developer Changelog for Piwik platform developers. All changes in ou
The Product Changelog at **[piwik.org/changelog](http://piwik.org/changelog)** lets you see more details about any Piwik release, such as the list of new guides and FAQs, security fixes, and links to all closed issues.
+## Piwik 2.16.3
+
+### New APIs
+* The Piwik JavaScript tracker has a new method `trackRequest` that allows you to send any tracking parameters to Piwik. For example `_paq.push(['trackRequest', 'te=foo&bar=baz'])`
+
## Piwik 2.16.2
### New APIs
diff --git a/config/global.ini.php b/config/global.ini.php
index 5f904efe27..edf9b867a2 100644
--- a/config/global.ini.php
+++ b/config/global.ini.php
@@ -807,6 +807,7 @@ Plugins[] = Heartbeat
Plugins[] = Intl
Plugins[] = ProfessionalServices
Plugins[] = UserId
+Plugins[] = CustomPiwikJs
[PluginsInstalled]
PluginsInstalled[] = Diagnostics
diff --git a/core/DataTable/Map.php b/core/DataTable/Map.php
index e7bc510194..e767d2f49a 100644
--- a/core/DataTable/Map.php
+++ b/core/DataTable/Map.php
@@ -228,6 +228,16 @@ class Map implements DataTableInterface
}
/**
+ * See {@link DataTable::disableFilter()}.
+ */
+ public function disableFilter($className)
+ {
+ foreach ($this->getDataTables() as $table) {
+ $table->disableFilter($className);
+ }
+ }
+
+ /**
* @ignore
*/
public function disableRecursiveFilters()
diff --git a/core/Filechecks.php b/core/Filechecks.php
index 417b13bbca..274453e96d 100644
--- a/core/Filechecks.php
+++ b/core/Filechecks.php
@@ -205,7 +205,7 @@ class Filechecks
return $message;
}
- private static function getUserAndGroup()
+ public static function getUserAndGroup()
{
$user = self::getUser();
if (!function_exists('shell_exec')) {
diff --git a/core/Plugin/Report.php b/core/Plugin/Report.php
index 053760d2d2..06165f6c32 100644
--- a/core/Plugin/Report.php
+++ b/core/Plugin/Report.php
@@ -545,6 +545,15 @@ class Report
}
/**
+ * Get report documentation.
+ * @return string
+ */
+ public function getDocumentation()
+ {
+ return $this->documentation;
+ }
+
+ /**
* Builts the report metadata for this report. Can be useful in case you want to change the behavior of
* {@link configureReportMetadata()}.
* @return array
diff --git a/core/Updates/2.16.3-b2.php b/core/Updates/2.16.3-b2.php
new file mode 100644
index 0000000000..3a1e75722d
--- /dev/null
+++ b/core/Updates/2.16.3-b2.php
@@ -0,0 +1,28 @@
+<?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\Updater;
+use Piwik\Updates as PiwikUpdates;
+
+/**
+ * Update for version 2.16.3b2
+ */
+class Updates_2_16_3_b2 extends PiwikUpdates
+{
+
+ public function doUpdate(Updater $updater)
+ {
+ try {
+ \Piwik\Plugin\Manager::getInstance()->activatePlugin('CustomPiwikJs');
+ } catch (\Exception $e) {
+ }
+ }
+}
diff --git a/core/Version.php b/core/Version.php
index d2214508d3..f5eb167b2a 100644
--- a/core/Version.php
+++ b/core/Version.php
@@ -20,7 +20,7 @@ final class Version
* The current Piwik version.
* @var string
*/
- const VERSION = '2.16.3-b1';
+ const VERSION = '2.16.3-b2';
public function isStableVersion($version)
{
diff --git a/js/README.md b/js/README.md
index 9556dc402e..b3700827eb 100644
--- a/js/README.md
+++ b/js/README.md
@@ -46,11 +46,11 @@ 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.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
+ $ 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
- /path/to/piwik/piwik.js
+ This will generate the minify /path/to/piwik/js/piwik.min.js and copy it to
+ /path/to/piwik/piwik.js. Both "js/piwik.min.js" and "piwik.js" need to be committed.
* In a production environment, the tests/javascript folder is not used and can
be removed (if present).
diff --git a/js/piwik.js b/js/piwik.js
index 5d847d5ba8..9a135e5edc 100644
--- a/js/piwik.js
+++ b/js/piwik.js
@@ -957,7 +957,7 @@ if (typeof JSON2 !== 'object' && typeof window.JSON === 'object' && window.JSON.
/*global unescape */
/*global ActiveXObject */
/*members Piwik, encodeURIComponent, decodeURIComponent, getElementsByTagName,
- shift, unshift, piwikAsyncInit, frameElement, self, hasFocus,
+ shift, unshift, piwikAsyncInit, piwikPluginAsyncInit, frameElement, self, hasFocus,
createElement, appendChild, characterSet, charset, all,
addEventListener, attachEvent, removeEventListener, detachEvent, disableCookies,
cookie, domain, readyState, documentElement, doScroll, title, text,
@@ -974,7 +974,7 @@ if (typeof JSON2 !== 'object' && typeof window.JSON === 'object' && window.JSON.
exec,
res, width, height,
pdf, qt, realp, wma, dir, fla, java, gears, ag,
- hook, getHook, getVisitorId, getVisitorInfo, setUserId, getUserId, setSiteId, getSiteId, setTrackerUrl, getTrackerUrl, appendToTrackingUrl, getRequest, addPlugin,
+ initialized, hook, getHook, getVisitorId, getVisitorInfo, setUserId, getUserId, setSiteId, getSiteId, setTrackerUrl, getTrackerUrl, appendToTrackingUrl, getRequest, addPlugin,
getAttributionInfo, getAttributionCampaignName, getAttributionCampaignKeyword,
getAttributionReferrerTimestamp, getAttributionReferrerUrl,
setCustomData, getCustomData,
@@ -993,7 +993,7 @@ if (typeof JSON2 !== 'object' && typeof window.JSON === 'object' && window.JSON.
doNotTrack, setDoNotTrack, msDoNotTrack, getValuesFromVisitorIdCookie,
addListener, enableLinkTracking, enableJSErrorTracking, setLinkTrackingTimer,
enableHeartBeatTimer, disableHeartBeatTimer, killFrame, redirectFile, setCountPreRendered,
- trackGoal, trackLink, trackPageView, trackSiteSearch, trackEvent,
+ trackGoal, trackLink, trackPageView, trackRequest, trackSiteSearch, trackEvent,
setEcommerceView, addEcommerceItem, trackEcommerceOrder, trackEcommerceCartUpdate,
deleteCookie, deleteCookies, offsetTop, offsetLeft, offsetHeight, offsetWidth, nodeType, defaultView,
innerHTML, scrollLeft, scrollTop, currentStyle, getComputedStyle, querySelectorAll, splice,
@@ -1030,7 +1030,7 @@ if (typeof JSON2 !== 'object' && typeof window.JSON === 'object' && window.JSON.
/*global _paq:true */
/*members push */
/*global Piwik:true */
-/*members addPlugin, getTracker, getAsyncTracker */
+/*members addPlugin, getTracker, getAsyncTracker, getAsyncTrackers, addTracker, trigger, on, off */
/*global Piwik_Overlay_Client */
/*global AnalyticsTracker:true */
/*members initialize */
@@ -1059,6 +1059,8 @@ if (typeof window.Piwik !== 'object') {
/* plugins */
plugins = {},
+ eventHandlers = {},
+
/* alias frequently used globals for added minification */
documentAlias = document,
navigatorAlias = navigator,
@@ -1184,13 +1186,38 @@ if (typeof window.Piwik !== 'object') {
for (j = 0; j < asyncTrackers.length; j++) {
if (isString(f)) {
+ var context = asyncTrackers[j];
+ var fParts;
+
+ var isStaticPluginCall = f.indexOf('::') > 0;
+ if (isStaticPluginCall) {
+ fParts = f.split('::');
+ context = fParts[0];
+ f = fParts[1];
+
+ if ('object' === typeof Piwik[context] && 'function' === typeof Piwik[context][f]) {
+ Piwik[context][f].apply(Piwik[context], parameterArray);
+ }
- if(asyncTrackers[j][f]) {
- asyncTrackers[j][f].apply(asyncTrackers[j], parameterArray);
+ return;
+ }
+
+ var isPluginTrackerCall = f.indexOf('.') > 0;
+
+ if (isPluginTrackerCall) {
+ fParts = f.split('.');
+ context = context[fParts[0]];
+ f = fParts[1];
+ }
+
+ if (context[f]) {
+ context[f].apply(context, parameterArray);
} else {
var message = 'The method \'' + f + '\' was not found in "_paq" variable. Please have a look at the Piwik tracker documentation: http://developer.piwik.org/api-reference/tracking-javascript';
logConsoleError(message);
- throw new TypeError(message);
+ if (!isPluginTrackerCall) {
+ throw new TypeError(message);
+ }
}
if (f === 'addTracker') {
@@ -5130,1330 +5157,1339 @@ if (typeof window.Piwik !== 'object') {
* Public data and methods
************************************************************/
- return {
+
/*<DEBUG>*/
- /*
- * Test hook accessors
- */
- hook: registeredHooks,
- getHook: function (hookName) {
- return registeredHooks[hookName];
- },
- getQuery: function () {
- return query;
- },
- getContent: function () {
- return content;
- },
+ /*
+ * Test hook accessors
+ */
+ this.hook = registeredHooks;
+ this.getHook = function (hookName) {
+ return registeredHooks[hookName];
+ };
+ this.getQuery = function () {
+ return query;
+ };
+ this.getContent = function () {
+ return content;
+ };
- buildContentImpressionRequest: buildContentImpressionRequest,
- buildContentInteractionRequest: buildContentInteractionRequest,
- buildContentInteractionRequestNode: buildContentInteractionRequestNode,
- buildContentInteractionTrackingRedirectUrl: buildContentInteractionTrackingRedirectUrl,
- getContentImpressionsRequestsFromNodes: getContentImpressionsRequestsFromNodes,
- getCurrentlyVisibleContentImpressionsRequestsIfNotTrackedYet: getCurrentlyVisibleContentImpressionsRequestsIfNotTrackedYet,
- trackCallbackOnLoad: trackCallbackOnLoad,
- trackCallbackOnReady: trackCallbackOnReady,
- buildContentImpressionsRequests: buildContentImpressionsRequests,
- wasContentImpressionAlreadyTracked: wasContentImpressionAlreadyTracked,
- appendContentInteractionToRequestIfPossible: getContentInteractionToRequestIfPossible,
- setupInteractionsTracking: setupInteractionsTracking,
- trackContentImpressionClickInteraction: trackContentImpressionClickInteraction,
- internalIsNodeVisible: isVisible,
- isNodeAuthorizedToTriggerInteraction: isNodeAuthorizedToTriggerInteraction,
- replaceHrefIfInternalLink: replaceHrefIfInternalLink,
- getDomains: function () {
- return configHostsAlias;
- },
- getConfigCookiePath: function () {
- return configCookiePath;
- },
- getConfigDownloadExtensions: function () {
- return configDownloadExtensions;
- },
- enableTrackOnlyVisibleContent: function (checkOnScroll, timeIntervalInMs) {
- return enableTrackOnlyVisibleContent(checkOnScroll, timeIntervalInMs, this);
- },
- clearTrackedContentImpressions: function () {
- trackedContentImpressions = [];
- },
- getTrackedContentImpressions: function () {
- return trackedContentImpressions;
- },
- clearEnableTrackOnlyVisibleContent: function () {
- isTrackOnlyVisibleContentEnabled = false;
- },
- disableLinkTracking: function () {
- linkTrackingInstalled = false;
- linkTrackingEnabled = false;
- },
- getConfigVisitorCookieTimeout: function () {
- return configVisitorCookieTimeout;
- },
- removeAllAsyncTrackersButFirst: function () {
- var firstTracker = asyncTrackers[0];
- asyncTrackers = [firstTracker];
- },
- getRemainingVisitorCookieTimeout: getRemainingVisitorCookieTimeout,
+ this.buildContentImpressionRequest = buildContentImpressionRequest;
+ this.buildContentInteractionRequest = buildContentInteractionRequest;
+ this.buildContentInteractionRequestNode = buildContentInteractionRequestNode;
+ this.buildContentInteractionTrackingRedirectUrl = buildContentInteractionTrackingRedirectUrl;
+ this.getContentImpressionsRequestsFromNodes = getContentImpressionsRequestsFromNodes;
+ this.getCurrentlyVisibleContentImpressionsRequestsIfNotTrackedYet = getCurrentlyVisibleContentImpressionsRequestsIfNotTrackedYet;
+ this.trackCallbackOnLoad = trackCallbackOnLoad;
+ this.trackCallbackOnReady = trackCallbackOnReady;
+ this.buildContentImpressionsRequests = buildContentImpressionsRequests;
+ this.wasContentImpressionAlreadyTracked = wasContentImpressionAlreadyTracked;
+ this.appendContentInteractionToRequestIfPossible = getContentInteractionToRequestIfPossible;
+ this.setupInteractionsTracking = setupInteractionsTracking;
+ this.trackContentImpressionClickInteraction = trackContentImpressionClickInteraction;
+ this.internalIsNodeVisible = isVisible;
+ this.isNodeAuthorizedToTriggerInteraction = isNodeAuthorizedToTriggerInteraction;
+ this.replaceHrefIfInternalLink = replaceHrefIfInternalLink;
+ this.getDomains = function () {
+ return configHostsAlias;
+ };
+ this.getConfigCookiePath = function () {
+ return configCookiePath;
+ };
+ this.getConfigDownloadExtensions = function () {
+ return configDownloadExtensions;
+ };
+ this.enableTrackOnlyVisibleContent = function (checkOnScroll, timeIntervalInMs) {
+ return enableTrackOnlyVisibleContent(checkOnScroll, timeIntervalInMs, this);
+ };
+ this.clearTrackedContentImpressions = function () {
+ trackedContentImpressions = [];
+ };
+ this.getTrackedContentImpressions = function () {
+ return trackedContentImpressions;
+ };
+ this.clearEnableTrackOnlyVisibleContent = function () {
+ isTrackOnlyVisibleContentEnabled = false;
+ };
+ this.disableLinkTracking = function () {
+ linkTrackingInstalled = false;
+ linkTrackingEnabled = false;
+ };
+ this.getConfigVisitorCookieTimeout = function () {
+ return configVisitorCookieTimeout;
+ };
+ this.removeAllAsyncTrackersButFirst = function () {
+ var firstTracker = asyncTrackers[0];
+ asyncTrackers = [firstTracker];
+ };
+ this.getRemainingVisitorCookieTimeout = getRemainingVisitorCookieTimeout;
/*</DEBUG>*/
- /**
- * Get visitor ID (from first party cookie)
- *
- * @return string Visitor ID in hexits (or empty string, if not yet known)
- */
- getVisitorId: function () {
- return getValuesFromVisitorIdCookie().uuid;
- },
-
- /**
- * Get the visitor information (from first party cookie)
- *
- * @return array
- */
- getVisitorInfo: function () {
- // Note: in a new method, we could return also return getValuesFromVisitorIdCookie()
- // which returns named parameters rather than returning integer indexed array
- return loadVisitorIdCookie();
- },
+ /**
+ * Get visitor ID (from first party cookie)
+ *
+ * @return string Visitor ID in hexits (or empty string, if not yet known)
+ */
+ this.getVisitorId = function () {
+ return getValuesFromVisitorIdCookie().uuid;
+ };
- /**
- * Get the Attribution information, which is an array that contains
- * the Referrer used to reach the site as well as the campaign name and keyword
- * It is useful only when used in conjunction with Tracker API function setAttributionInfo()
- * To access specific data point, you should use the other functions getAttributionReferrer* and getAttributionCampaign*
- *
- * @return array Attribution array, Example use:
- * 1) Call JSON2.stringify(piwikTracker.getAttributionInfo())
- * 2) Pass this json encoded string to the Tracking API (php or java client): setAttributionInfo()
- */
- getAttributionInfo: function () {
- return loadReferrerAttributionCookie();
- },
+ /**
+ * Get the visitor information (from first party cookie)
+ *
+ * @return array
+ */
+ this.getVisitorInfo = function () {
+ // Note: in a new method, we could return also return getValuesFromVisitorIdCookie()
+ // which returns named parameters rather than returning integer indexed array
+ return loadVisitorIdCookie();
+ };
- /**
- * Get the Campaign name that was parsed from the landing page URL when the visitor
- * landed on the site originally
- *
- * @return string
- */
- getAttributionCampaignName: function () {
- return loadReferrerAttributionCookie()[0];
- },
+ /**
+ * Get the Attribution information, which is an array that contains
+ * the Referrer used to reach the site as well as the campaign name and keyword
+ * It is useful only when used in conjunction with Tracker API function setAttributionInfo()
+ * To access specific data point, you should use the other functions getAttributionReferrer* and getAttributionCampaign*
+ *
+ * @return array Attribution array, Example use:
+ * 1) Call JSON2.stringify(piwikTracker.getAttributionInfo())
+ * 2) Pass this json encoded string to the Tracking API (php or java client): setAttributionInfo()
+ */
+ this.getAttributionInfo = function () {
+ return loadReferrerAttributionCookie();
+ };
- /**
- * Get the Campaign keyword that was parsed from the landing page URL when the visitor
- * landed on the site originally
- *
- * @return string
- */
- getAttributionCampaignKeyword: function () {
- return loadReferrerAttributionCookie()[1];
- },
+ /**
+ * Get the Campaign name that was parsed from the landing page URL when the visitor
+ * landed on the site originally
+ *
+ * @return string
+ */
+ this.getAttributionCampaignName = function () {
+ return loadReferrerAttributionCookie()[0];
+ };
- /**
- * Get the time at which the referrer (used for Goal Attribution) was detected
- *
- * @return int Timestamp or 0 if no referrer currently set
- */
- getAttributionReferrerTimestamp: function () {
- return loadReferrerAttributionCookie()[2];
- },
+ /**
+ * Get the Campaign keyword that was parsed from the landing page URL when the visitor
+ * landed on the site originally
+ *
+ * @return string
+ */
+ this.getAttributionCampaignKeyword = function () {
+ return loadReferrerAttributionCookie()[1];
+ };
- /**
- * Get the full referrer URL that will be used for Goal Attribution
- *
- * @return string Raw URL, or empty string '' if no referrer currently set
- */
- getAttributionReferrerUrl: function () {
- return loadReferrerAttributionCookie()[3];
- },
+ /**
+ * Get the time at which the referrer (used for Goal Attribution) was detected
+ *
+ * @return int Timestamp or 0 if no referrer currently set
+ */
+ this.getAttributionReferrerTimestamp = function () {
+ return loadReferrerAttributionCookie()[2];
+ };
- /**
- * Specify the Piwik server URL
- *
- * @param string trackerUrl
- */
- setTrackerUrl: function (trackerUrl) {
- configTrackerUrl = trackerUrl;
- },
+ /**
+ * Get the full referrer URL that will be used for Goal Attribution
+ *
+ * @return string Raw URL, or empty string '' if no referrer currently set
+ */
+ this.getAttributionReferrerUrl = function () {
+ return loadReferrerAttributionCookie()[3];
+ };
+ /**
+ * Specify the Piwik server URL
+ *
+ * @param string trackerUrl
+ */
+ this.setTrackerUrl = function (trackerUrl) {
+ configTrackerUrl = trackerUrl;
+ };
- /**
- * Returns the Piwik server URL
- * @returns string
- */
- getTrackerUrl: function () {
- return configTrackerUrl;
- },
+ /**
+ * Returns the Piwik server URL
+ * @returns string
+ */
+ this.getTrackerUrl = function () {
+ return configTrackerUrl;
+ };
- /**
- * Adds a new tracker. All sent requests will be also sent to the given siteId and piwikUrl.
- * If piwikUrl is not set, current url will be used.
- *
- * @param null|string piwikUrl If null, will reuse the same tracker URL of the current tracker instance
- * @param int|string siteId
- * @return Tracker
- */
- addTracker: function (piwikUrl, siteId) {
- if (!siteId) {
- throw new Error('A siteId must be given to add a new tracker');
- }
+ /**
+ * Adds a new tracker. All sent requests will be also sent to the given siteId and piwikUrl.
+ * If piwikUrl is not set, current url will be used.
+ *
+ * @param null|string piwikUrl If null, will reuse the same tracker URL of the current tracker instance
+ * @param int|string siteId
+ * @return Tracker
+ */
+ this.addTracker = function (piwikUrl, siteId) {
+ if (!siteId) {
+ throw new Error('A siteId must be given to add a new tracker');
+ }
- if (!isDefined(piwikUrl) || null === piwikUrl) {
- piwikUrl = this.getTrackerUrl();
- }
+ if (!isDefined(piwikUrl) || null === piwikUrl) {
+ piwikUrl = this.getTrackerUrl();
+ }
- var tracker = new Tracker(piwikUrl, siteId);
+ var tracker = new Tracker(piwikUrl, siteId);
- asyncTrackers.push(tracker);
+ asyncTrackers.push(tracker);
- return tracker;
- },
+ return tracker;
+ };
- /**
- * Returns the site ID
- *
- * @returns int
- */
- getSiteId: function() {
- return configTrackerSiteId;
- },
+ /**
+ * Returns the site ID
+ *
+ * @returns int
+ */
+ this.getSiteId = function() {
+ return configTrackerSiteId;
+ };
- /**
- * Specify the site ID
- *
- * @param int|string siteId
- */
- setSiteId: function (siteId) {
- setSiteId(siteId);
- },
+ /**
+ * Specify the site ID
+ *
+ * @param int|string siteId
+ */
+ this.setSiteId = function (siteId) {
+ setSiteId(siteId);
+ };
- /**
- * Sets a User ID to this user (such as an email address or a username)
- *
- * @param string User ID
- */
- setUserId: function (userId) {
- if(!isDefined(userId) || !userId.length) {
- return;
- }
- configUserId = userId;
- visitorUUID = hash(configUserId).substr(0, 16);
- },
+ /**
+ * Sets a User ID to this user (such as an email address or a username)
+ *
+ * @param string User ID
+ */
+ this.setUserId = function (userId) {
+ if(!isDefined(userId) || !userId.length) {
+ return;
+ }
+ configUserId = userId;
+ visitorUUID = hash(configUserId).substr(0, 16);
+ };
- /**
- * Gets the User ID if set.
- *
- * @returns string User ID
- */
- getUserId: function() {
- return configUserId;
- },
+ /**
+ * Gets the User ID if set.
+ *
+ * @returns string User ID
+ */
+ this.getUserId = function() {
+ return configUserId;
+ };
- /**
- * Pass custom data to the server
- *
- * Examples:
- * tracker.setCustomData(object);
- * tracker.setCustomData(key, value);
- *
- * @param mixed key_or_obj
- * @param mixed opt_value
- */
- setCustomData: function (key_or_obj, opt_value) {
- if (isObject(key_or_obj)) {
- configCustomData = key_or_obj;
- } else {
- if (!configCustomData) {
- configCustomData = {};
- }
- configCustomData[key_or_obj] = opt_value;
+ /**
+ * Pass custom data to the server
+ *
+ * Examples:
+ * tracker.setCustomData(object);
+ * tracker.setCustomData(key, value);
+ *
+ * @param mixed key_or_obj
+ * @param mixed opt_value
+ */
+ this.setCustomData = function (key_or_obj, opt_value) {
+ if (isObject(key_or_obj)) {
+ configCustomData = key_or_obj;
+ } else {
+ if (!configCustomData) {
+ configCustomData = {};
}
- },
+ configCustomData[key_or_obj] = opt_value;
+ }
+ };
- /**
- * Get custom data
- *
- * @return mixed
- */
- getCustomData: function () {
- return configCustomData;
- },
+ /**
+ * Get custom data
+ *
+ * @return mixed
+ */
+ this.getCustomData = function () {
+ return configCustomData;
+ };
- /**
- * Configure function with custom request content processing logic.
- * It gets called after request content in form of query parameters string has been prepared and before request content gets sent.
- *
- * Examples:
- * tracker.setCustomRequestProcessing(function(request){
- * var pairs = request.split('&');
- * var result = {};
- * pairs.forEach(function(pair) {
- * pair = pair.split('=');
- * result[pair[0]] = decodeURIComponent(pair[1] || '');
- * });
- * return JSON.stringify(result);
- * });
- *
- * @param function customRequestContentProcessingLogic
- */
- setCustomRequestProcessing: function (customRequestContentProcessingLogic) {
- configCustomRequestContentProcessing = customRequestContentProcessingLogic;
- },
+ /**
+ * Configure function with custom request content processing logic.
+ * It gets called after request content in form of query parameters string has been prepared and before request content gets sent.
+ *
+ * Examples:
+ * tracker.setCustomRequestProcessing(function(request){
+ * var pairs = request.split('&');
+ * var result = {};
+ * pairs.forEach(function(pair) {
+ * pair = pair.split('=');
+ * result[pair[0]] = decodeURIComponent(pair[1] || '');
+ * });
+ * return JSON.stringify(result);
+ * });
+ *
+ * @param function customRequestContentProcessingLogic
+ */
+ this.setCustomRequestProcessing = function (customRequestContentProcessingLogic) {
+ configCustomRequestContentProcessing = customRequestContentProcessingLogic;
+ };
- /**
- * Appends the specified query string to the piwik.php?... Tracking API URL
- *
- * @param string queryString eg. 'lat=140&long=100'
- */
- appendToTrackingUrl: function (queryString) {
- configAppendToTrackingUrl = queryString;
- },
+ /**
+ * Appends the specified query string to the piwik.php?... Tracking API URL
+ *
+ * @param string queryString eg. 'lat=140&long=100'
+ */
+ this.appendToTrackingUrl = function (queryString) {
+ configAppendToTrackingUrl = queryString;
+ };
- /**
- * Returns the query string for the current HTTP Tracking API request.
- * Piwik would prepend the hostname and path to Piwik: http://example.org/piwik/piwik.php?
- * prior to sending the request.
- *
- * @param request eg. "param=value&param2=value2"
- */
- getRequest: function (request) {
- return getRequest(request);
- },
+ /**
+ * Returns the query string for the current HTTP Tracking API request.
+ * Piwik would prepend the hostname and path to Piwik: http://example.org/piwik/piwik.php?
+ * prior to sending the request.
+ *
+ * @param request eg. "param=value&param2=value2"
+ */
+ this.getRequest = function (request) {
+ return getRequest(request);
+ };
- /**
- * Add plugin defined by a name and a callback function.
- * The callback function will be called whenever a tracking request is sent.
- * This can be used to append data to the tracking request, or execute other custom logic.
- *
- * @param string pluginName
- * @param Object pluginObj
- */
- addPlugin: function (pluginName, pluginObj) {
- plugins[pluginName] = pluginObj;
- },
+ /**
+ * Add plugin defined by a name and a callback function.
+ * The callback function will be called whenever a tracking request is sent.
+ * This can be used to append data to the tracking request, or execute other custom logic.
+ *
+ * @param string pluginName
+ * @param Object pluginObj
+ */
+ this.addPlugin = function (pluginName, pluginObj) {
+ plugins[pluginName] = pluginObj;
+ };
- /**
- * Set Custom Dimensions. Set Custom Dimensions will not be cleared after a tracked pageview and will
- * be sent along all following tracking requests. It is possible to remove/clear a value via `deleteCustomDimension`.
- *
- * @param int index A Custom Dimension index
- * @param string value
- */
- setCustomDimension: function (customDimensionId, value) {
- customDimensionId = parseInt(customDimensionId, 10);
- if (customDimensionId > 0) {
- if (!isDefined(value)) {
- value = '';
- }
- if (!isString(value)) {
- value = String(value);
- }
- customDimensions[customDimensionId] = value;
+ /**
+ * Set Custom Dimensions. Set Custom Dimensions will not be cleared after a tracked pageview and will
+ * be sent along all following tracking requests. It is possible to remove/clear a value via `deleteCustomDimension`.
+ *
+ * @param int index A Custom Dimension index
+ * @param string value
+ */
+ this.setCustomDimension = function (customDimensionId, value) {
+ customDimensionId = parseInt(customDimensionId, 10);
+ if (customDimensionId > 0) {
+ if (!isDefined(value)) {
+ value = '';
}
- },
-
- /**
- * Get a stored value for a specific Custom Dimension index.
- *
- * @param int index A Custom Dimension index
- */
- getCustomDimension: function (customDimensionId) {
- customDimensionId = parseInt(customDimensionId, 10);
- if (customDimensionId > 0 && Object.prototype.hasOwnProperty.call(customDimensions, customDimensionId)) {
- return customDimensions[customDimensionId];
+ if (!isString(value)) {
+ value = String(value);
}
- },
+ customDimensions[customDimensionId] = value;
+ }
+ };
- /**
- * Delete a custom dimension.
- *
- * @param int index Custom dimension Id
- */
- deleteCustomDimension: function (customDimensionId) {
- customDimensionId = parseInt(customDimensionId, 10);
- if (customDimensionId > 0) {
- delete customDimensions[customDimensionId];
- }
- },
+ /**
+ * Get a stored value for a specific Custom Dimension index.
+ *
+ * @param int index A Custom Dimension index
+ */
+ this.getCustomDimension = function (customDimensionId) {
+ customDimensionId = parseInt(customDimensionId, 10);
+ if (customDimensionId > 0 && Object.prototype.hasOwnProperty.call(customDimensions, customDimensionId)) {
+ return customDimensions[customDimensionId];
+ }
+ };
- /**
- * Set custom variable within this visit
- *
- * @param int index Custom variable slot ID from 1-5
- * @param string name
- * @param string value
- * @param string scope Scope of Custom Variable:
- * - "visit" will store the name/value in the visit and will persist it in the cookie for the duration of the visit,
- * - "page" will store the name/value in the next page view tracked.
- * - "event" will store the name/value in the next event tracked.
- */
- setCustomVariable: function (index, name, value, scope) {
- var toRecord;
+ /**
+ * Delete a custom dimension.
+ *
+ * @param int index Custom dimension Id
+ */
+ this.deleteCustomDimension = function (customDimensionId) {
+ customDimensionId = parseInt(customDimensionId, 10);
+ if (customDimensionId > 0) {
+ delete customDimensions[customDimensionId];
+ }
+ };
- if (!isDefined(scope)) {
- scope = 'visit';
- }
- if (!isDefined(name)) {
- return;
- }
- if (!isDefined(value)) {
- value = "";
- }
- if (index > 0) {
- name = !isString(name) ? String(name) : name;
- value = !isString(value) ? String(value) : value;
- toRecord = [name.slice(0, customVariableMaximumLength), value.slice(0, customVariableMaximumLength)];
- // numeric scope is there for GA compatibility
- if (scope === 'visit' || scope === 2) {
- loadCustomVariables();
- customVariables[index] = toRecord;
- } else if (scope === 'page' || scope === 3) {
- customVariablesPage[index] = toRecord;
- } else if (scope === 'event') { /* GA does not have 'event' scope but we do */
- customVariablesEvent[index] = toRecord;
- }
+ /**
+ * Set custom variable within this visit
+ *
+ * @param int index Custom variable slot ID from 1-5
+ * @param string name
+ * @param string value
+ * @param string scope Scope of Custom Variable:
+ * - "visit" will store the name/value in the visit and will persist it in the cookie for the duration of the visit,
+ * - "page" will store the name/value in the next page view tracked.
+ * - "event" will store the name/value in the next event tracked.
+ */
+ this.setCustomVariable = function (index, name, value, scope) {
+ var toRecord;
+
+ if (!isDefined(scope)) {
+ scope = 'visit';
+ }
+ if (!isDefined(name)) {
+ return;
+ }
+ if (!isDefined(value)) {
+ value = "";
+ }
+ if (index > 0) {
+ name = !isString(name) ? String(name) : name;
+ value = !isString(value) ? String(value) : value;
+ toRecord = [name.slice(0, customVariableMaximumLength), value.slice(0, customVariableMaximumLength)];
+ // numeric scope is there for GA compatibility
+ if (scope === 'visit' || scope === 2) {
+ loadCustomVariables();
+ customVariables[index] = toRecord;
+ } else if (scope === 'page' || scope === 3) {
+ customVariablesPage[index] = toRecord;
+ } else if (scope === 'event') { /* GA does not have 'event' scope but we do */
+ customVariablesEvent[index] = toRecord;
}
- },
+ }
+ };
- /**
- * Get custom variable
- *
- * @param int index Custom variable slot ID from 1-5
- * @param string scope Scope of Custom Variable: "visit" or "page" or "event"
- */
- getCustomVariable: function (index, scope) {
- var cvar;
+ /**
+ * Get custom variable
+ *
+ * @param int index Custom variable slot ID from 1-5
+ * @param string scope Scope of Custom Variable: "visit" or "page" or "event"
+ */
+ this.getCustomVariable = function (index, scope) {
+ var cvar;
- if (!isDefined(scope)) {
- scope = "visit";
- }
+ if (!isDefined(scope)) {
+ scope = "visit";
+ }
- if (scope === "page" || scope === 3) {
- cvar = customVariablesPage[index];
- } else if (scope === "event") {
- cvar = customVariablesEvent[index];
- } else if (scope === "visit" || scope === 2) {
- loadCustomVariables();
- cvar = customVariables[index];
- }
+ if (scope === "page" || scope === 3) {
+ cvar = customVariablesPage[index];
+ } else if (scope === "event") {
+ cvar = customVariablesEvent[index];
+ } else if (scope === "visit" || scope === 2) {
+ loadCustomVariables();
+ cvar = customVariables[index];
+ }
- if (!isDefined(cvar)
- || (cvar && cvar[0] === '')) {
- return false;
- }
+ if (!isDefined(cvar)
+ || (cvar && cvar[0] === '')) {
+ return false;
+ }
- return cvar;
- },
+ return cvar;
+ };
- /**
- * Delete custom variable
- *
- * @param int index Custom variable slot ID from 1-5
- * @param string scope
- */
- deleteCustomVariable: function (index, scope) {
- // Only delete if it was there already
- if (this.getCustomVariable(index, scope)) {
- this.setCustomVariable(index, '', '', scope);
- }
- },
+ /**
+ * Delete custom variable
+ *
+ * @param int index Custom variable slot ID from 1-5
+ * @param string scope
+ */
+ this.deleteCustomVariable = function (index, scope) {
+ // Only delete if it was there already
+ if (this.getCustomVariable(index, scope)) {
+ this.setCustomVariable(index, '', '', scope);
+ }
+ };
- /**
- * When called then the Custom Variables of scope "visit" will be stored (persisted) in a first party cookie
- * for the duration of the visit. This is useful if you want to call getCustomVariable later in the visit.
- *
- * By default, Custom Variables of scope "visit" are not stored on the visitor's computer.
- */
- storeCustomVariablesInCookie: function () {
- configStoreCustomVariablesInCookie = true;
- },
+ /**
+ * When called then the Custom Variables of scope "visit" will be stored (persisted) in a first party cookie
+ * for the duration of the visit. This is useful if you want to call getCustomVariable later in the visit.
+ *
+ * By default, Custom Variables of scope "visit" are not stored on the visitor's computer.
+ */
+ this.storeCustomVariablesInCookie = function () {
+ configStoreCustomVariablesInCookie = true;
+ };
- /**
- * Set delay for link tracking (in milliseconds)
- *
- * @param int delay
- */
- setLinkTrackingTimer: function (delay) {
- configTrackerPause = delay;
- },
+ /**
+ * Set delay for link tracking (in milliseconds)
+ *
+ * @param int delay
+ */
+ this.setLinkTrackingTimer = function (delay) {
+ configTrackerPause = delay;
+ };
- /**
- * Set list of file extensions to be recognized as downloads
- *
- * @param string|array extensions
- */
- setDownloadExtensions: function (extensions) {
- if(isString(extensions)) {
- extensions = extensions.split('|');
- }
- configDownloadExtensions = extensions;
- },
+ /**
+ * Set list of file extensions to be recognized as downloads
+ *
+ * @param string|array extensions
+ */
+ this.setDownloadExtensions = function (extensions) {
+ if(isString(extensions)) {
+ extensions = extensions.split('|');
+ }
+ configDownloadExtensions = extensions;
+ };
- /**
- * Specify additional file extensions to be recognized as downloads
- *
- * @param string|array extensions for example 'custom' or ['custom1','custom2','custom3']
- */
- addDownloadExtensions: function (extensions) {
- var i;
- if(isString(extensions)) {
- extensions = extensions.split('|');
- }
- for (i=0; i < extensions.length; i++) {
- configDownloadExtensions.push(extensions[i]);
- }
- },
+ /**
+ * Specify additional file extensions to be recognized as downloads
+ *
+ * @param string|array extensions for example 'custom' or ['custom1','custom2','custom3']
+ */
+ this.addDownloadExtensions = function (extensions) {
+ var i;
+ if(isString(extensions)) {
+ extensions = extensions.split('|');
+ }
+ for (i=0; i < extensions.length; i++) {
+ configDownloadExtensions.push(extensions[i]);
+ }
+ };
- /**
- * Removes specified file extensions from the list of recognized downloads
- *
- * @param string|array extensions for example 'custom' or ['custom1','custom2','custom3']
- */
- removeDownloadExtensions: function (extensions) {
- var i, newExtensions = [];
- if(isString(extensions)) {
- extensions = extensions.split('|');
- }
- for (i=0; i < configDownloadExtensions.length; i++) {
- if (indexOfArray(extensions, configDownloadExtensions[i]) === -1) {
- newExtensions.push(configDownloadExtensions[i]);
- }
+ /**
+ * Removes specified file extensions from the list of recognized downloads
+ *
+ * @param string|array extensions for example 'custom' or ['custom1','custom2','custom3']
+ */
+ this.removeDownloadExtensions = function (extensions) {
+ var i, newExtensions = [];
+ if(isString(extensions)) {
+ extensions = extensions.split('|');
+ }
+ for (i=0; i < configDownloadExtensions.length; i++) {
+ if (indexOfArray(extensions, configDownloadExtensions[i]) === -1) {
+ newExtensions.push(configDownloadExtensions[i]);
}
- configDownloadExtensions = newExtensions;
- },
-
- /**
- * Set array of domains to be treated as local. Also supports path, eg '.piwik.org/subsite1'. In this
- * 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.
- *
- * 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.
- *
- * The current domain will be added automatically if no given host alias contains a path and if no host
- * alias is already given for the current host alias. Say you are on "example.org" and set
- * "hostAlias = ['example.com', 'example.org/test']" then the current "example.org" domain will not be
- * added as there is already a more restrictive hostAlias 'example.org/test' given. We also do not add
- * it automatically if there was any other host specifying any path like
- * "['example.com', 'example2.com/test']". In this case we would also not add the current
- * domain "example.org" automatically as the "path" feature is used. As soon as someone uses the path
- * feature, for Piwik JS Tracker to work correctly in all cases, one needs to specify all hosts
- * manually.
- *
- * @param string|array hostsAlias
- */
- setDomains: function (hostsAlias) {
- configHostsAlias = isString(hostsAlias) ? [hostsAlias] : hostsAlias;
+ }
+ configDownloadExtensions = newExtensions;
+ };
- var hasDomainAliasAlready = false, i = 0, alias;
- for (i; i < configHostsAlias.length; i++) {
- alias = String(configHostsAlias[i]);
+ /**
+ * Set array of domains to be treated as local. Also supports path, eg '.piwik.org/subsite1'. In this
+ * 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.
+ *
+ * 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.
+ *
+ * The current domain will be added automatically if no given host alias contains a path and if no host
+ * alias is already given for the current host alias. Say you are on "example.org" and set
+ * "hostAlias = ['example.com', 'example.org/test']" then the current "example.org" domain will not be
+ * added as there is already a more restrictive hostAlias 'example.org/test' given. We also do not add
+ * it automatically if there was any other host specifying any path like
+ * "['example.com', 'example2.com/test']". In this case we would also not add the current
+ * domain "example.org" automatically as the "path" feature is used. As soon as someone uses the path
+ * feature, for Piwik JS Tracker to work correctly in all cases, one needs to specify all hosts
+ * manually.
+ *
+ * @param string|array hostsAlias
+ */
+ this.setDomains = function (hostsAlias) {
+ configHostsAlias = isString(hostsAlias) ? [hostsAlias] : hostsAlias;
- if (isSameHost(domainAlias, domainFixup(alias))) {
- hasDomainAliasAlready = true;
- break;
- }
+ var hasDomainAliasAlready = false, i = 0, alias;
+ for (i; i < configHostsAlias.length; i++) {
+ alias = String(configHostsAlias[i]);
- var pathName = getPathName(alias);
- if (pathName && pathName !== '/' && pathName !== '/*') {
- hasDomainAliasAlready = true;
- break;
- }
+ if (isSameHost(domainAlias, domainFixup(alias))) {
+ hasDomainAliasAlready = true;
+ break;
}
- // The current domain will be added automatically if no given host alias contains a path
- // and if no host alias is already given for the current host alias.
- if (!hasDomainAliasAlready) {
- /**
- * eg if domainAlias = 'piwik.org' and someone set hostsAlias = ['piwik.org/foo'] then we should
- * not add piwik.org as it would increase the allowed scope.
- */
- configHostsAlias.push(domainAlias);
+ var pathName = getPathName(alias);
+ if (pathName && pathName !== '/' && pathName !== '/*') {
+ hasDomainAliasAlready = true;
+ break;
}
- },
+ }
- /**
- * Set array of classes to be ignored if present in link
- *
- * @param string|array ignoreClasses
- */
- setIgnoreClasses: function (ignoreClasses) {
- configIgnoreClasses = isString(ignoreClasses) ? [ignoreClasses] : ignoreClasses;
- },
+ // The current domain will be added automatically if no given host alias contains a path
+ // and if no host alias is already given for the current host alias.
+ if (!hasDomainAliasAlready) {
+ /**
+ * eg if domainAlias = 'piwik.org' and someone set hostsAlias = ['piwik.org/foo'] then we should
+ * not add piwik.org as it would increase the allowed scope.
+ */
+ configHostsAlias.push(domainAlias);
+ }
+ };
- /**
- * Set request method
- *
- * @param string method GET or POST; default is GET
- */
- setRequestMethod: function (method) {
- configRequestMethod = method || defaultRequestMethod;
- },
+ /**
+ * Set array of classes to be ignored if present in link
+ *
+ * @param string|array ignoreClasses
+ */
+ this.setIgnoreClasses = function (ignoreClasses) {
+ configIgnoreClasses = isString(ignoreClasses) ? [ignoreClasses] : ignoreClasses;
+ };
- /**
- * Set request Content-Type header value, applicable when POST request method is used for submitting tracking events.
- * See XMLHttpRequest Level 2 spec, section 4.7.2 for invalid headers
- * @link http://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html
- *
- * @param string requestContentType; default is 'application/x-www-form-urlencoded; charset=UTF-8'
- */
- setRequestContentType: function (requestContentType) {
- configRequestContentType = requestContentType || defaultRequestContentType;
- },
+ /**
+ * Set request method
+ *
+ * @param string method GET or POST; default is GET
+ */
+ this.setRequestMethod = function (method) {
+ configRequestMethod = method || defaultRequestMethod;
+ };
- /**
- * Override referrer
- *
- * @param string url
- */
- setReferrerUrl: function (url) {
- configReferrerUrl = url;
- },
+ /**
+ * Set request Content-Type header value, applicable when POST request method is used for submitting tracking events.
+ * See XMLHttpRequest Level 2 spec, section 4.7.2 for invalid headers
+ * @link http://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html
+ *
+ * @param string requestContentType; default is 'application/x-www-form-urlencoded; charset=UTF-8'
+ */
+ this.setRequestContentType = function (requestContentType) {
+ configRequestContentType = requestContentType || defaultRequestContentType;
+ };
- /**
- * Override url
- *
- * @param string url
- */
- setCustomUrl: function (url) {
- configCustomUrl = resolveRelativeReference(locationHrefAlias, url);
- },
+ /**
+ * Override referrer
+ *
+ * @param string url
+ */
+ this.setReferrerUrl = function (url) {
+ configReferrerUrl = url;
+ };
- /**
- * Override document.title
- *
- * @param string title
- */
- setDocumentTitle: function (title) {
- configTitle = title;
- },
+ /**
+ * Override url
+ *
+ * @param string url
+ */
+ this.setCustomUrl = function (url) {
+ configCustomUrl = resolveRelativeReference(locationHrefAlias, url);
+ };
- /**
- * Set the URL of the Piwik API. It is used for Page Overlay.
- * This method should only be called when the API URL differs from the tracker URL.
- *
- * @param string apiUrl
- */
- setAPIUrl: function (apiUrl) {
- configApiUrl = apiUrl;
- },
+ /**
+ * Override document.title
+ *
+ * @param string title
+ */
+ this.setDocumentTitle = function (title) {
+ configTitle = title;
+ };
- /**
- * Set array of classes to be treated as downloads
- *
- * @param string|array downloadClasses
- */
- setDownloadClasses: function (downloadClasses) {
- configDownloadClasses = isString(downloadClasses) ? [downloadClasses] : downloadClasses;
- },
+ /**
+ * Set the URL of the Piwik API. It is used for Page Overlay.
+ * This method should only be called when the API URL differs from the tracker URL.
+ *
+ * @param string apiUrl
+ */
+ this.setAPIUrl = function (apiUrl) {
+ configApiUrl = apiUrl;
+ };
- /**
- * Set array of classes to be treated as outlinks
- *
- * @param string|array linkClasses
- */
- setLinkClasses: function (linkClasses) {
- configLinkClasses = isString(linkClasses) ? [linkClasses] : linkClasses;
- },
+ /**
+ * Set array of classes to be treated as downloads
+ *
+ * @param string|array downloadClasses
+ */
+ this.setDownloadClasses = function (downloadClasses) {
+ configDownloadClasses = isString(downloadClasses) ? [downloadClasses] : downloadClasses;
+ };
- /**
- * Set array of campaign name parameters
- *
- * @see http://piwik.org/faq/how-to/#faq_120
- * @param string|array campaignNames
- */
- setCampaignNameKey: function (campaignNames) {
- configCampaignNameParameters = isString(campaignNames) ? [campaignNames] : campaignNames;
- },
+ /**
+ * Set array of classes to be treated as outlinks
+ *
+ * @param string|array linkClasses
+ */
+ this.setLinkClasses = function (linkClasses) {
+ configLinkClasses = isString(linkClasses) ? [linkClasses] : linkClasses;
+ };
- /**
- * Set array of campaign keyword parameters
- *
- * @see http://piwik.org/faq/how-to/#faq_120
- * @param string|array campaignKeywords
- */
- setCampaignKeywordKey: function (campaignKeywords) {
- configCampaignKeywordParameters = isString(campaignKeywords) ? [campaignKeywords] : campaignKeywords;
- },
+ /**
+ * Set array of campaign name parameters
+ *
+ * @see http://piwik.org/faq/how-to/#faq_120
+ * @param string|array campaignNames
+ */
+ this.setCampaignNameKey = function (campaignNames) {
+ configCampaignNameParameters = isString(campaignNames) ? [campaignNames] : campaignNames;
+ };
- /**
- * Strip hash tag (or anchor) from URL
- * Note: this can be done in the Piwik>Settings>Websites on a per-website basis
- *
- * @deprecated
- * @param bool enableFilter
- */
- discardHashTag: function (enableFilter) {
- configDiscardHashTag = enableFilter;
- },
+ /**
+ * Set array of campaign keyword parameters
+ *
+ * @see http://piwik.org/faq/how-to/#faq_120
+ * @param string|array campaignKeywords
+ */
+ this.setCampaignKeywordKey = function (campaignKeywords) {
+ configCampaignKeywordParameters = isString(campaignKeywords) ? [campaignKeywords] : campaignKeywords;
+ };
- /**
- * Set first-party cookie name prefix
- *
- * @param string cookieNamePrefix
- */
- setCookieNamePrefix: function (cookieNamePrefix) {
- configCookieNamePrefix = cookieNamePrefix;
- // Re-init the Custom Variables cookie
- customVariables = getCustomVariablesFromCookie();
- },
+ /**
+ * Strip hash tag (or anchor) from URL
+ * Note: this can be done in the Piwik>Settings>Websites on a per-website basis
+ *
+ * @deprecated
+ * @param bool enableFilter
+ */
+ this.discardHashTag = function (enableFilter) {
+ configDiscardHashTag = enableFilter;
+ };
- /**
- * Set first-party cookie domain
- *
- * @param string domain
- */
- setCookieDomain: function (domain) {
- var domainFixed = domainFixup(domain);
+ /**
+ * Set first-party cookie name prefix
+ *
+ * @param string cookieNamePrefix
+ */
+ this.setCookieNamePrefix = function (cookieNamePrefix) {
+ configCookieNamePrefix = cookieNamePrefix;
+ // Re-init the Custom Variables cookie
+ customVariables = getCustomVariablesFromCookie();
+ };
- if (isPossibleToSetCookieOnDomain(domainFixed)) {
- configCookieDomain = domainFixed;
- updateDomainHash();
- }
- },
+ /**
+ * Set first-party cookie domain
+ *
+ * @param string domain
+ */
+ this.setCookieDomain = function (domain) {
+ var domainFixed = domainFixup(domain);
- /**
- * Set first-party cookie path
- *
- * @param string domain
- */
- setCookiePath: function (path) {
- configCookiePath = path;
+ if (isPossibleToSetCookieOnDomain(domainFixed)) {
+ configCookieDomain = domainFixed;
updateDomainHash();
- },
+ }
+ };
- /**
- * Set visitor cookie timeout (in seconds)
- * Defaults to 13 months (timeout=33955200)
- *
- * @param int timeout
- */
- setVisitorCookieTimeout: function (timeout) {
- configVisitorCookieTimeout = timeout * 1000;
- },
+ /**
+ * Set first-party cookie path
+ *
+ * @param string domain
+ */
+ this.setCookiePath = function (path) {
+ configCookiePath = path;
+ updateDomainHash();
+ };
- /**
- * Set session cookie timeout (in seconds).
- * Defaults to 30 minutes (timeout=1800)
- *
- * @param int timeout
- */
- setSessionCookieTimeout: function (timeout) {
- configSessionCookieTimeout = timeout * 1000;
- },
+ /**
+ * Set visitor cookie timeout (in seconds)
+ * Defaults to 13 months (timeout=33955200)
+ *
+ * @param int timeout
+ */
+ this.setVisitorCookieTimeout = function (timeout) {
+ configVisitorCookieTimeout = timeout * 1000;
+ };
- /**
- * Set referral cookie timeout (in seconds).
- * Defaults to 6 months (15768000000)
- *
- * @param int timeout
- */
- setReferralCookieTimeout: function (timeout) {
- configReferralCookieTimeout = timeout * 1000;
- },
+ /**
+ * Set session cookie timeout (in seconds).
+ * Defaults to 30 minutes (timeout=1800)
+ *
+ * @param int timeout
+ */
+ this.setSessionCookieTimeout = function (timeout) {
+ configSessionCookieTimeout = timeout * 1000;
+ };
- /**
- * Set conversion attribution to first referrer and campaign
- *
- * @param bool if true, use first referrer (and first campaign)
- * if false, use the last referrer (or campaign)
- */
- setConversionAttributionFirstReferrer: function (enable) {
- configConversionAttributionFirstReferrer = enable;
- },
+ /**
+ * Set referral cookie timeout (in seconds).
+ * Defaults to 6 months (15768000000)
+ *
+ * @param int timeout
+ */
+ this.setReferralCookieTimeout = function (timeout) {
+ configReferralCookieTimeout = timeout * 1000;
+ };
- /**
- * Disables all cookies from being set
- *
- * Existing cookies will be deleted on the next call to track
- */
- disableCookies: function () {
- configCookiesDisabled = true;
- browserFeatures.cookie = '0';
+ /**
+ * Set conversion attribution to first referrer and campaign
+ *
+ * @param bool if true, use first referrer (and first campaign)
+ * if false, use the last referrer (or campaign)
+ */
+ this.setConversionAttributionFirstReferrer = function (enable) {
+ configConversionAttributionFirstReferrer = enable;
+ };
- if (configTrackerSiteId) {
- deleteCookies();
- }
- },
+ /**
+ * Disables all cookies from being set
+ *
+ * Existing cookies will be deleted on the next call to track
+ */
+ this.disableCookies = function () {
+ configCookiesDisabled = true;
+ browserFeatures.cookie = '0';
- /**
- * One off cookies clearing. Useful to call this when you know for sure a new visitor is using the same browser,
- * it maybe helps to "reset" tracking cookies to prevent data reuse for different users.
- */
- deleteCookies: function () {
+ if (configTrackerSiteId) {
deleteCookies();
- },
+ }
+ };
- /**
- * Handle do-not-track requests
- *
- * @param bool enable If true, don't track if user agent sends 'do-not-track' header
- */
- setDoNotTrack: function (enable) {
- var dnt = navigatorAlias.doNotTrack || navigatorAlias.msDoNotTrack;
- configDoNotTrack = enable && (dnt === 'yes' || dnt === '1');
+ /**
+ * One off cookies clearing. Useful to call this when you know for sure a new visitor is using the same browser,
+ * it maybe helps to "reset" tracking cookies to prevent data reuse for different users.
+ */
+ this.deleteCookies = function () {
+ deleteCookies();
+ };
- // do not track also disables cookies and deletes existing cookies
- if (configDoNotTrack) {
- this.disableCookies();
- }
- },
+ /**
+ * Handle do-not-track requests
+ *
+ * @param bool enable If true, don't track if user agent sends 'do-not-track' header
+ */
+ this.setDoNotTrack = function (enable) {
+ var dnt = navigatorAlias.doNotTrack || navigatorAlias.msDoNotTrack;
+ configDoNotTrack = enable && (dnt === 'yes' || dnt === '1');
- /**
- * Add click listener to a specific link element.
- * When clicked, Piwik will log the click automatically.
- *
- * @param DOMElement element
- * @param bool enable If true, use pseudo click-handler (middle click + context menu)
- */
- addListener: function (element, enable) {
- addClickListener(element, enable);
- },
+ // do not track also disables cookies and deletes existing cookies
+ if (configDoNotTrack) {
+ this.disableCookies();
+ }
+ };
- /**
- * Install link tracker
- *
- * The default behaviour is to use actual click events. However, some browsers
- * (e.g., Firefox, Opera, and Konqueror) don't generate click events for the middle mouse button.
- *
- * To capture more "clicks", the pseudo click-handler uses mousedown + mouseup events.
- * This is not industry standard and is vulnerable to false positives (e.g., drag events).
- *
- * There is a Safari/Chrome/Webkit bug that prevents tracking requests from being sent
- * by either click handler. The workaround is to set a target attribute (which can't
- * be "_self", "_top", or "_parent").
- *
- * @see https://bugs.webkit.org/show_bug.cgi?id=54783
- *
- * @param bool enable If "true", use pseudo click-handler (treat middle click and open contextmenu as
- * left click). A right click (or any click that opens the context menu) on a link
- * will be tracked as clicked even if "Open in new tab" is not selected. If
- * "false" (default), nothing will be tracked on open context menu or middle click.
- * The context menu is usually opened to open a link / download in a new tab
- * therefore you can get more accurate results by treat it as a click but it can lead
- * to wrong click numbers.
- */
- enableLinkTracking: function (enable) {
- linkTrackingEnabled = true;
+ /**
+ * Add click listener to a specific link element.
+ * When clicked, Piwik will log the click automatically.
+ *
+ * @param DOMElement element
+ * @param bool enable If true, use pseudo click-handler (middle click + context menu)
+ */
+ this.addListener = function (element, enable) {
+ addClickListener(element, enable);
+ };
- trackCallback(function () {
- trackCallbackOnReady(function () {
- addClickListeners(enable);
- });
+ /**
+ * Install link tracker
+ *
+ * The default behaviour is to use actual click events. However, some browsers
+ * (e.g., Firefox, Opera, and Konqueror) don't generate click events for the middle mouse button.
+ *
+ * To capture more "clicks", the pseudo click-handler uses mousedown + mouseup events.
+ * This is not industry standard and is vulnerable to false positives (e.g., drag events).
+ *
+ * There is a Safari/Chrome/Webkit bug that prevents tracking requests from being sent
+ * by either click handler. The workaround is to set a target attribute (which can't
+ * be "_self", "_top", or "_parent").
+ *
+ * @see https://bugs.webkit.org/show_bug.cgi?id=54783
+ *
+ * @param bool enable If "true", use pseudo click-handler (treat middle click and open contextmenu as
+ * left click). A right click (or any click that opens the context menu) on a link
+ * will be tracked as clicked even if "Open in new tab" is not selected. If
+ * "false" (default), nothing will be tracked on open context menu or middle click.
+ * The context menu is usually opened to open a link / download in a new tab
+ * therefore you can get more accurate results by treat it as a click but it can lead
+ * to wrong click numbers.
+ */
+ this.enableLinkTracking = function (enable) {
+ linkTrackingEnabled = true;
+
+ trackCallback(function () {
+ trackCallbackOnReady(function () {
+ addClickListeners(enable);
});
- },
+ });
+ };
- /**
- * Enable tracking of uncatched JavaScript errors
- *
- * If enabled, uncaught JavaScript Errors will be tracked as an event by defining a
- * window.onerror handler. If a window.onerror handler is already defined we will make
- * sure to call this previously registered error handler after tracking the error.
- *
- * By default we return false in the window.onerror handler to make sure the error still
- * appears in the browser's console etc. Note: Some older browsers might behave differently
- * so it could happen that an actual JavaScript error will be suppressed.
- * If a window.onerror handler was registered we will return the result of this handler.
- *
- * Make sure not to overwrite the window.onerror handler after enabling the JS error
- * tracking as the error tracking won't work otherwise. To capture all JS errors we
- * recommend to include the Piwik JavaScript tracker in the HTML as early as possible.
- * If possible directly in <head></head> before loading any other JavaScript.
- */
- enableJSErrorTracking: function () {
- if (enableJSErrorTracking) {
- return;
- }
+ /**
+ * Enable tracking of uncatched JavaScript errors
+ *
+ * If enabled, uncaught JavaScript Errors will be tracked as an event by defining a
+ * window.onerror handler. If a window.onerror handler is already defined we will make
+ * sure to call this previously registered error handler after tracking the error.
+ *
+ * By default we return false in the window.onerror handler to make sure the error still
+ * appears in the browser's console etc. Note: Some older browsers might behave differently
+ * so it could happen that an actual JavaScript error will be suppressed.
+ * If a window.onerror handler was registered we will return the result of this handler.
+ *
+ * Make sure not to overwrite the window.onerror handler after enabling the JS error
+ * tracking as the error tracking won't work otherwise. To capture all JS errors we
+ * recommend to include the Piwik JavaScript tracker in the HTML as early as possible.
+ * If possible directly in <head></head> before loading any other JavaScript.
+ */
+ this.enableJSErrorTracking = function () {
+ if (enableJSErrorTracking) {
+ return;
+ }
- enableJSErrorTracking = true;
- var onError = windowAlias.onerror;
+ enableJSErrorTracking = true;
+ var onError = windowAlias.onerror;
- windowAlias.onerror = function (message, url, linenumber, column, error) {
- trackCallback(function () {
- var category = 'JavaScript Errors';
+ windowAlias.onerror = function (message, url, linenumber, column, error) {
+ trackCallback(function () {
+ var category = 'JavaScript Errors';
- var action = url + ':' + linenumber;
- if (column) {
- action += ':' + column;
- }
+ var action = url + ':' + linenumber;
+ if (column) {
+ action += ':' + column;
+ }
- logEvent(category, action, message);
- });
+ logEvent(category, action, message);
+ });
- if (onError) {
- return onError(message, url, linenumber, column, error);
- }
+ if (onError) {
+ return onError(message, url, linenumber, column, error);
+ }
- return false;
- };
- },
+ return false;
+ };
+ };
- /**
- * Disable automatic performance tracking
- */
- disablePerformanceTracking: function () {
- configPerformanceTrackingEnabled = false;
- },
+ /**
+ * Disable automatic performance tracking
+ */
+ this.disablePerformanceTracking = function () {
+ configPerformanceTrackingEnabled = false;
+ };
- /**
- * Set the server generation time.
- * If set, the browser's performance.timing API in not used anymore to determine the time.
- *
- * @param int generationTime
- */
- setGenerationTimeMs: function (generationTime) {
- configPerformanceGenerationTime = parseInt(generationTime, 10);
- },
+ /**
+ * Set the server generation time.
+ * If set, the browser's performance.timing API in not used anymore to determine the time.
+ *
+ * @param int generationTime
+ */
+ this.setGenerationTimeMs = function (generationTime) {
+ configPerformanceGenerationTime = parseInt(generationTime, 10);
+ };
- /**
- * Set heartbeat (in seconds)
- *
- * @param int heartBeatDelayInSeconds Defaults to 15. Cannot be lower than 1.
- */
- enableHeartBeatTimer: function (heartBeatDelayInSeconds) {
- heartBeatDelayInSeconds = Math.max(heartBeatDelayInSeconds, 1);
- configHeartBeatDelay = (heartBeatDelayInSeconds || 15) * 1000;
+ /**
+ * Set heartbeat (in seconds)
+ *
+ * @param int heartBeatDelayInSeconds Defaults to 15. Cannot be lower than 1.
+ */
+ this.enableHeartBeatTimer = function (heartBeatDelayInSeconds) {
+ heartBeatDelayInSeconds = Math.max(heartBeatDelayInSeconds, 1);
+ configHeartBeatDelay = (heartBeatDelayInSeconds || 15) * 1000;
- // if a tracking request has already been sent, start the heart beat timeout
- if (lastTrackerRequestTime !== null) {
- setUpHeartBeat();
- }
- },
+ // if a tracking request has already been sent, start the heart beat timeout
+ if (lastTrackerRequestTime !== null) {
+ setUpHeartBeat();
+ }
+ };
/*<DEBUG>*/
- /**
- * Clear heartbeat.
- */
- disableHeartBeatTimer: function () {
- heartBeatDown();
- configHeartBeatDelay = null;
+ /**
+ * Clear heartbeat.
+ */
+ this.disableHeartBeatTimer = function () {
+ heartBeatDown();
+ configHeartBeatDelay = null;
- window.removeEventListener('focus', heartBeatOnFocus);
- window.removeEventListener('blur', heartBeatOnBlur);
- },
+ window.removeEventListener('focus', heartBeatOnFocus);
+ window.removeEventListener('blur', heartBeatOnBlur);
+ };
/*</DEBUG>*/
- /**
- * Frame buster
- */
- killFrame: function () {
- if (windowAlias.location !== windowAlias.top.location) {
- windowAlias.top.location = windowAlias.location;
- }
- },
+ /**
+ * Frame buster
+ */
+ this.killFrame = function () {
+ if (windowAlias.location !== windowAlias.top.location) {
+ windowAlias.top.location = windowAlias.location;
+ }
+ };
- /**
- * Redirect if browsing offline (aka file: buster)
- *
- * @param string url Redirect to this URL
- */
- redirectFile: function (url) {
- if (windowAlias.location.protocol === 'file:') {
- windowAlias.location = url;
- }
- },
+ /**
+ * Redirect if browsing offline (aka file: buster)
+ *
+ * @param string url Redirect to this URL
+ */
+ this.redirectFile = function (url) {
+ if (windowAlias.location.protocol === 'file:') {
+ windowAlias.location = url;
+ }
+ };
- /**
- * Count sites in pre-rendered state
- *
- * @param bool enable If true, track when in pre-rendered state
- */
- setCountPreRendered: function (enable) {
- configCountPreRendered = enable;
- },
+ /**
+ * Count sites in pre-rendered state
+ *
+ * @param bool enable If true, track when in pre-rendered state
+ */
+ this.setCountPreRendered = function (enable) {
+ configCountPreRendered = enable;
+ };
- /**
- * Trigger a goal
- *
- * @param int|string idGoal
- * @param int|float customRevenue
- * @param mixed customData
- */
- trackGoal: function (idGoal, customRevenue, customData) {
+ /**
+ * Trigger a goal
+ *
+ * @param int|string idGoal
+ * @param int|float customRevenue
+ * @param mixed customData
+ */
+ this.trackGoal = function (idGoal, customRevenue, customData) {
+ trackCallback(function () {
+ logGoal(idGoal, customRevenue, customData);
+ });
+ };
+
+ /**
+ * Manually log a click from your own code
+ *
+ * @param string sourceUrl
+ * @param string linkType
+ * @param mixed customData
+ * @param function callback
+ */
+ this.trackLink = function (sourceUrl, linkType, customData, callback) {
+ trackCallback(function () {
+ logLink(sourceUrl, linkType, customData, callback);
+ });
+ };
+
+ /**
+ * Log visit to this page
+ *
+ * @param string customTitle
+ * @param mixed customData
+ * @param function callback
+ */
+ this.trackPageView = function (customTitle, customData, callback) {
+ trackedContentImpressions = [];
+
+ if (isOverlaySession(configTrackerSiteId)) {
trackCallback(function () {
- logGoal(idGoal, customRevenue, customData);
+ injectOverlayScripts(configTrackerUrl, configApiUrl, configTrackerSiteId);
});
- },
-
- /**
- * Manually log a click from your own code
- *
- * @param string sourceUrl
- * @param string linkType
- * @param mixed customData
- * @param function callback
- */
- trackLink: function (sourceUrl, linkType, customData, callback) {
+ } else {
trackCallback(function () {
- logLink(sourceUrl, linkType, customData, callback);
+ logPageView(customTitle, customData, callback);
});
- },
-
- /**
- * Log visit to this page
- *
- * @param string customTitle
- * @param mixed customData
- * @param function callback
- */
- trackPageView: function (customTitle, customData, callback) {
- trackedContentImpressions = [];
-
- if (isOverlaySession(configTrackerSiteId)) {
- trackCallback(function () {
- injectOverlayScripts(configTrackerUrl, configApiUrl, configTrackerSiteId);
- });
- } else {
- trackCallback(function () {
- logPageView(customTitle, customData, callback);
- });
- }
- },
+ }
+ };
- /**
- * Scans the entire DOM for all content blocks and tracks all impressions once the DOM ready event has
- * been triggered.
- *
- * If you only want to track visible content impressions have a look at `trackVisibleContentImpressions()`.
- * We do not track an impression of the same content block twice if you call this method multiple times
- * unless `trackPageView()` is called meanwhile. This is useful for single page applications.
- */
- trackAllContentImpressions: function () {
- if (isOverlaySession(configTrackerSiteId)) {
- return;
- }
+ /**
+ * Scans the entire DOM for all content blocks and tracks all impressions once the DOM ready event has
+ * been triggered.
+ *
+ * If you only want to track visible content impressions have a look at `trackVisibleContentImpressions()`.
+ * We do not track an impression of the same content block twice if you call this method multiple times
+ * unless `trackPageView()` is called meanwhile. This is useful for single page applications.
+ */
+ this.trackAllContentImpressions = function () {
+ if (isOverlaySession(configTrackerSiteId)) {
+ return;
+ }
- trackCallback(function () {
- trackCallbackOnReady(function () {
- // we have to wait till DOM ready
- var contentNodes = content.findContentNodes();
- var requests = getContentImpressionsRequestsFromNodes(contentNodes);
+ trackCallback(function () {
+ trackCallbackOnReady(function () {
+ // we have to wait till DOM ready
+ var contentNodes = content.findContentNodes();
+ var requests = getContentImpressionsRequestsFromNodes(contentNodes);
- sendBulkRequest(requests, configTrackerPause);
- });
+ sendBulkRequest(requests, configTrackerPause);
});
- },
+ });
+ };
- /**
- * Scans the entire DOM for all content blocks as soon as the page is loaded. It tracks an impression
- * only if a content block is actually visible. Meaning it is not hidden and the content is or was at
- * some point in the viewport.
- *
- * If you want to track all content blocks have a look at `trackAllContentImpressions()`.
- * We do not track an impression of the same content block twice if you call this method multiple times
- * unless `trackPageView()` is called meanwhile. This is useful for single page applications.
- *
- * Once you have called this method you can no longer change `checkOnScroll` or `timeIntervalInMs`.
- *
- * If you do want to only track visible content blocks but not want us to perform any automatic checks
- * as they can slow down your frames per second you can call `trackVisibleContentImpressions()` or
- * `trackContentImpressionsWithinNode()` manually at any time to rescan the entire DOM for newly
- * visible content blocks.
- * o Call `trackVisibleContentImpressions(false, 0)` to initially track only visible content impressions
- * o Call `trackVisibleContentImpressions()` at any time again to rescan the entire DOM for newly visible content blocks or
- * o Call `trackContentImpressionsWithinNode(node)` at any time to rescan only a part of the DOM for newly visible content blocks
- *
- * @param boolean [checkOnScroll=true] Optional, you can disable rescanning the entire DOM automatically
- * after each scroll event by passing the value `false`. If enabled,
- * we check whether a previously hidden content blocks became visible
- * after a scroll and if so track the impression.
- * Note: If a content block is placed within a scrollable element
- * (`overflow: scroll`), we can currently not detect when this block
- * becomes visible.
- * @param integer [timeIntervalInMs=750] Optional, you can define an interval to rescan the entire DOM
- * for new impressions every X milliseconds by passing
- * for instance `timeIntervalInMs=500` (rescan DOM every 500ms).
- * Rescanning the entire DOM and detecting the visible state of content
- * blocks can take a while depending on the browser and amount of content.
- * In case your frames per second goes down you might want to increase
- * this value or disable it by passing the value `0`.
- */
- trackVisibleContentImpressions: function (checkOnSroll, timeIntervalInMs) {
- if (isOverlaySession(configTrackerSiteId)) {
- return;
- }
+ /**
+ * Scans the entire DOM for all content blocks as soon as the page is loaded. It tracks an impression
+ * only if a content block is actually visible. Meaning it is not hidden and the content is or was at
+ * some point in the viewport.
+ *
+ * If you want to track all content blocks have a look at `trackAllContentImpressions()`.
+ * We do not track an impression of the same content block twice if you call this method multiple times
+ * unless `trackPageView()` is called meanwhile. This is useful for single page applications.
+ *
+ * Once you have called this method you can no longer change `checkOnScroll` or `timeIntervalInMs`.
+ *
+ * If you do want to only track visible content blocks but not want us to perform any automatic checks
+ * as they can slow down your frames per second you can call `trackVisibleContentImpressions()` or
+ * `trackContentImpressionsWithinNode()` manually at any time to rescan the entire DOM for newly
+ * visible content blocks.
+ * o Call `trackVisibleContentImpressions(false, 0)` to initially track only visible content impressions
+ * o Call `trackVisibleContentImpressions()` at any time again to rescan the entire DOM for newly visible content blocks or
+ * o Call `trackContentImpressionsWithinNode(node)` at any time to rescan only a part of the DOM for newly visible content blocks
+ *
+ * @param boolean [checkOnScroll=true] Optional, you can disable rescanning the entire DOM automatically
+ * after each scroll event by passing the value `false`. If enabled,
+ * we check whether a previously hidden content blocks became visible
+ * after a scroll and if so track the impression.
+ * Note: If a content block is placed within a scrollable element
+ * (`overflow: scroll`), we can currently not detect when this block
+ * becomes visible.
+ * @param integer [timeIntervalInMs=750] Optional, you can define an interval to rescan the entire DOM
+ * for new impressions every X milliseconds by passing
+ * for instance `timeIntervalInMs=500` (rescan DOM every 500ms).
+ * Rescanning the entire DOM and detecting the visible state of content
+ * blocks can take a while depending on the browser and amount of content.
+ * In case your frames per second goes down you might want to increase
+ * this value or disable it by passing the value `0`.
+ */
+ this.trackVisibleContentImpressions = function (checkOnSroll, timeIntervalInMs) {
+ if (isOverlaySession(configTrackerSiteId)) {
+ return;
+ }
- if (!isDefined(checkOnSroll)) {
- checkOnSroll = true;
- }
+ if (!isDefined(checkOnSroll)) {
+ checkOnSroll = true;
+ }
- if (!isDefined(timeIntervalInMs)) {
- timeIntervalInMs = 750;
- }
+ if (!isDefined(timeIntervalInMs)) {
+ timeIntervalInMs = 750;
+ }
- enableTrackOnlyVisibleContent(checkOnSroll, timeIntervalInMs, this);
+ enableTrackOnlyVisibleContent(checkOnSroll, timeIntervalInMs, this);
- trackCallback(function () {
- trackCallbackOnLoad(function () {
- // we have to wait till CSS parsed and applied
- var contentNodes = content.findContentNodes();
- var requests = getCurrentlyVisibleContentImpressionsRequestsIfNotTrackedYet(contentNodes);
+ trackCallback(function () {
+ trackCallbackOnLoad(function () {
+ // we have to wait till CSS parsed and applied
+ var contentNodes = content.findContentNodes();
+ var requests = getCurrentlyVisibleContentImpressionsRequestsIfNotTrackedYet(contentNodes);
- sendBulkRequest(requests, configTrackerPause);
- });
+ sendBulkRequest(requests, configTrackerPause);
});
- },
-
- /**
- * Tracks a content impression using the specified values. You should not call this method too often
- * as each call causes an XHR tracking request and can slow down your site or your server.
- *
- * @param string contentName For instance "Ad Sale".
- * @param string [contentPiece='Unknown'] For instance a path to an image or the text of a text ad.
- * @param string [contentTarget] For instance the URL of a landing page.
- */
- trackContentImpression: function (contentName, contentPiece, contentTarget) {
- if (isOverlaySession(configTrackerSiteId)) {
- return;
- }
+ });
+ };
- if (!contentName) {
- return;
- }
+ /**
+ * Tracks a content impression using the specified values. You should not call this method too often
+ * as each call causes an XHR tracking request and can slow down your site or your server.
+ *
+ * @param string contentName For instance "Ad Sale".
+ * @param string [contentPiece='Unknown'] For instance a path to an image or the text of a text ad.
+ * @param string [contentTarget] For instance the URL of a landing page.
+ */
+ this.trackContentImpression = function (contentName, contentPiece, contentTarget) {
+ if (isOverlaySession(configTrackerSiteId)) {
+ return;
+ }
- contentPiece = contentPiece || 'Unknown';
+ if (!contentName) {
+ return;
+ }
- trackCallback(function () {
- var request = buildContentImpressionRequest(contentName, contentPiece, contentTarget);
- sendRequest(request, configTrackerPause);
- });
- },
+ contentPiece = contentPiece || 'Unknown';
- /**
- * Scans the given DOM node and its children for content blocks and tracks an impression for them if
- * no impression was already tracked for it. If you have called `trackVisibleContentImpressions()`
- * upfront only visible content blocks will be tracked. You can use this method if you, for instance,
- * dynamically add an element using JavaScript to your DOM after we have tracked the initial impressions.
- *
- * @param Element domNode
- */
- trackContentImpressionsWithinNode: function (domNode) {
- if (isOverlaySession(configTrackerSiteId) || !domNode) {
- return;
- }
+ trackCallback(function () {
+ var request = buildContentImpressionRequest(contentName, contentPiece, contentTarget);
+ sendRequest(request, configTrackerPause);
+ });
+ };
- trackCallback(function () {
- if (isTrackOnlyVisibleContentEnabled) {
- trackCallbackOnLoad(function () {
- // we have to wait till CSS parsed and applied
- var contentNodes = content.findContentNodesWithinNode(domNode);
-
- var requests = getCurrentlyVisibleContentImpressionsRequestsIfNotTrackedYet(contentNodes);
- sendBulkRequest(requests, configTrackerPause);
- });
- } else {
- trackCallbackOnReady(function () {
- // we have to wait till DOM ready
- var contentNodes = content.findContentNodesWithinNode(domNode);
+ /**
+ * Scans the given DOM node and its children for content blocks and tracks an impression for them if
+ * no impression was already tracked for it. If you have called `trackVisibleContentImpressions()`
+ * upfront only visible content blocks will be tracked. You can use this method if you, for instance,
+ * dynamically add an element using JavaScript to your DOM after we have tracked the initial impressions.
+ *
+ * @param Element domNode
+ */
+ this.trackContentImpressionsWithinNode = function (domNode) {
+ if (isOverlaySession(configTrackerSiteId) || !domNode) {
+ return;
+ }
- var requests = getContentImpressionsRequestsFromNodes(contentNodes);
- sendBulkRequest(requests, configTrackerPause);
- });
- }
- });
- },
+ trackCallback(function () {
+ if (isTrackOnlyVisibleContentEnabled) {
+ trackCallbackOnLoad(function () {
+ // we have to wait till CSS parsed and applied
+ var contentNodes = content.findContentNodesWithinNode(domNode);
- /**
- * Tracks a content interaction using the specified values. You should use this method only in conjunction
- * with `trackContentImpression()`. The specified `contentName` and `contentPiece` has to be exactly the
- * same as the ones that were used in `trackContentImpression()`. Otherwise the interaction will not count.
- *
- * @param string contentInteraction The type of interaction that happened. For instance 'click' or 'submit'.
- * @param string contentName The name of the content. For instance "Ad Sale".
- * @param string [contentPiece='Unknown'] The actual content. For instance a path to an image or the text of a text ad.
- * @param string [contentTarget] For instance the URL of a landing page.
- */
- trackContentInteraction: function (contentInteraction, contentName, contentPiece, contentTarget) {
- if (isOverlaySession(configTrackerSiteId)) {
- return;
- }
+ var requests = getCurrentlyVisibleContentImpressionsRequestsIfNotTrackedYet(contentNodes);
+ sendBulkRequest(requests, configTrackerPause);
+ });
+ } else {
+ trackCallbackOnReady(function () {
+ // we have to wait till DOM ready
+ var contentNodes = content.findContentNodesWithinNode(domNode);
- if (!contentInteraction || !contentName) {
- return;
+ var requests = getContentImpressionsRequestsFromNodes(contentNodes);
+ sendBulkRequest(requests, configTrackerPause);
+ });
}
+ });
+ };
- contentPiece = contentPiece || 'Unknown';
+ /**
+ * Tracks a content interaction using the specified values. You should use this method only in conjunction
+ * with `trackContentImpression()`. The specified `contentName` and `contentPiece` has to be exactly the
+ * same as the ones that were used in `trackContentImpression()`. Otherwise the interaction will not count.
+ *
+ * @param string contentInteraction The type of interaction that happened. For instance 'click' or 'submit'.
+ * @param string contentName The name of the content. For instance "Ad Sale".
+ * @param string [contentPiece='Unknown'] The actual content. For instance a path to an image or the text of a text ad.
+ * @param string [contentTarget] For instance the URL of a landing page.
+ */
+ this.trackContentInteraction = function (contentInteraction, contentName, contentPiece, contentTarget) {
+ if (isOverlaySession(configTrackerSiteId)) {
+ return;
+ }
- trackCallback(function () {
- var request = buildContentInteractionRequest(contentInteraction, contentName, contentPiece, contentTarget);
- sendRequest(request, configTrackerPause);
- });
- },
+ if (!contentInteraction || !contentName) {
+ return;
+ }
- /**
- * Tracks an interaction with the given DOM node / content block.
- *
- * By default we track interactions on click but sometimes you might want to track interactions yourself.
- * For instance you might want to track an interaction manually on a double click or a form submit.
- * Make sure to disable the automatic interaction tracking in this case by specifying either the CSS
- * class `piwikContentIgnoreInteraction` or the attribute `data-content-ignoreinteraction`.
- *
- * @param Element domNode This element itself or any of its parent elements has to be a content block
- * element. Meaning one of those has to have a `piwikTrackContent` CSS class or
- * a `data-track-content` attribute.
- * @param string [contentInteraction='Unknown] The name of the interaction that happened. For instance
- * 'click', 'formSubmit', 'DblClick', ...
- */
- trackContentInteractionNode: function (domNode, contentInteraction) {
- if (isOverlaySession(configTrackerSiteId) || !domNode) {
- return;
- }
+ contentPiece = contentPiece || 'Unknown';
- trackCallback(function () {
- var request = buildContentInteractionRequestNode(domNode, contentInteraction);
- sendRequest(request, configTrackerPause);
- });
- },
+ trackCallback(function () {
+ var request = buildContentInteractionRequest(contentInteraction, contentName, contentPiece, contentTarget);
+ sendRequest(request, configTrackerPause);
+ });
+ };
- /**
- * Useful to debug content tracking. This method will log all detected content blocks to console
- * (if the browser supports the console). It will list the detected name, piece, and target of each
- * content block.
- */
- logAllContentBlocksOnPage: function () {
- var contentNodes = content.findContentNodes();
- var contents = content.collectContent(contentNodes);
+ /**
+ * Tracks an interaction with the given DOM node / content block.
+ *
+ * By default we track interactions on click but sometimes you might want to track interactions yourself.
+ * For instance you might want to track an interaction manually on a double click or a form submit.
+ * Make sure to disable the automatic interaction tracking in this case by specifying either the CSS
+ * class `piwikContentIgnoreInteraction` or the attribute `data-content-ignoreinteraction`.
+ *
+ * @param Element domNode This element itself or any of its parent elements has to be a content block
+ * element. Meaning one of those has to have a `piwikTrackContent` CSS class or
+ * a `data-track-content` attribute.
+ * @param string [contentInteraction='Unknown] The name of the interaction that happened. For instance
+ * 'click', 'formSubmit', 'DblClick', ...
+ */
+ this.trackContentInteractionNode = function (domNode, contentInteraction) {
+ if (isOverlaySession(configTrackerSiteId) || !domNode) {
+ return;
+ }
- if (console !== undefined && console && console.log) {
- console.log(contents);
- }
- },
+ trackCallback(function () {
+ var request = buildContentInteractionRequestNode(domNode, contentInteraction);
+ sendRequest(request, configTrackerPause);
+ });
+ };
- /**
- * Records an event
- *
- * @param string category The Event Category (Videos, Music, Games...)
- * @param string action The Event's Action (Play, Pause, Duration, Add Playlist, Downloaded, Clicked...)
- * @param string name (optional) The Event's object Name (a particular Movie name, or Song name, or File name...)
- * @param float value (optional) The Event's value
- * @param mixed customData
- */
- trackEvent: function (category, action, name, value, customData) {
- trackCallback(function () {
- logEvent(category, action, name, value, customData);
- });
- },
+ /**
+ * Useful to debug content tracking. This method will log all detected content blocks to console
+ * (if the browser supports the console). It will list the detected name, piece, and target of each
+ * content block.
+ */
+ this.logAllContentBlocksOnPage = function () {
+ var contentNodes = content.findContentNodes();
+ var contents = content.collectContent(contentNodes);
- /**
- * Log special pageview: Internal search
- *
- * @param string keyword
- * @param string category
- * @param int resultsCount
- * @param mixed customData
- */
- trackSiteSearch: function (keyword, category, resultsCount, customData) {
- trackCallback(function () {
- logSiteSearch(keyword, category, resultsCount, customData);
- });
- },
+ if (console !== undefined && console && console.log) {
+ console.log(contents);
+ }
+ };
- /**
- * Used to record that the current page view is an item (product) page view, or a Ecommerce Category page view.
- * This must be called before trackPageView() on the product/category page.
- * It will set 3 custom variables of scope "page" with the SKU, Name and Category for this page view.
- * Note: Custom Variables of scope "page" slots 3, 4 and 5 will be used.
- *
- * On a category page, you can set the parameter category, and set the other parameters to empty string or false
- *
- * Tracking Product/Category page views will allow Piwik to report on Product & Categories
- * conversion rates (Conversion rate = Ecommerce orders containing this product or category / Visits to the product or category)
- *
- * @param string sku Item's SKU code being viewed
- * @param string name Item's Name being viewed
- * @param string category Category page being viewed. On an Item's page, this is the item's category
- * @param float price Item's display price, not use in standard Piwik reports, but output in API product reports.
- */
- setEcommerceView: function (sku, name, category, price) {
- if (!isDefined(category) || !category.length) {
- category = "";
- } else if (category instanceof Array) {
- category = JSON2.stringify(category);
- }
+ /**
+ * Records an event
+ *
+ * @param string category The Event Category (Videos, Music, Games...)
+ * @param string action The Event's Action (Play, Pause, Duration, Add Playlist, Downloaded, Clicked...)
+ * @param string name (optional) The Event's object Name (a particular Movie name, or Song name, or File name...)
+ * @param float value (optional) The Event's value
+ * @param mixed customData
+ */
+ this.trackEvent = function (category, action, name, value, customData) {
+ trackCallback(function () {
+ logEvent(category, action, name, value, customData);
+ });
+ };
- customVariablesPage[5] = ['_pkc', category];
+ /**
+ * Log special pageview: Internal search
+ *
+ * @param string keyword
+ * @param string category
+ * @param int resultsCount
+ * @param mixed customData
+ */
+ this.trackSiteSearch = function (keyword, category, resultsCount, customData) {
+ trackCallback(function () {
+ logSiteSearch(keyword, category, resultsCount, customData);
+ });
+ };
- if (isDefined(price) && String(price).length) {
- customVariablesPage[2] = ['_pkp', price];
- }
+ /**
+ * Used to record that the current page view is an item (product) page view, or a Ecommerce Category page view.
+ * This must be called before trackPageView() on the product/category page.
+ * It will set 3 custom variables of scope "page" with the SKU, Name and Category for this page view.
+ * Note: Custom Variables of scope "page" slots 3, 4 and 5 will be used.
+ *
+ * On a category page, you can set the parameter category, and set the other parameters to empty string or false
+ *
+ * Tracking Product/Category page views will allow Piwik to report on Product & Categories
+ * conversion rates (Conversion rate = Ecommerce orders containing this product or category / Visits to the product or category)
+ *
+ * @param string sku Item's SKU code being viewed
+ * @param string name Item's Name being viewed
+ * @param string category Category page being viewed. On an Item's page, this is the item's category
+ * @param float price Item's display price, not use in standard Piwik reports, but output in API product reports.
+ */
+ this.setEcommerceView = function (sku, name, category, price) {
+ if (!isDefined(category) || !category.length) {
+ category = "";
+ } else if (category instanceof Array) {
+ category = JSON2.stringify(category);
+ }
- // On a category page, do not track Product name not defined
- if ((!isDefined(sku) || !sku.length)
- && (!isDefined(name) || !name.length)) {
- return;
- }
+ customVariablesPage[5] = ['_pkc', category];
- if (isDefined(sku) && sku.length) {
- customVariablesPage[3] = ['_pks', sku];
- }
+ if (isDefined(price) && String(price).length) {
+ customVariablesPage[2] = ['_pkp', price];
+ }
- if (!isDefined(name) || !name.length) {
- name = "";
- }
+ // On a category page, do not track Product name not defined
+ if ((!isDefined(sku) || !sku.length)
+ && (!isDefined(name) || !name.length)) {
+ return;
+ }
- customVariablesPage[4] = ['_pkn', name];
- },
+ if (isDefined(sku) && sku.length) {
+ customVariablesPage[3] = ['_pks', sku];
+ }
- /**
- * Adds an item (product) that is in the current Cart or in the Ecommerce order.
- * This function is called for every item (product) in the Cart or the Order.
- * The only required parameter is sku.
- * The items are deleted from this JavaScript object when the Ecommerce order is tracked via the method trackEcommerceOrder.
- *
- * @param string sku (required) Item's SKU Code. This is the unique identifier for the product.
- * @param string name (optional) Item's name
- * @param string name (optional) Item's category, or array of up to 5 categories
- * @param float price (optional) Item's price. If not specified, will default to 0
- * @param float quantity (optional) Item's quantity. If not specified, will default to 1
- */
- addEcommerceItem: function (sku, name, category, price, quantity) {
- if (sku.length) {
- ecommerceItems[sku] = [ sku, name, category, price, quantity ];
- }
- },
+ if (!isDefined(name) || !name.length) {
+ name = "";
+ }
- /**
- * Tracks an Ecommerce order.
- * If the Ecommerce order contains items (products), you must call first the addEcommerceItem() for each item in the order.
- * All revenues (grandTotal, subTotal, tax, shipping, discount) will be individually summed and reported in Piwik reports.
- * Parameters orderId and grandTotal are required. For others, you can set to false if you don't need to specify them.
- * After calling this method, items added to the cart will be removed from this JavaScript object.
- *
- * @param string|int orderId (required) Unique Order ID.
- * This will be used to count this order only once in the event the order page is reloaded several times.
- * orderId must be unique for each transaction, even on different days, or the transaction will not be recorded by Piwik.
- * @param float grandTotal (required) Grand Total revenue of the transaction (including tax, shipping, etc.)
- * @param float subTotal (optional) Sub total amount, typically the sum of items prices for all items in this order (before Tax and Shipping costs are applied)
- * @param float tax (optional) Tax amount for this order
- * @param float shipping (optional) Shipping amount for this order
- * @param float discount (optional) Discounted amount in this order
- */
- trackEcommerceOrder: function (orderId, grandTotal, subTotal, tax, shipping, discount) {
- logEcommerceOrder(orderId, grandTotal, subTotal, tax, shipping, discount);
- },
+ customVariablesPage[4] = ['_pkn', name];
+ };
- /**
- * Tracks a Cart Update (add item, remove item, update item).
- * On every Cart update, you must call addEcommerceItem() for each item (product) in the cart, including the items that haven't been updated since the last cart update.
- * Then you can call this function with the Cart grandTotal (typically the sum of all items' prices)
- * Calling this method does not remove from this JavaScript object the items that were added to the cart via addEcommerceItem
- *
- * @param float grandTotal (required) Items (products) amount in the Cart
- */
- trackEcommerceCartUpdate: function (grandTotal) {
- logEcommerceCartUpdate(grandTotal);
+ /**
+ * Adds an item (product) that is in the current Cart or in the Ecommerce order.
+ * This function is called for every item (product) in the Cart or the Order.
+ * The only required parameter is sku.
+ * The items are deleted from this JavaScript object when the Ecommerce order is tracked via the method trackEcommerceOrder.
+ *
+ * @param string sku (required) Item's SKU Code. This is the unique identifier for the product.
+ * @param string name (optional) Item's name
+ * @param string name (optional) Item's category, or array of up to 5 categories
+ * @param float price (optional) Item's price. If not specified, will default to 0
+ * @param float quantity (optional) Item's quantity. If not specified, will default to 1
+ */
+ this.addEcommerceItem = function (sku, name, category, price, quantity) {
+ if (sku.length) {
+ ecommerceItems[sku] = [ sku, name, category, price, quantity ];
}
+ };
+ /**
+ * Tracks an Ecommerce order.
+ * If the Ecommerce order contains items (products), you must call first the addEcommerceItem() for each item in the order.
+ * All revenues (grandTotal, subTotal, tax, shipping, discount) will be individually summed and reported in Piwik reports.
+ * Parameters orderId and grandTotal are required. For others, you can set to false if you don't need to specify them.
+ * After calling this method, items added to the cart will be removed from this JavaScript object.
+ *
+ * @param string|int orderId (required) Unique Order ID.
+ * This will be used to count this order only once in the event the order page is reloaded several times.
+ * orderId must be unique for each transaction, even on different days, or the transaction will not be recorded by Piwik.
+ * @param float grandTotal (required) Grand Total revenue of the transaction (including tax, shipping, etc.)
+ * @param float subTotal (optional) Sub total amount, typically the sum of items prices for all items in this order (before Tax and Shipping costs are applied)
+ * @param float tax (optional) Tax amount for this order
+ * @param float shipping (optional) Shipping amount for this order
+ * @param float discount (optional) Discounted amount in this order
+ */
+ this.trackEcommerceOrder = function (orderId, grandTotal, subTotal, tax, shipping, discount) {
+ logEcommerceOrder(orderId, grandTotal, subTotal, tax, shipping, discount);
};
- }
- /************************************************************
- * Proxy object
- * - this allows the caller to continue push()'ing to _paq
- * after the Tracker has been initialized and loaded
- ************************************************************/
+ /**
+ * Tracks a Cart Update (add item, remove item, update item).
+ * On every Cart update, you must call addEcommerceItem() for each item (product) in the cart, including the items that haven't been updated since the last cart update.
+ * Then you can call this function with the Cart grandTotal (typically the sum of all items' prices)
+ * Calling this method does not remove from this JavaScript object the items that were added to the cart via addEcommerceItem
+ *
+ * @param float grandTotal (required) Items (products) amount in the Cart
+ */
+ this.trackEcommerceCartUpdate = function (grandTotal) {
+ logEcommerceCartUpdate(grandTotal);
+ };
+
+ /**
+ * Sends a tracking request with custom request parameters.
+ * Piwik will prepend the hostname and path to Piwik, as well as all other needed tracking request
+ * parameters prior to sending the request. Useful eg if you track custom dimensions via a plugin.
+ *
+ * @param request eg. "param=value&param2=value2"
+ * @param customData
+ * @param callback
+ */
+ this.trackRequest = function (request, customData, callback) {
+ trackCallback(function () {
+ var fullRequest = getRequest(request, customData);
+ sendRequest(fullRequest, configTrackerPause, callback);
+ });
+ };
+
+ Piwik.trigger('TrackerSetup', [this]);
+ }
function TrackerProxy() {
return {
@@ -6503,31 +6539,97 @@ if (typeof window.Piwik !== 'object') {
* Constructor
************************************************************/
- // initialize the Piwik singleton
- addEventListener(windowAlias, 'beforeunload', beforeUnloadHandler, false);
-
- Date.prototype.getTimeAlias = Date.prototype.getTime;
+ var applyFirst = ['addTracker', 'disableCookies', 'setTrackerUrl', 'setAPIUrl', 'setCookiePath', 'setCookieDomain', 'setDomains', 'setUserId', 'setSiteId', 'enableLinkTracking'];
- asyncTrackers.push(new Tracker());
+ function createFirstTracker(piwikUrl, siteId)
+ {
+ var tracker = new Tracker(piwikUrl, siteId);
+ asyncTrackers.push(tracker);
- var applyFirst = ['addTracker', 'disableCookies', 'setTrackerUrl', 'setAPIUrl', 'setCookiePath', 'setCookieDomain', 'setDomains', 'setUserId', 'setSiteId', 'enableLinkTracking'];
- _paq = applyMethodsInOrder(_paq, applyFirst);
+ _paq = applyMethodsInOrder(_paq, applyFirst);
- // apply the queue of actions
- for (iterator = 0; iterator < _paq.length; iterator++) {
- if (_paq[iterator]) {
- apply(_paq[iterator]);
+ // apply the queue of actions
+ for (iterator = 0; iterator < _paq.length; iterator++) {
+ if (_paq[iterator]) {
+ apply(_paq[iterator]);
+ }
}
+
+ // replace initialization array with proxy object
+ _paq = new TrackerProxy();
+
+ return tracker;
}
- // replace initialization array with proxy object
- _paq = new TrackerProxy();
+ /************************************************************
+ * Proxy object
+ * - this allows the caller to continue push()'ing to _paq
+ * after the Tracker has been initialized and loaded
+ ************************************************************/
+
+ // initialize the Piwik singleton
+ addEventListener(windowAlias, 'beforeunload', beforeUnloadHandler, false);
+
+ Date.prototype.getTimeAlias = Date.prototype.getTime;
/************************************************************
* Public data and methods
************************************************************/
Piwik = {
+ initialized: false,
+
+ /**
+ * Listen to an event and invoke the handler when a the event is triggered.
+ *
+ * @param string event
+ * @param function handler
+ */
+ on: function (event, handler) {
+ if (!eventHandlers[event]) {
+ eventHandlers[event] = [];
+ }
+
+ eventHandlers[event].push(handler);
+ },
+
+ /**
+ * Remove a handler to no longer listen to the event. Must pass the same handler that was used when
+ * attaching the event via ".on".
+ * @param string event
+ * @param function handler
+ */
+ off: function (event, handler) {
+ if (!eventHandlers[event]) {
+ return;
+ }
+
+ var i = 0;
+ for (i; i < eventHandlers[event].length; i++) {
+ if (eventHandlers[event][i] === handler) {
+ delete eventHandlers[event][i];
+ }
+ }
+ },
+
+ /**
+ * Triggers the given event and passes the parameters to all handlers.
+ *
+ * @param string event
+ * @param Array extraParameters
+ * @param Object context If given the handler will be executed in this context
+ */
+ trigger: function (event, extraParameters, context) {
+ if (!eventHandlers[event]) {
+ return;
+ }
+
+ var i = 0;
+ for (i; i < eventHandlers[event].length; i++) {
+ eventHandlers[event][i].apply(context || windowAlias, extraParameters);
+ }
+ },
+
/**
* Add plugin
*
@@ -6557,6 +6659,31 @@ if (typeof window.Piwik !== 'object') {
},
/**
+ * Get all created async trackers
+ *
+ * @return Tracker[]
+ */
+ getAsyncTrackers: function () {
+ return asyncTrackers;
+ },
+
+ /**
+ * Adds a new tracker. All sent requests will be also sent to the given siteId and piwikUrl.
+ * If piwikUrl is not set, current url will be used.
+ *
+ * @param null|string piwikUrl If null, will reuse the same tracker URL of the current tracker instance
+ * @param int|string siteId
+ * @return Tracker
+ */
+ addTracker: function (piwikUrl, siteId) {
+ if (!asyncTrackers.length) {
+ createFirstTracker(piwikUrl, siteId);
+ } else {
+ asyncTrackers[0].addTracker(piwikUrl, siteId);
+ }
+ },
+
+ /**
* Get internal asynchronous tracker object.
*
* If no parameters are given, it returns the internal asynchronous tracker object. If a piwikUrl and idSite
@@ -6609,6 +6736,28 @@ if (typeof window.Piwik !== 'object') {
}());
}
+/*!! pluginTrackerHook */
+
+(function () {
+ 'use strict';
+
+ if (window
+ && 'object' === typeof window.piwikPluginAsyncInit
+ && window.piwikPluginAsyncInit.length) {
+ var i = 0;
+ for (i; i < window.piwikPluginAsyncInit.length; i++) {
+ if (typeof window.piwikPluginAsyncInit[i] === 'function') {
+ window.piwikPluginAsyncInit[i]();
+ }
+ }
+ }
+
+ window.Piwik.addTracker();
+
+ window.Piwik.trigger('PiwikInitialized', []);
+ window.Piwik.initialized = true;
+}());
+
if (window && window.piwikAsyncInit) {
window.piwikAsyncInit();
}
diff --git a/js/piwik.min.js b/js/piwik.min.js
new file mode 100644
index 0000000000..002e4cb757
--- /dev/null
+++ b/js/piwik.min.js
@@ -0,0 +1,71 @@
+/*!!
+ * Piwik - free/libre analytics platform
+ *
+ * JavaScript tracking client
+ *
+ * @link http://piwik.org
+ * @source https://github.com/piwik/piwik/blob/master/js/piwik.js
+ * @license http://piwik.org/free-software/bsd/ BSD-3 Clause (also in js/LICENSE.txt)
+ * @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 */
+(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])
+}}ac=null;return r.call(this,ae)}}m=function(ae,ah){var af=0,ac,ad,ag;(ac=function(){this.valueOf=0}).prototype.valueOf=0;ad=new ac();for(ag in ad){if(r.call(ad,ag)){af++}}ac=ad=null;if(!af){ad=["valueOf","toString","toLocaleString","propertyIsEnumerable","isPrototypeOf","hasOwnProperty","constructor"];m=function(aj,an){var am=u.call(aj)==U,al,ak;var ai=!am&&typeof aj.constructor!="function"&&e[typeof aj.hasOwnProperty]&&aj.hasOwnProperty||r;for(al in aj){if(!(am&&al=="prototype")&&ai.call(aj,al)){an(al)}}for(ak=ad.length;al=ad[--ak];ai.call(aj,al)&&an(al)){}}}else{if(af==2){m=function(aj,am){var ai={},al=u.call(aj)==U,ak;for(ak in aj){if(!(al&&ak=="prototype")&&!r.call(ai,ak)&&(ai[ak]=1)&&r.call(aj,ak)){am(ak)}}}}else{m=function(aj,am){var al=u.call(aj)==U,ak,ai;for(ak in aj){if(!(al&&ak=="prototype")&&r.call(aj,ak)&&!(ai=ak==="constructor")){am(ak)}}if(ai||r.call(aj,(ak="constructor"))){am(ak)}}}}return m(ae,ah)};if(!o("json-stringify")){var q={92:"\\\\",34:'\\"',8:"\\b",12:"\\f",10:"\\n",13:"\\r",9:"\\t"};
+var I="000000";var t=function(ac,ad){return(I+(ad||0)).slice(-ac)};var z="\\u00";var C=function(ai){var ad='"',ag=0,ah=ai.length,ac=!F||ah>10;var af=ac&&(F?ai.split(""):ai);for(;ag<ah;ag++){var ae=ai.charCodeAt(ag);switch(ae){case 8:case 9:case 10:case 12:case 13:case 34:case 92:ad+=q[ae];break;default:if(ae<32){ad+=z+t(2,ae.toString(16));break}ad+=ac?af[ag]:ai.charAt(ag)}}return ad+'"'};var p=function(ai,aA,ag,al,ax,ac,aj){var at,ae,ap,az,ay,ak,aw,au,aq,an,ar,ad,ah,af,av,ao;try{at=aA[ai]}catch(am){}if(typeof at=="object"&&at){ae=u.call(at);if(ae==Q&&!r.call(at,"toJSON")){if(at>-1/0&&at<1/0){if(D){ay=s(at/86400000);for(ap=s(ay/365.2425)+1970-1;D(ap+1,0)<=ay;ap++){}for(az=s((ay-D(ap,0))/30.42);D(ap,az+1)<=ay;az++){}ay=1+ay-D(ap,az);ak=(at%86400000+86400000)%86400000;aw=s(ak/3600000)%24;au=s(ak/60000)%60;aq=s(ak/1000)%60;an=ak%1000}else{ap=at.getUTCFullYear();az=at.getUTCMonth();ay=at.getUTCDate();aw=at.getUTCHours();au=at.getUTCMinutes();aq=at.getUTCSeconds();an=at.getUTCMilliseconds()}at=(ap<=0||ap>=10000?(ap<0?"-":"+")+t(6,ap<0?-ap:ap):t(4,ap))+"-"+t(2,az+1)+"-"+t(2,ay)+"T"+t(2,aw)+":"+t(2,au)+":"+t(2,aq)+"."+t(3,an)+"Z"
+}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={},r={},y=document,f=navigator,P=screen,L=window,g=L.performance||L.mozPerformance||L.msPerformance||L.webkitPerformance,n=L.encodeURIComponent,K=L.decodeURIComponent,i=unescape,A=[],x,d;
+function k(ac){try{return K(ac)}catch(ad){return unescape(ac)}}function B(ad){var ac=typeof ad;return ac!=="undefined"}function t(ac){return typeof ac==="function"}function O(ac){return typeof ac==="object"}function q(ac){return typeof ac==="string"||ac instanceof String}function u(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 Y(ac){if(console!==undefined&&console&&console.error){console.error(ac)}}function V(){var ag,af,ai,ac;for(ag=0;ag<arguments.length;ag+=1){ac=arguments[ag];ai=ac.shift();for(af=0;af<A.length;af++){if(q(ai)){var ad=A[af];var ah;var ae=ai.indexOf("::")>0;if(ae){ah=ai.split("::");ad=ah[0];ai=ah[1];if("object"===typeof d[ad]&&"function"===typeof d[ad][ai]){d[ad][ai].apply(d[ad],ac)}return}var aj=ai.indexOf(".")>0;if(aj){ah=ai.split(".");ad=ad[ah[0]];ai=ah[1]}if(ad[ai]){ad[ai].apply(ad,ac)}else{var ak="The method '"+ai+'\' was not found in "_paq" variable. Please have a look at the Piwik tracker documentation: http://developer.piwik.org/api-reference/tracking-javascript';
+Y(ak);if(!aj){throw new TypeError(ak)}}if(ai==="addTracker"){break}if(ai==="setTrackerUrl"||ai==="setSiteId"){break}}else{ai.apply(A[af],ac)}}}}function aa(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 S(ad,ah){var ac="",af,ae,ag;for(af in a){if(Object.prototype.hasOwnProperty.call(a,af)){ae=a[af][ad];if(t(ae)){ag=ae(ah);if(ag){ac+=ag}}}}return ac}function W(){var ac;S("unload");if(l){do{ac=new Date()}while(ac.getTimeAlias()<l)}}function j(ae,ad){var ac=y.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}y.getElementsByTagName("head")[0].appendChild(ac)}function C(){var ac="";try{ac=L.top.document.referrer}catch(ae){if(L.parent){try{ac=L.parent.document.referrer}catch(ad){ac=""}}}if(ac===""){ac=y.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 N(ae,ad){var ac="[\\?&#]"+ad+"=([^&#]*)";var ag=new RegExp(ac);var af=ag.exec(ae);return af?K(af[1]):""}function w(ac){return unescape(n(ac))}function Z(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=w(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 R(ae,ac,ad){if(!ae){ae=""}if(!ac){ac=""}if(ae==="translate.googleusercontent.com"){if(ad===""){ad=ac
+}ac=N(ac,"u");ae=c(ac)}else{if(ae==="cc.bingj.com"||ae==="webcache.googleusercontent.com"||ae.slice(0,5)==="74.6."){ac=y.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 ab(ad){ad=ad&&ad.text?ad.text:ad;if(!q(ad)){var ac=y.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 M(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 X(ad,ac){ad=String(ad);return ad.lastIndexOf(ac,0)===0}function J(ad,ac){ad=String(ad);return ad.indexOf(ac,ad.length-ac.length)!==-1}function s(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(L.getComputedStyle){return y.defaultView.getComputedStyle(ag,null)[ah]}if(ag.currentStyle){return ag.currentStyle[ah]}}function af(ag){ag=ag.parentNode;while(ag){if(ag===y){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 U={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=U.findMultiple([ad,ac]);return ae},findContentNodesWithinNode:function(af){if(!af){return[]}var ad=U.findNodesHavingCssClass(af,this.CONTENT_CLASS);var ac=U.findNodesHavingAttribute(af,this.CONTENT_ATTR);if(ac&&ac.length){var ae;for(ae=0;ae<ac.length;ae++){ad.push(ac[ae])}}if(U.hasNodeAttribute(af,this.CONTENT_ATTR)){ad.push(af)}else{if(U.hasNodeCssClass(af,this.CONTENT_CLASS)){ad.push(af)}}ad=U.makeNodesUnique(ad);return ad},findParentContentNode:function(ad){if(!ad){return}var ae=ad;var ac=0;while(ae&&ae!==y&&ae.parentNode){if(U.hasNodeAttribute(ae,this.CONTENT_ATTR)){return ae}if(U.hasNodeCssClass(ae,this.CONTENT_CLASS)){return ae}ae=ae.parentNode;if(ac>1000){break}ac++}},findPieceNode:function(ad){var ac;ac=U.findFirstNodeHavingAttribute(ad,this.CONTENT_PIECE_ATTR);if(!ac){ac=U.findFirstNodeHavingClass(ad,this.CONTENT_PIECE_CLASS)}if(ac){return ac}return ad},findTargetNodeNoDefault:function(ac){if(!ac){return}var ad=U.findFirstNodeHavingAttributeWithValue(ac,this.CONTENT_TARGET_ATTR);
+if(ad){return ad}ad=U.findFirstNodeHavingAttribute(ac,this.CONTENT_TARGET_ATTR);if(ad){return ad}ad=U.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=U.findFirstNodeHavingAttributeWithValue(ad,this.CONTENT_NAME_ATTR);if(ag){return U.getAttributeValueFromNode(ag,this.CONTENT_NAME_ATTR)}var ac=this.findContentPiece(ad);if(ac){return this.removeDomainIfIsInLink(ac)}if(U.hasNodeAttributeWithValue(ad,"title")){return U.getAttributeValueFromNode(ad,"title")}var ae=this.findPieceNode(ad);if(U.hasNodeAttributeWithValue(ae,"title")){return U.getAttributeValueFromNode(ae,"title")}var af=this.findTargetNode(ad);if(U.hasNodeAttributeWithValue(af,"title")){return U.getAttributeValueFromNode(af,"title")}},findContentPiece:function(ad){if(!ad){return}var af=U.findFirstNodeHavingAttributeWithValue(ad,this.CONTENT_PIECE_ATTR);if(af){return U.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(U.hasNodeAttributeWithValue(af,this.CONTENT_TARGET_ATTR)){return U.getAttributeValueFromNode(af,this.CONTENT_TARGET_ATTR)}var ad;if(U.hasNodeAttributeWithValue(af,"href")){ad=U.getAttributeValueFromNode(af,"href");return this.toAbsoluteUrl(ad)}var ac=this.findPieceNode(ae);if(U.hasNodeAttributeWithValue(ac,"href")){ad=U.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)&&U.findFirstNodeHavingAttributeWithValue(ag,"src")){var af=U.findFirstNodeHavingAttributeWithValue(ag,"src");return U.getAttributeValueFromNode(af,"src")}if(ac==="object"&&U.hasNodeAttributeWithValue(ag,"data")){return U.getAttributeValueFromNode(ag,"data")}if(ac==="object"){var ah=U.findNodesByTagName(ag,"param");if(ah&&ah.length){var ad;for(ad=0;ad<ah.length;ad++){if("movie"===U.getAttributeValueFromNode(ah[ad],"name")&&U.hasNodeAttributeWithValue(ah[ad],"value")){return U.getAttributeValueFromNode(ah[ad],"value")}}}var ai=U.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=y.documentElement||{};var ae=ag.top<0;if(ae&&ah.offsetTop){ae=(ah.offsetTop+ag.height)>0
+}var ad=af.clientWidth;if(L.innerWidth&&ad>L.innerWidth){ad=L.innerWidth}var ac=af.clientHeight;if(L.innerHeight&&ac>L.innerHeight){ac=L.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||L.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}U.setAnyAttribute(ad,"href",ac)},shouldIgnoreInteraction:function(ae){var ad=U.hasNodeAttribute(ae,this.CONTENT_IGNOREINTERACTION_ATTR);var ac=U.hasNodeCssClass(ae,this.CONTENT_IGNOREINTERACTION_CLASS);return ad||ac}};function G(ad,ag){if(ag){return ag}if(s(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(y.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)
+}}L.name=ak+"###"+ah+"###"+ac+"###"+af}var aj=L.name.split("###");return aj.length===4&&aj[0]===ak}function Q(ad,aj,af){var ai=L.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(){var ae;try{ae=L.frameElement}catch(ad){return true}if(B(ae)){return(ae&&String(ae.nodeName).toLowerCase()==="iframe")?true:false}try{return L.self!==L.top}catch(ac){return true}}function I(bK,bE){var bA=R(y.domain,L.location.href,C()),cj=D(bA[0]),bk=k(bA[1]),aZ=k(bA[2]),ch=false,bO="GET",cv=bO,aq="application/x-www-form-urlencoded; charset=UTF-8",b0=aq,am=bK||"",bf="",cn="",bC=bE||"",a8="",bl="",aK,aV="",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],a9=[],bi=[],aN=[],bg=500,ca,aL,bo,bm,ac,bW=["pk_campaign","piwik_campaign","utm_campaign","utm_source","utm_medium"],be=["pk_kwd","piwik_kwd","utm_term"],aW="_pk_",cl,a1,aX=false,cf,aT,a5,cb=33955200000,bU=1800000,cr=15768000000,aI=true,bS=0,bn=false,ax=false,bH,bs={},bR={},aY={},a4=200,co={},ct={},bG=[],bL=false,b4=false,ad=false,cu=false,av=false,aS=o(),cm=null,bI,ay,ba,bD=Z,a0;
+try{aV=y.title}catch(b2){aV=""}function cy(cI,cF,cE,cH,cD,cG){if(aX){return}var cC;if(cE){cC=new Date();cC.setTime(cC.getTime()+cE)}y.cookie=cI+"="+n(cF)+(cE?";expires="+cC.toGMTString():"")+";path="+(cH||"/")+(cD?";domain="+cD:"")+(cG?";secure":"")}function al(cE){if(aX){return 0}var cC=new RegExp("(^|;)[ ]*"+cE+"=([^;]*)"),cD=cC.exec(y.cookie);return cD?K(cD[2]):0}function by(cC){var cD;if(bm){cD=new RegExp("#.*");return cC.replace(cD,"")}return cC}function br(cE,cC){var cF=m(cC),cD;if(cF){return cC}if(cC.slice(0,1)==="/"){return m(cE)+"://"+c(cE)+cC}cE=by(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 bQ(cC){var cD=document.createElement("a");if(cC.indexOf("//")!==0&&cC.indexOf("http")!==0){if(cC.indexOf("*")===0){cC=cC.substr(1)
+}if(cC.indexOf(".")===0){cC=cC.substr(1)}cC="http://"+cC}cD.href=p.toAbsoluteUrl(cC);if(cD.pathname){return cD.pathname}return""}function aJ(cD,cC){if(!X(cC,"/")){cC="/"+cC}if(!X(cD,"/")){cD="/"+cD}var cE=(cC==="/"||cC==="/*");if(cE){return true}if(cD===cC){return true}cC=String(cC).toLowerCase();cD=String(cD).toLowerCase();if(J(cC,"*")){cC=cC.slice(0,-1);cE=(!cC||cC==="/");if(cE){return true}if(cD===cC){return true}return cD.indexOf(cC)===0}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=bQ(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 bV(cC,cE){var cD=new Image(1,1);cD.onload=function(){x=0;if(typeof cE==="function"){cE()
+}};cC=cC.replace("send_image=0","send_image=1");cD.src=am+(am.indexOf("?")<0?"?":"&")+cC}function cq(cD,cG,cC){if(!B(cC)||null===cC){cC=true}try{var cF=L.XMLHttpRequest?new L.XMLHttpRequest():L.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){bV(cD,cG)}else{if(this.readyState===4&&(typeof cG==="function")){cG()}}};cF.setRequestHeader("Content-Type",b0);cF.send(cD)}catch(cE){if(cC){bV(cD,cG)}}}function bM(cD){var cC=new Date();var cE=cC.getTime()+cD;if(!l||cE>l){l=cE}}function bT(cC){if(bI||!aL){return}bI=setTimeout(function cD(){bI=null;if(!aS){aS=(!y.hasFocus||y.hasFocus())}if(!aS){bT(aL);return}if(bo()){return}var cE=new Date(),cF=aL-(cE.getTime()-cm);cF=Math.min(aL,cF);bT(cF)},cC||aL)}function bh(){if(!bI){return}clearTimeout(bI);bI=null}function aP(){aS=true;if(bo()){return}bT()}function aj(){bh()}function cA(){if(av||!aL){return}av=true;aa(L,"focus",aP);
+aa(L,"blur",aj);bT()}function b5(cG){var cD=new Date();var cC=cD.getTime();cm=cC;if(b4&&cC<b4){var cE=b4-cC;setTimeout(cG,cE);bM(cE+50);b4+=50;return}if(b4===false){var cF=800;b4=cC+cF}cG()}function bd(cD,cC,cE){if(!cf&&cD){b5(function(){if(cv==="POST"){cq(cD,cE)}else{bV(cD,cE)}bM(cC)})}if(!av){cA()}else{bT()}}function bP(cC){if(cf){return false}return(cC&&cC.length)}function cz(cE,cC){if(!bP(cE)){return}var cD='{"requests":["?'+cE.join('","?')+'"]}';b5(function(){cq(cD,null,false);bM(cC)})}function aA(cC){return aW+cC+"."+bC+"."+a0}function bB(){if(aX){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 aU(){a0=bD((cl||cj)+(a1||"/")).slice(0,4)}function bt(){var cD=aA("cvar"),cC=al(cD);if(cC.length){cC=JSON2.parse(cC);if(O(cC)){return cC}}return{}}function b6(){if(ax===false){ax=bt()}}function cg(){return bD((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(bl.length){cG[1]=bl}return cG}if(bl.length){cF=bl}else{if("0"===bB()){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(!bC){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(),a1,cl)}function bj(){var cC=al(aA("ref"));if(cC.length){try{cC=JSON2.parse(cC);if(O(cC)){return cC}}catch(cD){}}return["","",0,""]}function bu(cE,cD,cC){cy(cE,"",-86400,cD,cC)
+}function a6(cD){var cC="testvalue";cy("test",cC,10000,null,cD);if(al("test")===cC){bu("test",null,cD);return true}return false}function an(){var cE=aX;aX=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)){bu(cF,a1,cl)}}aX=cE}function bz(cC){bC=cC;at()}function cB(cG){if(!cG||!O(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 bJ(){cy(aA("ses"),"*",bU,a1,cl)}function bX(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=bj(),c2=aK||bk,cK,cC;if(aX){an()}if(cf){return""}var cS=aE();if(!B(cF)){cF=""}var cP=y.characterSet||y.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=bU/1000;if(!cS.lastVisitTs||(cM-cS.lastVisitTs)>c1){cS.visitCount++;
+cS.lastVisitTs=cS.currentVisitTs}if(!a5||!cK.length){for(cY in bW){if(Object.prototype.hasOwnProperty.call(bW,cY)){cK=N(c2,bW[cY]);if(cK.length){break}}}for(cY in be){if(Object.prototype.hasOwnProperty.call(be,cY)){cC=N(c2,be[cY]);if(cC.length){break}}}}c5=c(aZ);cN=cX.length?c(cX):"";if(c5.length&&!aC(c5)&&(!a5||!cN.length||aC(cN))){cX=aZ}if(cX.length||cK.length){cJ=cM;cW=[cK,cC,cJ,by(cX.slice(0,cG))];cy(cT,JSON2.stringify(cW),cr,a1,cl)}}cE+="&idsite="+bC+"&rec=1&r="+String(Math.random()).slice(2,8)+"&h="+cD.getHours()+"&m="+cD.getMinutes()+"&s="+cD.getSeconds()+"&url="+n(by(c2))+(aZ.length?"&urlref="+n(by(aZ)):"")+((a8&&a8.length)?"&uid="+n(a8):"")+"&_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(by(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&&u(cZ)){cZ=null}for(cY in aY){if(Object.prototype.hasOwnProperty.call(aY,cY)){var cO=(-1===E(c4,cY));if(cO){cE+="&dimension"+cY+"="+aY[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(bs);var cU=cB(bR);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(bn){cy(cQ,JSON2.stringify(ax),bU,a1,cl)}}if(aI){if(bS){cE+="&gt_ms="+bS}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);bJ();cE+=S(c0);if(cn.length){cE+="&"+cn}if(t(bH)){cE=bH(cE)}return cE}bo=function aM(){var cC=new Date();if(cm+aL<=cC.getTime()){var cD=bX("ping=1",null,"ping");bd(cD,bg);return true}return false};function a2(cF,cE,cK,cG,cC,cN){var cI="idgoal=0",cJ,cD=new Date(),cL=[],cM,cH=String(cF).length;if(cH){cI+="&ec_id="+n(cF);cJ=Math.round(cD.getTime()/1000)}cI+="&revenue="+cE;if(String(cK).length){cI+="&ec_st="+cK}if(String(cG).length){cI+="&ec_tx="+cG}if(String(cC).length){cI+="&ec_sh="+cC}if(String(cN).length){cI+="&ec_dt="+cN}if(co){for(cM in co){if(Object.prototype.hasOwnProperty.call(co,cM)){if(!B(co[cM][1])){co[cM][1]=""}if(!B(co[cM][2])){co[cM][2]=""}if(!B(co[cM][3])||String(co[cM][3]).length===0){co[cM][3]=0}if(!B(co[cM][4])||String(co[cM][4]).length===0){co[cM][4]=1}cL.push(co[cM])}}cI+="&ec_items="+n(JSON2.stringify(cL))}cI=bX(cI,ac,"ecommerce",cJ);bd(cI,bg);if(cH){co={}}}function bv(cC,cG,cF,cE,cD,cH){if(String(cC).length&&B(cG)){a2(cC,cG,cF,cE,cD,cH)
+}}function a3(cC){if(B(cC)){a2("",cC,"","","","")}}function bw(cD,cF,cE){var cC=bX("action_name="+n(ab(cD||aV)),cF,"log");bd(cC,bg,cE)}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 bY(cG,cC,cH,cD){if(aB(cC)){return 0}var cF=aG(bi,"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(U.isLinkElement(cD)){break}cD=cC;cC=cD.parentNode}return cD}function cw(cH){cH=ag(cH);if(!U.hasNodeAttribute(cH,"href")){return}if(!B(cH.href)){return}var cG=U.getAttributeValueFromNode(cH,"href");if(aB(cG)){return}var cD=cH.pathname||bQ(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=bY(cH.className,cE,af(cJ,cD),U.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 bX(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 aQ(cC,cD){if(!cC||!cD){return false}var cE=p.findTargetNode(cC);if(p.shouldIgnoreInteraction(cE)){return false}cE=p.findTargetNodeNoDefault(cC);if(cE&&!M(cE,cD)){return false}return true}function bZ(cE,cD,cG){if(!cE){return}var cC=p.findParentContentNode(cE);if(!cC){return}if(!aQ(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(!bG||!bG.length){return false}var cC,cE;for(cC=0;cC<bG.length;cC++){cE=bG[cC];
+if(cE&&cE.name===cD.name&&cE.piece===cD.piece&&cE.target===cD.target){return true}}return false}function bc(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(U.isLinkElement(cI)&&U.hasNodeAttributeWithValue(cI,"href")){var cC=String(U.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(!U.hasNodeAttributeWithValue(cI,p.CONTENT_TARGET_ATTR)||cI.wasContentTargetAttrReplaced){cI.wasContentTargetAttrReplaced=true;cH=p.toAbsoluteUrl(cC);U.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++){bc(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(!aQ(cG,cH)){return}bM(bg);if(U.isLinkElement(cC)&&U.hasNodeAttributeWithValue(cC,"href")&&U.hasNodeAttributeWithValue(cC,p.CONTENT_TARGET_ATTR)){var cE=U.getAttributeValueFromNode(cC,"href");if(!aB(cE)&&cC.wasContentTargetAttrReplaced){U.setAnyAttribute(cC,p.CONTENT_TARGET_ATTR,"")}}var cL=cw(cC);if(ad&&cL&&cL.type){return cL.type}if(bc(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);bd(cJ,bg);return cJ}}function bx(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;aa(cD,"click",aF(cD))}}}function a7(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{bG.push(cE[cC])}}if(!cE||!cE.length){return[]}au(cF);bx(cF);var cG=[];for(cC=0;cC<cE.length;
+cC++){cD=bX(p.buildImpressionRequestParams(cE[cC].name,cE[cC].piece,cE[cC].target),undefined,"contentImpressions");if(cD){cG.push(cD)}}return cG}function b3(cD){var cC=p.collectContent(cD);return a7(cC,cD)}function aO(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 bX(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=bX(ce(cE,cG,cC,cF),cH,"event");bd(cD,bg)}function bF(cC,cF,cD,cG){var cE=bX("search="+n(cC)+(cF?"&search_cat="+n(cF):"")+(B(cD)?"&search_count="+cD:""),cG,"sitesearch");
+bd(cE,bg)}function ci(cC,cF,cE){var cD=bX("idgoal="+cC+(cF?"&revenue="+cF:""),cE,"goal");bd(cD,bg)}function cp(cF,cC,cJ,cI,cE){var cH=cC+"="+n(by(cF));var cD=bZ(cE,"click",cF);if(cD){cH+="&"+cD}var cG=bX(cH,cJ,"link");bd(cG,(cI?0:bg),cI)}function bp(cD,cC){if(cD!==""){return cD+cC.charAt(0).toUpperCase()+cC.slice(1)}return cC}function bN(cH){var cG,cC,cF=["","webkit","ms","moz"],cE;if(!aT){for(cC=0;cC<cF.length;cC++){cE=cF[cC];if(Object.prototype.hasOwnProperty.call(y,bp(cE,"hidden"))){if(y[bp(cE,"visibilityState")]==="prerender"){cG=true}break}}}if(cG){aa(y,cE+"visibilitychange",function cD(){y.removeEventListener(cE+"visibilitychange",cD,false);cH()});return}cH()}function ar(cC){if(y.readyState==="complete"){cC()}else{if(L.addEventListener){L.addEventListener("load",cC)}else{if(L.attachEvent){L.attachEvent("onload",cC)}}}}function aR(cF){var cC=false;if(y.attachEvent){cC=y.readyState==="complete"}else{cC=y.readyState!=="loading"}if(cC){cF();return}var cE;if(y.addEventListener){aa(y,"DOMContentLoaded",function cD(){y.removeEventListener("DOMContentLoaded",cD,false);
+if(!cC){cC=true;cF()}})}else{if(y.attachEvent){y.attachEvent("onreadystatechange",function cD(){if(y.readyState==="complete"){y.detachEvent("onreadystatechange",cD);if(!cC){cC=true;cF()}}});if(y.documentElement.doScroll&&L===L.top){(function cD(){if(!cC){try{y.documentElement.doScroll("left")}catch(cG){setTimeout(cD,0);return}cC=true;cF()}}())}}}aa(L,"load",function(){if(!cC){cC=true;cF()}},false)}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 b1(){return y.all&&!y.addEventListener}function ck(cC){var cE=cC.which;var cD=(typeof cC.button);if(!cE&&cD!=="undefined"){if(b1()){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 bq(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||L.event;
+var cE=bq(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;ba=cG}else{ay=ba=null}}else{if(cF.type==="mouseup"){if(cE===ay&&cG===ba){b9(cG)}ay=ba=null}else{if(cF.type==="contextmenu"){b9(cG)}}}}}}function ae(cD,cC){aa(cD,"click",ak(cC),false);if(cC){aa(cD,"mouseup",ak(cC),false);aa(cD,"mousedown",ak(cC),false);aa(cD,"contextmenu",ak(cC),false)}}function bb(cD){if(!ad){ad=true;var cE,cC=aG(a9,"ignore"),cF=y.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(bL){return true}bL=true;var cI=false;var cF,cD;function cC(){cI=true}ar(function(){function cJ(cL){setTimeout(function(){if(!bL){return}cI=false;cH.trackVisibleContentImpressions();cJ(cL)},cL)}function cK(cL){setTimeout(function(){if(!bL){return}if(cI){cI=false;cH.trackVisibleContentImpressions()}cK(cL)},cL)}if(cE){cF=["scroll","resize"];for(cD=0;cD<cF.length;cD++){if(y.addEventListener){y.addEventListener(cF[cD],cC)
+}else{L.attachEvent("on"+cF[cD],cC)}}cK(100)}if(cG&&cG>0){cG=parseInt(cG,10);cJ(cG)}})}function b7(){var cD,cF,cG={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"};if(!((new RegExp("MSIE")).test(f.userAgent))){if(f.mimeTypes&&f.mimeTypes.length){for(cD in cG){if(Object.prototype.hasOwnProperty.call(cG,cD)){cF=f.mimeTypes[cG[cD]];ct[cD]=(cF&&cF.enabledPlugin)?"1":"0"}}}if(typeof navigator.javaEnabled!=="unknown"&&B(f.javaEnabled)&&f.javaEnabled()){ct.java="1"}if(t(L.GearsFactory)){ct.gears="1"}ct.cookie=bB()}var cE=parseInt(P.width,10);var cC=parseInt(P.height,10);ct.res=parseInt(cE,10)+"x"+parseInt(cC,10)}b7();aU();at();this.getVisitorId=function(){return aE().uuid};this.getVisitorInfo=function(){return cd()};this.getAttributionInfo=function(){return bj()};this.getAttributionCampaignName=function(){return bj()[0]
+};this.getAttributionCampaignKeyword=function(){return bj()[1]};this.getAttributionReferrerTimestamp=function(){return bj()[2]};this.getAttributionReferrerUrl=function(){return bj()[3]};this.setTrackerUrl=function(cC){am=cC};this.getTrackerUrl=function(){return am};this.addTracker=function(cC,cE){if(!cE){throw new Error("A siteId must be given to add a new tracker")}if(!B(cC)||null===cC){cC=this.getTrackerUrl()}var cD=new I(cC,cE);A.push(cD);return cD};this.getSiteId=function(){return bC};this.setSiteId=function(cC){bz(cC)};this.setUserId=function(cC){if(!B(cC)||!cC.length){return}a8=cC;bl=bD(a8).substr(0,16)};this.getUserId=function(){return a8};this.setCustomData=function(cC,cD){if(O(cC)){ac=cC}else{if(!ac){ac={}}ac[cC]=cD}};this.getCustomData=function(){return ac};this.setCustomRequestProcessing=function(cC){bH=cC};this.appendToTrackingUrl=function(cC){cn=cC};this.getRequest=function(cC){return bX(cC)};this.addPlugin=function(cC,cD){a[cC]=cD};this.setCustomDimension=function(cC,cD){cC=parseInt(cC,10);
+if(cC>0){if(!B(cD)){cD=""}if(!q(cD)){cD=String(cD)}aY[cC]=cD}};this.getCustomDimension=function(cC){cC=parseInt(cC,10);if(cC>0&&Object.prototype.hasOwnProperty.call(aY,cC)){return aY[cC]}};this.deleteCustomDimension=function(cC){cC=parseInt(cC,10);if(cC>0){delete aY[cC]}};this.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,a4),cG.slice(0,a4)];if(cE==="visit"||cE===2){b6();ax[cD]=cF}else{if(cE==="page"||cE===3){bs[cD]=cF}else{if(cE==="event"){bR[cD]=cF}}}}};this.getCustomVariable=function(cD,cE){var cC;if(!B(cE)){cE="visit"}if(cE==="page"||cE===3){cC=bs[cD]}else{if(cE==="event"){cC=bR[cD]}else{if(cE==="visit"||cE===2){b6();cC=ax[cD]}}}if(!B(cC)||(cC&&cC[0]==="")){return false}return cC};this.deleteCustomVariable=function(cC,cD){if(this.getCustomVariable(cC,cD)){this.setCustomVariable(cC,"","",cD)}};this.storeCustomVariablesInCookie=function(){bn=true};this.setLinkTrackingTimer=function(cC){bg=cC
+};this.setDownloadExtensions=function(cC){if(q(cC)){cC=cC.split("|")}cs=cC};this.addDownloadExtensions=function(cD){var cC;if(q(cD)){cD=cD.split("|")}for(cC=0;cC<cD.length;cC++){cs.push(cD[cC])}};this.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};this.setDomains=function(cC){ai=q(cC)?[cC]:cC;var cG=false,cE=0,cD;for(cE;cE<ai.length;cE++){cD=String(ai[cE]);if(b8(cj,D(cD))){cG=true;break}var cF=bQ(cD);if(cF&&cF!=="/"&&cF!=="/*"){cG=true;break}}if(!cG){ai.push(cj)}};this.setIgnoreClasses=function(cC){a9=q(cC)?[cC]:cC};this.setRequestMethod=function(cC){cv=cC||bO};this.setRequestContentType=function(cC){b0=cC||aq};this.setReferrerUrl=function(cC){aZ=cC};this.setCustomUrl=function(cC){aK=br(bk,cC)};this.setDocumentTitle=function(cC){aV=cC};this.setAPIUrl=function(cC){bf=cC};this.setDownloadClasses=function(cC){bi=q(cC)?[cC]:cC};this.setLinkClasses=function(cC){aN=q(cC)?[cC]:cC};this.setCampaignNameKey=function(cC){bW=q(cC)?[cC]:cC
+};this.setCampaignKeywordKey=function(cC){be=q(cC)?[cC]:cC};this.discardHashTag=function(cC){bm=cC};this.setCookieNamePrefix=function(cC){aW=cC;ax=bt()};this.setCookieDomain=function(cC){var cD=D(cC);if(a6(cD)){cl=cD;aU()}};this.setCookiePath=function(cC){a1=cC;aU()};this.setVisitorCookieTimeout=function(cC){cb=cC*1000};this.setSessionCookieTimeout=function(cC){bU=cC*1000};this.setReferralCookieTimeout=function(cC){cr=cC*1000};this.setConversionAttributionFirstReferrer=function(cC){a5=cC};this.disableCookies=function(){aX=true;ct.cookie="0";if(bC){an()}};this.deleteCookies=function(){an()};this.setDoNotTrack=function(cD){var cC=f.doNotTrack||f.msDoNotTrack;cf=cD&&(cC==="yes"||cC==="1");if(cf){this.disableCookies()}};this.addListener=function(cD,cC){ae(cD,cC)};this.enableLinkTracking=function(cC){cu=true;bN(function(){aR(function(){bb(cC)})})};this.enableJSErrorTracking=function(){if(ch){return}ch=true;var cC=L.onerror;L.onerror=function(cH,cF,cE,cG,cD){bN(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}};this.disablePerformanceTracking=function(){aI=false};this.setGenerationTimeMs=function(cC){bS=parseInt(cC,10)};this.enableHeartBeatTimer=function(cC){cC=Math.max(cC,1);aL=(cC||15)*1000;if(cm!==null){cA()}};this.killFrame=function(){if(L.location!==L.top.location){L.top.location=L.location}};this.redirectFile=function(cC){if(L.location.protocol==="file:"){L.location=cC}};this.setCountPreRendered=function(cC){aT=cC};this.trackGoal=function(cC,cE,cD){bN(function(){ci(cC,cE,cD)})};this.trackLink=function(cD,cC,cF,cE){bN(function(){cp(cD,cC,cF,cE)})};this.trackPageView=function(cC,cE,cD){bG=[];if(F(bC)){bN(function(){Q(am,bf,bC)})}else{bN(function(){bw(cC,cE,cD)})}};this.trackAllContentImpressions=function(){if(F(bC)){return}bN(function(){aR(function(){var cC=p.findContentNodes();var cD=b3(cC);cz(cD,bg)})})};this.trackVisibleContentImpressions=function(cC,cD){if(F(bC)){return}if(!B(cC)){cC=true}if(!B(cD)){cD=750
+}az(cC,cD,this);bN(function(){ar(function(){var cE=p.findContentNodes();var cF=aO(cE);cz(cF,bg)})})};this.trackContentImpression=function(cE,cC,cD){if(F(bC)){return}if(!cE){return}cC=cC||"Unknown";bN(function(){var cF=ao(cE,cC,cD);bd(cF,bg)})};this.trackContentImpressionsWithinNode=function(cC){if(F(bC)||!cC){return}bN(function(){if(bL){ar(function(){var cD=p.findContentNodesWithinNode(cC);var cE=aO(cD);cz(cE,bg)})}else{aR(function(){var cD=p.findContentNodesWithinNode(cC);var cE=b3(cD);cz(cE,bg)})}})};this.trackContentInteraction=function(cE,cF,cC,cD){if(F(bC)){return}if(!cE||!cF){return}cC=cC||"Unknown";bN(function(){var cG=aw(cE,cF,cC,cD);bd(cG,bg)})};this.trackContentInteractionNode=function(cD,cC){if(F(bC)||!cD){return}bN(function(){var cE=cx(cD,cC);bd(cE,bg)})};this.logAllContentBlocksOnPage=function(){var cD=p.findContentNodes();var cC=p.collectContent(cD);if(console!==undefined&&console&&console.log){console.log(cC)}};this.trackEvent=function(cD,cF,cC,cE,cG){bN(function(){ah(cD,cF,cC,cE,cG)
+})};this.trackSiteSearch=function(cC,cE,cD,cF){bN(function(){bF(cC,cE,cD,cF)})};this.setEcommerceView=function(cF,cC,cE,cD){if(!B(cE)||!cE.length){cE=""}else{if(cE instanceof Array){cE=JSON2.stringify(cE)}}bs[5]=["_pkc",cE];if(B(cD)&&String(cD).length){bs[2]=["_pkp",cD]}if((!B(cF)||!cF.length)&&(!B(cC)||!cC.length)){return}if(B(cF)&&cF.length){bs[3]=["_pks",cF]}if(!B(cC)||!cC.length){cC=""}bs[4]=["_pkn",cC]};this.addEcommerceItem=function(cG,cC,cE,cD,cF){if(cG.length){co[cG]=[cG,cC,cE,cD,cF]}};this.trackEcommerceOrder=function(cC,cG,cF,cE,cD,cH){bv(cC,cG,cF,cE,cD,cH)};this.trackEcommerceCartUpdate=function(cC){a3(cC)};this.trackRequest=function(cC,cE,cD){bN(function(){var cF=bX(cC,cE);bd(cF,bg,cD)})};d.trigger("TrackerSetup",[this])}function z(){return{push:V}}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){V(ah[af]);delete ah[af];if(ai[ad]>1){Y("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}var v=["addTracker","disableCookies","setTrackerUrl","setAPIUrl","setCookiePath","setCookieDomain","setDomains","setUserId","setSiteId","enableLinkTracking"];function T(ac,ae){var ad=new I(ac,ae);A.push(ad);_paq=b(_paq,v);for(x=0;x<_paq.length;x++){if(_paq[x]){V(_paq[x])}}_paq=new z();return ad}aa(L,"beforeunload",W,false);Date.prototype.getTimeAlias=Date.prototype.getTime;d={initialized:false,on:function(ad,ac){if(!r[ad]){r[ad]=[]}r[ad].push(ac)},off:function(ae,ad){if(!r[ae]){return}var ac=0;for(ac;ac<r[ae].length;ac++){if(r[ae][ac]===ad){delete r[ae][ac]}}},trigger:function(ae,af,ad){if(!r[ae]){return}var ac=0;for(ac;ac<r[ae].length;ac++){r[ae][ac].apply(ad||L,af)}},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)},getAsyncTrackers:function(){return A},addTracker:function(ac,ad){if(!A.length){T(ac,ad)}else{A[0].addTracker(ac,ad)
+}},getAsyncTracker:function(ad,ag){var af;if(A&&A[0]){af=A[0]}if(!ag&&!ad){return af}if((!B(ag)||null===ag)&&af){ag=af.getSiteId()}if((!B(ad)||null===ad)&&af){ad=af.getTrackerUrl()}var ae,ac=0;for(ac;ac<A.length;ac++){ae=A[ac];if(ae&&String(ae.getSiteId())===String(ag)&&ae.getTrackerUrl()===ad){return ae}}}};if(typeof define==="function"&&define.amd){define("piwik",[],function(){return d})}return d}());
+/*!!! pluginTrackerHook */
+}(function(){if(window&&"object"===typeof window.piwikPluginAsyncInit&&window.piwikPluginAsyncInit.length){var a=0;for(a;a<window.piwikPluginAsyncInit.length;a++){if(typeof window.piwikPluginAsyncInit[a]==="function"){window.piwikPluginAsyncInit[a]()}}}window.Piwik.addTracker();window.Piwik.trigger("PiwikInitialized",[]);window.Piwik.initialized=true}());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/piwik.js b/piwik.js
index f89c3a539f..002e4cb757 100644
--- a/piwik.js
+++ b/piwik.js
@@ -18,51 +18,54 @@ 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={},x=document,f=navigator,O=screen,K=window,g=K.performance||K.mozPerformance||K.msPerformance||K.webkitPerformance,n=K.encodeURIComponent,J=K.decodeURIComponent,i=unescape,z=[],w,d;
-function k(aa){try{return J(aa)}catch(ab){return unescape(aa)}}function A(ab){var aa=typeof ab;return aa!=="undefined"}function s(aa){return typeof aa==="function"}function N(aa){return typeof aa==="object"}function q(aa){return typeof aa==="string"||aa instanceof String}function t(ab){if(!ab){return true}var aa;var ac=true;for(aa in ab){if(Object.prototype.hasOwnProperty.call(ab,aa)){ac=false}}return ac}function W(aa){if(console!==undefined&&console&&console.error){console.error(aa)}}function T(){var ab,aa,ae,ad;for(ab=0;ab<arguments.length;ab+=1){ad=arguments[ab];ae=ad.shift();for(aa=0;aa<z.length;aa++){if(q(ae)){if(z[aa][ae]){z[aa][ae].apply(z[aa],ad)}else{var ac="The method '"+ae+'\' was not found in "_paq" variable. Please have a look at the Piwik tracker documentation: http://developer.piwik.org/api-reference/tracking-javascript';W(ac);throw new TypeError(ac)}if(ae==="addTracker"){break}if(ae==="setTrackerUrl"||ae==="setSiteId"){break}}else{ae.apply(z[aa],ad)}}}}function Y(ad,ac,ab,aa){if(ad.addEventListener){ad.addEventListener(ac,ab,aa);
-return true}if(ad.attachEvent){return ad.attachEvent("on"+ac,ab)}ad["on"+ac]=ab}function R(ab,af){var aa="",ad,ac,ae;for(ad in a){if(Object.prototype.hasOwnProperty.call(a,ad)){ac=a[ad][ab];if(s(ac)){ae=ac(af);if(ae){aa+=ae}}}}return aa}function U(){var aa;R("unload");if(l){do{aa=new Date()}while(aa.getTimeAlias()<l)}}function j(ac,ab){var aa=x.createElement("script");aa.type="text/javascript";aa.src=ac;if(aa.readyState){aa.onreadystatechange=function(){var ad=this.readyState;if(ad==="loaded"||ad==="complete"){aa.onreadystatechange=null;ab()}}}else{aa.onload=ab}x.getElementsByTagName("head")[0].appendChild(aa)}function B(){var aa="";try{aa=K.top.document.referrer}catch(ac){if(K.parent){try{aa=K.parent.document.referrer}catch(ab){aa=""}}}if(aa===""){aa=x.referrer}return aa}function m(aa){var ac=new RegExp("^([a-z]+):"),ab=ac.exec(aa);return ab?ab[1]:null}function c(aa){var ac=new RegExp("^(?:(?:https?|ftp):)/*(?:[^@]+@)?([^:/#]+)"),ab=ac.exec(aa);return ab?ab[1]:aa}function M(ac,ab){var aa="[\\?&#]"+ab+"=([^&#]*)";
-var ae=new RegExp(aa);var ad=ae.exec(ac);return ad?J(ad[1]):""}function v(aa){return unescape(n(aa))}function X(ap){var ac=function(aw,av){return(aw<<av)|(aw>>>(32-av))},aq=function(ay){var aw="",ax,av;for(ax=7;ax>=0;ax--){av=(ay>>>(ax*4))&15;aw+=av.toString(16)}return aw},af,at,ar,ab=[],aj=1732584193,ah=4023233417,ag=2562383102,ae=271733878,ad=3285377520,ao,an,am,al,ak,au,aa,ai=[];ap=v(ap);aa=ap.length;for(at=0;at<aa-3;at+=4){ar=ap.charCodeAt(at)<<24|ap.charCodeAt(at+1)<<16|ap.charCodeAt(at+2)<<8|ap.charCodeAt(at+3);ai.push(ar)}switch(aa&3){case 0:at=2147483648;break;case 1:at=ap.charCodeAt(aa-1)<<24|8388608;break;case 2:at=ap.charCodeAt(aa-2)<<24|ap.charCodeAt(aa-1)<<16|32768;break;case 3:at=ap.charCodeAt(aa-3)<<24|ap.charCodeAt(aa-2)<<16|ap.charCodeAt(aa-1)<<8|128;break}ai.push(at);while((ai.length&15)!==14){ai.push(0)}ai.push(aa>>>29);ai.push((aa<<3)&4294967295);for(af=0;af<ai.length;af+=16){for(at=0;at<16;at++){ab[at]=ai[af+at]}for(at=16;at<=79;at++){ab[at]=ac(ab[at-3]^ab[at-8]^ab[at-14]^ab[at-16],1)
-}ao=aj;an=ah;am=ag;al=ae;ak=ad;for(at=0;at<=19;at++){au=(ac(ao,5)+((an&am)|(~an&al))+ak+ab[at]+1518500249)&4294967295;ak=al;al=am;am=ac(an,30);an=ao;ao=au}for(at=20;at<=39;at++){au=(ac(ao,5)+(an^am^al)+ak+ab[at]+1859775393)&4294967295;ak=al;al=am;am=ac(an,30);an=ao;ao=au}for(at=40;at<=59;at++){au=(ac(ao,5)+((an&am)|(an&al)|(am&al))+ak+ab[at]+2400959708)&4294967295;ak=al;al=am;am=ac(an,30);an=ao;ao=au}for(at=60;at<=79;at++){au=(ac(ao,5)+(an^am^al)+ak+ab[at]+3395469782)&4294967295;ak=al;al=am;am=ac(an,30);an=ao;ao=au}aj=(aj+ao)&4294967295;ah=(ah+an)&4294967295;ag=(ag+am)&4294967295;ae=(ae+al)&4294967295;ad=(ad+ak)&4294967295}au=aq(aj)+aq(ah)+aq(ag)+aq(ae)+aq(ad);return au.toLowerCase()}function Q(ac,aa,ab){if(!ac){ac=""}if(!aa){aa=""}if(ac==="translate.googleusercontent.com"){if(ab===""){ab=aa}aa=M(aa,"u");ac=c(aa)}else{if(ac==="cc.bingj.com"||ac==="webcache.googleusercontent.com"||ac.slice(0,5)==="74.6."){aa=x.links[0].href;ac=c(aa)}}return[ac,aa,ab]}function C(ab){var aa=ab.length;if(ab.charAt(--aa)==="."){ab=ab.slice(0,aa)
-}if(ab.slice(0,2)==="*."){ab=ab.slice(1)}if(ab.indexOf("/")!==-1){ab=ab.substr(0,ab.indexOf("/"))}return ab}function Z(ab){ab=ab&&ab.text?ab.text:ab;if(!q(ab)){var aa=x.getElementsByTagName("title");if(aa&&A(aa[0])){ab=aa[0].text}}return ab}function G(aa){if(!aa){return[]}if(!A(aa.children)&&A(aa.childNodes)){return aa.children}if(A(aa.children)){return aa.children}return[]}function L(ab,aa){if(!ab||!aa){return false}if(ab.contains){return ab.contains(aa)}if(ab===aa){return true}if(ab.compareDocumentPosition){return !!(ab.compareDocumentPosition(aa)&16)}return false}function D(ac,ad){if(ac&&ac.indexOf){return ac.indexOf(ad)}if(!A(ac)||ac===null){return -1}if(!ac.length){return -1}var aa=ac.length;if(aa===0){return -1}var ab=0;while(ab<aa){if(ac[ab]===ad){return ab}ab++}return -1}function V(ab,aa){ab=String(ab);return ab.lastIndexOf(aa,0)===0}function I(ab,aa){ab=String(ab);return ab.indexOf(aa,ab.length-aa.length)!==-1}function r(ab,aa){ab=String(ab);return ab.indexOf(aa)!==-1}function e(ab,aa){ab=String(ab);
-return ab.substr(0,ab.length-aa)}function h(ac){if(!ac){return false}function aa(ae,af){if(K.getComputedStyle){return x.defaultView.getComputedStyle(ae,null)[af]}if(ae.currentStyle){return ae.currentStyle[af]}}function ad(ae){ae=ae.parentNode;while(ae){if(ae===x){return true}ae=ae.parentNode}return false}function ab(ag,am,ae,aj,ah,ak,ai){var af=ag.parentNode,al=1;if(!ad(ag)){return false}if(9===af.nodeType){return true}if("0"===aa(ag,"opacity")||"none"===aa(ag,"display")||"hidden"===aa(ag,"visibility")){return false}if(!A(am)||!A(ae)||!A(aj)||!A(ah)||!A(ak)||!A(ai)){am=ag.offsetTop;ah=ag.offsetLeft;aj=am+ag.offsetHeight;ae=ah+ag.offsetWidth;ak=ag.offsetWidth;ai=ag.offsetHeight}if(ac===ag&&(0===ai||0===ak)&&"hidden"===aa(ag,"overflow")){return false}if(af){if(("hidden"===aa(af,"overflow")||"scroll"===aa(af,"overflow"))){if(ah+al>af.offsetWidth+af.scrollLeft||ah+ak-al<af.scrollLeft||am+al>af.offsetHeight+af.scrollTop||am+ai-al<af.scrollTop){return false}}if(ag.offsetParent===af){ah+=af.offsetLeft;
-am+=af.offsetTop}return ab(af,am,ae,aj,ah,ak,ai)}return true}return ab(ac)}var S={htmlCollectionToArray:function(ac){var aa=[],ab;if(!ac||!ac.length){return aa}for(ab=0;ab<ac.length;ab++){aa.push(ac[ab])}return aa},find:function(aa){if(!document.querySelectorAll||!aa){return[]}var ab=document.querySelectorAll(aa);return this.htmlCollectionToArray(ab)},findMultiple:function(ac){if(!ac||!ac.length){return[]}var ab,ad;var aa=[];for(ab=0;ab<ac.length;ab++){ad=this.find(ac[ab]);aa=aa.concat(ad)}aa=this.makeNodesUnique(aa);return aa},findNodesByTagName:function(ab,aa){if(!ab||!aa||!ab.getElementsByTagName){return[]}var ac=ab.getElementsByTagName(aa);return this.htmlCollectionToArray(ac)},makeNodesUnique:function(aa){var af=[].concat(aa);aa.sort(function(ah,ag){if(ah===ag){return 0}var aj=D(af,ah);var ai=D(af,ag);if(aj===ai){return 0}return aj>ai?-1:1});if(aa.length<=1){return aa}var ab=0;var ad=0;var ae=[];var ac;ac=aa[ab++];while(ac){if(ac===aa[ab]){ad=ae.push(ab)}ac=aa[ab++]||null}while(ad--){aa.splice(ae[ad],1)
-}return aa},getAttributeValueFromNode:function(ae,ac){if(!this.hasNodeAttribute(ae,ac)){return}if(ae&&ae.getAttribute){return ae.getAttribute(ac)}if(!ae||!ae.attributes){return}var ad=(typeof ae.attributes[ac]);if("undefined"===ad){return}if(ae.attributes[ac].value){return ae.attributes[ac].value}if(ae.attributes[ac].nodeValue){return ae.attributes[ac].nodeValue}var ab;var aa=ae.attributes;if(!aa){return}for(ab=0;ab<aa.length;ab++){if(aa[ab].nodeName===ac){return aa[ab].nodeValue}}return null},hasNodeAttributeWithValue:function(ab,aa){var ac=this.getAttributeValueFromNode(ab,aa);return !!ac},hasNodeAttribute:function(ac,aa){if(ac&&ac.hasAttribute){return ac.hasAttribute(aa)}if(ac&&ac.attributes){var ab=(typeof ac.attributes[aa]);return"undefined"!==ab}return false},hasNodeCssClass:function(ac,aa){if(ac&&aa&&ac.className){var ab=typeof ac.className==="string"?ac.className.split(" "):[];if(-1!==D(ab,aa)){return true}}return false},findNodesHavingAttribute:function(ae,ac,aa){if(!aa){aa=[]}if(!ae||!ac){return aa
-}var ad=G(ae);if(!ad||!ad.length){return aa}var ab,af;for(ab=0;ab<ad.length;ab++){af=ad[ab];if(this.hasNodeAttribute(af,ac)){aa.push(af)}aa=this.findNodesHavingAttribute(af,ac,aa)}return aa},findFirstNodeHavingAttribute:function(ac,ab){if(!ac||!ab){return}if(this.hasNodeAttribute(ac,ab)){return ac}var aa=this.findNodesHavingAttribute(ac,ab);if(aa&&aa.length){return aa[0]}},findFirstNodeHavingAttributeWithValue:function(ad,ac){if(!ad||!ac){return}if(this.hasNodeAttributeWithValue(ad,ac)){return ad}var aa=this.findNodesHavingAttribute(ad,ac);if(!aa||!aa.length){return}var ab;for(ab=0;ab<aa.length;ab++){if(this.getAttributeValueFromNode(aa[ab],ac)){return aa[ab]}}},findNodesHavingCssClass:function(ae,ad,aa){if(!aa){aa=[]}if(!ae||!ad){return aa}if(ae.getElementsByClassName){var af=ae.getElementsByClassName(ad);return this.htmlCollectionToArray(af)}var ac=G(ae);if(!ac||!ac.length){return[]}var ab,ag;for(ab=0;ab<ac.length;ab++){ag=ac[ab];if(this.hasNodeCssClass(ag,ad)){aa.push(ag)}aa=this.findNodesHavingCssClass(ag,ad,aa)
-}return aa},findFirstNodeHavingClass:function(ac,ab){if(!ac||!ab){return}if(this.hasNodeCssClass(ac,ab)){return ac}var aa=this.findNodesHavingCssClass(ac,ab);if(aa&&aa.length){return aa[0]}},isLinkElement:function(ab){if(!ab){return false}var aa=String(ab.nodeName).toLowerCase();var ad=["a","area"];var ac=D(ad,aa);return ac!==-1},setAnyAttribute:function(ab,aa,ac){if(!ab||!aa){return}if(ab.setAttribute){ab.setAttribute(aa,ac)}else{ab[aa]=ac}}};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 ab="."+this.CONTENT_CLASS;var aa="["+this.CONTENT_ATTR+"]";var ac=S.findMultiple([ab,aa]);return ac
-},findContentNodesWithinNode:function(ad){if(!ad){return[]}var ab=S.findNodesHavingCssClass(ad,this.CONTENT_CLASS);var aa=S.findNodesHavingAttribute(ad,this.CONTENT_ATTR);if(aa&&aa.length){var ac;for(ac=0;ac<aa.length;ac++){ab.push(aa[ac])}}if(S.hasNodeAttribute(ad,this.CONTENT_ATTR)){ab.push(ad)}else{if(S.hasNodeCssClass(ad,this.CONTENT_CLASS)){ab.push(ad)}}ab=S.makeNodesUnique(ab);return ab},findParentContentNode:function(ab){if(!ab){return}var ac=ab;var aa=0;while(ac&&ac!==x&&ac.parentNode){if(S.hasNodeAttribute(ac,this.CONTENT_ATTR)){return ac}if(S.hasNodeCssClass(ac,this.CONTENT_CLASS)){return ac}ac=ac.parentNode;if(aa>1000){break}aa++}},findPieceNode:function(ab){var aa;aa=S.findFirstNodeHavingAttribute(ab,this.CONTENT_PIECE_ATTR);if(!aa){aa=S.findFirstNodeHavingClass(ab,this.CONTENT_PIECE_CLASS)}if(aa){return aa}return ab},findTargetNodeNoDefault:function(aa){if(!aa){return}var ab=S.findFirstNodeHavingAttributeWithValue(aa,this.CONTENT_TARGET_ATTR);if(ab){return ab}ab=S.findFirstNodeHavingAttribute(aa,this.CONTENT_TARGET_ATTR);
-if(ab){return ab}ab=S.findFirstNodeHavingClass(aa,this.CONTENT_TARGET_CLASS);if(ab){return ab}},findTargetNode:function(aa){var ab=this.findTargetNodeNoDefault(aa);if(ab){return ab}return aa},findContentName:function(ab){if(!ab){return}var ae=S.findFirstNodeHavingAttributeWithValue(ab,this.CONTENT_NAME_ATTR);if(ae){return S.getAttributeValueFromNode(ae,this.CONTENT_NAME_ATTR)}var aa=this.findContentPiece(ab);if(aa){return this.removeDomainIfIsInLink(aa)}if(S.hasNodeAttributeWithValue(ab,"title")){return S.getAttributeValueFromNode(ab,"title")}var ac=this.findPieceNode(ab);if(S.hasNodeAttributeWithValue(ac,"title")){return S.getAttributeValueFromNode(ac,"title")}var ad=this.findTargetNode(ab);if(S.hasNodeAttributeWithValue(ad,"title")){return S.getAttributeValueFromNode(ad,"title")}},findContentPiece:function(ab){if(!ab){return}var ad=S.findFirstNodeHavingAttributeWithValue(ab,this.CONTENT_PIECE_ATTR);if(ad){return S.getAttributeValueFromNode(ad,this.CONTENT_PIECE_ATTR)}var aa=this.findPieceNode(ab);
-var ac=this.findMediaUrlInNode(aa);if(ac){return this.toAbsoluteUrl(ac)}},findContentTarget:function(ac){if(!ac){return}var ad=this.findTargetNode(ac);if(S.hasNodeAttributeWithValue(ad,this.CONTENT_TARGET_ATTR)){return S.getAttributeValueFromNode(ad,this.CONTENT_TARGET_ATTR)}var ab;if(S.hasNodeAttributeWithValue(ad,"href")){ab=S.getAttributeValueFromNode(ad,"href");return this.toAbsoluteUrl(ab)}var aa=this.findPieceNode(ac);if(S.hasNodeAttributeWithValue(aa,"href")){ab=S.getAttributeValueFromNode(aa,"href");return this.toAbsoluteUrl(ab)}},isSameDomain:function(aa){if(!aa||!aa.indexOf){return false}if(0===aa.indexOf(this.getLocation().origin)){return true}var ab=aa.indexOf(this.getLocation().host);if(8>=ab&&0<=ab){return true}return false},removeDomainIfIsInLink:function(ac){var ab="^https?://[^/]+";var aa="^.*//[^/]+";if(ac&&ac.search&&-1!==ac.search(new RegExp(ab))&&this.isSameDomain(ac)){ac=ac.replace(new RegExp(aa),"");if(!ac){ac="/"}}return ac},findMediaUrlInNode:function(ae){if(!ae){return
-}var ac=["img","embed","video","audio"];var aa=ae.nodeName.toLowerCase();if(-1!==D(ac,aa)&&S.findFirstNodeHavingAttributeWithValue(ae,"src")){var ad=S.findFirstNodeHavingAttributeWithValue(ae,"src");return S.getAttributeValueFromNode(ad,"src")}if(aa==="object"&&S.hasNodeAttributeWithValue(ae,"data")){return S.getAttributeValueFromNode(ae,"data")}if(aa==="object"){var af=S.findNodesByTagName(ae,"param");if(af&&af.length){var ab;for(ab=0;ab<af.length;ab++){if("movie"===S.getAttributeValueFromNode(af[ab],"name")&&S.hasNodeAttributeWithValue(af[ab],"value")){return S.getAttributeValueFromNode(af[ab],"value")}}}var ag=S.findNodesByTagName(ae,"embed");if(ag&&ag.length){return this.findMediaUrlInNode(ag[0])}}},trim:function(aa){if(aa&&String(aa)===aa){return aa.replace(/^\s+|\s+$/g,"")}return aa},isOrWasNodeInViewport:function(af){if(!af||!af.getBoundingClientRect||af.nodeType!==1){return true}var ae=af.getBoundingClientRect();var ad=x.documentElement||{};var ac=ae.top<0;if(ac&&af.offsetTop){ac=(af.offsetTop+ae.height)>0
-}var ab=ad.clientWidth;if(K.innerWidth&&ab>K.innerWidth){ab=K.innerWidth}var aa=ad.clientHeight;if(K.innerHeight&&aa>K.innerHeight){aa=K.innerHeight}return((ae.bottom>0||ac)&&ae.right>0&&ae.left<ab&&((ae.top<aa)||ac))},isNodeVisible:function(ab){var aa=h(ab);var ac=this.isOrWasNodeInViewport(ab);return aa&&ac},buildInteractionRequestParams:function(aa,ab,ac,ad){var ae="";if(aa){ae+="c_i="+n(aa)}if(ab){if(ae){ae+="&"}ae+="c_n="+n(ab)}if(ac){if(ae){ae+="&"}ae+="c_p="+n(ac)}if(ad){if(ae){ae+="&"}ae+="c_t="+n(ad)}return ae},buildImpressionRequestParams:function(aa,ab,ac){var ad="c_n="+n(aa)+"&c_p="+n(ab);if(ac){ad+="&c_t="+n(ac)}return ad},buildContentBlock:function(ac){if(!ac){return}var aa=this.findContentName(ac);var ab=this.findContentPiece(ac);var ad=this.findContentTarget(ac);aa=this.trim(aa);ab=this.trim(ab);ad=this.trim(ad);return{name:aa||"Unknown",piece:ab||"Unknown",target:ad||""}},collectContent:function(ad){if(!ad||!ad.length){return[]}var ac=[];var aa,ab;for(aa=0;aa<ad.length;
-aa++){ab=this.buildContentBlock(ad[aa]);if(A(ab)){ac.push(ab)}}return ac},setLocation:function(aa){this.location=aa},getLocation:function(){var aa=this.location||K.location;if(!aa.origin){aa.origin=aa.protocol+"//"+aa.hostname+(aa.port?":"+aa.port:"")}return aa},toAbsoluteUrl:function(ab){if((!ab||String(ab)!==ab)&&ab!==""){return ab}if(""===ab){return this.getLocation().href}if(ab.search(/^\/\//)!==-1){return this.getLocation().protocol+ab}if(ab.search(/:\/\//)!==-1){return ab}if(0===ab.indexOf("#")){return this.getLocation().origin+this.getLocation().pathname+ab}if(0===ab.indexOf("?")){return this.getLocation().origin+this.getLocation().pathname+ab}if(0===ab.search("^[a-zA-Z]{2,11}:")){return ab}if(ab.search(/^\//)!==-1){return this.getLocation().origin+ab}var aa="(.*/)";var ac=this.getLocation().origin+this.getLocation().pathname.match(new RegExp(aa))[0];return ac+ab},isUrlToCurrentDomain:function(ab){var ac=this.toAbsoluteUrl(ab);if(!ac){return false}var aa=this.getLocation().origin;
-if(aa===ac){return true}if(0===String(ac).indexOf(aa)){if(":"===String(ac).substr(aa.length,1)){return false}return true}return false},setHrefAttribute:function(ab,aa){if(!ab||!aa){return}S.setAnyAttribute(ab,"href",aa)},shouldIgnoreInteraction:function(ac){var ab=S.hasNodeAttribute(ac,this.CONTENT_IGNOREINTERACTION_ATTR);var aa=S.hasNodeCssClass(ac,this.CONTENT_IGNOREINTERACTION_CLASS);return ab||aa}};function F(ab,ae){if(ae){return ae}if(r(ab,"?")){var ad=ab.indexOf("?");ab=ab.slice(0,ad)}if(I(ab,"piwik.php")){ab=e(ab,"piwik.php".length)}else{if(I(ab,".php")){var aa=ab.lastIndexOf("/");var ac=1;ab=ab.slice(0,aa+ac)}}if(I(ab,"/js/")){ab=e(ab,"js/".length)}return ab}function E(ag){var ai="Piwik_Overlay";var ab=new RegExp("index\\.php\\?module=Overlay&action=startOverlaySession&idSite=([0-9]+)&period=([^&]+)&date=([^&]+)(&segment=.*)?$");var ac=ab.exec(x.referrer);if(ac){var ae=ac[1];if(ae!==String(ag)){return false}var af=ac[2],aa=ac[3],ad=ac[4];if(!ad){ad=""}else{if(ad.indexOf("&segment=")===0){ad=ad.substr("&segment=".length)
-}}K.name=ai+"###"+af+"###"+aa+"###"+ad}var ah=K.name.split("###");return ah.length===4&&ah[0]===ai}function P(ab,ah,ad){var ag=K.name.split("###"),af=ag[1],aa=ag[2],ae=ag[3],ac=F(ab,ah);j(ac+"plugins/Overlay/client/client.js?v=1",function(){Piwik_Overlay_Client.initialize(ac,ad,af,aa,ae)})}function o(){var ac;try{ac=K.frameElement}catch(ab){return true}if(A(ac)){return(ac&&String(ac.nodeName).toLowerCase()==="iframe")?true:false}try{return K.self!==K.top}catch(aa){return true}}function H(bI,bC){var by=Q(x.domain,K.location.href,B()),ch=C(by[0]),bi=k(by[1]),aX=k(by[2]),cf=false,bM="GET",ct=bM,ao="application/x-www-form-urlencoded; charset=UTF-8",bY=ao,ak=bI||"",bd="",cl="",bA=bC||"",a6="",bj="",aI,aT="",cq=["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"],ag=[ch],a7=[],bg=[],aL=[],be=500,b8,aJ,bm,bk,aa,bU=["pk_campaign","piwik_campaign","utm_campaign","utm_source","utm_medium"],bc=["pk_kwd","piwik_kwd","utm_term"],aU="_pk_",cj,aZ,aV=false,cd,aR,a3,b9=33955200000,bS=1800000,cp=15768000000,aG=true,bQ=0,bl=false,av=false,bF,bq={},bP={},aW={},a2=200,cm={},cr={},bE=[],bJ=false,b2=false,ab=false,cs=false,at=false,aQ=o(),ck=null,bG,aw,a8,bB=X,aY;
-try{aT=x.title}catch(b0){aT=""}function cw(cG,cD,cC,cF,cB,cE){if(aV){return}var cA;if(cC){cA=new Date();cA.setTime(cA.getTime()+cC)}x.cookie=cG+"="+n(cD)+(cC?";expires="+cA.toGMTString():"")+";path="+(cF||"/")+(cB?";domain="+cB:"")+(cE?";secure":"")}function aj(cC){if(aV){return 0}var cA=new RegExp("(^|;)[ ]*"+cC+"=([^;]*)"),cB=cA.exec(x.cookie);return cB?J(cB[2]):0}function bw(cA){var cB;if(bk){cB=new RegExp("#.*");return cA.replace(cB,"")}return cA}function bp(cC,cA){var cD=m(cA),cB;if(cD){return cA}if(cA.slice(0,1)==="/"){return m(cC)+"://"+c(cC)+cA}cC=bw(cC);cB=cC.indexOf("?");if(cB>=0){cC=cC.slice(0,cB)}cB=cC.lastIndexOf("/");if(cB!==cC.length-1){cC=cC.slice(0,cB+1)}return cC+cA}function b6(cC,cA){var cB;cC=String(cC).toLowerCase();cA=String(cA).toLowerCase();if(cC===cA){return true}if(cA.slice(0,1)==="."){if(cC===cA.slice(1)){return true}cB=cC.length-cA.length;if((cB>0)&&(cC.slice(cB)===cA)){return true}}return false}function bO(cA){var cB=document.createElement("a");if(cA.indexOf("//")!==0&&cA.indexOf("http")!==0){if(cA.indexOf("*")===0){cA=cA.substr(1)
-}if(cA.indexOf(".")===0){cA=cA.substr(1)}cA="http://"+cA}cB.href=p.toAbsoluteUrl(cA);if(cB.pathname){return cB.pathname}return""}function aH(cB,cA){if(!V(cA,"/")){cA="/"+cA}if(!V(cB,"/")){cB="/"+cB}var cC=(cA==="/"||cA==="/*");if(cC){return true}if(cB===cA){return true}cA=String(cA).toLowerCase();cB=String(cB).toLowerCase();if(I(cA,"*")){cA=cA.slice(0,-1);cC=(!cA||cA==="/");if(cC){return true}if(cB===cA){return true}return cB.indexOf(cA)===0}if(!I(cB,"/")){cB+="/"}if(!I(cA,"/")){cA+="/"}return cB.indexOf(cA)===0}function ad(cE,cG){var cB,cA,cC,cD,cF;for(cB=0;cB<ag.length;cB++){cD=C(ag[cB]);cF=bO(ag[cB]);if(b6(cE,cD)&&aH(cG,cF)){return true}}return false}function aA(cD){var cB,cA,cC;for(cB=0;cB<ag.length;cB++){cA=C(ag[cB].toLowerCase());if(cD===cA){return true}if(cA.slice(0,1)==="."){if(cD===cA.slice(1)){return true}cC=cD.length-cA.length;if((cC>0)&&(cD.slice(cC)===cA)){return true}}}return false}function bT(cA,cC){var cB=new Image(1,1);cB.onload=function(){w=0;if(typeof cC==="function"){cC()
-}};cA=cA.replace("send_image=0","send_image=1");cB.src=ak+(ak.indexOf("?")<0?"?":"&")+cA}function co(cB,cE,cA){if(!A(cA)||null===cA){cA=true}try{var cD=K.XMLHttpRequest?new K.XMLHttpRequest():K.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):null;cD.open("POST",ak,true);cD.onreadystatechange=function(){if(this.readyState===4&&!(this.status>=200&&this.status<300)&&cA){bT(cB,cE)}else{if(this.readyState===4&&(typeof cE==="function")){cE()}}};cD.setRequestHeader("Content-Type",bY);cD.send(cB)}catch(cC){if(cA){bT(cB,cE)}}}function bK(cB){var cA=new Date();var cC=cA.getTime()+cB;if(!l||cC>l){l=cC}}function bR(cA){if(bG||!aJ){return}bG=setTimeout(function cB(){bG=null;if(!aQ){aQ=(!x.hasFocus||x.hasFocus())}if(!aQ){bR(aJ);return}if(bm()){return}var cC=new Date(),cD=aJ-(cC.getTime()-ck);cD=Math.min(aJ,cD);bR(cD)},cA||aJ)}function bf(){if(!bG){return}clearTimeout(bG);bG=null}function aN(){aQ=true;if(bm()){return}bR()}function ah(){bf()}function cy(){if(at||!aJ){return}at=true;Y(K,"focus",aN);
-Y(K,"blur",ah);bR()}function b3(cE){var cB=new Date();var cA=cB.getTime();ck=cA;if(b2&&cA<b2){var cC=b2-cA;setTimeout(cE,cC);bK(cC+50);b2+=50;return}if(b2===false){var cD=800;b2=cA+cD}cE()}function bb(cB,cA,cC){if(!cd&&cB){b3(function(){if(ct==="POST"){co(cB,cC)}else{bT(cB,cC)}bK(cA)})}if(!at){cy()}else{bR()}}function bN(cA){if(cd){return false}return(cA&&cA.length)}function cx(cC,cA){if(!bN(cC)){return}var cB='{"requests":["?'+cC.join('","?')+'"]}';b3(function(){co(cB,null,false);bK(cA)})}function ay(cA){return aU+cA+"."+bA+"."+aY}function bz(){if(aV){return"0"}if(!A(f.cookieEnabled)){var cA=ay("testcookie");cw(cA,"1");return aj(cA)==="1"?"1":"0"}return f.cookieEnabled?"1":"0"}function aS(){aY=bB((cj||ch)+(aZ||"/")).slice(0,4)}function br(){var cB=ay("cvar"),cA=aj(cB);if(cA.length){cA=JSON2.parse(cA);if(N(cA)){return cA}}return{}}function b4(){if(av===false){av=br()}}function ce(){return bB((f.userAgent||"")+(f.platform||"")+JSON2.stringify(cr)+(new Date()).getTime()+Math.random()).slice(0,16)
-}function cb(){var cC=new Date(),cA=Math.round(cC.getTime()/1000),cB=ay("id"),cF=aj(cB),cE,cD;if(cF){cE=cF.split(".");cE.unshift("0");if(bj.length){cE[1]=bj}return cE}if(bj.length){cD=bj}else{if("0"===bz()){cD=""}else{cD=ce()}}cE=["1",cD,cA,0,cA,"",""];return cE}function aC(){var cH=cb(),cD=cH[0],cE=cH[1],cB=cH[2],cA=cH[3],cF=cH[4],cC=cH[5];if(!A(cH[6])){cH[6]=""}var cG=cH[6];return{newVisitor:cD,uuid:cE,createTs:cB,visitCount:cA,currentVisitTs:cF,lastVisitTs:cC,lastEcommerceOrderTs:cG}}function an(){var cD=new Date(),cB=cD.getTime(),cE=aC().createTs;var cA=parseInt(cE,10);var cC=(cA*1000)+b9-cB;return cC}function aq(cA){if(!bA){return}var cC=new Date(),cB=Math.round(cC.getTime()/1000);if(!A(cA)){cA=aC()}var cD=cA.uuid+"."+cA.createTs+"."+cA.visitCount+"."+cB+"."+cA.lastVisitTs+"."+cA.lastEcommerceOrderTs;cw(ay("id"),cD,an(),aZ,cj)}function bh(){var cA=aj(ay("ref"));if(cA.length){try{cA=JSON2.parse(cA);if(N(cA)){return cA}}catch(cB){}}return["","",0,""]}function bs(cC,cB,cA){cw(cC,"",-86400,cB,cA)
-}function a4(cB){var cA="testvalue";cw("test",cA,10000,null,cB);if(aj("test")===cA){bs("test",null,cB);return true}return false}function al(){var cC=aV;aV=false;var cA=["id","ses","cvar","ref"];var cB,cD;for(cB=0;cB<cA.length;cB++){cD=ay(cA[cB]);if(0!==aj(cD)){bs(cD,aZ,cj)}}aV=cC}function bx(cA){bA=cA;aq()}function cz(cE){if(!cE||!N(cE)){return}var cD=[];var cC;for(cC in cE){if(Object.prototype.hasOwnProperty.call(cE,cC)){cD.push(cC)}}var cF={};cD.sort();var cA=cD.length;var cB;for(cB=0;cB<cA;cB++){cF[cD[cB]]=cE[cD[cB]]}return cF}function bH(){cw(ay("ses"),"*",bS,aZ,cj)}function bV(cC,cX,cY,cD){var cW,cB=new Date(),cK=Math.round(cB.getTime()/1000),cH,cV,cE=1024,c3,cL,cT=av,cF=ay("ses"),cR=ay("ref"),cO=ay("cvar"),cP=aj(cF),cU=bh(),c0=aI||bi,cI,cA;if(aV){al()}if(cd){return""}var cQ=aC();if(!A(cD)){cD=""}var cN=x.characterSet||x.charset;if(!cN||cN.toLowerCase()==="utf-8"){cN=null}cI=cU[0];cA=cU[1];cH=cU[2];cV=cU[3];if(!cP){var cZ=bS/1000;if(!cQ.lastVisitTs||(cK-cQ.lastVisitTs)>cZ){cQ.visitCount++;
-cQ.lastVisitTs=cQ.currentVisitTs}if(!a3||!cI.length){for(cW in bU){if(Object.prototype.hasOwnProperty.call(bU,cW)){cI=M(c0,bU[cW]);if(cI.length){break}}}for(cW in bc){if(Object.prototype.hasOwnProperty.call(bc,cW)){cA=M(c0,bc[cW]);if(cA.length){break}}}}c3=c(aX);cL=cV.length?c(cV):"";if(c3.length&&!aA(c3)&&(!a3||!cL.length||aA(cL))){cV=aX}if(cV.length||cI.length){cH=cK;cU=[cI,cA,cH,bw(cV.slice(0,cE))];cw(cR,JSON2.stringify(cU),cp,aZ,cj)}}cC+="&idsite="+bA+"&rec=1&r="+String(Math.random()).slice(2,8)+"&h="+cB.getHours()+"&m="+cB.getMinutes()+"&s="+cB.getSeconds()+"&url="+n(bw(c0))+(aX.length?"&urlref="+n(bw(aX)):"")+((a6&&a6.length)?"&uid="+n(a6):"")+"&_id="+cQ.uuid+"&_idts="+cQ.createTs+"&_idvc="+cQ.visitCount+"&_idn="+cQ.newVisitor+(cI.length?"&_rcn="+n(cI):"")+(cA.length?"&_rck="+n(cA):"")+"&_refts="+cH+"&_viewts="+cQ.lastVisitTs+(String(cQ.lastEcommerceOrderTs).length?"&_ects="+cQ.lastEcommerceOrderTs:"")+(String(cV).length?"&_ref="+n(bw(cV.slice(0,cE))):"")+(cN?"&cs="+n(cN):"")+"&send_image=0";
-for(cW in cr){if(Object.prototype.hasOwnProperty.call(cr,cW)){cC+="&"+cW+"="+cr[cW]}}var c2=[];if(cX){for(cW in cX){if(Object.prototype.hasOwnProperty.call(cX,cW)&&/^dimension\d+$/.test(cW)){var cG=cW.replace("dimension","");c2.push(parseInt(cG,10));c2.push(String(cG));cC+="&"+cW+"="+cX[cW];delete cX[cW]}}}if(cX&&t(cX)){cX=null}for(cW in aW){if(Object.prototype.hasOwnProperty.call(aW,cW)){var cM=(-1===D(c2,cW));if(cM){cC+="&dimension"+cW+"="+aW[cW]}}}if(cX){cC+="&data="+n(JSON2.stringify(cX))}else{if(aa){cC+="&data="+n(JSON2.stringify(aa))}}function cJ(c4,c5){var c6=JSON2.stringify(c4);if(c6.length>2){return"&"+c5+"="+n(c6)}return""}var c1=cz(bq);var cS=cz(bP);cC+=cJ(c1,"cvar");cC+=cJ(cS,"e_cvar");if(av){cC+=cJ(av,"_cvar");for(cW in cT){if(Object.prototype.hasOwnProperty.call(cT,cW)){if(av[cW][0]===""||av[cW][1]===""){delete av[cW]}}}if(bl){cw(cO,JSON2.stringify(av),bS,aZ,cj)}}if(aG){if(bQ){cC+="&gt_ms="+bQ}else{if(g&&g.timing&&g.timing.requestStart&&g.timing.responseEnd){cC+="&gt_ms="+(g.timing.responseEnd-g.timing.requestStart)
-}}}cQ.lastEcommerceOrderTs=A(cD)&&String(cD).length?cD:cQ.lastEcommerceOrderTs;aq(cQ);bH();cC+=R(cY);if(cl.length){cC+="&"+cl}if(s(bF)){cC=bF(cC)}return cC}bm=function aK(){var cA=new Date();if(ck+aJ<=cA.getTime()){var cB=bV("ping=1",null,"ping");bb(cB,be);return true}return false};function a0(cD,cC,cI,cE,cA,cL){var cG="idgoal=0",cH,cB=new Date(),cJ=[],cK,cF=String(cD).length;if(cF){cG+="&ec_id="+n(cD);cH=Math.round(cB.getTime()/1000)}cG+="&revenue="+cC;if(String(cI).length){cG+="&ec_st="+cI}if(String(cE).length){cG+="&ec_tx="+cE}if(String(cA).length){cG+="&ec_sh="+cA}if(String(cL).length){cG+="&ec_dt="+cL}if(cm){for(cK in cm){if(Object.prototype.hasOwnProperty.call(cm,cK)){if(!A(cm[cK][1])){cm[cK][1]=""}if(!A(cm[cK][2])){cm[cK][2]=""}if(!A(cm[cK][3])||String(cm[cK][3]).length===0){cm[cK][3]=0}if(!A(cm[cK][4])||String(cm[cK][4]).length===0){cm[cK][4]=1}cJ.push(cm[cK])}}cG+="&ec_items="+n(JSON2.stringify(cJ))}cG=bV(cG,aa,"ecommerce",cH);bb(cG,be);if(cF){cm={}}}function bt(cA,cE,cD,cC,cB,cF){if(String(cA).length&&A(cE)){a0(cA,cE,cD,cC,cB,cF)
-}}function a1(cA){if(A(cA)){a0("",cA,"","","","")}}function bu(cB,cD,cC){var cA=bV("action_name="+n(Z(cB||aT)),cD,"log");bb(cA,be,cC)}function aE(cC,cB){var cD,cA="(^| )(piwik[_-]"+cB;if(cC){for(cD=0;cD<cC.length;cD++){cA+="|"+cC[cD]}}cA+=")( |$)";return new RegExp(cA)}function az(cA){return(ak&&cA&&0===String(cA).indexOf(ak))}function bW(cE,cA,cF,cB){if(az(cA)){return 0}var cD=aE(bg,"download"),cC=aE(aL,"link"),cG=new RegExp("\\.("+cq.join("|")+")([?&#]|$)","i");if(cC.test(cE)){return"link"}if(cB||cD.test(cE)||cG.test(cA)){return"download"}if(cF){return 0}return"link"}function ae(cB){var cA;cA=cB.parentNode;while(cA!==null&&A(cA)){if(S.isLinkElement(cB)){break}cB=cA;cA=cB.parentNode}return cB}function cu(cF){cF=ae(cF);if(!S.hasNodeAttribute(cF,"href")){return}if(!A(cF.href)){return}var cE=S.getAttributeValueFromNode(cF,"href");if(az(cE)){return}var cB=cF.pathname||bO(cF.href);var cG=cF.hostname||c(cF.href);var cH=cG.toLowerCase();var cC=cF.href.replace(cG,cH);var cD=new RegExp("^(javascript|vbscript|jscript|mocha|livescript|ecmascript|mailto|tel):","i");
-if(!cD.test(cC)){var cA=bW(cF.className,cC,ad(cH,cB),S.hasNodeAttribute(cF,"download"));if(cA){return{type:cA,href:cC}}}}function au(cA,cB,cC,cD){var cE=p.buildInteractionRequestParams(cA,cB,cC,cD);if(!cE){return}return bV(cE,null,"contentInteraction")}function ca(cC,cD,cH,cA,cB){if(!A(cC)){return}if(az(cC)){return cC}var cF=p.toAbsoluteUrl(cC);var cE="redirecturl="+n(cF)+"&";cE+=au(cD,cH,cA,(cB||cC));var cG="&";if(ak.indexOf("?")<0){cG="?"}return ak+cG+cE}function aO(cA,cB){if(!cA||!cB){return false}var cC=p.findTargetNode(cA);if(p.shouldIgnoreInteraction(cC)){return false}cC=p.findTargetNodeNoDefault(cA);if(cC&&!L(cC,cB)){return false}return true}function bX(cC,cB,cE){if(!cC){return}var cA=p.findParentContentNode(cC);if(!cA){return}if(!aO(cA,cC)){return}var cD=p.buildContentBlock(cA);if(!cD){return}if(!cD.target&&cE){cD.target=cE}return p.buildInteractionRequestParams(cB,cD.name,cD.piece,cD.target)}function aB(cB){if(!bE||!bE.length){return false}var cA,cC;for(cA=0;cA<bE.length;cA++){cC=bE[cA];
-if(cC&&cC.name===cB.name&&cC.piece===cB.piece&&cC.target===cB.target){return true}}return false}function ba(cD){if(!cD){return false}var cG=p.findTargetNode(cD);if(!cG||p.shouldIgnoreInteraction(cG)){return false}var cH=cu(cG);if(cs&&cH&&cH.type){return false}if(S.isLinkElement(cG)&&S.hasNodeAttributeWithValue(cG,"href")){var cA=String(S.getAttributeValueFromNode(cG,"href"));if(0===cA.indexOf("#")){return false}if(az(cA)){return true}if(!p.isUrlToCurrentDomain(cA)){return false}var cE=p.buildContentBlock(cD);if(!cE){return}var cC=cE.name;var cI=cE.piece;var cF=cE.target;if(!S.hasNodeAttributeWithValue(cG,p.CONTENT_TARGET_ATTR)||cG.wasContentTargetAttrReplaced){cG.wasContentTargetAttrReplaced=true;cF=p.toAbsoluteUrl(cA);S.setAnyAttribute(cG,p.CONTENT_TARGET_ATTR,cF)}var cB=ca(cA,"click",cC,cI,cF);p.setHrefAttribute(cG,cB);return true}return false}function ar(cB){if(!cB||!cB.length){return}var cA;for(cA=0;cA<cB.length;cA++){ba(cB[cA])}}function aD(cA){return function(cB){if(!cA){return}var cE=p.findParentContentNode(cA);
-var cF;if(cB){cF=cB.target||cB.srcElement}if(!cF){cF=cA}if(!aO(cE,cF)){return}bK(be);if(S.isLinkElement(cA)&&S.hasNodeAttributeWithValue(cA,"href")&&S.hasNodeAttributeWithValue(cA,p.CONTENT_TARGET_ATTR)){var cC=S.getAttributeValueFromNode(cA,"href");if(!az(cC)&&cA.wasContentTargetAttrReplaced){S.setAnyAttribute(cA,p.CONTENT_TARGET_ATTR,"")}}var cJ=cu(cA);if(ab&&cJ&&cJ.type){return cJ.type}if(ba(cE)){return"href"}var cG=p.buildContentBlock(cE);if(!cG){return}var cD=cG.name;var cK=cG.piece;var cI=cG.target;var cH=au("click",cD,cK,cI);bb(cH,be);return cH}}function bv(cC){if(!cC||!cC.length){return}var cA,cB;for(cA=0;cA<cC.length;cA++){cB=p.findTargetNode(cC[cA]);if(cB&&!cB.contentInteractionTrackingSetupDone){cB.contentInteractionTrackingSetupDone=true;Y(cB,"click",aD(cB))}}}function a5(cC,cD){if(!cC||!cC.length){return[]}var cA,cB;for(cA=0;cA<cC.length;cA++){if(aB(cC[cA])){cC.splice(cA,1);cA--}else{bE.push(cC[cA])}}if(!cC||!cC.length){return[]}ar(cD);bv(cD);var cE=[];for(cA=0;cA<cC.length;
-cA++){cB=bV(p.buildImpressionRequestParams(cC[cA].name,cC[cA].piece,cC[cA].target),undefined,"contentImpressions");if(cB){cE.push(cB)}}return cE}function b1(cB){var cA=p.collectContent(cB);return a5(cA,cB)}function aM(cB){if(!cB||!cB.length){return[]}var cA;for(cA=0;cA<cB.length;cA++){if(!p.isNodeVisible(cB[cA])){cB.splice(cA,1);cA--}}if(!cB||!cB.length){return[]}return b1(cB)}function am(cC,cA,cB){var cD=p.buildImpressionRequestParams(cC,cA,cB);return bV(cD,null,"contentImpression")}function cv(cD,cB){if(!cD){return}var cA=p.findParentContentNode(cD);var cC=p.buildContentBlock(cA);if(!cC){return}if(!cB){cB="Unknown"}return au(cB,cC.name,cC.piece,cC.target)}function cc(cB,cD,cA,cC){return"e_c="+n(cB)+"&e_a="+n(cD)+(A(cA)?"&e_n="+n(cA):"")+(A(cC)?"&e_v="+n(cC):"")}function af(cC,cE,cA,cD,cF){if(String(cC).length===0||String(cE).length===0){return false}var cB=bV(cc(cC,cE,cA,cD),cF,"event");bb(cB,be)}function bD(cA,cD,cB,cE){var cC=bV("search="+n(cA)+(cD?"&search_cat="+n(cD):"")+(A(cB)?"&search_count="+cB:""),cE,"sitesearch");
-bb(cC,be)}function cg(cA,cD,cC){var cB=bV("idgoal="+cA+(cD?"&revenue="+cD:""),cC,"goal");bb(cB,be)}function cn(cD,cA,cH,cG,cC){var cF=cA+"="+n(bw(cD));var cB=bX(cC,"click",cD);if(cB){cF+="&"+cB}var cE=bV(cF,cH,"link");bb(cE,(cG?0:be),cG)}function bn(cB,cA){if(cB!==""){return cB+cA.charAt(0).toUpperCase()+cA.slice(1)}return cA}function bL(cF){var cE,cA,cD=["","webkit","ms","moz"],cC;if(!aR){for(cA=0;cA<cD.length;cA++){cC=cD[cA];if(Object.prototype.hasOwnProperty.call(x,bn(cC,"hidden"))){if(x[bn(cC,"visibilityState")]==="prerender"){cE=true}break}}}if(cE){Y(x,cC+"visibilitychange",function cB(){x.removeEventListener(cC+"visibilitychange",cB,false);cF()});return}cF()}function ap(cA){if(x.readyState==="complete"){cA()}else{if(K.addEventListener){K.addEventListener("load",cA)}else{if(K.attachEvent){K.attachEvent("onload",cA)}}}}function aP(cD){var cA=false;if(x.attachEvent){cA=x.readyState==="complete"}else{cA=x.readyState!=="loading"}if(cA){cD();return}var cC;if(x.addEventListener){Y(x,"DOMContentLoaded",function cB(){x.removeEventListener("DOMContentLoaded",cB,false);
-if(!cA){cA=true;cD()}})}else{if(x.attachEvent){x.attachEvent("onreadystatechange",function cB(){if(x.readyState==="complete"){x.detachEvent("onreadystatechange",cB);if(!cA){cA=true;cD()}}});if(x.documentElement.doScroll&&K===K.top){(function cB(){if(!cA){try{x.documentElement.doScroll("left")}catch(cE){setTimeout(cB,0);return}cA=true;cD()}}())}}}Y(K,"load",function(){if(!cA){cA=true;cD()}},false)}function b7(cA){var cB=cu(cA);if(cB&&cB.type){cB.href=k(cB.href);cn(cB.href,cB.type,undefined,null,cA)}}function bZ(){return x.all&&!x.addEventListener}function ci(cA){var cC=cA.which;var cB=(typeof cA.button);if(!cC&&cB!=="undefined"){if(bZ()){if(cA.button&1){cC=1}else{if(cA.button&2){cC=3}else{if(cA.button&4){cC=2}}}}else{if(cA.button===0||cA.button==="0"){cC=1}else{if(cA.button&1){cC=2}else{if(cA.button&2){cC=3}}}}}return cC}function bo(cA){switch(ci(cA)){case 1:return"left";case 2:return"middle";case 3:return"right"}}function aF(cA){return cA.target||cA.srcElement}function ai(cA){return function(cD){cD=cD||K.event;
-var cC=bo(cD);var cE=aF(cD);if(cD.type==="click"){var cB=false;if(cA&&cC==="middle"){cB=true}if(cE&&!cB){b7(cE)}}else{if(cD.type==="mousedown"){if(cC==="middle"&&cE){aw=cC;a8=cE}else{aw=a8=null}}else{if(cD.type==="mouseup"){if(cC===aw&&cE===a8){b7(cE)}aw=a8=null}else{if(cD.type==="contextmenu"){b7(cE)}}}}}}function ac(cB,cA){Y(cB,"click",ai(cA),false);if(cA){Y(cB,"mouseup",ai(cA),false);Y(cB,"mousedown",ai(cA),false);Y(cB,"contextmenu",ai(cA),false)}}function a9(cB){if(!ab){ab=true;var cC,cA=aE(a7,"ignore"),cD=x.links;if(cD){for(cC=0;cC<cD.length;cC++){if(!cA.test(cD[cC].className)){ac(cD[cC],cB)}}}}}function ax(cC,cE,cF){if(bJ){return true}bJ=true;var cG=false;var cD,cB;function cA(){cG=true}ap(function(){function cH(cJ){setTimeout(function(){if(!bJ){return}cG=false;cF.trackVisibleContentImpressions();cH(cJ)},cJ)}function cI(cJ){setTimeout(function(){if(!bJ){return}if(cG){cG=false;cF.trackVisibleContentImpressions()}cI(cJ)},cJ)}if(cC){cD=["scroll","resize"];for(cB=0;cB<cD.length;cB++){if(x.addEventListener){x.addEventListener(cD[cB],cA)
-}else{K.attachEvent("on"+cD[cB],cA)}}cI(100)}if(cE&&cE>0){cE=parseInt(cE,10);cH(cE)}})}function b5(){var cB,cD,cE={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"};if(!((new RegExp("MSIE")).test(f.userAgent))){if(f.mimeTypes&&f.mimeTypes.length){for(cB in cE){if(Object.prototype.hasOwnProperty.call(cE,cB)){cD=f.mimeTypes[cE[cB]];cr[cB]=(cD&&cD.enabledPlugin)?"1":"0"}}}if(typeof navigator.javaEnabled!=="unknown"&&A(f.javaEnabled)&&f.javaEnabled()){cr.java="1"}if(s(K.GearsFactory)){cr.gears="1"}cr.cookie=bz()}var cC=parseInt(O.width,10);var cA=parseInt(O.height,10);cr.res=parseInt(cC,10)+"x"+parseInt(cA,10)}b5();aS();aq();return{getVisitorId:function(){return aC().uuid},getVisitorInfo:function(){return cb()},getAttributionInfo:function(){return bh()},getAttributionCampaignName:function(){return bh()[0]
-},getAttributionCampaignKeyword:function(){return bh()[1]},getAttributionReferrerTimestamp:function(){return bh()[2]},getAttributionReferrerUrl:function(){return bh()[3]},setTrackerUrl:function(cA){ak=cA},getTrackerUrl:function(){return ak},addTracker:function(cA,cC){if(!cC){throw new Error("A siteId must be given to add a new tracker")}if(!A(cA)||null===cA){cA=this.getTrackerUrl()}var cB=new H(cA,cC);z.push(cB);return cB},getSiteId:function(){return bA},setSiteId:function(cA){bx(cA)},setUserId:function(cA){if(!A(cA)||!cA.length){return}a6=cA;bj=bB(a6).substr(0,16)},getUserId:function(){return a6},setCustomData:function(cA,cB){if(N(cA)){aa=cA}else{if(!aa){aa={}}aa[cA]=cB}},getCustomData:function(){return aa},setCustomRequestProcessing:function(cA){bF=cA},appendToTrackingUrl:function(cA){cl=cA},getRequest:function(cA){return bV(cA)},addPlugin:function(cA,cB){a[cA]=cB},setCustomDimension:function(cA,cB){cA=parseInt(cA,10);if(cA>0){if(!A(cB)){cB=""}if(!q(cB)){cB=String(cB)}aW[cA]=cB}},getCustomDimension:function(cA){cA=parseInt(cA,10);
-if(cA>0&&Object.prototype.hasOwnProperty.call(aW,cA)){return aW[cA]}},deleteCustomDimension:function(cA){cA=parseInt(cA,10);if(cA>0){delete aW[cA]}},setCustomVariable:function(cB,cA,cE,cC){var cD;if(!A(cC)){cC="visit"}if(!A(cA)){return}if(!A(cE)){cE=""}if(cB>0){cA=!q(cA)?String(cA):cA;cE=!q(cE)?String(cE):cE;cD=[cA.slice(0,a2),cE.slice(0,a2)];if(cC==="visit"||cC===2){b4();av[cB]=cD}else{if(cC==="page"||cC===3){bq[cB]=cD}else{if(cC==="event"){bP[cB]=cD}}}}},getCustomVariable:function(cB,cC){var cA;if(!A(cC)){cC="visit"}if(cC==="page"||cC===3){cA=bq[cB]}else{if(cC==="event"){cA=bP[cB]}else{if(cC==="visit"||cC===2){b4();cA=av[cB]}}}if(!A(cA)||(cA&&cA[0]==="")){return false}return cA},deleteCustomVariable:function(cA,cB){if(this.getCustomVariable(cA,cB)){this.setCustomVariable(cA,"","",cB)}},storeCustomVariablesInCookie:function(){bl=true},setLinkTrackingTimer:function(cA){be=cA},setDownloadExtensions:function(cA){if(q(cA)){cA=cA.split("|")}cq=cA},addDownloadExtensions:function(cB){var cA;if(q(cB)){cB=cB.split("|")
-}for(cA=0;cA<cB.length;cA++){cq.push(cB[cA])}},removeDownloadExtensions:function(cC){var cB,cA=[];if(q(cC)){cC=cC.split("|")}for(cB=0;cB<cq.length;cB++){if(D(cC,cq[cB])===-1){cA.push(cq[cB])}}cq=cA},setDomains:function(cA){ag=q(cA)?[cA]:cA;var cE=false,cC=0,cB;for(cC;cC<ag.length;cC++){cB=String(ag[cC]);if(b6(ch,C(cB))){cE=true;break}var cD=bO(cB);if(cD&&cD!=="/"&&cD!=="/*"){cE=true;break}}if(!cE){ag.push(ch)}},setIgnoreClasses:function(cA){a7=q(cA)?[cA]:cA},setRequestMethod:function(cA){ct=cA||bM},setRequestContentType:function(cA){bY=cA||ao},setReferrerUrl:function(cA){aX=cA},setCustomUrl:function(cA){aI=bp(bi,cA)},setDocumentTitle:function(cA){aT=cA},setAPIUrl:function(cA){bd=cA},setDownloadClasses:function(cA){bg=q(cA)?[cA]:cA},setLinkClasses:function(cA){aL=q(cA)?[cA]:cA},setCampaignNameKey:function(cA){bU=q(cA)?[cA]:cA},setCampaignKeywordKey:function(cA){bc=q(cA)?[cA]:cA},discardHashTag:function(cA){bk=cA},setCookieNamePrefix:function(cA){aU=cA;av=br()},setCookieDomain:function(cA){var cB=C(cA);
-if(a4(cB)){cj=cB;aS()}},setCookiePath:function(cA){aZ=cA;aS()},setVisitorCookieTimeout:function(cA){b9=cA*1000},setSessionCookieTimeout:function(cA){bS=cA*1000},setReferralCookieTimeout:function(cA){cp=cA*1000},setConversionAttributionFirstReferrer:function(cA){a3=cA},disableCookies:function(){aV=true;cr.cookie="0";if(bA){al()}},deleteCookies:function(){al()},setDoNotTrack:function(cB){var cA=f.doNotTrack||f.msDoNotTrack;cd=cB&&(cA==="yes"||cA==="1");if(cd){this.disableCookies()}},addListener:function(cB,cA){ac(cB,cA)},enableLinkTracking:function(cA){cs=true;bL(function(){aP(function(){a9(cA)})})},enableJSErrorTracking:function(){if(cf){return}cf=true;var cA=K.onerror;K.onerror=function(cF,cD,cC,cE,cB){bL(function(){var cG="JavaScript Errors";var cH=cD+":"+cC;if(cE){cH+=":"+cE}af(cG,cH,cF)});if(cA){return cA(cF,cD,cC,cE,cB)}return false}},disablePerformanceTracking:function(){aG=false},setGenerationTimeMs:function(cA){bQ=parseInt(cA,10)},enableHeartBeatTimer:function(cA){cA=Math.max(cA,1);
-aJ=(cA||15)*1000;if(ck!==null){cy()}},killFrame:function(){if(K.location!==K.top.location){K.top.location=K.location}},redirectFile:function(cA){if(K.location.protocol==="file:"){K.location=cA}},setCountPreRendered:function(cA){aR=cA},trackGoal:function(cA,cC,cB){bL(function(){cg(cA,cC,cB)})},trackLink:function(cB,cA,cD,cC){bL(function(){cn(cB,cA,cD,cC)})},trackPageView:function(cA,cC,cB){bE=[];if(E(bA)){bL(function(){P(ak,bd,bA)})}else{bL(function(){bu(cA,cC,cB)})}},trackAllContentImpressions:function(){if(E(bA)){return}bL(function(){aP(function(){var cA=p.findContentNodes();var cB=b1(cA);cx(cB,be)})})},trackVisibleContentImpressions:function(cA,cB){if(E(bA)){return}if(!A(cA)){cA=true}if(!A(cB)){cB=750}ax(cA,cB,this);bL(function(){ap(function(){var cC=p.findContentNodes();var cD=aM(cC);cx(cD,be)})})},trackContentImpression:function(cC,cA,cB){if(E(bA)){return}if(!cC){return}cA=cA||"Unknown";bL(function(){var cD=am(cC,cA,cB);bb(cD,be)})},trackContentImpressionsWithinNode:function(cA){if(E(bA)||!cA){return
-}bL(function(){if(bJ){ap(function(){var cB=p.findContentNodesWithinNode(cA);var cC=aM(cB);cx(cC,be)})}else{aP(function(){var cB=p.findContentNodesWithinNode(cA);var cC=b1(cB);cx(cC,be)})}})},trackContentInteraction:function(cC,cD,cA,cB){if(E(bA)){return}if(!cC||!cD){return}cA=cA||"Unknown";bL(function(){var cE=au(cC,cD,cA,cB);bb(cE,be)})},trackContentInteractionNode:function(cB,cA){if(E(bA)||!cB){return}bL(function(){var cC=cv(cB,cA);bb(cC,be)})},logAllContentBlocksOnPage:function(){var cB=p.findContentNodes();var cA=p.collectContent(cB);if(console!==undefined&&console&&console.log){console.log(cA)}},trackEvent:function(cB,cD,cA,cC,cE){bL(function(){af(cB,cD,cA,cC,cE)})},trackSiteSearch:function(cA,cC,cB,cD){bL(function(){bD(cA,cC,cB,cD)})},setEcommerceView:function(cD,cA,cC,cB){if(!A(cC)||!cC.length){cC=""}else{if(cC instanceof Array){cC=JSON2.stringify(cC)}}bq[5]=["_pkc",cC];if(A(cB)&&String(cB).length){bq[2]=["_pkp",cB]}if((!A(cD)||!cD.length)&&(!A(cA)||!cA.length)){return}if(A(cD)&&cD.length){bq[3]=["_pks",cD]
-}if(!A(cA)||!cA.length){cA=""}bq[4]=["_pkn",cA]},addEcommerceItem:function(cE,cA,cC,cB,cD){if(cE.length){cm[cE]=[cE,cA,cC,cB,cD]}},trackEcommerceOrder:function(cA,cE,cD,cC,cB,cF){bt(cA,cE,cD,cC,cB,cF)},trackEcommerceCartUpdate:function(cA){a1(cA)}}}function y(){return{push:T}}function b(af,ae){var ag={};var ac,ad;for(ac=0;ac<ae.length;ac++){var aa=ae[ac];ag[aa]=1;for(ad=0;ad<af.length;ad++){if(af[ad]&&af[ad][0]){var ab=af[ad][0];if(aa===ab){T(af[ad]);delete af[ad];if(ag[ab]>1){W("The method "+ab+' 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')}ag[ab]++}}}}return af}Y(K,"beforeunload",U,false);Date.prototype.getTimeAlias=Date.prototype.getTime;z.push(new H());var u=["addTracker","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(aa,ab){a[aa]=ab},getTracker:function(aa,ab){if(!A(ab)){ab=this.getAsyncTracker().getSiteId()}if(!A(aa)){aa=this.getAsyncTracker().getTrackerUrl()}return new H(aa,ab)},getAsyncTracker:function(ab,ae){var ad;if(z&&z[0]){ad=z[0]}if(!ae&&!ab){return ad}if((!A(ae)||null===ae)&&ad){ae=ad.getSiteId()}if((!A(ab)||null===ab)&&ad){ab=ad.getTrackerUrl()}var ac,aa=0;for(aa;aa<z.length;aa++){ac=z[aa];if(ac&&String(ac.getSiteId())===String(ae)&&ac.getTrackerUrl()===ab){return ac}}}};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()}};
+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={},r={},y=document,f=navigator,P=screen,L=window,g=L.performance||L.mozPerformance||L.msPerformance||L.webkitPerformance,n=L.encodeURIComponent,K=L.decodeURIComponent,i=unescape,A=[],x,d;
+function k(ac){try{return K(ac)}catch(ad){return unescape(ac)}}function B(ad){var ac=typeof ad;return ac!=="undefined"}function t(ac){return typeof ac==="function"}function O(ac){return typeof ac==="object"}function q(ac){return typeof ac==="string"||ac instanceof String}function u(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 Y(ac){if(console!==undefined&&console&&console.error){console.error(ac)}}function V(){var ag,af,ai,ac;for(ag=0;ag<arguments.length;ag+=1){ac=arguments[ag];ai=ac.shift();for(af=0;af<A.length;af++){if(q(ai)){var ad=A[af];var ah;var ae=ai.indexOf("::")>0;if(ae){ah=ai.split("::");ad=ah[0];ai=ah[1];if("object"===typeof d[ad]&&"function"===typeof d[ad][ai]){d[ad][ai].apply(d[ad],ac)}return}var aj=ai.indexOf(".")>0;if(aj){ah=ai.split(".");ad=ad[ah[0]];ai=ah[1]}if(ad[ai]){ad[ai].apply(ad,ac)}else{var ak="The method '"+ai+'\' was not found in "_paq" variable. Please have a look at the Piwik tracker documentation: http://developer.piwik.org/api-reference/tracking-javascript';
+Y(ak);if(!aj){throw new TypeError(ak)}}if(ai==="addTracker"){break}if(ai==="setTrackerUrl"||ai==="setSiteId"){break}}else{ai.apply(A[af],ac)}}}}function aa(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 S(ad,ah){var ac="",af,ae,ag;for(af in a){if(Object.prototype.hasOwnProperty.call(a,af)){ae=a[af][ad];if(t(ae)){ag=ae(ah);if(ag){ac+=ag}}}}return ac}function W(){var ac;S("unload");if(l){do{ac=new Date()}while(ac.getTimeAlias()<l)}}function j(ae,ad){var ac=y.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}y.getElementsByTagName("head")[0].appendChild(ac)}function C(){var ac="";try{ac=L.top.document.referrer}catch(ae){if(L.parent){try{ac=L.parent.document.referrer}catch(ad){ac=""}}}if(ac===""){ac=y.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 N(ae,ad){var ac="[\\?&#]"+ad+"=([^&#]*)";var ag=new RegExp(ac);var af=ag.exec(ae);return af?K(af[1]):""}function w(ac){return unescape(n(ac))}function Z(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=w(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 R(ae,ac,ad){if(!ae){ae=""}if(!ac){ac=""}if(ae==="translate.googleusercontent.com"){if(ad===""){ad=ac
+}ac=N(ac,"u");ae=c(ac)}else{if(ae==="cc.bingj.com"||ae==="webcache.googleusercontent.com"||ae.slice(0,5)==="74.6."){ac=y.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 ab(ad){ad=ad&&ad.text?ad.text:ad;if(!q(ad)){var ac=y.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 M(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 X(ad,ac){ad=String(ad);return ad.lastIndexOf(ac,0)===0}function J(ad,ac){ad=String(ad);return ad.indexOf(ac,ad.length-ac.length)!==-1}function s(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(L.getComputedStyle){return y.defaultView.getComputedStyle(ag,null)[ah]}if(ag.currentStyle){return ag.currentStyle[ah]}}function af(ag){ag=ag.parentNode;while(ag){if(ag===y){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 U={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=U.findMultiple([ad,ac]);return ae},findContentNodesWithinNode:function(af){if(!af){return[]}var ad=U.findNodesHavingCssClass(af,this.CONTENT_CLASS);var ac=U.findNodesHavingAttribute(af,this.CONTENT_ATTR);if(ac&&ac.length){var ae;for(ae=0;ae<ac.length;ae++){ad.push(ac[ae])}}if(U.hasNodeAttribute(af,this.CONTENT_ATTR)){ad.push(af)}else{if(U.hasNodeCssClass(af,this.CONTENT_CLASS)){ad.push(af)}}ad=U.makeNodesUnique(ad);return ad},findParentContentNode:function(ad){if(!ad){return}var ae=ad;var ac=0;while(ae&&ae!==y&&ae.parentNode){if(U.hasNodeAttribute(ae,this.CONTENT_ATTR)){return ae}if(U.hasNodeCssClass(ae,this.CONTENT_CLASS)){return ae}ae=ae.parentNode;if(ac>1000){break}ac++}},findPieceNode:function(ad){var ac;ac=U.findFirstNodeHavingAttribute(ad,this.CONTENT_PIECE_ATTR);if(!ac){ac=U.findFirstNodeHavingClass(ad,this.CONTENT_PIECE_CLASS)}if(ac){return ac}return ad},findTargetNodeNoDefault:function(ac){if(!ac){return}var ad=U.findFirstNodeHavingAttributeWithValue(ac,this.CONTENT_TARGET_ATTR);
+if(ad){return ad}ad=U.findFirstNodeHavingAttribute(ac,this.CONTENT_TARGET_ATTR);if(ad){return ad}ad=U.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=U.findFirstNodeHavingAttributeWithValue(ad,this.CONTENT_NAME_ATTR);if(ag){return U.getAttributeValueFromNode(ag,this.CONTENT_NAME_ATTR)}var ac=this.findContentPiece(ad);if(ac){return this.removeDomainIfIsInLink(ac)}if(U.hasNodeAttributeWithValue(ad,"title")){return U.getAttributeValueFromNode(ad,"title")}var ae=this.findPieceNode(ad);if(U.hasNodeAttributeWithValue(ae,"title")){return U.getAttributeValueFromNode(ae,"title")}var af=this.findTargetNode(ad);if(U.hasNodeAttributeWithValue(af,"title")){return U.getAttributeValueFromNode(af,"title")}},findContentPiece:function(ad){if(!ad){return}var af=U.findFirstNodeHavingAttributeWithValue(ad,this.CONTENT_PIECE_ATTR);if(af){return U.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(U.hasNodeAttributeWithValue(af,this.CONTENT_TARGET_ATTR)){return U.getAttributeValueFromNode(af,this.CONTENT_TARGET_ATTR)}var ad;if(U.hasNodeAttributeWithValue(af,"href")){ad=U.getAttributeValueFromNode(af,"href");return this.toAbsoluteUrl(ad)}var ac=this.findPieceNode(ae);if(U.hasNodeAttributeWithValue(ac,"href")){ad=U.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)&&U.findFirstNodeHavingAttributeWithValue(ag,"src")){var af=U.findFirstNodeHavingAttributeWithValue(ag,"src");return U.getAttributeValueFromNode(af,"src")}if(ac==="object"&&U.hasNodeAttributeWithValue(ag,"data")){return U.getAttributeValueFromNode(ag,"data")}if(ac==="object"){var ah=U.findNodesByTagName(ag,"param");if(ah&&ah.length){var ad;for(ad=0;ad<ah.length;ad++){if("movie"===U.getAttributeValueFromNode(ah[ad],"name")&&U.hasNodeAttributeWithValue(ah[ad],"value")){return U.getAttributeValueFromNode(ah[ad],"value")}}}var ai=U.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=y.documentElement||{};var ae=ag.top<0;if(ae&&ah.offsetTop){ae=(ah.offsetTop+ag.height)>0
+}var ad=af.clientWidth;if(L.innerWidth&&ad>L.innerWidth){ad=L.innerWidth}var ac=af.clientHeight;if(L.innerHeight&&ac>L.innerHeight){ac=L.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||L.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}U.setAnyAttribute(ad,"href",ac)},shouldIgnoreInteraction:function(ae){var ad=U.hasNodeAttribute(ae,this.CONTENT_IGNOREINTERACTION_ATTR);var ac=U.hasNodeCssClass(ae,this.CONTENT_IGNOREINTERACTION_CLASS);return ad||ac}};function G(ad,ag){if(ag){return ag}if(s(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(y.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)
+}}L.name=ak+"###"+ah+"###"+ac+"###"+af}var aj=L.name.split("###");return aj.length===4&&aj[0]===ak}function Q(ad,aj,af){var ai=L.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(){var ae;try{ae=L.frameElement}catch(ad){return true}if(B(ae)){return(ae&&String(ae.nodeName).toLowerCase()==="iframe")?true:false}try{return L.self!==L.top}catch(ac){return true}}function I(bK,bE){var bA=R(y.domain,L.location.href,C()),cj=D(bA[0]),bk=k(bA[1]),aZ=k(bA[2]),ch=false,bO="GET",cv=bO,aq="application/x-www-form-urlencoded; charset=UTF-8",b0=aq,am=bK||"",bf="",cn="",bC=bE||"",a8="",bl="",aK,aV="",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],a9=[],bi=[],aN=[],bg=500,ca,aL,bo,bm,ac,bW=["pk_campaign","piwik_campaign","utm_campaign","utm_source","utm_medium"],be=["pk_kwd","piwik_kwd","utm_term"],aW="_pk_",cl,a1,aX=false,cf,aT,a5,cb=33955200000,bU=1800000,cr=15768000000,aI=true,bS=0,bn=false,ax=false,bH,bs={},bR={},aY={},a4=200,co={},ct={},bG=[],bL=false,b4=false,ad=false,cu=false,av=false,aS=o(),cm=null,bI,ay,ba,bD=Z,a0;
+try{aV=y.title}catch(b2){aV=""}function cy(cI,cF,cE,cH,cD,cG){if(aX){return}var cC;if(cE){cC=new Date();cC.setTime(cC.getTime()+cE)}y.cookie=cI+"="+n(cF)+(cE?";expires="+cC.toGMTString():"")+";path="+(cH||"/")+(cD?";domain="+cD:"")+(cG?";secure":"")}function al(cE){if(aX){return 0}var cC=new RegExp("(^|;)[ ]*"+cE+"=([^;]*)"),cD=cC.exec(y.cookie);return cD?K(cD[2]):0}function by(cC){var cD;if(bm){cD=new RegExp("#.*");return cC.replace(cD,"")}return cC}function br(cE,cC){var cF=m(cC),cD;if(cF){return cC}if(cC.slice(0,1)==="/"){return m(cE)+"://"+c(cE)+cC}cE=by(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 bQ(cC){var cD=document.createElement("a");if(cC.indexOf("//")!==0&&cC.indexOf("http")!==0){if(cC.indexOf("*")===0){cC=cC.substr(1)
+}if(cC.indexOf(".")===0){cC=cC.substr(1)}cC="http://"+cC}cD.href=p.toAbsoluteUrl(cC);if(cD.pathname){return cD.pathname}return""}function aJ(cD,cC){if(!X(cC,"/")){cC="/"+cC}if(!X(cD,"/")){cD="/"+cD}var cE=(cC==="/"||cC==="/*");if(cE){return true}if(cD===cC){return true}cC=String(cC).toLowerCase();cD=String(cD).toLowerCase();if(J(cC,"*")){cC=cC.slice(0,-1);cE=(!cC||cC==="/");if(cE){return true}if(cD===cC){return true}return cD.indexOf(cC)===0}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=bQ(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 bV(cC,cE){var cD=new Image(1,1);cD.onload=function(){x=0;if(typeof cE==="function"){cE()
+}};cC=cC.replace("send_image=0","send_image=1");cD.src=am+(am.indexOf("?")<0?"?":"&")+cC}function cq(cD,cG,cC){if(!B(cC)||null===cC){cC=true}try{var cF=L.XMLHttpRequest?new L.XMLHttpRequest():L.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){bV(cD,cG)}else{if(this.readyState===4&&(typeof cG==="function")){cG()}}};cF.setRequestHeader("Content-Type",b0);cF.send(cD)}catch(cE){if(cC){bV(cD,cG)}}}function bM(cD){var cC=new Date();var cE=cC.getTime()+cD;if(!l||cE>l){l=cE}}function bT(cC){if(bI||!aL){return}bI=setTimeout(function cD(){bI=null;if(!aS){aS=(!y.hasFocus||y.hasFocus())}if(!aS){bT(aL);return}if(bo()){return}var cE=new Date(),cF=aL-(cE.getTime()-cm);cF=Math.min(aL,cF);bT(cF)},cC||aL)}function bh(){if(!bI){return}clearTimeout(bI);bI=null}function aP(){aS=true;if(bo()){return}bT()}function aj(){bh()}function cA(){if(av||!aL){return}av=true;aa(L,"focus",aP);
+aa(L,"blur",aj);bT()}function b5(cG){var cD=new Date();var cC=cD.getTime();cm=cC;if(b4&&cC<b4){var cE=b4-cC;setTimeout(cG,cE);bM(cE+50);b4+=50;return}if(b4===false){var cF=800;b4=cC+cF}cG()}function bd(cD,cC,cE){if(!cf&&cD){b5(function(){if(cv==="POST"){cq(cD,cE)}else{bV(cD,cE)}bM(cC)})}if(!av){cA()}else{bT()}}function bP(cC){if(cf){return false}return(cC&&cC.length)}function cz(cE,cC){if(!bP(cE)){return}var cD='{"requests":["?'+cE.join('","?')+'"]}';b5(function(){cq(cD,null,false);bM(cC)})}function aA(cC){return aW+cC+"."+bC+"."+a0}function bB(){if(aX){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 aU(){a0=bD((cl||cj)+(a1||"/")).slice(0,4)}function bt(){var cD=aA("cvar"),cC=al(cD);if(cC.length){cC=JSON2.parse(cC);if(O(cC)){return cC}}return{}}function b6(){if(ax===false){ax=bt()}}function cg(){return bD((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(bl.length){cG[1]=bl}return cG}if(bl.length){cF=bl}else{if("0"===bB()){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(!bC){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(),a1,cl)}function bj(){var cC=al(aA("ref"));if(cC.length){try{cC=JSON2.parse(cC);if(O(cC)){return cC}}catch(cD){}}return["","",0,""]}function bu(cE,cD,cC){cy(cE,"",-86400,cD,cC)
+}function a6(cD){var cC="testvalue";cy("test",cC,10000,null,cD);if(al("test")===cC){bu("test",null,cD);return true}return false}function an(){var cE=aX;aX=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)){bu(cF,a1,cl)}}aX=cE}function bz(cC){bC=cC;at()}function cB(cG){if(!cG||!O(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 bJ(){cy(aA("ses"),"*",bU,a1,cl)}function bX(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=bj(),c2=aK||bk,cK,cC;if(aX){an()}if(cf){return""}var cS=aE();if(!B(cF)){cF=""}var cP=y.characterSet||y.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=bU/1000;if(!cS.lastVisitTs||(cM-cS.lastVisitTs)>c1){cS.visitCount++;
+cS.lastVisitTs=cS.currentVisitTs}if(!a5||!cK.length){for(cY in bW){if(Object.prototype.hasOwnProperty.call(bW,cY)){cK=N(c2,bW[cY]);if(cK.length){break}}}for(cY in be){if(Object.prototype.hasOwnProperty.call(be,cY)){cC=N(c2,be[cY]);if(cC.length){break}}}}c5=c(aZ);cN=cX.length?c(cX):"";if(c5.length&&!aC(c5)&&(!a5||!cN.length||aC(cN))){cX=aZ}if(cX.length||cK.length){cJ=cM;cW=[cK,cC,cJ,by(cX.slice(0,cG))];cy(cT,JSON2.stringify(cW),cr,a1,cl)}}cE+="&idsite="+bC+"&rec=1&r="+String(Math.random()).slice(2,8)+"&h="+cD.getHours()+"&m="+cD.getMinutes()+"&s="+cD.getSeconds()+"&url="+n(by(c2))+(aZ.length?"&urlref="+n(by(aZ)):"")+((a8&&a8.length)?"&uid="+n(a8):"")+"&_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(by(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&&u(cZ)){cZ=null}for(cY in aY){if(Object.prototype.hasOwnProperty.call(aY,cY)){var cO=(-1===E(c4,cY));if(cO){cE+="&dimension"+cY+"="+aY[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(bs);var cU=cB(bR);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(bn){cy(cQ,JSON2.stringify(ax),bU,a1,cl)}}if(aI){if(bS){cE+="&gt_ms="+bS}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);bJ();cE+=S(c0);if(cn.length){cE+="&"+cn}if(t(bH)){cE=bH(cE)}return cE}bo=function aM(){var cC=new Date();if(cm+aL<=cC.getTime()){var cD=bX("ping=1",null,"ping");bd(cD,bg);return true}return false};function a2(cF,cE,cK,cG,cC,cN){var cI="idgoal=0",cJ,cD=new Date(),cL=[],cM,cH=String(cF).length;if(cH){cI+="&ec_id="+n(cF);cJ=Math.round(cD.getTime()/1000)}cI+="&revenue="+cE;if(String(cK).length){cI+="&ec_st="+cK}if(String(cG).length){cI+="&ec_tx="+cG}if(String(cC).length){cI+="&ec_sh="+cC}if(String(cN).length){cI+="&ec_dt="+cN}if(co){for(cM in co){if(Object.prototype.hasOwnProperty.call(co,cM)){if(!B(co[cM][1])){co[cM][1]=""}if(!B(co[cM][2])){co[cM][2]=""}if(!B(co[cM][3])||String(co[cM][3]).length===0){co[cM][3]=0}if(!B(co[cM][4])||String(co[cM][4]).length===0){co[cM][4]=1}cL.push(co[cM])}}cI+="&ec_items="+n(JSON2.stringify(cL))}cI=bX(cI,ac,"ecommerce",cJ);bd(cI,bg);if(cH){co={}}}function bv(cC,cG,cF,cE,cD,cH){if(String(cC).length&&B(cG)){a2(cC,cG,cF,cE,cD,cH)
+}}function a3(cC){if(B(cC)){a2("",cC,"","","","")}}function bw(cD,cF,cE){var cC=bX("action_name="+n(ab(cD||aV)),cF,"log");bd(cC,bg,cE)}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 bY(cG,cC,cH,cD){if(aB(cC)){return 0}var cF=aG(bi,"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(U.isLinkElement(cD)){break}cD=cC;cC=cD.parentNode}return cD}function cw(cH){cH=ag(cH);if(!U.hasNodeAttribute(cH,"href")){return}if(!B(cH.href)){return}var cG=U.getAttributeValueFromNode(cH,"href");if(aB(cG)){return}var cD=cH.pathname||bQ(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=bY(cH.className,cE,af(cJ,cD),U.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 bX(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 aQ(cC,cD){if(!cC||!cD){return false}var cE=p.findTargetNode(cC);if(p.shouldIgnoreInteraction(cE)){return false}cE=p.findTargetNodeNoDefault(cC);if(cE&&!M(cE,cD)){return false}return true}function bZ(cE,cD,cG){if(!cE){return}var cC=p.findParentContentNode(cE);if(!cC){return}if(!aQ(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(!bG||!bG.length){return false}var cC,cE;for(cC=0;cC<bG.length;cC++){cE=bG[cC];
+if(cE&&cE.name===cD.name&&cE.piece===cD.piece&&cE.target===cD.target){return true}}return false}function bc(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(U.isLinkElement(cI)&&U.hasNodeAttributeWithValue(cI,"href")){var cC=String(U.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(!U.hasNodeAttributeWithValue(cI,p.CONTENT_TARGET_ATTR)||cI.wasContentTargetAttrReplaced){cI.wasContentTargetAttrReplaced=true;cH=p.toAbsoluteUrl(cC);U.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++){bc(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(!aQ(cG,cH)){return}bM(bg);if(U.isLinkElement(cC)&&U.hasNodeAttributeWithValue(cC,"href")&&U.hasNodeAttributeWithValue(cC,p.CONTENT_TARGET_ATTR)){var cE=U.getAttributeValueFromNode(cC,"href");if(!aB(cE)&&cC.wasContentTargetAttrReplaced){U.setAnyAttribute(cC,p.CONTENT_TARGET_ATTR,"")}}var cL=cw(cC);if(ad&&cL&&cL.type){return cL.type}if(bc(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);bd(cJ,bg);return cJ}}function bx(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;aa(cD,"click",aF(cD))}}}function a7(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{bG.push(cE[cC])}}if(!cE||!cE.length){return[]}au(cF);bx(cF);var cG=[];for(cC=0;cC<cE.length;
+cC++){cD=bX(p.buildImpressionRequestParams(cE[cC].name,cE[cC].piece,cE[cC].target),undefined,"contentImpressions");if(cD){cG.push(cD)}}return cG}function b3(cD){var cC=p.collectContent(cD);return a7(cC,cD)}function aO(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 bX(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=bX(ce(cE,cG,cC,cF),cH,"event");bd(cD,bg)}function bF(cC,cF,cD,cG){var cE=bX("search="+n(cC)+(cF?"&search_cat="+n(cF):"")+(B(cD)?"&search_count="+cD:""),cG,"sitesearch");
+bd(cE,bg)}function ci(cC,cF,cE){var cD=bX("idgoal="+cC+(cF?"&revenue="+cF:""),cE,"goal");bd(cD,bg)}function cp(cF,cC,cJ,cI,cE){var cH=cC+"="+n(by(cF));var cD=bZ(cE,"click",cF);if(cD){cH+="&"+cD}var cG=bX(cH,cJ,"link");bd(cG,(cI?0:bg),cI)}function bp(cD,cC){if(cD!==""){return cD+cC.charAt(0).toUpperCase()+cC.slice(1)}return cC}function bN(cH){var cG,cC,cF=["","webkit","ms","moz"],cE;if(!aT){for(cC=0;cC<cF.length;cC++){cE=cF[cC];if(Object.prototype.hasOwnProperty.call(y,bp(cE,"hidden"))){if(y[bp(cE,"visibilityState")]==="prerender"){cG=true}break}}}if(cG){aa(y,cE+"visibilitychange",function cD(){y.removeEventListener(cE+"visibilitychange",cD,false);cH()});return}cH()}function ar(cC){if(y.readyState==="complete"){cC()}else{if(L.addEventListener){L.addEventListener("load",cC)}else{if(L.attachEvent){L.attachEvent("onload",cC)}}}}function aR(cF){var cC=false;if(y.attachEvent){cC=y.readyState==="complete"}else{cC=y.readyState!=="loading"}if(cC){cF();return}var cE;if(y.addEventListener){aa(y,"DOMContentLoaded",function cD(){y.removeEventListener("DOMContentLoaded",cD,false);
+if(!cC){cC=true;cF()}})}else{if(y.attachEvent){y.attachEvent("onreadystatechange",function cD(){if(y.readyState==="complete"){y.detachEvent("onreadystatechange",cD);if(!cC){cC=true;cF()}}});if(y.documentElement.doScroll&&L===L.top){(function cD(){if(!cC){try{y.documentElement.doScroll("left")}catch(cG){setTimeout(cD,0);return}cC=true;cF()}}())}}}aa(L,"load",function(){if(!cC){cC=true;cF()}},false)}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 b1(){return y.all&&!y.addEventListener}function ck(cC){var cE=cC.which;var cD=(typeof cC.button);if(!cE&&cD!=="undefined"){if(b1()){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 bq(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||L.event;
+var cE=bq(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;ba=cG}else{ay=ba=null}}else{if(cF.type==="mouseup"){if(cE===ay&&cG===ba){b9(cG)}ay=ba=null}else{if(cF.type==="contextmenu"){b9(cG)}}}}}}function ae(cD,cC){aa(cD,"click",ak(cC),false);if(cC){aa(cD,"mouseup",ak(cC),false);aa(cD,"mousedown",ak(cC),false);aa(cD,"contextmenu",ak(cC),false)}}function bb(cD){if(!ad){ad=true;var cE,cC=aG(a9,"ignore"),cF=y.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(bL){return true}bL=true;var cI=false;var cF,cD;function cC(){cI=true}ar(function(){function cJ(cL){setTimeout(function(){if(!bL){return}cI=false;cH.trackVisibleContentImpressions();cJ(cL)},cL)}function cK(cL){setTimeout(function(){if(!bL){return}if(cI){cI=false;cH.trackVisibleContentImpressions()}cK(cL)},cL)}if(cE){cF=["scroll","resize"];for(cD=0;cD<cF.length;cD++){if(y.addEventListener){y.addEventListener(cF[cD],cC)
+}else{L.attachEvent("on"+cF[cD],cC)}}cK(100)}if(cG&&cG>0){cG=parseInt(cG,10);cJ(cG)}})}function b7(){var cD,cF,cG={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"};if(!((new RegExp("MSIE")).test(f.userAgent))){if(f.mimeTypes&&f.mimeTypes.length){for(cD in cG){if(Object.prototype.hasOwnProperty.call(cG,cD)){cF=f.mimeTypes[cG[cD]];ct[cD]=(cF&&cF.enabledPlugin)?"1":"0"}}}if(typeof navigator.javaEnabled!=="unknown"&&B(f.javaEnabled)&&f.javaEnabled()){ct.java="1"}if(t(L.GearsFactory)){ct.gears="1"}ct.cookie=bB()}var cE=parseInt(P.width,10);var cC=parseInt(P.height,10);ct.res=parseInt(cE,10)+"x"+parseInt(cC,10)}b7();aU();at();this.getVisitorId=function(){return aE().uuid};this.getVisitorInfo=function(){return cd()};this.getAttributionInfo=function(){return bj()};this.getAttributionCampaignName=function(){return bj()[0]
+};this.getAttributionCampaignKeyword=function(){return bj()[1]};this.getAttributionReferrerTimestamp=function(){return bj()[2]};this.getAttributionReferrerUrl=function(){return bj()[3]};this.setTrackerUrl=function(cC){am=cC};this.getTrackerUrl=function(){return am};this.addTracker=function(cC,cE){if(!cE){throw new Error("A siteId must be given to add a new tracker")}if(!B(cC)||null===cC){cC=this.getTrackerUrl()}var cD=new I(cC,cE);A.push(cD);return cD};this.getSiteId=function(){return bC};this.setSiteId=function(cC){bz(cC)};this.setUserId=function(cC){if(!B(cC)||!cC.length){return}a8=cC;bl=bD(a8).substr(0,16)};this.getUserId=function(){return a8};this.setCustomData=function(cC,cD){if(O(cC)){ac=cC}else{if(!ac){ac={}}ac[cC]=cD}};this.getCustomData=function(){return ac};this.setCustomRequestProcessing=function(cC){bH=cC};this.appendToTrackingUrl=function(cC){cn=cC};this.getRequest=function(cC){return bX(cC)};this.addPlugin=function(cC,cD){a[cC]=cD};this.setCustomDimension=function(cC,cD){cC=parseInt(cC,10);
+if(cC>0){if(!B(cD)){cD=""}if(!q(cD)){cD=String(cD)}aY[cC]=cD}};this.getCustomDimension=function(cC){cC=parseInt(cC,10);if(cC>0&&Object.prototype.hasOwnProperty.call(aY,cC)){return aY[cC]}};this.deleteCustomDimension=function(cC){cC=parseInt(cC,10);if(cC>0){delete aY[cC]}};this.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,a4),cG.slice(0,a4)];if(cE==="visit"||cE===2){b6();ax[cD]=cF}else{if(cE==="page"||cE===3){bs[cD]=cF}else{if(cE==="event"){bR[cD]=cF}}}}};this.getCustomVariable=function(cD,cE){var cC;if(!B(cE)){cE="visit"}if(cE==="page"||cE===3){cC=bs[cD]}else{if(cE==="event"){cC=bR[cD]}else{if(cE==="visit"||cE===2){b6();cC=ax[cD]}}}if(!B(cC)||(cC&&cC[0]==="")){return false}return cC};this.deleteCustomVariable=function(cC,cD){if(this.getCustomVariable(cC,cD)){this.setCustomVariable(cC,"","",cD)}};this.storeCustomVariablesInCookie=function(){bn=true};this.setLinkTrackingTimer=function(cC){bg=cC
+};this.setDownloadExtensions=function(cC){if(q(cC)){cC=cC.split("|")}cs=cC};this.addDownloadExtensions=function(cD){var cC;if(q(cD)){cD=cD.split("|")}for(cC=0;cC<cD.length;cC++){cs.push(cD[cC])}};this.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};this.setDomains=function(cC){ai=q(cC)?[cC]:cC;var cG=false,cE=0,cD;for(cE;cE<ai.length;cE++){cD=String(ai[cE]);if(b8(cj,D(cD))){cG=true;break}var cF=bQ(cD);if(cF&&cF!=="/"&&cF!=="/*"){cG=true;break}}if(!cG){ai.push(cj)}};this.setIgnoreClasses=function(cC){a9=q(cC)?[cC]:cC};this.setRequestMethod=function(cC){cv=cC||bO};this.setRequestContentType=function(cC){b0=cC||aq};this.setReferrerUrl=function(cC){aZ=cC};this.setCustomUrl=function(cC){aK=br(bk,cC)};this.setDocumentTitle=function(cC){aV=cC};this.setAPIUrl=function(cC){bf=cC};this.setDownloadClasses=function(cC){bi=q(cC)?[cC]:cC};this.setLinkClasses=function(cC){aN=q(cC)?[cC]:cC};this.setCampaignNameKey=function(cC){bW=q(cC)?[cC]:cC
+};this.setCampaignKeywordKey=function(cC){be=q(cC)?[cC]:cC};this.discardHashTag=function(cC){bm=cC};this.setCookieNamePrefix=function(cC){aW=cC;ax=bt()};this.setCookieDomain=function(cC){var cD=D(cC);if(a6(cD)){cl=cD;aU()}};this.setCookiePath=function(cC){a1=cC;aU()};this.setVisitorCookieTimeout=function(cC){cb=cC*1000};this.setSessionCookieTimeout=function(cC){bU=cC*1000};this.setReferralCookieTimeout=function(cC){cr=cC*1000};this.setConversionAttributionFirstReferrer=function(cC){a5=cC};this.disableCookies=function(){aX=true;ct.cookie="0";if(bC){an()}};this.deleteCookies=function(){an()};this.setDoNotTrack=function(cD){var cC=f.doNotTrack||f.msDoNotTrack;cf=cD&&(cC==="yes"||cC==="1");if(cf){this.disableCookies()}};this.addListener=function(cD,cC){ae(cD,cC)};this.enableLinkTracking=function(cC){cu=true;bN(function(){aR(function(){bb(cC)})})};this.enableJSErrorTracking=function(){if(ch){return}ch=true;var cC=L.onerror;L.onerror=function(cH,cF,cE,cG,cD){bN(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}};this.disablePerformanceTracking=function(){aI=false};this.setGenerationTimeMs=function(cC){bS=parseInt(cC,10)};this.enableHeartBeatTimer=function(cC){cC=Math.max(cC,1);aL=(cC||15)*1000;if(cm!==null){cA()}};this.killFrame=function(){if(L.location!==L.top.location){L.top.location=L.location}};this.redirectFile=function(cC){if(L.location.protocol==="file:"){L.location=cC}};this.setCountPreRendered=function(cC){aT=cC};this.trackGoal=function(cC,cE,cD){bN(function(){ci(cC,cE,cD)})};this.trackLink=function(cD,cC,cF,cE){bN(function(){cp(cD,cC,cF,cE)})};this.trackPageView=function(cC,cE,cD){bG=[];if(F(bC)){bN(function(){Q(am,bf,bC)})}else{bN(function(){bw(cC,cE,cD)})}};this.trackAllContentImpressions=function(){if(F(bC)){return}bN(function(){aR(function(){var cC=p.findContentNodes();var cD=b3(cC);cz(cD,bg)})})};this.trackVisibleContentImpressions=function(cC,cD){if(F(bC)){return}if(!B(cC)){cC=true}if(!B(cD)){cD=750
+}az(cC,cD,this);bN(function(){ar(function(){var cE=p.findContentNodes();var cF=aO(cE);cz(cF,bg)})})};this.trackContentImpression=function(cE,cC,cD){if(F(bC)){return}if(!cE){return}cC=cC||"Unknown";bN(function(){var cF=ao(cE,cC,cD);bd(cF,bg)})};this.trackContentImpressionsWithinNode=function(cC){if(F(bC)||!cC){return}bN(function(){if(bL){ar(function(){var cD=p.findContentNodesWithinNode(cC);var cE=aO(cD);cz(cE,bg)})}else{aR(function(){var cD=p.findContentNodesWithinNode(cC);var cE=b3(cD);cz(cE,bg)})}})};this.trackContentInteraction=function(cE,cF,cC,cD){if(F(bC)){return}if(!cE||!cF){return}cC=cC||"Unknown";bN(function(){var cG=aw(cE,cF,cC,cD);bd(cG,bg)})};this.trackContentInteractionNode=function(cD,cC){if(F(bC)||!cD){return}bN(function(){var cE=cx(cD,cC);bd(cE,bg)})};this.logAllContentBlocksOnPage=function(){var cD=p.findContentNodes();var cC=p.collectContent(cD);if(console!==undefined&&console&&console.log){console.log(cC)}};this.trackEvent=function(cD,cF,cC,cE,cG){bN(function(){ah(cD,cF,cC,cE,cG)
+})};this.trackSiteSearch=function(cC,cE,cD,cF){bN(function(){bF(cC,cE,cD,cF)})};this.setEcommerceView=function(cF,cC,cE,cD){if(!B(cE)||!cE.length){cE=""}else{if(cE instanceof Array){cE=JSON2.stringify(cE)}}bs[5]=["_pkc",cE];if(B(cD)&&String(cD).length){bs[2]=["_pkp",cD]}if((!B(cF)||!cF.length)&&(!B(cC)||!cC.length)){return}if(B(cF)&&cF.length){bs[3]=["_pks",cF]}if(!B(cC)||!cC.length){cC=""}bs[4]=["_pkn",cC]};this.addEcommerceItem=function(cG,cC,cE,cD,cF){if(cG.length){co[cG]=[cG,cC,cE,cD,cF]}};this.trackEcommerceOrder=function(cC,cG,cF,cE,cD,cH){bv(cC,cG,cF,cE,cD,cH)};this.trackEcommerceCartUpdate=function(cC){a3(cC)};this.trackRequest=function(cC,cE,cD){bN(function(){var cF=bX(cC,cE);bd(cF,bg,cD)})};d.trigger("TrackerSetup",[this])}function z(){return{push:V}}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){V(ah[af]);delete ah[af];if(ai[ad]>1){Y("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}var v=["addTracker","disableCookies","setTrackerUrl","setAPIUrl","setCookiePath","setCookieDomain","setDomains","setUserId","setSiteId","enableLinkTracking"];function T(ac,ae){var ad=new I(ac,ae);A.push(ad);_paq=b(_paq,v);for(x=0;x<_paq.length;x++){if(_paq[x]){V(_paq[x])}}_paq=new z();return ad}aa(L,"beforeunload",W,false);Date.prototype.getTimeAlias=Date.prototype.getTime;d={initialized:false,on:function(ad,ac){if(!r[ad]){r[ad]=[]}r[ad].push(ac)},off:function(ae,ad){if(!r[ae]){return}var ac=0;for(ac;ac<r[ae].length;ac++){if(r[ae][ac]===ad){delete r[ae][ac]}}},trigger:function(ae,af,ad){if(!r[ae]){return}var ac=0;for(ac;ac<r[ae].length;ac++){r[ae][ac].apply(ad||L,af)}},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)},getAsyncTrackers:function(){return A},addTracker:function(ac,ad){if(!A.length){T(ac,ad)}else{A[0].addTracker(ac,ad)
+}},getAsyncTracker:function(ad,ag){var af;if(A&&A[0]){af=A[0]}if(!ag&&!ad){return af}if((!B(ag)||null===ag)&&af){ag=af.getSiteId()}if((!B(ad)||null===ad)&&af){ad=af.getTrackerUrl()}var ae,ac=0;for(ac;ac<A.length;ac++){ae=A[ac];if(ae&&String(ae.getSiteId())===String(ag)&&ae.getTrackerUrl()===ad){return ae}}}};if(typeof define==="function"&&define.amd){define("piwik",[],function(){return d})}return d}());
+/*!!! pluginTrackerHook */
+}(function(){if(window&&"object"===typeof window.piwikPluginAsyncInit&&window.piwikPluginAsyncInit.length){var a=0;for(a;a<window.piwikPluginAsyncInit.length;a++){if(typeof window.piwikPluginAsyncInit[a]==="function"){window.piwikPluginAsyncInit[a]()}}}window.Piwik.addTracker();window.Piwik.trigger("PiwikInitialized",[]);window.Piwik.initialized=true}());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/Actions/javascripts/actionsDataTable.js b/plugins/Actions/javascripts/actionsDataTable.js
index 5d96ff2891..b15958db3d 100644
--- a/plugins/Actions/javascripts/actionsDataTable.js
+++ b/plugins/Actions/javascripts/actionsDataTable.js
@@ -54,6 +54,7 @@
var self = this;
self.cleanParams();
+ self.preBindEventsAndApplyStyleHook(domElem, rows);
if (!rows) {
rows = $('tr', domElem);
@@ -92,6 +93,7 @@
self.setFixWidthToMakeEllipsisWork(domElem);
self.handleSummaryRow(domElem);
self.openSubtableFromLevel0IfOnlyOneSubtableGiven(domElem);
+ self.postBindEventsAndApplyStyleHook(domElem, rows);
},
openSubtableFromLevel0IfOnlyOneSubtableGiven: function (domElem) {
diff --git a/plugins/CoreHome/javascripts/dataTable.js b/plugins/CoreHome/javascripts/dataTable.js
index e143af91dc..bb892a636c 100644
--- a/plugins/CoreHome/javascripts/dataTable.js
+++ b/plugins/CoreHome/javascripts/dataTable.js
@@ -302,6 +302,7 @@ $.extend(DataTable.prototype, UIControl.prototype, {
bindEventsAndApplyStyle: function (domElem) {
var self = this;
self.cleanParams();
+ self.preBindEventsAndApplyStyleHook(domElem);
self.handleSort(domElem);
self.handleLimit(domElem);
self.handleSearchBox(domElem);
@@ -321,6 +322,14 @@ $.extend(DataTable.prototype, UIControl.prototype, {
self.handleExpandFooter(domElem);
self.setFixWidthToMakeEllipsisWork(domElem);
self.handleSummaryRow(domElem);
+ self.postBindEventsAndApplyStyleHook(domElem);
+ },
+
+ preBindEventsAndApplyStyleHook: function (domElem) {
+
+ },
+ postBindEventsAndApplyStyleHook: function (domElem) {
+
},
setFixWidthToMakeEllipsisWork: function (domElem) {
diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php b/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php
index 90066a187a..ca699274c0 100644
--- a/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php
+++ b/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php
@@ -26,7 +26,6 @@ class AllColumns extends HtmlTable
public function beforeRender()
{
$this->config->show_extra_columns = true;
- $this->config->datatable_css_class = 'dataTableVizAllColumns';
$this->config->show_exclude_low_population = true;
parent::beforeRender();
@@ -34,6 +33,8 @@ class AllColumns extends HtmlTable
public function beforeGenericFiltersAreAppliedToLoadedDataTable()
{
+ $this->config->datatable_css_class = 'dataTableVizAllColumns';
+
$this->dataTable->filter('AddColumnsProcessedMetrics');
$properties = $this->config;
diff --git a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php
index 121cfdc315..84b53bae88 100644
--- a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php
+++ b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php
@@ -20,10 +20,10 @@ class Bar extends JqplotGraph
const ID = 'graphVerticalBar';
const FOOTER_ICON = 'plugins/Morpheus/images/chart_bar.png';
const FOOTER_ICON_TITLE = 'General_VBarGraph';
-
- public function beforeRender()
+
+ public function beforeLoadDataTable()
{
- parent::beforeRender();
+ parent::beforeLoadDataTable();
$this->config->datatable_js_type = 'JqplotBarGraphDataTable';
}
diff --git a/plugins/CustomPiwikJs/.gitignore b/plugins/CustomPiwikJs/.gitignore
new file mode 100644
index 0000000000..c8c9480010
--- /dev/null
+++ b/plugins/CustomPiwikJs/.gitignore
@@ -0,0 +1 @@
+tests/System/processed/*xml \ No newline at end of file
diff --git a/plugins/CustomPiwikJs/Commands/UpdateTracker.php b/plugins/CustomPiwikJs/Commands/UpdateTracker.php
new file mode 100644
index 0000000000..70754bc20f
--- /dev/null
+++ b/plugins/CustomPiwikJs/Commands/UpdateTracker.php
@@ -0,0 +1,62 @@
+<?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\CustomPiwikJs\Commands;
+
+use Piwik\Plugin\ConsoleCommand;
+use Piwik\Plugins\CustomPiwikJs\TrackerUpdater;
+use Piwik\Plugins\CustomPiwikJs\TrackingCode\PluginTrackerFiles;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class UpdateTracker extends ConsoleCommand
+{
+ protected function configure()
+ {
+ $this->setName('custom-piwik-js:update');
+ $this->addOption('source-file', null, InputOption::VALUE_REQUIRED, 'Absolute path to source PiwikJS file.', $this->getPathOriginalPiwikJs());
+ $this->addOption('target-file', null, InputOption::VALUE_REQUIRED, 'Absolute path to target file. Useful if your /piwik.js is not writable and you want to replace the file manually', PIWIK_DOCUMENT_ROOT . TrackerUpdater::TARGET_PIWIK_JS);
+ $this->addOption('ignore-minified', null, InputOption::VALUE_NONE, 'Ignore minified tracker files, useful during development so the original source file can be debugged');
+ $this->setDescription('Update the Javascript Tracker with plugin tracker additions');
+ }
+
+ private function getPathOriginalPiwikJs()
+ {
+ return PIWIK_DOCUMENT_ROOT . TrackerUpdater::ORIGINAL_PIWIK_JS;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $sourceFile = $input->getOption('source-file');
+ $targetFile = $input->getOption('target-file');
+ $ignoreMinified = $input->hasOption('ignore-minified');
+
+ $this->updateTracker($sourceFile, $targetFile, $ignoreMinified);
+
+ $output->writeln('<info>The Javascript Tracker has been updated</info>');
+ }
+
+ public function updateTracker($sourceFile, $targetFile, $ignoreMinified)
+ {
+ $pluginTrackerFiles = new PluginTrackerFiles();
+
+ if ($ignoreMinified) {
+ if (empty($sourceFile) || $sourceFile === $this->getPathOriginalPiwikJs()) {
+ // no custom source file was requested
+ $sourceFile = PIWIK_DOCUMENT_ROOT . TrackerUpdater::DEVELOPMENT_PIWIK_JS;
+ }
+ $pluginTrackerFiles->ignoreMinified();
+ }
+
+ $updater = new TrackerUpdater($sourceFile, $targetFile);
+ $updater->setTrackerFiles($pluginTrackerFiles);
+ $updater->checkWillSucceed();
+ $updater->update();
+ }
+}
diff --git a/plugins/CustomPiwikJs/CustomPiwikJs.php b/plugins/CustomPiwikJs/CustomPiwikJs.php
new file mode 100644
index 0000000000..4089f8cba8
--- /dev/null
+++ b/plugins/CustomPiwikJs/CustomPiwikJs.php
@@ -0,0 +1,35 @@
+<?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\CustomPiwikJs;
+
+use Piwik\Log;
+use Piwik\Plugin;
+
+class CustomPiwikJs extends Plugin
+{
+ public function getListHooksRegistered()
+ {
+ return array(
+ 'CoreUpdater.update.end' => 'updateTracker',
+ 'PluginManager.pluginDeactivated' => 'updateTracker',
+ 'PluginManager.pluginActivated' => 'updateTracker',
+ 'CronArchive.end' => 'updateTracker',
+ );
+ }
+
+ public function updateTracker()
+ {
+ try {
+ $trackerUpdater = new TrackerUpdater();
+ $trackerUpdater->update();
+ } catch (\Exception $e) {
+ Log::error('There was an error while updating the javascript tracker: ' . $e->getMessage());
+ }
+ }
+}
diff --git a/plugins/CustomPiwikJs/Diagnostic/PiwikJsCheck.php b/plugins/CustomPiwikJs/Diagnostic/PiwikJsCheck.php
new file mode 100644
index 0000000000..3766dc650b
--- /dev/null
+++ b/plugins/CustomPiwikJs/Diagnostic/PiwikJsCheck.php
@@ -0,0 +1,54 @@
+<?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\CustomPiwikJs\Diagnostic;
+
+use Piwik\Filechecks;
+use Piwik\Filesystem;
+use Piwik\Plugins\CustomPiwikJs\File;
+use Piwik\Plugins\Diagnostics\Diagnostic\Diagnostic;
+use Piwik\Plugins\Diagnostics\Diagnostic\DiagnosticResult;
+use Piwik\SettingsServer;
+use Piwik\Translation\Translator;
+
+/**
+ * Check Piwik JS is writable
+ */
+class PiwikJsCheck implements Diagnostic
+{
+ /**
+ * @var Translator
+ */
+ private $translator;
+
+ public function __construct(Translator $translator)
+ {
+ $this->translator = $translator;
+ }
+
+ public function execute()
+ {
+ $label = $this->translator->translate('CustomPiwikJs_DiagnosticPiwikJsWritable');
+
+ $file = new File(PIWIK_DOCUMENT_ROOT . '/piwik.js');
+
+ if ($file->hasWriteAccess()) {
+ return array(DiagnosticResult::singleResult($label, DiagnosticResult::STATUS_OK, ''));
+ }
+
+ $comment = $this->translator->translate('CustomPiwikJs_DiagnosticPiwikJsNotWritable');
+
+ if(!SettingsServer::isWindows()) {
+ $realpath = Filesystem::realpath(PIWIK_INCLUDE_PATH . '/piwik.js');
+ $command = "<br/><code> chmod +w $realpath<br/> chown ". Filechecks::getUserAndGroup() ." " . $realpath . "</code><br />";
+ $comment .= $this->translator->translate('CustomPiwikJs_DiagnosticPiwikJsMakeWritable', $command);
+ }
+
+ return array(DiagnosticResult::singleResult($label, DiagnosticResult::STATUS_WARNING, $comment));
+ }
+
+}
diff --git a/plugins/CustomPiwikJs/Exception/AccessDeniedException.php b/plugins/CustomPiwikJs/Exception/AccessDeniedException.php
new file mode 100644
index 0000000000..356e63e7be
--- /dev/null
+++ b/plugins/CustomPiwikJs/Exception/AccessDeniedException.php
@@ -0,0 +1,15 @@
+<?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\CustomPiwikJs\Exception;
+
+use Exception;
+
+class AccessDeniedException extends Exception
+{
+}
diff --git a/plugins/CustomPiwikJs/File.php b/plugins/CustomPiwikJs/File.php
new file mode 100644
index 0000000000..79a93e7437
--- /dev/null
+++ b/plugins/CustomPiwikJs/File.php
@@ -0,0 +1,75 @@
+<?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\CustomPiwikJs;
+
+use Piwik\Plugins\CustomPiwikJs\Exception\AccessDeniedException;
+
+class File
+{
+ /**
+ * @var string
+ */
+ private $file;
+
+ public function __construct($file)
+ {
+ $this->file = $file;
+ }
+
+ public function checkReadable()
+ {
+ if (!$this->hasReadAccess()) {
+ throw new AccessDeniedException(sprintf('The file %s is not readable', $this->file));
+ }
+ }
+
+ public function checkWritable()
+ {
+ if (!$this->hasWriteAccess()) {
+ throw new AccessDeniedException(sprintf('The file %s is not writable', $this->file));
+ }
+ }
+
+ public function save($content)
+ {
+ file_put_contents($this->file, $content);
+ }
+
+ public function getContent()
+ {
+ if (!$this->hasReadAccess()) {
+ return null;
+ }
+
+ return file_get_contents($this->file);
+ }
+
+ public function getName()
+ {
+ return basename($this->file);
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasWriteAccess()
+ {
+ return $this->hasReadAccess() && is_writable($this->file);
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasReadAccess()
+ {
+ return file_exists($this->file) && is_readable($this->file);
+ }
+
+
+}
diff --git a/plugins/CustomPiwikJs/Tasks.php b/plugins/CustomPiwikJs/Tasks.php
new file mode 100644
index 0000000000..1bb1bae384
--- /dev/null
+++ b/plugins/CustomPiwikJs/Tasks.php
@@ -0,0 +1,23 @@
+<?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\CustomPiwikJs;
+
+class Tasks extends \Piwik\Plugin\Tasks
+{
+ public function schedule()
+ {
+ $this->hourly('updateTracker');
+ }
+
+ public function updateTracker()
+ {
+ $updater = new TrackerUpdater();
+ $updater->update();
+ }
+}
diff --git a/plugins/CustomPiwikJs/TrackerUpdater.php b/plugins/CustomPiwikJs/TrackerUpdater.php
new file mode 100644
index 0000000000..6370287882
--- /dev/null
+++ b/plugins/CustomPiwikJs/TrackerUpdater.php
@@ -0,0 +1,78 @@
+<?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\CustomPiwikJs;
+
+use Piwik\Plugins\CustomPiwikJs\TrackingCode\PiwikJsManipulator;
+use Piwik\Plugins\CustomPiwikJs\TrackingCode\PluginTrackerFiles;
+
+/**
+ * Updates the Javascript file containing the Tracker.
+ */
+class TrackerUpdater
+{
+ const DEVELOPMENT_PIWIK_JS = '/js/piwik.js';
+ const ORIGINAL_PIWIK_JS = '/js/piwik.min.js';
+ const TARGET_PIWIK_JS = '/piwik.js';
+
+ /**
+ * @var File
+ */
+ private $fromFile;
+
+ /**
+ * @var File
+ */
+ private $toFile;
+
+ private $trackerFiles = array();
+
+ /**
+ * @param string|null $fromFile If null then the minified JS tracker file in /js fill be used
+ * @param string|null $toFile If null then the minified JS tracker will be updated.
+ */
+ public function __construct($fromFile = null, $toFile = null)
+ {
+ if (!isset($fromFile)) {
+ $fromFile = PIWIK_DOCUMENT_ROOT . self::ORIGINAL_PIWIK_JS;
+ }
+
+ if (!isset($toFile)) {
+ $toFile = PIWIK_DOCUMENT_ROOT . self::TARGET_PIWIK_JS;
+ }
+
+ $this->fromFile = new File($fromFile);
+ $this->toFile = new File($toFile);
+ $this->trackerFiles = new PluginTrackerFiles();
+ }
+
+ public function setTrackerFiles(PluginTrackerFiles $trackerFiles)
+ {
+ $this->trackerFiles = $trackerFiles;
+ }
+
+ public function checkWillSucceed()
+ {
+ $this->fromFile->checkReadable();
+ $this->toFile->checkWritable();
+ }
+
+ public function update()
+ {
+ if (!$this->toFile->hasWriteAccess() || !$this->fromFile->hasReadAccess()) {
+ return;
+ }
+
+ $trackingCode = new PiwikJsManipulator($this->fromFile->getContent(), $this->trackerFiles);
+ $newContent = $trackingCode->manipulateContent();
+
+ if ($newContent !== $this->toFile->getContent()) {
+ $this->toFile->save($newContent);
+ }
+ }
+}
diff --git a/plugins/CustomPiwikJs/TrackingCode/JsTestPluginTrackerFiles.php b/plugins/CustomPiwikJs/TrackingCode/JsTestPluginTrackerFiles.php
new file mode 100644
index 0000000000..773ac03286
--- /dev/null
+++ b/plugins/CustomPiwikJs/TrackingCode/JsTestPluginTrackerFiles.php
@@ -0,0 +1,27 @@
+<?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\CustomPiwikJs\TrackingCode;
+
+/**
+ * Used for when running Piwik tracker tests. We simply include all custom tracker files there.
+ */
+class JsTestPluginTrackerFiles extends PluginTrackerFiles
+{
+
+ public function __construct()
+ {
+ parent::__construct();
+ $this->ignoreMinified = true;
+ }
+
+ protected function isPluginActivated($pluginName)
+ {
+ return true;
+ }
+
+}
diff --git a/plugins/CustomPiwikJs/TrackingCode/PiwikJsManipulator.php b/plugins/CustomPiwikJs/TrackingCode/PiwikJsManipulator.php
new file mode 100644
index 0000000000..affac1fd46
--- /dev/null
+++ b/plugins/CustomPiwikJs/TrackingCode/PiwikJsManipulator.php
@@ -0,0 +1,57 @@
+<?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\CustomPiwikJs\TrackingCode;
+
+class PiwikJsManipulator
+{
+ const HOOK = '/*!!! pluginTrackerHook */';
+ /**
+ * @var string
+ */
+ private $content;
+
+ /** @var PluginTrackerFiles */
+ private $pluginTrackerFiles;
+
+ public function __construct($content, PluginTrackerFiles $pluginTrackerFiles)
+ {
+ $this->content = $content;
+ $this->pluginTrackerFiles = $pluginTrackerFiles;
+ }
+
+ public function manipulateContent()
+ {
+ $files = $this->pluginTrackerFiles->find();
+
+ foreach ($files as $file) {
+ $trackerExtension = $this->getSignatureWithContent($file->getName(), $file->getContent());
+
+ // for some reasons it is /*!!! in piwik.js minified and /*!! in js/piwik.js unminified
+ $this->content = str_replace(array(self::HOOK, '/*!! pluginTrackerHook */'), self::HOOK . $trackerExtension, $this->content);
+ }
+
+ return $this->content;
+ }
+
+ /**
+ * @param string $name
+ * @param string $content
+ * @return string
+ */
+ private function getSignatureWithContent($name, $content)
+ {
+ return sprintf(
+ "\n\n/* GENERATED: %s */\n%s\n/* END GENERATED: %s */\n",
+ $name,
+ $content,
+ $name
+ );
+ }
+
+}
diff --git a/plugins/CustomPiwikJs/TrackingCode/PluginTrackerFiles.php b/plugins/CustomPiwikJs/TrackingCode/PluginTrackerFiles.php
new file mode 100644
index 0000000000..f114565990
--- /dev/null
+++ b/plugins/CustomPiwikJs/TrackingCode/PluginTrackerFiles.php
@@ -0,0 +1,87 @@
+<?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\CustomPiwikJs\TrackingCode;
+
+use Piwik\Filesystem;
+use Piwik\Plugin;
+use Piwik\Plugins\CustomPiwikJs\File;
+
+class PluginTrackerFiles
+{
+ const TRACKER_FILE = 'tracker.js';
+ const MIN_TRACKER_FILE = 'tracker.min.js';
+
+ /**
+ * @var string
+ */
+ protected $dir;
+
+ /**
+ * @var Plugin\Manager
+ */
+ private $pluginManager;
+
+ /**
+ * @var bool
+ */
+ protected $ignoreMinified = false;
+
+ public function __construct()
+ {
+ $this->dir = PIWIK_DOCUMENT_ROOT . '/plugins/';
+ $this->pluginManager = Plugin\Manager::getInstance();
+ }
+
+ public function ignoreMinified()
+ {
+ $this->ignoreMinified = true;
+ }
+
+ /**
+ * @return File[]
+ */
+ public function find()
+ {
+ $jsFiles = array();
+
+ if (!$this->ignoreMinified) {
+ $trackerFiles = \_glob($this->dir . '*/' . self::MIN_TRACKER_FILE);
+
+ foreach ($trackerFiles as $trackerFile) {
+ $plugin = $this->getPluginNameFromFile($trackerFile);
+ if ($this->isPluginActivated($plugin)) {
+ $jsFiles[$plugin] = new File($trackerFile);
+ }
+ }
+ }
+
+ $trackerFiles = \_glob($this->dir . '*/' . self::TRACKER_FILE);
+
+ foreach ($trackerFiles as $trackerFile) {
+ $plugin = $this->getPluginNameFromFile($trackerFile);
+ if (!isset($jsFiles[$plugin])) {
+ if ($this->isPluginActivated($plugin)) {
+ $jsFiles[$plugin] = new File($trackerFile);
+ }
+ }
+ }
+
+ return $jsFiles;
+ }
+
+ protected function isPluginActivated($pluginName)
+ {
+ return $this->pluginManager->isPluginActivated($pluginName);
+ }
+
+ protected function getPluginNameFromFile($file)
+ {
+ $file = str_replace(array($this->dir, self::TRACKER_FILE, self::MIN_TRACKER_FILE), '', $file);
+ return trim($file, '/');
+ }
+}
diff --git a/plugins/CustomPiwikJs/config/config.php b/plugins/CustomPiwikJs/config/config.php
new file mode 100644
index 0000000000..cafd3336ac
--- /dev/null
+++ b/plugins/CustomPiwikJs/config/config.php
@@ -0,0 +1,7 @@
+<?php
+
+return array(
+ 'diagnostics.optional' => DI\add(array(
+ DI\get('Piwik\Plugins\CustomPiwikJs\Diagnostic\PiwikJsCheck'),
+ )),
+);
diff --git a/plugins/CustomPiwikJs/lang/en.json b/plugins/CustomPiwikJs/lang/en.json
new file mode 100644
index 0000000000..57dbea22a6
--- /dev/null
+++ b/plugins/CustomPiwikJs/lang/en.json
@@ -0,0 +1,7 @@
+{
+ "CustomPiwikJs": {
+ "DiagnosticPiwikJsWritable": "Writable JavaScript Tracker (\"/piwik.js\")",
+ "DiagnosticPiwikJsNotWritable": "The Piwik JavaScript tracker file \"/piwik.js\" is not writable which means other plugins cannot extend the JavaScript tracker. In the future even some core features might not work as expected. ",
+ "DiagnosticPiwikJsMakeWritable": "We recommend to Piwik.js writable by running this command: %s"
+ }
+} \ No newline at end of file
diff --git a/plugins/CustomPiwikJs/tests/Framework/Mock/PluginTrackerFilesMock.php b/plugins/CustomPiwikJs/tests/Framework/Mock/PluginTrackerFilesMock.php
new file mode 100644
index 0000000000..2503353ec0
--- /dev/null
+++ b/plugins/CustomPiwikJs/tests/Framework/Mock/PluginTrackerFilesMock.php
@@ -0,0 +1,36 @@
+<?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\CustomPiwikJs\tests\Framework\Mock;
+
+use Piwik\Plugins\CustomPiwikJs\File;
+use Piwik\Plugins\CustomPiwikJs\TrackingCode\PluginTrackerFiles;
+
+class PluginTrackerFilesMock extends PluginTrackerFiles
+{
+ /**
+ * @var array
+ */
+ private $files;
+
+ public function __construct($files)
+ {
+ $this->files = $files;
+ }
+
+ public function find()
+ {
+ $files = array();
+ foreach ($this->files as $file) {
+ $files[] = new File(PIWIK_DOCUMENT_ROOT . $file);
+ }
+ return $files;
+ }
+
+
+}
diff --git a/plugins/CustomPiwikJs/tests/Integration/FileTest.php b/plugins/CustomPiwikJs/tests/Integration/FileTest.php
new file mode 100644
index 0000000000..4d96bd6478
--- /dev/null
+++ b/plugins/CustomPiwikJs/tests/Integration/FileTest.php
@@ -0,0 +1,125 @@
+<?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\CustomPiwikJs\tests\Integration;
+
+use Piwik\Plugins\CustomPiwikJs\File;
+use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
+
+/**
+ * @group CustomPiwikJs
+ * @group FileTest
+ * @group File
+ * @group Plugins
+ */
+class FileTest extends IntegrationTestCase
+{
+ const NOT_EXISTING_FILE = 'notExisTinGFile.js';
+
+ /**
+ * @var string
+ */
+ private $dir = '';
+
+ public function setUp()
+ {
+ parent::setUp();
+ $this->dir = PIWIK_DOCUMENT_ROOT . '/plugins/CustomPiwikJs/tests/resources/';
+ }
+
+ public function tearDown()
+ {
+ if (file_exists($this->dir . self::NOT_EXISTING_FILE)) {
+ unlink($this->dir . self::NOT_EXISTING_FILE);
+ }
+
+ parent::tearDown();
+ }
+
+ private function makeFile($fileName = 'test.js')
+ {
+ return new File($this->dir . $fileName);
+ }
+
+ private function makeNotReadableFile()
+ {
+ return $this->makeFile(self::NOT_EXISTING_FILE);
+ }
+
+ public function test_getName()
+ {
+ $this->assertSame('test.js', $this->makeFile()->getName());
+ $this->assertSame('notExisTinGFile.js', $this->makeNotReadableFile()->getName());
+ }
+
+ public function test_hasReadAccess()
+ {
+ $this->assertTrue($this->makeFile()->hasReadAccess());
+ $this->assertFalse($this->makeNotReadableFile()->hasReadAccess());
+ }
+
+ public function test_hasWriteAccess()
+ {
+ $this->assertTrue($this->makeFile()->hasWriteAccess());
+ $this->assertFalse($this->makeNotReadableFile()->hasWriteAccess());
+ }
+
+ public function test_checkReadable_shouldNotThrowException_IfIsReadable()
+ {
+ $this->makeFile()->checkReadable();
+ $this->assertTrue(true);
+ }
+
+ public function test_checkWritable_shouldNotThrowException_IfIsWritable()
+ {
+ $this->makeFile()->checkWritable();
+ $this->assertTrue(true);
+ }
+
+ /**
+ * @expectedException \Piwik\Plugins\CustomPiwikJs\Exception\AccessDeniedException
+ * @expectedExceptionMessage not readable
+ */
+ public function test_checkReadable_shouldThrowException_IfNotIsReadable()
+ {
+ $this->makeNotReadableFile()->checkReadable();
+ }
+
+ /**
+ * @expectedException \Piwik\Plugins\CustomPiwikJs\Exception\AccessDeniedException
+ * @expectedExceptionMessage not writable
+ */
+ public function test_checkWritable_shouldThrowException_IfNotIsWritable()
+ {
+ $this->makeNotReadableFile()->checkWritable();
+ }
+
+ public function test_getContent()
+ {
+ $this->assertSame("// Hello world\nvar fooBar = 'test';", $this->makeFile()->getContent());
+ }
+
+ public function test_getContent_returnsNull_IfFileIsNotReadableOrNotExists()
+ {
+ $this->assertNull($this->makeNotReadableFile()->getContent());
+ }
+
+ public function test_save()
+ {
+ $notExistingFile = $this->makeNotReadableFile();
+ $this->assertFalse($notExistingFile->hasReadAccess());
+ $this->assertFalse($notExistingFile->hasWriteAccess());
+
+ $notExistingFile->save('myTestContent');
+
+ $this->assertEquals('myTestContent', $notExistingFile->getContent());
+ $this->assertTrue($notExistingFile->hasReadAccess());
+ $this->assertTrue($notExistingFile->hasWriteAccess());
+ }
+
+}
diff --git a/plugins/CustomPiwikJs/tests/Integration/PiwikJsManipulatorTest.php b/plugins/CustomPiwikJs/tests/Integration/PiwikJsManipulatorTest.php
new file mode 100644
index 0000000000..75c66b73f7
--- /dev/null
+++ b/plugins/CustomPiwikJs/tests/Integration/PiwikJsManipulatorTest.php
@@ -0,0 +1,73 @@
+<?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\CustomPiwikJs\tests\Integration;
+
+use Piwik\Plugins\CustomPiwikJs\tests\Framework\Mock\PluginTrackerFilesMock;
+use Piwik\Plugins\CustomPiwikJs\TrackingCode\PiwikJsManipulator;
+use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
+
+/**
+ * @group CustomPiwikJs
+ * @group PiwikJsManipulatorTest
+ * @group PiwikJsManipulator
+ * @group Plugins
+ */
+class PiwikJsManipulatorTest extends IntegrationTestCase
+{
+ private $content = 'var Piwik.js = "mytest";
+/*!!! pluginTrackerHook */
+
+var myArray = [];
+';
+
+ public function test_manipulateContent_shouldAddCodeOfTrackerPlugins()
+ {
+ $manipulator = $this->makeManipulator(array(
+ '/plugins/CustomPiwikJs/tests/resources/tracker.js',
+ '/plugins/CustomPiwikJs/tests/resources/tracker.min.js',
+ ));
+
+ $updatedContent = $manipulator->manipulateContent();
+
+ $this->assertSame('var Piwik.js = "mytest";
+/*!!! pluginTrackerHook */
+
+/* GENERATED: tracker.min.js */
+/* my license header */
+var mySecondCustomTracker = \'test\';
+/* END GENERATED: tracker.min.js */
+
+
+/* GENERATED: tracker.js */
+/** my license header*/
+var myCustomTracker = \'test\';
+
+var fooBar = \'baz\';
+/* END GENERATED: tracker.js */
+
+
+var myArray = [];
+', $updatedContent);
+ }
+
+ public function test_manipulateContent_shouldNotAddCodeOfTrackerPlugins_IfThereAreNoTrackerFiles()
+ {
+ $manipulator = $this->makeManipulator(array());
+
+ $updatedContent = $manipulator->manipulateContent();
+
+ $this->assertSame($this->content, $updatedContent);
+ }
+
+ private function makeManipulator($files)
+ {
+ return new PiwikJsManipulator($this->content, new PluginTrackerFilesMock($files));
+ }
+
+}
diff --git a/plugins/CustomPiwikJs/tests/Integration/PluginTrackerFilesTest.php b/plugins/CustomPiwikJs/tests/Integration/PluginTrackerFilesTest.php
new file mode 100644
index 0000000000..8c0cd2ee01
--- /dev/null
+++ b/plugins/CustomPiwikJs/tests/Integration/PluginTrackerFilesTest.php
@@ -0,0 +1,124 @@
+<?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\CustomPiwikJs\tests\Integration;
+
+use Piwik\Plugins\CustomPiwikJs\TrackingCode\PluginTrackerFiles;
+use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
+
+class CustomPluginTrackerFiles extends PluginTrackerFiles {
+
+ private $pluginNamesForFile = array();
+
+ public function __construct($pluginNameForRegularTrackerFile = 'CustomPiwikJs', $pluginNameForMinifiedTracker = 'CustomPiwikJs')
+ {
+ parent::__construct();
+
+ $this->dir = PIWIK_DOCUMENT_ROOT . '/plugins/CustomPiwikJs/tests/';
+
+ $this->pluginNamesForFile = array(
+ 'tracker.js' => $pluginNameForRegularTrackerFile,
+ 'tracker.min.js' => $pluginNameForMinifiedTracker
+ );
+ }
+
+ protected function getPluginNameFromFile($file)
+ {
+ $fileName = basename($file);
+ return $this->pluginNamesForFile[$fileName];
+ }
+}
+
+class CustomPluginTrackerFiles2 extends PluginTrackerFiles {
+
+ public function getPluginNameFromFile($file)
+ {
+ return parent::getPluginNameFromFile($file);
+ }
+}
+
+/**
+ * @group CustomPiwikJs
+ * @group PluginTrackerFilesTest
+ * @group PluginTrackerFiles
+ * @group Plugins
+ */
+class PluginTrackerFilesTest extends IntegrationTestCase
+{
+ public function test_find_ifAPluginDefinesAMinifiedAndARegularTrackerItShouldPreferTheMinifiedVersion()
+ {
+ $trackerFiles = new CustomPluginTrackerFiles();
+ $foundFiles = $trackerFiles->find();
+
+ $this->assertCount(1, $foundFiles);
+ $this->assertTrue(isset($foundFiles['CustomPiwikJs']));
+ $this->assertEquals('tracker.min.js', $foundFiles['CustomPiwikJs']->getName());
+ }
+
+ public function test_find_shouldIgnoreMinifiedVersion_IfRequested()
+ {
+ $trackerFiles = new CustomPluginTrackerFiles();
+ $trackerFiles->ignoreMinified();
+ $foundFiles = $trackerFiles->find();
+
+ $this->assertCount(1, $foundFiles);
+ $this->assertTrue(isset($foundFiles['CustomPiwikJs']));
+ $this->assertEquals('tracker.js', $foundFiles['CustomPiwikJs']->getName());
+ }
+
+ public function test_find_ifMultiplePluginsImplementATracker_ShouldReturnEachOfThem()
+ {
+ $trackerFiles = new CustomPluginTrackerFiles('CustomPiwikJs', 'Goals');
+ $foundFiles = $trackerFiles->find();
+
+ $this->assertCount(2, $foundFiles);
+ $this->assertTrue(isset($foundFiles['CustomPiwikJs']));
+ $this->assertTrue(isset($foundFiles['Goals']));
+ $this->assertEquals('tracker.js', $foundFiles['CustomPiwikJs']->getName());
+ $this->assertEquals('tracker.min.js', $foundFiles['Goals']->getName());
+ }
+
+ public function test_find_shouldNotReturnATrackerFile_IfPluginIsNotActivatedOrLoaded()
+ {
+ $trackerFiles = new CustomPluginTrackerFiles('MyNotExistingPlugin', 'Goals');
+ $foundFiles = $trackerFiles->find();
+
+ $this->assertCount(1, $foundFiles);
+ $this->assertTrue(isset($foundFiles['Goals']));
+ $this->assertEquals('tracker.min.js', $foundFiles['Goals']->getName());
+
+ $trackerFiles = new CustomPluginTrackerFiles('Goals', 'MyNotExistingPlugin');
+ $foundFiles = $trackerFiles->find();
+
+ $this->assertCount(1, $foundFiles);
+ $this->assertTrue(isset($foundFiles['Goals']));
+ $this->assertEquals('tracker.js', $foundFiles['Goals']->getName());
+ }
+
+ public function test_find_shouldNotReturnFileIfNoPluginActivated()
+ {
+ $trackerFiles = new CustomPluginTrackerFiles('MyNotExistingPlugin', 'MyNotExistingPlugin2');
+ $foundFiles = $trackerFiles->find();
+
+ $this->assertSame(array(), $foundFiles);
+ }
+
+ public function test_getPluginNameFromFile_shouldDetectPluginName()
+ {
+ $trackerFiles = new CustomPluginTrackerFiles2();
+ $pluginName = $trackerFiles->getPluginNameFromFile(PIWIK_DOCUMENT_ROOT . '/plugins/MyFooBarPlugin/tracker.js');
+ $this->assertSame('MyFooBarPlugin', $pluginName);
+
+ $pluginName = $trackerFiles->getPluginNameFromFile(PIWIK_DOCUMENT_ROOT . '/plugins//MyFooBarPlugin//tracker.js');
+ $this->assertSame('MyFooBarPlugin', $pluginName);
+
+ $pluginName = $trackerFiles->getPluginNameFromFile(PIWIK_DOCUMENT_ROOT . '/plugins//MyFooBarPlugin//tracker.min.js');
+ $this->assertSame('MyFooBarPlugin', $pluginName);
+ }
+
+}
diff --git a/plugins/CustomPiwikJs/tests/Integration/TrackerUpdaterTest.php b/plugins/CustomPiwikJs/tests/Integration/TrackerUpdaterTest.php
new file mode 100644
index 0000000000..240638c5e9
--- /dev/null
+++ b/plugins/CustomPiwikJs/tests/Integration/TrackerUpdaterTest.php
@@ -0,0 +1,121 @@
+<?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\CustomPiwikJs\tests\Integration;
+
+use Piwik\Plugins\CustomPiwikJs\tests\Framework\Mock\PluginTrackerFilesMock;
+use Piwik\Plugins\CustomPiwikJs\TrackerUpdater;
+use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
+
+/**
+ * @group CustomPiwikJs
+ * @group PiwikJsManipulatorTest
+ * @group PiwikJsManipulator
+ * @group Plugins
+ */
+class TrackerUpdaterTest extends IntegrationTestCase
+{
+ private $dir;
+
+ public function setUp()
+ {
+ parent::setUp();
+ $this->dir = PIWIK_DOCUMENT_ROOT . '/plugins/CustomPiwikJs/tests/resources/';
+
+ $this->cleanUp();
+ }
+
+ public function tearDown()
+ {
+ parent::tearDown();
+
+ $this->cleanUp();
+ }
+
+ private function cleanUp()
+ {
+ $target = $this->dir . 'MyTestTarget.js';
+ if (file_exists($target)) {
+ unlink($target);
+ }
+ }
+
+ private function makeUpdater($from = null, $to = null)
+ {
+ return new TrackerUpdater($from, $to);
+ }
+
+ public function test_checkWillSucceed_shouldNotThrowExceptionIfPiwikJsTargetIsWritable()
+ {
+ $updater = $this->makeUpdater();
+ $updater->checkWillSucceed();
+
+ $this->assertTrue(true);
+ }
+
+ /**
+ * @expectedException \Piwik\Plugins\CustomPiwikJs\Exception\AccessDeniedException
+ * @expectedExceptionMessage not writable
+ */
+ public function test_checkWillSucceed_shouldThrowExceptionIfTargetIsNotWritable()
+ {
+ $updater = $this->makeUpdater(null, $this->dir . 'MyNotExisIngFilessss.js');
+ $updater->checkWillSucceed();
+ }
+
+ public function test_update_shouldNotThrowAnError_IfTargetFileIsNotWritable()
+ {
+ $updater = $this->makeUpdater(null, $this->dir . 'MyNotExisIngFilessss.js');
+ $updater->update();
+ $this->assertTrue(true);
+ }
+
+ public function test_update_shouldNotWriteToFileIfThereIsNothingToChange()
+ {
+ $source = $this->dir . 'testpiwik.js';
+ $target = $this->dir . 'MyTestTarget.js';
+ file_put_contents($target, file_get_contents($source));
+ $updater = $this->makeUpdater($this->dir . 'testpiwik.js', $target);
+ $updater->setTrackerFiles(new PluginTrackerFilesMock(array()));
+ // mock that does not find any files . therefore there is nothing to di
+ $updater->update();
+
+ $this->assertSame(file_get_contents($source), file_get_contents($target));
+ }
+
+ public function test_update_targetFileIfPluginsDefineDifferentFiles()
+ {
+ $target = $this->dir . 'MyTestTarget.js';
+ file_put_contents($target, ''); // file has to exist in order to work
+
+ $updater = $this->makeUpdater($this->dir . 'testpiwik.js', $target);
+ $updater->setTrackerFiles(new PluginTrackerFilesMock(array(
+ $this->dir . 'tracker.js', $this->dir . 'tracker.min.js'
+ )));
+ $updater->update();
+
+ $this->assertSame('/** MyHeader*/
+var PiwikJs = "mytest";
+
+/*!!! pluginTrackerHook */
+
+/* GENERATED: tracker.min.js */
+
+/* END GENERATED: tracker.min.js */
+
+
+/* GENERATED: tracker.js */
+
+/* END GENERATED: tracker.js */
+
+
+var myArray = [];
+', file_get_contents($target));
+ }
+
+}
diff --git a/plugins/CustomPiwikJs/tests/System/PiwikJsContentTest.php b/plugins/CustomPiwikJs/tests/System/PiwikJsContentTest.php
new file mode 100644
index 0000000000..dd3f08ab3a
--- /dev/null
+++ b/plugins/CustomPiwikJs/tests/System/PiwikJsContentTest.php
@@ -0,0 +1,39 @@
+<?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\CustomPiwikJs\tests\System;
+
+use Piwik\Plugins\CustomPiwikJs\TrackerUpdater;
+use Piwik\Plugins\CustomPiwikJs\TrackingCode\PiwikJsManipulator;
+use Piwik\Tests\Framework\TestCase\SystemTestCase;
+
+/**
+ * @group CustomPiwikJs
+ * @group PiwikJsContentTest
+ * @group PiwikJsContent
+ * @group Plugins
+ */
+class PiwikJsContentTest extends SystemTestCase
+{
+ public function test_piwikJsAndPiwikMinJsMustHaveSameContent()
+ {
+ $piwikMin = PIWIK_DOCUMENT_ROOT . TrackerUpdater::ORIGINAL_PIWIK_JS;
+ $piwikJs = PIWIK_DOCUMENT_ROOT . TrackerUpdater::TARGET_PIWIK_JS;
+
+ $this->assertSame(file_get_contents($piwikMin), file_get_contents($piwikJs));
+ }
+
+ public function test_piwikJsContainsHook()
+ {
+ $piwikMin = PIWIK_DOCUMENT_ROOT . '/js/piwik.min.js';
+ $content = file_get_contents($piwikMin);
+
+ $this->assertContains(PiwikJsManipulator::HOOK, $content);
+ }
+
+} \ No newline at end of file
diff --git a/plugins/CustomPiwikJs/tests/resources/MyTestTarget2.js b/plugins/CustomPiwikJs/tests/resources/MyTestTarget2.js
new file mode 100644
index 0000000000..258c2d3e11
--- /dev/null
+++ b/plugins/CustomPiwikJs/tests/resources/MyTestTarget2.js
@@ -0,0 +1,16 @@
+/** MyHeader*/
+var PiwikJs = "mytest";
+
+/*!!! pluginTrackerHook */
+
+/* GENERATED: tracker.min.js */
+
+/* END GENERATED: tracker.min.js */
+
+
+/* GENERATED: tracker.js */
+
+/* END GENERATED: tracker.js */
+
+
+var myArray = [];
diff --git a/plugins/CustomPiwikJs/tests/resources/test.js b/plugins/CustomPiwikJs/tests/resources/test.js
new file mode 100644
index 0000000000..0ea6fcc24a
--- /dev/null
+++ b/plugins/CustomPiwikJs/tests/resources/test.js
@@ -0,0 +1,2 @@
+// Hello world
+var fooBar = 'test'; \ No newline at end of file
diff --git a/plugins/CustomPiwikJs/tests/resources/testpiwik.js b/plugins/CustomPiwikJs/tests/resources/testpiwik.js
new file mode 100644
index 0000000000..02b60f8bcd
--- /dev/null
+++ b/plugins/CustomPiwikJs/tests/resources/testpiwik.js
@@ -0,0 +1,6 @@
+/** MyHeader*/
+var PiwikJs = "mytest";
+
+/*!!! pluginTrackerHook */
+
+var myArray = [];
diff --git a/plugins/CustomPiwikJs/tests/resources/tracker.js b/plugins/CustomPiwikJs/tests/resources/tracker.js
new file mode 100644
index 0000000000..ae4d228f39
--- /dev/null
+++ b/plugins/CustomPiwikJs/tests/resources/tracker.js
@@ -0,0 +1,4 @@
+/** my license header*/
+var myCustomTracker = 'test';
+
+var fooBar = 'baz'; \ No newline at end of file
diff --git a/plugins/CustomPiwikJs/tests/resources/tracker.min.js b/plugins/CustomPiwikJs/tests/resources/tracker.min.js
new file mode 100644
index 0000000000..587ee0464d
--- /dev/null
+++ b/plugins/CustomPiwikJs/tests/resources/tracker.min.js
@@ -0,0 +1,2 @@
+/* my license header */
+var mySecondCustomTracker = 'test'; \ No newline at end of file
diff --git a/plugins/Live/javascripts/live.js b/plugins/Live/javascripts/live.js
index 36b59326a8..42231280f1 100644
--- a/plugins/Live/javascripts/live.js
+++ b/plugins/Live/javascripts/live.js
@@ -65,7 +65,14 @@
ajaxRequest.addParams(this.options.dataUrlParams, 'GET');
ajaxRequest.setFormat('html');
ajaxRequest.setCallback(function (r) {
- that._parseResponse(r);
+ if (that.options.replaceContent) {
+ $(that.element).html(r);
+ if (that.options.fadeInSpeed) {
+ $(that.element).effect("highlight", {}, that.options.fadeInSpeed);
+ }
+ } else {
+ that._parseResponse(r);
+ }
// add default interval to last interval if not updated or reset to default if so
if (!that.updated) {
diff --git a/tests/PHPUnit/Integration/ReleaseCheckListTest.php b/tests/PHPUnit/Integration/ReleaseCheckListTest.php
index d42a310626..bfc4ec13e3 100644
--- a/tests/PHPUnit/Integration/ReleaseCheckListTest.php
+++ b/tests/PHPUnit/Integration/ReleaseCheckListTest.php
@@ -438,8 +438,12 @@ class ReleaseCheckListTest extends \PHPUnit_Framework_TestCase
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'
+ PIWIK_DOCUMENT_ROOT . '/piwik.js',
+ 'minified /piwik.js is out of date, please re-generate the minified files using instructions in /js/README'
+ );
+ $this->assertFileEquals(PIWIK_DOCUMENT_ROOT . '/piwik-minified.js',
+ PIWIK_DOCUMENT_ROOT . '/js/piwik.min.js',
+ 'minified /js/piwik.min.js is out of date, please re-generate the minified files using instructions in /js/README'
);
}
diff --git a/tests/UI/expected-ui-screenshots b/tests/UI/expected-ui-screenshots
-Subproject 9291b72602d31ef1de5285ffa76685bab322ecf
+Subproject f1b6e9f1ae4eef30dbcd95e3995d55bb91f97e9
diff --git a/tests/angularjs/Gruntfile.js b/tests/angularjs/Gruntfile.js
index 2e50318f95..3527b5973a 100644
--- a/tests/angularjs/Gruntfile.js
+++ b/tests/angularjs/Gruntfile.js
@@ -2,6 +2,12 @@ module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
+ karma: {
+ unit: {
+ configFile: 'karma.conf.js',
+ autoWatch: true
+ }
+ },
pkg: grunt.file.readJSON('package.json'),
watch: {
scripts: {
@@ -13,7 +19,14 @@ module.exports = function(grunt) {
},
piwikjs: {
files: ['js/piwik.js'],
- tasks: ["shell:compilePiwikJs"],
+ tasks: ["shell:compilePiwikJs", "shell:updateTracker"],
+ options: {
+ spawn: false,
+ },
+ },
+ piwikjs2: {
+ files: ['plugins/*/tracker.js',],
+ tasks: ["shell:updateTracker"],
options: {
spawn: false,
},
@@ -27,6 +40,14 @@ module.exports = function(grunt) {
cwd: 'js'
}
}
+ },
+ updateTracker: {
+ command: "php console custom-piwik-js:update --ignore-minified",
+ options: {
+ execOptions: {
+ cwd: ''
+ }
+ }
}
},
"clean-pattern": {
diff --git a/tests/angularjs/karma.conf.js b/tests/angularjs/karma.conf.js
index 9525c7e06b..780fdb6d8e 100755
--- a/tests/angularjs/karma.conf.js
+++ b/tests/angularjs/karma.conf.js
@@ -20,7 +20,7 @@ module.exports = function(config) {
"libs/bower_components/angular-animate/angular-animate.js",
'libs/bower_components/angular-mocks/angular-mocks.js',
'libs/bower_components/jquery/dist/jquery.min.js',
- "libs/bower_components/jquery-ui/jquery-ui.min.js",
+ "libs/bower_components/jquery-ui/ui/minified/jquery-ui.min.js",
"plugins/CoreHome/javascripts/require.js",
"plugins/Morpheus/javascripts/piwikHelper.js",
"plugins/Morpheus/javascripts/ajaxHelper.js",
@@ -68,7 +68,7 @@ module.exports = function(config) {
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
- browsers: ['PhantomJS'],
+ browsers: [],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
diff --git a/tests/angularjs/package.json b/tests/angularjs/package.json
index 74b8e44936..0d8daedeed 100644
--- a/tests/angularjs/package.json
+++ b/tests/angularjs/package.json
@@ -24,5 +24,8 @@
"engines": {
"node": ">= 0.10.0"
},
- "version": "0.1.0"
+ "version": "0.1.0",
+ "devDependencies": {
+ "grunt-karma": "^2.0.0"
+ }
}
diff --git a/tests/javascript/index.php b/tests/javascript/index.php
index 043a9ef8c1..c03d06ba22 100644
--- a/tests/javascript/index.php
+++ b/tests/javascript/index.php
@@ -21,6 +21,20 @@ try {
$mysql = false;
}
+use \Piwik\Plugins\CustomPiwikJs\TrackerUpdater;
+use \Piwik\Plugins\CustomPiwikJs\TrackingCode\JsTestPluginTrackerFiles;
+
+$targetFileName = '/tests/resources/piwik.test.js';
+$sourceFile = PIWIK_DOCUMENT_ROOT . TrackerUpdater::DEVELOPMENT_PIWIK_JS;
+$targetFile = PIWIK_DOCUMENT_ROOT . $targetFileName;
+
+file_put_contents($targetFile, '');
+
+$updater = new TrackerUpdater($sourceFile, $targetFile);
+$updater->setTrackerFiles(new JsTestPluginTrackerFiles());
+$updater->checkWillSucceed();
+$updater->update();
+
if(file_exists("stub.tpl")) {
echo file_get_contents("stub.tpl");
}
@@ -60,7 +74,7 @@ testTrackPageViewAsync();
?>
</script>
<script src="../lib/q-1.4.1/q.js" type="text/javascript"></script>
- <script src="../../js/piwik.js?rand=<?php echo $cacheBuster ?>" type="text/javascript"></script>
+ <script src="../..<?php echo $targetFileName ?>?rand=<?php echo $cacheBuster ?>" type="text/javascript"></script>
<script src="../../plugins/Overlay/client/urlnormalizer.js" type="text/javascript"></script>
<script src="piwiktest.js" type="text/javascript"></script>
<link rel="stylesheet" href="assets/qunit.css" type="text/css" media="screen" />
@@ -1971,7 +1985,7 @@ function PiwikTest() {
});
test("API methods", function() {
- expect(70);
+ expect(71);
equal( typeof Piwik.addPlugin, 'function', 'addPlugin' );
equal( typeof Piwik.addPlugin, 'function', 'addTracker' );
@@ -2039,6 +2053,7 @@ function PiwikTest() {
equal( typeof tracker.trackGoal, 'function', 'trackGoal' );
equal( typeof tracker.trackLink, 'function', 'trackLink' );
equal( typeof tracker.trackPageView, 'function', 'trackPageView' );
+ equal( typeof tracker.trackRequest, 'function', 'trackRequest' );
// content
equal( typeof tracker.trackAllContentImpressions, 'function', 'trackAllContentImpressions' );
equal( typeof tracker.trackVisibleContentImpressions, 'function', 'trackVisibleContentImpressions' );
@@ -2997,7 +3012,7 @@ function PiwikTest() {
// Calling undefined methods should generate an error
function callNonExistingMethod() {
- _paq.push(['NonExistingFunction should error and display the error in the console.']);
+ _paq.push(['NonExistingFunction should error and display the error in the console']);
}
function callNonExistingMethodWithParameter() {
_paq.push(['NonExistingFunction should not error', 'this is a parameter']);
@@ -3172,7 +3187,7 @@ if ($mysql) {
});
test("tracking", function() {
- expect(118);
+ expect(119);
// Prevent Opera and HtmlUnit from performing the default action (i.e., load the href URL)
var stopEvent = function (evt) {
@@ -3351,6 +3366,9 @@ if ($mysql) {
var visitorIdEnd = tracker.getVisitorId();
ok( visitorIdStart == visitorIdEnd, "tracker.getVisitorId() same at the start and end of process");
+ // Tracker custom request
+ tracker.trackRequest('myFoo=bar&baz=1');
+
// Custom variables
tracker.storeCustomVariablesInCookie();
tracker.setCookieNamePrefix("PREFIX");
@@ -3495,7 +3513,7 @@ if ($mysql) {
xhr.open("GET", "piwik.php?requests=" + getToken(), false);
xhr.send(null);
results = xhr.responseText;
- equal( (/<span\>([0-9]+)\<\/span\>/.exec(results))[1], "36", "count tracking events" );
+ equal( (/<span\>([0-9]+)\<\/span\>/.exec(results))[1], "37", "count tracking events" );
// firing callback
ok( trackLinkCallbackFired, "trackLink() callback fired" );
@@ -3529,6 +3547,9 @@ if ($mysql) {
ok( /DoTrack/.test( results ), "setDoNotTrack(false)" );
ok( ! /DoNotTrack/.test( results ), "setDoNotTrack(true)" );
+ // custom tracking request
+ ok( /myFoo=bar&baz=1&idsite=1/.test( results ), "trackRequest sends custom parameters");
+
// Test Custom variables
ok( /SaveCustomVariableCookie.*&cvar=%7B%222%22%3A%5B%22cookiename2PAGE%22%2C%22cookievalue2PAGE%22%5D%7D.*&_cvar=%7B%221%22%3A%5B%22cookiename%22%2C%22cookievalue%22%5D%2C%222%22%3A%5B%22cookiename2%22%2C%22cookievalue2%22%5D%7D/.test(results), "test custom vars are set");