This repository has been archived by the owner. It is now read-only.
Permalink
Cannot retrieve contributors at this time
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
20420 lines (16784 sloc)
439 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function umd(require){ | |
if (typeof exports === 'object') { | |
module.exports = require('1'); | |
} else if (typeof define === 'function' && (define.amd || define.cmd)) { | |
define(function(){ return require('1'); }); | |
} else { | |
this['analytics'] = require('1'); | |
} | |
})((function outer(modules, cache, entries){ | |
/** | |
* Global | |
*/ | |
var global = (function(){ return this; })(); | |
/** | |
* Require `name`. | |
* | |
* @param {String} name | |
* @api public | |
*/ | |
function require(name){ | |
if (cache[name]) return cache[name].exports; | |
if (modules[name]) return call(name, require); | |
throw new Error('cannot find module "' + name + '"'); | |
} | |
/** | |
* Call module `id` and cache it. | |
* | |
* @param {Number} id | |
* @param {Function} require | |
* @return {Function} | |
* @api private | |
*/ | |
function call(id, require){ | |
var m = cache[id] = { exports: {} }; | |
var mod = modules[id]; | |
var name = mod[2]; | |
var fn = mod[0]; | |
var threw = true; | |
try { | |
fn.call(m.exports, function(req){ | |
var dep = modules[id][1][req]; | |
return require(dep || req); | |
}, m, m.exports, outer, modules, cache, entries); | |
threw = false; | |
} finally { | |
if (threw) { | |
delete cache[id]; | |
} else if (name) { | |
// expose as 'name'. | |
cache[name] = cache[id]; | |
} | |
} | |
return cache[id].exports; | |
} | |
/** | |
* Require all entries exposing them on global if needed. | |
*/ | |
for (var id in entries) { | |
if (entries[id]) { | |
global[entries[id]] = require(id); | |
} else { | |
require(id); | |
} | |
} | |
/** | |
* Duo flag. | |
*/ | |
require.duo = true; | |
/** | |
* Expose cache. | |
*/ | |
require.cache = cache; | |
/** | |
* Expose modules | |
*/ | |
require.modules = modules; | |
/** | |
* Return newest require. | |
*/ | |
return require; | |
})({ | |
1: [function(require, module, exports) { | |
/** | |
* Analytics.js | |
* | |
* (C) 2015 Segment.io Inc. | |
*/ | |
var analytics = require('segmentio/analytics.js-core'); | |
var Integrations = require('./integrations'); | |
var each = require('each'); | |
/** | |
* Expose the `analytics` singleton. | |
*/ | |
module.exports = exports = analytics; | |
/** | |
* Expose require. | |
*/ | |
analytics.require = require; | |
/** | |
* Expose `VERSION`. | |
*/ | |
exports.VERSION = require('../bower.json').version; | |
/** | |
* Add integrations. | |
*/ | |
each(Integrations, function(name, Integration) { | |
analytics.use(Integration); | |
}); | |
}, {"segmentio/analytics.js-core":2,"./integrations":3,"each":4,"../bower.json":5}], | |
2: [function(require, module, exports) { | |
/** | |
* Analytics.js | |
* | |
* (C) 2013 Segment.io Inc. | |
*/ | |
var Analytics = require('./analytics'); | |
/** | |
* Expose the `analytics` singleton. | |
*/ | |
var analytics = module.exports = exports = new Analytics(); | |
/** | |
* Expose require | |
*/ | |
analytics.require = require; | |
/** | |
* Expose `VERSION`. | |
*/ | |
exports.VERSION = require('../bower.json').version; | |
}, {"./analytics":6,"../bower.json":7}], | |
6: [function(require, module, exports) { | |
/** | |
* Module dependencies. | |
*/ | |
var _analytics = window.analytics; | |
var Emitter = require('emitter'); | |
var Facade = require('facade'); | |
var after = require('after'); | |
var bind = require('bind'); | |
var callback = require('callback'); | |
var clone = require('clone'); | |
var cookie = require('./cookie'); | |
var debug = require('debug'); | |
var defaults = require('defaults'); | |
var each = require('each'); | |
var group = require('./group'); | |
var is = require('is'); | |
var isMeta = require('is-meta'); | |
var keys = require('object').keys; | |
var memory = require('./memory'); | |
var normalize = require('./normalize'); | |
var on = require('event').bind; | |
var pageDefaults = require('./pageDefaults'); | |
var pick = require('pick'); | |
var prevent = require('prevent'); | |
var querystring = require('querystring'); | |
var size = require('object').length; | |
var store = require('./store'); | |
var user = require('./user'); | |
var Alias = Facade.Alias; | |
var Group = Facade.Group; | |
var Identify = Facade.Identify; | |
var Page = Facade.Page; | |
var Track = Facade.Track; | |
/** | |
* Expose `Analytics`. | |
*/ | |
exports = module.exports = Analytics; | |
/** | |
* Expose storage. | |
*/ | |
exports.cookie = cookie; | |
exports.store = store; | |
exports.memory = memory; | |
/** | |
* Initialize a new `Analytics` instance. | |
*/ | |
function Analytics() { | |
this._options({}); | |
this.Integrations = {}; | |
this._integrations = {}; | |
this._readied = false; | |
this._timeout = 300; | |
// XXX: BACKWARDS COMPATIBILITY | |
this._user = user; | |
this.log = debug('analytics.js'); | |
bind.all(this); | |
var self = this; | |
this.on('initialize', function(settings, options){ | |
if (options.initialPageview) self.page(); | |
self._parseQuery(); | |
}); | |
} | |
/** | |
* Event Emitter. | |
*/ | |
Emitter(Analytics.prototype); | |
/** | |
* Use a `plugin`. | |
* | |
* @param {Function} plugin | |
* @return {Analytics} | |
*/ | |
Analytics.prototype.use = function(plugin) { | |
plugin(this); | |
return this; | |
}; | |
/** | |
* Define a new `Integration`. | |
* | |
* @param {Function} Integration | |
* @return {Analytics} | |
*/ | |
Analytics.prototype.addIntegration = function(Integration) { | |
var name = Integration.prototype.name; | |
if (!name) throw new TypeError('attempted to add an invalid integration'); | |
this.Integrations[name] = Integration; | |
return this; | |
}; | |
/** | |
* Initialize with the given integration `settings` and `options`. | |
* | |
* Aliased to `init` for convenience. | |
* | |
* @param {Object} [settings={}] | |
* @param {Object} [options={}] | |
* @return {Analytics} | |
*/ | |
Analytics.prototype.init = Analytics.prototype.initialize = function(settings, options) { | |
settings = settings || {}; | |
options = options || {}; | |
this._options(options); | |
this._readied = false; | |
// clean unknown integrations from settings | |
var self = this; | |
each(settings, function(name) { | |
var Integration = self.Integrations[name]; | |
if (!Integration) delete settings[name]; | |
}); | |
// add integrations | |
each(settings, function(name, opts) { | |
var Integration = self.Integrations[name]; | |
var integration = new Integration(clone(opts)); | |
self.log('initialize %o - %o', name, opts); | |
self.add(integration); | |
}); | |
var integrations = this._integrations; | |
// load user now that options are set | |
user.load(); | |
group.load(); | |
// make ready callback | |
var ready = after(size(integrations), function() { | |
self._readied = true; | |
self.emit('ready'); | |
}); | |
// initialize integrations, passing ready | |
each(integrations, function(name, integration) { | |
if (options.initialPageview && integration.options.initialPageview === false) { | |
integration.page = after(2, integration.page); | |
} | |
integration.analytics = self; | |
integration.once('ready', ready); | |
integration.initialize(); | |
}); | |
// backwards compat with angular plugin. | |
// TODO: remove | |
this.initialized = true; | |
this.emit('initialize', settings, options); | |
return this; | |
}; | |
/** | |
* Set the user's `id`. | |
* | |
* @param {Mixed} id | |
*/ | |
Analytics.prototype.setAnonymousId = function(id){ | |
this.user().anonymousId(id); | |
return this; | |
}; | |
/** | |
* Add an integration. | |
* | |
* @param {Integration} integration | |
*/ | |
Analytics.prototype.add = function(integration){ | |
this._integrations[integration.name] = integration; | |
return this; | |
}; | |
/** | |
* Identify a user by optional `id` and `traits`. | |
* | |
* @param {string} [id=user.id()] User ID. | |
* @param {Object} [traits=null] User traits. | |
* @param {Object} [options=null] | |
* @param {Function} [fn] | |
* @return {Analytics} | |
*/ | |
Analytics.prototype.identify = function(id, traits, options, fn) { | |
// Argument reshuffling. | |
/* eslint-disable no-unused-expressions, no-sequences */ | |
if (is.fn(options)) fn = options, options = null; | |
if (is.fn(traits)) fn = traits, options = null, traits = null; | |
if (is.object(id)) options = traits, traits = id, id = user.id(); | |
/* eslint-enable no-unused-expressions, no-sequences */ | |
// clone traits before we manipulate so we don't do anything uncouth, and take | |
// from `user` so that we carryover anonymous traits | |
user.identify(id, traits); | |
var msg = this.normalize({ | |
options: options, | |
traits: user.traits(), | |
userId: user.id() | |
}); | |
this._invoke('identify', new Identify(msg)); | |
// emit | |
this.emit('identify', id, traits, options); | |
this._callback(fn); | |
return this; | |
}; | |
/** | |
* Return the current user. | |
* | |
* @return {Object} | |
*/ | |
Analytics.prototype.user = function() { | |
return user; | |
}; | |
/** | |
* Identify a group by optional `id` and `traits`. Or, if no arguments are | |
* supplied, return the current group. | |
* | |
* @param {string} [id=group.id()] Group ID. | |
* @param {Object} [traits=null] Group traits. | |
* @param {Object} [options=null] | |
* @param {Function} [fn] | |
* @return {Analytics|Object} | |
*/ | |
Analytics.prototype.group = function(id, traits, options, fn) { | |
/* eslint-disable no-unused-expressions, no-sequences */ | |
if (!arguments.length) return group; | |
if (is.fn(options)) fn = options, options = null; | |
if (is.fn(traits)) fn = traits, options = null, traits = null; | |
if (is.object(id)) options = traits, traits = id, id = group.id(); | |
/* eslint-enable no-unused-expressions, no-sequences */ | |
// grab from group again to make sure we're taking from the source | |
group.identify(id, traits); | |
var msg = this.normalize({ | |
options: options, | |
traits: group.traits(), | |
groupId: group.id() | |
}); | |
this._invoke('group', new Group(msg)); | |
this.emit('group', id, traits, options); | |
this._callback(fn); | |
return this; | |
}; | |
/** | |
* Track an `event` that a user has triggered with optional `properties`. | |
* | |
* @param {string} event | |
* @param {Object} [properties=null] | |
* @param {Object} [options=null] | |
* @param {Function} [fn] | |
* @return {Analytics} | |
*/ | |
Analytics.prototype.track = function(event, properties, options, fn) { | |
// Argument reshuffling. | |
/* eslint-disable no-unused-expressions, no-sequences */ | |
if (is.fn(options)) fn = options, options = null; | |
if (is.fn(properties)) fn = properties, options = null, properties = null; | |
/* eslint-enable no-unused-expressions, no-sequences */ | |
// figure out if the event is archived. | |
var plan = this.options.plan || {}; | |
var events = plan.track || {}; | |
// normalize | |
var msg = this.normalize({ | |
properties: properties, | |
options: options, | |
event: event | |
}); | |
// plan. | |
plan = events[event]; | |
if (plan) { | |
this.log('plan %o - %o', event, plan); | |
if (plan.enabled === false) return this._callback(fn); | |
defaults(msg.integrations, plan.integrations || {}); | |
} | |
this._invoke('track', new Track(msg)); | |
this.emit('track', event, properties, options); | |
this._callback(fn); | |
return this; | |
}; | |
/** | |
* Helper method to track an outbound link that would normally navigate away | |
* from the page before the analytics calls were sent. | |
* | |
* BACKWARDS COMPATIBILITY: aliased to `trackClick`. | |
* | |
* @param {Element|Array} links | |
* @param {string|Function} event | |
* @param {Object|Function} properties (optional) | |
* @return {Analytics} | |
*/ | |
Analytics.prototype.trackClick = Analytics.prototype.trackLink = function(links, event, properties) { | |
if (!links) return this; | |
// always arrays, handles jquery | |
if (is.element(links)) links = [links]; | |
var self = this; | |
each(links, function(el) { | |
if (!is.element(el)) throw new TypeError('Must pass HTMLElement to `analytics.trackLink`.'); | |
on(el, 'click', function(e) { | |
var ev = is.fn(event) ? event(el) : event; | |
var props = is.fn(properties) ? properties(el) : properties; | |
var href = el.getAttribute('href') | |
|| el.getAttributeNS('http://www.w3.org/1999/xlink', 'href') | |
|| el.getAttribute('xlink:href'); | |
self.track(ev, props); | |
if (href && el.target !== '_blank' && !isMeta(e)) { | |
prevent(e); | |
self._callback(function() { | |
window.location.href = href; | |
}); | |
} | |
}); | |
}); | |
return this; | |
}; | |
/** | |
* Helper method to track an outbound form that would normally navigate away | |
* from the page before the analytics calls were sent. | |
* | |
* BACKWARDS COMPATIBILITY: aliased to `trackSubmit`. | |
* | |
* @param {Element|Array} forms | |
* @param {string|Function} event | |
* @param {Object|Function} properties (optional) | |
* @return {Analytics} | |
*/ | |
Analytics.prototype.trackSubmit = Analytics.prototype.trackForm = function(forms, event, properties) { | |
if (!forms) return this; | |
// always arrays, handles jquery | |
if (is.element(forms)) forms = [forms]; | |
var self = this; | |
each(forms, function(el) { | |
if (!is.element(el)) throw new TypeError('Must pass HTMLElement to `analytics.trackForm`.'); | |
function handler(e) { | |
prevent(e); | |
var ev = is.fn(event) ? event(el) : event; | |
var props = is.fn(properties) ? properties(el) : properties; | |
self.track(ev, props); | |
self._callback(function() { | |
el.submit(); | |
}); | |
} | |
// Support the events happening through jQuery or Zepto instead of through | |
// the normal DOM API, because `el.submit` doesn't bubble up events... | |
var $ = window.jQuery || window.Zepto; | |
if ($) { | |
$(el).submit(handler); | |
} else { | |
on(el, 'submit', handler); | |
} | |
}); | |
return this; | |
}; | |
/** | |
* Trigger a pageview, labeling the current page with an optional `category`, | |
* `name` and `properties`. | |
* | |
* @param {string} [category] | |
* @param {string} [name] | |
* @param {Object|string} [properties] (or path) | |
* @param {Object} [options] | |
* @param {Function} [fn] | |
* @return {Analytics} | |
*/ | |
Analytics.prototype.page = function(category, name, properties, options, fn) { | |
// Argument reshuffling. | |
/* eslint-disable no-unused-expressions, no-sequences */ | |
if (is.fn(options)) fn = options, options = null; | |
if (is.fn(properties)) fn = properties, options = properties = null; | |
if (is.fn(name)) fn = name, options = properties = name = null; | |
if (is.object(category)) options = name, properties = category, name = category = null; | |
if (is.object(name)) options = properties, properties = name, name = null; | |
if (is.string(category) && !is.string(name)) name = category, category = null; | |
/* eslint-enable no-unused-expressions, no-sequences */ | |
properties = clone(properties) || {}; | |
if (name) properties.name = name; | |
if (category) properties.category = category; | |
// Ensure properties has baseline spec properties. | |
// TODO: Eventually move these entirely to `options.context.page` | |
var defs = pageDefaults(); | |
defaults(properties, defs); | |
// Mirror user overrides to `options.context.page` (but exclude custom properties) | |
// (Any page defaults get applied in `this.normalize` for consistency.) | |
// Weird, yeah--moving special props to `context.page` will fix this in the long term. | |
var overrides = pick(keys(defs), properties); | |
if (!is.empty(overrides)) { | |
options = options || {}; | |
options.context = options.context || {}; | |
options.context.page = overrides; | |
} | |
var msg = this.normalize({ | |
properties: properties, | |
category: category, | |
options: options, | |
name: name | |
}); | |
this._invoke('page', new Page(msg)); | |
this.emit('page', category, name, properties, options); | |
this._callback(fn); | |
return this; | |
}; | |
/** | |
* FIXME: BACKWARDS COMPATIBILITY: convert an old `pageview` to a `page` call. | |
* | |
* @param {string} [url] | |
* @return {Analytics} | |
* @api private | |
*/ | |
Analytics.prototype.pageview = function(url) { | |
var properties = {}; | |
if (url) properties.path = url; | |
this.page(properties); | |
return this; | |
}; | |
/** | |
* Merge two previously unassociated user identities. | |
* | |
* @param {string} to | |
* @param {string} from (optional) | |
* @param {Object} options (optional) | |
* @param {Function} fn (optional) | |
* @return {Analytics} | |
*/ | |
Analytics.prototype.alias = function(to, from, options, fn) { | |
// Argument reshuffling. | |
/* eslint-disable no-unused-expressions, no-sequences */ | |
if (is.fn(options)) fn = options, options = null; | |
if (is.fn(from)) fn = from, options = null, from = null; | |
if (is.object(from)) options = from, from = null; | |
/* eslint-enable no-unused-expressions, no-sequences */ | |
var msg = this.normalize({ | |
options: options, | |
previousId: from, | |
userId: to | |
}); | |
this._invoke('alias', new Alias(msg)); | |
this.emit('alias', to, from, options); | |
this._callback(fn); | |
return this; | |
}; | |
/** | |
* Register a `fn` to be fired when all the analytics services are ready. | |
* | |
* @param {Function} fn | |
* @return {Analytics} | |
*/ | |
Analytics.prototype.ready = function(fn) { | |
if (is.fn(fn)) { | |
if (this._readied) { | |
callback.async(fn); | |
} else { | |
this.once('ready', fn); | |
} | |
} | |
return this; | |
}; | |
/** | |
* Set the `timeout` (in milliseconds) used for callbacks. | |
* | |
* @param {Number} timeout | |
*/ | |
Analytics.prototype.timeout = function(timeout) { | |
this._timeout = timeout; | |
}; | |
/** | |
* Enable or disable debug. | |
* | |
* @param {string|boolean} str | |
*/ | |
Analytics.prototype.debug = function(str){ | |
if (!arguments.length || str) { | |
debug.enable('analytics:' + (str || '*')); | |
} else { | |
debug.disable(); | |
} | |
}; | |
/** | |
* Apply options. | |
* | |
* @param {Object} options | |
* @return {Analytics} | |
* @api private | |
*/ | |
Analytics.prototype._options = function(options) { | |
options = options || {}; | |
this.options = options; | |
cookie.options(options.cookie); | |
store.options(options.localStorage); | |
user.options(options.user); | |
group.options(options.group); | |
return this; | |
}; | |
/** | |
* Callback a `fn` after our defined timeout period. | |
* | |
* @param {Function} fn | |
* @return {Analytics} | |
* @api private | |
*/ | |
Analytics.prototype._callback = function(fn) { | |
callback.async(fn, this._timeout); | |
return this; | |
}; | |
/** | |
* Call `method` with `facade` on all enabled integrations. | |
* | |
* @param {string} method | |
* @param {Facade} facade | |
* @return {Analytics} | |
* @api private | |
*/ | |
Analytics.prototype._invoke = function(method, facade) { | |
this.emit('invoke', facade); | |
each(this._integrations, function(name, integration) { | |
if (!facade.enabled(name)) return; | |
integration.invoke.call(integration, method, facade); | |
}); | |
return this; | |
}; | |
/** | |
* Push `args`. | |
* | |
* @param {Array} args | |
* @api private | |
*/ | |
Analytics.prototype.push = function(args){ | |
var method = args.shift(); | |
if (!this[method]) return; | |
this[method].apply(this, args); | |
}; | |
/** | |
* Reset group and user traits and id's. | |
* | |
* @api public | |
*/ | |
Analytics.prototype.reset = function(){ | |
this.user().logout(); | |
this.group().logout(); | |
}; | |
/** | |
* Parse the query string for callable methods. | |
* | |
* @return {Analytics} | |
* @api private | |
*/ | |
Analytics.prototype._parseQuery = function() { | |
// Identify and track any `ajs_uid` and `ajs_event` parameters in the URL. | |
var q = querystring.parse(window.location.search); | |
if (q.ajs_uid) this.identify(q.ajs_uid); | |
if (q.ajs_event) this.track(q.ajs_event); | |
if (q.ajs_aid) user.anonymousId(q.ajs_aid); | |
return this; | |
}; | |
/** | |
* Normalize the given `msg`. | |
* | |
* @param {Object} msg | |
* @return {Object} | |
*/ | |
Analytics.prototype.normalize = function(msg){ | |
msg = normalize(msg, keys(this._integrations)); | |
if (msg.anonymousId) user.anonymousId(msg.anonymousId); | |
msg.anonymousId = user.anonymousId(); | |
// Ensure all outgoing requests include page data in their contexts. | |
msg.context.page = defaults(msg.context.page || {}, pageDefaults()); | |
return msg; | |
}; | |
/** | |
* No conflict support. | |
*/ | |
Analytics.prototype.noConflict = function(){ | |
window.analytics = _analytics; | |
return this; | |
}; | |
}, {"emitter":8,"facade":9,"after":10,"bind":11,"callback":12,"clone":13,"./cookie":14,"debug":15,"defaults":16,"each":4,"./group":17,"is":18,"is-meta":19,"object":20,"./memory":21,"./normalize":22,"event":23,"./pageDefaults":24,"pick":25,"prevent":26,"querystring":27,"./store":28,"./user":29}], | |
8: [function(require, module, exports) { | |
/** | |
* Module dependencies. | |
*/ | |
var index = require('indexof'); | |
/** | |
* Expose `Emitter`. | |
*/ | |
module.exports = Emitter; | |
/** | |
* Initialize a new `Emitter`. | |
* | |
* @api public | |
*/ | |
function Emitter(obj) { | |
if (obj) return mixin(obj); | |
}; | |
/** | |
* Mixin the emitter properties. | |
* | |
* @param {Object} obj | |
* @return {Object} | |
* @api private | |
*/ | |
function mixin(obj) { | |
for (var key in Emitter.prototype) { | |
obj[key] = Emitter.prototype[key]; | |
} | |
return obj; | |
} | |
/** | |
* Listen on the given `event` with `fn`. | |
* | |
* @param {String} event | |
* @param {Function} fn | |
* @return {Emitter} | |
* @api public | |
*/ | |
Emitter.prototype.on = | |
Emitter.prototype.addEventListener = function(event, fn){ | |
this._callbacks = this._callbacks || {}; | |
(this._callbacks[event] = this._callbacks[event] || []) | |
.push(fn); | |
return this; | |
}; | |
/** | |
* Adds an `event` listener that will be invoked a single | |
* time then automatically removed. | |
* | |
* @param {String} event | |
* @param {Function} fn | |
* @return {Emitter} | |
* @api public | |
*/ | |
Emitter.prototype.once = function(event, fn){ | |
var self = this; | |
this._callbacks = this._callbacks || {}; | |
function on() { | |
self.off(event, on); | |
fn.apply(this, arguments); | |
} | |
fn._off = on; | |
this.on(event, on); | |
return this; | |
}; | |
/** | |
* Remove the given callback for `event` or all | |
* registered callbacks. | |
* | |
* @param {String} event | |
* @param {Function} fn | |
* @return {Emitter} | |
* @api public | |
*/ | |
Emitter.prototype.off = | |
Emitter.prototype.removeListener = | |
Emitter.prototype.removeAllListeners = | |
Emitter.prototype.removeEventListener = function(event, fn){ | |
this._callbacks = this._callbacks || {}; | |
// all | |
if (0 == arguments.length) { | |
this._callbacks = {}; | |
return this; | |
} | |
// specific event | |
var callbacks = this._callbacks[event]; | |
if (!callbacks) return this; | |
// remove all handlers | |
if (1 == arguments.length) { | |
delete this._callbacks[event]; | |
return this; | |
} | |
// remove specific handler | |
var i = index(callbacks, fn._off || fn); | |
if (~i) callbacks.splice(i, 1); | |
return this; | |
}; | |
/** | |
* Emit `event` with the given args. | |
* | |
* @param {String} event | |
* @param {Mixed} ... | |
* @return {Emitter} | |
*/ | |
Emitter.prototype.emit = function(event){ | |
this._callbacks = this._callbacks || {}; | |
var args = [].slice.call(arguments, 1) | |
, callbacks = this._callbacks[event]; | |
if (callbacks) { | |
callbacks = callbacks.slice(0); | |
for (var i = 0, len = callbacks.length; i < len; ++i) { | |
callbacks[i].apply(this, args); | |
} | |
} | |
return this; | |
}; | |
/** | |
* Return array of callbacks for `event`. | |
* | |
* @param {String} event | |
* @return {Array} | |
* @api public | |
*/ | |
Emitter.prototype.listeners = function(event){ | |
this._callbacks = this._callbacks || {}; | |
return this._callbacks[event] || []; | |
}; | |
/** | |
* Check if this emitter has `event` handlers. | |
* | |
* @param {String} event | |
* @return {Boolean} | |
* @api public | |
*/ | |
Emitter.prototype.hasListeners = function(event){ | |
return !! this.listeners(event).length; | |
}; | |
}, {"indexof":30}], | |
30: [function(require, module, exports) { | |
module.exports = function(arr, obj){ | |
if (arr.indexOf) return arr.indexOf(obj); | |
for (var i = 0; i < arr.length; ++i) { | |
if (arr[i] === obj) return i; | |
} | |
return -1; | |
}; | |
}, {}], | |
9: [function(require, module, exports) { | |
var Facade = require('./facade'); | |
/** | |
* Expose `Facade` facade. | |
*/ | |
module.exports = Facade; | |
/** | |
* Expose specific-method facades. | |
*/ | |
Facade.Alias = require('./alias'); | |
Facade.Group = require('./group'); | |
Facade.Identify = require('./identify'); | |
Facade.Track = require('./track'); | |
Facade.Page = require('./page'); | |
Facade.Screen = require('./screen'); | |
}, {"./facade":31,"./alias":32,"./group":33,"./identify":34,"./track":35,"./page":36,"./screen":37}], | |
31: [function(require, module, exports) { | |
var traverse = require('isodate-traverse'); | |
var isEnabled = require('./is-enabled'); | |
var clone = require('./utils').clone; | |
var type = require('./utils').type; | |
var address = require('./address'); | |
var objCase = require('obj-case'); | |
var newDate = require('new-date'); | |
/** | |
* Expose `Facade`. | |
*/ | |
module.exports = Facade; | |
/** | |
* Initialize a new `Facade` with an `obj` of arguments. | |
* | |
* @param {Object} obj | |
*/ | |
function Facade (obj) { | |
obj = clone(obj); | |
if (!obj.hasOwnProperty('timestamp')) obj.timestamp = new Date(); | |
else obj.timestamp = newDate(obj.timestamp); | |
traverse(obj); | |
this.obj = obj; | |
} | |
/** | |
* Mixin address traits. | |
*/ | |
address(Facade.prototype); | |
/** | |
* 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 | |
*/ | |
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 transform(obj); | |
obj = objCase(obj, fields.join('.')); | |
return transform(obj); | |
}; | |
/** | |
* Directly access a specific `field` from the underlying object, returning a | |
* clone so outsiders don't mess with stuff. | |
* | |
* @param {String} field | |
* @return {Mixed} | |
*/ | |
Facade.prototype.field = function (field) { | |
var obj = this.obj[field]; | |
return transform(obj); | |
}; | |
/** | |
* 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} | |
*/ | |
Facade.proxy = function (field) { | |
return function () { | |
return this.proxy(field); | |
}; | |
}; | |
/** | |
* Utility method to directly access a `field`. | |
* | |
* @param {String} field | |
* @return {Function} | |
*/ | |
Facade.field = function (field) { | |
return function () { | |
return this.field(field); | |
}; | |
}; | |
/** | |
* Proxy multiple `path`. | |
* | |
* @param {String} path | |
* @return {Array} | |
*/ | |
Facade.multi = function(path){ | |
return function(){ | |
var multi = this.proxy(path + 's'); | |
if ('array' == type(multi)) return multi; | |
var one = this.proxy(path); | |
if (one) one = [clone(one)]; | |
return one || []; | |
}; | |
}; | |
/** | |
* Proxy one `path`. | |
* | |
* @param {String} path | |
* @return {Mixed} | |
*/ | |
Facade.one = function(path){ | |
return function(){ | |
var one = this.proxy(path); | |
if (one) return one; | |
var multi = this.proxy(path + 's'); | |
if ('array' == type(multi)) return multi[0]; | |
}; | |
}; | |
/** | |
* Get the basic json object of this facade. | |
* | |
* @return {Object} | |
*/ | |
Facade.prototype.json = function () { | |
var ret = clone(this.obj); | |
if (this.type) ret.type = this.type(); | |
return ret; | |
}; | |
/** | |
* 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.context = | |
Facade.prototype.options = function (integration) { | |
var options = clone(this.obj.options || this.obj.context) || {}; | |
if (!integration) return clone(options); | |
if (!this.enabled(integration)) return; | |
var integrations = this.integrations(); | |
var value = integrations[integration] || objCase(integrations, integration); | |
if ('boolean' == typeof value) value = {}; | |
return value || {}; | |
}; | |
/** | |
* Check whether an integration is enabled. | |
* | |
* @param {String} integration | |
* @return {Boolean} | |
*/ | |
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 = this.proxy('integrations.all'); | |
if (typeof allEnabled !== 'boolean') allEnabled = true; | |
var enabled = allEnabled && isEnabled(integration); | |
var options = this.integrations(); | |
// 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; | |
}; | |
/** | |
* Get all `integration` options. | |
* | |
* @param {String} integration | |
* @return {Object} | |
* @api private | |
*/ | |
Facade.prototype.integrations = function(){ | |
return this.obj.integrations | |
|| this.proxy('options.providers') | |
|| this.options(); | |
}; | |
/** | |
* 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; | |
}; | |
/** | |
* Get `sessionId / anonymousId`. | |
* | |
* @return {Mixed} | |
* @api public | |
*/ | |
Facade.prototype.sessionId = | |
Facade.prototype.anonymousId = function(){ | |
return this.field('anonymousId') | |
|| this.field('sessionId'); | |
}; | |
/** | |
* Get `groupId` from `context.groupId`. | |
* | |
* @return {String} | |
* @api public | |
*/ | |
Facade.prototype.groupId = Facade.proxy('options.groupId'); | |
/** | |
* Get the call's "super properties" which are just traits that have been | |
* passed in as if from an identify call. | |
* | |
* @param {Object} aliases | |
* @return {Object} | |
*/ | |
Facade.prototype.traits = function (aliases) { | |
var ret = this.proxy('options.traits') || {}; | |
var id = this.userId(); | |
aliases = aliases || {}; | |
if (id) ret.id = id; | |
for (var alias in aliases) { | |
var value = null == this[alias] | |
? this.proxy('options.traits.' + alias) | |
: this[alias](); | |
if (null == value) continue; | |
ret[aliases[alias]] = value; | |
delete ret[alias]; | |
} | |
return ret; | |
}; | |
/** | |
* Add a convenient way to get the library name and version | |
*/ | |
Facade.prototype.library = function(){ | |
var library = this.proxy('options.library'); | |
if (!library) return { name: 'unknown', version: null }; | |
if (typeof library === 'string') return { name: library, version: null }; | |
return library; | |
}; | |
/** | |
* Setup some basic proxies. | |
*/ | |
Facade.prototype.userId = Facade.field('userId'); | |
Facade.prototype.channel = Facade.field('channel'); | |
Facade.prototype.timestamp = Facade.field('timestamp'); | |
Facade.prototype.userAgent = Facade.proxy('options.userAgent'); | |
Facade.prototype.ip = Facade.proxy('options.ip'); | |
/** | |
* Return the cloned and traversed object | |
* | |
* @param {Mixed} obj | |
* @return {Mixed} | |
*/ | |
function transform(obj){ | |
var cloned = clone(obj); | |
return cloned; | |
} | |
}, {"isodate-traverse":38,"./is-enabled":39,"./utils":40,"./address":41,"obj-case":42,"new-date":43}], | |
38: [function(require, module, exports) { | |
var is = require('is'); | |
var isodate = require('isodate'); | |
var each; | |
try { | |
each = require('each'); | |
} catch (err) { | |
each = require('each-component'); | |
} | |
/** | |
* Expose `traverse`. | |
*/ | |
module.exports = traverse; | |
/** | |
* Traverse an object or array, and return a clone with all ISO strings parsed | |
* into Date objects. | |
* | |
* @param {Object} obj | |
* @return {Object} | |
*/ | |
function traverse (input, strict) { | |
if (strict === undefined) strict = true; | |
if (is.object(input)) return object(input, strict); | |
if (is.array(input)) return array(input, strict); | |
return input; | |
} | |
/** | |
* Object traverser. | |
* | |
* @param {Object} obj | |
* @param {Boolean} strict | |
* @return {Object} | |
*/ | |
function object (obj, strict) { | |
each(obj, function (key, val) { | |
if (isodate.is(val, strict)) { | |
obj[key] = isodate.parse(val); | |
} else if (is.object(val) || is.array(val)) { | |
traverse(val, strict); | |
} | |
}); | |
return obj; | |
} | |
/** | |
* Array traverser. | |
* | |
* @param {Array} arr | |
* @param {Boolean} strict | |
* @return {Array} | |
*/ | |
function array (arr, strict) { | |
each(arr, function (val, x) { | |
if (is.object(val)) { | |
traverse(val, strict); | |
} else if (isodate.is(val, strict)) { | |
arr[x] = isodate.parse(val); | |
} | |
}); | |
return arr; | |
} | |
}, {"is":44,"isodate":45,"each":4}], | |
44: [function(require, module, exports) { | |
var isEmpty = require('is-empty'); | |
try { | |
var typeOf = require('type'); | |
} catch (e) { | |
var typeOf = require('component-type'); | |
} | |
/** | |
* Types. | |
*/ | |
var types = [ | |
'arguments', | |
'array', | |
'boolean', | |
'date', | |
'element', | |
'function', | |
'null', | |
'number', | |
'object', | |
'regexp', | |
'string', | |
'undefined' | |
]; | |
/** | |
* Expose type checkers. | |
* | |
* @param {Mixed} value | |
* @return {Boolean} | |
*/ | |
for (var i = 0, type; type = types[i]; i++) exports[type] = generate(type); | |
/** | |
* Add alias for `function` for old browsers. | |
*/ | |
exports.fn = exports['function']; | |
/** | |
* Expose `empty` check. | |
*/ | |
exports.empty = isEmpty; | |
/** | |
* Expose `nan` check. | |
*/ | |
exports.nan = function (val) { | |
return exports.number(val) && val != val; | |
}; | |
/** | |
* Generate a type checker. | |
* | |
* @param {String} type | |
* @return {Function} | |
*/ | |
function generate (type) { | |
return function (value) { | |
return type === typeOf(value); | |
}; | |
} | |
}, {"is-empty":46,"type":47,"component-type":47}], | |
46: [function(require, module, exports) { | |
/** | |
* Expose `isEmpty`. | |
*/ | |
module.exports = isEmpty; | |
/** | |
* Has. | |
*/ | |
var has = Object.prototype.hasOwnProperty; | |
/** | |
* Test whether a value is "empty". | |
* | |
* @param {Mixed} val | |
* @return {Boolean} | |
*/ | |
function isEmpty (val) { | |
if (null == val) return true; | |
if ('number' == typeof val) return 0 === val; | |
if (undefined !== val.length) return 0 === val.length; | |
for (var key in val) if (has.call(val, key)) return false; | |
return true; | |
} | |
}, {}], | |
47: [function(require, module, exports) { | |
/** | |
* toString ref. | |
*/ | |
var toString = Object.prototype.toString; | |
/** | |
* Return the type of `val`. | |
* | |
* @param {Mixed} val | |
* @return {String} | |
* @api public | |
*/ | |
module.exports = function(val){ | |
switch (toString.call(val)) { | |
case '[object Date]': return 'date'; | |
case '[object RegExp]': return 'regexp'; | |
case '[object Arguments]': return 'arguments'; | |
case '[object Array]': return 'array'; | |
case '[object Error]': return 'error'; | |
} | |
if (val === null) return 'null'; | |
if (val === undefined) return 'undefined'; | |
if (val !== val) return 'nan'; | |
if (val && val.nodeType === 1) return 'element'; | |
val = val.valueOf | |
? val.valueOf() | |
: Object.prototype.valueOf.apply(val) | |
return typeof val; | |
}; | |
}, {}], | |
45: [function(require, module, exports) { | |
/** | |
* 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}))?)?)?$/; | |
/** | |
* 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} | |
*/ | |
exports.parse = function (iso) { | |
var numericKeys = [1, 5, 6, 7, 11, 12]; | |
var arr = matcher.exec(iso); | |
var offset = 0; | |
// fallback to native parsing | |
if (!arr) return new Date(iso); | |
// 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; | |
// month is 0-11 | |
arr[2]--; | |
// allow abitrary sub-second precision | |
arr[8] = arr[8] | |
? (arr[8] + '00').substring(0, 3) | |
: 0; | |
// 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); | |
}; | |
/** | |
* 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} | |
*/ | |
exports.is = function (string, strict) { | |
if (strict && false === /^\d{4}-\d{2}-\d{2}/.test(string)) return false; | |
return matcher.test(string); | |
}; | |
}, {}], | |
4: [function(require, module, exports) { | |
/** | |
* Module dependencies. | |
*/ | |
var type = require('type'); | |
/** | |
* HOP reference. | |
*/ | |
var has = Object.prototype.hasOwnProperty; | |
/** | |
* Iterate the given `obj` and invoke `fn(val, i)`. | |
* | |
* @param {String|Array|Object} obj | |
* @param {Function} fn | |
* @api public | |
*/ | |
module.exports = function(obj, fn){ | |
switch (type(obj)) { | |
case 'array': | |
return array(obj, fn); | |
case 'object': | |
if ('number' == typeof obj.length) return array(obj, fn); | |
return object(obj, fn); | |
case 'string': | |
return string(obj, fn); | |
} | |
}; | |
/** | |
* Iterate string chars. | |
* | |
* @param {String} obj | |
* @param {Function} fn | |
* @api private | |
*/ | |
function string(obj, fn) { | |
for (var i = 0; i < obj.length; ++i) { | |
fn(obj.charAt(i), i); | |
} | |
} | |
/** | |
* Iterate object keys. | |
* | |
* @param {Object} obj | |
* @param {Function} fn | |
* @api private | |
*/ | |
function object(obj, fn) { | |
for (var key in obj) { | |
if (has.call(obj, key)) { | |
fn(key, obj[key]); | |
} | |
} | |
} | |
/** | |
* Iterate array-ish. | |
* | |
* @param {Array|Object} obj | |
* @param {Function} fn | |
* @api private | |
*/ | |
function array(obj, fn) { | |
for (var i = 0; i < obj.length; ++i) { | |
fn(obj[i], i); | |
} | |
} | |
}, {"type":47}], | |
39: [function(require, module, exports) { | |
/** | |
* A few integrations are disabled by default. They must be explicitly | |
* enabled by setting options[Provider] = true. | |
*/ | |
var disabled = { | |
Salesforce: true | |
}; | |
/** | |
* Check whether an integration should be enabled by default. | |
* | |
* @param {String} integration | |
* @return {Boolean} | |
*/ | |
module.exports = function (integration) { | |
return ! disabled[integration]; | |
}; | |
}, {}], | |
40: [function(require, module, exports) { | |
/** | |
* TODO: use component symlink, everywhere ? | |
*/ | |
try { | |
exports.inherit = require('inherit'); | |
exports.clone = require('clone'); | |
exports.type = require('type'); | |
} catch (e) { | |
exports.inherit = require('inherit-component'); | |
exports.clone = require('clone-component'); | |
exports.type = require('type-component'); | |
} | |
}, {"inherit":48,"clone":49,"type":47}], | |
48: [function(require, module, exports) { | |
module.exports = function(a, b){ | |
var fn = function(){}; | |
fn.prototype = b.prototype; | |
a.prototype = new fn; | |
a.prototype.constructor = a; | |
}; | |
}, {}], | |
49: [function(require, module, exports) { | |
/** | |
* Module dependencies. | |
*/ | |
var type; | |
try { | |
type = require('component-type'); | |
} catch (_) { | |
type = require('type'); | |
} | |
/** | |
* Module exports. | |
*/ | |
module.exports = clone; | |
/** | |
* Clones objects. | |
* | |
* @param {Mixed} any object | |
* @api public | |
*/ | |
function clone(obj){ | |
switch (type(obj)) { | |
case 'object': | |
var copy = {}; | |
for (var key in obj) { | |
if (obj.hasOwnProperty(key)) { | |
copy[key] = clone(obj[key]); | |
} | |
} | |
return copy; | |
case 'array': | |
var copy = new Array(obj.length); | |
for (var i = 0, l = obj.length; i < l; i++) { | |
copy[i] = clone(obj[i]); | |
} | |
return copy; | |
case 'regexp': | |
// from millermedeiros/amd-utils - MIT | |
var flags = ''; | |
flags += obj.multiline ? 'm' : ''; | |
flags += obj.global ? 'g' : ''; | |
flags += obj.ignoreCase ? 'i' : ''; | |
return new RegExp(obj.source, flags); | |
case 'date': | |
return new Date(obj.getTime()); | |
default: // string, number, boolean, … | |
return obj; | |
} | |
} | |
}, {"component-type":47,"type":47}], | |
41: [function(require, module, exports) { | |
/** | |
* Module dependencies. | |
*/ | |
var get = require('obj-case'); | |
/** | |
* Add address getters to `proto`. | |
* | |
* @param {Function} proto | |
*/ | |
module.exports = function(proto){ | |
proto.zip = trait('postalCode', 'zip'); | |
proto.country = trait('country'); | |
proto.street = trait('street'); | |
proto.state = trait('state'); | |
proto.city = trait('city'); | |
function trait(a, b){ | |
return function(){ | |
var traits = this.traits(); | |
var props = this.properties ? this.properties() : {}; | |
return get(traits, 'address.' + a) | |
|| get(traits, a) | |
|| (b ? get(traits, 'address.' + b) : null) | |
|| (b ? get(traits, b) : null) | |
|| get(props, 'address.' + a) | |
|| get(props, a) | |
|| (b ? get(props, 'address.' + b) : null) | |
|| (b ? get(props, b) : null); | |
}; | |
} | |
}; | |
}, {"obj-case":42}], | |
42: [function(require, module, exports) { | |
var identity = function(_){ return _; }; | |
/** | |
* Module exports, export | |
*/ | |
module.exports = multiple(find); | |
module.exports.find = module.exports; | |
/** | |
* Export the replacement function, return the modified object | |
*/ | |
module.exports.replace = function (obj, key, val, options) { | |
multiple(replace).call(this, obj, key, val, options); | |
return obj; | |
}; | |
/** | |
* Export the delete function, return the modified object | |
*/ | |
module.exports.del = function (obj, key, options) { | |
multiple(del).call(this, obj, key, null, options); | |
return obj; | |
}; | |
/** | |
* Compose applying the function to a nested key | |
*/ | |
function multiple (fn) { | |
return function (obj, path, val, options) { | |
var normalize = options && isFunction(options.normalizer) ? options.normalizer : defaultNormalize; | |
path = normalize(path); | |
var key; | |
var finished = false; | |
while (!finished) loop(); | |
function loop() { | |
for (key in obj) { | |
var normalizedKey = normalize(key); | |
if (0 === path.indexOf(normalizedKey)) { | |
var temp = path.substr(normalizedKey.length); | |
if (temp.charAt(0) === '.' || temp.length === 0) { | |
path = temp.substr(1); | |
var child = obj[key]; | |
// we're at the end and there is nothing. | |
if (null == child) { | |
finished = true; | |
return; | |
} | |
// we're at the end and there is something. | |
if (!path.length) { | |
finished = true; | |
return; | |
} | |
// step into child | |
obj = child; | |
// but we're done here | |
return; | |
} | |
} | |
} | |
key = undefined; | |
// if we found no matching properties | |
// on the current object, there's no match. | |
finished = true; | |
} | |
if (!key) return; | |
if (null == obj) return obj; | |
// the `obj` and `key` is one above the leaf object and key, so | |
// start object: { a: { 'b.c': 10 } } | |
// end object: { 'b.c': 10 } | |
// end key: 'b.c' | |
// this way, you can do `obj[key]` and get `10`. | |
return fn(obj, key, val); | |
}; | |
} | |
/** | |
* Find an object by its key | |
* | |
* find({ first_name : 'Calvin' }, 'firstName') | |
*/ | |
function find (obj, key) { | |
if (obj.hasOwnProperty(key)) return obj[key]; | |
} | |
/** | |
* Delete a value for a given key | |
* | |
* del({ a : 'b', x : 'y' }, 'X' }) -> { a : 'b' } | |
*/ | |
function del (obj, key) { | |
if (obj.hasOwnProperty(key)) delete obj[key]; | |
return obj; | |
} | |
/** | |
* Replace an objects existing value with a new one | |
* | |
* replace({ a : 'b' }, 'a', 'c') -> { a : 'c' } | |
*/ | |
function replace (obj, key, val) { | |
if (obj.hasOwnProperty(key)) obj[key] = val; | |
return obj; | |
} | |
/** | |
* Normalize a `dot.separated.path`. | |
* | |
* A.HELL(!*&#(!)O_WOR LD.bar => ahelloworldbar | |
* | |
* @param {String} path | |
* @return {String} | |
*/ | |
function defaultNormalize(path) { | |
return path.replace(/[^a-zA-Z0-9\.]+/g, '').toLowerCase(); | |
} | |
/** | |
* Check if a value is a function. | |
* | |
* @param {*} val | |
* @return {boolean} Returns `true` if `val` is a function, otherwise `false`. | |
*/ | |
function isFunction(val) { | |
return typeof val === 'function'; | |
} | |
}, {}], | |
43: [function(require, module, exports) { | |
var is = require('is'); | |
var isodate = require('isodate'); | |
var milliseconds = require('./milliseconds'); | |
var seconds = require('./seconds'); | |
/** | |
* Returns a new Javascript Date object, allowing a variety of extra input types | |
* over the native Date constructor. | |
* | |
* @param {Date|String|Number} val | |
*/ | |
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); | |
}; | |
/** | |
* If the number passed val is seconds from the epoch, turn it into milliseconds. | |
* Milliseconds would be greater than 31557600000 (December 31, 1970). | |
* | |
* @param {Number} num | |
*/ | |
function toMs (num) { | |
if (num < 31557600000) return num * 1000; | |
return num; | |
} | |
}, {"is":50,"isodate":45,"./milliseconds":51,"./seconds":52}], | |
50: [function(require, module, exports) { | |
var isEmpty = require('is-empty') | |
, typeOf = require('type'); | |
/** | |
* Types. | |
*/ | |
var types = [ | |
'arguments', | |
'array', | |
'boolean', | |
'date', | |
'element', | |
'function', | |
'null', | |
'number', | |
'object', | |
'regexp', | |
'string', | |
'undefined' | |
]; | |
/** | |
* Expose type checkers. | |
* | |
* @param {Mixed} value | |
* @return {Boolean} | |
*/ | |
for (var i = 0, type; type = types[i]; i++) exports[type] = generate(type); | |
/** | |
* Add alias for `function` for old browsers. | |
*/ | |
exports.fn = exports['function']; | |
/** | |
* Expose `empty` check. | |
*/ | |
exports.empty = isEmpty; | |
/** | |
* Expose `nan` check. | |
*/ | |
exports.nan = function (val) { | |
return exports.number(val) && val != val; | |
}; | |
/** | |
* Generate a type checker. | |
* | |
* @param {String} type | |
* @return {Function} | |
*/ | |
function generate (type) { | |
return function (value) { | |
return type === typeOf(value); | |
}; | |
} | |
}, {"is-empty":46,"type":47}], | |
51: [function(require, module, exports) { | |
/** | |
* Matcher. | |
*/ | |
var matcher = /\d{13}/; | |
/** | |
* Check whether a string is a millisecond date string. | |
* | |
* @param {String} string | |
* @return {Boolean} | |
*/ | |
exports.is = function (string) { | |
return matcher.test(string); | |
}; | |
/** | |
* Convert a millisecond string to a date. | |
* | |
* @param {String} millis | |
* @return {Date} | |
*/ | |
exports.parse = function (millis) { | |
millis = parseInt(millis, 10); | |
return new Date(millis); | |
}; | |
}, {}], | |
52: [function(require, module, exports) { | |
/** | |
* Matcher. | |
*/ | |
var matcher = /\d{10}/; | |
/** | |
* Check whether a string is a second date string. | |
* | |
* @param {String} string | |
* @return {Boolean} | |
*/ | |
exports.is = function (string) { | |
return matcher.test(string); | |
}; | |
/** | |
* Convert a second string to a date. | |
* | |
* @param {String} seconds | |
* @return {Date} | |
*/ | |
exports.parse = function (seconds) { | |
var millis = parseInt(seconds, 10) * 1000; | |
return new Date(millis); | |
}; | |
}, {}], | |
32: [function(require, module, exports) { | |
/** | |
* Module dependencies. | |
*/ | |
var inherit = require('./utils').inherit; | |
var Facade = require('./facade'); | |
/** | |
* Expose `Alias` facade. | |
*/ | |
module.exports = Alias; | |
/** | |
* Initialize a new `Alias` facade with a `dictionary` of arguments. | |
* | |
* @param {Object} dictionary | |
* @property {String} from | |
* @property {String} to | |
* @property {Object} options | |
*/ | |
function Alias (dictionary) { | |
Facade.call(this, dictionary); | |
} | |
/** | |
* Inherit from `Facade`. | |
*/ | |
inherit(Alias, Facade); | |
/** | |
* Return type of facade. | |
* | |
* @return {String} | |
*/ | |
Alias.prototype.type = | |
Alias.prototype.action = function () { | |
return 'alias'; | |
}; | |
/** | |
* Get `previousId`. | |
* | |
* @return {Mixed} | |
* @api public | |
*/ | |
Alias.prototype.from = | |
Alias.prototype.previousId = function(){ | |
return this.field('previousId') | |
|| this.field('from'); | |
}; | |
/** | |
* Get `userId`. | |
* | |
* @return {String} | |
* @api public | |
*/ | |
Alias.prototype.to = | |
Alias.prototype.userId = function(){ | |
return this.field('userId') | |
|| this.field('to'); | |
}; | |
}, {"./utils":40,"./facade":31}], | |
33: [function(require, module, exports) { | |
/** | |
* Module dependencies. | |
*/ | |
var inherit = require('./utils').inherit; | |
var address = require('./address'); | |
var isEmail = require('is-email'); | |
var newDate = require('new-date'); | |
var Facade = require('./facade'); | |
/** | |
* Expose `Group` facade. | |
*/ | |
module.exports = Group; | |
/** | |
* 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 | |
*/ | |
function Group (dictionary) { | |
Facade.call(this, dictionary); | |
} | |
/** | |
* Inherit from `Facade` | |
*/ | |
inherit(Group, Facade); | |
/** | |
* Get the facade's action. | |
*/ | |
Group.prototype.type = | |
Group.prototype.action = function () { | |
return 'group'; | |
}; | |
/** | |
* Setup some basic proxies. | |
*/ | |
Group.prototype.groupId = Facade.field('groupId'); | |
/** | |
* Get created or createdAt. | |
* | |
* @return {Date} | |
*/ | |
Group.prototype.created = function(){ | |
var created = this.proxy('traits.createdAt') | |
|| this.proxy('traits.created') | |
|| this.proxy('properties.createdAt') | |
|| this.proxy('properties.created'); | |
if (created) return newDate(created); | |
}; | |
/** | |
* Get the group's email, falling back to the group ID if it's a valid email. | |
* | |
* @return {String} | |
*/ | |
Group.prototype.email = function () { | |
var email = this.proxy('traits.email'); | |
if (email) return email; | |
var groupId = this.groupId(); | |
if (isEmail(groupId)) return groupId; | |
}; | |
/** | |
* 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; | |
}; | |
/** | |
* Special traits. | |
*/ | |
Group.prototype.name = Facade.proxy('traits.name'); | |
Group.prototype.industry = Facade.proxy('traits.industry'); | |
Group.prototype.employees = Facade.proxy('traits.employees'); | |
/** | |
* Get traits or properties. | |
* | |
* TODO: remove me | |
* | |
* @return {Object} | |
*/ | |
Group.prototype.properties = function(){ | |
return this.field('traits') | |
|| this.field('properties') | |
|| {}; | |
}; | |
}, {"./utils":40,"./address":41,"is-email":53,"new-date":43,"./facade":31}], | |
53: [function(require, module, exports) { | |
/** | |
* Expose `isEmail`. | |
*/ | |
module.exports = isEmail; | |
/** | |
* Email address matcher. | |
*/ | |
var matcher = /.+\@.+\..+/; | |
/** | |
* Loosely validate an email address. | |
* | |
* @param {String} string | |
* @return {Boolean} | |
*/ | |
function isEmail (string) { | |
return matcher.test(string); | |
} | |
}, {}], | |
34: [function(require, module, exports) { | |
var address = require('./address'); | |
var Facade = require('./facade'); | |
var isEmail = require('is-email'); | |
var newDate = require('new-date'); | |
var utils = require('./utils'); | |
var get = require('obj-case'); | |
var trim = require('trim'); | |
var inherit = utils.inherit; | |
var clone = utils.clone; | |
var type = utils.type; | |
/** | |
* Expose `Idenfity` facade. | |
*/ | |
module.exports = Identify; | |
/** | |
* 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); | |
} | |
/** | |
* Inherit from `Facade`. | |
*/ | |
inherit(Identify, Facade); | |
/** | |
* Get the facade's action. | |
*/ | |
Identify.prototype.type = | |
Identify.prototype.action = function () { | |
return 'identify'; | |
}; | |
/** | |
* 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 || {}; | |
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; | |
if (alias !== aliases[alias]) delete ret[alias]; | |
} | |
return ret; | |
}; | |
/** | |
* 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 userId = this.userId(); | |
if (isEmail(userId)) return userId; | |
}; | |
/** | |
* Get the user's created date, optionally looking for `createdAt` since lots of | |
* people do that instead. | |
* | |
* @return {Date or Undefined} | |
*/ | |
Identify.prototype.created = function () { | |
var created = this.proxy('traits.created') || this.proxy('traits.createdAt'); | |
if (created) return newDate(created); | |
}; | |
/** | |
* Get the company created date. | |
* | |
* @return {Date or undefined} | |
*/ | |
Identify.prototype.companyCreated = function(){ | |
var created = this.proxy('traits.company.created') | |
|| this.proxy('traits.company.createdAt'); | |
if (created) return newDate(created); | |
}; | |
/** | |
* Get the user's name, optionally combining a first and last name if that's all | |
* that was provided. | |
* | |
* @return {String or Undefined} | |
*/ | |
Identify.prototype.name = function () { | |
var name = this.proxy('traits.name'); | |
if (typeof name === 'string') return trim(name); | |
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. | |
* | |
* @return {String or Undefined} | |
*/ | |
Identify.prototype.firstName = function () { | |
var firstName = this.proxy('traits.firstName'); | |
if (typeof firstName === 'string') return trim(firstName); | |
var name = this.proxy('traits.name'); | |
if (typeof name === 'string') return trim(name).split(' ')[0]; | |
}; | |
/** | |
* 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} | |
*/ | |
Identify.prototype.lastName = function () { | |
var lastName = this.proxy('traits.lastName'); | |
if (typeof lastName === 'string') return trim(lastName); | |
var name = this.proxy('traits.name'); | |