From 9c118ef8f5f2dcc6b9c51a7554fe0ac112b3d894 Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Wed, 18 Dec 2013 14:54:14 -0800 Subject: [PATCH] 1.2.3 --- History.md | 4 + analytics.js | 4333 +++++++++++++++++++++++----------------------- analytics.min.js | 12 +- bower.json | 2 +- component.json | 8 +- lib/index.js | 2 +- package.json | 2 +- 7 files changed, 2149 insertions(+), 2214 deletions(-) diff --git a/History.md b/History.md index 805eebe10..52e6cea09 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,7 @@ +1.2.3 - December 18, 2013 +------------------------- +* fix `facade` dependency + 1.2.2 - December 18, 2013 ------------------------- * upgrade `analytics.js-integrations` to `0.3.2` diff --git a/analytics.js b/analytics.js index 2fdc27fbd..c747b63f7 100644 --- a/analytics.js +++ b/analytics.js @@ -834,6 +834,15 @@ exports.unbind = function(el, type, fn, capture){ return fn; }; +}); +require.register("component-inherit/index.js", function(exports, require, module){ + +module.exports = function(a, b){ + var fn = function(){}; + fn.prototype = b.prototype; + a.prototype = new fn; + a.prototype.constructor = a; +}; }); require.register("component-object/index.js", function(exports, require, module){ @@ -921,15 +930,6 @@ exports.isEmpty = function(obj){ return 0 == exports.length(obj); }; }); -require.register("component-inherit/index.js", function(exports, require, module){ - -module.exports = function(a, b){ - var fn = function(){}; - fn.prototype = b.prototype; - a.prototype = new fn; - a.prototype.constructor = a; -}; -}); require.register("component-trim/index.js", function(exports, require, module){ exports = module.exports = trim; @@ -1115,8 +1115,13 @@ module.exports = function (obj) { }); require.register("ianstormtaylor-bind/index.js", function(exports, require, module){ -var bind = require('bind') - , bindAll = require('bind-all'); +try { + var bind = require('bind'); +} catch (e) { + var bind = require('bind-component'); +} + +var bindAll = require('bind-all'); /** @@ -1192,7 +1197,6 @@ else if (typeof window == 'undefined' || window.ActiveXObject || !window.postMes }); require.register("ianstormtaylor-callback/index.js", function(exports, require, module){ - var next = require('next-tick'); @@ -8675,2699 +8679,2644 @@ module.exports = function extend (object) { return object; }; }); -require.register("segmentio-is-email/index.js", function(exports, require, module){ - +require.register("CamShaft-require-component/index.js", function(exports, require, module){ /** - * Expose `isEmail`. + * Require a module with a fallback */ +module.exports = function(parent) { + function require(name, fallback) { + try { + return parent(name); + } + catch (e) { + try { + return parent(fallback || name+"-component"); + } + catch(e2) { + throw e; + } + } + }; -module.exports = isEmail; - + // Merge the old properties + for (var key in parent) { + require[key] = parent[key]; + } -/** - * Email address matcher. - */ + return require; +}; -var matcher = /.+\@.+\..+/; +}); +require.register("component-user-agent-parser/src/ua-parser.js", function(exports, require, module){ +// UAParser.js v0.6.0 +// Lightweight JavaScript-based User-Agent string parser +// https://github.com/faisalman/ua-parser-js +// +// Copyright © 2012-2013 Faisalman +// Dual licensed under GPLv2 & MIT +(function (window, undefined) { -/** - * Loosely validate an email address. - * - * @param {String} string - * @return {Boolean} - */ + 'use strict'; -function isEmail (string) { - return matcher.test(string); -} -}); -require.register("segmentio-is-meta/index.js", function(exports, require, module){ -module.exports = function isMeta (e) { - if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return true; + ////////////// + // Constants + ///////////// - // Logic that handles checks for the middle mouse button, based - // on [jQuery](https://github.com/jquery/jquery/blob/master/src/event.js#L466). - var which = e.which, button = e.button; - if (!which && button !== undefined) { - return (!button & 1) && (!button & 2) && (button & 4); - } else if (which === 2) { - return true; - } - return false; -}; -}); -require.register("segmentio-isodate/index.js", function(exports, require, module){ + var EMPTY = '', + UNKNOWN = '?', + FUNC_TYPE = 'function', + UNDEF_TYPE = 'undefined', + OBJ_TYPE = 'object', + MAJOR = 'major', + MODEL = 'model', + NAME = 'name', + TYPE = 'type', + VENDOR = 'vendor', + VERSION = 'version', + ARCHITECTURE= 'architecture', + CONSOLE = 'console', + MOBILE = 'mobile', + TABLET = 'tablet'; -/** - * Matcher, slightly modified from: - * - * https://github.com/csnover/js-iso8601/blob/lax/iso8601.js - */ -var matcher = /^(\d{4})(?:-?(\d{2})(?:-?(\d{2}))?)?(?:([ T])(\d{2}):?(\d{2})(?::?(\d{2})(?:[,\.](\d{1,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?)?)?$/; + /////////// + // Helper + ////////// -/** - * Convert an ISO date string to a date. Fallback to native `Date.parse`. - * - * https://github.com/csnover/js-iso8601/blob/lax/iso8601.js - * - * @param {String} iso - * @return {Date} - */ + var util = { + has : function (str1, str2) { + return str2.toLowerCase().indexOf(str1.toLowerCase()) !== -1; + }, + lowerize : function (str) { + return str.toLowerCase(); + } + }; -exports.parse = function (iso) { - var numericKeys = [1, 5, 6, 7, 8, 11, 12]; - var arr = matcher.exec(iso); - var offset = 0; - // fallback to native parsing - if (!arr) return new Date(iso); + /////////////// + // Map helper + ////////////// - // remove undefined values - for (var i = 0, val; val = numericKeys[i]; i++) { - arr[val] = parseInt(arr[val], 10) || 0; - } - // allow undefined days and months - arr[2] = parseInt(arr[2], 10) || 1; - arr[3] = parseInt(arr[3], 10) || 1; + var mapper = { - // month is 0-11 - arr[2]--; + rgx : function () { - // allow abitrary sub-second precision - if (arr[8]) arr[8] = (arr[8] + '00').substring(0, 3); + // loop through all regexes maps + for (var result, i = 0, j, k, p, q, matches, match, args = arguments; i < args.length; i += 2) { - // apply timezone if one exists - if (arr[4] == ' ') { - offset = new Date().getTimezoneOffset(); - } else if (arr[9] !== 'Z' && arr[10]) { - offset = arr[11] * 60 + arr[12]; - if ('+' == arr[10]) offset = 0 - offset; - } + var regex = args[i], // even sequence (0,2,4,..) + props = args[i + 1]; // odd sequence (1,3,5,..) - var millis = Date.UTC(arr[1], arr[2], arr[3], arr[5], arr[6] + offset, arr[7], arr[8]); - return new Date(millis); -}; + // construct object barebones + if (typeof(result) === UNDEF_TYPE) { + result = {}; + for (p in props) { + q = props[p]; + if (typeof(q) === OBJ_TYPE) { + result[q[0]] = undefined; + } else { + result[q] = undefined; + } + } + } + // try matching uastring with regexes + for (j = k = 0; j < regex.length; j++) { + matches = regex[j].exec(this.getUA()); + if (!!matches) { + for (p in props) { + match = matches[++k]; + q = props[p]; + // check if given property is actually array + if (typeof(q) === OBJ_TYPE && q.length > 0) { + if (q.length == 2) { + if (typeof(q[1]) == FUNC_TYPE) { + // assign modified match + result[q[0]] = q[1].call(this, match); + } else { + // assign given value, ignore regex match + result[q[0]] = q[1]; + } + } else if (q.length == 3) { + // check whether function or regex + if (typeof(q[1]) === FUNC_TYPE && !(q[1].exec && q[1].test)) { + // call function (usually string mapper) + result[q[0]] = match ? q[1].call(this, match, q[2]) : undefined; + } else { + // sanitize match using given regex + result[q[0]] = match ? match.replace(q[1], q[2]) : undefined; + } + } else if (q.length == 4) { + result[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined; + } + } else { + result[q] = match ? match : undefined; + } + } + break; + } + } -/** - * Checks whether a `string` is an ISO date string. `strict` mode requires that - * the date string at least have a year, month and date. - * - * @param {String} string - * @param {Boolean} strict - * @return {Boolean} - */ + if(!!matches) break; // break the loop immediately if match found + } + return result; + }, -exports.is = function (string, strict) { - if (strict && false === /^\d{4}-\d{2}-\d{2}/.test(string)) return false; - return matcher.test(string); -}; -}); -require.register("segmentio-isodate-traverse/index.js", function(exports, require, module){ + str : function (str, map) { -var is = require('is'); -var isodate = require('isodate'); + for (var i in map) { + // check if array + if (typeof(map[i]) === OBJ_TYPE && map[i].length > 0) { + for (var j in map[i]) { + if (util.has(map[i][j], str)) { + return (i === UNKNOWN) ? undefined : i; + } + } + } else if (util.has(map[i], str)) { + return (i === UNKNOWN) ? undefined : i; + } + } + return str; + } + }; -var clone; -var each; -try { - clone = require('clone'); - each = require('each'); -} catch (err) { - clone = require('clone-component'); - each = require('each-component'); -} + /////////////// + // String map + ////////////// -/** - * Expose `traverse`. - */ -module.exports = traverse; + var maps = { + browser : { + oldsafari : { + major : { + '1' : ['/8', '/1', '/3'], + '2' : '/4', + '?' : '/' + }, + version : { + '1.0' : '/8', + '1.2' : '/1', + '1.3' : '/3', + '2.0' : '/412', + '2.0.2' : '/416', + '2.0.3' : '/417', + '2.0.4' : '/419', + '?' : '/' + } + } + }, -/** - * Traverse an object, parsing all ISO strings into dates and returning a clone. - * - * @param {Object} obj - * @return {Object} - */ + device : { + sprint : { + model : { + 'Evo Shift 4G' : '7373KT' + }, + vendor : { + 'HTC' : 'APA', + 'Sprint' : 'Sprint' + } + } + }, -function traverse (obj, strict) { - obj = clone(obj); - if (strict === undefined) strict = true; - each(obj, function (key, val) { - if (isodate.is(val, strict)) { - obj[key] = isodate.parse(val); - } else if (is.object(val)) { - obj[key] = traverse(val); - } - }); - return obj; -} -}); -require.register("component-json-fallback/index.js", function(exports, require, module){ -/* - json2.js - 2011-10-19 + os : { + windows : { + version : { + 'ME' : '4.90', + 'NT 3.11' : 'NT3.51', + 'NT 4.0' : 'NT4.0', + '2000' : 'NT 5.0', + 'XP' : ['NT 5.1', 'NT 5.2'], + 'Vista' : 'NT 6.0', + '7' : 'NT 6.1', + '8' : 'NT 6.2', + 'RT' : 'ARM' + } + } + } + }; - Public Domain. - NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + ////////////// + // Regex map + ///////////// - See http://www.JSON.org/js.html + var regexes = { - This code should be minified before deployment. - See http://javascript.crockford.com/jsmin.html + browser : [[ - USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO - NOT CONTROL. + // Presto based + /(opera\smini)\/((\d+)?[\w\.-]+)/i, // Opera Mini + /(opera\s[mobiletab]+).+version\/((\d+)?[\w\.-]+)/i, // Opera Mobi/Tablet + /(opera).+version\/((\d+)?[\w\.]+)/i, // Opera > 9.80 + /(opera)[\/\s]+((\d+)?[\w\.]+)/i // Opera < 9.80 + ], [NAME, VERSION, MAJOR], [ - This file creates a global JSON object containing two methods: stringify - and parse. + /\s(opr)\/((\d+)?[\w\.]+)/i // Opera Webkit + ], [[NAME, 'Opera'], VERSION, MAJOR], [ - JSON.stringify(value, replacer, space) - value any JavaScript value, usually an object or array. + // Mixed + /(kindle)\/((\d+)?[\w\.]+)/i, // Kindle + /(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?((\d+)?[\w\.]+)*/i, + // Lunascape/Maxthon/Netfront/Jasmine/Blazer - replacer an optional parameter that determines how object - values are stringified for objects. It can be a - function or an array of strings. + // Trident based + /(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?((\d+)?[\w\.]*)/i, + // Avant/IEMobile/SlimBrowser/Baidu + /(?:ms|\()(ie)\s((\d+)?[\w\.]+)/i, // Internet Explorer - space an optional parameter that specifies the indentation - of nested structures. If it is omitted, the text will - be packed without extra whitespace. If it is a number, - it will specify the number of spaces to indent at each - level. If it is a string (such as '\t' or ' '), - it contains the characters used to indent at each level. + // Webkit/KHTML based + /(rekonq)((?:\/)[\w\.]+)*/i, // Rekonq + /(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt)\/((\d+)?[\w\.-]+)/i + // Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt + ], [NAME, VERSION, MAJOR], [ - This method produces a JSON text from a JavaScript value. + /(yabrowser)\/((\d+)?[\w\.]+)/i // Yandex + ], [[NAME, 'Yandex'], VERSION, MAJOR], [ - When an object value is found, if the object contains a toJSON - method, its toJSON method will be called and the result will be - stringified. A toJSON method does not serialize: it returns the - value represented by the name/value pair that should be serialized, - or undefined if nothing should be serialized. The toJSON method - will be passed the key associated with the value, and this will be - bound to the value + /(comodo_dragon)\/((\d+)?[\w\.]+)/i // Comodo Dragon + ], [[NAME, /_/g, ' '], VERSION, MAJOR], [ - For example, this would serialize Dates as ISO strings. + /(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?((\d+)?[\w\.]+)/i + // Chrome/OmniWeb/Arora/Tizen/Nokia + ], [NAME, VERSION, MAJOR], [ - Date.prototype.toJSON = function (key) { - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } + /(dolfin)\/((\d+)?[\w\.]+)/i // Dolphin + ], [[NAME, 'Dolphin'], VERSION, MAJOR], [ - return this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z'; - }; + /((?:android.+)crmo|crios)\/((\d+)?[\w\.]+)/i // Chrome for Android/iOS + ], [[NAME, 'Chrome'], VERSION, MAJOR], [ - You can provide an optional replacer method. It will be passed the - key and value of each member, with this bound to the containing - object. The value that is returned from your method will be - serialized. If your method returns undefined, then the member will - be excluded from the serialization. + /version\/((\d+)?[\w\.]+).+?mobile\/\w+\s(safari)/i // Mobile Safari + ], [VERSION, MAJOR, [NAME, 'Mobile Safari']], [ - If the replacer parameter is an array of strings, then it will be - used to select the members to be serialized. It filters the results - such that only members with keys listed in the replacer array are - stringified. + /version\/((\d+)?[\w\.]+).+?(mobile\s?safari|safari)/i // Safari & Safari Mobile + ], [VERSION, MAJOR, NAME], [ - Values that do not have JSON representations, such as undefined or - functions, will not be serialized. Such values in objects will be - dropped; in arrays they will be replaced with null. You can use - a replacer function to replace those with JSON values. - JSON.stringify(undefined) returns undefined. + /webkit.+?(mobile\s?safari|safari)((\/[\w\.]+))/i // Safari < 3.0 + ], [NAME, [MAJOR, mapper.str, maps.browser.oldsafari.major], [VERSION, mapper.str, maps.browser.oldsafari.version]], [ - The optional space parameter produces a stringification of the - value that is filled with line breaks and indentation to make it - easier to read. + /(konqueror)\/((\d+)?[\w\.]+)/i, // Konqueror + /(webkit|khtml)\/((\d+)?[\w\.]+)/i + ], [NAME, VERSION, MAJOR], [ - If the space parameter is a non-empty string, then that string will - be used for indentation. If the space parameter is a number, then - the indentation will be that many spaces. + // Gecko based + /(navigator|netscape)\/((\d+)?[\w\.-]+)/i // Netscape + ], [[NAME, 'Netscape'], VERSION, MAJOR], [ + /(swiftfox)/i, // Swiftfox + /(iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?((\d+)?[\w\.\+]+)/i, + // Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror + /(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/((\d+)?[\w\.-]+)/i, + // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix + /(mozilla)\/((\d+)?[\w\.]+).+rv\:.+gecko\/\d+/i, // Mozilla - Example: + // Other + /(uc\s?browser|polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf)[\/\s]?((\d+)?[\w\.]+)/i, + // UCBrowser/Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf + /(links)\s\(((\d+)?[\w\.]+)/i, // Links + /(gobrowser)\/?((\d+)?[\w\.]+)*/i, // GoBrowser + /(ice\s?browser)\/v?((\d+)?[\w\._]+)/i, // ICE Browser + /(mosaic)[\/\s]((\d+)?[\w\.]+)/i // Mosaic + ], [NAME, VERSION, MAJOR] + ], - text = JSON.stringify(['e', {pluribus: 'unum'}]); - // text is '["e",{"pluribus":"unum"}]' + cpu : [[ + /(?:(amd|x(?:(?:86|64)[_-])?|wow|win)64)[;\)]/i // AMD64 + ], [[ARCHITECTURE, 'amd64']], [ - text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); - // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' + /((?:i[346]|x)86)[;\)]/i // IA32 + ], [[ARCHITECTURE, 'ia32']], [ - text = JSON.stringify([new Date()], function (key, value) { - return this[key] instanceof Date ? - 'Date(' + this[key] + ')' : value; - }); - // text is '["Date(---current time---)"]' + /((?:ppc|powerpc)(?:64)?)(?:\smac|;|\))/i // PowerPC + ], [[ARCHITECTURE, /ower/, '', util.lowerize]], [ + /(sun4\w)[;\)]/i // SPARC + ], [[ARCHITECTURE, 'sparc']], [ - JSON.parse(text, reviver) - This method parses a JSON text to produce an object or array. - It can throw a SyntaxError exception. + /(ia64(?=;)|68k(?=\))|arm(?=v\d+;)|(?:irix|mips|sparc)(?:64)?(?=;)|pa-risc)/i + // IA64, 68K, ARM, IRIX, MIPS, SPARC, PA-RISC + ], [ARCHITECTURE, util.lowerize] + ], - The optional reviver parameter is a function that can filter and - transform the results. It receives each of the keys and values, - and its return value is used instead of the original value. - If it returns what it received, then the structure is not modified. - If it returns undefined then the member is deleted. + device : [[ - Example: + /\((ipad|playbook);[\w\s\);-]+(rim|apple)/i // iPad/PlayBook + ], [MODEL, VENDOR, [TYPE, TABLET]], [ - // Parse the text. Values that look like ISO date strings will - // be converted to Date objects. + /(hp).+(touchpad)/i, // HP TouchPad + /(kindle)\/([\w\.]+)/i, // Kindle + /\s(nook)[\w\s]+build\/(\w+)/i, // Nook + /(dell)\s(strea[kpr\s\d]*[\dko])/i // Dell Streak + ], [VENDOR, MODEL, [TYPE, TABLET]], [ - myData = JSON.parse(text, function (key, value) { - var a; - if (typeof value === 'string') { - a = -/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); - if (a) { - return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], - +a[5], +a[6])); - } - } - return value; - }); + /\((ip[honed]+);.+(apple)/i // iPod/iPhone + ], [MODEL, VENDOR, [TYPE, MOBILE]], [ - myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { - var d; - if (typeof value === 'string' && - value.slice(0, 5) === 'Date(' && - value.slice(-1) === ')') { - d = new Date(value.slice(5, -1)); - if (d) { - return d; - } - } - return value; - }); + /(blackberry)[\s-]?(\w+)/i, // BlackBerry + /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|huawei|meizu|motorola)[\s_-]?([\w-]+)*/i, + // BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Huawei/Meizu/Motorola + /(hp)\s([\w\s]+\w)/i, // HP iPAQ + /(asus)-?(\w+)/i // Asus + ], [VENDOR, MODEL, [TYPE, MOBILE]], [ + /\((bb10);\s(\w+)/i // BlackBerry 10 + ], [[VENDOR, 'BlackBerry'], MODEL, [TYPE, MOBILE]], [ + /android.+((transfo[prime\s]{4,10}\s\w+|eeepc|slider\s\w+))/i // Asus Tablets + ], [[VENDOR, 'Asus'], MODEL, [TYPE, TABLET]], [ - This is a reference implementation. You are free to copy, modify, or - redistribute. -*/ + /(sony)\s(tablet\s[ps])/i // Sony Tablets + ], [VENDOR, MODEL, [TYPE, TABLET]], [ -/*jslint evil: true, regexp: true */ + /(nintendo)\s([wids3u]+)/i // Nintendo + ], [VENDOR, MODEL, [TYPE, CONSOLE]], [ -/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, - call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, - getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, - lastIndex, length, parse, prototype, push, replace, slice, stringify, - test, toJSON, toString, valueOf -*/ + /((playstation)\s[3portablevi]+)/i // Playstation + ], [[VENDOR, 'Sony'], MODEL, [TYPE, CONSOLE]], [ + /(sprint\s(\w+))/i // Sprint Phones + ], [[VENDOR, mapper.str, maps.device.sprint.vendor], [MODEL, mapper.str, maps.device.sprint.model], [TYPE, MOBILE]], [ -// Create a JSON object only if one does not already exist. We create the -// methods in a closure to avoid creating global variables. + /(htc)[;_\s-]+([\w\s]+(?=\))|\w+)*/i, // HTC + /(zte)-(\w+)*/i, // ZTE + /(alcatel|geeksphone|huawei|lenovo|nexian|panasonic|(?=;\s)sony)[_\s-]?([\w-]+)*/i + // Alcatel/GeeksPhone/Huawei/Lenovo/Nexian/Panasonic/Sony + ], [VENDOR, [MODEL, /_/g, ' '], [TYPE, MOBILE]], [ -var JSON = {}; + /\s((milestone|droid[2x]?))[globa\s]*\sbuild\//i, // Motorola + /(mot)[\s-]?(\w+)*/i + ], [[VENDOR, 'Motorola'], MODEL, [TYPE, MOBILE]], [ + /android.+\s((mz60\d|xoom[\s2]{0,2}))\sbuild\//i + ], [[VENDOR, 'Motorola'], MODEL, [TYPE, TABLET]], [ -(function () { - 'use strict'; + /android.+((sch-i[89]0\d|shw-m380s|gt-p\d{4}|gt-n8000|sgh-t8[56]9))/i + ], [[VENDOR, 'Samsung'], MODEL, [TYPE, TABLET]], [ // Samsung + /((s[cgp]h-\w+|gt-\w+|galaxy\snexus))/i, + /(sam[sung]*)[\s-]*(\w+-?[\w-]*)*/i, + /sec-((sgh\w+))/i + ], [[VENDOR, 'Samsung'], MODEL, [TYPE, MOBILE]], [ + /(sie)-(\w+)*/i // Siemens + ], [[VENDOR, 'Siemens'], MODEL, [TYPE, MOBILE]], [ - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } + /(maemo|nokia).*(n900|lumia\s\d+)/i, // Nokia + /(nokia)[\s_-]?([\w-]+)*/i + ], [[VENDOR, 'Nokia'], MODEL, [TYPE, MOBILE]], [ - if (typeof Date.prototype.toJSON !== 'function') { + /android\s3\.[\s\w-;]{10}((a\d{3}))/i // Acer + ], [[VENDOR, 'Acer'], MODEL, [TYPE, TABLET]], [ - Date.prototype.toJSON = function (key) { + /android\s3\.[\s\w-;]{10}(lg?)-([06cv9]{3,4})/i // LG + ], [[VENDOR, 'LG'], MODEL, [TYPE, TABLET]], [ + /((nexus\s4))/i, + /(lg)[e;\s-\/]+(\w+)*/i + ], [[VENDOR, 'LG'], MODEL, [TYPE, MOBILE]], [ - return isFinite(this.valueOf()) - ? this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z' - : null; - }; + /(mobile|tablet);.+rv\:.+gecko\//i // Unidentifiable + ], [TYPE, VENDOR, MODEL] + ], - String.prototype.toJSON = - Number.prototype.toJSON = - Boolean.prototype.toJSON = function (key) { - return this.valueOf(); - }; - } + engine : [[ - var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, - escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, - gap, - indent, - meta = { // table of character substitutions - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '"' : '\\"', - '\\': '\\\\' - }, - rep; + /(presto)\/([\w\.]+)/i, // Presto + /(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m + /(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i, // KHTML/Tasman/Links + /(icab)[\/\s]([23]\.[\d\.]+)/i // iCab + ], [NAME, VERSION], [ + /rv\:([\w\.]+).*(gecko)/i // Gecko + ], [VERSION, NAME] + ], - function quote(string) { + os : [[ -// If the string contains no control characters, no quote characters, and no -// backslash characters, then we can safely slap some quotes around it. -// Otherwise we must also replace the offending characters with safe escape -// sequences. + // Windows based + /(windows)\snt\s6\.2;\s(arm)/i, // Windows RT + /(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i + ], [NAME, [VERSION, mapper.str, maps.os.windows.version]], [ + /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i + ], [[NAME, 'Windows'], [VERSION, mapper.str, maps.os.windows.version]], [ - escapable.lastIndex = 0; - return escapable.test(string) ? '"' + string.replace(escapable, function (a) { - var c = meta[a]; - return typeof c === 'string' - ? c - : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }) + '"' : '"' + string + '"'; - } + // Mobile/Embedded OS + /\((bb)(10);/i // BlackBerry 10 + ], [[NAME, 'BlackBerry'], VERSION], [ + /(blackberry)\w*\/?([\w\.]+)*/i, // Blackberry + /(tizen)\/([\w\.]+)/i, // Tizen + /(android|webos|palm\os|qnx|bada|rim\stablet\sos|meego)[\/\s-]?([\w\.]+)*/i + // Android/WebOS/Palm/QNX/Bada/RIM/MeeGo + ], [NAME, VERSION], [ + /(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i // Symbian + ], [[NAME, 'Symbian'], VERSION],[ + /mozilla.+\(mobile;.+gecko.+firefox/i // Firefox OS + ], [[NAME, 'Firefox OS'], VERSION], [ + // Console + /(nintendo|playstation)\s([wids3portablevu]+)/i, // Nintendo/Playstation - function str(key, holder) { + // GNU/Linux based + /(mint)[\/\s\(]?(\w+)*/i, // Mint + /(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk)[\/\s-]?([\w\.-]+)*/i, + // Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware + // Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk + /(hurd|linux)\s?([\w\.]+)*/i, // Hurd/Linux + /(gnu)\s?([\w\.]+)*/i // GNU + ], [NAME, VERSION], [ -// Produce a string from holder[key]. + /(cros)\s[\w]+\s([\w\.]+\w)/i // Chromium OS + ], [[NAME, 'Chromium OS'], VERSION],[ - var i, // The loop counter. - k, // The member key. - v, // The member value. - length, - mind = gap, - partial, - value = holder[key]; + // Solaris + /(sunos)\s?([\w\.]+\d)*/i // Solaris + ], [[NAME, 'Solaris'], VERSION], [ -// If the value has a toJSON method, call it to obtain a replacement value. + // BSD based + /\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i // FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly + ], [NAME, VERSION],[ - if (value && typeof value === 'object' && - typeof value.toJSON === 'function') { - value = value.toJSON(key); - } + /(ip[honead]+)(?:.*os\s*([\w]+)*\slike\smac|;\sopera)/i // iOS + ], [[NAME, 'iOS'], [VERSION, /_/g, '.']], [ -// If we were called with a replacer function, then call the replacer to -// obtain a replacement value. + /(mac\sos\sx)\s?([\w\s\.]+\w)*/i // Mac OS + ], [NAME, [VERSION, /_/g, '.']], [ - if (typeof rep === 'function') { - value = rep.call(holder, key, value); - } + // Other + /(haiku)\s(\w+)/i, // Haiku + /(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i, // AIX + /(macintosh|mac(?=_powerpc)|plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos)/i, + // Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS + /(unix)\s?([\w\.]+)*/i // UNIX + ], [NAME, VERSION] + ] + }; -// What happens next depends on the value's type. + var UAParser = function UAParser (uastring) { + if (!(this instanceof UAParser)) return new UAParser(uastring).getResult(); - switch (typeof value) { - case 'string': - return quote(value); + var ua = uastring || ((window && window.navigator && window.navigator.userAgent) ? window.navigator.userAgent : EMPTY); - case 'number': + if (!(this instanceof UAParser)) { + return new UAParser(uastring).getResult(); + } + this.getBrowser = function () { + return mapper.rgx.apply(this, regexes.browser); + }; + this.getCPU = function () { + return mapper.rgx.apply(this, regexes.cpu); + }; + this.getDevice = function () { + return mapper.rgx.apply(this, regexes.device); + }; + this.getEngine = function () { + return mapper.rgx.apply(this, regexes.engine); + }; + this.getOS = function () { + return mapper.rgx.apply(this, regexes.os); + }; + this.getResult = function() { + return { + browser : this.getBrowser(), + engine : this.getEngine(), + os : this.getOS(), + device : this.getDevice(), + cpu : this.getCPU() + }; + }; + this.getUA = function () { + return ua; + }; + this.setUA = function (uastring) { + ua = uastring; + return this; + }; + this.setUA(ua); + }; -// JSON numbers must be finite. Encode non-finite numbers as null. + module.exports = UAParser; +})(this); - return isFinite(value) ? String(value) : 'null'; +}); +require.register("yields-case/dist/Case.js", function(exports, require, module){ +/*! Case - v1.0.3 - 2013-08-23 +* Copyright (c) 2013 Nathan Bubna; Licensed MIT, GPL */ +(function() { + "use strict"; + var re = { + capitalize: /(^|\W|_)([a-z])/g, + squish: /(^|[\W_])+([a-zA-Z])/g, + fill: /[\W_]+(.|$)/g, + sentence: /(^\s*|[\?\!\.]+"?\s+"?|,\s+")([a-z])/g, + improper: /\b(A|An|And|As|At|But|By|En|For|If|In|Of|On|Or|The|To|Vs?\.?|Via)\b/g, + relax: /([^A-Z])([A-Z]*)([A-Z])(?=[a-z]|$)/g, + upper: /^[^a-z]+$/, + hole: /\s/, + room: /[\W_]/ + }, + _ = { + re: re, + types: [], + up: String.prototype.toUpperCase, + low: String.prototype.toLowerCase, + cap: function(s) { + return _.up.call(s.charAt(0))+s.slice(1); + }, + decap: function(s) { + return _.low.call(s.charAt(0))+s.slice(1); + }, + fill: function(s, fill) { + return !s || fill == null ? s : s.replace(re.fill, function(m, next) { + return next ? fill + next : ''; + }); + }, + prep: function(s, fill, squish, upper) { + if (!s){ return s || ''; } + if (!upper && re.upper.test(s)) { + s = _.low.call(s); + } + if (!fill && !re.hole.test(s)) { + s = _.fill(s, ' '); + } + if (!squish && !re.room.test(s)) { + s = s.replace(re.relax, _.relax); + } + return s; + }, + relax: function(m, before, acronym, caps) { + return before + ' ' + (acronym ? acronym+' ' : '') + caps; + } + }, + Case = { + _: _, + of: function(s) { + for (var i=0,m=_.types.length; i 1) { + key = keys.shift(); + obj = find(obj, key); - for (k in value) { - if (Object.prototype.hasOwnProperty.call(value, k)) { - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } + if (obj === null || obj === undefined) return; + } -// Join all of the member texts together, separated with commas, -// and wrap them in braces. + key = keys.shift(); + return fn(obj, key, val); + }; +} - v = partial.length === 0 - ? '{}' - : gap - ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' - : '{' + partial.join(',') + '}'; - gap = mind; - return v; - } - } -// If the JSON object does not yet have a stringify method, give it one. +/** + * Find an object by its key + * + * find({ first_name : 'Calvin' }, 'firstName') + */ - if (typeof JSON.stringify !== 'function') { - JSON.stringify = function (value, replacer, space) { +function find (obj, key) { + for (var i = 0; i < cases.length; i++) { + var cased = cases[i](key); + if (obj.hasOwnProperty(cased)) return obj[cased]; + } +} -// The stringify method takes a value and an optional replacer, and an optional -// space parameter, and returns a JSON text. The replacer can be a function -// that can replace values, or an array of strings that will select the keys. -// A default replacer method can be provided. Use of the space parameter can -// produce text that is more easily readable. - var i; - gap = ''; - indent = ''; - -// If the space parameter is a number, make an indent string containing that -// many spaces. - - if (typeof space === 'number') { - for (i = 0; i < space; i += 1) { - indent += ' '; - } - -// If the space parameter is a string, it will be used as the indent string. - - } else if (typeof space === 'string') { - indent = space; - } - -// If there is a replacer, it must be a function or an array. -// Otherwise, throw an error. - - rep = replacer; - if (replacer && typeof replacer !== 'function' && - (typeof replacer !== 'object' || - typeof replacer.length !== 'number')) { - throw new Error('JSON.stringify'); - } - -// Make a fake root object containing our value under the key of ''. -// Return the result of stringifying the value. - - return str('', {'': value}); - }; - } - - -// If the JSON object does not yet have a parse method, give it one. - - if (typeof JSON.parse !== 'function') { - JSON.parse = function (text, reviver) { - -// The parse method takes a text and an optional reviver function, and returns -// a JavaScript value if the text is a valid JSON text. - - var j; - - function walk(holder, key) { - -// The walk method is used to recursively walk the resulting structure so -// that modifications can be made. - - var k, v, value = holder[key]; - if (value && typeof value === 'object') { - for (k in value) { - if (Object.prototype.hasOwnProperty.call(value, k)) { - v = walk(value, k); - if (v !== undefined) { - value[k] = v; - } else { - delete value[k]; - } - } - } - } - return reviver.call(holder, key, value); - } - - -// Parsing happens in four stages. In the first stage, we replace certain -// Unicode characters with escape sequences. JavaScript handles many characters -// incorrectly, either silently deleting them, or treating them as line endings. - - text = String(text); - cx.lastIndex = 0; - if (cx.test(text)) { - text = text.replace(cx, function (a) { - return '\\u' + - ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }); - } - -// In the second stage, we run the text against regular expressions that look -// for non-JSON patterns. We are especially concerned with '()' and 'new' -// because they can cause invocation, and '=' because it can cause mutation. -// But just to be safe, we want to reject all unexpected forms. - -// We split the second stage into 4 regexp operations in order to work around -// crippling inefficiencies in IE's and Safari's regexp engines. First we -// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we -// replace all simple value tokens with ']' characters. Third, we delete all -// open brackets that follow a colon or comma or that begin the text. Finally, -// we look to see that the remaining characters are only whitespace or ']' or -// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. +/** + * Delete a value for a given key + * + * del({ a : 'b', x : 'y' }, 'X' }) -> { a : 'b' } + */ - if (/^[\],:{}\s]*$/ - .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') - .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') - .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { +function del (obj, key) { + for (var i = 0; i < cases.length; i++) { + var cased = cases[i](key); + if (obj.hasOwnProperty(cased)) delete obj[cased]; + } + return obj; +} -// In the third stage we use the eval function to compile the text into a -// JavaScript structure. The '{' operator is subject to a syntactic ambiguity -// in JavaScript: it can begin a block or an object literal. We wrap the text -// in parens to eliminate the ambiguity. - j = eval('(' + text + ')'); +/** + * Replace an objects existing value with a new one + * + * replace({ a : 'b' }, 'a', 'c') -> { a : 'c' } + */ -// In the optional fourth stage, we recursively walk the new structure, passing -// each name/value pair to a reviver function for possible transformation. +function replace (obj, key, val) { + for (var i = 0; i < cases.length; i++) { + var cased = cases[i](key); + if (obj.hasOwnProperty(cased)) obj[cased] = val; + } + return obj; +} +}); +require.register("segmentio-facade/lib/index.js", function(exports, require, module){ - return typeof reviver === 'function' - ? walk({'': j}, '') - : j; - } +var Facade = require('./facade'); -// If the text is not JSON parseable, then a SyntaxError is thrown. +/** + * Expose `Facade` facade. + */ - throw new SyntaxError('JSON.parse'); - }; - } -}()); +module.exports = Facade; -module.exports = JSON -}); -require.register("segmentio-json/index.js", function(exports, require, module){ +/** + * Expose specific-method facades. + */ -module.exports = 'undefined' == typeof JSON - ? require('json-fallback') - : JSON; +Facade.Alias = require('./alias'); +Facade.Group = require('./group'); +Facade.Identify = require('./identify'); +Facade.Track = require('./track'); +Facade.Page = require('./page'); }); -require.register("segmentio-new-date/lib/index.js", function(exports, require, module){ - -var is = require('is'); -var isodate = require('isodate'); -var milliseconds = require('./milliseconds'); -var seconds = require('./seconds'); +require.register("segmentio-facade/lib/alias.js", function(exports, require, module){ +var Facade = require('./facade'); +var component = require('require-component')(require); +var inherit = component('inherit'); /** - * Returns a new Javascript Date object, allowing a variety of extra input types - * over the native Date constructor. - * - * @param {Date|String|Number} val + * Expose `Alias` facade. */ -module.exports = function newDate (val) { - if (is.date(val)) return val; - if (is.number(val)) return new Date(toMs(val)); - - // date strings - if (isodate.is(val)) return isodate.parse(val); - if (milliseconds.is(val)) return milliseconds.parse(val); - if (seconds.is(val)) return seconds.parse(val); - - // fallback to Date.parse - return new Date(val); -}; - +module.exports = Alias; /** - * If the number passed val is seconds from the epoch, turn it into milliseconds. - * Milliseconds would be greater than 31557600000 (December 31, 1970). + * Initialize a new `Alias` facade with a `dictionary` of arguments. * - * @param {Number} num + * @param {Object} dictionary + * @property {String} from + * @property {String} to + * @property {Object} options */ -function toMs (num) { - if (num < 31557600000) return num * 1000; - return num; +function Alias (dictionary) { + Facade.call(this, dictionary); } -}); -require.register("segmentio-new-date/lib/milliseconds.js", function(exports, require, module){ /** - * Matcher. + * Inherit from `Facade`. */ -var matcher = /\d{13}/; - +inherit(Alias, Facade); /** - * Check whether a string is a millisecond date string. + * Return type of facade. * - * @param {String} string - * @return {Boolean} + * @return {String} */ -exports.is = function (string) { - return matcher.test(string); +Alias.prototype.action = function () { + return 'alias'; }; - /** - * Convert a millisecond string to a date. - * - * @param {String} millis - * @return {Date} + * Setup some basic proxies. */ -exports.parse = function (millis) { - millis = parseInt(millis, 10); - return new Date(millis); -}; +Alias.prototype.from = Facade.field('from'); +Alias.prototype.to = Facade.field('to'); }); -require.register("segmentio-new-date/lib/seconds.js", function(exports, require, module){ +require.register("segmentio-facade/lib/facade.js", function(exports, require, module){ + +var component = require('require-component')(require); +var clone = component('clone'); +var isEnabled = component('./is-enabled'); +var objCase = component('obj-case'); /** - * Matcher. + * Expose `Facade`. */ -var matcher = /\d{10}/; +module.exports = Facade; + +/** + * Initialize a new `Facade` with an `obj` of arguments. + * + * @param {Object} obj + */ +function Facade (obj) { + if (!obj.hasOwnProperty('timestamp')) obj.timestamp = new Date(); + else obj.timestamp = new Date(obj.timestamp); + this.obj = obj; +} /** - * Check whether a string is a second date string. + * Return a proxy function for a `field` that will attempt to first use methods, + * and fallback to accessing the underlying object directly. You can specify + * deeply nested fields too like: * - * @param {String} string - * @return {Boolean} + * this.proxy('options.Librato'); + * + * @param {String} field */ -exports.is = function (string) { - return matcher.test(string); -}; +Facade.prototype.proxy = function (field) { + var fields = field.split('.'); + field = fields.shift(); + + // Call a function at the beginning to take advantage of facaded fields + var obj = this[field] || this.field(field); + if (!obj) return obj; + if (typeof obj === 'function') obj = obj.call(this) || {}; + if (fields.length === 0) return clone(obj); + obj = objCase(obj, fields.join('.')); + return clone(obj); +}; /** - * Convert a second string to a date. + * Directly access a specific `field` from the underlying object, returning a + * clone so outsiders don't mess with stuff. * - * @param {String} seconds - * @return {Date} + * @param {String} field + * @return {Mixed} */ -exports.parse = function (seconds) { - var millis = parseInt(seconds, 10) * 1000; - return new Date(millis); +Facade.prototype.field = function (field) { + return clone(this.obj[field]); }; -}); -require.register("segmentio-store.js/store.js", function(exports, require, module){ -;(function(win){ - var store = {}, - doc = win.document, - localStorageName = 'localStorage', - namespace = '__storejs__', - storage - store.disabled = false - store.set = function(key, value) {} - store.get = function(key) {} - store.remove = function(key) {} - store.clear = function() {} - store.transact = function(key, defaultVal, transactionFn) { - var val = store.get(key) - if (transactionFn == null) { - transactionFn = defaultVal - defaultVal = null - } - if (typeof val == 'undefined') { val = defaultVal || {} } - transactionFn(val) - store.set(key, val) - } - store.getAll = function() {} +/** + * Utility method to always proxy a particular `field`. You can specify deeply + * nested fields too like: + * + * Facade.proxy('options.Librato'); + * + * @param {String} field + * @return {Function} + */ - store.serialize = function(value) { - return JSON.stringify(value) - } - store.deserialize = function(value) { - if (typeof value != 'string') { return undefined } - try { return JSON.parse(value) } - catch(e) { return value || undefined } - } +Facade.proxy = function (field) { + return function () { + return this.proxy(field); + }; +}; - // Functions to encapsulate questionable FireFox 3.6.13 behavior - // when about.config::dom.storage.enabled === false - // See https://github.com/marcuswestin/store.js/issues#issue/13 - function isLocalStorageNameSupported() { - try { return (localStorageName in win && win[localStorageName]) } - catch(err) { return false } - } +/** + * Utility method to directly access a `field`. + * + * @param {String} field + * @return {Function} + */ - if (isLocalStorageNameSupported()) { - storage = win[localStorageName] - store.set = function(key, val) { - if (val === undefined) { return store.remove(key) } - storage.setItem(key, store.serialize(val)) - return val - } - store.get = function(key) { return store.deserialize(storage.getItem(key)) } - store.remove = function(key) { storage.removeItem(key) } - store.clear = function() { storage.clear() } - store.getAll = function() { - var ret = {} - for (var i=0; idocument.w=window') - storageContainer.close() - storageOwner = storageContainer.w.frames[0].document - storage = storageOwner.createElement('div') - } catch(e) { - // somehow ActiveXObject instantiation failed (perhaps some special - // security settings or otherwse), fall back to per-path storage - storage = doc.createElement('div') - storageOwner = doc.body - } - function withIEStorage(storeFunction) { - return function() { - var args = Array.prototype.slice.call(arguments, 0) - args.unshift(storage) - // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx - // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx - storageOwner.appendChild(storage) - storage.addBehavior('#default#userData') - storage.load(localStorageName) - var result = storeFunction.apply(store, args) - storageOwner.removeChild(storage) - return result - } - } +Facade.field = function (field) { + return function () { + return this.field(field); + }; +}; - // In IE7, keys may not contain special chars. See all of https://github.com/marcuswestin/store.js/issues/40 - var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g") - function ieKeyFix(key) { - return key.replace(forbiddenCharsRegex, '___') - } - store.set = withIEStorage(function(storage, key, val) { - key = ieKeyFix(key) - if (val === undefined) { return store.remove(key) } - storage.setAttribute(key, store.serialize(val)) - storage.save(localStorageName) - return val - }) - store.get = withIEStorage(function(storage, key) { - key = ieKeyFix(key) - return store.deserialize(storage.getAttribute(key)) - }) - store.remove = withIEStorage(function(storage, key) { - key = ieKeyFix(key) - storage.removeAttribute(key) - storage.save(localStorageName) - }) - store.clear = withIEStorage(function(storage) { - var attributes = storage.XMLDocument.documentElement.attributes - storage.load(localStorageName) - for (var i=0, attr; attr=attributes[i]; i++) { - storage.removeAttribute(attr.name) - } - storage.save(localStorageName) - }) - store.getAll = withIEStorage(function(storage) { - var attributes = storage.XMLDocument.documentElement.attributes - var ret = {} - for (var i=0, attr; attr=attributes[i]; ++i) { - var key = ieKeyFix(attr.name) - ret[attr.name] = store.deserialize(storage.getAttribute(key)) - } - return ret - }) - } +/** + * Get the basic json object of this facade. + * + * @return {Object} + */ - try { - store.set(namespace, namespace) - if (store.get(namespace) != namespace) { store.disabled = true } - store.remove(namespace) - } catch(e) { - store.disabled = true - } - store.enabled = !store.disabled - if (typeof module != 'undefined' && module.exports) { module.exports = store } - else if (typeof define === 'function' && define.amd) { define(store) } - else { win.store = store } -})(this.window || global); +Facade.prototype.json = function () { + return clone(this.obj); +}; -}); -require.register("segmentio-top-domain/index.js", function(exports, require, module){ +/** + * Get the options of a call (formerly called "context"). If you pass an + * integration name, it will get the options for that specific integration, or + * undefined if the integration is not enabled. + * + * @param {String} integration (optional) + * @return {Object or Null} + */ -var url = require('url'); +Facade.prototype.options = function (integration) { + var options = clone(this.obj.options || this.obj.context) || {}; + if (!integration) return clone(options); + if (!this.enabled(integration)) return; -// Official Grammar: http://tools.ietf.org/html/rfc883#page-56 -// Look for tlds with up to 2-6 characters. + options = options[integration] || {}; + return typeof options === 'boolean' ? {} : clone(options); +}; -module.exports = function (urlStr) { +/** + * Check whether an integration is enabled. + * + * @param {String} integration + * @return {Boolean} + */ - var host = url.parse(urlStr).hostname - , topLevel = host.match(/[a-z0-9][a-z0-9\-]*[a-z0-9]\.[a-z\.]{2,6}$/i); +Facade.prototype.enabled = function (integration) { + var allEnabled = this.proxy('options.providers.all'); + if (typeof allEnabled !== 'boolean') allEnabled = this.proxy('options.all'); + if (typeof allEnabled !== 'boolean') allEnabled = true; - return topLevel ? topLevel[0] : host; + var enabled = allEnabled && isEnabled(integration); + var options = this.options(); + + // If the integration is explicitly enabled or disabled, use that + // First, check options.providers for backwards compatibility + if (options.providers && options.providers.hasOwnProperty(integration)) { + enabled = options.providers[integration]; + } + + // Next, check for the integration's existence in 'options' to enable it. + // If the settings are a boolean, use that, otherwise it should be enabled. + if (options.hasOwnProperty(integration)) { + var settings = options[integration]; + if (typeof settings === 'boolean') { + enabled = settings; + } else { + enabled = true; + } + } + + return enabled ? true : false; }; -}); -require.register("yields-prevent/index.js", function(exports, require, module){ /** - * prevent default on the given `e`. - * - * examples: - * - * anchor.onclick = prevent; - * anchor.onclick = function(e){ - * if (something) return prevent(e); - * }; - * - * @param {Event} e + * Get the `userAgent` option. + * + * @return {String} */ -module.exports = function(e){ - e = e || window.event - return e.preventDefault - ? e.preventDefault() - : e.returnValue = false; +Facade.prototype.userAgent = function () {}; + +/** + * Check whether the user is active. + * + * @return {Boolean} + */ + +Facade.prototype.active = function () { + var active = this.proxy('options.active'); + if (active === null || active === undefined) active = true; + return active; }; -}); -require.register("visionmedia-debug/index.js", function(exports, require, module){ -if ('undefined' == typeof window) { - module.exports = require('./lib/debug'); -} else { - module.exports = require('./debug'); -} +/** + * Setup some basic proxies. + */ + +Facade.prototype.channel = Facade.field('channel'); +Facade.prototype.timestamp = Facade.field('timestamp'); +Facade.prototype.ip = Facade.proxy('options.ip'); }); -require.register("visionmedia-debug/debug.js", function(exports, require, module){ +require.register("segmentio-facade/lib/group.js", function(exports, require, module){ + +var Facade = require('./facade'); +var component = require('require-component')(require); +var inherit = component('inherit'); +var newDate = component('new-date'); /** - * Expose `debug()` as the module. + * Expose `Group` facade. */ -module.exports = debug; +module.exports = Group; /** - * Create a debugger with the given `name`. + * Initialize a new `Group` facade with a `dictionary` of arguments. * - * @param {String} name - * @return {Type} - * @api public + * @param {Object} dictionary + * @param {String} userId + * @param {String} groupId + * @param {Object} properties + * @param {Object} options */ -function debug(name) { - if (!debug.enabled(name)) return function(){}; +function Group (dictionary) { + Facade.call(this, dictionary); +} - return function(fmt){ - fmt = coerce(fmt); +/** + * Inherit from `Facade` + */ - var curr = new Date; - var ms = curr - (debug[name] || curr); - debug[name] = curr; +inherit(Group, Facade); - fmt = name - + ' ' - + fmt - + ' +' + debug.humanize(ms); +/** + * Get the facade's action. + */ - // 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); - } -} +Group.prototype.action = function () { + return 'group'; +}; /** - * The currently active debug mode names. + * Setup some basic proxies. */ -debug.names = []; -debug.skips = []; +Group.prototype.groupId = Facade.field('groupId'); +Group.prototype.userId = Facade.field('userId'); /** - * Enables a debug mode by name. This can include modes - * separated by a colon and wildcards. + * Get created or createdAt. * - * @param {String} name - * @api public + * @return {Date} */ -debug.enable = function(name) { - try { - localStorage.debug = name; - } catch(e){} +Group.prototype.created = function(){ + var created = this.proxy('traits.createdAt') + || this.proxy('traits.created') + || this.proxy('properties.createdAt') + || this.proxy('properties.created'); - var split = (name || '').split(/[\s,]+/) - , len = split.length; + if (created) return newDate(created); +}; - 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 + '$')); - } +/** + * Get the group's traits. + * + * @param {Object} aliases + * @return {Object} + */ + +Group.prototype.traits = function (aliases) { + var ret = this.properties(); + var id = this.groupId(); + aliases = aliases || {}; + + if (id) ret.id = id; + + for (var alias in aliases) { + var value = null == this[alias] + ? this.proxy('traits.' + alias) + : this[alias](); + if (null == value) continue; + ret[aliases[alias]] = value; + delete ret[alias]; } + + return ret; }; /** - * Disable debug output. - * - * @api public + * Get traits or properties. + * + * TODO: remove me + * + * @return {Object} + */ + +Group.prototype.properties = function(){ + return this.field('traits') + || this.field('properties') + || {}; +}; + +}); +require.register("segmentio-facade/lib/page.js", function(exports, require, module){ + +var component = require('require-component')(require); +var Facade = component('./facade'); +var inherit = component('inherit'); +var Track = require('./track'); + +/** + * Expose `Page` facade + */ + +module.exports = Page; + +/** + * Initialize new `Page` facade with `dictionary`. + * + * @param {Object} dictionary + * @param {String} category + * @param {String} name + * @param {Object} traits + * @param {Object} options + */ + +function Page(dictionary){ + Facade.call(this, dictionary); +} + +/** + * Inherit from `Facade` */ -debug.disable = function(){ - debug.enable(''); -}; +inherit(Page, Facade); /** - * Humanize the given `ms`. + * Get the facade's action. * - * @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'; +Page.prototype.action = function(){ + return 'page'; }; /** - * Returns true if the given mode name is enabled, false otherwise. + * Proxies + */ + +Page.prototype.category = Facade.field('category'); +Page.prototype.name = Facade.field('name'); + +/** + * Get the page properties mixing `category` and `name`. * - * @param {String} name - * @return {Boolean} - * @api public + * @return {Object} */ -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; +Page.prototype.properties = function(){ + var props = this.field('properties') || {}; + var category = this.category(); + var name = this.name(); + if (category) props.category = category; + if (name) props.name = name; + return props; }; /** - * Coerce `val`. + * Get the page fullName. + * + * @return {String} */ -function coerce(val) { - if (val instanceof Error) return val.stack || val.message; - return val; -} +Page.prototype.fullName = function(){ + var category = this.category(); + var name = this.name(); + return name && category + ? category + ' ' + name + : name; +}; -// persist +/** + * Get event with `name`. + * + * @return {String} + */ -try { - if (window.localStorage) debug.enable(localStorage.debug); -} catch(e){} +Page.prototype.event = function(name){ + return name + ? 'Viewed ' + name + ' Page' + : 'Loaded a Page'; +}; -}); -require.register("CamShaft-require-component/index.js", function(exports, require, module){ /** - * Require a module with a fallback + * Convert this Page to a Track facade with `name`. + * + * @param {String} name + * @return {Track} */ -module.exports = function(parent) { - function require(name, fallback) { - try { - return parent(name); - } - catch (e) { - try { - return parent(fallback || name+"-component"); - } - catch(e2) { - throw e; - } - } - }; - - // Merge the old properties - for (var key in parent) { - require[key] = parent[key]; - } - return require; +Page.prototype.track = function(name){ + var props = this.properties(); + return new Track({ + event: this.event(name), + properties: props + }); }; }); -require.register("component-user-agent-parser/src/ua-parser.js", function(exports, require, module){ -// UAParser.js v0.6.0 -// Lightweight JavaScript-based User-Agent string parser -// https://github.com/faisalman/ua-parser-js -// -// Copyright © 2012-2013 Faisalman -// Dual licensed under GPLv2 & MIT - -(function (window, undefined) { - - 'use strict'; - - ////////////// - // Constants - ///////////// - - - var EMPTY = '', - UNKNOWN = '?', - FUNC_TYPE = 'function', - UNDEF_TYPE = 'undefined', - OBJ_TYPE = 'object', - MAJOR = 'major', - MODEL = 'model', - NAME = 'name', - TYPE = 'type', - VENDOR = 'vendor', - VERSION = 'version', - ARCHITECTURE= 'architecture', - CONSOLE = 'console', - MOBILE = 'mobile', - TABLET = 'tablet'; - - - /////////// - // Helper - ////////// - - - var util = { - has : function (str1, str2) { - return str2.toLowerCase().indexOf(str1.toLowerCase()) !== -1; - }, - lowerize : function (str) { - return str.toLowerCase(); - } - }; - - - /////////////// - // Map helper - ////////////// - - - var mapper = { +require.register("segmentio-facade/lib/identify.js", function(exports, require, module){ - rgx : function () { +var component = require('require-component')(require); +var clone = component('clone'); +var Facade = component('./facade'); +var inherit = component('inherit'); +var isEmail = component('is-email'); +var newDate = component('new-date'); +var trim = component('trim'); - // loop through all regexes maps - for (var result, i = 0, j, k, p, q, matches, match, args = arguments; i < args.length; i += 2) { +/** + * Expose `Idenfity` facade. + */ - var regex = args[i], // even sequence (0,2,4,..) - props = args[i + 1]; // odd sequence (1,3,5,..) +module.exports = Identify; - // construct object barebones - if (typeof(result) === UNDEF_TYPE) { - result = {}; - for (p in props) { - q = props[p]; - if (typeof(q) === OBJ_TYPE) { - result[q[0]] = undefined; - } else { - result[q] = undefined; - } - } - } +/** + * Initialize a new `Identify` facade with a `dictionary` of arguments. + * + * @param {Object} dictionary + * @param {String} userId + * @param {String} sessionId + * @param {Object} traits + * @param {Object} options + */ - // try matching uastring with regexes - for (j = k = 0; j < regex.length; j++) { - matches = regex[j].exec(this.getUA()); - if (!!matches) { - for (p in props) { - match = matches[++k]; - q = props[p]; - // check if given property is actually array - if (typeof(q) === OBJ_TYPE && q.length > 0) { - if (q.length == 2) { - if (typeof(q[1]) == FUNC_TYPE) { - // assign modified match - result[q[0]] = q[1].call(this, match); - } else { - // assign given value, ignore regex match - result[q[0]] = q[1]; - } - } else if (q.length == 3) { - // check whether function or regex - if (typeof(q[1]) === FUNC_TYPE && !(q[1].exec && q[1].test)) { - // call function (usually string mapper) - result[q[0]] = match ? q[1].call(this, match, q[2]) : undefined; - } else { - // sanitize match using given regex - result[q[0]] = match ? match.replace(q[1], q[2]) : undefined; - } - } else if (q.length == 4) { - result[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined; - } - } else { - result[q] = match ? match : undefined; - } - } - break; - } - } +function Identify (dictionary) { + Facade.call(this, dictionary); +} - if(!!matches) break; // break the loop immediately if match found - } - return result; - }, +/** + * Inherit from `Facade`. + */ - str : function (str, map) { +inherit(Identify, Facade); - for (var i in map) { - // check if array - if (typeof(map[i]) === OBJ_TYPE && map[i].length > 0) { - for (var j in map[i]) { - if (util.has(map[i][j], str)) { - return (i === UNKNOWN) ? undefined : i; - } - } - } else if (util.has(map[i], str)) { - return (i === UNKNOWN) ? undefined : i; - } - } - return str; - } - }; +/** + * Get the facade's action. + */ +Identify.prototype.action = function () { + return 'identify'; +}; - /////////////// - // String map - ////////////// +/** + * Setup some basic proxies. + */ +Identify.prototype.userId = Facade.field('userId'); +Identify.prototype.sessionId = Facade.field('sessionId'); - var maps = { +/** + * Get the user's traits. + * + * @param {Object} aliases + * @return {Object} + */ - browser : { - oldsafari : { - major : { - '1' : ['/8', '/1', '/3'], - '2' : '/4', - '?' : '/' - }, - version : { - '1.0' : '/8', - '1.2' : '/1', - '1.3' : '/3', - '2.0' : '/412', - '2.0.2' : '/416', - '2.0.3' : '/417', - '2.0.4' : '/419', - '?' : '/' - } - } - }, +Identify.prototype.traits = function (aliases) { + var ret = this.field('traits') || {}; + var id = this.userId(); + aliases = aliases || {}; - device : { - sprint : { - model : { - 'Evo Shift 4G' : '7373KT' - }, - vendor : { - 'HTC' : 'APA', - 'Sprint' : 'Sprint' - } - } - }, + if (id) ret.id = id; - os : { - windows : { - version : { - 'ME' : '4.90', - 'NT 3.11' : 'NT3.51', - 'NT 4.0' : 'NT4.0', - '2000' : 'NT 5.0', - 'XP' : ['NT 5.1', 'NT 5.2'], - 'Vista' : 'NT 6.0', - '7' : 'NT 6.1', - '8' : 'NT 6.2', - 'RT' : 'ARM' - } - } - } - }; + for (var alias in aliases) { + var value = null == this[alias] + ? this.proxy('traits.' + alias) + : this[alias](); + if (null == value) continue; + ret[aliases[alias]] = value; + delete ret[alias]; + } + return ret; +}; - ////////////// - // Regex map - ///////////// +/** + * Get the user's email, falling back to their user ID if it's a valid email. + * + * @return {String} + */ +Identify.prototype.email = function () { + var email = this.proxy('traits.email'); + if (email) return email; - var regexes = { + var userId = this.userId(); + if (isEmail(userId)) return userId; +}; - browser : [[ +/** + * Get the user's created date, optionally looking for `createdAt` since lots of + * people do that instead. + * + * @return {Date or Undefined} + */ - // Presto based - /(opera\smini)\/((\d+)?[\w\.-]+)/i, // Opera Mini - /(opera\s[mobiletab]+).+version\/((\d+)?[\w\.-]+)/i, // Opera Mobi/Tablet - /(opera).+version\/((\d+)?[\w\.]+)/i, // Opera > 9.80 - /(opera)[\/\s]+((\d+)?[\w\.]+)/i // Opera < 9.80 +Identify.prototype.created = function () { + var created = this.proxy('traits.created') || this.proxy('traits.createdAt'); + if (created) return newDate(created); +}; - ], [NAME, VERSION, MAJOR], [ +/** + * Get the company created date. + * + * @return {Date or undefined} + */ - /\s(opr)\/((\d+)?[\w\.]+)/i // Opera Webkit - ], [[NAME, 'Opera'], VERSION, MAJOR], [ +Identify.prototype.companyCreated = function(){ + var created = this.proxy('traits.company.created') + || this.proxy('traits.company.createdAt'); - // Mixed - /(kindle)\/((\d+)?[\w\.]+)/i, // Kindle - /(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?((\d+)?[\w\.]+)*/i, - // Lunascape/Maxthon/Netfront/Jasmine/Blazer + if (created) return newDate(created); +}; - // Trident based - /(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?((\d+)?[\w\.]*)/i, - // Avant/IEMobile/SlimBrowser/Baidu - /(?:ms|\()(ie)\s((\d+)?[\w\.]+)/i, // Internet Explorer +/** + * Get the user's name, optionally combining a first and last name if that's all + * that was provided. + * + * @return {String or Undefined} + */ - // Webkit/KHTML based - /(rekonq)((?:\/)[\w\.]+)*/i, // Rekonq - /(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt)\/((\d+)?[\w\.-]+)/i - // Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt - ], [NAME, VERSION, MAJOR], [ +Identify.prototype.name = function () { + var name = this.proxy('traits.name'); + if (name) return trim(name); - /(yabrowser)\/((\d+)?[\w\.]+)/i // Yandex - ], [[NAME, 'Yandex'], VERSION, MAJOR], [ + var firstName = this.firstName(); + var lastName = this.lastName(); + if (firstName && lastName) return trim(firstName + ' ' + lastName); +}; - /(comodo_dragon)\/((\d+)?[\w\.]+)/i // Comodo Dragon - ], [[NAME, /_/g, ' '], VERSION, MAJOR], [ +/** + * Get the user's first name, optionally splitting it out of a single name if + * that's all that was provided. + * + * @return {String or Undefined} + */ - /(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?((\d+)?[\w\.]+)/i - // Chrome/OmniWeb/Arora/Tizen/Nokia - ], [NAME, VERSION, MAJOR], [ +Identify.prototype.firstName = function () { + var firstName = this.proxy('traits.firstName'); + if (firstName) return trim(firstName); - /(dolfin)\/((\d+)?[\w\.]+)/i // Dolphin - ], [[NAME, 'Dolphin'], VERSION, MAJOR], [ + var name = this.proxy('traits.name'); + if (name) return trim(name).split(' ')[0]; +}; - /((?:android.+)crmo|crios)\/((\d+)?[\w\.]+)/i // Chrome for Android/iOS - ], [[NAME, 'Chrome'], VERSION, MAJOR], [ +/** + * Get the user's last name, optionally splitting it out of a single name if + * that's all that was provided. + * + * @return {String or Undefined} + */ - /version\/((\d+)?[\w\.]+).+?mobile\/\w+\s(safari)/i // Mobile Safari - ], [VERSION, MAJOR, [NAME, 'Mobile Safari']], [ +Identify.prototype.lastName = function () { + var lastName = this.proxy('traits.lastName'); + if (lastName) return trim(lastName); - /version\/((\d+)?[\w\.]+).+?(mobile\s?safari|safari)/i // Safari & Safari Mobile - ], [VERSION, MAJOR, NAME], [ + var name = this.proxy('traits.name'); + if (!name) return; - /webkit.+?(mobile\s?safari|safari)((\/[\w\.]+))/i // Safari < 3.0 - ], [NAME, [MAJOR, mapper.str, maps.browser.oldsafari.major], [VERSION, mapper.str, maps.browser.oldsafari.version]], [ + var space = trim(name).indexOf(' '); + if (space === -1) return; - /(konqueror)\/((\d+)?[\w\.]+)/i, // Konqueror - /(webkit|khtml)\/((\d+)?[\w\.]+)/i - ], [NAME, VERSION, MAJOR], [ + return trim(name.substr(space + 1)); +}; - // Gecko based - /(navigator|netscape)\/((\d+)?[\w\.-]+)/i // Netscape - ], [[NAME, 'Netscape'], VERSION, MAJOR], [ - /(swiftfox)/i, // Swiftfox - /(iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?((\d+)?[\w\.\+]+)/i, - // Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror - /(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/((\d+)?[\w\.-]+)/i, - // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix - /(mozilla)\/((\d+)?[\w\.]+).+rv\:.+gecko\/\d+/i, // Mozilla +/** + * Get the user's unique id. + * + * @return {String or undefined} + */ - // Other - /(uc\s?browser|polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf)[\/\s]?((\d+)?[\w\.]+)/i, - // UCBrowser/Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf - /(links)\s\(((\d+)?[\w\.]+)/i, // Links - /(gobrowser)\/?((\d+)?[\w\.]+)*/i, // GoBrowser - /(ice\s?browser)\/v?((\d+)?[\w\._]+)/i, // ICE Browser - /(mosaic)[\/\s]((\d+)?[\w\.]+)/i // Mosaic - ], [NAME, VERSION, MAJOR] - ], +Identify.prototype.uid = function(){ + return this.userId() + || this.username() + || this.email(); +}; - cpu : [[ +/** + * Get description. + * + * @return {String} + */ - /(?:(amd|x(?:(?:86|64)[_-])?|wow|win)64)[;\)]/i // AMD64 - ], [[ARCHITECTURE, 'amd64']], [ +Identify.prototype.description = function(){ + return this.proxy('traits.description') + || this.proxy('traits.background'); +}; - /((?:i[346]|x)86)[;\)]/i // IA32 - ], [[ARCHITECTURE, 'ia32']], [ +/** + * Setup sme basic "special" trait proxies. + */ - /((?:ppc|powerpc)(?:64)?)(?:\smac|;|\))/i // PowerPC - ], [[ARCHITECTURE, /ower/, '', util.lowerize]], [ +Identify.prototype.username = Facade.proxy('traits.username'); +Identify.prototype.website = Facade.proxy('traits.website'); +Identify.prototype.phone = Facade.proxy('traits.phone'); +Identify.prototype.address = Facade.proxy('traits.address'); +Identify.prototype.avatar = Facade.proxy('traits.avatar'); - /(sun4\w)[;\)]/i // SPARC - ], [[ARCHITECTURE, 'sparc']], [ +}); +require.register("segmentio-facade/lib/is-enabled.js", function(exports, require, module){ - /(ia64(?=;)|68k(?=\))|arm(?=v\d+;)|(?:irix|mips|sparc)(?:64)?(?=;)|pa-risc)/i - // IA64, 68K, ARM, IRIX, MIPS, SPARC, PA-RISC - ], [ARCHITECTURE, util.lowerize] - ], +/** + * A few integrations are disabled by default. They must be explicitly + * enabled by setting options[Provider] = true. + */ - device : [[ +var disabled = { + Salesforce: true, + Marketo: true +}; - /\((ipad|playbook);[\w\s\);-]+(rim|apple)/i // iPad/PlayBook - ], [MODEL, VENDOR, [TYPE, TABLET]], [ +/** + * Check whether an integration should be enabled by default. + * + * @param {String} integration + * @return {Boolean} + */ - /(hp).+(touchpad)/i, // HP TouchPad - /(kindle)\/([\w\.]+)/i, // Kindle - /\s(nook)[\w\s]+build\/(\w+)/i, // Nook - /(dell)\s(strea[kpr\s\d]*[\dko])/i // Dell Streak - ], [VENDOR, MODEL, [TYPE, TABLET]], [ +module.exports = function (integration) { + return ! disabled[integration]; +}; +}); +require.register("segmentio-facade/lib/track.js", function(exports, require, module){ - /\((ip[honed]+);.+(apple)/i // iPod/iPhone - ], [MODEL, VENDOR, [TYPE, MOBILE]], [ +var component = require('require-component')(require); +var clone = component('clone'); +var Facade = component('./facade'); +var Identify = component('./identify'); +var inherit = component('inherit'); +var isEmail = component('is-email'); +var traverse = component('isodate-traverse'); - /(blackberry)[\s-]?(\w+)/i, // BlackBerry - /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|huawei|meizu|motorola)[\s_-]?([\w-]+)*/i, - // BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Huawei/Meizu/Motorola - /(hp)\s([\w\s]+\w)/i, // HP iPAQ - /(asus)-?(\w+)/i // Asus - ], [VENDOR, MODEL, [TYPE, MOBILE]], [ - /\((bb10);\s(\w+)/i // BlackBerry 10 - ], [[VENDOR, 'BlackBerry'], MODEL, [TYPE, MOBILE]], [ +/** + * Expose `Track` facade. + */ - /android.+((transfo[prime\s]{4,10}\s\w+|eeepc|slider\s\w+))/i // Asus Tablets - ], [[VENDOR, 'Asus'], MODEL, [TYPE, TABLET]], [ +module.exports = Track; - /(sony)\s(tablet\s[ps])/i // Sony Tablets - ], [VENDOR, MODEL, [TYPE, TABLET]], [ +/** + * Initialize a new `Track` facade with a `dictionary` of arguments. + * + * @param {object} dictionary + * @property {String} event + * @property {String} userId + * @property {String} sessionId + * @property {Object} properties + * @property {Object} options + */ - /(nintendo)\s([wids3u]+)/i // Nintendo - ], [VENDOR, MODEL, [TYPE, CONSOLE]], [ +function Track (dictionary) { + Facade.call(this, dictionary); +} - /((playstation)\s[3portablevi]+)/i // Playstation - ], [[VENDOR, 'Sony'], MODEL, [TYPE, CONSOLE]], [ +/** + * Inherit from `Facade`. + */ - /(sprint\s(\w+))/i // Sprint Phones - ], [[VENDOR, mapper.str, maps.device.sprint.vendor], [MODEL, mapper.str, maps.device.sprint.model], [TYPE, MOBILE]], [ +inherit(Track, Facade); - /(htc)[;_\s-]+([\w\s]+(?=\))|\w+)*/i, // HTC - /(zte)-(\w+)*/i, // ZTE - /(alcatel|geeksphone|huawei|lenovo|nexian|panasonic|(?=;\s)sony)[_\s-]?([\w-]+)*/i - // Alcatel/GeeksPhone/Huawei/Lenovo/Nexian/Panasonic/Sony - ], [VENDOR, [MODEL, /_/g, ' '], [TYPE, MOBILE]], [ +/** + * Return the facade's action. + * + * @return {String} + */ - /\s((milestone|droid[2x]?))[globa\s]*\sbuild\//i, // Motorola - /(mot)[\s-]?(\w+)*/i - ], [[VENDOR, 'Motorola'], MODEL, [TYPE, MOBILE]], [ - /android.+\s((mz60\d|xoom[\s2]{0,2}))\sbuild\//i - ], [[VENDOR, 'Motorola'], MODEL, [TYPE, TABLET]], [ +Track.prototype.action = function () { + return 'track'; +}; - /android.+((sch-i[89]0\d|shw-m380s|gt-p\d{4}|gt-n8000|sgh-t8[56]9))/i - ], [[VENDOR, 'Samsung'], MODEL, [TYPE, TABLET]], [ // Samsung - /((s[cgp]h-\w+|gt-\w+|galaxy\snexus))/i, - /(sam[sung]*)[\s-]*(\w+-?[\w-]*)*/i, - /sec-((sgh\w+))/i - ], [[VENDOR, 'Samsung'], MODEL, [TYPE, MOBILE]], [ - /(sie)-(\w+)*/i // Siemens - ], [[VENDOR, 'Siemens'], MODEL, [TYPE, MOBILE]], [ +/** + * Setup some basic proxies. + */ - /(maemo|nokia).*(n900|lumia\s\d+)/i, // Nokia - /(nokia)[\s_-]?([\w-]+)*/i - ], [[VENDOR, 'Nokia'], MODEL, [TYPE, MOBILE]], [ +Track.prototype.userId = Facade.field('userId'); +Track.prototype.sessionId = Facade.field('sessionId'); +Track.prototype.event = Facade.field('event'); +Track.prototype.value = Facade.proxy('properties.value'); - /android\s3\.[\s\w-;]{10}((a\d{3}))/i // Acer - ], [[VENDOR, 'Acer'], MODEL, [TYPE, TABLET]], [ +/** + * BACKWARDS COMPATIBILITY: should probably re-examine where these come from. + */ - /android\s3\.[\s\w-;]{10}(lg?)-([06cv9]{3,4})/i // LG - ], [[VENDOR, 'LG'], MODEL, [TYPE, TABLET]], [ - /((nexus\s4))/i, - /(lg)[e;\s-\/]+(\w+)*/i - ], [[VENDOR, 'LG'], MODEL, [TYPE, MOBILE]], [ +Track.prototype.referrer = Facade.proxy('properties.referrer'); +Track.prototype.query = Facade.proxy('options.query'); - /(mobile|tablet);.+rv\:.+gecko\//i // Unidentifiable - ], [TYPE, VENDOR, MODEL] - ], +/** + * Get the call's properties. + * + * @param {Object} aliases + * @return {Object} + */ - engine : [[ +Track.prototype.properties = function (aliases) { + var ret = this.field('properties') || {}; + aliases = aliases || {}; - /(presto)\/([\w\.]+)/i, // Presto - /(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m - /(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i, // KHTML/Tasman/Links - /(icab)[\/\s]([23]\.[\d\.]+)/i // iCab - ], [NAME, VERSION], [ + for (var alias in aliases) { + var value = null == this[alias] + ? this.proxy('properties.' + alias) + : this[alias](); + if (null == value) continue; + ret[aliases[alias]] = value; + delete ret[alias]; + } - /rv\:([\w\.]+).*(gecko)/i // Gecko - ], [VERSION, NAME] - ], + return clone(traverse(ret)); +}; - os : [[ +/** + * Get the call's "super properties" which are just traits that have been + * passed in as if from an identify call. + * + * @return {Object} + */ - // Windows based - /(windows)\snt\s6\.2;\s(arm)/i, // Windows RT - /(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i - ], [NAME, [VERSION, mapper.str, maps.os.windows.version]], [ - /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i - ], [[NAME, 'Windows'], [VERSION, mapper.str, maps.os.windows.version]], [ +Track.prototype.traits = function () { + return this.proxy('options.traits') || {}; +}; - // Mobile/Embedded OS - /\((bb)(10);/i // BlackBerry 10 - ], [[NAME, 'BlackBerry'], VERSION], [ - /(blackberry)\w*\/?([\w\.]+)*/i, // Blackberry - /(tizen)\/([\w\.]+)/i, // Tizen - /(android|webos|palm\os|qnx|bada|rim\stablet\sos|meego)[\/\s-]?([\w\.]+)*/i - // Android/WebOS/Palm/QNX/Bada/RIM/MeeGo - ], [NAME, VERSION], [ - /(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i // Symbian - ], [[NAME, 'Symbian'], VERSION],[ - /mozilla.+\(mobile;.+gecko.+firefox/i // Firefox OS - ], [[NAME, 'Firefox OS'], VERSION], [ +/** + * Get the call's username. + * + * @return {String or Undefined} + */ - // Console - /(nintendo|playstation)\s([wids3portablevu]+)/i, // Nintendo/Playstation +Track.prototype.username = function () { + return this.proxy('traits.username') || + this.proxy('properties.username') || + this.userId() || + this.sessionId(); +}; - // GNU/Linux based - /(mint)[\/\s\(]?(\w+)*/i, // Mint - /(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk)[\/\s-]?([\w\.-]+)*/i, - // Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware - // Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk - /(hurd|linux)\s?([\w\.]+)*/i, // Hurd/Linux - /(gnu)\s?([\w\.]+)*/i // GNU - ], [NAME, VERSION], [ +/** + * Get the call's email, using an the user ID if it's a valid email. + * + * @return {String or Undefined} + */ - /(cros)\s[\w]+\s([\w\.]+\w)/i // Chromium OS - ], [[NAME, 'Chromium OS'], VERSION],[ +Track.prototype.email = function () { + var email = this.proxy('traits.email'); + if (email) return email; - // Solaris - /(sunos)\s?([\w\.]+\d)*/i // Solaris - ], [[NAME, 'Solaris'], VERSION], [ + var userId = this.userId(); + if (isEmail(userId)) return userId; +}; - // BSD based - /\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i // FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly - ], [NAME, VERSION],[ +/** + * Get the call's revenue, parsing it from a string with an optional leading + * dollar sign. + * + * @return {String or Undefined} + */ - /(ip[honead]+)(?:.*os\s*([\w]+)*\slike\smac|;\sopera)/i // iOS - ], [[NAME, 'iOS'], [VERSION, /_/g, '.']], [ +Track.prototype.revenue = function () { + var revenue = this.proxy('properties.revenue'); - /(mac\sos\sx)\s?([\w\s\.]+\w)*/i // Mac OS - ], [NAME, [VERSION, /_/g, '.']], [ + if (!revenue) return; + if (typeof revenue === 'number') return revenue; + if (typeof revenue !== 'string') return; - // Other - /(haiku)\s(\w+)/i, // Haiku - /(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i, // AIX - /(macintosh|mac(?=_powerpc)|plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos)/i, - // Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS - /(unix)\s?([\w\.]+)*/i // UNIX - ], [NAME, VERSION] - ] - }; + revenue = revenue.replace(/\$/g, ''); + revenue = parseFloat(revenue); - var UAParser = function UAParser (uastring) { - if (!(this instanceof UAParser)) return new UAParser(uastring).getResult(); + if (!isNaN(revenue)) return revenue; +}; - var ua = uastring || ((window && window.navigator && window.navigator.userAgent) ? window.navigator.userAgent : EMPTY); +/** + * Get cents. + * + * @return {Number} + */ - if (!(this instanceof UAParser)) { - return new UAParser(uastring).getResult(); - } - this.getBrowser = function () { - return mapper.rgx.apply(this, regexes.browser); - }; - this.getCPU = function () { - return mapper.rgx.apply(this, regexes.cpu); - }; - this.getDevice = function () { - return mapper.rgx.apply(this, regexes.device); - }; - this.getEngine = function () { - return mapper.rgx.apply(this, regexes.engine); - }; - this.getOS = function () { - return mapper.rgx.apply(this, regexes.os); - }; - this.getResult = function() { - return { - browser : this.getBrowser(), - engine : this.getEngine(), - os : this.getOS(), - device : this.getDevice(), - cpu : this.getCPU() - }; - }; - this.getUA = function () { - return ua; - }; - this.setUA = function (uastring) { - ua = uastring; - return this; - }; - this.setUA(ua); - }; +Track.prototype.cents = function(){ + var revenue = this.revenue(); + return 'number' != typeof revenue + ? this.value() || 0 + : revenue * 100; +}; - module.exports = UAParser; -})(this); +/** + * A utility to turn the pieces of a track call into an identify. Used for + * integrations with super properties or rate limits. + * + * TODO: remove me. + * + * @return {Facade} + */ + +Track.prototype.identify = function () { + var json = this.json(); + json.traits = this.traits(); + return new Identify(json); +}; }); -require.register("yields-case/dist/Case.js", function(exports, require, module){ -/*! Case - v1.0.3 - 2013-08-23 -* Copyright (c) 2013 Nathan Bubna; Licensed MIT, GPL */ -(function() { - "use strict"; - var re = { - capitalize: /(^|\W|_)([a-z])/g, - squish: /(^|[\W_])+([a-zA-Z])/g, - fill: /[\W_]+(.|$)/g, - sentence: /(^\s*|[\?\!\.]+"?\s+"?|,\s+")([a-z])/g, - improper: /\b(A|An|And|As|At|But|By|En|For|If|In|Of|On|Or|The|To|Vs?\.?|Via)\b/g, - relax: /([^A-Z])([A-Z]*)([A-Z])(?=[a-z]|$)/g, - upper: /^[^a-z]+$/, - hole: /\s/, - room: /[\W_]/ - }, - _ = { - re: re, - types: [], - up: String.prototype.toUpperCase, - low: String.prototype.toLowerCase, - cap: function(s) { - return _.up.call(s.charAt(0))+s.slice(1); - }, - decap: function(s) { - return _.low.call(s.charAt(0))+s.slice(1); - }, - fill: function(s, fill) { - return !s || fill == null ? s : s.replace(re.fill, function(m, next) { - return next ? fill + next : ''; - }); - }, - prep: function(s, fill, squish, upper) { - if (!s){ return s || ''; } - if (!upper && re.upper.test(s)) { - s = _.low.call(s); - } - if (!fill && !re.hole.test(s)) { - s = _.fill(s, ' '); - } - if (!squish && !re.room.test(s)) { - s = s.replace(re.relax, _.relax); - } - return s; - }, - relax: function(m, before, acronym, caps) { - return before + ' ' + (acronym ? acronym+' ' : '') + caps; - } - }, - Case = { - _: _, - of: function(s) { - for (var i=0,m=_.types.length; i 1) { - key = keys.shift(); - obj = find(obj, key); + // month is 0-11 + arr[2]--; - if (obj === null || obj === undefined) return; - } + // allow abitrary sub-second precision + if (arr[8]) arr[8] = (arr[8] + '00').substring(0, 3); - key = keys.shift(); - return fn(obj, key, val); - }; -} + // apply timezone if one exists + if (arr[4] == ' ') { + offset = new Date().getTimezoneOffset(); + } else if (arr[9] !== 'Z' && arr[10]) { + offset = arr[11] * 60 + arr[12]; + if ('+' == arr[10]) offset = 0 - offset; + } + + var millis = Date.UTC(arr[1], arr[2], arr[3], arr[5], arr[6] + offset, arr[7], arr[8]); + return new Date(millis); +}; /** - * Find an object by its key + * Checks whether a `string` is an ISO date string. `strict` mode requires that + * the date string at least have a year, month and date. * - * find({ first_name : 'Calvin' }, 'firstName') + * @param {String} string + * @param {Boolean} strict + * @return {Boolean} */ -function find (obj, key) { - for (var i = 0; i < cases.length; i++) { - var cased = cases[i](key); - if (obj.hasOwnProperty(cased)) return obj[cased]; - } -} +exports.is = function (string, strict) { + if (strict && false === /^\d{4}-\d{2}-\d{2}/.test(string)) return false; + return matcher.test(string); +}; +}); +require.register("segmentio-isodate-traverse/index.js", function(exports, require, module){ + +var is = require('is'); +var isodate = require('isodate'); + +var clone; +var each; +try { + clone = require('clone'); + each = require('each'); +} catch (err) { + clone = require('clone-component'); + each = require('each-component'); +} /** - * Delete a value for a given key - * - * del({ a : 'b', x : 'y' }, 'X' }) -> { a : 'b' } + * Expose `traverse`. */ -function del (obj, key) { - for (var i = 0; i < cases.length; i++) { - var cased = cases[i](key); - if (obj.hasOwnProperty(cased)) delete obj[cased]; - } - return obj; -} +module.exports = traverse; /** - * Replace an objects existing value with a new one + * Traverse an object, parsing all ISO strings into dates and returning a clone. * - * replace({ a : 'b' }, 'a', 'c') -> { a : 'c' } + * @param {Object} obj + * @return {Object} */ -function replace (obj, key, val) { - for (var i = 0; i < cases.length; i++) { - var cased = cases[i](key); - if (obj.hasOwnProperty(cased)) obj[cased] = val; - } +function traverse (obj, strict) { + obj = clone(obj); + if (strict === undefined) strict = true; + each(obj, function (key, val) { + if (isodate.is(val, strict)) { + obj[key] = isodate.parse(val); + } else if (is.object(val)) { + obj[key] = traverse(val); + } + }); return obj; } }); -require.register("segmentio-facade/lib/index.js", function(exports, require, module){ - -var Facade = require('./facade'); +require.register("component-json-fallback/index.js", function(exports, require, module){ +/* + json2.js + 2011-10-19 -/** - * Expose `Facade` facade. - */ + Public Domain. -module.exports = Facade; + NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. -/** - * Expose specific-method facades. - */ + See http://www.JSON.org/js.html -Facade.Alias = require('./alias'); -Facade.Group = require('./group'); -Facade.Identify = require('./identify'); -Facade.Track = require('./track'); -Facade.Page = require('./page'); -}); -require.register("segmentio-facade/lib/alias.js", function(exports, require, module){ + This code should be minified before deployment. + See http://javascript.crockford.com/jsmin.html -var Facade = require('./facade'); -var component = require('require-component')(require); -var inherit = component('inherit'); + USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO + NOT CONTROL. -/** - * Expose `Alias` facade. - */ -module.exports = Alias; + This file creates a global JSON object containing two methods: stringify + and parse. -/** - * Initialize a new `Alias` facade with a `dictionary` of arguments. - * - * @param {Object} dictionary - * @property {String} from - * @property {String} to - * @property {Object} options - */ + JSON.stringify(value, replacer, space) + value any JavaScript value, usually an object or array. -function Alias (dictionary) { - Facade.call(this, dictionary); -} + replacer an optional parameter that determines how object + values are stringified for objects. It can be a + function or an array of strings. -/** - * Inherit from `Facade`. - */ + space an optional parameter that specifies the indentation + of nested structures. If it is omitted, the text will + be packed without extra whitespace. If it is a number, + it will specify the number of spaces to indent at each + level. If it is a string (such as '\t' or ' '), + it contains the characters used to indent at each level. -inherit(Alias, Facade); + This method produces a JSON text from a JavaScript value. -/** - * Return type of facade. - * - * @return {String} - */ + When an object value is found, if the object contains a toJSON + method, its toJSON method will be called and the result will be + stringified. A toJSON method does not serialize: it returns the + value represented by the name/value pair that should be serialized, + or undefined if nothing should be serialized. The toJSON method + will be passed the key associated with the value, and this will be + bound to the value -Alias.prototype.action = function () { - return 'alias'; -}; + For example, this would serialize Dates as ISO strings. -/** - * Setup some basic proxies. - */ + Date.prototype.toJSON = function (key) { + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } -Alias.prototype.from = Facade.field('from'); -Alias.prototype.to = Facade.field('to'); -}); -require.register("segmentio-facade/lib/facade.js", function(exports, require, module){ + return this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z'; + }; -var component = require('require-component')(require); -var clone = component('clone'); -var isEnabled = component('./is-enabled'); -var objCase = component('obj-case'); + You can provide an optional replacer method. It will be passed the + key and value of each member, with this bound to the containing + object. The value that is returned from your method will be + serialized. If your method returns undefined, then the member will + be excluded from the serialization. -/** - * Expose `Facade`. - */ + If the replacer parameter is an array of strings, then it will be + used to select the members to be serialized. It filters the results + such that only members with keys listed in the replacer array are + stringified. -module.exports = Facade; + Values that do not have JSON representations, such as undefined or + functions, will not be serialized. Such values in objects will be + dropped; in arrays they will be replaced with null. You can use + a replacer function to replace those with JSON values. + JSON.stringify(undefined) returns undefined. -/** - * Initialize a new `Facade` with an `obj` of arguments. - * - * @param {Object} obj - */ + The optional space parameter produces a stringification of the + value that is filled with line breaks and indentation to make it + easier to read. -function Facade (obj) { - if (!obj.hasOwnProperty('timestamp')) obj.timestamp = new Date(); - else obj.timestamp = new Date(obj.timestamp); - this.obj = obj; -} + If the space parameter is a non-empty string, then that string will + be used for indentation. If the space parameter is a number, then + the indentation will be that many spaces. -/** - * Return a proxy function for a `field` that will attempt to first use methods, - * and fallback to accessing the underlying object directly. You can specify - * deeply nested fields too like: - * - * this.proxy('options.Librato'); - * - * @param {String} field - */ + Example: -Facade.prototype.proxy = function (field) { - var fields = field.split('.'); - field = fields.shift(); + text = JSON.stringify(['e', {pluribus: 'unum'}]); + // text is '["e",{"pluribus":"unum"}]' - // Call a function at the beginning to take advantage of facaded fields - var obj = this[field] || this.field(field); - if (!obj) return obj; - if (typeof obj === 'function') obj = obj.call(this) || {}; - if (fields.length === 0) return clone(obj); - obj = objCase(obj, fields.join('.')); - return clone(obj); -}; + text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); + // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' -/** - * Directly access a specific `field` from the underlying object, returning a - * clone so outsiders don't mess with stuff. - * - * @param {String} field - * @return {Mixed} - */ + text = JSON.stringify([new Date()], function (key, value) { + return this[key] instanceof Date ? + 'Date(' + this[key] + ')' : value; + }); + // text is '["Date(---current time---)"]' -Facade.prototype.field = function (field) { - return clone(this.obj[field]); -}; -/** - * Utility method to always proxy a particular `field`. You can specify deeply - * nested fields too like: - * - * Facade.proxy('options.Librato'); - * - * @param {String} field - * @return {Function} - */ + JSON.parse(text, reviver) + This method parses a JSON text to produce an object or array. + It can throw a SyntaxError exception. -Facade.proxy = function (field) { - return function () { - return this.proxy(field); - }; -}; + The optional reviver parameter is a function that can filter and + transform the results. It receives each of the keys and values, + and its return value is used instead of the original value. + If it returns what it received, then the structure is not modified. + If it returns undefined then the member is deleted. -/** - * Utility method to directly access a `field`. - * - * @param {String} field - * @return {Function} - */ + Example: -Facade.field = function (field) { - return function () { - return this.field(field); - }; -}; + // Parse the text. Values that look like ISO date strings will + // be converted to Date objects. -/** - * Get the basic json object of this facade. - * - * @return {Object} - */ + myData = JSON.parse(text, function (key, value) { + var a; + if (typeof value === 'string') { + a = +/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); + if (a) { + return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], + +a[5], +a[6])); + } + } + return value; + }); -Facade.prototype.json = function () { - return clone(this.obj); -}; + myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { + var d; + if (typeof value === 'string' && + value.slice(0, 5) === 'Date(' && + value.slice(-1) === ')') { + d = new Date(value.slice(5, -1)); + if (d) { + return d; + } + } + return value; + }); -/** - * Get the options of a call (formerly called "context"). If you pass an - * integration name, it will get the options for that specific integration, or - * undefined if the integration is not enabled. - * - * @param {String} integration (optional) - * @return {Object or Null} - */ -Facade.prototype.options = function (integration) { - var options = clone(this.obj.options || this.obj.context) || {}; - if (!integration) return clone(options); - if (!this.enabled(integration)) return; + This is a reference implementation. You are free to copy, modify, or + redistribute. +*/ - options = options[integration] || {}; - return typeof options === 'boolean' ? {} : clone(options); -}; +/*jslint evil: true, regexp: true */ -/** - * Check whether an integration is enabled. - * - * @param {String} integration - * @return {Boolean} - */ +/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, + call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, + getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, + lastIndex, length, parse, prototype, push, replace, slice, stringify, + test, toJSON, toString, valueOf +*/ -Facade.prototype.enabled = function (integration) { - var allEnabled = this.proxy('options.providers.all'); - if (typeof allEnabled !== 'boolean') allEnabled = this.proxy('options.all'); - if (typeof allEnabled !== 'boolean') allEnabled = true; - var enabled = allEnabled && isEnabled(integration); - var options = this.options(); +// Create a JSON object only if one does not already exist. We create the +// methods in a closure to avoid creating global variables. - // If the integration is explicitly enabled or disabled, use that - // First, check options.providers for backwards compatibility - if (options.providers && options.providers.hasOwnProperty(integration)) { - enabled = options.providers[integration]; - } +var JSON = {}; - // Next, check for the integration's existence in 'options' to enable it. - // If the settings are a boolean, use that, otherwise it should be enabled. - if (options.hasOwnProperty(integration)) { - var settings = options[integration]; - if (typeof settings === 'boolean') { - enabled = settings; - } else { - enabled = true; +(function () { + 'use strict'; + + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; } - } - return enabled ? true : false; -}; + if (typeof Date.prototype.toJSON !== 'function') { -/** - * Get the `userAgent` option. - * - * @return {String} - */ + Date.prototype.toJSON = function (key) { -Facade.prototype.userAgent = function () {}; + return isFinite(this.valueOf()) + ? this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z' + : null; + }; -/** - * Check whether the user is active. - * - * @return {Boolean} - */ + String.prototype.toJSON = + Number.prototype.toJSON = + Boolean.prototype.toJSON = function (key) { + return this.valueOf(); + }; + } -Facade.prototype.active = function () { - var active = this.proxy('options.active'); - if (active === null || active === undefined) active = true; - return active; -}; + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + rep; -/** - * Setup some basic proxies. - */ -Facade.prototype.channel = Facade.field('channel'); -Facade.prototype.timestamp = Facade.field('timestamp'); -Facade.prototype.ip = Facade.proxy('options.ip'); + function quote(string) { -}); -require.register("segmentio-facade/lib/group.js", function(exports, require, module){ +// If the string contains no control characters, no quote characters, and no +// backslash characters, then we can safely slap some quotes around it. +// Otherwise we must also replace the offending characters with safe escape +// sequences. -var Facade = require('./facade'); -var component = require('require-component')(require); -var inherit = component('inherit'); -var newDate = component('new-date'); + escapable.lastIndex = 0; + return escapable.test(string) ? '"' + string.replace(escapable, function (a) { + var c = meta[a]; + return typeof c === 'string' + ? c + : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + '"' : '"' + string + '"'; + } -/** - * Expose `Group` facade. - */ -module.exports = Group; + function str(key, holder) { + +// Produce a string from holder[key]. + + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; -/** - * Initialize a new `Group` facade with a `dictionary` of arguments. - * - * @param {Object} dictionary - * @param {String} userId - * @param {String} groupId - * @param {Object} properties - * @param {Object} options - */ +// If the value has a toJSON method, call it to obtain a replacement value. -function Group (dictionary) { - Facade.call(this, dictionary); -} + if (value && typeof value === 'object' && + typeof value.toJSON === 'function') { + value = value.toJSON(key); + } -/** - * Inherit from `Facade` - */ +// If we were called with a replacer function, then call the replacer to +// obtain a replacement value. -inherit(Group, Facade); + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } -/** - * Get the facade's action. - */ +// What happens next depends on the value's type. -Group.prototype.action = function () { - return 'group'; -}; + switch (typeof value) { + case 'string': + return quote(value); -/** - * Setup some basic proxies. - */ + case 'number': -Group.prototype.groupId = Facade.field('groupId'); -Group.prototype.userId = Facade.field('userId'); +// JSON numbers must be finite. Encode non-finite numbers as null. -/** - * Get created or createdAt. - * - * @return {Date} - */ + return isFinite(value) ? String(value) : 'null'; -Group.prototype.created = function(){ - var created = this.proxy('traits.createdAt') - || this.proxy('traits.created') - || this.proxy('properties.createdAt') - || this.proxy('properties.created'); + case 'boolean': + case 'null': - if (created) return newDate(created); -}; +// If the value is a boolean or null, convert it to a string. Note: +// typeof null does not produce 'null'. The case is included here in +// the remote chance that this gets fixed someday. -/** - * Get the group's traits. - * - * @param {Object} aliases - * @return {Object} - */ + return String(value); -Group.prototype.traits = function (aliases) { - var ret = this.properties(); - var id = this.groupId(); - aliases = aliases || {}; +// If the type is 'object', we might be dealing with an object or an array or +// null. - if (id) ret.id = id; + case 'object': - for (var alias in aliases) { - var value = null == this[alias] - ? this.proxy('traits.' + alias) - : this[alias](); - if (null == value) continue; - ret[aliases[alias]] = value; - delete ret[alias]; - } +// Due to a specification blunder in ECMAScript, typeof null is 'object', +// so watch out for that case. - return ret; -}; + if (!value) { + return 'null'; + } -/** - * Get traits or properties. - * - * TODO: remove me - * - * @return {Object} - */ +// Make an array to hold the partial results of stringifying this object value. -Group.prototype.properties = function(){ - return this.field('traits') - || this.field('properties') - || {}; -}; + gap += indent; + partial = []; -}); -require.register("segmentio-facade/lib/page.js", function(exports, require, module){ +// Is the value an array? -var component = require('require-component')(require); -var Facade = component('./facade'); -var inherit = component('inherit'); -var Track = require('./track'); + if (Object.prototype.toString.apply(value) === '[object Array]') { -/** - * Expose `Page` facade - */ +// The value is an array. Stringify every element. Use null as a placeholder +// for non-JSON values. -module.exports = Page; + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } -/** - * Initialize new `Page` facade with `dictionary`. - * - * @param {Object} dictionary - * @param {String} category - * @param {String} name - * @param {Object} traits - * @param {Object} options - */ +// Join all of the elements together, separated with commas, and wrap them in +// brackets. -function Page(dictionary){ - Facade.call(this, dictionary); -} + v = partial.length === 0 + ? '[]' + : gap + ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' + : '[' + partial.join(',') + ']'; + gap = mind; + return v; + } -/** - * Inherit from `Facade` - */ +// If the replacer is an array, use it to select the members to be stringified. -inherit(Page, Facade); + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + if (typeof rep[i] === 'string') { + k = rep[i]; + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { -/** - * Get the facade's action. - * - * @return {String} - */ +// Otherwise, iterate through all of the keys in the object. -Page.prototype.action = function(){ - return 'page'; -}; + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } -/** - * Proxies - */ +// Join all of the member texts together, separated with commas, +// and wrap them in braces. -Page.prototype.category = Facade.field('category'); -Page.prototype.name = Facade.field('name'); + v = partial.length === 0 + ? '{}' + : gap + ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' + : '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } -/** - * Get the page properties mixing `category` and `name`. - * - * @return {Object} - */ +// If the JSON object does not yet have a stringify method, give it one. -Page.prototype.properties = function(){ - var props = this.field('properties') || {}; - var category = this.category(); - var name = this.name(); - if (category) props.category = category; - if (name) props.name = name; - return props; -}; + if (typeof JSON.stringify !== 'function') { + JSON.stringify = function (value, replacer, space) { -/** - * Get the page fullName. - * - * @return {String} - */ +// The stringify method takes a value and an optional replacer, and an optional +// space parameter, and returns a JSON text. The replacer can be a function +// that can replace values, or an array of strings that will select the keys. +// A default replacer method can be provided. Use of the space parameter can +// produce text that is more easily readable. -Page.prototype.fullName = function(){ - var category = this.category(); - var name = this.name(); - return name && category - ? category + ' ' + name - : name; -}; + var i; + gap = ''; + indent = ''; -/** - * Get event with `name`. - * - * @return {String} - */ +// If the space parameter is a number, make an indent string containing that +// many spaces. -Page.prototype.event = function(name){ - return name - ? 'Viewed ' + name + ' Page' - : 'Loaded a Page'; -}; + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } -/** - * Convert this Page to a Track facade with `name`. - * - * @param {String} name - * @return {Track} - */ +// If the space parameter is a string, it will be used as the indent string. -Page.prototype.track = function(name){ - var props = this.properties(); - return new Track({ - event: this.event(name), - properties: props - }); -}; + } else if (typeof space === 'string') { + indent = space; + } -}); -require.register("segmentio-facade/lib/identify.js", function(exports, require, module){ +// If there is a replacer, it must be a function or an array. +// Otherwise, throw an error. -var component = require('require-component')(require); -var clone = component('clone'); -var Facade = component('./facade'); -var inherit = component('inherit'); -var isEmail = component('is-email'); -var newDate = component('new-date'); -var trim = component('trim'); + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify'); + } -/** - * Expose `Idenfity` facade. - */ +// Make a fake root object containing our value under the key of ''. +// Return the result of stringifying the value. -module.exports = Identify; + return str('', {'': value}); + }; + } -/** - * Initialize a new `Identify` facade with a `dictionary` of arguments. - * - * @param {Object} dictionary - * @param {String} userId - * @param {String} sessionId - * @param {Object} traits - * @param {Object} options - */ -function Identify (dictionary) { - Facade.call(this, dictionary); -} +// If the JSON object does not yet have a parse method, give it one. -/** - * Inherit from `Facade`. - */ + if (typeof JSON.parse !== 'function') { + JSON.parse = function (text, reviver) { -inherit(Identify, Facade); +// The parse method takes a text and an optional reviver function, and returns +// a JavaScript value if the text is a valid JSON text. -/** - * Get the facade's action. - */ + var j; -Identify.prototype.action = function () { - return 'identify'; -}; + function walk(holder, key) { -/** - * Setup some basic proxies. - */ +// The walk method is used to recursively walk the resulting structure so +// that modifications can be made. -Identify.prototype.userId = Facade.field('userId'); -Identify.prototype.sessionId = Facade.field('sessionId'); + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + } -/** - * Get the user's traits. - * - * @param {Object} aliases - * @return {Object} - */ -Identify.prototype.traits = function (aliases) { - var ret = this.field('traits') || {}; - var id = this.userId(); - aliases = aliases || {}; +// Parsing happens in four stages. In the first stage, we replace certain +// Unicode characters with escape sequences. JavaScript handles many characters +// incorrectly, either silently deleting them, or treating them as line endings. - if (id) ret.id = id; + text = String(text); + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } - for (var alias in aliases) { - var value = null == this[alias] - ? this.proxy('traits.' + alias) - : this[alias](); - if (null == value) continue; - ret[aliases[alias]] = value; - delete ret[alias]; - } +// In the second stage, we run the text against regular expressions that look +// for non-JSON patterns. We are especially concerned with '()' and 'new' +// because they can cause invocation, and '=' because it can cause mutation. +// But just to be safe, we want to reject all unexpected forms. - return ret; -}; +// We split the second stage into 4 regexp operations in order to work around +// crippling inefficiencies in IE's and Safari's regexp engines. First we +// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we +// replace all simple value tokens with ']' characters. Third, we delete all +// open brackets that follow a colon or comma or that begin the text. Finally, +// we look to see that the remaining characters are only whitespace or ']' or +// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. -/** - * Get the user's email, falling back to their user ID if it's a valid email. - * - * @return {String} - */ + if (/^[\],:{}\s]*$/ + .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') + .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') + .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { -Identify.prototype.email = function () { - var email = this.proxy('traits.email'); - if (email) return email; +// In the third stage we use the eval function to compile the text into a +// JavaScript structure. The '{' operator is subject to a syntactic ambiguity +// in JavaScript: it can begin a block or an object literal. We wrap the text +// in parens to eliminate the ambiguity. - var userId = this.userId(); - if (isEmail(userId)) return userId; -}; + j = eval('(' + text + ')'); -/** - * Get the user's created date, optionally looking for `createdAt` since lots of - * people do that instead. - * - * @return {Date or Undefined} - */ +// In the optional fourth stage, we recursively walk the new structure, passing +// each name/value pair to a reviver function for possible transformation. -Identify.prototype.created = function () { - var created = this.proxy('traits.created') || this.proxy('traits.createdAt'); - if (created) return newDate(created); -}; + return typeof reviver === 'function' + ? walk({'': j}, '') + : j; + } -/** - * Get the company created date. - * - * @return {Date or undefined} - */ +// If the text is not JSON parseable, then a SyntaxError is thrown. -Identify.prototype.companyCreated = function(){ - var created = this.proxy('traits.company.created') - || this.proxy('traits.company.createdAt'); + throw new SyntaxError('JSON.parse'); + }; + } +}()); - if (created) return newDate(created); -}; +module.exports = JSON +}); +require.register("segmentio-json/index.js", function(exports, require, module){ -/** - * Get the user's name, optionally combining a first and last name if that's all - * that was provided. - * - * @return {String or Undefined} - */ +module.exports = 'undefined' == typeof JSON + ? require('json-fallback') + : JSON; -Identify.prototype.name = function () { - var name = this.proxy('traits.name'); - if (name) return trim(name); +}); +require.register("segmentio-new-date/index.js", function(exports, require, module){ + +var is = require('is'); - var firstName = this.firstName(); - var lastName = this.lastName(); - if (firstName && lastName) return trim(firstName + ' ' + lastName); -}; /** - * Get the user's first name, optionally splitting it out of a single name if - * that's all that was provided. + * Returns a new Javascript Date object, allowing a variety of extra input types + * over the native Date constructor. * - * @return {String or Undefined} + * @param {Date|String|Number} val */ -Identify.prototype.firstName = function () { - var firstName = this.proxy('traits.firstName'); - if (firstName) return trim(firstName); +module.exports = function newDate (val) { + if (is.number(val)) return new Date(toMs(val)); + if (is.date(val)) return new Date(val.getTime()); // construtor woulda floored - var name = this.proxy('traits.name'); - if (name) return trim(name).split(' ')[0]; + // default to letting the Date constructor parse it + var date = new Date(val); + + // couldn't parse, but we have a string, assume it was a second/milli string + if (is.nan(date.getTime()) && is.string(val)) { + var millis = toMs(parseInt(val, 10)); + date = new Date(millis); + } + + return date; }; + /** - * Get the user's last name, optionally splitting it out of a single name if - * that's all that was provided. + * If the number passed val is seconds from the epoch, turn it into milliseconds. + * Milliseconds would be greater than 31557600000 (December 31, 1970). * - * @return {String or Undefined} + * @param {Number} num */ -Identify.prototype.lastName = function () { - var lastName = this.proxy('traits.lastName'); - if (lastName) return trim(lastName); - - var name = this.proxy('traits.name'); - if (!name) return; +function toMs (num) { + if (num < 31557600000) return num * 1000; + return num; +} +}); +require.register("segmentio-store.js/store.js", function(exports, require, module){ +;(function(win){ + var store = {}, + doc = win.document, + localStorageName = 'localStorage', + namespace = '__storejs__', + storage - var space = trim(name).indexOf(' '); - if (space === -1) return; + store.disabled = false + store.set = function(key, value) {} + store.get = function(key) {} + store.remove = function(key) {} + store.clear = function() {} + store.transact = function(key, defaultVal, transactionFn) { + var val = store.get(key) + if (transactionFn == null) { + transactionFn = defaultVal + defaultVal = null + } + if (typeof val == 'undefined') { val = defaultVal || {} } + transactionFn(val) + store.set(key, val) + } + store.getAll = function() {} - return trim(name.substr(space + 1)); -}; + store.serialize = function(value) { + return JSON.stringify(value) + } + store.deserialize = function(value) { + if (typeof value != 'string') { return undefined } + try { return JSON.parse(value) } + catch(e) { return value || undefined } + } -/** - * Get the user's unique id. - * - * @return {String or undefined} - */ + // Functions to encapsulate questionable FireFox 3.6.13 behavior + // when about.config::dom.storage.enabled === false + // See https://github.com/marcuswestin/store.js/issues#issue/13 + function isLocalStorageNameSupported() { + try { return (localStorageName in win && win[localStorageName]) } + catch(err) { return false } + } -Identify.prototype.uid = function(){ - return this.userId() - || this.username() - || this.email(); -}; + if (isLocalStorageNameSupported()) { + storage = win[localStorageName] + store.set = function(key, val) { + if (val === undefined) { return store.remove(key) } + storage.setItem(key, store.serialize(val)) + return val + } + store.get = function(key) { return store.deserialize(storage.getItem(key)) } + store.remove = function(key) { storage.removeItem(key) } + store.clear = function() { storage.clear() } + store.getAll = function() { + var ret = {} + for (var i=0; idocument.w=window') + storageContainer.close() + storageOwner = storageContainer.w.frames[0].document + storage = storageOwner.createElement('div') + } catch(e) { + // somehow ActiveXObject instantiation failed (perhaps some special + // security settings or otherwse), fall back to per-path storage + storage = doc.createElement('div') + storageOwner = doc.body + } + function withIEStorage(storeFunction) { + return function() { + var args = Array.prototype.slice.call(arguments, 0) + args.unshift(storage) + // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx + // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx + storageOwner.appendChild(storage) + storage.addBehavior('#default#userData') + storage.load(localStorageName) + var result = storeFunction.apply(store, args) + storageOwner.removeChild(storage) + return result + } + } -/** - * Setup sme basic "special" trait proxies. - */ + // In IE7, keys may not contain special chars. See all of https://github.com/marcuswestin/store.js/issues/40 + var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g") + function ieKeyFix(key) { + return key.replace(forbiddenCharsRegex, '___') + } + store.set = withIEStorage(function(storage, key, val) { + key = ieKeyFix(key) + if (val === undefined) { return store.remove(key) } + storage.setAttribute(key, store.serialize(val)) + storage.save(localStorageName) + return val + }) + store.get = withIEStorage(function(storage, key) { + key = ieKeyFix(key) + return store.deserialize(storage.getAttribute(key)) + }) + store.remove = withIEStorage(function(storage, key) { + key = ieKeyFix(key) + storage.removeAttribute(key) + storage.save(localStorageName) + }) + store.clear = withIEStorage(function(storage) { + var attributes = storage.XMLDocument.documentElement.attributes + storage.load(localStorageName) + for (var i=0, attr; attr=attributes[i]; i++) { + storage.removeAttribute(attr.name) + } + storage.save(localStorageName) + }) + store.getAll = withIEStorage(function(storage) { + var attributes = storage.XMLDocument.documentElement.attributes + var ret = {} + for (var i=0, attr; attr=attributes[i]; ++i) { + var key = ieKeyFix(attr.name) + ret[attr.name] = store.deserialize(storage.getAttribute(key)) + } + return ret + }) + } -Identify.prototype.username = Facade.proxy('traits.username'); -Identify.prototype.website = Facade.proxy('traits.website'); -Identify.prototype.phone = Facade.proxy('traits.phone'); -Identify.prototype.address = Facade.proxy('traits.address'); -Identify.prototype.avatar = Facade.proxy('traits.avatar'); + try { + store.set(namespace, namespace) + if (store.get(namespace) != namespace) { store.disabled = true } + store.remove(namespace) + } catch(e) { + store.disabled = true + } + store.enabled = !store.disabled + if (typeof module != 'undefined' && module.exports) { module.exports = store } + else if (typeof define === 'function' && define.amd) { define(store) } + else { win.store = store } +})(this.window || global); }); -require.register("segmentio-facade/lib/is-enabled.js", function(exports, require, module){ +require.register("segmentio-top-domain/index.js", function(exports, require, module){ -/** - * A few integrations are disabled by default. They must be explicitly - * enabled by setting options[Provider] = true. - */ +var url = require('url'); -var disabled = { - Salesforce: true, - Marketo: true -}; +// Official Grammar: http://tools.ietf.org/html/rfc883#page-56 +// Look for tlds with up to 2-6 characters. -/** - * Check whether an integration should be enabled by default. - * - * @param {String} integration - * @return {Boolean} - */ +module.exports = function (urlStr) { -module.exports = function (integration) { - return ! disabled[integration]; + var host = url.parse(urlStr).hostname + , topLevel = host.match(/[a-z0-9][a-z0-9\-]*[a-z0-9]\.[a-z\.]{2,6}$/i); + + return topLevel ? topLevel[0] : host; }; }); -require.register("segmentio-facade/lib/track.js", function(exports, require, module){ +require.register("visionmedia-debug/index.js", function(exports, require, module){ +if ('undefined' == typeof window) { + module.exports = require('./lib/debug'); +} else { + module.exports = require('./debug'); +} -var component = require('require-component')(require); -var clone = component('clone'); -var Facade = component('./facade'); -var Identify = component('./identify'); -var inherit = component('inherit'); -var isEmail = component('is-email'); -var traverse = component('isodate-traverse'); +}); +require.register("visionmedia-debug/debug.js", function(exports, require, module){ /** - * Expose `Track` facade. + * Expose `debug()` as the module. */ -module.exports = Track; +module.exports = debug; /** - * Initialize a new `Track` facade with a `dictionary` of arguments. + * Create a debugger with the given `name`. * - * @param {object} dictionary - * @property {String} event - * @property {String} userId - * @property {String} sessionId - * @property {Object} properties - * @property {Object} options - */ - -function Track (dictionary) { - Facade.call(this, dictionary); -} - -/** - * Inherit from `Facade`. + * @param {String} name + * @return {Type} + * @api public */ -inherit(Track, Facade); +function debug(name) { + if (!debug.enabled(name)) return function(){}; -/** - * Return the facade's action. - * - * @return {String} - */ + return function(fmt){ + fmt = coerce(fmt); -Track.prototype.action = function () { - return 'track'; -}; + var curr = new Date; + var ms = curr - (debug[name] || curr); + debug[name] = curr; -/** - * Setup some basic proxies. - */ + fmt = name + + ' ' + + fmt + + ' +' + debug.humanize(ms); -Track.prototype.userId = Facade.field('userId'); -Track.prototype.sessionId = Facade.field('sessionId'); -Track.prototype.event = Facade.field('event'); -Track.prototype.value = Facade.proxy('properties.value'); + // 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); + } +} /** - * BACKWARDS COMPATIBILITY: should probably re-examine where these come from. + * The currently active debug mode names. */ -Track.prototype.referrer = Facade.proxy('properties.referrer'); -Track.prototype.query = Facade.proxy('options.query'); +debug.names = []; +debug.skips = []; /** - * Get the call's properties. + * Enables a debug mode by name. This can include modes + * separated by a colon and wildcards. * - * @param {Object} aliases - * @return {Object} + * @param {String} name + * @api public */ -Track.prototype.properties = function (aliases) { - var ret = this.field('properties') || {}; - aliases = aliases || {}; +debug.enable = function(name) { + try { + localStorage.debug = name; + } catch(e){} - for (var alias in aliases) { - var value = null == this[alias] - ? this.proxy('properties.' + alias) - : this[alias](); - if (null == value) continue; - ret[aliases[alias]] = value; - delete ret[alias]; - } + var split = (name || '').split(/[\s,]+/) + , len = split.length; - return clone(traverse(ret)); + 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 + '$')); + } + } }; /** - * Get the call's "super properties" which are just traits that have been - * passed in as if from an identify call. + * Disable debug output. * - * @return {Object} + * @api public */ -Track.prototype.traits = function () { - return this.proxy('options.traits') || {}; +debug.disable = function(){ + debug.enable(''); }; /** - * Get the call's username. + * Humanize the given `ms`. * - * @return {String or Undefined} + * @param {Number} m + * @return {String} + * @api private */ -Track.prototype.username = function () { - return this.proxy('traits.username') || - this.proxy('properties.username') || - this.userId() || - this.sessionId(); +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'; }; /** - * Get the call's email, using an the user ID if it's a valid email. + * Returns true if the given mode name is enabled, false otherwise. * - * @return {String or Undefined} + * @param {String} name + * @return {Boolean} + * @api public */ -Track.prototype.email = function () { - var email = this.proxy('traits.email'); - if (email) return email; - - var userId = this.userId(); - if (isEmail(userId)) return userId; +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; }; /** - * Get the call's revenue, parsing it from a string with an optional leading - * dollar sign. - * - * @return {String or Undefined} + * Coerce `val`. */ -Track.prototype.revenue = function () { - var revenue = this.proxy('properties.revenue'); - - if (!revenue) return; - if (typeof revenue === 'number') return revenue; - if (typeof revenue !== 'string') return; - - revenue = revenue.replace(/\$/g, ''); - revenue = parseFloat(revenue); +function coerce(val) { + if (val instanceof Error) return val.stack || val.message; + return val; +} - if (!isNaN(revenue)) return revenue; -}; +// persist -/** - * Get cents. - * - * @return {Number} - */ +try { + if (window.localStorage) debug.enable(localStorage.debug); +} catch(e){} -Track.prototype.cents = function(){ - var revenue = this.revenue(); - return 'number' != typeof revenue - ? this.value() || 0 - : revenue * 100; -}; +}); +require.register("yields-prevent/index.js", function(exports, require, module){ /** - * A utility to turn the pieces of a track call into an identify. Used for - * integrations with super properties or rate limits. - * - * TODO: remove me. - * - * @return {Facade} + * prevent default on the given `e`. + * + * examples: + * + * anchor.onclick = prevent; + * anchor.onclick = function(e){ + * if (something) return prevent(e); + * }; + * + * @param {Event} e */ -Track.prototype.identify = function () { - var json = this.json(); - json.traits = this.traits(); - return new Identify(json); +module.exports = function(e){ + e = e || window.event + return e.preventDefault + ? e.preventDefault() + : e.returnValue = false; }; }); @@ -11395,7 +11344,7 @@ var analytics = module.exports = exports = new Analytics(); * Expose `VERSION`. */ -exports.VERSION = '1.2.2'; +exports.VERSION = '1.2.3'; /** @@ -12598,12 +12547,12 @@ require.alias("component-indexof/index.js", "component-emitter/deps/indexof/inde require.alias("component-event/index.js", "analytics/deps/event/index.js"); require.alias("component-event/index.js", "event/index.js"); -require.alias("component-object/index.js", "analytics/deps/object/index.js"); -require.alias("component-object/index.js", "object/index.js"); - require.alias("component-inherit/index.js", "analytics/deps/inherit/index.js"); require.alias("component-inherit/index.js", "inherit/index.js"); +require.alias("component-object/index.js", "analytics/deps/object/index.js"); +require.alias("component-object/index.js", "object/index.js"); + require.alias("component-querystring/index.js", "analytics/deps/querystring/index.js"); require.alias("component-querystring/index.js", "querystring/index.js"); require.alias("component-trim/index.js", "component-querystring/deps/trim/index.js"); @@ -12849,18 +12798,12 @@ require.alias("component-user-agent-parser/src/ua-parser.js", "segmentio-facade/ require.alias("component-user-agent-parser/src/ua-parser.js", "component-user-agent-parser/index.js"); require.alias("segmentio-is-email/index.js", "segmentio-facade/deps/is-email/index.js"); -require.alias("segmentio-new-date/lib/index.js", "segmentio-facade/deps/new-date/lib/index.js"); -require.alias("segmentio-new-date/lib/milliseconds.js", "segmentio-facade/deps/new-date/lib/milliseconds.js"); -require.alias("segmentio-new-date/lib/seconds.js", "segmentio-facade/deps/new-date/lib/seconds.js"); -require.alias("segmentio-new-date/lib/index.js", "segmentio-facade/deps/new-date/index.js"); +require.alias("segmentio-new-date/index.js", "segmentio-facade/deps/new-date/index.js"); require.alias("ianstormtaylor-is/index.js", "segmentio-new-date/deps/is/index.js"); require.alias("component-type/index.js", "ianstormtaylor-is/deps/type/index.js"); require.alias("ianstormtaylor-is-empty/index.js", "ianstormtaylor-is/deps/is-empty/index.js"); -require.alias("segmentio-isodate/index.js", "segmentio-new-date/deps/isodate/index.js"); - -require.alias("segmentio-new-date/lib/index.js", "segmentio-new-date/index.js"); require.alias("segmentio-obj-case/index.js", "segmentio-facade/deps/obj-case/index.js"); require.alias("segmentio-obj-case/index.js", "segmentio-facade/deps/obj-case/index.js"); require.alias("yields-case/dist/Case.js", "segmentio-obj-case/deps/case/dist/Case.js"); @@ -12908,63 +12851,6 @@ require.alias("segmentio-canonical/index.js", "canonical/index.js"); require.alias("segmentio-extend/index.js", "analytics/deps/extend/index.js"); require.alias("segmentio-extend/index.js", "extend/index.js"); -require.alias("segmentio-is-email/index.js", "analytics/deps/is-email/index.js"); -require.alias("segmentio-is-email/index.js", "is-email/index.js"); - -require.alias("segmentio-is-meta/index.js", "analytics/deps/is-meta/index.js"); -require.alias("segmentio-is-meta/index.js", "is-meta/index.js"); - -require.alias("segmentio-isodate-traverse/index.js", "analytics/deps/isodate-traverse/index.js"); -require.alias("segmentio-isodate-traverse/index.js", "isodate-traverse/index.js"); -require.alias("component-clone/index.js", "segmentio-isodate-traverse/deps/clone/index.js"); -require.alias("component-type/index.js", "component-clone/deps/type/index.js"); - -require.alias("component-each/index.js", "segmentio-isodate-traverse/deps/each/index.js"); -require.alias("component-to-function/index.js", "component-each/deps/to-function/index.js"); - -require.alias("component-type/index.js", "component-each/deps/type/index.js"); - -require.alias("ianstormtaylor-is/index.js", "segmentio-isodate-traverse/deps/is/index.js"); -require.alias("component-type/index.js", "ianstormtaylor-is/deps/type/index.js"); - -require.alias("ianstormtaylor-is-empty/index.js", "ianstormtaylor-is/deps/is-empty/index.js"); - -require.alias("segmentio-isodate/index.js", "segmentio-isodate-traverse/deps/isodate/index.js"); - -require.alias("segmentio-json/index.js", "analytics/deps/json/index.js"); -require.alias("segmentio-json/index.js", "json/index.js"); -require.alias("component-json-fallback/index.js", "segmentio-json/deps/json-fallback/index.js"); - -require.alias("segmentio-new-date/lib/index.js", "analytics/deps/new-date/lib/index.js"); -require.alias("segmentio-new-date/lib/milliseconds.js", "analytics/deps/new-date/lib/milliseconds.js"); -require.alias("segmentio-new-date/lib/seconds.js", "analytics/deps/new-date/lib/seconds.js"); -require.alias("segmentio-new-date/lib/index.js", "analytics/deps/new-date/index.js"); -require.alias("segmentio-new-date/lib/index.js", "new-date/index.js"); -require.alias("ianstormtaylor-is/index.js", "segmentio-new-date/deps/is/index.js"); -require.alias("component-type/index.js", "ianstormtaylor-is/deps/type/index.js"); - -require.alias("ianstormtaylor-is-empty/index.js", "ianstormtaylor-is/deps/is-empty/index.js"); - -require.alias("segmentio-isodate/index.js", "segmentio-new-date/deps/isodate/index.js"); - -require.alias("segmentio-new-date/lib/index.js", "segmentio-new-date/index.js"); -require.alias("segmentio-store.js/store.js", "analytics/deps/store/store.js"); -require.alias("segmentio-store.js/store.js", "analytics/deps/store/index.js"); -require.alias("segmentio-store.js/store.js", "store/index.js"); -require.alias("segmentio-store.js/store.js", "segmentio-store.js/index.js"); -require.alias("segmentio-top-domain/index.js", "analytics/deps/top-domain/index.js"); -require.alias("segmentio-top-domain/index.js", "analytics/deps/top-domain/index.js"); -require.alias("segmentio-top-domain/index.js", "top-domain/index.js"); -require.alias("component-url/index.js", "segmentio-top-domain/deps/url/index.js"); - -require.alias("segmentio-top-domain/index.js", "segmentio-top-domain/index.js"); -require.alias("yields-prevent/index.js", "analytics/deps/prevent/index.js"); -require.alias("yields-prevent/index.js", "prevent/index.js"); - -require.alias("visionmedia-debug/index.js", "analytics/deps/debug/index.js"); -require.alias("visionmedia-debug/debug.js", "analytics/deps/debug/debug.js"); -require.alias("visionmedia-debug/index.js", "debug/index.js"); - require.alias("segmentio-facade/lib/index.js", "analytics/deps/facade/lib/index.js"); require.alias("segmentio-facade/lib/alias.js", "analytics/deps/facade/lib/alias.js"); require.alias("segmentio-facade/lib/facade.js", "analytics/deps/facade/lib/facade.js"); @@ -13005,18 +12891,12 @@ require.alias("component-user-agent-parser/src/ua-parser.js", "segmentio-facade/ require.alias("component-user-agent-parser/src/ua-parser.js", "component-user-agent-parser/index.js"); require.alias("segmentio-is-email/index.js", "segmentio-facade/deps/is-email/index.js"); -require.alias("segmentio-new-date/lib/index.js", "segmentio-facade/deps/new-date/lib/index.js"); -require.alias("segmentio-new-date/lib/milliseconds.js", "segmentio-facade/deps/new-date/lib/milliseconds.js"); -require.alias("segmentio-new-date/lib/seconds.js", "segmentio-facade/deps/new-date/lib/seconds.js"); -require.alias("segmentio-new-date/lib/index.js", "segmentio-facade/deps/new-date/index.js"); +require.alias("segmentio-new-date/index.js", "segmentio-facade/deps/new-date/index.js"); require.alias("ianstormtaylor-is/index.js", "segmentio-new-date/deps/is/index.js"); require.alias("component-type/index.js", "ianstormtaylor-is/deps/type/index.js"); require.alias("ianstormtaylor-is-empty/index.js", "ianstormtaylor-is/deps/is-empty/index.js"); -require.alias("segmentio-isodate/index.js", "segmentio-new-date/deps/isodate/index.js"); - -require.alias("segmentio-new-date/lib/index.js", "segmentio-new-date/index.js"); require.alias("segmentio-obj-case/index.js", "segmentio-facade/deps/obj-case/index.js"); require.alias("segmentio-obj-case/index.js", "segmentio-facade/deps/obj-case/index.js"); require.alias("yields-case/dist/Case.js", "segmentio-obj-case/deps/case/dist/Case.js"); @@ -13024,6 +12904,57 @@ require.alias("yields-case/dist/Case.js", "segmentio-obj-case/deps/case/index.js require.alias("yields-case/dist/Case.js", "yields-case/index.js"); require.alias("segmentio-obj-case/index.js", "segmentio-obj-case/index.js"); require.alias("segmentio-facade/lib/index.js", "segmentio-facade/index.js"); +require.alias("segmentio-is-email/index.js", "analytics/deps/is-email/index.js"); +require.alias("segmentio-is-email/index.js", "is-email/index.js"); + +require.alias("segmentio-is-meta/index.js", "analytics/deps/is-meta/index.js"); +require.alias("segmentio-is-meta/index.js", "is-meta/index.js"); + +require.alias("segmentio-isodate-traverse/index.js", "analytics/deps/isodate-traverse/index.js"); +require.alias("segmentio-isodate-traverse/index.js", "isodate-traverse/index.js"); +require.alias("component-clone/index.js", "segmentio-isodate-traverse/deps/clone/index.js"); +require.alias("component-type/index.js", "component-clone/deps/type/index.js"); + +require.alias("component-each/index.js", "segmentio-isodate-traverse/deps/each/index.js"); +require.alias("component-to-function/index.js", "component-each/deps/to-function/index.js"); + +require.alias("component-type/index.js", "component-each/deps/type/index.js"); + +require.alias("ianstormtaylor-is/index.js", "segmentio-isodate-traverse/deps/is/index.js"); +require.alias("component-type/index.js", "ianstormtaylor-is/deps/type/index.js"); + +require.alias("ianstormtaylor-is-empty/index.js", "ianstormtaylor-is/deps/is-empty/index.js"); + +require.alias("segmentio-isodate/index.js", "segmentio-isodate-traverse/deps/isodate/index.js"); + +require.alias("segmentio-json/index.js", "analytics/deps/json/index.js"); +require.alias("segmentio-json/index.js", "json/index.js"); +require.alias("component-json-fallback/index.js", "segmentio-json/deps/json-fallback/index.js"); + +require.alias("segmentio-new-date/index.js", "analytics/deps/new-date/index.js"); +require.alias("segmentio-new-date/index.js", "new-date/index.js"); +require.alias("ianstormtaylor-is/index.js", "segmentio-new-date/deps/is/index.js"); +require.alias("component-type/index.js", "ianstormtaylor-is/deps/type/index.js"); + +require.alias("ianstormtaylor-is-empty/index.js", "ianstormtaylor-is/deps/is-empty/index.js"); + +require.alias("segmentio-store.js/store.js", "analytics/deps/store/store.js"); +require.alias("segmentio-store.js/store.js", "analytics/deps/store/index.js"); +require.alias("segmentio-store.js/store.js", "store/index.js"); +require.alias("segmentio-store.js/store.js", "segmentio-store.js/index.js"); +require.alias("segmentio-top-domain/index.js", "analytics/deps/top-domain/index.js"); +require.alias("segmentio-top-domain/index.js", "analytics/deps/top-domain/index.js"); +require.alias("segmentio-top-domain/index.js", "top-domain/index.js"); +require.alias("component-url/index.js", "segmentio-top-domain/deps/url/index.js"); + +require.alias("segmentio-top-domain/index.js", "segmentio-top-domain/index.js"); +require.alias("visionmedia-debug/index.js", "analytics/deps/debug/index.js"); +require.alias("visionmedia-debug/debug.js", "analytics/deps/debug/debug.js"); +require.alias("visionmedia-debug/index.js", "debug/index.js"); + +require.alias("yields-prevent/index.js", "analytics/deps/prevent/index.js"); +require.alias("yields-prevent/index.js", "prevent/index.js"); + require.alias("analytics/lib/index.js", "analytics/index.js");if (typeof exports == "object") { module.exports = require("analytics"); } else if (typeof define == "function" && define.amd) { diff --git a/analytics.min.js b/analytics.min.js index fd862a571..ec248d4fc 100644 --- a/analytics.min.js +++ b/analytics.min.js @@ -1,6 +1,6 @@ -(function(){function require(path,parent,orig){var resolved=require.resolve(path);if(null==resolved){orig=orig||path;parent=parent||"root";var err=new Error('Failed to require "'+orig+'" from "'+parent+'"');err.path=orig;err.parent=parent;err.require=true;throw err}var module=require.modules[resolved];if(!module.exports){module.exports={};module.client=module.component=true;module.call(this,module.exports,require.relative(resolved),module)}return module.exports}require.modules={};require.aliases={};require.resolve=function(path){if(path.charAt(0)==="/")path=path.slice(1);var paths=[path,path+".js",path+".json",path+"/index.js",path+"/index.json"];for(var i=0;i',""],optgroup:[1,'"],legend:[1,"
","
"],thead:[1,"","
"],tbody:[1,"","
"],tfoot:[1,"","
"],colgroup:[1,"","
"],caption:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],th:[3,"","
"],col:[2,"","
"],_default:[0,"",""]};function parse(html){if("string"!=typeof html)throw new TypeError("String expected");html=html.replace(/^\s+|\s+$/g,"");var m=/<([\w:]+)/.exec(html);if(!m)return document.createTextNode(html);var tag=m[1];if(tag=="body"){var el=document.createElement("html");el.innerHTML=html;return el.removeChild(el.lastChild)}var wrap=map[tag]||map._default;var depth=wrap[0];var prefix=wrap[1];var suffix=wrap[2];var el=document.createElement("div");el.innerHTML=prefix+html+suffix;while(depth--)el=el.lastChild;if(1==el.children.length){return el.removeChild(el.children[0])}var fragment=document.createDocumentFragment();while(el.children.length){fragment.appendChild(el.removeChild(el.children[0]))}return fragment}});require.register("component-once/index.js",function(exports,require,module){var n=0;var global=function(){return this}();module.exports=function(fn){var id=n++;function once(){if(this==global){if(once.called)return;once.called=true;return fn.apply(this,arguments)}var key="__called_"+id+"__";if(this[key])return;this[key]=true;return fn.apply(this,arguments)}return once}});require.register("segmentio-alias/index.js",function(exports,require,module){var type=require("type");try{var clone=require("clone")}catch(e){var clone=require("clone-component")}module.exports=alias;function alias(obj,method){switch(type(method)){case"object":return aliasByDictionary(clone(obj),method);case"function":return aliasByFunction(clone(obj),method)}}function aliasByDictionary(obj,aliases){for(var key in aliases){if(undefined===obj[key])continue;obj[aliases[key]]=obj[key];delete obj[key]}return obj}function aliasByFunction(obj,convert){var output={};for(var key in obj)output[convert(key)]=obj[key];return output}});require.register("segmentio-convert-dates/index.js",function(exports,require,module){var is=require("is");try{var clone=require("clone")}catch(e){var clone=require("clone-component")}module.exports=convertDates;function convertDates(obj,convert){obj=clone(obj);for(var key in obj){var val=obj[key];if(is.date(val))obj[key]=convert(val);if(is.object(val))obj[key]=convertDates(val,convert)}return obj}});require.register("segmentio-global-queue/index.js",function(exports,require,module){module.exports=generate;function generate(name,options){options=options||{};return function(args){args=[].slice.call(arguments);window[name]||(window[name]=[]);options.wrap===false?window[name].push.apply(window[name],args):window[name].push(args)}}});require.register("segmentio-load-date/index.js",function(exports,require,module){var time=new Date,perf=window.performance;if(perf&&perf.timing&&perf.timing.responseEnd){time=new Date(perf.timing.responseEnd)}module.exports=time});require.register("segmentio-load-script/index.js",function(exports,require,module){var type=require("type");module.exports=function loadScript(options,callback){if(!options)throw new Error("Cant load nothing...");if(type(options)==="string")options={src:options};var https=document.location.protocol==="https:"||document.location.protocol==="chrome-extension:";if(options.src&&options.src.indexOf("//")===0){options.src=https?"https:"+options.src:"http:"+options.src}if(https&&options.https)options.src=options.https;else if(!https&&options.http)options.src=options.http;var script=document.createElement("script");script.type="text/javascript";script.async=true;script.src=options.src;var firstScript=document.getElementsByTagName("script")[0];firstScript.parentNode.insertBefore(script,firstScript);if(callback&&type(callback)==="function"){if(script.addEventListener){script.addEventListener("load",function(event){callback(null,event)},false);script.addEventListener("error",function(event){callback(new Error("Failed to load the script."),event)},false)}else if(script.attachEvent){script.attachEvent("onreadystatechange",function(event){if(/complete|loaded/.test(script.readyState)){callback(null,event)}})}}return script}});require.register("segmentio-on-body/index.js",function(exports,require,module){var each=require("each");var body=false;var callbacks=[];module.exports=function onBody(callback){if(body){call(callback)}else{callbacks.push(callback)}};var interval=setInterval(function(){if(!document.body)return;body=true;each(callbacks,call);clearInterval(interval)},5);function call(callback){callback(document.body)}});require.register("segmentio-on-error/index.js",function(exports,require,module){module.exports=onError;var callbacks=[];if("function"==typeof window.onerror)callbacks.push(window.onerror);window.onerror=handler;function handler(){for(var i=0,fn;fn=callbacks[i];i++)fn.apply(this,arguments)}function onError(fn){callbacks.push(fn);if(window.onerror!=handler){callbacks.push(window.onerror);window.onerror=handler}}});require.register("segmentio-to-iso-string/index.js",function(exports,require,module){module.exports=toIsoString;function toIsoString(date){return date.getUTCFullYear()+"-"+pad(date.getUTCMonth()+1)+"-"+pad(date.getUTCDate())+"T"+pad(date.getUTCHours())+":"+pad(date.getUTCMinutes())+":"+pad(date.getUTCSeconds())+"."+String((date.getUTCMilliseconds()/1e3).toFixed(3)).slice(2,5)+"Z"}function pad(number){var n=number.toString();return n.length===1?"0"+n:n}});require.register("segmentio-to-unix-timestamp/index.js",function(exports,require,module){module.exports=toUnixTimestamp;function toUnixTimestamp(date){return Math.floor(date.getTime()/1e3)}});require.register("segmentio-use-https/index.js",function(exports,require,module){module.exports=function(url){switch(arguments.length){case 0:return check();case 1:return transform(url)}};function transform(url){return check()?"https:"+url:"http:"+url}function check(){return location.protocol=="https:"||location.protocol=="chrome-extension:"}});require.register("visionmedia-batch/index.js",function(exports,require,module){try{var EventEmitter=require("events").EventEmitter}catch(err){var Emitter=require("emitter")}function noop(){}module.exports=Batch;function Batch(){if(!(this instanceof Batch))return new Batch;this.fns=[];this.concurrency(Infinity);this.throws(true);for(var i=0,len=arguments.length;i