From a6874a580520a696b24384a9afde0616d13de411 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Tue, 15 Mar 2016 16:53:58 -0600 Subject: [PATCH 01/10] Use js-cookie instead of cookies-js. o_O --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5b723e7..fa316e4 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "component-emitter": "^1.2.0", - "cookies-js": "^1.2.1", + "js-cookie": "2.1.0", "json3": "^3.3.2" }, "devDependencies": { From b0bd0fd223443d01b43c89766e96c45a77e877c7 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Tue, 15 Mar 2016 17:31:16 -0600 Subject: [PATCH 02/10] Update cookie.js to use js-cookie lib --- lib/utils/cookie.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/utils/cookie.js b/lib/utils/cookie.js index 457ea09..4d942aa 100644 --- a/lib/utils/cookie.js +++ b/lib/utils/cookie.js @@ -1,4 +1,4 @@ -var Cookies = require('cookies-js'); +var Cookies = require('js-cookie'); var json = require('./json'); var extend = require('./extend'); @@ -15,6 +15,7 @@ function cookie(str){ options: {} }; this.data = this.get(); + this.enabled = true; return this; } @@ -22,7 +23,7 @@ cookie.prototype.get = function(str){ var data = {}; if (Cookies.get(this.config.key)) { - data = json.parse( decodeURIComponent(Cookies.get(this.config.key)) ); + data = json.parse(Cookies.get(this.config.key)); } if (str) { return ('undefined' !== typeof data[str]) ? data[str] : null; @@ -33,19 +34,19 @@ cookie.prototype.get = function(str){ }; cookie.prototype.set = function(str, value){ - if (!arguments.length || !this.enabled()) return this; + if (!arguments.length || !this.enabled) return this; if ('string' === typeof str && arguments.length === 2) { this.data[str] = value ? value : null; } else if ('object' === typeof str && arguments.length === 1) { extend(this.data, str); } - Cookies.set(this.config.key, encodeURIComponent( json.stringify(this.data) ), this.config.options); + Cookies.set(this.config.key, this.data, this.config.options); return this; }; cookie.prototype.expire = function(){ - Cookies.expire(this.config.key); + Cookies.remove(this.config.key); this.data = {}; return this; }; @@ -54,8 +55,4 @@ cookie.prototype.options = function(obj){ if (!arguments.length) return this.config.options; this.config.options = (typeof obj === 'object') ? obj : {}; return this; -}; - -cookie.prototype.enabled = function(){ - return Cookies.enabled; -}; +}; \ No newline at end of file From 5268e9a9d6083166307136a6902a9a1fb925e49a Mon Sep 17 00:00:00 2001 From: aroc Date: Thu, 24 Mar 2016 12:12:32 -0600 Subject: [PATCH 03/10] Remove sourcemap file. --- .gitignore | 1 + dist/keen-tracking.js | 1985 ------------------------------------- dist/keen-tracking.js.map | 1 - 3 files changed, 1 insertion(+), 1986 deletions(-) delete mode 100644 dist/keen-tracking.js delete mode 100644 dist/keen-tracking.js.map diff --git a/.gitignore b/.gitignore index 8325737..cda9841 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ bower_components node_modules test/unit/build/* .awspublish-keen-js +dist/keen-tracking.js.map \ No newline at end of file diff --git a/dist/keen-tracking.js b/dist/keen-tracking.js deleted file mode 100644 index faae03c..0000000 --- a/dist/keen-tracking.js +++ /dev/null @@ -1,1985 +0,0 @@ -(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o or
DOM element'); - } - if (timeoutCallback) { - callback = function(){ - if(!triggered){ - triggered = true; - timeoutCallback(); - } - }; - } - this.recordEvent(eventCollection, payload, callback); - setTimeout(callback, timer); - if (!evt.metaKey) { - return false; - } - } - if (!Array.prototype.indexOf){ - Array.prototype.indexOf = function(elt /*, from*/) { - var len = this.length >>> 0; - var from = Number(arguments[1]) || 0; - from = (from < 0) - ? Math.ceil(from) - : Math.floor(from); - if (from < 0) - from += len; - for (; from < len; from++) { - if (from in this && - this[from] === elt) - return from; - } - return -1; - }; - } - module.exports = Keen; - return Keen; -}); -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./":10,"./defer-events":2,"./extend-events":3,"./helpers/getBrowserProfile":4,"./helpers/getDatetimeIndex":5,"./helpers/getDomNodePath":6,"./helpers/getScreenProfile":7,"./helpers/getUniqueId":8,"./helpers/getWindowProfile":9,"./record-events-browser":11,"./utils/cookie":13,"./utils/deepExtend":14,"./utils/each":15,"./utils/extend":16,"./utils/listener":18,"./utils/parseParams":19,"./utils/timer":21}],2:[function(require,module,exports){ -var Keen = require('./index'); -var each = require('./utils/each'); -var queue = require('./utils/queue'); -module.exports = { - 'deferEvent': deferEvent, - 'deferEvents': deferEvents, - 'queueCapacity': queueCapacity, - 'queueInterval': queueInterval, - 'recordDeferredEvents': recordDeferredEvents -}; -function deferEvent(eventCollection, eventBody){ - if (arguments.length !== 2 || typeof eventCollection !== 'string') { - handleValidationError.call(this, 'Incorrect arguments provided to #deferEvent method'); - return; - } - this.queue.events[eventCollection] = this.queue.events[eventCollection] || []; - this.queue.events[eventCollection].push(eventBody); - this.queue.capacity++; - this.emit('deferEvent', eventCollection, eventBody); - return this; -} -function deferEvents(eventsHash){ - var self = this; - if (arguments.length !== 1 || typeof eventsHash !== 'object') { - handleValidationError.call(this, 'Incorrect arguments provided to #deferEvents method'); - return; - } - each(eventsHash, function(eventList, eventCollection){ - self.queue.events[eventCollection] = self.queue.events[eventCollection] || []; - self.queue.events[eventCollection] = self.queue.events[eventCollection].concat(eventList); - self.queue.capacity = self.queue.capacity + eventList.length; - }); - self.emit('deferEvents', eventsHash); - return self; -} -function queueCapacity(num){ - if (!arguments.length) return this.queue.config.capacity; - this.queue.config.capacity = num ? Number(num): 0; - return this; -} -function queueInterval(num){ - if (!arguments.length) return this.queue.config.interval; - this.queue.config.interval = num ? Number(num): 0; - return this; -} -function recordDeferredEvents(){ - var self = this, currentQueue; - if (self.queue.capacity > 0) { - currentQueue = JSON.parse(JSON.stringify(self.queue)); - self.queue = queue(); - self.queue.options = currentQueue.options; - self.emit('recordDeferredEvents', currentQueue.events); - self.recordEvents(currentQueue.events, function(err, res){ - if (err) { - self.recordEvents(currentQueue.events); - } - else { - currentQueue = void 0; - } - }); - } - return self; -} -function handleValidationError(message){ - var err = 'Event(s) not deferred: ' + message; - this.emit('error', err); -} -},{"./index":10,"./utils/each":15,"./utils/queue":20}],3:[function(require,module,exports){ -var deepExtend = require('./utils/deepExtend'); -var each = require('./utils/each'); -module.exports = { - 'extendEvent': extendEvent, - 'extendEvents': extendEvents, - 'getExtendedEventBody': getExtendedEventBody -}; -function extendEvent(eventCollection, eventModifier){ - if (arguments.length !== 2 || typeof eventCollection !== 'string' - || ('object' !== typeof eventModifier && 'function' !== typeof eventModifier)) { - handleValidationError.call(this, 'Incorrect arguments provided to #extendEvent method'); - return; - } - this.extensions.collections[eventCollection] = this.extensions.collections[eventCollection] || []; - this.extensions.collections[eventCollection].push(eventModifier); - this.emit('extendEvent', eventCollection, eventModifier); - return this; -} -function extendEvents(eventsModifier){ - if (arguments.length !== 1 || ('object' !== typeof eventsModifier && 'function' !== typeof eventsModifier)) { - handleValidationError.call(this, 'Incorrect arguments provided to #extendEvents method'); - return; - } - this.extensions.events.push(eventsModifier); - this.emit('extendEvents', eventsModifier); - return this; -} -function handleValidationError(message){ - var err = 'Event(s) not extended: ' + message; - this.emit('error', err); -} -function getExtendedEventBody(result, queue){ - if (queue && queue.length > 0) { - each(queue, function(eventModifier, i){ - var modifierResult = (typeof eventModifier === 'function') ? eventModifier() : eventModifier; - deepExtend(result, modifierResult); - }); - } - return result; -} -},{"./utils/deepExtend":14,"./utils/each":15}],4:[function(require,module,exports){ -var getScreenProfile = require('./getScreenProfile'), - getWindowProfile = require('./getWindowProfile'); -function getBrowserProfile(){ - return { - 'cookies' : ('undefined' !== typeof navigator.cookieEnabled) ? navigator.cookieEnabled : false, - 'codeName' : navigator.appCodeName, - 'language' : navigator.language, - 'name' : navigator.appName, - 'online' : navigator.onLine, - 'platform' : navigator.platform, - 'useragent': navigator.userAgent, - 'version' : navigator.appVersion, - 'screen' : getScreenProfile(), - 'window' : getWindowProfile() - } -} -module.exports = getBrowserProfile; -},{"./getScreenProfile":7,"./getWindowProfile":9}],5:[function(require,module,exports){ -function getDateTimeIndex(input){ - var date = input || new Date(); - return { - 'hour_of_day' : date.getHours(), - 'day_of_week' : parseInt( 1 + date.getDay() ), - 'day_of_month' : date.getDate(), - 'month' : parseInt( 1 + date.getMonth() ), - 'year' : date.getFullYear() - }; -} -module.exports = getDateTimeIndex; -},{}],6:[function(require,module,exports){ -function getDomNodePath(el){ - if (!el.nodeName) return ''; - var stack = []; - while ( el.parentNode != null ) { - var sibCount = 0; - var sibIndex = 0; - for ( var i = 0; i < el.parentNode.childNodes.length; i++ ) { - var sib = el.parentNode.childNodes[i]; - if ( sib.nodeName == el.nodeName ) { - if ( sib === el ) { - sibIndex = sibCount; - } - sibCount++; - } - } - if ( el.hasAttribute('id') && el.id != '' ) { - stack.unshift(el.nodeName.toLowerCase() + '#' + el.id); - } else if ( sibCount > 1 ) { - stack.unshift(el.nodeName.toLowerCase() + ':eq(' + sibIndex + ')'); - } else { - stack.unshift(el.nodeName.toLowerCase()); - } - el = el.parentNode; - } - return stack.slice(1).join(' > '); -} -module.exports = getDomNodePath; -},{}],7:[function(require,module,exports){ -function getScreenProfile(){ - var keys, output; - if ('undefined' == typeof window || !window.screen) return {}; - keys = ['height', 'width', 'colorDepth', 'pixelDepth', 'availHeight', 'availWidth']; - output = {}; - for (var i = 0; i < keys.length; i++) { - output[keys[i]] = window.screen[keys[i]] ? window.screen[keys[i]] : null; - } - output.orientation = { - 'angle' : window.screen.orientation ? window.screen.orientation['angle'] : 0, - 'type' : window.innerWidth > window.innerHeight ? 'landscape': 'portrait' - }; - return output; -} -module.exports = getScreenProfile; -},{}],8:[function(require,module,exports){ -function getUniqueId(){ - var str = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'; - return str.replace(/[xy]/g, function(c) { - var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); - return v.toString(16); - }); -} -module.exports = getUniqueId; -},{}],9:[function(require,module,exports){ -function getWindowProfile(){ - var body, html, output; - if ('undefined' == typeof document) return {}; - body = document.body; - html = document.documentElement; - output = { - 'height': ('innerHeight' in window) ? window.innerHeight : document.documentElement.offsetHeight, - 'width': ('innerWidth' in window) ? window.innerWidth : document.documentElement.offsetWidth, - 'scrollHeight': Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight ) || null - }; - if (window.screen) { - output.ratio = { - 'height': (window.screen.availHeight) ? parseFloat( (window.innerHeight/window.screen.availHeight).toFixed(2) ) : null, - 'width': (window.screen.availWidth) ? parseFloat( (window.innerWidth/window.screen.availWidth).toFixed(2) ) : null - }; - } - return output; -} -module.exports = getWindowProfile; -/* - Notes: - document.documentElement.offsetHeight/Width is a workaround for IE8 and below, where window.innerHeight/Width is undefined -*/ -},{}],10:[function(require,module,exports){ -var Emitter = require('component-emitter'); -var json = require('./utils/json'); -var each = require('./utils/each'); -var extend = require('./utils/extend'); -var queue = require('./utils/queue'); -var K = function(config){ - var self = this; - this.configure(config); - extend(this.config.resources, K.resources); - this.extensions = { - events: [], - collections: {} - }; - this.queue = queue(); - this.queue.on('flush', function(){ - self.recordDeferredEvents(); - }); - if (K.debug) { - this.on('error', K.log); - } - this.emit('ready'); - K.emit('client', this); -}; -Emitter(K); -Emitter(K.prototype); -extend(K, { - debug: false, - enabled: true, - loaded: false, - helpers: {}, - resources: { - 'base' : '{protocol}://{host}', - 'version' : '{protocol}://{host}/3.0', - 'projects' : '{protocol}://{host}/3.0/projects', - 'projectId' : '{protocol}://{host}/3.0/projects/{projectId}', - 'events' : '{protocol}://{host}/3.0/projects/{projectId}/events' - }, - utils: {}, - version: '0.1.1' -}); -K.log = function(message) { - if (K.debug && typeof console == 'object') { - console.log('[Keen IO]', message); - } -}; -K.prototype.configure = function(cfg){ - var self = this, - config = cfg || {}, - defaultProtocol = 'https'; - this.config = this.config || { - projectId: undefined, - writeKey: undefined, - host: 'api.keen.io', - protocol: defaultProtocol, - requestType: 'jsonp', - resources: {}, - writePath: undefined - }; - if ('undefined' !== typeof document && document.all) { - config['protocol'] = (document.location.protocol !== 'https:') ? 'http' : defaultProtocol; - } - if (config['host']) { - config['host'].replace(/.*?:\/\//g, ''); - } - extend(this.config, config); - return self; -}; -K.prototype.projectId = function(str){ - if (!arguments.length) return this.config.projectId; - this.config.projectId = (str ? String(str) : null); - return this; -}; -K.prototype.writeKey = function(str){ - if (!arguments.length) return this.config.writeKey; - this.config.writeKey = (str ? String(str) : null); - return this; -}; -K.prototype.resources = function(obj){ - if (!arguments.length) return this.config.resources; - var self = this; - if (typeof obj === 'object') { - each(obj, function(value, key){ - self.config.resources[key] = (value ? value : null); - }); - } - return this; -}; -K.prototype.url = function(name){ - var args = Array.prototype.slice.call(arguments, 1), - baseUrl = K.resources.base || '{protocol}://{host}', - path; - if (name && typeof name === 'string') { - if (this.config.resources[name]) { - path = this.config.resources[name]; - } - else { - path = baseUrl + name; - } - } - else { - path = baseUrl; - } - each(this.config, function(value, key){ - if (typeof value !== 'object') { - path = path.replace('{' + key + '}', value); - } - }); - each(args, function(arg, i){ - if (typeof arg === 'string') { - path += '/' + arg; - } - else if (typeof arg === 'object') { - path += '?'; - each(arg, function(value, key){ - path += key + '=' + value + '&'; - }); - path = path.slice(0, -1); - } - }); - return path; -}; -K.prototype.setGlobalProperties = function(props){ - K.log('This method has been deprecated. Check out #extendEvents: https://github.com/keen/keen-tracking.js#extend-events'); - if (!props || typeof props !== 'function') { - this.emit('error', 'Invalid value for global properties: ' + props); - return; - } - this.config.globalProperties = props; - return this; -}; -K.prototype.writePath = function(str){ - K.log('This method has been deprecated. Use client.url(\'events\') instead.'); - if (!arguments.length) return this.config.writePath; - if (!this.projectId()) { - this.emit('error', 'Client instance is missing a projectId property'); - return this.config.writePath || ('/3.0/projects/' + this.projectId() + '/events'); - } - this.config.writePath = str ? String(str) : ('/3.0/projects/' + this.projectId() + '/events'); - return this; -}; -function serialize(data){ - var query = []; - each(data, function(value, key){ - if ('string' !== typeof value) { - value = json.stringify(value); - } - query.push(key + '=' + encodeURIComponent(value)); - }); - return query.join('&'); -} -module.exports = K; -},{"./utils/each":15,"./utils/extend":16,"./utils/json":17,"./utils/queue":20,"component-emitter":22}],11:[function(require,module,exports){ -var Keen = require('./index'); -var base64 = require('./utils/base64'); -var each = require('./utils/each'); -var extend = require('./utils/extend'); -var extendEvents = require('./extend-events'); -var json = require('./utils/json'); -module.exports = { - 'recordEvent': recordEvent, - 'recordEvents': recordEvents, - 'addEvent': addEvent, - 'addEvents': addEvents -}; -function recordEvent(eventCollection, eventBody, callback, async){ - var url, data, cb, getRequestUrl, getRequestUrlOkLength, extendedEventBody, isAsync; - url = this.url('events', encodeURIComponent(eventCollection)); - data = {}; - cb = callback; - isAsync = ('boolean' === typeof async) ? async : true; - if (!checkValidation.call(this, cb)) { - return; - } - if (!eventCollection || typeof eventCollection !== 'string') { - handleValidationError.call(this, 'Collection name must be a string.', cb); - return; - } - if (this.config.globalProperties) { - data = this.config.globalProperties(eventCollection); - } - extend(data, eventBody); - extendedEventBody = {}; - extendEvents.getExtendedEventBody(extendedEventBody, this.extensions.events); - extendEvents.getExtendedEventBody(extendedEventBody, this.extensions.collections[eventCollection]); - extendEvents.getExtendedEventBody(extendedEventBody, [data]); - this.emit('recordEvent', eventCollection, extendedEventBody); - if (!Keen.enabled) { - handleValidationError.call(this, 'Keen.enabled is set to false.', cb); - return false; - } - getRequestUrl = this.url('events', encodeURIComponent(eventCollection), { - api_key : this.writeKey(), - data : base64.encode( json.stringify(extendedEventBody) ), - modified : new Date().getTime() - }); - getRequestUrlOkLength = getRequestUrl.length < getUrlMaxLength(); - if (isAsync) { - switch (this.config.requestType) { - case 'xhr': - sendXhr.call(this, 'POST', url, extendedEventBody, cb); - break; - case 'beacon': - if (getRequestUrlOkLength) { - sendBeacon.call(this, getRequestUrl, cb); - } - else { - attemptPostXhr.call(this, url, extendedEventBody, - 'Beacon URL length exceeds current browser limit, and XHR is not supported.', cb) - } - break; - default: - if (getRequestUrlOkLength) { - sendJSONp.call(this, getRequestUrl, cb); - } - else { - attemptPostXhr.call(this, url, extendedEventBody, - 'JSONp URL length exceeds current browser limit, and XHR is not supported.', cb) - } - break; - } - } - else { - if (getRequestUrlOkLength) { - sendSynchronousXhr(getRequestUrl); - } - } - callback = cb = null; - return this; -} -function recordEvents(eventsHash, callback){ - var self = this, url, cb, extendedEventsHash; - url = this.url('events'); - cb = callback; - callback = null; - if (!checkValidation.call(this, cb)) { - return; - } - if ('object' !== typeof eventsHash || eventsHash instanceof Array) { - handleValidationError.call(this, 'First argument must be an object', cb); - return; - } - if (arguments.length > 2) { - handleValidationError.call(this, 'Incorrect arguments provided to #recordEvents method', cb); - return; - } - if (this.config.globalProperties) { - each(eventsHash, function(events, collection){ - each(events, function(body, index){ - var modified = self.config.globalProperties(collection); - eventsHash[collection][index] = extend(modified, body); - }); - }); - } - extendedEventsHash = {}; - each(eventsHash, function(eventList, eventCollection){ - extendedEventsHash[eventCollection] = extendedEventsHash[eventCollection] || []; - each(eventList, function(eventBody, index){ - var extendedEventBody = {}; - extendEvents.getExtendedEventBody(extendedEventBody, self.extensions.events); - extendEvents.getExtendedEventBody(extendedEventBody, self.extensions.collections[eventCollection]); - extendEvents.getExtendedEventBody(extendedEventBody, [eventBody]); - extendedEventsHash[eventCollection].push(extendedEventBody); - }); - }); - this.emit('recordEvents', extendedEventsHash); - if (!Keen.enabled) { - handleValidationError.call(this, 'Keen.enabled is set to false.', cb); - return false; - } - if (getXhr()) { - sendXhr.call(this, 'POST', url, extendedEventsHash, cb); - } - else { - } - callback = cb = null; - return this; -} -function addEvent(){ - this.emit('error', 'This method has been deprecated. Check out #recordEvent: https://github.com/keen/keen-tracking.js#record-a-single-event'); - recordEvent.apply(this, arguments); -} -function addEvents(){ - this.emit('error', 'This method has been deprecated. Check out #recordEvents: https://github.com/keen/keen-tracking.js#record-multiple-events'); - recordEvents.apply(this, arguments); -} -function checkValidation(callback){ - var cb = callback; - callback = null; - if (!this.projectId()) { - handleValidationError.call(this, 'Keen.Client is missing a projectId property.', cb); - return false; - } - if (!this.writeKey()) { - handleValidationError.call(this, 'Keen.Client is missing a writeKey property.', cb); - return false; - } - return true; -} -function handleValidationError(message, cb){ - var err = 'Event(s) not recorded: ' + message; - this.emit('error', err); - if (cb) { - cb.call(this, err, null); - cb = null; - } -} -function getUrlMaxLength(){ - if ('undefined' !== typeof window) { - if (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') > 0) { - return 2000; - } - } - return 16000; -} -function attemptPostXhr(url, data, noXhrError, callback) { - if (getXhr()) { - sendXhr.call(this, 'POST', url, data, callback); - } - else { - handleValidationError.call(this, noXhrError); - } -} -function sendXhr(method, url, data, callback){ - var self = this; - var payload; - var xhr = getXhr(); - var cb = callback; - callback = null; - xhr.onreadystatechange = function() { - var response; - if (xhr.readyState == 4) { - if (xhr.status >= 200 && xhr.status < 300) { - try { - response = json.parse( xhr.responseText ); - } catch (e) { - Keen.emit('error', 'Could not parse HTTP response: ' + xhr.responseText); - if (cb) { - cb.call(self, xhr, null); - } - } - if (cb && response) { - cb.call(self, null, response); - } - } - else { - Keen.emit('error', 'HTTP request failed.'); - if (cb) { - cb.call(self, xhr, null); - } - } - } - }; - xhr.open(method, url, true); - xhr.setRequestHeader('Authorization', self.writeKey()); - xhr.setRequestHeader('Content-Type', 'application/json'); - if (data) { - payload = json.stringify(data); - } - if (method.toUpperCase() === 'GET') { - xhr.send(); - } - if (method.toUpperCase() === 'POST') { - xhr.send(payload); - } -} -function sendSynchronousXhr(url){ - var xhr = getXhr(); - if (xhr) { - xhr.open('GET', url, false); - xhr.send(null); - } -} -function getXhr() { - var root = 'undefined' == typeof window ? this : window; - if (root.XMLHttpRequest && ('file:' != root.location.protocol || !root.ActiveXObject)) { - return new XMLHttpRequest; - } else { - try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {} - try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {} - try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {} - try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {} - } - return false; -}; -function sendJSONp(url, callback){ - var self = this, - cb = callback, - timestamp = new Date().getTime(), - script = document.createElement('script'), - parent = document.getElementsByTagName('head')[0], - callbackName = 'keenJSONPCallback', - loaded = false; - callback = null; - callbackName += timestamp; - while (callbackName in window) { - callbackName += 'a'; - } - window[callbackName] = function(response) { - if (loaded === true) return; - loaded = true; - if (cb) { - cb.call(self, null, response); - } - cleanup(); - }; - script.src = url + '&jsonp=' + callbackName; - parent.appendChild(script); - script.onreadystatechange = function() { - if (loaded === false && this.readyState === 'loaded') { - loaded = true; - handleError(); - cleanup(); - } - }; - script.onerror = function() { - if (loaded === false) { - loaded = true; - handleError(); - cleanup(); - } - }; - function handleError(){ - if (cb) { - cb.call(self, 'An error occurred!', null); - } - } - function cleanup(){ - window[callbackName] = undefined; - try { - delete window[callbackName]; - } catch(e){}; - parent.removeChild(script); - } -} -function sendBeacon(url, callback){ - var self = this, - cb = callback, - img = document.createElement('img'), - loaded = false; - callback = null; - img.onload = function() { - loaded = true; - if ('naturalHeight' in this) { - if (this.naturalHeight + this.naturalWidth === 0) { - this.onerror(); - return; - } - } else if (this.width + this.height === 0) { - this.onerror(); - return; - } - if (cb) { - cb.call(self); - } - }; - img.onerror = function() { - loaded = true; - if (cb) { - cb.call(self, 'An error occurred!', null); - } - }; - img.src = url + '&c=clv1'; -} -},{"./extend-events":3,"./index":10,"./utils/base64":12,"./utils/each":15,"./utils/extend":16,"./utils/json":17}],12:[function(require,module,exports){ -module.exports = { - map: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", - encode: function (n) { - "use strict"; - var o = "", i = 0, m = this.map, i1, i2, i3, e1, e2, e3, e4; - n = this.utf8.encode(n); - while (i < n.length) { - i1 = n.charCodeAt(i++); i2 = n.charCodeAt(i++); i3 = n.charCodeAt(i++); - e1 = (i1 >> 2); e2 = (((i1 & 3) << 4) | (i2 >> 4)); e3 = (isNaN(i2) ? 64 : ((i2 & 15) << 2) | (i3 >> 6)); - e4 = (isNaN(i2) || isNaN(i3)) ? 64 : i3 & 63; - o = o + m.charAt(e1) + m.charAt(e2) + m.charAt(e3) + m.charAt(e4); - } return o; - }, - decode: function (n) { - "use strict"; - var o = "", i = 0, m = this.map, cc = String.fromCharCode, e1, e2, e3, e4, c1, c2, c3; - n = n.replace(/[^A-Za-z0-9\+\/\=]/g, ""); - while (i < n.length) { - e1 = m.indexOf(n.charAt(i++)); e2 = m.indexOf(n.charAt(i++)); - e3 = m.indexOf(n.charAt(i++)); e4 = m.indexOf(n.charAt(i++)); - c1 = (e1 << 2) | (e2 >> 4); c2 = ((e2 & 15) << 4) | (e3 >> 2); - c3 = ((e3 & 3) << 6) | e4; - o = o + (cc(c1) + ((e3 != 64) ? cc(c2) : "")) + (((e4 != 64) ? cc(c3) : "")); - } return this.utf8.decode(o); - }, - utf8: { - encode: function (n) { - "use strict"; - var o = "", i = 0, cc = String.fromCharCode, c; - while (i < n.length) { - c = n.charCodeAt(i++); o = o + ((c < 128) ? cc(c) : ((c > 127) && (c < 2048)) ? - (cc((c >> 6) | 192) + cc((c & 63) | 128)) : (cc((c >> 12) | 224) + cc(((c >> 6) & 63) | 128) + cc((c & 63) | 128))); - } return o; - }, - decode: function (n) { - "use strict"; - var o = "", i = 0, cc = String.fromCharCode, c2, c; - while (i < n.length) { - c = n.charCodeAt(i); - o = o + ((c < 128) ? [cc(c), i++][0] : ((c > 191) && (c < 224)) ? - [cc(((c & 31) << 6) | ((c2 = n.charCodeAt(i + 1)) & 63)), (i += 2)][0] : - [cc(((c & 15) << 12) | (((c2 = n.charCodeAt(i + 1)) & 63) << 6) | ((c3 = n.charCodeAt(i + 2)) & 63)), (i += 3)][0]); - } return o; - } - } -}; -},{}],13:[function(require,module,exports){ -var Cookies = require('cookies-js'); -var json = require('./json'); -var extend = require('./extend'); -module.exports = cookie; -function cookie(str){ - if (!arguments.length) return; - if (this instanceof cookie === false) { - return new cookie(str); - } - this.config = { - key: str, - options: {} - }; - this.data = this.get(); - return this; -} -cookie.prototype.get = function(str){ - var data = {}; - if (Cookies.get(this.config.key)) { - data = json.parse( decodeURIComponent(Cookies.get(this.config.key)) ); - } - if (str) { - return ('undefined' !== typeof data[str]) ? data[str] : null; - } - else { - return data; - } -}; -cookie.prototype.set = function(str, value){ - if (!arguments.length || !this.enabled()) return this; - if ('string' === typeof str && arguments.length === 2) { - this.data[str] = value ? value : null; - } - else if ('object' === typeof str && arguments.length === 1) { - extend(this.data, str); - } - Cookies.set(this.config.key, encodeURIComponent( json.stringify(this.data) ), this.config.options); - return this; -}; -cookie.prototype.expire = function(){ - Cookies.expire(this.config.key); - this.data = {}; - return this; -}; -cookie.prototype.options = function(obj){ - if (!arguments.length) return this.config.options; - this.config.options = (typeof obj === 'object') ? obj : {}; - return this; -}; -cookie.prototype.enabled = function(){ - return Cookies.enabled; -}; -},{"./extend":16,"./json":17,"cookies-js":23}],14:[function(require,module,exports){ -var json = require('./json'); -module.exports = deepExtend; -function deepExtend(target){ - for (var i = 1; i < arguments.length; i++) { - if (target instanceof Array && arguments[i] instanceof Array) { - for (var j = 0; j < arguments[i].length; j++) { - if (target.indexOf(arguments[i][j]) < 0) { - target.push(arguments[i][j]); - } - } - } - else { - for (var prop in arguments[i]){ - if ('undefined' !== typeof target[prop] && 'object' === typeof arguments[i][prop] && arguments[i][prop] !== null) { - deepExtend(target[prop], clone(arguments[i][prop])); - } - else { - target[prop] = clone(arguments[i][prop]); - } - } - } - } - return target; -} -function clone(input){ - return json.parse( json.stringify(input) ); -} -},{"./json":17}],15:[function(require,module,exports){ -module.exports = each; -function each(o, cb, s){ - var n; - if (!o){ - return 0; - } - s = !s ? o : s; - if (o instanceof Array){ - for (n=0; n a"); - myClicker.on("click", function(e){ - }); - myClicker.once("click", function(e){ }); - myClicker.off("click"); - myClicker.off(); -*/ -module.exports = function(ctx){ - ctx.domListeners = ctx.domListeners || { - /* - 'click': { - '.nav li > a': [fn, fn, fn] - } - */ - }; - function listener(str){ - if (!str) return; - if (this instanceof listener === false) { - return new listener(str); - } - this.selector = str; - return this; - } - listener.prototype.on = function(str, fn){ - var self = this; - if (arguments.length !== 2 || 'string' !== typeof str || 'function' !== typeof fn) return this; - if ('undefined' === typeof ctx.domListeners[str]) { - addListener(str, eventHandler(str)); - ctx.domListeners[str] = {}; - } - ctx.domListeners[str][self.selector] = ctx.domListeners[str][self.selector] || []; - ctx.domListeners[str][self.selector].push(fn); - return self; - }; - listener.prototype.once = function(str, fn){ - var self = this; - function on() { - self.off(str, on); - return fn.apply(self, arguments); - } - on.fn = fn; - self.on(str, on); - return self; - }; - listener.prototype.off = function(str, fn){ - var self = this, survivors = []; - if (arguments.length === 2) { - each(ctx.domListeners[str][self.selector], function(handler, i){ - if (handler === fn || handler.fn === fn) return; - survivors.push(handler); - }); - ctx.domListeners[str][self.selector] = survivors; - } - else if (arguments.length === 1) { - try { - delete ctx.domListeners[str][self.selector]; - } - catch(e){ - ctx.domListeners[str][self.selector] = []; - } - } - else { - each(ctx.domListeners, function(hash, eventType){ - try { - delete ctx.domListeners[eventType][self.selector]; - } - catch(e){ - ctx.domListeners[eventType][self.selector] = function(){}; - } - }); - } - return self; - }; - function eventHandler(eventType){ - return function(e){ - var evt, target; - evt = e || window.event; - target = evt.target || evt.srcElement; - if ('undefined' === ctx.domListeners[eventType]) return; - each(ctx.domListeners[eventType], function(handlers, key){ - if (matches(target, key)) { - each(handlers, function(fn, i){ - if ('click' === eventType && 'A' === target.nodeName) { - deferClickEvent(evt, target, fn); - } - else if ('submit' === eventType && 'FORM' === target.nodeName) { - deferFormSubmit(evt, target, fn); - } - else { - fn(evt); - } - }); - } - else if ('window' === key) { - each(handlers, function(fn, i){ - fn(evt); - }); - } - return; - }); - }; - } - return listener; -} -function addListener(eventType, fn){ - if (document.addEventListener) { - document.addEventListener(eventType, fn, false); - } else { - document.attachEvent("on" + eventType, fn); - } -} -function matches(elem, selector) { - var nodeList = ( elem.parentNode || document ).querySelectorAll( selector ) || [], - i = nodeList.length; - while ( i-- ) { - if ( nodeList[i] == elem ) { return true; } - } - return false; -} -function deferClickEvent(evt, anchor, callback){ - var timeout = 500, - targetAttr, - cbResponse; - if (anchor.getAttribute !== void 0) { - targetAttr = anchor.getAttribute("target"); - } else if (anchor.target) { - targetAttr = anchor.target; - } - cbResponse = callback(evt); - if (('boolean' === typeof cbResponse && cbResponse === false) || evt.defaultPrevented || evt.returnValue === false) { - if (evt.preventDefault) { - evt.preventDefault(); - } - evt.returnValue = false; - return false; - } - else if (targetAttr !== '_blank' && targetAttr !== 'blank' && !evt.metaKey) { - if (evt.preventDefault) { - evt.preventDefault(); - } - evt.returnValue = false; - setTimeout(function(){ - window.location = anchor.href; - }, timeout); - } - return false; -} -function deferFormSubmit(evt, form, callback){ - var timeout = 500; - cbResponse = callback(evt); - if (('boolean' === typeof cbResponse && cbResponse === false) || evt.defaultPrevented || evt.returnValue === false) { - if (evt.preventDefault) { - evt.preventDefault(); - } - evt.returnValue = false; - return false; - } - else { - if (evt.preventDefault) { - evt.preventDefault(); - } - evt.returnValue = false; - setTimeout(function(){ - form.submit(); - }, timeout); - } - return false; -} -},{"./each":15,"component-emitter":22}],19:[function(require,module,exports){ -function parseParams(str){ - var urlParams = {}, - match, - pl = /\+/g, - search = /([^&=]+)=?([^&]*)/g, - decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); }, - query = str.split("?")[1]; - while (!!(match=search.exec(query))) { - urlParams[decode(match[1])] = decode(match[2]); - } - return urlParams; -}; -module.exports = parseParams; -},{}],20:[function(require,module,exports){ -var Emitter = require('component-emitter'); -module.exports = queue; -function queue(){ - var self = this; - if (this instanceof queue === false) { - return new queue(); - } - self.capacity = 0; - self.interval = 0; - self.config = { - capacity: 5000, - interval: 15 - }; - self.events = { - }; - setInterval(function(){ - self.interval++; - checkQueue.call(self); - }, 1000); - return self; -} -function checkQueue(){ - if ((this.capacity > 0 && this.interval >= this.config.interval) - || this.capacity >= this.config.capacity) { - this.emit('flush'); - this.interval = 0; - } -} -Emitter(queue.prototype); -},{"component-emitter":22}],21:[function(require,module,exports){ -module.exports = timer; -function timer(num){ - if (this instanceof timer === false) { - return new timer(num); - } - this.count = num || 0; - return this; -} -timer.prototype.start = function(){ - var self = this; - this.pause(); - this.interval = setInterval(function(){ - self.count++; - }, 1000); - return this; -}; -timer.prototype.pause = function(){ - clearInterval(this.interval); - return this; -}; -timer.prototype.value = function(){ - return this.count; -}; -timer.prototype.clear = function(){ - this.count = 0; - return this; -}; -},{}],22:[function(require,module,exports){ -/** - * 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){ - function on() { - this.off(event, on); - fn.apply(this, arguments); - } - on.fn = fn; - 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 || {}; - if (0 == arguments.length) { - this._callbacks = {}; - return this; - } - var callbacks = this._callbacks['$' + event]; - if (!callbacks) return this; - if (1 == arguments.length) { - delete this._callbacks['$' + event]; - return this; - } - var cb; - for (var i = 0; i < callbacks.length; i++) { - cb = callbacks[i]; - if (cb === fn || cb.fn === fn) { - callbacks.splice(i, 1); - break; - } - } - 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; -}; -},{}],23:[function(require,module,exports){ -/* * Cookies.js - 1.2.1 * https://github.com/ScottHamper/Cookies * * This is free and unencumbered software released into the public domain. */ (function (global, undefined) { 'use strict'; var factory = function (window) { if (typeof window.document !== 'object') { throw new Error('Cookies.js requires a `window` with a `document` object'); } var Cookies = function (key, value, options) { return arguments.length === 1 ? Cookies.get(key) : Cookies.set(key, value, options); }; Cookies._document = window.document; Cookies._cacheKeyPrefix = 'cookey.'; Cookies._maxExpireDate = new Date('Fri, 31 Dec 9999 23:59:59 UTC'); Cookies.defaults = { path: '/', secure: false }; Cookies.get = function (key) { if (Cookies._cachedDocumentCookie !== Cookies._document.cookie) { Cookies._renewCache(); } return Cookies._cache[Cookies._cacheKeyPrefix + key]; }; Cookies.set = function (key, value, options) { options = Cookies._getExtendedOptions(options); options.expires = Cookies._getExpiresDate(value === undefined ? -1 : options.expires); Cookies._document.cookie = Cookies._generateCookieString(key, value, options); return Cookies; }; Cookies.expire = function (key, options) { return Cookies.set(key, undefined, options); }; Cookies._getExtendedOptions = function (options) { return { path: options && options.path || Cookies.defaults.path, domain: options && options.domain || Cookies.defaults.domain, expires: options && options.expires || Cookies.defaults.expires, secure: options && options.secure !== undefined ? options.secure : Cookies.defaults.secure }; }; Cookies._isValidDate = function (date) { return Object.prototype.toString.call(date) === '[object Date]' && !isNaN(date.getTime()); }; Cookies._getExpiresDate = function (expires, now) { now = now || new Date(); if (typeof expires === 'number') { expires = expires === Infinity ? Cookies._maxExpireDate : new Date(now.getTime() + expires * 1000); } else if (typeof expires === 'string') { expires = new Date(expires); } if (expires && !Cookies._isValidDate(expires)) { throw new Error('`expires` parameter cannot be converted to a valid Date instance'); } return expires; }; Cookies._generateCookieString = function (key, value, options) { key = key.replace(/[^#$&+\^`|]/g, encodeURIComponent); key = key.replace(/\(/g, '%28').replace(/\)/g, '%29'); value = (value + '').replace(/[^!#$&-+\--:<-\[\]-~]/g, encodeURIComponent); options = options || {}; var cookieString = key + '=' + value; cookieString += options.path ? ';path=' + options.path : ''; cookieString += options.domain ? ';domain=' + options.domain : ''; cookieString += options.expires ? ';expires=' + options.expires.toUTCString() : ''; cookieString += options.secure ? ';secure' : ''; return cookieString; }; Cookies._getCacheFromString = function (documentCookie) { var cookieCache = {}; var cookiesArray = documentCookie ? documentCookie.split('; ') : []; for (var i = 0; i < cookiesArray.length; i++) { var cookieKvp = Cookies._getKeyValuePairFromCookieString(cookiesArray[i]); if (cookieCache[Cookies._cacheKeyPrefix + cookieKvp.key] === undefined) { cookieCache[Cookies._cacheKeyPrefix + cookieKvp.key] = cookieKvp.value; } } return cookieCache; }; Cookies._getKeyValuePairFromCookieString = function (cookieString) { var separatorIndex = cookieString.indexOf('='); separatorIndex = separatorIndex < 0 ? cookieString.length : separatorIndex; return { key: decodeURIComponent(cookieString.substr(0, separatorIndex)), value: decodeURIComponent(cookieString.substr(separatorIndex + 1)) }; }; Cookies._renewCache = function () { Cookies._cache = Cookies._getCacheFromString(Cookies._document.cookie); Cookies._cachedDocumentCookie = Cookies._document.cookie; }; Cookies._areEnabled = function () { var testKey = 'cookies.js'; var areEnabled = Cookies.set(testKey, 1).get(testKey) === '1'; Cookies.expire(testKey); return areEnabled; }; Cookies.enabled = Cookies._areEnabled(); return Cookies; }; var cookiesExport = typeof global.document === 'object' ? factory(global) : factory; if (false) { define(function () { return cookiesExport; }); } else if (typeof exports === 'object') { if (typeof module === 'object' && typeof module.exports === 'object') { exports = module.exports = cookiesExport; } exports.Cookies = cookiesExport; } else { global.Cookies = cookiesExport; } })(typeof window === 'undefined' ? this : window); -},{}],24:[function(require,module,exports){ -(function (global){ -/*! JSON v3.3.2 | http://bestiejs.github.io/json3 | Copyright 2012-2014, Kit Cambridge | http://kit.mit-license.org */ -;(function () { - var isLoader = typeof define === "function" && define.amd; - var objectTypes = { - "function": true, - "object": true - }; - var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; - var root = objectTypes[typeof window] && window || this, - freeGlobal = freeExports && objectTypes[typeof module] && module && !module.nodeType && typeof global == "object" && global; - if (freeGlobal && (freeGlobal["global"] === freeGlobal || freeGlobal["window"] === freeGlobal || freeGlobal["self"] === freeGlobal)) { - root = freeGlobal; - } - function runInContext(context, exports) { - context || (context = root["Object"]()); - exports || (exports = root["Object"]()); - var Number = context["Number"] || root["Number"], - String = context["String"] || root["String"], - Object = context["Object"] || root["Object"], - Date = context["Date"] || root["Date"], - SyntaxError = context["SyntaxError"] || root["SyntaxError"], - TypeError = context["TypeError"] || root["TypeError"], - Math = context["Math"] || root["Math"], - nativeJSON = context["JSON"] || root["JSON"]; - if (typeof nativeJSON == "object" && nativeJSON) { - exports.stringify = nativeJSON.stringify; - exports.parse = nativeJSON.parse; - } - var objectProto = Object.prototype, - getClass = objectProto.toString, - isProperty, forEach, undef; - var isExtended = new Date(-3509827334573292); - try { - isExtended = isExtended.getUTCFullYear() == -109252 && isExtended.getUTCMonth() === 0 && isExtended.getUTCDate() === 1 && - isExtended.getUTCHours() == 10 && isExtended.getUTCMinutes() == 37 && isExtended.getUTCSeconds() == 6 && isExtended.getUTCMilliseconds() == 708; - } catch (exception) {} - function has(name) { - if (has[name] !== undef) { - return has[name]; - } - var isSupported; - if (name == "bug-string-char-index") { - isSupported = "a"[0] != "a"; - } else if (name == "json") { - isSupported = has("json-stringify") && has("json-parse"); - } else { - var value, serialized = '{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}'; - if (name == "json-stringify") { - var stringify = exports.stringify, stringifySupported = typeof stringify == "function" && isExtended; - if (stringifySupported) { - (value = function () { - return 1; - }).toJSON = value; - try { - stringifySupported = - stringify(0) === "0" && - stringify(new Number()) === "0" && - stringify(new String()) == '""' && - stringify(getClass) === undef && - stringify(undef) === undef && - stringify() === undef && - stringify(value) === "1" && - stringify([value]) == "[1]" && - stringify([undef]) == "[null]" && - stringify(null) == "null" && - stringify([undef, getClass, null]) == "[null,null,null]" && - stringify({ "a": [value, true, false, null, "\x00\b\n\f\r\t"] }) == serialized && - stringify(null, value) === "1" && - stringify([1, 2], null, 1) == "[\n 1,\n 2\n]" && - stringify(new Date(-8.64e15)) == '"-271821-04-20T00:00:00.000Z"' && - stringify(new Date(8.64e15)) == '"+275760-09-13T00:00:00.000Z"' && - stringify(new Date(-621987552e5)) == '"-000001-01-01T00:00:00.000Z"' && - stringify(new Date(-1)) == '"1969-12-31T23:59:59.999Z"'; - } catch (exception) { - stringifySupported = false; - } - } - isSupported = stringifySupported; - } - if (name == "json-parse") { - var parse = exports.parse; - if (typeof parse == "function") { - try { - if (parse("0") === 0 && !parse(false)) { - value = parse(serialized); - var parseSupported = value["a"].length == 5 && value["a"][0] === 1; - if (parseSupported) { - try { - parseSupported = !parse('"\t"'); - } catch (exception) {} - if (parseSupported) { - try { - parseSupported = parse("01") !== 1; - } catch (exception) {} - } - if (parseSupported) { - try { - parseSupported = parse("1.") !== 1; - } catch (exception) {} - } - } - } - } catch (exception) { - parseSupported = false; - } - } - isSupported = parseSupported; - } - } - return has[name] = !!isSupported; - } - if (!has("json")) { - var functionClass = "[object Function]", - dateClass = "[object Date]", - numberClass = "[object Number]", - stringClass = "[object String]", - arrayClass = "[object Array]", - booleanClass = "[object Boolean]"; - var charIndexBuggy = has("bug-string-char-index"); - if (!isExtended) { - var floor = Math.floor; - var Months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]; - var getDay = function (year, month) { - return Months[month] + 365 * (year - 1970) + floor((year - 1969 + (month = +(month > 1))) / 4) - floor((year - 1901 + month) / 100) + floor((year - 1601 + month) / 400); - }; - } - if (!(isProperty = objectProto.hasOwnProperty)) { - isProperty = function (property) { - var members = {}, constructor; - if ((members.__proto__ = null, members.__proto__ = { - "toString": 1 - }, members).toString != getClass) { - isProperty = function (property) { - var original = this.__proto__, result = property in (this.__proto__ = null, this); - this.__proto__ = original; - return result; - }; - } else { - constructor = members.constructor; - isProperty = function (property) { - var parent = (this.constructor || constructor).prototype; - return property in this && !(property in parent && this[property] === parent[property]); - }; - } - members = null; - return isProperty.call(this, property); - }; - } - forEach = function (object, callback) { - var size = 0, Properties, members, property; - (Properties = function () { - this.valueOf = 0; - }).prototype.valueOf = 0; - members = new Properties(); - for (property in members) { - if (isProperty.call(members, property)) { - size++; - } - } - Properties = members = null; - if (!size) { - members = ["valueOf", "toString", "toLocaleString", "propertyIsEnumerable", "isPrototypeOf", "hasOwnProperty", "constructor"]; - forEach = function (object, callback) { - var isFunction = getClass.call(object) == functionClass, property, length; - var hasProperty = !isFunction && typeof object.constructor != "function" && objectTypes[typeof object.hasOwnProperty] && object.hasOwnProperty || isProperty; - for (property in object) { - if (!(isFunction && property == "prototype") && hasProperty.call(object, property)) { - callback(property); - } - } - for (length = members.length; property = members[--length]; hasProperty.call(object, property) && callback(property)); - }; - } else if (size == 2) { - forEach = function (object, callback) { - var members = {}, isFunction = getClass.call(object) == functionClass, property; - for (property in object) { - if (!(isFunction && property == "prototype") && !isProperty.call(members, property) && (members[property] = 1) && isProperty.call(object, property)) { - callback(property); - } - } - }; - } else { - forEach = function (object, callback) { - var isFunction = getClass.call(object) == functionClass, property, isConstructor; - for (property in object) { - if (!(isFunction && property == "prototype") && isProperty.call(object, property) && !(isConstructor = property === "constructor")) { - callback(property); - } - } - if (isConstructor || isProperty.call(object, (property = "constructor"))) { - callback(property); - } - }; - } - return forEach(object, callback); - }; - if (!has("json-stringify")) { - var Escapes = { - 92: "\\\\", - 34: '\\"', - 8: "\\b", - 12: "\\f", - 10: "\\n", - 13: "\\r", - 9: "\\t" - }; - var leadingZeroes = "000000"; - var toPaddedString = function (width, value) { - return (leadingZeroes + (value || 0)).slice(-width); - }; - var unicodePrefix = "\\u00"; - var quote = function (value) { - var result = '"', index = 0, length = value.length, useCharIndex = !charIndexBuggy || length > 10; - var symbols = useCharIndex && (charIndexBuggy ? value.split("") : value); - for (; index < length; index++) { - var charCode = value.charCodeAt(index); - switch (charCode) { - case 8: case 9: case 10: case 12: case 13: case 34: case 92: - result += Escapes[charCode]; - break; - default: - if (charCode < 32) { - result += unicodePrefix + toPaddedString(2, charCode.toString(16)); - break; - } - result += useCharIndex ? symbols[index] : value.charAt(index); - } - } - return result + '"'; - }; - var serialize = function (property, object, callback, properties, whitespace, indentation, stack) { - var value, className, year, month, date, time, hours, minutes, seconds, milliseconds, results, element, index, length, prefix, result; - try { - value = object[property]; - } catch (exception) {} - if (typeof value == "object" && value) { - className = getClass.call(value); - if (className == dateClass && !isProperty.call(value, "toJSON")) { - if (value > -1 / 0 && value < 1 / 0) { - if (getDay) { - date = floor(value / 864e5); - for (year = floor(date / 365.2425) + 1970 - 1; getDay(year + 1, 0) <= date; year++); - for (month = floor((date - getDay(year, 0)) / 30.42); getDay(year, month + 1) <= date; month++); - date = 1 + date - getDay(year, month); - time = (value % 864e5 + 864e5) % 864e5; - hours = floor(time / 36e5) % 24; - minutes = floor(time / 6e4) % 60; - seconds = floor(time / 1e3) % 60; - milliseconds = time % 1e3; - } else { - year = value.getUTCFullYear(); - month = value.getUTCMonth(); - date = value.getUTCDate(); - hours = value.getUTCHours(); - minutes = value.getUTCMinutes(); - seconds = value.getUTCSeconds(); - milliseconds = value.getUTCMilliseconds(); - } - value = (year <= 0 || year >= 1e4 ? (year < 0 ? "-" : "+") + toPaddedString(6, year < 0 ? -year : year) : toPaddedString(4, year)) + - "-" + toPaddedString(2, month + 1) + "-" + toPaddedString(2, date) + - "T" + toPaddedString(2, hours) + ":" + toPaddedString(2, minutes) + ":" + toPaddedString(2, seconds) + - "." + toPaddedString(3, milliseconds) + "Z"; - } else { - value = null; - } - } else if (typeof value.toJSON == "function" && ((className != numberClass && className != stringClass && className != arrayClass) || isProperty.call(value, "toJSON"))) { - value = value.toJSON(property); - } - } - if (callback) { - value = callback.call(object, property, value); - } - if (value === null) { - return "null"; - } - className = getClass.call(value); - if (className == booleanClass) { - return "" + value; - } else if (className == numberClass) { - return value > -1 / 0 && value < 1 / 0 ? "" + value : "null"; - } else if (className == stringClass) { - return quote("" + value); - } - if (typeof value == "object") { - for (length = stack.length; length--;) { - if (stack[length] === value) { - throw TypeError(); - } - } - stack.push(value); - results = []; - prefix = indentation; - indentation += whitespace; - if (className == arrayClass) { - for (index = 0, length = value.length; index < length; index++) { - element = serialize(index, value, callback, properties, whitespace, indentation, stack); - results.push(element === undef ? "null" : element); - } - result = results.length ? (whitespace ? "[\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "]" : ("[" + results.join(",") + "]")) : "[]"; - } else { - forEach(properties || value, function (property) { - var element = serialize(property, value, callback, properties, whitespace, indentation, stack); - if (element !== undef) { - results.push(quote(property) + ":" + (whitespace ? " " : "") + element); - } - }); - result = results.length ? (whitespace ? "{\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "}" : ("{" + results.join(",") + "}")) : "{}"; - } - stack.pop(); - return result; - } - }; - exports.stringify = function (source, filter, width) { - var whitespace, callback, properties, className; - if (objectTypes[typeof filter] && filter) { - if ((className = getClass.call(filter)) == functionClass) { - callback = filter; - } else if (className == arrayClass) { - properties = {}; - for (var index = 0, length = filter.length, value; index < length; value = filter[index++], ((className = getClass.call(value)), className == stringClass || className == numberClass) && (properties[value] = 1)); - } - } - if (width) { - if ((className = getClass.call(width)) == numberClass) { - if ((width -= width % 1) > 0) { - for (whitespace = "", width > 10 && (width = 10); whitespace.length < width; whitespace += " "); - } - } else if (className == stringClass) { - whitespace = width.length <= 10 ? width : width.slice(0, 10); - } - } - return serialize("", (value = {}, value[""] = source, value), callback, properties, whitespace, "", []); - }; - } - if (!has("json-parse")) { - var fromCharCode = String.fromCharCode; - var Unescapes = { - 92: "\\", - 34: '"', - 47: "/", - 98: "\b", - 116: "\t", - 110: "\n", - 102: "\f", - 114: "\r" - }; - var Index, Source; - var abort = function () { - Index = Source = null; - throw SyntaxError(); - }; - var lex = function () { - var source = Source, length = source.length, value, begin, position, isSigned, charCode; - while (Index < length) { - charCode = source.charCodeAt(Index); - switch (charCode) { - case 9: case 10: case 13: case 32: - Index++; - break; - case 123: case 125: case 91: case 93: case 58: case 44: - value = charIndexBuggy ? source.charAt(Index) : source[Index]; - Index++; - return value; - case 34: - for (value = "@", Index++; Index < length;) { - charCode = source.charCodeAt(Index); - if (charCode < 32) { - abort(); - } else if (charCode == 92) { - charCode = source.charCodeAt(++Index); - switch (charCode) { - case 92: case 34: case 47: case 98: case 116: case 110: case 102: case 114: - value += Unescapes[charCode]; - Index++; - break; - case 117: - begin = ++Index; - for (position = Index + 4; Index < position; Index++) { - charCode = source.charCodeAt(Index); - if (!(charCode >= 48 && charCode <= 57 || charCode >= 97 && charCode <= 102 || charCode >= 65 && charCode <= 70)) { - abort(); - } - } - value += fromCharCode("0x" + source.slice(begin, Index)); - break; - default: - abort(); - } - } else { - if (charCode == 34) { - break; - } - charCode = source.charCodeAt(Index); - begin = Index; - while (charCode >= 32 && charCode != 92 && charCode != 34) { - charCode = source.charCodeAt(++Index); - } - value += source.slice(begin, Index); - } - } - if (source.charCodeAt(Index) == 34) { - Index++; - return value; - } - abort(); - default: - begin = Index; - if (charCode == 45) { - isSigned = true; - charCode = source.charCodeAt(++Index); - } - if (charCode >= 48 && charCode <= 57) { - if (charCode == 48 && ((charCode = source.charCodeAt(Index + 1)), charCode >= 48 && charCode <= 57)) { - abort(); - } - isSigned = false; - for (; Index < length && ((charCode = source.charCodeAt(Index)), charCode >= 48 && charCode <= 57); Index++); - if (source.charCodeAt(Index) == 46) { - position = ++Index; - for (; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++); - if (position == Index) { - abort(); - } - Index = position; - } - charCode = source.charCodeAt(Index); - if (charCode == 101 || charCode == 69) { - charCode = source.charCodeAt(++Index); - if (charCode == 43 || charCode == 45) { - Index++; - } - for (position = Index; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++); - if (position == Index) { - abort(); - } - Index = position; - } - return +source.slice(begin, Index); - } - if (isSigned) { - abort(); - } - if (source.slice(Index, Index + 4) == "true") { - Index += 4; - return true; - } else if (source.slice(Index, Index + 5) == "false") { - Index += 5; - return false; - } else if (source.slice(Index, Index + 4) == "null") { - Index += 4; - return null; - } - abort(); - } - } - return "$"; - }; - var get = function (value) { - var results, hasMembers; - if (value == "$") { - abort(); - } - if (typeof value == "string") { - if ((charIndexBuggy ? value.charAt(0) : value[0]) == "@") { - return value.slice(1); - } - if (value == "[") { - results = []; - for (;; hasMembers || (hasMembers = true)) { - value = lex(); - if (value == "]") { - break; - } - if (hasMembers) { - if (value == ",") { - value = lex(); - if (value == "]") { - abort(); - } - } else { - abort(); - } - } - if (value == ",") { - abort(); - } - results.push(get(value)); - } - return results; - } else if (value == "{") { - results = {}; - for (;; hasMembers || (hasMembers = true)) { - value = lex(); - if (value == "}") { - break; - } - if (hasMembers) { - if (value == ",") { - value = lex(); - if (value == "}") { - abort(); - } - } else { - abort(); - } - } - if (value == "," || typeof value != "string" || (charIndexBuggy ? value.charAt(0) : value[0]) != "@" || lex() != ":") { - abort(); - } - results[value.slice(1)] = get(lex()); - } - return results; - } - abort(); - } - return value; - }; - var update = function (source, property, callback) { - var element = walk(source, property, callback); - if (element === undef) { - delete source[property]; - } else { - source[property] = element; - } - }; - var walk = function (source, property, callback) { - var value = source[property], length; - if (typeof value == "object" && value) { - if (getClass.call(value) == arrayClass) { - for (length = value.length; length--;) { - update(value, length, callback); - } - } else { - forEach(value, function (property) { - update(value, property, callback); - }); - } - } - return callback.call(source, property, value); - }; - exports.parse = function (source, callback) { - var result, value; - Index = 0; - Source = "" + source; - result = get(lex()); - if (lex() != "$") { - abort(); - } - Index = Source = null; - return callback && getClass.call(callback) == functionClass ? walk((value = {}, value[""] = result, value), "", callback) : result; - }; - } - } - exports["runInContext"] = runInContext; - return exports; - } - if (freeExports && !isLoader) { - runInContext(root, freeExports); - } else { - var nativeJSON = root.JSON, - previousJSON = root["JSON3"], - isRestored = false; - var JSON3 = runInContext(root, (root["JSON3"] = { - "noConflict": function () { - if (!isRestored) { - isRestored = true; - root.JSON = nativeJSON; - root["JSON3"] = previousJSON; - nativeJSON = previousJSON = null; - } - return JSON3; - } - })); - root.JSON = { - "parse": JSON3.parse, - "stringify": JSON3.stringify - }; - } - if (isLoader) { - define(function () { - return JSON3; - }); - } -}).call(this); -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}]},{},[1]); - -//# sourceMappingURL=keen-tracking.js.map \ No newline at end of file diff --git a/dist/keen-tracking.js.map b/dist/keen-tracking.js.map deleted file mode 100644 index 63ea79c..0000000 --- a/dist/keen-tracking.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"names":[],"mappings":"","sources":["keen-tracking.js"],"sourcesContent":["(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o or DOM element');\n }\n if (timeoutCallback) {\n callback = function(){\n if(!triggered){\n triggered = true;\n timeoutCallback();\n }\n };\n }\n this.recordEvent(eventCollection, payload, callback);\n setTimeout(callback, timer);\n if (!evt.metaKey) {\n return false;\n }\n }\n\n // IE-specific polyfills, yay!\n // -----------------------------\n if (!Array.prototype.indexOf){\n Array.prototype.indexOf = function(elt /*, from*/) {\n var len = this.length >>> 0;\n\n var from = Number(arguments[1]) || 0;\n from = (from < 0)\n ? Math.ceil(from)\n : Math.floor(from);\n if (from < 0)\n from += len;\n\n for (; from < len; from++) {\n if (from in this &&\n this[from] === elt)\n return from;\n }\n return -1;\n };\n }\n\n module.exports = Keen;\n return Keen;\n});\n\n}).call(this,typeof global !== \"undefined\" ? global : typeof self !== \"undefined\" ? self : typeof window !== \"undefined\" ? window : {})\n},{\"./\":10,\"./defer-events\":2,\"./extend-events\":3,\"./helpers/getBrowserProfile\":4,\"./helpers/getDatetimeIndex\":5,\"./helpers/getDomNodePath\":6,\"./helpers/getScreenProfile\":7,\"./helpers/getUniqueId\":8,\"./helpers/getWindowProfile\":9,\"./record-events-browser\":11,\"./utils/cookie\":13,\"./utils/deepExtend\":14,\"./utils/each\":15,\"./utils/extend\":16,\"./utils/listener\":18,\"./utils/parseParams\":19,\"./utils/timer\":21}],2:[function(require,module,exports){\nvar Keen = require('./index');\nvar each = require('./utils/each');\nvar queue = require('./utils/queue');\n\nmodule.exports = {\n 'deferEvent': deferEvent,\n 'deferEvents': deferEvents,\n 'queueCapacity': queueCapacity,\n 'queueInterval': queueInterval,\n 'recordDeferredEvents': recordDeferredEvents\n};\n\nfunction deferEvent(eventCollection, eventBody){\n\n if (arguments.length !== 2 || typeof eventCollection !== 'string') {\n handleValidationError.call(this, 'Incorrect arguments provided to #deferEvent method');\n return;\n }\n\n this.queue.events[eventCollection] = this.queue.events[eventCollection] || [];\n this.queue.events[eventCollection].push(eventBody);\n this.queue.capacity++;\n this.emit('deferEvent', eventCollection, eventBody);\n return this;\n}\n\nfunction deferEvents(eventsHash){\n var self = this;\n\n if (arguments.length !== 1 || typeof eventsHash !== 'object') {\n handleValidationError.call(this, 'Incorrect arguments provided to #deferEvents method');\n return;\n }\n\n each(eventsHash, function(eventList, eventCollection){\n self.queue.events[eventCollection] = self.queue.events[eventCollection] || [];\n self.queue.events[eventCollection] = self.queue.events[eventCollection].concat(eventList);\n self.queue.capacity = self.queue.capacity + eventList.length;\n });\n self.emit('deferEvents', eventsHash);\n return self;\n}\n\nfunction queueCapacity(num){\n if (!arguments.length) return this.queue.config.capacity;\n this.queue.config.capacity = num ? Number(num): 0;\n return this;\n}\n\nfunction queueInterval(num){\n if (!arguments.length) return this.queue.config.interval;\n this.queue.config.interval = num ? Number(num): 0;\n return this;\n}\n\nfunction recordDeferredEvents(){\n var self = this, currentQueue;\n if (self.queue.capacity > 0) {\n currentQueue = JSON.parse(JSON.stringify(self.queue));\n self.queue = queue();\n self.queue.options = currentQueue.options;\n\n self.emit('recordDeferredEvents', currentQueue.events);\n self.recordEvents(currentQueue.events, function(err, res){\n if (err) {\n // Retry once\n self.recordEvents(currentQueue.events);\n }\n else {\n currentQueue = void 0;\n }\n });\n }\n return self;\n}\n\nfunction handleValidationError(message){\n var err = 'Event(s) not deferred: ' + message;\n this.emit('error', err);\n}\n\n},{\"./index\":10,\"./utils/each\":15,\"./utils/queue\":20}],3:[function(require,module,exports){\nvar deepExtend = require('./utils/deepExtend');\nvar each = require('./utils/each');\n\nmodule.exports = {\n 'extendEvent': extendEvent,\n 'extendEvents': extendEvents,\n 'getExtendedEventBody': getExtendedEventBody\n};\n\nfunction extendEvent(eventCollection, eventModifier){\n if (arguments.length !== 2 || typeof eventCollection !== 'string'\n || ('object' !== typeof eventModifier && 'function' !== typeof eventModifier)) {\n handleValidationError.call(this, 'Incorrect arguments provided to #extendEvent method');\n return;\n }\n this.extensions.collections[eventCollection] = this.extensions.collections[eventCollection] || [];\n this.extensions.collections[eventCollection].push(eventModifier);\n this.emit('extendEvent', eventCollection, eventModifier);\n return this;\n}\n\nfunction extendEvents(eventsModifier){\n if (arguments.length !== 1 || ('object' !== typeof eventsModifier && 'function' !== typeof eventsModifier)) {\n handleValidationError.call(this, 'Incorrect arguments provided to #extendEvents method');\n return;\n }\n this.extensions.events.push(eventsModifier);\n this.emit('extendEvents', eventsModifier);\n return this;\n}\n\nfunction handleValidationError(message){\n var err = 'Event(s) not extended: ' + message;\n this.emit('error', err);\n}\n\nfunction getExtendedEventBody(result, queue){\n if (queue && queue.length > 0) {\n each(queue, function(eventModifier, i){\n var modifierResult = (typeof eventModifier === 'function') ? eventModifier() : eventModifier;\n deepExtend(result, modifierResult);\n });\n }\n return result;\n}\n\n},{\"./utils/deepExtend\":14,\"./utils/each\":15}],4:[function(require,module,exports){\nvar getScreenProfile = require('./getScreenProfile'),\n getWindowProfile = require('./getWindowProfile');\n\nfunction getBrowserProfile(){\n return {\n 'cookies' : ('undefined' !== typeof navigator.cookieEnabled) ? navigator.cookieEnabled : false,\n 'codeName' : navigator.appCodeName,\n 'language' : navigator.language,\n 'name' : navigator.appName,\n 'online' : navigator.onLine,\n 'platform' : navigator.platform,\n 'useragent': navigator.userAgent,\n 'version' : navigator.appVersion,\n 'screen' : getScreenProfile(),\n 'window' : getWindowProfile()\n }\n}\n\nmodule.exports = getBrowserProfile;\n\n},{\"./getScreenProfile\":7,\"./getWindowProfile\":9}],5:[function(require,module,exports){\nfunction getDateTimeIndex(input){\n var date = input || new Date();\n return {\n 'hour_of_day' : date.getHours(),\n 'day_of_week' : parseInt( 1 + date.getDay() ),\n 'day_of_month' : date.getDate(),\n 'month' : parseInt( 1 + date.getMonth() ),\n 'year' : date.getFullYear()\n };\n}\n\nmodule.exports = getDateTimeIndex;\n\n},{}],6:[function(require,module,exports){\nfunction getDomNodePath(el){\n if (!el.nodeName) return '';\n\n var stack = [];\n while ( el.parentNode != null ) {\n // console.log(el.nodeName);\n var sibCount = 0;\n var sibIndex = 0;\n for ( var i = 0; i < el.parentNode.childNodes.length; i++ ) {\n var sib = el.parentNode.childNodes[i];\n if ( sib.nodeName == el.nodeName ) {\n if ( sib === el ) {\n sibIndex = sibCount;\n }\n sibCount++;\n }\n }\n if ( el.hasAttribute('id') && el.id != '' ) {\n stack.unshift(el.nodeName.toLowerCase() + '#' + el.id);\n } else if ( sibCount > 1 ) {\n stack.unshift(el.nodeName.toLowerCase() + ':eq(' + sibIndex + ')');\n } else {\n stack.unshift(el.nodeName.toLowerCase());\n }\n el = el.parentNode;\n }\n\n return stack.slice(1).join(' > ');\n}\n\nmodule.exports = getDomNodePath;\n\n// via: http://stackoverflow.com/a/16742828/2511985\n\n},{}],7:[function(require,module,exports){\nfunction getScreenProfile(){\n var keys, output;\n\n if ('undefined' == typeof window || !window.screen) return {};\n\n keys = ['height', 'width', 'colorDepth', 'pixelDepth', 'availHeight', 'availWidth'];\n output = {};\n\n for (var i = 0; i < keys.length; i++) {\n output[keys[i]] = window.screen[keys[i]] ? window.screen[keys[i]] : null;\n }\n\n output.orientation = {\n 'angle' : window.screen.orientation ? window.screen.orientation['angle'] : 0,\n 'type' : window.innerWidth > window.innerHeight ? 'landscape': 'portrait'\n };\n\n return output;\n}\n\nmodule.exports = getScreenProfile;\n\n},{}],8:[function(require,module,exports){\n// via: http://stackoverflow.com/a/2117523/2511985\n\nfunction getUniqueId(){\n var str = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';\n return str.replace(/[xy]/g, function(c) {\n var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);\n return v.toString(16);\n });\n}\n\nmodule.exports = getUniqueId;\n\n},{}],9:[function(require,module,exports){\nfunction getWindowProfile(){\n var body, html, output;\n\n if ('undefined' == typeof document) return {};\n\n body = document.body;\n html = document.documentElement;\n\n output = {\n 'height': ('innerHeight' in window) ? window.innerHeight : document.documentElement.offsetHeight,\n 'width': ('innerWidth' in window) ? window.innerWidth : document.documentElement.offsetWidth,\n 'scrollHeight': Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight ) || null\n };\n\n if (window.screen) {\n output.ratio = {\n 'height': (window.screen.availHeight) ? parseFloat( (window.innerHeight/window.screen.availHeight).toFixed(2) ) : null,\n 'width': (window.screen.availWidth) ? parseFloat( (window.innerWidth/window.screen.availWidth).toFixed(2) ) : null\n };\n }\n\n return output;\n}\n\nmodule.exports = getWindowProfile;\n\n/*\n Notes:\n document.documentElement.offsetHeight/Width is a workaround for IE8 and below, where window.innerHeight/Width is undefined\n*/\n\n},{}],10:[function(require,module,exports){\nvar Emitter = require('component-emitter');\nvar json = require('./utils/json');\n\nvar each = require('./utils/each');\nvar extend = require('./utils/extend');\nvar queue = require('./utils/queue');\n\nvar K = function(config){\n var self = this;\n\n this.configure(config);\n\n extend(this.config.resources, K.resources);\n\n this.extensions = {\n events: [],\n collections: {}\n };\n\n this.queue = queue();\n this.queue.on('flush', function(){\n self.recordDeferredEvents();\n });\n\n if (K.debug) {\n this.on('error', K.log);\n }\n\n this.emit('ready');\n K.emit('client', this);\n};\n\nEmitter(K);\nEmitter(K.prototype);\n\nextend(K, {\n debug: false,\n enabled: true,\n loaded: false,\n helpers: {},\n resources: {\n 'base' : '{protocol}://{host}',\n 'version' : '{protocol}://{host}/3.0',\n 'projects' : '{protocol}://{host}/3.0/projects',\n 'projectId' : '{protocol}://{host}/3.0/projects/{projectId}',\n 'events' : '{protocol}://{host}/3.0/projects/{projectId}/events'\n },\n utils: {},\n version: '__VERSION__'\n});\n\nK.log = function(message) {\n if (K.debug && typeof console == 'object') {\n console.log('[Keen IO]', message);\n }\n};\n\nK.prototype.configure = function(cfg){\n var self = this,\n config = cfg || {},\n defaultProtocol = 'https';\n\n this.config = this.config || {\n projectId: undefined,\n writeKey: undefined,\n host: 'api.keen.io',\n protocol: defaultProtocol,\n requestType: 'jsonp',\n resources: {},\n writePath: undefined\n };\n\n // IE<10 request shim\n if ('undefined' !== typeof document && document.all) {\n config['protocol'] = (document.location.protocol !== 'https:') ? 'http' : defaultProtocol;\n }\n if (config['host']) {\n config['host'].replace(/.*?:\\/\\//g, '');\n }\n\n extend(this.config, config);\n return self;\n};\n\nK.prototype.projectId = function(str){\n if (!arguments.length) return this.config.projectId;\n this.config.projectId = (str ? String(str) : null);\n return this;\n};\n\nK.prototype.writeKey = function(str){\n if (!arguments.length) return this.config.writeKey;\n this.config.writeKey = (str ? String(str) : null);\n return this;\n};\n\nK.prototype.resources = function(obj){\n if (!arguments.length) return this.config.resources;\n var self = this;\n if (typeof obj === 'object') {\n each(obj, function(value, key){\n self.config.resources[key] = (value ? value : null);\n });\n }\n return this;\n};\n\nK.prototype.url = function(name){\n var args = Array.prototype.slice.call(arguments, 1),\n baseUrl = K.resources.base || '{protocol}://{host}',\n path;\n\n if (name && typeof name === 'string') {\n if (this.config.resources[name]) {\n path = this.config.resources[name];\n }\n else {\n path = baseUrl + name;\n }\n }\n else {\n path = baseUrl;\n }\n\n each(this.config, function(value, key){\n if (typeof value !== 'object') {\n path = path.replace('{' + key + '}', value);\n }\n });\n\n each(args, function(arg, i){\n if (typeof arg === 'string') {\n path += '/' + arg;\n }\n else if (typeof arg === 'object') {\n path += '?';\n each(arg, function(value, key){\n path += key + '=' + value + '&';\n });\n path = path.slice(0, -1);\n }\n });\n\n return path;\n};\n\n\n// ----------------------\n// DEPRECATED\n// ----------------------\n\nK.prototype.setGlobalProperties = function(props){\n K.log('This method has been deprecated. Check out #extendEvents: https://github.com/keen/keen-tracking.js#extend-events');\n if (!props || typeof props !== 'function') {\n this.emit('error', 'Invalid value for global properties: ' + props);\n return;\n }\n this.config.globalProperties = props;\n return this;\n};\n\nK.prototype.writePath = function(str){\n K.log('This method has been deprecated. Use client.url(\\'events\\') instead.');\n if (!arguments.length) return this.config.writePath;\n if (!this.projectId()) {\n this.emit('error', 'Client instance is missing a projectId property');\n return this.config.writePath || ('/3.0/projects/' + this.projectId() + '/events');\n }\n this.config.writePath = str ? String(str) : ('/3.0/projects/' + this.projectId() + '/events');\n return this;\n};\n\n\nfunction serialize(data){\n var query = [];\n each(data, function(value, key){\n if ('string' !== typeof value) {\n value = json.stringify(value);\n }\n query.push(key + '=' + encodeURIComponent(value));\n });\n return query.join('&');\n}\n\nmodule.exports = K;\n\n},{\"./utils/each\":15,\"./utils/extend\":16,\"./utils/json\":17,\"./utils/queue\":20,\"component-emitter\":22}],11:[function(require,module,exports){\nvar Keen = require('./index');\nvar base64 = require('./utils/base64');\nvar each = require('./utils/each');\nvar extend = require('./utils/extend');\nvar extendEvents = require('./extend-events');\nvar json = require('./utils/json');\n\nmodule.exports = {\n 'recordEvent': recordEvent,\n 'recordEvents': recordEvents,\n\n // DEPRECATED\n 'addEvent': addEvent,\n 'addEvents': addEvents\n};\n\n// ------------------------------\n// .recordEvent\n// ------------------------------\n\nfunction recordEvent(eventCollection, eventBody, callback, async){\n var url, data, cb, getRequestUrl, getRequestUrlOkLength, extendedEventBody, isAsync;\n\n url = this.url('events', encodeURIComponent(eventCollection));\n data = {};\n cb = callback;\n\n // Requests are asynchronous by default\n isAsync = ('boolean' === typeof async) ? async : true;\n\n if (!checkValidation.call(this, cb)) {\n return;\n }\n\n if (!eventCollection || typeof eventCollection !== 'string') {\n handleValidationError.call(this, 'Collection name must be a string.', cb);\n return;\n }\n\n // ------------------------------\n // DEPRECATED\n // Apply client.globalProperties\n // ------------------------------\n if (this.config.globalProperties) {\n data = this.config.globalProperties(eventCollection);\n }\n extend(data, eventBody);\n\n // ------------------------------\n // Run extendEvent(s) transforms\n // ------------------------------\n extendedEventBody = {};\n extendEvents.getExtendedEventBody(extendedEventBody, this.extensions.events);\n extendEvents.getExtendedEventBody(extendedEventBody, this.extensions.collections[eventCollection]);\n extendEvents.getExtendedEventBody(extendedEventBody, [data]);\n\n this.emit('recordEvent', eventCollection, extendedEventBody);\n\n if (!Keen.enabled) {\n handleValidationError.call(this, 'Keen.enabled is set to false.', cb);\n return false;\n }\n\n // ------------------------------\n // Send event\n // ------------------------------\n\n getRequestUrl = this.url('events', encodeURIComponent(eventCollection), {\n api_key : this.writeKey(),\n data : base64.encode( json.stringify(extendedEventBody) ),\n modified : new Date().getTime()\n });\n getRequestUrlOkLength = getRequestUrl.length < getUrlMaxLength();\n\n if (isAsync) {\n switch (this.config.requestType) {\n case 'xhr':\n sendXhr.call(this, 'POST', url, extendedEventBody, cb);\n break;\n case 'beacon':\n if (getRequestUrlOkLength) {\n sendBeacon.call(this, getRequestUrl, cb);\n }\n else {\n attemptPostXhr.call(this, url, extendedEventBody,\n 'Beacon URL length exceeds current browser limit, and XHR is not supported.', cb)\n }\n break;\n default:\n if (getRequestUrlOkLength) {\n sendJSONp.call(this, getRequestUrl, cb);\n }\n else {\n attemptPostXhr.call(this, url, extendedEventBody,\n 'JSONp URL length exceeds current browser limit, and XHR is not supported.', cb)\n }\n break;\n }\n }\n else {\n // Send synchronous request\n if (getRequestUrlOkLength) {\n sendSynchronousXhr(getRequestUrl);\n }\n }\n\n callback = cb = null;\n return this;\n}\n\n// ------------------------------\n// .recordEvents\n// ------------------------------\n\nfunction recordEvents(eventsHash, callback){\n var self = this, url, cb, extendedEventsHash;\n\n url = this.url('events');\n cb = callback;\n callback = null;\n\n if (!checkValidation.call(this, cb)) {\n return;\n }\n\n if ('object' !== typeof eventsHash || eventsHash instanceof Array) {\n handleValidationError.call(this, 'First argument must be an object', cb);\n return;\n }\n\n if (arguments.length > 2) {\n handleValidationError.call(this, 'Incorrect arguments provided to #recordEvents method', cb);\n return;\n }\n\n // ------------------------------\n // DEPRECATED\n // Apply client.globalProperties\n // ------------------------------\n if (this.config.globalProperties) {\n // Loop over each set of events\n each(eventsHash, function(events, collection){\n // Loop over each individual event\n each(events, function(body, index){\n // Start with global properties for this collection\n var modified = self.config.globalProperties(collection);\n // Apply provided properties for this event body\n eventsHash[collection][index] = extend(modified, body);\n });\n });\n }\n\n // ------------------------------\n // Run extendEvent(s) transforms\n // ------------------------------\n extendedEventsHash = {};\n each(eventsHash, function(eventList, eventCollection){\n // Find or create collection on new hash\n extendedEventsHash[eventCollection] = extendedEventsHash[eventCollection] || [];\n // Loop over each eventBody in the existing hash\n each(eventList, function(eventBody, index){\n // Create a new data object\n var extendedEventBody = {};\n // Process \"events\" transform pipeline\n extendEvents.getExtendedEventBody(extendedEventBody, self.extensions.events);\n // Process \"collection\" transform pipeline\n extendEvents.getExtendedEventBody(extendedEventBody, self.extensions.collections[eventCollection]);\n // Blend existing eventBody data into the result\n extendEvents.getExtendedEventBody(extendedEventBody, [eventBody]);\n // Push extendedEventBody into new hash\n extendedEventsHash[eventCollection].push(extendedEventBody);\n });\n });\n\n this.emit('recordEvents', extendedEventsHash);\n\n if (!Keen.enabled) {\n handleValidationError.call(this, 'Keen.enabled is set to false.', cb);\n return false;\n }\n\n if (getXhr()) {\n sendXhr.call(this, 'POST', url, extendedEventsHash, cb);\n }\n else {\n // each(eventsHash, function(eventArray, eventCollection){\n // ... send each individually?\n // });\n }\n\n callback = cb = null;\n return this;\n}\n\n\n// ----------------------\n// DEPRECATED\n// ----------------------\n\nfunction addEvent(){\n this.emit('error', 'This method has been deprecated. Check out #recordEvent: https://github.com/keen/keen-tracking.js#record-a-single-event');\n recordEvent.apply(this, arguments);\n}\n\nfunction addEvents(){\n this.emit('error', 'This method has been deprecated. Check out #recordEvents: https://github.com/keen/keen-tracking.js#record-multiple-events');\n recordEvents.apply(this, arguments);\n}\n\n\n// ------------------------------\n// Validation\n// ------------------------------\n\nfunction checkValidation(callback){\n var cb = callback;\n callback = null;\n\n if (!this.projectId()) {\n handleValidationError.call(this, 'Keen.Client is missing a projectId property.', cb);\n return false;\n }\n if (!this.writeKey()) {\n handleValidationError.call(this, 'Keen.Client is missing a writeKey property.', cb);\n return false;\n }\n return true;\n}\n\nfunction handleValidationError(message, cb){\n var err = 'Event(s) not recorded: ' + message;\n this.emit('error', err);\n if (cb) {\n cb.call(this, err, null);\n cb = null;\n }\n}\n\nfunction getUrlMaxLength(){\n if ('undefined' !== typeof window) {\n if (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') > 0) {\n return 2000;\n }\n }\n return 16000;\n}\n\n\n// ------------------------------\n// XHR Requests\n// ------------------------------\n\nfunction attemptPostXhr(url, data, noXhrError, callback) {\n if (getXhr()) {\n sendXhr.call(this, 'POST', url, data, callback);\n }\n else {\n handleValidationError.call(this, noXhrError);\n }\n}\n\nfunction sendXhr(method, url, data, callback){\n var self = this;\n var payload;\n var xhr = getXhr();\n var cb = callback;\n callback = null;\n\n xhr.onreadystatechange = function() {\n var response;\n if (xhr.readyState == 4) {\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n response = json.parse( xhr.responseText );\n } catch (e) {\n Keen.emit('error', 'Could not parse HTTP response: ' + xhr.responseText);\n if (cb) {\n cb.call(self, xhr, null);\n }\n }\n if (cb && response) {\n cb.call(self, null, response);\n }\n }\n else {\n Keen.emit('error', 'HTTP request failed.');\n if (cb) {\n cb.call(self, xhr, null);\n }\n }\n }\n };\n\n xhr.open(method, url, true);\n xhr.setRequestHeader('Authorization', self.writeKey());\n xhr.setRequestHeader('Content-Type', 'application/json');\n\n if (data) {\n payload = json.stringify(data);\n }\n\n if (method.toUpperCase() === 'GET') {\n xhr.send();\n }\n if (method.toUpperCase() === 'POST') {\n xhr.send(payload);\n }\n\n}\n\nfunction sendSynchronousXhr(url){\n var xhr = getXhr();\n if (xhr) {\n xhr.open('GET', url, false);\n xhr.send(null);\n }\n}\n\nfunction getXhr() {\n // yay, superagent!\n var root = 'undefined' == typeof window ? this : window;\n if (root.XMLHttpRequest && ('file:' != root.location.protocol || !root.ActiveXObject)) {\n return new XMLHttpRequest;\n } else {\n try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {}\n try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {}\n try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {}\n try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {}\n }\n return false;\n};\n\n\n// ------------------------------\n// JSON-P Requests\n// ------------------------------\n\nfunction sendJSONp(url, callback){\n var self = this,\n cb = callback,\n timestamp = new Date().getTime(),\n script = document.createElement('script'),\n parent = document.getElementsByTagName('head')[0],\n callbackName = 'keenJSONPCallback',\n loaded = false;\n\n callback = null;\n\n callbackName += timestamp;\n while (callbackName in window) {\n callbackName += 'a';\n }\n window[callbackName] = function(response) {\n if (loaded === true) return;\n loaded = true;\n if (cb) {\n cb.call(self, null, response);\n }\n cleanup();\n };\n script.src = url + '&jsonp=' + callbackName;\n parent.appendChild(script);\n\n // for early IE w/ no onerror event\n script.onreadystatechange = function() {\n if (loaded === false && this.readyState === 'loaded') {\n loaded = true;\n handleError();\n cleanup();\n }\n };\n // non-ie, etc\n script.onerror = function() {\n // on IE9 both onerror and onreadystatechange are called\n if (loaded === false) {\n loaded = true;\n handleError();\n cleanup();\n }\n };\n\n function handleError(){\n if (cb) {\n cb.call(self, 'An error occurred!', null);\n }\n }\n\n function cleanup(){\n window[callbackName] = undefined;\n try {\n delete window[callbackName];\n } catch(e){};\n parent.removeChild(script);\n }\n\n}\n\n\n// ------------------------------\n// Image Beacon Requests\n// ------------------------------\n\nfunction sendBeacon(url, callback){\n var self = this,\n cb = callback,\n img = document.createElement('img'),\n loaded = false;\n\n callback = null;\n\n img.onload = function() {\n loaded = true;\n if ('naturalHeight' in this) {\n if (this.naturalHeight + this.naturalWidth === 0) {\n this.onerror();\n return;\n }\n } else if (this.width + this.height === 0) {\n this.onerror();\n return;\n }\n if (cb) {\n cb.call(self);\n }\n };\n img.onerror = function() {\n loaded = true;\n if (cb) {\n cb.call(self, 'An error occurred!', null);\n }\n };\n img.src = url + '&c=clv1';\n}\n\n},{\"./extend-events\":3,\"./index\":10,\"./utils/base64\":12,\"./utils/each\":15,\"./utils/extend\":16,\"./utils/json\":17}],12:[function(require,module,exports){\nmodule.exports = {\n map: \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\",\n encode: function (n) {\n \"use strict\";\n var o = \"\", i = 0, m = this.map, i1, i2, i3, e1, e2, e3, e4;\n n = this.utf8.encode(n);\n while (i < n.length) {\n i1 = n.charCodeAt(i++); i2 = n.charCodeAt(i++); i3 = n.charCodeAt(i++);\n e1 = (i1 >> 2); e2 = (((i1 & 3) << 4) | (i2 >> 4)); e3 = (isNaN(i2) ? 64 : ((i2 & 15) << 2) | (i3 >> 6));\n e4 = (isNaN(i2) || isNaN(i3)) ? 64 : i3 & 63;\n o = o + m.charAt(e1) + m.charAt(e2) + m.charAt(e3) + m.charAt(e4);\n } return o;\n },\n decode: function (n) {\n \"use strict\";\n var o = \"\", i = 0, m = this.map, cc = String.fromCharCode, e1, e2, e3, e4, c1, c2, c3;\n n = n.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n while (i < n.length) {\n e1 = m.indexOf(n.charAt(i++)); e2 = m.indexOf(n.charAt(i++));\n e3 = m.indexOf(n.charAt(i++)); e4 = m.indexOf(n.charAt(i++));\n c1 = (e1 << 2) | (e2 >> 4); c2 = ((e2 & 15) << 4) | (e3 >> 2);\n c3 = ((e3 & 3) << 6) | e4;\n o = o + (cc(c1) + ((e3 != 64) ? cc(c2) : \"\")) + (((e4 != 64) ? cc(c3) : \"\"));\n } return this.utf8.decode(o);\n },\n utf8: {\n encode: function (n) {\n \"use strict\";\n var o = \"\", i = 0, cc = String.fromCharCode, c;\n while (i < n.length) {\n c = n.charCodeAt(i++); o = o + ((c < 128) ? cc(c) : ((c > 127) && (c < 2048)) ?\n (cc((c >> 6) | 192) + cc((c & 63) | 128)) : (cc((c >> 12) | 224) + cc(((c >> 6) & 63) | 128) + cc((c & 63) | 128)));\n } return o;\n },\n decode: function (n) {\n \"use strict\";\n var o = \"\", i = 0, cc = String.fromCharCode, c2, c;\n while (i < n.length) {\n c = n.charCodeAt(i);\n o = o + ((c < 128) ? [cc(c), i++][0] : ((c > 191) && (c < 224)) ?\n [cc(((c & 31) << 6) | ((c2 = n.charCodeAt(i + 1)) & 63)), (i += 2)][0] :\n [cc(((c & 15) << 12) | (((c2 = n.charCodeAt(i + 1)) & 63) << 6) | ((c3 = n.charCodeAt(i + 2)) & 63)), (i += 3)][0]);\n } return o;\n }\n }\n};\n\n},{}],13:[function(require,module,exports){\nvar Cookies = require('cookies-js');\nvar json = require('./json');\nvar extend = require('./extend');\n\nmodule.exports = cookie;\n\nfunction cookie(str){\n if (!arguments.length) return;\n if (this instanceof cookie === false) {\n return new cookie(str);\n }\n\n this.config = {\n key: str,\n options: {}\n };\n this.data = this.get();\n return this;\n}\n\ncookie.prototype.get = function(str){\n var data = {};\n\n if (Cookies.get(this.config.key)) {\n data = json.parse( decodeURIComponent(Cookies.get(this.config.key)) );\n }\n if (str) {\n return ('undefined' !== typeof data[str]) ? data[str] : null;\n }\n else {\n return data;\n }\n};\n\ncookie.prototype.set = function(str, value){\n if (!arguments.length || !this.enabled()) return this;\n if ('string' === typeof str && arguments.length === 2) {\n this.data[str] = value ? value : null;\n }\n else if ('object' === typeof str && arguments.length === 1) {\n extend(this.data, str);\n }\n Cookies.set(this.config.key, encodeURIComponent( json.stringify(this.data) ), this.config.options);\n return this;\n};\n\ncookie.prototype.expire = function(){\n Cookies.expire(this.config.key);\n this.data = {};\n return this;\n};\n\ncookie.prototype.options = function(obj){\n if (!arguments.length) return this.config.options;\n this.config.options = (typeof obj === 'object') ? obj : {};\n return this;\n};\n\ncookie.prototype.enabled = function(){\n return Cookies.enabled;\n};\n\n},{\"./extend\":16,\"./json\":17,\"cookies-js\":23}],14:[function(require,module,exports){\nvar json = require('./json');\n\nmodule.exports = deepExtend;\n\nfunction deepExtend(target){\n for (var i = 1; i < arguments.length; i++) {\n // Copy unique items from incoming array\n if (target instanceof Array && arguments[i] instanceof Array) {\n for (var j = 0; j < arguments[i].length; j++) {\n if (target.indexOf(arguments[i][j]) < 0) {\n target.push(arguments[i][j]);\n }\n }\n }\n // Blend objects\n else {\n for (var prop in arguments[i]){\n // Recurse when both contain objects of same name and incoming is not a null object\n if ('undefined' !== typeof target[prop] && 'object' === typeof arguments[i][prop] && arguments[i][prop] !== null) {\n deepExtend(target[prop], clone(arguments[i][prop]));\n }\n // Otherwise just copy it over...\n else {\n target[prop] = clone(arguments[i][prop]);\n }\n }\n }\n }\n return target;\n}\n\nfunction clone(input){\n return json.parse( json.stringify(input) );\n}\n\n},{\"./json\":17}],15:[function(require,module,exports){\nmodule.exports = each;\n\nfunction each(o, cb, s){\n var n;\n if (!o){\n return 0;\n }\n s = !s ? o : s;\n if (o instanceof Array){\n // Indexed arrays, needed for Safari\n for (n=0; n a\");\n\n // Listen for a given event\n myClicker.on(\"click\", function(e){\n // do stuff!\n });\n\n // Listen for event once\n myClicker.once(\"click\", function(e){ });\n\n // Cancel a given event listener\n myClicker.off(\"click\");\n\n // Cancel all event listners\n myClicker.off();\n\n*/\n\nmodule.exports = function(ctx){\n\n // Make sure this object exists\n ctx.domListeners = ctx.domListeners || {\n /*\n 'click': {\n '.nav li > a': [fn, fn, fn]\n }\n */\n };\n\n function listener(str){\n if (!str) return;\n if (this instanceof listener === false) {\n return new listener(str);\n }\n this.selector = str;\n return this;\n }\n\n listener.prototype.on = function(str, fn){\n var self = this;\n\n if (arguments.length !== 2 || 'string' !== typeof str || 'function' !== typeof fn) return this;\n\n // Set each listener on a parent dictionary, indexed by event:\n if ('undefined' === typeof ctx.domListeners[str]) {\n addListener(str, eventHandler(str));\n ctx.domListeners[str] = {};\n }\n ctx.domListeners[str][self.selector] = ctx.domListeners[str][self.selector] || [];\n ctx.domListeners[str][self.selector].push(fn);\n return self;\n };\n\n listener.prototype.once = function(str, fn){\n var self = this;\n function on() {\n self.off(str, on);\n return fn.apply(self, arguments);\n }\n on.fn = fn;\n self.on(str, on);\n return self;\n };\n\n listener.prototype.off = function(str, fn){\n var self = this, survivors = [];\n if (arguments.length === 2) {\n each(ctx.domListeners[str][self.selector], function(handler, i){\n if (handler === fn || handler.fn === fn) return;\n survivors.push(handler);\n });\n ctx.domListeners[str][self.selector] = survivors;\n }\n else if (arguments.length === 1) {\n try {\n delete ctx.domListeners[str][self.selector];\n }\n catch(e){\n ctx.domListeners[str][self.selector] = [];\n }\n }\n else {\n // loop over every eventType and delete handlers\n each(ctx.domListeners, function(hash, eventType){\n // if ('undefined' === typeof hash[str]) return;\n try {\n delete ctx.domListeners[eventType][self.selector];\n }\n catch(e){\n ctx.domListeners[eventType][self.selector] = function(){};\n }\n });\n }\n return self;\n };\n\n function eventHandler(eventType){\n return function(e){\n var evt, target;\n\n evt = e || window.event;\n target = evt.target || evt.srcElement;\n\n // If nothing assigned to this event type, let it go\n if ('undefined' === ctx.domListeners[eventType]) return;\n\n each(ctx.domListeners[eventType], function(handlers, key){\n\n if (matches(target, key)) {\n // Call all handlers for this eventType + node\n each(handlers, function(fn, i){\n if ('click' === eventType && 'A' === target.nodeName) {\n deferClickEvent(evt, target, fn);\n }\n else if ('submit' === eventType && 'FORM' === target.nodeName) {\n deferFormSubmit(evt, target, fn);\n }\n else {\n fn(evt);\n }\n });\n }\n else if ('window' === key) {\n // Call all handlers\n each(handlers, function(fn, i){\n fn(evt);\n });\n }\n return;\n });\n };\n }\n\n return listener;\n}\n\n\n// ------------------------------\n// Attach global event listener\n// ------------------------------\n\nfunction addListener(eventType, fn){\n if (document.addEventListener) {\n document.addEventListener(eventType, fn, false);\n } else {\n document.attachEvent(\"on\" + eventType, fn);\n }\n}\n\n\n// ------------------------------\n// Match DOM element to selector\n// ------------------------------\n\nfunction matches(elem, selector) {\n // We'll use querySelectorAll to find all element matching the selector,\n // then check if the given element is included in that list.\n // Executing the query on the parentNode reduces the resulting nodeList,\n // document doesn't have a parentNode, though.\n var nodeList = ( elem.parentNode || document ).querySelectorAll( selector ) || [],\n i = nodeList.length;\n\n // loop on the nodeList\n while ( i-- ) {\n if ( nodeList[i] == elem ) { return true; }\n }\n return false;\n}\n\n\n// ------------------------------\n// Handle 'click' events (A)\n// ------------------------------\n\nfunction deferClickEvent(evt, anchor, callback){\n var timeout = 500,\n targetAttr,\n cbResponse;\n\n // Get 'target' attribute from anchor\n if (anchor.getAttribute !== void 0) {\n targetAttr = anchor.getAttribute(\"target\");\n } else if (anchor.target) {\n targetAttr = anchor.target;\n }\n\n // Fire listener and catch possible response (return false)\n cbResponse = callback(evt);\n\n // If prevented within callback, bail:\n if (('boolean' === typeof cbResponse && cbResponse === false) || evt.defaultPrevented || evt.returnValue === false) {\n if (evt.preventDefault) {\n evt.preventDefault();\n }\n evt.returnValue = false;\n return false;\n }\n // Else if anchor doesn't kick off a new window or tab.. defer and replay the event:\n else if (targetAttr !== '_blank' && targetAttr !== 'blank' && !evt.metaKey) {\n if (evt.preventDefault) {\n evt.preventDefault();\n }\n evt.returnValue = false;\n setTimeout(function(){\n window.location = anchor.href;\n }, timeout);\n }\n\n return false;\n}\n\n\n// ------------------------------\n// Handle 'submit' events (FORM)\n// ------------------------------\n\nfunction deferFormSubmit(evt, form, callback){\n var timeout = 500;\n\n // Fire listener and catch possible response (return false)\n cbResponse = callback(evt);\n\n // If prevented within callback, bail\n if (('boolean' === typeof cbResponse && cbResponse === false) || evt.defaultPrevented || evt.returnValue === false) {\n if (evt.preventDefault) {\n evt.preventDefault();\n }\n evt.returnValue = false;\n return false;\n }\n // Defer and replay event\n else {\n if (evt.preventDefault) {\n evt.preventDefault();\n }\n evt.returnValue = false;\n setTimeout(function(){\n form.submit();\n }, timeout);\n }\n\n return false;\n}\n\n},{\"./each\":15,\"component-emitter\":22}],19:[function(require,module,exports){\nfunction parseParams(str){\n // via: http://stackoverflow.com/a/2880929/2511985\n var urlParams = {},\n match,\n pl = /\\+/g, // Regex for replacing addition symbol with a space\n search = /([^&=]+)=?([^&]*)/g,\n decode = function (s) { return decodeURIComponent(s.replace(pl, \" \")); },\n query = str.split(\"?\")[1];\n\n while (!!(match=search.exec(query))) {\n urlParams[decode(match[1])] = decode(match[2]);\n }\n return urlParams;\n};\n\nmodule.exports = parseParams;\n\n},{}],20:[function(require,module,exports){\nvar Emitter = require('component-emitter');\n\nmodule.exports = queue;\n\nfunction queue(){\n var self = this;\n if (this instanceof queue === false) {\n return new queue();\n }\n\n self.capacity = 0;\n self.interval = 0;\n\n self.config = {\n capacity: 5000,\n interval: 15\n };\n\n self.events = {\n // \"collection 1\": [],\n // \"collection 2\": []\n };\n\n setInterval(function(){\n self.interval++;\n checkQueue.call(self);\n }, 1000);\n\n return self;\n}\n\nfunction checkQueue(){\n if ((this.capacity > 0 && this.interval >= this.config.interval)\n || this.capacity >= this.config.capacity) {\n this.emit('flush');\n this.interval = 0;\n }\n}\n\nEmitter(queue.prototype);\n\n},{\"component-emitter\":22}],21:[function(require,module,exports){\nmodule.exports = timer;\n\nfunction timer(num){\n if (this instanceof timer === false) {\n return new timer(num);\n }\n this.count = num || 0;\n return this;\n}\n\ntimer.prototype.start = function(){\n var self = this;\n this.pause();\n this.interval = setInterval(function(){\n self.count++;\n }, 1000);\n return this;\n};\n\ntimer.prototype.pause = function(){\n clearInterval(this.interval);\n return this;\n};\n\ntimer.prototype.value = function(){\n return this.count;\n};\n\ntimer.prototype.clear = function(){\n this.count = 0;\n return this;\n};\n\n},{}],22:[function(require,module,exports){\n\n/**\n * Expose `Emitter`.\n */\n\nmodule.exports = Emitter;\n\n/**\n * Initialize a new `Emitter`.\n *\n * @api public\n */\n\nfunction Emitter(obj) {\n if (obj) return mixin(obj);\n};\n\n/**\n * Mixin the emitter properties.\n *\n * @param {Object} obj\n * @return {Object}\n * @api private\n */\n\nfunction mixin(obj) {\n for (var key in Emitter.prototype) {\n obj[key] = Emitter.prototype[key];\n }\n return obj;\n}\n\n/**\n * Listen on the given `event` with `fn`.\n *\n * @param {String} event\n * @param {Function} fn\n * @return {Emitter}\n * @api public\n */\n\nEmitter.prototype.on =\nEmitter.prototype.addEventListener = function(event, fn){\n this._callbacks = this._callbacks || {};\n (this._callbacks['$' + event] = this._callbacks['$' + event] || [])\n .push(fn);\n return this;\n};\n\n/**\n * Adds an `event` listener that will be invoked a single\n * time then automatically removed.\n *\n * @param {String} event\n * @param {Function} fn\n * @return {Emitter}\n * @api public\n */\n\nEmitter.prototype.once = function(event, fn){\n function on() {\n this.off(event, on);\n fn.apply(this, arguments);\n }\n\n on.fn = fn;\n this.on(event, on);\n return this;\n};\n\n/**\n * Remove the given callback for `event` or all\n * registered callbacks.\n *\n * @param {String} event\n * @param {Function} fn\n * @return {Emitter}\n * @api public\n */\n\nEmitter.prototype.off =\nEmitter.prototype.removeListener =\nEmitter.prototype.removeAllListeners =\nEmitter.prototype.removeEventListener = function(event, fn){\n this._callbacks = this._callbacks || {};\n\n // all\n if (0 == arguments.length) {\n this._callbacks = {};\n return this;\n }\n\n // specific event\n var callbacks = this._callbacks['$' + event];\n if (!callbacks) return this;\n\n // remove all handlers\n if (1 == arguments.length) {\n delete this._callbacks['$' + event];\n return this;\n }\n\n // remove specific handler\n var cb;\n for (var i = 0; i < callbacks.length; i++) {\n cb = callbacks[i];\n if (cb === fn || cb.fn === fn) {\n callbacks.splice(i, 1);\n break;\n }\n }\n return this;\n};\n\n/**\n * Emit `event` with the given args.\n *\n * @param {String} event\n * @param {Mixed} ...\n * @return {Emitter}\n */\n\nEmitter.prototype.emit = function(event){\n this._callbacks = this._callbacks || {};\n var args = [].slice.call(arguments, 1)\n , callbacks = this._callbacks['$' + event];\n\n if (callbacks) {\n callbacks = callbacks.slice(0);\n for (var i = 0, len = callbacks.length; i < len; ++i) {\n callbacks[i].apply(this, args);\n }\n }\n\n return this;\n};\n\n/**\n * Return array of callbacks for `event`.\n *\n * @param {String} event\n * @return {Array}\n * @api public\n */\n\nEmitter.prototype.listeners = function(event){\n this._callbacks = this._callbacks || {};\n return this._callbacks['$' + event] || [];\n};\n\n/**\n * Check if this emitter has `event` handlers.\n *\n * @param {String} event\n * @return {Boolean}\n * @api public\n */\n\nEmitter.prototype.hasListeners = function(event){\n return !! this.listeners(event).length;\n};\n\n},{}],23:[function(require,module,exports){\n/*\r\n * Cookies.js - 1.2.1\r\n * https://github.com/ScottHamper/Cookies\r\n *\r\n * This is free and unencumbered software released into the public domain.\r\n */\r\n(function (global, undefined) {\r\n 'use strict';\r\n\r\n var factory = function (window) {\r\n if (typeof window.document !== 'object') {\r\n throw new Error('Cookies.js requires a `window` with a `document` object');\r\n }\r\n\r\n var Cookies = function (key, value, options) {\r\n return arguments.length === 1 ?\r\n Cookies.get(key) : Cookies.set(key, value, options);\r\n };\r\n\r\n // Allows for setter injection in unit tests\r\n Cookies._document = window.document;\r\n\r\n // Used to ensure cookie keys do not collide with\r\n // built-in `Object` properties\r\n Cookies._cacheKeyPrefix = 'cookey.'; // Hurr hurr, :)\r\n \r\n Cookies._maxExpireDate = new Date('Fri, 31 Dec 9999 23:59:59 UTC');\r\n\r\n Cookies.defaults = {\r\n path: '/',\r\n secure: false\r\n };\r\n\r\n Cookies.get = function (key) {\r\n if (Cookies._cachedDocumentCookie !== Cookies._document.cookie) {\r\n Cookies._renewCache();\r\n }\r\n\r\n return Cookies._cache[Cookies._cacheKeyPrefix + key];\r\n };\r\n\r\n Cookies.set = function (key, value, options) {\r\n options = Cookies._getExtendedOptions(options);\r\n options.expires = Cookies._getExpiresDate(value === undefined ? -1 : options.expires);\r\n\r\n Cookies._document.cookie = Cookies._generateCookieString(key, value, options);\r\n\r\n return Cookies;\r\n };\r\n\r\n Cookies.expire = function (key, options) {\r\n return Cookies.set(key, undefined, options);\r\n };\r\n\r\n Cookies._getExtendedOptions = function (options) {\r\n return {\r\n path: options && options.path || Cookies.defaults.path,\r\n domain: options && options.domain || Cookies.defaults.domain,\r\n expires: options && options.expires || Cookies.defaults.expires,\r\n secure: options && options.secure !== undefined ? options.secure : Cookies.defaults.secure\r\n };\r\n };\r\n\r\n Cookies._isValidDate = function (date) {\r\n return Object.prototype.toString.call(date) === '[object Date]' && !isNaN(date.getTime());\r\n };\r\n\r\n Cookies._getExpiresDate = function (expires, now) {\r\n now = now || new Date();\r\n\r\n if (typeof expires === 'number') {\r\n expires = expires === Infinity ?\r\n Cookies._maxExpireDate : new Date(now.getTime() + expires * 1000);\r\n } else if (typeof expires === 'string') {\r\n expires = new Date(expires);\r\n }\r\n\r\n if (expires && !Cookies._isValidDate(expires)) {\r\n throw new Error('`expires` parameter cannot be converted to a valid Date instance');\r\n }\r\n\r\n return expires;\r\n };\r\n\r\n Cookies._generateCookieString = function (key, value, options) {\r\n key = key.replace(/[^#$&+\\^`|]/g, encodeURIComponent);\r\n key = key.replace(/\\(/g, '%28').replace(/\\)/g, '%29');\r\n value = (value + '').replace(/[^!#$&-+\\--:<-\\[\\]-~]/g, encodeURIComponent);\r\n options = options || {};\r\n\r\n var cookieString = key + '=' + value;\r\n cookieString += options.path ? ';path=' + options.path : '';\r\n cookieString += options.domain ? ';domain=' + options.domain : '';\r\n cookieString += options.expires ? ';expires=' + options.expires.toUTCString() : '';\r\n cookieString += options.secure ? ';secure' : '';\r\n\r\n return cookieString;\r\n };\r\n\r\n Cookies._getCacheFromString = function (documentCookie) {\r\n var cookieCache = {};\r\n var cookiesArray = documentCookie ? documentCookie.split('; ') : [];\r\n\r\n for (var i = 0; i < cookiesArray.length; i++) {\r\n var cookieKvp = Cookies._getKeyValuePairFromCookieString(cookiesArray[i]);\r\n\r\n if (cookieCache[Cookies._cacheKeyPrefix + cookieKvp.key] === undefined) {\r\n cookieCache[Cookies._cacheKeyPrefix + cookieKvp.key] = cookieKvp.value;\r\n }\r\n }\r\n\r\n return cookieCache;\r\n };\r\n\r\n Cookies._getKeyValuePairFromCookieString = function (cookieString) {\r\n // \"=\" is a valid character in a cookie value according to RFC6265, so cannot `split('=')`\r\n var separatorIndex = cookieString.indexOf('=');\r\n\r\n // IE omits the \"=\" when the cookie value is an empty string\r\n separatorIndex = separatorIndex < 0 ? cookieString.length : separatorIndex;\r\n\r\n return {\r\n key: decodeURIComponent(cookieString.substr(0, separatorIndex)),\r\n value: decodeURIComponent(cookieString.substr(separatorIndex + 1))\r\n };\r\n };\r\n\r\n Cookies._renewCache = function () {\r\n Cookies._cache = Cookies._getCacheFromString(Cookies._document.cookie);\r\n Cookies._cachedDocumentCookie = Cookies._document.cookie;\r\n };\r\n\r\n Cookies._areEnabled = function () {\r\n var testKey = 'cookies.js';\r\n var areEnabled = Cookies.set(testKey, 1).get(testKey) === '1';\r\n Cookies.expire(testKey);\r\n return areEnabled;\r\n };\r\n\r\n Cookies.enabled = Cookies._areEnabled();\r\n\r\n return Cookies;\r\n };\r\n\r\n var cookiesExport = typeof global.document === 'object' ? factory(global) : factory;\r\n\r\n // AMD support\r\n if (typeof define === 'function' && define.amd) {\r\n define(function () { return cookiesExport; });\r\n // CommonJS/Node.js support\r\n } else if (typeof exports === 'object') {\r\n // Support Node.js specific `module.exports` (which can be a function)\r\n if (typeof module === 'object' && typeof module.exports === 'object') {\r\n exports = module.exports = cookiesExport;\r\n }\r\n // But always support CommonJS module 1.1.1 spec (`exports` cannot be a function)\r\n exports.Cookies = cookiesExport;\r\n } else {\r\n global.Cookies = cookiesExport;\r\n }\r\n})(typeof window === 'undefined' ? this : window);\n},{}],24:[function(require,module,exports){\n(function (global){\n/*! JSON v3.3.2 | http://bestiejs.github.io/json3 | Copyright 2012-2014, Kit Cambridge | http://kit.mit-license.org */\n;(function () {\n // Detect the `define` function exposed by asynchronous module loaders. The\n // strict `define` check is necessary for compatibility with `r.js`.\n var isLoader = typeof define === \"function\" && define.amd;\n\n // A set of types used to distinguish objects from primitives.\n var objectTypes = {\n \"function\": true,\n \"object\": true\n };\n\n // Detect the `exports` object exposed by CommonJS implementations.\n var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;\n\n // Use the `global` object exposed by Node (including Browserify via\n // `insert-module-globals`), Narwhal, and Ringo as the default context,\n // and the `window` object in browsers. Rhino exports a `global` function\n // instead.\n var root = objectTypes[typeof window] && window || this,\n freeGlobal = freeExports && objectTypes[typeof module] && module && !module.nodeType && typeof global == \"object\" && global;\n\n if (freeGlobal && (freeGlobal[\"global\"] === freeGlobal || freeGlobal[\"window\"] === freeGlobal || freeGlobal[\"self\"] === freeGlobal)) {\n root = freeGlobal;\n }\n\n // Public: Initializes JSON 3 using the given `context` object, attaching the\n // `stringify` and `parse` functions to the specified `exports` object.\n function runInContext(context, exports) {\n context || (context = root[\"Object\"]());\n exports || (exports = root[\"Object\"]());\n\n // Native constructor aliases.\n var Number = context[\"Number\"] || root[\"Number\"],\n String = context[\"String\"] || root[\"String\"],\n Object = context[\"Object\"] || root[\"Object\"],\n Date = context[\"Date\"] || root[\"Date\"],\n SyntaxError = context[\"SyntaxError\"] || root[\"SyntaxError\"],\n TypeError = context[\"TypeError\"] || root[\"TypeError\"],\n Math = context[\"Math\"] || root[\"Math\"],\n nativeJSON = context[\"JSON\"] || root[\"JSON\"];\n\n // Delegate to the native `stringify` and `parse` implementations.\n if (typeof nativeJSON == \"object\" && nativeJSON) {\n exports.stringify = nativeJSON.stringify;\n exports.parse = nativeJSON.parse;\n }\n\n // Convenience aliases.\n var objectProto = Object.prototype,\n getClass = objectProto.toString,\n isProperty, forEach, undef;\n\n // Test the `Date#getUTC*` methods. Based on work by @Yaffle.\n var isExtended = new Date(-3509827334573292);\n try {\n // The `getUTCFullYear`, `Month`, and `Date` methods return nonsensical\n // results for certain dates in Opera >= 10.53.\n isExtended = isExtended.getUTCFullYear() == -109252 && isExtended.getUTCMonth() === 0 && isExtended.getUTCDate() === 1 &&\n // Safari < 2.0.2 stores the internal millisecond time value correctly,\n // but clips the values returned by the date methods to the range of\n // signed 32-bit integers ([-2 ** 31, 2 ** 31 - 1]).\n isExtended.getUTCHours() == 10 && isExtended.getUTCMinutes() == 37 && isExtended.getUTCSeconds() == 6 && isExtended.getUTCMilliseconds() == 708;\n } catch (exception) {}\n\n // Internal: Determines whether the native `JSON.stringify` and `parse`\n // implementations are spec-compliant. Based on work by Ken Snyder.\n function has(name) {\n if (has[name] !== undef) {\n // Return cached feature test result.\n return has[name];\n }\n var isSupported;\n if (name == \"bug-string-char-index\") {\n // IE <= 7 doesn't support accessing string characters using square\n // bracket notation. IE 8 only supports this for primitives.\n isSupported = \"a\"[0] != \"a\";\n } else if (name == \"json\") {\n // Indicates whether both `JSON.stringify` and `JSON.parse` are\n // supported.\n isSupported = has(\"json-stringify\") && has(\"json-parse\");\n } else {\n var value, serialized = '{\"a\":[1,true,false,null,\"\\\\u0000\\\\b\\\\n\\\\f\\\\r\\\\t\"]}';\n // Test `JSON.stringify`.\n if (name == \"json-stringify\") {\n var stringify = exports.stringify, stringifySupported = typeof stringify == \"function\" && isExtended;\n if (stringifySupported) {\n // A test function object with a custom `toJSON` method.\n (value = function () {\n return 1;\n }).toJSON = value;\n try {\n stringifySupported =\n // Firefox 3.1b1 and b2 serialize string, number, and boolean\n // primitives as object literals.\n stringify(0) === \"0\" &&\n // FF 3.1b1, b2, and JSON 2 serialize wrapped primitives as object\n // literals.\n stringify(new Number()) === \"0\" &&\n stringify(new String()) == '\"\"' &&\n // FF 3.1b1, 2 throw an error if the value is `null`, `undefined`, or\n // does not define a canonical JSON representation (this applies to\n // objects with `toJSON` properties as well, *unless* they are nested\n // within an object or array).\n stringify(getClass) === undef &&\n // IE 8 serializes `undefined` as `\"undefined\"`. Safari <= 5.1.7 and\n // FF 3.1b3 pass this test.\n stringify(undef) === undef &&\n // Safari <= 5.1.7 and FF 3.1b3 throw `Error`s and `TypeError`s,\n // respectively, if the value is omitted entirely.\n stringify() === undef &&\n // FF 3.1b1, 2 throw an error if the given value is not a number,\n // string, array, object, Boolean, or `null` literal. This applies to\n // objects with custom `toJSON` methods as well, unless they are nested\n // inside object or array literals. YUI 3.0.0b1 ignores custom `toJSON`\n // methods entirely.\n stringify(value) === \"1\" &&\n stringify([value]) == \"[1]\" &&\n // Prototype <= 1.6.1 serializes `[undefined]` as `\"[]\"` instead of\n // `\"[null]\"`.\n stringify([undef]) == \"[null]\" &&\n // YUI 3.0.0b1 fails to serialize `null` literals.\n stringify(null) == \"null\" &&\n // FF 3.1b1, 2 halts serialization if an array contains a function:\n // `[1, true, getClass, 1]` serializes as \"[1,true,],\". FF 3.1b3\n // elides non-JSON values from objects and arrays, unless they\n // define custom `toJSON` methods.\n stringify([undef, getClass, null]) == \"[null,null,null]\" &&\n // Simple serialization test. FF 3.1b1 uses Unicode escape sequences\n // where character escape codes are expected (e.g., `\\b` => `\\u0008`).\n stringify({ \"a\": [value, true, false, null, \"\\x00\\b\\n\\f\\r\\t\"] }) == serialized &&\n // FF 3.1b1 and b2 ignore the `filter` and `width` arguments.\n stringify(null, value) === \"1\" &&\n stringify([1, 2], null, 1) == \"[\\n 1,\\n 2\\n]\" &&\n // JSON 2, Prototype <= 1.7, and older WebKit builds incorrectly\n // serialize extended years.\n stringify(new Date(-8.64e15)) == '\"-271821-04-20T00:00:00.000Z\"' &&\n // The milliseconds are optional in ES 5, but required in 5.1.\n stringify(new Date(8.64e15)) == '\"+275760-09-13T00:00:00.000Z\"' &&\n // Firefox <= 11.0 incorrectly serializes years prior to 0 as negative\n // four-digit years instead of six-digit years. Credits: @Yaffle.\n stringify(new Date(-621987552e5)) == '\"-000001-01-01T00:00:00.000Z\"' &&\n // Safari <= 5.1.5 and Opera >= 10.53 incorrectly serialize millisecond\n // values less than 1000. Credits: @Yaffle.\n stringify(new Date(-1)) == '\"1969-12-31T23:59:59.999Z\"';\n } catch (exception) {\n stringifySupported = false;\n }\n }\n isSupported = stringifySupported;\n }\n // Test `JSON.parse`.\n if (name == \"json-parse\") {\n var parse = exports.parse;\n if (typeof parse == \"function\") {\n try {\n // FF 3.1b1, b2 will throw an exception if a bare literal is provided.\n // Conforming implementations should also coerce the initial argument to\n // a string prior to parsing.\n if (parse(\"0\") === 0 && !parse(false)) {\n // Simple parsing test.\n value = parse(serialized);\n var parseSupported = value[\"a\"].length == 5 && value[\"a\"][0] === 1;\n if (parseSupported) {\n try {\n // Safari <= 5.1.2 and FF 3.1b1 allow unescaped tabs in strings.\n parseSupported = !parse('\"\\t\"');\n } catch (exception) {}\n if (parseSupported) {\n try {\n // FF 4.0 and 4.0.1 allow leading `+` signs and leading\n // decimal points. FF 4.0, 4.0.1, and IE 9-10 also allow\n // certain octal literals.\n parseSupported = parse(\"01\") !== 1;\n } catch (exception) {}\n }\n if (parseSupported) {\n try {\n // FF 4.0, 4.0.1, and Rhino 1.7R3-R4 allow trailing decimal\n // points. These environments, along with FF 3.1b1 and 2,\n // also allow trailing commas in JSON objects and arrays.\n parseSupported = parse(\"1.\") !== 1;\n } catch (exception) {}\n }\n }\n }\n } catch (exception) {\n parseSupported = false;\n }\n }\n isSupported = parseSupported;\n }\n }\n return has[name] = !!isSupported;\n }\n\n if (!has(\"json\")) {\n // Common `[[Class]]` name aliases.\n var functionClass = \"[object Function]\",\n dateClass = \"[object Date]\",\n numberClass = \"[object Number]\",\n stringClass = \"[object String]\",\n arrayClass = \"[object Array]\",\n booleanClass = \"[object Boolean]\";\n\n // Detect incomplete support for accessing string characters by index.\n var charIndexBuggy = has(\"bug-string-char-index\");\n\n // Define additional utility methods if the `Date` methods are buggy.\n if (!isExtended) {\n var floor = Math.floor;\n // A mapping between the months of the year and the number of days between\n // January 1st and the first of the respective month.\n var Months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];\n // Internal: Calculates the number of days between the Unix epoch and the\n // first day of the given month.\n var getDay = function (year, month) {\n return Months[month] + 365 * (year - 1970) + floor((year - 1969 + (month = +(month > 1))) / 4) - floor((year - 1901 + month) / 100) + floor((year - 1601 + month) / 400);\n };\n }\n\n // Internal: Determines if a property is a direct property of the given\n // object. Delegates to the native `Object#hasOwnProperty` method.\n if (!(isProperty = objectProto.hasOwnProperty)) {\n isProperty = function (property) {\n var members = {}, constructor;\n if ((members.__proto__ = null, members.__proto__ = {\n // The *proto* property cannot be set multiple times in recent\n // versions of Firefox and SeaMonkey.\n \"toString\": 1\n }, members).toString != getClass) {\n // Safari <= 2.0.3 doesn't implement `Object#hasOwnProperty`, but\n // supports the mutable *proto* property.\n isProperty = function (property) {\n // Capture and break the object's prototype chain (see section 8.6.2\n // of the ES 5.1 spec). The parenthesized expression prevents an\n // unsafe transformation by the Closure Compiler.\n var original = this.__proto__, result = property in (this.__proto__ = null, this);\n // Restore the original prototype chain.\n this.__proto__ = original;\n return result;\n };\n } else {\n // Capture a reference to the top-level `Object` constructor.\n constructor = members.constructor;\n // Use the `constructor` property to simulate `Object#hasOwnProperty` in\n // other environments.\n isProperty = function (property) {\n var parent = (this.constructor || constructor).prototype;\n return property in this && !(property in parent && this[property] === parent[property]);\n };\n }\n members = null;\n return isProperty.call(this, property);\n };\n }\n\n // Internal: Normalizes the `for...in` iteration algorithm across\n // environments. Each enumerated key is yielded to a `callback` function.\n forEach = function (object, callback) {\n var size = 0, Properties, members, property;\n\n // Tests for bugs in the current environment's `for...in` algorithm. The\n // `valueOf` property inherits the non-enumerable flag from\n // `Object.prototype` in older versions of IE, Netscape, and Mozilla.\n (Properties = function () {\n this.valueOf = 0;\n }).prototype.valueOf = 0;\n\n // Iterate over a new instance of the `Properties` class.\n members = new Properties();\n for (property in members) {\n // Ignore all properties inherited from `Object.prototype`.\n if (isProperty.call(members, property)) {\n size++;\n }\n }\n Properties = members = null;\n\n // Normalize the iteration algorithm.\n if (!size) {\n // A list of non-enumerable properties inherited from `Object.prototype`.\n members = [\"valueOf\", \"toString\", \"toLocaleString\", \"propertyIsEnumerable\", \"isPrototypeOf\", \"hasOwnProperty\", \"constructor\"];\n // IE <= 8, Mozilla 1.0, and Netscape 6.2 ignore shadowed non-enumerable\n // properties.\n forEach = function (object, callback) {\n var isFunction = getClass.call(object) == functionClass, property, length;\n var hasProperty = !isFunction && typeof object.constructor != \"function\" && objectTypes[typeof object.hasOwnProperty] && object.hasOwnProperty || isProperty;\n for (property in object) {\n // Gecko <= 1.0 enumerates the `prototype` property of functions under\n // certain conditions; IE does not.\n if (!(isFunction && property == \"prototype\") && hasProperty.call(object, property)) {\n callback(property);\n }\n }\n // Manually invoke the callback for each non-enumerable property.\n for (length = members.length; property = members[--length]; hasProperty.call(object, property) && callback(property));\n };\n } else if (size == 2) {\n // Safari <= 2.0.4 enumerates shadowed properties twice.\n forEach = function (object, callback) {\n // Create a set of iterated properties.\n var members = {}, isFunction = getClass.call(object) == functionClass, property;\n for (property in object) {\n // Store each property name to prevent double enumeration. The\n // `prototype` property of functions is not enumerated due to cross-\n // environment inconsistencies.\n if (!(isFunction && property == \"prototype\") && !isProperty.call(members, property) && (members[property] = 1) && isProperty.call(object, property)) {\n callback(property);\n }\n }\n };\n } else {\n // No bugs detected; use the standard `for...in` algorithm.\n forEach = function (object, callback) {\n var isFunction = getClass.call(object) == functionClass, property, isConstructor;\n for (property in object) {\n if (!(isFunction && property == \"prototype\") && isProperty.call(object, property) && !(isConstructor = property === \"constructor\")) {\n callback(property);\n }\n }\n // Manually invoke the callback for the `constructor` property due to\n // cross-environment inconsistencies.\n if (isConstructor || isProperty.call(object, (property = \"constructor\"))) {\n callback(property);\n }\n };\n }\n return forEach(object, callback);\n };\n\n // Public: Serializes a JavaScript `value` as a JSON string. The optional\n // `filter` argument may specify either a function that alters how object and\n // array members are serialized, or an array of strings and numbers that\n // indicates which properties should be serialized. The optional `width`\n // argument may be either a string or number that specifies the indentation\n // level of the output.\n if (!has(\"json-stringify\")) {\n // Internal: A map of control characters and their escaped equivalents.\n var Escapes = {\n 92: \"\\\\\\\\\",\n 34: '\\\\\"',\n 8: \"\\\\b\",\n 12: \"\\\\f\",\n 10: \"\\\\n\",\n 13: \"\\\\r\",\n 9: \"\\\\t\"\n };\n\n // Internal: Converts `value` into a zero-padded string such that its\n // length is at least equal to `width`. The `width` must be <= 6.\n var leadingZeroes = \"000000\";\n var toPaddedString = function (width, value) {\n // The `|| 0` expression is necessary to work around a bug in\n // Opera <= 7.54u2 where `0 == -0`, but `String(-0) !== \"0\"`.\n return (leadingZeroes + (value || 0)).slice(-width);\n };\n\n // Internal: Double-quotes a string `value`, replacing all ASCII control\n // characters (characters with code unit values between 0 and 31) with\n // their escaped equivalents. This is an implementation of the\n // `Quote(value)` operation defined in ES 5.1 section 15.12.3.\n var unicodePrefix = \"\\\\u00\";\n var quote = function (value) {\n var result = '\"', index = 0, length = value.length, useCharIndex = !charIndexBuggy || length > 10;\n var symbols = useCharIndex && (charIndexBuggy ? value.split(\"\") : value);\n for (; index < length; index++) {\n var charCode = value.charCodeAt(index);\n // If the character is a control character, append its Unicode or\n // shorthand escape sequence; otherwise, append the character as-is.\n switch (charCode) {\n case 8: case 9: case 10: case 12: case 13: case 34: case 92:\n result += Escapes[charCode];\n break;\n default:\n if (charCode < 32) {\n result += unicodePrefix + toPaddedString(2, charCode.toString(16));\n break;\n }\n result += useCharIndex ? symbols[index] : value.charAt(index);\n }\n }\n return result + '\"';\n };\n\n // Internal: Recursively serializes an object. Implements the\n // `Str(key, holder)`, `JO(value)`, and `JA(value)` operations.\n var serialize = function (property, object, callback, properties, whitespace, indentation, stack) {\n var value, className, year, month, date, time, hours, minutes, seconds, milliseconds, results, element, index, length, prefix, result;\n try {\n // Necessary for host object support.\n value = object[property];\n } catch (exception) {}\n if (typeof value == \"object\" && value) {\n className = getClass.call(value);\n if (className == dateClass && !isProperty.call(value, \"toJSON\")) {\n if (value > -1 / 0 && value < 1 / 0) {\n // Dates are serialized according to the `Date#toJSON` method\n // specified in ES 5.1 section 15.9.5.44. See section 15.9.1.15\n // for the ISO 8601 date time string format.\n if (getDay) {\n // Manually compute the year, month, date, hours, minutes,\n // seconds, and milliseconds if the `getUTC*` methods are\n // buggy. Adapted from @Yaffle's `date-shim` project.\n date = floor(value / 864e5);\n for (year = floor(date / 365.2425) + 1970 - 1; getDay(year + 1, 0) <= date; year++);\n for (month = floor((date - getDay(year, 0)) / 30.42); getDay(year, month + 1) <= date; month++);\n date = 1 + date - getDay(year, month);\n // The `time` value specifies the time within the day (see ES\n // 5.1 section 15.9.1.2). The formula `(A % B + B) % B` is used\n // to compute `A modulo B`, as the `%` operator does not\n // correspond to the `modulo` operation for negative numbers.\n time = (value % 864e5 + 864e5) % 864e5;\n // The hours, minutes, seconds, and milliseconds are obtained by\n // decomposing the time within the day. See section 15.9.1.10.\n hours = floor(time / 36e5) % 24;\n minutes = floor(time / 6e4) % 60;\n seconds = floor(time / 1e3) % 60;\n milliseconds = time % 1e3;\n } else {\n year = value.getUTCFullYear();\n month = value.getUTCMonth();\n date = value.getUTCDate();\n hours = value.getUTCHours();\n minutes = value.getUTCMinutes();\n seconds = value.getUTCSeconds();\n milliseconds = value.getUTCMilliseconds();\n }\n // Serialize extended years correctly.\n value = (year <= 0 || year >= 1e4 ? (year < 0 ? \"-\" : \"+\") + toPaddedString(6, year < 0 ? -year : year) : toPaddedString(4, year)) +\n \"-\" + toPaddedString(2, month + 1) + \"-\" + toPaddedString(2, date) +\n // Months, dates, hours, minutes, and seconds should have two\n // digits; milliseconds should have three.\n \"T\" + toPaddedString(2, hours) + \":\" + toPaddedString(2, minutes) + \":\" + toPaddedString(2, seconds) +\n // Milliseconds are optional in ES 5.0, but required in 5.1.\n \".\" + toPaddedString(3, milliseconds) + \"Z\";\n } else {\n value = null;\n }\n } else if (typeof value.toJSON == \"function\" && ((className != numberClass && className != stringClass && className != arrayClass) || isProperty.call(value, \"toJSON\"))) {\n // Prototype <= 1.6.1 adds non-standard `toJSON` methods to the\n // `Number`, `String`, `Date`, and `Array` prototypes. JSON 3\n // ignores all `toJSON` methods on these objects unless they are\n // defined directly on an instance.\n value = value.toJSON(property);\n }\n }\n if (callback) {\n // If a replacement function was provided, call it to obtain the value\n // for serialization.\n value = callback.call(object, property, value);\n }\n if (value === null) {\n return \"null\";\n }\n className = getClass.call(value);\n if (className == booleanClass) {\n // Booleans are represented literally.\n return \"\" + value;\n } else if (className == numberClass) {\n // JSON numbers must be finite. `Infinity` and `NaN` are serialized as\n // `\"null\"`.\n return value > -1 / 0 && value < 1 / 0 ? \"\" + value : \"null\";\n } else if (className == stringClass) {\n // Strings are double-quoted and escaped.\n return quote(\"\" + value);\n }\n // Recursively serialize objects and arrays.\n if (typeof value == \"object\") {\n // Check for cyclic structures. This is a linear search; performance\n // is inversely proportional to the number of unique nested objects.\n for (length = stack.length; length--;) {\n if (stack[length] === value) {\n // Cyclic structures cannot be serialized by `JSON.stringify`.\n throw TypeError();\n }\n }\n // Add the object to the stack of traversed objects.\n stack.push(value);\n results = [];\n // Save the current indentation level and indent one additional level.\n prefix = indentation;\n indentation += whitespace;\n if (className == arrayClass) {\n // Recursively serialize array elements.\n for (index = 0, length = value.length; index < length; index++) {\n element = serialize(index, value, callback, properties, whitespace, indentation, stack);\n results.push(element === undef ? \"null\" : element);\n }\n result = results.length ? (whitespace ? \"[\\n\" + indentation + results.join(\",\\n\" + indentation) + \"\\n\" + prefix + \"]\" : (\"[\" + results.join(\",\") + \"]\")) : \"[]\";\n } else {\n // Recursively serialize object members. Members are selected from\n // either a user-specified list of property names, or the object\n // itself.\n forEach(properties || value, function (property) {\n var element = serialize(property, value, callback, properties, whitespace, indentation, stack);\n if (element !== undef) {\n // According to ES 5.1 section 15.12.3: \"If `gap` {whitespace}\n // is not the empty string, let `member` {quote(property) + \":\"}\n // be the concatenation of `member` and the `space` character.\"\n // The \"`space` character\" refers to the literal space\n // character, not the `space` {width} argument provided to\n // `JSON.stringify`.\n results.push(quote(property) + \":\" + (whitespace ? \" \" : \"\") + element);\n }\n });\n result = results.length ? (whitespace ? \"{\\n\" + indentation + results.join(\",\\n\" + indentation) + \"\\n\" + prefix + \"}\" : (\"{\" + results.join(\",\") + \"}\")) : \"{}\";\n }\n // Remove the object from the traversed object stack.\n stack.pop();\n return result;\n }\n };\n\n // Public: `JSON.stringify`. See ES 5.1 section 15.12.3.\n exports.stringify = function (source, filter, width) {\n var whitespace, callback, properties, className;\n if (objectTypes[typeof filter] && filter) {\n if ((className = getClass.call(filter)) == functionClass) {\n callback = filter;\n } else if (className == arrayClass) {\n // Convert the property names array into a makeshift set.\n properties = {};\n for (var index = 0, length = filter.length, value; index < length; value = filter[index++], ((className = getClass.call(value)), className == stringClass || className == numberClass) && (properties[value] = 1));\n }\n }\n if (width) {\n if ((className = getClass.call(width)) == numberClass) {\n // Convert the `width` to an integer and create a string containing\n // `width` number of space characters.\n if ((width -= width % 1) > 0) {\n for (whitespace = \"\", width > 10 && (width = 10); whitespace.length < width; whitespace += \" \");\n }\n } else if (className == stringClass) {\n whitespace = width.length <= 10 ? width : width.slice(0, 10);\n }\n }\n // Opera <= 7.54u2 discards the values associated with empty string keys\n // (`\"\"`) only if they are used directly within an object member list\n // (e.g., `!(\"\" in { \"\": 1})`).\n return serialize(\"\", (value = {}, value[\"\"] = source, value), callback, properties, whitespace, \"\", []);\n };\n }\n\n // Public: Parses a JSON source string.\n if (!has(\"json-parse\")) {\n var fromCharCode = String.fromCharCode;\n\n // Internal: A map of escaped control characters and their unescaped\n // equivalents.\n var Unescapes = {\n 92: \"\\\\\",\n 34: '\"',\n 47: \"/\",\n 98: \"\\b\",\n 116: \"\\t\",\n 110: \"\\n\",\n 102: \"\\f\",\n 114: \"\\r\"\n };\n\n // Internal: Stores the parser state.\n var Index, Source;\n\n // Internal: Resets the parser state and throws a `SyntaxError`.\n var abort = function () {\n Index = Source = null;\n throw SyntaxError();\n };\n\n // Internal: Returns the next token, or `\"$\"` if the parser has reached\n // the end of the source string. A token may be a string, number, `null`\n // literal, or Boolean literal.\n var lex = function () {\n var source = Source, length = source.length, value, begin, position, isSigned, charCode;\n while (Index < length) {\n charCode = source.charCodeAt(Index);\n switch (charCode) {\n case 9: case 10: case 13: case 32:\n // Skip whitespace tokens, including tabs, carriage returns, line\n // feeds, and space characters.\n Index++;\n break;\n case 123: case 125: case 91: case 93: case 58: case 44:\n // Parse a punctuator token (`{`, `}`, `[`, `]`, `:`, or `,`) at\n // the current position.\n value = charIndexBuggy ? source.charAt(Index) : source[Index];\n Index++;\n return value;\n case 34:\n // `\"` delimits a JSON string; advance to the next character and\n // begin parsing the string. String tokens are prefixed with the\n // sentinel `@` character to distinguish them from punctuators and\n // end-of-string tokens.\n for (value = \"@\", Index++; Index < length;) {\n charCode = source.charCodeAt(Index);\n if (charCode < 32) {\n // Unescaped ASCII control characters (those with a code unit\n // less than the space character) are not permitted.\n abort();\n } else if (charCode == 92) {\n // A reverse solidus (`\\`) marks the beginning of an escaped\n // control character (including `\"`, `\\`, and `/`) or Unicode\n // escape sequence.\n charCode = source.charCodeAt(++Index);\n switch (charCode) {\n case 92: case 34: case 47: case 98: case 116: case 110: case 102: case 114:\n // Revive escaped control characters.\n value += Unescapes[charCode];\n Index++;\n break;\n case 117:\n // `\\u` marks the beginning of a Unicode escape sequence.\n // Advance to the first character and validate the\n // four-digit code point.\n begin = ++Index;\n for (position = Index + 4; Index < position; Index++) {\n charCode = source.charCodeAt(Index);\n // A valid sequence comprises four hexdigits (case-\n // insensitive) that form a single hexadecimal value.\n if (!(charCode >= 48 && charCode <= 57 || charCode >= 97 && charCode <= 102 || charCode >= 65 && charCode <= 70)) {\n // Invalid Unicode escape sequence.\n abort();\n }\n }\n // Revive the escaped character.\n value += fromCharCode(\"0x\" + source.slice(begin, Index));\n break;\n default:\n // Invalid escape sequence.\n abort();\n }\n } else {\n if (charCode == 34) {\n // An unescaped double-quote character marks the end of the\n // string.\n break;\n }\n charCode = source.charCodeAt(Index);\n begin = Index;\n // Optimize for the common case where a string is valid.\n while (charCode >= 32 && charCode != 92 && charCode != 34) {\n charCode = source.charCodeAt(++Index);\n }\n // Append the string as-is.\n value += source.slice(begin, Index);\n }\n }\n if (source.charCodeAt(Index) == 34) {\n // Advance to the next character and return the revived string.\n Index++;\n return value;\n }\n // Unterminated string.\n abort();\n default:\n // Parse numbers and literals.\n begin = Index;\n // Advance past the negative sign, if one is specified.\n if (charCode == 45) {\n isSigned = true;\n charCode = source.charCodeAt(++Index);\n }\n // Parse an integer or floating-point value.\n if (charCode >= 48 && charCode <= 57) {\n // Leading zeroes are interpreted as octal literals.\n if (charCode == 48 && ((charCode = source.charCodeAt(Index + 1)), charCode >= 48 && charCode <= 57)) {\n // Illegal octal literal.\n abort();\n }\n isSigned = false;\n // Parse the integer component.\n for (; Index < length && ((charCode = source.charCodeAt(Index)), charCode >= 48 && charCode <= 57); Index++);\n // Floats cannot contain a leading decimal point; however, this\n // case is already accounted for by the parser.\n if (source.charCodeAt(Index) == 46) {\n position = ++Index;\n // Parse the decimal component.\n for (; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++);\n if (position == Index) {\n // Illegal trailing decimal.\n abort();\n }\n Index = position;\n }\n // Parse exponents. The `e` denoting the exponent is\n // case-insensitive.\n charCode = source.charCodeAt(Index);\n if (charCode == 101 || charCode == 69) {\n charCode = source.charCodeAt(++Index);\n // Skip past the sign following the exponent, if one is\n // specified.\n if (charCode == 43 || charCode == 45) {\n Index++;\n }\n // Parse the exponential component.\n for (position = Index; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++);\n if (position == Index) {\n // Illegal empty exponent.\n abort();\n }\n Index = position;\n }\n // Coerce the parsed value to a JavaScript number.\n return +source.slice(begin, Index);\n }\n // A negative sign may only precede numbers.\n if (isSigned) {\n abort();\n }\n // `true`, `false`, and `null` literals.\n if (source.slice(Index, Index + 4) == \"true\") {\n Index += 4;\n return true;\n } else if (source.slice(Index, Index + 5) == \"false\") {\n Index += 5;\n return false;\n } else if (source.slice(Index, Index + 4) == \"null\") {\n Index += 4;\n return null;\n }\n // Unrecognized token.\n abort();\n }\n }\n // Return the sentinel `$` character if the parser has reached the end\n // of the source string.\n return \"$\";\n };\n\n // Internal: Parses a JSON `value` token.\n var get = function (value) {\n var results, hasMembers;\n if (value == \"$\") {\n // Unexpected end of input.\n abort();\n }\n if (typeof value == \"string\") {\n if ((charIndexBuggy ? value.charAt(0) : value[0]) == \"@\") {\n // Remove the sentinel `@` character.\n return value.slice(1);\n }\n // Parse object and array literals.\n if (value == \"[\") {\n // Parses a JSON array, returning a new JavaScript array.\n results = [];\n for (;; hasMembers || (hasMembers = true)) {\n value = lex();\n // A closing square bracket marks the end of the array literal.\n if (value == \"]\") {\n break;\n }\n // If the array literal contains elements, the current token\n // should be a comma separating the previous element from the\n // next.\n if (hasMembers) {\n if (value == \",\") {\n value = lex();\n if (value == \"]\") {\n // Unexpected trailing `,` in array literal.\n abort();\n }\n } else {\n // A `,` must separate each array element.\n abort();\n }\n }\n // Elisions and leading commas are not permitted.\n if (value == \",\") {\n abort();\n }\n results.push(get(value));\n }\n return results;\n } else if (value == \"{\") {\n // Parses a JSON object, returning a new JavaScript object.\n results = {};\n for (;; hasMembers || (hasMembers = true)) {\n value = lex();\n // A closing curly brace marks the end of the object literal.\n if (value == \"}\") {\n break;\n }\n // If the object literal contains members, the current token\n // should be a comma separator.\n if (hasMembers) {\n if (value == \",\") {\n value = lex();\n if (value == \"}\") {\n // Unexpected trailing `,` in object literal.\n abort();\n }\n } else {\n // A `,` must separate each object member.\n abort();\n }\n }\n // Leading commas are not permitted, object property names must be\n // double-quoted strings, and a `:` must separate each property\n // name and value.\n if (value == \",\" || typeof value != \"string\" || (charIndexBuggy ? value.charAt(0) : value[0]) != \"@\" || lex() != \":\") {\n abort();\n }\n results[value.slice(1)] = get(lex());\n }\n return results;\n }\n // Unexpected token encountered.\n abort();\n }\n return value;\n };\n\n // Internal: Updates a traversed object member.\n var update = function (source, property, callback) {\n var element = walk(source, property, callback);\n if (element === undef) {\n delete source[property];\n } else {\n source[property] = element;\n }\n };\n\n // Internal: Recursively traverses a parsed JSON object, invoking the\n // `callback` function for each value. This is an implementation of the\n // `Walk(holder, name)` operation defined in ES 5.1 section 15.12.2.\n var walk = function (source, property, callback) {\n var value = source[property], length;\n if (typeof value == \"object\" && value) {\n // `forEach` can't be used to traverse an array in Opera <= 8.54\n // because its `Object#hasOwnProperty` implementation returns `false`\n // for array indices (e.g., `![1, 2, 3].hasOwnProperty(\"0\")`).\n if (getClass.call(value) == arrayClass) {\n for (length = value.length; length--;) {\n update(value, length, callback);\n }\n } else {\n forEach(value, function (property) {\n update(value, property, callback);\n });\n }\n }\n return callback.call(source, property, value);\n };\n\n // Public: `JSON.parse`. See ES 5.1 section 15.12.2.\n exports.parse = function (source, callback) {\n var result, value;\n Index = 0;\n Source = \"\" + source;\n result = get(lex());\n // If a JSON string contains multiple tokens, it is invalid.\n if (lex() != \"$\") {\n abort();\n }\n // Reset the parser state.\n Index = Source = null;\n return callback && getClass.call(callback) == functionClass ? walk((value = {}, value[\"\"] = result, value), \"\", callback) : result;\n };\n }\n }\n\n exports[\"runInContext\"] = runInContext;\n return exports;\n }\n\n if (freeExports && !isLoader) {\n // Export for CommonJS environments.\n runInContext(root, freeExports);\n } else {\n // Export for web browsers and JavaScript engines.\n var nativeJSON = root.JSON,\n previousJSON = root[\"JSON3\"],\n isRestored = false;\n\n var JSON3 = runInContext(root, (root[\"JSON3\"] = {\n // Public: Restores the original value of the global `JSON` object and\n // returns a reference to the `JSON3` object.\n \"noConflict\": function () {\n if (!isRestored) {\n isRestored = true;\n root.JSON = nativeJSON;\n root[\"JSON3\"] = previousJSON;\n nativeJSON = previousJSON = null;\n }\n return JSON3;\n }\n }));\n\n root.JSON = {\n \"parse\": JSON3.parse,\n \"stringify\": JSON3.stringify\n };\n }\n\n // Export for asynchronous module loaders.\n if (isLoader) {\n define(function () {\n return JSON3;\n });\n }\n}).call(this);\n\n}).call(this,typeof global !== \"undefined\" ? global : typeof self !== \"undefined\" ? self : typeof window !== \"undefined\" ? window : {})\n},{}]},{},[1]);\n"],"file":"keen-tracking.js","sourceRoot":"/source/"} \ No newline at end of file From b3687d22dce22e3eecda8cac4096159aab9e626b Mon Sep 17 00:00:00 2001 From: aroc Date: Thu, 24 Mar 2016 12:13:59 -0600 Subject: [PATCH 04/10] Use property instead of function --- dist/keen-tracking.js | 2099 ++++++++++++++++++++++++ dist/keen-tracking.min.js | 10 +- test/unit/modules/utils/cookie-spec.js | 10 +- 3 files changed, 2115 insertions(+), 4 deletions(-) create mode 100644 dist/keen-tracking.js diff --git a/dist/keen-tracking.js b/dist/keen-tracking.js new file mode 100644 index 0000000..7d7b010 --- /dev/null +++ b/dist/keen-tracking.js @@ -0,0 +1,2099 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o or DOM element'); + } + if (timeoutCallback) { + callback = function(){ + if(!triggered){ + triggered = true; + timeoutCallback(); + } + }; + } + this.recordEvent(eventCollection, payload, callback); + setTimeout(callback, timer); + if (!evt.metaKey) { + return false; + } + } + if (!Array.prototype.indexOf){ + Array.prototype.indexOf = function(elt /*, from*/) { + var len = this.length >>> 0; + var from = Number(arguments[1]) || 0; + from = (from < 0) + ? Math.ceil(from) + : Math.floor(from); + if (from < 0) + from += len; + for (; from < len; from++) { + if (from in this && + this[from] === elt) + return from; + } + return -1; + }; + } + module.exports = Keen; + return Keen; +}); +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./":10,"./defer-events":2,"./extend-events":3,"./helpers/getBrowserProfile":4,"./helpers/getDatetimeIndex":5,"./helpers/getDomNodePath":6,"./helpers/getScreenProfile":7,"./helpers/getUniqueId":8,"./helpers/getWindowProfile":9,"./record-events-browser":11,"./utils/cookie":13,"./utils/deepExtend":14,"./utils/each":15,"./utils/extend":16,"./utils/listener":18,"./utils/parseParams":19,"./utils/timer":21}],2:[function(require,module,exports){ +var Keen = require('./index'); +var each = require('./utils/each'); +var queue = require('./utils/queue'); +module.exports = { + 'deferEvent': deferEvent, + 'deferEvents': deferEvents, + 'queueCapacity': queueCapacity, + 'queueInterval': queueInterval, + 'recordDeferredEvents': recordDeferredEvents +}; +function deferEvent(eventCollection, eventBody){ + if (arguments.length !== 2 || typeof eventCollection !== 'string') { + handleValidationError.call(this, 'Incorrect arguments provided to #deferEvent method'); + return; + } + this.queue.events[eventCollection] = this.queue.events[eventCollection] || []; + this.queue.events[eventCollection].push(eventBody); + this.queue.capacity++; + this.emit('deferEvent', eventCollection, eventBody); + return this; +} +function deferEvents(eventsHash){ + var self = this; + if (arguments.length !== 1 || typeof eventsHash !== 'object') { + handleValidationError.call(this, 'Incorrect arguments provided to #deferEvents method'); + return; + } + each(eventsHash, function(eventList, eventCollection){ + self.queue.events[eventCollection] = self.queue.events[eventCollection] || []; + self.queue.events[eventCollection] = self.queue.events[eventCollection].concat(eventList); + self.queue.capacity = self.queue.capacity + eventList.length; + }); + self.emit('deferEvents', eventsHash); + return self; +} +function queueCapacity(num){ + if (!arguments.length) return this.queue.config.capacity; + this.queue.config.capacity = num ? Number(num): 0; + return this; +} +function queueInterval(num){ + if (!arguments.length) return this.queue.config.interval; + this.queue.config.interval = num ? Number(num): 0; + return this; +} +function recordDeferredEvents(){ + var self = this, currentQueue; + if (self.queue.capacity > 0) { + currentQueue = JSON.parse(JSON.stringify(self.queue)); + self.queue = queue(); + self.queue.options = currentQueue.options; + self.emit('recordDeferredEvents', currentQueue.events); + self.recordEvents(currentQueue.events, function(err, res){ + if (err) { + self.recordEvents(currentQueue.events); + } + else { + currentQueue = void 0; + } + }); + } + return self; +} +function handleValidationError(message){ + var err = 'Event(s) not deferred: ' + message; + this.emit('error', err); +} +},{"./index":10,"./utils/each":15,"./utils/queue":20}],3:[function(require,module,exports){ +var deepExtend = require('./utils/deepExtend'); +var each = require('./utils/each'); +module.exports = { + 'extendEvent': extendEvent, + 'extendEvents': extendEvents, + 'getExtendedEventBody': getExtendedEventBody +}; +function extendEvent(eventCollection, eventModifier){ + if (arguments.length !== 2 || typeof eventCollection !== 'string' + || ('object' !== typeof eventModifier && 'function' !== typeof eventModifier)) { + handleValidationError.call(this, 'Incorrect arguments provided to #extendEvent method'); + return; + } + this.extensions.collections[eventCollection] = this.extensions.collections[eventCollection] || []; + this.extensions.collections[eventCollection].push(eventModifier); + this.emit('extendEvent', eventCollection, eventModifier); + return this; +} +function extendEvents(eventsModifier){ + if (arguments.length !== 1 || ('object' !== typeof eventsModifier && 'function' !== typeof eventsModifier)) { + handleValidationError.call(this, 'Incorrect arguments provided to #extendEvents method'); + return; + } + this.extensions.events.push(eventsModifier); + this.emit('extendEvents', eventsModifier); + return this; +} +function handleValidationError(message){ + var err = 'Event(s) not extended: ' + message; + this.emit('error', err); +} +function getExtendedEventBody(result, queue){ + if (queue && queue.length > 0) { + each(queue, function(eventModifier, i){ + var modifierResult = (typeof eventModifier === 'function') ? eventModifier() : eventModifier; + deepExtend(result, modifierResult); + }); + } + return result; +} +},{"./utils/deepExtend":14,"./utils/each":15}],4:[function(require,module,exports){ +var getScreenProfile = require('./getScreenProfile'), + getWindowProfile = require('./getWindowProfile'); +function getBrowserProfile(){ + return { + 'cookies' : ('undefined' !== typeof navigator.cookieEnabled) ? navigator.cookieEnabled : false, + 'codeName' : navigator.appCodeName, + 'language' : navigator.language, + 'name' : navigator.appName, + 'online' : navigator.onLine, + 'platform' : navigator.platform, + 'useragent': navigator.userAgent, + 'version' : navigator.appVersion, + 'screen' : getScreenProfile(), + 'window' : getWindowProfile() + } +} +module.exports = getBrowserProfile; +},{"./getScreenProfile":7,"./getWindowProfile":9}],5:[function(require,module,exports){ +function getDateTimeIndex(input){ + var date = input || new Date(); + return { + 'hour_of_day' : date.getHours(), + 'day_of_week' : parseInt( 1 + date.getDay() ), + 'day_of_month' : date.getDate(), + 'month' : parseInt( 1 + date.getMonth() ), + 'year' : date.getFullYear() + }; +} +module.exports = getDateTimeIndex; +},{}],6:[function(require,module,exports){ +function getDomNodePath(el){ + if (!el.nodeName) return ''; + var stack = []; + while ( el.parentNode != null ) { + var sibCount = 0; + var sibIndex = 0; + for ( var i = 0; i < el.parentNode.childNodes.length; i++ ) { + var sib = el.parentNode.childNodes[i]; + if ( sib.nodeName == el.nodeName ) { + if ( sib === el ) { + sibIndex = sibCount; + } + sibCount++; + } + } + if ( el.hasAttribute('id') && el.id != '' ) { + stack.unshift(el.nodeName.toLowerCase() + '#' + el.id); + } else if ( sibCount > 1 ) { + stack.unshift(el.nodeName.toLowerCase() + ':eq(' + sibIndex + ')'); + } else { + stack.unshift(el.nodeName.toLowerCase()); + } + el = el.parentNode; + } + return stack.slice(1).join(' > '); +} +module.exports = getDomNodePath; +},{}],7:[function(require,module,exports){ +function getScreenProfile(){ + var keys, output; + if ('undefined' == typeof window || !window.screen) return {}; + keys = ['height', 'width', 'colorDepth', 'pixelDepth', 'availHeight', 'availWidth']; + output = {}; + for (var i = 0; i < keys.length; i++) { + output[keys[i]] = window.screen[keys[i]] ? window.screen[keys[i]] : null; + } + output.orientation = { + 'angle' : window.screen.orientation ? window.screen.orientation['angle'] : 0, + 'type' : window.innerWidth > window.innerHeight ? 'landscape': 'portrait' + }; + return output; +} +module.exports = getScreenProfile; +},{}],8:[function(require,module,exports){ +function getUniqueId(){ + var str = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'; + return str.replace(/[xy]/g, function(c) { + var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); + return v.toString(16); + }); +} +module.exports = getUniqueId; +},{}],9:[function(require,module,exports){ +function getWindowProfile(){ + var body, html, output; + if ('undefined' == typeof document) return {}; + body = document.body; + html = document.documentElement; + output = { + 'height': ('innerHeight' in window) ? window.innerHeight : document.documentElement.offsetHeight, + 'width': ('innerWidth' in window) ? window.innerWidth : document.documentElement.offsetWidth, + 'scrollHeight': Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight ) || null + }; + if (window.screen) { + output.ratio = { + 'height': (window.screen.availHeight) ? parseFloat( (window.innerHeight/window.screen.availHeight).toFixed(2) ) : null, + 'width': (window.screen.availWidth) ? parseFloat( (window.innerWidth/window.screen.availWidth).toFixed(2) ) : null + }; + } + return output; +} +module.exports = getWindowProfile; +/* + Notes: + document.documentElement.offsetHeight/Width is a workaround for IE8 and below, where window.innerHeight/Width is undefined +*/ +},{}],10:[function(require,module,exports){ +var Emitter = require('component-emitter'); +var json = require('./utils/json'); +var each = require('./utils/each'); +var extend = require('./utils/extend'); +var queue = require('./utils/queue'); +var K = function(config){ + var self = this; + this.configure(config); + extend(this.config.resources, K.resources); + this.extensions = { + events: [], + collections: {} + }; + this.queue = queue(); + this.queue.on('flush', function(){ + self.recordDeferredEvents(); + }); + if (K.debug) { + this.on('error', K.log); + } + this.emit('ready'); + K.emit('client', this); +}; +Emitter(K); +Emitter(K.prototype); +extend(K, { + debug: false, + enabled: true, + loaded: false, + helpers: {}, + resources: { + 'base' : '{protocol}://{host}', + 'version' : '{protocol}://{host}/3.0', + 'projects' : '{protocol}://{host}/3.0/projects', + 'projectId' : '{protocol}://{host}/3.0/projects/{projectId}', + 'events' : '{protocol}://{host}/3.0/projects/{projectId}/events' + }, + utils: {}, + version: '0.1.1' +}); +K.log = function(message) { + if (K.debug && typeof console == 'object') { + console.log('[Keen IO]', message); + } +}; +K.prototype.configure = function(cfg){ + var self = this, + config = cfg || {}, + defaultProtocol = 'https'; + this.config = this.config || { + projectId: undefined, + writeKey: undefined, + host: 'api.keen.io', + protocol: defaultProtocol, + requestType: 'jsonp', + resources: {}, + writePath: undefined + }; + if ('undefined' !== typeof document && document.all) { + config['protocol'] = (document.location.protocol !== 'https:') ? 'http' : defaultProtocol; + } + if (config['host']) { + config['host'].replace(/.*?:\/\//g, ''); + } + extend(this.config, config); + return self; +}; +K.prototype.projectId = function(str){ + if (!arguments.length) return this.config.projectId; + this.config.projectId = (str ? String(str) : null); + return this; +}; +K.prototype.writeKey = function(str){ + if (!arguments.length) return this.config.writeKey; + this.config.writeKey = (str ? String(str) : null); + return this; +}; +K.prototype.resources = function(obj){ + if (!arguments.length) return this.config.resources; + var self = this; + if (typeof obj === 'object') { + each(obj, function(value, key){ + self.config.resources[key] = (value ? value : null); + }); + } + return this; +}; +K.prototype.url = function(name){ + var args = Array.prototype.slice.call(arguments, 1), + baseUrl = K.resources.base || '{protocol}://{host}', + path; + if (name && typeof name === 'string') { + if (this.config.resources[name]) { + path = this.config.resources[name]; + } + else { + path = baseUrl + name; + } + } + else { + path = baseUrl; + } + each(this.config, function(value, key){ + if (typeof value !== 'object') { + path = path.replace('{' + key + '}', value); + } + }); + each(args, function(arg, i){ + if (typeof arg === 'string') { + path += '/' + arg; + } + else if (typeof arg === 'object') { + path += '?'; + each(arg, function(value, key){ + path += key + '=' + value + '&'; + }); + path = path.slice(0, -1); + } + }); + return path; +}; +K.prototype.setGlobalProperties = function(props){ + K.log('This method has been deprecated. Check out #extendEvents: https://github.com/keen/keen-tracking.js#extend-events'); + if (!props || typeof props !== 'function') { + this.emit('error', 'Invalid value for global properties: ' + props); + return; + } + this.config.globalProperties = props; + return this; +}; +K.prototype.writePath = function(str){ + K.log('This method has been deprecated. Use client.url(\'events\') instead.'); + if (!arguments.length) return this.config.writePath; + if (!this.projectId()) { + this.emit('error', 'Client instance is missing a projectId property'); + return this.config.writePath || ('/3.0/projects/' + this.projectId() + '/events'); + } + this.config.writePath = str ? String(str) : ('/3.0/projects/' + this.projectId() + '/events'); + return this; +}; +function serialize(data){ + var query = []; + each(data, function(value, key){ + if ('string' !== typeof value) { + value = json.stringify(value); + } + query.push(key + '=' + encodeURIComponent(value)); + }); + return query.join('&'); +} +module.exports = K; +},{"./utils/each":15,"./utils/extend":16,"./utils/json":17,"./utils/queue":20,"component-emitter":22}],11:[function(require,module,exports){ +var Keen = require('./index'); +var base64 = require('./utils/base64'); +var each = require('./utils/each'); +var extend = require('./utils/extend'); +var extendEvents = require('./extend-events'); +var json = require('./utils/json'); +module.exports = { + 'recordEvent': recordEvent, + 'recordEvents': recordEvents, + 'addEvent': addEvent, + 'addEvents': addEvents +}; +function recordEvent(eventCollection, eventBody, callback, async){ + var url, data, cb, getRequestUrl, getRequestUrlOkLength, extendedEventBody, isAsync; + url = this.url('events', encodeURIComponent(eventCollection)); + data = {}; + cb = callback; + isAsync = ('boolean' === typeof async) ? async : true; + if (!checkValidation.call(this, cb)) { + return; + } + if (!eventCollection || typeof eventCollection !== 'string') { + handleValidationError.call(this, 'Collection name must be a string.', cb); + return; + } + if (this.config.globalProperties) { + data = this.config.globalProperties(eventCollection); + } + extend(data, eventBody); + extendedEventBody = {}; + extendEvents.getExtendedEventBody(extendedEventBody, this.extensions.events); + extendEvents.getExtendedEventBody(extendedEventBody, this.extensions.collections[eventCollection]); + extendEvents.getExtendedEventBody(extendedEventBody, [data]); + this.emit('recordEvent', eventCollection, extendedEventBody); + if (!Keen.enabled) { + handleValidationError.call(this, 'Keen.enabled is set to false.', cb); + return false; + } + getRequestUrl = this.url('events', encodeURIComponent(eventCollection), { + api_key : this.writeKey(), + data : base64.encode( json.stringify(extendedEventBody) ), + modified : new Date().getTime() + }); + getRequestUrlOkLength = getRequestUrl.length < getUrlMaxLength(); + if (isAsync) { + switch (this.config.requestType) { + case 'xhr': + sendXhr.call(this, 'POST', url, extendedEventBody, cb); + break; + case 'beacon': + if (getRequestUrlOkLength) { + sendBeacon.call(this, getRequestUrl, cb); + } + else { + attemptPostXhr.call(this, url, extendedEventBody, + 'Beacon URL length exceeds current browser limit, and XHR is not supported.', cb) + } + break; + default: + if (getRequestUrlOkLength) { + sendJSONp.call(this, getRequestUrl, cb); + } + else { + attemptPostXhr.call(this, url, extendedEventBody, + 'JSONp URL length exceeds current browser limit, and XHR is not supported.', cb) + } + break; + } + } + else { + if (getRequestUrlOkLength) { + sendSynchronousXhr(getRequestUrl); + } + } + callback = cb = null; + return this; +} +function recordEvents(eventsHash, callback){ + var self = this, url, cb, extendedEventsHash; + url = this.url('events'); + cb = callback; + callback = null; + if (!checkValidation.call(this, cb)) { + return; + } + if ('object' !== typeof eventsHash || eventsHash instanceof Array) { + handleValidationError.call(this, 'First argument must be an object', cb); + return; + } + if (arguments.length > 2) { + handleValidationError.call(this, 'Incorrect arguments provided to #recordEvents method', cb); + return; + } + if (this.config.globalProperties) { + each(eventsHash, function(events, collection){ + each(events, function(body, index){ + var modified = self.config.globalProperties(collection); + eventsHash[collection][index] = extend(modified, body); + }); + }); + } + extendedEventsHash = {}; + each(eventsHash, function(eventList, eventCollection){ + extendedEventsHash[eventCollection] = extendedEventsHash[eventCollection] || []; + each(eventList, function(eventBody, index){ + var extendedEventBody = {}; + extendEvents.getExtendedEventBody(extendedEventBody, self.extensions.events); + extendEvents.getExtendedEventBody(extendedEventBody, self.extensions.collections[eventCollection]); + extendEvents.getExtendedEventBody(extendedEventBody, [eventBody]); + extendedEventsHash[eventCollection].push(extendedEventBody); + }); + }); + this.emit('recordEvents', extendedEventsHash); + if (!Keen.enabled) { + handleValidationError.call(this, 'Keen.enabled is set to false.', cb); + return false; + } + if (getXhr()) { + sendXhr.call(this, 'POST', url, extendedEventsHash, cb); + } + else { + } + callback = cb = null; + return this; +} +function addEvent(){ + this.emit('error', 'This method has been deprecated. Check out #recordEvent: https://github.com/keen/keen-tracking.js#record-a-single-event'); + recordEvent.apply(this, arguments); +} +function addEvents(){ + this.emit('error', 'This method has been deprecated. Check out #recordEvents: https://github.com/keen/keen-tracking.js#record-multiple-events'); + recordEvents.apply(this, arguments); +} +function checkValidation(callback){ + var cb = callback; + callback = null; + if (!this.projectId()) { + handleValidationError.call(this, 'Keen.Client is missing a projectId property.', cb); + return false; + } + if (!this.writeKey()) { + handleValidationError.call(this, 'Keen.Client is missing a writeKey property.', cb); + return false; + } + return true; +} +function handleValidationError(message, cb){ + var err = 'Event(s) not recorded: ' + message; + this.emit('error', err); + if (cb) { + cb.call(this, err, null); + cb = null; + } +} +function getUrlMaxLength(){ + if ('undefined' !== typeof window) { + if (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') > 0) { + return 2000; + } + } + return 16000; +} +function attemptPostXhr(url, data, noXhrError, callback) { + if (getXhr()) { + sendXhr.call(this, 'POST', url, data, callback); + } + else { + handleValidationError.call(this, noXhrError); + } +} +function sendXhr(method, url, data, callback){ + var self = this; + var payload; + var xhr = getXhr(); + var cb = callback; + callback = null; + xhr.onreadystatechange = function() { + var response; + if (xhr.readyState == 4) { + if (xhr.status >= 200 && xhr.status < 300) { + try { + response = json.parse( xhr.responseText ); + } catch (e) { + Keen.emit('error', 'Could not parse HTTP response: ' + xhr.responseText); + if (cb) { + cb.call(self, xhr, null); + } + } + if (cb && response) { + cb.call(self, null, response); + } + } + else { + Keen.emit('error', 'HTTP request failed.'); + if (cb) { + cb.call(self, xhr, null); + } + } + } + }; + xhr.open(method, url, true); + xhr.setRequestHeader('Authorization', self.writeKey()); + xhr.setRequestHeader('Content-Type', 'application/json'); + if (data) { + payload = json.stringify(data); + } + if (method.toUpperCase() === 'GET') { + xhr.send(); + } + if (method.toUpperCase() === 'POST') { + xhr.send(payload); + } +} +function sendSynchronousXhr(url){ + var xhr = getXhr(); + if (xhr) { + xhr.open('GET', url, false); + xhr.send(null); + } +} +function getXhr() { + var root = 'undefined' == typeof window ? this : window; + if (root.XMLHttpRequest && ('file:' != root.location.protocol || !root.ActiveXObject)) { + return new XMLHttpRequest; + } else { + try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {} + try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {} + try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {} + try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {} + } + return false; +}; +function sendJSONp(url, callback){ + var self = this, + cb = callback, + timestamp = new Date().getTime(), + script = document.createElement('script'), + parent = document.getElementsByTagName('head')[0], + callbackName = 'keenJSONPCallback', + loaded = false; + callback = null; + callbackName += timestamp; + while (callbackName in window) { + callbackName += 'a'; + } + window[callbackName] = function(response) { + if (loaded === true) return; + loaded = true; + if (cb) { + cb.call(self, null, response); + } + cleanup(); + }; + script.src = url + '&jsonp=' + callbackName; + parent.appendChild(script); + script.onreadystatechange = function() { + if (loaded === false && this.readyState === 'loaded') { + loaded = true; + handleError(); + cleanup(); + } + }; + script.onerror = function() { + if (loaded === false) { + loaded = true; + handleError(); + cleanup(); + } + }; + function handleError(){ + if (cb) { + cb.call(self, 'An error occurred!', null); + } + } + function cleanup(){ + window[callbackName] = undefined; + try { + delete window[callbackName]; + } catch(e){}; + parent.removeChild(script); + } +} +function sendBeacon(url, callback){ + var self = this, + cb = callback, + img = document.createElement('img'), + loaded = false; + callback = null; + img.onload = function() { + loaded = true; + if ('naturalHeight' in this) { + if (this.naturalHeight + this.naturalWidth === 0) { + this.onerror(); + return; + } + } else if (this.width + this.height === 0) { + this.onerror(); + return; + } + if (cb) { + cb.call(self); + } + }; + img.onerror = function() { + loaded = true; + if (cb) { + cb.call(self, 'An error occurred!', null); + } + }; + img.src = url + '&c=clv1'; +} +},{"./extend-events":3,"./index":10,"./utils/base64":12,"./utils/each":15,"./utils/extend":16,"./utils/json":17}],12:[function(require,module,exports){ +module.exports = { + map: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", + encode: function (n) { + "use strict"; + var o = "", i = 0, m = this.map, i1, i2, i3, e1, e2, e3, e4; + n = this.utf8.encode(n); + while (i < n.length) { + i1 = n.charCodeAt(i++); i2 = n.charCodeAt(i++); i3 = n.charCodeAt(i++); + e1 = (i1 >> 2); e2 = (((i1 & 3) << 4) | (i2 >> 4)); e3 = (isNaN(i2) ? 64 : ((i2 & 15) << 2) | (i3 >> 6)); + e4 = (isNaN(i2) || isNaN(i3)) ? 64 : i3 & 63; + o = o + m.charAt(e1) + m.charAt(e2) + m.charAt(e3) + m.charAt(e4); + } return o; + }, + decode: function (n) { + "use strict"; + var o = "", i = 0, m = this.map, cc = String.fromCharCode, e1, e2, e3, e4, c1, c2, c3; + n = n.replace(/[^A-Za-z0-9\+\/\=]/g, ""); + while (i < n.length) { + e1 = m.indexOf(n.charAt(i++)); e2 = m.indexOf(n.charAt(i++)); + e3 = m.indexOf(n.charAt(i++)); e4 = m.indexOf(n.charAt(i++)); + c1 = (e1 << 2) | (e2 >> 4); c2 = ((e2 & 15) << 4) | (e3 >> 2); + c3 = ((e3 & 3) << 6) | e4; + o = o + (cc(c1) + ((e3 != 64) ? cc(c2) : "")) + (((e4 != 64) ? cc(c3) : "")); + } return this.utf8.decode(o); + }, + utf8: { + encode: function (n) { + "use strict"; + var o = "", i = 0, cc = String.fromCharCode, c; + while (i < n.length) { + c = n.charCodeAt(i++); o = o + ((c < 128) ? cc(c) : ((c > 127) && (c < 2048)) ? + (cc((c >> 6) | 192) + cc((c & 63) | 128)) : (cc((c >> 12) | 224) + cc(((c >> 6) & 63) | 128) + cc((c & 63) | 128))); + } return o; + }, + decode: function (n) { + "use strict"; + var o = "", i = 0, cc = String.fromCharCode, c2, c; + while (i < n.length) { + c = n.charCodeAt(i); + o = o + ((c < 128) ? [cc(c), i++][0] : ((c > 191) && (c < 224)) ? + [cc(((c & 31) << 6) | ((c2 = n.charCodeAt(i + 1)) & 63)), (i += 2)][0] : + [cc(((c & 15) << 12) | (((c2 = n.charCodeAt(i + 1)) & 63) << 6) | ((c3 = n.charCodeAt(i + 2)) & 63)), (i += 3)][0]); + } return o; + } + } +}; +},{}],13:[function(require,module,exports){ +var Cookies = require('js-cookie'); +var json = require('./json'); +var extend = require('./extend'); +module.exports = cookie; +function cookie(str){ + if (!arguments.length) return; + if (this instanceof cookie === false) { + return new cookie(str); + } + this.config = { + key: str, + options: {} + }; + this.data = this.get(); + this.enabled = true; + return this; +} +cookie.prototype.get = function(str){ + var data = {}; + if (Cookies.get(this.config.key)) { + data = json.parse(Cookies.get(this.config.key)); + } + if (str) { + return ('undefined' !== typeof data[str]) ? data[str] : null; + } + else { + return data; + } +}; +cookie.prototype.set = function(str, value){ + if (!arguments.length || !this.enabled) return this; + if ('string' === typeof str && arguments.length === 2) { + this.data[str] = value ? value : null; + } + else if ('object' === typeof str && arguments.length === 1) { + extend(this.data, str); + } + Cookies.set(this.config.key, this.data, this.config.options); + return this; +}; +cookie.prototype.expire = function(){ + Cookies.remove(this.config.key); + this.data = {}; + return this; +}; +cookie.prototype.options = function(obj){ + if (!arguments.length) return this.config.options; + this.config.options = (typeof obj === 'object') ? obj : {}; + return this; +}; +},{"./extend":16,"./json":17,"js-cookie":23}],14:[function(require,module,exports){ +var json = require('./json'); +module.exports = deepExtend; +function deepExtend(target){ + for (var i = 1; i < arguments.length; i++) { + if (target instanceof Array && arguments[i] instanceof Array) { + for (var j = 0; j < arguments[i].length; j++) { + if (target.indexOf(arguments[i][j]) < 0) { + target.push(arguments[i][j]); + } + } + } + else { + for (var prop in arguments[i]){ + if ('undefined' !== typeof target[prop] && 'object' === typeof arguments[i][prop] && arguments[i][prop] !== null) { + deepExtend(target[prop], clone(arguments[i][prop])); + } + else { + target[prop] = clone(arguments[i][prop]); + } + } + } + } + return target; +} +function clone(input){ + return json.parse( json.stringify(input) ); +} +},{"./json":17}],15:[function(require,module,exports){ +module.exports = each; +function each(o, cb, s){ + var n; + if (!o){ + return 0; + } + s = !s ? o : s; + if (o instanceof Array){ + for (n=0; n a"); + myClicker.on("click", function(e){ + }); + myClicker.once("click", function(e){ }); + myClicker.off("click"); + myClicker.off(); +*/ +module.exports = function(ctx){ + ctx.domListeners = ctx.domListeners || { + /* + 'click': { + '.nav li > a': [fn, fn, fn] + } + */ + }; + function listener(str){ + if (!str) return; + if (this instanceof listener === false) { + return new listener(str); + } + this.selector = str; + return this; + } + listener.prototype.on = function(str, fn){ + var self = this; + if (arguments.length !== 2 || 'string' !== typeof str || 'function' !== typeof fn) return this; + if ('undefined' === typeof ctx.domListeners[str]) { + addListener(str, eventHandler(str)); + ctx.domListeners[str] = {}; + } + ctx.domListeners[str][self.selector] = ctx.domListeners[str][self.selector] || []; + ctx.domListeners[str][self.selector].push(fn); + return self; + }; + listener.prototype.once = function(str, fn){ + var self = this; + function on() { + self.off(str, on); + return fn.apply(self, arguments); + } + on.fn = fn; + self.on(str, on); + return self; + }; + listener.prototype.off = function(str, fn){ + var self = this, survivors = []; + if (arguments.length === 2) { + each(ctx.domListeners[str][self.selector], function(handler, i){ + if (handler === fn || handler.fn === fn) return; + survivors.push(handler); + }); + ctx.domListeners[str][self.selector] = survivors; + } + else if (arguments.length === 1) { + try { + delete ctx.domListeners[str][self.selector]; + } + catch(e){ + ctx.domListeners[str][self.selector] = []; + } + } + else { + each(ctx.domListeners, function(hash, eventType){ + try { + delete ctx.domListeners[eventType][self.selector]; + } + catch(e){ + ctx.domListeners[eventType][self.selector] = function(){}; + } + }); + } + return self; + }; + function eventHandler(eventType){ + return function(e){ + var evt, target; + evt = e || window.event; + target = evt.target || evt.srcElement; + if ('undefined' === ctx.domListeners[eventType]) return; + each(ctx.domListeners[eventType], function(handlers, key){ + if (matches(target, key)) { + each(handlers, function(fn, i){ + if ('click' === eventType && 'A' === target.nodeName) { + deferClickEvent(evt, target, fn); + } + else if ('submit' === eventType && 'FORM' === target.nodeName) { + deferFormSubmit(evt, target, fn); + } + else { + fn(evt); + } + }); + } + else if ('window' === key) { + each(handlers, function(fn, i){ + fn(evt); + }); + } + return; + }); + }; + } + return listener; +} +function addListener(eventType, fn){ + if (document.addEventListener) { + document.addEventListener(eventType, fn, false); + } else { + document.attachEvent("on" + eventType, fn); + } +} +function matches(elem, selector) { + var nodeList = ( elem.parentNode || document ).querySelectorAll( selector ) || [], + i = nodeList.length; + while ( i-- ) { + if ( nodeList[i] == elem ) { return true; } + } + return false; +} +function deferClickEvent(evt, anchor, callback){ + var timeout = 500, + targetAttr, + cbResponse; + if (anchor.getAttribute !== void 0) { + targetAttr = anchor.getAttribute("target"); + } else if (anchor.target) { + targetAttr = anchor.target; + } + cbResponse = callback(evt); + if (('boolean' === typeof cbResponse && cbResponse === false) || evt.defaultPrevented || evt.returnValue === false) { + if (evt.preventDefault) { + evt.preventDefault(); + } + evt.returnValue = false; + return false; + } + else if (targetAttr !== '_blank' && targetAttr !== 'blank' && !evt.metaKey) { + if (evt.preventDefault) { + evt.preventDefault(); + } + evt.returnValue = false; + setTimeout(function(){ + window.location = anchor.href; + }, timeout); + } + return false; +} +function deferFormSubmit(evt, form, callback){ + var timeout = 500; + cbResponse = callback(evt); + if (('boolean' === typeof cbResponse && cbResponse === false) || evt.defaultPrevented || evt.returnValue === false) { + if (evt.preventDefault) { + evt.preventDefault(); + } + evt.returnValue = false; + return false; + } + else { + if (evt.preventDefault) { + evt.preventDefault(); + } + evt.returnValue = false; + setTimeout(function(){ + form.submit(); + }, timeout); + } + return false; +} +},{"./each":15,"component-emitter":22}],19:[function(require,module,exports){ +function parseParams(str){ + var urlParams = {}, + match, + pl = /\+/g, + search = /([^&=]+)=?([^&]*)/g, + decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); }, + query = str.split("?")[1]; + while (!!(match=search.exec(query))) { + urlParams[decode(match[1])] = decode(match[2]); + } + return urlParams; +}; +module.exports = parseParams; +},{}],20:[function(require,module,exports){ +var Emitter = require('component-emitter'); +module.exports = queue; +function queue(){ + var self = this; + if (this instanceof queue === false) { + return new queue(); + } + self.capacity = 0; + self.interval = 0; + self.config = { + capacity: 5000, + interval: 15 + }; + self.events = { + }; + setInterval(function(){ + self.interval++; + checkQueue.call(self); + }, 1000); + return self; +} +function checkQueue(){ + if ((this.capacity > 0 && this.interval >= this.config.interval) + || this.capacity >= this.config.capacity) { + this.emit('flush'); + this.interval = 0; + } +} +Emitter(queue.prototype); +},{"component-emitter":22}],21:[function(require,module,exports){ +module.exports = timer; +function timer(num){ + if (this instanceof timer === false) { + return new timer(num); + } + this.count = num || 0; + return this; +} +timer.prototype.start = function(){ + var self = this; + this.pause(); + this.interval = setInterval(function(){ + self.count++; + }, 1000); + return this; +}; +timer.prototype.pause = function(){ + clearInterval(this.interval); + return this; +}; +timer.prototype.value = function(){ + return this.count; +}; +timer.prototype.clear = function(){ + this.count = 0; + return this; +}; +},{}],22:[function(require,module,exports){ +/** + * 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){ + function on() { + this.off(event, on); + fn.apply(this, arguments); + } + on.fn = fn; + 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 || {}; + if (0 == arguments.length) { + this._callbacks = {}; + return this; + } + var callbacks = this._callbacks['$' + event]; + if (!callbacks) return this; + if (1 == arguments.length) { + delete this._callbacks['$' + event]; + return this; + } + var cb; + for (var i = 0; i < callbacks.length; i++) { + cb = callbacks[i]; + if (cb === fn || cb.fn === fn) { + callbacks.splice(i, 1); + break; + } + } + 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; +}; +},{}],23:[function(require,module,exports){ +/*! + * JavaScript Cookie v2.1.0 + * https://github.com/js-cookie/js-cookie + * + * Copyright 2006, 2015 Klaus Hartl & Fagner Brack + * Released under the MIT license + */ +(function (factory) { + if (false) { + define(factory); + } else if (typeof exports === 'object') { + module.exports = factory(); + } else { + var _OldCookies = window.Cookies; + var api = window.Cookies = factory(); + api.noConflict = function () { + window.Cookies = _OldCookies; + return api; + }; + } +}(function () { + function extend () { + var i = 0; + var result = {}; + for (; i < arguments.length; i++) { + var attributes = arguments[ i ]; + for (var key in attributes) { + result[key] = attributes[key]; + } + } + return result; + } + function init (converter) { + function api (key, value, attributes) { + var result; + if (arguments.length > 1) { + attributes = extend({ + path: '/' + }, api.defaults, attributes); + if (typeof attributes.expires === 'number') { + var expires = new Date(); + expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5); + attributes.expires = expires; + } + try { + result = JSON.stringify(value); + if (/^[\{\[]/.test(result)) { + value = result; + } + } catch (e) {} + if (!converter.write) { + value = encodeURIComponent(String(value)) + .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent); + } else { + value = converter.write(value, key); + } + key = encodeURIComponent(String(key)); + key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent); + key = key.replace(/[\(\)]/g, escape); + return (document.cookie = [ + key, '=', value, + attributes.expires && '; expires=' + attributes.expires.toUTCString(), + attributes.path && '; path=' + attributes.path, + attributes.domain && '; domain=' + attributes.domain, + attributes.secure ? '; secure' : '' + ].join('')); + } + if (!key) { + result = {}; + } + var cookies = document.cookie ? document.cookie.split('; ') : []; + var rdecode = /(%[0-9A-Z]{2})+/g; + var i = 0; + for (; i < cookies.length; i++) { + var parts = cookies[i].split('='); + var name = parts[0].replace(rdecode, decodeURIComponent); + var cookie = parts.slice(1).join('='); + if (cookie.charAt(0) === '"') { + cookie = cookie.slice(1, -1); + } + try { + cookie = converter.read ? + converter.read(cookie, name) : converter(cookie, name) || + cookie.replace(rdecode, decodeURIComponent); + if (this.json) { + try { + cookie = JSON.parse(cookie); + } catch (e) {} + } + if (key === name) { + result = cookie; + break; + } + if (!key) { + result[name] = cookie; + } + } catch (e) {} + } + return result; + } + api.get = api.set = api; + api.getJSON = function () { + return api.apply({ + json: true + }, [].slice.call(arguments)); + }; + api.defaults = {}; + api.remove = function (key, attributes) { + api(key, '', extend(attributes, { + expires: -1 + })); + }; + api.withConverter = init; + return api; + } + return init(function () {}); +})); +},{}],24:[function(require,module,exports){ +(function (global){ +/*! JSON v3.3.2 | http://bestiejs.github.io/json3 | Copyright 2012-2014, Kit Cambridge | http://kit.mit-license.org */ +;(function () { + var isLoader = typeof define === "function" && define.amd; + var objectTypes = { + "function": true, + "object": true + }; + var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; + var root = objectTypes[typeof window] && window || this, + freeGlobal = freeExports && objectTypes[typeof module] && module && !module.nodeType && typeof global == "object" && global; + if (freeGlobal && (freeGlobal["global"] === freeGlobal || freeGlobal["window"] === freeGlobal || freeGlobal["self"] === freeGlobal)) { + root = freeGlobal; + } + function runInContext(context, exports) { + context || (context = root["Object"]()); + exports || (exports = root["Object"]()); + var Number = context["Number"] || root["Number"], + String = context["String"] || root["String"], + Object = context["Object"] || root["Object"], + Date = context["Date"] || root["Date"], + SyntaxError = context["SyntaxError"] || root["SyntaxError"], + TypeError = context["TypeError"] || root["TypeError"], + Math = context["Math"] || root["Math"], + nativeJSON = context["JSON"] || root["JSON"]; + if (typeof nativeJSON == "object" && nativeJSON) { + exports.stringify = nativeJSON.stringify; + exports.parse = nativeJSON.parse; + } + var objectProto = Object.prototype, + getClass = objectProto.toString, + isProperty, forEach, undef; + var isExtended = new Date(-3509827334573292); + try { + isExtended = isExtended.getUTCFullYear() == -109252 && isExtended.getUTCMonth() === 0 && isExtended.getUTCDate() === 1 && + isExtended.getUTCHours() == 10 && isExtended.getUTCMinutes() == 37 && isExtended.getUTCSeconds() == 6 && isExtended.getUTCMilliseconds() == 708; + } catch (exception) {} + function has(name) { + if (has[name] !== undef) { + return has[name]; + } + var isSupported; + if (name == "bug-string-char-index") { + isSupported = "a"[0] != "a"; + } else if (name == "json") { + isSupported = has("json-stringify") && has("json-parse"); + } else { + var value, serialized = '{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}'; + if (name == "json-stringify") { + var stringify = exports.stringify, stringifySupported = typeof stringify == "function" && isExtended; + if (stringifySupported) { + (value = function () { + return 1; + }).toJSON = value; + try { + stringifySupported = + stringify(0) === "0" && + stringify(new Number()) === "0" && + stringify(new String()) == '""' && + stringify(getClass) === undef && + stringify(undef) === undef && + stringify() === undef && + stringify(value) === "1" && + stringify([value]) == "[1]" && + stringify([undef]) == "[null]" && + stringify(null) == "null" && + stringify([undef, getClass, null]) == "[null,null,null]" && + stringify({ "a": [value, true, false, null, "\x00\b\n\f\r\t"] }) == serialized && + stringify(null, value) === "1" && + stringify([1, 2], null, 1) == "[\n 1,\n 2\n]" && + stringify(new Date(-8.64e15)) == '"-271821-04-20T00:00:00.000Z"' && + stringify(new Date(8.64e15)) == '"+275760-09-13T00:00:00.000Z"' && + stringify(new Date(-621987552e5)) == '"-000001-01-01T00:00:00.000Z"' && + stringify(new Date(-1)) == '"1969-12-31T23:59:59.999Z"'; + } catch (exception) { + stringifySupported = false; + } + } + isSupported = stringifySupported; + } + if (name == "json-parse") { + var parse = exports.parse; + if (typeof parse == "function") { + try { + if (parse("0") === 0 && !parse(false)) { + value = parse(serialized); + var parseSupported = value["a"].length == 5 && value["a"][0] === 1; + if (parseSupported) { + try { + parseSupported = !parse('"\t"'); + } catch (exception) {} + if (parseSupported) { + try { + parseSupported = parse("01") !== 1; + } catch (exception) {} + } + if (parseSupported) { + try { + parseSupported = parse("1.") !== 1; + } catch (exception) {} + } + } + } + } catch (exception) { + parseSupported = false; + } + } + isSupported = parseSupported; + } + } + return has[name] = !!isSupported; + } + if (!has("json")) { + var functionClass = "[object Function]", + dateClass = "[object Date]", + numberClass = "[object Number]", + stringClass = "[object String]", + arrayClass = "[object Array]", + booleanClass = "[object Boolean]"; + var charIndexBuggy = has("bug-string-char-index"); + if (!isExtended) { + var floor = Math.floor; + var Months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]; + var getDay = function (year, month) { + return Months[month] + 365 * (year - 1970) + floor((year - 1969 + (month = +(month > 1))) / 4) - floor((year - 1901 + month) / 100) + floor((year - 1601 + month) / 400); + }; + } + if (!(isProperty = objectProto.hasOwnProperty)) { + isProperty = function (property) { + var members = {}, constructor; + if ((members.__proto__ = null, members.__proto__ = { + "toString": 1 + }, members).toString != getClass) { + isProperty = function (property) { + var original = this.__proto__, result = property in (this.__proto__ = null, this); + this.__proto__ = original; + return result; + }; + } else { + constructor = members.constructor; + isProperty = function (property) { + var parent = (this.constructor || constructor).prototype; + return property in this && !(property in parent && this[property] === parent[property]); + }; + } + members = null; + return isProperty.call(this, property); + }; + } + forEach = function (object, callback) { + var size = 0, Properties, members, property; + (Properties = function () { + this.valueOf = 0; + }).prototype.valueOf = 0; + members = new Properties(); + for (property in members) { + if (isProperty.call(members, property)) { + size++; + } + } + Properties = members = null; + if (!size) { + members = ["valueOf", "toString", "toLocaleString", "propertyIsEnumerable", "isPrototypeOf", "hasOwnProperty", "constructor"]; + forEach = function (object, callback) { + var isFunction = getClass.call(object) == functionClass, property, length; + var hasProperty = !isFunction && typeof object.constructor != "function" && objectTypes[typeof object.hasOwnProperty] && object.hasOwnProperty || isProperty; + for (property in object) { + if (!(isFunction && property == "prototype") && hasProperty.call(object, property)) { + callback(property); + } + } + for (length = members.length; property = members[--length]; hasProperty.call(object, property) && callback(property)); + }; + } else if (size == 2) { + forEach = function (object, callback) { + var members = {}, isFunction = getClass.call(object) == functionClass, property; + for (property in object) { + if (!(isFunction && property == "prototype") && !isProperty.call(members, property) && (members[property] = 1) && isProperty.call(object, property)) { + callback(property); + } + } + }; + } else { + forEach = function (object, callback) { + var isFunction = getClass.call(object) == functionClass, property, isConstructor; + for (property in object) { + if (!(isFunction && property == "prototype") && isProperty.call(object, property) && !(isConstructor = property === "constructor")) { + callback(property); + } + } + if (isConstructor || isProperty.call(object, (property = "constructor"))) { + callback(property); + } + }; + } + return forEach(object, callback); + }; + if (!has("json-stringify")) { + var Escapes = { + 92: "\\\\", + 34: '\\"', + 8: "\\b", + 12: "\\f", + 10: "\\n", + 13: "\\r", + 9: "\\t" + }; + var leadingZeroes = "000000"; + var toPaddedString = function (width, value) { + return (leadingZeroes + (value || 0)).slice(-width); + }; + var unicodePrefix = "\\u00"; + var quote = function (value) { + var result = '"', index = 0, length = value.length, useCharIndex = !charIndexBuggy || length > 10; + var symbols = useCharIndex && (charIndexBuggy ? value.split("") : value); + for (; index < length; index++) { + var charCode = value.charCodeAt(index); + switch (charCode) { + case 8: case 9: case 10: case 12: case 13: case 34: case 92: + result += Escapes[charCode]; + break; + default: + if (charCode < 32) { + result += unicodePrefix + toPaddedString(2, charCode.toString(16)); + break; + } + result += useCharIndex ? symbols[index] : value.charAt(index); + } + } + return result + '"'; + }; + var serialize = function (property, object, callback, properties, whitespace, indentation, stack) { + var value, className, year, month, date, time, hours, minutes, seconds, milliseconds, results, element, index, length, prefix, result; + try { + value = object[property]; + } catch (exception) {} + if (typeof value == "object" && value) { + className = getClass.call(value); + if (className == dateClass && !isProperty.call(value, "toJSON")) { + if (value > -1 / 0 && value < 1 / 0) { + if (getDay) { + date = floor(value / 864e5); + for (year = floor(date / 365.2425) + 1970 - 1; getDay(year + 1, 0) <= date; year++); + for (month = floor((date - getDay(year, 0)) / 30.42); getDay(year, month + 1) <= date; month++); + date = 1 + date - getDay(year, month); + time = (value % 864e5 + 864e5) % 864e5; + hours = floor(time / 36e5) % 24; + minutes = floor(time / 6e4) % 60; + seconds = floor(time / 1e3) % 60; + milliseconds = time % 1e3; + } else { + year = value.getUTCFullYear(); + month = value.getUTCMonth(); + date = value.getUTCDate(); + hours = value.getUTCHours(); + minutes = value.getUTCMinutes(); + seconds = value.getUTCSeconds(); + milliseconds = value.getUTCMilliseconds(); + } + value = (year <= 0 || year >= 1e4 ? (year < 0 ? "-" : "+") + toPaddedString(6, year < 0 ? -year : year) : toPaddedString(4, year)) + + "-" + toPaddedString(2, month + 1) + "-" + toPaddedString(2, date) + + "T" + toPaddedString(2, hours) + ":" + toPaddedString(2, minutes) + ":" + toPaddedString(2, seconds) + + "." + toPaddedString(3, milliseconds) + "Z"; + } else { + value = null; + } + } else if (typeof value.toJSON == "function" && ((className != numberClass && className != stringClass && className != arrayClass) || isProperty.call(value, "toJSON"))) { + value = value.toJSON(property); + } + } + if (callback) { + value = callback.call(object, property, value); + } + if (value === null) { + return "null"; + } + className = getClass.call(value); + if (className == booleanClass) { + return "" + value; + } else if (className == numberClass) { + return value > -1 / 0 && value < 1 / 0 ? "" + value : "null"; + } else if (className == stringClass) { + return quote("" + value); + } + if (typeof value == "object") { + for (length = stack.length; length--;) { + if (stack[length] === value) { + throw TypeError(); + } + } + stack.push(value); + results = []; + prefix = indentation; + indentation += whitespace; + if (className == arrayClass) { + for (index = 0, length = value.length; index < length; index++) { + element = serialize(index, value, callback, properties, whitespace, indentation, stack); + results.push(element === undef ? "null" : element); + } + result = results.length ? (whitespace ? "[\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "]" : ("[" + results.join(",") + "]")) : "[]"; + } else { + forEach(properties || value, function (property) { + var element = serialize(property, value, callback, properties, whitespace, indentation, stack); + if (element !== undef) { + results.push(quote(property) + ":" + (whitespace ? " " : "") + element); + } + }); + result = results.length ? (whitespace ? "{\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "}" : ("{" + results.join(",") + "}")) : "{}"; + } + stack.pop(); + return result; + } + }; + exports.stringify = function (source, filter, width) { + var whitespace, callback, properties, className; + if (objectTypes[typeof filter] && filter) { + if ((className = getClass.call(filter)) == functionClass) { + callback = filter; + } else if (className == arrayClass) { + properties = {}; + for (var index = 0, length = filter.length, value; index < length; value = filter[index++], ((className = getClass.call(value)), className == stringClass || className == numberClass) && (properties[value] = 1)); + } + } + if (width) { + if ((className = getClass.call(width)) == numberClass) { + if ((width -= width % 1) > 0) { + for (whitespace = "", width > 10 && (width = 10); whitespace.length < width; whitespace += " "); + } + } else if (className == stringClass) { + whitespace = width.length <= 10 ? width : width.slice(0, 10); + } + } + return serialize("", (value = {}, value[""] = source, value), callback, properties, whitespace, "", []); + }; + } + if (!has("json-parse")) { + var fromCharCode = String.fromCharCode; + var Unescapes = { + 92: "\\", + 34: '"', + 47: "/", + 98: "\b", + 116: "\t", + 110: "\n", + 102: "\f", + 114: "\r" + }; + var Index, Source; + var abort = function () { + Index = Source = null; + throw SyntaxError(); + }; + var lex = function () { + var source = Source, length = source.length, value, begin, position, isSigned, charCode; + while (Index < length) { + charCode = source.charCodeAt(Index); + switch (charCode) { + case 9: case 10: case 13: case 32: + Index++; + break; + case 123: case 125: case 91: case 93: case 58: case 44: + value = charIndexBuggy ? source.charAt(Index) : source[Index]; + Index++; + return value; + case 34: + for (value = "@", Index++; Index < length;) { + charCode = source.charCodeAt(Index); + if (charCode < 32) { + abort(); + } else if (charCode == 92) { + charCode = source.charCodeAt(++Index); + switch (charCode) { + case 92: case 34: case 47: case 98: case 116: case 110: case 102: case 114: + value += Unescapes[charCode]; + Index++; + break; + case 117: + begin = ++Index; + for (position = Index + 4; Index < position; Index++) { + charCode = source.charCodeAt(Index); + if (!(charCode >= 48 && charCode <= 57 || charCode >= 97 && charCode <= 102 || charCode >= 65 && charCode <= 70)) { + abort(); + } + } + value += fromCharCode("0x" + source.slice(begin, Index)); + break; + default: + abort(); + } + } else { + if (charCode == 34) { + break; + } + charCode = source.charCodeAt(Index); + begin = Index; + while (charCode >= 32 && charCode != 92 && charCode != 34) { + charCode = source.charCodeAt(++Index); + } + value += source.slice(begin, Index); + } + } + if (source.charCodeAt(Index) == 34) { + Index++; + return value; + } + abort(); + default: + begin = Index; + if (charCode == 45) { + isSigned = true; + charCode = source.charCodeAt(++Index); + } + if (charCode >= 48 && charCode <= 57) { + if (charCode == 48 && ((charCode = source.charCodeAt(Index + 1)), charCode >= 48 && charCode <= 57)) { + abort(); + } + isSigned = false; + for (; Index < length && ((charCode = source.charCodeAt(Index)), charCode >= 48 && charCode <= 57); Index++); + if (source.charCodeAt(Index) == 46) { + position = ++Index; + for (; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++); + if (position == Index) { + abort(); + } + Index = position; + } + charCode = source.charCodeAt(Index); + if (charCode == 101 || charCode == 69) { + charCode = source.charCodeAt(++Index); + if (charCode == 43 || charCode == 45) { + Index++; + } + for (position = Index; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++); + if (position == Index) { + abort(); + } + Index = position; + } + return +source.slice(begin, Index); + } + if (isSigned) { + abort(); + } + if (source.slice(Index, Index + 4) == "true") { + Index += 4; + return true; + } else if (source.slice(Index, Index + 5) == "false") { + Index += 5; + return false; + } else if (source.slice(Index, Index + 4) == "null") { + Index += 4; + return null; + } + abort(); + } + } + return "$"; + }; + var get = function (value) { + var results, hasMembers; + if (value == "$") { + abort(); + } + if (typeof value == "string") { + if ((charIndexBuggy ? value.charAt(0) : value[0]) == "@") { + return value.slice(1); + } + if (value == "[") { + results = []; + for (;; hasMembers || (hasMembers = true)) { + value = lex(); + if (value == "]") { + break; + } + if (hasMembers) { + if (value == ",") { + value = lex(); + if (value == "]") { + abort(); + } + } else { + abort(); + } + } + if (value == ",") { + abort(); + } + results.push(get(value)); + } + return results; + } else if (value == "{") { + results = {}; + for (;; hasMembers || (hasMembers = true)) { + value = lex(); + if (value == "}") { + break; + } + if (hasMembers) { + if (value == ",") { + value = lex(); + if (value == "}") { + abort(); + } + } else { + abort(); + } + } + if (value == "," || typeof value != "string" || (charIndexBuggy ? value.charAt(0) : value[0]) != "@" || lex() != ":") { + abort(); + } + results[value.slice(1)] = get(lex()); + } + return results; + } + abort(); + } + return value; + }; + var update = function (source, property, callback) { + var element = walk(source, property, callback); + if (element === undef) { + delete source[property]; + } else { + source[property] = element; + } + }; + var walk = function (source, property, callback) { + var value = source[property], length; + if (typeof value == "object" && value) { + if (getClass.call(value) == arrayClass) { + for (length = value.length; length--;) { + update(value, length, callback); + } + } else { + forEach(value, function (property) { + update(value, property, callback); + }); + } + } + return callback.call(source, property, value); + }; + exports.parse = function (source, callback) { + var result, value; + Index = 0; + Source = "" + source; + result = get(lex()); + if (lex() != "$") { + abort(); + } + Index = Source = null; + return callback && getClass.call(callback) == functionClass ? walk((value = {}, value[""] = result, value), "", callback) : result; + }; + } + } + exports["runInContext"] = runInContext; + return exports; + } + if (freeExports && !isLoader) { + runInContext(root, freeExports); + } else { + var nativeJSON = root.JSON, + previousJSON = root["JSON3"], + isRestored = false; + var JSON3 = runInContext(root, (root["JSON3"] = { + "noConflict": function () { + if (!isRestored) { + isRestored = true; + root.JSON = nativeJSON; + root["JSON3"] = previousJSON; + nativeJSON = previousJSON = null; + } + return JSON3; + } + })); + root.JSON = { + "parse": JSON3.parse, + "stringify": JSON3.stringify + }; + } + if (isLoader) { + define(function () { + return JSON3; + }); + } +}).call(this); +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}]},{},[1]); + +//# sourceMappingURL=keen-tracking.js.map diff --git a/dist/keen-tracking.min.js b/dist/keen-tracking.min.js index d81638d..0d9b2cc 100644 --- a/dist/keen-tracking.min.js +++ b/dist/keen-tracking.min.js @@ -1,3 +1,11 @@ -(function e(b,g,d){function c(m,j){if(!g[m]){if(!b[m]){var i=typeof require=="function"&&require;if(!j&&i){return i(m,!0)}if(a){return a(m,!0)}var k=new Error("Cannot find module '"+m+"'");throw k.code="MODULE_NOT_FOUND",k}var h=g[m]={exports:{}};b[m][0].call(h.exports,function(l){var o=b[m][1][l];return c(o?o:l)},h,h.exports,e,b,g,d)}return g[m].exports}var a=typeof require=="function"&&require;for(var f=0;f or DOM element")}}if(v){y=function(){if(!q){q=true;v()}}}this.recordEvent(o,w,y);setTimeout(y,p);if(!x.metaKey){return false}}if(!Array.prototype.indexOf){Array.prototype.indexOf=function(p){var o=this.length>>>0;var q=Number(arguments[1])||0;q=(q<0)?Math.ceil(q):Math.floor(q);if(q<0){q+=o}for(;q0){o=JSON.parse(JSON.stringify(n.queue));n.queue=h();n.queue.options=o.options;n.emit("recordDeferredEvents",o.events);n.recordEvents(o.events,function(q,p){if(q){n.recordEvents(o.events)}else{o=void 0}})}return n}function i(o){var n="Event(s) not deferred: "+o;this.emit("error",n)}},{"./index":10,"./utils/each":15,"./utils/queue":20}],3:[function(d,c,g){var f=d("./utils/deepExtend");var i=d("./utils/each");c.exports={extendEvent:b,extendEvents:j,getExtendedEventBody:a};function b(k,l){if(arguments.length!==2||typeof k!=="string"||("object"!==typeof l&&"function"!==typeof l)){h.call(this,"Incorrect arguments provided to #extendEvent method");return}this.extensions.collections[k]=this.extensions.collections[k]||[];this.extensions.collections[k].push(l);this.emit("extendEvent",k,l);return this}function j(k){if(arguments.length!==1||("object"!==typeof k&&"function"!==typeof k)){h.call(this,"Incorrect arguments provided to #extendEvents method");return}this.extensions.events.push(k);this.emit("extendEvents",k);return this}function h(l){var k="Event(s) not extended: "+l;this.emit("error",k)}function a(l,k){if(k&&k.length>0){i(k,function(o,n){var m=(typeof o==="function")?o():o;f(l,m)})}return l}},{"./utils/deepExtend":14,"./utils/each":15}],4:[function(d,f,b){var a=d("./getScreenProfile"),g=d("./getWindowProfile");function c(){return{cookies:("undefined"!==typeof navigator.cookieEnabled)?navigator.cookieEnabled:false,codeName:navigator.appCodeName,language:navigator.language,name:navigator.appName,online:navigator.onLine,platform:navigator.platform,useragent:navigator.userAgent,version:navigator.appVersion,screen:a(),window:g()}}f.exports=c},{"./getScreenProfile":7,"./getWindowProfile":9}],5:[function(b,c,a){function d(f){var g=f||new Date();return{hour_of_day:g.getHours(),day_of_week:parseInt(1+g.getDay()),day_of_month:g.getDate(),month:parseInt(1+g.getMonth()),year:g.getFullYear()}}c.exports=d},{}],6:[function(c,d,a){function b(l){if(!l.nodeName){return""}var f=[];while(l.parentNode!=null){var k=0;var g=0;for(var j=0;j1){f.unshift(l.nodeName.toLowerCase()+":eq("+g+")")}else{f.unshift(l.nodeName.toLowerCase())}}l=l.parentNode}return f.slice(1).join(" > ")}d.exports=b},{}],7:[function(c,d,b){function a(){var h,f;if("undefined"==typeof window||!window.screen){return{}}h=["height","width","colorDepth","pixelDepth","availHeight","availWidth"];f={};for(var g=0;gwindow.innerHeight?"landscape":"portrait"};return f}d.exports=a},{}],8:[function(b,c,a){function d(){var f="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";return f.replace(/[xy]/g,function(i){var h=Math.random()*16|0,g=i=="x"?h:(h&3|8);return g.toString(16)})}c.exports=d},{}],9:[function(b,c,a){function d(){var f,h,g;if("undefined"==typeof document){return{}}f=document.body;h=document.documentElement;g={height:("innerHeight" in window)?window.innerHeight:document.documentElement.offsetHeight,width:("innerWidth" in window)?window.innerWidth:document.documentElement.offsetWidth,scrollHeight:Math.max(f.scrollHeight,f.offsetHeight,h.clientHeight,h.scrollHeight,h.offsetHeight)||null};if(window.screen){g.ratio={height:(window.screen.availHeight)?parseFloat((window.innerHeight/window.screen.availHeight).toFixed(2)):null,width:(window.screen.availWidth)?parseFloat((window.innerWidth/window.screen.availWidth).toFixed(2)):null}}return g}c.exports=d},{}],10:[function(b,a,c){var h=b("component-emitter");var j=b("./utils/json");var i=b("./utils/each");var f=b("./utils/extend");var d=b("./utils/queue");var g=function(m){var l=this;this.configure(m);f(this.config.resources,g.resources);this.extensions={events:[],collections:{}};this.queue=d();this.queue.on("flush",function(){l.recordDeferredEvents()});if(g.debug){this.on("error",g.log)}this.emit("ready");g.emit("client",this)};h(g);h(g.prototype);f(g,{debug:false,enabled:true,loaded:false,helpers:{},resources:{base:"{protocol}://{host}",version:"{protocol}://{host}/3.0",projects:"{protocol}://{host}/3.0/projects",projectId:"{protocol}://{host}/3.0/projects/{projectId}",events:"{protocol}://{host}/3.0/projects/{projectId}/events"},utils:{},version:"0.1.1"});g.log=function(l){if(g.debug&&typeof console=="object"){console.log("[Keen IO]",l)}};g.prototype.configure=function(l){var m=this,n=l||{},o="https";this.config=this.config||{projectId:undefined,writeKey:undefined,host:"api.keen.io",protocol:o,requestType:"jsonp",resources:{},writePath:undefined};if("undefined"!==typeof document&&document.all){n.protocol=(document.location.protocol!=="https:")?"http":o}if(n.host){n.host.replace(/.*?:\/\//g,"")}f(this.config,n);return m};g.prototype.projectId=function(l){if(!arguments.length){return this.config.projectId}this.config.projectId=(l?String(l):null);return this};g.prototype.writeKey=function(l){if(!arguments.length){return this.config.writeKey}this.config.writeKey=(l?String(l):null);return this};g.prototype.resources=function(m){if(!arguments.length){return this.config.resources}var l=this;if(typeof m==="object"){i(m,function(o,n){l.config.resources[n]=(o?o:null)})}return this};g.prototype.url=function(m){var l=Array.prototype.slice.call(arguments,1),n=g.resources.base||"{protocol}://{host}",o;if(m&&typeof m==="string"){if(this.config.resources[m]){o=this.config.resources[m]}else{o=n+m}}else{o=n}i(this.config,function(q,p){if(typeof q!=="object"){o=o.replace("{"+p+"}",q)}});i(l,function(p,q){if(typeof p==="string"){o+="/"+p}else{if(typeof p==="object"){o+="?";i(p,function(s,r){o+=r+"="+s+"&"});o=o.slice(0,-1)}}});return o};g.prototype.setGlobalProperties=function(l){g.log("This method has been deprecated. Check out #extendEvents: https://github.com/keen/keen-tracking.js#extend-events");if(!l||typeof l!=="function"){this.emit("error","Invalid value for global properties: "+l);return}this.config.globalProperties=l;return this};g.prototype.writePath=function(l){g.log("This method has been deprecated. Use client.url('events') instead.");if(!arguments.length){return this.config.writePath}if(!this.projectId()){this.emit("error","Client instance is missing a projectId property");return this.config.writePath||("/3.0/projects/"+this.projectId()+"/events")}this.config.writePath=l?String(l):("/3.0/projects/"+this.projectId()+"/events");return this};function k(m){var l=[];i(m,function(o,n){if("string"!==typeof o){o=j.stringify(o)}l.push(n+"="+encodeURIComponent(o))});return l.join("&")}a.exports=g},{"./utils/each":15,"./utils/extend":16,"./utils/json":17,"./utils/queue":20,"component-emitter":22}],11:[function(h,d,w){var c=h("./index");var b=h("./utils/base64");var f=h("./utils/each");var s=h("./utils/extend");var r=h("./extend-events");var q=h("./utils/json");d.exports={recordEvent:k,recordEvents:i,addEvent:n,addEvents:l};function k(x,G,F,A){var y,D,B,H,C,E,z;y=this.url("events",encodeURIComponent(x));D={};B=F;z=("boolean"===typeof A)?A:true;if(!v.call(this,B)){return}if(!x||typeof x!=="string"){m.call(this,"Collection name must be a string.",B);return}if(this.config.globalProperties){D=this.config.globalProperties(x)}s(D,G);E={};r.getExtendedEventBody(E,this.extensions.events);r.getExtendedEventBody(E,this.extensions.collections[x]);r.getExtendedEventBody(E,[D]);this.emit("recordEvent",x,E);if(!c.enabled){m.call(this,"Keen.enabled is set to false.",B);return false}H=this.url("events",encodeURIComponent(x),{api_key:this.writeKey(),data:b.encode(q.stringify(E)),modified:new Date().getTime()});C=H.length2){m.call(this,"Incorrect arguments provided to #recordEvents method",x);return}if(this.config.globalProperties){f(B,function(D,E){f(D,function(F,H){var G=y.config.globalProperties(E);B[E][H]=s(G,F)})})}z={};f(B,function(E,D){z[D]=z[D]||[];f(E,function(H,G){var F={};r.getExtendedEventBody(F,y.extensions.events);r.getExtendedEventBody(F,y.extensions.collections[D]);r.getExtendedEventBody(F,[H]);z[D].push(F)})});this.emit("recordEvents",z);if(!c.enabled){m.call(this,"Keen.enabled is set to false.",x);return false}if(p()){u.call(this,"POST",A,z,x)}else{}C=x=null;return this}function n(){this.emit("error","This method has been deprecated. Check out #recordEvent: https://github.com/keen/keen-tracking.js#record-a-single-event");k.apply(this,arguments)}function l(){this.emit("error","This method has been deprecated. Check out #recordEvents: https://github.com/keen/keen-tracking.js#record-multiple-events");i.apply(this,arguments)}function v(y){var x=y;y=null;if(!this.projectId()){m.call(this,"Keen.Client is missing a projectId property.",x);return false}if(!this.writeKey()){m.call(this,"Keen.Client is missing a writeKey property.",x);return false}return true}function m(z,x){var y="Event(s) not recorded: "+z;this.emit("error",y);if(x){x.call(this,y,null);x=null}}function t(){if("undefined"!==typeof window){if(navigator.userAgent.indexOf("MSIE")!==-1||navigator.appVersion.indexOf("Trident/")>0){return 2000}}return 16000}function o(x,z,y,A){if(p()){u.call(this,"POST",x,z,A)}else{m.call(this,y)}}function u(E,z,A,D){var y=this;var B;var C=p();var x=D;D=null;C.onreadystatechange=function(){var F;if(C.readyState==4){if(C.status>=200&&C.status<300){try{F=q.parse(C.responseText)}catch(G){c.emit("error","Could not parse HTTP response: "+C.responseText);if(x){x.call(y,C,null)}}if(x&&F){x.call(y,null,F)}}else{c.emit("error","HTTP request failed.");if(x){x.call(y,C,null)}}}};C.open(E,z,true);C.setRequestHeader("Authorization",y.writeKey());C.setRequestHeader("Content-Type","application/json");if(A){B=q.stringify(A)}if(E.toUpperCase()==="GET"){C.send()}if(E.toUpperCase()==="POST"){C.send(B)}}function a(x){var y=p();if(y){y.open("GET",x,false);y.send(null)}}function p(){var x="undefined"==typeof window?this:window;if(x.XMLHttpRequest&&("file:"!=x.location.protocol||!x.ActiveXObject)){return new XMLHttpRequest}else{try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(y){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(y){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(y){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(y){}}return false}function g(x,G){var H=this,A=G,C=new Date().getTime(),E=document.createElement("script"),F=document.getElementsByTagName("head")[0],D="keenJSONPCallback",B=false;G=null;D+=C;while(D in window){D+="a"}window[D]=function(I){if(B===true){return}B=true;if(A){A.call(H,null,I)}y()};E.src=x+"&jsonp="+D;F.appendChild(E);E.onreadystatechange=function(){if(B===false&&this.readyState==="loaded"){B=true;z();y()}};E.onerror=function(){if(B===false){B=true;z();y()}};function z(){if(A){A.call(H,"An error occurred!",null)}}function y(){window[D]=undefined;try{delete window[D]}catch(I){}F.removeChild(E)}}function j(B,C){var z=this,x=C,y=document.createElement("img"),A=false;C=null;y.onload=function(){A=true;if("naturalHeight" in this){if(this.naturalHeight+this.naturalWidth===0){this.onerror();return}}else{if(this.width+this.height===0){this.onerror();return}}if(x){x.call(z)}};y.onerror=function(){A=true;if(x){x.call(z,"An error occurred!",null)}};y.src=B+"&c=clv1"}},{"./extend-events":3,"./index":10,"./utils/base64":12,"./utils/each":15,"./utils/extend":16,"./utils/json":17}],12:[function(b,c,a){c.exports={map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(f){var d="",l=0,h=this.map,k,j,g,s,r,q,p;f=this.utf8.encode(f);while(l>2);r=(((k&3)<<4)|(j>>4));q=(isNaN(j)?64:((j&15)<<2)|(g>>6));p=(isNaN(j)||isNaN(g))?64:g&63;d=d+h.charAt(s)+h.charAt(r)+h.charAt(q)+h.charAt(p)}return d},decode:function(f){var d="",p=0,h=this.map,g=String.fromCharCode,t,s,r,q,l,k,j;f=f.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(p>4);k=((s&15)<<4)|(r>>2);j=((r&3)<<6)|q;d=d+(g(l)+((r!=64)?g(k):""))+(((q!=64)?g(j):""))}return this.utf8.decode(d)},utf8:{encode:function(j){var f="",d=0,h=String.fromCharCode,g;while(d127)&&(g<2048))?(h((g>>6)|192)+h((g&63)|128)):(h((g>>12)|224)+h(((g>>6)&63)|128)+h((g&63)|128)))}return f},decode:function(k){var g="",f=0,j=String.fromCharCode,d,h;while(f191)&&(h<224))?[j(((h&31)<<6)|((d=k.charCodeAt(f+1))&63)),(f+=2)][0]:[j(((h&15)<<12)|(((d=k.charCodeAt(f+1))&63)<<6)|((c3=k.charCodeAt(f+2))&63)),(f+=3)][0])}return g}}}},{}],13:[function(b,g,a){var f=b("cookies-js");var d=b("./json");var h=b("./extend");g.exports=c;function c(i){if(!arguments.length){return}if(this instanceof c===false){return new c(i)}this.config={key:i,options:{}};this.data=this.get();return this}c.prototype.get=function(j){var i={};if(f.get(this.config.key)){i=d.parse(decodeURIComponent(f.get(this.config.key)))}if(j){return("undefined"!==typeof i[j])?i[j]:null}else{return i}};c.prototype.set=function(j,i){if(!arguments.length||!this.enabled()){return this}if("string"===typeof j&&arguments.length===2){this.data[j]=i?i:null}else{if("object"===typeof j&&arguments.length===1){h(this.data,j)}}f.set(this.config.key,encodeURIComponent(d.stringify(this.data)),this.config.options);return this};c.prototype.expire=function(){f.expire(this.config.key);this.data={};return this};c.prototype.options=function(i){if(!arguments.length){return this.config.options}this.config.options=(typeof i==="object")?i:{};return this};c.prototype.enabled=function(){return f.enabled}},{"./extend":16,"./json":17,"cookies-js":23}],14:[function(c,f,a){var d=c("./json");f.exports=b;function b(l){for(var k=1;k0&&this.interval>=this.config.interval)||this.capacity>=this.config.capacity){this.emit("flush");this.interval=0}}f(a.prototype)},{"component-emitter":22}],21:[function(b,c,a){c.exports=d;function d(f){if(this instanceof d===false){return new d(f)}this.count=f||0;return this}d.prototype.start=function(){var f=this;this.pause();this.interval=setInterval(function(){f.count++},1000);return this};d.prototype.pause=function(){clearInterval(this.interval);return this};d.prototype.value=function(){return this.count};d.prototype.clear=function(){this.count=0;return this}},{}],22:[function(c,d,b){d.exports=f;function f(g){if(g){return a(g)}}function a(h){for(var g in f.prototype){h[g]=f.prototype[g]}return h}f.prototype.on=f.prototype.addEventListener=function(h,g){this._callbacks=this._callbacks||{};(this._callbacks["$"+h]=this._callbacks["$"+h]||[]).push(g);return this};f.prototype.once=function(i,h){function g(){this.off(i,g);h.apply(this,arguments)}g.fn=h;this.on(i,g);return this};f.prototype.off=f.prototype.removeListener=f.prototype.removeAllListeners=f.prototype.removeEventListener=function(l,j){this._callbacks=this._callbacks||{};if(0==arguments.length){this._callbacks={};return this}var k=this._callbacks["$"+l];if(!k){return this}if(1==arguments.length){delete this._callbacks["$"+l];return this}var g;for(var h=0;h or DOM element")}}if(v){y=function(){if(!q){q=true;v()}}}this.recordEvent(o,w,y);setTimeout(y,p);if(!x.metaKey){return false}}if(!Array.prototype.indexOf){Array.prototype.indexOf=function(p){var o=this.length>>>0;var q=Number(arguments[1])||0;q=(q<0)?Math.ceil(q):Math.floor(q);if(q<0){q+=o}for(;q0){o=JSON.parse(JSON.stringify(n.queue));n.queue=h();n.queue.options=o.options;n.emit("recordDeferredEvents",o.events);n.recordEvents(o.events,function(q,p){if(q){n.recordEvents(o.events)}else{o=void 0}})}return n}function i(o){var n="Event(s) not deferred: "+o;this.emit("error",n)}},{"./index":10,"./utils/each":15,"./utils/queue":20}],3:[function(d,c,g){var f=d("./utils/deepExtend");var i=d("./utils/each");c.exports={extendEvent:b,extendEvents:j,getExtendedEventBody:a};function b(k,l){if(arguments.length!==2||typeof k!=="string"||("object"!==typeof l&&"function"!==typeof l)){h.call(this,"Incorrect arguments provided to #extendEvent method");return}this.extensions.collections[k]=this.extensions.collections[k]||[];this.extensions.collections[k].push(l);this.emit("extendEvent",k,l);return this}function j(k){if(arguments.length!==1||("object"!==typeof k&&"function"!==typeof k)){h.call(this,"Incorrect arguments provided to #extendEvents method");return}this.extensions.events.push(k);this.emit("extendEvents",k);return this}function h(l){var k="Event(s) not extended: "+l;this.emit("error",k)}function a(l,k){if(k&&k.length>0){i(k,function(o,n){var m=(typeof o==="function")?o():o;f(l,m)})}return l}},{"./utils/deepExtend":14,"./utils/each":15}],4:[function(d,f,b){var a=d("./getScreenProfile"),g=d("./getWindowProfile");function c(){return{cookies:("undefined"!==typeof navigator.cookieEnabled)?navigator.cookieEnabled:false,codeName:navigator.appCodeName,language:navigator.language,name:navigator.appName,online:navigator.onLine,platform:navigator.platform,useragent:navigator.userAgent,version:navigator.appVersion,screen:a(),window:g()}}f.exports=c},{"./getScreenProfile":7,"./getWindowProfile":9}],5:[function(b,c,a){function d(f){var g=f||new Date();return{hour_of_day:g.getHours(),day_of_week:parseInt(1+g.getDay()),day_of_month:g.getDate(),month:parseInt(1+g.getMonth()),year:g.getFullYear()}}c.exports=d},{}],6:[function(c,d,a){function b(l){if(!l.nodeName){return""}var f=[];while(l.parentNode!=null){var k=0;var g=0;for(var j=0;j1){f.unshift(l.nodeName.toLowerCase()+":eq("+g+")")}else{f.unshift(l.nodeName.toLowerCase())}}l=l.parentNode}return f.slice(1).join(" > ")}d.exports=b},{}],7:[function(c,d,b){function a(){var h,f;if("undefined"==typeof window||!window.screen){return{}}h=["height","width","colorDepth","pixelDepth","availHeight","availWidth"];f={};for(var g=0;gwindow.innerHeight?"landscape":"portrait"};return f}d.exports=a},{}],8:[function(b,c,a){function d(){var f="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";return f.replace(/[xy]/g,function(i){var h=Math.random()*16|0,g=i=="x"?h:(h&3|8);return g.toString(16)})}c.exports=d},{}],9:[function(b,c,a){function d(){var f,h,g;if("undefined"==typeof document){return{}}f=document.body;h=document.documentElement;g={height:("innerHeight" in window)?window.innerHeight:document.documentElement.offsetHeight,width:("innerWidth" in window)?window.innerWidth:document.documentElement.offsetWidth,scrollHeight:Math.max(f.scrollHeight,f.offsetHeight,h.clientHeight,h.scrollHeight,h.offsetHeight)||null};if(window.screen){g.ratio={height:(window.screen.availHeight)?parseFloat((window.innerHeight/window.screen.availHeight).toFixed(2)):null,width:(window.screen.availWidth)?parseFloat((window.innerWidth/window.screen.availWidth).toFixed(2)):null}}return g}c.exports=d},{}],10:[function(b,a,c){var h=b("component-emitter");var j=b("./utils/json");var i=b("./utils/each");var f=b("./utils/extend");var d=b("./utils/queue");var g=function(m){var l=this;this.configure(m);f(this.config.resources,g.resources);this.extensions={events:[],collections:{}};this.queue=d();this.queue.on("flush",function(){l.recordDeferredEvents()});if(g.debug){this.on("error",g.log)}this.emit("ready");g.emit("client",this)};h(g);h(g.prototype);f(g,{debug:false,enabled:true,loaded:false,helpers:{},resources:{base:"{protocol}://{host}",version:"{protocol}://{host}/3.0",projects:"{protocol}://{host}/3.0/projects",projectId:"{protocol}://{host}/3.0/projects/{projectId}",events:"{protocol}://{host}/3.0/projects/{projectId}/events"},utils:{},version:"0.1.1"});g.log=function(l){if(g.debug&&typeof console=="object"){console.log("[Keen IO]",l)}};g.prototype.configure=function(l){var m=this,n=l||{},o="https";this.config=this.config||{projectId:undefined,writeKey:undefined,host:"api.keen.io",protocol:o,requestType:"jsonp",resources:{},writePath:undefined};if("undefined"!==typeof document&&document.all){n.protocol=(document.location.protocol!=="https:")?"http":o}if(n.host){n.host.replace(/.*?:\/\//g,"")}f(this.config,n);return m};g.prototype.projectId=function(l){if(!arguments.length){return this.config.projectId}this.config.projectId=(l?String(l):null);return this};g.prototype.writeKey=function(l){if(!arguments.length){return this.config.writeKey}this.config.writeKey=(l?String(l):null);return this};g.prototype.resources=function(m){if(!arguments.length){return this.config.resources}var l=this;if(typeof m==="object"){i(m,function(o,n){l.config.resources[n]=(o?o:null)})}return this};g.prototype.url=function(m){var l=Array.prototype.slice.call(arguments,1),n=g.resources.base||"{protocol}://{host}",o;if(m&&typeof m==="string"){if(this.config.resources[m]){o=this.config.resources[m]}else{o=n+m}}else{o=n}i(this.config,function(q,p){if(typeof q!=="object"){o=o.replace("{"+p+"}",q)}});i(l,function(p,q){if(typeof p==="string"){o+="/"+p}else{if(typeof p==="object"){o+="?";i(p,function(s,r){o+=r+"="+s+"&"});o=o.slice(0,-1)}}});return o};g.prototype.setGlobalProperties=function(l){g.log("This method has been deprecated. Check out #extendEvents: https://github.com/keen/keen-tracking.js#extend-events");if(!l||typeof l!=="function"){this.emit("error","Invalid value for global properties: "+l);return}this.config.globalProperties=l;return this};g.prototype.writePath=function(l){g.log("This method has been deprecated. Use client.url('events') instead.");if(!arguments.length){return this.config.writePath}if(!this.projectId()){this.emit("error","Client instance is missing a projectId property");return this.config.writePath||("/3.0/projects/"+this.projectId()+"/events")}this.config.writePath=l?String(l):("/3.0/projects/"+this.projectId()+"/events");return this};function k(m){var l=[];i(m,function(o,n){if("string"!==typeof o){o=j.stringify(o)}l.push(n+"="+encodeURIComponent(o))});return l.join("&")}a.exports=g},{"./utils/each":15,"./utils/extend":16,"./utils/json":17,"./utils/queue":20,"component-emitter":22}],11:[function(h,d,w){var c=h("./index");var b=h("./utils/base64");var f=h("./utils/each");var s=h("./utils/extend");var r=h("./extend-events");var q=h("./utils/json");d.exports={recordEvent:k,recordEvents:i,addEvent:n,addEvents:l};function k(x,G,F,A){var y,D,B,H,C,E,z;y=this.url("events",encodeURIComponent(x));D={};B=F;z=("boolean"===typeof A)?A:true;if(!v.call(this,B)){return}if(!x||typeof x!=="string"){m.call(this,"Collection name must be a string.",B);return}if(this.config.globalProperties){D=this.config.globalProperties(x)}s(D,G);E={};r.getExtendedEventBody(E,this.extensions.events);r.getExtendedEventBody(E,this.extensions.collections[x]);r.getExtendedEventBody(E,[D]);this.emit("recordEvent",x,E);if(!c.enabled){m.call(this,"Keen.enabled is set to false.",B);return false}H=this.url("events",encodeURIComponent(x),{api_key:this.writeKey(),data:b.encode(q.stringify(E)),modified:new Date().getTime()});C=H.length2){m.call(this,"Incorrect arguments provided to #recordEvents method",x);return}if(this.config.globalProperties){f(B,function(D,E){f(D,function(F,H){var G=y.config.globalProperties(E);B[E][H]=s(G,F)})})}z={};f(B,function(E,D){z[D]=z[D]||[];f(E,function(H,G){var F={};r.getExtendedEventBody(F,y.extensions.events);r.getExtendedEventBody(F,y.extensions.collections[D]);r.getExtendedEventBody(F,[H]);z[D].push(F)})});this.emit("recordEvents",z);if(!c.enabled){m.call(this,"Keen.enabled is set to false.",x);return false}if(p()){u.call(this,"POST",A,z,x)}else{}C=x=null;return this}function n(){this.emit("error","This method has been deprecated. Check out #recordEvent: https://github.com/keen/keen-tracking.js#record-a-single-event");k.apply(this,arguments)}function l(){this.emit("error","This method has been deprecated. Check out #recordEvents: https://github.com/keen/keen-tracking.js#record-multiple-events");i.apply(this,arguments)}function v(y){var x=y;y=null;if(!this.projectId()){m.call(this,"Keen.Client is missing a projectId property.",x);return false}if(!this.writeKey()){m.call(this,"Keen.Client is missing a writeKey property.",x);return false}return true}function m(z,x){var y="Event(s) not recorded: "+z;this.emit("error",y);if(x){x.call(this,y,null);x=null}}function t(){if("undefined"!==typeof window){if(navigator.userAgent.indexOf("MSIE")!==-1||navigator.appVersion.indexOf("Trident/")>0){return 2000}}return 16000}function o(x,z,y,A){if(p()){u.call(this,"POST",x,z,A)}else{m.call(this,y)}}function u(E,z,A,D){var y=this;var B;var C=p();var x=D;D=null;C.onreadystatechange=function(){var F;if(C.readyState==4){if(C.status>=200&&C.status<300){try{F=q.parse(C.responseText)}catch(G){c.emit("error","Could not parse HTTP response: "+C.responseText);if(x){x.call(y,C,null)}}if(x&&F){x.call(y,null,F)}}else{c.emit("error","HTTP request failed.");if(x){x.call(y,C,null)}}}};C.open(E,z,true);C.setRequestHeader("Authorization",y.writeKey());C.setRequestHeader("Content-Type","application/json");if(A){B=q.stringify(A)}if(E.toUpperCase()==="GET"){C.send()}if(E.toUpperCase()==="POST"){C.send(B)}}function a(x){var y=p();if(y){y.open("GET",x,false);y.send(null)}}function p(){var x="undefined"==typeof window?this:window;if(x.XMLHttpRequest&&("file:"!=x.location.protocol||!x.ActiveXObject)){return new XMLHttpRequest}else{try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(y){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(y){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(y){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(y){}}return false}function g(x,G){var H=this,A=G,C=new Date().getTime(),E=document.createElement("script"),F=document.getElementsByTagName("head")[0],D="keenJSONPCallback",B=false;G=null;D+=C;while(D in window){D+="a"}window[D]=function(I){if(B===true){return}B=true;if(A){A.call(H,null,I)}y()};E.src=x+"&jsonp="+D;F.appendChild(E);E.onreadystatechange=function(){if(B===false&&this.readyState==="loaded"){B=true;z();y()}};E.onerror=function(){if(B===false){B=true;z();y()}};function z(){if(A){A.call(H,"An error occurred!",null)}}function y(){window[D]=undefined;try{delete window[D]}catch(I){}F.removeChild(E)}}function j(B,C){var z=this,x=C,y=document.createElement("img"),A=false;C=null;y.onload=function(){A=true;if("naturalHeight" in this){if(this.naturalHeight+this.naturalWidth===0){this.onerror();return}}else{if(this.width+this.height===0){this.onerror();return}}if(x){x.call(z)}};y.onerror=function(){A=true;if(x){x.call(z,"An error occurred!",null)}};y.src=B+"&c=clv1"}},{"./extend-events":3,"./index":10,"./utils/base64":12,"./utils/each":15,"./utils/extend":16,"./utils/json":17}],12:[function(b,c,a){c.exports={map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(f){var d="",l=0,h=this.map,k,j,g,s,r,q,p;f=this.utf8.encode(f);while(l>2);r=(((k&3)<<4)|(j>>4));q=(isNaN(j)?64:((j&15)<<2)|(g>>6));p=(isNaN(j)||isNaN(g))?64:g&63;d=d+h.charAt(s)+h.charAt(r)+h.charAt(q)+h.charAt(p)}return d},decode:function(f){var d="",p=0,h=this.map,g=String.fromCharCode,t,s,r,q,l,k,j;f=f.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(p>4);k=((s&15)<<4)|(r>>2);j=((r&3)<<6)|q;d=d+(g(l)+((r!=64)?g(k):""))+(((q!=64)?g(j):""))}return this.utf8.decode(d)},utf8:{encode:function(j){var f="",d=0,h=String.fromCharCode,g;while(d127)&&(g<2048))?(h((g>>6)|192)+h((g&63)|128)):(h((g>>12)|224)+h(((g>>6)&63)|128)+h((g&63)|128)))}return f},decode:function(k){var g="",f=0,j=String.fromCharCode,d,h;while(f191)&&(h<224))?[j(((h&31)<<6)|((d=k.charCodeAt(f+1))&63)),(f+=2)][0]:[j(((h&15)<<12)|(((d=k.charCodeAt(f+1))&63)<<6)|((c3=k.charCodeAt(f+2))&63)),(f+=3)][0])}return g}}}},{}],13:[function(b,g,a){var f=b("js-cookie");var d=b("./json");var h=b("./extend");g.exports=c;function c(i){if(!arguments.length){return}if(this instanceof c===false){return new c(i)}this.config={key:i,options:{}};this.data=this.get();this.enabled=true;return this}c.prototype.get=function(j){var i={};if(f.get(this.config.key)){i=d.parse(f.get(this.config.key))}if(j){return("undefined"!==typeof i[j])?i[j]:null}else{return i}};c.prototype.set=function(j,i){if(!arguments.length||!this.enabled){return this}if("string"===typeof j&&arguments.length===2){this.data[j]=i?i:null}else{if("object"===typeof j&&arguments.length===1){h(this.data,j)}}f.set(this.config.key,this.data,this.config.options);return this};c.prototype.expire=function(){f.remove(this.config.key);this.data={};return this};c.prototype.options=function(i){if(!arguments.length){return this.config.options}this.config.options=(typeof i==="object")?i:{};return this}},{"./extend":16,"./json":17,"js-cookie":23}],14:[function(c,f,a){var d=c("./json");f.exports=b;function b(l){for(var k=1;k0&&this.interval>=this.config.interval)||this.capacity>=this.config.capacity){this.emit("flush");this.interval=0}}f(a.prototype)},{"component-emitter":22}],21:[function(b,c,a){c.exports=d;function d(f){if(this instanceof d===false){return new d(f)}this.count=f||0;return this}d.prototype.start=function(){var f=this;this.pause();this.interval=setInterval(function(){f.count++},1000);return this};d.prototype.pause=function(){clearInterval(this.interval);return this};d.prototype.value=function(){return this.count};d.prototype.clear=function(){this.count=0;return this}},{}],22:[function(c,d,b){d.exports=f;function f(g){if(g){return a(g)}}function a(h){for(var g in f.prototype){h[g]=f.prototype[g]}return h}f.prototype.on=f.prototype.addEventListener=function(h,g){this._callbacks=this._callbacks||{};(this._callbacks["$"+h]=this._callbacks["$"+h]||[]).push(g);return this};f.prototype.once=function(i,h){function g(){this.off(i,g);h.apply(this,arguments)}g.fn=h;this.on(i,g);return this};f.prototype.off=f.prototype.removeListener=f.prototype.removeAllListeners=f.prototype.removeEventListener=function(l,j){this._callbacks=this._callbacks||{};if(0==arguments.length){this._callbacks={};return this}var k=this._callbacks["$"+l];if(!k){return this}if(1==arguments.length){delete this._callbacks["$"+l];return this}var g;for(var h=0;h1){n=f({path:"/"},g.defaults,n);if(typeof n.expires==="number"){var l=new Date();l.setMilliseconds(l.getMilliseconds()+n.expires*86400000);n.expires=l}try{u=JSON.stringify(q);if(/^[\{\[]/.test(u)){q=u}}catch(p){}if(!h.write){q=encodeURIComponent(String(q)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent)}else{q=h.write(q,r)}r=encodeURIComponent(String(r));r=r.replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent);r=r.replace(/[\(\)]/g,escape);return(document.cookie=[r,"=",q,n.expires&&"; expires="+n.expires.toUTCString(),n.path&&"; path="+n.path,n.domain&&"; domain="+n.domain,n.secure?"; secure":""].join(""))}if(!r){u={}}var t=document.cookie?document.cookie.split("; "):[];var s=/(%[0-9A-Z]{2})+/g;var o=0;for(;o1)))/4)-w((ag-1901+ah)/100)+w((ag-1601+ah)/400)}}if(!(v=r.hasOwnProperty)){v=function(ai){var ag={},ah;if((ag.__proto__=null,ag.__proto__={toString:1},ag).toString!=y){v=function(al){var ak=this.__proto__,aj=al in (this.__proto__=null,this);this.__proto__=ak;return aj}}else{ah=ag.constructor;v=function(ak){var aj=(this.constructor||ah).prototype;return ak in this&&!(ak in aj&&this[ak]===aj[ak])}}ag=null;return v.call(this,ai)}}q=function(ai,al){var aj=0,ag,ah,ak;(ag=function(){this.valueOf=0}).prototype.valueOf=0;ah=new ag();for(ak in ah){if(v.call(ah,ak)){aj++}}ag=ah=null;if(!aj){ah=["valueOf","toString","toLocaleString","propertyIsEnumerable","isPrototypeOf","hasOwnProperty","constructor"];q=function(an,ar){var aq=y.call(an)==Y,ap,ao;var am=!aq&&typeof an.constructor!="function"&&i[typeof an.hasOwnProperty]&&an.hasOwnProperty||v;for(ap in an){if(!(aq&&ap=="prototype")&&am.call(an,ap)){ar(ap)}}for(ao=ah.length;ap=ah[--ao];am.call(an,ap)&&ar(ap)){}}}else{if(aj==2){q=function(an,aq){var am={},ap=y.call(an)==Y,ao;for(ao in an){if(!(ap&&ao=="prototype")&&!v.call(am,ao)&&(am[ao]=1)&&v.call(an,ao)){aq(ao)}}}}else{q=function(an,aq){var ap=y.call(an)==Y,ao,am;for(ao in an){if(!(ap&&ao=="prototype")&&v.call(an,ao)&&!(am=ao==="constructor")){aq(ao)}}if(am||v.call(an,(ao="constructor"))){aq(ao)}}}}return q(ai,al)};if(!s("json-stringify")){var u={92:"\\\\",34:'\\"',8:"\\b",12:"\\f",10:"\\n",13:"\\r",9:"\\t"};var M="000000";var x=function(ag,ah){return(M+(ah||0)).slice(-ag)};var D="\\u00";var G=function(am){var ah='"',ak=0,al=am.length,ag=!J||al>10;var aj=ag&&(J?am.split(""):am);for(;ak-1/0&&ax<1/0){if(H){aC=w(ax/86400000);for(au=w(aC/365.2425)+1970-1;H(au+1,0)<=aC;au++){}for(aD=w((aC-H(au,0))/30.42);H(au,aD+1)<=aC;aD++){}aC=1+aC-H(au,aD);ao=(ax%86400000+86400000)%86400000;aA=w(ao/3600000)%24;ay=w(ao/60000)%60;av=w(ao/1000)%60;ar=ao%1000}else{au=ax.getUTCFullYear();aD=ax.getUTCMonth();aC=ax.getUTCDate();aA=ax.getUTCHours();ay=ax.getUTCMinutes();av=ax.getUTCSeconds();ar=ax.getUTCMilliseconds()}ax=(au<=0||au>=10000?(au<0?"-":"+")+x(6,au<0?-au:au):x(4,au))+"-"+x(2,aD+1)+"-"+x(2,aC)+"T"+x(2,aA)+":"+x(2,ay)+":"+x(2,av)+"."+x(3,ar)+"Z"}else{ax=null}}else{if(typeof ax.toJSON=="function"&&((ai!=R&&ai!=S&&ai!=I)||v.call(ax,"toJSON"))){ax=ax.toJSON(am)}}}if(ak){ax=ak.call(aE,am,ax)}if(ax===null){return"null"}ai=y.call(ax);if(ai==E){return""+ax}else{if(ai==R){return ax>-1/0&&ax<1/0?""+ax:"null"}else{if(ai==S){return G(""+ax)}}}if(typeof ax=="object"){for(aj=an.length;aj--;){if(an[aj]===ax){throw ae()}}an.push(ax);aw=[];az=ag;ag+=aB;if(ai==I){for(al=0,aj=ax.length;al0){for(ah="",aj>10&&(aj=10);ah.length=48&&ah<=57||ah>=97&&ah<=102||ah>=65&&ah<=70)){L()}}ak+=Q("0x"+al.slice(ai,K));break;default:L()}}else{if(ah==34){break}ah=al.charCodeAt(K);ai=K;while(ah>=32&&ah!=92&&ah!=34){ah=al.charCodeAt(++K)}ak+=al.slice(ai,K)}}}if(al.charCodeAt(K)==34){K++;return ak}L();default:ai=K;if(ah==45){am=true;ah=al.charCodeAt(++K)}if(ah>=48&&ah<=57){if(ah==48&&((ah=al.charCodeAt(K+1)),ah>=48&&ah<=57)){L()}am=false;for(;K=48&&ah<=57);K++){}if(al.charCodeAt(K)==46){ag=++K;for(;ag=48&&ah<=57);ag++){}if(ag==K){L()}K=ag}ah=al.charCodeAt(K);if(ah==101||ah==69){ah=al.charCodeAt(++K);if(ah==43||ah==45){K++}for(ag=K;ag=48&&ah<=57);ag++){}if(ag==K){L()}K=ag}return +al.slice(ai,K)}if(am){L()}if(al.slice(K,K+4)=="true"){K+=4;return true}else{if(al.slice(K,K+5)=="false"){K+=5;return false}else{if(al.slice(K,K+4)=="null"){K+=4;return null}}}L()}}return"$"};var aa=function(ah){var ag,ai;if(ah=="$"){L()}if(typeof ah=="string"){if((J?ah.charAt(0):ah[0])=="@"){return ah.slice(1)}if(ah=="["){ag=[];for(;;ai||(ai=true)){ah=C();if(ah=="]"){break}if(ai){if(ah==","){ah=C();if(ah=="]"){L()}}else{L()}}if(ah==","){L()}ag.push(aa(ah))}return ag}else{if(ah=="{"){ag={};for(;;ai||(ai=true)){ah=C();if(ah=="}"){break}if(ai){if(ah==","){ah=C();if(ah=="}"){L()}}else{L()}}if(ah==","||typeof ah!="string"||(J?ah.charAt(0):ah[0])!="@"||C()!=":"){L()}ag[ah.slice(1)]=aa(C())}return ag}}L()}return ah};var T=function(ai,ah,aj){var ag=A(ai,ah,aj);if(ag===P){delete ai[ah]}else{ai[ah]=ag}};var A=function(aj,ai,ak){var ah=aj[ai],ag;if(typeof ah=="object"&&ah){if(y.call(ah)==I){for(ag=ah.length;ag--;){T(ah,ag,ak)}}else{q(ah,function(al){T(ah,al,ak)})}}return ak.call(aj,ai,ah)};Z.parse=function(ai,aj){var ag,ah;K=0;ab=""+ai;ag=aa(C());if(C()!="$"){L()}K=ab=null;return aj&&y.call(aj)==Y?A((ah={},ah[""]=ag,ah),"",aj):ag}}}Z.runInContext=n;return Z}if(l&&!g){n(m,l)}else{var j=m.JSON,o=m.JSON3,h=false;var k=n(m,(m.JSON3={noConflict:function(){if(!h){h=true;m.JSON=j;m.JSON3=o;j=o=null}return k}}));m.JSON={parse:k.parse,stringify:k.stringify}}if(g){define(function(){return k})}}).call(this)}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{})},{}]},{},[1]); \ No newline at end of file diff --git a/test/unit/modules/utils/cookie-spec.js b/test/unit/modules/utils/cookie-spec.js index 56eb9ae..34c4873 100644 --- a/test/unit/modules/utils/cookie-spec.js +++ b/test/unit/modules/utils/cookie-spec.js @@ -112,10 +112,14 @@ describe('Keen.utils.cookie', function() { }); - describe('.enabled', function(){ + describe('enabled property', function(){ - it('should return a boolean value', function(){ - assert.isBoolean(this.cookie.enabled()); + it('should be a boolean value by default', function(){ + assert.isBoolean(this.cookie.enabled); + }); + + it('should be true by default', function(){ + assert.isTrue(this.cookie.enabled); }); }); From d544a266d56b59e9783c23f5b1618e15b84a904f Mon Sep 17 00:00:00 2001 From: aroc Date: Thu, 24 Mar 2016 14:00:48 -0600 Subject: [PATCH 05/10] Allow setting expiration setting on cookie. --- lib/utils/cookie.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/utils/cookie.js b/lib/utils/cookie.js index 4d942aa..8b9eeb8 100644 --- a/lib/utils/cookie.js +++ b/lib/utils/cookie.js @@ -33,7 +33,7 @@ cookie.prototype.get = function(str){ } }; -cookie.prototype.set = function(str, value){ +cookie.prototype.set = function(str, value, daysUntilExpire){ if (!arguments.length || !this.enabled) return this; if ('string' === typeof str && arguments.length === 2) { this.data[str] = value ? value : null; @@ -41,7 +41,9 @@ cookie.prototype.set = function(str, value){ else if ('object' === typeof str && arguments.length === 1) { extend(this.data, str); } - Cookies.set(this.config.key, this.data, this.config.options); + var extraOptions = {}; + if (daysUntilExpire) { extraOptions.expires = daysUntilExpire }; + Cookies.set(this.config.key, this.data, extend(this.config.options, extraOptions)); return this; }; From 5ed515c0f7db53598aacc239afe693a7213cf592 Mon Sep 17 00:00:00 2001 From: aroc Date: Thu, 24 Mar 2016 14:02:15 -0600 Subject: [PATCH 06/10] Swap sides of comparison statements. --- lib/utils/cookie.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/utils/cookie.js b/lib/utils/cookie.js index 8b9eeb8..e8f7077 100644 --- a/lib/utils/cookie.js +++ b/lib/utils/cookie.js @@ -26,7 +26,7 @@ cookie.prototype.get = function(str){ data = json.parse(Cookies.get(this.config.key)); } if (str) { - return ('undefined' !== typeof data[str]) ? data[str] : null; + return (typeof data[str] !== 'undefined') ? data[str] : null; } else { return data; @@ -35,10 +35,10 @@ cookie.prototype.get = function(str){ cookie.prototype.set = function(str, value, daysUntilExpire){ if (!arguments.length || !this.enabled) return this; - if ('string' === typeof str && arguments.length === 2) { + if (typeof str === 'string' && arguments.length === 2) { this.data[str] = value ? value : null; } - else if ('object' === typeof str && arguments.length === 1) { + else if (typeof str === 'object' && arguments.length === 1) { extend(this.data, str); } var extraOptions = {}; From 0d71d941a23e585118e2cfc1ba854eeae18fea39 Mon Sep 17 00:00:00 2001 From: aroc Date: Thu, 24 Mar 2016 14:37:19 -0600 Subject: [PATCH 07/10] Build files. --- dist/keen-tracking.js | 12 +++++++----- dist/keen-tracking.min.js | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/dist/keen-tracking.js b/dist/keen-tracking.js index 7d7b010..2f3abb7 100644 --- a/dist/keen-tracking.js +++ b/dist/keen-tracking.js @@ -921,21 +921,23 @@ cookie.prototype.get = function(str){ data = json.parse(Cookies.get(this.config.key)); } if (str) { - return ('undefined' !== typeof data[str]) ? data[str] : null; + return (typeof data[str] !== 'undefined') ? data[str] : null; } else { return data; } }; -cookie.prototype.set = function(str, value){ +cookie.prototype.set = function(str, value, daysUntilExpire){ if (!arguments.length || !this.enabled) return this; - if ('string' === typeof str && arguments.length === 2) { + if (typeof str === 'string' && arguments.length === 2) { this.data[str] = value ? value : null; } - else if ('object' === typeof str && arguments.length === 1) { + else if (typeof str === 'object' && arguments.length === 1) { extend(this.data, str); } - Cookies.set(this.config.key, this.data, this.config.options); + var extraOptions = {}; + if (daysUntilExpire) { extraOptions.expires = daysUntilExpire }; + Cookies.set(this.config.key, this.data, extend(this.config.options, extraOptions)); return this; }; cookie.prototype.expire = function(){ diff --git a/dist/keen-tracking.min.js b/dist/keen-tracking.min.js index 0d9b2cc..63edbb0 100644 --- a/dist/keen-tracking.min.js +++ b/dist/keen-tracking.min.js @@ -1,4 +1,4 @@ -(function e(b,g,d){function c(m,j){if(!g[m]){if(!b[m]){var i=typeof require=="function"&&require;if(!j&&i){return i(m,!0)}if(a){return a(m,!0)}var k=new Error("Cannot find module '"+m+"'");throw k.code="MODULE_NOT_FOUND",k}var h=g[m]={exports:{}};b[m][0].call(h.exports,function(l){var o=b[m][1][l];return c(o?o:l)},h,h.exports,e,b,g,d)}return g[m].exports}var a=typeof require=="function"&&require;for(var f=0;f or DOM element")}}if(v){y=function(){if(!q){q=true;v()}}}this.recordEvent(o,w,y);setTimeout(y,p);if(!x.metaKey){return false}}if(!Array.prototype.indexOf){Array.prototype.indexOf=function(p){var o=this.length>>>0;var q=Number(arguments[1])||0;q=(q<0)?Math.ceil(q):Math.floor(q);if(q<0){q+=o}for(;q0){o=JSON.parse(JSON.stringify(n.queue));n.queue=h();n.queue.options=o.options;n.emit("recordDeferredEvents",o.events);n.recordEvents(o.events,function(q,p){if(q){n.recordEvents(o.events)}else{o=void 0}})}return n}function i(o){var n="Event(s) not deferred: "+o;this.emit("error",n)}},{"./index":10,"./utils/each":15,"./utils/queue":20}],3:[function(d,c,g){var f=d("./utils/deepExtend");var i=d("./utils/each");c.exports={extendEvent:b,extendEvents:j,getExtendedEventBody:a};function b(k,l){if(arguments.length!==2||typeof k!=="string"||("object"!==typeof l&&"function"!==typeof l)){h.call(this,"Incorrect arguments provided to #extendEvent method");return}this.extensions.collections[k]=this.extensions.collections[k]||[];this.extensions.collections[k].push(l);this.emit("extendEvent",k,l);return this}function j(k){if(arguments.length!==1||("object"!==typeof k&&"function"!==typeof k)){h.call(this,"Incorrect arguments provided to #extendEvents method");return}this.extensions.events.push(k);this.emit("extendEvents",k);return this}function h(l){var k="Event(s) not extended: "+l;this.emit("error",k)}function a(l,k){if(k&&k.length>0){i(k,function(o,n){var m=(typeof o==="function")?o():o;f(l,m)})}return l}},{"./utils/deepExtend":14,"./utils/each":15}],4:[function(d,f,b){var a=d("./getScreenProfile"),g=d("./getWindowProfile");function c(){return{cookies:("undefined"!==typeof navigator.cookieEnabled)?navigator.cookieEnabled:false,codeName:navigator.appCodeName,language:navigator.language,name:navigator.appName,online:navigator.onLine,platform:navigator.platform,useragent:navigator.userAgent,version:navigator.appVersion,screen:a(),window:g()}}f.exports=c},{"./getScreenProfile":7,"./getWindowProfile":9}],5:[function(b,c,a){function d(f){var g=f||new Date();return{hour_of_day:g.getHours(),day_of_week:parseInt(1+g.getDay()),day_of_month:g.getDate(),month:parseInt(1+g.getMonth()),year:g.getFullYear()}}c.exports=d},{}],6:[function(c,d,a){function b(l){if(!l.nodeName){return""}var f=[];while(l.parentNode!=null){var k=0;var g=0;for(var j=0;j1){f.unshift(l.nodeName.toLowerCase()+":eq("+g+")")}else{f.unshift(l.nodeName.toLowerCase())}}l=l.parentNode}return f.slice(1).join(" > ")}d.exports=b},{}],7:[function(c,d,b){function a(){var h,f;if("undefined"==typeof window||!window.screen){return{}}h=["height","width","colorDepth","pixelDepth","availHeight","availWidth"];f={};for(var g=0;gwindow.innerHeight?"landscape":"portrait"};return f}d.exports=a},{}],8:[function(b,c,a){function d(){var f="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";return f.replace(/[xy]/g,function(i){var h=Math.random()*16|0,g=i=="x"?h:(h&3|8);return g.toString(16)})}c.exports=d},{}],9:[function(b,c,a){function d(){var f,h,g;if("undefined"==typeof document){return{}}f=document.body;h=document.documentElement;g={height:("innerHeight" in window)?window.innerHeight:document.documentElement.offsetHeight,width:("innerWidth" in window)?window.innerWidth:document.documentElement.offsetWidth,scrollHeight:Math.max(f.scrollHeight,f.offsetHeight,h.clientHeight,h.scrollHeight,h.offsetHeight)||null};if(window.screen){g.ratio={height:(window.screen.availHeight)?parseFloat((window.innerHeight/window.screen.availHeight).toFixed(2)):null,width:(window.screen.availWidth)?parseFloat((window.innerWidth/window.screen.availWidth).toFixed(2)):null}}return g}c.exports=d},{}],10:[function(b,a,c){var h=b("component-emitter");var j=b("./utils/json");var i=b("./utils/each");var f=b("./utils/extend");var d=b("./utils/queue");var g=function(m){var l=this;this.configure(m);f(this.config.resources,g.resources);this.extensions={events:[],collections:{}};this.queue=d();this.queue.on("flush",function(){l.recordDeferredEvents()});if(g.debug){this.on("error",g.log)}this.emit("ready");g.emit("client",this)};h(g);h(g.prototype);f(g,{debug:false,enabled:true,loaded:false,helpers:{},resources:{base:"{protocol}://{host}",version:"{protocol}://{host}/3.0",projects:"{protocol}://{host}/3.0/projects",projectId:"{protocol}://{host}/3.0/projects/{projectId}",events:"{protocol}://{host}/3.0/projects/{projectId}/events"},utils:{},version:"0.1.1"});g.log=function(l){if(g.debug&&typeof console=="object"){console.log("[Keen IO]",l)}};g.prototype.configure=function(l){var m=this,n=l||{},o="https";this.config=this.config||{projectId:undefined,writeKey:undefined,host:"api.keen.io",protocol:o,requestType:"jsonp",resources:{},writePath:undefined};if("undefined"!==typeof document&&document.all){n.protocol=(document.location.protocol!=="https:")?"http":o}if(n.host){n.host.replace(/.*?:\/\//g,"")}f(this.config,n);return m};g.prototype.projectId=function(l){if(!arguments.length){return this.config.projectId}this.config.projectId=(l?String(l):null);return this};g.prototype.writeKey=function(l){if(!arguments.length){return this.config.writeKey}this.config.writeKey=(l?String(l):null);return this};g.prototype.resources=function(m){if(!arguments.length){return this.config.resources}var l=this;if(typeof m==="object"){i(m,function(o,n){l.config.resources[n]=(o?o:null)})}return this};g.prototype.url=function(m){var l=Array.prototype.slice.call(arguments,1),n=g.resources.base||"{protocol}://{host}",o;if(m&&typeof m==="string"){if(this.config.resources[m]){o=this.config.resources[m]}else{o=n+m}}else{o=n}i(this.config,function(q,p){if(typeof q!=="object"){o=o.replace("{"+p+"}",q)}});i(l,function(p,q){if(typeof p==="string"){o+="/"+p}else{if(typeof p==="object"){o+="?";i(p,function(s,r){o+=r+"="+s+"&"});o=o.slice(0,-1)}}});return o};g.prototype.setGlobalProperties=function(l){g.log("This method has been deprecated. Check out #extendEvents: https://github.com/keen/keen-tracking.js#extend-events");if(!l||typeof l!=="function"){this.emit("error","Invalid value for global properties: "+l);return}this.config.globalProperties=l;return this};g.prototype.writePath=function(l){g.log("This method has been deprecated. Use client.url('events') instead.");if(!arguments.length){return this.config.writePath}if(!this.projectId()){this.emit("error","Client instance is missing a projectId property");return this.config.writePath||("/3.0/projects/"+this.projectId()+"/events")}this.config.writePath=l?String(l):("/3.0/projects/"+this.projectId()+"/events");return this};function k(m){var l=[];i(m,function(o,n){if("string"!==typeof o){o=j.stringify(o)}l.push(n+"="+encodeURIComponent(o))});return l.join("&")}a.exports=g},{"./utils/each":15,"./utils/extend":16,"./utils/json":17,"./utils/queue":20,"component-emitter":22}],11:[function(h,d,w){var c=h("./index");var b=h("./utils/base64");var f=h("./utils/each");var s=h("./utils/extend");var r=h("./extend-events");var q=h("./utils/json");d.exports={recordEvent:k,recordEvents:i,addEvent:n,addEvents:l};function k(x,G,F,A){var y,D,B,H,C,E,z;y=this.url("events",encodeURIComponent(x));D={};B=F;z=("boolean"===typeof A)?A:true;if(!v.call(this,B)){return}if(!x||typeof x!=="string"){m.call(this,"Collection name must be a string.",B);return}if(this.config.globalProperties){D=this.config.globalProperties(x)}s(D,G);E={};r.getExtendedEventBody(E,this.extensions.events);r.getExtendedEventBody(E,this.extensions.collections[x]);r.getExtendedEventBody(E,[D]);this.emit("recordEvent",x,E);if(!c.enabled){m.call(this,"Keen.enabled is set to false.",B);return false}H=this.url("events",encodeURIComponent(x),{api_key:this.writeKey(),data:b.encode(q.stringify(E)),modified:new Date().getTime()});C=H.length2){m.call(this,"Incorrect arguments provided to #recordEvents method",x);return}if(this.config.globalProperties){f(B,function(D,E){f(D,function(F,H){var G=y.config.globalProperties(E);B[E][H]=s(G,F)})})}z={};f(B,function(E,D){z[D]=z[D]||[];f(E,function(H,G){var F={};r.getExtendedEventBody(F,y.extensions.events);r.getExtendedEventBody(F,y.extensions.collections[D]);r.getExtendedEventBody(F,[H]);z[D].push(F)})});this.emit("recordEvents",z);if(!c.enabled){m.call(this,"Keen.enabled is set to false.",x);return false}if(p()){u.call(this,"POST",A,z,x)}else{}C=x=null;return this}function n(){this.emit("error","This method has been deprecated. Check out #recordEvent: https://github.com/keen/keen-tracking.js#record-a-single-event");k.apply(this,arguments)}function l(){this.emit("error","This method has been deprecated. Check out #recordEvents: https://github.com/keen/keen-tracking.js#record-multiple-events");i.apply(this,arguments)}function v(y){var x=y;y=null;if(!this.projectId()){m.call(this,"Keen.Client is missing a projectId property.",x);return false}if(!this.writeKey()){m.call(this,"Keen.Client is missing a writeKey property.",x);return false}return true}function m(z,x){var y="Event(s) not recorded: "+z;this.emit("error",y);if(x){x.call(this,y,null);x=null}}function t(){if("undefined"!==typeof window){if(navigator.userAgent.indexOf("MSIE")!==-1||navigator.appVersion.indexOf("Trident/")>0){return 2000}}return 16000}function o(x,z,y,A){if(p()){u.call(this,"POST",x,z,A)}else{m.call(this,y)}}function u(E,z,A,D){var y=this;var B;var C=p();var x=D;D=null;C.onreadystatechange=function(){var F;if(C.readyState==4){if(C.status>=200&&C.status<300){try{F=q.parse(C.responseText)}catch(G){c.emit("error","Could not parse HTTP response: "+C.responseText);if(x){x.call(y,C,null)}}if(x&&F){x.call(y,null,F)}}else{c.emit("error","HTTP request failed.");if(x){x.call(y,C,null)}}}};C.open(E,z,true);C.setRequestHeader("Authorization",y.writeKey());C.setRequestHeader("Content-Type","application/json");if(A){B=q.stringify(A)}if(E.toUpperCase()==="GET"){C.send()}if(E.toUpperCase()==="POST"){C.send(B)}}function a(x){var y=p();if(y){y.open("GET",x,false);y.send(null)}}function p(){var x="undefined"==typeof window?this:window;if(x.XMLHttpRequest&&("file:"!=x.location.protocol||!x.ActiveXObject)){return new XMLHttpRequest}else{try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(y){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(y){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(y){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(y){}}return false}function g(x,G){var H=this,A=G,C=new Date().getTime(),E=document.createElement("script"),F=document.getElementsByTagName("head")[0],D="keenJSONPCallback",B=false;G=null;D+=C;while(D in window){D+="a"}window[D]=function(I){if(B===true){return}B=true;if(A){A.call(H,null,I)}y()};E.src=x+"&jsonp="+D;F.appendChild(E);E.onreadystatechange=function(){if(B===false&&this.readyState==="loaded"){B=true;z();y()}};E.onerror=function(){if(B===false){B=true;z();y()}};function z(){if(A){A.call(H,"An error occurred!",null)}}function y(){window[D]=undefined;try{delete window[D]}catch(I){}F.removeChild(E)}}function j(B,C){var z=this,x=C,y=document.createElement("img"),A=false;C=null;y.onload=function(){A=true;if("naturalHeight" in this){if(this.naturalHeight+this.naturalWidth===0){this.onerror();return}}else{if(this.width+this.height===0){this.onerror();return}}if(x){x.call(z)}};y.onerror=function(){A=true;if(x){x.call(z,"An error occurred!",null)}};y.src=B+"&c=clv1"}},{"./extend-events":3,"./index":10,"./utils/base64":12,"./utils/each":15,"./utils/extend":16,"./utils/json":17}],12:[function(b,c,a){c.exports={map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(f){var d="",l=0,h=this.map,k,j,g,s,r,q,p;f=this.utf8.encode(f);while(l>2);r=(((k&3)<<4)|(j>>4));q=(isNaN(j)?64:((j&15)<<2)|(g>>6));p=(isNaN(j)||isNaN(g))?64:g&63;d=d+h.charAt(s)+h.charAt(r)+h.charAt(q)+h.charAt(p)}return d},decode:function(f){var d="",p=0,h=this.map,g=String.fromCharCode,t,s,r,q,l,k,j;f=f.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(p>4);k=((s&15)<<4)|(r>>2);j=((r&3)<<6)|q;d=d+(g(l)+((r!=64)?g(k):""))+(((q!=64)?g(j):""))}return this.utf8.decode(d)},utf8:{encode:function(j){var f="",d=0,h=String.fromCharCode,g;while(d127)&&(g<2048))?(h((g>>6)|192)+h((g&63)|128)):(h((g>>12)|224)+h(((g>>6)&63)|128)+h((g&63)|128)))}return f},decode:function(k){var g="",f=0,j=String.fromCharCode,d,h;while(f191)&&(h<224))?[j(((h&31)<<6)|((d=k.charCodeAt(f+1))&63)),(f+=2)][0]:[j(((h&15)<<12)|(((d=k.charCodeAt(f+1))&63)<<6)|((c3=k.charCodeAt(f+2))&63)),(f+=3)][0])}return g}}}},{}],13:[function(b,g,a){var f=b("js-cookie");var d=b("./json");var h=b("./extend");g.exports=c;function c(i){if(!arguments.length){return}if(this instanceof c===false){return new c(i)}this.config={key:i,options:{}};this.data=this.get();this.enabled=true;return this}c.prototype.get=function(j){var i={};if(f.get(this.config.key)){i=d.parse(f.get(this.config.key))}if(j){return("undefined"!==typeof i[j])?i[j]:null}else{return i}};c.prototype.set=function(j,i){if(!arguments.length||!this.enabled){return this}if("string"===typeof j&&arguments.length===2){this.data[j]=i?i:null}else{if("object"===typeof j&&arguments.length===1){h(this.data,j)}}f.set(this.config.key,this.data,this.config.options);return this};c.prototype.expire=function(){f.remove(this.config.key);this.data={};return this};c.prototype.options=function(i){if(!arguments.length){return this.config.options}this.config.options=(typeof i==="object")?i:{};return this}},{"./extend":16,"./json":17,"js-cookie":23}],14:[function(c,f,a){var d=c("./json");f.exports=b;function b(l){for(var k=1;k0&&this.interval>=this.config.interval)||this.capacity>=this.config.capacity){this.emit("flush");this.interval=0}}f(a.prototype)},{"component-emitter":22}],21:[function(b,c,a){c.exports=d;function d(f){if(this instanceof d===false){return new d(f)}this.count=f||0;return this}d.prototype.start=function(){var f=this;this.pause();this.interval=setInterval(function(){f.count++},1000);return this};d.prototype.pause=function(){clearInterval(this.interval);return this};d.prototype.value=function(){return this.count};d.prototype.clear=function(){this.count=0;return this}},{}],22:[function(c,d,b){d.exports=f;function f(g){if(g){return a(g)}}function a(h){for(var g in f.prototype){h[g]=f.prototype[g]}return h}f.prototype.on=f.prototype.addEventListener=function(h,g){this._callbacks=this._callbacks||{};(this._callbacks["$"+h]=this._callbacks["$"+h]||[]).push(g);return this};f.prototype.once=function(i,h){function g(){this.off(i,g);h.apply(this,arguments)}g.fn=h;this.on(i,g);return this};f.prototype.off=f.prototype.removeListener=f.prototype.removeAllListeners=f.prototype.removeEventListener=function(l,j){this._callbacks=this._callbacks||{};if(0==arguments.length){this._callbacks={};return this}var k=this._callbacks["$"+l];if(!k){return this}if(1==arguments.length){delete this._callbacks["$"+l];return this}var g;for(var h=0;h or DOM element")}}if(v){y=function(){if(!q){q=true;v()}}}this.recordEvent(o,w,y);setTimeout(y,p);if(!x.metaKey){return false}}if(!Array.prototype.indexOf){Array.prototype.indexOf=function(p){var o=this.length>>>0;var q=Number(arguments[1])||0;q=(q<0)?Math.ceil(q):Math.floor(q);if(q<0){q+=o}for(;q0){o=JSON.parse(JSON.stringify(n.queue));n.queue=h();n.queue.options=o.options;n.emit("recordDeferredEvents",o.events);n.recordEvents(o.events,function(q,p){if(q){n.recordEvents(o.events)}else{o=void 0}})}return n}function i(o){var n="Event(s) not deferred: "+o;this.emit("error",n)}},{"./index":10,"./utils/each":15,"./utils/queue":20}],3:[function(d,c,g){var f=d("./utils/deepExtend");var i=d("./utils/each");c.exports={extendEvent:b,extendEvents:j,getExtendedEventBody:a};function b(k,l){if(arguments.length!==2||typeof k!=="string"||("object"!==typeof l&&"function"!==typeof l)){h.call(this,"Incorrect arguments provided to #extendEvent method");return}this.extensions.collections[k]=this.extensions.collections[k]||[];this.extensions.collections[k].push(l);this.emit("extendEvent",k,l);return this}function j(k){if(arguments.length!==1||("object"!==typeof k&&"function"!==typeof k)){h.call(this,"Incorrect arguments provided to #extendEvents method");return}this.extensions.events.push(k);this.emit("extendEvents",k);return this}function h(l){var k="Event(s) not extended: "+l;this.emit("error",k)}function a(l,k){if(k&&k.length>0){i(k,function(o,n){var m=(typeof o==="function")?o():o;f(l,m)})}return l}},{"./utils/deepExtend":14,"./utils/each":15}],4:[function(d,f,b){var a=d("./getScreenProfile"),g=d("./getWindowProfile");function c(){return{cookies:("undefined"!==typeof navigator.cookieEnabled)?navigator.cookieEnabled:false,codeName:navigator.appCodeName,language:navigator.language,name:navigator.appName,online:navigator.onLine,platform:navigator.platform,useragent:navigator.userAgent,version:navigator.appVersion,screen:a(),window:g()}}f.exports=c},{"./getScreenProfile":7,"./getWindowProfile":9}],5:[function(b,c,a){function d(f){var g=f||new Date();return{hour_of_day:g.getHours(),day_of_week:parseInt(1+g.getDay()),day_of_month:g.getDate(),month:parseInt(1+g.getMonth()),year:g.getFullYear()}}c.exports=d},{}],6:[function(c,d,a){function b(l){if(!l.nodeName){return""}var f=[];while(l.parentNode!=null){var k=0;var g=0;for(var j=0;j1){f.unshift(l.nodeName.toLowerCase()+":eq("+g+")")}else{f.unshift(l.nodeName.toLowerCase())}}l=l.parentNode}return f.slice(1).join(" > ")}d.exports=b},{}],7:[function(c,d,b){function a(){var h,f;if("undefined"==typeof window||!window.screen){return{}}h=["height","width","colorDepth","pixelDepth","availHeight","availWidth"];f={};for(var g=0;gwindow.innerHeight?"landscape":"portrait"};return f}d.exports=a},{}],8:[function(b,c,a){function d(){var f="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";return f.replace(/[xy]/g,function(i){var h=Math.random()*16|0,g=i=="x"?h:(h&3|8);return g.toString(16)})}c.exports=d},{}],9:[function(b,c,a){function d(){var f,h,g;if("undefined"==typeof document){return{}}f=document.body;h=document.documentElement;g={height:("innerHeight" in window)?window.innerHeight:document.documentElement.offsetHeight,width:("innerWidth" in window)?window.innerWidth:document.documentElement.offsetWidth,scrollHeight:Math.max(f.scrollHeight,f.offsetHeight,h.clientHeight,h.scrollHeight,h.offsetHeight)||null};if(window.screen){g.ratio={height:(window.screen.availHeight)?parseFloat((window.innerHeight/window.screen.availHeight).toFixed(2)):null,width:(window.screen.availWidth)?parseFloat((window.innerWidth/window.screen.availWidth).toFixed(2)):null}}return g}c.exports=d},{}],10:[function(b,a,c){var h=b("component-emitter");var j=b("./utils/json");var i=b("./utils/each");var f=b("./utils/extend");var d=b("./utils/queue");var g=function(m){var l=this;this.configure(m);f(this.config.resources,g.resources);this.extensions={events:[],collections:{}};this.queue=d();this.queue.on("flush",function(){l.recordDeferredEvents()});if(g.debug){this.on("error",g.log)}this.emit("ready");g.emit("client",this)};h(g);h(g.prototype);f(g,{debug:false,enabled:true,loaded:false,helpers:{},resources:{base:"{protocol}://{host}",version:"{protocol}://{host}/3.0",projects:"{protocol}://{host}/3.0/projects",projectId:"{protocol}://{host}/3.0/projects/{projectId}",events:"{protocol}://{host}/3.0/projects/{projectId}/events"},utils:{},version:"0.1.1"});g.log=function(l){if(g.debug&&typeof console=="object"){console.log("[Keen IO]",l)}};g.prototype.configure=function(l){var m=this,n=l||{},o="https";this.config=this.config||{projectId:undefined,writeKey:undefined,host:"api.keen.io",protocol:o,requestType:"jsonp",resources:{},writePath:undefined};if("undefined"!==typeof document&&document.all){n.protocol=(document.location.protocol!=="https:")?"http":o}if(n.host){n.host.replace(/.*?:\/\//g,"")}f(this.config,n);return m};g.prototype.projectId=function(l){if(!arguments.length){return this.config.projectId}this.config.projectId=(l?String(l):null);return this};g.prototype.writeKey=function(l){if(!arguments.length){return this.config.writeKey}this.config.writeKey=(l?String(l):null);return this};g.prototype.resources=function(m){if(!arguments.length){return this.config.resources}var l=this;if(typeof m==="object"){i(m,function(o,n){l.config.resources[n]=(o?o:null)})}return this};g.prototype.url=function(m){var l=Array.prototype.slice.call(arguments,1),n=g.resources.base||"{protocol}://{host}",o;if(m&&typeof m==="string"){if(this.config.resources[m]){o=this.config.resources[m]}else{o=n+m}}else{o=n}i(this.config,function(q,p){if(typeof q!=="object"){o=o.replace("{"+p+"}",q)}});i(l,function(p,q){if(typeof p==="string"){o+="/"+p}else{if(typeof p==="object"){o+="?";i(p,function(s,r){o+=r+"="+s+"&"});o=o.slice(0,-1)}}});return o};g.prototype.setGlobalProperties=function(l){g.log("This method has been deprecated. Check out #extendEvents: https://github.com/keen/keen-tracking.js#extend-events");if(!l||typeof l!=="function"){this.emit("error","Invalid value for global properties: "+l);return}this.config.globalProperties=l;return this};g.prototype.writePath=function(l){g.log("This method has been deprecated. Use client.url('events') instead.");if(!arguments.length){return this.config.writePath}if(!this.projectId()){this.emit("error","Client instance is missing a projectId property");return this.config.writePath||("/3.0/projects/"+this.projectId()+"/events")}this.config.writePath=l?String(l):("/3.0/projects/"+this.projectId()+"/events");return this};function k(m){var l=[];i(m,function(o,n){if("string"!==typeof o){o=j.stringify(o)}l.push(n+"="+encodeURIComponent(o))});return l.join("&")}a.exports=g},{"./utils/each":15,"./utils/extend":16,"./utils/json":17,"./utils/queue":20,"component-emitter":22}],11:[function(h,d,w){var c=h("./index");var b=h("./utils/base64");var f=h("./utils/each");var s=h("./utils/extend");var r=h("./extend-events");var q=h("./utils/json");d.exports={recordEvent:k,recordEvents:i,addEvent:n,addEvents:l};function k(x,G,F,A){var y,D,B,H,C,E,z;y=this.url("events",encodeURIComponent(x));D={};B=F;z=("boolean"===typeof A)?A:true;if(!v.call(this,B)){return}if(!x||typeof x!=="string"){m.call(this,"Collection name must be a string.",B);return}if(this.config.globalProperties){D=this.config.globalProperties(x)}s(D,G);E={};r.getExtendedEventBody(E,this.extensions.events);r.getExtendedEventBody(E,this.extensions.collections[x]);r.getExtendedEventBody(E,[D]);this.emit("recordEvent",x,E);if(!c.enabled){m.call(this,"Keen.enabled is set to false.",B);return false}H=this.url("events",encodeURIComponent(x),{api_key:this.writeKey(),data:b.encode(q.stringify(E)),modified:new Date().getTime()});C=H.length2){m.call(this,"Incorrect arguments provided to #recordEvents method",x);return}if(this.config.globalProperties){f(B,function(D,E){f(D,function(F,H){var G=y.config.globalProperties(E);B[E][H]=s(G,F)})})}z={};f(B,function(E,D){z[D]=z[D]||[];f(E,function(H,G){var F={};r.getExtendedEventBody(F,y.extensions.events);r.getExtendedEventBody(F,y.extensions.collections[D]);r.getExtendedEventBody(F,[H]);z[D].push(F)})});this.emit("recordEvents",z);if(!c.enabled){m.call(this,"Keen.enabled is set to false.",x);return false}if(p()){u.call(this,"POST",A,z,x)}else{}C=x=null;return this}function n(){this.emit("error","This method has been deprecated. Check out #recordEvent: https://github.com/keen/keen-tracking.js#record-a-single-event");k.apply(this,arguments)}function l(){this.emit("error","This method has been deprecated. Check out #recordEvents: https://github.com/keen/keen-tracking.js#record-multiple-events");i.apply(this,arguments)}function v(y){var x=y;y=null;if(!this.projectId()){m.call(this,"Keen.Client is missing a projectId property.",x);return false}if(!this.writeKey()){m.call(this,"Keen.Client is missing a writeKey property.",x);return false}return true}function m(z,x){var y="Event(s) not recorded: "+z;this.emit("error",y);if(x){x.call(this,y,null);x=null}}function t(){if("undefined"!==typeof window){if(navigator.userAgent.indexOf("MSIE")!==-1||navigator.appVersion.indexOf("Trident/")>0){return 2000}}return 16000}function o(x,z,y,A){if(p()){u.call(this,"POST",x,z,A)}else{m.call(this,y)}}function u(E,z,A,D){var y=this;var B;var C=p();var x=D;D=null;C.onreadystatechange=function(){var F;if(C.readyState==4){if(C.status>=200&&C.status<300){try{F=q.parse(C.responseText)}catch(G){c.emit("error","Could not parse HTTP response: "+C.responseText);if(x){x.call(y,C,null)}}if(x&&F){x.call(y,null,F)}}else{c.emit("error","HTTP request failed.");if(x){x.call(y,C,null)}}}};C.open(E,z,true);C.setRequestHeader("Authorization",y.writeKey());C.setRequestHeader("Content-Type","application/json");if(A){B=q.stringify(A)}if(E.toUpperCase()==="GET"){C.send()}if(E.toUpperCase()==="POST"){C.send(B)}}function a(x){var y=p();if(y){y.open("GET",x,false);y.send(null)}}function p(){var x="undefined"==typeof window?this:window;if(x.XMLHttpRequest&&("file:"!=x.location.protocol||!x.ActiveXObject)){return new XMLHttpRequest}else{try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(y){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(y){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(y){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(y){}}return false}function g(x,G){var H=this,A=G,C=new Date().getTime(),E=document.createElement("script"),F=document.getElementsByTagName("head")[0],D="keenJSONPCallback",B=false;G=null;D+=C;while(D in window){D+="a"}window[D]=function(I){if(B===true){return}B=true;if(A){A.call(H,null,I)}y()};E.src=x+"&jsonp="+D;F.appendChild(E);E.onreadystatechange=function(){if(B===false&&this.readyState==="loaded"){B=true;z();y()}};E.onerror=function(){if(B===false){B=true;z();y()}};function z(){if(A){A.call(H,"An error occurred!",null)}}function y(){window[D]=undefined;try{delete window[D]}catch(I){}F.removeChild(E)}}function j(B,C){var z=this,x=C,y=document.createElement("img"),A=false;C=null;y.onload=function(){A=true;if("naturalHeight" in this){if(this.naturalHeight+this.naturalWidth===0){this.onerror();return}}else{if(this.width+this.height===0){this.onerror();return}}if(x){x.call(z)}};y.onerror=function(){A=true;if(x){x.call(z,"An error occurred!",null)}};y.src=B+"&c=clv1"}},{"./extend-events":3,"./index":10,"./utils/base64":12,"./utils/each":15,"./utils/extend":16,"./utils/json":17}],12:[function(b,c,a){c.exports={map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(f){var d="",l=0,h=this.map,k,j,g,s,r,q,p;f=this.utf8.encode(f);while(l>2);r=(((k&3)<<4)|(j>>4));q=(isNaN(j)?64:((j&15)<<2)|(g>>6));p=(isNaN(j)||isNaN(g))?64:g&63;d=d+h.charAt(s)+h.charAt(r)+h.charAt(q)+h.charAt(p)}return d},decode:function(f){var d="",p=0,h=this.map,g=String.fromCharCode,t,s,r,q,l,k,j;f=f.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(p>4);k=((s&15)<<4)|(r>>2);j=((r&3)<<6)|q;d=d+(g(l)+((r!=64)?g(k):""))+(((q!=64)?g(j):""))}return this.utf8.decode(d)},utf8:{encode:function(j){var f="",d=0,h=String.fromCharCode,g;while(d127)&&(g<2048))?(h((g>>6)|192)+h((g&63)|128)):(h((g>>12)|224)+h(((g>>6)&63)|128)+h((g&63)|128)))}return f},decode:function(k){var g="",f=0,j=String.fromCharCode,d,h;while(f191)&&(h<224))?[j(((h&31)<<6)|((d=k.charCodeAt(f+1))&63)),(f+=2)][0]:[j(((h&15)<<12)|(((d=k.charCodeAt(f+1))&63)<<6)|((c3=k.charCodeAt(f+2))&63)),(f+=3)][0])}return g}}}},{}],13:[function(b,g,a){var f=b("js-cookie");var d=b("./json");var h=b("./extend");g.exports=c;function c(i){if(!arguments.length){return}if(this instanceof c===false){return new c(i)}this.config={key:i,options:{}};this.data=this.get();this.enabled=true;return this}c.prototype.get=function(j){var i={};if(f.get(this.config.key)){i=d.parse(f.get(this.config.key))}if(j){return(typeof i[j]!=="undefined")?i[j]:null}else{return i}};c.prototype.set=function(l,k,i){if(!arguments.length||!this.enabled){return this}if(typeof l==="string"&&arguments.length===2){this.data[l]=k?k:null}else{if(typeof l==="object"&&arguments.length===1){h(this.data,l)}}var j={};if(i){j.expires=i}f.set(this.config.key,this.data,h(this.config.options,j));return this};c.prototype.expire=function(){f.remove(this.config.key);this.data={};return this};c.prototype.options=function(i){if(!arguments.length){return this.config.options}this.config.options=(typeof i==="object")?i:{};return this}},{"./extend":16,"./json":17,"js-cookie":23}],14:[function(c,f,a){var d=c("./json");f.exports=b;function b(l){for(var k=1;k0&&this.interval>=this.config.interval)||this.capacity>=this.config.capacity){this.emit("flush");this.interval=0}}f(a.prototype)},{"component-emitter":22}],21:[function(b,c,a){c.exports=d;function d(f){if(this instanceof d===false){return new d(f)}this.count=f||0;return this}d.prototype.start=function(){var f=this;this.pause();this.interval=setInterval(function(){f.count++},1000);return this};d.prototype.pause=function(){clearInterval(this.interval);return this};d.prototype.value=function(){return this.count};d.prototype.clear=function(){this.count=0;return this}},{}],22:[function(c,d,b){d.exports=f;function f(g){if(g){return a(g)}}function a(h){for(var g in f.prototype){h[g]=f.prototype[g]}return h}f.prototype.on=f.prototype.addEventListener=function(h,g){this._callbacks=this._callbacks||{};(this._callbacks["$"+h]=this._callbacks["$"+h]||[]).push(g);return this};f.prototype.once=function(i,h){function g(){this.off(i,g);h.apply(this,arguments)}g.fn=h;this.on(i,g);return this};f.prototype.off=f.prototype.removeListener=f.prototype.removeAllListeners=f.prototype.removeEventListener=function(l,j){this._callbacks=this._callbacks||{};if(0==arguments.length){this._callbacks={};return this}var k=this._callbacks["$"+l];if(!k){return this}if(1==arguments.length){delete this._callbacks["$"+l];return this}var g;for(var h=0;h Date: Thu, 24 Mar 2016 15:58:05 -0600 Subject: [PATCH 08/10] Ensure there is an expiration. Otherwise the cookie gers removed when the browser is closed. --- lib/utils/cookie.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/utils/cookie.js b/lib/utils/cookie.js index e8f7077..2fab393 100644 --- a/lib/utils/cookie.js +++ b/lib/utils/cookie.js @@ -12,7 +12,9 @@ function cookie(str){ this.config = { key: str, - options: {} + options: { + expires: 365 + } }; this.data = this.get(); this.enabled = true; From 0e133c9d30fbb8c9f405058ea64ce609208c5269 Mon Sep 17 00:00:00 2001 From: aroc Date: Thu, 24 Mar 2016 16:40:56 -0600 Subject: [PATCH 09/10] Update `set` and `expire` signature. --- lib/utils/cookie.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/utils/cookie.js b/lib/utils/cookie.js index 2fab393..269261d 100644 --- a/lib/utils/cookie.js +++ b/lib/utils/cookie.js @@ -35,7 +35,7 @@ cookie.prototype.get = function(str){ } }; -cookie.prototype.set = function(str, value, daysUntilExpire){ +cookie.prototype.set = function(str, value){ if (!arguments.length || !this.enabled) return this; if (typeof str === 'string' && arguments.length === 2) { this.data[str] = value ? value : null; @@ -43,15 +43,17 @@ cookie.prototype.set = function(str, value, daysUntilExpire){ else if (typeof str === 'object' && arguments.length === 1) { extend(this.data, str); } - var extraOptions = {}; - if (daysUntilExpire) { extraOptions.expires = daysUntilExpire }; - Cookies.set(this.config.key, this.data, extend(this.config.options, extraOptions)); + Cookies.set(this.config.key, this.data, this.config.options); return this; }; -cookie.prototype.expire = function(){ - Cookies.remove(this.config.key); - this.data = {}; +cookie.prototype.expire = function(daysUntilExpire){ + if (daysUntilExpire) { + Cookies.set(this.config.key, this.data, extend(this.config.options, { expires: daysUntilExpire })); + } else { + Cookies.remove(this.config.key); + this.data = {}; + } return this; }; From 15a8d15b6472d294eda45f08b7ef0566d73dac9e Mon Sep 17 00:00:00 2001 From: aroc Date: Thu, 24 Mar 2016 17:05:31 -0600 Subject: [PATCH 10/10] Add enabled function back. --- dist/keen-tracking.js | 26 ++++++++++++++++---------- dist/keen-tracking.min.js | 2 +- lib/utils/cookie.js | 7 +++++-- test/unit/modules/utils/cookie-spec.js | 10 +++------- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/dist/keen-tracking.js b/dist/keen-tracking.js index 2f3abb7..6a1a364 100644 --- a/dist/keen-tracking.js +++ b/dist/keen-tracking.js @@ -909,10 +909,11 @@ function cookie(str){ } this.config = { key: str, - options: {} + options: { + expires: 365 + } }; this.data = this.get(); - this.enabled = true; return this; } cookie.prototype.get = function(str){ @@ -927,22 +928,24 @@ cookie.prototype.get = function(str){ return data; } }; -cookie.prototype.set = function(str, value, daysUntilExpire){ - if (!arguments.length || !this.enabled) return this; +cookie.prototype.set = function(str, value){ + if (!arguments.length || !this.enabled()) return this; if (typeof str === 'string' && arguments.length === 2) { this.data[str] = value ? value : null; } else if (typeof str === 'object' && arguments.length === 1) { extend(this.data, str); } - var extraOptions = {}; - if (daysUntilExpire) { extraOptions.expires = daysUntilExpire }; - Cookies.set(this.config.key, this.data, extend(this.config.options, extraOptions)); + Cookies.set(this.config.key, this.data, this.config.options); return this; }; -cookie.prototype.expire = function(){ - Cookies.remove(this.config.key); - this.data = {}; +cookie.prototype.expire = function(daysUntilExpire){ + if (daysUntilExpire) { + Cookies.set(this.config.key, this.data, extend(this.config.options, { expires: daysUntilExpire })); + } else { + Cookies.remove(this.config.key); + this.data = {}; + } return this; }; cookie.prototype.options = function(obj){ @@ -950,6 +953,9 @@ cookie.prototype.options = function(obj){ this.config.options = (typeof obj === 'object') ? obj : {}; return this; }; +cookie.prototype.enabled = function(){ + return navigator.cookieEnabled; +}; },{"./extend":16,"./json":17,"js-cookie":23}],14:[function(require,module,exports){ var json = require('./json'); module.exports = deepExtend; diff --git a/dist/keen-tracking.min.js b/dist/keen-tracking.min.js index 63edbb0..f66febd 100644 --- a/dist/keen-tracking.min.js +++ b/dist/keen-tracking.min.js @@ -1,4 +1,4 @@ -(function e(b,g,d){function c(m,j){if(!g[m]){if(!b[m]){var i=typeof require=="function"&&require;if(!j&&i){return i(m,!0)}if(a){return a(m,!0)}var k=new Error("Cannot find module '"+m+"'");throw k.code="MODULE_NOT_FOUND",k}var h=g[m]={exports:{}};b[m][0].call(h.exports,function(l){var o=b[m][1][l];return c(o?o:l)},h,h.exports,e,b,g,d)}return g[m].exports}var a=typeof require=="function"&&require;for(var f=0;f or DOM element")}}if(v){y=function(){if(!q){q=true;v()}}}this.recordEvent(o,w,y);setTimeout(y,p);if(!x.metaKey){return false}}if(!Array.prototype.indexOf){Array.prototype.indexOf=function(p){var o=this.length>>>0;var q=Number(arguments[1])||0;q=(q<0)?Math.ceil(q):Math.floor(q);if(q<0){q+=o}for(;q0){o=JSON.parse(JSON.stringify(n.queue));n.queue=h();n.queue.options=o.options;n.emit("recordDeferredEvents",o.events);n.recordEvents(o.events,function(q,p){if(q){n.recordEvents(o.events)}else{o=void 0}})}return n}function i(o){var n="Event(s) not deferred: "+o;this.emit("error",n)}},{"./index":10,"./utils/each":15,"./utils/queue":20}],3:[function(d,c,g){var f=d("./utils/deepExtend");var i=d("./utils/each");c.exports={extendEvent:b,extendEvents:j,getExtendedEventBody:a};function b(k,l){if(arguments.length!==2||typeof k!=="string"||("object"!==typeof l&&"function"!==typeof l)){h.call(this,"Incorrect arguments provided to #extendEvent method");return}this.extensions.collections[k]=this.extensions.collections[k]||[];this.extensions.collections[k].push(l);this.emit("extendEvent",k,l);return this}function j(k){if(arguments.length!==1||("object"!==typeof k&&"function"!==typeof k)){h.call(this,"Incorrect arguments provided to #extendEvents method");return}this.extensions.events.push(k);this.emit("extendEvents",k);return this}function h(l){var k="Event(s) not extended: "+l;this.emit("error",k)}function a(l,k){if(k&&k.length>0){i(k,function(o,n){var m=(typeof o==="function")?o():o;f(l,m)})}return l}},{"./utils/deepExtend":14,"./utils/each":15}],4:[function(d,f,b){var a=d("./getScreenProfile"),g=d("./getWindowProfile");function c(){return{cookies:("undefined"!==typeof navigator.cookieEnabled)?navigator.cookieEnabled:false,codeName:navigator.appCodeName,language:navigator.language,name:navigator.appName,online:navigator.onLine,platform:navigator.platform,useragent:navigator.userAgent,version:navigator.appVersion,screen:a(),window:g()}}f.exports=c},{"./getScreenProfile":7,"./getWindowProfile":9}],5:[function(b,c,a){function d(f){var g=f||new Date();return{hour_of_day:g.getHours(),day_of_week:parseInt(1+g.getDay()),day_of_month:g.getDate(),month:parseInt(1+g.getMonth()),year:g.getFullYear()}}c.exports=d},{}],6:[function(c,d,a){function b(l){if(!l.nodeName){return""}var f=[];while(l.parentNode!=null){var k=0;var g=0;for(var j=0;j1){f.unshift(l.nodeName.toLowerCase()+":eq("+g+")")}else{f.unshift(l.nodeName.toLowerCase())}}l=l.parentNode}return f.slice(1).join(" > ")}d.exports=b},{}],7:[function(c,d,b){function a(){var h,f;if("undefined"==typeof window||!window.screen){return{}}h=["height","width","colorDepth","pixelDepth","availHeight","availWidth"];f={};for(var g=0;gwindow.innerHeight?"landscape":"portrait"};return f}d.exports=a},{}],8:[function(b,c,a){function d(){var f="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";return f.replace(/[xy]/g,function(i){var h=Math.random()*16|0,g=i=="x"?h:(h&3|8);return g.toString(16)})}c.exports=d},{}],9:[function(b,c,a){function d(){var f,h,g;if("undefined"==typeof document){return{}}f=document.body;h=document.documentElement;g={height:("innerHeight" in window)?window.innerHeight:document.documentElement.offsetHeight,width:("innerWidth" in window)?window.innerWidth:document.documentElement.offsetWidth,scrollHeight:Math.max(f.scrollHeight,f.offsetHeight,h.clientHeight,h.scrollHeight,h.offsetHeight)||null};if(window.screen){g.ratio={height:(window.screen.availHeight)?parseFloat((window.innerHeight/window.screen.availHeight).toFixed(2)):null,width:(window.screen.availWidth)?parseFloat((window.innerWidth/window.screen.availWidth).toFixed(2)):null}}return g}c.exports=d},{}],10:[function(b,a,c){var h=b("component-emitter");var j=b("./utils/json");var i=b("./utils/each");var f=b("./utils/extend");var d=b("./utils/queue");var g=function(m){var l=this;this.configure(m);f(this.config.resources,g.resources);this.extensions={events:[],collections:{}};this.queue=d();this.queue.on("flush",function(){l.recordDeferredEvents()});if(g.debug){this.on("error",g.log)}this.emit("ready");g.emit("client",this)};h(g);h(g.prototype);f(g,{debug:false,enabled:true,loaded:false,helpers:{},resources:{base:"{protocol}://{host}",version:"{protocol}://{host}/3.0",projects:"{protocol}://{host}/3.0/projects",projectId:"{protocol}://{host}/3.0/projects/{projectId}",events:"{protocol}://{host}/3.0/projects/{projectId}/events"},utils:{},version:"0.1.1"});g.log=function(l){if(g.debug&&typeof console=="object"){console.log("[Keen IO]",l)}};g.prototype.configure=function(l){var m=this,n=l||{},o="https";this.config=this.config||{projectId:undefined,writeKey:undefined,host:"api.keen.io",protocol:o,requestType:"jsonp",resources:{},writePath:undefined};if("undefined"!==typeof document&&document.all){n.protocol=(document.location.protocol!=="https:")?"http":o}if(n.host){n.host.replace(/.*?:\/\//g,"")}f(this.config,n);return m};g.prototype.projectId=function(l){if(!arguments.length){return this.config.projectId}this.config.projectId=(l?String(l):null);return this};g.prototype.writeKey=function(l){if(!arguments.length){return this.config.writeKey}this.config.writeKey=(l?String(l):null);return this};g.prototype.resources=function(m){if(!arguments.length){return this.config.resources}var l=this;if(typeof m==="object"){i(m,function(o,n){l.config.resources[n]=(o?o:null)})}return this};g.prototype.url=function(m){var l=Array.prototype.slice.call(arguments,1),n=g.resources.base||"{protocol}://{host}",o;if(m&&typeof m==="string"){if(this.config.resources[m]){o=this.config.resources[m]}else{o=n+m}}else{o=n}i(this.config,function(q,p){if(typeof q!=="object"){o=o.replace("{"+p+"}",q)}});i(l,function(p,q){if(typeof p==="string"){o+="/"+p}else{if(typeof p==="object"){o+="?";i(p,function(s,r){o+=r+"="+s+"&"});o=o.slice(0,-1)}}});return o};g.prototype.setGlobalProperties=function(l){g.log("This method has been deprecated. Check out #extendEvents: https://github.com/keen/keen-tracking.js#extend-events");if(!l||typeof l!=="function"){this.emit("error","Invalid value for global properties: "+l);return}this.config.globalProperties=l;return this};g.prototype.writePath=function(l){g.log("This method has been deprecated. Use client.url('events') instead.");if(!arguments.length){return this.config.writePath}if(!this.projectId()){this.emit("error","Client instance is missing a projectId property");return this.config.writePath||("/3.0/projects/"+this.projectId()+"/events")}this.config.writePath=l?String(l):("/3.0/projects/"+this.projectId()+"/events");return this};function k(m){var l=[];i(m,function(o,n){if("string"!==typeof o){o=j.stringify(o)}l.push(n+"="+encodeURIComponent(o))});return l.join("&")}a.exports=g},{"./utils/each":15,"./utils/extend":16,"./utils/json":17,"./utils/queue":20,"component-emitter":22}],11:[function(h,d,w){var c=h("./index");var b=h("./utils/base64");var f=h("./utils/each");var s=h("./utils/extend");var r=h("./extend-events");var q=h("./utils/json");d.exports={recordEvent:k,recordEvents:i,addEvent:n,addEvents:l};function k(x,G,F,A){var y,D,B,H,C,E,z;y=this.url("events",encodeURIComponent(x));D={};B=F;z=("boolean"===typeof A)?A:true;if(!v.call(this,B)){return}if(!x||typeof x!=="string"){m.call(this,"Collection name must be a string.",B);return}if(this.config.globalProperties){D=this.config.globalProperties(x)}s(D,G);E={};r.getExtendedEventBody(E,this.extensions.events);r.getExtendedEventBody(E,this.extensions.collections[x]);r.getExtendedEventBody(E,[D]);this.emit("recordEvent",x,E);if(!c.enabled){m.call(this,"Keen.enabled is set to false.",B);return false}H=this.url("events",encodeURIComponent(x),{api_key:this.writeKey(),data:b.encode(q.stringify(E)),modified:new Date().getTime()});C=H.length2){m.call(this,"Incorrect arguments provided to #recordEvents method",x);return}if(this.config.globalProperties){f(B,function(D,E){f(D,function(F,H){var G=y.config.globalProperties(E);B[E][H]=s(G,F)})})}z={};f(B,function(E,D){z[D]=z[D]||[];f(E,function(H,G){var F={};r.getExtendedEventBody(F,y.extensions.events);r.getExtendedEventBody(F,y.extensions.collections[D]);r.getExtendedEventBody(F,[H]);z[D].push(F)})});this.emit("recordEvents",z);if(!c.enabled){m.call(this,"Keen.enabled is set to false.",x);return false}if(p()){u.call(this,"POST",A,z,x)}else{}C=x=null;return this}function n(){this.emit("error","This method has been deprecated. Check out #recordEvent: https://github.com/keen/keen-tracking.js#record-a-single-event");k.apply(this,arguments)}function l(){this.emit("error","This method has been deprecated. Check out #recordEvents: https://github.com/keen/keen-tracking.js#record-multiple-events");i.apply(this,arguments)}function v(y){var x=y;y=null;if(!this.projectId()){m.call(this,"Keen.Client is missing a projectId property.",x);return false}if(!this.writeKey()){m.call(this,"Keen.Client is missing a writeKey property.",x);return false}return true}function m(z,x){var y="Event(s) not recorded: "+z;this.emit("error",y);if(x){x.call(this,y,null);x=null}}function t(){if("undefined"!==typeof window){if(navigator.userAgent.indexOf("MSIE")!==-1||navigator.appVersion.indexOf("Trident/")>0){return 2000}}return 16000}function o(x,z,y,A){if(p()){u.call(this,"POST",x,z,A)}else{m.call(this,y)}}function u(E,z,A,D){var y=this;var B;var C=p();var x=D;D=null;C.onreadystatechange=function(){var F;if(C.readyState==4){if(C.status>=200&&C.status<300){try{F=q.parse(C.responseText)}catch(G){c.emit("error","Could not parse HTTP response: "+C.responseText);if(x){x.call(y,C,null)}}if(x&&F){x.call(y,null,F)}}else{c.emit("error","HTTP request failed.");if(x){x.call(y,C,null)}}}};C.open(E,z,true);C.setRequestHeader("Authorization",y.writeKey());C.setRequestHeader("Content-Type","application/json");if(A){B=q.stringify(A)}if(E.toUpperCase()==="GET"){C.send()}if(E.toUpperCase()==="POST"){C.send(B)}}function a(x){var y=p();if(y){y.open("GET",x,false);y.send(null)}}function p(){var x="undefined"==typeof window?this:window;if(x.XMLHttpRequest&&("file:"!=x.location.protocol||!x.ActiveXObject)){return new XMLHttpRequest}else{try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(y){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(y){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(y){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(y){}}return false}function g(x,G){var H=this,A=G,C=new Date().getTime(),E=document.createElement("script"),F=document.getElementsByTagName("head")[0],D="keenJSONPCallback",B=false;G=null;D+=C;while(D in window){D+="a"}window[D]=function(I){if(B===true){return}B=true;if(A){A.call(H,null,I)}y()};E.src=x+"&jsonp="+D;F.appendChild(E);E.onreadystatechange=function(){if(B===false&&this.readyState==="loaded"){B=true;z();y()}};E.onerror=function(){if(B===false){B=true;z();y()}};function z(){if(A){A.call(H,"An error occurred!",null)}}function y(){window[D]=undefined;try{delete window[D]}catch(I){}F.removeChild(E)}}function j(B,C){var z=this,x=C,y=document.createElement("img"),A=false;C=null;y.onload=function(){A=true;if("naturalHeight" in this){if(this.naturalHeight+this.naturalWidth===0){this.onerror();return}}else{if(this.width+this.height===0){this.onerror();return}}if(x){x.call(z)}};y.onerror=function(){A=true;if(x){x.call(z,"An error occurred!",null)}};y.src=B+"&c=clv1"}},{"./extend-events":3,"./index":10,"./utils/base64":12,"./utils/each":15,"./utils/extend":16,"./utils/json":17}],12:[function(b,c,a){c.exports={map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(f){var d="",l=0,h=this.map,k,j,g,s,r,q,p;f=this.utf8.encode(f);while(l>2);r=(((k&3)<<4)|(j>>4));q=(isNaN(j)?64:((j&15)<<2)|(g>>6));p=(isNaN(j)||isNaN(g))?64:g&63;d=d+h.charAt(s)+h.charAt(r)+h.charAt(q)+h.charAt(p)}return d},decode:function(f){var d="",p=0,h=this.map,g=String.fromCharCode,t,s,r,q,l,k,j;f=f.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(p>4);k=((s&15)<<4)|(r>>2);j=((r&3)<<6)|q;d=d+(g(l)+((r!=64)?g(k):""))+(((q!=64)?g(j):""))}return this.utf8.decode(d)},utf8:{encode:function(j){var f="",d=0,h=String.fromCharCode,g;while(d127)&&(g<2048))?(h((g>>6)|192)+h((g&63)|128)):(h((g>>12)|224)+h(((g>>6)&63)|128)+h((g&63)|128)))}return f},decode:function(k){var g="",f=0,j=String.fromCharCode,d,h;while(f191)&&(h<224))?[j(((h&31)<<6)|((d=k.charCodeAt(f+1))&63)),(f+=2)][0]:[j(((h&15)<<12)|(((d=k.charCodeAt(f+1))&63)<<6)|((c3=k.charCodeAt(f+2))&63)),(f+=3)][0])}return g}}}},{}],13:[function(b,g,a){var f=b("js-cookie");var d=b("./json");var h=b("./extend");g.exports=c;function c(i){if(!arguments.length){return}if(this instanceof c===false){return new c(i)}this.config={key:i,options:{}};this.data=this.get();this.enabled=true;return this}c.prototype.get=function(j){var i={};if(f.get(this.config.key)){i=d.parse(f.get(this.config.key))}if(j){return(typeof i[j]!=="undefined")?i[j]:null}else{return i}};c.prototype.set=function(l,k,i){if(!arguments.length||!this.enabled){return this}if(typeof l==="string"&&arguments.length===2){this.data[l]=k?k:null}else{if(typeof l==="object"&&arguments.length===1){h(this.data,l)}}var j={};if(i){j.expires=i}f.set(this.config.key,this.data,h(this.config.options,j));return this};c.prototype.expire=function(){f.remove(this.config.key);this.data={};return this};c.prototype.options=function(i){if(!arguments.length){return this.config.options}this.config.options=(typeof i==="object")?i:{};return this}},{"./extend":16,"./json":17,"js-cookie":23}],14:[function(c,f,a){var d=c("./json");f.exports=b;function b(l){for(var k=1;k0&&this.interval>=this.config.interval)||this.capacity>=this.config.capacity){this.emit("flush");this.interval=0}}f(a.prototype)},{"component-emitter":22}],21:[function(b,c,a){c.exports=d;function d(f){if(this instanceof d===false){return new d(f)}this.count=f||0;return this}d.prototype.start=function(){var f=this;this.pause();this.interval=setInterval(function(){f.count++},1000);return this};d.prototype.pause=function(){clearInterval(this.interval);return this};d.prototype.value=function(){return this.count};d.prototype.clear=function(){this.count=0;return this}},{}],22:[function(c,d,b){d.exports=f;function f(g){if(g){return a(g)}}function a(h){for(var g in f.prototype){h[g]=f.prototype[g]}return h}f.prototype.on=f.prototype.addEventListener=function(h,g){this._callbacks=this._callbacks||{};(this._callbacks["$"+h]=this._callbacks["$"+h]||[]).push(g);return this};f.prototype.once=function(i,h){function g(){this.off(i,g);h.apply(this,arguments)}g.fn=h;this.on(i,g);return this};f.prototype.off=f.prototype.removeListener=f.prototype.removeAllListeners=f.prototype.removeEventListener=function(l,j){this._callbacks=this._callbacks||{};if(0==arguments.length){this._callbacks={};return this}var k=this._callbacks["$"+l];if(!k){return this}if(1==arguments.length){delete this._callbacks["$"+l];return this}var g;for(var h=0;h or DOM element")}}if(v){y=function(){if(!q){q=true;v()}}}this.recordEvent(o,w,y);setTimeout(y,p);if(!x.metaKey){return false}}if(!Array.prototype.indexOf){Array.prototype.indexOf=function(p){var o=this.length>>>0;var q=Number(arguments[1])||0;q=(q<0)?Math.ceil(q):Math.floor(q);if(q<0){q+=o}for(;q0){o=JSON.parse(JSON.stringify(n.queue));n.queue=h();n.queue.options=o.options;n.emit("recordDeferredEvents",o.events);n.recordEvents(o.events,function(q,p){if(q){n.recordEvents(o.events)}else{o=void 0}})}return n}function i(o){var n="Event(s) not deferred: "+o;this.emit("error",n)}},{"./index":10,"./utils/each":15,"./utils/queue":20}],3:[function(d,c,g){var f=d("./utils/deepExtend");var i=d("./utils/each");c.exports={extendEvent:b,extendEvents:j,getExtendedEventBody:a};function b(k,l){if(arguments.length!==2||typeof k!=="string"||("object"!==typeof l&&"function"!==typeof l)){h.call(this,"Incorrect arguments provided to #extendEvent method");return}this.extensions.collections[k]=this.extensions.collections[k]||[];this.extensions.collections[k].push(l);this.emit("extendEvent",k,l);return this}function j(k){if(arguments.length!==1||("object"!==typeof k&&"function"!==typeof k)){h.call(this,"Incorrect arguments provided to #extendEvents method");return}this.extensions.events.push(k);this.emit("extendEvents",k);return this}function h(l){var k="Event(s) not extended: "+l;this.emit("error",k)}function a(l,k){if(k&&k.length>0){i(k,function(o,n){var m=(typeof o==="function")?o():o;f(l,m)})}return l}},{"./utils/deepExtend":14,"./utils/each":15}],4:[function(d,f,b){var a=d("./getScreenProfile"),g=d("./getWindowProfile");function c(){return{cookies:("undefined"!==typeof navigator.cookieEnabled)?navigator.cookieEnabled:false,codeName:navigator.appCodeName,language:navigator.language,name:navigator.appName,online:navigator.onLine,platform:navigator.platform,useragent:navigator.userAgent,version:navigator.appVersion,screen:a(),window:g()}}f.exports=c},{"./getScreenProfile":7,"./getWindowProfile":9}],5:[function(b,c,a){function d(f){var g=f||new Date();return{hour_of_day:g.getHours(),day_of_week:parseInt(1+g.getDay()),day_of_month:g.getDate(),month:parseInt(1+g.getMonth()),year:g.getFullYear()}}c.exports=d},{}],6:[function(c,d,a){function b(l){if(!l.nodeName){return""}var f=[];while(l.parentNode!=null){var k=0;var g=0;for(var j=0;j1){f.unshift(l.nodeName.toLowerCase()+":eq("+g+")")}else{f.unshift(l.nodeName.toLowerCase())}}l=l.parentNode}return f.slice(1).join(" > ")}d.exports=b},{}],7:[function(c,d,b){function a(){var h,f;if("undefined"==typeof window||!window.screen){return{}}h=["height","width","colorDepth","pixelDepth","availHeight","availWidth"];f={};for(var g=0;gwindow.innerHeight?"landscape":"portrait"};return f}d.exports=a},{}],8:[function(b,c,a){function d(){var f="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";return f.replace(/[xy]/g,function(i){var h=Math.random()*16|0,g=i=="x"?h:(h&3|8);return g.toString(16)})}c.exports=d},{}],9:[function(b,c,a){function d(){var f,h,g;if("undefined"==typeof document){return{}}f=document.body;h=document.documentElement;g={height:("innerHeight" in window)?window.innerHeight:document.documentElement.offsetHeight,width:("innerWidth" in window)?window.innerWidth:document.documentElement.offsetWidth,scrollHeight:Math.max(f.scrollHeight,f.offsetHeight,h.clientHeight,h.scrollHeight,h.offsetHeight)||null};if(window.screen){g.ratio={height:(window.screen.availHeight)?parseFloat((window.innerHeight/window.screen.availHeight).toFixed(2)):null,width:(window.screen.availWidth)?parseFloat((window.innerWidth/window.screen.availWidth).toFixed(2)):null}}return g}c.exports=d},{}],10:[function(b,a,c){var h=b("component-emitter");var j=b("./utils/json");var i=b("./utils/each");var f=b("./utils/extend");var d=b("./utils/queue");var g=function(m){var l=this;this.configure(m);f(this.config.resources,g.resources);this.extensions={events:[],collections:{}};this.queue=d();this.queue.on("flush",function(){l.recordDeferredEvents()});if(g.debug){this.on("error",g.log)}this.emit("ready");g.emit("client",this)};h(g);h(g.prototype);f(g,{debug:false,enabled:true,loaded:false,helpers:{},resources:{base:"{protocol}://{host}",version:"{protocol}://{host}/3.0",projects:"{protocol}://{host}/3.0/projects",projectId:"{protocol}://{host}/3.0/projects/{projectId}",events:"{protocol}://{host}/3.0/projects/{projectId}/events"},utils:{},version:"0.1.1"});g.log=function(l){if(g.debug&&typeof console=="object"){console.log("[Keen IO]",l)}};g.prototype.configure=function(l){var m=this,n=l||{},o="https";this.config=this.config||{projectId:undefined,writeKey:undefined,host:"api.keen.io",protocol:o,requestType:"jsonp",resources:{},writePath:undefined};if("undefined"!==typeof document&&document.all){n.protocol=(document.location.protocol!=="https:")?"http":o}if(n.host){n.host.replace(/.*?:\/\//g,"")}f(this.config,n);return m};g.prototype.projectId=function(l){if(!arguments.length){return this.config.projectId}this.config.projectId=(l?String(l):null);return this};g.prototype.writeKey=function(l){if(!arguments.length){return this.config.writeKey}this.config.writeKey=(l?String(l):null);return this};g.prototype.resources=function(m){if(!arguments.length){return this.config.resources}var l=this;if(typeof m==="object"){i(m,function(o,n){l.config.resources[n]=(o?o:null)})}return this};g.prototype.url=function(m){var l=Array.prototype.slice.call(arguments,1),n=g.resources.base||"{protocol}://{host}",o;if(m&&typeof m==="string"){if(this.config.resources[m]){o=this.config.resources[m]}else{o=n+m}}else{o=n}i(this.config,function(q,p){if(typeof q!=="object"){o=o.replace("{"+p+"}",q)}});i(l,function(p,q){if(typeof p==="string"){o+="/"+p}else{if(typeof p==="object"){o+="?";i(p,function(s,r){o+=r+"="+s+"&"});o=o.slice(0,-1)}}});return o};g.prototype.setGlobalProperties=function(l){g.log("This method has been deprecated. Check out #extendEvents: https://github.com/keen/keen-tracking.js#extend-events");if(!l||typeof l!=="function"){this.emit("error","Invalid value for global properties: "+l);return}this.config.globalProperties=l;return this};g.prototype.writePath=function(l){g.log("This method has been deprecated. Use client.url('events') instead.");if(!arguments.length){return this.config.writePath}if(!this.projectId()){this.emit("error","Client instance is missing a projectId property");return this.config.writePath||("/3.0/projects/"+this.projectId()+"/events")}this.config.writePath=l?String(l):("/3.0/projects/"+this.projectId()+"/events");return this};function k(m){var l=[];i(m,function(o,n){if("string"!==typeof o){o=j.stringify(o)}l.push(n+"="+encodeURIComponent(o))});return l.join("&")}a.exports=g},{"./utils/each":15,"./utils/extend":16,"./utils/json":17,"./utils/queue":20,"component-emitter":22}],11:[function(h,d,w){var c=h("./index");var b=h("./utils/base64");var f=h("./utils/each");var s=h("./utils/extend");var r=h("./extend-events");var q=h("./utils/json");d.exports={recordEvent:k,recordEvents:i,addEvent:n,addEvents:l};function k(x,G,F,A){var y,D,B,H,C,E,z;y=this.url("events",encodeURIComponent(x));D={};B=F;z=("boolean"===typeof A)?A:true;if(!v.call(this,B)){return}if(!x||typeof x!=="string"){m.call(this,"Collection name must be a string.",B);return}if(this.config.globalProperties){D=this.config.globalProperties(x)}s(D,G);E={};r.getExtendedEventBody(E,this.extensions.events);r.getExtendedEventBody(E,this.extensions.collections[x]);r.getExtendedEventBody(E,[D]);this.emit("recordEvent",x,E);if(!c.enabled){m.call(this,"Keen.enabled is set to false.",B);return false}H=this.url("events",encodeURIComponent(x),{api_key:this.writeKey(),data:b.encode(q.stringify(E)),modified:new Date().getTime()});C=H.length2){m.call(this,"Incorrect arguments provided to #recordEvents method",x);return}if(this.config.globalProperties){f(B,function(D,E){f(D,function(F,H){var G=y.config.globalProperties(E);B[E][H]=s(G,F)})})}z={};f(B,function(E,D){z[D]=z[D]||[];f(E,function(H,G){var F={};r.getExtendedEventBody(F,y.extensions.events);r.getExtendedEventBody(F,y.extensions.collections[D]);r.getExtendedEventBody(F,[H]);z[D].push(F)})});this.emit("recordEvents",z);if(!c.enabled){m.call(this,"Keen.enabled is set to false.",x);return false}if(p()){u.call(this,"POST",A,z,x)}else{}C=x=null;return this}function n(){this.emit("error","This method has been deprecated. Check out #recordEvent: https://github.com/keen/keen-tracking.js#record-a-single-event");k.apply(this,arguments)}function l(){this.emit("error","This method has been deprecated. Check out #recordEvents: https://github.com/keen/keen-tracking.js#record-multiple-events");i.apply(this,arguments)}function v(y){var x=y;y=null;if(!this.projectId()){m.call(this,"Keen.Client is missing a projectId property.",x);return false}if(!this.writeKey()){m.call(this,"Keen.Client is missing a writeKey property.",x);return false}return true}function m(z,x){var y="Event(s) not recorded: "+z;this.emit("error",y);if(x){x.call(this,y,null);x=null}}function t(){if("undefined"!==typeof window){if(navigator.userAgent.indexOf("MSIE")!==-1||navigator.appVersion.indexOf("Trident/")>0){return 2000}}return 16000}function o(x,z,y,A){if(p()){u.call(this,"POST",x,z,A)}else{m.call(this,y)}}function u(E,z,A,D){var y=this;var B;var C=p();var x=D;D=null;C.onreadystatechange=function(){var F;if(C.readyState==4){if(C.status>=200&&C.status<300){try{F=q.parse(C.responseText)}catch(G){c.emit("error","Could not parse HTTP response: "+C.responseText);if(x){x.call(y,C,null)}}if(x&&F){x.call(y,null,F)}}else{c.emit("error","HTTP request failed.");if(x){x.call(y,C,null)}}}};C.open(E,z,true);C.setRequestHeader("Authorization",y.writeKey());C.setRequestHeader("Content-Type","application/json");if(A){B=q.stringify(A)}if(E.toUpperCase()==="GET"){C.send()}if(E.toUpperCase()==="POST"){C.send(B)}}function a(x){var y=p();if(y){y.open("GET",x,false);y.send(null)}}function p(){var x="undefined"==typeof window?this:window;if(x.XMLHttpRequest&&("file:"!=x.location.protocol||!x.ActiveXObject)){return new XMLHttpRequest}else{try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(y){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(y){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(y){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(y){}}return false}function g(x,G){var H=this,A=G,C=new Date().getTime(),E=document.createElement("script"),F=document.getElementsByTagName("head")[0],D="keenJSONPCallback",B=false;G=null;D+=C;while(D in window){D+="a"}window[D]=function(I){if(B===true){return}B=true;if(A){A.call(H,null,I)}y()};E.src=x+"&jsonp="+D;F.appendChild(E);E.onreadystatechange=function(){if(B===false&&this.readyState==="loaded"){B=true;z();y()}};E.onerror=function(){if(B===false){B=true;z();y()}};function z(){if(A){A.call(H,"An error occurred!",null)}}function y(){window[D]=undefined;try{delete window[D]}catch(I){}F.removeChild(E)}}function j(B,C){var z=this,x=C,y=document.createElement("img"),A=false;C=null;y.onload=function(){A=true;if("naturalHeight" in this){if(this.naturalHeight+this.naturalWidth===0){this.onerror();return}}else{if(this.width+this.height===0){this.onerror();return}}if(x){x.call(z)}};y.onerror=function(){A=true;if(x){x.call(z,"An error occurred!",null)}};y.src=B+"&c=clv1"}},{"./extend-events":3,"./index":10,"./utils/base64":12,"./utils/each":15,"./utils/extend":16,"./utils/json":17}],12:[function(b,c,a){c.exports={map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(f){var d="",l=0,h=this.map,k,j,g,s,r,q,p;f=this.utf8.encode(f);while(l>2);r=(((k&3)<<4)|(j>>4));q=(isNaN(j)?64:((j&15)<<2)|(g>>6));p=(isNaN(j)||isNaN(g))?64:g&63;d=d+h.charAt(s)+h.charAt(r)+h.charAt(q)+h.charAt(p)}return d},decode:function(f){var d="",p=0,h=this.map,g=String.fromCharCode,t,s,r,q,l,k,j;f=f.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(p>4);k=((s&15)<<4)|(r>>2);j=((r&3)<<6)|q;d=d+(g(l)+((r!=64)?g(k):""))+(((q!=64)?g(j):""))}return this.utf8.decode(d)},utf8:{encode:function(j){var f="",d=0,h=String.fromCharCode,g;while(d127)&&(g<2048))?(h((g>>6)|192)+h((g&63)|128)):(h((g>>12)|224)+h(((g>>6)&63)|128)+h((g&63)|128)))}return f},decode:function(k){var g="",f=0,j=String.fromCharCode,d,h;while(f191)&&(h<224))?[j(((h&31)<<6)|((d=k.charCodeAt(f+1))&63)),(f+=2)][0]:[j(((h&15)<<12)|(((d=k.charCodeAt(f+1))&63)<<6)|((c3=k.charCodeAt(f+2))&63)),(f+=3)][0])}return g}}}},{}],13:[function(b,g,a){var f=b("js-cookie");var d=b("./json");var h=b("./extend");g.exports=c;function c(i){if(!arguments.length){return}if(this instanceof c===false){return new c(i)}this.config={key:i,options:{expires:365}};this.data=this.get();return this}c.prototype.get=function(j){var i={};if(f.get(this.config.key)){i=d.parse(f.get(this.config.key))}if(j){return(typeof i[j]!=="undefined")?i[j]:null}else{return i}};c.prototype.set=function(j,i){if(!arguments.length||!this.enabled()){return this}if(typeof j==="string"&&arguments.length===2){this.data[j]=i?i:null}else{if(typeof j==="object"&&arguments.length===1){h(this.data,j)}}f.set(this.config.key,this.data,this.config.options);return this};c.prototype.expire=function(i){if(i){f.set(this.config.key,this.data,h(this.config.options,{expires:i}))}else{f.remove(this.config.key);this.data={}}return this};c.prototype.options=function(i){if(!arguments.length){return this.config.options}this.config.options=(typeof i==="object")?i:{};return this};c.prototype.enabled=function(){return navigator.cookieEnabled}},{"./extend":16,"./json":17,"js-cookie":23}],14:[function(c,f,a){var d=c("./json");f.exports=b;function b(l){for(var k=1;k0&&this.interval>=this.config.interval)||this.capacity>=this.config.capacity){this.emit("flush");this.interval=0}}f(a.prototype)},{"component-emitter":22}],21:[function(b,c,a){c.exports=d;function d(f){if(this instanceof d===false){return new d(f)}this.count=f||0;return this}d.prototype.start=function(){var f=this;this.pause();this.interval=setInterval(function(){f.count++},1000);return this};d.prototype.pause=function(){clearInterval(this.interval);return this};d.prototype.value=function(){return this.count};d.prototype.clear=function(){this.count=0;return this}},{}],22:[function(c,d,b){d.exports=f;function f(g){if(g){return a(g)}}function a(h){for(var g in f.prototype){h[g]=f.prototype[g]}return h}f.prototype.on=f.prototype.addEventListener=function(h,g){this._callbacks=this._callbacks||{};(this._callbacks["$"+h]=this._callbacks["$"+h]||[]).push(g);return this};f.prototype.once=function(i,h){function g(){this.off(i,g);h.apply(this,arguments)}g.fn=h;this.on(i,g);return this};f.prototype.off=f.prototype.removeListener=f.prototype.removeAllListeners=f.prototype.removeEventListener=function(l,j){this._callbacks=this._callbacks||{};if(0==arguments.length){this._callbacks={};return this}var k=this._callbacks["$"+l];if(!k){return this}if(1==arguments.length){delete this._callbacks["$"+l];return this}var g;for(var h=0;h