define('core/analytics/jester',[ 'jquery', 'underscore', 'backbone', 'core/analytics/identity', 'core/config/urls', ], function ( $, _, Backbone, identity, urls ) { 'use strict'; /* Jester is an ActivityStreams logger for Disqus. # About Product, Zone, Section, Area: Yeah, you are probably confused about what these descriptors mean. We are mostly confused, too. So, to help out, here is a comprehensive guide: Product A product is a suite of one or many applications that fall underneath an analytics 'umbrella'. These are currently only 'embed' and 'home'. Zone A zone represents the product application that the user is currently interacting with. These are currently 'thread', 'notifications', 'profile', 'onboard', and 'community'. Section Section is the "route" that the application is currently displaying. This is analogous to a Backbone.Router method. It must uniquely represent the *visual state* of the application at the time of the interaction we are logging. Applications may have only one route, or they may have many routes. Area An xpath-ish type identifier that describes where in the DOM the logged interaction took place, if any. Some interactions may not have a DOM location, in which case 'n/a' is sent instead. Actual Xpath not really required. # Serializing Product, Zone, Section, Area: When we serialize Product, Zone, Section, or Area as an ActivitySteam object, we use a specific format that allows for proper analytics rollups both between products and between cross product applications: Products: object_type='product' object_id= Zones: object_type='zone' object_id= Sections: object_type='section' object_id=/
Areas: object_type='area' object_id=/
# */ var ActivityClient = Backbone.Model.extend({ url: urls.jester + '/event.js', defaults: { experiment: 'default', variant: 'control', }, setHostReferrer: function (url) { if (!url) { // Indicate no referrer as direct traffic this.set('page_referrer', 'direct'); } else if (url.indexOf('http') === -1) { // We should only set fully qualified URLs as // the referrer domain. } else { // If this the client visited cnn.com from facebook.com/xxxx, // and cnn.com loaded this embed, the page_referrer would // be facebook.com/xxxx. this.set('page_referrer', url); } }, decoratePayload: function (payload) { // The default category for all our events // is 'activity'. Only allow overrides of this // during an `emit` call. if (!payload.event) payload.event = 'activity'; // Allow payload attributes to override attributes // set on the client instance. payload = _.extend(this.toJSON(), payload); _.extend(payload, { imp: identity.impression.impId, prev_imp: identity.impression.prevImp, }); // If there is no current application route for this event, // we assume it is the 'default' route of the application. if (!payload.section) payload.section = 'default'; // If there is no specified event xpath (maybe this event did not // originate in the DOM), then we pass Not Available. if (!payload.area) payload.area = 'n/a'; // IE8 and IE9 has a stupid limit on the URL length and we cannot // use POST method with Jester yet due to CORS issues (again in IE8 // and IE9) so we simply check total length of the QSA part as // mentioned in MS KB article http://support.microsoft.com/kb/q208427 // and if it is longer than the limit, 2048 chars, we replace it // with a more modest, page_referrer_domain // // NOTE: The final URL is still NOT guaranteed to be < 2048 chars var qsaLength = $.param(payload).length; if (qsaLength > 2048 && this.has('page_referrer')) { var referrerLink = window.document.createElement('a'); referrerLink.href = this.get('page_referrer'); var hostname = referrerLink.hostname; if (hostname) payload.page_referrer_domain = hostname; delete payload.page_referrer; } return payload; }, emit: function (payload) { // Fire the event to the jester endpoint and return // the deferred object return $.ajax({ url: _.result(this, 'url'), data: this.decoratePayload(payload), dataType: 'script', // default is false for 'script' dataType, setting to true // so that "_={timestamp}" isn't appended to this request cache: true, }); }, }); var logStat = function logStat(name) { var beacon = new window.Image(); beacon.src = urls.jester + '/stat.gif?' + $.param({ event: name }); return beacon; }; var telemetry = function telemetry(endpoint, payload) { if (_.any(payload, function (val) { return val < 0; })) return; // discard the whole data set if anything looks wrong // Round all values since statsd expects integers _.each(payload, function (val, key) { payload[key] = Math.round(val); }); var beacon = new window.Image(); beacon.src = urls.jester + '/telemetry/' + endpoint + '.gif?' + $.param(payload); return beacon; }; var client = new ActivityClient(); client.setHostReferrer(window.document.referrer); return { ActivityClient: ActivityClient, client: client, logStat: logStat, telemetry: telemetry, }; }); // https://c.disquscdn.com/next/next-core/core/analytics/jester.js