/* JS Tag functions Copyright (c) Flirtomatic 2008 */
function importTags(scopeObj, tagArray) {
	scopeObj.isArray = function (o) {
		return o!=null && o!=undefined && o.constructor==Array ;
	}

/** "tags" **/	
	scopeObj.tags = {
		document:document,
		
		isIE: (window && window.navigator && window.navigator.userAgent && window.navigator.userAgent.toLowerCase().indexOf('msie')>=0),
		isWebkit: (window && window.navigator && window.navigator.userAgent && window.navigator.userAgent.toLowerCase().indexOf('webkit')>=0),		// Chrome, Safari
		isOpera: (window && window.navigator && window.navigator.userAgent && window.navigator.userAgent.toLowerCase().indexOf('opera')>=0),
		isFirefox: (window && window.navigator && window.navigator.userAgent && window.navigator.userAgent.toLowerCase().indexOf('firefox')>=0),
		isGecko: (window && window.navigator && window.navigator.userAgent && window.navigator.userAgent.toLowerCase().indexOf('gecko')>=0),

		getInnerText: function(e) { return e.innerText || e.textContent},
		
		ID:function(id) {
			return scopeObj.tags.document.getElementById(id) ;
		},
		
		E: function(elem, attributes) {
			if (elem && attributes) {
				for (var key in attributes) {
					/* "inherits" is a special attribute that means treat the value as further attributes (like an include). 
					 * It's typically used to add in a whole load of properties such as inherits:MyFunctions, or 
					 * inherits:[ListInterface,titleStyle] */
					if (key=='inherits') {	
						if (scopeObj.isArray(attributes[key]))
							for (var n=0; n<attributes[key].length; n++)
								arguments.callee(elem,attributes[key][n]) ;
						else
							arguments.callee(elem,attributes[key]) ;
					} else {
						var keys = key.split(/[.$]/);	// "." is the "normal" key separator, as in "style.color", but requires quoting, so we accept $ in its place
						if(keys.length >  1) {
							if (scopeObj.tags.isIE && keys[0]=='style' && keys[1]=='opacity') {
								if (Number(attributes[key])>=1) {
									elem.style.filter =  '';
								} else {
									elem.style.filter =  'alpha(opacity=' + (Number(attributes[key])*100) + ')';
								}
							} else if (scopeObj.tags.isIE && keys[0]=='style' && keys[1]=='cssFloat')
								elem.style.styleFloat = attributes[key];
							else
								elem[keys[0]][keys[1]] = attributes[key];
						}  else {
							if (elem.nodeName=='INPUT' && (elem.type=='radio' || elem.type=='checkbox') && key=='checked' &&  scopeObj.tags.isIE)
								elem['defaultChecked'] = attributes[key] ;
							else	 {
// Debug - log if we're overriding								
//								if (elem[key] && elem[key] !== attributes[key])
//									console.log("Override "+elem.nodeName+" "+key+" "+elem[key].toString()+" > "+attributes[key].toString()) ;
								elem[key] = attributes[key];
								if (key=='onclick' && elem[key])
									elem.style.cursor = 'pointer' ;
							}
						}
					}
				}
			}
			return elem;
		},

		/* Find a checked element in a named set (e.g. a radio button) */
		getCheckedByName:function(name) {
			var a = scopeObj.tags.document.getElementsByName(name) ;
			for (var i=0; i<a.length; i++)
				if (a[i].checked)
					return a[i] ;
			return null ;
		},
		
		/* Executes the named attribute for the specified node and all its children. 
			If (!node), body is used and the entire DOM is checked  for the named attribute and re-evaluated.
			Use mark-up constructs such as <img onDayChange="this.src=getImgSrc(this)"> coupled
			with js calls to updateElements("onDayChange") ;*/		
		updateElements:function(attrName, node) {
		      if(!node) node = scopeObj.tags.document.body;
		      var a = node.getElementsByTagName("*") ;
		      for (var i=0; i<a.length; i++) if (a[i] && a[i].nodeName) {
			      var showtime = a[i].getAttribute(attrName) ;
			      if (showtime) {
			    	  var fn ;
				      if (typeof showtime=="function")
				    	 fn = showtime ;
				      else
					      fn = new Function(showtime.toString()) ;
				      fn.apply(a[i]) ;
			      }
			 }
		},
		
		removeChildren:function(elem) {
			if (!elem.nodeName) elem = scopeObj.tags.ID(elem) ;
			while (elem.firstChild)
				elem.removeChild(elem.firstChild) ;
		},
			
		/* Replace all the children of elem with the specified child/array */
		replace:function(elem,child) {
			if (!elem.nodeName) elem = scopeObj.tags.ID(elem) ;
			scopeObj.tags.removeChildren(elem) ;
			scopeObj.tags.append(elem,child) ;
		},

		/* Replace elem with the specified child/array */
		replaceNode:function(oldChild,newChild) {
			if (!oldChild.nodeName) oldChild = scopeObj.tags.ID(oldChild) ;
			if (oldChild==newChild)
				return newChild ;
			
			if (!oldChild || !oldChild.parentNode) // Specified oldChild has no parent
				return oldChild ;

			var inserted = scopeObj.tags.append(oldChild.parentNode,newChild,oldChild) ;
			if (oldChild!=inserted) // && !inserted.isSameNode(oldChild))
				oldChild.parentNode.removeChild(oldChild) ;
			return inserted ;
		},

		/* Check if an element is part of the document's DOM */
		isOutOfBody:function(elt) {
			if (elt==null || !elt.nodeName)
				return true ; // Not an element
			return !scopeObj.tags.isChildOf(elt,scopeObj.tags.document.body) ;
		},
		
		/* Check if an element is a child of the specified superNode */
		isChildOf:function(elt,superNode) {
			if (elt==null || !elt.nodeName)
				return false ; // Not an element
			if (superNode==null || !superNode.nodeName)
				return false ; // Not an element
			if (superNode.contains)
				return superNode.contains(elt) ;
			if (elt.compareDocumentPosition)
				return (elt.compareDocumentPosition(superNode) & 8) ;
			while (elt) {
				if (!elt)
					return false ;
				if (elt==superNode)
					return true ;
				elt = elt.parentNode ;
			}
		},
		
		/* Update dynamic elements 
		 * 	updateName	- an arbitrary string used to define which elements are dynamic (see DYNAMIC or the element form {updateName:function(){ return .... }})
		 * 	id - optionally a "subtest" to discriminate between update instances - either a string/number which is treated as a sub-name of updateName, or an element
		 * 	passThruArgs - optional parameter passed through to the dynamic-element function
		 * */
		update:function(updateName,id,passThruArgs) {
			if (id && !id.nodeName) {	// If ID is not a node, use it to discriminate what to update
				updateName += "$"+id ;
				id  = null ;
			}
			
			if (scopeObj.tags.document.dynamicElements) {
				var i = 0 ;
				while (scopeObj.tags.document.dynamicElements[updateName] && i < scopeObj.tags.document.dynamicElements[updateName].length) {
					var eltFn = scopeObj.tags.document.dynamicElements[updateName][i] ;
					if (eltFn) {
						if (!id || !eltFn.node || scopeObj.tags.isChildOf(eltFn.node,id)) {
							var newNode ;
							newNode = eltFn.fn.apply(eltFn.node,passThruArgs || []) ;	// Call the function dynamic function in the form "oldElement.function(pass-thru-args)"
							if (newNode && newNode != eltFn.node) {
								eltFn.node = scopeObj.tags.replaceNode(eltFn.node,newNode) ;
							}
						}
						i++;
					}
				}
			}
		},

		dynamicElements:function(updateName,id){
			if (id && !id.nodeName) {	// If ID is not a node, use it to discriminate what to update
				updateName += "$"+id ;
			}
			return scopeObj.tags.document.dynamicElements[updateName] || []; 	
		},
		
		setDynamic:function(event,fn,id,noInvoke) {
				if (id)
					event += "$"+id ;
				if (!scopeObj.tags.document.dynamicElements)
					scopeObj.tags.document.dynamicElements = {} ;
				if (!scopeObj.tags.document.dynamicElements[event])
					scopeObj.tags.document.dynamicElements[event] = [] ;
				scopeObj.tags.document.dynamicElements[event][scopeObj.tags.document.dynamicElements[event].length] = {node:this,fn:fn} ;
				if (!noInvoke)
					fn.apply(this) ;
				return this ;
			}, 
		
		removeDynamic:function(elt,updateName,id){
			if (id)
				updateName += "$"+id ;
			if (scopeObj.tags.document.dynamicElements && scopeObj.tags.document.dynamicElements[updateName]) {
				var i = 0 ;
				while (i < scopeObj.tags.document.dynamicElements[updateName].length) {
					var eltFn = scopeObj.tags.document.dynamicElements[updateName][i] ;
					if (eltFn.node == elt) {
						// Remove from the dynamic element maps
						scopeObj.tags.document.dynamicElements[updateName].splice(i,1) ;	
						if(scopeObj.tags.document.dynamicElements[updateName].length==0){  
						 	delete scopeObj.tags.document.dynamicElements[updateName];
						 	break ;
						}
					} else i++ ;
				}
			}
		},

		validateDynamicElements:function(){
			try {
				var n = 0 ;
				var m = 0 ;
				var z = "" ;
				if (scopeObj.tags.document.dynamicElements) {
					for (var u in scopeObj.tags.document.dynamicElements) {
						var v = 0 ;
						while (v < scopeObj.tags.document.dynamicElements[u].length) {
							var eltFn = scopeObj.tags.document.dynamicElements[u][v] ;
							if (eltFn && scopeObj.tags.isOutOfBody(eltFn.node)) {
								m++ ;
								scopeObj.tags.document.dynamicElements[u][v] = null ;
								scopeObj.tags.document.dynamicElements[u].splice(v,1) ;
								delete eltFn.fn ;
								delete eltFn.node ;
								delete eltFn ;
							} else {
								n++ ;
								v++ ;
							}
						}
						if(scopeObj.tags.document.dynamicElements[u].length==0){
							z += u+" " ;  
						 	delete scopeObj.tags.document.dynamicElements[u];
						}
					}
				}
			} catch (ex) {}
		},

		/* Insert a tree of nodes into elem, before "before". If before is null, append to the end of elem
		 * Returns the first element appended or inserted 
		 */
		append:function(elem,child,before) {
			if (!elem.nodeName) elem = scopeObj.tags.ID(elem) ;
			if (child || (typeof child=="number") || (typeof child=="string"))
			{
				function insertNode(e,c,b) { // IE-friendly version of insertBefore
					b?e.insertBefore(c,b):e.appendChild(c) ;
					return c ;
				}
				
				// child is a single element
				if (child.nodeName) {	
					return insertNode(elem,child,before) ;
				} 
				
				// child is an array of children  
				if (scopeObj.isArray(child)) {
					var inserted = null ;
					for (var i in child) {
						var elt = scopeObj.tags.append(elem,child[i],before) ;
						inserted = inserted||elt ;
					}
					return inserted ;
				} 
				
				/* child is an object. There are two uses of an object at the moment:
				 * 1) where the element to be inserted is a "dynamic" element. These are of the form:
				*			{evaluationEvent:function(element){ return TAG(....dependent on evaluation event...)}}
				* 2) named members of 'this' to be created, for example
				* 			x = DIV({},{y:A('link'), z:SPAN(something)}) ;
				* 	will create a DIV named "x" with two auto-created members x.y (a A tag) and x.z (a SPAN tag).
				* In the second case, care must be taken not to name a member the same as an inbuilt member (e.g innerHTML, nodeName or similar), to set these
				* attributes use the attr() function or pass them in as the initial object to the tag building function.
				*/
				if (typeof child=='object') {
					var inserted = null ;
					for (var i in child) {
						var elt = null ;
						if (typeof child[i]=='function') {
							/* "dynamic" element content */
							var newNode = child[i].apply({nodeName:null},[elem,i]) ;
							elt = scopeObj.tags.append(elem,newNode,before) ;
							elt.setDynamic(i,child[i],null,true) ;
						}
						else { // Named element
							elt = scopeObj.tags.append(elem,child[i],before) ;
							if (elem[i] == undefined)
								elem[i] = elt ;
						}
						inserted = inserted||elt ;
					}
					return inserted ;
				} 
				
				if (child != null && child !=undefined)
				{	// child is a value
					var lines = child.toString().split("\n") ;
					var sep = null ;
					var inserted = null ;
					var elt = null ;
					
					if (scopeObj.tags.isIE) {
						/* Cannot add arbitrary properties to a text node in IE, so wrap the text nodes in a span */
						inserted = scopeObj.tags.document.createElement("span") ;
						scopeObj.tags.E(inserted,scopeObj.tags.inherit) ;
						insertNode(elem,inserted,before);
						before = undefined ;
						elem = inserted ;
					}
					
					for (var i=0; i<lines.length; i++)
					{
						if (sep) {
							elt = insertNode(elem,sep,before);
							before = sep.nextSibling ;
						}
						var textNode = scopeObj.tags.document.createTextNode(lines[i]) ;
						elt = insertNode(elem,textNode,before);
						sep = scopeObj.tags.document.createElement("br") ;
						inserted = inserted||elt ;
					}
					if (!scopeObj.tags.isIE)
						scopeObj.tags.E(inserted,scopeObj.tags.inherit) ;
					return inserted ;
				}
			}
			return null ;
		},
	
		realize:function() {
			/*if (scopeObj.tags.isIE)
			{
				var ees = scopeObj.tags.document.getElementsByTagName("INPUT") ;
				for (var i=0; i<ees.length; i++)
					if (ees[i] && ees[i]['_checked'])
						ees[i]['checked'] = true ;
			}*/
		 }
	 };
		
	scopeObj.DYNAMIC = function(updateName,fn,id) {
		var r = {} ;
		if (id) 
			r[updateName+"$"+id] = fn ;
		else
			r[updateName] = fn ;
		return r ;
	}
	
/** Menus **/
	scopeObj.menus = {
		createMenu:function(e) {
			var eltMenu = scopeObj.tags.ID("popupMenu") ;
			if (eltMenu)
				scopeObj.tags.document.body.removeChild(eltMenu) ;
			eltMenu = scopeObj.DIV({id:"popupMenu", maxLabelLength:1, className:"popupMenu" , 'style.left':scopeObj.click.x(e) , 'style.top': scopeObj.click.y(e)}) ;
			scopeObj.tags.document.body.appendChild(eltMenu) ;
	
			eltMenu.addItem = function(n,f) {
				var itm = scopeObj.DIV({innerHTML:n,
					value:n,
					className:'menuItem',
					onclick: function() { scopeObj.tags.document.body.removeChild(this.parentNode) ; if (f) f(this.parentNode.value,this) ; }, 
					onmouseover:function() { this.defColor=this.style.backgroundColor ; this.style.backgroundColor = '#a0a0a0'; },
					onmouseout:function() { this.style.backgroundColor = this.defColor; }}) ;
				this.appendChild(itm) ;
				if (n.length>this.maxLabelLength)
				{
					this.maxLabelLength = n.length ;
					scopeObj.tags.E(this,{'style.width':' '+(3*this.maxLabelLength/4)+'em'}) ;
				}
				return itm ;
			}

			eltMenu.addMenuItem = function(eltMenu,n,f){this.addItem(n,f)} ;
			
			var closeItem = eltMenu.addItem("close") ;
			closeItem.style.textAlign = "right" ;
			closeItem.style.backgroundColor = "#4040ff" ;

			return eltMenu ;
		}
	} ;
	
	/** Click events and browser independant layout stuff **/
	scopeObj.click = {
			x:function(e){ e = e || window.event ; return scopeObj.tags.isIE?event.x:e.pageX},
			y:function(e){ e = e || window.event ; return scopeObj.tags.isIE?event.y:e.pageY},
			dragX:function(e){ e = e || window.event ; return (scopeObj.tags.isWebkit || scopeObj.tags.isOpera)?e.pageX:e.clientX},
			dragY:function(e){ e = e || window.event ; return (scopeObj.tags.isWebkit || scopeObj.tags.isOpera)?e.pageY:e.clientY},
			eltOffset:function(e){ e = e || window.event ; return scopeObj.tags.isFirefox?{x:e.layerX,y:e.layerY}:{x:e.offsetX,y:e.offsetY}},
			eventTarget:function(e){ e = e || window.event ; return e.srcElement || e.target},
			getBoundingClientRect:function(e){
				var r = e.getBoundingClientRect();
				if (scopeObj.tags.isIE) {
					var s = {} ;
					for (var i in r) s[i] = r[i] ;
					r = s ;
				}
				if (typeof r.right==typeof undefined)
					r.right = r.width+r.left ;
				if (typeof r.width==typeof undefined)
					r.width = r.right-r.left ;
				if (typeof r.bottom==typeof undefined)
					r.bottom = r.height+r.top ;
				if (typeof r.height==typeof undefined)
					r.height = r.bottom-r.top ;
				return r ;
			},
			
			getDocXY:function(){
				var scrOfX = 0, scrOfY = 0;
				if (scopeObj.tags.document.documentElement && scopeObj.tags.document.documentElement.clientHeight) { 
					scrOfY = scopeObj.tags.document.documentElement.clientHeight;
					scrOfX = scopeObj.tags.document.documentElement.clientWidth;
				} else if (scopeObj.tags.document.body && typeof( scopeObj.tags.document.body.clientHeight ) == 'number' ) {
				    scrOfY = scopeObj.tags.document.body.clientHeight;
				    scrOfX = scopeObj.tags.document.body.clientWidth;
				 }
				 return {x:scrOfX, y:scrOfY};
			},
				
			getScrollXY:function(){
				  var scrOfX = 0, scrOfY = 0;
				  if (typeof( window.pageYOffset ) == 'number' ) { //Netscape compliant
				    scrOfY = window.pageYOffset;
				    scrOfX = window.pageXOffset;
				  } else if (scopeObj.tags.document.body && ( scopeObj.tags.document.body.scrollLeft || scopeObj.tags.document.body.scrollTop ) ) { //DOM compliant
				    scrOfY = scopeObj.tags.document.body.scrollTop;
				    scrOfX = scopeObj.tags.document.body.scrollLeft;
				  } else if (scopeObj.tags.document.documentElement && ( scopeObj.tags.document.documentElement.scrollLeft || scopeObj.tags.document.documentElement.scrollTop ) ) { //IE6 standards compliant mode
				    scrOfY = scopeObj.tags.document.documentElement.scrollTop;
				    scrOfX = scopeObj.tags.document.documentElement.scrollLeft;
				  }
				  return {x:scrOfX, y:scrOfY};
				},
					
			stopBubble:function(e){ 
				if (!e) e = window.event;
				e.cancelBubble = true;
				if (e.stopPropagation) e.stopPropagation(); 
			},
				
			preventDefault:function(e){
				if (!e) e = window.event ;
				if (e.preventDefault)
					e.preventDefault() ;
				else if (e.returnValue != undefined)
					e.returnValue = false;
			}
	};

	scopeObj.enableTooltips = function(doc){
		/* Attach the tooltip handler */
		if (!scopeObj.ANIMATE)
			scopeObj.enableAnimation() ;
		
		doc.onmousemove = function(e){
			if (!doc.elementFromPoint)
				return ; // FF2 won't do tooltips
			var evt = e || window.event;
			var x = scopeObj.click.dragX(evt) ;
			var y = scopeObj.click.dragY(evt) ;
			var elt = doc.elementFromPoint(x,y);

			while (elt) {
				if (elt.tooltip) {
					if (arguments.callee.ttPrev==elt) 
						return ;
					arguments.callee.ttPrev = elt ;
					
					if (arguments.callee.ttElt)
						arguments.callee.ttElt.parentNode.removeChild(arguments.callee.ttElt) ;
					arguments.callee.ttElt = null ;
					
					var tt = elt.tooltip ; 
					if (typeof tt=='function')
						tt = tt.apply(elt) ;
					if (!tt)
						break ;

					var r = scopeObj.click.getBoundingClientRect(elt) ;

					switch (elt.tooltipXoffset)
					{
					case 'middle':
						x = Math.floor((r.left+r.right)/2) ;
						break ;
					case 'right':
					case 'left':
						x = r[elt.tooltipXoffset] ;
						break ;
					default:
						if (!isNaN(Number(elt.tooltipXoffset)))
							x += Number(elt.tooltipXoffset) ;
						break ;
					}
					
					switch (elt.tooltipYoffset)
					{
					case 'middle':
						y = Math.floor((r.top+r.bottom)/2) ;
						break ;
					case 'bottom':
					case 'top':
						y = r[elt.tooltipYoffset] ;
						break ;
					default:
						if (!isNaN(Number(elt.tooltipYoffset)))
							y += Number(elt.tooltipYoffset) ;
						break ;
					}
					
					if (!tt.nodeName)
						tt = DIV({className:'default'},tt) ;
					arguments.callee.ttElt = DIV({
						className:'tooltip',
						style$left:String(x)+"px",
						style$top:String(y)+"px"},
						tt) ;
					var body = doc.body ;
					tags.append(body,scopeObj.ANIMATE(scopeObj.fadeIn,arguments.callee.ttElt),body.firstChild) ;
					return ;
				}
				elt = elt.parentNode ;
			}
			arguments.callee.ttPrev = elt ;
			if (arguments.callee.ttElt)
				arguments.callee.ttElt.parentNode.removeChild(arguments.callee.ttElt) ;
			arguments.callee.ttElt = null ;
			
		}
		doc.onmousemove.ttPrev = null ;
		doc.onmousemove.ttElt = null ;
	} ;
	
	scopeObj.enableAnimation=function() {
		/** Animation element and types **/
		function setOpacity(e,value) {
			if (value>=10) {
				e.style.opacity = '';
				e.style.filter = '';
			} else {
				e.style.opacity = value/10;
				e.style.filter = 'alpha(opacity=' + value*10 + ')';
			}
		}

		scopeObj.setOpacity = setOpacity ;
		
		scopeObj.fadeOut=function(e,args){
			var num = (args&&args.numFrames) || 10 ;
			var delay = (args&&args.delay) || 0 ;
			
			var f = e.animation.frame-delay ;
			if (f<0) f = 0 ;
			
			if (f>num) {
				setOpacity(e,0) ;
				return false ;	// Stop animating
			}
			setOpacity(e,10-((f/num)*10)) ;
			return true ; // Keep animating
		}

		scopeObj.fadeIn=function(e,args){
			var num = (args&&args.numFrames) || 10 ;
			var delay = (args&&args.delay) || 0 ;
			
			var f = e.animation.frame-delay ;
			if (f<0) f = 0 ;
			
			if (f>num) {
				setOpacity(e,10) ;
				return false ;	// Stop animating
			}
			setOpacity(e,(f/num)*10) ;
			return true ; // Keep animating
		}

		scopeObj.slideIn=function(e){
			e.style.position = 'relative' ;
			if (e.animation.frame>10) {
				e.style.top = e.style.left = "0px" ;
				return false ;	// Stop animating
			}
			e.style.top = e.style.left = String(10-e.animation.frame)+"px" ;
			return true ; // Keep animating
		}

		scopeObj.pulsar=function(e){
			var f = (e.animation.frame/4)%20 ;
			if (f<3) {
				e.style.position = 'relative' ;
				e.style.top = f+'px' ;
				e.style.left = f+'px' ;
				e.style.right = f+'px' ;
				e.style.bottom = f+'px' ;
			}
			return true ; // Keep animating
		}

		scopeObj.ANIMATE = function(type,e,args) {
			if (scopeObj.isArray(e))	// Only single nodes can be animated. Surround arrays by a DIV
				e = DIV(e) ;	
			e.animation = {frame:0, type:type, args:args} ;
			e.setDynamic("animate",scopeObj.ANIMATE.nextFrame) ;
			return e ;
		}
		
		scopeObj.ANIMATE.nextFrame = function() {
			if (!this.animation.frame)
				this.animation.frame = 0 ;
			if (!this.animation.type(this,this.animation.args)) {
				if (this.onAnimationEnd)
					this.onAnimationEnd(this) ;
				this.removeDynamic("animate") ;
				this.animation = null ;
			}
			else
				this.animation.frame += 1 ;
			return this ;
		} 

		scopeObj.setFrameRate = function(r) {
			if (scopeObj.animationTimerID)
				clearInterval(scopeObj.animationTimerID) ;
			scopeObj.animationTimerID = setInterval(function(){try{scopeObj.tags.update("animate")}catch(ex){}},1000/r) ;
		}
		
		scopeObj.setFrameRate(15) ;
	}

	/*
	 * Default functions inherited by all elements created by the tag library.
	 * Additional functions can be added/overridden
	 */
	scopeObj.tags.inherit = {
		append:function(child,before){scopeObj.tags.append(this,child,before); return this}, 
		replace:function(child){scopeObj.tags.replace(this,child); return this},
		attrs:function(attr){scopeObj.tags.E(this,attr); return this},
		replaceNode:function(newElt){ return scopeObj.tags.replaceNode(this,newElt) ; },
		remove:function(){ if (this.parentNode) this.parentNode.removeChild(this) },
		setDynamic:scopeObj.tags.setDynamic,
		removeDynamic:function(up,i) { scopeObj.tags.removeDynamic(this,up,i) },
		getInnerText:function() { return scopeObj.tags.getInnerText(this) }
	} ;
	
/** Importer **/
	if (scopeObj.isArray(tagArray)) {
		for (var i=0; i<tagArray.length; i++) {
			scopeObj[tagArray[i]] = function() {
				var args = Array.prototype.slice.call(arguments);
				var elem = scopeObj.tags.document.createElement(arguments.callee.tagName);
	
				/* Add in our "standard" DOM functions. We don't use the prototype as IE and Safari don't allow you to mod the prototype of HTMLElement or DOMElement */
				scopeObj.tags.E(elem,scopeObj.tags.inherit) ;
				/* Add in any element specific functions */
				scopeObj.tags.E(elem,arguments.callee.inherit) ;
				
				if (!args[0] || 
		  	      ((! args[0].nodeName) &&
		  	      ((typeof args[0]) == "object") &&
		  	      !scopeObj.isArray(args[0])))		// Check it's not an array 
				{
					var attributes = args.shift(); 
					if (attributes)
						scopeObj.tags.E(elem, attributes);
	  	    	}
				scopeObj.tags.append(elem,args) ;
				return elem ;
			}
			scopeObj[tagArray[i]].inherit = {} ;
			scopeObj[tagArray[i]].tagName = tagArray[i].toLowerCase() ;
			scopeObj[tagArray[i]].name = scopeObj[tagArray[i]].tagName ; // For FF debug
		}
	}
	;
	setInterval(scopeObj.tags.validateDynamicElements,5000) ;
}
 	



if (!window.location.getParameter) {
	window.location.getParameter = function(key, default_) {
	  if (default_==null) default_="";
	  key = key.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
	  var regex = new RegExp("[\\?&]"+key+"=([^&#]*)");
	  var qs = regex.exec(window.location.href);
	  if(qs == null)
	    return default_;
	  else
	    return qs[1];
	}
}


function Cookie() {
	return {
		set:function(name,value,days, domain) {
			if (!domain) {
				domain = window.location.hostname.split("flirtomatic") ;
				domain[0] = "flirtomatic" ;
				domain = domain.join("") ;
			}
			days = days || 3653 ;
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			var expires = "; expires="+date.toGMTString();
			document.cookie = name+"="+value+expires+"; path=/; domain="+domain;
		},
		get:function(name) {
			var nameEQ = name + "=";
			var ca = document.cookie.split(';');
			for(var i=0;i < ca.length;i++) {
				var c = ca[i];
				while (c.charAt(0)==' ') c = c.substring(1,c.length);
				if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
			}
			return null;
		},
		clear:function (name) {
			this.set(name,"",-1);
		}
	} ;
}


/* JSCastingPrototypeBuilder(com.flirtomatic.intl.LocalizedResources) */
var LocalizedResources = function() { this.java$class=arguments.callee.java$class };
LocalizedResources.java$class='com.flirtomatic.intl.LocalizedResources';
imports['com.flirtomatic.intl.LocalizedResources'] = LocalizedResources;
LocalizedResources.getInheritedMap = function( String_1,_return,_cb,_except) { return rJS.Exec(this.java$class,rJS.Call('getInheritedMap', rJS.JavaString(String_1)),_return,_cb||this,_except,rJS.MethodCall); }
LocalizedResources.getLocalizedMap = function( String_1,_return,_cb,_except) { return rJS.Exec(this.java$class,rJS.Call('getLocalizedMap', rJS.JavaString(String_1)),_return,_cb||this,_except,rJS.MethodCall); }
LocalizedResources.getResourceFile = function( Locale_1, String_2, boolean_3,_return,_cb,_except) { return rJS.Exec(this.java$class,rJS.Call('getResourceFile', Locale_1, rJS.JavaString(String_2), rJS.Boolean(boolean_3)),_return,_cb||this,_except,rJS.MethodCall); }
LocalizedResources.getPhotoRejectionMessage = function( String_1, long_2,_return,_cb,_except) { return rJS.Exec(this.java$class,rJS.Call('getPhotoRejectionMessage', rJS.JavaString(String_1), rJS.Long(long_2)),_return,_cb||this,_except,rJS.MethodCall); }
/* end { LocalizedResources } */



function Intl(fileName,onload,prefix,suffix) {
	prefix=prefix||"^";
	suffix=suffix||"^";
	var msg = function(resourceId) {
			if (this.keyMode)
				return prefix+resourceId+suffix ;
	        var str = msg.msgs[resourceId];
	        if(str == null) {
	        	str = prefix+resourceId+suffix ;
	            for (var i=1; i< arguments.length; i++)
					str += (typeof arguments[i]=='function')?((arguments[i].name||"LINK")+"^"):arguments[i]+"^" ;
	        }
			else
			{
	            for (var i=1; i< arguments.length; i++) {
	                    var repl = "\\{" + (i-1) + "\\}";
	                    var a = arguments[i] ;
	                    if (a==null || a==undefined)
	                    	a = '' ;
	                    str = str.replace(new RegExp(repl,"g"),a);
	            }
			}
	        return str.replace(/''/g,"'") ;
	} ;
	
	msg.elts = function(attr){
		function splitParts(regex, str) {
			var parts ;
			if (tags.isIE) {		// String.split is broken in IE
				var n ;
				parts = [] ;
				while ((n = str.search(regex))>=0) {
					parts.push(str.substring(0,n)) ;
					parts.push(str.substring(n,n+1)) ;
					str = str.substring(n+1) ;
				}
				parts.push(str) ;
			} else {
				parts = str.split(regex) ;
			}
			return parts ;
		}
		function addResult(x) {
			if (x==null || x==undefined)
				return ;
			if (typeof x=='number')
				x = String(x) ;		
			if (typeof x=='string') {
				if (x.length)	{
					x = x.replace(/~/g," ").replace(/''/g,"'") ;
					if (result.length && typeof(result[result.length-1])=='string') {
						result[result.length-1] += x ;
					} else {
						result.push(x) ;
					}
				}
			} else {
				result.push(x) ;
			}
		}
		
		var appliedAttrs = {} ;
		var args = Array.prototype.slice.apply(arguments,[0]) ;
		if (typeof attr=='object' && !isArray(attr))
			appliedAttrs = args.shift() ;
		var key = args.shift() ;
		var str = msg.msgs[key] ;
		if (!str) {
			str = "^"+key+"^" ;
			for (var i=0; i<args.length; i++)
				str += "{"+i+"}!" ;
		}
	
		var result = [] ;
		var parts = splitParts(/([\s\{\}[\]])/g,str) ;
		for (var k=0; k<parts.length; k++) {
			var text = parts[k] ;
			var n = -1 ;
			if (text=='{') {
				n = Number(parts[k+1]) ;
			} else if (text=='[') {
				if (parts[k+1].substring(0,5)=='link.')
					n = Number(parts[k+1].split('.')[1]) ;
				else {
					while (parts[k]!=']') {
						if (k>=parts.length)
							break ;
						k++ ;
					}
					if (k>=parts.length)
						break ;
					continue ; 	// Ignore unknown [...] directive
				} 
			}
			if (n>=0) {
				if (typeof args[n]=='function') {
					addResult(A({onclick:args[n]},parts[k+3].replace(/~/g," ").replace(/''/g,"'"))) ;
					k += 3 ;
				} else { 
					addResult(args[n]) ;
					k += 2 ;
				}
			} else {
				addResult(text) ;
			}
		}
		return SPAN(appliedAttrs,result) ;
	}
	
	msg.onload = onload ;
	msg.exists = function(k){ return msg.msgs[k] };
    msg.msgs = LocalizedResources.getLocalizedMap(fileName) ;
    if (msg.onload)
    	msg.onload() ;
    return msg ;
}

function Undo(w) {
	var h = {
		wnd:null,
		prev:null,
		goingBack:false,
		list:[],
		index:0,
		add:function(title,fnRestore,objRestore,argsRestore){
			if (!this.goingBack) {
				this.list[this.index] = Array.prototype.slice.call(arguments) ;
				this.index = (this.index+1)%10 ;
				this.prev = this.index ;
				this.wnd.location.hash = "#"+this.index ;
				this.wnd.document.title = title ;
			}
		},
		clear:function(){
			this.list = [] ;
			this.add('Flirtomatic') ;
		},
		reload:function(){
			var anchor = Number(this.wnd.location.hash.substring(1)) ;
			this.prev = anchor ;
			var args = this.list[anchor-1] ;
			if (args) {
				this.wnd.document.title = args[0] ;
				if (args[1]) {
					this.goingBack = true ;
					args[1].apply(args[2]||this.wnd,args[3]||[]) ;
					this.goingBack = false ;
				}
			}
		},
		syncHistory:function(){
			if (!this.wnd.location.hash) {
				this.clear() ;
			} else {
				var anchor = Number(this.wnd.location.hash.substring(1)) ;
				if (anchor > this.index){ // Someone pressed refresh, and the history has been cleared
					this.wnd.location.hash = "#"+this.list.length ;
					this.index = this.list.length ;
				} else if (this.prev != anchor)
					this.reload() ;
				// Limit "forward" to 5 clicks
//				if (this.list.length>(anchor+5))
//						this.list = this.list.slice(0,anchor+5) ;
			}
		}
	} ;

	h.wnd = w ;
	setInterval(function(){
		try {
			h.syncHistory() ;
		} catch (ex) {}
		},500) ;
		
	return h ;
}

