function cloneDict(oldDict) {
	newDict = {};
  for (i in oldDict) {
    if (oldDict[i] && typeof oldDict[i] == "object") {
      newDict[i] = cloneDict(oldDict[i]);
    } else newDict[i] = oldDict[i]
  } return newDict;
};


var trackableObjects = {};
		/* EXAMPLES:
		trackableObjects['movieShare'] = {'bindings': ["click"],
			'category':"content",
			'subcategory':"share",
			'placement':"video_player"
			};	
		trackableObjects['movieShareEngaged'] = {'bindings': ["click"],
			'genre':"engagement",
			'category':"share",
			'subcategory':"video",
			'placement':"video_player"
			};	
		trackableObjects['movieThumb'] = {'bindings': ["click"],
			'category':"content",
			'subcategory':"video",
			'placement':"video_feed"
			};	
		trackableObjects['movieThumbEngaged'] = {'bindings': ["mouseover"],
			'genre':"engagement",
			'category':"consume",
			'subcategory':"video",
			'placement':"video_feed"
			};	
		trackableObjects['pauseButton'] = {'bindings': ["focus"],
			'genre':"click",
			'category':"video",
			'subcategory':"pause",
			'placement':"video_feed"
			};	
			
			*/
			


		trackableObjects['pubStoriesSelect'] = {'bindings': ["click"],
			'genre':"click",
			'category':"control",
			'subcategory':"filter"//,
//			'placement':"story_feed"
			};	
			
//okay these should be the finals
		trackableObjects['sharePageClick'] = {'bindings': ["click"],
			'genre':"click",
			'category':"content",
			'subcategory':"share",
			'placement':"masthead",
			'kind':"undefined"
			};				
		trackableObjects['shareStoryClick'] = {'bindings': ["click"],
			'genre':"click",
			'category':"content",
			'subcategory':"share",
//			'placement':"story_feed",
			'kind':"undefined"
			};				
		trackableObjects['shareStoryEng'] = {'bindings': ["click"],
			'genre':"engagement",
			'category':"share",
			'subcategory':"story"//,
//			'placement':"story_feed"
			};		
		trackableObjects['storyExpandClick'] = {'bindings': ["click"],
			'genre':"click",
			'category':"content",
			'subcategory':"story",
//			'placement':"story_feed",
			'asset':"story_link"
			};	
		trackableObjects['storyExpandEng'] = {'bindings': ["click"],
			'genre':"engagement",
			'category':"consume",
			'subcategory':"story",
			'kind':"summary"//,
//			'placement':"story_feed"
			};	
		trackableObjects['launchStoryExternalLinkClick'] = {'bindings': ["click"],
			'genre':"click",
			'category':"content",
			'subcategory':"story",
//			'placement':"story_feed",
			'asset':"continue_reading_link"
			};	
		trackableObjects['launchStoryExternalLinkEng'] = {'bindings': ["click"],
			'genre':"engagement",
			'category':"consume",
			'subcategory':"story",
			'kind':"article"//,
//			'placement':"story_feed"
			};	
		trackableObjects['headingClick'] = {'bindings': ["click"],
			'genre':"click",
			'category':"branding",
			'placement':"header",
			'asset':"logo"
			};	

		trackableObjects['communityStreamTab'] = {'bindings': ["click"],
			'genre':"click",
			'category':"control",
			'subcategory':"filter",
			'placement':"community_stream"
			};	
		trackableObjects['communityStreamClick'] = {'bindings': ["click"],
			'genre':"click",
			'category':"branding",
			'placement':"community_stream"
			};		
		trackableObjects['communityFeedShare'] = {'bindings': ["click"],
			'genre':"click",
			'category':"branding",
			'placement':"community_stream"
			};	
		trackableObjects['appStoreClick'] = {'bindings': ["click"],
			'genre':"click",
			'category':"branding"//,
//			'placement':"app_world_feed"
			};	
		trackableObjects['appStoreMoreClick'] = {'bindings': ["click"],
			'genre':"click",
			'category':"branding",
//			'placement':"app_world_feed",
			'asset':"see_more_apps_link"
			};				

		
		
		
		(function( $ ){
			jQuery.fn.nsTrackable = function() {
				this.each(function() {	//for each trackable object

					//like classes, an object can have more than one objType, delimited by spaces. So we have to loop through these and set up the bindings
					if ($(this).attr("objType") == undefined) {
						alert("You didn't define any object types for " + $(this).attr('tagName') + "#" + $(this).attr('id') + "." + $(this).attr('className'));
						return false;
					}
					
					//i'm not sure if this is helping but IE8 seems to have an issue with a split command that results in one element
					var objTypeString = jQuery.trim($(this).attr("objType"));
					if (objTypeString.indexOf(" ") >= 0) {
						var objTypes = [];
						objTypes = objTypeString.split(" ");						
					} else {
						var objTypes = [objTypeString];
					}
					
					for (var i = 0; i < objTypes.length; i++) {
					//get the trackable object type
						var objType = i;
						
						//make sure this is a valid object and error if it's not so that the developer knows they screwed up
						if (trackableObjects[objTypes[i]] === undefined) {
											alert("objtypestring is -"+objTypeString+"-");
											alert(objTypes.join("%"));
							alert("The objType ("+i+") \""+objTypes[i]+"\" which looks like this "+trackableObjects[objTypes[i]]+"\" is not defined as a trackable object and will not be tracked properly");
						}
						
						
						//for each of the applicable tracking events
						for (j = 0; j <trackableObjects[objTypes[objType]].bindings.length; j++) {
							var trackableEvent = j;
							
							//bind tracking function to the tracking event
							var eventBinding = trackableObjects[objTypes[objType]].bindings[trackableEvent];						

							//If we have two objTypes associated with a single object with the same event on them, it will trigger multiple times because we'll have multiple bindings.
							//we only need to bind once since the bound event matches all objTypes and (event)
							if ($(this).attr("isBound") == undefined) {	//don't double-bind
								$(this).attr("isBound", 'true');
								$(this).bind(eventBinding, function( event ) {
								//------------------------------------------------------------------------------------------------------------------------------------------------------
									//this is not  redundant, looping through the objTypes again, because inside this BIND is a seperate function.
									//this is getting run when one of the bound events actually gets triggered					
									var objTypes2 = $(this).attr("objType").split(" ");
									
									//loop through the objTypes associated with this object
									for (k = 0; k < objTypes2.length; k++) {
										objType3 = k;
									
										//for the object which was interacted with, for the current objType, is the interaction bound to this object?
										if (jQuery.inArray(event.type, trackableObjects[objTypes2[objType3]].bindings) >= 0) {
										
										
											var reportingObject = {};
											 reportingObject = cloneDict(trackableObjects[objTypes2[objType3]]);
											
											if (reportingObject.kind === undefined) {
												if (reportingObject.genre == 'engagement' && $(this).attr("nstrack-eng-kind")) {
													reportingObject.kind = $(this).attr("nstrack-eng-kind");
												} else {
													reportingObject.kind = $(this).attr("nstrack-kind");
												}
											}
											
											if (reportingObject.asset === undefined) {
												if (reportingObject.genre == 'engagement' && $(this).attr("nstrack-eng-asset")) {
													reportingObject.asset = $(this).attr("nstrack-eng-asset");
												} else {
													reportingObject.asset = $(this).attr("nstrack-asset");
												}
											}
											
											if (reportingObject.placement === undefined) {
												if (reportingObject.genre == 'engagement' && $(this).attr("nstrack-eng-placement")) {
													reportingObject.placement = $(this).attr("nstrack-eng-placement");
												} else {
													reportingObject.placement = $(this).attr("nstrack-placement");
												}
											}
											
											
											netShelter.trackEvent({
													'genre':		reportingObject.genre,
													'category':		reportingObject.category,
													'subcategory':	reportingObject.subcategory,
													'kind':			reportingObject.kind,
													'placement':	reportingObject.placement,
													'asset':		reportingObject.asset,
													'x':			event.pageX, 
													'y':			event.pageY
												});
										} else {
										/*
											console.log("for object " + objTypes[objType] + " bindings are: " + trackableObjects[objTypes[objType]].bindings);
											console.log();
											console.log("Of which none are " + event.type);
											*/
										}
									}
									
								//------end bind statmenet-------------------------------------------------------------------------------------------------------------------------------
								});
							}
	
						}
						
					}
				});			
			};
		})( jQuery );
		
		
			
			//-------------------------------------------------------------------------------------------------------------------------------------------------			
			//----------- plugin for testing which events are currently being tracked based on the setup . -----------
			//-------------------------------------------------------------------------------------------------------------------------------------------------
		
		(function( $ ){
			jQuery.fn.nsCheckTrackable = function() {
					if ($("#report").length <= 0) {
						$("body").append("<div id='report' style='background: white; color: black; padding: 10px; border: 1px solid gray;'></div><br />");
					}
					$("#report").append("<h2 style='font-weight: bold;'>Tracked Event Test Results<br /></h2>");
					
				this.each(function() {	//for each trackable object
				
					$('#report').append("<b>Testing ("+ (($(this).text().length>24) ? $(this).text().substr(0, 24) + "..." : $(this).text()) +")</b> ["+$(this).attr('id')+"]<br>");
					$('#report').append("Associated Object Types: "+$(this).attr("objType") + "<br>");
					
					var objTypes3 = $(this).attr("objType").split(" ");
					$(this).addClass("showTracked");
						
					var thisObj = $(this);			
					for (myObjType in objTypes3) {
					//get the trackable object type
					
						//make sure this is a valid object and error if it's not so that the developer knows they screwed up
						if (trackableObjects[objTypes3[myObjType]] == undefined) {
							alert("The objType \""+objTypes3[myObjType]+"\" is not defined as a trackable object and will not be tracked properly");
						}

						var reportingObject = {};
						 reportingObject = cloneDict(trackableObjects[objTypes3[myObjType]]);

						if (reportingObject.genre === undefined) { 
							reportingObject.genre = thisObj.attr("nstrack-genre"); 
							if (thisObj.attr("nstrack-eng-genre")) {
								reportingObject.genre += "[ifEngagement="+thisObj.attr("nstrack-eng-genre")+"]";
							}

						}
						
						if (reportingObject.kind === undefined) { 
							reportingObject.kind = thisObj.attr("nstrack-kind"); 
							if (thisObj.attr("nstrack-eng-kind")) {
								reportingObject.kind += "[ifEngagement="+thisObj.attr("nstrack-eng-kind")+"]";
							}
						}
						

						if (reportingObject.placement === undefined) { 
							reportingObject.placement = thisObj.attr("nstrack-placement"); 
							if (thisObj.attr("nstrack-eng-placement")) {
								reportingObject.placement += "[ifEngagement="+thisObj.attr("nstrack-eng-placement")+"]";
							}
						}
				
						if (reportingObject.asset === undefined) {
							reportingObject.asset = thisObj.attr("nstrack-asset");
							if (thisObj.attr("nstrack-eng-asset")) {
								reportingObject.asset += "[ifEngagement="+thisObj.attr("nstrack-eng-asset")+"]";
							}
						}
						
						$('#report').append("<div class='objTypeBox'><u>Details for: "+objTypes3[myObjType]+"</u><br>Bound on the following events: " + reportingObject.bindings+"<br />Payload:"+JSON.stringify(reportingObject)+"</div><br />");
						
							//for tooltip presentation (requires easyTooltip.js)
							var titNow = $(this).attr('title');
							if (titNow === undefined) { titNow = ""; } 
							$(this).attr('title', titNow+""+JSON.stringify(reportingObject).replace(/","/g, ",<br>").replace(/":"/g, "=").replace(/{"/g, "<br>").replace(/"}/g, "<br><br>"));
						
						delete(reportingObject);
					}
					
					$(".trackable").easyTooltip();
					$('#report').append("</br>");
				});			
			};
		})( jQuery );
			

			
			//-------------------------------------------------------------------------------------------------------------------------------------------------			
			//----------- plugin for testing which events do NOT have "trackable" attached to them. -----------
			//-------------------------------------------------------------------------------------------------------------------------------------------------
			
			
						(function($) {
				$.checkUnTrackable = function(selector, root) {
					var s = [];
					$(selector || '*', root).andSelf().each(function() {

						var e = $.data(this, 'events');
						if (!e) {

							var possibleEvents = ["onclick", "onmouseover", "onmouseout", "onkeypress", "onkeydown", "onkeyup", "onfocus", "onblur", "onscroll"];
							for (possibleEvent in possibleEvents) {
								if ($(this).attr(possibleEvents[possibleEvent])) {
										//i know this will overwrite with the last event but one event at a time should be enough for untracked events
										var eventStr = possibleEvents[possibleEvent].toString();
										var e = {};
										e[eventStr] = {'type': eventStr };
								}
							}
						}
						if (this.tagName == 'A' && $(this).attr('href') && $(this).attr('href') != '#') {
							var e = {};
							e['click'] = {'type': 'href' };
						}
						if (!e) return;						
						if (!this.className || this.className.indexOf('trackable') == -1) {
//							console.log("trackable == -1. class is: "+this.className);
							s.push(this.tagName);
							if(this.id) s.push('#', this.id);
							if(this.className) s.push('.', this.className);
							if($(this).text()) s.push(" - (" + (($(this).text().length>24) ? $(this).text().substr(0, 24) + "..." : $(this).text()) +")");
							if($(this).attr('href')) s.push(" [href=" + (($(this).attr('href').length>64) ? $(this).attr('href').substr(0, 64) + "..." : $(this).attr('href')) +"]");
							if($(this).attr('src')) s.push(" - (" + (($(this).attr('src').length>24) ? $(this).attr('src').substr(0, 24) + "..." : $(this).attr('src')) +")");
							for (var p in e) s.push('<br />', p);
							s.push('<br /><br />');
							if ($(this).hasClass('ignorable')) {
								$(this).addClass("beingIgnored");
							} else {
								$(this).addClass("notBeingTracked");
							}
						} else {
//							console.log(this.tagName + "." + this.className + "("+ $(this).text() + " is being properly tracked");
						}
					});
					return s.join('');
				}
				
				$.fn.nsCheckUnTrackable = function(selector) {
					//return 
					if ($("#report").length <= 0) {
						$("body").append("<div id='report' style='background: white; color: black; padding: 10px; border: 1px solid gray;'></div><br />");
					}
					
					$("#report").append("<h2 style='font-weight: bold;'>Untracked Event Test Results<br /></h2>");
					var results = $.checkUnTrackable(selector, $("*"));

					$('#report').append(results);
					
				}
			})(jQuery);
			
			
			
			
			

			
			//-------------------------------------------------------------------------------------------------------------------------------------------------			
			//----------- debug stuff, not actually needed for this code to work, just here so we can make sure we maintain backwards compatability -----------
			//-------------------------------------------------------------------------------------------------------------------------------------------------
			
			
			
			
			TrackableGenre = {
	'CLICK':					'click',
	'ENGAGEMENT':				'engagement',
	'HOVER':					'hover',
	'IMPRESSION':				'impression',
	'MEDIA':					'media'
}

TrackableCategory = {
	'BRANDING':					'branding',
	'COMPLETE':					'complete',
	'CONSUME':					'consume',
	'CONTENT':					'content',
	'CONTROL':					'control',
	'FOLLOW':					'follow',
	'LOAD':						'load',
	'SERVE':					'serve',
	'SHARE':					'share',
	'TIME':						'time',
	'VIEW':						'view'
}

TrackableSubcategory = {
	'COLLECT':					'collect',
	'CREATIVE':					'creative',
	'CUSTOM':					'custom',
	'EXPORT':					'export',
	'FILTER':					'filter',
	'HIDE':						'hide',
	'PRODUCT':					'product',
	'PUBLISHER':				'publisher',
	'SCROLL':					'scroll',
	'SHARE':					'share',
	'SOCIAL':					'social',
	'STORY':					'story',
	'VIDEO':					'video',
	'WHITEPAPER':				'whitepaper'
}

TrackableKind = {
	'ARTICLE':					'article',
	'PLAY':						'play',
	'PRECIS':					'precis',
	'SUMMARY':					'summary'
}

TrackablePlacement = {
	'COMMUNITY_STREAM':			'community_stream',
	'EXTERNAL':					'external',
	'FOLLOW_BUTTON':			'follow_button',
	'HEADER':					'header',
	'MASTHEAD':					'masthead',
	'PRODUCT_INFO':				'product_info',
	'SHARING_BAR':				'sharing_bar',
	'SPLASH':					'splash',
	'STORY_FEED':				'story_feed',
	'STORY_PRECIS':				'story_precis',
	'VIDEO_FEED':				'video_feed',
	'VIDEO_PLAYER':				'video_player',
	'WHITEPAPER_FEED':			'whitepaper_feed'
}

TrackableAsset = {
	'BACKGROUND':				'background',
	'CALL_TO_ACTION':			'call_to_action',
	'ENTER_FULL_SCREEN_BUTTON':	'enter_full_screen_button',
	'EXIT_FULL_SCREEN_BUTTON':	'exit_full_screen_button',
	'FOLLOW_BUTTON':			'follow_button',
	'HEADLINE':					'headline',
	'LOGO':						'logo',
	'MUTE_BUTTON':				'mute_button',
	'NEXT_ARROW':				'next_arrow',
	'PREVIOUS_ARROW':			'previous_arrow',
	'PRODUCT_IMAGE':			'product_image',
	'PAUSE_BUTTON':				'pause_button',
	'PLAY_BUTTON':				'play_button',
	'SCROLL_BAR':				'scroll_bar',
	'SHARE_BUTTON':				'share_button',
	'TIMELINE':					'timeline',
	'UNMUTE_BUTTON':			'unmute_button'
}

TrackableAssetSource = {
	'DELIMITER':				'.',
	'FACEBOOK':					'facebook',
	'GOOGLE_PLUS':				'google_plus',
	'N2I':						'n2i',
	'SHOPLOCAL':				'shoplocal',
	'TWITTER':					'twitter',
	'URL':						'url',
	'YOUTUBE':					'youtube'
}

expectedTrackingKeys = [
	'guid',
	'sessionID',
	'experienceID',
	'campaign',
	'creative',
	'parent',
	'creativeSize',
	'site',
	'genre',
	'category',
	'subcategory',
	'kind',
	'placement',
	'asset',
	'label',
	'value',
	'x',
	'y',
	'redir'
];

trackingInfo = {
	'guid':					null,
	'sessionID':			null,
	'experienceID':			null,
	'campaign':				null,
	'creative':				null,
	'creativeSize':			null,
	'site':					null,
	'parent':				null
}
	
			
			function trackEvent(parameters, api, version) {
			/*	Tracks an event to the backend specified by api and version. 
			 *	Defaults to NetShelter Analytics Platform (NAP).
			 */
//			 console.log("parameters: ");
					if ($("#console").length <= 0) {
						$("body").append("<div id='console' style='background: gray; color: black; padding: 10px; border: 1px solid gray;'><h1>Console:</h1></div><br />");
					}
					var jsonString = "<b>TrackEvent received:</b><br>";
					for (param in parameters) {
						if (parameters[param]) {
							jsonString += param + "=" + parameters[param] + "<br>";
						}
					}
					jsonString += "------------------------<br><br>";
					$("#console").append(jsonString);

//			 console.log(parameters);
//			 console.log("api: "+api+"; version: "+version); 
			}
			
			

