if (redux) {
	var o=redux.invue={};
	o.users={};
	
	o.mousex=-1; o.mousey=-1; o.packet=[]; o.packetsequence=1;
	o.packetstart=o.mousestart=(new Date().getTime()); 
	
	o.getWidth = function () {
		 if (this.webkit419) return document.innerWidth;
		 if (this.opera) return document.body.clientWidth;
		 return document.documentElement.clientWidth;		
	}
	
	o.pingResult = function(v) {
		
		if (v.test) return;
		var currentuser=false;
		this.width=this.getWidth();
		v=v.watch;
		for(var res=0; res<v.length; res++) {
			var user=v[res];
			if (!this.users[user.uid]) this.users[user.uid]={};
			var currentuser=this.users[user.uid];
			currentuser.page=user.page;
			currentuser.query=user.query;
			currentuser.width=user.w;
			
			if (!currentuser.activity) {
				currentuser.activity=[];
				//get first sequence if new activity
				currentuser.sequence=-1;
				currentuser.timing=-1;
				//new tracker - generate an element
				currentuser.icon = new Element('img',{'src':'/inc/redux/images/cursor.png','class':'user_monitor_icon','id':user.uid});
				//currentuser.icon.innerHTML=user.activity;
				$('worker').appendChild(this.users[user.uid].icon);
			}

			currentuser.icon.setStyle('visibility','visible');
			activity=user.activity;
			
			for (var x in activity) {
				if ((parseInt(x)>currentuser.sequence) || ((parseInt(x)==1) && (currentuser.sequence>2))){
					//process it
					for (var pline=0; pline<activity[x].length; pline++) {
						currentuser.activity.push(activity[x][pline]);
					}
					currentuser.sequence=parseInt(x);
				}
			}
			
			if (currentuser.timing < 0) {
				this.mouseMove();
			}
		}
		
		if($("debug_window_text") && currentuser) $("debug_window_text").innerHTML="[] Activity: "+currentuser.activity.length+" Timer: "+currentuser.timing+"<br>"+$("debug_window_text").innerHTML;
		return true;
	}	

	o.userRemove = function(key) {}
		o.mouseMove = function() {
		var me=redux.invue;
		for (var key in me.users) {
			var user=me.users[key];
			if (user.activity.length == 0) {
				me.userRemove(key);
				me.users[key].timing=-1;
				//$("debug_window_text").innerHTML="[S]Empty!!<br>"+$("debug_window_text").innerHTML;
			} else {
				var coord=user.activity.shift();
				
				if (user.timing<coord.t) {
					var timing=coord.t-user.timing;
				} else {
					var timing=coord.t;
				}
				user.timing=coord.t;
				
				if (coord.p) {
					redux.get(coord.p,true);
					if($("debug_window_text")) $("debug_window_text").innerHTML=coord.p+"<br>"+$("debug_window_text").innerHTML;
				}
				if (coord.m || coord.c) {
					if (coord.m) var dim=coord.m.split('.');
					if (coord.c) var dim=coord.c.split('.');
					if (user.width != me.width) {
						var twidth = parseInt(user.width)/2;
						var dwidth = parseInt(me.width)/2;
						dim[0]=parseInt(dim[0])-twidth+dwidth-5;
					}
					
					if($("debug_window_text")) $("debug_window_text").innerHTML="[S]"+user.timing+":"+dim[0]+":"+dim[1]+"<br>"+$("debug_window_text").innerHTML;
					var fx = new Fx.Styles(user.icon, {duration:timing, wait:false});    
					fx.start({'left': parseInt(dim[0]),'top': parseInt(dim[1])});
					if (coord.c) {
						var fx = new Fx.Styles(user.icon, {duration:300, wait:true}); 
						fx.start.delay(timing,fx,{width:['10px','35px'],height:['10px','35px']});
					}
				}
				this.mouseid=setTimeout('redux.invue.mouseMove()',timing);
			}
			//user.icon.innerHTML=user.activity.join(":");
		}
		//this.mouseid = window.setInterval(redux.invue.mouseMove, 500);
		//this.mouseid=setTimeout('redux.invue.mouseMove()',400);
	}
	

	o.onmousemove = function (e) {
		var _x; var _y; var o=redux.invue;
		var estart=new Date().getTime();
		
		if (!window.ie) {_x = e.pageX;_y = e.pageY;}
		if (window.ie) {
			_x = event.clientX + document.body.scrollLeft;
			_y = event.clientY + document.body.scrollTop;
		}
		if (estart-o.mousestart > 50) {
			o.mousex=_x; o.mousey=_y;
			o.pushPacket("m",_x+"."+_y)
			o.mousestart=estart;
		}
		return true;	
	}
	
	o.onclick = function(o) {redux.invue.pushPacket("c",redux.invue.mousex+"."+redux.invue.mousey);}
	
	o.trapFocus = function(o) {
		x1=$ES('select,input,textarea',$(o));

		$each(x1,function(o){
			if (o.name) {
				if (['submit'].contains(o.type) || ['image'].contains(o.type)) {
					if (o.getProperty('clicked') != null) {
						if (!an[o.name]) an[o.name]=[];
						fv=escape(o.value);
						o.removeProperty('clicked');
					}
					return;
				}
				if (['radio'].contains(o.type) && !o.getValue()) return;			
				if (!an[o.name]) an[o.name]=[];
				var fv=escape(o.getValue());
				if (fv) {var co=an[o.name]; co.push(fv);}
			}
		});
	}
	
	o.pushPacket = function(cmd,info) {
		var timer=(new Date().getTime()) - this.packetstart;
		redux.invue.packet.push("{t:"+timer+","+cmd+":'"+escape(info)+"'}");		
	}
	
	o.init = function () {
		if (!window.ie) document.captureEvents(Event.MOUSEMOVE);
		document.onmousemove = this.onmousemove; 
		this.pingid=setTimeout('redux.invue.ping()',4000);
		document.body.onclick = this.onclick;
		
	}
	
	o.ping = function () {
		var src = '/listener.cfm?ts=' + (new Date().getTime()) + '-' + redux.uid;
		var v=[];
		v[0]='page='+redux.bundle.name;
		v[1]='packet='+redux.invue.packetsequence+':['+redux.invue.packet.join(",")+']';
		v[2]='width='+redux.invue.getWidth();
		v[3]='query='+redux.bundle.query;
		if (redux.invue.userid) v[4]='user='+redux.invue.userid;
		redux.invue.packetsequence+=1;
		redux.invue.packetstart=new Date().getTime(); 
		redux.invue.packet=[];
		if ($("debug_window_text")) $("debug_window_text").innerHTML="[P]"+v.join("&")+"<br>"+$("debug_window_text").innerHTML;
		var myXHR = new XHR({method:'post', onSuccess: function(r){redux.invue.pingResult(Json.evaluate(r))}}).send(src,v.join("&"));
		this.pingid=setTimeout('redux.invue.ping()',4000);
	}
	o.init();
	//o.pingid=setTimeout('redux.invue.ping()',3000);
}
