//#require /script/csiCom/global/common.js
//#require /script/csiCom/external/jquery.min.js

// prototype-ish stuff
if(typeof($)=="undefined"){
	eval("function $(id){return document.getElementById(id);}");
}

function $$(arg){
  // helper for jquery
  // created as a hack for the coordinator
  // you can pass the following:
  // a node
  // an ID
  // an object with a .target attribute (e.g. event)
  // an existing jQuery (will be returned)
  // returns a jQuery for the referenced node
  if(arg){
    if(arg.target) return $(arg.target);
    if(arg.nodeName) return $(arg);
    if(arg instanceof jQuery) return arg;
    // assume string ID
    return $("#" + arg);
  }
  else{
    return null;
  }
}


var dom=new Object();

dom.isIE = window.ActiveXObject ? true : false; // ActiveX is only used in Internet Explorer
dom.isFirefox=(window.navigator.userAgent.indexOf("Firefox")>-1);
dom.isMac=(window.navigator.userAgent.indexOf("Macintosh")>-1);

dom.isDomNode = function(arg){
	return(arg && arg.nodeName && arg.nodeType);
	
}

dom.getWindowInfo = function(){
	var win = arguments[0] ? arguments[0] : window;
	var obj = {window:{height:0,width:0}, document:{height:0,width:0}, scroll:{x:0,y:0}};
	
	if(!win ||!win.document || !win.document.body)return obj;
	
	/// WINDOW SIZE AND DOCUMENT SIZE
	if(win.document.compatMode && win.document.compatMode != "BackCompat"){
		// IE XHTML mode
		//debug.comment("XHTML MODE");
		
		var de = win.document.documentElement;
		obj.window.height = de.clientHeight;
		obj.window.width = de.clientWidth;
		
		obj.document.height = win.document.body.clientHeight;
		obj.document.width = win.document.body.clientWidth;
	}
	else if(window.innerHeight){
		// Mozilla
		obj.window.height = win.innerHeight;
		obj.window.width = win.innerWidth;
		
		var de=win.document.documentElement;
		obj.document.height = de.clientHeight;
		obj.document.width = de.clientWidth;
	}
	else{
		// IE HTML mode
		obj.window.height = win.document.body.clientHeight;
		obj.window.width = win.document.body.clientWidth;
		
		obj.document.height = win.document.body.offsetHeight;
		obj.document.width = win.document.body.offsetWidth;
	}

	// SCROLLING
	if( typeof( win.pageYOffset ) == 'number' ) {
		//debug.print("netscape");
		//Netscape compliant
		obj.scroll.y = win.pageYOffset;
		obj.scroll.x = win.pageXOffset;
	} 
	else if( win.document.body && ( win.document.body.scrollLeft || win.document.body.scrollTop ) ) {
		//DOM compliant
		//debug.print("DOM");
		obj.scroll.y = win.document.body.scrollTop;
		obj.scroll.x = win.document.body.scrollLeft;
	} 
	else if( win.document.documentElement && ( win.document.documentElement.scrollLeft || win.document.documentElement.scrollTop ) ) {
		//IE6 standards compliant mode
		//debug.print("IE6");
		obj.scroll.y = win.document.documentElement.scrollTop;
		obj.scroll.x = win.document.documentElement.scrollLeft;
	}
	
	if(!obj.scroll.y) obj.scroll.y = 0;
	if(!obj.scroll.x) obj.scroll.x = 0;
	
	return obj;
}

// DEPRECATED -- use dom.getWindowInfo()
dom.getWindowSize=function(){
	var obj={};
	if(document.compatMode && document.compatMode != "BackCompat"){
		// IE XHTML mode
		//debug.comment("XHTML MODE");
		
		var de=document.documentElement;
		obj.clientHeight=de.clientHeight;
		obj.clientWidth = de.clientWidth;
	}
	else if(window.innerHeight){
		// Mozilla
		obj.clientHeight=window.innerHeight;
		obj.clientWidth = window.innerWidth;
	}
	else{
		// IE HTML mode
		obj.clientHeight=document.body.clientHeight;
		obj.clientWidth = document.body.clientWidth;
	}
	return obj;
}

// DEPRECATED -- use dom.getWindowInfo()
dom.getDocumentSize=function(){
	var obj={};
	
	if(document.compatMode && document.compatMode != "BackCompat"){
		// IE XHTML mode
		//debug.comment("XHTML MODE");
		obj.documentHeight=document.body.clientHeight;
		obj.documentWidth = document.body.clientWidth;
	}
	else if(window.innerHeight){
		// Mozilla
		//debug.comment("Mozilla MODE");
		var de=document.documentElement;
		obj.documentHeight=de.clientHeight;
		obj.documentWidth = de.clientWidth;
	}
	else {
		obj.documentHeight=document.body.offsetHeight;
		obj.documentWidth = document.body.offsetWidth;
	}
	return obj;
}

// DEPRECATED -- use dom.getWindowInfo()
dom.getScrolling = function(){
	var obj = {};
	
	if( typeof( window.pageYOffset ) == 'number' ) {
		//Netscape compliant
		obj.y = window.pageYOffset;
		obj.x = window.pageXOffset;
	} else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
		//DOM compliant
		obj.y = document.body.scrollTop;
		obj.x = document.body.scrollLeft;
	} else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
		//IE6 standards compliant mode
		obj.y = document.documentElement.scrollTop;
		obj.x = document.documentElement.scrollLeft;
	}
	
	if(!obj.y) obj.y = 0;
	if(!obj.x) obj.x = 0;
	
	return obj;
}


dom.scrollTo = function(el, arg) {
	//find the first parent element with overflow-x/-y set to scroll
	var n;
	n = dom.ascendTo(el, function(e) {
		var ox = dom.getStyle(e,"overflowX");
		var oy = dom.getStyle(e,"overflowY"); 
		return ox == "scroll" || oy == "scroll"; 
				
		//var s = getComputedStyle(e, "");
		//return s.overflowX == "scroll" || s.overflowY == "scroll";
	});
	//debug.comment(n);
	var s = getComputeStyle(document.body, "");
	//debug.comment(s.overflowX, s.overflowY);
}


dom.scrollToTop = function(el){
	if(!el){
		window.scrollTo(0,0);
	}
	else{
		var p = dom.getPosition(el);
		window.scrollTo(0, p.top);
	}
}

/*
argument object
	node: the node to scroll into view
	topMargin: 
	bottomMargin:
	(topMargin and bottomMargin are to allow for fixed content)
	
	// modified 1/12/10: only scrolls in the vertical direction (temporarily)
*/
dom.scrollIntoView = function(arg){
	if(arg.parentNode) {
		arg = {node:arg, topMargin:0};
	}
	var node = arg.node;
	var pNode = dom.getPosition(node);

	var root;
	root = dom.ascendTo(node, function(e) {
		var ox = dom.getStyle(e,"overflowX");
		var oy = dom.getStyle(e,"overflowY"); 
		return ox == "scroll" || oy == "scroll" || ox == "auto" || oy == "auto"; 
	});
	var pRoot = dom.getPosition(root);

	var wi = dom.getWindowInfo();
	
	//console.log("sitoview",pNode,pRoot,wi);
	
	var tm = arg.topMargin ? arg.topMargin : 0; // top margin
	var bm = arg.bottomMargin ? arg.bottomMargin : 0; // bottom margin
	var sh = wi.scroll.y; // amount window is scrolled
	var wh = wi.window.height; // height of the window (we have to stay inside here)
	var rt = pRoot.top; // top of the scrolled element
	var rh = pRoot.height; // height of the scrolled element
	var nt = pNode.top; // current top of the target node
	var nh = pNode.height; // height of the target node
	
	
	
	if((nt - sh) > tm){
		//debug.comment("top of node is visible.");
		// so check the bottom
		//debug.comment(nt, nh, sh, wh, bm, (nt + nh) - sh, wh - bm);
		// if node bottom (nt + nh) is below window bottom (wh - bm), considering scroll (sh):
		if((nt + nh) - sh > wh - bm){
			//debug.comment("bottom is not visible");
			
			var scr = Math.max(0, (nh + nt) - (wh - bm));
			var ascr = Math.max(0,nt-tm); // the amount we would need to scroll to make the top visible
			//debug.comment(scr, ascr);
			root.scrollTop = Math.min(scr, ascr); // scroll up, but do not scroll off the top
		}
		else{
			// do nothing
		}
	}
	else{
		//debug.comment("top is scrolled off the top of the screen, so bring it back");
		//debug.comment(sh, tm, nt, nt-tm);
		root.scrollTop = Math.max(0,nt-tm);
	}
	
	/*
	
	//t:  how far the top edge of the node is below the top edge of the root
	//b:  how far the bottom edge of the node is below the bottom edge of the root
	var t = pNode.top - pRoot.top - root.scrollTop;
	var b = (pNode.top - pRoot.top + pNode.height) - pRoot.height - root.scrollTop;

		
	//if the node is already visible
	if(t > 0 && b < 0) {
		//do nothing
	}
	//if the node + margins is taller than the root
	else if(pNode.height + 2*arg.margin > pRoot.height) {
		root.scrollTop = root.scrollTop + t - arg.margin; //top visible
	}
	else {
		root.scrollTop = root.scrollTop + b + arg.margin; //bottom visible
	}
	*/
	
}

dom.getPosition = function(el){
	//console.log("dom.getPosition",el);
	var lx = 0;
	var ly = 0;
	var sx = 0;
	var sy = 0;
	var p = {
		width:el.offsetWidth,
		height:el.offsetHeight
	};
	var inFixed = false;
	var inAbsolute = false;
	
	//debug.comment("getPosition");
	while(el != null){
		//debug.comment(el,el.id,el.className,el.style.position,"left="+el.offsetLeft,"top="+el.offsetTop);
		//console.log(el,dom.getStyle(el,"position"), el.offsetTop);
		var np = dom.getStyle(el,"position");
		if(!inFixed)inFixed = (np == "fixed");
		if(!inAbsolute)inAbsolute = (np == "absolute");
		lx += el.offsetLeft;
		ly += el.offsetTop;
		sx += el.scrollLeft;
		sy += el.scrollTop;
		el = el.offsetParent;
	}
	p.left = lx;
	p.top = ly;
	p.right = lx + p.width;
	p.bottom = ly + p.height;
	
	p.netScrollTop = sy;
	p.netScrollLeft = sx;
	
	p.inFixed = inFixed;
	p.inAbsolute = inAbsolute;
	
	return p;
}


//gets the position of the element relative to the first absolutely positioned element above it
dom.getRelativePosition = function(el) {
	//returns the x,y position of the object
	//alert("dom.getOffset");
	var lx = 0;
	var ly = 0;
	var p = {
		width:el.offsetWidth,
		height:el.offsetHeight
	};
	
	while(el != null){
		//debug.comment("left="+lx+" top="+ly);
		lx += el.offsetLeft;
		ly += el.offsetTop;
		
		var st = dom.getStyle(el,"position");
		if(st && (st == "absolute" || st == "relative")) break;
		
		//var st = getComputedStyle(el, "");
		//if(st && (st.position == "absolute" || st.position == "relative")) break;
		
		el = el.offsetParent;
	}
	p.left = lx;
	p.top = ly;
	p.right = lx + p.width;
	p.bottom = ly + p.height;
	
	return p;
}

////////////////////////////////////////////////////////
//
//	DOM MANIPULATION
//	
//	addClassName, removeClassName, hasClassName
//
//
//
////////////////////////////////////////////////////////
dom.addClassName = function(el,name){
	if(el && !dom.hasClassName(el,name)){
		el.className += " " + name;
	}
}
dom.removeClassName = function(el,name){
	if(el){
		var re = new RegExp("\\s" + name + "(?=\\s)","g");
		//alert(re);
		var s = " " + el.className + " ";
		//alert(re.exec(s));
	
		el.className = s.replace(re," ");
	}
}
dom.hasClassName = function(el, name) {
	//console.log("dom.hasClassName",el, name);
	return (el && (" " + el.className + " ").indexOf(" " + name + " ") > -1);
}


// adapted from: 
// http://www.robertnyman.com/2006/04/24/get-the-rendered-style-of-an-element/
dom.getStyle = function(el,rule){
	var s = "";
	if(document.defaultView && document.defaultView.getComputedStyle){
		s = document.defaultView.getComputedStyle(el, "")[rule]; //.getPropertyValue(rule);
	}
	else if(el.currentStyle){
		rule = rule.replace(/\-(\w)/g, function (strMatch, p1){
			return p1.toUpperCase();
		});
		s = el.currentStyle[rule];
	}
	return s;
}




////////////////////////////////////////////////////////
//
//	DOM INVESTIGATION AND NAVIGATION
//	
//	isPartOf(node,parentNode): returns true if node is a child of parentNode
//	getChildIndex(node): returns the index in the parentNode's collection
//
//
//	NAVIGATION
//	ascendTo(el,f) climb the tree, testing nodes until f(node)==true
//	search(el,f,immdeiateOnly) searches childnodes (recursively by default). returns array of matches.
//  traverse(el,f,reverse) searches (forward by default) through the dom tree for a node matching f(node).
//  traverseAll(el,f,reverse) similar to traverse, but returns an array of all matches
//		example: var arr=dom.traverse(<tablenode>,function(n){return n.nodeName=="TR" && n.className=="myClass"});
//	
//
//  DEPRECATED VERSIONS FOR LAZY TYPISTS
//	ascendToTagName(el,tagName): ascends from el to the given tagName (or returns el if it matches)
//
//	ascendToTagNameWithClassName(el,tagName,className): same as above, but className must also match
//
//	ascendToTagNameWithAttribute(el,tagName,attrName,attrValue): 
//		same idea, but looks for attrName==attrValue.
//		if attrValue is not provided, then simply looks for a node having attrName
//
//
//
////////////////////////////////////////////////////////
dom.isPartOf=function(node,arg){
	var el=node;
	//debug.comment("isPartOf",node,arg);
	if(typeof(arg)=="function"){
		el=dom.ascendTo(node,arg);
		return(el!=null);
	}
	else{
		while(el && el!=arg && el.parentNode){
			el=el.parentNode;
		}
		return(el==arg);
	}	
}
//dom.getChildIndex: returns index of the child in its parents childNodes collection
dom.getChildIndex=function(node){
	var count=0;
	var el=node;
	while(el.previousSibling){
		count++;
		el=el.previousSibling;
	}
	return count;
}




dom.ascendTo=function(el,f){
	while(el && el.nodeName!="HTML" && !f(el)){
			el=el.parentNode;
	}
	if(el && el.tagName!="HTML"){
		return el;
	}
	else{
		return null;
	}
}
dom.search=function(el,testFunction,immediateChildrenOnly){
	//debug.comment(testFunction);
	var res=[];
	var arr;
	if( immediateChildrenOnly ){
		arr=el.childNodes;
	}
	else{
		arr=el.getElementsByTagName("*");
	}
	for(var i=0;i<arr.length;i++){
		//debug.comment(arr[i], testFunction(arr[i]));
		if(testFunction(arr[i]))res.push(arr[i]);
	}
	return res;
}
dom.findFirst = function(el,testFunction,immediateChildrenOnly){
	var arr;
	if( immediateChildrenOnly ){
		arr=el.childNodes;
	}
	else{
		arr=el.getElementsByTagName("*");
	}
	for(var i=0;i<arr.length;i++){
		//debug.comment(arr[i], testFunction(arr[i]));
		if(testFunction(arr[i])) return arr[i];
	}
	return null;
}

dom.traverse = function(el,f,r){
	if(!el)return null;
	
	var arr = document.body.getElementsByTagName("*");
	var ix_el;
	for(var i = 0; i < arr.length; i++) {
		if(arr[i] == el) {
			ix_el = i;
			break;
		}
	}
	
	if(ix_el) {
		if(r){
			//reverse
			for(i = ix_el; i > -1; i--) {
				if(f(arr[i])) return arr[i];
			}
		}
		else{
			//forward
			for(var i = ix_el; i < arr.length; i++) {
				if(f(arr[i])) return arr[i];
			}
		}
	}
	return null;
}
dom.traverseAll=function(el,f,r){
	// similar to traverse, but returns an array of all matches
	var res=[];
	if(!el)return res;
	
	var arr = document.body.getElementsByTagName("*");
	
	var ix_el;
	for(var i=0; i<arr.length; i++) {
		if(arr[i] == el) {
			ix_el = i;
			break;
		}
	}
	
	if(ix_el) {
		if(r){
			//reverse
			for(i=ix_el; i>-1; i--) {
				if(f(arr[i])) res.push(arr[i]);
			}
		}
		else{
			//forward
			for(var i=ix_el; i<arr.length; i++) {
				if(f(arr[i])) res.push(arr[i]);
			}
		}
	}
	return res;
}

dom.removeEmptyTextNodes = function(el){
	$(el).contents().filter(function() {
		return this.nodeType == 3;
	}).remove();
}







/* these versions are deprecated, but used everywhere, so probably will never go away */
/* but the ascendTo, search, and traverse functions are cleaner and more versatile */
dom.ascendToTagName = function(el,tagName){
	if(!el)return null;
	var tn = tagName.toLowerCase();
	while(el && el.nodeName.toLowerCase() != tn && el.nodeName.toLowerCase() != "html"){
		el = el.parentNode;
	}
	if(el && el.nodeName.toLowerCase() == tn){
		return el;
	}
	else{
		return null;
	}
}
dom.ascendToTagNameWithClassName=function(el,tagName,className){
	if(!el)return null;
	var tn=tagName.toLowerCase();
	var re=new RegExp("(^|\\s)"+className+"(\\s|$)");
	while(el && el.tagName.toLowerCase()!="html"){
		if(el.tagName.toLowerCase()==tn && re.test(el.className)){
				return el;
		}
		el=el.parentNode;
	}
	return null;
}
dom.ascendToTagNameWithAttribute=function(el,tagName,attrName,attrValue){
	if(!el) return null;
	
	var tn=tagName.toLowerCase();
	var attr;
	while(el && el.tagName.toLowerCase()!="html"){
		if(el.tagName.toLowerCase()==tn){
			attr=el.getAttribute(attrName);
			if(attr!=null && (typeof attrValue =="undefined" || attr==attrValue)) return el;
		}
		el=el.parentNode;
	}
	return null;
}


//dom.getElementsByClassName=function(className){
	// todo
	// prototype has this already!
//}

//Returns an array of the elements between el1 and el2
//If inlcude is true, then el1 and el2 will be inlcuded in the array
dom.getElementsBetween = function(el1, el2, include) {
	var targets = new Array();
	//the elements don't have the same parent...
	if(el1.parentNode != el2.parentNode) {
		return false;
	}
	//the elements are the same...
	else if(el1 == el2) {
		if(include) targets.push(el1);
	}
	else {
		var els = $A(el1.parentNode.childNodes);
		
		var target = false;
		els.each(function(el) {
			if(el == el1 || el == el2) target = !target;
			if(target) targets.push(el);
		});
		
		if(include) {
			if(targets[0] == el1) targets.push(el2);
			if(targets[0] == el2) targets.push(el1);
		}
		else {
			targets.splice(0, 1);
		}
	}
	return targets;
}

dom.elementAfter = function(el, target) {
	var r = new Array();
	if(el.parentNode != target.parentNode || el == target) {
		return false;
	}
	else {
		var els = $A(el.parentNode.childNodes);
		els.each(function(ell) {
			if(ell == el) r.push(ell);
			if(ell == target) r.push(ell);
		});
	}
	if(r[0] == target && r[1] == el) return true;
	else return false;
}

dom.elementBefore = function(el, target) {
	var r = new Array();
	if(el.parentNode != target.parentNode || el == target) {
		return false;
	}
	else {
		var els = $A(el.parentNode.childNodes);
		els.each(function(ell) {
			if(ell == el) r.push(ell);
			if(ell == target) r.push(ell);
		});
	}
	if(r[0] == el && r[1] == target) return true;
	else return false;
}


dom.prepend = function(el,html){
	var d = document.createElement("div");
	d.innerHTML = html;
	var n = d.childNodes.length;
	for(var i = n - 1; i > -1; i --){
		//alert(d.childNodes[i]);
		el.insertBefore(d.childNodes[i],el.childNodes[0]);
	}
	delete d;
}

dom.append = function(el,html){
	var d = document.createElement("div");
	d.innerHTML = html;
	var n = d.childNodes.length;
	for(var i = 0; i < n; i ++){
		//alert(d.childNodes[i]);
		el.appendChild(d.childNodes[0]);
	}
	delete d;
}

dom.insertAfter = function(node, target) {
	//debug.comment(node, target, target.parent, target.parentNode);
	
	if(!node || !target || !target.parentNode) return false;
	var parent = target.parentNode;
	//debug.comment("dom.insertAfter");
	if(target.nextSibling) parent.insertBefore(node, target.nextSibling);
	else parent.appendChild(node);
}

dom.removeNode = function(node) {
	if(!node || !node.parentNode) return false;
	node.parentNode.removeChild(node);
}
dom.swapNodes = function (node1,node2) {
	var ns = node1.nextSibling;
	while(ns && ns.nodeType==3)ns=ns.nextSibling;
	var parentNode = node1.parentNode;
	node2.parentNode.replaceChild(node1,node2);
	parentNode.insertBefore(node2, ns);
}




////////////////////////////////////////////////////////
//
//	STYLING
//
//
////////////////////////////////////////////////////////
dom.userSelectNone = function(el){
	if(el){
		var st = el.style;
		if(st){
			//debug.comment(st.userSelect,st.MozUserSelect,st.webkitUserSelect);
			if(typeof(st.userSelect) != "undefined"){
				st.userSelect = "none";
			}
			else if(typeof(st.MozUserSelect) != "undefined"){
				st.MozUserSelect = "none";
			}
			else if(typeof(st.webkitUserSelect) != "undefined"){
				st.webkitUserSelect = "none";
			}
		}
	}
}
dom.userSelectNormal = function(el){
	if(el){
		var st = el.style;
		if(st){
			//console.log(st.userSelect,st.MozUserSelect,st.webkitUserSelect);
			if(typeof(st.userSelect) != "undefined"){
				st.userSelect = "text";
			}
			else if(typeof(st.MozUserSelect) != "undefined"){
				st.MozUserSelect = "text";
			}
			else if(typeof(st.webkitUserSelect) != "undefined"){
				st.webkitUserSelect = "text";
			}
		}
	}
}






////////////////////////////////////////////////////////
//
//	EVENTS
//
//
//	getEventData: returns a friendly event data object
//
//	addEvent
//	removeEvent
//
//
////////////////////////////////////////////////////////
dom.getEventData=function(e){
	var obj={};
	if(!e)e=window.event;
	if(e){
		obj.type=e.type;
		obj.keyCode=(e.keyCode)?e.keyCode:e.which;
		obj.srcElement=(e.srcElement)?e.srcElement:e.target;
		obj.toElement=(e.relatedTarget)?e.relatedTarget:e.toElement;
		obj.clientX=e.clientX;
		obj.clientY=e.clientY;
		obj.which=e.which;
		obj.ctrlKey=e.ctrlKey;
		obj.shiftKey=e.shiftKey;
	}
	return obj;
}
dom.getExtEventData = dom.getExtendedEventData = function(e){
	var obj = dom.getEventData(e);

	var el = obj.srcElement;
	el = dom.ascendTo(el,function(e){return e.name || e.getAttribute("name")});
	
	if(el){
		var c = obj.namedNode = {};
		c.node = el;
		c.name = el.name?el.name:el.getAttribute("name");
		c.mode = el.getAttribute("mode");
	}
	else{
		obj.namedNode = {};
	}
	return obj;
}

dom.addEvent = function(el,eventType,fn){
	// based on code found in Sitepoint's Modern Web Design and attributed to Scott Andrew
	// modified by cyberCSI
	//alert("dom.addEventListener");
	if(el){
		if(el.addEventListener){
			//console.log("addEventListener",el,eventType,fn);
			el.addEventListener(eventType,fn,false);
			//alert(el);
			return true;
		}
		else if (el.attachEvent){
			//alert("attaching event");
			//alert(el);
		//	alert(eventType);
			var r = el.attachEvent('on'+eventType,fn);
			//alert(r);
			return r;
		}
		else{
			el['on' + eventType] = fn;
		}
	}
}
dom.removeEvent = function( el, eventType, fn ) {
	if(el){
		if ( el.removeEventListener ) {
			//console.log("removeEventListener",el,eventType,fn);
			el.removeEventListener( eventType, fn, false );
		} else {
			el.detachEvent( 'on' + eventType, fn);
		}
	}
}


/*

dom.addEvent=function( obj, type, fn ) {
	//alert("dom.addEvent");
	//alert(obj);
	//alert(obj[type]);
	//alert(obj["on"+type]);
	
	
	if ( obj.addEventListener ) {
		obj.addEventListener( type, fn, false );
		//	alert(obj);
	//alert(obj[type]);
	//alert(obj["on"+type]);
	} else {
		//
		if ( "clickmouseovermousedownmouseupmouseout".indexOf(type.toLowerCase()) > -1 ) {
			// add a mouseenter and mouseleave to record the currenttarget
			addEvent(obj,'mouseenter',function (e) {
				this.currTarg = e.srcElement;
			});
			addEvent(obj,'mouseleave',function (e) {
				this.currTarg = e.toElement;
			});
		}
		//
		obj['e'+type+fn] = fn;
		obj[type+fn] = function(){
			var e = window.event;
			if ( "clickmouseovermousedownmouseupmouseout".indexOf(e.type) > -1 ) {
				e.currentTarget =  (e.currentTarget) ? e.currentTarget : obj.currTarg;
			}
			obj['e'+type+fn](e);
		}
		obj.attachEvent( 'on'+type, obj[type+fn] );
	}
}
dom.removeEvent=function( obj, type, fn ) {
	if ( obj.removeEventListener ) {
		obj.removeEventListener( type, fn, false );
	} else {
		obj.detachEvent( 'on'+type, obj[type+fn] );
	}
}
*/

////////////////////////////////////////////////////////
//
//  cursor location
//	monitors cursor location for all to see and use!
//
////////////////////////////////////////////////////////

dom.clientX = 0;
dom.clientY = 0;
dom._updateMouseLocation = function(e){
	var evt = dom.getEventData(e);
	dom.clientX = e.clientX;
	dom.clientY = e.clientY;
}
dom.addEvent(window,"mousemove",dom._updateMouseLocation);

/*
dom._recordActiveElement = function() {
//if (typeof dom.activeElement == "undefined")
dom.addEvent(document, "focus", function(event) {
	dom.activeElement = (event.target.nodeType == Node.TEXT_NODE) ? event.target.parentNode : event.target;
}, false);
}
dom.addEvent(window, "load", dom._recordActiveElement);
*/
dom.parseException=function(e){
	var m;
		
	if(typeof(e)=="object"){
		if(e.description){
			m=e.description;
		}
		else{
			m=e.message;
		}
			//m=e.toString();
	}
		else{
			m=e;
	}
	return m;
}



////////////////////////////////////////////////////////
//
// PARSE LOCATION (url)
//
////////////////////////////////////////////////////////
dom.parseUrl=function(url){
    var re=/^((http|ftp):\/)?\/?([^:\/\s]+)((\/\w+)*\/)([\w\-\.]+\.[^#?\s]+)(#[\w\-]+)?$/;

    if (url.match(re)) {
        return  {
				url: RegExp['$&'],
                protocol: RegExp.$2,
                host:RegExp.$3,
                path:RegExp.$4,
                file:RegExp.$6,
                hash:RegExp.$7
				};
    }
    else {
        return  {url:"", protocol:"",host:"",path:"",file:"",hash:""};
    }
}

dom.parseRootName=function(obj){
	var path;
	if(typeof(obj)=="string"){ path=obj }
	else if(obj && obj.pathname){ path=obj.pathname }
	else{ path="" }
	
	//console.log(path); 
	
	var re=/^\/(\w+)/;

    if (path.match(re)) {
		return RegExp.$1;
    }
    else {
        return "";
    }
}
dom.parsePageName=function(obj){
	var path;
	if(typeof(obj)=="string"){ path=obj }
	else if(obj && obj.pathname){ path=obj.pathname }
	else{ path="" }
	
	//alert(window.location);
	//alert(path);
	
	//console.log(path); 
	var s = [];
	for(var i = 0; i < path.length; i ++){
		var c = path[i];
		//alert(c);
		
		if(c == "/"){
			s = [];
		}
		else{
			s.push(c);
		}
	}
	//alert(s.join(""));
	return s.join("");
	
	/*
	var re=/^\/(\w+)/;

    if (path.match(re)) {
		return RegExp.$1;
    }
    else {
        return "";
    }
    */
}


////////////////////////////////////////////////////////
//
//	COOKIE CUTTERS
//	based on code found here: 
//	http://www.netspade.com/articles/javascript/cookies.xml
//
////////////////////////////////////////////////////////

/**
 * Sets a Cookie with the given name and value.
 *
 * name       Name of the cookie
 * value      Value of the cookie
 * [expires]  Expiration date of the cookie (default: end of current session)
 * [path]     Path where the cookie is valid (default: path of calling document)
 * [domain]   Domain where the cookie is valid
 *              (default: domain of calling document)
 * [secure]   Boolean value indicating if the cookie transmission requires a
 *              secure transmission
 */
dom.setCookie=function(name, value, expires, path, domain, secure)
{
    document.cookie= name + "=" + escape(value) +
        ((expires) ? "; expires=" + expires.toGMTString() : "") +
        ((path) ? "; path=" + path : "") +
        ((domain) ? "; domain=" + domain : "") +
        ((secure) ? "; secure" : "");
}

/**
 * Gets the value of the specified cookie.
 *
 * name  Name of the desired cookie.
 *
 * Returns a string containing value of specified cookie,
 *   or null if cookie does not exist.
 */
dom.getCookie=function(name)
{
    var dc = document.cookie;
	if(!dc && document && document.documentElement)dc=document.documentElement.cookie;
	if(!dc)return null;
	
	var prefix = name + "=";
	var begin = dc.indexOf("; " + prefix);
	if (begin == -1)
	{
		begin = dc.indexOf(prefix);
		if (begin != 0) return null;
	}
	else
	{
		begin += 2;
	}
	var end = document.cookie.indexOf(";", begin);
	if (end == -1)
	{
		end = dc.length;
	}
	return unescape(dc.substring(begin + prefix.length, end));
	
}

/**
 * Deletes the specified cookie.
 *
 * name      name of the cookie
 * [path]    path of the cookie (must be same as path used to create cookie)
 * [domain]  domain of the cookie (must be same as domain used to create cookie)
 */
dom.deleteCookie=function(name, path, domain)
{
    if (dom.getCookie(name))
    {
        document.cookie = name + "=" + 
            ((path) ? "; path=" + path : "") +
            ((domain) ? "; domain=" + domain : "") +
            "; expires=Thu, 01-Jan-70 00:00:01 GMT";
    }
}





////////////////////////////////////////////////////////
//
//	QUERY STRING FUNCTIONS 
//	based on code found here: 
//	http://www.netspade.com/articles/javascript/cookies.xml
//
////////////////////////////////////////////////////////

//gets an array of all keys
dom.getQueryStringKeys=function(){
	if(!dom._qs)dom.init_qs();
	var arr=new Array();
	for(var n in dom._qs){
		arr.push(n);
	}
	return arr;
}
//gets a specific value for a given key
dom.getQueryStringValue=function(key){
	if(!dom._qs)dom.init_qs();
	if(dom._qs[key]){
		return unescape(dom._qs[key]);
	}
	else{
		return null;
	}
	
}
//private -- initialize key-value collection
dom.init_qs=function(){
	dom._qs=new Object();
	var q=window.location.search;
	//alert(q);
	if(q&&q.length>1)q=q.substring(1,q.length);
	if(q&&q.length>1){
		var arr=q.split("&");
		var n,v,t,s;
		for(var i=0;i<arr.length;i++){
			s=arr[i].split("=");
			n=s[0];
			v=(s.length>1)?s[1]:"";
			dom._qs[n]=v;
		}
	}
}


////////////////////////////////////////////////////////
//
//	CLIPBOARD SUPPORT
//	SEMI-SUPPORT FOR CLIPBOARD OPERATIONS
//
//	currently Prototyping this in the notes table in 
//  AimObjectUI5
//
////////////////////////////////////////////////////////



/*
dom.setupClip=function(node,data){
	if(dom._clipNode==node)return false;
	
	if(dom._clipNode && dom._clipNode!=node){
		dom.removeClassName(dom._clipNode,"copying");
	}
	
	dom.addClassName(node,"copying");
	dom._clipNode=node;
	if(typeof(data)=="undefined")data=node.innerHTML;
	if(data)data=data.toCrLf();
	
	var pos=dom.getPosition(node);
	var ta=dom._clipTa;
	if(!ta){
		ta=dom._clipTa=document.createElement("textarea");
		dom.addEvent(ta,"mousedown",dom._beginClip);
	}
	ta.value=data?data:node.innerHTML.toCrLf();
	var st=ta.style;
	st.opacity=0; //.5;
	st.position="absolute";
	st.border="none";
	st.overflow="hidden";
	st.padding=node.style.padding;
	st.top=(pos.top)+"px";
	st.left=pos.left+"px";
	st.width=(pos.width)+"px";
	st.height=(pos.height)+"px";

	document.body.appendChild(ta);
	ta.select();

}
dom._beginClip=function(e){
	var evt=dom.getEventData(e);
	if(e.which!=3){
		dom._clipTa.style.left="-1500px";
		if(dom._clipNode)dom._clipNode.style.backgroundColor="";
		dom._clipNode=null;
	}
	else{
		dom._beginClipAnimateCount=0;
		if(dom._beginClipAnimateInterval){
			window.clearInterval(dom._beginClipAnimateInterval);
		}
		dom._beginClipAnimateInterval=window.setInterval(dom._beginClipAnimate,20);
	}
}
dom._beginClipAnimate=function(){
	var i=(dom._beginClipAnimateCount++);
	if(i>16){
		window.clearInterval(dom._beginClipAnimateInterval);
		dom._beginClipAnimateInterval=null;
		dom._clipTa.style.left="-1500px";
		dom._clipNode.style.backgroundColor="";
		//debug.comment("animate complete",dom._clipTa.style.left);
		return false;
	}
	var h="0123456789ABCDEF".substring(i,i+1);
	dom._clipNode.style.backgroundColor="ff"+h;
}
*/
/*
dom.toClip=function(node,data){
	//if(dom._clipNode==node)return false;
	
	//if(dom._clipNode && dom._clipNode!=node){
	//	dom.removeClassName(dom._clipNode,"copying");
	//}
	
//	dom.addClassName(node,"copying");
	dom._clipNode=node;
	if(typeof(data)=="undefined"){
		data=node.innerHTML;
		//if(data)data=data.toCrLf();
	}

	
	var ta=dom._clipTa;
	if(!ta){
		//debug.comment("creating new");
		ta=dom._clipTa=document.createElement("textarea");
		//dom.addEvent(ta,"mousedown",dom._beginClip);
		var st=ta.style;
		st.opacity=0.5; //.5;//.5;
		st.position="absolute";
		st.border="none";
		st.overflow="hidden";
		document.body.appendChild(ta);
	}
	ta.value=data;
	var pos=dom.getPosition(node);
	var st=ta.style;
	st.padding=node.style.padding;
	st.top=pos.top+"px";
	st.left=pos.left+"px";
	st.width=pos.width+"px";
	st.height=pos.height+"px";
	ta.focus();
	ta.select();
	
	//debug.comment(ta);
	
	
	dom._clipAnimateSequence=0;
	if(dom._clipAnimateInterval){
		window.clearInterval(dom._clipAnimateInterval);
	}
	dom._clipAnimateInterval=window.setInterval(dom._clipAnimate,20);
	
			
}
dom._clipAnimate=function(){
	var i=(dom._clipAnimateSequence++);
	if(i==1){
		
	}
	if(i>16){
		window.clearInterval(dom._clipAnimateInterval);
		dom._clipAnimateInterval=null;
		//dom._clipTa.style.left="-1500px";	
		dom._clipNode.style.backgroundColor="";
		//debug.comment("animate complete",dom._clipTa.style.left);
		dom._clipTa.style.top="500px";
		return false;
	}
	var h="0123456789ABCDEF".substring(i,i+1);
	dom._clipNode.style.backgroundColor="ff"+h;
}
*/
/*
dom.toClip=function(el,data){
	var node=dom._clipNode=el;
	var pos=dom.getPosition(node);

	var ta=dom._toClipTa;
	if(!ta)ta=dom._toClipTa=document.createElement("textarea");
	ta.value=data?data:node.innerHTML.toCrLf();
	var st=ta.style;
	st.opacity=0; //1.0;
	st.position="absolute";
	st.border="none";
	st.overflow="hidden";
	st.padding=node.style.padding;
	st.top=(pos.top)+"px";
	st.left=pos.left+"px";
	st.width=(pos.width)+"px";
	st.height=(pos.height)+"px";

	document.body.appendChild(ta);
	ta.select();
	
	dom._toClipCount=0;
	dom._toClipInterval=window.setInterval(dom.toClipAnimate,20);
}


*/
