http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/83aa4115/extensions/web-tracker/javascript/dist/unomi-tracker.js ---------------------------------------------------------------------- diff --git a/extensions/web-tracker/javascript/dist/unomi-tracker.js b/extensions/web-tracker/javascript/dist/unomi-tracker.js new file mode 100644 index 0000000..73d96a9 --- /dev/null +++ b/extensions/web-tracker/javascript/dist/unomi-tracker.js @@ -0,0 +1,12457 @@ +/*! + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @license Apache-2.0 + */ + +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.unomiTracker = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ +'use strict'; + +/* + * Module dependencies. + */ + +var arity = require('@ndhoule/arity'); + +var objToString = Object.prototype.toString; + +/** + * Determine if a value is a function. + * + * @param {*} val + * @return {boolean} + */ +// TODO: Move to lib +var isFunction = function(val) { + return typeof val === 'function'; +}; + +/** + * Determine if a value is a number. + * + * @param {*} val + * @return {boolean} + */ +// TODO: Move to lib +var isNumber = function(val) { + var type = typeof val; + return type === 'number' || (type === 'object' && objToString.call(val) === '[object Number]'); +}; + +/** + * Wrap a function `fn` in a function that will invoke `fn` when invoked `n` or + * more times. + * + * @name after + * @api public + * @category Function + * @param {Number} n The number of + * @param {Function} fn The function to wrap. + * @return {Function} A function that will call `fn` after `n` or more + * invocations. + * @example + */ +var after = function after(n, fn) { + if (!isNumber(n)) { + throw new TypeError('Expected a number but received ' + typeof n); + } + + if (!isFunction(fn)) { + throw new TypeError('Expected a function but received ' + typeof fn); + } + + var callCount = 0; + + return arity(fn.length, function() { + callCount += 1; + + if (callCount < n) { + return; + } + + return fn.apply(this, arguments); + }); +}; + +/* + * Exports. + */ + +module.exports = after; + +},{"@ndhoule/arity":2}],2:[function(require,module,exports){ +'use strict'; + +var objToString = Object.prototype.toString; + +/** + * Determine if a value is a function. + * + * @param {*} val + * @return {boolean} + */ +// TODO: Move to lib +var isFunction = function(val) { + return typeof val === 'function'; +}; + +/** + * Determine if a value is a number. + * + * @param {*} val + * @return {boolean} + */ +// TODO: Move to lib +var isNumber = function(val) { + var type = typeof val; + return type === 'number' || (type === 'object' && objToString.call(val) === '[object Number]'); +}; + + /** + * Creates an array of generic, numbered argument names. + * + * @name createParams + * @api private + * @param {number} n + * @return {Array} + * @example + * argNames(2); + * //=> ['arg1', 'arg2'] + */ +var createParams = function createParams(n) { + var args = []; + + for (var i = 1; i <= n; i += 1) { + args.push('arg' + i); + } + + return args; +}; + + /** + * Dynamically construct a wrapper function of `n` arity that. + * + * If at all possible, prefer a function from the arity wrapper cache above to + * avoid allocating a new function at runtime. + * + * @name createArityWrapper + * @api private + * @param {number} n + * @return {Function(Function)} + */ +var createArityWrapper = function createArityWrapper(n) { + var paramNames = createParams(n).join(', '); + var wrapperBody = ''.concat( + ' return function(', paramNames, ') {\n', + ' return func.apply(this, arguments);\n', + ' };' + ); + + /* eslint-disable no-new-func */ + return new Function('func', wrapperBody); + /* eslint-enable no-new-func */ +}; + +// Cache common arity wrappers to avoid constructing them at runtime +var arityWrapperCache = [ + /* eslint-disable no-unused-vars */ + function(fn) { + return function() { + return fn.apply(this, arguments); + }; + }, + + function(fn) { + return function(arg1) { + return fn.apply(this, arguments); + }; + }, + + function(fn) { + return function(arg1, arg2) { + return fn.apply(this, arguments); + }; + }, + + function(fn) { + return function(arg1, arg2, arg3) { + return fn.apply(this, arguments); + }; + }, + + function(fn) { + return function(arg1, arg2, arg3, arg4) { + return fn.apply(this, arguments); + }; + }, + + function(fn) { + return function(arg1, arg2, arg3, arg4, arg5) { + return fn.apply(this, arguments); + }; + } + /* eslint-enable no-unused-vars */ +]; + +/** + * Takes a function and an [arity](https://en.wikipedia.org/wiki/Arity) `n`, and returns a new + * function that expects `n` arguments. + * + * @name arity + * @api public + * @category Function + * @see {@link curry} + * @param {Number} n The desired arity of the returned function. + * @param {Function} fn The function to wrap. + * @return {Function} A function of n arity, wrapping `fn`. + * @example + * var add = function(a, b) { + * return a + b; + * }; + * + * // Check the number of arguments this function expects by accessing `.length`: + * add.length; + * //=> 2 + * + * var unaryAdd = arity(1, add); + * unaryAdd.length; + * //=> 1 + */ +var arity = function arity(n, func) { + if (!isFunction(func)) { + throw new TypeError('Expected a function but got ' + typeof func); + } + + n = Math.max(isNumber(n) ? n : 0, 0); + + if (!arityWrapperCache[n]) { + arityWrapperCache[n] = createArityWrapper(n); + } + + return arityWrapperCache[n](func); +}; + +/* + * Exports. + */ + +module.exports = arity; + +},{}],3:[function(require,module,exports){ +'use strict'; + +/* + * Module dependencies. + */ + +var type = require('component-type'); + +/** + * Deeply clone an object. + * + * @param {*} obj Any object. + */ + +var clone = function clone(obj) { + var t = type(obj); + + if (t === 'object') { + var copy = {}; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + copy[key] = clone(obj[key]); + } + } + return copy; + } + + if (t === 'array') { + var copy = new Array(obj.length); + for (var i = 0, l = obj.length; i < l; i++) { + copy[i] = clone(obj[i]); + } + return copy; + } + + if (t === 'regexp') { + // from millermedeiros/amd-utils - MIT + var flags = ''; + flags += obj.multiline ? 'm' : ''; + flags += obj.global ? 'g' : ''; + flags += obj.ignoreCase ? 'i' : ''; + return new RegExp(obj.source, flags); + } + + if (t === 'date') { + return new Date(obj.getTime()); + } + + // string, number, boolean, etc. + return obj; +}; + +/* + * Exports. + */ + +module.exports = clone; + +},{"component-type":53}],4:[function(require,module,exports){ +'use strict'; + +/* + * Module dependencies. + */ + +var drop = require('@ndhoule/drop'); +var rest = require('@ndhoule/rest'); + +var has = Object.prototype.hasOwnProperty; +var objToString = Object.prototype.toString; + +/** + * Returns `true` if a value is an object, otherwise `false`. + * + * @name isObject + * @api private + * @param {*} val The value to test. + * @return {boolean} + */ +// TODO: Move to a library +var isObject = function isObject(value) { + return Boolean(value) && typeof value === 'object'; +}; + +/** + * Returns `true` if a value is a plain object, otherwise `false`. + * + * @name isPlainObject + * @api private + * @param {*} val The value to test. + * @return {boolean} + */ +// TODO: Move to a library +var isPlainObject = function isPlainObject(value) { + return Boolean(value) && objToString.call(value) === '[object Object]'; +}; + +/** + * Assigns a key-value pair to a target object when the value assigned is owned, + * and where target[key] is undefined. + * + * @name shallowCombiner + * @api private + * @param {Object} target + * @param {Object} source + * @param {*} value + * @param {string} key + */ +var shallowCombiner = function shallowCombiner(target, source, value, key) { + if (has.call(source, key) && target[key] === undefined) { + target[key] = value; + } + return source; +}; + +/** + * Assigns a key-value pair to a target object when the value assigned is owned, + * and where target[key] is undefined; also merges objects recursively. + * + * @name deepCombiner + * @api private + * @param {Object} target + * @param {Object} source + * @param {*} value + * @param {string} key + * @return {Object} + */ +var deepCombiner = function(target, source, value, key) { + if (has.call(source, key)) { + if (isPlainObject(target[key]) && isPlainObject(value)) { + target[key] = defaultsDeep(target[key], value); + } else if (target[key] === undefined) { + target[key] = value; + } + } + + return source; +}; + +/** + * TODO: Document + * + * @name defaultsWith + * @api private + * @param {Function} combiner + * @param {Object} target + * @param {...Object} sources + * @return {Object} Return the input `target`. + */ +var defaultsWith = function(combiner, target /*, ...sources */) { + if (!isObject(target)) { + return target; + } + + combiner = combiner || shallowCombiner; + var sources = drop(2, arguments); + + for (var i = 0; i < sources.length; i += 1) { + for (var key in sources[i]) { + combiner(target, sources[i], sources[i][key], key); + } + } + + return target; +}; + +/** + * Copies owned, enumerable properties from a source object(s) to a target + * object when the value of that property on the source object is `undefined`. + * Recurses on objects. + * + * @name defaultsDeep + * @api public + * @param {Object} target + * @param {...Object} sources + * @return {Object} The input `target`. + */ +var defaultsDeep = function defaultsDeep(target /*, sources */) { + // TODO: Replace with `partial` call? + return defaultsWith.apply(null, [deepCombiner, target].concat(rest(arguments))); +}; + +/** + * Copies owned, enumerable properties from a source object(s) to a target + * object when the value of that property on the source object is `undefined`. + * + * @name defaults + * @api public + * @param {Object} target + * @param {...Object} sources + * @return {Object} + * @example + * var a = { a: 1 }; + * var b = { a: 2, b: 2 }; + * + * defaults(a, b); + * console.log(a); //=> { a: 1, b: 2 } + */ +var defaults = function(target /*, ...sources */) { + // TODO: Replace with `partial` call? + return defaultsWith.apply(null, [null, target].concat(rest(arguments))); +}; + +/* + * Exports. + */ + +module.exports = defaults; +module.exports.deep = defaultsDeep; + +},{"@ndhoule/drop":5,"@ndhoule/rest":14}],5:[function(require,module,exports){ +'use strict'; + +var max = Math.max; + +/** + * Produce a new array composed of all but the first `n` elements of an input `collection`. + * + * @name drop + * @api public + * @param {number} count The number of elements to drop. + * @param {Array} collection The collection to iterate over. + * @return {Array} A new array containing all but the first element from `collection`. + * @example + * drop(0, [1, 2, 3]); // => [1, 2, 3] + * drop(1, [1, 2, 3]); // => [2, 3] + * drop(2, [1, 2, 3]); // => [3] + * drop(3, [1, 2, 3]); // => [] + * drop(4, [1, 2, 3]); // => [] + */ +var drop = function drop(count, collection) { + var length = collection ? collection.length : 0; + + if (!length) { + return []; + } + + // Preallocating an array *significantly* boosts performance when dealing with + // `arguments` objects on v8. For a summary, see: + // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments + var toDrop = max(Number(count) || 0, 0); + var resultsLength = max(length - toDrop, 0); + var results = new Array(resultsLength); + + for (var i = 0; i < resultsLength; i += 1) { + results[i] = collection[i + toDrop]; + } + + return results; +}; + +/* + * Exports. + */ + +module.exports = drop; + +},{}],6:[function(require,module,exports){ +'use strict'; + +/* + * Module dependencies. + */ + +var keys = require('@ndhoule/keys'); + +var objToString = Object.prototype.toString; + +/** + * Tests if a value is a number. + * + * @name isNumber + * @api private + * @param {*} val The value to test. + * @return {boolean} Returns `true` if `val` is a number, otherwise `false`. + */ +// TODO: Move to library +var isNumber = function isNumber(val) { + var type = typeof val; + return type === 'number' || (type === 'object' && objToString.call(val) === '[object Number]'); +}; + +/** + * Tests if a value is an array. + * + * @name isArray + * @api private + * @param {*} val The value to test. + * @return {boolean} Returns `true` if the value is an array, otherwise `false`. + */ +// TODO: Move to library +var isArray = typeof Array.isArray === 'function' ? Array.isArray : function isArray(val) { + return objToString.call(val) === '[object Array]'; +}; + +/** + * Tests if a value is array-like. Array-like means the value is not a function and has a numeric + * `.length` property. + * + * @name isArrayLike + * @api private + * @param {*} val + * @return {boolean} + */ +// TODO: Move to library +var isArrayLike = function isArrayLike(val) { + return val != null && (isArray(val) || (val !== 'function' && isNumber(val.length))); +}; + +/** + * Internal implementation of `each`. Works on arrays and array-like data structures. + * + * @name arrayEach + * @api private + * @param {Function(value, key, collection)} iterator The function to invoke per iteration. + * @param {Array} array The array(-like) structure to iterate over. + * @return {undefined} + */ +var arrayEach = function arrayEach(iterator, array) { + for (var i = 0; i < array.length; i += 1) { + // Break iteration early if `iterator` returns `false` + if (iterator(array[i], i, array) === false) { + break; + } + } +}; + +/** + * Internal implementation of `each`. Works on objects. + * + * @name baseEach + * @api private + * @param {Function(value, key, collection)} iterator The function to invoke per iteration. + * @param {Object} object The object to iterate over. + * @return {undefined} + */ +var baseEach = function baseEach(iterator, object) { + var ks = keys(object); + + for (var i = 0; i < ks.length; i += 1) { + // Break iteration early if `iterator` returns `false` + if (iterator(object[ks[i]], ks[i], object) === false) { + break; + } + } +}; + +/** + * Iterate over an input collection, invoking an `iterator` function for each element in the + * collection and passing to it three arguments: `(value, index, collection)`. The `iterator` + * function can end iteration early by returning `false`. + * + * @name each + * @api public + * @param {Function(value, key, collection)} iterator The function to invoke per iteration. + * @param {Array|Object|string} collection The collection to iterate over. + * @return {undefined} Because `each` is run only for side effects, always returns `undefined`. + * @example + * var log = console.log.bind(console); + * + * each(log, ['a', 'b', 'c']); + * //-> 'a', 0, ['a', 'b', 'c'] + * //-> 'b', 1, ['a', 'b', 'c'] + * //-> 'c', 2, ['a', 'b', 'c'] + * //=> undefined + * + * each(log, 'tim'); + * //-> 't', 2, 'tim' + * //-> 'i', 1, 'tim' + * //-> 'm', 0, 'tim' + * //=> undefined + * + * // Note: Iteration order not guaranteed across environments + * each(log, { name: 'tim', occupation: 'enchanter' }); + * //-> 'tim', 'name', { name: 'tim', occupation: 'enchanter' } + * //-> 'enchanter', 'occupation', { name: 'tim', occupation: 'enchanter' } + * //=> undefined + */ +var each = function each(iterator, collection) { + return (isArrayLike(collection) ? arrayEach : baseEach).call(this, iterator, collection); +}; + +/* + * Exports. + */ + +module.exports = each; + +},{"@ndhoule/keys":11}],7:[function(require,module,exports){ +'use strict'; + +/* + * Module dependencies. + */ + +var each = require('@ndhoule/each'); + +/** + * Check if a predicate function returns `true` for all values in a `collection`. + * Checks owned, enumerable values and exits early when `predicate` returns + * `false`. + * + * @name every + * @param {Function} predicate The function used to test values. + * @param {Array|Object|string} collection The collection to search. + * @return {boolean} True if all values passes the predicate test, otherwise false. + * @example + * var isEven = function(num) { return num % 2 === 0; }; + * + * every(isEven, []); // => true + * every(isEven, [1, 2]); // => false + * every(isEven, [2, 4, 6]); // => true + */ +var every = function every(predicate, collection) { + if (typeof predicate !== 'function') { + throw new TypeError('`predicate` must be a function but was a ' + typeof predicate); + } + + var result = true; + + each(function(val, key, collection) { + result = !!predicate(val, key, collection); + + // Exit early + if (!result) { + return false; + } + }, collection); + + return result; +}; + +/* + * Exports. + */ + +module.exports = every; + +},{"@ndhoule/each":6}],8:[function(require,module,exports){ +'use strict'; + +var has = Object.prototype.hasOwnProperty; + +/** + * Copy the properties of one or more `objects` onto a destination object. Input objects are iterated over + * in left-to-right order, so duplicate properties on later objects will overwrite those from + * erevious ones. Only enumerable and own properties of the input objects are copied onto the + * resulting object. + * + * @name extend + * @api public + * @category Object + * @param {Object} dest The destination object. + * @param {...Object} sources The source objects. + * @return {Object} `dest`, extended with the properties of all `sources`. + * @example + * var a = { a: 'a' }; + * var b = { b: 'b' }; + * var c = { c: 'c' }; + * + * extend(a, b, c); + * //=> { a: 'a', b: 'b', c: 'c' }; + */ +var extend = function extend(dest /*, sources */) { + var sources = Array.prototype.slice.call(arguments, 1); + + for (var i = 0; i < sources.length; i += 1) { + for (var key in sources[i]) { + if (has.call(sources[i], key)) { + dest[key] = sources[i][key]; + } + } + } + + return dest; +}; + +/* + * Exports. + */ + +module.exports = extend; + +},{}],9:[function(require,module,exports){ +'use strict'; + +/* + * Module dependencies. + */ + +var each = require('@ndhoule/each'); + +/** + * Reduces all the values in a collection down into a single value. Does so by iterating through the + * collection from left to right, repeatedly calling an `iterator` function and passing to it four + * arguments: `(accumulator, value, index, collection)`. + * + * Returns the final return value of the `iterator` function. + * + * @name foldl + * @api public + * @param {Function} iterator The function to invoke per iteration. + * @param {*} accumulator The initial accumulator value, passed to the first invocation of `iterator`. + * @param {Array|Object} collection The collection to iterate over. + * @return {*} The return value of the final call to `iterator`. + * @example + * foldl(function(total, n) { + * return total + n; + * }, 0, [1, 2, 3]); + * //=> 6 + * + * var phonebook = { bob: '555-111-2345', tim: '655-222-6789', sheila: '655-333-1298' }; + * + * foldl(function(results, phoneNumber) { + * if (phoneNumber[0] === '6') { + * return results.concat(phoneNumber); + * } + * return results; + * }, [], phonebook); + * // => ['655-222-6789', '655-333-1298'] + */ +var foldl = function foldl(iterator, accumulator, collection) { + if (typeof iterator !== 'function') { + throw new TypeError('Expected a function but received a ' + typeof iterator); + } + + each(function(val, i, collection) { + accumulator = iterator(accumulator, val, i, collection); + }, collection); + + return accumulator; +}; + +/* + * Exports. + */ + +module.exports = foldl; + +},{"@ndhoule/each":6}],10:[function(require,module,exports){ +'use strict'; + +/* + * Module dependencies. + */ + +var each = require('@ndhoule/each'); + +var strIndexOf = String.prototype.indexOf; + +/** + * Object.is/sameValueZero polyfill. + * + * @api private + * @param {*} value1 + * @param {*} value2 + * @return {boolean} + */ +// TODO: Move to library +var sameValueZero = function sameValueZero(value1, value2) { + // Normal values and check for 0 / -0 + if (value1 === value2) { + return value1 !== 0 || 1 / value1 === 1 / value2; + } + // NaN + return value1 !== value1 && value2 !== value2; +}; + +/** + * Searches a given `collection` for a value, returning true if the collection + * contains the value and false otherwise. Can search strings, arrays, and + * objects. + * + * @name includes + * @api public + * @param {*} searchElement The element to search for. + * @param {Object|Array|string} collection The collection to search. + * @return {boolean} + * @example + * includes(2, [1, 2, 3]); + * //=> true + * + * includes(4, [1, 2, 3]); + * //=> false + * + * includes(2, { a: 1, b: 2, c: 3 }); + * //=> true + * + * includes('a', { a: 1, b: 2, c: 3 }); + * //=> false + * + * includes('abc', 'xyzabc opq'); + * //=> true + * + * includes('nope', 'xyzabc opq'); + * //=> false + */ +var includes = function includes(searchElement, collection) { + var found = false; + + // Delegate to String.prototype.indexOf when `collection` is a string + if (typeof collection === 'string') { + return strIndexOf.call(collection, searchElement) !== -1; + } + + // Iterate through enumerable/own array elements and object properties. + each(function(value) { + if (sameValueZero(value, searchElement)) { + found = true; + // Exit iteration early when found + return false; + } + }, collection); + + return found; +}; + +/* + * Exports. + */ + +module.exports = includes; + +},{"@ndhoule/each":6}],11:[function(require,module,exports){ +'use strict'; + +var hop = Object.prototype.hasOwnProperty; +var strCharAt = String.prototype.charAt; +var toStr = Object.prototype.toString; + +/** + * Returns the character at a given index. + * + * @param {string} str + * @param {number} index + * @return {string|undefined} + */ +// TODO: Move to a library +var charAt = function(str, index) { + return strCharAt.call(str, index); +}; + +/** + * hasOwnProperty, wrapped as a function. + * + * @name has + * @api private + * @param {*} context + * @param {string|number} prop + * @return {boolean} + */ + +// TODO: Move to a library +var has = function has(context, prop) { + return hop.call(context, prop); +}; + +/** + * Returns true if a value is a string, otherwise false. + * + * @name isString + * @api private + * @param {*} val + * @return {boolean} + */ + +// TODO: Move to a library +var isString = function isString(val) { + return toStr.call(val) === '[object String]'; +}; + +/** + * Returns true if a value is array-like, otherwise false. Array-like means a + * value is not null, undefined, or a function, and has a numeric `length` + * property. + * + * @name isArrayLike + * @api private + * @param {*} val + * @return {boolean} + */ +// TODO: Move to a library +var isArrayLike = function isArrayLike(val) { + return val != null && (typeof val !== 'function' && typeof val.length === 'number'); +}; + + +/** + * indexKeys + * + * @name indexKeys + * @api private + * @param {} target + * @param {Function} pred + * @return {Array} + */ +var indexKeys = function indexKeys(target, pred) { + pred = pred || has; + + var results = []; + + for (var i = 0, len = target.length; i < len; i += 1) { + if (pred(target, i)) { + results.push(String(i)); + } + } + + return results; +}; + +/** + * Returns an array of an object's owned keys. + * + * @name objectKeys + * @api private + * @param {*} target + * @param {Function} pred Predicate function used to include/exclude values from + * the resulting array. + * @return {Array} + */ +var objectKeys = function objectKeys(target, pred) { + pred = pred || has; + + var results = []; + + for (var key in target) { + if (pred(target, key)) { + results.push(String(key)); + } + } + + return results; +}; + +/** + * Creates an array composed of all keys on the input object. Ignores any non-enumerable properties. + * More permissive than the native `Object.keys` function (non-objects will not throw errors). + * + * @name keys + * @api public + * @category Object + * @param {Object} source The value to retrieve keys from. + * @return {Array} An array containing all the input `source`'s keys. + * @example + * keys({ likes: 'avocado', hates: 'pineapple' }); + * //=> ['likes', 'pineapple']; + * + * // Ignores non-enumerable properties + * var hasHiddenKey = { name: 'Tim' }; + * Object.defineProperty(hasHiddenKey, 'hidden', { + * value: 'i am not enumerable!', + * enumerable: false + * }) + * keys(hasHiddenKey); + * //=> ['name']; + * + * // Works on arrays + * keys(['a', 'b', 'c']); + * //=> ['0', '1', '2'] + * + * // Skips unpopulated indices in sparse arrays + * var arr = [1]; + * arr[4] = 4; + * keys(arr); + * //=> ['0', '4'] + */ +var keys = function keys(source) { + if (source == null) { + return []; + } + + // IE6-8 compatibility (string) + if (isString(source)) { + return indexKeys(source, charAt); + } + + // IE6-8 compatibility (arguments) + if (isArrayLike(source)) { + return indexKeys(source, has); + } + + return objectKeys(source); +}; + +/* + * Exports. + */ + +module.exports = keys; + +},{}],12:[function(require,module,exports){ +'use strict'; + +/* + * Module dependencies. + */ + +var each = require('@ndhoule/each'); + +/** + * Produce a new array by passing each value in the input `collection` through a transformative + * `iterator` function. The `iterator` function is passed three arguments: + * `(value, index, collection)`. + * + * @name map + * @api public + * @param {Function} iterator The transformer function to invoke per iteration. + * @param {Array} collection The collection to iterate over. + * @return {Array} A new array containing the results of each `iterator` invocation. + * @example + * var square = function(x) { return x * x; }; + * + * map(square, [1, 2, 3]); + * //=> [1, 4, 9] + */ +var map = function map(iterator, collection) { + if (typeof iterator !== 'function') { + throw new TypeError('Expected a function but received a ' + typeof iterator); + } + + var result = []; + + each(function(val, i, collection) { + result.push(iterator(val, i, collection)); + }, collection); + + return result; +}; + +/* + * Exports. + */ + +module.exports = map; + +},{"@ndhoule/each":6}],13:[function(require,module,exports){ +'use strict'; + +var objToString = Object.prototype.toString; + +// TODO: Move to lib +var existy = function(val) { + return val != null; +}; + +// TODO: Move to lib +var isArray = function(val) { + return objToString.call(val) === '[object Array]'; +}; + +// TODO: Move to lib +var isString = function(val) { + return typeof val === 'string' || objToString.call(val) === '[object String]'; +}; + +// TODO: Move to lib +var isObject = function(val) { + return val != null && typeof val === 'object'; +}; + +/** + * Returns a copy of the new `object` containing only the specified properties. + * + * @name pick + * @api public + * @param {string|string[]} props The property or properties to keep. + * @param {Object} object The object to iterate over. + * @return {Object} A new object containing only the specified properties from `object`. + * @example + * var person = { name: 'Tim', occupation: 'enchanter', fears: 'rabbits' }; + * + * pick('name', person); + * //=> { name: 'Tim' } + * + * pick(['name', 'fears'], person); + * //=> { name: 'Tim', fears: 'rabbits' } + */ +var pick = function pick(props, object) { + if (!existy(object) || !isObject(object)) { + return {}; + } + + if (isString(props)) { + props = [props]; + } + + if (!isArray(props)) { + props = []; + } + + var result = {}; + + for (var i = 0; i < props.length; i += 1) { + if (isString(props[i]) && props[i] in object) { + result[props[i]] = object[props[i]]; + } + } + + return result; +}; + +/* + * Exports. + */ + +module.exports = pick; + +},{}],14:[function(require,module,exports){ +'use strict'; + +var max = Math.max; + +/** + * Produce a new array by passing each value in the input `collection` through a transformative + * `iterator` function. The `iterator` function is passed three arguments: + * `(value, index, collection)`. + * + * @name rest + * @api public + * @param {Array} collection The collection to iterate over. + * @return {Array} A new array containing all but the first element from `collection`. + * @example + * rest([1, 2, 3]); // => [2, 3] + */ +var rest = function rest(collection) { + if (collection == null || !collection.length) { + return []; + } + + // Preallocating an array *significantly* boosts performance when dealing with + // `arguments` objects on v8. For a summary, see: + // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments + var results = new Array(max(collection.length - 2, 0)); + + for (var i = 1; i < collection.length; i += 1) { + results[i - 1] = collection[i]; + } + + return results; +}; + +/* + * Exports. + */ + +module.exports = rest; + +},{}],15:[function(require,module,exports){ +(function (global){ +'use strict'; + +var _analytics = global.analytics; + +/* + * Module dependencies. + */ + +var Alias = require('segmentio-facade').Alias; +var Emitter = require('component-emitter'); +var Group = require('segmentio-facade').Group; +var Identify = require('segmentio-facade').Identify; +var Page = require('segmentio-facade').Page; +var Track = require('segmentio-facade').Track; +var after = require('@ndhoule/after'); +var bindAll = require('bind-all'); +var clone = require('@ndhoule/clone'); +var extend = require('extend'); +var cookie = require('./cookie'); +var metrics = require('./metrics'); +var debug = require('debug'); +var defaults = require('@ndhoule/defaults'); +var each = require('@ndhoule/each'); +var foldl = require('@ndhoule/foldl'); +var group = require('./group'); +var is = require('is'); +var isMeta = require('@segment/is-meta'); +var keys = require('@ndhoule/keys'); +var memory = require('./memory'); +var nextTick = require('next-tick'); +var normalize = require('./normalize'); +var on = require('component-event').bind; +var pageDefaults = require('./pageDefaults'); +var pick = require('@ndhoule/pick'); +var prevent = require('@segment/prevent-default'); +var querystring = require('component-querystring'); +var store = require('./store'); +var user = require('./user'); +var type = require('component-type'); + +/** + * Initialize a new `Analytics` instance. + */ + +function Analytics() { + this._options({}); + this.Integrations = {}; + this._integrations = {}; + this._readied = false; + this._timeout = 300; + // XXX: BACKWARDS COMPATIBILITY + this._user = user; + this.log = debug('analytics.js'); + bindAll(this); + + var self = this; + this.on('initialize', function(settings, options) { + if (options.initialPageview) self.page(); + self._parseQuery(window.location.search); + }); +} + +/** + * Mix in event emitter. + */ + +Emitter(Analytics.prototype); + +/** + * Use a `plugin`. + * + * @param {Function} plugin + * @return {Analytics} + */ + +Analytics.prototype.use = function(plugin) { + plugin(this); + return this; +}; + +/** + * Define a new `Integration`. + * + * @param {Function} Integration + * @return {Analytics} + */ + +Analytics.prototype.addIntegration = function(Integration) { + var name = Integration.prototype.name; + if (!name) throw new TypeError('attempted to add an invalid integration'); + this.Integrations[name] = Integration; + return this; +}; + +/** + * Initialize with the given integration `settings` and `options`. + * + * Aliased to `init` for convenience. + * + * @param {Object} [settings={}] + * @param {Object} [options={}] + * @return {Analytics} + */ + +Analytics.prototype.init = Analytics.prototype.initialize = function( + settings, + options +) { + settings = settings || {}; + options = options || {}; + + this._options(options); + this._readied = false; + + // clean unknown integrations from settings + var self = this; + each(function(opts, name) { + var Integration = self.Integrations[name]; + if (!Integration) delete settings[name]; + }, settings); + + // add integrations + each(function(opts, name) { + // Don't load disabled integrations + if (options.integrations) { + if ( + options.integrations[name] === false || + (options.integrations.All === false && !options.integrations[name]) + ) { + return; + } + } + + var Integration = self.Integrations[name]; + var clonedOpts = {}; + extend(true, clonedOpts, opts); // deep clone opts + var integration = new Integration(clonedOpts); + self.log('initialize %o - %o', name, opts); + self.add(integration); + }, settings); + + var integrations = this._integrations; + + // load user now that options are set + user.load(); + group.load(); + + // make ready callback + var integrationCount = keys(integrations).length; + var ready = after(integrationCount, function() { + self._readied = true; + self.emit('ready'); + }); + + // init if no integrations + if (integrationCount <= 0) { + ready(); + } + + // initialize integrations, passing ready + // create a list of any integrations that did not initialize - this will be passed with all events for replay support: + this.failedInitializations = []; + each(function(integration) { + if ( + options.initialPageview && + integration.options.initialPageview === false + ) { + integration.page = after(2, integration.page); + } + + integration.analytics = self; + integration.once('ready', ready); + try { + metrics.increment('analytics_js.integration.invoke', { + method: 'initialize', + integration_name: integration.name + }); + integration.initialize(); + } catch (e) { + var integrationName = integration.name; + metrics.increment('analytics_js.integration.invoke.error', { + method: 'initialize', + integration_name: integration.name + }); + self.failedInitializations.push(integrationName); + self.log('Error initializing %s integration: %o', integrationName, e); + // Mark integration as ready to prevent blocking of anyone listening to analytics.ready() + integration.ready(); + } + }, integrations); + + // backwards compat with angular plugin. + // TODO: remove + this.initialized = true; + + this.emit('initialize', settings, options); + return this; +}; + +/** + * Set the user's `id`. + * + * @param {Mixed} id + */ + +Analytics.prototype.setAnonymousId = function(id) { + this.user().anonymousId(id); + return this; +}; + +/** + * Add an integration. + * + * @param {Integration} integration + */ + +Analytics.prototype.add = function(integration) { + this._integrations[integration.name] = integration; + return this; +}; + +/** + * Identify a user by optional `id` and `traits`. + * + * @param {string} [id=user.id()] User ID. + * @param {Object} [traits=null] User traits. + * @param {Object} [options=null] + * @param {Function} [fn] + * @return {Analytics} + */ + +Analytics.prototype.identify = function(id, traits, options, fn) { + // Argument reshuffling. + /* eslint-disable no-unused-expressions, no-sequences */ + if (is.fn(options)) (fn = options), (options = null); + if (is.fn(traits)) (fn = traits), (options = null), (traits = null); + if (is.object(id)) (options = traits), (traits = id), (id = user.id()); + /* eslint-enable no-unused-expressions, no-sequences */ + + // clone traits before we manipulate so we don't do anything uncouth, and take + // from `user` so that we carryover anonymous traits + user.identify(id, traits); + + var msg = this.normalize({ + options: options, + traits: user.traits(), + userId: user.id() + }); + + // Add the initialize integrations so the server-side ones can be disabled too + if (this.options.integrations) { + defaults(msg.integrations, this.options.integrations); + } + + this._invoke('identify', new Identify(msg)); + + // emit + this.emit('identify', id, traits, options); + this._callback(fn); + return this; +}; + +/** + * Return the current user. + * + * @return {Object} + */ + +Analytics.prototype.user = function() { + return user; +}; + +/** + * Identify a group by optional `id` and `traits`. Or, if no arguments are + * supplied, return the current group. + * + * @param {string} [id=group.id()] Group ID. + * @param {Object} [traits=null] Group traits. + * @param {Object} [options=null] + * @param {Function} [fn] + * @return {Analytics|Object} + */ + +Analytics.prototype.group = function(id, traits, options, fn) { + /* eslint-disable no-unused-expressions, no-sequences */ + if (!arguments.length) return group; + if (is.fn(options)) (fn = options), (options = null); + if (is.fn(traits)) (fn = traits), (options = null), (traits = null); + if (is.object(id)) (options = traits), (traits = id), (id = group.id()); + /* eslint-enable no-unused-expressions, no-sequences */ + + // grab from group again to make sure we're taking from the source + group.identify(id, traits); + + var msg = this.normalize({ + options: options, + traits: group.traits(), + groupId: group.id() + }); + + // Add the initialize integrations so the server-side ones can be disabled too + if (this.options.integrations) { + defaults(msg.integrations, this.options.integrations); + } + + this._invoke('group', new Group(msg)); + + this.emit('group', id, traits, options); + this._callback(fn); + return this; +}; + +/** + * Track an `event` that a user has triggered with optional `properties`. + * + * @param {string} event + * @param {Object} [properties=null] + * @param {Object} [options=null] + * @param {Function} [fn] + * @return {Analytics} + */ + +Analytics.prototype.track = function(event, properties, options, fn) { + // Argument reshuffling. + /* eslint-disable no-unused-expressions, no-sequences */ + if (is.fn(options)) (fn = options), (options = null); + if (is.fn(properties)) + (fn = properties), (options = null), (properties = null); + /* eslint-enable no-unused-expressions, no-sequences */ + + // figure out if the event is archived. + var plan = this.options.plan || {}; + var events = plan.track || {}; + var planIntegrationOptions = {}; + + // normalize + var msg = this.normalize({ + properties: properties, + options: options, + event: event + }); + + // plan. + plan = events[event]; + if (plan) { + this.log('plan %o - %o', event, plan); + if (plan.enabled === false) { + // Disabled events should always be sent to Segment. + planIntegrationOptions = { All: false, 'Segment.io': true }; + } else { + planIntegrationOptions = plan.integrations || {}; + } + } else { + var defaultPlan = events.__default || { enabled: true }; + if (!defaultPlan.enabled) { + // Disabled events should always be sent to Segment. + planIntegrationOptions = { All: false, 'Segment.io': true }; + } + } + + // Add the initialize integrations so the server-side ones can be disabled too + defaults( + msg.integrations, + this._mergeInitializeAndPlanIntegrations(planIntegrationOptions) + ); + + this._invoke('track', new Track(msg)); + + this.emit('track', event, properties, options); + this._callback(fn); + return this; +}; + +/** + * Helper method to track an outbound link that would normally navigate away + * from the page before the analytics calls were sent. + * + * BACKWARDS COMPATIBILITY: aliased to `trackClick`. + * + * @param {Element|Array} links + * @param {string|Function} event + * @param {Object|Function} properties (optional) + * @return {Analytics} + */ + +Analytics.prototype.trackClick = Analytics.prototype.trackLink = function( + links, + event, + properties +) { + if (!links) return this; + // always arrays, handles jquery + if (type(links) === 'element') links = [links]; + + var self = this; + each(function(el) { + if (type(el) !== 'element') { + throw new TypeError('Must pass HTMLElement to `analytics.trackLink`.'); + } + on(el, 'click', function(e) { + var ev = is.fn(event) ? event(el) : event; + var props = is.fn(properties) ? properties(el) : properties; + var href = + el.getAttribute('href') || + el.getAttributeNS('http://www.w3.org/1999/xlink', 'href') || + el.getAttribute('xlink:href'); + + self.track(ev, props); + + if (href && el.target !== '_blank' && !isMeta(e)) { + prevent(e); + self._callback(function() { + window.location.href = href; + }); + } + }); + }, links); + + return this; +}; + +/** + * Helper method to track an outbound form that would normally navigate away + * from the page before the analytics calls were sent. + * + * BACKWARDS COMPATIBILITY: aliased to `trackSubmit`. + * + * @param {Element|Array} forms + * @param {string|Function} event + * @param {Object|Function} properties (optional) + * @return {Analytics} + */ + +Analytics.prototype.trackSubmit = Analytics.prototype.trackForm = function( + forms, + event, + properties +) { + if (!forms) return this; + // always arrays, handles jquery + if (type(forms) === 'element') forms = [forms]; + + var self = this; + each(function(el) { + if (type(el) !== 'element') + throw new TypeError('Must pass HTMLElement to `analytics.trackForm`.'); + function handler(e) { + prevent(e); + + var ev = is.fn(event) ? event(el) : event; + var props = is.fn(properties) ? properties(el) : properties; + self.track(ev, props); + + self._callback(function() { + el.submit(); + }); + } + + // Support the events happening through jQuery or Zepto instead of through + // the normal DOM API, because `el.submit` doesn't bubble up events... + var $ = window.jQuery || window.Zepto; + if ($) { + $(el).submit(handler); + } else { + on(el, 'submit', handler); + } + }, forms); + + return this; +}; + +/** + * Trigger a pageview, labeling the current page with an optional `category`, + * `name` and `properties`. + * + * @param {string} [category] + * @param {string} [name] + * @param {Object|string} [properties] (or path) + * @param {Object} [options] + * @param {Function} [fn] + * @return {Analytics} + */ + +Analytics.prototype.page = function(category, name, properties, options, fn) { + // Argument reshuffling. + /* eslint-disable no-unused-expressions, no-sequences */ + if (is.fn(options)) (fn = options), (options = null); + if (is.fn(properties)) (fn = properties), (options = properties = null); + if (is.fn(name)) (fn = name), (options = properties = name = null); + if (type(category) === 'object') + (options = name), (properties = category), (name = category = null); + if (type(name) === 'object') + (options = properties), (properties = name), (name = null); + if (type(category) === 'string' && type(name) !== 'string') + (name = category), (category = null); + /* eslint-enable no-unused-expressions, no-sequences */ + + properties = clone(properties) || {}; + if (name) properties.name = name; + if (category) properties.category = category; + + // Ensure properties has baseline spec properties. + // TODO: Eventually move these entirely to `options.context.page` + var defs = pageDefaults(); + defaults(properties, defs); + + // Mirror user overrides to `options.context.page` (but exclude custom properties) + // (Any page defaults get applied in `this.normalize` for consistency.) + // Weird, yeah--moving special props to `context.page` will fix this in the long term. + var overrides = pick(keys(defs), properties); + if (!is.empty(overrides)) { + options = options || {}; + options.context = options.context || {}; + options.context.page = overrides; + } + + var msg = this.normalize({ + properties: properties, + category: category, + options: options, + name: name + }); + + // Add the initialize integrations so the server-side ones can be disabled too + if (this.options.integrations) { + defaults(msg.integrations, this.options.integrations); + } + + this._invoke('page', new Page(msg)); + + this.emit('page', category, name, properties, options); + this._callback(fn); + return this; +}; + +/** + * FIXME: BACKWARDS COMPATIBILITY: convert an old `pageview` to a `page` call. + * + * @param {string} [url] + * @return {Analytics} + * @api private + */ + +Analytics.prototype.pageview = function(url) { + var properties = {}; + if (url) properties.path = url; + this.page(properties); + return this; +}; + +/** + * Merge two previously unassociated user identities. + * + * @param {string} to + * @param {string} from (optional) + * @param {Object} options (optional) + * @param {Function} fn (optional) + * @return {Analytics} + */ + +Analytics.prototype.alias = function(to, from, options, fn) { + // Argument reshuffling. + /* eslint-disable no-unused-expressions, no-sequences */ + if (is.fn(options)) (fn = options), (options = null); + if (is.fn(from)) (fn = from), (options = null), (from = null); + if (is.object(from)) (options = from), (from = null); + /* eslint-enable no-unused-expressions, no-sequences */ + + var msg = this.normalize({ + options: options, + previousId: from, + userId: to + }); + + // Add the initialize integrations so the server-side ones can be disabled too + if (this.options.integrations) { + defaults(msg.integrations, this.options.integrations); + } + + this._invoke('alias', new Alias(msg)); + + this.emit('alias', to, from, options); + this._callback(fn); + return this; +}; + +/** + * Register a `fn` to be fired when all the analytics services are ready. + * + * @param {Function} fn + * @return {Analytics} + */ + +Analytics.prototype.ready = function(fn) { + if (is.fn(fn)) { + if (this._readied) { + nextTick(fn); + } else { + this.once('ready', fn); + } + } + return this; +}; + +/** + * Set the `timeout` (in milliseconds) used for callbacks. + * + * @param {Number} timeout + */ + +Analytics.prototype.timeout = function(timeout) { + this._timeout = timeout; +}; + +/** + * Enable or disable debug. + * + * @param {string|boolean} str + */ + +Analytics.prototype.debug = function(str) { + if (!arguments.length || str) { + debug.enable('analytics:' + (str || '*')); + } else { + debug.disable(); + } +}; + +/** + * Apply options. + * + * @param {Object} options + * @return {Analytics} + * @api private + */ + +Analytics.prototype._options = function(options) { + options = options || {}; + this.options = options; + cookie.options(options.cookie); + metrics.options(options.metrics); + store.options(options.localStorage); + user.options(options.user); + group.options(options.group); + return this; +}; + +/** + * Callback a `fn` after our defined timeout period. + * + * @param {Function} fn + * @return {Analytics} + * @api private + */ + +Analytics.prototype._callback = function(fn) { + if (is.fn(fn)) { + this._timeout ? setTimeout(fn, this._timeout) : nextTick(fn); + } + return this; +}; + +/** + * Call `method` with `facade` on all enabled integrations. + * + * @param {string} method + * @param {Facade} facade + * @return {Analytics} + * @api private + */ + +Analytics.prototype._invoke = function(method, facade) { + var self = this; + metrics.increment('analytics_js.invoke', { + method: method + }); + this.emit('invoke', facade); + + var failedInitializations = self.failedInitializations || []; + each(function(integration, name) { + if (!facade.enabled(name)) return; + // Check if an integration failed to initialize. + // If so, do not process the message as the integration is in an unstable state. + if (failedInitializations.indexOf(name) >= 0) { + self.log( + 'Skipping invokation of .%s method of %s integration. Integation failed to initialize properly.', + method, + name + ); + } else { + try { + metrics.increment('analytics_js.integration.invoke', { + method: method, + integration_name: integration.name + }); + integration.invoke.call(integration, method, facade); + } catch (e) { + metrics.increment('analytics_js.integration.invoke.error', { + method: method, + integration_name: integration.name + }); + self.log( + 'Error invoking .%s method of %s integration: %o', + method, + name, + e + ); + } + } + }, this._integrations); + + return this; +}; + +/** + * Push `args`. + * + * @param {Array} args + * @api private + */ + +Analytics.prototype.push = function(args) { + var method = args.shift(); + if (!this[method]) return; + this[method].apply(this, args); +}; + +/** + * Reset group and user traits and id's. + * + * @api public + */ + +Analytics.prototype.reset = function() { + this.user().logout(); + this.group().logout(); +}; + +/** + * Parse the query string for callable methods. + * + * @param {String} query + * @return {Analytics} + * @api private + */ + +Analytics.prototype._parseQuery = function(query) { + // Parse querystring to an object + var q = querystring.parse(query); + // Create traits and properties objects, populate from querysting params + var traits = pickPrefix('ajs_trait_', q); + var props = pickPrefix('ajs_prop_', q); + // Trigger based on callable parameters in the URL + if (q.ajs_uid) this.identify(q.ajs_uid, traits); + if (q.ajs_event) this.track(q.ajs_event, props); + if (q.ajs_aid) user.anonymousId(q.ajs_aid); + return this; + + /** + * Create a shallow copy of an input object containing only the properties + * whose keys are specified by a prefix, stripped of that prefix + * + * @param {String} prefix + * @param {Object} object + * @return {Object} + * @api private + */ + + function pickPrefix(prefix, object) { + var length = prefix.length; + var sub; + return foldl( + function(acc, val, key) { + if (key.substr(0, length) === prefix) { + sub = key.substr(length); + acc[sub] = val; + } + return acc; + }, + {}, + object + ); + } +}; + +/** + * Normalize the given `msg`. + * + * @param {Object} msg + * @return {Object} + */ + +Analytics.prototype.normalize = function(msg) { + msg = normalize(msg, keys(this._integrations)); + if (msg.anonymousId) user.anonymousId(msg.anonymousId); + msg.anonymousId = user.anonymousId(); + + // Ensure all outgoing requests include page data in their contexts. + msg.context.page = defaults(msg.context.page || {}, pageDefaults()); + + return msg; +}; + +/** + * Merges the tracking plan and initialization integration options. + * + * @param {Object} planIntegrations Tracking plan integrations. + * @return {Object} The merged integrations. + */ +Analytics.prototype._mergeInitializeAndPlanIntegrations = function( + planIntegrations +) { + // Do nothing if there are no initialization integrations + if (!this.options.integrations) { + return planIntegrations; + } + + // Clone the initialization integrations + var integrations = extend({}, this.options.integrations); + var integrationName; + + // Allow the tracking plan to disable integrations that were explicitly + // enabled on initialization + if (planIntegrations.All === false) { + integrations = { All: false }; + } + + for (integrationName in planIntegrations) { + if (planIntegrations.hasOwnProperty(integrationName)) { + // Don't allow the tracking plan to re-enable disabled integrations + if (this.options.integrations[integrationName] !== false) { + integrations[integrationName] = planIntegrations[integrationName]; + } + } + } + + return integrations; +}; + +/** + * No conflict support. + */ + +Analytics.prototype.noConflict = function() { + window.analytics = _analytics; + return this; +}; + +/* + * Exports. + */ + +module.exports = Analytics; +module.exports.cookie = cookie; +module.exports.memory = memory; +module.exports.store = store; +module.exports.metrics = metrics; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./cookie":16,"./group":18,"./memory":20,"./metrics":21,"./normalize":22,"./pageDefaults":23,"./store":24,"./user":25,"@ndhoule/after":1,"@ndhoule/clone":3,"@ndhoule/defaults":4,"@ndhoule/each":6,"@ndhoule/foldl":9,"@ndhoule/keys":11,"@ndhoule/pick":13,"@segment/is-meta":34,"@segment/prevent-default":38,"bind-all":43,"component-emitter":48,"component-event":49,"component-querystring":51,"component-type":53,"debug":26,"extend":58,"is":62,"next-tick":71,"segmentio-facade":81}],16:[function(require,module,exports){ +'use strict'; + +/** + * Module dependencies. + */ + +var bindAll = require('bind-all'); +var clone = require('@ndhoule/clone'); +var cookie = require('component-cookie'); +var debug = require('debug')('analytics.js:cookie'); +var defaults = require('@ndhoule/defaults'); +var json = require('json3'); +var topDomain = require('@segment/top-domain'); + +/** + * Initialize a new `Cookie` with `options`. + * + * @param {Object} options + */ + +function Cookie(options) { + this.options(options); +} + +/** + * Get or set the cookie options. + * + * @param {Object} options + * @field {Number} maxage (1 year) + * @field {String} domain + * @field {String} path + * @field {Boolean} secure + */ + +Cookie.prototype.options = function(options) { + if (arguments.length === 0) return this._options; + + options = options || {}; + + var domain = '.' + topDomain(window.location.href); + if (domain === '.') domain = null; + + this._options = defaults(options, { + // default to a year + maxage: 31536000000, + path: '/', + domain: domain + }); + + // http://curl.haxx.se/rfc/cookie_spec.html + // https://publicsuffix.org/list/effective_tld_names.dat + // + // try setting a dummy cookie with the options + // if the cookie isn't set, it probably means + // that the domain is on the public suffix list + // like myapp.herokuapp.com or localhost / ip. + this.set('ajs:test', true); + if (!this.get('ajs:test')) { + debug('fallback to domain=null'); + this._options.domain = null; + } + this.remove('ajs:test'); +}; + +/** + * Set a `key` and `value` in our cookie. + * + * @param {String} key + * @param {Object} value + * @return {Boolean} saved + */ + +Cookie.prototype.set = function(key, value) { + try { + value = json.stringify(value); + cookie(key, value, clone(this._options)); + return true; + } catch (e) { + return false; + } +}; + +/** + * Get a value from our cookie by `key`. + * + * @param {String} key + * @return {Object} value + */ + +Cookie.prototype.get = function(key) { + try { + var value = cookie(key); + value = value ? json.parse(value) : null; + return value; + } catch (e) { + return null; + } +}; + +/** + * Remove a value from our cookie by `key`. + * + * @param {String} key + * @return {Boolean} removed + */ + +Cookie.prototype.remove = function(key) { + try { + cookie(key, null, clone(this._options)); + return true; + } catch (e) { + return false; + } +}; + +/** + * Expose the cookie singleton. + */ + +module.exports = bindAll(new Cookie()); + +/** + * Expose the `Cookie` constructor. + */ + +module.exports.Cookie = Cookie; + +},{"@ndhoule/clone":3,"@ndhoule/defaults":4,"@segment/top-domain":41,"bind-all":43,"component-cookie":45,"debug":26,"json3":63}],17:[function(require,module,exports){ +'use strict'; + +/* + * Module dependencies. + */ + +var clone = require('@ndhoule/clone'); +var cookie = require('./cookie'); +var debug = require('debug')('analytics:entity'); +var defaults = require('@ndhoule/defaults'); +var extend = require('@ndhoule/extend'); +var memory = require('./memory'); +var store = require('./store'); +var isodateTraverse = require('@segment/isodate-traverse'); + +/** + * Expose `Entity` + */ + +module.exports = Entity; + +/** + * Initialize new `Entity` with `options`. + * + * @param {Object} options + */ + +function Entity(options) { + this.options(options); + this.initialize(); +} + +/** + * Initialize picks the storage. + * + * Checks to see if cookies can be set + * otherwise fallsback to localStorage. + */ + +Entity.prototype.initialize = function() { + cookie.set('ajs:cookies', true); + + // cookies are enabled. + if (cookie.get('ajs:cookies')) { + cookie.remove('ajs:cookies'); + this._storage = cookie; + return; + } + + // localStorage is enabled. + if (store.enabled) { + this._storage = store; + return; + } + + // fallback to memory storage. + debug( + 'warning using memory store both cookies and localStorage are disabled' + ); + this._storage = memory; +}; + +/** + * Get the storage. + */ + +Entity.prototype.storage = function() { + return this._storage; +}; + +/** + * Get or set storage `options`. + * + * @param {Object} options + * @property {Object} cookie + * @property {Object} localStorage + * @property {Boolean} persist (default: `true`) + */ + +Entity.prototype.options = function(options) { + if (arguments.length === 0) return this._options; + this._options = defaults(options || {}, this.defaults || {}); +}; + +/** + * Get or set the entity's `id`. + * + * @param {String} id + */ + +Entity.prototype.id = function(id) { + switch (arguments.length) { + case 0: + return this._getId(); + case 1: + return this._setId(id); + default: + // No default case + } +}; + +/** + * Get the entity's id. + * + * @return {String} + */ + +Entity.prototype._getId = function() { + var ret = this._options.persist + ? this.storage().get(this._options.cookie.key) + : this._id; + return ret === undefined ? null : ret; +}; + +/** + * Set the entity's `id`. + * + * @param {String} id + */ + +Entity.prototype._setId = function(id) { + if (this._options.persist) { + this.storage().set(this._options.cookie.key, id); + } else { + this._id = id; + } +}; + +/** + * Get or set the entity's `traits`. + * + * BACKWARDS COMPATIBILITY: aliased to `properties` + * + * @param {Object} traits + */ + +Entity.prototype.properties = Entity.prototype.traits = function(traits) { + switch (arguments.length) { + case 0: + return this._getTraits(); + case 1: + return this._setTraits(traits); + default: + // No default case + } +}; + +/** + * Get the entity's traits. Always convert ISO date strings into real dates, + * since they aren't parsed back from local storage. + * + * @return {Object} + */ + +Entity.prototype._getTraits = function() { + var ret = this._options.persist + ? store.get(this._options.localStorage.key) + : this._traits; + return ret ? isodateTraverse(clone(ret)) : {}; +}; + +/** + * Set the entity's `traits`. + * + * @param {Object} traits + */ + +Entity.prototype._setTraits = function(traits) { + traits = traits || {}; + if (this._options.persist) { + store.set(this._options.localStorage.key, traits); + } else { + this._traits = traits; + } +}; + +/** + * Identify the entity with an `id` and `traits`. If we it's the same entity, + * extend the existing `traits` instead of overwriting. + * + * @param {String} id + * @param {Object} traits + */ + +Entity.prototype.identify = function(id, traits) { + traits = traits || {}; + var current = this.id(); + if (current === null || current === id) + traits = extend(this.traits(), traits); + if (id) this.id(id); + this.debug('identify %o, %o', id, traits); + this.traits(traits); + this.save(); +}; + +/** + * Save the entity to local storage and the cookie. + * + * @return {Boolean} + */ + +Entity.prototype.save = function() { + if (!this._options.persist) return false; + cookie.set(this._options.cookie.key, this.id()); + store.set(this._options.localStorage.key, this.traits()); + return true; +}; + +/** + * Log the entity out, reseting `id` and `traits` to defaults. + */ + +Entity.prototype.logout = function() { + this.id(null); + this.traits({}); + cookie.remove(this._options.cookie.key); + store.remove(this._options.localStorage.key); +}; + +/** + * Reset all entity state, logging out and returning options to defaults. + */ + +Entity.prototype.reset = function() { + this.logout(); + this.options({}); +}; + +/** + * Load saved entity `id` or `traits` from storage. + */ + +Entity.prototype.load = function() { + this.id(cookie.get(this._options.cookie.key)); + this.traits(store.get(this._options.localStorage.key)); +}; + +},{"./cookie":16,"./memory":20,"./store":24,"@ndhoule/clone":3,"@ndhoule/defaults":4,"@ndhoule/extend":8,"@segment/isodate-traverse":35,"debug":26}],18:[function(require,module,exports){ +'use strict'; + +/* + * Module dependencies. + */ + +var Entity = require('./entity'); +var bindAll = require('bind-all'); +var debug = require('debug')('analytics:group'); +var inherit = require('inherits'); + +/** + * Group defaults + */ + +Group.defaults = { + persist: true, + cookie: { + key: 'ajs_group_id' + }, + localStorage: { + key: 'ajs_group_properties' + } +}; + +/** + * Initialize a new `Group` with `options`. + * + * @param {Object} options + */ + +function Group(options) { + this.defaults = Group.defaults; + this.debug = debug; + Entity.call(this, options); +} + +/** + * Inherit `Entity` + */ + +inherit(Group, Entity); + +/** + * Expose the group singleton. + */ + +module.exports = bindAll(new Group()); + +/** + * Expose the `Group` constructor. + */ + +module.exports.Group = Group; + +},{"./entity":17,"bind-all":43,"debug":26,"inherits":60}],19:[function(require,module,exports){ +'use strict'; + +/** + * Analytics.js + * + * (C) 2013-2016 Segment.io Inc. + */ + +var Analytics = require('./analytics'); + +// Create a new `analytics` singleton. +var analytics = new Analytics(); + +// Expose `require`. +// TODO(ndhoule): Look into deprecating, we no longer need to expose it in tests +analytics.require = require; + +// Expose package version. +analytics.VERSION = require('../package.json').version; + +/* + * Exports. + */ + +module.exports = analytics; + +},{"../package.json":27,"./analytics":15}],20:[function(require,module,exports){ +'use strict'; + +/* + * Module Dependencies. + */ + +var bindAll = require('bind-all'); +var clone = require('@ndhoule/clone'); + +/** + * HOP. + */ + +var has = Object.prototype.hasOwnProperty; + +/** + * Expose `Memory` + */ + +module.exports = bindAll(new Memory()); + +/** + * Initialize `Memory` store + */ + +function Memory() { + this.store = {}; +} + +/** + * Set a `key` and `value`. + * + * @param {String} key + * @param {Mixed} value + * @return {Boolean} + */ + +Memory.prototype.set = function(key, value) { + this.store[key] = clone(value); + return true; +}; + +/** + * Get a `key`. + * + * @param {String} key + */ + +Memory.prototype.get = function(key) { + if (!has.call(this.store, key)) return; + return clone(this.store[key]); +}; + +/** + * Remove a `key`. + * + * @param {String} key + * @return {Boolean} + */ + +Memory.prototype.remove = function(key) { + delete this.store[key]; + return true; +}; + +},{"@ndhoule/clone":3,"bind-all":43}],21:[function(require,module,exports){ +'use strict'; + +var bindAll = require('bind-all'); +var send = require('@segment/send-json'); +var debug = require('debug')('analytics.js:metrics'); + +function Metrics(options) { + this.options(options); +} + +/** + * Set the metrics options. + * + * @param {Object} options + * @field {String} host + * @field {Number} sampleRate + * @field {Number} flushTimer + */ + +Metrics.prototype.options = function(options) { + options = options || {}; + + this.host = options.host || 'api.segment.io/v1'; + this.sampleRate = options.sampleRate || 0; // disable metrics by default. + this.flushTimer = options.flushTimer || 30 * 1000 /* 30s */; + this.maxQueueSize = options.maxQueueSize || 20; + + this.queue = []; + + if (this.sampleRate > 0) { + var self = this; + setInterval(function() { + self._flush(); + }, this.flushTimer); + } +}; + +/** + * Increments the counter identified by name and tags by one. + * + * @param {String} metric Name of the metric to increment. + * @param {Object} tags Dimensions associated with the metric. + */ +Metrics.prototype.increment = function(metric, tags) { + if (Math.random() > this.sampleRate) { + return; + } + + if (this.queue.length >= this.maxQueueSize) { + return; + } + + this.queue.push({ type: 'Counter', metric: metric, value: 1, tags: tags }); + + // Trigger a flush if this is an error metric. + if (metric.indexOf('error') > 0) { + this._flush(); + } +}; + +/** + * Flush all queued metrics. + */ +Metrics.prototype._flush = function() { + var self = this; + + if (self.queue.length <= 0) { + return; + } + + var payload = { series: this.queue }; + var headers = { 'Content-Type': 'text/plain' }; + + self.queue = []; + + // This endpoint does not support jsonp, so only proceed if the browser + // supports xhr. + if (send.type !== 'xhr') return; + + send('https://' + this.host + '/m', payload, headers, function(err, res) { + debug('sent %O, received %O', payload, [err, res]); + }); +}; + +/** + * Expose the metrics singleton. + */ + +module.exports = bindAll(new Metrics()); + +/** + * Expose the `Metrics` constructor. + */ + +module.exports.Metrics = Metrics; + +},{"@segment/send-json":39,"bind-all":43,"debug":26}],22:[function(require,module,exports){ +'use strict'; + +/** + * Module Dependencies. + */ + +var debug = require('debug')('analytics.js:normalize'); +var defaults = require('@ndhoule/defaults'); +var each = require('@ndhoule/each'); +var includes = require('@ndhoule/includes'); +var map = require('@ndhoule/map'); +var type = require('component-type'); + +/** + * HOP. + */ + +var has = Object.prototype.hasOwnProperty; + +/** + * Expose `normalize` + */ + +module.exports = normalize; + +/** + * Toplevel properties. + */ + +var toplevel = ['integrations', 'anonymousId', 'timestamp', 'context']; + +/** + * Normalize `msg` based on integrations `list`. + * + * @param {Object} msg + * @param {Array} list + * @return {Function} + */ + +function normalize(msg, list) { + var lower = map(function(s) { + return s.toLowerCase(); + }, list); + var opts = msg.options || {}; + var integrations = opts.integrations || {}; + var providers = opts.providers || {}; + var context = opts.context || {}; + var ret = {}; + debug('<-', msg); + + // integrations. + each(function(value, key) { + if (!integration(key)) return; + if (!has.call(integrations, key)) integrations[key] = value; + delete opts[key]; + }, opts); + + // providers. + delete opts.providers; + each(function(value, key) { + if (!integration(key)) return; + if (type(integrations[key]) === 'object') return; + if (has.call(integrations, key) && typeof providers[key] === 'boolean') + return; + integrations[key] = value; + }, providers); + + // move all toplevel options to msg + // and the rest to context. + each(function(value, key) { + if (includes(key, toplevel)) { + ret[key] = opts[key]; + } else { + context[key] = opts[key]; + } + }, opts); + + // cleanup + delete msg.options; + ret.integrations = integrations; + ret.context = context; + ret = defaults(ret, msg); + debug('->', ret); + return ret; + + function integration(name) { + return !!( + includes(name, list) || + name.toLowerCase() === 'all' || + includes(name.toLowerCase(), lower) + ); + } +} + +},{"@ndhoule/defaults":4,"@ndhoule/each":6,"@ndhoule/includes":10,"@ndhoule/map":12,"component-type":53,"debug":26}],23:[function(require,module,exports){ +'use strict'; + +/* + * Module dependencies. + */ + +var canonical = require('@segment/canonical'); +var includes = require('@ndhoule/includes'); +var url = require('component-url'); + +/** + * Return a default `options.context.page` object. + * + * https://segment.com/docs/spec/page/#properties + * + * @return {Object} + */ + +function pageDefaults() { + return { + path: canonicalPath(), + referrer: document.referrer, + search: location.search, + title: document.title, + url: canonicalUrl(location.search) + }; +} + +/** + * Return the canonical path for the page. + * + * @return {string} + */ + +function canonicalPath() { + var canon = canonical(); + if (!canon) return window.location.pathname; + var parsed = url.parse(canon); + return parsed.pathname; +} + +/** + * Return the canonical URL for the page concat the given `search` + * and strip the hash. + * + * @param {string} search + * @return {string} + */ + +function canonicalUrl(search) { + var canon = canonical(); + if (canon) return includes('?', canon) ? canon : canon + search; + var url = window.location.href; + var i = url.indexOf('#'); + return i === -1 ? url : url.slice(0, i); +} + +/* + * Exports. + */ + +module.exports = pageDefaults; + +},{"@ndhoule/includes":10,"@segment/canonical":32,"component-url":54}],24:[function(require,module,exports){ +'use strict'; + +/* + * Module dependencies. + */ + +var bindAll = require('bind-all'); +var defaults = require('@ndhoule/defaults'); +var store = require('@segment/store'); + +/** + * Initialize a new `Store` with `options`. + * + * @param {Object} options + */ + +function Store(options) { + this.options(options); +} + +/** + * Set the `options` for the store. + * + * @param {Object} options + * @field {Boolean} enabled (true) + */ + +Store.prototype.options = function(options) { + if (arguments.length === 0) return this._options; + + options = options || {}; + defaults(options, { enabled: true }); + + this.enabled = options.enabled && store.enabled; + this._options = options; +}; + +/** + * Set a `key` and `value` in local storage. + * + * @param {string} key + * @param {Object} value + */ + +Store.prototype.set = function(key, value) { + if (!this.enabled) return false; + return store.set(key, value); +}; + +/** + * Get a value from local storage by `key`. + * + * @param {string} key + * @return {Object} + */ + +Store.prototype.get = function(key) { + if (!this.enabled) return null; + return store.get(key); +}; + +/** + * Remove a value from local storage by `key`. + * + * @param {string} key + */ + +Store.prototype.remove = function(key) { + if (!this.enabled) return false; + return store.remove(key); +}; + +/** + * Expose the store singleton. + */ + +module.exports = bindAll(new Store()); + +/** + * Expose the `Store` constructor. + */ + +module.exports.Store = Store; + +},{"@ndhoule/defaults":4,"@segment/store":40,"bind-all":43}],25:[function(require,module,exports){ +'use strict'; + +/* + * Module dependencies. + */ + +var Entity = require('./entity'); +var bindAll = require('bind-all'); +var cookie = require('./cookie'); +var debug = require('debug')('analytics:user'); +var inherit = require('inherits'); +var rawCookie = require('component-cookie'); +var uuid = require('uuid'); + +/** + * User defaults + */ + +User.defaults = { + persist: true, + cookie: { + key: 'ajs_user_id', + oldKey: 'ajs_user' + }, + localStorage: { + key: 'ajs_user_traits' + } +}; + +/** + * Initialize a new `User` with `options`. + * + * @param {Object} options + */ + +function User(options) { + this.defaults = User.defaults; + this.debug = debug; + Entity.call(this, options); +} + +/** + * Inherit `Entity` + */ + +inherit(User, Entity); + +/** + * Set/get the user id. + * + * When the user id changes, the method will reset his anonymousId to a new one. + * + * // FIXME: What are the mixed types? + * @param {string} id + * @return {Mixed} + * @example + * // didn't change because the user didn't have previous id. + * anonymousId = user.anonymousId(); + * user.id('foo'); + * assert.equal(anonymousId, user.anonymousId()); + * + * // didn't change because the user id changed to null. + * anonymousId = user.anonymousId(); + * user.id('foo'); + * user.id(null); + * assert.equal(anonymousId, user.anonymousId()); + * + * // change because the user had previous id. + * anonymousId = user.anonymousId(); + * user.id('foo'); + * user.id('baz'); // triggers change + * user.id('baz'); // no change + * assert.notEqual(anonymousId, user.anonymousId()); + */ + +User.prototype.id = function(id) { + var prev = this._getId(); + var ret = Entity.prototype.id.apply(this, arguments); + if (prev == null) return ret; + // FIXME: We're relying on coercion here (1 == "1"), but our API treats these + // two values differently. Figure out what will break if we remove this and + // change to strict equality + /* eslint-disable eqeqeq */ + if (prev != id && id) this.anonymousId(null); + /* eslint-enable eqeqeq */ + return ret; +}; + +/** + * Set / get / remove anonymousId. + * + * @param {String} anonymousId + * @return {String|User} + */ + +User.prototype.anonymousId = function(anonymousId) { + var store = this.storage(); + + // set / remove + if (arguments.length) { + store.set('ajs_anonymous_id', anonymousId); + return this; + } + + // new + anonymousId = store.get('ajs_anonymous_id'); + if (anonymousId) { + return anonymousId; + } + + // old - it is not stringified so we use the raw cookie. + anonymousId = rawCookie('_sio'); + if (anonymousId) { + anonymousId = anonymousId.split('----')[0]; + store.set('ajs_anonymous_id', anonymousId); + store.remove('_sio'); + return anonymousId; + } + + // empty + anonymousId = uuid.v4(); + store.set('ajs_anonymous_id', anonymousId); + return store.get('ajs_anonymous_id'); +}; + +/** + * Remove anonymous id on logout too. + */ + +User.prototype.logout = function() { + Entity.prototype.logout.call(this); + this.anonymousId(null); +}; + +/** + * Load saved user `id` or `traits` from storage. + */ + +User.prototype.load = function() { + if (this._loadOldCookie()) return; + Entity.prototype.load.call(this); +}; + +/** + * BACKWARDS COMPATIBILITY: Load the old user from the cookie. + * + * @api private + * @return {boolean} + */ + +User.prototype._loadOldCookie = function() { + var user = cookie.get(this._options.cookie.oldKey); + if (!user) return false; + + this.id(user.id); + this.traits(user.traits); + cookie.remove(this._options.cookie.oldKey); + return true; +}; + +/** + * Expose the user singleton. + */ + +module.exports = bindAll(new User()); + +/** + * Expose the `User` constructor. + */ + +module.exports.User = User; + +},{"./cookie":16,"./entity":17,"bind-all":43,"component-cookie":45,"debug":26,"inherits":60,"uuid":95}],26:[function(require,module,exports){ + +/** + * Expose `debug()` as the module. + */ + +module.exports = debug; + +/** + * Create a debugger with the given `name`. + * + * @param {String} name + * @return {Type} + * @api public + */ + +function debug(name) { + if (!debug.enabled(name)) return function(){}; + + return function(fmt){ + fmt = coerce(fmt); + + var curr = new Date; + var ms = curr - (debug[name] || curr); + debug[name] = curr; + + fmt = name + + ' ' + + fmt + + ' +' + debug.humanize(ms); + + // This hackery is required for IE8 + // where `console.log` doesn't have 'apply' + window.console + && console.log + && Function.prototype.apply.call(console.log, console, arguments); + } +} + +/** + * The currently active debug mode names. + */ + +debug.names = []; +debug.skips = []; + +/** + * Enables a debug mode by name. This can include modes + * separated by a colon and wildcards. + * + * @param {String} name + * @api public + */ + +debug.enable = function(name) { + try { + localStorage.debug = name; + } catch(e){} + + var split = (name || '').split(/[\s,]+/) + , len = split.length; + + for (var i = 0; i < len; i++) { + name = split[i].replace('*', '.*?'); + if (name[0] === '-') { + debug.skips.push(new RegExp('^' + name.substr(1) + '$')); + } + else { + debug.names.push(new RegExp('^' + name + '$')); + } + } +}; + +/** + * Disable debug output. + * + * @api public + */ + +debug.disable = function(){ + debug.enable(''); +}; + +/** + * Humanize the given `ms`. + * + * @param {Number} m + * @return {String} + * @api private + */ + +debug.humanize = function(ms) { + var sec = 1000 + , min = 60 * 1000 + , hour = 60 * min; + + if (ms >= hour) return (ms / hour).toFixed(1) + 'h'; + if (ms >= min) return (ms / min).toFixed(1) + 'm'; + if (ms >= sec) return (ms / sec | 0) + 's'; + return ms + 'ms'; +}; + +/** + * Returns true if the given mode name is enabled, false otherwise. + * + * @param {String} name + * @return {Boolean} + * @api public + */ + +debug.enabled = function(name) { + for (var i = 0, len = debug.skips.length; i < len; i++) { + if (debug.skips[i].test(name)) { + return false; + } + } + for (var i = 0, len = debug.names.length; i < len; i++) { + if (debug.names[i].test(name)) { + return true; + } + } + return false; +}; + +/** + * Coerce `val`. + */ + +function coerce(val) { + if (val instanceof Error) return val.stack || val.message; + return val; +} + +// persist + +try { + if (window.localStorage) debug.enable(localStorage.debug); +} catch(e){} + +},{}],27:[function(require,module,exports){ +module.exports={ + "name": "@segment/analytics.js-core", + "author": "Segment <[email protected]>", + "version": "3.7.2", + "description": "The hassle-free way to integrate analytics into any web application.", + "keywords": [ + "analytics", + "analytics.js", + "segment", + "segment.io" + ], + "main": "lib/index.js", + "scripts": { + "test": "make test", + "lint": "eslint \"./{lib,test}/**/*.js\"", + "format": "prettier-eslint --write --list-different \"./{lib,test}/**/*.{js,json,md}\"", + "precommit": "lint-staged", + "np": "np --no-publish" + }, + "lint-staged": { + "linters": { + "*.{js,json,md}": [ + "prettier-eslint --write", + "git add" + ] + } + }, + "repository": { + "type": "git", + "url": "https://github.com/segmentio/analytics.js-core" + }, + "license": "SEE LICENSE IN LICENSE", + "bugs": { + "url": "https://github.com/segmentio/analytics.js-core/issues" + }, + "homepage": "https://github.com/segmentio/analytics.js-core#readme", + "dependencies": { + "@ndhoule/after": "^1.0.0", + "@ndhoule/clone": "^1.0.0", + "@ndhoule/defaults": "^2.0.1", + "@ndhoule/each": "^2.0.1", + "@ndhoule/extend": "^2.0.0", + "@ndhoule/foldl": "^2.0.1", + "@ndhoule/includes": "^2.0.1", + "@ndhoule/keys": "^2.0.0", + "@ndhoule/map": "^2.0.1", + "@ndhoule/pick": "^2.0.0", + "@segment/canonical": "^1.0.0", + "@segment/is-meta": "^1.0.0", + "@segment/isodate": "^1.0.2", + "@segment/isodate-traverse": "^1.0.1", + "@segment/prevent-default": "^1.0.0", + "@segment/send-json": "^3.0.0", + "@segment/store": "^1.3.20", + "@segment/top-domain": "^3.0.0", + "bind-all": "^1.0.0", + "component-cookie": "^1.1.2", + "component-emitter": "^1.2.1", + "component-event": "^0.1.4", + "component-querystring": "^2.0.0", + "component-type": "^1.2.1", + "component-url": "^0.2.1", + "debug": "^0.7.4", + "extend": "3.0.1", + "inherits": "^2.0.1", + "install": "^0.7.3", + "is": "^3.1.0", + "json3": "^3.3.2", + "new-date": "^1.0.0", + "next-tick": "^0.2.2", + "segmentio-facade": "^3.0.2", + "uuid": "^2.0.2" + }, + "devDependencies": { + "@segment/analytics.js-integration": "^3.2.1", + "@segment/eslint-config": "^4.0.0", + "browserify": "13.0.0", + "browserify-istanbul": "^2.0.0", + "codecov": "^3.0.2", + "compat-trigger-event": "^1.0.0", + "component-each": "^0.2.6", + "eslint": "^4.19.1", + "eslint-config-prettier": "^2.9.0", + "eslint-plugin-mocha": "^5.0.0", + "eslint-plugin-react": "^7.9.1", + "eslint-plugin-require-path-exists": "^1.1.8", + "husky": "^0.14.3", + "istanbul": "^0.4.3", + "jquery": "^3.2.1", + "karma": "1.3.0", + "karma-browserify": "^5.0.4", + "karma-chrome-launcher": "^1.0.1", + "karma-coverage": "^1.0.0", + "karma-junit-reporter": "^1.0.0", + "karma-mocha": "1.0.1", + "karma-phantomjs-launcher": "^1.0.0", + "karma-sauce-launcher": "^1.0.0", + "karma-spec-reporter": "0.0.26", + "karma-summary-reporter": "^1.5.0", + "lint-staged": "^7.2.0", + "mocha": "^2.2.5", + "np": "^3.0.4", + "phantomjs-prebuilt": "^2.1.7", + "prettier-eslint-cli": "^4.7.1", + "proclaim": "^3.4.1", + "sinon": "^1.7.3", + "snyk": "^1.83.0", + "watchify": "^3.7.0" + } +} + +},{}],28:[function(require,module,exports){ +'use strict'; + +/** + * Module dependencies. + */ + +var bind = require('component-bind'); +var clone = require('@ndhoule/clone'); +var debug = require('debug'); +var defaults = require('@ndhoule/defaults'); +var extend = require('@ndhoule/extend'); +var slug = require('slug-component'); +var protos = require('./protos'); +var statics = require('./statics'); + +/** + * Create a new `Integration` constructor. + * + * @constructs Integration + * @param {string} name + * @return {Function} Integration + */ + +function createIntegration(name) { + /** + * Initialize a new `Integration`. + * + * @class + * @param {Object} options + */ + + function Integration(options) { + if (options && options.addIntegration) { + // plugin + return options.addIntegration(Integration); + } + this.debug = debug('analytics:integration:' + slug(name)); + this.options = defaults(clone(options) || {}, this.defaults); + this._queue = []; + this.once('ready', bind(this, this.flush)); + + Integration.emit('construct', this); + this.ready = bind(this, this.ready); + this._wrapInitialize(); + this._wrapPage(); + this._wrapTrack(); + } + + Integration.prototype.defaults = {}; + Integration.prototype.globals = []; + Integration.prototype.templates = {}; + Integration.prototype.name = name; + extend(Integration, statics); + extend(Integration.prototype, protos); + + return Integration; +} + +/** + * Exports. + */ + +module.exports = createIntegration; + +},{"./protos":29,"./statics":30,"@ndhoule/clone":3,"@ndhoule/defaults":4,"@ndhoule/extend":8,"component-bind":44,"debug":55,"slug-component":87}],29:[function(require,module,exports){ +'use strict'; + +/** + * Module dependencies. + */ + +var Emitter = require('component-emitter'); +var after = require('@ndhoule/after'); +var each = require('@ndhoule/each'); +var events = require('analytics-events'); +var every = require('@ndhoule/every'); +var fmt = require('@segment/fmt'); +var foldl = require('@ndhoule/foldl'); +var is = require('is'); +var loadIframe = require('load-iframe'); +var loadScript = require('@segment/load-script'); +var nextTick = require('next-tick'); +var normalize = require('to-no-case'); + +/** + * hasOwnProperty reference. + */ + +var has = Object.prototype.hasOwnProperty; + +/** + * No operation. + */ + +var noop = function noop() {}; + +/** + * Window defaults. + */ + +var onerror = window.onerror; +var onload = null; + +/** + * Mixin emitter. + */ + +/* eslint-disable new-cap */ +Emitter(exports); +/* eslint-enable new-cap */ + +/** + * Initialize. + */ + +exports.initialize = function() { + var ready = this.ready; + nextTick(ready); +}; + +/** + * Loaded? + * + * @api private + * @return {boolean} + */ + +exports.loaded = function() { + return false; +}; + +/** + * Page. + * + * @api public + * @param {Page} page + */ + +/* eslint-disable no-unused-vars */ +exports.page = function(page) {}; +/* eslint-enable no-unused-vars */ + +/** + * Track. + * + * @api public + * @param {Track} track + */ + +/* eslint-disable no-unused-vars */ +exports.track = function(track) {}; +/* eslint-enable no-unused-vars */ + +/** + * Get values from items in `options` that are mapped to `key`. + * `options` is an integration setting which is a collection + * of type 'map', 'array', or 'mixed' + * + * Use cases include mapping events to pixelIds (map), sending generic + * conversion pixels only for specific events (array), or configuring dynamic + * mappings of event properties to query string parameters based on event (mixed) + * + * @api public + * @param {Object|Object[]|String[]} options An object, array of objects, or + * array of strings pulled from settings.mapping. + * @param {string} key The name of the item in options whose metadata + * we're looking for. + * @return {Array} An array of settings that match the input `key` name. + * @example + * + * // 'Map' + * var events = { my_event: 'a4991b88' }; + * .map(events, 'My Event'); + * // => ["a4991b88"] + * .map(events, 'whatever'); + * // => [] + * + * // 'Array' + * * var events = ['Completed Order', 'My Event']; + * .map(events, 'My Event'); + * // => ["My Event"] + * .map(events, 'whatever'); + * // => [] + * + * // 'Mixed' + * var events = [{ key: 'my event', value: '9b5eb1fa' }]; + * .map(events, 'my_event'); + * // => ["9b5eb1fa"] + * .map(events, 'whatever'); + * // => [] + */ + +exports.map = function(options, key) { + var normalizedComparator = normalize(key); + var mappingType = getMappingType(options); + + if (mappingType === 'unknown') { + return []; + } + + return foldl(function(matchingValues, val, key) { + var compare; + var result; + + if (mappingType === 'map') { + compare = key; + result = val; + } + + if (mappingType === 'array') { + compare = val; + result = val; + } + + if (mappingType === 'mixed') { + compare = val.key; + result = val.value; + } + + if (normalize(compare) === normalizedComparator) { + matchingValues.push(result); + } + + return matchingValues; + }, [], options); +}; + +/** + * Invoke a `method` that may or may not exist on the prototype with `args`, + * queueing or not depending on whether the integration is "ready". Don't + * trust the method call, since it contains integration party code. + * + * @api private + * @param {string} method + * @param {...*} args + */ + +exports.invoke = function(method) { + if (!this[method]) return; + var args = Array.prototype.slice.call(arguments, 1); + if (!this._ready) return this.queue(method, args); + + this.debug('%s with %o', method, args); + return this[method].apply(this, args); +}; + +/** + * Queue a `method` with `args`. If the integration assumes an initial + * pageview, then let the first call to `page` pass through. + * + * @api private + * @param {string} method + * @param {Array} args + */ + +exports.queue = function(method, args) { + if (method === 'page' && this._assumesPageview && !this._initialized) { + return this.page.apply(this, args); + } + + this._queue.push({ method: method, args: args }); +}; + +/** + * Flush the internal queue. + * + * @api private + */ + +exports.flush = function() { + this._ready = true; + var self = this; + + each(function(call) { + self[call.method].apply(self, call.args); + }, this._queue); + + // Empty the queue. + this._queue.length = 0; +}; + +/** + * Reset the integration, removing its global variables. + * + * @api private + */ + +exports.reset = function() { + for (var i = 0; i < this.globals.length; i++) { + window[this.globals[i]] = undefined; + } + + window.onerror = onerror; + window.onload = onload; +}; + +/** + * Load a tag by `name`. + * + * @param {string} name The name of the tag. + *
<TRUNCATED>
