Add analytics
[bus.git] / busui / owa / modules / base / js / owa.tracker.js
blob:a/busui/owa/modules/base/js/owa.tracker.js -> blob:b/busui/owa/modules/base/js/owa.tracker.js
--- a/busui/owa/modules/base/js/owa.tracker.js
+++ b/busui/owa/modules/base/js/owa.tracker.js
@@ -1,1 +1,1797 @@
-
+//
+// Open Web Analytics - An Open Source Web Analytics Framework
+//
+// Copyright 2006 Peter Adams. All rights reserved.
+//
+// Licensed under GPL v2.0 http://www.gnu.org/copyleft/gpl.html
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// $Id$
+//
+
+/**
+ * OWA Generic Event Object
+ * 
+ * @author      Peter Adams <peter@openwebanalytics.com>
+ * @copyright   Copyright &copy; 2006 Peter Adams <peter@openwebanalytics.com>
+ * @license     http://www.gnu.org/copyleft/gpl.html GPL v2.0
+ * @category    owa
+ * @package     owa
+ * @version		$Revision$	      
+ * @since		owa 1.2.1
+ */
+OWA.event = function() {
+
+	this.properties = new Object();
+	this.set('timestamp', OWA.util.getCurrentUnixTimestamp() );
+}
+
+OWA.event.prototype = {
+	
+	id : '',
+	
+	siteId : '',
+	
+	properties : {},
+	
+	get : function(name) {
+		
+		if ( this.properties.hasOwnProperty(name) ) {
+		
+			return this.properties[name];
+		}
+	},
+	
+	set : function(name, value) {
+		
+		this.properties[name] = value;
+	},
+	
+	setEventType : function(event_type) {
+	
+		this.set("event_type", event_type);
+	},
+	
+	getProperties : function() {
+		
+		return this.properties;
+	},
+	
+	merge : function(properties) {
+		
+		for(param in properties) {
+			
+			if (properties.hasOwnProperty(param)) {
+	       
+				this.set(param, properties[param]);
+			}
+	    }
+	}
+}
+
+OWA.commandQueue = function() {
+
+	OWA.debug('Command Queue object created');
+}
+
+OWA.commandQueue.prototype = {
+	asyncCmds: '',
+	push : function (cmd) {
+		
+		//alert(func[0]);
+		var args = Array.prototype.slice.call(cmd, 1);
+		//alert(args);
+		
+		var obj_name = '';
+		var method = '';
+		var check = OWA.util.strpos( cmd[0], '.' );
+		
+		if ( ! check ) {
+			obj_name = 'OWATracker';
+			method = cmd[0];
+		} else {
+			var parts = cmd[0].split( '.' );
+			obj_name = parts[0];
+			method = parts[1];
+		}
+		
+		OWA.debug('cmd queue object name %s', obj_name);
+		OWA.debug('cmd queue object method name %s', method);
+		
+		// is OWATracker created?
+		if ( typeof window[obj_name] == "undefined" ) {
+			OWA.debug('making global object named: %s', obj_name);
+			window[obj_name] = new OWA.tracker( { globalObjectName: obj_name } );
+		}
+		
+		window[obj_name][method].apply(window[obj_name], args);
+	},
+	
+	loadCmds: function(cmds) {
+		
+		this.asyncCmds = cmds;
+	},
+	
+	process: function() {
+		
+		for (var i=0; i < this.asyncCmds.length;i++) {
+			this.push(this.asyncCmds[i]);
+		}
+	}
+};
+
+/**
+ * Javascript Tracker Object
+ * 
+ * @author      Peter Adams <peter@openwebanalytics.com>
+ * @copyright   Copyright &copy; 2006 Peter Adams <peter@openwebanalytics.com>
+ * @license     http://www.gnu.org/copyleft/gpl.html GPL v2.0
+ * @category    owa
+ * @package     owa
+ * @version		$Revision$	      
+ * @since		owa 1.2.1
+ */
+OWA.tracker = function( options ) {
+	
+	//this.setDebug(true);
+	// set start time
+	this.startTime = this.getTimestamp();
+	
+	// Configuration options
+	this.options = {
+		logClicks: true, 
+		logPage: true, 
+		logMovement: false, 
+		encodeProperties: false, 
+		movementInterval: 100,
+		logDomStreamPercentage: 100,
+		domstreamLoggingInterval: 3000,
+		domstreamEventThreshold: 10,
+		maxPriorCampaigns: 5,
+		campaignAttributionWindow: 60,
+		trafficAttributionMode: 'direct',
+		sessionLength: 1800,
+		thirdParty: false,
+		cookie_domain: false, 
+		campaignKeys: [
+				{ public: 'owa_medium', private: 'md', full: 'medium' },
+				{ public: 'owa_campaign', private: 'cn', full: 'campaign' },
+				{ public: 'owa_source', private: 'sr', full: 'source' },
+				{ public: 'owa_search_terms', private: 'tr', full: 'search_terms' }, 
+				{ public: 'owa_ad', private: 'ad', full: 'ad' },
+				{ public: 'owa_ad_type', private: 'at', full: 'ad_type' } ],
+		logger_endpoint: '',
+		api_endpoint: ''
+		
+	};
+	
+	// Endpoint URL of log service. needed for backwards compatability with old tags
+	var endpoint = window.owa_baseUrl || OWA.config.baseUrl ;
+	if (endpoint) {
+		this.setEndpoint(endpoint); 
+	} else {
+		OWA.debug('no global endpoint url found.');
+	}
+	
+	this.endpoint = OWA.config.baseUrl;
+	// Active status of tracker
+	this.active = true;
+	
+	if ( options ) {
+		
+		for (opt in options) {
+			
+			this.options[opt] = options[opt];
+		}
+	}
+	
+	// private vars
+	this.ecommerce_transaction = '',
+	this.isClickTrackingEnabled = false;
+	
+	// check to se if an overlay session is active
+	this.checkForOverlaySession();
+	
+	// set default page properties
+	this.page = new OWA.event();
+    this.page.set('page_url', document.URL);
+	this.setPageTitle(document.title);
+	this.page.set("referer", document.referrer);
+	this.page.set('timestamp', this.startTime);
+	
+	// merge page properties from global owa_params object
+	if (typeof owa_params != 'undefined') {
+		// merge page params from the global object if it exists
+		if (owa_params.length > 0) {
+			this.page.merge(owa_params);
+		}
+	}
+}
+
+OWA.tracker.prototype = {
+
+	id : '',
+	// site id
+	siteId : '',
+	// ???
+	init: 0,
+	// flag to tell if client state has been set
+	stateInit: false,
+	// properties that should be added to all events
+	globalEventProperties: {},
+	// state sores that can be shared across sites
+	sharableStateStores: ['v', 's', 'c'],
+	// Time When tracker is loaded
+	startTime: null,
+	// time when tracker is unloaded
+	endTime: null,
+	// campaign state holder
+	campaignState : [],
+	// flag for new campaign status
+	isNewCampaign: false,
+	// flag for new session status
+	isNewSessionFlag: false,
+	// flag for whether or not traffic has been attributed
+	isTrafficAttributed: false,
+	cookie_names: ['owa_s', 'owa_v', 'owa_c'],
+	linkedStateSet: false,
+	hashCookiesToDomain: true,
+	/**
+	 * GET params parsed from URL
+	 */ 
+	urlParams: {},
+	/**
+	 * DOM stream Event Binding Methods
+	 */ 
+	streamBindings : ['bindMovementEvents', 'bindScrollEvents','bindKeypressEvents', 'bindClickEvents'],
+	/**
+	 * Page view event
+	 */
+	page : '',
+	/**
+	 * Latest click event
+	 */
+	click : '',
+	/**
+	 * Domstream event
+	 */
+	domstream : '',
+	/**
+	 * Latest Movement Event
+	 */
+	movement : '',
+	/**
+	 * Latest Keystroke Event
+	 */
+	keystroke : '',
+	/**
+	 * Latest Hover Event
+	 */
+	hover : '',
+	
+	last_event : '',
+	last_movement : '',
+	/**
+	 * DOM Stream Event Queue
+	 */
+	event_queue : [],
+	player: '',
+	overlay: '',
+	
+	setDebug : function(bool) {
+		
+		OWA.setSetting('debug', bool);
+	},
+	
+	checkForLinkedState : function() {
+		
+		var ls = this.getUrlParam('owa_state');
+		
+		if ( ! ls ) {
+			ls = this.getAnchorParam('owa_state');
+		}
+		
+		if ( ls ) {
+			OWA.debug('Shared OWA state detected...');
+			
+			ls = OWA.util.base64_decode(OWA.util.urldecode(ls));
+			//ls = OWA.util.trim(ls, '\u0000');
+			//ls = OWA.util.trim(ls, '\u0000');	
+			OWA.debug('linked state: %s', ls);
+			
+			var state = ls.split('.');
+			//var state = OWA.util.explode('.', ls);
+			OWA.debug('linked state: %s', JSON.stringify(state));
+			if ( state ) {
+			
+				for (var i=0; state.length > i; i++) {
+					
+					var pair = state[i].split('=');
+					OWA.debug('pair: %s', pair);
+					// add cookie domain hash for current cookie domain
+					var value = OWA.util.urldecode(pair[1]);
+					OWA.debug('pair: %s', value);
+					//OWA.debug('about to decode shared link state value: %s', value);
+					decodedvalue = OWA.util.decodeCookieValue(value);
+					//OWA.debug('decoded shared link state value: %s', JSON.stringify(decodedvalue));
+					var format = OWA.util.getCookieValueFormat(value);
+					//OWA.debug('format of decoded shared state value: %s', format);
+					decodedvalue.cdh = OWA.util.getCookieDomainHash( this.getCookieDomain() );
+					
+					OWA.replaceState( pair[0], decodedvalue, true, format );	
+				}
+			}
+		}
+		
+		this.linkedStateSet = true;
+	},
+	
+	/**
+	 * Shares User State cross domains using GET string
+ 	 *
+	 * gets cookies and concatenates them together using:
+	 * name1=encoded_value1.name2=encoded_value2
+	 * then base64 encodes the entire string and appends it
+	 * to an href
+	 * 
+	 * @param	url	string
+	 */
+	shareStateByLink : function(url) {
+	
+		OWA.debug( 'href of link: '+ url );		
+		if ( url ) {
+			
+			var state = this.createSharedStateValue();
+			
+			//check to see if we can just stick this on the anchor
+			var anchor = this.getUrlAnchorValue();
+			if ( ! anchor ) {
+
+				OWA.debug('shared state: %s', state);
+				document.location.href = url + '#owa_state.' + state ;
+			
+			// if not then we need ot insert it into GET params
+			} else {
+				
+			}
+		}	
+	},
+	
+	createSharedStateValue : function() {
+		
+		var state = '';
+
+		for (var i=0; this.sharableStateStores.length > i;i++) {
+			var value = OWA.getState( this.sharableStateStores[i] );
+			value = OWA.util.encodeJsonForCookie(value, OWA.getStateStoreFormat(this.sharableStateStores[i]));
+			
+			if (value) {
+				state += OWA.util.sprintf( '%s=%s', this.sharableStateStores[i], OWA.util.urlEncode(value) );					
+				if ( this.sharableStateStores.length != ( i + 1) ) {
+					state += '.';
+				}
+			}
+		}
+		
+		// base64 for transport
+		if ( state ) {
+			OWA.debug('linked state to send: %s', state);
+			
+			state = OWA.util.base64_encode(state);
+			state = OWA.util.urlEncode(state);
+			return state;
+		}
+	},
+	
+	shareShareByPost : function (form) {
+
+		var state = this.createSharedStateValue();
+		form.action += '#owa_state.' + state;
+		form.submit();
+	},
+
+	getCookieDomain : function() {
+	
+		return this.getOption('cookie_domain') || OWA.getSetting('cookie_domain') || document.domain;
+
+	},
+	
+	setCookieDomain : function(domain) {
+		
+		var not_passed = false;
+		
+		if ( ! domain ) {
+			domain = document.domain;
+			not_passed = true;
+			//this.setOption('cookie_domain_mode', 'auto');
+			//OWA.setSetting('cookie_domain_mode', 'auto');
+		}
+		
+		// remove the leading period
+		var period = domain.substr(0,1);
+		if (period === '.') {
+			domain = domain.substr(1);
+		}
+		
+		var contains_www = false;
+		var www = domain.substr(0,4);
+		// check for www and eliminate it if no domain was passed.
+		if (www === 'www.') {
+			if ( not_passed ) {
+				domain = domain.substr(4);
+			} 
+
+			contains_www = true;
+		}
+		
+		var match = false;
+		if (document.domain === domain) {
+			 match = true;
+		}
+		
+		/*
+		if (match === true) {
+			// check to see if the domain is www 
+			if ( contains_www === true ) {
+				// eliminate any top level domain cookies
+				OWA.debug('document domain matches cookie domain and includes www. cleaning up cookies.');
+				//erase the no www domain cookie (ie. .openwebanalytics.com)
+				var top_domain =  document.domain.substr(4);
+				OWA.util.eraseMultipleCookies(this.cookie_names, top_domain);
+			}
+			
+		} else {
+			// erase the document.domain version of all cookies (ie. www.openwebanalytics.com)
+			OWA.debug('document domain does not match cookie domain. cleaning up by erasing cookies under document.domain .');
+			OWA.util.eraseMultipleCookies(this.cookie_names, document.domain);
+			
+			
+			//if ( contains_www === true) {
+			//	OWA.util.eraseMultipleCookies(this.cookie_names, document.domain.substr(4));
+			//	OWA.util.eraseMultipleCookies(this.cookie_names, document.domain.substr(4));
+			//}
+			
+		}
+		*/
+		
+		// add the leading period back
+		domain =  '.' + domain;
+		this.setOption('cookie_domain', domain);
+		this.setOption('cookie_domain_set', true);
+		OWA.setSetting('cookie_domain', domain);
+		OWA.debug('Cookie domain is: %s', domain);
+	},
+	
+	getCookieDomainHash: function(domain) {
+		
+		return OWA.util.crc32(domain);
+	},
+	
+	setCookieDomainHashing: function(value) {
+		this.hashCookiesToDomain = value;
+		OWA.setSetting('hashCookiesToDomain', value);
+	},
+	
+	checkForOverlaySession: function() {
+		
+		// check to see if overlay sesson should be created
+		var a = this.getAnchorParam('owa_overlay');
+		
+		if ( a ) {
+			a = OWA.util.base64_decode(OWA.util.urldecode(a));
+			//a = OWA.util.trim(a, '\u0000');
+			a = OWA.util.urldecode( a );
+			OWA.debug('overlay anchor value: ' + a);
+			//var domain = this.getCookieDomain();
+			
+			// set the overlay cookie
+			OWA.util.setCookie('owa_overlay',a, '','/', document.domain );
+			////alert(OWA.util.readCookie('owa_overlay') );
+			// pause tracker so we dont log anything during an overlay session
+			this.pause();
+			// start overlay session
+			OWA.startOverlaySession( OWA.util.decodeCookieValue( a ) );
+		}			
+	},
+	
+	getUrlAnchorValue : function() {
+	
+		var anchor = self.document.location.hash.substring(1);
+		OWA.debug('anchor value: ' + anchor);
+		return anchor;	
+	},
+	
+	getAnchorParam : function(name) {
+	
+		var anchor = this.getUrlAnchorValue();
+		
+		if ( anchor ) {
+			OWA.debug('anchor is: %s', anchor);
+			var pairs = anchor.split(',');
+			OWA.debug('anchor pairs: %s', JSON.stringify(pairs));
+			if ( pairs.length > 0 ) {
+			
+				var values = {};
+				for( var i=0; pairs.length > i;i++ ) {
+					
+					var pieces = pairs[i].split('.');
+					OWA.debug('anchor pieces: %s', JSON.stringify(pieces));	
+					values[pieces[0]] = pieces[1];
+				}
+				
+				OWA.debug('anchor values: %s', JSON.stringify(values));
+				
+				if ( values.hasOwnProperty( name ) ) {
+					return values[name];
+				}
+			}
+			
+		}
+	},
+	
+	getUrlParam : function(name) {
+		
+		this.urlParams = this.urlParams || OWA.util.parseUrlParams();
+		
+		if ( this.urlParams.hasOwnProperty( name ) ) {
+			return this.urlParams[name];
+		} else {
+			return false;
+		}
+	},
+	
+	dynamicFunc : function (func){
+		//alert(func[0]);
+		var args = Array.prototype.slice.call(func, 1);
+		//alert(args);
+		this[func[0]].apply(this, args);
+	},
+	
+	/**
+	 * Convienence method for seting page title
+	 */
+	setPageTitle: function(title) {
+		
+		this.page.set("page_title", title);
+	},
+	
+	/**
+	 * Convienence method for seting page type
+	 */
+	setPageType : function(type) {
+		
+		this.page.set("page_type", type);
+	},
+	
+	/**
+	 * Sets the siteId to be appended to all logging events
+	 */
+	setSiteId : function(site_id) {
+		this.siteId = site_id;
+	},
+	
+	/**
+	 * Convienence method for getting siteId of the logger
+	 */
+	getSiteId : function() {
+		return this.siteId;
+	},
+	
+	setEndpoint : function (endpoint) {
+		
+		endpoint = ('https:' == document.location.protocol ? window.owa_baseSecUrl || endpoint.replace(/http:/, 'https:') : endpoint );
+		this.setOption('baseUrl', endpoint);
+		OWA.config.baseUrl = endpoint;
+	},
+	
+	setLoggerEndpoint : function(url) {
+		
+		this.setOption( 'logger_endpoint', this.forceUrlProtocol( url ) );
+	},
+	
+	getLoggerEndpoint : function() {
+	
+		var url = this.getOption( 'logger_endpoint') || this.getEndpoint() || OWA.getSetting('baseUrl') ;
+		
+		return url + 'log.php';
+	},
+	
+	setApiEndpoint : function(url) {
+			
+		this.setOption( 'api_endpoint', this.forceUrlProtocol( url ) );
+		OWA.setApiEndpoint(url);
+	},
+	
+	getApiEndpoint : function() {
+	
+		return this.getOption('api_endpoint') || this.getEndpoint() + 'api.php';
+	},
+	
+	forceUrlProtocol : function (url) {
+		
+		url = ('https:' == document.location.protocol ? url.replace(/http:/, 'https:') : url );
+		return url;
+	},
+
+	
+	getEndpoint : function() {
+		return this.getOption('baseUrl');
+	},
+	
+	/**
+	 * Logs a page view event
+	 */
+	trackPageView : function(url) {
+		
+		if (url) {
+			this.page.set('page_url', url);
+		}
+		
+		this.page.setEventType("base.page_request");
+		
+		return this.trackEvent(this.page);
+	},
+	
+	trackAction : function(action_group, action_name, action_label, numeric_value) {
+		
+		var event = new OWA.event;
+		
+		event.setEventType('track.action');
+		event.set('site_id', this.getSiteId());
+		event.set('page_url', this.page.get('page_url'));
+		event.set('action_group', action_group);
+		event.set('action_name', action_name);
+		event.set('action_label', action_label);
+		event.set('numeric_value', numeric_value);
+		this.trackEvent(event);
+		OWA.debug("Action logged");
+	},
+	
+	trackClicks : function(handler) {
+		// flag to tell handler to log clicks as they happen
+		this.setOption('logClicksAsTheyHappen', true);
+		this.bindClickEvents();		
+		
+	},
+	
+	bindClickEvents : function() {
+	
+		if ( ! this.isClickTrackingEnabled ) {
+			var that = this;
+			// Registers the handler for the before navigate event so that the dom stream can be logged
+			if (window.addEventListener) {
+				window.addEventListener('click', function (e) {that.clickEventHandler(e);}, false);
+			} else if(window.attachEvent) {
+				window.attachEvent('click', function (e) {that.clickEventHandler(e);});
+			}
+			
+			this.isClickTrackingEnabled = true;
+		}
+	
+	},
+	
+	trackDomStream : function() {
+		
+		if (this.active) {
+		
+			// check random number against logging percentage
+			var rand = Math.floor(Math.random() * 100 + 1 );
+
+			if (rand <= this.getOption('logDomStreamPercentage')) {
+				
+				// needed by click handler 
+				this.setOption('trackDomStream', true);	
+				// loop through stream event bindings
+				var len = this.streamBindings.length;
+				for ( var i = 0; i < len; i++ ) {	
+				//for (method in this.streamBindings) {
+				
+					this.callMethod(this.streamBindings[i]);
+				}
+				
+				this.startDomstreamTimer();			
+			} else {
+				OWA.debug("not tracking domstream for this user.");
+			}
+		}
+	},
+	
+	logDomStream : function() {
+    	
+    	this.domstream = this.domstream || new OWA.event;
+    	
+    	if ( this.event_queue.length > this.options.domstreamEventThreshold ) {
+    		
+			// make an domstream_id if one does not exist. needed for upstream processing
+			if ( ! this.domstream.get('domstream_guid') ) {
+				var salt = 'domstream' + this.page.get('page_url') + this.getSiteId();
+				this.domstream.set( 'domstream_guid', OWA.util.generateRandomGuid( salt ) );
+			}
+			
+			this.domstream.setEventType( 'dom.stream' );
+			this.domstream.set( 'site_id', this.getSiteId());
+			this.domstream.set( 'page_url', this.page.get('page_url') );
+			//this.domstream.set( 'timestamp', this.startTime);
+			this.domstream.set( 'timestamp', OWA.util.getCurrentUnixTimestamp() );
+			this.domstream.set( 'duration', this.getElapsedTime());
+			this.domstream.set( 'stream_events', JSON.stringify(this.event_queue));
+			this.domstream.set( 'stream_length', this.event_queue.length );
+			this.trackEvent( this.domstream );
+			this.event_queue = [];
+	
+		} else {
+			OWA.debug("Domstream had too few events to log.");
+		}
+	},
+	
+	startDomstreamTimer : function() {
+		
+		var interval = this.getOption('domstreamLoggingInterval')
+		var that = this;
+		var domstreamTimer = setInterval(
+			function(){ that.logDomStream() }, 
+			interval
+		);
+	},
+	
+	/**
+	 * Deprecated
+	 */
+	log : function() {
+    	this.page.setEventType("base.page_request");
+    	return this.logEvent(this.page);
+    },
+    
+    /**
+     * Logs event asyncronously using AJAX GET
+     */
+    logEventAjax : function (event, method) {
+    	if (this.active) {
+    		
+    		if (event instanceof OWA.event) { 
+	    		var properties = event.getProperties(); 
+	    	} else {
+	    		var properties = event;
+	    	}
+	    	
+	    	method = method || 'GET';
+	    	
+	    	if (method === 'GET') {
+	    		return this.ajaxGet(properties);
+	    	} else {
+	    		this.ajaxPost(properties);
+	    		return;
+	    	}
+    		
+    	}
+    	
+    	
+    },
+    
+    isObjectType : function(obj, type) {
+    	return !!(obj && type && type.prototype && obj.constructor == type.prototype.constructor);
+	},
+
+    
+    /**
+     * Gets XMLHttpRequest Object
+     */
+    getAjaxObj : function() {
+    
+    	if (window.XMLHttpRequest){
+			// If IE7, Mozilla, Safari, etc: Use native object
+			var ajax = new XMLHttpRequest()
+		} else {
+			
+			if (window.ActiveXObject){
+		          // ...otherwise, use the ActiveX control for IE5.x and IE6
+		          var ajax = new ActiveXObject("Microsoft.XMLHTTP"); 
+			}
+	
+		}
+		return ajax;
+    },
+    
+    ajaxGet : function(properties) {
+    	
+    	var url = this._assembleRequestUrl(properties);
+		var ajax = this.getAjaxObj();
+		ajax.open("GET", url, false); 
+		ajax.send(null);
+    },
+    
+    /**
+     * AJAX POST Request
+     */
+    ajaxPost : function(properties) {
+    	
+    	var ajax = this.getAjaxObj();
+	    var params = this.prepareRequestParams(properties);
+	    
+		ajax.open("POST", this.getLoggerEndpoint(), false); 
+		//Send the proper header information along with the request
+		ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+		ajax.setRequestHeader("Content-length", params.length);
+		ajax.setRequestHeader("Connection", "close");
+		
+		ajax.onreadystatechange = function() {//Call a function when the state changes.
+			if(ajax.readyState == 4 && ajax.status == 200) {
+				//console.log("ajax response: %s", ajax.responseText);
+			}
+		}
+
+		ajax.send(params);
+    	
+    },
+    
+    ajaxJsonp : function (url) {                
+	   
+	    var script = document.createElement("script");        
+	    script.setAttribute("src",url);
+	    script.setAttribute("type","text/javascript");                
+	    document.body.appendChild(script);
+	},
+    
+    prepareRequestParams : function(properties) {
+    
+  		var get = '';
+    	
+    	// append site_id to properties
+    	properties.site_id = this.getSiteId();
+    	//assemble query string
+	    for ( param in properties ) {  
+	    	// print out the params
+			var value = '';
+			var kvp = '';
+				
+			if ( properties.hasOwnProperty(param) ) {
+	  			
+	  			if ( OWA.util.is_array( properties[param] ) ) {
+				
+					for ( var i = 0, n = properties[param].length; i < n; i++ ) {
+						
+						if ( OWA.util.is_object( properties[param][i] ) ) {
+							for ( o_param in properties[param][i] ) {
+								kvp = OWA.util.sprintf('owa_%s[%s][%s]=%s&', param, i, o_param, OWA.util.urlEncode( properties[param][i][o_param] ) );
+								get += kvp;
+							}
+						} else {
+							// what the heck is it then. assum string
+							kvp = OWA.util.sprintf('owa_%s[%s]=%s&', param, i, OWA.util.urlEncode( properties[param][i] ) );
+							get += kvp;
+						}
+					}
+				// assume it's a string
+				} else {
+					kvp = OWA.util.sprintf('owa_%s=%s&', param, OWA.util.urlEncode( properties[param] ) );
+					
+				}
+			
+				
+    		//needed?	
+	    	} else {
+    	
+    			kvp = OWA.util.sprintf('owa_%s=%s&', '', OWA.util.urlEncode( properties[param] ) );
+    		}
+    		
+    		get += kvp;
+		}
+		//OWA.debug('GET string: %s', get);
+		return get;
+    },
+    
+    /** 
+     * Sends an OWA event to the server for processing using GET
+     * inserts 1x1 pixel IMG tag into DOM
+     */
+    trackEvent : function(event, block) {
+    	//OWA.debug('pre global event: %s', JSON.stringify(event));
+    	
+    	if ( this.getOption('cookie_domain_set') != true ) {
+    		// set default cookie domain
+			this.setCookieDomain();
+    	}
+    	
+    	if ( this.linkedStateSet != true ) {
+    		//check for linked state send from another domain
+			this.checkForLinkedState();
+    	}
+    	
+    	if ( this.active ) {
+	    	if ( ! block ) {
+	    		block_flag = false;
+	    	} else {
+	    		block_flag = true;
+	    	}
+	    	
+	    	// check for third party mode.
+	    	if ( this.getOption( 'thirdParty' ) ) {
+	    		// tell upstream client to manage state
+	    		this.globalEventProperties.thirdParty = true;
+	    		// add in campaign related properties for upstream evaluation
+	    		this.setCampaignRelatedProperties(event);
+	    	} else {
+	    		// else we are in first party mode, so manage state on the client.
+	    		this.manageState(event);
+	    	}
+	    	
+	    	this.addGlobalPropertiesToEvent( event );
+	    	//OWA.debug('post global event: %s', JSON.stringify(event));
+	    	return this.logEvent( event.getProperties(), block_flag );
+	    }
+    },
+    
+    addGlobalPropertiesToEvent : function ( event ) {
+    	OWA.debug( 'Adding global properties to event: %s', JSON.stringify(this.globalEventProperties) );	
+    	for ( prop in this.globalEventProperties ) {
+    		event.set( prop, this.globalEventProperties[prop] );
+    	}
+    },
+    
+
+    /** 
+     * Logs event by inserting 1x1 pixel IMG tag into DOM
+     */
+    logEvent : function (properties, block) {
+    	
+    	if (this.active) {
+    	
+	    	var url = this._assembleRequestUrl(properties);
+	    	OWA.debug('url : %s', url);
+		   	image = new Image(1, 1);
+		   	//expireDateTime = now.getTime() + delay;
+		   	image.onLoad = function () { };
+			image.src = url;
+			if (block) {
+				//OWA.debug(' blocking...');
+			}
+			OWA.debug('Inserted web bug for %s', properties['event_type']);
+		}
+    },
+        
+    /**
+     * Private method for helping assemble request params
+     */
+    _assembleRequestUrl : function(properties) {
+    
+    	// append site_id to properties
+    	properties.site_id = this.getSiteId();
+    	var get = this.prepareRequestParams(properties);
+    	
+    	var log_url = this.getLoggerEndpoint();
+    	
+    	if (log_url.indexOf('?') === -1) {
+    		log_url += '?';
+    	} else {
+    		log_url += '&';
+    	}
+    	    	
+		// add some radomness for cache busting
+		return log_url + get;
+    },	
+	
+	getViewportDimensions : function() {
+	
+		var viewport = new Object();
+		viewport.width = window.innerWidth ? window.innerWidth : document.body.offsetWidth;
+		viewport.height = window.innerHeight ? window.innerHeight : document.body.offsetHeight;
+		return viewport;
+	},
+	
+	/**
+	 * Sets the X coordinate of where in the browser the user clicked
+	 *