Two tracker namespaces are instantiated on this page.
+
Warning: if your browser's Do Not Track feature is enabled and respectDoNotTrack is enabled, all tracking will be prevented.
+
If you are viewing the page using a file URL, you must edit the script URL in the Snowplow tag to include an http scheme. Otherwise a file scheme will be inferred and the page will attempt to load sp.js from the local filesystem..
+
Press the buttons below to trigger individual tracking events:
+
+
+
+
+
+ Both trackers will track this link
+
+ Only the cf tracker will track this link
+
+ Neither tracker will track this link
+
+
+
+
diff --git a/snowplow-javascript-tracker/examples/web/async-small.html b/snowplow-javascript-tracker/examples/web/async-small.html
new file mode 100644
index 0000000000..5770d43162
--- /dev/null
+++ b/snowplow-javascript-tracker/examples/web/async-small.html
@@ -0,0 +1,168 @@
+
+
+
+
+ Small asynchronous website/webapp examples for snowplow.js
+
+
+
+
+
+
+
+
+
+
+
+
Small_asynchronous_examples_for_snowplow.js
+
+
Warning: if your browser's Do Not Track feature is enabled and respectDoNotTrack is enabled, all tracking will be prevented.
+
If you are viewing the page using a file URL, you must edit the script URL in the Snowplow tag to include an http scheme. Otherwise a file scheme will be inferred and the page will attempt to load sp.js from the local filesystem..
+
+
Press the buttons below to trigger individual tracking events:
+
+
+
+
+
Warning: if your browser's Do Not Track feature is enabled and respectDoNotTrack is enabled, all tracking will be prevented.
+
If you are viewing the page using a file URL, you must edit the script URL in the Snowplow tag to include an http scheme. Otherwise a file scheme will be inferred and the page will attempt to load sp.js from the local filesystem..
+
Press the buttons below to trigger individual tracking events:
+
+
+
+
+
+
+
diff --git a/snowplow-javascript-tracker/local_test.sh b/snowplow-javascript-tracker/local_test.sh
new file mode 100755
index 0000000000..12839b5379
--- /dev/null
+++ b/snowplow-javascript-tracker/local_test.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+cd core
+grunt
+cd ..
+grunt local
+if [[ "$(uname)" == "Darwin" ]]; then
+ (sleep 1 && open http:127.0.0.1:8000/integration.html)&
+elif [[ "$(expr substr $(uname -s) 1 5)" == "Linux" ]]; then
+ (sleep 1 && xdg-open http:127.0.0.1:8000/integration.html)&
+elif [[ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]]; then
+ :
+elif [[ "$(expr substr $(uname -s) 1 10)" == "MINGW64_NT" ]]; then
+ :
+fi
+python3 ./tests/local/http-server.py
diff --git a/snowplow-javascript-tracker/npm-shrinkwrap.json b/snowplow-javascript-tracker/npm-shrinkwrap.json
new file mode 100644
index 0000000000..3b45c13f79
--- /dev/null
+++ b/snowplow-javascript-tracker/npm-shrinkwrap.json
@@ -0,0 +1,6046 @@
+{
+ "name": "snowplow-tracker",
+ "version": "2.9.3",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
+ "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.0.0"
+ }
+ },
+ "@babel/core": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.1.6.tgz",
+ "integrity": "sha512-Hz6PJT6e44iUNpAn8AoyAs6B3bl60g7MJQaI0rZEar6ECzh6+srYO1xlIdssio34mPaUtAb1y+XlkkSJzok3yw==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "@babel/generator": "^7.1.6",
+ "@babel/helpers": "^7.1.5",
+ "@babel/parser": "^7.1.6",
+ "@babel/template": "^7.1.2",
+ "@babel/traverse": "^7.1.6",
+ "@babel/types": "^7.1.6",
+ "convert-source-map": "^1.1.0",
+ "debug": "^4.1.0",
+ "json5": "^2.1.0",
+ "lodash": "^4.17.10",
+ "resolve": "^1.3.2",
+ "semver": "^5.4.1",
+ "source-map": "^0.5.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
+ "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
+ "dev": true
+ }
+ }
+ },
+ "@babel/generator": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.1.6.tgz",
+ "integrity": "sha512-brwPBtVvdYdGxtenbQgfCdDPmtkmUBZPjUoK5SXJEBuHaA5BCubh9ly65fzXz7R6o5rA76Rs22ES8Z+HCc0YIQ==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.1.6",
+ "jsesc": "^2.5.1",
+ "lodash": "^4.17.10",
+ "source-map": "^0.5.0",
+ "trim-right": "^1.0.1"
+ }
+ },
+ "@babel/helper-annotate-as-pure": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz",
+ "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helper-builder-binary-assignment-operator-visitor": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz",
+ "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-explode-assignable-expression": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helper-call-delegate": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.1.0.tgz",
+ "integrity": "sha512-YEtYZrw3GUK6emQHKthltKNZwszBcHK58Ygcis+gVUrF4/FmTVr5CCqQNSfmvg2y+YDEANyYoaLz/SHsnusCwQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-hoist-variables": "^7.0.0",
+ "@babel/traverse": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helper-define-map": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz",
+ "integrity": "sha512-yPPcW8dc3gZLN+U1mhYV91QU3n5uTbx7DUdf8NnPbjS0RMwBuHi9Xt2MUgppmNz7CJxTBWsGczTiEp1CSOTPRg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-function-name": "^7.1.0",
+ "@babel/types": "^7.0.0",
+ "lodash": "^4.17.10"
+ }
+ },
+ "@babel/helper-explode-assignable-expression": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz",
+ "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==",
+ "dev": true,
+ "requires": {
+ "@babel/traverse": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helper-function-name": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz",
+ "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-get-function-arity": "^7.0.0",
+ "@babel/template": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helper-get-function-arity": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz",
+ "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helper-hoist-variables": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0.tgz",
+ "integrity": "sha512-Ggv5sldXUeSKsuzLkddtyhyHe2YantsxWKNi7A+7LeD12ExRDWTRk29JCXpaHPAbMaIPZSil7n+lq78WY2VY7w==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helper-member-expression-to-functions": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz",
+ "integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helper-module-imports": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz",
+ "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helper-module-transforms": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.1.0.tgz",
+ "integrity": "sha512-0JZRd2yhawo79Rcm4w0LwSMILFmFXjugG3yqf+P/UsKsRS1mJCmMwwlHDlMg7Avr9LrvSpp4ZSULO9r8jpCzcw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-imports": "^7.0.0",
+ "@babel/helper-simple-access": "^7.1.0",
+ "@babel/helper-split-export-declaration": "^7.0.0",
+ "@babel/template": "^7.1.0",
+ "@babel/types": "^7.0.0",
+ "lodash": "^4.17.10"
+ }
+ },
+ "@babel/helper-optimise-call-expression": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz",
+ "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helper-plugin-utils": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz",
+ "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==",
+ "dev": true
+ },
+ "@babel/helper-regex": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.0.0.tgz",
+ "integrity": "sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.10"
+ }
+ },
+ "@babel/helper-remap-async-to-generator": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz",
+ "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.0.0",
+ "@babel/helper-wrap-function": "^7.1.0",
+ "@babel/template": "^7.1.0",
+ "@babel/traverse": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helper-replace-supers": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.1.0.tgz",
+ "integrity": "sha512-BvcDWYZRWVuDeXTYZWxekQNO5D4kO55aArwZOTFXw6rlLQA8ZaDicJR1sO47h+HrnCiDFiww0fSPV0d713KBGQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-member-expression-to-functions": "^7.0.0",
+ "@babel/helper-optimise-call-expression": "^7.0.0",
+ "@babel/traverse": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helper-simple-access": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz",
+ "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==",
+ "dev": true,
+ "requires": {
+ "@babel/template": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helper-split-export-declaration": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz",
+ "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helper-wrap-function": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.1.0.tgz",
+ "integrity": "sha512-R6HU3dete+rwsdAfrOzTlE9Mcpk4RjU3aX3gi9grtmugQY0u79X7eogUvfXA5sI81Mfq1cn6AgxihfN33STjJA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-function-name": "^7.1.0",
+ "@babel/template": "^7.1.0",
+ "@babel/traverse": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "@babel/helpers": {
+ "version": "7.1.5",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.1.5.tgz",
+ "integrity": "sha512-2jkcdL02ywNBry1YNFAH/fViq4fXG0vdckHqeJk+75fpQ2OH+Az6076tX/M0835zA45E0Cqa6pV5Kiv9YOqjEg==",
+ "dev": true,
+ "requires": {
+ "@babel/template": "^7.1.2",
+ "@babel/traverse": "^7.1.5",
+ "@babel/types": "^7.1.5"
+ }
+ },
+ "@babel/highlight": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
+ "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.0.0",
+ "esutils": "^2.0.2",
+ "js-tokens": "^4.0.0"
+ }
+ },
+ "@babel/parser": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.1.6.tgz",
+ "integrity": "sha512-dWP6LJm9nKT6ALaa+bnL247GHHMWir3vSlZ2+IHgHgktZQx0L3Uvq2uAWcuzIe+fujRsYWBW2q622C5UvGK9iQ==",
+ "dev": true
+ },
+ "@babel/plugin-proposal-async-generator-functions": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.1.0.tgz",
+ "integrity": "sha512-Fq803F3Jcxo20MXUSDdmZZXrPe6BWyGcWBPPNB/M7WaUYESKDeKMOGIxEzQOjGSmW/NWb6UaPZrtTB2ekhB/ew==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-remap-async-to-generator": "^7.1.0",
+ "@babel/plugin-syntax-async-generators": "^7.0.0"
+ }
+ },
+ "@babel/plugin-proposal-json-strings": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.0.0.tgz",
+ "integrity": "sha512-kfVdUkIAGJIVmHmtS/40i/fg/AGnw/rsZBCaapY5yjeO5RA9m165Xbw9KMOu2nqXP5dTFjEjHdfNdoVcHv133Q==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-syntax-json-strings": "^7.0.0"
+ }
+ },
+ "@babel/plugin-proposal-object-rest-spread": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0.tgz",
+ "integrity": "sha512-14fhfoPcNu7itSen7Py1iGN0gEm87hX/B+8nZPqkdmANyyYWYMY2pjA3r8WXbWVKMzfnSNS0xY8GVS0IjXi/iw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-syntax-object-rest-spread": "^7.0.0"
+ }
+ },
+ "@babel/plugin-proposal-optional-catch-binding": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.0.0.tgz",
+ "integrity": "sha512-JPqAvLG1s13B/AuoBjdBYvn38RqW6n1TzrQO839/sIpqLpbnXKacsAgpZHzLD83Sm8SDXMkkrAvEnJ25+0yIpw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-syntax-optional-catch-binding": "^7.0.0"
+ }
+ },
+ "@babel/plugin-proposal-unicode-property-regex": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.0.0.tgz",
+ "integrity": "sha512-tM3icA6GhC3ch2SkmSxv7J/hCWKISzwycub6eGsDrFDgukD4dZ/I+x81XgW0YslS6mzNuQ1Cbzh5osjIMgepPQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-regex": "^7.0.0",
+ "regexpu-core": "^4.2.0"
+ }
+ },
+ "@babel/plugin-syntax-async-generators": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.0.0.tgz",
+ "integrity": "sha512-im7ged00ddGKAjcZgewXmp1vxSZQQywuQXe2B1A7kajjZmDeY/ekMPmWr9zJgveSaQH0k7BcGrojQhcK06l0zA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-syntax-json-strings": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.0.0.tgz",
+ "integrity": "sha512-UlSfNydC+XLj4bw7ijpldc1uZ/HB84vw+U6BTuqMdIEmz/LDe63w/GHtpQMdXWdqQZFeAI9PjnHe/vDhwirhKA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-syntax-object-rest-spread": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0.tgz",
+ "integrity": "sha512-5A0n4p6bIiVe5OvQPxBnesezsgFJdHhSs3uFSvaPdMqtsovajLZ+G2vZyvNe10EzJBWWo3AcHGKhAFUxqwp2dw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-syntax-optional-catch-binding": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.0.0.tgz",
+ "integrity": "sha512-Wc+HVvwjcq5qBg1w5RG9o9RVzmCaAg/Vp0erHCKpAYV8La6I94o4GQAmFYNmkzoMO6gzoOSulpKeSSz6mPEoZw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-arrow-functions": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0.tgz",
+ "integrity": "sha512-2EZDBl1WIO/q4DIkIp4s86sdp4ZifL51MoIviLY/gG/mLSuOIEg7J8o6mhbxOTvUJkaN50n+8u41FVsr5KLy/w==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-async-to-generator": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.1.0.tgz",
+ "integrity": "sha512-rNmcmoQ78IrvNCIt/R9U+cixUHeYAzgusTFgIAv+wQb9HJU4szhpDD6e5GCACmj/JP5KxuCwM96bX3L9v4ZN/g==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-imports": "^7.0.0",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-remap-async-to-generator": "^7.1.0"
+ }
+ },
+ "@babel/plugin-transform-block-scoped-functions": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.0.0.tgz",
+ "integrity": "sha512-AOBiyUp7vYTqz2Jibe1UaAWL0Hl9JUXEgjFvvvcSc9MVDItv46ViXFw2F7SVt1B5k+KWjl44eeXOAk3UDEaJjQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-block-scoping": {
+ "version": "7.1.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.1.5.tgz",
+ "integrity": "sha512-jlYcDrz+5ayWC7mxgpn1Wj8zj0mmjCT2w0mPIMSwO926eXBRxpEgoN/uQVRBfjtr8ayjcmS+xk2G1jaP8JjMJQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "lodash": "^4.17.10"
+ }
+ },
+ "@babel/plugin-transform-classes": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.1.0.tgz",
+ "integrity": "sha512-rNaqoD+4OCBZjM7VaskladgqnZ1LO6o2UxuWSDzljzW21pN1KXkB7BstAVweZdxQkHAujps5QMNOTWesBciKFg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.0.0",
+ "@babel/helper-define-map": "^7.1.0",
+ "@babel/helper-function-name": "^7.1.0",
+ "@babel/helper-optimise-call-expression": "^7.0.0",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-replace-supers": "^7.1.0",
+ "@babel/helper-split-export-declaration": "^7.0.0",
+ "globals": "^11.1.0"
+ }
+ },
+ "@babel/plugin-transform-computed-properties": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.0.0.tgz",
+ "integrity": "sha512-ubouZdChNAv4AAWAgU7QKbB93NU5sHwInEWfp+/OzJKA02E6Woh9RVoX4sZrbRwtybky/d7baTUqwFx+HgbvMA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-destructuring": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.1.3.tgz",
+ "integrity": "sha512-Mb9M4DGIOspH1ExHOUnn2UUXFOyVTiX84fXCd+6B5iWrQg/QMeeRmSwpZ9lnjYLSXtZwiw80ytVMr3zue0ucYw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-dotall-regex": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.0.0.tgz",
+ "integrity": "sha512-00THs8eJxOJUFVx1w8i1MBF4XH4PsAjKjQ1eqN/uCH3YKwP21GCKfrn6YZFZswbOk9+0cw1zGQPHVc1KBlSxig==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-regex": "^7.0.0",
+ "regexpu-core": "^4.1.3"
+ }
+ },
+ "@babel/plugin-transform-duplicate-keys": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.0.0.tgz",
+ "integrity": "sha512-w2vfPkMqRkdxx+C71ATLJG30PpwtTpW7DDdLqYt2acXU7YjztzeWW2Jk1T6hKqCLYCcEA5UQM/+xTAm+QCSnuQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-exponentiation-operator": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.1.0.tgz",
+ "integrity": "sha512-uZt9kD1Pp/JubkukOGQml9tqAeI8NkE98oZnHZ2qHRElmeKCodbTZgOEUtujSCSLhHSBWbzNiFSDIMC4/RBTLQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-for-of": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.0.0.tgz",
+ "integrity": "sha512-TlxKecN20X2tt2UEr2LNE6aqA0oPeMT1Y3cgz8k4Dn1j5ObT8M3nl9aA37LLklx0PBZKETC9ZAf9n/6SujTuXA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-function-name": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.1.0.tgz",
+ "integrity": "sha512-VxOa1TMlFMtqPW2IDYZQaHsFrq/dDoIjgN098NowhexhZcz3UGlvPgZXuE1jEvNygyWyxRacqDpCZt+par1FNg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-function-name": "^7.1.0",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-literals": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.0.0.tgz",
+ "integrity": "sha512-1NTDBWkeNXgpUcyoVFxbr9hS57EpZYXpje92zv0SUzjdu3enaRwF/l3cmyRnXLtIdyJASyiS6PtybK+CgKf7jA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-modules-amd": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.1.0.tgz",
+ "integrity": "sha512-wt8P+xQ85rrnGNr2x1iV3DW32W8zrB6ctuBkYBbf5/ZzJY99Ob4MFgsZDFgczNU76iy9PWsy4EuxOliDjdKw6A==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-transforms": "^7.1.0",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-modules-commonjs": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.1.0.tgz",
+ "integrity": "sha512-wtNwtMjn1XGwM0AXPspQgvmE6msSJP15CX2RVfpTSTNPLhKhaOjaIfBaVfj4iUZ/VrFSodcFedwtPg/NxwQlPA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-transforms": "^7.1.0",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-simple-access": "^7.1.0"
+ }
+ },
+ "@babel/plugin-transform-modules-systemjs": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.1.3.tgz",
+ "integrity": "sha512-PvTxgjxQAq4pvVUZF3mD5gEtVDuId8NtWkJsZLEJZMZAW3TvgQl1pmydLLN1bM8huHFVVU43lf0uvjQj9FRkKw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-hoist-variables": "^7.0.0",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-modules-umd": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.1.0.tgz",
+ "integrity": "sha512-enrRtn5TfRhMmbRwm7F8qOj0qEYByqUvTttPEGimcBH4CJHphjyK1Vg7sdU7JjeEmgSpM890IT/efS2nMHwYig==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-transforms": "^7.1.0",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-new-target": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz",
+ "integrity": "sha512-yin069FYjah+LbqfGeTfzIBODex/e++Yfa0rH0fpfam9uTbuEeEOx5GLGr210ggOV77mVRNoeqSYqeuaqSzVSw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-object-super": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.1.0.tgz",
+ "integrity": "sha512-/O02Je1CRTSk2SSJaq0xjwQ8hG4zhZGNjE8psTsSNPXyLRCODv7/PBozqT5AmQMzp7MI3ndvMhGdqp9c96tTEw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-replace-supers": "^7.1.0"
+ }
+ },
+ "@babel/plugin-transform-parameters": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.1.0.tgz",
+ "integrity": "sha512-vHV7oxkEJ8IHxTfRr3hNGzV446GAb+0hgbA7o/0Jd76s+YzccdWuTU296FOCOl/xweU4t/Ya4g41yWz80RFCRw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-call-delegate": "^7.1.0",
+ "@babel/helper-get-function-arity": "^7.0.0",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-regenerator": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0.tgz",
+ "integrity": "sha512-sj2qzsEx8KDVv1QuJc/dEfilkg3RRPvPYx/VnKLtItVQRWt1Wqf5eVCOLZm29CiGFfYYsA3VPjfizTCV0S0Dlw==",
+ "dev": true,
+ "requires": {
+ "regenerator-transform": "^0.13.3"
+ }
+ },
+ "@babel/plugin-transform-shorthand-properties": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0.tgz",
+ "integrity": "sha512-g/99LI4vm5iOf5r1Gdxq5Xmu91zvjhEG5+yZDJW268AZELAu4J1EiFLnkSG3yuUsZyOipVOVUKoGPYwfsTymhw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-spread": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.0.0.tgz",
+ "integrity": "sha512-L702YFy2EvirrR4shTj0g2xQp7aNwZoWNCkNu2mcoU0uyzMl0XRwDSwzB/xp6DSUFiBmEXuyAyEN16LsgVqGGQ==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-sticky-regex": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.0.0.tgz",
+ "integrity": "sha512-LFUToxiyS/WD+XEWpkx/XJBrUXKewSZpzX68s+yEOtIbdnsRjpryDw9U06gYc6klYEij/+KQVRnD3nz3AoKmjw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-regex": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-template-literals": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.0.0.tgz",
+ "integrity": "sha512-vA6rkTCabRZu7Nbl9DfLZE1imj4tzdWcg5vtdQGvj+OH9itNNB6hxuRMHuIY8SGnEt1T9g5foqs9LnrHzsqEFg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.0.0",
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-typeof-symbol": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.0.0.tgz",
+ "integrity": "sha512-1r1X5DO78WnaAIvs5uC48t41LLckxsYklJrZjNKcevyz83sF2l4RHbw29qrCPr/6ksFsdfRpT/ZgxNWHXRnffg==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0"
+ }
+ },
+ "@babel/plugin-transform-unicode-regex": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.0.0.tgz",
+ "integrity": "sha512-uJBrJhBOEa3D033P95nPHu3nbFwFE9ZgXsfEitzoIXIwqAZWk7uXcg06yFKXz9FSxBH5ucgU/cYdX0IV8ldHKw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/helper-regex": "^7.0.0",
+ "regexpu-core": "^4.1.3"
+ }
+ },
+ "@babel/preset-env": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.1.6.tgz",
+ "integrity": "sha512-YIBfpJNQMBkb6MCkjz/A9J76SNCSuGVamOVBgoUkLzpJD/z8ghHi9I42LQ4pulVX68N/MmImz6ZTixt7Azgexw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-module-imports": "^7.0.0",
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/plugin-proposal-async-generator-functions": "^7.1.0",
+ "@babel/plugin-proposal-json-strings": "^7.0.0",
+ "@babel/plugin-proposal-object-rest-spread": "^7.0.0",
+ "@babel/plugin-proposal-optional-catch-binding": "^7.0.0",
+ "@babel/plugin-proposal-unicode-property-regex": "^7.0.0",
+ "@babel/plugin-syntax-async-generators": "^7.0.0",
+ "@babel/plugin-syntax-object-rest-spread": "^7.0.0",
+ "@babel/plugin-syntax-optional-catch-binding": "^7.0.0",
+ "@babel/plugin-transform-arrow-functions": "^7.0.0",
+ "@babel/plugin-transform-async-to-generator": "^7.1.0",
+ "@babel/plugin-transform-block-scoped-functions": "^7.0.0",
+ "@babel/plugin-transform-block-scoping": "^7.1.5",
+ "@babel/plugin-transform-classes": "^7.1.0",
+ "@babel/plugin-transform-computed-properties": "^7.0.0",
+ "@babel/plugin-transform-destructuring": "^7.0.0",
+ "@babel/plugin-transform-dotall-regex": "^7.0.0",
+ "@babel/plugin-transform-duplicate-keys": "^7.0.0",
+ "@babel/plugin-transform-exponentiation-operator": "^7.1.0",
+ "@babel/plugin-transform-for-of": "^7.0.0",
+ "@babel/plugin-transform-function-name": "^7.1.0",
+ "@babel/plugin-transform-literals": "^7.0.0",
+ "@babel/plugin-transform-modules-amd": "^7.1.0",
+ "@babel/plugin-transform-modules-commonjs": "^7.1.0",
+ "@babel/plugin-transform-modules-systemjs": "^7.0.0",
+ "@babel/plugin-transform-modules-umd": "^7.1.0",
+ "@babel/plugin-transform-new-target": "^7.0.0",
+ "@babel/plugin-transform-object-super": "^7.1.0",
+ "@babel/plugin-transform-parameters": "^7.1.0",
+ "@babel/plugin-transform-regenerator": "^7.0.0",
+ "@babel/plugin-transform-shorthand-properties": "^7.0.0",
+ "@babel/plugin-transform-spread": "^7.0.0",
+ "@babel/plugin-transform-sticky-regex": "^7.0.0",
+ "@babel/plugin-transform-template-literals": "^7.0.0",
+ "@babel/plugin-transform-typeof-symbol": "^7.0.0",
+ "@babel/plugin-transform-unicode-regex": "^7.0.0",
+ "browserslist": "^4.1.0",
+ "invariant": "^2.2.2",
+ "js-levenshtein": "^1.1.3",
+ "semver": "^5.3.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
+ "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
+ "dev": true
+ }
+ }
+ },
+ "@babel/template": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.1.2.tgz",
+ "integrity": "sha512-SY1MmplssORfFiLDcOETrW7fCLl+PavlwMh92rrGcikQaRq4iWPVH0MpwPpY3etVMx6RnDjXtr6VZYr/IbP/Ag==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "@babel/parser": "^7.1.2",
+ "@babel/types": "^7.1.2"
+ }
+ },
+ "@babel/traverse": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.1.6.tgz",
+ "integrity": "sha512-CXedit6GpISz3sC2k2FsGCUpOhUqKdyL0lqNrImQojagnUMXf8hex4AxYFRuMkNGcvJX5QAFGzB5WJQmSv8SiQ==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "@babel/generator": "^7.1.6",
+ "@babel/helper-function-name": "^7.1.0",
+ "@babel/helper-split-export-declaration": "^7.0.0",
+ "@babel/parser": "^7.1.6",
+ "@babel/types": "^7.1.6",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0",
+ "lodash": "^4.17.10"
+ }
+ },
+ "@babel/types": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.1.6.tgz",
+ "integrity": "sha512-DMiUzlY9DSjVsOylJssxLHSgj6tWM9PRFJOGW/RaOglVOK9nzTxoOMfTfRQXGUCUQ/HmlG2efwC+XqUEJ5ay4w==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2",
+ "lodash": "^4.17.10",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "JSON": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/JSON/-/JSON-1.0.0.tgz",
+ "integrity": "sha1-hoFTHCj4Q4oHVYn/BySCRuqWDYw=",
+ "dev": true
+ },
+ "JSONStream": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
+ "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
+ "dev": true,
+ "requires": {
+ "jsonparse": "^1.2.0",
+ "through": ">=2.2.7 <3"
+ }
+ },
+ "abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+ "dev": true
+ },
+ "acorn": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.4.tgz",
+ "integrity": "sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg==",
+ "dev": true
+ },
+ "acorn-dynamic-import": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz",
+ "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==",
+ "dev": true
+ },
+ "acorn-node": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.6.2.tgz",
+ "integrity": "sha512-rIhNEZuNI8ibQcL7ANm/mGyPukIaZsRNX9psFNQURyJW0nu6k8wjSDld20z6v2mDBWqX13pIEnk9gGZJHIlEXg==",
+ "dev": true,
+ "requires": {
+ "acorn": "^6.0.2",
+ "acorn-dynamic-import": "^4.0.0",
+ "acorn-walk": "^6.1.0",
+ "xtend": "^4.0.1"
+ }
+ },
+ "acorn-walk": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz",
+ "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==",
+ "dev": true
+ },
+ "amdefine": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
+ "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
+ "dev": true
+ },
+ "ansi-regex": {
+ "version": "0.2.1",
+ "resolved": "http://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz",
+ "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "anymatch": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
+ "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
+ "dev": true,
+ "requires": {
+ "micromatch": "^2.1.5",
+ "normalize-path": "^2.0.0"
+ }
+ },
+ "argparse": {
+ "version": "0.1.16",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz",
+ "integrity": "sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw=",
+ "dev": true,
+ "requires": {
+ "underscore": "~1.7.0",
+ "underscore.string": "~2.4.0"
+ },
+ "dependencies": {
+ "underscore.string": {
+ "version": "2.4.0",
+ "resolved": "http://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz",
+ "integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs=",
+ "dev": true
+ }
+ }
+ },
+ "arr-diff": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+ "dev": true,
+ "requires": {
+ "arr-flatten": "^1.0.1"
+ }
+ },
+ "arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+ "dev": true
+ },
+ "arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
+ "dev": true
+ },
+ "array-filter": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz",
+ "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=",
+ "dev": true
+ },
+ "array-map": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz",
+ "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=",
+ "dev": true
+ },
+ "array-reduce": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz",
+ "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=",
+ "dev": true
+ },
+ "array-unique": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
+ "dev": true
+ },
+ "asn1.js": {
+ "version": "4.10.1",
+ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz",
+ "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "assert": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz",
+ "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=",
+ "dev": true,
+ "requires": {
+ "util": "0.10.3"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=",
+ "dev": true
+ },
+ "util": {
+ "version": "0.10.3",
+ "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz",
+ "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.1"
+ }
+ }
+ }
+ },
+ "assertion-error": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
+ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
+ "dev": true
+ },
+ "assign-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
+ "dev": true
+ },
+ "async": {
+ "version": "0.1.22",
+ "resolved": "http://registry.npmjs.org/async/-/async-0.1.22.tgz",
+ "integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE=",
+ "dev": true
+ },
+ "async-each": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
+ "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=",
+ "dev": true
+ },
+ "atob": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+ "dev": true
+ },
+ "aws-sdk": {
+ "version": "2.1.50",
+ "resolved": "http://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1.50.tgz",
+ "integrity": "sha1-Zd3CuEDmkCEIftNfKC1jKgUpShs=",
+ "dev": true,
+ "requires": {
+ "sax": "0.5.3",
+ "xml2js": "0.2.8",
+ "xmlbuilder": "0.4.2"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+ "dev": true
+ },
+ "base": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+ "dev": true,
+ "requires": {
+ "cache-base": "^1.0.1",
+ "class-utils": "^0.3.5",
+ "component-emitter": "^1.2.1",
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.1",
+ "mixin-deep": "^1.2.0",
+ "pascalcase": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+ "dev": true
+ }
+ }
+ },
+ "base64-js": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
+ "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==",
+ "dev": true
+ },
+ "binary-extensions": {
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz",
+ "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==",
+ "dev": true
+ },
+ "bl": {
+ "version": "1.2.2",
+ "resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
+ "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
+ "dev": true,
+ "requires": {
+ "readable-stream": "^2.3.5",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "bn.js": {
+ "version": "4.11.8",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+ "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==",
+ "dev": true
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "braces": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+ "dev": true,
+ "requires": {
+ "expand-range": "^1.8.1",
+ "preserve": "^0.2.0",
+ "repeat-element": "^1.1.2"
+ }
+ },
+ "brorand": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
+ "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
+ "dev": true
+ },
+ "browser-cookie-lite": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/browser-cookie-lite/-/browser-cookie-lite-0.3.1.tgz",
+ "integrity": "sha1-Y4hN0sDDnSf/1lmPK21Jjmj7IjM="
+ },
+ "browser-pack": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz",
+ "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==",
+ "dev": true,
+ "requires": {
+ "JSONStream": "^1.0.3",
+ "combine-source-map": "~0.8.0",
+ "defined": "^1.0.0",
+ "safe-buffer": "^5.1.1",
+ "through2": "^2.0.0",
+ "umd": "^3.0.0"
+ }
+ },
+ "browser-resolve": {
+ "version": "1.11.3",
+ "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz",
+ "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==",
+ "dev": true,
+ "requires": {
+ "resolve": "1.1.7"
+ },
+ "dependencies": {
+ "resolve": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
+ "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
+ "dev": true
+ }
+ }
+ },
+ "browserify": {
+ "version": "16.2.3",
+ "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.2.3.tgz",
+ "integrity": "sha512-zQt/Gd1+W+IY+h/xX2NYMW4orQWhqSwyV+xsblycTtpOuB27h1fZhhNQuipJ4t79ohw4P4mMem0jp/ZkISQtjQ==",
+ "dev": true,
+ "requires": {
+ "JSONStream": "^1.0.3",
+ "assert": "^1.4.0",
+ "browser-pack": "^6.0.1",
+ "browser-resolve": "^1.11.0",
+ "browserify-zlib": "~0.2.0",
+ "buffer": "^5.0.2",
+ "cached-path-relative": "^1.0.0",
+ "concat-stream": "^1.6.0",
+ "console-browserify": "^1.1.0",
+ "constants-browserify": "~1.0.0",
+ "crypto-browserify": "^3.0.0",
+ "defined": "^1.0.0",
+ "deps-sort": "^2.0.0",
+ "domain-browser": "^1.2.0",
+ "duplexer2": "~0.1.2",
+ "events": "^2.0.0",
+ "glob": "^7.1.0",
+ "has": "^1.0.0",
+ "htmlescape": "^1.1.0",
+ "https-browserify": "^1.0.0",
+ "inherits": "~2.0.1",
+ "insert-module-globals": "^7.0.0",
+ "labeled-stream-splicer": "^2.0.0",
+ "mkdirp": "^0.5.0",
+ "module-deps": "^6.0.0",
+ "os-browserify": "~0.3.0",
+ "parents": "^1.0.1",
+ "path-browserify": "~0.0.0",
+ "process": "~0.11.0",
+ "punycode": "^1.3.2",
+ "querystring-es3": "~0.2.0",
+ "read-only-stream": "^2.0.0",
+ "readable-stream": "^2.0.2",
+ "resolve": "^1.1.4",
+ "shasum": "^1.0.0",
+ "shell-quote": "^1.6.1",
+ "stream-browserify": "^2.0.0",
+ "stream-http": "^2.0.0",
+ "string_decoder": "^1.1.1",
+ "subarg": "^1.0.0",
+ "syntax-error": "^1.1.1",
+ "through2": "^2.0.0",
+ "timers-browserify": "^1.0.1",
+ "tty-browserify": "0.0.1",
+ "url": "~0.11.0",
+ "util": "~0.10.1",
+ "vm-browserify": "^1.0.0",
+ "xtend": "^4.0.0"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ }
+ }
+ },
+ "browserify-aes": {
+ "version": "1.2.0",
+ "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
+ "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
+ "dev": true,
+ "requires": {
+ "buffer-xor": "^1.0.3",
+ "cipher-base": "^1.0.0",
+ "create-hash": "^1.1.0",
+ "evp_bytestokey": "^1.0.3",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "browserify-cache-api": {
+ "version": "3.0.1",
+ "resolved": "http://registry.npmjs.org/browserify-cache-api/-/browserify-cache-api-3.0.1.tgz",
+ "integrity": "sha1-liR+hT8Gj9bg1FzHPwuyzZd47wI=",
+ "dev": true,
+ "requires": {
+ "async": "^1.5.2",
+ "through2": "^2.0.0",
+ "xtend": "^4.0.0"
+ },
+ "dependencies": {
+ "async": {
+ "version": "1.5.2",
+ "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
+ "dev": true
+ }
+ }
+ },
+ "browserify-cipher": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
+ "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
+ "dev": true,
+ "requires": {
+ "browserify-aes": "^1.0.4",
+ "browserify-des": "^1.0.0",
+ "evp_bytestokey": "^1.0.0"
+ }
+ },
+ "browserify-des": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
+ "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
+ "dev": true,
+ "requires": {
+ "cipher-base": "^1.0.1",
+ "des.js": "^1.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "browserify-incremental": {
+ "version": "3.1.1",
+ "resolved": "http://registry.npmjs.org/browserify-incremental/-/browserify-incremental-3.1.1.tgz",
+ "integrity": "sha1-BxPLdYckemMqnwjPG9FpuHi2Koo=",
+ "dev": true,
+ "requires": {
+ "JSONStream": "^0.10.0",
+ "browserify-cache-api": "^3.0.0",
+ "through2": "^2.0.0",
+ "xtend": "^4.0.0"
+ },
+ "dependencies": {
+ "JSONStream": {
+ "version": "0.10.0",
+ "resolved": "http://registry.npmjs.org/JSONStream/-/JSONStream-0.10.0.tgz",
+ "integrity": "sha1-dDSdDYlSK3HzDwoD/5vSDKbxKsA=",
+ "dev": true,
+ "requires": {
+ "jsonparse": "0.0.5",
+ "through": ">=2.2.7 <3"
+ }
+ },
+ "jsonparse": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-0.0.5.tgz",
+ "integrity": "sha1-MwVCrT8KZUZlt3jz6y2an6UHrGQ=",
+ "dev": true
+ }
+ }
+ },
+ "browserify-rsa": {
+ "version": "4.0.1",
+ "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
+ "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "randombytes": "^2.0.1"
+ }
+ },
+ "browserify-sign": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
+ "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.1",
+ "browserify-rsa": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "create-hmac": "^1.1.2",
+ "elliptic": "^6.0.0",
+ "inherits": "^2.0.1",
+ "parse-asn1": "^5.0.0"
+ }
+ },
+ "browserify-zlib": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
+ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
+ "dev": true,
+ "requires": {
+ "pako": "~1.0.5"
+ }
+ },
+ "browserslist": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.3.4.tgz",
+ "integrity": "sha512-u5iz+ijIMUlmV8blX82VGFrB9ecnUg5qEt55CMZ/YJEhha+d8qpBfOFuutJ6F/VKRXjZoD33b6uvarpPxcl3RA==",
+ "dev": true,
+ "requires": {
+ "caniuse-lite": "^1.0.30000899",
+ "electron-to-chromium": "^1.3.82",
+ "node-releases": "^1.0.1"
+ }
+ },
+ "buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz",
+ "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==",
+ "dev": true,
+ "requires": {
+ "base64-js": "^1.0.2",
+ "ieee754": "^1.1.4"
+ }
+ },
+ "buffer-alloc": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
+ "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
+ "dev": true,
+ "requires": {
+ "buffer-alloc-unsafe": "^1.1.0",
+ "buffer-fill": "^1.0.0"
+ }
+ },
+ "buffer-alloc-unsafe": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
+ "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==",
+ "dev": true
+ },
+ "buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
+ "dev": true
+ },
+ "buffer-fill": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
+ "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=",
+ "dev": true
+ },
+ "buffer-from": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+ "dev": true
+ },
+ "buffer-to-vinyl": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/buffer-to-vinyl/-/buffer-to-vinyl-1.1.0.tgz",
+ "integrity": "sha1-APFfruOreh3aLN5tkSG//dB7ImI=",
+ "dev": true,
+ "requires": {
+ "file-type": "^3.1.0",
+ "readable-stream": "^2.0.2",
+ "uuid": "^2.0.1",
+ "vinyl": "^1.0.0"
+ }
+ },
+ "buffer-xor": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
+ "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
+ "dev": true
+ },
+ "builtin-status-codes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
+ "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
+ "dev": true
+ },
+ "cache-base": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+ "dev": true,
+ "requires": {
+ "collection-visit": "^1.0.0",
+ "component-emitter": "^1.2.1",
+ "get-value": "^2.0.6",
+ "has-value": "^1.0.0",
+ "isobject": "^3.0.1",
+ "set-value": "^2.0.0",
+ "to-object-path": "^0.3.0",
+ "union-value": "^1.0.0",
+ "unset-value": "^1.0.0"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ }
+ }
+ },
+ "cached-path-relative": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.2.tgz",
+ "integrity": "sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg==",
+ "dev": true
+ },
+ "caniuse-lite": {
+ "version": "1.0.30000912",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000912.tgz",
+ "integrity": "sha512-M3zAtV36U+xw5mMROlTXpAHClmPAor6GPKAMD5Yi7glCB5sbMPFtnQ3rGpk4XqPdUrrTIaVYSJZxREZWNy8QJg==",
+ "dev": true
+ },
+ "chai": {
+ "version": "3.5.0",
+ "resolved": "http://registry.npmjs.org/chai/-/chai-3.5.0.tgz",
+ "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=",
+ "dev": true,
+ "requires": {
+ "assertion-error": "^1.0.1",
+ "deep-eql": "^0.1.3",
+ "type-detect": "^1.0.0"
+ }
+ },
+ "chalk": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "charenc": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
+ "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
+ },
+ "charm": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/charm/-/charm-0.2.0.tgz",
+ "integrity": "sha1-us0G2HF3WTYvemYqHpZ691N/2os=",
+ "dev": true
+ },
+ "chokidar": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
+ "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
+ "dev": true,
+ "requires": {
+ "anymatch": "^1.3.0",
+ "async-each": "^1.0.0",
+ "glob-parent": "^2.0.0",
+ "inherits": "^2.0.1",
+ "is-binary-path": "^1.0.0",
+ "is-glob": "^2.0.0",
+ "path-is-absolute": "^1.0.0",
+ "readdirp": "^2.0.0"
+ }
+ },
+ "cipher-base": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+ "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "class-utils": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+ "dev": true,
+ "requires": {
+ "arr-union": "^3.1.0",
+ "define-property": "^0.2.5",
+ "isobject": "^3.0.0",
+ "static-extend": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ }
+ }
+ },
+ "clone": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+ "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
+ "dev": true
+ },
+ "clone-stats": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz",
+ "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=",
+ "dev": true
+ },
+ "coffee-script": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.3.3.tgz",
+ "integrity": "sha1-FQ1rTLUiiUNp7+1qIQHCC8f0pPQ=",
+ "dev": true
+ },
+ "collection-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+ "dev": true,
+ "requires": {
+ "map-visit": "^1.0.0",
+ "object-visit": "^1.0.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "dev": true
+ },
+ "colors": {
+ "version": "0.6.2",
+ "resolved": "http://registry.npmjs.org/colors/-/colors-0.6.2.tgz",
+ "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=",
+ "dev": true
+ },
+ "combine-source-map": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz",
+ "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=",
+ "dev": true,
+ "requires": {
+ "convert-source-map": "~1.1.0",
+ "inline-source-map": "~0.6.0",
+ "lodash.memoize": "~3.0.3",
+ "source-map": "~0.5.3"
+ },
+ "dependencies": {
+ "convert-source-map": {
+ "version": "1.1.3",
+ "resolved": "http://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz",
+ "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=",
+ "dev": true
+ }
+ }
+ },
+ "commander": {
+ "version": "2.17.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
+ "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==",
+ "dev": true
+ },
+ "component-emitter": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
+ "dev": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
+ },
+ "concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "dev": true,
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "console-browserify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
+ "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
+ "dev": true,
+ "requires": {
+ "date-now": "^0.1.4"
+ }
+ },
+ "constants-browserify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
+ "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
+ "dev": true
+ },
+ "convert-source-map": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz",
+ "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.1"
+ }
+ },
+ "copy-descriptor": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+ "dev": true
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "dev": true
+ },
+ "create-ecdh": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz",
+ "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "elliptic": "^6.0.0"
+ }
+ },
+ "create-hash": {
+ "version": "1.2.0",
+ "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
+ "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
+ "dev": true,
+ "requires": {
+ "cipher-base": "^1.0.1",
+ "inherits": "^2.0.1",
+ "md5.js": "^1.3.4",
+ "ripemd160": "^2.0.1",
+ "sha.js": "^2.4.0"
+ }
+ },
+ "create-hmac": {
+ "version": "1.1.7",
+ "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
+ "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
+ "dev": true,
+ "requires": {
+ "cipher-base": "^1.0.3",
+ "create-hash": "^1.1.0",
+ "inherits": "^2.0.1",
+ "ripemd160": "^2.0.0",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
+ "crypt": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
+ "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs="
+ },
+ "crypto-browserify": {
+ "version": "3.12.0",
+ "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
+ "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
+ "dev": true,
+ "requires": {
+ "browserify-cipher": "^1.0.0",
+ "browserify-sign": "^4.0.0",
+ "create-ecdh": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "create-hmac": "^1.1.0",
+ "diffie-hellman": "^5.0.0",
+ "inherits": "^2.0.1",
+ "pbkdf2": "^3.0.3",
+ "public-encrypt": "^4.0.0",
+ "randombytes": "^2.0.0",
+ "randomfill": "^1.0.3"
+ }
+ },
+ "date-now": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
+ "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=",
+ "dev": true
+ },
+ "dateformat": {
+ "version": "1.0.2-1.2.3",
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.2-1.2.3.tgz",
+ "integrity": "sha1-sCIMAt6YYXQztyhRz0fePfLNvuk=",
+ "dev": true
+ },
+ "debug": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz",
+ "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "decode-uri-component": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+ "dev": true
+ },
+ "decompress": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/decompress/-/decompress-3.0.0.tgz",
+ "integrity": "sha1-rx3VDQbjv8QyRh033hGzjA2ZG+0=",
+ "dev": true,
+ "requires": {
+ "buffer-to-vinyl": "^1.0.0",
+ "concat-stream": "^1.4.6",
+ "decompress-tar": "^3.0.0",
+ "decompress-tarbz2": "^3.0.0",
+ "decompress-targz": "^3.0.0",
+ "decompress-unzip": "^3.0.0",
+ "stream-combiner2": "^1.1.1",
+ "vinyl-assign": "^1.0.1",
+ "vinyl-fs": "^2.2.0"
+ }
+ },
+ "decompress-tar": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-3.1.0.tgz",
+ "integrity": "sha1-IXx4n5uURQ76rcXF5TeXj8MzxGY=",
+ "dev": true,
+ "requires": {
+ "is-tar": "^1.0.0",
+ "object-assign": "^2.0.0",
+ "strip-dirs": "^1.0.0",
+ "tar-stream": "^1.1.1",
+ "through2": "^0.6.1",
+ "vinyl": "^0.4.3"
+ },
+ "dependencies": {
+ "clone": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz",
+ "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=",
+ "dev": true
+ },
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+ "dev": true
+ },
+ "object-assign": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
+ "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=",
+ "dev": true
+ },
+ "readable-stream": {
+ "version": "1.0.34",
+ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+ "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "~0.10.x"
+ }
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+ "dev": true
+ },
+ "through2": {
+ "version": "0.6.5",
+ "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
+ "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
+ "dev": true,
+ "requires": {
+ "readable-stream": ">=1.0.33-1 <1.1.0-0",
+ "xtend": ">=4.0.0 <4.1.0-0"
+ }
+ },
+ "vinyl": {
+ "version": "0.4.6",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
+ "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=",
+ "dev": true,
+ "requires": {
+ "clone": "^0.2.0",
+ "clone-stats": "^0.0.1"
+ }
+ }
+ }
+ },
+ "decompress-tarbz2": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-3.1.0.tgz",
+ "integrity": "sha1-iyOTVoE1X58YnYclag+L3ZbZZm0=",
+ "dev": true,
+ "requires": {
+ "is-bzip2": "^1.0.0",
+ "object-assign": "^2.0.0",
+ "seek-bzip": "^1.0.3",
+ "strip-dirs": "^1.0.0",
+ "tar-stream": "^1.1.1",
+ "through2": "^0.6.1",
+ "vinyl": "^0.4.3"
+ },
+ "dependencies": {
+ "clone": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz",
+ "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=",
+ "dev": true
+ },
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+ "dev": true
+ },
+ "object-assign": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
+ "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=",
+ "dev": true
+ },
+ "readable-stream": {
+ "version": "1.0.34",
+ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+ "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "~0.10.x"
+ }
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+ "dev": true
+ },
+ "through2": {
+ "version": "0.6.5",
+ "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
+ "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
+ "dev": true,
+ "requires": {
+ "readable-stream": ">=1.0.33-1 <1.1.0-0",
+ "xtend": ">=4.0.0 <4.1.0-0"
+ }
+ },
+ "vinyl": {
+ "version": "0.4.6",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
+ "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=",
+ "dev": true,
+ "requires": {
+ "clone": "^0.2.0",
+ "clone-stats": "^0.0.1"
+ }
+ }
+ }
+ },
+ "decompress-targz": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-3.1.0.tgz",
+ "integrity": "sha1-ssE9+YFmJomRtxXWRH9kLpaW9aA=",
+ "dev": true,
+ "requires": {
+ "is-gzip": "^1.0.0",
+ "object-assign": "^2.0.0",
+ "strip-dirs": "^1.0.0",
+ "tar-stream": "^1.1.1",
+ "through2": "^0.6.1",
+ "vinyl": "^0.4.3"
+ },
+ "dependencies": {
+ "clone": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz",
+ "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=",
+ "dev": true
+ },
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+ "dev": true
+ },
+ "object-assign": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
+ "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=",
+ "dev": true
+ },
+ "readable-stream": {
+ "version": "1.0.34",
+ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+ "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "~0.10.x"
+ }
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+ "dev": true
+ },
+ "through2": {
+ "version": "0.6.5",
+ "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
+ "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
+ "dev": true,
+ "requires": {
+ "readable-stream": ">=1.0.33-1 <1.1.0-0",
+ "xtend": ">=4.0.0 <4.1.0-0"
+ }
+ },
+ "vinyl": {
+ "version": "0.4.6",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
+ "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=",
+ "dev": true,
+ "requires": {
+ "clone": "^0.2.0",
+ "clone-stats": "^0.0.1"
+ }
+ }
+ }
+ },
+ "decompress-unzip": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-3.4.0.tgz",
+ "integrity": "sha1-YUdbQVIGa74/7hL51inRX+ZHjus=",
+ "dev": true,
+ "requires": {
+ "is-zip": "^1.0.0",
+ "read-all-stream": "^3.0.0",
+ "stat-mode": "^0.2.0",
+ "strip-dirs": "^1.0.0",
+ "through2": "^2.0.0",
+ "vinyl": "^1.0.0",
+ "yauzl": "^2.2.1"
+ }
+ },
+ "deep-eql": {
+ "version": "0.1.3",
+ "resolved": "http://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz",
+ "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=",
+ "dev": true,
+ "requires": {
+ "type-detect": "0.1.1"
+ },
+ "dependencies": {
+ "type-detect": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz",
+ "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=",
+ "dev": true
+ }
+ }
+ },
+ "deep-is": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+ "dev": true
+ },
+ "define-property": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.2",
+ "isobject": "^3.0.1"
+ },
+ "dependencies": {
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+ "dev": true
+ }
+ }
+ },
+ "defined": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
+ "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
+ "dev": true
+ },
+ "deps-sort": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz",
+ "integrity": "sha1-CRckkC6EZYJg65EHSMzNGvbiH7U=",
+ "dev": true,
+ "requires": {
+ "JSONStream": "^1.0.3",
+ "shasum": "^1.0.0",
+ "subarg": "^1.0.0",
+ "through2": "^2.0.0"
+ }
+ },
+ "des.js": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz",
+ "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "detective": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/detective/-/detective-5.1.0.tgz",
+ "integrity": "sha512-TFHMqfOvxlgrfVzTEkNBSh9SvSNX/HfF4OFI2QFGCyPm02EsyILqnUeb5P6q7JZ3SFNTBL5t2sePRgrN4epUWQ==",
+ "dev": true,
+ "requires": {
+ "acorn-node": "^1.3.0",
+ "defined": "^1.0.0",
+ "minimist": "^1.1.1"
+ }
+ },
+ "diff": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-1.1.0.tgz",
+ "integrity": "sha1-eYpJOBqkZBUem08Ob/Kwmooa0j8=",
+ "dev": true
+ },
+ "diffie-hellman": {
+ "version": "5.0.3",
+ "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
+ "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "miller-rabin": "^4.0.0",
+ "randombytes": "^2.0.0"
+ }
+ },
+ "digdug": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/digdug/-/digdug-1.5.2.tgz",
+ "integrity": "sha1-LnB4UV/CuEhTAY6bwtPsuZCKibM=",
+ "dev": true,
+ "requires": {
+ "decompress": "3.0.0",
+ "dojo": "2.0.0-alpha.7"
+ }
+ },
+ "dojo": {
+ "version": "2.0.0-alpha.7",
+ "resolved": "http://registry.npmjs.org/dojo/-/dojo-2.0.0-alpha.7.tgz",
+ "integrity": "sha1-wrJdQ9j3LMycj+iaNJBqLSceXJE=",
+ "dev": true
+ },
+ "domain-browser": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
+ "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
+ "dev": true
+ },
+ "duplexer": {
+ "version": "0.1.1",
+ "resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
+ "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
+ "dev": true
+ },
+ "duplexer2": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
+ "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=",
+ "dev": true,
+ "requires": {
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "duplexify": {
+ "version": "3.6.1",
+ "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz",
+ "integrity": "sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA==",
+ "dev": true,
+ "requires": {
+ "end-of-stream": "^1.0.0",
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.0",
+ "stream-shift": "^1.0.0"
+ }
+ },
+ "electron-to-chromium": {
+ "version": "1.3.85",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.85.tgz",
+ "integrity": "sha512-kWSDVVF9t3mft2OHVZy4K85X2beP6c6mFm3teFS/mLSDJpQwuFIWHrULCX+w6H1E55ZYmFRlT+ATAFRwhrYzsw==",
+ "dev": true
+ },
+ "elliptic": {
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz",
+ "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.4.0",
+ "brorand": "^1.0.1",
+ "hash.js": "^1.0.0",
+ "hmac-drbg": "^1.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0",
+ "minimalistic-crypto-utils": "^1.0.0"
+ }
+ },
+ "end-of-stream": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
+ "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
+ "dev": true,
+ "requires": {
+ "once": "^1.4.0"
+ }
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "dev": true
+ },
+ "escodegen": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz",
+ "integrity": "sha1-MOz89mypjcZ80v0WKr626vqM5vw=",
+ "dev": true,
+ "requires": {
+ "esprima": "^1.2.2",
+ "estraverse": "^1.9.1",
+ "esutils": "^2.0.2",
+ "optionator": "^0.5.0",
+ "source-map": "~0.2.0"
+ },
+ "dependencies": {
+ "esprima": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz",
+ "integrity": "sha1-CZNQL+r2aBODJXVvMPmlH+7sEek=",
+ "dev": true
+ },
+ "source-map": {
+ "version": "0.2.0",
+ "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz",
+ "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "amdefine": ">=0.0.4"
+ }
+ }
+ }
+ },
+ "esprima": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz",
+ "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=",
+ "dev": true
+ },
+ "estraverse": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz",
+ "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=",
+ "dev": true
+ },
+ "esutils": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+ "dev": true
+ },
+ "eventemitter2": {
+ "version": "0.4.14",
+ "resolved": "http://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz",
+ "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=",
+ "dev": true
+ },
+ "events": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz",
+ "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==",
+ "dev": true
+ },
+ "evp_bytestokey": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
+ "dev": true,
+ "requires": {
+ "md5.js": "^1.3.4",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "exit": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
+ "dev": true
+ },
+ "expand-brackets": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+ "dev": true,
+ "requires": {
+ "is-posix-bracket": "^0.1.0"
+ }
+ },
+ "expand-range": {
+ "version": "1.8.2",
+ "resolved": "http://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
+ "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
+ "dev": true,
+ "requires": {
+ "fill-range": "^2.1.0"
+ }
+ },
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true
+ },
+ "extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+ "dev": true,
+ "requires": {
+ "assign-symbols": "^1.0.0",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "extglob": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^1.0.0"
+ }
+ },
+ "fast-levenshtein": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz",
+ "integrity": "sha1-AXjc3uAjuSkFGTrwlZ6KdjnP3Lk=",
+ "dev": true
+ },
+ "fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
+ "dev": true,
+ "requires": {
+ "pend": "~1.2.0"
+ }
+ },
+ "figures": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
+ "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.5",
+ "object-assign": "^4.1.0"
+ }
+ },
+ "file-type": {
+ "version": "3.9.0",
+ "resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
+ "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=",
+ "dev": true
+ },
+ "filename-regex": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
+ "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
+ "dev": true
+ },
+ "fileset": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz",
+ "integrity": "sha1-WI74lzxmI7KnbfRlEFaWuWqsgGc=",
+ "dev": true,
+ "requires": {
+ "glob": "5.x",
+ "minimatch": "2.x"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "5.0.15",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
+ "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
+ "dev": true,
+ "requires": {
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "2 || 3",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "minimatch": {
+ "version": "2.0.10",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz",
+ "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.0.0"
+ }
+ }
+ }
+ },
+ "fill-range": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
+ "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
+ "dev": true,
+ "requires": {
+ "is-number": "^2.1.0",
+ "isobject": "^2.0.0",
+ "randomatic": "^3.0.0",
+ "repeat-element": "^1.1.2",
+ "repeat-string": "^1.5.2"
+ }
+ },
+ "findup-sync": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz",
+ "integrity": "sha1-fz56l7gjksZTvwZYm9hRkOk8NoM=",
+ "dev": true,
+ "requires": {
+ "glob": "~3.2.9",
+ "lodash": "~2.4.1"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "3.2.11",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz",
+ "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=",
+ "dev": true,
+ "requires": {
+ "inherits": "2",
+ "minimatch": "0.3"
+ }
+ },
+ "lodash": {
+ "version": "2.4.2",
+ "resolved": "http://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz",
+ "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=",
+ "dev": true
+ },
+ "minimatch": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz",
+ "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=",
+ "dev": true,
+ "requires": {
+ "lru-cache": "2",
+ "sigmund": "~1.0.0"
+ }
+ }
+ }
+ },
+ "first-chunk-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz",
+ "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=",
+ "dev": true
+ },
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+ "dev": true
+ },
+ "for-own": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
+ "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
+ "dev": true,
+ "requires": {
+ "for-in": "^1.0.1"
+ }
+ },
+ "fragment-cache": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+ "dev": true,
+ "requires": {
+ "map-cache": "^0.2.2"
+ }
+ },
+ "fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+ "dev": true
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "get-assigned-identifiers": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz",
+ "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==",
+ "dev": true
+ },
+ "get-stdin": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
+ "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
+ "dev": true
+ },
+ "get-value": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+ "dev": true
+ },
+ "getobject": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz",
+ "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=",
+ "dev": true
+ },
+ "glob": {
+ "version": "3.1.21",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz",
+ "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "~1.2.0",
+ "inherits": "1",
+ "minimatch": "~0.2.11"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz",
+ "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=",
+ "dev": true
+ }
+ }
+ },
+ "glob-base": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
+ "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
+ "dev": true,
+ "requires": {
+ "glob-parent": "^2.0.0",
+ "is-glob": "^2.0.0"
+ }
+ },
+ "glob-parent": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+ "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+ "dev": true,
+ "requires": {
+ "is-glob": "^2.0.0"
+ }
+ },
+ "glob-stream": {
+ "version": "5.3.5",
+ "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-5.3.5.tgz",
+ "integrity": "sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=",
+ "dev": true,
+ "requires": {
+ "extend": "^3.0.0",
+ "glob": "^5.0.3",
+ "glob-parent": "^3.0.0",
+ "micromatch": "^2.3.7",
+ "ordered-read-streams": "^0.3.0",
+ "through2": "^0.6.0",
+ "to-absolute-glob": "^0.1.1",
+ "unique-stream": "^2.0.2"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "5.0.15",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
+ "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
+ "dev": true,
+ "requires": {
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "2 || 3",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "glob-parent": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+ "dev": true,
+ "requires": {
+ "is-glob": "^3.1.0",
+ "path-dirname": "^1.0.0"
+ }
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ },
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+ "dev": true
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "readable-stream": {
+ "version": "1.0.34",
+ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+ "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "~0.10.x"
+ }
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+ "dev": true
+ },
+ "through2": {
+ "version": "0.6.5",
+ "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
+ "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
+ "dev": true,
+ "requires": {
+ "readable-stream": ">=1.0.33-1 <1.1.0-0",
+ "xtend": ">=4.0.0 <4.1.0-0"
+ }
+ }
+ }
+ },
+ "globals": {
+ "version": "11.9.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.9.0.tgz",
+ "integrity": "sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg==",
+ "dev": true
+ },
+ "graceful-fs": {
+ "version": "1.2.3",
+ "resolved": "http://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz",
+ "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=",
+ "dev": true
+ },
+ "graceful-readlink": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
+ "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
+ "dev": true
+ },
+ "grunt": {
+ "version": "0.4.5",
+ "resolved": "https://registry.npmjs.org/grunt/-/grunt-0.4.5.tgz",
+ "integrity": "sha1-VpN81RlDJK3/bSB2MYMqnWuk5/A=",
+ "dev": true,
+ "requires": {
+ "async": "~0.1.22",
+ "coffee-script": "~1.3.3",
+ "colors": "~0.6.2",
+ "dateformat": "1.0.2-1.2.3",
+ "eventemitter2": "~0.4.13",
+ "exit": "~0.1.1",
+ "findup-sync": "~0.1.2",
+ "getobject": "~0.1.0",
+ "glob": "~3.1.21",
+ "grunt-legacy-log": "~0.1.0",
+ "grunt-legacy-util": "~0.2.0",
+ "hooker": "~0.2.3",
+ "iconv-lite": "~0.2.11",
+ "js-yaml": "~2.0.5",
+ "lodash": "~0.9.2",
+ "minimatch": "~0.2.12",
+ "nopt": "~1.0.10",
+ "rimraf": "~2.2.8",
+ "underscore.string": "~2.2.1",
+ "which": "~1.0.5"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "0.9.2",
+ "resolved": "http://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz",
+ "integrity": "sha1-jzSZxSRdNG1oLlsNO0B2fgnxqSw=",
+ "dev": true
+ }
+ }
+ },
+ "grunt-aws": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/grunt-aws/-/grunt-aws-0.6.2.tgz",
+ "integrity": "sha1-JncoLBLwxdE1TNXr4g7gWpBcN+w=",
+ "dev": true,
+ "requires": {
+ "async": "~0.2.9",
+ "aws-sdk": "~2.1.29",
+ "lodash": "~1.3.1",
+ "mime": "~1.2.11"
+ },
+ "dependencies": {
+ "async": {
+ "version": "0.2.10",
+ "resolved": "http://registry.npmjs.org/async/-/async-0.2.10.tgz",
+ "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=",
+ "dev": true
+ },
+ "lodash": {
+ "version": "1.3.1",
+ "resolved": "http://registry.npmjs.org/lodash/-/lodash-1.3.1.tgz",
+ "integrity": "sha1-pGY7U2hriV/wdOK6UE37dqjit3A=",
+ "dev": true
+ }
+ }
+ },
+ "grunt-babel": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/grunt-babel/-/grunt-babel-8.0.0.tgz",
+ "integrity": "sha512-WuiZFvGzcyzlEoPIcY1snI234ydDWeWWV5bpnB7PZsOLHcDsxWKnrR1rMWEUsbdVPPjvIirwFNsuo4CbJmsdFQ==",
+ "dev": true
+ },
+ "grunt-browserify": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/grunt-browserify/-/grunt-browserify-5.3.0.tgz",
+ "integrity": "sha1-R/2M+LrFj+LeaDr9xX9/OoDKeS0=",
+ "dev": true,
+ "requires": {
+ "async": "^2.5.0",
+ "browserify": "^16.0.0",
+ "browserify-incremental": "^3.1.1",
+ "glob": "^7.1.2",
+ "lodash": "^4.17.4",
+ "resolve": "^1.1.6",
+ "watchify": "^3.6.1"
+ },
+ "dependencies": {
+ "async": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz",
+ "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.10"
+ }
+ },
+ "glob": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ }
+ }
+ },
+ "grunt-contrib-concat": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-0.5.1.tgz",
+ "integrity": "sha1-lTxu/f39LBB6uchQd/LUsk0xzUk=",
+ "dev": true,
+ "requires": {
+ "chalk": "^0.5.1",
+ "source-map": "^0.3.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz",
+ "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "0.5.1",
+ "resolved": "http://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz",
+ "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^1.1.0",
+ "escape-string-regexp": "^1.0.0",
+ "has-ansi": "^0.1.0",
+ "strip-ansi": "^0.3.0",
+ "supports-color": "^0.2.0"
+ }
+ },
+ "source-map": {
+ "version": "0.3.0",
+ "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.3.0.tgz",
+ "integrity": "sha1-hYb7mloAXltQHiHNGLbyG0V60fk=",
+ "dev": true,
+ "requires": {
+ "amdefine": ">=0.0.4"
+ }
+ },
+ "supports-color": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz",
+ "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=",
+ "dev": true
+ }
+ }
+ },
+ "grunt-contrib-uglify": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-4.0.0.tgz",
+ "integrity": "sha512-vy3Vop2KDqdiwcGOGAjyKvjHFrRD/YK4KPQWR3Yt6OdYlgFw1z7HCuk66+IJ9s7oJmp9uRQXuuSHyawKRAgiMw==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.1",
+ "maxmin": "^2.1.0",
+ "uglify-js": "~3.4.8",
+ "uri-path": "^1.0.0"
+ }
+ },
+ "grunt-legacy-log": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz",
+ "integrity": "sha1-7ClCboAwIa9ZAp+H0vnNczWgVTE=",
+ "dev": true,
+ "requires": {
+ "colors": "~0.6.2",
+ "grunt-legacy-log-utils": "~0.1.1",
+ "hooker": "~0.2.3",
+ "lodash": "~2.4.1",
+ "underscore.string": "~2.3.3"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "2.4.2",
+ "resolved": "http://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz",
+ "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=",
+ "dev": true
+ },
+ "underscore.string": {
+ "version": "2.3.3",
+ "resolved": "http://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz",
+ "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=",
+ "dev": true
+ }
+ }
+ },
+ "grunt-legacy-log-utils": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz",
+ "integrity": "sha1-wHBrndkGThFvNvI/5OawSGcsD34=",
+ "dev": true,
+ "requires": {
+ "colors": "~0.6.2",
+ "lodash": "~2.4.1",
+ "underscore.string": "~2.3.3"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "2.4.2",
+ "resolved": "http://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz",
+ "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=",
+ "dev": true
+ },
+ "underscore.string": {
+ "version": "2.3.3",
+ "resolved": "http://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz",
+ "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=",
+ "dev": true
+ }
+ }
+ },
+ "grunt-legacy-util": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz",
+ "integrity": "sha1-kzJIhNv343qf98Am3/RR2UqeVUs=",
+ "dev": true,
+ "requires": {
+ "async": "~0.1.22",
+ "exit": "~0.1.1",
+ "getobject": "~0.1.0",
+ "hooker": "~0.2.3",
+ "lodash": "~0.9.2",
+ "underscore.string": "~2.2.1",
+ "which": "~1.0.5"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "0.9.2",
+ "resolved": "http://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz",
+ "integrity": "sha1-jzSZxSRdNG1oLlsNO0B2fgnxqSw=",
+ "dev": true
+ }
+ }
+ },
+ "gulp-sourcemaps": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz",
+ "integrity": "sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw=",
+ "dev": true,
+ "requires": {
+ "convert-source-map": "^1.1.1",
+ "graceful-fs": "^4.1.2",
+ "strip-bom": "^2.0.0",
+ "through2": "^2.0.0",
+ "vinyl": "^1.0.0"
+ },
+ "dependencies": {
+ "graceful-fs": {
+ "version": "4.1.15",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
+ "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
+ "dev": true
+ }
+ }
+ },
+ "gzip-size": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz",
+ "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=",
+ "dev": true,
+ "requires": {
+ "duplexer": "^0.1.1"
+ }
+ },
+ "handlebars": {
+ "version": "4.0.12",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz",
+ "integrity": "sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA==",
+ "dev": true,
+ "requires": {
+ "async": "^2.5.0",
+ "optimist": "^0.6.1",
+ "source-map": "^0.6.1",
+ "uglify-js": "^3.1.4"
+ },
+ "dependencies": {
+ "async": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz",
+ "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.10"
+ }
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-ansi": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz",
+ "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^0.2.0"
+ }
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true
+ },
+ "has-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+ "dev": true,
+ "requires": {
+ "get-value": "^2.0.6",
+ "has-values": "^1.0.0",
+ "isobject": "^3.0.0"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ }
+ }
+ },
+ "has-values": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+ "dev": true,
+ "requires": {
+ "is-number": "^3.0.0",
+ "kind-of": "^4.0.0"
+ },
+ "dependencies": {
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "kind-of": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "hash-base": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz",
+ "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "hash.js": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.5.tgz",
+ "integrity": "sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "minimalistic-assert": "^1.0.1"
+ }
+ },
+ "hmac-drbg": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
+ "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
+ "dev": true,
+ "requires": {
+ "hash.js": "^1.0.3",
+ "minimalistic-assert": "^1.0.0",
+ "minimalistic-crypto-utils": "^1.0.1"
+ }
+ },
+ "hooker": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz",
+ "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=",
+ "dev": true
+ },
+ "htmlescape": {
+ "version": "1.1.1",
+ "resolved": "http://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz",
+ "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=",
+ "dev": true
+ },
+ "https-browserify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
+ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
+ "dev": true
+ },
+ "iconv-lite": {
+ "version": "0.2.11",
+ "resolved": "http://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz",
+ "integrity": "sha1-HOYKOleGSiktEyH/RgnKS7llrcg=",
+ "dev": true
+ },
+ "ieee754": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz",
+ "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==",
+ "dev": true
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "dev": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "dev": true
+ },
+ "inline-source-map": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz",
+ "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=",
+ "dev": true,
+ "requires": {
+ "source-map": "~0.5.3"
+ }
+ },
+ "insert-module-globals": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.0.tgz",
+ "integrity": "sha512-VE6NlW+WGn2/AeOMd496AHFYmE7eLKkUY6Ty31k4og5vmA3Fjuwe9v6ifH6Xx/Hz27QvdoMoviw1/pqWRB09Sw==",
+ "dev": true,
+ "requires": {
+ "JSONStream": "^1.0.3",
+ "acorn-node": "^1.5.2",
+ "combine-source-map": "^0.8.0",
+ "concat-stream": "^1.6.1",
+ "is-buffer": "^1.1.0",
+ "path-is-absolute": "^1.0.1",
+ "process": "~0.11.0",
+ "through2": "^2.0.0",
+ "undeclared-identifiers": "^1.1.2",
+ "xtend": "^4.0.0"
+ }
+ },
+ "intern": {
+ "version": "3.3.2",
+ "resolved": "http://registry.npmjs.org/intern/-/intern-3.3.2.tgz",
+ "integrity": "sha1-0Rp5bZwFzScVEVbl1Mf7KftSIsA=",
+ "dev": true,
+ "requires": {
+ "chai": "3.5.0",
+ "charm": "0.2.0",
+ "diff": "1.1.0",
+ "digdug": "~1.5.2",
+ "dojo": "2.0.0-alpha.7",
+ "glob": "7.0.3",
+ "istanbul": "0.4.1",
+ "leadfoot": "~1.6.12",
+ "mimetype": "0.0.8",
+ "source-map": "0.1.33"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.3.tgz",
+ "integrity": "sha1-CqI1kxpKlqwT1g/6wvuHe9btT1g=",
+ "dev": true,
+ "requires": {
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "2 || 3",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "source-map": {
+ "version": "0.1.33",
+ "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.1.33.tgz",
+ "integrity": "sha1-xlkpenOvGMBzsKoufMkeMWtcVww=",
+ "dev": true,
+ "requires": {
+ "amdefine": ">=0.0.4"
+ }
+ }
+ }
+ },
+ "invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "dev": true,
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ },
+ "is-absolute": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
+ "integrity": "sha1-hHSREZ/MtftDYhfMc39/qtUPYD8=",
+ "dev": true,
+ "requires": {
+ "is-relative": "^0.1.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ }
+ },
+ "is-binary-path": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+ "dev": true,
+ "requires": {
+ "binary-extensions": "^1.0.0"
+ }
+ },
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true
+ },
+ "is-bzip2": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-bzip2/-/is-bzip2-1.0.0.tgz",
+ "integrity": "sha1-XuWOqlounIDiFAe+3yOuWsCRs/w=",
+ "dev": true
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ }
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true
+ }
+ }
+ },
+ "is-dotfile": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
+ "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
+ "dev": true
+ },
+ "is-equal-shallow": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
+ "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
+ "dev": true,
+ "requires": {
+ "is-primitive": "^2.0.0"
+ }
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+ "dev": true
+ },
+ "is-extglob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^1.0.0"
+ }
+ },
+ "is-gzip": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-gzip/-/is-gzip-1.0.0.tgz",
+ "integrity": "sha1-bKiwe5nHeZgCWQDlVc7Y7YCHmoM=",
+ "dev": true
+ },
+ "is-natural-number": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-2.1.1.tgz",
+ "integrity": "sha1-fUxXKDd+84bD4ZSpkRv1fG3DNec=",
+ "dev": true
+ },
+ "is-number": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
+ "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ }
+ },
+ "is-plain-object": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ }
+ }
+ },
+ "is-posix-bracket": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
+ "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
+ "dev": true
+ },
+ "is-primitive": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
+ "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
+ "dev": true
+ },
+ "is-relative": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz",
+ "integrity": "sha1-kF/uiuhvRbPsYUvDwVyGnfCHboI=",
+ "dev": true
+ },
+ "is-stream": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
+ "dev": true
+ },
+ "is-tar": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-tar/-/is-tar-1.0.0.tgz",
+ "integrity": "sha1-L2suF5LB9bs2UZrKqdZcDSb+hT0=",
+ "dev": true
+ },
+ "is-utf8": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
+ "dev": true
+ },
+ "is-valid-glob": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-0.3.0.tgz",
+ "integrity": "sha1-1LVcafUYhvm2XHDWwmItN+KfSP4=",
+ "dev": true
+ },
+ "is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+ "dev": true
+ },
+ "is-zip": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-zip/-/is-zip-1.0.0.tgz",
+ "integrity": "sha1-R7Co/004p2QxzP2ZqOFaTIa6IyU=",
+ "dev": true
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "dev": true
+ },
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "dev": true,
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ },
+ "istanbul": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.1.tgz",
+ "integrity": "sha1-zXMI6zSdBbnyGBYyukxKO1NNJyQ=",
+ "dev": true,
+ "requires": {
+ "abbrev": "1.0.x",
+ "async": "1.x",
+ "escodegen": "1.7.x",
+ "esprima": "2.7.x",
+ "fileset": "0.2.x",
+ "handlebars": "^4.0.1",
+ "js-yaml": "3.x",
+ "mkdirp": "0.5.x",
+ "nopt": "3.x",
+ "once": "1.x",
+ "resolve": "1.1.x",
+ "supports-color": "^3.1.0",
+ "which": "^1.1.1",
+ "wordwrap": "^1.0.0"
+ },
+ "dependencies": {
+ "abbrev": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz",
+ "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=",
+ "dev": true
+ },
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "async": {
+ "version": "1.5.2",
+ "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
+ "dev": true
+ },
+ "esprima": {
+ "version": "2.7.3",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
+ "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true
+ },
+ "js-yaml": {
+ "version": "3.12.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
+ "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "dependencies": {
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true
+ }
+ }
+ },
+ "nopt": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
+ "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
+ "dev": true,
+ "requires": {
+ "abbrev": "1"
+ }
+ },
+ "resolve": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
+ "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ },
+ "which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ }
+ }
+ },
+ "js-base64": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.1.9.tgz",
+ "integrity": "sha1-8OgK4DmkvWVLXygfyT8EqRSn/M4=",
+ "dev": true
+ },
+ "js-levenshtein": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.4.tgz",
+ "integrity": "sha512-PxfGzSs0ztShKrUYPIn5r0MtyAhYcCwmndozzpz8YObbPnD1jFxzlBGbRnX2mIu6Z13xN6+PTu05TQFnZFlzow==",
+ "dev": true
+ },
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
+ "js-yaml": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz",
+ "integrity": "sha1-olrmUJmZ6X3yeMZxnaEb0Gh3Q6g=",
+ "dev": true,
+ "requires": {
+ "argparse": "~ 0.1.11",
+ "esprima": "~ 1.0.2"
+ }
+ },
+ "jsesc": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+ "dev": true
+ },
+ "json-stable-stringify": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz",
+ "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=",
+ "dev": true,
+ "requires": {
+ "jsonify": "~0.0.0"
+ }
+ },
+ "json5": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz",
+ "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.0"
+ }
+ },
+ "jsonify": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
+ "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
+ "dev": true
+ },
+ "jsonparse": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+ "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
+ "dev": true
+ },
+ "jstimezonedetect": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/jstimezonedetect/-/jstimezonedetect-1.0.5.tgz",
+ "integrity": "sha1-k9A1zSDox9ZOsTdc9ap6EKAkRmo="
+ },
+ "jszip": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-2.5.0.tgz",
+ "integrity": "sha1-dET9hVHd8+XacZj+oMkbyDCMwnQ=",
+ "dev": true,
+ "requires": {
+ "pako": "~0.2.5"
+ },
+ "dependencies": {
+ "pako": {
+ "version": "0.2.9",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
+ "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=",
+ "dev": true
+ }
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ },
+ "labeled-stream-splicer": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.1.tgz",
+ "integrity": "sha512-MC94mHZRvJ3LfykJlTUipBqenZz1pacOZEMhhQ8dMGcDHs0SBE5GbsavUXV7YtP3icBW17W0Zy1I0lfASmo9Pg==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "isarray": "^2.0.4",
+ "stream-splicer": "^2.0.0"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.4.tgz",
+ "integrity": "sha512-GMxXOiUirWg1xTKRipM0Ek07rX+ubx4nNVElTJdNLYmNO/2YrDkgJGw9CljXn+r4EWiDQg/8lsRdHyg2PJuUaA==",
+ "dev": true
+ }
+ }
+ },
+ "lazystream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
+ "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
+ "dev": true,
+ "requires": {
+ "readable-stream": "^2.0.5"
+ }
+ },
+ "leadfoot": {
+ "version": "1.6.12",
+ "resolved": "https://registry.npmjs.org/leadfoot/-/leadfoot-1.6.12.tgz",
+ "integrity": "sha1-QkUL/QmKkmrY5d2WhHB50NGqDqs=",
+ "dev": true,
+ "requires": {
+ "dojo": "2.0.0-alpha.7",
+ "jszip": "2.5.0"
+ }
+ },
+ "levn": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz",
+ "integrity": "sha1-uo0znQykphDjo/FFucr0iAcVUFQ=",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "~1.1.0",
+ "type-check": "~0.3.1"
+ }
+ },
+ "lodash": {
+ "version": "4.17.11",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
+ "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+ "dev": true
+ },
+ "lodash.isequal": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+ "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=",
+ "dev": true
+ },
+ "lodash.memoize": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz",
+ "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=",
+ "dev": true
+ },
+ "loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dev": true,
+ "requires": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ }
+ },
+ "lru-cache": {
+ "version": "2.7.3",
+ "resolved": "http://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz",
+ "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=",
+ "dev": true
+ },
+ "map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
+ "dev": true
+ },
+ "map-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+ "dev": true,
+ "requires": {
+ "object-visit": "^1.0.0"
+ }
+ },
+ "math-random": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz",
+ "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=",
+ "dev": true
+ },
+ "maxmin": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-2.1.0.tgz",
+ "integrity": "sha1-TTsiCQPZXu5+t6x/qGTnLcCaMWY=",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.0.0",
+ "figures": "^1.0.1",
+ "gzip-size": "^3.0.0",
+ "pretty-bytes": "^3.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ }
+ },
+ "has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "md5.js": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+ "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+ "dev": true,
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "merge-stream": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz",
+ "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=",
+ "dev": true,
+ "requires": {
+ "readable-stream": "^2.0.1"
+ }
+ },
+ "micromatch": {
+ "version": "2.3.11",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+ "dev": true,
+ "requires": {
+ "arr-diff": "^2.0.0",
+ "array-unique": "^0.2.1",
+ "braces": "^1.8.2",
+ "expand-brackets": "^0.1.4",
+ "extglob": "^0.3.1",
+ "filename-regex": "^2.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.1",
+ "kind-of": "^3.0.2",
+ "normalize-path": "^2.0.1",
+ "object.omit": "^2.0.0",
+ "parse-glob": "^3.0.4",
+ "regex-cache": "^0.4.2"
+ }
+ },
+ "miller-rabin": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
+ "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.0.0",
+ "brorand": "^1.0.1"
+ }
+ },
+ "mime": {
+ "version": "1.2.11",
+ "resolved": "http://registry.npmjs.org/mime/-/mime-1.2.11.tgz",
+ "integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA=",
+ "dev": true
+ },
+ "mimetype": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/mimetype/-/mimetype-0.0.8.tgz",
+ "integrity": "sha1-+zACJ5S793Jct7Rt+CDofdkf0IY=",
+ "dev": true
+ },
+ "minimalistic-assert": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
+ "dev": true
+ },
+ "minimalistic-crypto-utils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
+ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
+ "dev": true
+ },
+ "minimatch": {
+ "version": "0.2.14",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz",
+ "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=",
+ "dev": true,
+ "requires": {
+ "lru-cache": "2",
+ "sigmund": "~1.0.0"
+ }
+ },
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+ "dev": true
+ },
+ "mixin-deep": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
+ "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
+ "dev": true,
+ "requires": {
+ "for-in": "^1.0.2",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "dev": true,
+ "requires": {
+ "minimist": "0.0.8"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "0.0.8",
+ "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+ "dev": true
+ }
+ }
+ },
+ "module-deps": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.0.tgz",
+ "integrity": "sha512-hKPmO06so6bL/ZvqVNVqdTVO8UAYsi3tQWlCa+z9KuWhoN4KDQtb5hcqQQv58qYiDE21wIvnttZEPiDgEbpwbA==",
+ "dev": true,
+ "requires": {
+ "JSONStream": "^1.0.3",
+ "browser-resolve": "^1.7.0",
+ "cached-path-relative": "^1.0.0",
+ "concat-stream": "~1.6.0",
+ "defined": "^1.0.0",
+ "detective": "^5.0.2",
+ "duplexer2": "^0.1.2",
+ "inherits": "^2.0.1",
+ "parents": "^1.0.0",
+ "readable-stream": "^2.0.2",
+ "resolve": "^1.4.0",
+ "stream-combiner2": "^1.1.1",
+ "subarg": "^1.0.0",
+ "through2": "^2.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+ "dev": true
+ },
+ "murmurhash": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/murmurhash/-/murmurhash-0.0.2.tgz",
+ "integrity": "sha1-bwe9ihEF5wnCb8iUIMtZMMJFhf4="
+ },
+ "nan": {
+ "version": "2.11.1",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.1.tgz",
+ "integrity": "sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA=="
+ },
+ "nanomatch": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+ "dev": true,
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "fragment-cache": "^0.2.1",
+ "is-windows": "^1.0.2",
+ "kind-of": "^6.0.2",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+ "dev": true
+ },
+ "array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+ "dev": true
+ }
+ }
+ },
+ "node-releases": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.0.5.tgz",
+ "integrity": "sha512-Ky7q0BO1BBkG/rQz6PkEZ59rwo+aSfhczHP1wwq8IowoVdN/FpiP7qp0XW0P2+BVCWe5fQUBozdbVd54q1RbCQ==",
+ "dev": true,
+ "requires": {
+ "semver": "^5.3.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
+ "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
+ "dev": true
+ }
+ }
+ },
+ "nopt": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
+ "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
+ "dev": true,
+ "requires": {
+ "abbrev": "1"
+ }
+ },
+ "normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "dev": true,
+ "requires": {
+ "remove-trailing-separator": "^1.0.1"
+ }
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+ "dev": true
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "dev": true
+ },
+ "object-copy": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+ "dev": true,
+ "requires": {
+ "copy-descriptor": "^0.1.0",
+ "define-property": "^0.2.5",
+ "kind-of": "^3.0.3"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "object-visit": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.0"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ }
+ }
+ },
+ "object.omit": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
+ "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
+ "dev": true,
+ "requires": {
+ "for-own": "^0.1.4",
+ "is-extendable": "^0.1.1"
+ }
+ },
+ "object.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ }
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "optimist": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
+ "dev": true,
+ "requires": {
+ "minimist": "~0.0.1",
+ "wordwrap": "~0.0.2"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "0.0.10",
+ "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
+ "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
+ "dev": true
+ },
+ "wordwrap": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+ "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
+ "dev": true
+ }
+ }
+ },
+ "optionator": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
+ "integrity": "sha1-t1qJlaLUF98ltuTjhi9QqohlE2g=",
+ "dev": true,
+ "requires": {
+ "deep-is": "~0.1.2",
+ "fast-levenshtein": "~1.0.0",
+ "levn": "~0.2.5",
+ "prelude-ls": "~1.1.1",
+ "type-check": "~0.3.1",
+ "wordwrap": "~0.0.2"
+ },
+ "dependencies": {
+ "wordwrap": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+ "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
+ "dev": true
+ }
+ }
+ },
+ "ordered-read-streams": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz",
+ "integrity": "sha1-cTfmmzKYuzQiR6G77jiByA4v14s=",
+ "dev": true,
+ "requires": {
+ "is-stream": "^1.0.1",
+ "readable-stream": "^2.0.1"
+ }
+ },
+ "os-browserify": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
+ "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=",
+ "dev": true
+ },
+ "outpipe": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/outpipe/-/outpipe-1.1.1.tgz",
+ "integrity": "sha1-UM+GFjZeh+Ax4ppeyTOaPaRyX6I=",
+ "dev": true,
+ "requires": {
+ "shell-quote": "^1.4.2"
+ }
+ },
+ "pako": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz",
+ "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==",
+ "dev": true
+ },
+ "parents": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz",
+ "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=",
+ "dev": true,
+ "requires": {
+ "path-platform": "~0.11.15"
+ }
+ },
+ "parse-asn1": {
+ "version": "5.1.1",
+ "resolved": "http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz",
+ "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==",
+ "dev": true,
+ "requires": {
+ "asn1.js": "^4.0.0",
+ "browserify-aes": "^1.0.0",
+ "create-hash": "^1.1.0",
+ "evp_bytestokey": "^1.0.0",
+ "pbkdf2": "^3.0.3"
+ }
+ },
+ "parse-glob": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
+ "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
+ "dev": true,
+ "requires": {
+ "glob-base": "^0.3.0",
+ "is-dotfile": "^1.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.0"
+ }
+ },
+ "pascalcase": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
+ "dev": true
+ },
+ "path-browserify": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
+ "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==",
+ "dev": true
+ },
+ "path-dirname": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+ "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
+ "dev": true
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true
+ },
+ "path-parse": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+ "dev": true
+ },
+ "path-platform": {
+ "version": "0.11.15",
+ "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz",
+ "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=",
+ "dev": true
+ },
+ "pbkdf2": {
+ "version": "3.0.17",
+ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz",
+ "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==",
+ "dev": true,
+ "requires": {
+ "create-hash": "^1.1.2",
+ "create-hmac": "^1.1.4",
+ "ripemd160": "^2.0.1",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
+ "pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
+ "dev": true
+ },
+ "pinkie": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+ "dev": true
+ },
+ "pinkie-promise": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+ "dev": true,
+ "requires": {
+ "pinkie": "^2.0.0"
+ }
+ },
+ "posix-character-classes": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
+ "dev": true
+ },
+ "prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+ "dev": true
+ },
+ "preserve": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
+ "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
+ "dev": true
+ },
+ "pretty-bytes": {
+ "version": "3.0.1",
+ "resolved": "http://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz",
+ "integrity": "sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8=",
+ "dev": true,
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "private": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
+ "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==",
+ "dev": true
+ },
+ "process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
+ "dev": true
+ },
+ "process-nextick-args": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+ "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+ "dev": true
+ },
+ "public-encrypt": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
+ "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "browserify-rsa": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "parse-asn1": "^5.0.0",
+ "randombytes": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+ "dev": true
+ },
+ "querystring": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+ "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
+ "dev": true
+ },
+ "querystring-es3": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
+ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
+ "dev": true
+ },
+ "randomatic": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz",
+ "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==",
+ "dev": true,
+ "requires": {
+ "is-number": "^4.0.0",
+ "kind-of": "^6.0.0",
+ "math-random": "^1.0.1"
+ },
+ "dependencies": {
+ "is-number": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+ "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+ "dev": true
+ }
+ }
+ },
+ "randombytes": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz",
+ "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "randomfill": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
+ "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
+ "dev": true,
+ "requires": {
+ "randombytes": "^2.0.5",
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "read-all-stream": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz",
+ "integrity": "sha1-NcPhd/IHjveJ7kv6+kNzB06u9Po=",
+ "dev": true,
+ "requires": {
+ "pinkie-promise": "^2.0.0",
+ "readable-stream": "^2.0.0"
+ }
+ },
+ "read-only-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz",
+ "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=",
+ "dev": true,
+ "requires": {
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ },
+ "dependencies": {
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "readdirp": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.11",
+ "micromatch": "^3.1.10",
+ "readable-stream": "^2.0.2"
+ },
+ "dependencies": {
+ "arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+ "dev": true
+ },
+ "array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+ "dev": true
+ },
+ "braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "dev": true,
+ "requires": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+ "dev": true,
+ "requires": {
+ "debug": "^2.3.3",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "posix-character-classes": "^0.1.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ }
+ },
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true
+ }
+ }
+ },
+ "extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "dev": true,
+ "requires": {
+ "array-unique": "^0.3.2",
+ "define-property": "^1.0.0",
+ "expand-brackets": "^2.1.4",
+ "extend-shallow": "^2.0.1",
+ "fragment-cache": "^0.2.1",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "graceful-fs": {
+ "version": "4.1.15",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
+ "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
+ "dev": true
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+ "dev": true
+ },
+ "micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+ "dev": true,
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "braces": "^2.3.1",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "extglob": "^2.0.4",
+ "fragment-cache": "^0.2.1",
+ "kind-of": "^6.0.2",
+ "nanomatch": "^1.2.9",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.2"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "regenerate": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz",
+ "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==",
+ "dev": true
+ },
+ "regenerate-unicode-properties": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz",
+ "integrity": "sha512-s5NGghCE4itSlUS+0WUj88G6cfMVMmH8boTPNvABf8od+2dhT9WDlWu8n01raQAJZMOK8Ch6jSexaRO7swd6aw==",
+ "dev": true,
+ "requires": {
+ "regenerate": "^1.4.0"
+ }
+ },
+ "regenerator-transform": {
+ "version": "0.13.3",
+ "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.3.tgz",
+ "integrity": "sha512-5ipTrZFSq5vU2YoGoww4uaRVAK4wyYC4TSICibbfEPOruUu8FFP7ErV0BjmbIOEpn3O/k9na9UEdYR/3m7N6uA==",
+ "dev": true,
+ "requires": {
+ "private": "^0.1.6"
+ }
+ },
+ "regex-cache": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
+ "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
+ "dev": true,
+ "requires": {
+ "is-equal-shallow": "^0.1.3"
+ }
+ },
+ "regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^3.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "regexpu-core": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.2.0.tgz",
+ "integrity": "sha512-Z835VSnJJ46CNBttalHD/dB+Sj2ezmY6Xp38npwU87peK6mqOzOpV8eYktdkLTEkzzD+JsTcxd84ozd8I14+rw==",
+ "dev": true,
+ "requires": {
+ "regenerate": "^1.4.0",
+ "regenerate-unicode-properties": "^7.0.0",
+ "regjsgen": "^0.4.0",
+ "regjsparser": "^0.3.0",
+ "unicode-match-property-ecmascript": "^1.0.4",
+ "unicode-match-property-value-ecmascript": "^1.0.2"
+ }
+ },
+ "regjsgen": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.4.0.tgz",
+ "integrity": "sha512-X51Lte1gCYUdlwhF28+2YMO0U6WeN0GLpgpA7LK7mbdDnkQYiwvEpmpe0F/cv5L14EbxgrdayAG3JETBv0dbXA==",
+ "dev": true
+ },
+ "regjsparser": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.3.0.tgz",
+ "integrity": "sha512-zza72oZBBHzt64G7DxdqrOo/30bhHkwMUoT0WqfGu98XLd7N+1tsy5MJ96Bk4MD0y74n629RhmrGW6XlnLLwCA==",
+ "dev": true,
+ "requires": {
+ "jsesc": "~0.5.0"
+ },
+ "dependencies": {
+ "jsesc": {
+ "version": "0.5.0",
+ "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+ "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
+ "dev": true
+ }
+ }
+ },
+ "remove-trailing-separator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+ "dev": true
+ },
+ "repeat-element": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+ "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
+ "dev": true
+ },
+ "repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+ "dev": true
+ },
+ "replace-ext": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz",
+ "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=",
+ "dev": true
+ },
+ "resolve": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
+ "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==",
+ "dev": true,
+ "requires": {
+ "path-parse": "^1.0.5"
+ }
+ },
+ "resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+ "dev": true
+ },
+ "ret": {
+ "version": "0.1.15",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+ "dev": true
+ },
+ "rimraf": {
+ "version": "2.2.8",
+ "resolved": "http://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz",
+ "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=",
+ "dev": true
+ },
+ "ripemd160": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
+ "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
+ "dev": true,
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "safe-regex": {
+ "version": "1.1.0",
+ "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+ "dev": true,
+ "requires": {
+ "ret": "~0.1.10"
+ }
+ },
+ "sax": {
+ "version": "0.5.3",
+ "resolved": "http://registry.npmjs.org/sax/-/sax-0.5.3.tgz",
+ "integrity": "sha1-N3NxSg2RV8qqcwKXHvpcbc2lUtY=",
+ "dev": true
+ },
+ "seek-bzip": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz",
+ "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=",
+ "dev": true,
+ "requires": {
+ "commander": "~2.8.1"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.8.1",
+ "resolved": "http://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
+ "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
+ "dev": true,
+ "requires": {
+ "graceful-readlink": ">= 1.0.0"
+ }
+ }
+ }
+ },
+ "semver": {
+ "version": "4.3.2",
+ "resolved": "http://registry.npmjs.org/semver/-/semver-4.3.2.tgz",
+ "integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=",
+ "dev": true
+ },
+ "set-value": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
+ "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.3",
+ "split-string": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "sha.js": {
+ "version": "2.4.11",
+ "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "sha1": {
+ "version": "git://github.com/pvorb/node-sha1.git#910081c83f3661507d9d89e66e3f38d8b59d5559",
+ "from": "git://github.com/pvorb/node-sha1.git#910081c83f3661507d9d89e66e3f38d8b59d5559",
+ "requires": {
+ "charenc": ">= 0.0.0",
+ "crypt": ">= 0.0.0"
+ }
+ },
+ "shasum": {
+ "version": "1.0.2",
+ "resolved": "http://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz",
+ "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=",
+ "dev": true,
+ "requires": {
+ "json-stable-stringify": "~0.0.0",
+ "sha.js": "~2.4.4"
+ }
+ },
+ "shell-quote": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz",
+ "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=",
+ "dev": true,
+ "requires": {
+ "array-filter": "~0.0.0",
+ "array-map": "~0.0.0",
+ "array-reduce": "~0.0.0",
+ "jsonify": "~0.0.0"
+ }
+ },
+ "sigmund": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
+ "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=",
+ "dev": true
+ },
+ "simple-concat": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz",
+ "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=",
+ "dev": true
+ },
+ "snapdragon": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+ "dev": true,
+ "requires": {
+ "base": "^0.11.1",
+ "debug": "^2.2.0",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "map-cache": "^0.2.2",
+ "source-map": "^0.5.6",
+ "source-map-resolve": "^0.5.0",
+ "use": "^3.1.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "snapdragon-node": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+ "dev": true,
+ "requires": {
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.0",
+ "snapdragon-util": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+ "dev": true
+ }
+ }
+ },
+ "snapdragon-util": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.2.0"
+ }
+ },
+ "snowplow-tracker-core": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/snowplow-tracker-core/-/snowplow-tracker-core-0.6.1.tgz",
+ "integrity": "sha1-9c8NQEJ98g54HEGrH5jGxmjKMIA=",
+ "requires": {
+ "uuid": "2.0.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ },
+ "source-map-resolve": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
+ "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
+ "dev": true,
+ "requires": {
+ "atob": "^2.1.1",
+ "decode-uri-component": "^0.2.0",
+ "resolve-url": "^0.2.1",
+ "source-map-url": "^0.4.0",
+ "urix": "^0.1.0"
+ }
+ },
+ "source-map-url": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
+ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
+ "dev": true
+ },
+ "split-string": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^3.0.0"
+ }
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+ "dev": true
+ },
+ "stat-mode": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.2.2.tgz",
+ "integrity": "sha1-5sgLYjEj19gM8TLOU480YokHJQI=",
+ "dev": true
+ },
+ "static-extend": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+ "dev": true,
+ "requires": {
+ "define-property": "^0.2.5",
+ "object-copy": "^0.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "stream-browserify": {
+ "version": "2.0.1",
+ "resolved": "http://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
+ "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=",
+ "dev": true,
+ "requires": {
+ "inherits": "~2.0.1",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "stream-combiner2": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz",
+ "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=",
+ "dev": true,
+ "requires": {
+ "duplexer2": "~0.1.0",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "stream-http": {
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz",
+ "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==",
+ "dev": true,
+ "requires": {
+ "builtin-status-codes": "^3.0.0",
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.3.6",
+ "to-arraybuffer": "^1.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "stream-shift": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz",
+ "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=",
+ "dev": true
+ },
+ "stream-splicer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz",
+ "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "string_decoder": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz",
+ "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "0.3.0",
+ "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz",
+ "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^0.2.1"
+ }
+ },
+ "strip-bom": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+ "dev": true,
+ "requires": {
+ "is-utf8": "^0.2.0"
+ }
+ },
+ "strip-bom-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz",
+ "integrity": "sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=",
+ "dev": true,
+ "requires": {
+ "first-chunk-stream": "^1.0.0",
+ "strip-bom": "^2.0.0"
+ }
+ },
+ "strip-dirs": {
+ "version": "1.1.1",
+ "resolved": "http://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz",
+ "integrity": "sha1-lgu9EoeETzl1pFWKoQOoJV4kVqA=",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.0.0",
+ "get-stdin": "^4.0.1",
+ "is-absolute": "^0.1.5",
+ "is-natural-number": "^2.0.0",
+ "minimist": "^1.1.0",
+ "sum-up": "^1.0.1"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ }
+ },
+ "has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "subarg": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
+ "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.1.0"
+ }
+ },
+ "sum-up": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.3.tgz",
+ "integrity": "sha1-HGYfZnBX9jvLeHWqFDi8FiUlFW4=",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ }
+ },
+ "has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "syntax-error": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz",
+ "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==",
+ "dev": true,
+ "requires": {
+ "acorn-node": "^1.2.0"
+ }
+ },
+ "tar-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz",
+ "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==",
+ "dev": true,
+ "requires": {
+ "bl": "^1.0.0",
+ "buffer-alloc": "^1.2.0",
+ "end-of-stream": "^1.0.0",
+ "fs-constants": "^1.0.0",
+ "readable-stream": "^2.3.0",
+ "to-buffer": "^1.1.1",
+ "xtend": "^4.0.0"
+ }
+ },
+ "through": {
+ "version": "2.3.8",
+ "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+ "dev": true
+ },
+ "through2": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+ "dev": true,
+ "requires": {
+ "readable-stream": "~2.3.6",
+ "xtend": "~4.0.1"
+ }
+ },
+ "through2-filter": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-2.0.0.tgz",
+ "integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=",
+ "dev": true,
+ "requires": {
+ "through2": "~2.0.0",
+ "xtend": "~4.0.0"
+ }
+ },
+ "timers-browserify": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz",
+ "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=",
+ "dev": true,
+ "requires": {
+ "process": "~0.11.0"
+ }
+ },
+ "to-absolute-glob": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz",
+ "integrity": "sha1-HN+kcqnvUMI57maZm2YsoOs5k38=",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^2.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "to-arraybuffer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
+ "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
+ "dev": true
+ },
+ "to-buffer": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
+ "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==",
+ "dev": true
+ },
+ "to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
+ "dev": true
+ },
+ "to-object-path": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ }
+ },
+ "to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+ "dev": true,
+ "requires": {
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "regex-not": "^1.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+ "dev": true,
+ "requires": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ },
+ "dependencies": {
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ }
+ }
+ }
+ },
+ "trim-right": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
+ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
+ "dev": true
+ },
+ "tty-browserify": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz",
+ "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==",
+ "dev": true
+ },
+ "type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "~1.1.2"
+ }
+ },
+ "type-detect": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz",
+ "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=",
+ "dev": true
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+ "dev": true
+ },
+ "uglify-js": {
+ "version": "3.4.9",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz",
+ "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==",
+ "dev": true,
+ "requires": {
+ "commander": "~2.17.1",
+ "source-map": "~0.6.1"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "umd": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz",
+ "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==",
+ "dev": true
+ },
+ "undeclared-identifiers": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.2.tgz",
+ "integrity": "sha512-13EaeocO4edF/3JKime9rD7oB6QI8llAGhgn5fKOPyfkJbRb6NFv9pYV6dFEmpa4uRjKeBqLZP8GpuzqHlKDMQ==",
+ "dev": true,
+ "requires": {
+ "acorn-node": "^1.3.0",
+ "get-assigned-identifiers": "^1.2.0",
+ "simple-concat": "^1.0.0",
+ "xtend": "^4.0.1"
+ }
+ },
+ "underscore": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz",
+ "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=",
+ "dev": true
+ },
+ "underscore.string": {
+ "version": "2.2.1",
+ "resolved": "http://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz",
+ "integrity": "sha1-18D6KvXVoaZ/QlPa7pgTLnM/Dxk=",
+ "dev": true
+ },
+ "unicode-canonical-property-names-ecmascript": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
+ "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==",
+ "dev": true
+ },
+ "unicode-match-property-ecmascript": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz",
+ "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==",
+ "dev": true,
+ "requires": {
+ "unicode-canonical-property-names-ecmascript": "^1.0.4",
+ "unicode-property-aliases-ecmascript": "^1.0.4"
+ }
+ },
+ "unicode-match-property-value-ecmascript": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.0.2.tgz",
+ "integrity": "sha512-Rx7yODZC1L/T8XKo/2kNzVAQaRE88AaMvI1EF/Xnj3GW2wzN6fop9DDWuFAKUVFH7vozkz26DzP0qyWLKLIVPQ==",
+ "dev": true
+ },
+ "unicode-property-aliases-ecmascript": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.4.tgz",
+ "integrity": "sha512-2WSLa6OdYd2ng8oqiGIWnJqyFArvhn+5vgx5GTxMbUYjCYKUcuKS62YLFF0R/BDGlB1yzXjQOLtPAfHsgirEpg==",
+ "dev": true
+ },
+ "union-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
+ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
+ "dev": true,
+ "requires": {
+ "arr-union": "^3.1.0",
+ "get-value": "^2.0.6",
+ "is-extendable": "^0.1.1",
+ "set-value": "^0.4.3"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "set-value": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
+ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.1",
+ "to-object-path": "^0.3.0"
+ }
+ }
+ }
+ },
+ "unique-stream": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.2.1.tgz",
+ "integrity": "sha1-WqADz76Uxf+GbE59ZouxxNuts2k=",
+ "dev": true,
+ "requires": {
+ "json-stable-stringify": "^1.0.0",
+ "through2-filter": "^2.0.0"
+ },
+ "dependencies": {
+ "json-stable-stringify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
+ "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
+ "dev": true,
+ "requires": {
+ "jsonify": "~0.0.0"
+ }
+ }
+ }
+ },
+ "unset-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+ "dev": true,
+ "requires": {
+ "has-value": "^0.3.1",
+ "isobject": "^3.0.0"
+ },
+ "dependencies": {
+ "has-value": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+ "dev": true,
+ "requires": {
+ "get-value": "^2.0.3",
+ "has-values": "^0.1.4",
+ "isobject": "^2.0.0"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "dev": true,
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ }
+ }
+ },
+ "has-values": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+ "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
+ "dev": true
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ }
+ }
+ },
+ "uri-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz",
+ "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=",
+ "dev": true
+ },
+ "urix": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+ "dev": true
+ },
+ "url": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
+ "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
+ "dev": true,
+ "requires": {
+ "punycode": "1.3.2",
+ "querystring": "0.2.0"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+ "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
+ "dev": true
+ }
+ }
+ },
+ "use": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+ "dev": true
+ },
+ "util": {
+ "version": "0.10.4",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
+ "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.3"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
+ "uuid": {
+ "version": "2.0.3",
+ "resolved": "http://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz",
+ "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho="
+ },
+ "vali-date": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz",
+ "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=",
+ "dev": true
+ },
+ "vinyl": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz",
+ "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=",
+ "dev": true,
+ "requires": {
+ "clone": "^1.0.0",
+ "clone-stats": "^0.0.1",
+ "replace-ext": "0.0.1"
+ }
+ },
+ "vinyl-assign": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/vinyl-assign/-/vinyl-assign-1.2.1.tgz",
+ "integrity": "sha1-TRmIkbVRWRHXcajNnFSApGoHSkU=",
+ "dev": true,
+ "requires": {
+ "object-assign": "^4.0.1",
+ "readable-stream": "^2.0.0"
+ }
+ },
+ "vinyl-fs": {
+ "version": "2.4.4",
+ "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-2.4.4.tgz",
+ "integrity": "sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=",
+ "dev": true,
+ "requires": {
+ "duplexify": "^3.2.0",
+ "glob-stream": "^5.3.2",
+ "graceful-fs": "^4.0.0",
+ "gulp-sourcemaps": "1.6.0",
+ "is-valid-glob": "^0.3.0",
+ "lazystream": "^1.0.0",
+ "lodash.isequal": "^4.0.0",
+ "merge-stream": "^1.0.0",
+ "mkdirp": "^0.5.0",
+ "object-assign": "^4.0.0",
+ "readable-stream": "^2.0.4",
+ "strip-bom": "^2.0.0",
+ "strip-bom-stream": "^1.0.0",
+ "through2": "^2.0.0",
+ "through2-filter": "^2.0.0",
+ "vali-date": "^1.0.0",
+ "vinyl": "^1.0.0"
+ },
+ "dependencies": {
+ "graceful-fs": {
+ "version": "4.1.15",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
+ "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
+ "dev": true
+ }
+ }
+ },
+ "vm-browserify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz",
+ "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==",
+ "dev": true
+ },
+ "watchify": {
+ "version": "3.11.0",
+ "resolved": "https://registry.npmjs.org/watchify/-/watchify-3.11.0.tgz",
+ "integrity": "sha512-7jWG0c3cKKm2hKScnSAMUEUjRJKXUShwMPk0ASVhICycQhwND3IMAdhJYmc1mxxKzBUJTSF5HZizfrKrS6BzkA==",
+ "dev": true,
+ "requires": {
+ "anymatch": "^1.3.0",
+ "browserify": "^16.1.0",
+ "chokidar": "^1.0.0",
+ "defined": "^1.0.0",
+ "outpipe": "^1.1.0",
+ "through2": "^2.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "which": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz",
+ "integrity": "sha1-RgwdoPgQED0DIam2M6+eV15kSG8=",
+ "dev": true
+ },
+ "wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+ "dev": true
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "xml2js": {
+ "version": "0.2.8",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.2.8.tgz",
+ "integrity": "sha1-m4FpCTFjH/CdGVdUn69U9PmAs8I=",
+ "dev": true,
+ "requires": {
+ "sax": "0.5.x"
+ }
+ },
+ "xmlbuilder": {
+ "version": "0.4.2",
+ "resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-0.4.2.tgz",
+ "integrity": "sha1-F3bWXz/brUcKCNhgTN6xxOVA/4M=",
+ "dev": true
+ },
+ "xtend": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+ "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
+ "dev": true
+ },
+ "yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
+ "dev": true,
+ "requires": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ }
+ }
+}
diff --git a/snowplow-javascript-tracker/package.json b/snowplow-javascript-tracker/package.json
new file mode 100644
index 0000000000..fd5e556e1a
--- /dev/null
+++ b/snowplow-javascript-tracker/package.json
@@ -0,0 +1,49 @@
+{
+ "name": "snowplow-tracker",
+ "version": "2.10.0",
+ "dependencies": {
+ "snowplow-tracker-core": "0.7.0",
+ "browser-cookie-lite": "0.3.1",
+ "jstimezonedetect": "1.0.5",
+ "murmurhash": "0.0.2",
+ "sha1": "git://github.com/pvorb/node-sha1.git#910081c83f3661507d9d89e66e3f38d8b59d5559",
+ "uuid": "2.0.3"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.1.2",
+ "@babel/preset-env": "^7.1.0",
+ "JSON": "1.0.0",
+ "grunt": "^1.0.3",
+ "grunt-aws": "0.6.2",
+ "grunt-babel": "^8.0.0",
+ "lodash": "^4.17.11",
+ "grunt-browserify": "^5.3.0",
+ "grunt-contrib-concat": "^1.0.1",
+ "grunt-contrib-uglify": "^4.0.0",
+ "intern": "3.3.2",
+ "js-base64": "^2.4.9",
+ "semver": "4.3.2"
+ },
+ "contributors": [
+ "Alex Dean",
+ "Simon Andersson",
+ "Anthon Pang",
+ "Fred Blundun",
+ "Joshua Beemster",
+ "Michael Hadam"
+ ],
+ "description": "JavaScript tracker for Snowplow",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/snowplow/snowplow-javascript-tracker.git"
+ },
+ "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues",
+ "keywords": [
+ "tracking",
+ "web analytics",
+ "events",
+ "open source"
+ ],
+ "license": "Simplified BSD",
+ "private": true
+}
diff --git a/snowplow-javascript-tracker/src/js/errors.js b/snowplow-javascript-tracker/src/js/errors.js
new file mode 100644
index 0000000000..5d0d6f069f
--- /dev/null
+++ b/snowplow-javascript-tracker/src/js/errors.js
@@ -0,0 +1,127 @@
+/*
+ * JavaScript tracker for Snowplow: tracker.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2016 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+var isFunction = require('lodash/isFunction'),
+ helpers = require('./lib/helpers'),
+ object = typeof exports !== 'undefined' ? exports : this,
+ windowAlias = window;
+
+
+object.errorManager = function (core) {
+
+ /**
+ * Send error as self-describing event
+ *
+ * @param message string Message appeared in console
+ * @param filename string Source file (not used)
+ * @param lineno number Line number
+ * @param colno number Column number (not used)
+ * @param error Error error object (not present in all browsers)
+ * @param contexts Array of custom contexts
+ */
+ function track(message, filename, lineno, colno, error, contexts) {
+ var stack = (error && error.stack) ? error.stack : null;
+
+ core.trackSelfDescribingEvent({
+ schema: 'iglu:com.snowplowanalytics.snowplow/application_error/jsonschema/1-0-1',
+ data: {
+ programmingLanguage: "JAVASCRIPT",
+ message: message || "JS Exception. Browser doesn't support ErrorEvent API",
+ stackTrace: stack,
+ lineNumber: lineno,
+ lineColumn: colno,
+ fileName: filename
+ }
+ }, contexts)
+ }
+
+ /**
+ * Attach custom contexts using `contextAdder`
+ *
+ *
+ * @param contextsAdder function to get details from internal browser state
+ * @returns {Array} custom contexts
+ */
+ function sendError(errorEvent, commonContexts, contextsAdder) {
+ var contexts;
+ if (isFunction(contextsAdder)) {
+ contexts = commonContexts.concat(contextsAdder(errorEvent));
+ } else {
+ contexts = commonContexts;
+ }
+
+ track(errorEvent.message, errorEvent.filename, errorEvent.lineno, errorEvent.colno, errorEvent.error, contexts)
+ }
+
+ return {
+
+ /**
+ * Track unhandled exception.
+ * This method supposed to be used inside try/catch block or with window.onerror
+ * (contexts won't be attached), but NOT with `addEventListener` - use
+ * `enableErrorTracker` for this
+ *
+ * @param message string Message appeared in console
+ * @param filename string Source file (not used)
+ * @param lineno number Line number
+ * @param colno number Column number (not used)
+ * @param error Error error object (not present in all browsers)
+ * @param contexts Array of custom contexts
+ */
+ trackError: track,
+
+ /**
+ * Curried function to enable tracking of unhandled exceptions.
+ * Listen for `error` event and
+ *
+ * @param filter Function ErrorEvent => Bool to check whether error should be tracker
+ * @param contextsAdder Function ErrorEvent => Array to add custom contexts with
+ * internal state based on particular error
+ */
+ enableErrorTracking: function (filter, contextsAdder, contexts) {
+ /**
+ * Closure callback to filter, contextualize and track unhandled exceptions
+ *
+ * @param errorEvent ErrorEvent passed to event listener
+ */
+ function captureError (errorEvent) {
+ if (isFunction(filter) && filter(errorEvent) || filter == null) {
+ sendError(errorEvent, contexts, contextsAdder)
+ }
+ }
+
+ helpers.addEventListener(windowAlias, 'error', captureError, true);
+ }
+ }
+};
diff --git a/snowplow-javascript-tracker/src/js/forms.js b/snowplow-javascript-tracker/src/js/forms.js
new file mode 100755
index 0000000000..1efc033c65
--- /dev/null
+++ b/snowplow-javascript-tracker/src/js/forms.js
@@ -0,0 +1,189 @@
+/*
+ * JavaScript tracker for Snowplow: forms.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+var forEach = require('lodash/forEach'),
+ filter = require('lodash/filter'),
+ find = require('lodash/find'),
+ helpers = require('./lib/helpers'),
+ object = typeof exports !== 'undefined' ? exports : this;
+
+/**
+ * Object for handling automatic form tracking
+ *
+ * @param object core The tracker core
+ * @param string trackerId Unique identifier for the tracker instance, used to mark tracked elements
+ * @param function contextAdder Function to add common contexts like PerformanceTiming to all events
+ * @return object formTrackingManager instance
+ */
+object.getFormTrackingManager = function (core, trackerId, contextAdder) {
+
+ // Tag names of mutable elements inside a form
+ var innerElementTags = ['textarea', 'input', 'select'];
+
+ // Used to mark elements with event listeners
+ var trackingMarker = trackerId + 'form';
+
+ // Filter to determine which forms should be tracked
+ var formFilter = function () { return true };
+
+ // Filter to determine which form fields should be tracked
+ var fieldFilter = function () { return true };
+
+ // Default function applied to all elements, optionally overridden by transform field
+ var fieldTransform = function (x) { return x };
+
+ /*
+ * Get an identifier for a form, input, textarea, or select element
+ */
+ function getFormElementName(elt) {
+ return elt[find(['name', 'id', 'type', 'nodeName'], function (propName) {
+
+ // If elt has a child whose name is "id", that element will be returned
+ // instead of the actual id of elt unless we ensure that a string is returned
+ return elt[propName] && typeof elt[propName] === 'string';
+ })];
+ }
+
+ /*
+ * Identifies the parent form in which an element is contained
+ */
+ function getParentFormName(elt) {
+ while (elt && elt.nodeName && elt.nodeName.toUpperCase() !== 'HTML' && elt.nodeName.toUpperCase() !== 'FORM') {
+ elt = elt.parentNode;
+ }
+ if (elt && elt.nodeName && elt.nodeName.toUpperCase() === 'FORM') {
+ return getFormElementName(elt);
+ }
+ }
+
+ /*
+ * Returns a list of the input, textarea, and select elements inside a form along with their values
+ */
+ function getInnerFormElements(elt) {
+ var innerElements = [];
+ forEach(innerElementTags, function (tagname) {
+
+ var trackedChildren = filter(elt.getElementsByTagName(tagname), function (child) {
+ return child.hasOwnProperty(trackingMarker);
+ });
+
+ forEach(trackedChildren, function (child) {
+ if (child.type === 'submit') {
+ return;
+ }
+ var elementJson = {
+ name: getFormElementName(child),
+ value: child.value,
+ nodeName: child.nodeName
+ };
+ if (child.type && child.nodeName.toUpperCase() === 'INPUT') {
+ elementJson.type = child.type;
+ }
+
+ if ((child.type === 'checkbox' || child.type === 'radio') && !child.checked) {
+ elementJson.value = null;
+ }
+ innerElements.push(elementJson);
+ });
+ });
+
+ return innerElements;
+ }
+
+ /*
+ * Return function to handle form field change event
+ */
+ function getFormChangeListener(event_type, context) {
+ return function (e) {
+ var elt = e.target;
+ var type = (elt.nodeName && elt.nodeName.toUpperCase() === 'INPUT') ? elt.type : null;
+ var value = (elt.type === 'checkbox' && !elt.checked) ? null : fieldTransform(elt.value);
+ if (event_type === 'change_form' || (type !== 'checkbox' && type !== 'radio')) {
+ core.trackFormFocusOrChange(event_type, getParentFormName(elt), getFormElementName(elt), elt.nodeName, type, helpers.getCssClasses(elt), value, contextAdder(helpers.resolveDynamicContexts(context, elt, type, value)));
+ }
+ };
+ }
+
+ /*
+ * Return function to handle form submission event
+ */
+ function getFormSubmissionListener(context) {
+ return function (e) {
+ var elt = e.target;
+ var innerElements = getInnerFormElements(elt);
+ forEach(innerElements, function (innerElement) {
+ innerElement.value = fieldTransform(innerElement.value);
+ });
+ core.trackFormSubmission(getFormElementName(elt), helpers.getCssClasses(elt), innerElements, contextAdder(helpers.resolveDynamicContexts(context, elt, innerElements)));
+ };
+ }
+
+ return {
+
+ /*
+ * Configures form tracking: which forms and fields will be tracked, and the context to attach
+ */
+ configureFormTracking: function (config) {
+ if (config) {
+ formFilter = helpers.getFilter(config.forms, true);
+ fieldFilter = helpers.getFilter(config.fields, false);
+ fieldTransform = helpers.getTransform(config.fields);
+ }
+ },
+
+ /*
+ * Add submission event listeners to all form elements
+ * Add value change event listeners to all mutable inner form elements
+ */
+ addFormListeners: function (context) {
+ forEach(document.getElementsByTagName('form'), function (form) {
+ if (formFilter(form) && !form[trackingMarker]) {
+
+ forEach(innerElementTags, function (tagname) {
+ forEach(form.getElementsByTagName(tagname), function (innerElement) {
+ if (fieldFilter(innerElement) && !innerElement[trackingMarker] && innerElement.type.toLowerCase() !== 'password') {
+ helpers.addEventListener(innerElement, 'focus', getFormChangeListener('focus_form', context), false);
+ helpers.addEventListener(innerElement, 'change', getFormChangeListener('change_form', context), false);
+ innerElement[trackingMarker] = true;
+ }
+ });
+ });
+
+ helpers.addEventListener(form, 'submit', getFormSubmissionListener(context));
+ form[trackingMarker] = true;
+ }
+ });
+ }
+ };
+};
diff --git a/snowplow-javascript-tracker/src/js/guard.js b/snowplow-javascript-tracker/src/js/guard.js
new file mode 100644
index 0000000000..7c53dbd0fa
--- /dev/null
+++ b/snowplow-javascript-tracker/src/js/guard.js
@@ -0,0 +1,60 @@
+/*
+ * JavaScript tracker for Snowplow: tracker.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2018 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+var object = typeof exports !== 'undefined' ? exports : this;
+
+var makeSafe = function (fn) {
+ return function () {
+ try {
+ return fn.apply(this, arguments);
+ } catch (ex) {
+ // TODO: Debug mode
+ }
+ };
+};
+
+exports.productionize = function (methods) {
+ let safeMethods = {};
+ if (typeof methods === 'object' && methods !== null) {
+ Object.getOwnPropertyNames(methods).forEach(
+ function (val, idx, array) {
+ if (typeof methods[val] === 'function') {
+ safeMethods[val] = makeSafe(methods[val]);
+ }
+ }
+ );
+ }
+ return safeMethods;
+};
\ No newline at end of file
diff --git a/snowplow-javascript-tracker/src/js/in_queue.js b/snowplow-javascript-tracker/src/js/in_queue.js
new file mode 100644
index 0000000000..f6ff72326f
--- /dev/null
+++ b/snowplow-javascript-tracker/src/js/in_queue.js
@@ -0,0 +1,193 @@
+/*
+ * JavaScript tracker for Snowplow: queue.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+;(function() {
+
+ var
+ map = require('lodash/map'),
+ isUndefined = require('lodash/isUndefined'),
+ isFunction = require('lodash/isFunction'),
+ helpers = require('./lib/helpers'),
+
+ object = typeof exports !== 'undefined' ? exports : this; // For eventual node.js environment support
+
+ /************************************************************
+ * Proxy object
+ * - this allows the caller to continue push()'ing to _snaq
+ * after the Tracker has been initialized and loaded
+ ************************************************************/
+
+ object.InQueueManager = function(TrackerConstructor, version, mutSnowplowState, asyncQueue, functionName) {
+
+ // Page view ID should be shared between all tracker instances
+ var trackerDictionary = {};
+
+ /**
+ * Get an array of trackers to which a function should be applied.
+ *
+ * @param array names List of namespaces to use. If empty, use all namespaces.
+ */
+ function getNamedTrackers(names) {
+ var namedTrackers = [];
+
+ if (!names || names.length === 0) {
+ namedTrackers = map(trackerDictionary);
+ } else {
+ for (var i = 0; i < names.length; i++) {
+ if (trackerDictionary.hasOwnProperty(names[i])) {
+ namedTrackers.push(trackerDictionary[names[i]]);
+ } else {
+ helpers.warn('Warning: Tracker namespace "' + names[i] + '" not configured');
+ }
+ }
+ }
+
+ if (namedTrackers.length === 0) {
+ helpers.warn('Warning: No tracker configured');
+ }
+
+ return namedTrackers;
+ }
+
+ /**
+ * Legacy support for input of the form _snaq.push(['setCollectorCf', 'd34uzc5hjrimh8'])
+ *
+ * @param string f Either 'setCollectorCf' or 'setCollectorUrl'
+ * @param string endpoint
+ * @param string namespace Optional tracker name
+ *
+ * TODO: remove this in 2.1.0
+ */
+ function legacyCreateNewNamespace(f, endpoint, namespace) {
+ helpers.warn(f + ' is deprecated. Set the collector when a new tracker instance using newTracker.');
+
+ var name;
+
+ if (isUndefined(namespace)) {
+ name = 'sp';
+ } else {
+ name = namespace;
+ }
+
+ createNewNamespace(name);
+ trackerDictionary[name][f](endpoint);
+ }
+
+ /**
+ * Initiate a new tracker namespace
+ *
+ * @param string namespace
+ * @param string endpoint Of the form d3rkrsqld9gmqf.cloudfront.net
+ */
+ function createNewNamespace(namespace, endpoint, argmap) {
+ argmap = argmap || {};
+
+ if (!trackerDictionary.hasOwnProperty(namespace)) {
+ trackerDictionary[namespace] = new TrackerConstructor(functionName, namespace, version, mutSnowplowState, argmap);
+ trackerDictionary[namespace].setCollectorUrl(endpoint);
+ } else {
+ helpers.warn('Tracker namespace ' + namespace + ' already exists.');
+ }
+ }
+
+ /**
+ * Output an array of the form ['functionName', [trackerName1, trackerName2, ...]]
+ *
+ * @param string inputString
+ */
+ function parseInputString(inputString) {
+ var separatedString = inputString.split(':'),
+ extractedFunction = separatedString[0],
+ extractedNames = (separatedString.length > 1) ? separatedString[1].split(';') : [];
+
+ return [extractedFunction, extractedNames];
+ }
+
+ /**
+ * apply wrapper
+ *
+ * @param array parameterArray An array comprising either:
+ * [ 'methodName', optional_parameters ]
+ * or:
+ * [ functionObject, optional_parameters ]
+ */
+ function applyAsyncFunction() {
+ var i, j, f, parameterArray, input, parsedString, names, namedTrackers;
+
+ // Outer loop in case someone push'es in zarg of arrays
+ for (i = 0; i < arguments.length; i += 1) {
+ parameterArray = arguments[i];
+
+ // Arguments is not an array, so we turn it into one
+ input = Array.prototype.shift.call(parameterArray);
+
+ // Custom callback rather than tracker method, called with trackerDictionary as the context
+ if (isFunction(input)) {
+ input.apply(trackerDictionary, parameterArray);
+ continue;
+ }
+
+ parsedString = parseInputString(input);
+ f = parsedString[0];
+ names = parsedString[1];
+
+ if (f === 'newTracker') {
+ createNewNamespace(parameterArray[0], parameterArray[1], parameterArray[2]);
+ continue;
+ }
+
+ if ((f === 'setCollectorCf' || f === 'setCollectorUrl') && (!names || names.length === 0)) {
+ legacyCreateNewNamespace(f, parameterArray[0], parameterArray[1]);
+ continue;
+ }
+
+ namedTrackers = getNamedTrackers(names);
+
+ for (j = 0; j < namedTrackers.length; j++) {
+ namedTrackers[j][f].apply(namedTrackers[j], parameterArray);
+ }
+ }
+ }
+
+ // We need to manually apply any events collected before this initialization
+ for (var i = 0; i < asyncQueue.length; i++) {
+ applyAsyncFunction(asyncQueue[i]);
+ }
+
+ return {
+ push: applyAsyncFunction
+ };
+ };
+
+}());
diff --git a/snowplow-javascript-tracker/src/js/init.js b/snowplow-javascript-tracker/src/js/init.js
new file mode 100644
index 0000000000..9e243b1929
--- /dev/null
+++ b/snowplow-javascript-tracker/src/js/init.js
@@ -0,0 +1,53 @@
+/*
+ * JavaScript tracker for Snowplow: init.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Snowplow Asynchronous Queue
+
+/*
+ * Get the name of the global input function
+ */
+
+var snowplow = require('./snowplow'),
+ queueName,
+ queue,
+ windowAlias = window;
+
+if (windowAlias.GlobalSnowplowNamespace && windowAlias.GlobalSnowplowNamespace.length > 0) {
+ queueName = windowAlias.GlobalSnowplowNamespace.shift();
+ queue = windowAlias[queueName];
+ queue.q = new snowplow.Snowplow(queue.q, queueName);
+} else {
+ windowAlias._snaq = windowAlias._snaq || [];
+ windowAlias._snaq = new snowplow.Snowplow(windowAlias._snaq, '_snaq');
+}
diff --git a/snowplow-javascript-tracker/src/js/lib/detectors.js b/snowplow-javascript-tracker/src/js/lib/detectors.js
new file mode 100644
index 0000000000..e9c11b2075
--- /dev/null
+++ b/snowplow-javascript-tracker/src/js/lib/detectors.js
@@ -0,0 +1,254 @@
+/*
+ * JavaScript tracker for Snowplow: detectors.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+;(function() {
+
+ var
+ isFunction = require('lodash/isFunction'),
+ isUndefined = require('lodash/isUndefined'),
+ murmurhash3_32_gc = require('murmurhash').v3,
+ tz = require('jstimezonedetect').jstz.determine(),
+ cookie = require('browser-cookie-lite'),
+
+ object = typeof exports !== 'undefined' ? exports : this, // For eventual node.js environment support
+
+ windowAlias = window,
+ navigatorAlias = navigator,
+ screenAlias = screen,
+ documentAlias = document;
+
+ /*
+ * Checks whether sessionStorage is available, in a way that
+ * does not throw a SecurityError in Firefox if "always ask"
+ * is enabled for cookies (https://github.com/snowplow/snowplow/issues/163).
+ */
+ object.hasSessionStorage = function () {
+ try {
+ return !!windowAlias.sessionStorage;
+ } catch (e) {
+ return true; // SecurityError when referencing it means it exists
+ }
+ };
+
+ /*
+ * Checks whether localStorage is available, in a way that
+ * does not throw a SecurityError in Firefox if "always ask"
+ * is enabled for cookies (https://github.com/snowplow/snowplow/issues/163).
+ */
+ object.hasLocalStorage = function () {
+ try {
+ return !!windowAlias.localStorage;
+ } catch (e) {
+ return true; // SecurityError when referencing it means it exists
+ }
+ };
+
+ /*
+ * Checks whether localStorage is accessible
+ * sets and removes an item to handle private IOS5 browsing
+ * (http://git.io/jFB2Xw)
+ */
+ object.localStorageAccessible = function() {
+ var mod = 'modernizr';
+ if (!object.hasLocalStorage()) {
+ return false;
+ }
+ try {
+ windowAlias.localStorage.setItem(mod, mod);
+ windowAlias.localStorage.removeItem(mod);
+ return true;
+ } catch(e) {
+ return false;
+ }
+ };
+
+ /*
+ * Does browser have cookies enabled (for this site)?
+ */
+ object.hasCookies = function(testCookieName) {
+ var cookieName = testCookieName || 'testcookie';
+
+ if (isUndefined(navigatorAlias.cookieEnabled)) {
+ cookie.cookie(cookieName, '1');
+ return cookie.cookie(cookieName) === '1' ? '1' : '0';
+ }
+
+ return navigatorAlias.cookieEnabled ? '1' : '0';
+ };
+
+ /**
+ * JS Implementation for browser fingerprint.
+ * Does not require any external resources.
+ * Based on https://github.com/carlo/jquery-browser-fingerprint
+ * @return {number} 32-bit positive integer hash
+ */
+ object.detectSignature = function(hashSeed) {
+
+ var fingerprint = [
+ navigatorAlias.userAgent,
+ [ screenAlias.height, screenAlias.width, screenAlias.colorDepth ].join("x"),
+ ( new Date() ).getTimezoneOffset(),
+ object.hasSessionStorage(),
+ object.hasLocalStorage()
+ ];
+
+ var plugins = [];
+ if (navigatorAlias.plugins)
+ {
+ for(var i = 0; i < navigatorAlias.plugins.length; i++)
+ {
+ if (navigatorAlias.plugins[i]) {
+ var mt = [];
+ for(var j = 0; j < navigatorAlias.plugins[i].length; j++) {
+ mt.push([navigatorAlias.plugins[i][j].type, navigatorAlias.plugins[i][j].suffixes]);
+ }
+ plugins.push([navigatorAlias.plugins[i].name + "::" + navigatorAlias.plugins[i].description, mt.join("~")]);
+ }
+ }
+ }
+ return murmurhash3_32_gc(fingerprint.join("###") + "###" + plugins.sort().join(";"), hashSeed);
+ };
+
+ /*
+ * Returns visitor timezone
+ */
+ object.detectTimezone = function() {
+ return (typeof (tz) === 'undefined') ? '' : tz.name();
+ };
+
+ /**
+ * Gets the current viewport.
+ *
+ * Code based on:
+ * - http://andylangton.co.uk/articles/javascript/get-viewport-size-javascript/
+ * - http://responsejs.com/labs/dimensions/
+ */
+ object.detectViewport = function() {
+ var e = windowAlias, a = 'inner';
+ if (!('innerWidth' in windowAlias)) {
+ a = 'client';
+ e = documentAlias.documentElement || documentAlias.body;
+ }
+ var width = e[a+'Width'];
+ var height = e[a+'Height'];
+ if (width >= 0 && height >= 0) {
+ return width + 'x' + height;
+ } else {
+ return null;
+ }
+ };
+
+ /**
+ * Gets the dimensions of the current
+ * document.
+ *
+ * Code based on:
+ * - http://andylangton.co.uk/articles/javascript/get-viewport-size-javascript/
+ */
+ object.detectDocumentSize = function() {
+ var de = documentAlias.documentElement, // Alias
+ be = documentAlias.body,
+
+ // document.body may not have rendered, so check whether be.offsetHeight is null
+ bodyHeight = be ? Math.max(be.offsetHeight, be.scrollHeight) : 0;
+ var w = Math.max(de.clientWidth, de.offsetWidth, de.scrollWidth);
+ var h = Math.max(de.clientHeight, de.offsetHeight, de.scrollHeight, bodyHeight);
+ return isNaN(w) || isNaN(h) ? '' : w + 'x' + h;
+ };
+
+ /**
+ * Returns browser features (plugins, resolution, cookies)
+ *
+ * @param boolean useCookies Whether to test for cookies
+ * @param string testCookieName Name to use for the test cookie
+ * @return Object containing browser features
+ */
+ object.detectBrowserFeatures = function(useCookies, testCookieName) {
+ var i,
+ mimeType,
+ pluginMap = {
+ // document types
+ pdf: 'application/pdf',
+
+ // media players
+ qt: 'video/quicktime',
+ realp: 'audio/x-pn-realaudio-plugin',
+ wma: 'application/x-mplayer2',
+
+ // interactive multimedia
+ dir: 'application/x-director',
+ fla: 'application/x-shockwave-flash',
+
+ // RIA
+ java: 'application/x-java-vm',
+ gears: 'application/x-googlegears',
+ ag: 'application/x-silverlight'
+ },
+ features = {};
+
+ // General plugin detection
+ if (navigatorAlias.mimeTypes && navigatorAlias.mimeTypes.length) {
+ for (i in pluginMap) {
+ if (Object.prototype.hasOwnProperty.call(pluginMap, i)) {
+ mimeType = navigatorAlias.mimeTypes[pluginMap[i]];
+ features[i] = (mimeType && mimeType.enabledPlugin) ? '1' : '0';
+ }
+ }
+ }
+
+ // Safari and Opera
+ // IE6/IE7 navigator.javaEnabled can't be aliased, so test directly
+ if (navigatorAlias.constructor === window.Navigator &&
+ typeof navigatorAlias.javaEnabled !== 'unknown' &&
+ !isUndefined(navigatorAlias.javaEnabled) &&
+ navigatorAlias.javaEnabled()) {
+ features.java = '1';
+ }
+
+ // Firefox
+ if (isFunction(windowAlias.GearsFactory)) {
+ features.gears = '1';
+ }
+
+ // Other browser features
+ features.res = screenAlias.width + 'x' + screenAlias.height;
+ features.cd = screenAlias.colorDepth;
+ if (useCookies) {
+ features.cookie = object.hasCookies(testCookieName);
+ }
+
+ return features;
+ };
+
+}());
diff --git a/snowplow-javascript-tracker/src/js/lib/helpers.js b/snowplow-javascript-tracker/src/js/lib/helpers.js
new file mode 100755
index 0000000000..3a6a0b8b51
--- /dev/null
+++ b/snowplow-javascript-tracker/src/js/lib/helpers.js
@@ -0,0 +1,436 @@
+/*
+ * JavaScript tracker for Snowplow: Snowplow.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+;(function () {
+
+ var
+ isString = require('lodash/isString'),
+ isUndefined = require('lodash/isUndefined'),
+ isObject = require('lodash/isObject'),
+ map = require('lodash/map'),
+ cookie = require('browser-cookie-lite'),
+
+ object = typeof exports !== 'undefined' ? exports : this; // For eventual node.js environment support
+
+ /**
+ * Cleans up the page title
+ */
+ object.fixupTitle = function (title) {
+ if (!isString(title)) {
+ title = title.text || '';
+
+ var tmp = document.getElementsByTagName('title');
+ if (tmp && !isUndefined(tmp[0])) {
+ title = tmp[0].text;
+ }
+ }
+ return title;
+ };
+
+ /**
+ * Extract hostname from URL
+ */
+ object.getHostName = function (url) {
+ // scheme : // [username [: password] @] hostname [: port] [/ [path] [? query] [# fragment]]
+ var e = new RegExp('^(?:(?:https?|ftp):)/*(?:[^@]+@)?([^:/#]+)'),
+ matches = e.exec(url);
+
+ return matches ? matches[1] : url;
+ };
+
+ /**
+ * Fix-up domain
+ */
+ object.fixupDomain = function (domain) {
+ var dl = domain.length;
+
+ // remove trailing '.'
+ if (domain.charAt(--dl) === '.') {
+ domain = domain.slice(0, dl);
+ }
+ // remove leading '*'
+ if (domain.slice(0, 2) === '*.') {
+ domain = domain.slice(1);
+ }
+ return domain;
+ };
+
+ /**
+ * Get page referrer. In the case of a single-page app,
+ * if the URL changes without the page reloading, pass
+ * in the old URL. It will be returned unless overriden
+ * by a "refer(r)er" parameter in the querystring.
+ *
+ * @param string oldLocation Optional.
+ * @return string The referrer
+ */
+ object.getReferrer = function (oldLocation) {
+
+ var referrer = '';
+
+ var fromQs = object.fromQuerystring('referrer', window.location.href) ||
+ object.fromQuerystring('referer', window.location.href);
+
+ // Short-circuit
+ if (fromQs) {
+ return fromQs;
+ }
+
+ // In the case of a single-page app, return the old URL
+ if (oldLocation) {
+ return oldLocation;
+ }
+
+ try {
+ referrer = window.top.document.referrer;
+ } catch (e) {
+ if (window.parent) {
+ try {
+ referrer = window.parent.document.referrer;
+ } catch (e2) {
+ referrer = '';
+ }
+ }
+ }
+ if (referrer === '') {
+ referrer = document.referrer;
+ }
+ return referrer;
+ };
+
+ /**
+ * Cross-browser helper function to add event handler
+ */
+ object.addEventListener = function (element, eventType, eventHandler, useCapture) {
+ if (element.addEventListener) {
+ element.addEventListener(eventType, eventHandler, useCapture);
+ return true;
+ }
+ if (element.attachEvent) {
+ return element.attachEvent('on' + eventType, eventHandler);
+ }
+ element['on' + eventType] = eventHandler;
+ };
+
+ /**
+ * Return value from name-value pair in querystring
+ */
+ object.fromQuerystring = function (field, url) {
+ var match = new RegExp('^[^#]*[?&]' + field + '=([^]*)').exec(url);
+ if (!match) {
+ return null;
+ }
+ return decodeURIComponent(match[1].replace(/\+/g, ' '));
+ };
+
+ /*
+ * Find dynamic context generating functions and merge their results into the static contexts
+ * Combine an array of unchanging contexts with the result of a context-creating function
+ *
+ * @param {(object|function(...*): ?object)[]} dynamicOrStaticContexts Array of custom context Objects or custom context generating functions
+ * @param {...*} Parameters to pass to dynamic callbacks
+ */
+ object.resolveDynamicContexts = function (dynamicOrStaticContexts) {
+ let params = Array.prototype.slice.call(arguments, 1);
+ return map(dynamicOrStaticContexts, function(context) {
+ if (typeof context === 'function') {
+ try {
+ return context.apply(null, params);
+ } catch (e) {
+ //TODO: provide warning
+ }
+ } else {
+ return context;
+ }
+ });
+ };
+
+ /**
+ * Only log deprecation warnings if they won't cause an error
+ */
+ object.warn = function(message) {
+ if (typeof console !== 'undefined') {
+ console.warn('Snowplow: ' + message);
+ }
+ };
+
+ /**
+ * List the classes of a DOM element without using elt.classList (for compatibility with IE 9)
+ */
+ object.getCssClasses = function (elt) {
+ return elt.className.match(/\S+/g) || [];
+ };
+
+ /**
+ * Check whether an element has at least one class from a given list
+ */
+ function checkClass(elt, classList) {
+ var classes = object.getCssClasses(elt),
+ i;
+
+ for (i = 0; i < classes.length; i++) {
+ if (classList[classes[i]]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Convert a criterion object to a filter function
+ *
+ * @param object criterion Either {whitelist: [array of allowable strings]}
+ * or {blacklist: [array of allowable strings]}
+ * or {filter: function (elt) {return whether to track the element}
+ * @param boolean byClass Whether to whitelist/blacklist based on an element's classes (for forms)
+ * or name attribute (for fields)
+ */
+ object.getFilter = function (criterion, byClass) {
+
+ // If the criterion argument is not an object, add listeners to all elements
+ if (Array.isArray(criterion) || !isObject(criterion)) {
+ return function () {
+ return true;
+ };
+ }
+
+ if (criterion.hasOwnProperty('filter')) {
+ return criterion.filter;
+ } else {
+ var inclusive = criterion.hasOwnProperty('whitelist');
+ var specifiedClasses = criterion.whitelist || criterion.blacklist;
+ if (!Array.isArray(specifiedClasses)) {
+ specifiedClasses = [specifiedClasses];
+ }
+
+ // Convert the array of classes to an object of the form {class1: true, class2: true, ...}
+ var specifiedClassesSet = {};
+ for (var i=0; i= 0) {
+ var currentDomain = split.slice(position, split.length).join('.');
+ cookie.cookie(cookieName, cookieValue, 0, '/', currentDomain);
+ if (cookie.cookie(cookieName) === cookieValue) {
+
+ // Clean up created cookie(s)
+ object.deleteCookie(cookieName, currentDomain);
+ var cookieNames = object.getCookiesWithPrefix(cookiePrefix);
+ for (var i = 0; i < cookieNames.length; i++) {
+ object.deleteCookie(cookieNames[i], currentDomain);
+ }
+
+ return currentDomain;
+ }
+ position -= 1;
+ }
+
+ // Cookies cannot be read
+ return window.location.hostname;
+ };
+
+ /**
+ * Checks whether a value is present within an array
+ *
+ * @param val The value to check for
+ * @param array The array to check within
+ * @return boolean Whether it exists
+ */
+ object.isValueInArray = function (val, array) {
+ for (var i = 0; i < array.length; i++) {
+ if (array[i] === val) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ /**
+ * Deletes an arbitrary cookie by setting the expiration date to the past
+ *
+ * @param cookieName The name of the cookie to delete
+ * @param domainName The domain the cookie is in
+ */
+ object.deleteCookie = function (cookieName, domainName) {
+ cookie.cookie(cookieName, '', -1, '/', domainName);
+ };
+
+ /**
+ * Fetches the name of all cookies beginning with a certain prefix
+ *
+ * @param cookiePrefix The prefix to check for
+ * @return array The cookies that begin with the prefix
+ */
+ object.getCookiesWithPrefix = function (cookiePrefix) {
+ var cookies = document.cookie.split("; ");
+ var cookieNames = [];
+ for (var i = 0; i < cookies.length; i++) {
+ if (cookies[i].substring(0, cookiePrefix.length) === cookiePrefix) {
+ cookieNames.push(cookies[i]);
+ }
+ }
+ return cookieNames;
+ };
+
+ /**
+ * Parses an object and returns either the
+ * integer or undefined.
+ *
+ * @param obj The object to parse
+ * @return the result of the parse operation
+ */
+ object.parseInt = function (obj) {
+ var result = parseInt(obj);
+ return isNaN(result) ? undefined : result;
+ };
+
+ /**
+ * Parses an object and returns either the
+ * number or undefined.
+ *
+ * @param obj The object to parse
+ * @return the result of the parse operation
+ */
+ object.parseFloat = function (obj) {
+ var result = parseFloat(obj);
+ return isNaN(result) ? undefined : result;
+ }
+
+}());
diff --git a/snowplow-javascript-tracker/src/js/lib/proxies.js b/snowplow-javascript-tracker/src/js/lib/proxies.js
new file mode 100644
index 0000000000..ee7cefd294
--- /dev/null
+++ b/snowplow-javascript-tracker/src/js/lib/proxies.js
@@ -0,0 +1,101 @@
+/*
+ * JavaScript tracker for Snowplow: proxies.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+;(function(){
+
+ var
+ helpers = require('./helpers'),
+ object = typeof exports !== 'undefined' ? exports : this;
+
+ /*
+ * Test whether a string is an IP address
+ */
+ function isIpAddress(string) {
+ var IPRegExp = new RegExp('^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$');
+ return IPRegExp.test(string);
+ }
+
+ /*
+ * If the hostname is an IP address, look for text indicating
+ * that the page is cached by Yahoo
+ */
+ function isYahooCachedPage(hostName) {
+ var
+ initialDivText,
+ cachedIndicator;
+ if (isIpAddress(hostName)) {
+ try {
+ initialDivText = document.body.children[0].children[0].children[0].children[0].children[0].children[0].innerHTML;
+ cachedIndicator = 'You have reached the cached page for';
+ return initialDivText.slice(0, cachedIndicator.length) === cachedIndicator;
+ } catch (e) {
+ return false;
+ }
+ }
+ }
+
+ /*
+ * Extract parameter from URL
+ */
+ function getParameter(url, name) {
+ // scheme : // [username [: password] @] hostname [: port] [/ [path] [? query] [# fragment]]
+ var e = new RegExp('^(?:https?|ftp)(?::/*(?:[^?]+))([?][^#]+)'),
+ matches = e.exec(url),
+ result = helpers.fromQuerystring(name, matches[1]);
+
+ return result;
+ }
+
+ /*
+ * Fix-up URL when page rendered from search engine cache or translated page.
+ * TODO: it would be nice to generalise this and/or move into the ETL phase.
+ */
+ object.fixupUrl = function (hostName, href, referrer) {
+
+ if (hostName === 'translate.googleusercontent.com') { // Google
+ if (referrer === '') {
+ referrer = href;
+ }
+ href = getParameter(href, 'u');
+ hostName = helpers.getHostName(href);
+ } else if (hostName === 'cc.bingj.com' || // Bing
+ hostName === 'webcache.googleusercontent.com' || // Google
+ isYahooCachedPage(hostName)) { // Yahoo (via Inktomi 74.6.0.0/16)
+ href = document.links[0].href;
+ hostName = helpers.getHostName(href);
+ }
+ return [hostName, href, referrer];
+ };
+
+}());
diff --git a/snowplow-javascript-tracker/src/js/links.js b/snowplow-javascript-tracker/src/js/links.js
new file mode 100755
index 0000000000..c7b08feb14
--- /dev/null
+++ b/snowplow-javascript-tracker/src/js/links.js
@@ -0,0 +1,181 @@
+/*
+ * JavaScript tracker for Snowplow: links.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+var isUndefined = require('lodash/isUndefined'),
+ helpers = require('./lib/helpers'),
+ object = typeof exports !== 'undefined' ? exports : this;
+
+/**
+ * Object for handling automatic link tracking
+ *
+ * @param object core The tracker core
+ * @param string trackerId Unique identifier for the tracker instance, used to mark tracked links
+ * @param function contextAdder Function to add common contexts like PerformanceTiming to all events
+ * @return object linkTrackingManager instance
+ */
+object.getLinkTrackingManager = function (core, trackerId, contextAdder) {
+
+ // Filter function used to determine whether clicks on a link should be tracked
+ var linkTrackingFilter,
+
+ // Whether pseudo clicks are tracked
+ linkTrackingPseudoClicks,
+
+ // Whether to track the innerHTML of clicked links
+ linkTrackingContent,
+
+ // The context attached to link click events
+ linkTrackingContext,
+
+ // Internal state of the pseudo click handler
+ lastButton,
+ lastTarget;
+
+ /*
+ * Process clicks
+ */
+ function processClick(sourceElement, context) {
+
+ var parentElement,
+ tag,
+ elementId,
+ elementClasses,
+ elementTarget,
+ elementContent;
+
+ while ((parentElement = sourceElement.parentNode) !== null &&
+ !isUndefined(parentElement) && // buggy IE5.5
+ ((tag = sourceElement.tagName.toUpperCase()) !== 'A' && tag !== 'AREA')) {
+ sourceElement = parentElement;
+ }
+
+ if (!isUndefined(sourceElement.href)) {
+ // browsers, such as Safari, don't downcase hostname and href
+ var originalSourceHostName = sourceElement.hostname || helpers.getHostName(sourceElement.href),
+ sourceHostName = originalSourceHostName.toLowerCase(),
+ sourceHref = sourceElement.href.replace(originalSourceHostName, sourceHostName),
+ scriptProtocol = new RegExp('^(javascript|vbscript|jscript|mocha|livescript|ecmascript|mailto):', 'i');
+
+ // Ignore script pseudo-protocol links
+ if (!scriptProtocol.test(sourceHref)) {
+
+ elementId = sourceElement.id;
+ elementClasses = helpers.getCssClasses(sourceElement);
+ elementTarget = sourceElement.target;
+ elementContent = linkTrackingContent ? sourceElement.innerHTML : null;
+
+ // decodeUrl %xx
+ sourceHref = unescape(sourceHref);
+ core.trackLinkClick(sourceHref, elementId, elementClasses, elementTarget, elementContent, contextAdder(helpers.resolveDynamicContexts(context, sourceElement)));
+ }
+ }
+ }
+
+ /*
+ * Return function to handle click event
+ */
+ function getClickHandler(context) {
+ return function (evt) {
+ var button,
+ target;
+
+ evt = evt || window.event;
+ button = evt.which || evt.button;
+ target = evt.target || evt.srcElement;
+
+ // Using evt.type (added in IE4), we avoid defining separate handlers for mouseup and mousedown.
+ if (evt.type === 'click') {
+ if (target) {
+ processClick(target, context);
+ }
+ } else if (evt.type === 'mousedown') {
+ if ((button === 1 || button === 2) && target) {
+ lastButton = button;
+ lastTarget = target;
+ } else {
+ lastButton = lastTarget = null;
+ }
+ } else if (evt.type === 'mouseup') {
+ if (button === lastButton && target === lastTarget) {
+ processClick(target, context);
+ }
+ lastButton = lastTarget = null;
+ }
+ };
+ }
+
+ /*
+ * Add click listener to a DOM element
+ */
+ function addClickListener(element) {
+ if (linkTrackingPseudoClicks) {
+ // for simplicity and performance, we ignore drag events
+ helpers.addEventListener(element, 'mouseup', getClickHandler(linkTrackingContext), false);
+ helpers.addEventListener(element, 'mousedown', getClickHandler(linkTrackingContext), false);
+ } else {
+ helpers.addEventListener(element, 'click', getClickHandler(linkTrackingContext), false);
+ }
+ }
+
+ return {
+
+ /*
+ * Configures link click tracking: how to filter which links will be tracked,
+ * whether to use pseudo click tracking, and what context to attach to link_click events
+ */
+ configureLinkClickTracking: function (criterion, pseudoClicks, trackContent, context) {
+ linkTrackingContent = trackContent;
+ linkTrackingContext = context;
+ linkTrackingPseudoClicks = pseudoClicks;
+ linkTrackingFilter = helpers.getFilter(criterion, true);
+ },
+
+ /*
+ * Add click handlers to anchor and AREA elements, except those to be ignored
+ */
+ addClickListeners: function () {
+
+ var linkElements = document.links,
+ i;
+
+ for (i = 0; i < linkElements.length; i++) {
+ // Add a listener to link elements which pass the filter and aren't already tracked
+ if (linkTrackingFilter(linkElements[i]) && !linkElements[i][trackerId]) {
+ addClickListener(linkElements[i]);
+ linkElements[i][trackerId] = true;
+ }
+ }
+ }
+ };
+};
diff --git a/snowplow-javascript-tracker/src/js/out_queue.js b/snowplow-javascript-tracker/src/js/out_queue.js
new file mode 100644
index 0000000000..d780f8d1d1
--- /dev/null
+++ b/snowplow-javascript-tracker/src/js/out_queue.js
@@ -0,0 +1,369 @@
+/*
+ * JavaScript tracker for Snowplow: out_queue.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+;(function() {
+
+ var
+ mapValues = require('lodash/mapValues'),
+ isString = require('lodash/isString'),
+ map = require('lodash/map'),
+ localStorageAccessible = require('./lib/detectors').localStorageAccessible,
+ helpers = require('./lib/helpers'),
+ object = typeof exports !== 'undefined' ? exports : this; // For eventual node.js environment support
+
+ /**
+ * Object handling sending events to a collector.
+ * Instantiated once per tracker instance.
+ *
+ * @param string functionName The Snowplow function name (used to generate the localStorage key)
+ * @param string namespace The tracker instance's namespace (used to generate the localStorage key)
+ * @param object mutSnowplowState Gives the pageUnloadGuard a reference to the outbound queue
+ * so it can unload the page when all queues are empty
+ * @param boolean useLocalStorage Whether to use localStorage at all
+ * @param string eventMethod if null will use 'beacon' otherwise can be set to 'post', 'get', or 'beacon' to force.
+ * @param int bufferSize How many events to batch in localStorage before sending them all.
+ * Only applies when sending POST requests and when localStorage is available.
+ * @param int maxPostBytes Maximum combined size in bytes of the event JSONs in a POST request
+ * @param string postPath The path where events are to be posted
+ * @return object OutQueueManager instance
+ */
+ object.OutQueueManager = function (functionName, namespace, mutSnowplowState, useLocalStorage, eventMethod, postPath, bufferSize, maxPostBytes) {
+ var queueName,
+ executingQueue = false,
+ configCollectorUrl,
+ outQueue;
+
+ //Force to lower case if its a string
+ eventMethod = eventMethod.toLowerCase ? eventMethod.toLowerCase() : eventMethod;
+
+ // Use the Beacon API if eventMethod is set null, true, or 'beacon'.
+ var isBeaconRequested = (eventMethod === null) || (eventMethod === true) || (eventMethod === "beacon") || (eventMethod === "true");
+ // Fall back to POST or GET for browsers which don't support Beacon API
+ var isBeaconAvailable = Boolean(isBeaconRequested && navigator && navigator.sendBeacon);
+ var useBeacon = (isBeaconAvailable && isBeaconRequested);
+
+ // Use GET if specified
+ var isGetRequested = (eventMethod === "get");
+
+ // Use POST if specified
+ var isPostRequested = (eventMethod === "post");
+ // usePost acts like a catch all for POST methods - Beacon or XHR
+ var usePost = (isPostRequested || useBeacon) && !isGetRequested;
+ // Don't use POST for browsers which don't support CORS XMLHttpRequests (e.g. IE <= 9)
+ usePost = usePost && Boolean(window.XMLHttpRequest && ('withCredentials' in new XMLHttpRequest()));
+
+ // Resolve all options and capabilities and decide path
+ var path = usePost ? postPath : '/i';
+
+ bufferSize = (localStorageAccessible() && useLocalStorage && usePost && bufferSize) || 1;
+
+ // Different queue names for GET and POST since they are stored differently
+ queueName = ['snowplowOutQueue', functionName, namespace, usePost ? 'post2' : 'get'].join('_');
+
+ if (useLocalStorage) {
+ // Catch any JSON parse errors or localStorage that might be thrown
+ try {
+ // TODO: backward compatibility with the old version of the queue for POST requests
+ outQueue = JSON.parse(localStorage.getItem(queueName));
+ }
+ catch(e) {}
+ }
+
+ // Initialize to and empty array if we didn't get anything out of localStorage
+ if (!Array.isArray(outQueue)) {
+ outQueue = [];
+ }
+
+ // Used by pageUnloadGuard
+ mutSnowplowState.outQueues.push(outQueue);
+
+ if (usePost && bufferSize > 1) {
+ mutSnowplowState.bufferFlushers.push(function () {
+ if (!executingQueue) {
+ executeQueue();
+ }
+ });
+ }
+
+ /*
+ * Convert a dictionary to a querystring
+ * The context field is the last in the querystring
+ */
+ function getQuerystring(request) {
+ var querystring = '?',
+ lowPriorityKeys = {'co': true, 'cx': true},
+ firstPair = true;
+
+ for (var key in request) {
+ if (request.hasOwnProperty(key) && !(lowPriorityKeys.hasOwnProperty(key))) {
+ if (!firstPair) {
+ querystring += '&';
+ } else {
+ firstPair = false;
+ }
+ querystring += encodeURIComponent(key) + '=' + encodeURIComponent(request[key]);
+ }
+ }
+
+ for (var contextKey in lowPriorityKeys) {
+ if (request.hasOwnProperty(contextKey) && lowPriorityKeys.hasOwnProperty(contextKey)) {
+ querystring += '&' + contextKey + '=' + encodeURIComponent(request[contextKey]);
+ }
+ }
+
+ return querystring;
+ }
+
+ /*
+ * Convert numeric fields to strings to match payload_data schema
+ */
+ function getBody(request) {
+ var cleanedRequest = mapValues(request, function (v) {
+ return v.toString();
+ });
+ return {
+ evt: cleanedRequest,
+ bytes: getUTF8Length(JSON.stringify(cleanedRequest))
+ };
+ }
+
+ /**
+ * Count the number of bytes a string will occupy when UTF-8 encoded
+ * Taken from http://stackoverflow.com/questions/2848462/count-bytes-in-textarea-using-javascript/
+ *
+ * @param string s
+ * @return number Length of s in bytes when UTF-8 encoded
+ */
+ function getUTF8Length(s) {
+ var len = 0;
+ for (var i = 0; i < s.length; i++) {
+ var code = s.charCodeAt(i);
+ if (code <= 0x7f) {
+ len += 1;
+ } else if (code <= 0x7ff) {
+ len += 2;
+ } else if (code >= 0xd800 && code <= 0xdfff) {
+ // Surrogate pair: These take 4 bytes in UTF-8 and 2 chars in UCS-2
+ // (Assume next char is the other [valid] half and just skip it)
+ len += 4; i++;
+ } else if (code < 0xffff) {
+ len += 3;
+ } else {
+ len += 4;
+ }
+ }
+ return len;
+ }
+
+ /*
+ * Queue an image beacon for submission to the collector.
+ * If we're not processing the queue, we'll start.
+ */
+ function enqueueRequest (request, url) {
+
+ configCollectorUrl = url + path;
+ if (usePost) {
+ var body = getBody(request);
+ if (body.bytes >= maxPostBytes) {
+ helpers.warn("Event of size " + body.bytes + " is too long - the maximum size is " + maxPostBytes);
+ var xhr = initializeXMLHttpRequest(configCollectorUrl);
+ xhr.send(encloseInPayloadDataEnvelope(attachStmToEvent([body.evt])));
+ return;
+ } else {
+ outQueue.push(body);
+ }
+ } else {
+ outQueue.push(getQuerystring(request));
+ }
+ var savedToLocalStorage = false;
+ if (useLocalStorage) {
+ savedToLocalStorage = helpers.attemptWriteLocalStorage(queueName, JSON.stringify(outQueue));
+ }
+
+ if (!executingQueue && (!savedToLocalStorage || outQueue.length >= bufferSize)) {
+ executeQueue();
+ }
+ }
+
+ /*
+ * Run through the queue of image beacons, sending them one at a time.
+ * Stops processing when we run out of queued requests, or we get an error.
+ */
+ function executeQueue () {
+
+ // Failsafe in case there is some way for a bad value like "null" to end up in the outQueue
+ while (outQueue.length && typeof outQueue[0] !== 'string' && typeof outQueue[0] !== 'object') {
+ outQueue.shift();
+ }
+
+ if (outQueue.length < 1) {
+ executingQueue = false;
+ return;
+ }
+
+ // Let's check that we have a Url to ping
+ if (!isString(configCollectorUrl)) {
+ throw "No Snowplow collector configured, cannot track";
+ }
+
+ executingQueue = true;
+
+ var nextRequest = outQueue[0];
+
+ if (usePost) {
+
+ var xhr = initializeXMLHttpRequest(configCollectorUrl);
+
+ // Time out POST requests after 5 seconds
+ var xhrTimeout = setTimeout(function () {
+ xhr.abort();
+ executingQueue = false;
+ }, 5000);
+
+ function chooseHowManyToExecute(q) {
+ var numberToSend = 0;
+ var byteCount = 0;
+ while (numberToSend < q.length) {
+ byteCount += q[numberToSend].bytes;
+ if (byteCount >= maxPostBytes) {
+ break;
+ } else {
+ numberToSend += 1;
+ }
+ }
+ return numberToSend;
+ }
+
+ // Keep track of number of events to delete from queue
+ var numberToSend = chooseHowManyToExecute(outQueue);
+
+ xhr.onreadystatechange = function () {
+ if (xhr.readyState === 4 && xhr.status >= 200 && xhr.status < 400) {
+ for (var deleteCount = 0; deleteCount < numberToSend; deleteCount++) {
+ outQueue.shift();
+ }
+ if (useLocalStorage) {
+ helpers.attemptWriteLocalStorage(queueName, JSON.stringify(outQueue));
+ }
+ clearTimeout(xhrTimeout);
+ executeQueue();
+ } else if (xhr.readyState === 4 && xhr.status >= 400) {
+ clearTimeout(xhrTimeout);
+ executingQueue = false;
+ }
+ };
+
+ var batch = map(outQueue.slice(0, numberToSend), function (x) {
+ return x.evt;
+ });
+
+ if (batch.length > 0) {
+ var beaconStatus;
+
+ if (useBeacon) {
+ const headers = { type: 'application/json' };
+ const blob = new Blob([encloseInPayloadDataEnvelope(attachStmToEvent(batch))], headers);
+ beaconStatus = navigator.sendBeacon(configCollectorUrl, blob);
+ }
+ if (!useBeacon || !beaconStatus) {
+ xhr.send(encloseInPayloadDataEnvelope(attachStmToEvent(batch)));
+ }
+ }
+
+ } else {
+ var image = new Image(1, 1);
+
+ image.onload = function () {
+ outQueue.shift();
+ if (useLocalStorage) {
+ helpers.attemptWriteLocalStorage(queueName, JSON.stringify(outQueue));
+ }
+ executeQueue();
+ };
+
+ image.onerror = function () {
+ executingQueue = false;
+ };
+
+ image.src = configCollectorUrl + nextRequest.replace('?', '?stm=' + new Date().getTime() + '&');
+ }
+ }
+
+ /**
+ * Open an XMLHttpRequest for a given endpoint with the correct credentials and header
+ *
+ * @param string url The destination URL
+ * @return object The XMLHttpRequest
+ */
+ function initializeXMLHttpRequest(url) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('POST', url, true);
+ xhr.withCredentials = true;
+ xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
+ return xhr;
+ }
+
+ /**
+ * Enclose an array of events in a self-describing payload_data JSON string
+ *
+ * @param array events Batch of events
+ * @return string payload_data self-describing JSON
+ */
+ function encloseInPayloadDataEnvelope(events) {
+ return JSON.stringify({
+ schema: 'iglu:com.snowplowanalytics.snowplow/payload_data/jsonschema/1-0-4',
+ data: events
+ });
+ }
+
+ /**
+ * Attaches the STM field to outbound POST events.
+ *
+ * @param events the events to attach the STM to
+ */
+ function attachStmToEvent(events) {
+ var stm = new Date().getTime().toString();
+ for (var i = 0; i < events.length; i++) {
+ events[i]['stm'] = stm;
+ }
+ return events
+ }
+
+ return {
+ enqueueRequest: enqueueRequest,
+ executeQueue: executeQueue
+ };
+ };
+
+}());
diff --git a/snowplow-javascript-tracker/src/js/snowplow.js b/snowplow-javascript-tracker/src/js/snowplow.js
new file mode 100644
index 0000000000..008976a8f5
--- /dev/null
+++ b/snowplow-javascript-tracker/src/js/snowplow.js
@@ -0,0 +1,268 @@
+/*
+ * JavaScript tracker for Snowplow: snowplow.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*jslint browser:true, plusplus:true, vars:true, nomen:true, evil:true */
+/*global window */
+/*global unescape */
+/*global ActiveXObject */
+/*global _snaq:true */
+/*members encodeURIComponent, decodeURIComponent, getElementsByTagName,
+ shift, unshift,
+ addEventListener, attachEvent, removeEventListener, detachEvent,
+ cookie, domain, readyState, documentElement, doScroll, title, text,
+ location, top, document, referrer, parent, links, href, protocol, GearsFactory,
+ event, which, button, srcElement, type, target,
+ parentNode, tagName, hostname, className,
+ userAgent, cookieEnabled, platform, mimeTypes, enabledPlugin, javaEnabled,
+ XDomainRequest, XMLHttpRequest, ActiveXObject, open, setRequestHeader, onreadystatechange, setRequestHeader, send, readyState, status,
+ getTime, getTimeAlias, setTime, toGMTString, getHours, getMinutes, getSeconds,
+ toLowerCase, charAt, indexOf, lastIndexOf, split, slice, toUpperCase,
+ onload, src,
+ round, random,
+ exec,
+ res, width, height,
+ pdf, qt, realp, wma, dir, fla, java, gears, ag,
+ hook, getHook,
+ setCollectorCf, setCollectorUrl, setAppId,
+ setDownloadExtensions, addDownloadExtensions,
+ setDomains, setIgnoreClasses, setRequestMethod,
+ setReferrerUrl, setCustomUrl, setDocumentTitle,
+ setDownloadClasses, setLinkClasses,
+ discardHashTag,
+ setCookieNamePrefix, setCookieDomain, setCookiePath, setVisitorIdCookie,
+ setVisitorCookieTimeout, setSessionCookieTimeout, setReferralCookieTimeout,
+ doNotTrack, respectDoNotTrack, msDoNotTrack, getTimestamp, getCookieValue,
+ detectTimezone, detectViewport,
+ addListener, enableLinkTracking, enableActivityTracking, setLinkTrackingTimer,
+ enableDarkSocialTracking,
+ killFrame, redirectFile, setCountPreRendered,
+ trackLink, trackPageView, trackImpression,
+ addPlugin, getAsyncTracker
+*/
+
+;(function() {
+
+ // Load all our modules (at least until we fully modularize & remove grunt-concat)
+ var
+ uuid = require('uuid'),
+ forEach = require('lodash/forEach'),
+ filter = require('lodash/filter'),
+ helpers = require('./lib/helpers'),
+ queue = require('./in_queue'),
+ tracker = require('./tracker'),
+
+ object = typeof exports !== 'undefined' ? exports : this; // For eventual node.js environment support
+
+ object.Snowplow = function(asynchronousQueue, functionName) {
+
+ var
+ documentAlias = document,
+ windowAlias = window,
+
+ /* Tracker identifier with version */
+ version = 'js-' + '<%= pkg.version %>', // Update banner.js too
+
+ /* Contains four variables that are shared with tracker.js and must be passed by reference */
+ mutSnowplowState = {
+
+ /* List of request queues - one per Tracker instance */
+ outQueues: [],
+ bufferFlushers: [],
+
+ /* Time at which to stop blocking excecution */
+ expireDateTime: null,
+
+ /* DOM Ready */
+ hasLoaded: false,
+ registeredOnLoadHandlers: [],
+
+ /* pageViewId, which can changed by other trackers on page;
+ * initialized by tracker sent first event */
+ pageViewId: null
+ };
+
+ /************************************************************
+ * Private methods
+ ************************************************************/
+
+
+ /*
+ * Handle beforeunload event
+ *
+ * Subject to Safari's "Runaway JavaScript Timer" and
+ * Chrome V8 extension that terminates JS that exhibits
+ * "slow unload", i.e., calling getTime() > 1000 times
+ */
+ function beforeUnloadHandler() {
+ var now;
+
+ // Flush all POST queues
+ forEach(mutSnowplowState.bufferFlushers, function (flusher) {
+ flusher();
+ });
+
+ /*
+ * Delay/pause (blocks UI)
+ */
+ if (mutSnowplowState.expireDateTime) {
+ // the things we do for backwards compatibility...
+ // in ECMA-262 5th ed., we could simply use:
+ // while (Date.now() < mutSnowplowState.expireDateTime) { }
+ do {
+ now = new Date();
+ if (filter(mutSnowplowState.outQueues, function (queue) {
+ return queue.length > 0;
+ }).length === 0) {
+ break;
+ }
+ } while (now.getTime() < mutSnowplowState.expireDateTime);
+ }
+ }
+
+ /*
+ * Handler for onload event
+ */
+ function loadHandler() {
+ var i;
+
+ if (!mutSnowplowState.hasLoaded) {
+ mutSnowplowState.hasLoaded = true;
+ for (i = 0; i < mutSnowplowState.registeredOnLoadHandlers.length; i++) {
+ mutSnowplowState.registeredOnLoadHandlers[i]();
+ }
+ }
+ return true;
+ }
+
+ /*
+ * Add onload or DOM ready handler
+ */
+ function addReadyListener() {
+ var _timer;
+
+ if (documentAlias.addEventListener) {
+ helpers.addEventListener(documentAlias, 'DOMContentLoaded', function ready() {
+ documentAlias.removeEventListener('DOMContentLoaded', ready, false);
+ loadHandler();
+ });
+ } else if (documentAlias.attachEvent) {
+ documentAlias.attachEvent('onreadystatechange', function ready() {
+ if (documentAlias.readyState === 'complete') {
+ documentAlias.detachEvent('onreadystatechange', ready);
+ loadHandler();
+ }
+ });
+
+ if (documentAlias.documentElement.doScroll && windowAlias === windowAlias.top) {
+ (function ready() {
+ if (!mutSnowplowState.hasLoaded) {
+ try {
+ documentAlias.documentElement.doScroll('left');
+ } catch (error) {
+ setTimeout(ready, 0);
+ return;
+ }
+ loadHandler();
+ }
+ }());
+ }
+ }
+
+ // sniff for older WebKit versions
+ if ((new RegExp('WebKit')).test(navigator.userAgent)) {
+ _timer = setInterval(function () {
+ if (mutSnowplowState.hasLoaded || /loaded|complete/.test(documentAlias.readyState)) {
+ clearInterval(_timer);
+ loadHandler();
+ }
+ }, 10);
+ }
+
+ // fallback
+ helpers.addEventListener(windowAlias, 'load', loadHandler, false);
+ }
+
+ /************************************************************
+ * Public data and methods
+ ************************************************************/
+
+ windowAlias.Snowplow = {
+
+ /**
+ * Returns a Tracker object, configured with a
+ * CloudFront collector.
+ *
+ * @param string distSubdomain The subdomain on your CloudFront collector's distribution
+ */
+ getTrackerCf: function (distSubdomain) {
+ var t = new tracker.Tracker(functionName, '', version, mutSnowplowState, {});
+ t.setCollectorCf(distSubdomain);
+ return t;
+ },
+
+ /**
+ * Returns a Tracker object, configured with the
+ * URL to the collector to use.
+ *
+ * @param string rawUrl The collector URL minus protocol and /i
+ */
+ getTrackerUrl: function (rawUrl) {
+ var t = new tracker.Tracker(functionName, '', version, mutSnowplowState, {});
+ t.setCollectorUrl(rawUrl);
+ return t;
+ },
+
+ /**
+ * Get internal asynchronous tracker object
+ *
+ * @return Tracker
+ */
+ getAsyncTracker: function () {
+ return new tracker.Tracker(functionName, '', version, mutSnowplowState, {});
+ }
+ };
+
+ /************************************************************
+ * Constructor
+ ************************************************************/
+
+ // initialize the Snowplow singleton
+ helpers.addEventListener(windowAlias, 'beforeunload', beforeUnloadHandler, false);
+ addReadyListener();
+
+ // Now replace initialization array with queue manager object
+ return new queue.InQueueManager(tracker.Tracker, version, mutSnowplowState, asynchronousQueue, functionName);
+ };
+
+}());
diff --git a/snowplow-javascript-tracker/src/js/tracker.js b/snowplow-javascript-tracker/src/js/tracker.js
new file mode 100755
index 0000000000..e8b96feb84
--- /dev/null
+++ b/snowplow-javascript-tracker/src/js/tracker.js
@@ -0,0 +1,2739 @@
+/*
+ * JavaScript tracker for Snowplow: tracker.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2016 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+;(function() {
+
+ var
+ forEach = require('lodash/forEach'),
+ map = require('lodash/map'),
+ helpers = require('./lib/helpers'),
+ proxies = require('./lib/proxies'),
+ cookie = require('browser-cookie-lite'),
+ detectors = require('./lib/detectors'),
+ sha1 = require('sha1'),
+ links = require('./links'),
+ forms = require('./forms'),
+ errors = require('./errors'),
+ requestQueue = require('./out_queue'),
+ coreConstructor = require('snowplow-tracker-core').trackerCore,
+ productionize = require('./guard').productionize,
+ uuid = require('uuid'),
+
+ object = typeof exports !== 'undefined' ? exports : this; // For eventual node.js environment support
+
+ /**
+ * Snowplow Tracker class
+ *
+ * @param functionName global function name
+ * @param namespace The namespace of the tracker object
+ * @param version The current version of the JavaScript Tracker
+ * @param mutSnowplowState An object containing hasLoaded, registeredOnLoadHandlers, and expireDateTime
+ * Passed in by reference in case they are altered by snowplow.js
+ * @param argmap Optional dictionary of configuration options. Supported fields and their default values:
+ *
+ * 1. encodeBase64, true
+ * 2. cookieDomain, null
+ * 3. cookieName, '_sp_'
+ * 4. appId, ''
+ * 5. platform, 'web'
+ * 6. respectDoNotTrack, false
+ * 7. userFingerprintSeed, 123412414
+ * 8. pageUnloadTimer, 500
+ * 9. forceSecureTracker, false
+ * 10. forceUnsecureTracker, false
+ * 11. useLocalStorage, true
+ * 12. useCookies, true
+ * 13. sessionCookieTimeout, 1800
+ * 14. contexts, {}
+ * 15. eventMethod, 'beacon'
+ * 16. post, false *DEPRECATED use eventMethod instead*
+ * 17. postPath, null
+ * 18. bufferSize, 1
+ * 19. crossDomainLinker, false
+ * 20. maxPostBytes, 40000
+ * 21. discoverRootDomain, false
+ * 22. cookieLifetime, 63072000
+ * 23. stateStorageStrategy, 'cookieAndLocalStorage'
+ */
+ object.Tracker = function Tracker(functionName, namespace, version, mutSnowplowState, argmap) {
+
+ /************************************************************
+ * Private members
+ ************************************************************/
+
+ var argmap = argmap || {};
+
+ //use POST if that property is present on the argmap
+ if(argmap.hasOwnProperty('post')) {
+ argmap.eventMethod = argmap.post === true ? 'post' : 'get';
+ } else {
+ argmap.eventMethod = argmap.eventMethod || 'beacon'
+ }
+
+ var
+ // Tracker core
+ core = coreConstructor(true, function(payload) {
+ addBrowserData(payload);
+ sendRequest(payload, configTrackerPause);
+ }),
+
+ // Debug - whether to raise errors to console and log to console
+ // or silence all errors from public methods
+ debug = false,
+
+ // API functions of the tracker
+ apiMethods = {},
+
+ // Safe methods (i.e. ones that won't raise errors)
+ // These values should be guarded publicMethods
+ safeMethods = {},
+
+ // The client-facing methods returned from tracker IIFE
+ returnMethods = {},
+
+ // Aliases
+ documentAlias = document,
+ windowAlias = window,
+ navigatorAlias = navigator,
+
+ // Current URL and Referrer URL
+ locationArray = proxies.fixupUrl(documentAlias.domain, windowAlias.location.href, helpers.getReferrer()),
+ domainAlias = helpers.fixupDomain(locationArray[0]),
+ locationHrefAlias = locationArray[1],
+ configReferrerUrl = locationArray[2],
+
+ // Holder of the logPagePing interval
+ pagePingInterval,
+
+ customReferrer,
+
+ // Request method is always GET for Snowplow
+ configRequestMethod = 'GET',
+
+ // Platform defaults to web for this tracker
+ configPlatform = argmap.hasOwnProperty('platform') ? argmap.platform : 'web',
+
+ // Snowplow collector URL
+ configCollectorUrl,
+
+ // Custom path for post requests (to get around adblockers)
+ configPostPath = argmap.hasOwnProperty('postPath') ? argmap.postPath : '/com.snowplowanalytics.snowplow/tp2',
+
+ // Site ID
+ configTrackerSiteId = argmap.hasOwnProperty('appId') ? argmap.appId : '', // Updated for Snowplow
+
+ // Document URL
+ configCustomUrl,
+
+ // Document title
+ lastDocumentTitle = documentAlias.title,
+
+ // Custom title
+ lastConfigTitle,
+
+ // Maximum delay to wait for web bug image to be fetched (in milliseconds)
+ configTrackerPause = argmap.hasOwnProperty('pageUnloadTimer') ? argmap.pageUnloadTimer : 500,
+
+ // Whether appropriate values have been supplied to enableActivityTracking
+ activityTrackingEnabled = false,
+
+ // Minimum visit time after initial page view (in milliseconds)
+ configMinimumVisitTime,
+
+ // Recurring heart beat after initial ping (in milliseconds)
+ configHeartBeatTimer,
+
+ // Disallow hash tags in URL. TODO: Should this be set to true by default?
+ configDiscardHashTag,
+
+ // First-party cookie name prefix
+ configCookieNamePrefix = argmap.hasOwnProperty('cookieName') ? argmap.cookieName : '_sp_',
+
+ // First-party cookie domain
+ // User agent defaults to origin hostname
+ configCookieDomain = argmap.hasOwnProperty('cookieDomain') ? argmap.cookieDomain : null,
+
+ // First-party cookie path
+ // Default is user agent defined.
+ configCookiePath = '/',
+
+ // Do Not Track browser feature
+ dnt = navigatorAlias.doNotTrack || navigatorAlias.msDoNotTrack || windowAlias.doNotTrack,
+
+ // Do Not Track
+ configDoNotTrack = argmap.hasOwnProperty('respectDoNotTrack') ? argmap.respectDoNotTrack && (dnt === 'yes' || dnt === '1') : false,
+
+ // Opt out of cookie tracking
+ configOptOutCookie,
+
+ // Count sites which are pre-rendered
+ configCountPreRendered,
+
+ // Life of the visitor cookie (in seconds)
+ configVisitorCookieTimeout = argmap.hasOwnProperty('cookieLifetime') ? argmap.cookieLifetime : 63072000, // 2 years
+
+ // Life of the session cookie (in seconds)
+ configSessionCookieTimeout = argmap.hasOwnProperty('sessionCookieTimeout') ? argmap.sessionCookieTimeout : 1800, // 30 minutes
+
+ // Default hash seed for MurmurHash3 in detectors.detectSignature
+ configUserFingerprintHashSeed = argmap.hasOwnProperty('userFingerprintSeed') ? argmap.userFingerprintSeed : 123412414,
+
+ // Document character set
+ documentCharset = documentAlias.characterSet || documentAlias.charset,
+
+ // This forces the tracker to be HTTPS even if the page is not secure
+ forceSecureTracker = argmap.hasOwnProperty('forceSecureTracker') ? (argmap.forceSecureTracker === true) : false,
+
+ // This forces the tracker to be HTTP even if the page is secure
+ forceUnsecureTracker = !forceSecureTracker && argmap.hasOwnProperty('forceUnsecureTracker') ? (argmap.forceUnsecureTracker === true) : false,
+
+ // Whether to use localStorage to store events between sessions while offline
+ useLocalStorage = argmap.hasOwnProperty('useLocalStorage') ? (
+ helpers.warn('argmap.useLocalStorage is deprecated. ' +
+ 'Use argmap.stateStorageStrategy instead.'),
+ argmap.useLocalStorage
+ ) : true,
+
+ // Whether to use cookies
+ configUseCookies = argmap.hasOwnProperty('useCookies') ? (
+ helpers.warn(
+ 'argmap.useCookies is deprecated. Use argmap.stateStorageStrategy instead.'),
+ argmap.useCookies
+ ) : true,
+
+ // Strategy defining how to store the state: cookie, localStorage or none
+ configStateStorageStrategy = argmap.hasOwnProperty('stateStorageStrategy') ?
+ argmap.stateStorageStrategy : (!configUseCookies && !useLocalStorage ?
+ 'none' : (configUseCookies && useLocalStorage ?
+ 'cookieAndLocalStorage' : (configUseCookies ? 'cookie' : 'localStorage'))),
+
+ // Browser language (or Windows language for IE). Imperfect but CloudFront doesn't log the Accept-Language header
+ browserLanguage = navigatorAlias.userLanguage || navigatorAlias.language,
+
+ // Browser features via client-side data collection
+ browserFeatures = detectors.detectBrowserFeatures(
+ configStateStorageStrategy == 'cookie' ||
+ configStateStorageStrategy == 'cookieAndLocalStorage',
+ getSnowplowCookieName('testcookie')),
+
+ // Visitor fingerprint
+ userFingerprint = (argmap.userFingerprint === false) ? '' : detectors.detectSignature(configUserFingerprintHashSeed),
+
+ // Unique ID for the tracker instance used to mark links which are being tracked
+ trackerId = functionName + '_' + namespace,
+
+ // Guard against installing the activity tracker more than once per Tracker instance
+ activityTrackingInstalled = false,
+
+ // Last activity timestamp
+ lastActivityTime,
+
+ // The last time an event was fired on the page - used to invalidate session if cookies are disabled
+ lastEventTime = new Date().getTime(),
+
+ // How are we scrolling?
+ minXOffset,
+ maxXOffset,
+ minYOffset,
+ maxYOffset,
+
+ // Hash function
+ hash = sha1,
+
+ // Domain hash value
+ domainHash,
+
+ // Domain unique user ID
+ domainUserId,
+
+ // ID for the current session
+ memorizedSessionId,
+
+ // Index for the current session - kept in memory in case cookies are disabled
+ memorizedVisitCount = 1,
+
+ // Business-defined unique user ID
+ businessUserId,
+
+ // Ecommerce transaction data
+ // Will be committed, sent and emptied by a call to trackTrans.
+ ecommerceTransaction = ecommerceTransactionTemplate(),
+
+ // Manager for automatic link click tracking
+ linkTrackingManager = links.getLinkTrackingManager(core, trackerId, addCommonContexts),
+
+ // Manager for automatic form tracking
+ formTrackingManager = forms.getFormTrackingManager(core, trackerId, addCommonContexts),
+
+ // Manager for tracking unhandled exceptions
+ errorManager = errors.errorManager(core),
+
+ // Manager for local storage queue
+ outQueueManager = new requestQueue.OutQueueManager(
+ functionName,
+ namespace,
+ mutSnowplowState,
+ configStateStorageStrategy == 'localStorage' ||
+ configStateStorageStrategy == 'cookieAndLocalStorage',
+ argmap.eventMethod,
+ configPostPath,
+ argmap.bufferSize,
+ argmap.maxPostBytes || 40000),
+
+ // Flag to prevent the geolocation context being added multiple times
+ geolocationContextAdded = false,
+
+ // Set of contexts to be added to every event
+ autoContexts = argmap.contexts || {},
+
+ // Context to be added to every event
+ commonContexts = [],
+
+ // Enhanced Ecommerce Contexts to be added on every `trackEnhancedEcommerceAction` call
+ enhancedEcommerceContexts = [],
+
+ // Whether pageViewId should be regenerated after each trackPageView. Affect web_page context
+ preservePageViewId = false,
+
+ // Whether first trackPageView was fired and pageViewId should not be changed anymore until reload
+ pageViewSent = false;
+
+ if (argmap.hasOwnProperty('discoverRootDomain') && argmap.discoverRootDomain) {
+ configCookieDomain = helpers.findRootDomain();
+ }
+
+ if (autoContexts.gaCookies) {
+ commonContexts.push(getGaCookiesContext());
+ }
+
+ if (autoContexts.geolocation) {
+ enableGeolocationContext();
+ }
+
+ // Enable base 64 encoding for self-describing events and custom contexts
+ core.setBase64Encoding(argmap.hasOwnProperty('encodeBase64') ? argmap.encodeBase64 : true);
+
+ // Set up unchanging name-value pairs
+ core.setTrackerVersion(version);
+ core.setTrackerNamespace(namespace);
+ core.setAppId(configTrackerSiteId);
+ core.setPlatform(configPlatform);
+ core.setTimezone(detectors.detectTimezone());
+ core.addPayloadPair('lang', browserLanguage);
+ core.addPayloadPair('cs', documentCharset);
+
+ // Browser features. Cookies, color depth and resolution don't get prepended with f_ (because they're not optional features)
+ for (var i in browserFeatures) {
+ if (Object.prototype.hasOwnProperty.call(browserFeatures, i)) {
+ if (i === 'res' || i === 'cd' || i === 'cookie') {
+ core.addPayloadPair(i, browserFeatures[i]);
+ } else {
+ core.addPayloadPair('f_' + i, browserFeatures[i]);
+ }
+ }
+ }
+
+ /**
+ * Recalculate the domain, URL, and referrer
+ */
+ function refreshUrl() {
+ locationArray = proxies.fixupUrl(documentAlias.domain, windowAlias.location.href, helpers.getReferrer());
+
+ // If this is a single-page app and the page URL has changed, then:
+ // - if the new URL's querystring contains a "refer(r)er" parameter, use it as the referrer
+ // - otherwise use the old URL as the referer
+ if (locationArray[1] !== locationHrefAlias) {
+ configReferrerUrl = helpers.getReferrer(locationHrefAlias);
+ }
+
+ domainAlias = helpers.fixupDomain(locationArray[0]);
+ locationHrefAlias = locationArray[1];
+ }
+
+ /**
+ * Decorate the querystring of a single link
+ *
+ * @param event e The event targeting the link
+ */
+ function linkDecorationHandler() {
+ var tstamp = new Date().getTime();
+ if (this.href) {
+ this.href = helpers.decorateQuerystring(this.href, '_sp', domainUserId + '.' + tstamp);
+ }
+ }
+
+ /**
+ * Enable querystring decoration for links pasing a filter
+ * Whenever such a link is clicked on or navigated to via the keyboard,
+ * add "_sp={{duid}}.{{timestamp}}" to its querystring
+ *
+ * @param crossDomainLinker Function used to determine which links to decorate
+ */
+ function decorateLinks(crossDomainLinker) {
+ for (var i=0; i= 0) {
+ baseUrl = baseUrl.slice(0, i);
+ }
+ if ((i = baseUrl.lastIndexOf('/')) !== baseUrl.length - 1) {
+ baseUrl = baseUrl.slice(0, i + 1);
+ }
+
+ return baseUrl + url;
+ }
+
+ /*
+ * Send request
+ */
+ function sendRequest(request, delay) {
+ var now = new Date();
+
+ // Set to true if Opt-out cookie is defined
+ var toOptoutByCookie;
+ if (configOptOutCookie) {
+ toOptoutByCookie = !!cookie.cookie(configOptOutCookie);
+ } else {
+ toOptoutByCookie = false;
+ }
+
+ if (!(configDoNotTrack || toOptoutByCookie)) {
+ outQueueManager.enqueueRequest(request.build(), configCollectorUrl);
+ mutSnowplowState.expireDateTime = now.getTime() + delay;
+ }
+ }
+
+ /*
+ * Get cookie name with prefix and domain hash
+ */
+ function getSnowplowCookieName(baseName) {
+ return configCookieNamePrefix + baseName + '.' + domainHash;
+ }
+
+ /*
+ * Cookie getter.
+ */
+ function getSnowplowCookieValue(cookieName) {
+ var fullName = getSnowplowCookieName(cookieName);
+ if (configStateStorageStrategy == 'localStorage') {
+ return helpers.attemptGetLocalStorage(fullName);
+ } else if (configStateStorageStrategy == 'cookie' ||
+ configStateStorageStrategy == 'cookieAndLocalStorage') {
+ return cookie.cookie(fullName);
+ }
+ }
+
+ /*
+ * Update domain hash
+ */
+ function updateDomainHash() {
+ refreshUrl();
+ domainHash = hash((configCookieDomain || domainAlias) + (configCookiePath || '/')).slice(0, 4); // 4 hexits = 16 bits
+ }
+
+ /*
+ * Process all "activity" events.
+ * For performance, this function must have low overhead.
+ */
+ function activityHandler() {
+ var now = new Date();
+ lastActivityTime = now.getTime();
+ }
+
+ /*
+ * Process all "scroll" events.
+ */
+ function scrollHandler() {
+ updateMaxScrolls();
+ activityHandler();
+ }
+
+ /*
+ * Returns [pageXOffset, pageYOffset].
+ * Adapts code taken from: http://www.javascriptkit.com/javatutors/static2.shtml
+ */
+ function getPageOffsets() {
+ var iebody = (documentAlias.compatMode && documentAlias.compatMode !== "BackCompat") ?
+ documentAlias.documentElement :
+ documentAlias.body;
+ return [iebody.scrollLeft || windowAlias.pageXOffset, iebody.scrollTop || windowAlias.pageYOffset];
+ }
+
+ /*
+ * Quick initialization/reset of max scroll levels
+ */
+ function resetMaxScrolls() {
+ var offsets = getPageOffsets();
+
+ var x = offsets[0];
+ minXOffset = x;
+ maxXOffset = x;
+
+ var y = offsets[1];
+ minYOffset = y;
+ maxYOffset = y;
+ }
+
+ /*
+ * Check the max scroll levels, updating as necessary
+ */
+ function updateMaxScrolls() {
+ var offsets = getPageOffsets();
+
+ var x = offsets[0];
+ if (x < minXOffset) {
+ minXOffset = x;
+ } else if (x > maxXOffset) {
+ maxXOffset = x;
+ }
+
+ var y = offsets[1];
+ if (y < minYOffset) {
+ minYOffset = y;
+ } else if (y > maxYOffset) {
+ maxYOffset = y;
+ }
+ }
+
+ /*
+ * Prevents offsets from being decimal or NaN
+ * See https://github.com/snowplow/snowplow-javascript-tracker/issues/324
+ * TODO: the NaN check should be moved into the core
+ */
+ function cleanOffset(offset) {
+ var rounded = Math.round(offset);
+ if (!isNaN(rounded)) {
+ return rounded;
+ }
+ }
+
+ /*
+ * Sets or renews the session cookie
+ */
+ function setSessionCookie() {
+ var cookieName = getSnowplowCookieName('ses');
+ var cookieValue = '*';
+ setCookie(cookieName, cookieValue, configSessionCookieTimeout);
+ }
+
+ /*
+ * Sets the Visitor ID cookie: either the first time loadDomainUserIdCookie is called
+ * or when there is a new visit or a new page view
+ */
+ function setDomainUserIdCookie(_domainUserId, createTs, visitCount, nowTs, lastVisitTs, sessionId) {
+ var cookieName = getSnowplowCookieName('id');
+ var cookieValue = _domainUserId + '.' + createTs + '.' + visitCount + '.' + nowTs +
+ '.' + lastVisitTs + '.' + sessionId;
+ setCookie(cookieName, cookieValue, configVisitorCookieTimeout);
+ }
+
+ /*
+ * Sets a cookie based on the storage strategy:
+ * - if 'localStorage': attemps to write to local storage
+ * - if 'cookie': writes to cookies
+ * - otherwise: no-op
+ */
+ function setCookie(name, value, timeout) {
+ if (configStateStorageStrategy == 'localStorage') {
+ helpers.attemptWriteLocalStorage(name, value);
+ } else if (configStateStorageStrategy == 'cookie' ||
+ configStateStorageStrategy == 'cookieAndLocalStorage') {
+ cookie.cookie(name, value, timeout, configCookiePath, configCookieDomain);
+ }
+ }
+
+ /**
+ * Generate a pseudo-unique ID to fingerprint this user
+ */
+ function createNewDomainUserId() {
+ return uuid.v4();
+ }
+
+ /*
+ * Load the domain user ID and the session ID
+ * Set the cookies (if cookies are enabled)
+ */
+ function initializeIdsAndCookies() {
+ var sesCookieSet =
+ configStateStorageStrategy != 'none' && !!getSnowplowCookieValue('ses');
+ var idCookieComponents = loadDomainUserIdCookie();
+
+ if (idCookieComponents[1]) {
+ domainUserId = idCookieComponents[1];
+ } else {
+ domainUserId = createNewDomainUserId();
+ idCookieComponents[1] = domainUserId;
+ }
+
+ memorizedSessionId = idCookieComponents[6];
+
+ if (!sesCookieSet) {
+ // Increment the session ID
+ idCookieComponents[3] ++;
+ // Create a new sessionId
+ memorizedSessionId = uuid.v4();
+ idCookieComponents[6] = memorizedSessionId;
+ // Set lastVisitTs to currentVisitTs
+ idCookieComponents[5] = idCookieComponents[4];
+ }
+
+ if (configStateStorageStrategy != 'none') {
+ setSessionCookie();
+ // Update currentVisitTs
+ idCookieComponents[4] = Math.round(new Date().getTime() / 1000);
+ idCookieComponents.shift();
+ setDomainUserIdCookie.apply(null, idCookieComponents);
+ }
+ }
+
+ /*
+ * Load visitor ID cookie
+ */
+ function loadDomainUserIdCookie() {
+ if (configStateStorageStrategy == 'none') {
+ return [];
+ }
+ var now = new Date(),
+ nowTs = Math.round(now.getTime() / 1000),
+ id = getSnowplowCookieValue('id'),
+ tmpContainer;
+
+ if (id) {
+ tmpContainer = id.split('.');
+ // cookies enabled
+ tmpContainer.unshift('0');
+ } else {
+
+ tmpContainer = [
+ // cookies disabled
+ '1',
+ // Domain user ID
+ domainUserId,
+ // Creation timestamp - seconds since Unix epoch
+ nowTs,
+ // visitCount - 0 = no previous visit
+ 0,
+ // Current visit timestamp
+ nowTs,
+ // Last visit timestamp - blank meaning no previous visit
+ ''
+ ];
+ }
+
+ if (!tmpContainer[6]) {
+ // session id
+ tmpContainer[6] = uuid.v4();
+ }
+
+ return tmpContainer;
+ }
+
+ /*
+ * Attaches common web fields to every request
+ * (resolution, url, referrer, etc.)
+ * Also sets the required cookies.
+ */
+ function addBrowserData(sb) {
+ var nowTs = Math.round(new Date().getTime() / 1000),
+ idname = getSnowplowCookieName('id'),
+ sesname = getSnowplowCookieName('ses'),
+ ses = getSnowplowCookieValue('ses'),
+ id = loadDomainUserIdCookie(),
+ cookiesDisabled = id[0],
+ _domainUserId = id[1], // We could use the global (domainUserId) but this is better etiquette
+ createTs = id[2],
+ visitCount = id[3],
+ currentVisitTs = id[4],
+ lastVisitTs = id[5],
+ sessionIdFromCookie = id[6];
+
+ var toOptoutByCookie;
+ if (configOptOutCookie) {
+ toOptoutByCookie = !!cookie.cookie(configOptOutCookie);
+ } else {
+ toOptoutByCookie = false;
+ }
+
+
+ if ((configDoNotTrack || toOptoutByCookie) &&
+ configStateStorageStrategy != 'none') {
+ if (configStateStorageStrategy == 'localStorage') {
+ helpers.attemptWriteLocalStorage(idname, '');
+ helpers.attemptWriteLocalStorage(sesname, '');
+ } else if (configStateStorageStrategy == 'cookie' ||
+ configStateStorageStrategy == 'cookieAndLocalStorage') {
+ cookie.cookie(idname, '', -1, configCookiePath, configCookieDomain);
+ cookie.cookie(sesname, '', -1, configCookiePath, configCookieDomain);
+ }
+ return;
+ }
+
+ // If cookies are enabled, base visit count and session ID on the cookies
+ if (cookiesDisabled === '0') {
+ memorizedSessionId = sessionIdFromCookie;
+
+ // New session?
+ if (!ses && configStateStorageStrategy != 'none') {
+ // New session (aka new visit)
+ visitCount++;
+ // Update the last visit timestamp
+ lastVisitTs = currentVisitTs;
+ // Regenerate the session ID
+ memorizedSessionId = uuid.v4();
+ }
+
+ memorizedVisitCount = visitCount;
+
+ // Otherwise, a new session starts if configSessionCookieTimeout seconds have passed since the last event
+ } else {
+ if ((new Date().getTime() - lastEventTime) > configSessionCookieTimeout * 1000) {
+ memorizedSessionId = uuid.v4();
+ memorizedVisitCount++;
+ }
+ }
+
+ // Build out the rest of the request
+ sb.add('vp', detectors.detectViewport());
+ sb.add('ds', detectors.detectDocumentSize());
+ sb.add('vid', memorizedVisitCount);
+ sb.add('sid', memorizedSessionId);
+ sb.add('duid', _domainUserId); // Set to our local variable
+ sb.add('fp', userFingerprint);
+ sb.add('uid', businessUserId);
+
+ refreshUrl();
+
+ sb.add('refr', purify(customReferrer || configReferrerUrl));
+
+ // Add the page URL last as it may take us over the IE limit (and we don't always need it)
+ sb.add('url', purify(configCustomUrl || locationHrefAlias));
+
+ // Update cookies
+ if (configStateStorageStrategy != 'none') {
+ setDomainUserIdCookie(_domainUserId, createTs, memorizedVisitCount, nowTs,
+ lastVisitTs, memorizedSessionId);
+ setSessionCookie();
+ }
+
+ lastEventTime = new Date().getTime();
+ }
+
+ /**
+ * Builds a collector URL from a CloudFront distribution.
+ * We don't bother to support custom CNAMEs because Amazon CloudFront doesn't support that for SSL.
+ *
+ * @param string account The account ID to build the tracker URL from
+ *
+ * @return string The URL on which the collector is hosted
+ */
+ function collectorUrlFromCfDist(distSubdomain) {
+ return asCollectorUrl(distSubdomain + '.cloudfront.net');
+ }
+
+ /**
+ * Adds the protocol in front of our collector URL, and i to the end
+ *
+ * @param string rawUrl The collector URL without protocol
+ *
+ * @return string collectorUrl The tracker URL with protocol
+ */
+ function asCollectorUrl(rawUrl) {
+ if (forceSecureTracker) {
+ return ('https' + '://' + rawUrl);
+ }
+ if (forceUnsecureTracker) {
+ return ('http' + '://' + rawUrl);
+ }
+ return ('https:' === documentAlias.location.protocol ? 'https' : 'http') + '://' + rawUrl;
+ }
+
+ /**
+ * Add common contexts to every event
+ * TODO: move this functionality into the core
+ *
+ * @param array userContexts List of user-defined contexts
+ * @return userContexts combined with commonContexts
+ */
+ function addCommonContexts(userContexts) {
+ var combinedContexts = commonContexts.concat(userContexts || []);
+
+ if (autoContexts.webPage) {
+ combinedContexts.push(getWebPageContext());
+ }
+
+ // Add PerformanceTiming Context
+ if (autoContexts.performanceTiming) {
+ var performanceTimingContext = getPerformanceTimingContext();
+ if (performanceTimingContext) {
+ combinedContexts.push(performanceTimingContext);
+ }
+ }
+
+ // Add Optimizely Contexts
+ if (windowAlias.optimizely) {
+
+ if (autoContexts.optimizelySummary) {
+ var activeExperiments = getOptimizelySummaryContexts();
+ forEach(activeExperiments, function (e) {
+ combinedContexts.push(e)
+ })
+ }
+
+ if (autoContexts.optimizelyXSummary) {
+ var activeExperiments = getOptimizelyXSummaryContexts();
+ forEach(activeExperiments, function (e) {
+ combinedContexts.push(e);
+ })
+ }
+
+ if (autoContexts.optimizelyExperiments) {
+ var experimentContexts = getOptimizelyExperimentContexts();
+ for (var i = 0; i < experimentContexts.length; i++) {
+ combinedContexts.push(experimentContexts[i]);
+ }
+ }
+
+ if (autoContexts.optimizelyStates) {
+ var stateContexts = getOptimizelyStateContexts();
+ for (var i = 0; i < stateContexts.length; i++) {
+ combinedContexts.push(stateContexts[i]);
+ }
+ }
+
+ if (autoContexts.optimizelyVariations) {
+ var variationContexts = getOptimizelyVariationContexts();
+ for (var i = 0; i < variationContexts.length; i++) {
+ combinedContexts.push(variationContexts[i]);
+ }
+ }
+
+ if (autoContexts.optimizelyVisitor) {
+ var optimizelyVisitorContext = getOptimizelyVisitorContext();
+ if (optimizelyVisitorContext) {
+ combinedContexts.push(optimizelyVisitorContext);
+ }
+ }
+
+ if (autoContexts.optimizelyAudiences) {
+ var audienceContexts = getOptimizelyAudienceContexts();
+ for (var i = 0; i < audienceContexts.length; i++) {
+ combinedContexts.push(audienceContexts[i]);
+ }
+ }
+
+ if (autoContexts.optimizelyDimensions) {
+ var dimensionContexts = getOptimizelyDimensionContexts();
+ for (var i = 0; i < dimensionContexts.length; i++) {
+ combinedContexts.push(dimensionContexts[i]);
+ }
+ }
+ }
+
+ // Add Augur Context
+ if (autoContexts.augurIdentityLite) {
+ var augurIdentityLiteContext = getAugurIdentityLiteContext();
+ if (augurIdentityLiteContext) {
+ combinedContexts.push(augurIdentityLiteContext);
+ }
+ }
+
+ //Add Parrable Context
+ if (autoContexts.parrable) {
+ var parrableContext = getParrableContext();
+ if (parrableContext) {
+ combinedContexts.push(parrableContext);
+ }
+ }
+ return combinedContexts;
+ }
+
+ /**
+ * Initialize new `pageViewId` if it shouldn't be preserved.
+ * Should be called when `trackPageView` is invoked
+ */
+ function resetPageView() {
+ if (!preservePageViewId || mutSnowplowState.pageViewId == null) {
+ mutSnowplowState.pageViewId = uuid.v4();
+ }
+ }
+
+ /**
+ * Safe function to get `pageViewId`.
+ * Generates it if it wasn't initialized by other tracker
+ */
+ function getPageViewId() {
+ if (mutSnowplowState.pageViewId == null) {
+ mutSnowplowState.pageViewId = uuid.v4();
+ }
+ return mutSnowplowState.pageViewId
+ }
+
+ /**
+ * Put together a web page context with a unique UUID for the page view
+ *
+ * @return object web_page context
+ */
+ function getWebPageContext() {
+ return {
+ schema: 'iglu:com.snowplowanalytics.snowplow/web_page/jsonschema/1-0-0',
+ data: {
+ id: getPageViewId()
+ }
+ };
+ }
+
+ /**
+ * Creates a context from the window.performance.timing object
+ *
+ * @return object PerformanceTiming context
+ */
+ function getPerformanceTimingContext() {
+ var allowedKeys = [
+ 'navigationStart', 'redirectStart', 'redirectEnd', 'fetchStart', 'domainLookupStart', 'domainLookupEnd', 'connectStart',
+ 'secureConnectionStart', 'connectEnd', 'requestStart', 'responseStart', 'responseEnd', 'unloadEventStart', 'unloadEventEnd',
+ 'domLoading', 'domInteractive', 'domContentLoadedEventStart', 'domContentLoadedEventEnd', 'domComplete', 'loadEventStart',
+ 'loadEventEnd', 'msFirstPaint', 'chromeFirstPaint', 'requestEnd', 'proxyStart', 'proxyEnd'
+ ];
+ var performance = windowAlias.performance || windowAlias.mozPerformance || windowAlias.msPerformance || windowAlias.webkitPerformance;
+ if (performance) {
+
+ // On Safari, the fields we are interested in are on the prototype chain of
+ // performance.timing so we cannot copy them using lodash.clone
+ var performanceTiming = {};
+ for (var field in performance.timing) {
+ if (helpers.isValueInArray(field, allowedKeys) && (performance.timing[field] !== null)) {
+ performanceTiming[field] = performance.timing[field];
+ }
+ }
+
+ // Old Chrome versions add an unwanted requestEnd field
+ delete performanceTiming.requestEnd;
+
+ // Add the Chrome firstPaintTime to the performance if it exists
+ if (windowAlias.chrome && windowAlias.chrome.loadTimes && typeof windowAlias.chrome.loadTimes().firstPaintTime === 'number') {
+ performanceTiming.chromeFirstPaint = Math.round(windowAlias.chrome.loadTimes().firstPaintTime * 1000);
+ }
+
+ return {
+ schema: 'iglu:org.w3/PerformanceTiming/jsonschema/1-0-0',
+ data: performanceTiming
+ };
+ }
+ }
+
+ /**
+ * Check that *both* optimizely and optimizely.data exist and return
+ * optimizely.data.property
+ *
+ * @param property optimizely data property
+ * @param snd optional nested property
+ */
+ function getOptimizelyData(property, snd) {
+ var data;
+ if (windowAlias.optimizely && windowAlias.optimizely.data) {
+ data = windowAlias.optimizely.data[property];
+ if (typeof snd !== 'undefined' && data !== undefined) {
+ data = data[snd]
+ }
+ }
+ return data
+ }
+
+ /**
+ * Check that *both* optimizely and optimizely.data exist
+ *
+ * @param property optimizely data property
+ * @param snd optional nested property
+ */
+ function getOptimizelyXData(property, snd) {
+ var data;
+ if (windowAlias.optimizely) {
+ data = windowAlias.optimizely.get(property);
+ if (typeof snd !== 'undefined' && data !== undefined) {
+ data = data[snd]
+ }
+ }
+ return data
+ }
+
+ /**
+ * Get data for Optimizely "lite" contexts - active experiments on current page
+ *
+ * @returns Array content of lite optimizely lite context
+ */
+ function getOptimizelySummary() {
+ var state = getOptimizelyData('state');
+ var experiments = getOptimizelyData('experiments');
+
+ return map(state && experiments && state.activeExperiments, function (activeExperiment) {
+ var current = experiments[activeExperiment];
+ return {
+ activeExperimentId: activeExperiment.toString(),
+ // User can be only in one variation (don't know why is this array)
+ variation: state.variationIdsMap[activeExperiment][0].toString(),
+ conditional: current && current.conditional,
+ manual: current && current.manual,
+ name: current && current.name
+ }
+ });
+ }
+
+ /**
+ * Get data for OptimizelyX contexts - active experiments on current page
+ *
+ * @returns Array content of lite optimizely lite context
+ */
+ function getOptimizelyXSummary() {
+ var state = getOptimizelyXData('state');
+ var experiment_ids = state.getActiveExperimentIds();
+ var experiments = getOptimizelyXData('data', 'experiments');
+ var visitor = getOptimizelyXData('visitor');
+
+ return map(experiment_ids, function(activeExperiment) {
+ variation = state.getVariationMap()[activeExperiment];
+ variationName = variation.name;
+ variationId = variation.id;
+ visitorId = visitor.visitorId;
+ return {
+ experimentId: parseInt(activeExperiment),
+ variationName: variationName,
+ variation: parseInt(variationId),
+ visitorId: visitorId
+ }
+ })
+ }
+
+ /**
+ * Creates a context from the window['optimizely'].data.experiments object
+ *
+ * @return Array Experiment contexts
+ */
+ function getOptimizelyExperimentContexts() {
+ var experiments = getOptimizelyData('experiments');
+ if (experiments) {
+ var contexts = [];
+
+ for (var key in experiments) {
+ if (experiments.hasOwnProperty(key)) {
+ var context = {};
+ context.id = key;
+ var experiment = experiments[key];
+ context.code = experiment.code;
+ context.manual = experiment.manual;
+ context.conditional = experiment.conditional;
+ context.name = experiment.name;
+ context.variationIds = experiment.variation_ids;
+
+ contexts.push({
+ schema: 'iglu:com.optimizely/experiment/jsonschema/1-0-0',
+ data: context
+ });
+ }
+ }
+ return contexts;
+ }
+ return [];
+ }
+
+ /**
+ * Creates a context from the window['optimizely'].data.state object
+ *
+ * @return Array State contexts
+ */
+ function getOptimizelyStateContexts() {
+ var experimentIds = [];
+ var experiments = getOptimizelyData('experiments');
+ if (experiments) {
+ for (var key in experiments) {
+ if (experiments.hasOwnProperty(key)) {
+ experimentIds.push(key);
+ }
+ }
+ }
+
+ var state = getOptimizelyData('state');
+ if (state) {
+ var contexts = [];
+ var activeExperiments = state.activeExperiments || [];
+
+ for (var i = 0; i < experimentIds.length; i++) {
+ var experimentId = experimentIds[i];
+ var context = {};
+ context.experimentId = experimentId;
+ context.isActive = helpers.isValueInArray(experimentIds[i], activeExperiments);
+ var variationMap = state.variationMap || {};
+ context.variationIndex = variationMap[experimentId];
+ var variationNamesMap = state.variationNamesMap || {};
+ context.variationName = variationNamesMap[experimentId];
+ var variationIdsMap = state.variationIdsMap || {};
+ if (variationIdsMap[experimentId] && variationIdsMap[experimentId].length === 1) {
+ context.variationId = variationIdsMap[experimentId][0];
+ }
+
+ contexts.push({
+ schema: 'iglu:com.optimizely/state/jsonschema/1-0-0',
+ data: context
+ });
+ }
+ return contexts;
+ }
+ return [];
+ }
+
+ /**
+ * Creates a context from the window['optimizely'].data.variations object
+ *
+ * @return Array Variation contexts
+ */
+ function getOptimizelyVariationContexts() {
+ var variations = getOptimizelyData('variations');
+ if (variations) {
+ var contexts = [];
+
+ for (var key in variations) {
+ if (variations.hasOwnProperty(key)) {
+ var context = {};
+ context.id = key;
+ var variation = variations[key];
+ context.name = variation.name;
+ context.code = variation.code;
+
+ contexts.push({
+ schema: 'iglu:com.optimizely/variation/jsonschema/1-0-0',
+ data: context
+ });
+ }
+ }
+ return contexts;
+ }
+ return [];
+ }
+
+ /**
+ * Creates a context from the window['optimizely'].data.visitor object
+ *
+ * @return object Visitor context
+ */
+ function getOptimizelyVisitorContext() {
+ var visitor = getOptimizelyData('visitor');
+ if (visitor) {
+ var context = {};
+ context.browser = visitor.browser;
+ context.browserVersion = visitor.browserVersion;
+ context.device = visitor.device;
+ context.deviceType = visitor.deviceType;
+ context.ip = visitor.ip;
+ var platform = visitor.platform || {};
+ context.platformId = platform.id;
+ context.platformVersion = platform.version;
+ var location = visitor.location || {};
+ context.locationCity = location.city;
+ context.locationRegion = location.region;
+ context.locationCountry = location.country;
+ context.mobile = visitor.mobile;
+ context.mobileId = visitor.mobileId;
+ context.referrer = visitor.referrer;
+ context.os = visitor.os;
+
+ return {
+ schema: 'iglu:com.optimizely/visitor/jsonschema/1-0-0',
+ data: context
+ };
+ }
+ }
+
+ /**
+ * Creates a context from the window['optimizely'].data.visitor.audiences object
+ *
+ * @return Array VisitorAudience contexts
+ */
+ function getOptimizelyAudienceContexts() {
+ var audienceIds = getOptimizelyData('visitor', 'audiences');
+ if (audienceIds) {
+ var contexts = [];
+
+ for (var key in audienceIds) {
+ if (audienceIds.hasOwnProperty(key)) {
+ var context = { id: key, isMember: audienceIds[key] };
+
+ contexts.push({
+ schema: 'iglu:com.optimizely/visitor_audience/jsonschema/1-0-0',
+ data: context
+ });
+ }
+ }
+ return contexts;
+ }
+ return [];
+ }
+
+ /**
+ * Creates a context from the window['optimizely'].data.visitor.dimensions object
+ *
+ * @return Array VisitorDimension contexts
+ */
+ function getOptimizelyDimensionContexts() {
+ var dimensionIds = getOptimizelyData('visitor', 'dimensions');
+ if (dimensionIds) {
+ var contexts = [];
+
+ for (var key in dimensionIds) {
+ if (dimensionIds.hasOwnProperty(key)) {
+ var context = { id: key, value: dimensionIds[key] };
+
+ contexts.push({
+ schema: 'iglu:com.optimizely/visitor_dimension/jsonschema/1-0-0',
+ data: context
+ });
+ }
+ }
+ return contexts;
+ }
+ return [];
+ }
+
+
+ /**
+ * Creates an Optimizely lite context containing only data required to join
+ * event to experiment data
+ *
+ * @returns Array of custom contexts
+ */
+ function getOptimizelySummaryContexts() {
+ return map(getOptimizelySummary(), function (experiment) {
+ return {
+ schema: 'iglu:com.optimizely.snowplow/optimizely_summary/jsonschema/1-0-0',
+ data: experiment
+ };
+ });
+ }
+
+ /**
+ * Creates an OptimizelyX context containing only data required to join
+ * event to experiment data
+ *
+ * @returns Array of custom contexts
+ */
+ function getOptimizelyXSummaryContexts() {
+ return map(getOptimizelyXSummary(), function (experiment) {
+ return {
+ schema: 'iglu:com.optimizely.optimizelyx/summary/jsonschema/1-0-0',
+ data: experiment
+ };
+ });
+ }
+
+ /**
+ * Creates a context from the window['augur'] object
+ *
+ * @return object The IdentityLite context
+ */
+ function getAugurIdentityLiteContext() {
+ var augur = windowAlias.augur;
+ if (augur) {
+ var context = { consumer: {}, device: {} };
+ var consumer = augur.consumer || {};
+ context.consumer.UUID = consumer.UID;
+ var device = augur.device || {};
+ context.device.ID = device.ID;
+ context.device.isBot = device.isBot;
+ context.device.isProxied = device.isProxied;
+ context.device.isTor = device.isTor;
+ var fingerprint = device.fingerprint || {};
+ context.device.isIncognito = fingerprint.browserHasIncognitoEnabled;
+
+ return {
+ schema: 'iglu:io.augur.snowplow/identity_lite/jsonschema/1-0-0',
+ data: context
+ };
+ }
+ }
+
+ /**
+ * Creates a context from the window['_hawk'] object
+ *
+ * @return object The Parrable context
+ */
+ function getParrableContext() {
+ var parrable = window['_hawk'];
+ if (parrable) {
+ var context = { encryptedId: null, optout: null };
+ context['encryptedId'] = parrable.browserid;
+ var regex = new RegExp('(?:^|;)\\s?' + "_parrable_hawk_optout".replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1') + '=(.*?)(?:;|$)', 'i'), match = document.cookie.match(regex);
+ context['optout'] = (match && decodeURIComponent(match[1])) ? match && decodeURIComponent(match[1]) : "false";
+ return {
+ schema: 'iglu:com.parrable/encrypted_payload/jsonschema/1-0-0',
+ data: context
+ };
+ }
+ }
+
+ /**
+ * Expires current session and starts a new session.
+ */
+ function newSession() {
+ // If cookies are enabled, base visit count and session ID on the cookies
+ var nowTs = Math.round(new Date().getTime() / 1000),
+ ses = getSnowplowCookieValue('ses'),
+ id = loadDomainUserIdCookie(),
+ cookiesDisabled = id[0],
+ _domainUserId = id[1], // We could use the global (domainUserId) but this is better etiquette
+ createTs = id[2],
+ visitCount = id[3],
+ currentVisitTs = id[4],
+ lastVisitTs = id[5],
+ sessionIdFromCookie = id[6];
+
+ // When cookies are enabled
+ if (cookiesDisabled === '0') {
+ memorizedSessionId = sessionIdFromCookie;
+
+ // When cookie/local storage is enabled - make a new session
+ if (configStateStorageStrategy != 'none') {
+ // New session (aka new visit)
+ visitCount++;
+ // Update the last visit timestamp
+ lastVisitTs = currentVisitTs;
+ // Regenerate the session ID
+ memorizedSessionId = uuid.v4();
+ }
+
+ memorizedVisitCount = visitCount;
+
+ // Create a new session cookie
+ setSessionCookie()
+
+ } else {
+ memorizedSessionId = uuid.v4();
+ memorizedVisitCount++;
+ }
+
+ // Update cookies
+ if (configStateStorageStrategy != 'none') {
+ setDomainUserIdCookie(_domainUserId, createTs, memorizedVisitCount, nowTs,
+ lastVisitTs, memorizedSessionId);
+ setSessionCookie();
+ }
+
+ lastEventTime = new Date().getTime();
+ }
+
+ /**
+ * Attempts to create a context using the geolocation API and add it to commonContexts
+ */
+ function enableGeolocationContext() {
+ if (!geolocationContextAdded && navigatorAlias.geolocation && navigatorAlias.geolocation.getCurrentPosition) {
+ geolocationContextAdded = true;
+ navigatorAlias.geolocation.getCurrentPosition(function (position) {
+ var coords = position.coords;
+ var geolocationContext = {
+ schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0',
+ data: {
+ latitude: coords.latitude,
+ longitude: coords.longitude,
+ latitudeLongitudeAccuracy: coords.accuracy,
+ altitude: coords.altitude,
+ altitudeAccuracy: coords.altitudeAccuracy,
+ bearing: coords.heading,
+ speed: coords.speed,
+ timestamp: Math.round(position.timestamp)
+ }
+ };
+ commonContexts.push(geolocationContext);
+ });
+ }
+ }
+
+ /**
+ * Creates a context containing the values of the cookies set by GA
+ *
+ * @return object GA cookies context
+ */
+ function getGaCookiesContext() {
+ var gaCookieData = {};
+ forEach(['__utma', '__utmb', '__utmc', '__utmv', '__utmz', '_ga'], function (cookieType) {
+ var value = cookie.cookie(cookieType);
+ if (value) {
+ gaCookieData[cookieType] = value;
+ }
+ });
+ return {
+ schema: 'iglu:com.google.analytics/cookies/jsonschema/1-0-0',
+ data: gaCookieData
+ };
+ }
+
+ /**
+ * Combine an array of unchanging contexts with the result of a context-creating function
+ *
+ * @param staticContexts Array of custom contexts
+ * @param contextCallback Function returning an array of contexts
+ */
+ function finalizeContexts(staticContexts, contextCallback) {
+ return (staticContexts || []).concat(contextCallback ? contextCallback() : []);
+ }
+
+ /**
+ * Log the page view / visit
+ *
+ * @param customTitle string The user-defined page title to attach to this page view
+ * @param context object Custom context relating to the event
+ * @param contextCallback Function returning an array of contexts
+ * @param tstamp number
+ */
+ function logPageView(customTitle, context, contextCallback, tstamp) {
+
+ refreshUrl();
+ if (pageViewSent) { // Do not reset pageViewId if previous events were not page_view
+ resetPageView();
+ }
+ pageViewSent = true;
+
+ // So we know what document.title was at the time of trackPageView
+ lastDocumentTitle = documentAlias.title;
+ lastConfigTitle = customTitle;
+
+ // Fixup page title
+ var pageTitle = helpers.fixupTitle(lastConfigTitle || lastDocumentTitle);
+
+ // Log page view
+ core.trackPageView(
+ purify(configCustomUrl || locationHrefAlias),
+ pageTitle,
+ purify(customReferrer || configReferrerUrl),
+ addCommonContexts(finalizeContexts(context, contextCallback)),
+ tstamp);
+
+ // Send ping (to log that user has stayed on page)
+ var now = new Date();
+
+ if (activityTrackingEnabled && !activityTrackingInstalled) {
+ activityTrackingInstalled = true;
+
+ // Add mousewheel event handler, detect passive event listeners for performance
+ var detectPassiveEvents = {
+ update: function update() {
+ if (typeof window !== 'undefined' && typeof window.addEventListener === 'function') {
+ var passive = false;
+ var options = Object.defineProperty({}, 'passive', {
+ get: function get() {
+ passive = true;
+ }
+ });
+ // note: have to set and remove a no-op listener instead of null
+ // (which was used previously), becasue Edge v15 throws an error
+ // when providing a null callback.
+ // https://github.com/rafrex/detect-passive-events/pull/3
+ var noop = function noop() {
+ };
+ window.addEventListener('testPassiveEventSupport', noop, options);
+ window.removeEventListener('testPassiveEventSupport', noop, options);
+ detectPassiveEvents.hasSupport = passive;
+ }
+ }
+ };
+ detectPassiveEvents.update();
+
+ // Detect available wheel event
+ var wheelEvent = "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel"
+ document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel"
+ "DOMMouseScroll"; // let's assume that remaining browsers are older Firefox
+
+ if (Object.prototype.hasOwnProperty.call(detectPassiveEvents, 'hasSupport')) {
+ helpers.addEventListener(documentAlias, wheelEvent, activityHandler, {passive: true});
+ } else {
+ helpers.addEventListener(documentAlias, wheelEvent, activityHandler);
+ }
+
+ // Capture our initial scroll points
+ resetMaxScrolls();
+
+ // Add event handlers; cross-browser compatibility here varies significantly
+ // @see http://quirksmode.org/dom/events
+ helpers.addEventListener(documentAlias, 'click', activityHandler);
+ helpers.addEventListener(documentAlias, 'mouseup', activityHandler);
+ helpers.addEventListener(documentAlias, 'mousedown', activityHandler);
+ helpers.addEventListener(documentAlias, 'mousemove', activityHandler);
+ helpers.addEventListener(windowAlias, 'scroll', scrollHandler); // Will updateMaxScrolls() for us
+ helpers.addEventListener(documentAlias, 'keypress', activityHandler);
+ helpers.addEventListener(documentAlias, 'keydown', activityHandler);
+ helpers.addEventListener(documentAlias, 'keyup', activityHandler);
+ helpers.addEventListener(windowAlias, 'resize', activityHandler);
+ helpers.addEventListener(windowAlias, 'focus', activityHandler);
+ helpers.addEventListener(windowAlias, 'blur', activityHandler);
+
+ // Periodic check for activity.
+ lastActivityTime = now.getTime();
+ clearInterval(pagePingInterval);
+ pagePingInterval = setInterval(function heartBeat() {
+ var now = new Date();
+
+ // There was activity during the heart beat period;
+ // on average, this is going to overstate the visitDuration by configHeartBeatTimer/2
+ if ((lastActivityTime + configHeartBeatTimer) > now.getTime()) {
+ // Send ping if minimum visit time has elapsed
+ if (configMinimumVisitTime < now.getTime()) {
+ logPagePing(finalizeContexts(context, contextCallback)); // Grab the min/max globals
+ }
+ }
+ }, configHeartBeatTimer);
+ }
+ }
+
+ /**
+ * Log that a user is still viewing a given page
+ * by sending a page ping.
+ * Not part of the public API - only called from
+ * logPageView() above.
+ *
+ * @param context object Custom context relating to the event
+ */
+ function logPagePing(context) {
+ refreshUrl();
+ var newDocumentTitle = documentAlias.title;
+ if (newDocumentTitle !== lastDocumentTitle) {
+ lastDocumentTitle = newDocumentTitle;
+ lastConfigTitle = null;
+ }
+ core.trackPagePing(
+ purify(configCustomUrl || locationHrefAlias),
+ helpers.fixupTitle(lastConfigTitle || lastDocumentTitle),
+ purify(customReferrer || configReferrerUrl),
+ cleanOffset(minXOffset),
+ cleanOffset(maxXOffset),
+ cleanOffset(minYOffset),
+ cleanOffset(maxYOffset),
+ addCommonContexts(context));
+ resetMaxScrolls();
+ }
+
+ /**
+ * Log ecommerce transaction metadata
+ *
+ * @param string orderId
+ * @param string affiliation
+ * @param string total
+ * @param string tax
+ * @param string shipping
+ * @param string city
+ * @param string state
+ * @param string country
+ * @param string currency The currency the total/tax/shipping are expressed in
+ * @param object context Custom context relating to the event
+ * @param tstamp number or Timestamp object
+ */
+ function logTransaction(orderId, affiliation, total, tax, shipping, city, state, country, currency, context, tstamp) {
+ core.trackEcommerceTransaction(orderId, affiliation, total, tax, shipping, city, state, country, currency, addCommonContexts(context), tstamp);
+ }
+
+ /**
+ * Log ecommerce transaction item
+ *
+ * @param string orderId
+ * @param string sku
+ * @param string name
+ * @param string category
+ * @param string price
+ * @param string quantity
+ * @param string currency The currency the price is expressed in
+ * @param object context Custom context relating to the event
+ */
+ function logTransactionItem(orderId, sku, name, category, price, quantity, currency, context, tstamp) {
+ core.trackEcommerceTransactionItem(orderId, sku, name, category, price, quantity, currency, addCommonContexts(context), tstamp);
+ }
+
+ /**
+ * Construct a browser prefix
+ *
+ * E.g: (moz, hidden) -> mozHidden
+ */
+ function prefixPropertyName(prefix, propertyName) {
+
+ if (prefix !== '') {
+ return prefix + propertyName.charAt(0).toUpperCase() + propertyName.slice(1);
+ }
+
+ return propertyName;
+ }
+
+ /**
+ * Check for pre-rendered web pages, and log the page view/link
+ * according to the configuration and/or visibility
+ *
+ * @see http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html
+ */
+ function trackCallback(callback) {
+ var isPreRendered,
+ i,
+ // Chrome 13, IE10, FF10
+ prefixes = ['', 'webkit', 'ms', 'moz'],
+ prefix;
+
+ // If configPrerendered == true - we'll never set `isPreRendered` to true and fire immediately,
+ // otherwise we need to check if this is just prerendered
+ if (!configCountPreRendered) { // true by default
+
+ for (i = 0; i < prefixes.length; i++) {
+ prefix = prefixes[i];
+
+ // does this browser support the page visibility API? (drop this check along with IE9 and iOS6)
+ if (documentAlias[prefixPropertyName(prefix, 'hidden')]) {
+ // if pre-rendered, then defer callback until page visibility changes
+ if (documentAlias[prefixPropertyName(prefix, 'visibilityState')] === 'prerender') {
+ isPreRendered = true;
+ }
+ break;
+ } else if (documentAlias[prefixPropertyName(prefix, 'hidden')] === false) { break }
+ }
+ }
+
+ // Implies configCountPreRendered = false
+ if (isPreRendered) {
+ // note: the event name doesn't follow the same naming convention as vendor properties
+ helpers.addEventListener(documentAlias, prefix + 'visibilitychange', function ready() {
+ documentAlias.removeEventListener(prefix + 'visibilitychange', ready, false);
+ callback();
+ });
+ return;
+ }
+
+ // configCountPreRendered === true || isPreRendered === false
+ callback();
+ }
+
+ /**
+ * Update the returned methods (public facing methods)
+ */
+ function updateReturnMethods() {
+ if (debug) {
+ returnMethods = apiMethods;
+ } else {
+ returnMethods = safeMethods;
+ }
+ }
+
+ /************************************************************
+ * Constructor
+ ************************************************************/
+
+ /*
+ * Initialize tracker
+ */
+ updateDomainHash();
+
+ initializeIdsAndCookies();
+
+ if (argmap.crossDomainLinker) {
+ decorateLinks(argmap.crossDomainLinker);
+ }
+
+ /************************************************************
+ * Public data and methods
+ ************************************************************/
+
+ /**
+ * Get the domain session index also known as current memorized visit count.
+ *
+ * @return int Domain session index
+ */
+ apiMethods.getDomainSessionIndex = function() {
+ return memorizedVisitCount;
+ };
+
+ /**
+ * Get the page view ID as generated or provided by mutSnowplowState.pageViewId.
+ *
+ * @return string Page view ID
+ */
+ apiMethods.getPageViewId = function () {
+ return getPageViewId();
+ };
+
+ /**
+ * Expires current session and starts a new session.
+ */
+ apiMethods.newSession = newSession;
+
+ /**
+ * Get the cookie name as cookieNamePrefix + basename + . + domain.
+ *
+ * @return string Cookie name
+ */
+ apiMethods.getCookieName = function(basename) {
+ return getSnowplowCookieName(basename);
+ };
+
+ /**
+ * Get the current user ID (as set previously
+ * with setUserId()).
+ *
+ * @return string Business-defined user ID
+ */
+ apiMethods.getUserId = function () {
+ return businessUserId;
+ };
+
+ /**
+ * Get visitor ID (from first party cookie)
+ *
+ * @return string Visitor ID in hexits (or null, if not yet known)
+ */
+ apiMethods.getDomainUserId = function () {
+ return (loadDomainUserIdCookie())[1];
+ };
+
+ /**
+ * Get the visitor information (from first party cookie)
+ *
+ * @return array
+ */
+ apiMethods.getDomainUserInfo = function () {
+ return loadDomainUserIdCookie();
+ };
+
+ /**
+ * Get the user fingerprint
+ *
+ * @return string The user fingerprint
+ */
+ apiMethods.getUserFingerprint = function () {
+ return userFingerprint;
+ };
+
+ /**
+ * Specify the app ID
+ *
+ * @param int|string appId
+ */
+ apiMethods.setAppId = function (appId) {
+ helpers.warn('setAppId is deprecated. Instead add an "appId" field to the argmap argument of newTracker.');
+ core.setAppId(appId);
+ };
+
+ /**
+ * Override referrer
+ *
+ * @param string url
+ */
+ apiMethods.setReferrerUrl = function (url) {
+ customReferrer = url;
+ };
+
+ /**
+ * Override url
+ *
+ * @param string url
+ */
+ apiMethods.setCustomUrl = function (url) {
+ refreshUrl();
+ configCustomUrl = resolveRelativeReference(locationHrefAlias, url);
+ };
+
+ /**
+ * Override document.title
+ *
+ * @param string title
+ */
+ apiMethods.setDocumentTitle = function (title) {
+ // So we know what document.title was at the time of trackPageView
+ lastDocumentTitle = documentAlias.title;
+ lastConfigTitle = title;
+ };
+
+ /**
+ * Strip hash tag (or anchor) from URL
+ *
+ * @param bool enableFilter
+ */
+ apiMethods.discardHashTag = function (enableFilter) {
+ configDiscardHashTag = enableFilter;
+ };
+
+ /**
+ * Set first-party cookie name prefix
+ *
+ * @param string cookieNamePrefix
+ */
+ apiMethods.setCookieNamePrefix = function (cookieNamePrefix) {
+ helpers.warn('setCookieNamePrefix is deprecated. Instead add a "cookieName" field to the argmap argument of newTracker.');
+ configCookieNamePrefix = cookieNamePrefix;
+ };
+
+ /**
+ * Set first-party cookie domain
+ *
+ * @param string domain
+ */
+ apiMethods.setCookieDomain = function (domain) {
+ helpers.warn('setCookieDomain is deprecated. Instead add a "cookieDomain" field to the argmap argument of newTracker.');
+ configCookieDomain = helpers.fixupDomain(domain);
+ updateDomainHash();
+ };
+
+ /**
+ * Set first-party cookie path
+ *
+ * @param string domain
+ */
+ apiMethods.setCookiePath = function (path) {
+ configCookiePath = path;
+ updateDomainHash();
+ };
+
+ /**
+ * Set visitor cookie timeout (in seconds)
+ *
+ * @param int timeout
+ */
+ apiMethods.setVisitorCookieTimeout = function (timeout) {
+ configVisitorCookieTimeout = timeout;
+ };
+
+ /**
+ * Set session cookie timeout (in seconds)
+ *
+ * @param int timeout
+ */
+ apiMethods.setSessionCookieTimeout = function (timeout) {
+ helpers.warn('setSessionCookieTimeout is deprecated. Instead add a "sessionCookieTimeout" field to the argmap argument of newTracker.')
+ configSessionCookieTimeout = timeout;
+ };
+
+ /**
+ * @param number seed The seed used for MurmurHash3
+ */
+ apiMethods.setUserFingerprintSeed = function(seed) {
+ helpers.warn('setUserFingerprintSeed is deprecated. Instead add a "userFingerprintSeed" field to the argmap argument of newTracker.');
+ configUserFingerprintHashSeed = seed;
+ userFingerprint = detectors.detectSignature(configUserFingerprintHashSeed);
+ };
+
+ /**
+ * Enable/disable user fingerprinting. User fingerprinting is enabled by default.
+ * @param bool enable If false, turn off user fingerprinting
+ */
+ apiMethods.enableUserFingerprint = function(enable) {
+ helpers.warn('enableUserFingerprintSeed is deprecated. Instead add a "userFingerprint" field to the argmap argument of newTracker.');
+ if (!enable) {
+ userFingerprint = '';
+ }
+ };
+
+ /**
+ * Prevent tracking if user's browser has Do Not Track feature enabled,
+ * where tracking is:
+ * 1) Sending events to a collector
+ * 2) Setting first-party cookies
+ * @param bool enable If true and Do Not Track feature enabled, don't track.
+ */
+ apiMethods.respectDoNotTrack = function (enable) {
+ helpers.warn('This usage of respectDoNotTrack is deprecated. Instead add a "respectDoNotTrack" field to the argmap argument of newTracker.');
+ var dnt = navigatorAlias.doNotTrack || navigatorAlias.msDoNotTrack;
+
+ configDoNotTrack = enable && (dnt === 'yes' || dnt === '1');
+ };
+
+ /**
+ * Enable querystring decoration for links pasing a filter
+ *
+ * @param function crossDomainLinker Function used to determine which links to decorate
+ */
+ apiMethods.crossDomainLinker = function (crossDomainLinkerCriterion) {
+ decorateLinks(crossDomainLinkerCriterion);
+ };
+
+ /**
+ * Install link tracker
+ *
+ * The default behaviour is to use actual click events. However, some browsers
+ * (e.g., Firefox, Opera, and Konqueror) don't generate click events for the middle mouse button.
+ *
+ * To capture more "clicks", the pseudo click-handler uses mousedown + mouseup events.
+ * This is not industry standard and is vulnerable to false positives (e.g., drag events).
+ *
+ * There is a Safari/Chrome/Webkit bug that prevents tracking requests from being sent
+ * by either click handler. The workaround is to set a target attribute (which can't
+ * be "_self", "_top", or "_parent").
+ *
+ * @see https://bugs.webkit.org/show_bug.cgi?id=54783
+ *
+ * @param object criterion Criterion by which it will be decided whether a link will be tracked
+ * @param bool pseudoClicks If true, use pseudo click-handler (mousedown+mouseup)
+ * @param bool trackContent Whether to track the innerHTML of the link element
+ * @param array context Context for all link click events
+ */
+ apiMethods.enableLinkClickTracking = function (criterion, pseudoClicks, trackContent, context) {
+ if (mutSnowplowState.hasLoaded) {
+ // the load event has already fired, add the click listeners now
+ linkTrackingManager.configureLinkClickTracking(criterion, pseudoClicks, trackContent, context);
+ linkTrackingManager.addClickListeners();
+ } else {
+ // defer until page has loaded
+ mutSnowplowState.registeredOnLoadHandlers.push(function () {
+ linkTrackingManager.configureLinkClickTracking(criterion, pseudoClicks, trackContent, context);
+ linkTrackingManager.addClickListeners();
+ });
+ }
+ };
+
+ /**
+ * Add click event listeners to links which have been added to the page since the
+ * last time enableLinkClickTracking or refreshLinkClickTracking was used
+ */
+ apiMethods.refreshLinkClickTracking = function () {
+ if (mutSnowplowState.hasLoaded) {
+ linkTrackingManager.addClickListeners();
+ } else {
+ mutSnowplowState.registeredOnLoadHandlers.push(function () {
+ linkTrackingManager.addClickListeners();
+ });
+ }
+ };
+
+ /**
+ * Enables page activity tracking (sends page
+ * pings to the Collector regularly).
+ *
+ * @param int minimumVisitLength Seconds to wait before sending first page ping
+ * @param int heartBeatDelay Seconds to wait between pings
+ */
+ apiMethods.enableActivityTracking = function (minimumVisitLength, heartBeatDelay) {
+ if (minimumVisitLength === parseInt(minimumVisitLength, 10) &&
+ heartBeatDelay === parseInt(heartBeatDelay, 10)) {
+ activityTrackingEnabled = true;
+ configMinimumVisitTime = new Date().getTime() + minimumVisitLength * 1000;
+ configHeartBeatTimer = heartBeatDelay * 1000;
+ } else {
+ helpers.warn("Activity tracking not enabled, please provide integer values " +
+ "for minimumVisitLength and heartBeatDelay.")
+ }
+ };
+
+ /**
+ * Triggers the activityHandler manually to allow external user defined
+ * activity. i.e. While watching a video
+ */
+ apiMethods.updatePageActivity = function () {
+ activityHandler();
+ };
+
+ /**
+ * Enables automatic form tracking.
+ * An event will be fired when a form field is changed or a form submitted.
+ * This can be called multiple times: only forms not already tracked will be tracked.
+ *
+ * @param object config Configuration object determining which forms and fields to track.
+ * Has two properties: "forms" and "fields"
+ * @param array context Context for all form tracking events
+ */
+ apiMethods.enableFormTracking = function (config, context) {
+ if (mutSnowplowState.hasLoaded) {
+ formTrackingManager.configureFormTracking(config);
+ formTrackingManager.addFormListeners(context);
+ } else {
+ mutSnowplowState.registeredOnLoadHandlers.push(function () {
+ formTrackingManager.configureFormTracking(config);
+ formTrackingManager.addFormListeners(context);
+ });
+ }
+ };
+
+ /**
+ * Frame buster
+ */
+ apiMethods.killFrame = function () {
+ if (windowAlias.location !== windowAlias.top.location) {
+ windowAlias.top.location = windowAlias.location;
+ }
+ };
+
+ /**
+ * Redirect if browsing offline (aka file: buster)
+ *
+ * @param string url Redirect to this URL
+ */
+ apiMethods.redirectFile = function (url) {
+ if (windowAlias.location.protocol === 'file:') {
+ windowAlias.location = url;
+ }
+ };
+
+ /**
+ * Sets the opt out cookie.
+ *
+ * @param string name of the opt out cookie
+ */
+ apiMethods.setOptOutCookie = function (name) {
+ configOptOutCookie = name;
+ };
+
+ /**
+ * Count sites in pre-rendered state
+ *
+ * @param bool enable If true, track when in pre-rendered state
+ */
+ apiMethods.setCountPreRendered = function (enable) {
+ configCountPreRendered = enable;
+ };
+
+ /**
+ * Set the business-defined user ID for this user.
+ *
+ * @param string userId The business-defined user ID
+ */
+ apiMethods.setUserId = function(userId) {
+ businessUserId = userId;
+ };
+
+ /**
+ * Alias for setUserId.
+ *
+ * @param string userId The business-defined user ID
+ */
+ apiMethods.identifyUser = function(userId) {
+ setUserId(userId);
+ };
+
+ /**
+ * Set the business-defined user ID for this user using the location querystring.
+ *
+ * @param string queryName Name of a querystring name-value pair
+ */
+ apiMethods.setUserIdFromLocation = function(querystringField) {
+ refreshUrl();
+ businessUserId = helpers.fromQuerystring(querystringField, locationHrefAlias);
+ };
+
+ /**
+ * Set the business-defined user ID for this user using the referrer querystring.
+ *
+ * @param string queryName Name of a querystring name-value pair
+ */
+ apiMethods.setUserIdFromReferrer = function(querystringField) {
+ refreshUrl();
+ businessUserId = helpers.fromQuerystring(querystringField, configReferrerUrl);
+ };
+
+ /**
+ * Set the business-defined user ID for this user to the value of a cookie.
+ *
+ * @param string cookieName Name of the cookie whose value will be assigned to businessUserId
+ */
+ apiMethods.setUserIdFromCookie = function(cookieName) {
+ businessUserId = cookie.cookie(cookieName);
+ };
+
+ /**
+ * Configure this tracker to log to a CloudFront collector.
+ *
+ * @param string distSubdomain The subdomain on your CloudFront collector's distribution
+ */
+ apiMethods.setCollectorCf = function (distSubdomain) {
+ configCollectorUrl = collectorUrlFromCfDist(distSubdomain);
+ };
+
+ /**
+ *
+ * Specify the Snowplow collector URL. No need to include HTTP
+ * or HTTPS - we will add this.
+ *
+ * @param string rawUrl The collector URL minus protocol and /i
+ */
+ apiMethods.setCollectorUrl = function (rawUrl) {
+ configCollectorUrl = asCollectorUrl(rawUrl);
+ };
+
+ /**
+ * Specify the platform
+ *
+ * @param string platform Overrides the default tracking platform
+ */
+ apiMethods.setPlatform = function(platform) {
+ helpers.warn('setPlatform is deprecated. Instead add a "platform" field to the argmap argument of newTracker.');
+ core.setPlatform(platform);
+ };
+
+ /**
+ *
+ * Enable Base64 encoding for self-describing event payload
+ *
+ * @param bool enabled A boolean value indicating if the Base64 encoding for self-describing events should be enabled or not
+ */
+ apiMethods.encodeBase64 = function (enabled) {
+ helpers.warn('This usage of encodeBase64 is deprecated. Instead add an "encodeBase64" field to the argmap argument of newTracker.');
+ core.setBase64Encoding(enabled);
+ };
+
+ /**
+ * Send all events in the outQueue
+ * Use only when sending POSTs with a bufferSize of at least 2
+ */
+ apiMethods.flushBuffer = function () {
+ outQueueManager.executeQueue();
+ };
+
+ /**
+ * Add the geolocation context to all events
+ */
+ apiMethods.enableGeolocationContext = enableGeolocationContext,
+
+ /**
+ * Log visit to this page
+ *
+ * @param string customTitle
+ * @param object Custom context relating to the event
+ * @param object contextCallback Function returning an array of contexts
+ * @param tstamp number or Timestamp object
+ */
+ apiMethods.trackPageView = function (customTitle, context, contextCallback, tstamp) {
+ trackCallback(function () {
+ logPageView(customTitle, context, contextCallback, tstamp);
+ });
+ };
+
+ /**
+ * Track a structured event happening on this page.
+ *
+ * Replaces trackEvent, making clear that the type
+ * of event being tracked is a structured one.
+ *
+ * @param string category The name you supply for the group of objects you want to track
+ * @param string action A string that is uniquely paired with each category, and commonly used to define the type of user interaction for the web object
+ * @param string label (optional) An optional string to provide additional dimensions to the event data
+ * @param string property (optional) Describes the object or the action performed on it, e.g. quantity of item added to basket
+ * @param int|float|string value (optional) An integer that you can use to provide numerical data about the user event
+ * @param object Custom context relating to the event
+ * @param tstamp number or Timestamp object
+ */
+ apiMethods.trackStructEvent = function (category, action, label, property, value, context, tstamp) {
+ trackCallback(function () {
+ core.trackStructEvent(category, action, label, property, value, addCommonContexts(context), tstamp);
+ });
+ };
+
+ /**
+ * Track a self-describing event (previously unstructured event) happening on this page.
+ *
+ * @param object eventJson Contains the properties and schema location for the event
+ * @param object context Custom context relating to the event
+ * @param tstamp number or Timestamp object
+ */
+ apiMethods.trackSelfDescribingEvent = function (eventJson, context, tstamp) {
+ trackCallback(function () {
+ core.trackSelfDescribingEvent(eventJson, addCommonContexts(context), tstamp);
+ });
+ };
+
+ /**
+ * Alias for `trackSelfDescribingEvent`, left for compatibility
+ */
+ apiMethods.trackUnstructEvent = function (eventJson, context, tstamp) {
+ trackCallback(function () {
+ core.trackSelfDescribingEvent(eventJson, addCommonContexts(context), tstamp);
+ });
+ };
+
+ /**
+ * Track an ecommerce transaction
+ *
+ * @param string orderId Required. Internal unique order id number for this transaction.
+ * @param string affiliation Optional. Partner or store affiliation.
+ * @param string total Required. Total amount of the transaction.
+ * @param string tax Optional. Tax amount of the transaction.
+ * @param string shipping Optional. Shipping charge for the transaction.
+ * @param string city Optional. City to associate with transaction.
+ * @param string state Optional. State to associate with transaction.
+ * @param string country Optional. Country to associate with transaction.
+ * @param string currency Optional. Currency to associate with this transaction.
+ * @param object context Optional. Context relating to the event.
+ * @param tstamp number or Timestamp object
+ */
+ apiMethods.addTrans = function(orderId, affiliation, total, tax, shipping, city, state, country, currency, context, tstamp) {
+ ecommerceTransaction.transaction = {
+ orderId: orderId,
+ affiliation: affiliation,
+ total: total,
+ tax: tax,
+ shipping: shipping,
+ city: city,
+ state: state,
+ country: country,
+ currency: currency,
+ context: context,
+ tstamp: tstamp
+ };
+ };
+
+ /**
+ * Track an ecommerce transaction item
+ *
+ * @param string orderId Required Order ID of the transaction to associate with item.
+ * @param string sku Required. Item's SKU code.
+ * @param string name Optional. Product name.
+ * @param string category Optional. Product category.
+ * @param string price Required. Product price.
+ * @param string quantity Required. Purchase quantity.
+ * @param string currency Optional. Product price currency.
+ * @param object context Optional. Context relating to the event.
+ * @param tstamp number or Timestamp object
+ */
+ apiMethods.addItem = function(orderId, sku, name, category, price, quantity, currency, context, tstamp) {
+ ecommerceTransaction.items.push({
+ orderId: orderId,
+ sku: sku,
+ name: name,
+ category: category,
+ price: price,
+ quantity: quantity,
+ currency: currency,
+ context: context,
+ tstamp: tstamp
+ });
+ };
+
+ /**
+ * Commit the ecommerce transaction
+ *
+ * This call will send the data specified with addTrans,
+ * addItem methods to the tracking server.
+ */
+ apiMethods.trackTrans = function() {
+ trackCallback(function () {
+
+ logTransaction(
+ ecommerceTransaction.transaction.orderId,
+ ecommerceTransaction.transaction.affiliation,
+ ecommerceTransaction.transaction.total,
+ ecommerceTransaction.transaction.tax,
+ ecommerceTransaction.transaction.shipping,
+ ecommerceTransaction.transaction.city,
+ ecommerceTransaction.transaction.state,
+ ecommerceTransaction.transaction.country,
+ ecommerceTransaction.transaction.currency,
+ ecommerceTransaction.transaction.context,
+ ecommerceTransaction.transaction.tstamp
+ );
+ for (var i = 0; i < ecommerceTransaction.items.length; i++) {
+ var item = ecommerceTransaction.items[i];
+ logTransactionItem(
+ item.orderId,
+ item.sku,
+ item.name,
+ item.category,
+ item.price,
+ item.quantity,
+ item.currency,
+ item.context,
+ item.tstamp
+ );
+ }
+
+ ecommerceTransaction = ecommerceTransactionTemplate();
+ });
+ };
+
+ /**
+ * Manually log a click from your own code
+ *
+ * @param string elementId
+ * @param array elementClasses
+ * @param string elementTarget
+ * @param string targetUrl
+ * @param string elementContent innerHTML of the element
+ * @param object Custom context relating to the event
+ * @param tstamp number or Timestamp object
+ */
+ // TODO: break this into trackLink(destUrl) and trackDownload(destUrl)
+ apiMethods.trackLinkClick = function(targetUrl, elementId, elementClasses, elementTarget, elementContent, context, tstamp) {
+ trackCallback(function () {
+ core.trackLinkClick(targetUrl, elementId, elementClasses, elementTarget, elementContent, addCommonContexts(context), tstamp);
+ });
+ };
+
+ /**
+ * Track an ad being served
+ *
+ * @param string impressionId Identifier for a particular ad impression
+ * @param string costModel The cost model. 'cpa', 'cpc', or 'cpm'
+ * @param number cost Cost
+ * @param string bannerId Identifier for the ad banner displayed
+ * @param string zoneId Identifier for the ad zone
+ * @param string advertiserId Identifier for the advertiser
+ * @param string campaignId Identifier for the campaign which the banner belongs to
+ * @param object Custom context relating to the event
+ * @param tstamp number or Timestamp object
+ */
+ apiMethods.trackAdImpression = function(impressionId, costModel, cost, targetUrl, bannerId, zoneId, advertiserId, campaignId, context, tstamp) {
+ trackCallback(function () {
+ core.trackAdImpression(impressionId, costModel, cost, targetUrl, bannerId, zoneId, advertiserId, campaignId, addCommonContexts(context), tstamp);
+ });
+ };
+
+ /**
+ * Track an ad being clicked
+ *
+ * @param string clickId Identifier for the ad click
+ * @param string costModel The cost model. 'cpa', 'cpc', or 'cpm'
+ * @param number cost Cost
+ * @param string targetUrl (required) The link's target URL
+ * @param string bannerId Identifier for the ad banner displayed
+ * @param string zoneId Identifier for the ad zone
+ * @param string impressionId Identifier for a particular ad impression
+ * @param string advertiserId Identifier for the advertiser
+ * @param string campaignId Identifier for the campaign which the banner belongs to
+ * @param object Custom context relating to the event
+ * @param tstamp number or Timestamp object
+ */
+ apiMethods.trackAdClick = function(targetUrl, clickId, costModel, cost, bannerId, zoneId, impressionId, advertiserId, campaignId, context, tstamp) {
+ trackCallback(function () {
+ core.trackAdClick(targetUrl, clickId, costModel, cost, bannerId, zoneId, impressionId, advertiserId, campaignId, addCommonContexts(context), tstamp);
+ });
+ };
+
+ /**
+ * Track an ad conversion event
+ *
+ * @param string conversionId Identifier for the ad conversion event
+ * @param number cost Cost
+ * @param string category The name you supply for the group of objects you want to track
+ * @param string action A string that is uniquely paired with each category
+ * @param string property Describes the object of the conversion or the action performed on it
+ * @param number initialValue Revenue attributable to the conversion at time of conversion
+ * @param string advertiserId Identifier for the advertiser
+ * @param string costModel The cost model. 'cpa', 'cpc', or 'cpm'
+ * @param string campaignId Identifier for the campaign which the banner belongs to
+ * @param object Custom context relating to the event
+ * @param tstamp number or Timestamp object
+ */
+ apiMethods.trackAdConversion = function(conversionId, costModel, cost, category, action, property, initialValue, advertiserId, campaignId, context, tstamp) {
+ trackCallback(function () {
+ core.trackAdConversion(conversionId, costModel, cost, category, action, property, initialValue, advertiserId, campaignId, addCommonContexts(context), tstamp);
+ });
+ };
+
+ /**
+ * Track a social interaction event
+ *
+ * @param string action (required) Social action performed
+ * @param string network (required) Social network
+ * @param string target Object of the social action e.g. the video liked, the tweet retweeted
+ * @param object Custom context relating to the event
+ * @param tstamp number or Timestamp object
+ */
+ apiMethods.trackSocialInteraction = function(action, network, target, context, tstamp) {
+ trackCallback(function () {
+ core.trackSocialInteraction(action, network, target, addCommonContexts(context), tstamp);
+ });
+ };
+
+ /**
+ * Track an add-to-cart event
+ *
+ * @param string sku Required. Item's SKU code.
+ * @param string name Optional. Product name.
+ * @param string category Optional. Product category.
+ * @param string unitPrice Optional. Product price.
+ * @param string quantity Required. Quantity added.
+ * @param string currency Optional. Product price currency.
+ * @param array context Optional. Context relating to the event.
+ * @param tstamp number or Timestamp object
+ */
+ apiMethods.trackAddToCart = function(sku, name, category, unitPrice, quantity, currency, context, tstamp) {
+ trackCallback(function () {
+ core.trackAddToCart(sku, name, category, unitPrice, quantity, currency, addCommonContexts(context), tstamp);
+ });
+ };
+
+ /**
+ * Track a remove-from-cart event
+ *
+ * @param string sku Required. Item's SKU code.
+ * @param string name Optional. Product name.
+ * @param string category Optional. Product category.
+ * @param string unitPrice Optional. Product price.
+ * @param string quantity Required. Quantity removed.
+ * @param string currency Optional. Product price currency.
+ * @param array context Optional. Context relating to the event.
+ * @param tstamp Opinal number or Timestamp object
+ */
+ apiMethods.trackRemoveFromCart = function(sku, name, category, unitPrice, quantity, currency, context, tstamp) {
+ trackCallback(function () {
+ core.trackRemoveFromCart(sku, name, category, unitPrice, quantity, currency, addCommonContexts(context), tstamp);
+ });
+ };
+
+ /**
+ * Track an internal search event
+ *
+ * @param array terms Search terms
+ * @param object filters Search filters
+ * @param number totalResults Number of results
+ * @param number pageResults Number of results displayed on page
+ * @param array context Optional. Context relating to the event.
+ * @param tstamp Opinal number or Timestamp object
+ */
+ apiMethods.trackSiteSearch = function(terms, filters, totalResults, pageResults, context, tstamp) {
+ trackCallback(function () {
+ core.trackSiteSearch(terms, filters, totalResults, pageResults, addCommonContexts(context), tstamp);
+ });
+ };
+
+ /**
+ * Track a timing event (such as the time taken for a resource to load)
+ *
+ * @param string category Required.
+ * @param string variable Required.
+ * @param number timing Required.
+ * @param string label Optional.
+ * @param array context Optional. Context relating to the event.
+ * @param tstamp Opinal number or Timestamp object
+ */
+ apiMethods.trackTiming = function (category, variable, timing, label, context, tstamp) {
+ trackCallback(function () {
+ core.trackSelfDescribingEvent({
+ schema: 'iglu:com.snowplowanalytics.snowplow/timing/jsonschema/1-0-0',
+ data: {
+ category: category,
+ variable: variable,
+ timing: timing,
+ label: label
+ }
+ }, addCommonContexts(context), tstamp)
+ });
+ };
+
+ /**
+ * Track a consent withdrawn action
+ *
+ * @param {boolean} all - Indicates user withdraws all consent regardless of context documents.
+ * @param {string} [id] - Number associated with document.
+ * @param {string} [version] - Document version number.
+ * @param {string} [name] - Document name.
+ * @param {string} [description] - Document description.
+ * @param {array} [context] - Context relating to the event.
+ * @param {number|Timestamp} [tstamp] - Number or Timestamp object.
+ */
+ apiMethods.trackConsentWithdrawn = function (all, id, version, name, description, context, tstamp) {
+ trackCallback(function () {
+ core.trackConsentWithdrawn(all, id, version, name, description, addCommonContexts(context), tstamp);
+ });
+ };
+
+ /**
+ * Track a consent granted action
+ *
+ * @param {string} id - ID number associated with document.
+ * @param {string} version - Document version number.
+ * @param {string} [name] - Document name.
+ * @param {string} [description] - Document description.
+ * @param {string} [expiry] - Date-time when consent document(s) expire.
+ * @param {array} [context] - Context containing consent documents.
+ * @param {Timestamp|number} [tstamp] - number or Timestamp object.
+ */
+ apiMethods.trackConsentGranted = function (id, version, name, description, expiry, context, tstamp) {
+ trackCallback(function () {
+ core.trackConsentGranted(id, version, name, description, expiry, addCommonContexts(context), tstamp);
+ });
+ };
+
+ /**
+ * Track a GA Enhanced Ecommerce Action with all stored
+ * Enhanced Ecommerce contexts
+ *
+ * @param string action
+ * @param array context Optional. Context relating to the event.
+ * @param tstamp Opinal number or Timestamp object
+ */
+ apiMethods.trackEnhancedEcommerceAction = function (action, context, tstamp) {
+ var combinedEnhancedEcommerceContexts = enhancedEcommerceContexts.concat(context || []);
+ enhancedEcommerceContexts.length = 0;
+
+ trackCallback(function () {
+ core.trackSelfDescribingEvent({
+ schema: 'iglu:com.google.analytics.enhanced-ecommerce/action/jsonschema/1-0-0',
+ data: {
+ action: action
+ }
+ }, addCommonContexts(combinedEnhancedEcommerceContexts), tstamp);
+ });
+ };
+
+ /**
+ * Adds a GA Enhanced Ecommerce Action Context
+ *
+ * @param string id
+ * @param string affiliation
+ * @param number revenue
+ * @param number tax
+ * @param number shipping
+ * @param string coupon
+ * @param string list
+ * @param integer step
+ * @param string option
+ * @param string currency
+ */
+ apiMethods.addEnhancedEcommerceActionContext = function (id, affiliation, revenue, tax, shipping, coupon, list, step, option, currency) {
+ enhancedEcommerceContexts.push({
+ schema: 'iglu:com.google.analytics.enhanced-ecommerce/actionFieldObject/jsonschema/1-0-0',
+ data: {
+ id: id,
+ affiliation: affiliation,
+ revenue: helpers.parseFloat(revenue),
+ tax: helpers.parseFloat(tax),
+ shipping: helpers.parseFloat(shipping),
+ coupon: coupon,
+ list: list,
+ step: helpers.parseInt(step),
+ option: option,
+ currency: currency
+ }
+ });
+ };
+
+ /**
+ * Adds a GA Enhanced Ecommerce Impression Context
+ *
+ * @param string id
+ * @param string name
+ * @param string list
+ * @param string brand
+ * @param string category
+ * @param string variant
+ * @param integer position
+ * @param number price
+ * @param string currency
+ */
+ apiMethods.addEnhancedEcommerceImpressionContext = function (id, name, list, brand, category, variant, position, price, currency) {
+ enhancedEcommerceContexts.push({
+ schema: 'iglu:com.google.analytics.enhanced-ecommerce/impressionFieldObject/jsonschema/1-0-0',
+ data: {
+ id: id,
+ name: name,
+ list: list,
+ brand: brand,
+ category: category,
+ variant: variant,
+ position: helpers.parseInt(position),
+ price: helpers.parseFloat(price),
+ currency: currency
+ }
+ });
+ };
+
+ /**
+ * Adds a GA Enhanced Ecommerce Product Context
+ *
+ * @param string id
+ * @param string name
+ * @param string list
+ * @param string brand
+ * @param string category
+ * @param string variant
+ * @param number price
+ * @param integer quantity
+ * @param string coupon
+ * @param integer position
+ * @param string currency
+ */
+ apiMethods.addEnhancedEcommerceProductContext = function (id, name, list, brand, category, variant, price, quantity, coupon, position, currency) {
+ enhancedEcommerceContexts.push({
+ schema: 'iglu:com.google.analytics.enhanced-ecommerce/productFieldObject/jsonschema/1-0-0',
+ data: {
+ id: id,
+ name: name,
+ list: list,
+ brand: brand,
+ category: category,
+ variant: variant,
+ price: helpers.parseFloat(price),
+ quantity: helpers.parseInt(quantity),
+ coupon: coupon,
+ position: helpers.parseInt(position),
+ currency: currency
+ }
+ });
+ };
+
+ /**
+ * Adds a GA Enhanced Ecommerce Promo Context
+ *
+ * @param string id
+ * @param string name
+ * @param string creative
+ * @param string position
+ * @param string currency
+ */
+ apiMethods.addEnhancedEcommercePromoContext = function (id, name, creative, position, currency) {
+ enhancedEcommerceContexts.push({
+ schema: 'iglu:com.google.analytics.enhanced-ecommerce/promoFieldObject/jsonschema/1-0-0',
+ data: {
+ id: id,
+ name: name,
+ creative: creative,
+ position: position,
+ currency: currency
+ }
+ });
+ };
+
+ /**
+ * All provided contexts will be sent with every event
+ *
+ * @param contexts Array
+ */
+ apiMethods.addGlobalContexts = function (contexts) { core.addGlobalContexts(contexts); };
+
+ /**
+ * All provided contexts will no longer be sent with every event
+ *
+ * @param contexts Array
+ */
+ apiMethods.removeGlobalContexts = function (contexts) { core.removeGlobalContexts(contexts); };
+
+ /**
+ * Clear all global contexts that are sent with events
+ */
+ apiMethods.clearGlobalContexts = function () { core.clearGlobalContexts(); };
+
+ /**
+ * Enable tracking of unhandled exceptions with custom contexts
+ *
+ * @param filter Function ErrorEvent => Bool to check whether error should be tracker
+ * @param contextsAdder Function ErrorEvent => Array to add custom contexts with
+ * internal state based on particular error
+ */
+ apiMethods.enableErrorTracking = function (filter, contextsAdder) {
+ errorManager.enableErrorTracking(filter, contextsAdder, addCommonContexts())
+ };
+
+ /**
+ * Track unhandled exception.
+ * This method supposed to be used inside try/catch block
+ *
+ * @param message string Message appeared in console
+ * @param filename string Source file (not used)
+ * @param lineno number Line number
+ * @param colno number Column number (not used)
+ * @param error Error error object (not present in all browsers)
+ * @param contexts Array of custom contexts
+ */
+ apiMethods.trackError = function (message, filename, lineno, colno, error, contexts) {
+ var enrichedContexts = addCommonContexts(contexts);
+ errorManager.trackError(message, filename, lineno, colno, error, enrichedContexts);
+ };
+
+ /**
+ * Stop regenerating `pageViewId` (available from `web_page` context)
+ */
+ apiMethods.preservePageViewId = function () {
+ preservePageViewId = true
+ };
+
+ apiMethods.setDebug = function (isDebug) {
+ debug = Boolean(isDebug).valueOf();
+ updateReturnMethods();
+ };
+
+ // Create guarded methods from apiMethods,
+ // and set returnMethods to apiMethods or safeMethods depending on value of debug
+ safeMethods = productionize(apiMethods);
+ updateReturnMethods();
+
+ return returnMethods;
+ };
+}());
diff --git a/snowplow-javascript-tracker/tags/tag.js b/snowplow-javascript-tracker/tags/tag.js
new file mode 100644
index 0000000000..bfb5409654
--- /dev/null
+++ b/snowplow-javascript-tracker/tags/tag.js
@@ -0,0 +1,81 @@
+/*
+ * JavaScript tracker for Snowplow: tag.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Use this function to load Snowplow
+ *
+ * @param object p The window
+ * @param object l The document
+ * @param string o "script", the tag name of script elements
+ * @param string w The source of the Snowplow script. Make sure you get the latest version.
+ * @param string i The Snowplow namespace. The Snowplow user should set this.
+ * @param undefined n The new script (to be created inside the function)
+ * @param undefined g The first script on the page (to be found inside the function)
+ */
+;(function(p,l,o,w,i,n,g) {
+ "p:nomunge, l:nomunge, o:nomunge, w:nomunge, i:nomunge, n:nomunge, g:nomunge";
+
+ // Stop if the Snowplow namespace i already exists
+ if (!p[i]) {
+
+ // Initialise the 'GlobalSnowplowNamespace' array
+ p['GlobalSnowplowNamespace'] = p['GlobalSnowplowNamespace'] || [];
+
+ // Add the new Snowplow namespace to the global array so sp.js can find it
+ p['GlobalSnowplowNamespace'].push(i);
+
+ // Create the Snowplow function
+ p[i] = function() {
+ (p[i].q = p[i].q || []).push(arguments);
+ };
+
+ // Initialise the asynchronous queue
+ p[i].q = p[i].q || [];
+
+ // Create a new script element
+ n = l.createElement(o);
+
+ // Get the first script on the page
+ g = l.getElementsByTagName(o)[0];
+
+ // The new script should load asynchronously
+ n.async = 1;
+
+ // Load Snowplow
+ n.src = w;
+
+ // Insert the Snowplow script before every other script so it executes as soon as possible
+ g.parentNode.insertBefore(n,g);
+ }
+} (window, document, 'script', '//d1fc8wv8zag5ca.cloudfront.net/2/sp.js', 'new_name_here'));
diff --git a/snowplow-javascript-tracker/tests/functional/detectors.js b/snowplow-javascript-tracker/tests/functional/detectors.js
new file mode 100644
index 0000000000..a7fb5ac6a7
--- /dev/null
+++ b/snowplow-javascript-tracker/tests/functional/detectors.js
@@ -0,0 +1,201 @@
+/*
+ * JavaScript tracker for Snowplow: tests/functional/detectors.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+define([
+ 'intern!object',
+ 'intern/chai!assert'
+], function(registerSuite, assert) {
+
+ var
+ // Expected viewport dimensions vary based on browser
+ expectedViewportWidths = [
+ 996,
+ 1008, // Windows 8, Windows 8.1
+ 1016, // Linux, Firefox 27
+ 1014, // Windows 7, Chrome 32
+ 1022,
+ 1024, // Windows 7, IE 9, Firefox 27; Mac OS, Safari
+ 1020 // Windows 8, Windows 8.1
+ ],
+ expectedViewportHeights = [
+ 660, // Firefox 27.0, Linux
+ 632, // Firefox 27.0, Linux
+ 658, // Firefox 27.0, Windows 7
+ 666,
+ 670, // Safari 6/7
+ 687, // Windows 7, IE 9
+ 694, // Chrome 32, Windows 7 - 707
+ 695, // Windows 7, IE 9
+ 686, // Chrome 32, Linux - 686
+ 705, // Windows 8/8.1
+ 717 // Windows 8/8.1
+ ],
+
+ // User fingerprint varies based on browser features
+ // TODO: try to hash this off the useragent -
+ // i.e. formal 1:1 relationship between viewport or signature and an individual browser
+ expectedSignatures = [
+ 1587753772, // IE9, Windows 7
+ 1101697779, // IE10, Windows 8
+ 645783373, // IE11, Windows 8
+ 580945094, // Firefox 27.0, Windows 7
+ 1382842778, // Firefox 27.0, Linux
+ 1727588738, // Chrome 32.0, Windows 7
+ 3978691790, // Chrome 32.0, Linux
+ 3552180943, // Safari 7, OS X 10.9
+ 812921052 // Safari 6.2.7 Mac OS X 10.8
+ ];
+
+ registerSuite({
+
+ name: 'Detectors test',
+
+ // These tests don't work as intended.
+ // I tend to blame SauceLabs on this, because it can fail on one of two subsequent runs
+ // on equal environments, while these functions are fully deterministic.
+ //
+ // 'Get viewport dimensions': function() {
+ //
+ // return this.remote
+ // .get(require.toUrl('tests/pages/detectors.html'))
+ // .setFindTimeout(5000)
+ // .setWindowSize(1024, 768)
+ // .findByCssSelector('body.loaded')
+ // .findById('detectViewport')
+ // .getVisibleText()
+ // .then(function (text) {
+ // var dimensions = text.split('x');
+ // assert.include(expectedViewportWidths, parseInt(dimensions[0]), 'Viewport width is valid');
+ // assert.include(expectedViewportHeights, parseInt(dimensions[1]), 'Viewport height is valid');
+ // });
+ // },
+ //
+ // 'Detect document size': function () {
+ // return this.remote
+ // .get(require.toUrl('tests/pages/detectors.html'))
+ // .setFindTimeout(5000)
+ // .setWindowSize(1024, 768)
+ // .findByCssSelector('body.loaded')
+ // .findById('detectDocumentDimensions')
+ // .getVisibleText()
+ // .then(function (text) {
+ // var dimensions = text.split('x');
+ // assert.include(expectedViewportWidths, parseInt(dimensions[0]), 'Document width is valid');
+ // assert.include(expectedViewportHeights, parseInt(dimensions[1]), 'Document height is valid');
+ // });
+ // },
+ //
+ // 'User fingerprinting': function() {
+ //
+ // return this.remote
+ // .get(require.toUrl('tests/pages/detectors.html'))
+ // .setFindTimeout(5000)
+ // .setWindowSize(1024, 768)
+ // .findByCssSelector('body.loaded')
+ // .findById('detectSignature')
+ // .getVisibleText()
+ // .then(function (text) {
+ // assert.include(expectedSignatures, parseInt(text), 'Create a user fingerprint based on browser features');
+ // });
+ // },
+
+ 'Check localStorage availability': function() {
+
+ return this.remote
+ .get(require.toUrl('tests/pages/detectors.html'))
+ .setFindTimeout(5000)
+ .findByCssSelector('body.loaded')
+ .findById('localStorageAccessible')
+ .getVisibleText()
+ .then(function (text) {
+ assert.strictEqual(text, 'true', 'Detect localStorage accessibility');
+ });
+ },
+
+ 'Check sessionStorage availability': function() {
+
+ return this.remote
+ .get(require.toUrl('tests/pages/detectors.html'))
+ .setFindTimeout(5000)
+ .findByCssSelector('body.loaded')
+ .findById('hasSessionStorage')
+ .getVisibleText()
+ .then(function (text) {
+ assert.strictEqual(text, 'true', 'Detect sessionStorage');
+ });
+ },
+
+ 'Check whether cookies are enabled': function() {
+
+ return this.remote
+ .get(require.toUrl('tests/pages/detectors.html'))
+ .setFindTimeout(5000)
+ .findByCssSelector('body.loaded')
+ .findById('hasCookies')
+ .getVisibleText()
+ .then(function (text) {
+ assert.equal(text, '1', 'Detect whether cookies can be set');
+ });
+ },
+
+ 'Detect timezone': function() {
+
+ return this.remote
+ .get(require.toUrl('tests/pages/detectors.html'))
+ .setFindTimeout(5000)
+ .findByCssSelector('body.loaded')
+ .findById('detectTimezone')
+ .getVisibleText()
+ .then(function (text) {
+ assert.include(['UTC', 'America/Los_Angeles'], text, 'Detect the timezone');
+ });
+ },
+
+ 'Browser features': function() {
+
+ return this.remote
+ .get(require.toUrl('tests/pages/detectors.html'))
+ .setFindTimeout(5000)
+ .findByCssSelector('body.loaded')
+ .findById('detectBrowserFeatures')
+ .getVisibleText()
+ .then(function (text) {
+ var features = JSON.parse(text);
+ // The only features which are the same for all tested browsers
+ assert.equal('1', features.java, 'Detect Java');
+ assert.equal(24, features.cd, 'Detect color depth');
+ });
+ }
+ });
+});
diff --git a/snowplow-javascript-tracker/tests/functional/helpers.js b/snowplow-javascript-tracker/tests/functional/helpers.js
new file mode 100644
index 0000000000..543d9e632f
--- /dev/null
+++ b/snowplow-javascript-tracker/tests/functional/helpers.js
@@ -0,0 +1,98 @@
+/*
+ * JavaScript tracker for Snowplow: tests/functional/helpers.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+define([
+ 'intern!object',
+ 'intern/chai!assert',
+ 'intern/dojo/node!../../src/js/lib/helpers'
+], function(registerSuite, assert, helpers) {
+
+ registerSuite({
+
+ name: 'Helpers test',
+
+ 'Get page title': function() {
+
+ return this.remote
+ .get(require.toUrl('tests/pages/helpers.html'))
+ .setFindTimeout(5000)
+ .findByCssSelector('body.loaded')
+ .findById('title')
+ .getVisibleText()
+ .then(function (text) {
+ assert.strictEqual(text, 'Helpers test page', 'Get the page title' );
+ });
+ },
+
+ 'Get host name': function() {
+
+ return this.remote
+ .get(require.toUrl('tests/pages/helpers.html'))
+ .setFindTimeout(5000)
+ .findByCssSelector('body.loaded')
+ .findById('hostname')
+ .getVisibleText()
+ .then(function (text){
+ assert.strictEqual(text, 'localhost', 'Get the host name');
+ });
+ },
+
+ 'Get referrer from querystring': function() {
+
+ return this.remote
+ .get(require.toUrl('tests/pages/helpers.html') + '?name=value&referrer=previous#fragment')
+ .setFindTimeout(5000)
+ .findByCssSelector('body.loaded')
+ .findById('referrer')
+ .getVisibleText()
+ .then(function (text){
+ assert.strictEqual(text, 'previous', 'Get the referrer from the querystring');
+ });
+ },
+
+ 'Add event listener': function() {
+
+ return this.remote
+ .get(require.toUrl('tests/pages/helpers.html'))
+ .setFindTimeout(5000)
+ .findByCssSelector('body.loaded')
+ .findById('click')
+ .click()
+ .getVisibleText()
+ .then(function (text){
+ assert.strictEqual(text, 'clicked', 'Add a click event listener');
+ });
+ }
+ });
+});
diff --git a/snowplow-javascript-tracker/tests/integration/integration.js b/snowplow-javascript-tracker/tests/integration/integration.js
new file mode 100755
index 0000000000..7d644bba3e
--- /dev/null
+++ b/snowplow-javascript-tracker/tests/integration/integration.js
@@ -0,0 +1,320 @@
+/*
+ * JavaScript tracker for Snowplow: tests/functional/helpers.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2016 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+define([
+ 'intern!object',
+ 'intern/chai!assert',
+ 'intern/dojo/node!lodash',
+ 'intern/dojo/node!http',
+ 'intern/dojo/node!url',
+ "intern/dojo/node!js-base64"
+], function(registerSuite, assert, lodash, http, url, jsBase64) {
+ var decodeBase64 = jsBase64.Base64.fromBase64;
+
+ /**
+ * Expected amount of request for each browser
+ * This must be increased when new tracking call added to
+ * pages/integration-template.html
+ */
+ var log = [];
+
+ function pageViewsHaveDifferentIds () {
+ var pageViews = lodash.filter(log, function (logLine) {
+ return logLine.e === 'pv';
+ });
+ var contexts = lodash.map(pageViews, function (logLine) {
+ var data = JSON.parse(decodeBase64(logLine.cx)).data;
+ return lodash.find(data, function (context) {
+ return context.schema === 'iglu:com.snowplowanalytics.snowplow/web_page/jsonschema/1-0-0';
+ });
+ });
+ var ids = lodash.map(contexts, function (wpContext) {
+ return wpContext.data.id;
+ });
+
+ return lodash.uniq(ids).length >= 2;
+ }
+
+ /**
+ * Check if expected payload exists in `log`
+ */
+ function checkExistenceOfExpectedQuerystring(expected) {
+ function compare(e, other) { // e === expected
+ var result = lodash.map(e, function (v, k) {
+ if (lodash.isFunction(v)) { return v(other[k]); }
+ else { return lodash.isEqual(v, other[k]); }
+ });
+ return lodash.every(result);
+ }
+
+ function strip(logLine) {
+ var expectedKeys = lodash.keys(expected);
+ var stripped = lodash.pickBy(logLine, function (v, k) { return lodash.includes(expectedKeys, k); });
+ if (lodash.keys(stripped).length !== expectedKeys.length) { return null; }
+ else { return stripped; }
+ }
+
+ return lodash.some(log, function (logLine) {
+ var stripped = strip(logLine);
+ if (stripped == null) { return false; }
+ else { return lodash.isEqualWith(expected, stripped, compare); }
+ });
+ }
+
+ function someTestsFailed(suite) {
+ return lodash.some(suite.tests, function (test) { return test.error !== null; });
+ }
+
+ // Ngrok must be running to forward requests to localhost
+ http.createServer(function (request, response) {
+ response.writeHead(200, {'Content-Type': 'image/gif'});
+
+ if (request.method === 'GET') {
+ var payload = url.parse(request.url, true).query;
+ log.push(payload);
+ }
+
+ var img = new Buffer('47494638396101000100800000dbdfef00000021f90401000000002c00000000010001000002024401003b', 'hex');
+ response.end(img, 'binary');
+
+ }).listen(8500, function () { console.log("Collector mock running...\n"); });
+
+ registerSuite({
+
+ teardown: function () {
+ if (someTestsFailed(this)) {
+ console.log("Tests failed with following log:");
+ lodash.forEach(log, function (l) { console.log(l); });
+ }
+ console.log("Cleaning log");
+ log = [];
+ },
+
+ name: 'Test that request_recorder logs meet expectations',
+
+ 'Check existence of page view in log': function () {
+ assert.isTrue(checkExistenceOfExpectedQuerystring({
+ e: 'pv',
+ p: 'mob',
+ aid: 'CFe23a',
+ uid: 'Malcolm',
+ page: 'My Title',
+ cx: function (cx) {
+ var contexts = JSON.parse(decodeBase64(cx)).data;
+ return lodash.some(contexts,
+ lodash.matches({
+ schema:"iglu:com.example_company/user/jsonschema/2-0-0",
+ data:{
+ userType:'tester'
+ }
+ })
+ );
+ }
+ }), 'A page view should be detected');
+ },
+
+ 'Check nonexistence of nonexistent event types in log': function () {
+ assert.isFalse(checkExistenceOfExpectedQuerystring({
+ e: 'ad'
+ }), 'No nonexistent event type should be detected');
+ },
+
+ 'Check a structured event was sent': function () {
+ assert.isTrue(checkExistenceOfExpectedQuerystring({
+ e: 'se',
+ se_ca: 'Mixes',
+ se_ac: 'Play',
+ se_la: 'MRC/fabric-0503-mix',
+ se_va: '0.0'
+ }), 'A structured event should be detected');
+ },
+
+ 'Check an unstructured event with true timestamp was sent': function () {
+ assert.isTrue(checkExistenceOfExpectedQuerystring({
+ e: 'ue',
+ ue_px: 'eyJzY2hlbWEiOiJpZ2x1OmNvbS5zbm93cGxvd2FuYWx5dGljcy5zbm93cGxvdy91bnN0cnVjdF9ldmVudC9qc29uc2NoZW1hLzEtMC0wIiwiZGF0YSI6eyJzY2hlbWEiOiJpZ2x1OmNvbS5hY21lX2NvbXBhbnkvdmlld2VkX3Byb2R1Y3QvanNvbnNjaGVtYS81LTAtMCIsImRhdGEiOnsicHJvZHVjdElkIjoiQVNPMDEwNDMifX19',
+ ttm: '1477401868'
+ }), 'An unstructured event should be detected');
+ },
+
+ 'Check a transaction event was sent': function () {
+ assert.isTrue(checkExistenceOfExpectedQuerystring({
+ e: 'tr',
+ tr_id: 'order-123',
+ tr_af: 'acme',
+ tr_tt: '8000',
+ tr_tx: '100',
+ tr_ci: 'phoenix',
+ tr_st: 'arizona',
+ tr_co: 'USA',
+ tr_cu: 'JPY'
+ }), 'A transaction event should be detected');
+ },
+
+ 'Check a transaction item event was sent': function () {
+ assert.isTrue(checkExistenceOfExpectedQuerystring({
+ e: 'ti',
+ ti_id: 'order-123',
+ ti_sk: '1001',
+ ti_nm: 'Blue t-shirt',
+ ti_ca: 'clothing',
+ ti_pr: '2000',
+ ti_qu: '2',
+ ti_cu: 'JPY'
+ }), 'A transaction item event should be detected');
+ },
+
+ 'Check an unhandled exception was sent': function () {
+ assert.isTrue(checkExistenceOfExpectedQuerystring({
+ ue_px: function (ue) {
+ var event = JSON.parse(decodeBase64(ue)).data;
+ // We cannot test more because implementations vary much in old browsers (FF27,IE9)
+ return (event.schema === 'iglu:com.snowplowanalytics.snowplow/application_error/jsonschema/1-0-1') &&
+ (event.data.programmingLanguage === 'JAVASCRIPT') &&
+ (event.data.message != null);
+ }
+ }));
+ },
+
+ 'Check pageViewId is regenerated for each trackPageView': function () {
+ assert.isTrue(pageViewsHaveDifferentIds());
+ },
+
+ 'Check global contexts are for structured events': function () {
+ assert.isTrue(checkExistenceOfExpectedQuerystring({
+ e: 'se',
+ cx: function (cx) {
+ var contexts = JSON.parse(decodeBase64(cx)).data;
+ return 2 === lodash.size(
+ lodash.filter(contexts,
+ lodash.overSome(
+ lodash.matches({
+ schema: "iglu:com.snowplowanalytics.snowplow/mobile_context/jsonschema/1-0-1",
+ data: {
+ osType: 'ubuntu'
+ }
+ }),
+ lodash.matches({
+ schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0',
+ data: {
+ 'latitude': 40.0,
+ 'longitude': 55.1
+ }
+ })
+ )
+ )
+ );
+ }
+ }));
+ },
+
+ 'Check an unstructured event with global context from accept ruleset': function () {
+ assert.isTrue(checkExistenceOfExpectedQuerystring({
+ e: 'ue',
+ ue_px: function (ue_px) {
+ var event = JSON.parse(decodeBase64(ue_px)).data;
+ return lodash.isMatch(event,
+ {
+ schema:"iglu:com.acme_company/viewed_product/jsonschema/5-0-0",
+ data:{
+ productId: 'ASO01042'
+ }
+ }
+ );
+ },
+ cx: function (cx) {
+ var contexts = JSON.parse(decodeBase64(cx)).data;
+ return 2 === lodash.size(
+ lodash.filter(contexts,
+ lodash.overSome(
+ lodash.matches({
+ schema: "iglu:com.snowplowanalytics.snowplow/mobile_context/jsonschema/1-0-1",
+ data: {
+ osType: 'ubuntu'
+ }
+ }),
+ lodash.matches({
+ schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0',
+ data: {
+ 'latitude': 40.0,
+ 'longitude': 55.1
+ }
+ })
+ )
+ )
+ );
+ }
+ }), 'An unstructured event with global contexts should be detected');
+ },
+
+ 'Check an unstructured event missing global context from reject ruleset': function () {
+ assert.isTrue(checkExistenceOfExpectedQuerystring({
+ e: 'ue',
+ ue_px: function (ue_px) {
+ var event = JSON.parse(decodeBase64(ue_px)).data;
+ return lodash.isMatch(event,
+ {
+ schema:"iglu:com.acme_company/viewed_product/jsonschema/5-0-0",
+ data:{
+ productId: 'ASO01041'
+ }
+ }
+ );
+ },
+ cx: function (cx) {
+ var contexts = JSON.parse(decodeBase64(cx)).data;
+ return 0 === lodash.size(
+ lodash.filter(contexts,
+ lodash.overSome(
+ lodash.matches({
+ schema: "iglu:com.snowplowanalytics.snowplow/mobile_context/jsonschema/1-0-1",
+ data: {
+ osType: 'ubuntu'
+ }
+ }),
+ lodash.matches({
+ schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0',
+ data: {
+ 'latitude': 40.0,
+ 'longitude': 55.1
+ }
+ })
+ )
+ )
+ );
+ }
+ }), 'An unstructured event without global contexts should be detected');
+ }
+ });
+});
diff --git a/snowplow-javascript-tracker/tests/integration/setup.js b/snowplow-javascript-tracker/tests/integration/setup.js
new file mode 100644
index 0000000000..0689b99708
--- /dev/null
+++ b/snowplow-javascript-tracker/tests/integration/setup.js
@@ -0,0 +1,52 @@
+/*
+ * JavaScript tracker for Snowplow: tests/functional/detectors.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+define([
+ 'intern!object'
+], function(registerSuite) {
+
+ registerSuite({
+
+ name: 'Integration setup',
+
+ 'Set up the page and send some events to request_recorder': function() {
+
+ return this.remote
+ .get(require.toUrl('tests/pages/integration.html'))
+ .setFindTimeout(5000)
+ .findByCssSelector('body.loaded')
+ .sleep(15000); // Time for requests to get written
+ }
+ });
+});
diff --git a/snowplow-javascript-tracker/tests/intern.js b/snowplow-javascript-tracker/tests/intern.js
new file mode 100644
index 0000000000..b143f25b98
--- /dev/null
+++ b/snowplow-javascript-tracker/tests/intern.js
@@ -0,0 +1,61 @@
+/*
+ * JavaScript tracker for Snowplow: tests/intern.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+define({
+
+ capabilities: {
+ 'selenium-version': '2.48.0'
+ },
+
+ environments: [
+ { browserName: 'internet explorer', version: '11', platform: 'Windows 8.1' },
+ { browserName: 'internet explorer', version: '10', platform: 'Windows 8' },
+ { browserName: 'internet explorer', version: '9', platform: 'Windows 7' },
+ { browserName: 'firefox', version: '27', platform: [ 'Windows 7', 'Linux' ] },
+ { browserName: 'chrome', version: '32', platform: [ 'Windows 7', 'Linux' ] },
+ { browserName: 'safari', version: '8', platform: 'OS X 10.10' },
+ { browserName: 'safari', version: '10', platform: 'OS X 10.11' }
+ ],
+
+ maxConcurrency: 1,
+
+ tunnel: 'SauceLabsTunnel',
+ tunnelOptions: {
+ logFile: process.cwd() + '/SauceLabsTunnel.log'
+ },
+
+ // A regular expression matching URLs to files that should not be included in code coverage analysis
+ excludeInstrumentation: /^(?:tests|node_modules)\//
+
+});
diff --git a/snowplow-javascript-tracker/tests/local/http-server.py b/snowplow-javascript-tracker/tests/local/http-server.py
new file mode 100644
index 0000000000..a1dac7da6f
--- /dev/null
+++ b/snowplow-javascript-tracker/tests/local/http-server.py
@@ -0,0 +1,71 @@
+import os
+import sys
+from http.server import HTTPServer, BaseHTTPRequestHandler
+from http.client import NO_CONTENT
+from pprint import pprint
+
+
+gif_string = b'GIF87a\x01\x00\x01\x00\x80\x00\x00\xff\xff\xff\xff\xff\xff,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;'
+file_path = os.path.dirname(__file__)
+
+def get_serve(file):
+ return os.path.join(file_path, 'serve', file)
+
+class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
+
+ def do_HEAD(self):
+ self.send_response(200)
+ if (self.path == '/integration.html'):
+ self.send_header("Content-type", "text/html")
+ self.end_headers()
+ else:
+ self.send_header("Content-type", "image/gif")
+ self.end_headers()
+
+
+ def do_GET(self):
+ """Respond to a GET request."""
+ self.send_response(200)
+ if (self.path == '/integration.html'):
+ self.send_header("Content-type", "text/html")
+ self.end_headers()
+ f = open(get_serve('integration.html'), "rb")
+ body = f.read()
+ f.close()
+ self.wfile.write(body)
+ elif (self.path == '/snowplow.js'):
+ self.send_header("Content-type", "text/html")
+ self.end_headers()
+ f = open(get_serve('snowplow.js'), "rb")
+ body = f.read()
+ f.close()
+ self.wfile.write(body)
+ else:
+ self.send_header("Content-type", "image/gif")
+ self.end_headers()
+ self.wfile.write(gif_string)
+
+ def do_POST(self):
+ self.send_response(200)
+ self.send_header("Content-type", "image/gif")
+ self.end_headers()
+ self.wfile.write(''.encode())
+ content_len = int(self.headers.get('content-length', 0))
+ post_body = self.rfile.read(content_len)
+ pprint(post_body)
+
+ def do_OPTIONS(self):
+ self.send_response(200)
+ self.send_header('Access-Control-Allow-Origin', 'null')
+ self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
+ self.send_header("Access-Control-Allow-Headers", "X-Requested-With")
+ self.send_header("Access-Control-Allow-Headers", "Content-Type")
+ self.end_headers()
+
+
+httpd = HTTPServer(('127.0.0.1', 8000), SimpleHTTPRequestHandler)
+try:
+ httpd.serve_forever()
+except KeyboardInterrupt:
+ print('User closed server with Ctrl-c')
+ sys.exit(0)
diff --git a/snowplow-javascript-tracker/tests/nonfunctional/helpers.js b/snowplow-javascript-tracker/tests/nonfunctional/helpers.js
new file mode 100644
index 0000000000..9a137b7890
--- /dev/null
+++ b/snowplow-javascript-tracker/tests/nonfunctional/helpers.js
@@ -0,0 +1,156 @@
+/*
+ * JavaScript tracker for Snowplow: tests/nonfunctional/helpers.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+define([
+ "intern!object",
+ "intern/chai!assert",
+ "intern/dojo/node!../../src/js/lib/helpers"
+], function (registerSuite, assert, helpers) {
+
+ var decorateQuerystring = helpers.decorateQuerystring;
+ var resolveDynamicContexts = helpers.resolveDynamicContexts;
+
+ registerSuite({
+ name: "decorateQuerystring test",
+ "Decorate a URL with no querystring or fragment": function () {
+ var url = 'http://www.example.com';
+ var expected = 'http://www.example.com?_sp=a.b';
+ var actual = decorateQuerystring(url, '_sp', 'a.b');
+ assert.equal(actual, expected);
+ },
+
+ "Decorate a URL with a fragment but no querystring": function () {
+ var url = 'http://www.example.com#fragment';
+ var expected = 'http://www.example.com?_sp=a.b#fragment';
+ var actual = decorateQuerystring(url, '_sp', 'a.b');
+ assert.equal(actual, expected);
+ },
+
+ "Decorate a URL with an empty querystring": function () {
+ var url = 'http://www.example.com?';
+ var expected = 'http://www.example.com?_sp=a.b';
+ var actual = decorateQuerystring(url, '_sp', 'a.b');
+ assert.equal(actual, expected);
+ },
+
+ "Decorate a URL with a nonempty querystring": function () {
+ var url = 'http://www.example.com?name=value';
+ var expected = 'http://www.example.com?_sp=a.b&name=value';
+ var actual = decorateQuerystring(url, '_sp', 'a.b');
+ assert.equal(actual, expected);
+ },
+
+ "Override an existing field": function () {
+ var url = 'http://www.example.com?_sp=outdated';
+ var expected = 'http://www.example.com?_sp=a.b';
+ var actual = decorateQuerystring(url, '_sp', 'a.b');
+ assert.equal(actual, expected);
+ },
+
+ "Decorate a URL whose querystring contains multiple question marks": function () {
+ var url = 'http://www.example.com?test=working?&name=value';
+ var expected = 'http://www.example.com?_sp=a.b&test=working?&name=value';
+ var actual = decorateQuerystring(url, '_sp', 'a.b');
+ assert.equal(actual, expected);
+ },
+
+ "Override a field in a querystring containing a question mark": function () {
+ var url = 'http://www.example.com?test=working?&_sp=outdated';
+ var expected = 'http://www.example.com?test=working?&_sp=a.b';
+ var actual = decorateQuerystring(url, '_sp', 'a.b');
+ assert.equal(actual, expected);
+ },
+
+ "Decorate a querystring with multiple ?s and #s": function () {
+ var url = 'http://www.example.com?test=working?&_sp=outdated?&?name=value#fragment?#?#';
+ var expected = 'http://www.example.com?test=working?&_sp=a.b&?name=value#fragment?#?#';
+ var actual = decorateQuerystring(url, '_sp', 'a.b');
+ assert.equal(actual, expected);
+ },
+ });
+
+ registerSuite({
+ name: "getCssClasses test",
+ "Tokenize a DOM element's className field": function () {
+ var element = {
+ className: ' the quick brown_fox-jumps/over\nthe\t\tlazy dog '
+ };
+ var expected = ['the', 'quick', 'brown_fox-jumps/over', 'the', 'lazy', 'dog'];
+ var actual = helpers.getCssClasses(element);
+ assert.deepEqual(actual, expected);
+ },
+ });
+
+ registerSuite({
+ name: "resolveDynamicContexts tests",
+ "Resolves context generators and static contexts": function () {
+ var contextGenerator = function () {
+ return {
+ 'schema': 'iglu:com.acme.marketing/some_event/jsonschema/1-0-0',
+ 'data': {'test': 1}
+ }
+ };
+ var staticContext = {
+ 'schema': 'iglu:com.acme.marketing/some_event/jsonschema/1-0-0',
+ 'data': {'test': 1}
+ };
+ var expected = [contextGenerator(), staticContext];
+ var actual = resolveDynamicContexts([contextGenerator, staticContext]);
+ assert.deepEqual(actual, expected);
+ },
+
+ "Resolves context generators with arguments": function () {
+ var contextGenerator = function (argOne, argTwo) {
+ return {
+ 'schema': 'iglu:com.acme.marketing/some_event/jsonschema/1-0-0',
+ 'data': {
+ 'firstVal': argOne,
+ 'secondVal': argTwo
+ }
+ }
+ };
+ var expected = [
+ {
+ 'schema': 'iglu:com.acme.marketing/some_event/jsonschema/1-0-0',
+ 'data': {
+ 'firstVal': 1,
+ 'secondVal': 2
+ }
+ }
+ ];
+ var actual = resolveDynamicContexts([contextGenerator], 1, 2);
+ assert.deepEqual(actual, expected);
+ },
+ });
+});
diff --git a/snowplow-javascript-tracker/tests/nonfunctional/in_queue.js b/snowplow-javascript-tracker/tests/nonfunctional/in_queue.js
new file mode 100755
index 0000000000..341d3cd969
--- /dev/null
+++ b/snowplow-javascript-tracker/tests/nonfunctional/in_queue.js
@@ -0,0 +1,104 @@
+/*
+ * JavaScript tracker for Snowplow: tests/nonfunctional/in_queue.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+define([
+ "intern!object",
+ "intern/chai!assert",
+ "intern/dojo/node!../../src/js/in_queue"
+], function(registerSuite, assert, in_queue) {
+
+ var output = 0;
+
+ function mockTrackerConstructor (functionName, namespace, version, mutSnowplowState, argmap) {
+ var configCollectorUrl,
+ attribute = 10;
+
+ return {
+ setCollectorUrl: function(rawUrl) {
+ configCollectorUrl = "http://" + rawUrl + "/i";
+ },
+ increaseAttribute: function(n) {
+ attribute += n;
+ },
+ setAttribute: function(p) {
+ attribute = p;
+ },
+ setOutputToAttribute: function() {
+ output = attribute;
+ },
+ addAttributeToOutput: function() {
+ output += attribute;
+ }
+ };
+ }
+
+ var asyncQueue = [
+ ["newTracker", "firstTracker", "firstEndpoint"],
+ ["increaseAttribute", 5],
+ ["setOutputToAttribute"]
+ ];
+ asyncQueue = new in_queue.InQueueManager(mockTrackerConstructor, 0, {}, asyncQueue, 'snowplow');
+
+ registerSuite({
+ name: "InQueueManager test",
+ "Make a proxy": function() {
+ assert.equal(output, 15, "Function originally stored in asyncQueue is executed when asyncQueue becomes an AsyncQueueProxy");
+ },
+
+ "Add to asyncQueue after conversion": function() {
+ asyncQueue.push(["setAttribute", 7]);
+ asyncQueue.push(["setOutputToAttribute"]);
+ assert.equal(output, 7, "Function added to asyncQueue after it becomes an AsyncQueueProxy is executed");
+ },
+
+ "Backward compatibility: Create a tracker using the legacy setCollectorUrl method": function() {
+ asyncQueue.push(["setCollectorUrl", "secondEndpoint"]);
+ asyncQueue.push(["addAttributeToOutput"]);
+ assert.equal(output, 24, "A second tracker is created and both trackers' attributes are added to output");
+ },
+
+ "Use 'function:tracker1;tracker2' syntax to control which trackers execute which functions": function() {
+ asyncQueue.push(["setAttribute:firstTracker", 2]);
+ asyncQueue.push(["setAttribute:sp", 3]);
+ asyncQueue.push(["addAttributeToOutput:firstTracker;sp"]);
+ assert.equal(output, 29, "Set the attributes of the two trackers individually, then add both to output");
+ },
+
+ "Execute a user-defined custom callback": function () {
+ var callbackExecuted = false;
+ asyncQueue.push([function () { callbackExecuted = true; }]);
+ assert.isTrue(callbackExecuted);
+ }
+ });
+});
diff --git a/snowplow-javascript-tracker/tests/nonfunctional/proxies.js b/snowplow-javascript-tracker/tests/nonfunctional/proxies.js
new file mode 100644
index 0000000000..fd082eac2b
--- /dev/null
+++ b/snowplow-javascript-tracker/tests/nonfunctional/proxies.js
@@ -0,0 +1,141 @@
+/*
+ * JavaScript tracker for Snowplow: tests/nonfunctional/proxies.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+define([
+ "intern!object",
+ "intern/chai!assert",
+ "intern/dojo/node!../../src/js/lib/proxies"
+], function(registerSuite, assert, proxies) {
+
+ this.document = {
+ links: [{href: "http://www.example.com/"}],
+ body: {
+ children: [{
+ children: [{
+ children: [{
+ children: [{
+ children: [{
+ children: [{
+ innerHTML: 'You have reached the cached page for'
+ }]
+ }]
+ }]
+ }]
+ }]
+ }]
+ }
+ };
+
+ registerSuite({
+
+ "name": "Proxies test",
+
+ "Host name is not a special case": function() {
+
+ var
+ initialLocationArray = ["normalhostname", "href", "http://referrer.com"],
+ fixedupLocationArray = proxies.fixupUrl.apply(null, initialLocationArray),
+ expectedLocationArray = fixedupLocationArray,
+ i;
+
+ for (i = 0; i < 3; i++) {
+ assert.strictEqual(fixedupLocationArray[i], expectedLocationArray[i], 'Except in special cases, fixupUrl changes nothing');
+ }
+ },
+
+ "Host name = 'translate.googleusercontent.com'": function() {
+ var
+ initialLocationArray = [
+ "translate.googleusercontent.com",
+ "http://translate.googleusercontent.com/translate?hl=en&sl=fr&u=http:www.francais.fr/path",
+ ""],
+ fixedupLocationArray = proxies.fixupUrl.apply(null, initialLocationArray),
+ expectedLocationArray = [
+ "www.francais.fr",
+ "http:www.francais.fr/path",
+ "http://translate.googleusercontent.com/translate?hl=en&sl=fr&u=http:www.francais.fr/path"],
+ i;
+
+ for (i = 0; i < 3; i++) {
+ assert.strictEqual(fixedupLocationArray[i], expectedLocationArray[i], 'Get the URL for the untranslated page from the querystring and make the translated page the referrer');
+ }
+ },
+
+ "Host name = 'ccj.bingj.com'": function() {
+ var
+ initialLocationArray = [
+ "cc.bingj.com",
+ "http://cc.bingj.com/cache.aspx?q=example.com&d=4870936571937837&mkt=en-GB&setlang=en-GB&w=QyOPD1fo3C2nC9sXMLmUUs81Jt78MYIp",
+ "http://referrer.com"],
+ fixedupLocationArray = proxies.fixupUrl.apply(null, initialLocationArray),
+ expectedLocationArray = [ "www.example.com", "http://www.example.com/", "http://referrer.com" ],
+ i;
+
+ for (i = 0; i < 3; i++) {
+ assert.strictEqual(fixedupLocationArray[i], expectedLocationArray[i], 'On a page cached by Bing, get the original URL from the first link');
+ }
+ },
+
+ "Host name = 'webcache.googleusercontent.com'": function() {
+ var
+ initialLocationArray = [
+ "webcache.googleusercontent.com",
+ "http://webcache.googleusercontent.com/search?q=cache:http://example.com/#fragment",
+ "http://referrer.com"],
+ fixedupLocationArray = proxies.fixupUrl.apply(null, initialLocationArray),
+ expectedLocationArray = [ "www.example.com", "http://www.example.com/", "http://referrer.com" ],
+ i;
+
+ for (i = 0; i < 3; i++) {
+ assert.strictEqual(fixedupLocationArray[i], expectedLocationArray[i], 'On a page cached by Google, get the original URL from the first link');
+ }
+ },
+
+
+ "Host name is an IP address": function() {
+ var
+ initialLocationArray = [
+ "98.139.21.31",
+ "http://98.139.21.31/search/srpcache",
+ "http://referrer.com"],
+ fixedupLocationArray = proxies.fixupUrl.apply(null, initialLocationArray),
+ expectedLocationArray = [ "www.example.com", "http://www.example.com/", "http://referrer.com" ],
+ i;
+
+ for (i = 0; i < 3; i++) {
+ assert.strictEqual(fixedupLocationArray[i], expectedLocationArray[i], 'On a page cached by Yahoo, get the original URL from the first link');
+ }
+ }
+ })
+});
diff --git a/snowplow-javascript-tracker/tests/pages/detectors.html b/snowplow-javascript-tracker/tests/pages/detectors.html
new file mode 100644
index 0000000000..fdccf3911c
--- /dev/null
+++ b/snowplow-javascript-tracker/tests/pages/detectors.html
@@ -0,0 +1,25 @@
+
+
+
+ Detectors test page
+
+
+
Viewport dimensions here
+
Document dimensions here
+
localStorage accessibility here
+
sessionStorage here
+
hasCookies here
+
Timezone here
+
User fingerprint here
+
User fingerprint here
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/snowplow-javascript-tracker/tests/pages/helpers.html b/snowplow-javascript-tracker/tests/pages/helpers.html
new file mode 100644
index 0000000000..615c8961be
--- /dev/null
+++ b/snowplow-javascript-tracker/tests/pages/helpers.html
@@ -0,0 +1,21 @@
+
+
+
+ Helpers test page
+
+
+
Title here
+
Hostname here
+
Referrer here
+
Click here
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/snowplow-javascript-tracker/tests/pages/integration-template.html b/snowplow-javascript-tracker/tests/pages/integration-template.html
new file mode 100644
index 0000000000..dc3c5eca19
--- /dev/null
+++ b/snowplow-javascript-tracker/tests/pages/integration-template.html
@@ -0,0 +1,157 @@
+
+
+
+ Integration test page
+
+
+
Page for sending requests to request_recorder
+
+
+
+
+
+
+
diff --git a/snowplow-javascript-tracker/tests/scripts/detectors.js b/snowplow-javascript-tracker/tests/scripts/detectors.js
new file mode 100644
index 0000000000..7add52ffdc
--- /dev/null
+++ b/snowplow-javascript-tracker/tests/scripts/detectors.js
@@ -0,0 +1,44 @@
+/*
+ * JavaScript tracker for Snowplow: tests/scripts/detectors.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+var detectors = require('../../src/js/lib/detectors.js');
+
+document.getElementById('detectViewport').innerHTML = detectors.detectViewport();
+document.getElementById('detectDocumentDimensions').innerHTML = detectors.detectDocumentSize();
+document.getElementById('localStorageAccessible').innerHTML = detectors.localStorageAccessible();
+document.getElementById('hasSessionStorage').innerHTML = detectors.hasSessionStorage();
+document.getElementById('hasCookies').innerHTML = detectors.hasCookies();
+document.getElementById('detectTimezone').innerHTML = detectors.detectTimezone();
+document.getElementById('detectSignature').innerHTML = detectors.detectSignature();
+document.getElementById('detectBrowserFeatures').innerHTML = JSON.stringify(detectors.detectBrowserFeatures(), undefined, 2);
diff --git a/snowplow-javascript-tracker/tests/scripts/helpers.js b/snowplow-javascript-tracker/tests/scripts/helpers.js
new file mode 100644
index 0000000000..3782c06af4
--- /dev/null
+++ b/snowplow-javascript-tracker/tests/scripts/helpers.js
@@ -0,0 +1,42 @@
+/*
+ * JavaScript tracker for Snowplow: tests/scripts/helpers.js
+ *
+ * Significant portions copyright 2010 Anthon Pang. Remainder copyright
+ * 2012-2014 Snowplow Analytics Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the
+ * names of their contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+var helpers = require('../../src/js/lib/helpers.js');
+
+document.getElementById('title').innerHTML = helpers.fixupTitle(0);
+document.getElementById('hostname').innerHTML = helpers.getHostName(location.href);
+document.getElementById('referrer').innerHTML = helpers.getReferrer();
+helpers.addEventListener(document.getElementById('click'), 'click', function(){
+ document.getElementById('click').innerHTML = 'clicked';
+});
diff --git a/snowplow-javascript-tracker/vagrant/.gitignore b/snowplow-javascript-tracker/vagrant/.gitignore
new file mode 100644
index 0000000000..1b4b29ff1f
--- /dev/null
+++ b/snowplow-javascript-tracker/vagrant/.gitignore
@@ -0,0 +1,3 @@
+.peru
+oss-playbooks
+ansible
diff --git a/snowplow-javascript-tracker/vagrant/ansible.hosts b/snowplow-javascript-tracker/vagrant/ansible.hosts
new file mode 100644
index 0000000000..588fa08c76
--- /dev/null
+++ b/snowplow-javascript-tracker/vagrant/ansible.hosts
@@ -0,0 +1,2 @@
+[vagrant]
+127.0.0.1:2222
diff --git a/snowplow-javascript-tracker/vagrant/peru.yaml b/snowplow-javascript-tracker/vagrant/peru.yaml
new file mode 100644
index 0000000000..e7fdf41cf7
--- /dev/null
+++ b/snowplow-javascript-tracker/vagrant/peru.yaml
@@ -0,0 +1,14 @@
+imports:
+ ansible: ansible
+ ansible_playbooks: oss-playbooks
+
+curl module ansible:
+ # Equivalent of git cloning tags/v1.6.6 but much, much faster
+ url: https://codeload.github.com/ansible/ansible/zip/69d85c22c7475ccf8169b6ec9dee3ee28c92a314
+ unpack: zip
+ export: ansible-69d85c22c7475ccf8169b6ec9dee3ee28c92a314
+
+git module ansible_playbooks:
+ url: https://github.com/snowplow/ansible-playbooks.git
+ # Comment out to fetch a specific rev instead of master:
+ # rev: xxx
diff --git a/snowplow-javascript-tracker/vagrant/up.bash b/snowplow-javascript-tracker/vagrant/up.bash
new file mode 100755
index 0000000000..7450ae897e
--- /dev/null
+++ b/snowplow-javascript-tracker/vagrant/up.bash
@@ -0,0 +1,50 @@
+#!/bin/bash
+set -e
+
+vagrant_dir=/vagrant/vagrant
+bashrc=/home/vagrant/.bashrc
+
+echo "========================================"
+echo "INSTALLING PERU AND ANSIBLE DEPENDENCIES"
+echo "----------------------------------------"
+apt-get update
+apt-get install -y language-pack-en git unzip libyaml-dev python3-pip python-yaml python-paramiko python-jinja2
+
+echo "==============="
+echo "INSTALLING PERU"
+echo "---------------"
+sudo pip3 install peru
+
+echo "======================================="
+echo "CLONING ANSIBLE AND PLAYBOOKS WITH PERU"
+echo "---------------------------------------"
+cd ${vagrant_dir} && peru sync -v
+echo "... done"
+
+env_setup=${vagrant_dir}/ansible/hacking/env-setup
+hosts=${vagrant_dir}/ansible.hosts
+
+echo "==================="
+echo "CONFIGURING ANSIBLE"
+echo "-------------------"
+touch ${bashrc}
+echo "source ${env_setup}" >> ${bashrc}
+echo "export ANSIBLE_HOSTS=${hosts}" >> ${bashrc}
+echo "... done"
+
+echo "=========================================="
+echo "RUNNING PLAYBOOKS WITH ANSIBLE*"
+echo "* no output while each playbook is running"
+echo "------------------------------------------"
+while read pb; do
+ su - -c "source ${env_setup} && ${vagrant_dir}/ansible/bin/ansible-playbook ${vagrant_dir}/${pb} --connection=local --inventory-file=${hosts}" vagrant
+done <${vagrant_dir}/up.playbooks
+
+guidance=${vagrant_dir}/up.guidance
+
+if [ -f ${guidance} ]; then
+ echo "==========="
+ echo "PLEASE READ"
+ echo "-----------"
+ cat $guidance
+fi
diff --git a/snowplow-javascript-tracker/vagrant/up.guidance b/snowplow-javascript-tracker/vagrant/up.guidance
new file mode 100644
index 0000000000..25078aa213
--- /dev/null
+++ b/snowplow-javascript-tracker/vagrant/up.guidance
@@ -0,0 +1,6 @@
+To get started:
+vagrant ssh
+cd /vagrant
+sudo npm install
+cd core
+sudo npm install
diff --git a/snowplow-javascript-tracker/vagrant/up.playbooks b/snowplow-javascript-tracker/vagrant/up.playbooks
new file mode 100644
index 0000000000..9e621ab9f8
--- /dev/null
+++ b/snowplow-javascript-tracker/vagrant/up.playbooks
@@ -0,0 +1,3 @@
+oss-playbooks/java10.yml
+oss-playbooks/nodejs.yml
+oss-playbooks/grunt.yml