From d58368b37c7e04e86ac5e213194a14a7a651ae6b Mon Sep 17 00:00:00 2001 From: Matus Tomlein Date: Tue, 4 Oct 2022 07:55:16 +0200 Subject: [PATCH 1/6] Upgrade min Flutter, Dart and Android SDK versions and upgrade dependencies (close #19) PR #21 Co-authored-by: Bruno Koga --- .github/workflows/build.yml | 10 +++--- .github/workflows/publish.yml | 2 +- android/build.gradle | 8 ++--- example/android/app/build.gradle | 2 +- example/android/build.gradle | 4 +-- example/integration_test/helpers.dart | 2 +- example/ios/Podfile.lock | 2 +- example/ios/Runner/Info.plist | 2 ++ example/lib/main_page.dart | 4 +-- example/pubspec.lock | 45 ++++++++++++++++----------- example/pubspec.yaml | 12 +++---- pubspec.yaml | 12 +++---- 12 files changed, 57 insertions(+), 48 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3203ec5..04a7b3b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,7 +6,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - flutter: ['2.8.0'] + flutter: ['3.0.0'] steps: - uses: actions/checkout@v2 - uses: subosito/flutter-action@v1 @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@v2 - uses: subosito/flutter-action@v1 with: - flutter-version: '2.8.0' + flutter-version: '3.0.0' channel: 'stable' - run: flutter pub get - run: flutter analyze @@ -60,7 +60,7 @@ jobs: # -- Integration tests -- - uses: subosito/flutter-action@v1 with: - flutter-version: '2.8.0' + flutter-version: '3.0.0' channel: 'stable' - name: Run Flutter Driver tests @@ -108,7 +108,7 @@ jobs: - uses: subosito/flutter-action@v1 with: - flutter-version: '2.8.0' + flutter-version: '3.0.0' channel: 'stable' - run: "flutter clean" @@ -146,7 +146,7 @@ jobs: # -- Integration tests -- - uses: subosito/flutter-action@v1 with: - flutter-version: '2.8.0' + flutter-version: '3.0.0' channel: 'stable' - run: chromedriver --port=4444 & diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 1997545..4ef2c24 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - flutter: ['2.8.0'] + flutter: ['3.0.0'] steps: - uses: actions/checkout@v2 - uses: subosito/flutter-action@v1 diff --git a/android/build.gradle b/android/build.gradle index f122870..1982482 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,14 +2,14 @@ group 'com.snowplowanalytics.snowplow_tracker' version '1.0-SNAPSHOT' buildscript { - ext.kotlin_version = '1.4.32' + ext.kotlin_version = '1.7.10' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' + classpath 'com.android.tools.build:gradle:4.1.3' classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } @@ -27,7 +27,7 @@ apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' android { - compileSdkVersion 30 + compileSdkVersion 31 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -43,7 +43,7 @@ android { } defaultConfig { - minSdkVersion 16 + minSdkVersion 21 } } diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 87853a4..132ca8a 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -65,5 +65,5 @@ flutter { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "com.squareup.okhttp3:okhttp:4.9.3" + implementation "com.squareup.okhttp3:okhttp:4.10.0" } diff --git a/example/android/build.gradle b/example/android/build.gradle index 6a9509c..28c7fab 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlin_version = '1.4.32' + ext.kotlin_version = '1.7.10' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.0.2' + classpath 'com.android.tools.build:gradle:7.0.4' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/example/integration_test/helpers.dart b/example/integration_test/helpers.dart index 1690202..a3899cd 100644 --- a/example/integration_test/helpers.dart +++ b/example/integration_test/helpers.dart @@ -28,7 +28,7 @@ class SnowplowTests { } static Future resetMicro() async { - await http.get(Uri.parse(microEndpoint + '/micro/reset')); + await http.get(Uri.parse('$microEndpoint/micro/reset')); await Future.delayed(const Duration(seconds: 1), () {}); } diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index a8f9395..3384557 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -38,4 +38,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c -COCOAPODS: 1.11.2 +COCOAPODS: 1.11.3 diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index 82d988f..73ecc60 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -43,5 +43,7 @@ UIViewControllerBasedStatusBarAppearance + CADisableMinimumFrameDurationOnPhone + diff --git a/example/lib/main_page.dart b/example/lib/main_page.dart index 4929ab5..2b5629f 100644 --- a/example/lib/main_page.dart +++ b/example/lib/main_page.dart @@ -15,7 +15,7 @@ class MainPage extends StatefulWidget { final SnowplowTracker tracker; @override - _MainPageState createState() => _MainPageState(); + State createState() => _MainPageState(); } class _MainPageState extends State with WidgetsBindingObserver { @@ -38,7 +38,7 @@ class _MainPageState extends State with WidgetsBindingObserver { updateState(); - WidgetsBinding.instance?.addObserver(this); + WidgetsBinding.instance.addObserver(this); } Future updateState() async { diff --git a/example/pubspec.lock b/example/pubspec.lock index 7352fa5..3ffbe45 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,7 +7,7 @@ packages: name: archive url: "https://pub.dartlang.org" source: hosted - version: "3.1.6" + version: "3.1.11" args: dependency: transitive description: @@ -56,7 +56,7 @@ packages: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0" + version: "1.16.0" crypto: dependency: transitive description: @@ -70,14 +70,14 @@ packages: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "1.0.5" fake_async: dependency: transitive description: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.0" file: dependency: transitive description: @@ -101,14 +101,14 @@ packages: name: flutter_lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.1" flutter_markdown: dependency: "direct main" description: name: flutter_markdown url: "https://pub.dartlang.org" source: hosted - version: "0.6.9" + version: "0.6.12" flutter_test: dependency: "direct dev" description: flutter @@ -130,7 +130,7 @@ packages: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.13.4" + version: "0.13.5" http_parser: dependency: transitive description: @@ -149,21 +149,21 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.3" + version: "0.6.4" lints: dependency: transitive description: name: lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "2.0.0" markdown: dependency: transitive description: name: markdown url: "https://pub.dartlang.org" source: hosted - version: "4.0.1" + version: "6.0.1" matcher: dependency: transitive description: @@ -171,6 +171,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.12.11" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.4" meta: dependency: transitive description: @@ -184,14 +191,14 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.8.1" platform: dependency: transitive description: name: platform url: "https://pub.dartlang.org" source: hosted - version: "3.0.2" + version: "3.1.0" process: dependency: transitive description: @@ -217,7 +224,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" stack_trace: dependency: transitive description: @@ -259,7 +266,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.3" + version: "0.4.9" typed_data: dependency: transitive description: @@ -273,21 +280,21 @@ packages: name: uuid url: "https://pub.dartlang.org" source: hosted - version: "3.0.5" + version: "3.0.6" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.2" vm_service: dependency: transitive description: name: vm_service url: "https://pub.dartlang.org" source: hosted - version: "7.3.0" + version: "8.2.2" webdriver: dependency: transitive description: @@ -296,5 +303,5 @@ packages: source: hosted version: "3.0.0" sdks: - dart: ">=2.15.0 <3.0.0" - flutter: ">=2.8.0" + dart: ">=2.17.0 <3.0.0" + flutter: ">=3.0.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 4fea863..1f5f104 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -6,7 +6,7 @@ description: Demonstrates how to use the snowplow_tracker plugin. publish_to: 'none' # Remove this line if you wish to publish to pub.dev environment: - sdk: ">=2.15.0 <3.0.0" + sdk: ">=2.17.0 <3.0.0" # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -17,7 +17,7 @@ environment: dependencies: flutter: sdk: flutter - uuid: ^3.0.5 + uuid: ^3.0.6 snowplow_tracker: # When depending on this package from a real application you should use: @@ -29,23 +29,23 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.2 + cupertino_icons: ^1.0.5 - flutter_markdown: ^0.6.9 + flutter_markdown: ^0.6.12 dev_dependencies: integration_test: sdk: flutter flutter_test: sdk: flutter - http: ^0.13.3 + http: ^0.13.5 # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. - flutter_lints: ^1.0.0 + flutter_lints: ^2.0.1 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/pubspec.yaml b/pubspec.yaml index 36d13dc..6fe76fa 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,22 +5,22 @@ homepage: https://github.com/snowplow-incubator/snowplow-flutter-tracker repository: https://github.com/snowplow-incubator/snowplow-flutter-tracker environment: - sdk: ">=2.15.0 <3.0.0" - flutter: ">=2.8.0" + sdk: ">=2.17.0 <3.0.0" + flutter: ">=3.0.0" dependencies: flutter: sdk: flutter flutter_web_plugins: sdk: flutter - js: ^0.6.3 - uuid: ^3.0.5 + js: ^0.6.4 + uuid: ^3.0.6 dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^1.0.0 - http: ^0.13.3 + flutter_lints: ^2.0.1 + http: ^0.13.5 flutter: plugin: From 66396a12c5bae2456d765e8b8449e62ac514d973 Mon Sep 17 00:00:00 2001 From: Matus Tomlein Date: Wed, 5 Oct 2022 15:35:38 +0200 Subject: [PATCH 2/6] Remove loading custom JavaScript for session context and reading cookies (close #13) PR #20 --- README.md | 2 +- doc/01-getting-started.md | 2 +- example/lib/overview.dart | 2 +- example/web/sp.js | 4 +- lib/js/sp_session_context_plugin.js | 115 ------------------ lib/snowplow_tracker_plugin_web.dart | 25 ---- .../configurations/configuration_reader.dart | 7 +- .../tracker_configuration_reader.dart | 3 + lib/src/web/snowplow_tracker_controller.dart | 24 ++-- lib/src/web/sp.dart | 15 --- pubspec.yaml | 3 - 11 files changed, 27 insertions(+), 175 deletions(-) delete mode 100644 lib/js/sp_session_context_plugin.js diff --git a/README.md b/README.md index 525c8bf..7e9a4c7 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ import 'package:snowplow_tracker/snowplow_tracker.dart' If using the tracker within a Flutter app for Web, you will also need to import the Snowplow JavaScript Tracker in your `index.html` file. Please load the JS tracker with the Snowplow tag as [described in the official documentation](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-trackers/javascript-tracker/javascript-tracker-v3/tracker-setup/loading/). Do not change the global function name `snowplow` that is used to access the tracker – the Flutter APIs assume that it remains the default as shown in documentation. -Make sure to use JavaScript tracker version `3.2` or newer. You may also refer to the [example project](https://github.com/snowplow-incubator/snowplow-flutter-tracker/tree/main/example) in the Flutter tracker repository to see this in action. +Make sure to use JavaScript tracker version `3.5` or newer. You may also refer to the [example project](https://github.com/snowplow-incubator/snowplow-flutter-tracker/tree/main/example) in the Flutter tracker repository to see this in action. ### Using the Tracker diff --git a/doc/01-getting-started.md b/doc/01-getting-started.md index a960b8d..7bdec40 100644 --- a/doc/01-getting-started.md +++ b/doc/01-getting-started.md @@ -29,7 +29,7 @@ import 'package:snowplow_tracker/snowplow_tracker.dart' If using the tracker within a Flutter app for Web, you will also need to import the Snowplow JavaScript Tracker in your `index.html` file. Please load the JS tracker with the Snowplow tag as [described in the official documentation](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-trackers/javascript-tracker/javascript-tracker-v3/tracker-setup/loading/). Do not change the global function name `snowplow` that is used to access the tracker – the Flutter APIs assume that it remains the default as shown in documentation. -Make sure to use JavaScript tracker version `3.2` or newer. You may also refer to the [example project](https://github.com/snowplow-incubator/snowplow-flutter-tracker/tree/main/example) in the Flutter tracker repository to see this in action. +Make sure to use JavaScript tracker version `3.5` or newer. You may also refer to the [example project](https://github.com/snowplow-incubator/snowplow-flutter-tracker/tree/main/example) in the Flutter tracker repository to see this in action. ## Initialization diff --git a/example/lib/overview.dart b/example/lib/overview.dart index da2341d..0063291 100644 --- a/example/lib/overview.dart +++ b/example/lib/overview.dart @@ -40,7 +40,7 @@ import 'package:snowplow_tracker/snowplow_tracker.dart' If using the tracker within a Flutter app for Web, you will also need to import the Snowplow JavaScript Tracker in your `index.html` file. Please load the JS tracker with the Snowplow tag as [described in the official documentation](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-trackers/javascript-tracker/javascript-tracker-v3/tracker-setup/loading/). Do not change the global function name `snowplow` that is used to access the tracker – the Flutter APIs assume that it remains the default as shown in documentation. -Make sure to use JavaScript tracker version `3.2` or newer. You may also refer to the [example project](https://github.com/snowplow-incubator/snowplow-flutter-tracker/tree/main/example) in the Flutter tracker repository to see this in action. +Make sure to use JavaScript tracker version `3.5` or newer. You may also refer to the [example project](https://github.com/snowplow-incubator/snowplow-flutter-tracker/tree/main/example) in the Flutter tracker repository to see this in action. ### Using the Tracker diff --git a/example/web/sp.js b/example/web/sp.js index 70638bd..40a49a9 100644 --- a/example/web/sp.js +++ b/example/web/sp.js @@ -1,8 +1,8 @@ /*! - * Web analytics for Snowplow v3.2.3 (http://bit.ly/sp-js) + * Web analytics for Snowplow v3.6.0 (http://bit.ly/sp-js) * Copyright 2022 Snowplow Analytics Ltd, 2010 Anthon Pang * Licensed under BSD-3-Clause */ -"use strict";!function(){function e(e,n){var t,o={};for(t in e)Object.prototype.hasOwnProperty.call(e,t)&&0>n.indexOf(t)&&(o[t]=e[t]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(t=Object.getOwnPropertySymbols(e);rn.indexOf(t[r])&&Object.prototype.propertyIsEnumerable.call(e,t[r])&&(o[t[r]]=e[t[r]])}return o}function n(e,n,t){if(t||2===arguments.length)for(var o,r=0,a=n.length;r=e.length}function g(e){return p(e)||m(e)}function v(e){return!(!Array.isArray(e)||2!==e.length)&&(Array.isArray(e[1])?p(e[0])&&e[1].every(g):p(e[0])&&g(e[1]))}function h(e){return!(!Array.isArray(e)||2!==e.length)&&(!!function(e){var n=0;if(null!=e&&"object"==typeof e&&!Array.isArray(e)){if(Object.prototype.hasOwnProperty.call(e,"accept")){if(!d(e.accept))return!1;n+=1}if(Object.prototype.hasOwnProperty.call(e,"reject")){if(!d(e.reject))return!1;n+=1}return 0=n}return!1}(e[0])&&(Array.isArray(e[1])?e[1].every(g):g(e[1])))}function y(e){return v(e)||h(e)}function w(e,n){if(!l(e))return!1;if(e=u(e),n=null!==(n=/^iglu:([a-zA-Z0-9-_.]+)\/([a-zA-Z0-9-_]+)\/jsonschema\/([1-9][0-9]*)-(0|[1-9][0-9]*)-(0|[1-9][0-9]*)$/.exec(n))?n.slice(1,6):void 0,e&&n){if(!function(e,n){if(n=n.split("."),e=e.split("."),n&&e){if(n.length!==e.length)return!1;for(var t=0;tt;t++)if(!k(e[t],n[t]))return!1;return!0}return!1}function k(e,n){return e&&n&&"*"===e||e===n}function b(e){return Array.isArray(e)?e:[e]}function A(e,n,t,o){var r;return e=b(e).map((function(e){e:if(m(e))e=[e];else{if(p(e)){n:{var r=void 0;try{if(r=e({event:n.getPayload(),eventType:t,eventSchema:o}),Array.isArray(r)&&r.every(m)||m(r)){var a=r;break n}a=void 0;break n}catch(e){}a=void 0}if(m(a)){e=[a];break e}if(Array.isArray(a)){e=a;break e}}e=void 0}if(e&&0!==e.length)return e})),(r=[]).concat.apply(r,e.filter((function(e){return null!=e&&e.filter(Boolean)})))}function P(e){void 0===e&&(e={});var n,t,o,r,c,s,u,l=e.base64,f=e.corePlugins,d=null!=f?f:[];n=null==l||l,t=d,o=e.callback,r=function(e){return{addPluginContexts:function(n){var t=null!=n?n:[];return e.forEach((function(e){try{e.contexts&&t.push.apply(t,e.contexts())}catch(e){Ue.error("Error adding plugin contexts",e)}})),t}}}(t),c=i(),s=n,u={};var m=Pe(Pe({},e={track:function(e,n,a){e.withJsonProcessor(function(e){return function(n,t){for(var o=0;o>18&63,d=p>>12&63,m=p>>6&63,p&=63,l[u++]=Be.charAt(f)+Be.charAt(d)+Be.charAt(m)+Be.charAt(p)}while(s=o?n+=1:2047>=o?n+=2:55296<=o&&57343>=o?(n+=4,t++):n=65535>o?n+3:n+4}return n}function p(e){for(void 0===e&&(e=!1);T.length&&"string"!=typeof T[0]&&"object"!=typeof T[0];)T.shift();if(1>T.length)P=!1;else{if(!w||"string"!=typeof w.valueOf())throw"No collector configured";if(P=!0,C){var n=function(e){for(var n=0,t=0;n=i);)n+=1;return n},o=void 0;if(I(T))var r=g(o=w,!0,e),a=n(T);else o=y(T[0]),r=g(o,!1,e),a=1;var c=setTimeout((function(){r.abort(),P=!1}),u),f=function(e){for(var n=0;nr.status?(clearTimeout(c),f(a)):4===r.readyState&&400<=r.status&&(clearTimeout(c),P=!1)},I(T)){if(0<(n=T.slice(0,a)).length){if(e=!1,n=n.map((function(e){return e.evt})),S){var d=new Blob([v(h(n))],{type:"application/json"});try{e=navigator.sendBeacon(o,d)}catch(n){e=!1}}!0===e?f(a):r.send(v(h(n)))}}else r.send()}else if(l||I(T))P=!1;else{o=new Image(1,1);var m=!0;o.onload=function(){m&&(m=!1,T.shift(),t&&L(E,JSON.stringify(T.slice(0,s))),p())},o.onerror=function(){m&&(P=m=!1)},o.src=y(T[0]),setTimeout((function(){m&&P&&(m=!1,p())}),u)}}}function g(e,n,t){var o=new XMLHttpRequest;for(var r in n?(o.open("POST",e,!t),o.setRequestHeader("Content-Type","application/json; charset=UTF-8")):o.open("GET",e,!t),o.withCredentials=d,l&&o.setRequestHeader("SP-Anonymous","*"),f)Object.prototype.hasOwnProperty.call(f,r)&&o.setRequestHeader(r,f[r]);return o}function v(e){return JSON.stringify({schema:"iglu:com.snowplowanalytics.snowplow/payload_data/jsonschema/1-0-4",data:e})}function h(e){for(var n=(new Date).getTime().toString(),t=0;t=i)return Ue.warn("Event ("+e.bytes+"B) too big, max is "+i),void g(w,!0,!1).send(v(h([e.evt])));T.push(e)}else{var o,r=(n=T).push,c="?",u={co:!0,cx:!0},l=!0;for(o in e)e.hasOwnProperty(o)&&!u.hasOwnProperty(o)&&(l?l=!1:c+="&",c+=encodeURIComponent(o)+"="+encodeURIComponent(e[o]));for(var f in u)e.hasOwnProperty(f)&&u.hasOwnProperty(f)&&(c+="&"+f+"="+encodeURIComponent(e[f]));r.call(n,c)}e=!1,t&&(e=L(E,JSON.stringify(T.slice(0,s)))),P||e&&!(T.length>=a)||p()},executeQueue:function(){P||p()},setUseLocalStorage:function(e){t=e},setAnonymousTracking:function(e){l=e},setCollectorUrl:function(e){w=e+x},setBufferSize:function(e){a=e}}}function J(e,n,t){return"translate.googleusercontent.com"===e?(""===t&&(t=n),e=E(n=null!=(e=(e=/^(?:https?|ftp)(?::\/*(?:[^?]+))([?][^#]+)/.exec(n))&&1<(null==e?void 0:e.length)?N("u",e[1]):null)?e:"")):"cc.bingj.com"!==e&&"webcache.googleusercontent.com"!==e||(e=E(n=document.links[0].href)),[e,n,t]}function Y(e,n,t,r,a,i){void 0===i&&(i={});var c=[];e=function(e,n,t,r,a,i){function s(){(Be=J(window.location.hostname,window.location.href,I()))[1]!==Me&&(Fe=I(Me)),ze=j(Be[0]),Me=Be[1]}function u(e){var n=(new Date).getTime();if(null!=(e=e.currentTarget)&&e.href){n="_sp="+xe+"."+n;var t=e.href.split("#"),o=t[0].split("?"),r=o.shift();if(o=o.join("?")){for(var a=!0,i=o.split("&"),c=0;cDate.now())var o=n.getItem(e);else n.removeItem(e),n.removeItem(e+".expires"),o=void 0}catch(e){o=void 0}return o}if("cookie"==cn||"cookieAndLocalStorage"==cn)return z(e)}function p(){s(),Oe=Re((We||ze)+(Xe||"/")).slice(0,4)}function g(){Ae=(new Date).getTime()}function v(){var e=h(),n=e[0];n_e&&(_e=n),(e=e[1])Ce&&(Ce=e),g()}function h(){var e=document.documentElement;return e?[e.scrollLeft||window.pageXOffset,e.scrollTop||window.pageYOffset]:[0,0]}function y(){var e=h(),n=e[0];_e=Te=n,Ce=Se=e=e[1]}function w(){b(Ke+"ses."+Oe,"*",tn)}function k(e,n,t,o,r,a){b(Ke+"id."+Oe,e+"."+n+"."+t+"."+o+"."+r+"."+a,nn)}function b(e,n,t){an&&!on||("localStorage"==cn?L(e,n,t):("cookie"==cn||"cookieAndLocalStorage"==cn)&&z(e,n,t,Xe,We,Qe,Ze))}function A(e){var n=Ke+"id."+Oe,t=Ke+"ses."+Oe;B(n),B(t),z(n,"",-1,"/",We,Qe,Ze),z(t,"",-1,"/",We,Qe,Ze),null!=e&&e.preserveSession||(Ee=Le.v4(),un=0),null!=e&&e.preserveUser||(xe=Le.v4(),je=null)}function T(e){e&&e.stateStorageStrategy&&(i.stateStorageStrategy=e.stateStorageStrategy,cn=me(i)),an=!!i.anonymousTracking,on=pe(i),rn=ge(i),ln.setUseLocalStorage("localStorage"==cn||"cookieAndLocalStorage"==cn),ln.setAnonymousTracking(rn)}function _(){if(!an||on){var e="none"!=cn&&!!m("ses"),n=S();n[1]?xe=n[1]:(xe=an?"":Le.v4(),n[1]=xe),Ee=n[6],e||(n[3]++,Ee=Le.v4(),n[6]=Ee,n[5]=n[4]),"none"!=cn&&(w(),n[4]=Math.round((new Date).getTime()/1e3),n.shift(),k.apply(null,n))}}function S(){if("none"==cn)return[];var e=Math.round((new Date).getTime()/1e3),n=m("id");return n?(e=n.split(".")).unshift("0"):e=["1",xe,e,0,e,""],e[6]&&"undefined"!==e[6]||(e[6]=Le.v4()),e}function O(e){return 0===e.indexOf("http")?e:("https:"===document.location.protocol?"https":"http")+"://"+e}function M(){fn&&null!=a.pageViewId||(a.pageViewId=Le.v4())}function U(){return null==a.pageViewId&&(a.pageViewId=Le.v4()),a.pageViewId}function F(e){var n=e.title,t=e.context,r=e.timestamp;if(e=e.contextCallback,s(),dn&&M(),dn=!0,Je=document.title,n=x((ye=n)||Je),Ie.track(function(e){var n=e.pageUrl,t=e.pageTitle;e=e.referrer;var r=o();return r.add("e","pv"),r.add("url",n),r.add("page",t),r.add("refr",e),r}({pageUrl:f(he||Me),pageTitle:n,referrer:f(ve||Fe)}),(t||[]).concat(e?e():[]),r),r=new Date,n=!1,mn.enabled&&!mn.installed){n=mn.installed=!0;var a={update:function(){if("undefined"!=typeof window&&"function"==typeof window.addEventListener){var e=!1,n=Object.defineProperty({},"passive",{get:function(){e=!0},set:function(){}}),t=function(){};window.addEventListener("testPassiveEventSupport",t,n),window.removeEventListener("testPassiveEventSupport",t,n),a.hasSupport=e}}};a.update();var i="onwheel"in document.createElement("div")?"wheel":void 0!==document.onmousewheel?"mousewheel":"DOMMouseScroll";Object.prototype.hasOwnProperty.call(a,"hasSupport")?D(document,i,g,{passive:!0}):D(document,i,g),y(),i=function(e,n){return void 0===n&&(n=g),function(e){return D(document,e,n)}},"click mouseup mousedown mousemove keypress keydown keyup".split(" ").forEach(i(document)),["resize","focus","blur"].forEach(i(window)),i(window,v)("scroll")}if(mn.enabled&&(Ye||n))for(r in Ae=r.getTime(),r=void 0,mn.configurations)(n=mn.configurations[r])&&(window.clearInterval(n.activityInterval),V(n,t,e))}function V(e,n,t){var o=function(e,n){s(),e({context:n,pageViewId:U(),minXOffset:Te,minYOffset:Se,maxXOffset:_e,maxYOffset:Ce}),y()},r=function(){Ae+e.configHeartBeatTimer>(new Date).getTime()&&o(e.callback,(n||[]).concat(t?t():[]))};e.activityInterval=0!=e.configMinimumVisitLength?window.setTimeout((function(){Ae+e.configMinimumVisitLength>(new Date).getTime()&&o(e.callback,(n||[]).concat(t?t():[])),e.activityInterval=window.setInterval(r,e.configHeartBeatTimer)}),e.configMinimumVisitLength):window.setInterval(r,e.configHeartBeatTimer)}function H(e){var n=e.minimumVisitLength,t=e.heartbeatDelay;if(e=e.callback,C(n)&&C(t))return{configMinimumVisitLength:1e3*n,configHeartBeatTimer:1e3*t,callback:e};Ue.error("Activity tracking minimumVisitLength & heartbeatDelay must be integers")}function R(e){var n=e.context,t=e.minXOffset,r=e.minYOffset,a=e.maxXOffset,i=e.maxYOffset;(e=document.title)!==Je&&(Je=e,ye=void 0);var c=(e=Ie).track,s=f(he||Me),u=x(ye||Je),l=f(ve||Fe);t=Math.round(t),a=Math.round(a),r=Math.round(r),i=Math.round(i);var d=o();d.add("e","pp"),d.add("url",s),d.add("page",u),d.add("refr",l),t&&!isNaN(Number(t))&&d.add("pp_mix",t.toString()),a&&!isNaN(Number(a))&&d.add("pp_max",a.toString()),r&&!isNaN(Number(r))&&d.add("pp_miy",r.toString()),i&&!isNaN(Number(i))&&d.add("pp_may",i.toString()),c.call(e,d,n)}var G,Y,K,W,X,Q,Z,$,ee,ne,te,oe,re,ae,ie,ce,se,ue,le,fe,de;i.eventMethod=null!==(G=i.eventMethod)&&void 0!==G?G:"post";var me=function(e){var n;return null!==(n=e.stateStorageStrategy)&&void 0!==n?n:"cookieAndLocalStorage"},pe=function(e){var n,t;return"boolean"!=typeof e.anonymousTracking&&(null!==(t=!0===(null===(n=e.anonymousTracking)||void 0===n?void 0:n.withSessionTracking))&&void 0!==t&&t)},ge=function(e){var n,t;return"boolean"!=typeof e.anonymousTracking&&(null!==(t=!0===(null===(n=e.anonymousTracking)||void 0===n?void 0:n.withServerAnonymisation))&&void 0!==t&&t)};c.push({beforeTrack:function(e){var n=Math.round((new Date).getTime()/1e3),t=m("ses"),o=S(),r=o[0],a=o[1],i=o[2],c=o[3],u=o[4],l=o[5];o=o[6];var d=!!be&&!!z(be);en||d?A():("0"===r?(Ee=o,t||"none"==cn||(c++,l=u,Ee=Le.v4()),un=c):(new Date).getTime()-sn>1e3*tn&&(Ee=Le.v4(),un++),t=e.add,"innerWidth"in window?(r=window.innerWidth,c=window.innerHeight):(r=(c=document.documentElement||document.body).clientWidth,c=c.clientHeight),t.call(e,"vp",0<=r&&0<=c?r+"x"+c:null),t=e.add,c=document.documentElement,u=document.body,r=Math.max(c.clientWidth,c.offsetWidth,c.scrollWidth),c=Math.max(c.clientHeight,c.offsetHeight,c.scrollHeight,u?Math.max(u.offsetHeight,u.scrollHeight):0),r=isNaN(r)||isNaN(c)?"":r+"x"+c,t.call(e,"ds",r),e.add("vid",on?un:an?null:un),e.add("sid",on?Ee:an?null:Ee),e.add("duid",an?null:a),e.add("uid",an?null:je),s(),e.add("refr",f(ve||Fe)),e.add("url",f(he||Me)),"none"!=cn&&(k(a,i,un,n,l,Ee),w()),sn=(new Date).getTime())}}),(null===(K=null===(Y=null==i?void 0:i.contexts)||void 0===Y?void 0:Y.webPage)||void 0===K||K)&&c.push({contexts:function(){return[{schema:"iglu:com.snowplowanalytics.snowplow/web_page/jsonschema/1-0-0",data:{id:U()}}]}}),c.push.apply(c,null!==(W=i.plugins)&&void 0!==W?W:[]);var ve,he,ye,we,ke,be,Ae,Te,_e,Se,Ce,Oe,xe,Ee,je,Ie=P({base64:i.encodeBase64,corePlugins:c,callback:function(e){var n=!!be&&!!z(be);en||n||ln.enqueueRequest(e.build(),He)}}),De=navigator.userLanguage||navigator.language,Ne=document.characterSet||document.charset,Be=J(window.location.hostname,window.location.href,I()),ze=j(Be[0]),Me=Be[1],Fe=Be[2],Ve=null!==(X=i.platform)&&void 0!==X?X:"web",He=O(r),Ge=null!==(Q=i.postPath)&&void 0!==Q?Q:"/com.snowplowanalytics.snowplow/tp2",qe=null!==(Z=i.appId)&&void 0!==Z?Z:"",Je=document.title,Ye=null===($=i.resetActivityTrackingOnPageView)||void 0===$||$,Ke=null!==(ee=i.cookieName)&&void 0!==ee?ee:"_sp_",We=null!==(ne=i.cookieDomain)&&void 0!==ne?ne:void 0,Xe="/",Qe=null!==(te=i.cookieSameSite)&&void 0!==te?te:"None",Ze=null===(oe=i.cookieSecure)||void 0===oe||oe,$e=navigator.doNotTrack||navigator.msDoNotTrack||window.doNotTrack,en=void 0!==i.respectDoNotTrack&&(i.respectDoNotTrack&&("yes"===$e||"1"===$e)),nn=null!==(re=i.cookieLifetime)&&void 0!==re?re:63072e3,tn=null!==(ae=i.sessionCookieTimeout)&&void 0!==ae?ae:1800,on=pe(i),rn=ge(i),an=!!i.anonymousTracking,cn=me(i),sn=(new Date).getTime(),un=1,ln=q(e,a,"localStorage"==cn||"cookieAndLocalStorage"==cn,i.eventMethod,Ge,null!==(ie=i.bufferSize)&&void 0!==ie?ie:1,null!==(ce=i.maxPostBytes)&&void 0!==ce?ce:4e4,null===(se=i.useStm)||void 0===se||se,null!==(ue=i.maxLocalStorageQueueSize)&&void 0!==ue?ue:1e3,null!==(le=i.connectionTimeout)&&void 0!==le?le:5e3,rn,null!==(fe=i.customHeaders)&&void 0!==fe?fe:{},null===(de=i.withCredentials)||void 0===de||de),fn=!1,dn=!1,mn={enabled:!1,installed:!1,configurations:{}};return i.hasOwnProperty("discoverRootDomain")&&i.discoverRootDomain&&(We=function(e,n){for(var t=window.location.hostname,o="_sp_root_domain_test_"+(new Date).getTime(),r="_test_value_"+(new Date).getTime(),a=t.split("."),i=a.length-1;0<=i;){var c=a.slice(i,a.length).join(".");if(z(o,r,0,"/",c,e,n),z(o)===r){for(z(o,"",-1,"/",c,e,n),t=document.cookie.split("; "),o=[],r=0;rn;n++)0==(3&n)&&(e=4294967296*Math.random()),o[n]=e>>>((3&n)<<3)&255;return o}}})),_e=[],Se=0;256>Se;++Se)_e[Se]=(Se+256).toString(16).substr(1);var Ce,Oe,xe=function(e,n){return n=n||0,[_e[e[n++]],_e[e[n++]],_e[e[n++]],_e[e[n++]],"-",_e[e[n++]],_e[e[n++]],"-",_e[e[n++]],_e[e[n++]],"-",_e[e[n++]],_e[e[n++]],"-",_e[e[n++]],_e[e[n++]],_e[e[n++]],_e[e[n++]],_e[e[n++]],_e[e[n++]]].join("")},Ee=0,je=0,Ie=function(e,n,t){if(t=n&&t||0,"string"==typeof e&&(n="binary"===e?Array(16):null,e=null),(e=(e=e||{}).random||(e.rng||Te)())[6]=15&e[6]|64,e[8]=63&e[8]|128,n)for(var o=0;16>o;++o)n[t+o]=e[o];return n||xe(e)};Ie.v1=function(e,n,t){t=n&&t||0;var o=n||[],r=(e=e||{}).node||Ce,a=void 0!==e.clockseq?e.clockseq:Oe;if(null==r||null==a){var i=Te();null==r&&(r=Ce=[1|i[0],i[1],i[2],i[3],i[4],i[5]]),null==a&&(a=Oe=16383&(i[6]<<8|i[7]))}i=void 0!==e.msecs?e.msecs:(new Date).getTime();var c=void 0!==e.nsecs?e.nsecs:je+1,s=i-Ee+(c-je)/1e4;if(0>s&&void 0===e.clockseq&&(a=a+1&16383),(0>s||i>Ee)&&void 0===e.nsecs&&(c=0),1e4<=c)throw Error("uuid.v1(): Can't create more than 10M uuids/sec");for(Ee=i,je=c,Oe=a,e=(1e4*(268435455&(i+=122192928e5))+c)%4294967296,o[t++]=e>>>24&255,o[t++]=e>>>16&255,o[t++]=e>>>8&255,o[t++]=255&e,e=i/4294967296*1e4&268435455,o[t++]=e>>>8&255,o[t++]=255&e,o[t++]=e>>>24&15|16,o[t++]=e>>>16&255,o[t++]=a>>>8|128,o[t++]=255&a,a=0;6>a;++a)o[t+a]=r[a];return n||xe(o)};var De,Ne,Le=Ie.v4=Ie,Be="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";(Ne=De||(De={}))[Ne.none=0]="none",Ne[Ne.error=1]="error",Ne[Ne.warn=2]="warn",Ne[Ne.debug=3]="debug",Ne[Ne.info=4]="info";var ze,Me,Ue=function(e){return void 0===e&&(e=De.warn),{setLogLevel:function(n){e=De[n]?n:De.warn},warn:function(t,o){for(var r=[],a=2;a=De.warn&&"undefined"!=typeof console&&(a="Snowplow: "+t,o?console.warn.apply(console,n([a+"\n",o],r)):console.warn.apply(console,n([a],r)))},error:function(t,o){for(var r=[],a=2;a=De.error&&"undefined"!=typeof console&&(a="Snowplow: "+t+"\n",o?console.error.apply(console,n([a+"\n",o],r)):console.error.apply(console,n([a],r)))},debug:function(t){for(var o=[],r=1;r=De.debug&&"undefined"!=typeof console&&console.debug.apply(console,n(["Snowplow: "+t],o))},info:function(t){for(var o=[],r=1;r=De.info&&"undefined"!=typeof console&&console.info.apply(console,n(["Snowplow: "+t],o))}}}(),Fe=t((function(e){var n;n={rotl:function(e,n){return e<>>32-n},rotr:function(e,n){return e<<32-n|e>>>n},endian:function(e){if(e.constructor==Number)return 16711935&n.rotl(e,8)|4278255360&n.rotl(e,24);for(var t=0;t>>5]|=e[t]<<24-o%32;return n},wordsToBytes:function(e){for(var n=[],t=0;t<32*e.length;t+=8)n.push(e[t>>>5]>>>24-t%32&255);return n},bytesToHex:function(e){for(var n=[],t=0;t>>4).toString(16)),n.push((15&e[t]).toString(16));return n.join("")},hexToBytes:function(e){for(var n=[],t=0;tr;r++)8*t+6*r<=8*e.length?n.push("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(o>>>6*(3-r)&63)):n.push("=");return n.join("")},base64ToBytes:function(e){e=e.replace(/[^A-Z0-9+\/]/gi,"");for(var n=[],t=0,o=0;t>>6-2*o);return n}},e.exports=n})),Ve={utf8:{stringToBytes:function(e){return Ve.bin.stringToBytes(unescape(encodeURIComponent(e)))},bytesToString:function(e){return decodeURIComponent(escape(Ve.bin.bytesToString(e)))}},bin:{stringToBytes:function(e){for(var n=[],t=0;t>5]|=128<<24-i%32,e[15+(i+64>>>9<<4)]=i,i=0;ih;h++){if(16>h)a[h]=e[i+h];else{var y=a[h-3]^a[h-8]^a[h-14]^a[h-16];a[h]=y<<1|y>>>31}y=(c<<5|c>>>27)+f+(a[h]>>>0)+(20>h?1518500249+(s&u|~s&l):40>h?1859775393+(s^u^l):60>h?(s&u|s&l|u&l)-1894007588:(s^u^l)-899497514),f=l,l=u,u=s<<30|s>>>2,s=c,c=y}c+=d,s+=m,u+=p,l+=g,f+=v}return r=r.call(Fe,[c,s,u,l,f]),o&&o.asBytes?r:o&&o.asString?t.bytesToString(r):Fe.bytesToHex(r)})._blocksize=16,o._digestsize=20,e.exports=o})),Ge={},qe=function(){this.outQueues=[],this.bufferFlushers=[],this.hasLoaded=!1,this.registeredOnLoadHandlers=[]},Je="undefined"!=typeof window?Z():void 0,Ye=Object.freeze({__proto__:null,addGlobalContexts:function(e,n){K(n,(function(n){n.core.addGlobalContexts(e)}))},addPlugin:function(e,n){K(n,(function(n){n.addPlugin(e)}))},clearGlobalContexts:function(e){K(e,(function(e){e.core.clearGlobalContexts()}))},clearUserData:function(e,n){K(n,(function(n){n.clearUserData(e)}))},crossDomainLinker:function(e,n){K(n,(function(n){n.crossDomainLinker(e)}))},disableAnonymousTracking:function(e,n){K(n,(function(n){n.disableAnonymousTracking(e)}))},discardBrace:function(e,n){K(n,(function(n){n.discardBrace(e)}))},discardHashTag:function(e,n){K(n,(function(n){n.discardHashTag(e)}))},enableActivityTracking:function(e,n){K(n,(function(n){n.enableActivityTracking(e)}))},enableActivityTrackingCallback:function(e,n){K(n,(function(n){n.enableActivityTrackingCallback(e)}))},enableAnonymousTracking:function(e,n){K(n,(function(n){n.enableAnonymousTracking(e)}))},flushBuffer:function(e,n){K(n,(function(n){n.flushBuffer(e)}))},newSession:function(e){K(e,(function(e){e.newSession()}))},newTracker:function(e,n,t){if(void 0===t&&(t={}),Je)return X(e,e,"js-3.2.3",n,Je,t)},preservePageViewId:function(e){K(e,(function(e){e.preservePageViewId()}))},removeGlobalContexts:function(e,n){K(n,(function(n){n.core.removeGlobalContexts(e)}))},setBufferSize:function(e,n){K(n,(function(n){n.setBufferSize(e)}))},setCollectorUrl:function(e,n){K(n,(function(n){n.setCollectorUrl(e)}))},setCookiePath:function(e,n){K(n,(function(n){n.setCookiePath(e)}))},setCustomUrl:function(e,n){K(n,(function(n){n.setCustomUrl(e)}))},setDocumentTitle:function(e,n){K(n,(function(n){n.setDocumentTitle(e)}))},setOptOutCookie:function(e,n){K(n,(function(n){n.setOptOutCookie(e)}))},setReferrerUrl:function(e,n){K(n,(function(n){n.setReferrerUrl(e)}))},setUserId:function(e,n){K(n,(function(n){n.setUserId(e)}))},setUserIdFromCookie:function(e,n){K(n,(function(n){n.setUserIdFromCookie(e)}))},setUserIdFromLocation:function(e,n){K(n,(function(n){n.setUserIdFromLocation(e)}))},setUserIdFromReferrer:function(e,n){K(n,(function(n){n.setUserIdFromReferrer(e)}))},setVisitorCookieTimeout:function(e,n){K(n,(function(n){n.setVisitorCookieTimeout(e)}))},trackPageView:function(e,n){K(n,(function(n){n.trackPageView(e)}))},trackSelfDescribingEvent:function(e,n){K(n,(function(n){n.core.track(T({event:e.event}),e.context,e.timestamp)}))},trackStructEvent:function(e,n){K(n,(function(n){var t=(n=n.core).track,r=e.category,a=e.action,i=e.label,c=e.property,s=e.value,u=o();u.add("e","se"),u.add("se_ca",r),u.add("se_ac",a),u.add("se_la",i),u.add("se_pr",c),u.add("se_va",null==s?void 0:s.toString()),t.call(n,u,e.context,e.timestamp)}))},updatePageActivity:function(e){K(e,(function(e){e.updatePageActivity()}))},version:"3.2.3"}),Ke=Object.freeze({__proto__:null,ClientHintsPlugin:$}),We=Object.freeze({__proto__:null,OptimizelyXPlugin:ee}),Xe=Object.freeze({__proto__:null,PerformanceTimingPlugin:ne});!function(e){e.consent="consent",e.contract="contract",e.legalObligation="legal_obligation",e.vitalInterests="vital_interests",e.publicTask="public_task",e.legitimateInterests="legitimate_interests"}(Me||(Me={}));var Qe,Ze,$e={},en={},nn=Object.freeze({__proto__:null,ConsentPlugin:te,enableGdprContext:function(e,n){void 0===n&&(n=Object.keys($e));var t=e.documentId,o=e.documentVersion,r=e.documentDescription,a=Me[e.basisForProcessing];a?n.forEach((function(e){$e[e]&&(en[e]={basisForProcessing:a,documentId:null!=t?t:null,documentVersion:null!=o?o:null,documentDescription:null!=r?r:null})})):Qe.warn("enableGdprContext: basisForProcessing must be one of: consent, contract, legalObligation, vitalInterests, publicTask, legitimateInterests")},get gdprBasis(){return Me},trackConsentGranted:function(e,n){void 0===n&&(n=Object.keys($e)),W(n,$e,(function(n){var t=e.expiry,o={schema:"iglu:com.snowplowanalytics.snowplow/consent_document/jsonschema/1-0-0",data:S({id:e.id,version:e.version,name:e.name,description:e.description})};t=T({event:{schema:"iglu:com.snowplowanalytics.snowplow/consent_granted/jsonschema/1-0-0",data:S({expiry:t})}}),o=[o],n.core.track(t,e.context?e.context.concat(o):o,e.timestamp)}))},trackConsentWithdrawn:function(e,n){void 0===n&&(n=Object.keys($e)),W(n,$e,(function(n){var t=e.all,o={schema:"iglu:com.snowplowanalytics.snowplow/consent_document/jsonschema/1-0-0",data:S({id:e.id,version:e.version,name:e.name,description:e.description})};t=T({event:{schema:"iglu:com.snowplowanalytics.snowplow/consent_withdrawn/jsonschema/1-0-0",data:S({all:t})}}),o=[o],n.core.track(t,e.context?e.context.concat(o):o,e.timestamp)}))}}),tn={},on=!1,rn=Object.freeze({__proto__:null,GeolocationPlugin:oe,enableGeolocationContext:re}),an=Object.freeze({__proto__:null,GaCookiesPlugin:ae}),cn={},sn={},un=Object.freeze({__proto__:null,LinkClickTrackingPlugin:ie,enableLinkClickTracking:function(e,n){void 0===e&&(e={}),void 0===n&&(n=Object.keys(cn)),n.forEach((function(n){cn[n]&&(cn[n].sharedState.hasLoaded?(ue(e,n),le(n)):cn[n].sharedState.registeredOnLoadHandlers.push((function(){ue(e,n),le(n)})))}))},refreshLinkClickTracking:function(e){void 0===e&&(e=Object.keys(cn)),e.forEach((function(e){cn[e]&&(cn[e].sharedState.hasLoaded?le(e):cn[e].sharedState.registeredOnLoadHandlers.push((function(){le(e)})))}))},trackLinkClick:function(e,n){void 0===n&&(n=Object.keys(cn)),W(n,cn,(function(n){n.core.track(_(e),e.context,e.timestamp)}))}}),ln=["textarea","input","select"],fn=function(e){return e},dn={},mn=Object.freeze({__proto__:null,FormTrackingPlugin:ge,enableFormTracking:function(e,n){void 0===e&&(e={}),void 0===n&&(n=Object.keys(dn)),n.forEach((function(n){dn[n]&&(dn[n].sharedState.hasLoaded?fe(dn[n],e):dn[n].sharedState.registeredOnLoadHandlers.push((function(){fe(dn[n],e)})))}))}}),pn={},gn=Object.freeze({__proto__:null,ErrorTrackingPlugin:ve,enableErrorTracking:function(e,n){void 0===e&&(e={}),void 0===n&&(n=Object.keys(pn));var t=e.filter,o=e.contextAdder,r=e.context;D(window,"error",(function(e){if(t&&O(t)&&t(e)||null==t){var a=n,i=r||[];o&&O(o)&&(i=i.concat(o(e))),he({message:e.message,filename:e.filename,lineno:e.lineno,colno:e.colno,error:e.error,context:i},a)}}),!0)},trackError:he}),vn=t((function(e){var n,t,o,r,a,i;n={"America/Denver":["America/Mazatlan"],"America/Chicago":["America/Mexico_City"],"America/Asuncion":["America/Campo_Grande","America/Santiago"],"America/Montevideo":["America/Sao_Paulo","America/Santiago"],"Asia/Beirut":"Asia/Amman Asia/Jerusalem Europe/Helsinki Asia/Damascus Africa/Cairo Asia/Gaza Europe/Minsk Africa/Windhoek".split(" "),"Pacific/Auckland":["Pacific/Fiji"],"America/Los_Angeles":["America/Santa_Isabel"],"America/New_York":["America/Havana"],"America/Halifax":["America/Goose_Bay"],"America/Godthab":["America/Miquelon"],"Asia/Dubai":["Asia/Yerevan"],"Asia/Jakarta":["Asia/Krasnoyarsk"],"Asia/Shanghai":["Asia/Irkutsk","Australia/Perth"],"Australia/Sydney":["Australia/Lord_Howe"],"Asia/Tokyo":["Asia/Yakutsk"],"Asia/Dhaka":["Asia/Omsk"],"Asia/Baku":["Asia/Yerevan"],"Australia/Brisbane":["Asia/Vladivostok"],"Pacific/Noumea":["Asia/Vladivostok"],"Pacific/Majuro":["Asia/Kamchatka","Pacific/Fiji"],"Pacific/Tongatapu":["Pacific/Apia"],"Asia/Baghdad":["Europe/Minsk","Europe/Moscow"],"Asia/Karachi":["Asia/Yekaterinburg"],"Africa/Johannesburg":["Asia/Gaza","Africa/Cairo"]},t=function(){for(var e=[],n=0;11>=n;n++)for(var t=1;28>=t;t++){var o=-new Date(2014,n,t).getTimezoneOffset();o=null!==o?o:0,e?e&&e[e.length-1]!==o&&e.push(o):e.push()}return e},o=function e(n,t,o){void 0===t&&(t=864e5,o=36e5);var r=new Date(n.getTime()-t).getTime();n=n.getTime()+t;for(var a=new Date(r).getTimezoneOffset(),i=null;ra&&(s=u),a=l),r+=864e5}t=!(!c||!s)&&{s:o(c).getTime(),e:o(s).getTime()},e.push(t)}return e}();return function(e){for(var n=0;n=f.rules[m].s&&e[m].e<=f.rules[m].e)){d="N/A";break}if(d=0,d+=Math.abs(e[m].s-f.rules[m].s),864e6<(d+=Math.abs(f.rules[m].e-e[m].e))){d="N/A";break}}"N/A"!==(f=r(e,t,d,f))&&(o[l.name]=f)}for(var p in o)if(o.hasOwnProperty(p))for(e=0;ee?n[0]+",1":0n.length&&Array.isArray(n[0])&&(n=[{},n[0]]),r(e[0],n)})))}var i;if("string"==typeof n[0]&&f(n[1])&&(void 0===n[2]||Array.isArray(n[2]))){var c=n[0],s=n[1],d=n[2];(null===(i=n[3])||void 0===i||i)&&(i=u.setTimeout((function(){o(c)}),5e3),p[c]={timeout:i}),(i=l.createElement("script")).setAttribute("src",c),i.setAttribute("async","1"),D(i,"error",(function(){o(c),Ue.warn("Failed to load plugin "+s[0]+" from "+c)}),!0),D(i,"load",(function(){var n=s[1],r=u[s[0]];if(r&&"object"==typeof r){var i=r[n];n=e(r,["symbol"==typeof n?n:n+""]),h.addPlugin.apply(null,[{plugin:i.apply(null,d)},t]),a(n)}o(c)}),!0),l.head.appendChild(i)}else{if("object"==typeof n[0]&&"string"==typeof n[1]&&(void 0===n[2]||Array.isArray(n[2]))){var m=n[0],v=n[1];if(i=n[2],m)return n=m[v],m=e(m,["symbol"==typeof v?v:v+""]),h.addPlugin.apply(null,[{plugin:n.apply(null,i)},t]),void a(m)}Ue.warn("Failed to add Plugin: "+n[1])}}function s(){for(var e=[],t=0;tn.indexOf(t)&&(o[t]=e[t]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(t=Object.getOwnPropertySymbols(e);rn.indexOf(t[r])&&Object.prototype.propertyIsEnumerable.call(e,t[r])&&(o[t[r]]=e[t[r]])}return o}function n(e,n,t){if(t||2===arguments.length)for(var o,r=0,a=n.length;r>18&63,u=f>>12&63,l=f>>6&63,f&=63,c[i++]=He.charAt(s)+He.charAt(u)+He.charAt(l)+He.charAt(f)}while(a>16&255,c=u>>8&255,u&=255,a[o++]=64===r?String.fromCharCode(i):64===s?String.fromCharCode(i,c):String.fromCharCode(i,c,u)}while(t=e.length}function g(e){return p(e)||m(e)}function v(e){return!(!Array.isArray(e)||2!==e.length)&&(Array.isArray(e[1])?p(e[0])&&e[1].every(g):p(e[0])&&g(e[1]))}function h(e){return!(!Array.isArray(e)||2!==e.length)&&(!!function(e){var n=0;if(null!=e&&"object"==typeof e&&!Array.isArray(e)){if(Object.prototype.hasOwnProperty.call(e,"accept")){if(!d(e.accept))return!1;n+=1}if(Object.prototype.hasOwnProperty.call(e,"reject")){if(!d(e.reject))return!1;n+=1}return 0=n}return!1}(e[0])&&(Array.isArray(e[1])?e[1].every(g):g(e[1])))}function y(e){return v(e)||h(e)}function w(e,n){if(!l(e))return!1;if(e=u(e),n=null!==(n=/^iglu:([a-zA-Z0-9-_.]+)\/([a-zA-Z0-9-_]+)\/jsonschema\/([1-9][0-9]*)-(0|[1-9][0-9]*)-(0|[1-9][0-9]*)$/.exec(n))?n.slice(1,6):void 0,e&&n){if(!function(e,n){if(n=n.split("."),e=e.split("."),n&&e){if(n.length!==e.length)return!1;for(var t=0;tt;t++)if(!k(e[t],n[t]))return!1;return!0}return!1}function k(e,n){return e&&n&&"*"===e||e===n}function A(e){return Array.isArray(e)?e:[e]}function b(e,n,t,o){var r;return e=A(e).map((function(e){e:if(m(e))e=[e];else{if(p(e)){n:{var r=void 0;try{if(r=e({event:n.getPayload(),eventType:t,eventSchema:o}),Array.isArray(r)&&r.every(m)||m(r)){var a=r;break n}a=void 0;break n}catch(e){}a=void 0}if(m(a)){e=[a];break e}if(Array.isArray(a)){e=a;break e}}e=void 0}if(e&&0!==e.length)return e})),(r=[]).concat.apply(r,e.filter((function(e){return null!=e&&e.filter(Boolean)})))}function _(e){void 0===e&&(e={});var t,r,c,s,u,l,f,d=e.base64,m=e.corePlugins,p=null!=m?m:[];t=null==d||d,r=p,c=e.callback,s=function(e){return{addPluginContexts:function(t){var o=t?n([],t,!0):[];return e.forEach((function(e){try{e.contexts&&o.push.apply(o,e.contexts())}catch(e){Ge.error("Error adding plugin contexts",e)}})),o}}}(r),u=i(),l=t,f={};var g=Te(Te({},e={track:function(e,n,t){e.withJsonProcessor(o(l)),e.add("eid",Ve.v4()),e.addDict(f),t=function(e){return null==e?{type:"dtm",value:(new Date).getTime()}:"number"==typeof e?{type:"dtm",value:e}:"ttm"===e.type?{type:"ttm",value:e.value}:{type:"dtm",value:e.value||(new Date).getTime()}}(t),e.add(t.type,t.value.toString()),n=function(e,n){e=u.getApplicableContexts(e);var t=[];return n&&n.length&&t.push.apply(t,n),e&&e.length&&t.push.apply(t,e),t}(e,s.addPluginContexts(n)),void 0!==(n=n&&n.length?{schema:"iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-0",data:n}:void 0)&&e.addJson("cx","co",n),r.forEach((function(n){try{n.beforeTrack&&n.beforeTrack(e)}catch(e){Ge.error("Plugin beforeTrack",e)}})),"function"==typeof c&&c(e);var a=e.build();return r.forEach((function(e){try{e.afterTrack&&e.afterTrack(a)}catch(e){Ge.error("Plugin afterTrack",e)}})),a},addPayloadPair:function(e,n){f[e]=n},getBase64Encoding:function(){return l},setBase64Encoding:function(e){l=e},addPayloadDict:function(e){for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(f[n]=e[n])},resetPayloadPairs:function(e){f=a(e)?e:{}},setTrackerVersion:function(e){f.tv=e},setTrackerNamespace:function(e){f.tna=e},setAppId:function(e){f.aid=e},setPlatform:function(e){f.p=e},setUserId:function(e){f.uid=e},setScreenResolution:function(e,n){f.res=e+"x"+n},setViewport:function(e,n){f.vp=e+"x"+n},setColorDepth:function(e){f.cd=e},setTimezone:function(e){f.tz=e},setLang:function(e){f.lang=e},setIpAddress:function(e){f.ip=e},setUseragent:function(e){f.ua=e},addGlobalContexts:function(e){u.addGlobalContexts(e)},clearGlobalContexts:function(){u.clearGlobalContexts()},removeGlobalContexts:function(e){u.removeGlobalContexts(e)}}),{addPlugin:function(e){var n,t;e=e.plugin,p.push(e),null===(n=e.logger)||void 0===n||n.call(e,Ge),null===(t=e.activateCorePlugin)||void 0===t||t.call(e,g)}});return null==p||p.forEach((function(e){var n,t;null===(n=e.logger)||void 0===n||n.call(e,Ge),null===(t=e.activateCorePlugin)||void 0===t||t.call(e,g)})),g}function P(e){var n=e.event;return e={schema:"iglu:com.snowplowanalytics.snowplow/unstruct_event/jsonschema/1-0-0",data:{schema:e=n.schema,data:n.data}},(n=t()).add("e","ue"),n.addJson("ue_px","ue_pr",e),n}function T(e){return P({event:e={schema:"iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1",data:S({targetUrl:e.targetUrl,elementId:e.elementId,elementClasses:e.elementClasses,elementTarget:e.elementTarget,elementContent:e.elementContent})}})}function S(e,n){void 0===n&&(n={});var t,o={};for(t in e)(n[t]||null!==e[t]&&void 0!==e[t])&&(o[t]=e[t]);return o}function C(e){return Number.isInteger&&Number.isInteger(e)||"number"==typeof e&&isFinite(e)&&Math.floor(e)===e}function O(e){return!(!e||"function"!=typeof e)}function x(e){if(!e||"string"!=typeof e.valueOf()){e=e.text||"";var n=document.getElementsByTagName("title");n&&null!=n[0]&&(e=n[0].text)}return e}function E(e){var n=/^(?:(?:https?|ftp):)\/*(?:[^@]+@)?([^:/#]+)/.exec(e);return n?n[1]:e}function I(e){var n=e.length;return"."===e.charAt(--n)&&(e=e.slice(0,n)),"*."===e.slice(0,2)&&(e=e.slice(1)),e}function j(e){var n=window,t=B("referrer",n.location.href)||B("referer",n.location.href);if(t)return t;if(e)return e;try{if(n.top)return n.top.document.referrer;if(n.parent)return n.parent.document.referrer}catch(e){}return document.referrer}function N(e,n,t,o){return e.addEventListener?(e.addEventListener(n,t,o),!0):e.attachEvent?e.attachEvent("on"+n,t):void(e["on"+n]=t)}function B(e,n){return(e=new RegExp("^[^#]*[?&]"+e+"=([^&#]*)").exec(n))?decodeURIComponent(e[1].replace(/\+/g," ")):null}function D(e,n,t){void 0===t&&(t=63072e3);try{var o=window.localStorage,r=Date.now()+1e3*t;return o.setItem("".concat(e,".expires"),r.toString()),o.setItem(e,n),!0}catch(e){return!1}}function L(e){try{var n=window.localStorage;return n.removeItem(e),n.removeItem(e+".expires"),!0}catch(e){return!1}}function M(e,n,t,o,r,a,i){return 1=o?n+=1:2047>=o?n+=2:55296<=o&&57343>=o?(n+=4,t++):n=65535>o?n+3:n+4}return n}function y(e){for(void 0===e&&(e=!1);O.length&&"string"!=typeof O[0]&&"object"!=typeof O[0];)O.shift();if(1>O.length)C=!1;else{if(!_||"string"!=typeof _.valueOf())throw"No collector configured";if(C=!0,I){var n=function(e){for(var n=0,t=0;n=i);)n+=1;return n},o=void 0;if(M(O))var r=w(o=_,!0,e),a=n(O);else o=b(O[0]),r=w(o,!1,e),a=1;var c=setTimeout((function(){r.abort(),C=!1}),l),s=function(e){for(var n=0;nr.status)s(a),y();else{var e=r.status;(e=!(200<=e&&300>e)&&(!!p.includes(e)||!g.includes(e)))||(Ge.error("Status ".concat(r.status,", will not retry.")),s(a)),C=!1}},M(O)){if(0<(n=O.slice(0,a)).length){if(e=!1,n=n.map((function(e){return e.evt})),E){var d=new Blob([k(A(n))],{type:"application/json"});try{e=navigator.sendBeacon(o,d)}catch(n){e=!1}}!0===e?(s(a),y()):r.send(k(A(n)))}}else r.send()}else if(f||M(O))C=!1;else{o=new Image(1,1);var m=!0;o.onload=function(){m&&(m=!1,O.shift(),t&&D(B,JSON.stringify(O.slice(0,u))),y())},o.onerror=function(){m&&(C=m=!1)},o.src=b(O[0]),setTimeout((function(){m&&C&&(m=!1,y())}),l)}}}function w(e,n,t){var o=new XMLHttpRequest;for(var r in n?(o.open("POST",e,!t),o.setRequestHeader("Content-Type","application/json; charset=UTF-8")):o.open("GET",e,!t),o.withCredentials=m,f&&o.setRequestHeader("SP-Anonymous","*"),d)Object.prototype.hasOwnProperty.call(d,r)&&o.setRequestHeader(r,d[r]);return o}function k(e){return JSON.stringify({schema:"iglu:com.snowplowanalytics.snowplow/payload_data/jsonschema/1-0-4",data:e})}function A(e){for(var n=(new Date).getTime().toString(),t=0;t=i)return Ge.warn("Event ("+e.bytes+"B) too big, max is "+i),n=e,void w(_,!0,!1).send(k(A([n.evt])));O.push(e)}else{var o,s="?",l={co:!0,cx:!0},f=!0;for(o in e)e.hasOwnProperty(o)&&!l.hasOwnProperty(o)&&(f?f=!1:s+="&",s+=encodeURIComponent(o)+"="+encodeURIComponent(e[o]));for(var d in l)e.hasOwnProperty(d)&&l.hasOwnProperty(d)&&(s+="&"+d+"="+encodeURIComponent(e[d]));if(0=c)return Ge.warn("Event ("+l+"B) too big, max is "+c),void(I&&(e=v(e),w(n+r,!0,!1).send(k(A([e.evt])))));O.push(s)}n=!1,t&&(n=D(B,JSON.stringify(O.slice(0,u)))),C||n&&!(O.length>=a)||y()},executeQueue:function(){C||y()},setUseLocalStorage:function(e){t=e},setAnonymousTracking:function(e){f=e},setCollectorUrl:function(e){_=e+N},setBufferSize:function(e){a=e}}}function J(e,n,t){return"translate.googleusercontent.com"===e?(""===t&&(t=n),e=E(n=null!=(e=(e=/^(?:https?|ftp)(?::\/*(?:[^?]+))([?][^#]+)/.exec(n))&&1<(null==e?void 0:e.length)?B("u",e[1]):null)?e:"")):"cc.bingj.com"!==e&&"webcache.googleusercontent.com"!==e||(e=E(n=document.links[0].href)),[e,n,t]}function Y(e,n){return void 0===n&&(n=1),"0"===e[0]?(e[7]=e[6],e[5]=e[4],e[3]++):e[3]=n,n=Ve.v4(),e[6]=n,e[10]=0,e[8]="",e[9]=void 0,n}function K(e){e[4]=Math.round((new Date).getTime()/1e3)}function W(e,n,o,r,a,i){void 0===i&&(i={});var c=[];e=function(e,n,o,r,a,i){function s(){(qe=J(window.location.hostname,window.location.href,j()))[1]!==Ye&&(Ke=j(Ye)),Je=I(qe[0]),Ye=qe[1]}function u(e){var n=(new Date).getTime();if(null!=(e=e.currentTarget)&&e.href){n="_sp="+Le+"."+n;var t=e.href.split("#"),o=t[0].split("?"),r=o.shift();if(o=o.join("?")){for(var a=!0,i=o.split("&"),c=0;cDate.now())var o=n.getItem(e);else n.removeItem(e),n.removeItem(e+".expires"),o=void 0}catch(e){o=void 0}return o}if("cookie"==gn||"cookieAndLocalStorage"==gn)return M(e)}function p(){s(),De=Qe((on||Je)+(rn||"/")).slice(0,4)}function g(){Ee=(new Date).getTime()}function v(){var e=h(),n=e[0];nje&&(je=n),(e=e[1])Be&&(Be=e),g()}function h(){var e=document.documentElement;return e?[e.scrollLeft||window.pageXOffset,e.scrollTop||window.pageYOffset]:[0,0]}function y(){var e=h(),n=e[0];je=Ie=n,Be=Ne=e=e[1]}function w(){A(tn+"ses."+De,"*",fn)}function k(e){var n=tn+"id."+De;e.shift(),A(n,e=e.join("."),ln)}function A(e,n,t){pn&&!dn||("localStorage"==gn?D(e,n,t):("cookie"==gn||"cookieAndLocalStorage"==gn)&&M(e,n,t,rn,on,an,cn))}function b(e){var n=tn+"id."+De,t=tn+"ses."+De;L(n),L(t),M(n,"",-1,"/",on,an,cn),M(t,"",-1,"/",on,an,cn),null!=e&&e.preserveSession||(Me=Ve.v4(),hn=1),null!=e&&e.preserveUser||(Le=Ve.v4(),ze=null)}function P(e){e&&e.stateStorageStrategy&&(i.stateStorageStrategy=e.stateStorageStrategy,gn=ke(i)),pn=!!i.anonymousTracking,dn=Ae(i),mn=be(i),yn.setUseLocalStorage("localStorage"==gn||"cookieAndLocalStorage"==gn),yn.setAnonymousTracking(mn)}function T(){if(!pn||dn){var e="none"!=gn&&!!m("ses"),n=S();if(n[1])var t=n[1];else t=pn?"":Ve.v4(),n[1]=t;Le=t,Me=e?n[6]:Y(n),hn=n[3],"none"!=gn&&(w(),K(n),k(n))}}function S(){return"none"==gn?["1","",0,0,0,void 0,"","","",void 0,0]:function(e,n,t,o){var r=Math.round((new Date).getTime()/1e3);e?(e=e.split(".")).unshift("0"):e=["1",n,r,o,r,"",t],e[6]&&"undefined"!==e[6]||(e[6]=Ve.v4()),e[7]&&"undefined"!==e[7]||(e[7]=""),e[8]&&"undefined"!==e[8]||(e[8]=""),e[9]&&"undefined"!==e[9]||(e[9]=""),e[10]&&"undefined"!==e[10]||(e[10]=0);var a=function(e,n){return e=parseInt(e),isNaN(e)?n:e};return n=function(e){return e?a(e,void 0):void 0},[e[0],e[1],a(e[2],r),a(e[3],o),a(e[4],r),n(e[5]),e[6],e[7],e[8],n(e[9]),a(e[10],0)]}(m("id")||void 0,Le,Me,hn)}function O(e){return 0===e.indexOf("http")?e:("https:"===document.location.protocol?"https":"http")+"://"+e}function z(){wn&&null!=a.pageViewId||(a.pageViewId=Ve.v4())}function U(){return null==a.pageViewId&&(a.pageViewId=Ve.v4()),a.pageViewId}function F(e){var n=e.title,o=e.context,r=e.timestamp;if(e=e.contextCallback,s(),kn&&z(),kn=!0,en=document.title,n=x((Se=n)||en),Fe.track(function(e){var n=e.pageUrl,o=e.pageTitle;e=e.referrer;var r=t();return r.add("e","pv"),r.add("url",n),r.add("page",o),r.add("refr",e),r}({pageUrl:f(Pe||Ye),pageTitle:n,referrer:f(_e||Ke)}),(o||[]).concat(e?e():[]),r),r=new Date,n=!1,An.enabled&&!An.installed){n=An.installed=!0;var a={update:function(){if("undefined"!=typeof window&&"function"==typeof window.addEventListener){var e=!1,n=Object.defineProperty({},"passive",{get:function(){e=!0},set:function(){}}),t=function(){};window.addEventListener("testPassiveEventSupport",t,n),window.removeEventListener("testPassiveEventSupport",t,n),a.hasSupport=e}}};a.update();var i="onwheel"in document.createElement("div")?"wheel":void 0!==document.onmousewheel?"mousewheel":"DOMMouseScroll";Object.prototype.hasOwnProperty.call(a,"hasSupport")?N(document,i,g,{passive:!0}):N(document,i,g),y(),i=function(e,n){return void 0===n&&(n=g),function(e){return N(document,e,n)}},"click mouseup mousedown mousemove keypress keydown keyup".split(" ").forEach(i(document)),["resize","focus","blur"].forEach(i(window)),i(window,v)("scroll")}if(An.enabled&&(nn||n))for(r in Ee=r.getTime(),r=void 0,An.configurations)(n=An.configurations[r])&&(window.clearInterval(n.activityInterval),R(n,o,e))}function R(e,n,t){var o=function(e,n){s(),e({context:n,pageViewId:U(),minXOffset:Ie,minYOffset:Ne,maxXOffset:je,maxYOffset:Be}),y()},r=function(){Ee+e.configHeartBeatTimer>(new Date).getTime()&&o(e.callback,(n||[]).concat(t?t():[]))};e.activityInterval=0!=e.configMinimumVisitLength?window.setTimeout((function(){Ee+e.configMinimumVisitLength>(new Date).getTime()&&o(e.callback,(n||[]).concat(t?t():[])),e.activityInterval=window.setInterval(r,e.configHeartBeatTimer)}),e.configMinimumVisitLength):window.setInterval(r,e.configHeartBeatTimer)}function V(e){var n=e.minimumVisitLength,t=e.heartbeatDelay;if(e=e.callback,C(n)&&C(t))return{configMinimumVisitLength:1e3*n,configHeartBeatTimer:1e3*t,callback:e};Ge.error("Activity tracking minimumVisitLength & heartbeatDelay must be integers")}function H(e){var n=e.context,o=e.minXOffset,r=e.minYOffset,a=e.maxXOffset,i=e.maxYOffset;(e=document.title)!==en&&(en=e,Se=void 0);var c=(e=Fe).track,s=f(Pe||Ye),u=x(Se||en),l=f(_e||Ke);o=Math.round(o),a=Math.round(a),r=Math.round(r),i=Math.round(i);var d=t();d.add("e","pp"),d.add("url",s),d.add("page",u),d.add("refr",l),o&&!isNaN(Number(o))&&d.add("pp_mix",o.toString()),a&&!isNaN(Number(a))&&d.add("pp_max",a.toString()),r&&!isNaN(Number(r))&&d.add("pp_miy",r.toString()),i&&!isNaN(Number(i))&&d.add("pp_may",i.toString()),c.call(e,d,n)}var G,W,X,Q,Z,$,ee,ne,te,oe,re,ae,ie,ce,se,ue,le,fe,de,me,pe,ge,ve,he,ye,we;i.eventMethod=null!==(G=i.eventMethod)&&void 0!==G?G:"post";var ke=function(e){var n;return null!==(n=e.stateStorageStrategy)&&void 0!==n?n:"cookieAndLocalStorage"},Ae=function(e){var n,t;return"boolean"!=typeof e.anonymousTracking&&(null!==(t=!0===(null===(n=e.anonymousTracking)||void 0===n?void 0:n.withSessionTracking))&&void 0!==t&&t)},be=function(e){var n,t;return"boolean"!=typeof e.anonymousTracking&&(null!==(t=!0===(null===(n=e.anonymousTracking)||void 0===n?void 0:n.withServerAnonymisation))&&void 0!==t&&t)};c.push({beforeTrack:function(e){var n=m("ses"),t=S();if(Ue=!!xe&&!!M(xe),un||Ue)b();else{if("0"===t[0]?(Me=n||"none"==gn?t[6]:Y(t),hn=t[3]):(new Date).getTime()-vn>1e3*fn&&(hn++,Me=Y(t,hn)),K(t),0===t[10]&&(n=e.build(),t[8]=n.eid,n=n.dtm||n.ttm,t[9]=n?parseInt(n):void 0),t[10]+=1,n=e.add,"innerWidth"in window)var o=window.innerWidth,r=window.innerHeight;else o=(r=document.documentElement||document.body).clientWidth,r=r.clientHeight;n.call(e,"vp",0<=o&&0<=r?o+"x"+r:null),n=e.add,r=document.documentElement;var a=document.body;o=Math.max(r.clientWidth,r.offsetWidth,r.scrollWidth),r=Math.max(r.clientHeight,r.offsetHeight,r.scrollHeight,a?Math.max(a.offsetHeight,a.scrollHeight):0),o=isNaN(o)||isNaN(r)?"":o+"x"+r,n.call(e,"ds",o),e.add("vid",dn?hn:pn?null:hn),e.add("sid",dn?Me:pn?null:Me),e.add("duid",pn?null:t[1]),e.add("uid",pn?null:ze),s(),e.add("refr",f(_e||Ke)),e.add("url",f(Pe||Ye)),!bn||dn||pn||(n=t[9],n={userId:t[1],sessionId:t[6],eventIndex:t[10],sessionIndex:t[3],previousSessionId:t[7]||null,storageMechanism:"localStorage"==gn?"LOCAL_STORAGE":"COOKIE_1",firstEventId:t[8]||null,firstEventTimestamp:n?new Date(n).toISOString():null},e.addContextEntity({schema:"iglu:com.snowplowanalytics.snowplow/client_session/jsonschema/1-0-2",data:n})),"none"!=gn&&(k(t),w()),vn=(new Date).getTime()}}}),(null===(X=null===(W=null==i?void 0:i.contexts)||void 0===W?void 0:W.webPage)||void 0===X||X)&&c.push({contexts:function(){return[{schema:"iglu:com.snowplowanalytics.snowplow/web_page/jsonschema/1-0-0",data:{id:U()}}]}}),c.push.apply(c,null!==(Q=i.plugins)&&void 0!==Q?Q:[]);var _e,Pe,Se,Ce,Oe,xe,Ee,Ie,je,Ne,Be,De,Le,Me,ze,Ue,Fe=_({base64:i.encodeBase64,corePlugins:c,callback:function(e){un||Ue||yn.enqueueRequest(e.build(),Xe)}}),Re=navigator.userLanguage||navigator.language,He=document.characterSet||document.charset,qe=J(window.location.hostname,window.location.href,j()),Je=I(qe[0]),Ye=qe[1],Ke=qe[2],We=null!==(Z=i.platform)&&void 0!==Z?Z:"web",Xe=O(r),Ze=null!==($=i.postPath)&&void 0!==$?$:"/com.snowplowanalytics.snowplow/tp2",$e=null!==(ee=i.appId)&&void 0!==ee?ee:"",en=document.title,nn=null===(ne=i.resetActivityTrackingOnPageView)||void 0===ne||ne,tn=null!==(te=i.cookieName)&&void 0!==te?te:"_sp_",on=null!==(oe=i.cookieDomain)&&void 0!==oe?oe:void 0,rn="/",an=null!==(re=i.cookieSameSite)&&void 0!==re?re:"None",cn=null===(ae=i.cookieSecure)||void 0===ae||ae,sn=navigator.doNotTrack||navigator.msDoNotTrack||window.doNotTrack,un=void 0!==i.respectDoNotTrack&&(i.respectDoNotTrack&&("yes"===sn||"1"===sn)),ln=null!==(ie=i.cookieLifetime)&&void 0!==ie?ie:63072e3,fn=null!==(ce=i.sessionCookieTimeout)&&void 0!==ce?ce:1800,dn=Ae(i),mn=be(i),pn=!!i.anonymousTracking,gn=ke(i),vn=(new Date).getTime(),hn=1,yn=q(e,a,"localStorage"==gn||"cookieAndLocalStorage"==gn,i.eventMethod,Ze,null!==(se=i.bufferSize)&&void 0!==se?se:1,null!==(ue=i.maxPostBytes)&&void 0!==ue?ue:4e4,null!==(le=i.maxGetBytes)&&void 0!==le?le:0,null===(fe=i.useStm)||void 0===fe||fe,null!==(de=i.maxLocalStorageQueueSize)&&void 0!==de?de:1e3,null!==(me=i.connectionTimeout)&&void 0!==me?me:5e3,mn,null!==(pe=i.customHeaders)&&void 0!==pe?pe:{},null===(ge=i.withCredentials)||void 0===ge||ge,null!==(ve=i.retryStatusCodes)&&void 0!==ve?ve:[],(null!==(he=i.dontRetryStatusCodes)&&void 0!==he?he:[]).concat([400,401,403,410,422])),wn=!1,kn=!1,An={enabled:!1,installed:!1,configurations:{}},bn=null!==(we=null===(ye=i.contexts)||void 0===ye?void 0:ye.session)&&void 0!==we&&we;return i.hasOwnProperty("discoverRootDomain")&&i.discoverRootDomain&&(on=function(e,n){for(var t=window.location.hostname,o="_sp_root_domain_test_"+(new Date).getTime(),r="_test_value_"+(new Date).getTime(),a=t.split("."),i=a.length-1;0<=i;){var c=a.slice(i,a.length).join(".");if(M(o,r,0,"/",c,e,n),M(o)===r){for(M(o,"",-1,"/",c,e,n),t=document.cookie.split("; "),o=[],r=0;rn;n++)0==(3&n)&&(e=4294967296*Math.random()),xe[n]=e>>>((3&n)<<3)&255;return xe}}for(var Ee=[],Ie=0;256>Ie;++Ie)Ee[Ie]=(Ie+256).toString(16).substr(1);var je,Ne,Be=function(e,n){return n=n||0,[Ee[e[n++]],Ee[e[n++]],Ee[e[n++]],Ee[e[n++]],"-",Ee[e[n++]],Ee[e[n++]],"-",Ee[e[n++]],Ee[e[n++]],"-",Ee[e[n++]],Ee[e[n++]],"-",Ee[e[n++]],Ee[e[n++]],Ee[e[n++]],Ee[e[n++]],Ee[e[n++]],Ee[e[n++]]].join("")},De=Se,Le=0,Me=0,ze=Se,Ue=function(e,n,t){if(t=n&&t||0,"string"==typeof e&&(n="binary"===e?Array(16):null,e=null),(e=(e=e||{}).random||(e.rng||ze)())[6]=15&e[6]|64,e[8]=63&e[8]|128,n)for(var o=0;16>o;++o)n[t+o]=e[o];return n||Be(e)};Ue.v1=function(e,n,t){t=n&&t||0;var o=n||[],r=(e=e||{}).node||je,a=void 0!==e.clockseq?e.clockseq:Ne;if(null==r||null==a){var i=De();null==r&&(r=je=[1|i[0],i[1],i[2],i[3],i[4],i[5]]),null==a&&(a=Ne=16383&(i[6]<<8|i[7]))}i=void 0!==e.msecs?e.msecs:(new Date).getTime();var c=void 0!==e.nsecs?e.nsecs:Me+1,s=i-Le+(c-Me)/1e4;if(0>s&&void 0===e.clockseq&&(a=a+1&16383),(0>s||i>Le)&&void 0===e.nsecs&&(c=0),1e4<=c)throw Error("uuid.v1(): Can't create more than 10M uuids/sec");for(Le=i,Me=c,Ne=a,e=(1e4*(268435455&(i+=122192928e5))+c)%4294967296,o[t++]=e>>>24&255,o[t++]=e>>>16&255,o[t++]=e>>>8&255,o[t++]=255&e,e=i/4294967296*1e4&268435455,o[t++]=e>>>8&255,o[t++]=255&e,o[t++]=e>>>24&15|16,o[t++]=e>>>16&255,o[t++]=a>>>8|128,o[t++]=255&a,a=0;6>a;++a)o[t+a]=r[a];return n||Be(o)};var Fe,Re,Ve=Ue.v4=Ue,He="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";(Re=Fe||(Fe={}))[Re.none=0]="none",Re[Re.error=1]="error",Re[Re.warn=2]="warn",Re[Re.debug=3]="debug",Re[Re.info=4]="info";var Ge=function(e){return void 0===e&&(e=Fe.warn),{setLogLevel:function(n){e=Fe[n]?n:Fe.warn},warn:function(t,o){for(var r=[],a=2;a=Fe.warn&&"undefined"!=typeof console&&(a="Snowplow: "+t,o?console.warn.apply(console,n([a+"\n",o],r,!1)):console.warn.apply(console,n([a],r,!1)))},error:function(t,o){for(var r=[],a=2;a=Fe.error&&"undefined"!=typeof console&&(a="Snowplow: "+t+"\n",o?console.error.apply(console,n([a+"\n",o],r,!1)):console.error.apply(console,n([a],r,!1)))},debug:function(t){for(var o=[],r=1;r=Fe.debug&&"undefined"!=typeof console&&console.debug.apply(console,n(["Snowplow: "+t],o,!1))},info:function(t){for(var o=[],r=1;r=Fe.info&&"undefined"!=typeof console&&console.info.apply(console,n(["Snowplow: "+t],o,!1))}}}(),qe={},Je={};!function(){var e={rotl:function(e,n){return e<>>32-n},rotr:function(e,n){return e<<32-n|e>>>n},endian:function(n){if(n.constructor==Number)return 16711935&e.rotl(n,8)|4278255360&e.rotl(n,24);for(var t=0;t>>5]|=e[t]<<24-o%32;return n},wordsToBytes:function(e){for(var n=[],t=0;t<32*e.length;t+=8)n.push(e[t>>>5]>>>24-t%32&255);return n},bytesToHex:function(e){for(var n=[],t=0;t>>4).toString(16)),n.push((15&e[t]).toString(16));return n.join("")},hexToBytes:function(e){for(var n=[],t=0;tr;r++)8*t+6*r<=8*e.length?n.push("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(o>>>6*(3-r)&63)):n.push("=");return n.join("")},base64ToBytes:function(e){e=e.replace(/[^A-Z0-9+\/]/gi,"");for(var n=[],t=0,o=0;t>>6-2*o);return n}};Je=e}();var Ye={utf8:{stringToBytes:function(e){return Ye.bin.stringToBytes(unescape(encodeURIComponent(e)))},bytesToString:function(e){return decodeURIComponent(escape(Ye.bin.bytesToString(e)))}},bin:{stringToBytes:function(e){for(var n=[],t=0;t>5]|=128<<24-c%32,o[15+(c+64>>>9<<4)]=c,c=0;cy;y++){if(16>y)i[y]=o[c+y];else{var w=i[y-3]^i[y-8]^i[y-14]^i[y-16];i[y]=w<<1|w>>>31}w=(s<<5|s>>>27)+d+(i[y]>>>0)+(20>y?1518500249+(u&l|~u&f):40>y?1859775393+(u^l^f):60>y?(u&l|u&f|l&f)-1894007588:(u^l^f)-899497514),d=f,f=l,l=u<<30|u>>>2,u=s,s=w}s+=m,u+=p,l+=g,f+=v,d+=h}return a=a.call(e,[s,u,l,f,d]),r&&r.asBytes?a:r&&r.asString?t.bytesToString(a):e.bytesToHex(a)};o._blocksize=16,o._digestsize=20,qe=o}();var We,Xe,Qe=qe,Ze={},$e=function(){this.outQueues=[],this.bufferFlushers=[],this.hasLoaded=!1,this.registeredOnLoadHandlers=[]},en="undefined"!=typeof window?ee():void 0,nn=Object.freeze({__proto__:null,addGlobalContexts:function(e,n){X(n,(function(n){n.core.addGlobalContexts(e)}))},addPlugin:function(e,n){X(n,(function(n){n.addPlugin(e)}))},clearGlobalContexts:function(e){X(e,(function(e){e.core.clearGlobalContexts()}))},clearUserData:function(e,n){X(n,(function(n){n.clearUserData(e)}))},crossDomainLinker:function(e,n){X(n,(function(n){n.crossDomainLinker(e)}))},disableAnonymousTracking:function(e,n){X(n,(function(n){n.disableAnonymousTracking(e)}))},discardBrace:function(e,n){X(n,(function(n){n.discardBrace(e)}))},discardHashTag:function(e,n){X(n,(function(n){n.discardHashTag(e)}))},enableActivityTracking:function(e,n){X(n,(function(n){n.enableActivityTracking(e)}))},enableActivityTrackingCallback:function(e,n){X(n,(function(n){n.enableActivityTrackingCallback(e)}))},enableAnonymousTracking:function(e,n){X(n,(function(n){n.enableAnonymousTracking(e)}))},flushBuffer:function(e,n){X(n,(function(n){n.flushBuffer(e)}))},newSession:function(e){X(e,(function(e){e.newSession()}))},newTracker:function(e,n,t){if(void 0===t&&(t={}),en)return Z(e,e,"js-".concat("3.6.0"),n,en,t)},preservePageViewId:function(e){X(e,(function(e){e.preservePageViewId()}))},removeGlobalContexts:function(e,n){X(n,(function(n){n.core.removeGlobalContexts(e)}))},setBufferSize:function(e,n){X(n,(function(n){n.setBufferSize(e)}))},setCollectorUrl:function(e,n){X(n,(function(n){n.setCollectorUrl(e)}))},setCookiePath:function(e,n){X(n,(function(n){n.setCookiePath(e)}))},setCustomUrl:function(e,n){X(n,(function(n){n.setCustomUrl(e)}))},setDocumentTitle:function(e,n){X(n,(function(n){n.setDocumentTitle(e)}))},setOptOutCookie:function(e,n){X(n,(function(n){n.setOptOutCookie(e)}))},setReferrerUrl:function(e,n){X(n,(function(n){n.setReferrerUrl(e)}))},setUserId:function(e,n){X(n,(function(n){n.setUserId(e)}))},setUserIdFromCookie:function(e,n){X(n,(function(n){n.setUserIdFromCookie(e)}))},setUserIdFromLocation:function(e,n){X(n,(function(n){n.setUserIdFromLocation(e)}))},setUserIdFromReferrer:function(e,n){X(n,(function(n){n.setUserIdFromReferrer(e)}))},setVisitorCookieTimeout:function(e,n){X(n,(function(n){n.setVisitorCookieTimeout(e)}))},trackPageView:function(e,n){X(n,(function(n){n.trackPageView(e)}))},trackSelfDescribingEvent:function(e,n){X(n,(function(n){n.core.track(P({event:e.event}),e.context,e.timestamp)}))},trackStructEvent:function(e,n){X(n,(function(n){var o=(n=n.core).track,r=e.category,a=e.action,i=e.label,c=e.property,s=e.value,u=t();u.add("e","se"),u.add("se_ca",r),u.add("se_ac",a),u.add("se_la",i),u.add("se_pr",c),u.add("se_va",null==s?void 0:s.toString()),o.call(n,u,e.context,e.timestamp)}))},updatePageActivity:function(e){X(e,(function(e){e.updatePageActivity()}))},version:"3.6.0"}),tn=Object.freeze({__proto__:null,ClientHintsPlugin:ne}),on=Object.freeze({__proto__:null,OptimizelyXPlugin:te}),rn=Object.freeze({__proto__:null,PerformanceTimingPlugin:oe});!function(e){e.consent="consent",e.contract="contract",e.legalObligation="legal_obligation",e.vitalInterests="vital_interests",e.publicTask="public_task",e.legitimateInterests="legitimate_interests"}(Xe||(Xe={}));var an,cn,sn,un={},ln={},fn=Object.freeze({__proto__:null,ConsentPlugin:re,enableGdprContext:function(e,n){void 0===n&&(n=Object.keys(un));var t=e.documentId,o=e.documentVersion,r=e.documentDescription,a=Xe[e.basisForProcessing];a?n.forEach((function(e){un[e]&&(ln[e]={basisForProcessing:a,documentId:null!=t?t:null,documentVersion:null!=o?o:null,documentDescription:null!=r?r:null})})):an.warn("enableGdprContext: basisForProcessing must be one of: consent, contract, legalObligation, vitalInterests, publicTask, legitimateInterests")},get gdprBasis(){return Xe},trackConsentGranted:function(e,n){void 0===n&&(n=Object.keys(un)),Q(n,un,(function(n){var t=e.expiry,o={schema:"iglu:com.snowplowanalytics.snowplow/consent_document/jsonschema/1-0-0",data:S({id:e.id,version:e.version,name:e.name,description:e.description})};t=P({event:{schema:"iglu:com.snowplowanalytics.snowplow/consent_granted/jsonschema/1-0-0",data:S({expiry:t})}}),o=[o],n.core.track(t,e.context?e.context.concat(o):o,e.timestamp)}))},trackConsentWithdrawn:function(e,n){void 0===n&&(n=Object.keys(un)),Q(n,un,(function(n){var t=e.all,o={schema:"iglu:com.snowplowanalytics.snowplow/consent_document/jsonschema/1-0-0",data:S({id:e.id,version:e.version,name:e.name,description:e.description})};t=P({event:{schema:"iglu:com.snowplowanalytics.snowplow/consent_withdrawn/jsonschema/1-0-0",data:S({all:t})}}),o=[o],n.core.track(t,e.context?e.context.concat(o):o,e.timestamp)}))}}),dn={},mn=!1,pn=Object.freeze({__proto__:null,GeolocationPlugin:ae,enableGeolocationContext:ie}),gn=Object.freeze({__proto__:null,GaCookiesPlugin:ce}),vn={},hn={},yn=Object.freeze({__proto__:null,LinkClickTrackingPlugin:se,enableLinkClickTracking:function(e,n){void 0===e&&(e={}),void 0===n&&(n=Object.keys(vn)),n.forEach((function(n){vn[n]&&(vn[n].sharedState.hasLoaded?(fe(e,n),de(n)):vn[n].sharedState.registeredOnLoadHandlers.push((function(){fe(e,n),de(n)})))}))},refreshLinkClickTracking:function(e){void 0===e&&(e=Object.keys(vn)),e.forEach((function(e){vn[e]&&(vn[e].sharedState.hasLoaded?de(e):vn[e].sharedState.registeredOnLoadHandlers.push((function(){de(e)})))}))},trackLinkClick:function(e,n){void 0===n&&(n=Object.keys(vn)),Q(n,vn,(function(n){n.core.track(T(e),e.context,e.timestamp)}))}});!function(e){e.CHANGE_FORM="change_form",e.FOCUS_FORM="focus_form",e.SUBMIT_FORM="submit_form"}(sn||(sn={}));var wn=[sn.CHANGE_FORM,sn.FOCUS_FORM,sn.SUBMIT_FORM],kn=["textarea","input","select"],An=function(e){return e},bn={},_n=Object.freeze({__proto__:null,FormTrackingPlugin:he,enableFormTracking:function(e,n){void 0===e&&(e={}),void 0===n&&(n=Object.keys(bn)),n.forEach((function(n){bn[n]&&(bn[n].sharedState.hasLoaded?me(bn[n],e):bn[n].sharedState.registeredOnLoadHandlers.push((function(){me(bn[n],e)})))}))}}),Pn={},Tn=Object.freeze({__proto__:null,ErrorTrackingPlugin:ye,enableErrorTracking:function(e,n){void 0===e&&(e={}),void 0===n&&(n=Object.keys(Pn));var t=e.filter,o=e.contextAdder,r=e.context;N(window,"error",(function(e){if(t&&O(t)&&t(e)||null==t){var a=n,i=r||[];o&&O(o)&&(i=i.concat(o(e))),we({message:e.message,filename:e.filename,lineno:e.lineno,colno:e.colno,error:e.error,context:i},a)}}),!0)},trackError:we}),Sn={exports:{}};!function(e){var n,t,o,r,a,i;n={"America/Denver":["America/Mazatlan"],"America/Chicago":["America/Mexico_City"],"America/Asuncion":["America/Campo_Grande","America/Santiago"],"America/Montevideo":["America/Sao_Paulo","America/Santiago"],"Asia/Beirut":"Asia/Amman Asia/Jerusalem Europe/Helsinki Asia/Damascus Africa/Cairo Asia/Gaza Europe/Minsk Africa/Windhoek".split(" "),"Pacific/Auckland":["Pacific/Fiji"],"America/Los_Angeles":["America/Santa_Isabel"],"America/New_York":["America/Havana"],"America/Halifax":["America/Goose_Bay"],"America/Godthab":["America/Miquelon"],"Asia/Dubai":["Asia/Yerevan"],"Asia/Jakarta":["Asia/Krasnoyarsk"],"Asia/Shanghai":["Asia/Irkutsk","Australia/Perth"],"Australia/Sydney":["Australia/Lord_Howe"],"Asia/Tokyo":["Asia/Yakutsk"],"Asia/Dhaka":["Asia/Omsk"],"Asia/Baku":["Asia/Yerevan"],"Australia/Brisbane":["Asia/Vladivostok"],"Pacific/Noumea":["Asia/Vladivostok"],"Pacific/Majuro":["Asia/Kamchatka","Pacific/Fiji"],"Pacific/Tongatapu":["Pacific/Apia"],"Asia/Baghdad":["Europe/Minsk","Europe/Moscow"],"Asia/Karachi":["Asia/Yekaterinburg"],"Africa/Johannesburg":["Asia/Gaza","Africa/Cairo"]},t=function(){for(var e=[],n=0;11>=n;n++)for(var t=1;28>=t;t++){var o=-new Date(2014,n,t).getTimezoneOffset();o=null!==o?o:0,e?e&&e[e.length-1]!==o&&e.push(o):e.push()}return e},o=function e(n,t,o){void 0===t&&(t=864e5,o=36e5);var r=new Date(n.getTime()-t).getTime();n=n.getTime()+t;for(var a=new Date(r).getTimezoneOffset(),i=null;ra&&(s=u),a=l),r+=864e5}t=!(!c||!s)&&{s:o(c).getTime(),e:o(s).getTime()},e.push(t)}return e}();return function(e){for(var n=0;n=f.rules[m].s&&e[m].e<=f.rules[m].e)){d="N/A";break}if(d=0,d+=Math.abs(e[m].s-f.rules[m].s),864e6<(d+=Math.abs(f.rules[m].e-e[m].e))){d="N/A";break}}"N/A"!==(f=r(e,t,d,f))&&(o[l.name]=f)}for(var p in o)if(o.hasOwnProperty(p))for(e=0;ee?n[0]+",1":0n.length&&Array.isArray(n[0])&&(n=[{},n[0]]),r(e[0],n)})))}var i;if("string"==typeof n[0]&&f(n[1])&&(void 0===n[2]||Array.isArray(n[2]))){var c=n[0],s=n[1],d=n[2];(null===(i=n[3])||void 0===i||i)&&(i=u.setTimeout((function(){o(c)}),5e3),p[c]={timeout:i}),(i=l.createElement("script")).setAttribute("src",c),i.setAttribute("async","1"),N(i,"error",(function(){o(c),Ge.warn("Failed to load plugin ".concat(s[0]," from ").concat(c))}),!0),N(i,"load",(function(){var n=s[1],r=u[s[0]];if(r&&"object"==typeof r){var i=r[n];n=e(r,["symbol"==typeof n?n:n+""]),h.addPlugin.apply(null,[{plugin:i.apply(null,d)},t]),a(n)}o(c)}),!0),l.head.appendChild(i)}else{if("object"==typeof n[0]&&"string"==typeof n[1]&&(void 0===n[2]||Array.isArray(n[2]))){var m=n[0],v=n[1];if(i=n[2],m)return n=m[v],m=e(m,["symbol"==typeof v?v:v+""]),h.addPlugin.apply(null,[{plugin:n.apply(null,i)},t]),void a(m)}Ge.warn("Failed to add Plugin: ".concat(n[1]))}}function s(){for(var e=[],t=0;t handleMethodCall(MethodCall call) async { - if (!isSnowplowInstalled()) { - throw PlatformException( - code: 'Unimplemented', - details: 'Snowplow JS tracker is not installed', - ); - } - switch (call.method) { case 'createTracker': return onCreateTracker(call); diff --git a/lib/src/web/readers/configurations/configuration_reader.dart b/lib/src/web/readers/configurations/configuration_reader.dart index ab8f021..591e11d 100644 --- a/lib/src/web/readers/configurations/configuration_reader.dart +++ b/lib/src/web/readers/configurations/configuration_reader.dart @@ -20,9 +20,8 @@ class ConfigurationReader extends Configuration { : super( namespace: map['namespace'], networkConfig: NetworkConfigurationReader(map['networkConfig']), - trackerConfig: map['trackerConfig'] != null - ? TrackerConfigurationReader(map['trackerConfig']) - : null, + trackerConfig: + TrackerConfigurationReader(map['trackerConfig'] ?? {}), subjectConfig: map['subjectConfig'] != null ? SubjectConfigurationReader(map['subjectConfig']) : null, @@ -30,8 +29,6 @@ class ConfigurationReader extends Configuration { ? GdprConfigurationReader(map['gdprConfig']) : null); - bool get addSessionContext => trackerConfig?.sessionContext ?? true; - dynamic getTrackerOptions() { var options = {}; diff --git a/lib/src/web/readers/configurations/tracker_configuration_reader.dart b/lib/src/web/readers/configurations/tracker_configuration_reader.dart index f24a1f7..7ba27a7 100644 --- a/lib/src/web/readers/configurations/tracker_configuration_reader.dart +++ b/lib/src/web/readers/configurations/tracker_configuration_reader.dart @@ -45,6 +45,9 @@ class TrackerConfigurationReader extends TrackerConfiguration { if (webPageContext != null) { contexts['webPage'] = webPageContext; } + if (sessionContext ?? true) { + contexts['session'] = true; + } if (contexts.isNotEmpty) { options['contexts'] = contexts; } diff --git a/lib/src/web/snowplow_tracker_controller.dart b/lib/src/web/snowplow_tracker_controller.dart index 03a2d49..0b3123f 100644 --- a/lib/src/web/snowplow_tracker_controller.dart +++ b/lib/src/web/snowplow_tracker_controller.dart @@ -10,6 +10,7 @@ // See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. import 'dart:js_util'; +import 'dart:html'; import 'readers/configurations/configuration_reader.dart'; import 'readers/messages/event_message_reader.dart'; @@ -50,10 +51,6 @@ class SnowplowTrackerController { 'heartbeatDelay': webActivityTracking.heartbeatDelay })); } - - if (configuration.addSessionContext) { - addSessionContextPlugin(configuration.namespace); - } } static void trackEvent(EventMessageReader message) { @@ -70,14 +67,27 @@ class SnowplowTrackerController { } static String? getSessionUserId() { - return getSnowplowDuid(); + return _getSnowplowCookieParts()?[0]; } static String? getSessionId() { - return getSnowplowSid(); + return _getSnowplowCookieParts()?[5]; } static int? getSessionIndex() { - return getSnowplowVid(); + final cookiePart = _getSnowplowCookieParts()?[2]; + if (cookiePart != null) { + return int.tryParse(cookiePart); + } + return null; + } + + static List? _getSnowplowCookieParts() { + final regex = RegExp(r'_sp_id\.[a-f0-9]+=([^;]+);?'); + if (document.cookie != null) { + final cookieValue = regex.firstMatch(document.cookie!)?.group(1); + return cookieValue?.split('.'); + } + return null; } } diff --git a/lib/src/web/sp.dart b/lib/src/web/sp.dart index 035623b..973160a 100644 --- a/lib/src/web/sp.dart +++ b/lib/src/web/sp.dart @@ -22,18 +22,3 @@ external void snowplow(String method, dynamic arg4, dynamic arg5, dynamic arg6]); - -@JS('addSessionContextPlugin') -external void addSessionContextPlugin(String tracker); - -@JS('getSnowplowDuid') -external String? getSnowplowDuid(); - -@JS('getSnowplowSid') -external String? getSnowplowSid(); - -@JS('getSnowplowVid') -external int? getSnowplowVid(); - -@JS('isSnowplowInstalled') -external bool isSnowplowInstalled(); diff --git a/pubspec.yaml b/pubspec.yaml index 6fe76fa..9dfaaca 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,6 +33,3 @@ flutter: web: pluginClass: SnowplowTrackerPluginWeb fileName: snowplow_tracker_plugin_web.dart - - assets: - - packages/snowplow_tracker/js/sp_session_context_plugin.js From b7e5b0c91b7bad03cec3e837530297554aed0093 Mon Sep 17 00:00:00 2001 From: Matus Tomlein Date: Thu, 6 Oct 2022 15:44:27 +0200 Subject: [PATCH 3/6] Fix schema link in documentation for ScreenView (close #12) PR #23 --- CONTRIBUTING.md | 6 +++--- README.md | 10 +++++----- doc/01-getting-started.md | 6 +++--- doc/02-configuration.md | 2 +- doc/03-tracking-events.md | 12 ++++++------ doc/05-sessions.md | 4 ++-- example/lib/overview.dart | 2 +- lib/events/self_describing.dart | 4 ++-- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index df02bc2..50ca0a0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ The Snowplow Flutter Tracker is maintained by the Engineering team at Snowplow A We are extremely grateful for all contributions we receive, whether that is reporting an issue or a change to the code which can be made in the form of a pull request. -For support requests, please use our community support Discourse forum: https://discourse.snowplowanalytics.com/. +For support requests, please use our community support Discourse forum: https://discourse.snowplow.io/. ## Setting up an Environment @@ -16,7 +16,7 @@ You should ensure you are comfortable building and testing the existing release ### Creating an issue -The project contains an issue template which should help guiding you through the process. However, please keep in mind that support requests should go to our Discourse forum: https://discourse.snowplowanalytics.com/ and not GitHub issues. +The project contains an issue template which should help guiding you through the process. However, please keep in mind that support requests should go to our Discourse forum: https://discourse.snowplow.io/ and not GitHub issues. It's also a good idea to log an issue before starting to work on a pull request to discuss it with the maintainers. A pull request is just one solution to a problem and it is often a good idea to talk about the problem with the maintainers first. @@ -75,6 +75,6 @@ The @snowplowcla bot will guide you through the process. ### Community support requests -Please do not log an issue if you are asking for support, all of our community support requests go through our Discourse forum: https://discourse.snowplowanalytics.com/. +Please do not log an issue if you are asking for support, all of our community support requests go through our Discourse forum: https://discourse.snowplow.io/. Posting your problem there ensures more people will see it and you should get support faster than creating a new issue on GitHub. Please do create a new issue on GitHub if you think you've found a bug though! diff --git a/README.md b/README.md index 7e9a4c7..107af21 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ import 'package:snowplow_tracker/snowplow_tracker.dart' #### Installation on Web -If using the tracker within a Flutter app for Web, you will also need to import the Snowplow JavaScript Tracker in your `index.html` file. Please load the JS tracker with the Snowplow tag as [described in the official documentation](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-trackers/javascript-tracker/javascript-tracker-v3/tracker-setup/loading/). Do not change the global function name `snowplow` that is used to access the tracker – the Flutter APIs assume that it remains the default as shown in documentation. +If using the tracker within a Flutter app for Web, you will also need to import the Snowplow JavaScript Tracker in your `index.html` file. Please load the JS tracker with the Snowplow tag as [described in the official documentation](https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/javascript-trackers/javascript-tracker/javascript-tracker-v3/tracker-setup/loading/). Do not change the global function name `snowplow` that is used to access the tracker – the Flutter APIs assume that it remains the default as shown in documentation. Make sure to use JavaScript tracker version `3.5` or newer. You may also refer to the [example project](https://github.com/snowplow-incubator/snowplow-flutter-tracker/tree/main/example) in the Flutter tracker repository to see this in action. @@ -223,8 +223,8 @@ limitations under the License. [website]: https://snowplowanalytics.com [snowplow]: https://github.com/snowplow/snowplow -[docs]: https://docs.snowplowanalytics.com/ -[flutter-docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/flutter-tracker/ +[docs]: https://docs.snowplow.io/ +[flutter-docs]: https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/flutter-tracker/ [gh-actions]: https://github.com/snowplow-incubator/snowplow-flutter-tracker/actions/workflows/build.yml [gh-actions-image]: https://github.com/snowplow-incubator/snowplow-flutter-tracker/actions/workflows/build.yml/badge.svg @@ -235,9 +235,9 @@ limitations under the License. [release-image]: https://img.shields.io/pub/v/snowplow_tracker [releases]: https://pub.dev/packages/snowplow_tracker -[techdocs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/flutter-tracker/ +[techdocs]: https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/flutter-tracker/ [techdocs-image]: https://d3i6fms1cm1j0i.cloudfront.net/github/images/techdocs.png -[setup]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/flutter-tracker/quick-start-guide +[setup]: https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/flutter-tracker/quick-start-guide [setup-image]: https://d3i6fms1cm1j0i.cloudfront.net/github/images/setup.png [api-docs]: https://snowplow.github.io/snowplow-flutter-tracker/ diff --git a/doc/01-getting-started.md b/doc/01-getting-started.md index 7bdec40..f68ce0e 100644 --- a/doc/01-getting-started.md +++ b/doc/01-getting-started.md @@ -1,6 +1,6 @@ # Getting started -Designing how and what to track in your app is an important decision. Check out our docs about tracking design [here](https://docs.snowplowanalytics.com/docs/understanding-tracking-design/introduction-to-tracking-design/). +Designing how and what to track in your app is an important decision. Check out our docs about tracking design [here](https://docs.snowplow.io/docs/understanding-tracking-design/introduction-to-tracking-design/). The following steps will guide you through setting up the Flutter tracker in your project and tracking a simple event. @@ -27,7 +27,7 @@ import 'package:snowplow_tracker/snowplow_tracker.dart' ### Installation on Web -If using the tracker within a Flutter app for Web, you will also need to import the Snowplow JavaScript Tracker in your `index.html` file. Please load the JS tracker with the Snowplow tag as [described in the official documentation](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-trackers/javascript-tracker/javascript-tracker-v3/tracker-setup/loading/). Do not change the global function name `snowplow` that is used to access the tracker – the Flutter APIs assume that it remains the default as shown in documentation. +If using the tracker within a Flutter app for Web, you will also need to import the Snowplow JavaScript Tracker in your `index.html` file. Please load the JS tracker with the Snowplow tag as [described in the official documentation](https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/javascript-trackers/javascript-tracker/javascript-tracker-v3/tracker-setup/loading/). Do not change the global function name `snowplow` that is used to access the tracker – the Flutter APIs assume that it remains the default as shown in documentation. Make sure to use JavaScript tracker version `3.5` or newer. You may also refer to the [example project](https://github.com/snowplow-incubator/snowplow-flutter-tracker/tree/main/example) in the Flutter tracker repository to see this in action. @@ -66,4 +66,4 @@ Visit documentation about [tracking events](03-tracking-events.md) to learn abou Testing that your event tracking is properly configured can be as important as testing the other aspects of your app. It confirms that you are generating the events you expect. -We provide two types of pipeline for testing and debugging. [Snowplow Mini](https://docs.snowplowanalytics.com/docs/understanding-your-pipeline/what-is-snowplow-mini/) is especially useful in manual schema and pipeline testing. [Snowplow Micro](https://docs.snowplowanalytics.com/docs/understanding-your-pipeline/what-is-snowplow-micro/) is a minimal pipeline designed to be used as part of your app's automated test suite. +We provide two types of pipeline for testing and debugging. [Snowplow Mini](https://docs.snowplow.io/docs/understanding-your-pipeline/what-is-snowplow-mini/) is especially useful in manual schema and pipeline testing. [Snowplow Micro](https://docs.snowplow.io/docs/understanding-your-pipeline/what-is-snowplow-micro/) is a minimal pipeline designed to be used as part of your app's automated test suite. diff --git a/doc/02-configuration.md b/doc/02-configuration.md index df8f6b8..2e0ab97 100644 --- a/doc/02-configuration.md +++ b/doc/02-configuration.md @@ -63,7 +63,7 @@ Some of the properties are only configurable on iOS and Android and are automati | `screenViewport` | `Size?` | The screen viewport. | ✔ | ✔ | Non-configurable, auto-assigned. | | | `colorDepth` | `double?` | The color depth. | ✔ | ✔ | Non-configurable, auto-assigned. | | -The configured attributes are mapped to Snowplow event properties described in the [Snowplow Tracker Protocol](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/snowplow-tracker-protocol/). They are mapped as follows: +The configured attributes are mapped to Snowplow event properties described in the [Snowplow Tracker Protocol](https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/snowplow-tracker-protocol/). They are mapped as follows: | Attribute | Event Property | |---|---| diff --git a/doc/03-tracking-events.md b/doc/03-tracking-events.md index 9c75349..ee12f4e 100644 --- a/doc/03-tracking-events.md +++ b/doc/03-tracking-events.md @@ -17,7 +17,7 @@ Event classes supported by the Flutter Tracker: All the methods share common features and parameters. Every type of event can have an optional context added. See the [next page](04-adding-data.md) to learn about adding extra data to events. It's important to understand how event context works, as it is one of the most powerful Snowplow features. Adding event context is a way to add depth, richness and value to all of your events. -Snowplow events are all processed into the same format, regardless of the event type (and regardless of the tracker language used). Read about the different properties and fields of events in the [Snowplow Tracker Protocol](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/snowplow-tracker-protocol/). +Snowplow events are all processed into the same format, regardless of the event type (and regardless of the tracker language used). Read about the different properties and fields of events in the [Snowplow Tracker Protocol](https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/snowplow-tracker-protocol/). We will first discuss the custom event types, followed by the out-of-the-box event types. Note that you can also design and create your own page view, or screen view, using `selfDescribing`, to fit your business needs better. The out-of-the-box event types are provided so you can get started with generating event data quickly. @@ -32,11 +32,11 @@ This is particularly useful when: - You want to track event types which are proprietary/specific to your business - You want to track events which have unpredictable or frequently changing properties -A self-describing JSON has two keys, `schema` and `data`. The `schema` value should point to a valid self-describing JSON schema. They are called self-describing because the schema will specify the fields allowed in the data value. Read more about how schemas are used with Snowplow [here](https://docs.snowplowanalytics.com/docs/understanding-tracking-design/understanding-schemas-and-validation/). +A self-describing JSON has two keys, `schema` and `data`. The `schema` value should point to a valid self-describing JSON schema. They are called self-describing because the schema will specify the fields allowed in the data value. Read more about how schemas are used with Snowplow [here](https://docs.snowplow.io/docs/understanding-tracking-design/understanding-schemas-and-validation/). After events have been collected by the event collector, they are validated to ensure that the properties match the self-describing JSONs. Mistakes (e.g. extra fields, or incorrect types) will result in events being processed as Bad Events. This means that only high-quality, valid events arrive in your data storage or real-time stream. -Your schemas must be accessible to your pipeline to allow this validation. We provide [Iglu](https://docs.snowplowanalytics.com/docs/pipeline-components-and-applications/iglu/) for schema management. If you are a paid Snowplow customer, you can manage your schemas through your console. Check out our [Ruby tracker Rails](https://github.com/snowplow-incubator/snowplow-ruby-tracker-examples) example to see how we included schemas in the Snowplow Micro testing pipeline in that app. +Your schemas must be accessible to your pipeline to allow this validation. We provide [Iglu](https://docs.snowplow.io/docs/pipeline-components-and-applications/iglu/) for schema management. If you are a paid Snowplow customer, you can manage your schemas through your console. Check out our [Ruby tracker Rails](https://github.com/snowplow-incubator/snowplow-ruby-tracker-examples) example to see how we included schemas in the Snowplow Micro testing pipeline in that app. Creating an instance of `SelfDescribing` takes a schema name and a dictionary of event data. @@ -84,15 +84,15 @@ tracker.track(Structured( The `PageViewEvent` may be used to track page views on the Web. The event is designed to track web page views and automatically captures page title, referrer and URL. Being Web-only, it is not implemented on Android and iOS where the app is not displayed as a Web page. -Page view events are the basic building blocks for the [Snowplow web data model](https://docs.snowplowanalytics.com/docs/modeling-your-data/the-snowplow-web-data-model/). +Page view events are the basic building blocks for the [Snowplow web data model](https://docs.snowplow.io/docs/modeling-your-data/the-snowplow-web-data-model/). ## Track screen views with `ScreenView` Use `ScreenView` to track a user viewing a screen (or similar) within your app. This is the page view equivalent for apps that are not webpages. The arguments are `name`, `id`, `type`, and `transitionType`. The `name` and `id` properties are required. "Name" is the human-readable screen name, and "ID" should be the unique screen ID (UUID v4). -Screen view events are used in the [Snowplow mobile data model](https://docs.snowplowanalytics.com/docs/modeling-your-data/the-snowplow-mobile-model/). Nevertheless, the Flutter tracker also implements them on Web. You may adopt the mobile data model and choose to track screen views instead of page views on Web to provide consistent event tracking across all platforms. +Screen view events are used in the [Snowplow mobile data model](https://docs.snowplow.io/docs/modeling-your-data/the-snowplow-mobile-data-model/). Nevertheless, the Flutter tracker also implements them on Web. You may adopt the mobile data model and choose to track screen views instead of page views on Web to provide consistent event tracking across all platforms. -This method creates an unstruct event, by creating and tracking a self-describing event. The schema ID for this is "iglu:com.snowplowanalytics.snowplow/screen_view/jsonschema/1-0-0", and the data field will contain the parameters which you provide. That schema is hosted on the schema repository Iglu Central, and so will always be available to your pipeline. +This method creates a self-describing event, by creating and tracking a self-describing event. The schema ID for this is "iglu:com.snowplowanalytics.mobile/screen_view/jsonschema/1-0-0", and the data field will contain the parameters which you provide. That schema is hosted on the schema repository Iglu Central, and so will always be available to your pipeline. | Argument | Description | Required in event? | |---|---|---| diff --git a/doc/05-sessions.md b/doc/05-sessions.md index 58e0170..886cb7b 100644 --- a/doc/05-sessions.md +++ b/doc/05-sessions.md @@ -1,8 +1,8 @@ # Sessions and data model -The Flutter tracker gives you the option to adopt the [Snowplow mobile data model](https://docs.snowplowanalytics.com/docs/modeling-your-data/the-snowplow-mobile-model/) across all supported platforms – Android, iOS, and Web. In contrast with the [web data model](https://docs.snowplowanalytics.com/docs/modeling-your-data/the-snowplow-web-data-model/) which builds on page view and page ping events, the mobile data model uses screen view events. The mobile data model was chosen in order to make event tracking consistent across all supported Flutter platforms. +The Flutter tracker gives you the option to adopt the [Snowplow mobile data model](https://docs.snowplow.io/docs/modeling-your-data/the-snowplow-mobile-model/) across all supported platforms – Android, iOS, and Web. In contrast with the [web data model](https://docs.snowplow.io/docs/modeling-your-data/the-snowplow-web-data-model/) which builds on page view and page ping events, the mobile data model uses screen view events. The mobile data model was chosen in order to make event tracking consistent across all supported Flutter platforms. -In addition to adopting screen view events, the mobile data model defines that sessions are represented using a [context entity](https://github.com/snowplow/iglu-central/blob/master/schemas/com.snowplowanalytics.snowplow/client_session/jsonschema/1-0-1). Concretely, the `client_session` context entity is added to all tracked events if session tracking is enabled in the tracker configuration (through the `sessionContext` property). This entity consists of the following properties: +In addition to adopting screen view events, the mobile data model defines that sessions are represented using a [context entity](http://iglucentral.com/schemas/com.snowplowanalytics.snowplow/client_session/jsonschema/1-0-2). Concretely, the `client_session` context entity is added to all tracked events if session tracking is enabled in the tracker configuration (through the `sessionContext` property). This entity consists of the following properties: | Attribute | Description | Required? | |---|---|---| diff --git a/example/lib/overview.dart b/example/lib/overview.dart index 0063291..c0af7c1 100644 --- a/example/lib/overview.dart +++ b/example/lib/overview.dart @@ -38,7 +38,7 @@ import 'package:snowplow_tracker/snowplow_tracker.dart' #### Installation on Web -If using the tracker within a Flutter app for Web, you will also need to import the Snowplow JavaScript Tracker in your `index.html` file. Please load the JS tracker with the Snowplow tag as [described in the official documentation](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-trackers/javascript-tracker/javascript-tracker-v3/tracker-setup/loading/). Do not change the global function name `snowplow` that is used to access the tracker – the Flutter APIs assume that it remains the default as shown in documentation. +If using the tracker within a Flutter app for Web, you will also need to import the Snowplow JavaScript Tracker in your `index.html` file. Please load the JS tracker with the Snowplow tag as [described in the official documentation](https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/javascript-trackers/javascript-tracker/javascript-tracker-v3/tracker-setup/loading/). Do not change the global function name `snowplow` that is used to access the tracker – the Flutter APIs assume that it remains the default as shown in documentation. Make sure to use JavaScript tracker version `3.5` or newer. You may also refer to the [example project](https://github.com/snowplow-incubator/snowplow-flutter-tracker/tree/main/example) in the Flutter tracker repository to see this in action. diff --git a/lib/events/self_describing.dart b/lib/events/self_describing.dart index 77910b9..8a1c8d6 100644 --- a/lib/events/self_describing.dart +++ b/lib/events/self_describing.dart @@ -15,8 +15,8 @@ import 'package:snowplow_tracker/events/event.dart'; /// Event to track custom information that does not fit into the out-of-the box events. /// -/// Self-describing events are a [data structure based on JSON Schemas](https://docs.snowplowanalytics.com/docs/understanding-tracking-design/understanding-schemas-and-validation/) and can have arbitrarily many fields. -/// To define your own custom self-describing event, you must create a JSON schema for that event and upload it to an [Iglu Schema Repository](https://github.com/snowplow/iglu) using [igluctl](https://docs.snowplowanalytics.com/docs/open-source-components-and-applications/iglu/) (or if a Snowplow BDP customer, you can use the [Snowplow BDP Console UI](https://docs.snowplowanalytics.com/docs/understanding-tracking-design/managing-data-structures/) or [Data Structures API](https://docs.snowplowanalytics.com/docs/understanding-tracking-design/managing-data-structures-via-the-api-2/)). +/// Self-describing events are a [data structure based on JSON Schemas](https://docs.snowplow.io/docs/understanding-tracking-design/understanding-schemas-and-validation/) and can have arbitrarily many fields. +/// To define your own custom self-describing event, you must create a JSON schema for that event and upload it to an [Iglu Schema Repository](https://github.com/snowplow/iglu) using [igluctl](https://docs.snowplow.io/docs/open-source-components-and-applications/iglu/) (or if a Snowplow BDP customer, you can use the [Snowplow BDP Console UI](https://docs.snowplow.io/docs/understanding-tracking-design/managing-data-structures/) or [Data Structures API](https://docs.snowplow.io/docs/understanding-tracking-design/managing-data-structures-via-the-api-2/)). /// Snowplow uses the schema to validate that the JSON containing the event properties is well-formed. /// {@category Tracking events} /// {@category Adding data to your events} From e8558934ef3c794a5a89d4e69555d571b77a9fef Mon Sep 17 00:00:00 2001 From: Miranda Wilson Date: Thu, 6 Oct 2022 15:51:38 +0100 Subject: [PATCH 4/6] Upgrade underlying mobile native trackers to version 4 (close #17) PR #24 * Upgrade to iOS tracker v4 * Update pubspec.lock * Use Android v4 * Fix pubspec.lock in example --- android/build.gradle | 2 +- example/ios/Flutter/AppFrameworkInfo.plist | 2 +- example/ios/Podfile | 2 +- example/ios/Podfile.lock | 12 ++++---- example/pubspec.lock | 35 +++++++++++----------- ios/snowplow_tracker.podspec | 2 +- 6 files changed, 28 insertions(+), 27 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 1982482..591dd17 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -49,5 +49,5 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "com.snowplowanalytics:snowplow-android-tracker:3.+" + implementation "com.snowplowanalytics:snowplow-android-tracker:4.+" } diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index 8d4492f..9625e10 100644 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 9.0 + 11.0 diff --git a/example/ios/Podfile b/example/ios/Podfile index 1e8c3c9..88359b2 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '11.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 3384557..4ae28db 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -7,8 +7,8 @@ PODS: - Flutter - snowplow_tracker (0.1.0): - Flutter - - SnowplowTracker (~> 3.0.2) - - SnowplowTracker (3.0.2): + - SnowplowTracker (~> 4.0) + - SnowplowTracker (4.0.0): - FMDB (~> 2.7) DEPENDENCIES: @@ -30,12 +30,12 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/snowplow_tracker/ios" SPEC CHECKSUMS: - Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a + Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a integration_test: a1e7d09bd98eca2fc37aefd79d4f41ad37bdbbe5 - snowplow_tracker: 90ea9083b578578110e3bfeb65a0720b654755b2 - SnowplowTracker: a96fd8819c86c56844f930af372d0f4f92c35472 + snowplow_tracker: 0a5e9a965a7ef88141c2dba156c43148ee1acdb0 + SnowplowTracker: 2ddc6db70af5415a87ac279f044d27d140b3a2b8 -PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c +PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 COCOAPODS: 1.11.3 diff --git a/example/pubspec.lock b/example/pubspec.lock index 3ffbe45..8496dfa 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,7 +7,7 @@ packages: name: archive url: "https://pub.dartlang.org" source: hosted - version: "3.1.11" + version: "3.3.0" args: dependency: transitive description: @@ -21,7 +21,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.2" + version: "2.9.0" boolean_selector: dependency: transitive description: @@ -35,7 +35,7 @@ packages: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" charcode: dependency: transitive description: @@ -49,7 +49,7 @@ packages: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" collection: dependency: transitive description: @@ -63,7 +63,7 @@ packages: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.2" cupertino_icons: dependency: "direct main" description: @@ -77,7 +77,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" file: dependency: transitive description: @@ -170,28 +170,28 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.11" + version: "0.12.12" material_color_utilities: dependency: transitive description: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.4" + version: "0.1.5" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" platform: dependency: transitive description: @@ -224,7 +224,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.2" + version: "1.9.0" stack_trace: dependency: transitive description: @@ -245,35 +245,35 @@ packages: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" sync_http: dependency: transitive description: name: sync_http url: "https://pub.dartlang.org" source: hosted - version: "0.3.0" + version: "0.3.1" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.9" + version: "0.4.12" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" uuid: dependency: "direct main" description: @@ -294,7 +294,7 @@ packages: name: vm_service url: "https://pub.dartlang.org" source: hosted - version: "8.2.2" + version: "9.0.0" webdriver: dependency: transitive description: @@ -305,3 +305,4 @@ packages: sdks: dart: ">=2.17.0 <3.0.0" flutter: ">=3.0.0" + diff --git a/ios/snowplow_tracker.podspec b/ios/snowplow_tracker.podspec index 9642127..f1c9595 100644 --- a/ios/snowplow_tracker.podspec +++ b/ios/snowplow_tracker.podspec @@ -15,7 +15,7 @@ A package for tracking Snowplow events in Flutter apps. s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.dependency 'Flutter' - s.dependency 'SnowplowTracker', '~> 3.0.2' + s.dependency 'SnowplowTracker', '~> 4.0' s.platform = :ios, '9.0' # Flutter.framework does not contain a i386 slice. From fbfc3fb01b03240c515864710fc3589d6ff6f1d3 Mon Sep 17 00:00:00 2001 From: Miranda Wilson Date: Fri, 7 Oct 2022 13:07:40 +0100 Subject: [PATCH 5/6] Configure custom POST path (close #15) PR #22. * Add customPostPath to Snowplow class * Add docstring for customPostPath * Update Android config reader * Set customPostPath for Android * Set customPostPath for iOS * Set customPostPath for web * Restore demo app endpoint * Tidy up code * Remove leading slash, but add it back for web * Update docstring * Update docs * Allow iOS tracker to add a leading / if necessary --- .../NetworkConfigurationReader.kt | 13 ++++--- doc/02-configuration.md | 22 ++++++------ example/pubspec.lock | 1 - .../NetworkConfigurationReader.swift | 12 +++++-- lib/configurations/network_configuration.dart | 12 +++++-- lib/snowplow.dart | 5 ++- .../network_configuration_reader.dart | 6 +++- test/snowplow_test.dart | 34 +++++++++++++++++++ 8 files changed, 83 insertions(+), 22 deletions(-) diff --git a/android/src/main/kotlin/com/snowplowanalytics/snowplow_tracker/readers/configurations/NetworkConfigurationReader.kt b/android/src/main/kotlin/com/snowplowanalytics/snowplow_tracker/readers/configurations/NetworkConfigurationReader.kt index 3b03aec..33a5c94 100644 --- a/android/src/main/kotlin/com/snowplowanalytics/snowplow_tracker/readers/configurations/NetworkConfigurationReader.kt +++ b/android/src/main/kotlin/com/snowplowanalytics/snowplow_tracker/readers/configurations/NetworkConfigurationReader.kt @@ -19,15 +19,18 @@ class NetworkConfigurationReader(values: Map) { val endpoint: String by values val method: String? by valuesDefault + val customPostPath: String? by valuesDefault fun toConfiguration(): NetworkConfiguration { - if (method != null) { - return NetworkConfiguration( - endpoint, - if ("get".equals(method, true)) { HttpMethod.GET } else { HttpMethod.POST } + val networkConfig: NetworkConfiguration = if (method != null) { + NetworkConfiguration( + endpoint, + if ("get".equals(method, true)) { HttpMethod.GET } else { HttpMethod.POST } ) } else { - return NetworkConfiguration(endpoint) + NetworkConfiguration(endpoint) } + customPostPath?.let { networkConfig.customPostPath(it) } + return networkConfig } } diff --git a/doc/02-configuration.md b/doc/02-configuration.md index 2e0ab97..9d4c4fe 100644 --- a/doc/02-configuration.md +++ b/doc/02-configuration.md @@ -6,7 +6,6 @@ The package provides a single method to initialize and configure a new tracker, SnowplowTracker tracker = await Snowplow.createTracker( namespace: 'ns1', endpoint: 'http://...', - method: Method.post, trackerConfig: const TrackerConfiguration(...), gdprConfig: const GdprConfiguration(...), subjectConfig: const SubjectConfiguration(...)); @@ -15,16 +14,19 @@ SnowplowTracker tracker = await Snowplow.createTracker( The method returns a `SnowplowTracker` instance. This can be later used for tracking events, or accessing tracker properties. However, all methods provided by the `SnowplowTracker` instance are also available as static functions in the `Snowplow` class but they require passing the tracker namespace as string. -The only required attributes of the `Snowplow.createTracker` method are `namespace` used to identify the tracker, and the Snowplow collector `endpoint`. Additionally, one can configure the HTTP method to be used when sending events to the collector and provide configuration by instantiating classes for `TrackerConfiguration`, `SubjectConfiguration`, or `GdprConfiguration`. The following arguments are accepted by the `Snowplow.createTracker` method: +The only required attributes of the `Snowplow.createTracker` method are `namespace` used to identify the tracker, and the Snowplow collector `endpoint`. Additionally, one can configure the HTTP method to be used when sending events to the collector, as well as a custom POST path, and provide configuration by instantiating classes for `TrackerConfiguration`, `SubjectConfiguration`, or `GdprConfiguration`. By default, events are sent by POST. The following arguments are accepted by the `Snowplow.createTracker` method: -| Attribute | Type | Description | -|---|---|---| -| `namespace` | `String` | Tracker namespace to identify the tracker. | -| `endpoint` | `String` | URI for the Snowplow collector endpoint. | -| `method` | `Method?` | HTTP method to use. `Method.get` and `Method.post` options are available. | -| `trackerConfig` | `TrackerConfiguration?` | Configuration of the tracker and the core tracker properties. | -| `gdprConfig` | `GdprConfiguration?` | Determines the GDPR context that will be attached to all events sent by the tracker. | -| `subjectConfig` | `SubjectConfiguration?` | Subject information about tracked user and device that is added to events. | +| Attribute | Type | Description | +|---|-------------------------|--------------------------------------------------------------------------------------| +| `namespace` | `String` | Tracker namespace to identify the tracker. | +| `endpoint` | `String` | URI for the Snowplow collector endpoint. | +| `method` | `Method?` | HTTP method to use: `Method.get` or `Method.post` (`Method.post` is default). | +| `customPostPath` | `String?` | Custom POST path. | +| `trackerConfig` | `TrackerConfiguration?` | Configuration of the tracker and the core tracker properties. | +| `gdprConfig` | `GdprConfiguration?` | Determines the GDPR context that will be attached to all events sent by the tracker. | +| `subjectConfig` | `SubjectConfiguration?` | Subject information about tracked user and device that is added to events. | + +Setting a custom POST path can be useful in avoiding adblockers; it replaces the default "com.snowplowanalytics/snowplow/tp2". Your event collector must also be configured to accept the custom path. ## Configuration of tracker properties: `TrackerConfiguration` diff --git a/example/pubspec.lock b/example/pubspec.lock index 8496dfa..4fbe26b 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -305,4 +305,3 @@ packages: sdks: dart: ">=2.17.0 <3.0.0" flutter: ">=3.0.0" - diff --git a/ios/Classes/readers/configurations/NetworkConfigurationReader.swift b/ios/Classes/readers/configurations/NetworkConfigurationReader.swift index e98d7fe..40e9795 100644 --- a/ios/Classes/readers/configurations/NetworkConfigurationReader.swift +++ b/ios/Classes/readers/configurations/NetworkConfigurationReader.swift @@ -15,14 +15,22 @@ import SnowplowTracker struct NetworkConfigurationReader: Decodable { let endpoint: String let method: String? + let customPostPath: String? } extension NetworkConfigurationReader { func toConfiguration() -> NetworkConfiguration { + let networkConfig: NetworkConfiguration + if let m = method { - return NetworkConfiguration(endpoint: endpoint, method: m == "get" ? .get : .post) + networkConfig = NetworkConfiguration(endpoint: endpoint, method: m == "get" ? .get : .post) } else { - return NetworkConfiguration(endpoint: endpoint, method: .post) + networkConfig = NetworkConfiguration(endpoint: endpoint, method: .post) + } + + if let c = customPostPath { + networkConfig.customPostPath(c) } + return networkConfig } } diff --git a/lib/configurations/network_configuration.dart b/lib/configurations/network_configuration.dart index 3c05f73..c5e8de5 100644 --- a/lib/configurations/network_configuration.dart +++ b/lib/configurations/network_configuration.dart @@ -22,12 +22,20 @@ class NetworkConfiguration { /// Choice of GET or POST (default) HTTP method used to send events to the collector. final Method? method; - const NetworkConfiguration({required this.endpoint, this.method}); + /// Set a path for POST requests. This will override the default "com.snowplowanalytics.snowplow/tp2" path. + /// You will need to configure your collector to accept your custom path. + final String? customPostPath; + + const NetworkConfiguration( + {required this.endpoint, this.method, this.customPostPath}); Map toMap() { final conf = { 'endpoint': endpoint, - 'method': method?.name + 'method': method?.name, + 'customPostPath': customPostPath?[0] == '/' + ? customPostPath?.substring(1) + : customPostPath }; conf.removeWhere((key, value) => value == null); return conf; diff --git a/lib/snowplow.dart b/lib/snowplow.dart index a00e8a0..fa56e9e 100644 --- a/lib/snowplow.dart +++ b/lib/snowplow.dart @@ -32,16 +32,19 @@ class Snowplow { /// /// [endpoint] refers to the Snowplow collector endpoint. /// [method] is the HTTP method used to send events to collector and it defaults to POST. + /// [customPostPath] is an optional string for custom POST collector paths. static Future createTracker( {required String namespace, required String endpoint, Method? method, + String? customPostPath, TrackerConfiguration? trackerConfig, SubjectConfiguration? subjectConfig, GdprConfiguration? gdprConfig}) async { final configuration = Configuration( namespace: namespace, - networkConfig: NetworkConfiguration(endpoint: endpoint, method: method), + networkConfig: NetworkConfiguration( + endpoint: endpoint, method: method, customPostPath: customPostPath), trackerConfig: trackerConfig, subjectConfig: subjectConfig, gdprConfig: gdprConfig); diff --git a/lib/src/web/readers/configurations/network_configuration_reader.dart b/lib/src/web/readers/configurations/network_configuration_reader.dart index 3d07452..7fc51cd 100644 --- a/lib/src/web/readers/configurations/network_configuration_reader.dart +++ b/lib/src/web/readers/configurations/network_configuration_reader.dart @@ -17,11 +17,15 @@ class NetworkConfigurationReader extends NetworkConfiguration { endpoint: map['endpoint'], method: map['method'] == null ? null - : Method.values.byName(map['method'])); + : Method.values.byName(map['method']), + customPostPath: map['customPostPath']); void addTrackerOptions(dynamic options) { if (method != null) { options['eventMethod'] = method?.name; } + if (customPostPath != null) { + options['postPath'] = '/$customPostPath'; + } } } diff --git a/test/snowplow_test.dart b/test/snowplow_test.dart index bbfe4cf..6b8ed2e 100644 --- a/test/snowplow_test.dart +++ b/test/snowplow_test.dart @@ -12,6 +12,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:snowplow_tracker/configurations/gdpr_configuration.dart'; +import 'package:snowplow_tracker/configurations/network_configuration.dart'; import 'package:snowplow_tracker/configurations/tracker_configuration.dart'; import 'package:snowplow_tracker/events/consent_granted.dart'; import 'package:snowplow_tracker/events/consent_withdrawn.dart'; @@ -71,6 +72,39 @@ void main() { })); }); + test('createsTrackerWithCustomPostPath', () async { + await Snowplow.createTracker( + namespace: 'tns1', + endpoint: 'https://snowplowanalytics.com', + method: Method.post, + customPostPath: 'com.custom', + trackerConfig: const TrackerConfiguration( + devicePlatform: DevicePlatform.iot, base64Encoding: true), + gdprConfig: const GdprConfiguration( + basisForProcessing: 'b', + documentId: 'd', + documentVersion: 'v', + documentDescription: 'e')); + + expect( + methodCall, + isMethodCall('createTracker', arguments: { + 'namespace': 'tns1', + 'networkConfig': { + 'endpoint': 'https://snowplowanalytics.com', + 'method': 'post', + 'customPostPath': 'com.custom' + }, + 'trackerConfig': {'devicePlatform': 'iot', 'base64Encoding': true}, + 'gdprConfig': { + 'basisForProcessing': 'b', + 'documentId': 'd', + 'documentVersion': 'v', + 'documentDescription': 'e', + } + })); + }); + test('tracks structured event', () async { Event event = const Structured(category: 'c1', action: 'a1'); await Snowplow.track(event, tracker: 'tns3'); From f69ced893f25d44f82dbef72b4970429e28ecc6f Mon Sep 17 00:00:00 2001 From: Miranda Wilson Date: Fri, 7 Oct 2022 13:25:31 +0100 Subject: [PATCH 6/6] Prepare for 0.2.0 release --- CHANGELOG.md | 7 +++++++ README.md | 2 +- .../snowplowanalytics/snowplow_tracker/TrackerVersion.kt | 2 +- doc/01-getting-started.md | 2 +- example/ios/Podfile.lock | 4 ++-- example/lib/overview.dart | 2 +- example/pubspec.lock | 2 +- ios/Classes/TrackerVersion.swift | 2 +- ios/snowplow_tracker.podspec | 2 +- pubspec.yaml | 2 +- 10 files changed, 17 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0502b05..b849dc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# 0.2.0 +* Configure custom POST path (#15) +* Upgrade underlying mobile native trackers to version 4 (#17) +* Fix schema link in documentation for ScreenView (#12) +* Remove loading custom JavaScript for session context and reading cookies (#13) +* Upgrade min Flutter, Dart and Android SDK versions and upgrade dependencies (#19) - thanks @koga for the Android work! + # 0.1.0 * Add route observer for auto tracking screen or page view events on navigation (#9) diff --git a/README.md b/README.md index 107af21..57e12b9 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ This will add a line with the dependency like this to your `pubspec.yaml`: ```yml dependencies: - snowplow_tracker: ^0.1.0 + snowplow_tracker: ^0.2.0 ``` Import the package into your Dart code: diff --git a/android/src/main/kotlin/com/snowplowanalytics/snowplow_tracker/TrackerVersion.kt b/android/src/main/kotlin/com/snowplowanalytics/snowplow_tracker/TrackerVersion.kt index e477e91..48e21f3 100644 --- a/android/src/main/kotlin/com/snowplowanalytics/snowplow_tracker/TrackerVersion.kt +++ b/android/src/main/kotlin/com/snowplowanalytics/snowplow_tracker/TrackerVersion.kt @@ -12,5 +12,5 @@ package com.snowplowanalytics.snowplow_tracker object TrackerVersion { - val TRACKER_VERSION = "flutter-0.1.0" + val TRACKER_VERSION = "flutter-0.2.0" } diff --git a/doc/01-getting-started.md b/doc/01-getting-started.md index f68ce0e..fb2f8b8 100644 --- a/doc/01-getting-started.md +++ b/doc/01-getting-started.md @@ -16,7 +16,7 @@ This will add a line with the dependency like to your pubspec.yaml: ```yml dependencies: - snowplow_tracker: ^0.1.0 + snowplow_tracker: ^0.2.0 ``` Import the package into your Dart code: diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 4ae28db..81c8367 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -5,7 +5,7 @@ PODS: - FMDB/standard (2.7.5) - integration_test (0.0.1): - Flutter - - snowplow_tracker (0.1.0): + - snowplow_tracker (0.2.0): - Flutter - SnowplowTracker (~> 4.0) - SnowplowTracker (4.0.0): @@ -33,7 +33,7 @@ SPEC CHECKSUMS: Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a integration_test: a1e7d09bd98eca2fc37aefd79d4f41ad37bdbbe5 - snowplow_tracker: 0a5e9a965a7ef88141c2dba156c43148ee1acdb0 + snowplow_tracker: 486ec0bd2a083c545a4f3e426ab2123a927ee65b SnowplowTracker: 2ddc6db70af5415a87ac279f044d27d140b3a2b8 PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 diff --git a/example/lib/overview.dart b/example/lib/overview.dart index c0af7c1..03030c2 100644 --- a/example/lib/overview.dart +++ b/example/lib/overview.dart @@ -27,7 +27,7 @@ This will add a line with the dependency like this to your `pubspec.yaml`: ```yml dependencies: - snowplow_tracker: ^0.1.0 + snowplow_tracker: ^0.2.0 ``` Import the package into your Dart code: diff --git a/example/pubspec.lock b/example/pubspec.lock index 4fbe26b..7a97e62 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -217,7 +217,7 @@ packages: path: ".." relative: true source: path - version: "0.1.0" + version: "0.2.0" source_span: dependency: transitive description: diff --git a/ios/Classes/TrackerVersion.swift b/ios/Classes/TrackerVersion.swift index b8b288b..7abc757 100644 --- a/ios/Classes/TrackerVersion.swift +++ b/ios/Classes/TrackerVersion.swift @@ -12,5 +12,5 @@ import Foundation class TrackerVersion { - static let TRACKER_VERSION = "flutter-0.1.0" + static let TRACKER_VERSION = "flutter-0.2.0" } diff --git a/ios/snowplow_tracker.podspec b/ios/snowplow_tracker.podspec index f1c9595..bda9a64 100644 --- a/ios/snowplow_tracker.podspec +++ b/ios/snowplow_tracker.podspec @@ -4,7 +4,7 @@ # Pod::Spec.new do |s| s.name = 'snowplow_tracker' - s.version = '0.1.0' + s.version = '0.2.0' s.summary = 'A package for tracking Snowplow events in Flutter apps.' s.description = <<-DESC A package for tracking Snowplow events in Flutter apps. diff --git a/pubspec.yaml b/pubspec.yaml index 9dfaaca..8494608 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: snowplow_tracker description: A package for tracking Snowplow events in Flutter apps -version: 0.1.0 +version: 0.2.0 homepage: https://github.com/snowplow-incubator/snowplow-flutter-tracker repository: https://github.com/snowplow-incubator/snowplow-flutter-tracker