//var gbDebug = false;
var gIEVersion = parseFloat(navigator.appVersion.split('MSIE')[1]);

var eEmbededNone			= 0;
var eEmbededMidi			= 1;
var eEmbededMini			= 2;

var gEmbeded = eEmbededNone;
DetermineEmbeded();

ZEGlobals = new Object();

function IsIE()
{
	//navigator.appName.indexOf( 'Internet Explorer' )>=0
	//return (document.all ? true : false);
	return (gIEVersion ? true : false );
}

function ZE_OnSubmitDisable(form)
{
	if ( !form ) { return; }
	
	// set the button for the form to be disabled
	for (var i=0;i<form.length;i++)
	{
	    var el = form.elements[i];
	    if ( el && el.type == 'submit')
	    {
	    	window.setTimeout( function(){el.disabled=true;}, 5);
	    }
	}
}

function IsEmbeded()
{
	return gEmbeded > 0;
}

function DetermineEmbeded()
{
	gEmbeded = eEmbededNone;
	if ( GetDomain().match( /^mini\./i ) || Search_GetValue( 'mini' ) )
	{
		gEmbeded = eEmbededMini;
	}
	else if ( GetDomain().match( /^midi\./i ) || Search_GetValue( 'midi' ) )
	{
		gEmbeded = eEmbededMidi;
	}
}

function IsEmbededMini()
{
	return gEmbeded == eEmbededMini;
}

function IsEmbededMidi()
{
	return gEmbeded == eEmbededMidi;
}

function ConvertToInt(s)
{
    var n = parseInt(s);
    if (!n) return 0;
    if (isNaN(n)) return 0;
    return n;
}

function ConvertTime( tms ) 
{
	var r 		= 60*60*1000;
	var hrs 	= Math.floor( tms / r );
	var rem 	= tms % r;
	r 			= 60*1000;
	var mins 	= Math.floor( rem / r );
	rem			= rem % r;
	var secs 	= Math.floor( rem / 1000 );
	return (hrs?(hrs.toString() + ':'):'') + (hrs&&mins<10?'0':'') + mins.toString() + ':' + (secs<10?'0':'') + secs.toString();
}

function GetTimeMS()
{
	var time_cur = new Date();
	return time_cur.getTime();
}

//var gCalledCounter = 0;
var gSeed = new Date();
gSeed = gSeed.getSeconds();
function GetRandomNumber( min, max )
{
//	++gCalledCounter; //DebugOutput( 'GetRandomNumber call count: ' + gCalledCounter );
	if ( min > max ) { DebugOutput( 'GetRandomNumber -- called with bad parameters: min=' + min + ', max=' + max ); return 0; }
	
	gSeed = ( 69069 * gSeed + 1 ) % 4294967296; //(2^32)
//	DebugOutput( gCalledCounter + ', seed='  + gSeed ); // + "\n" + ZOO_GetCallStack() );
//	DebugOutput( min + ((gSeed>>>5) % (max - min)) );
	return min + ((gSeed>>>5) % (max - min));
}

function ValidateTextEntry( field, min, max, compareField, func, errorText )
{
    if ( !field ) 
	{
//		alert( "No field?" );
		return "No field";
    }
    var errorMsg = "";
    var len = field.value.length;
    if ( len < min ) 
	{
		errorMsg = "Entry must be at least " + min + " characters.";
    } 
	else if ( len > max ) 
	{
		errorMsg = "Entry must not exceed " + max + " characters.";
    } 
	else if ( field.value && func && !func(field.value) ) 
	{
		errorMsg = errorText ? errorText : "Entry contains invalid characters."; 
 	}
	else if ( compareField && field.value != compareField.value ) 
	{
		errorMsg = "Entries don't match.";
    }
    
    return errorMsg;
}

function GetElement( id )
{
    if (document.getElementById) return document.getElementById(id);
    if (document.all) return document.all[id];
    return null;
}

function GetElements( prefix, startIndex )
{
	if ( prefix === undefined || startIndex === undefined || startIndex < 0 ) { return; }
	
	var elements = new Array( '' );
	var counter = startIndex;
	do
	{
		var el = GetElement( prefix + counter.toString() );
		if ( el )
		{
			elements.push( el );
			
		}
		++counter;
	} while( el );	
	
	return elements;
}

function Event_GetElement( evt )
{
	if ( !evt ) evt = window.event;

	var e = undefined;
	if ( evt && evt.srcElement ) 
	{
		e = evt.srcElement;
	}
	else if ( evt && evt.target )
	{
		e = evt.target;
	}
	return e;
}

function Event_Cancel( evt, bCancelBubble )
{
	if ( bCancelBubble === undefined ) { bCancelBubble = true; }
	if ( !evt ) evt = window.event;
	if ( !evt ) { ErrorOutput( 'no event' ); return; }
	
	if ( evt.preventDefault )
	{
		evt.preventDefault();
	}
	if ( evt.stopPropagation )
	{
		evt.stopPropagation();
	}
	evt.cancelBubble = bCancelBubble; // IE
	evt.returnValue = false; // IE
}

document.oncontextmenu = function(evt)
{
	var el = Event_GetElement(evt);
	if ( el && el.tagName.toLowerCase() == 'img' )
	{
		return Event_Cancel(evt);
	}
};

function SetMessageForTextField( id, msg )
{
    var bob = GetElement( id );
    if (bob) {
		bob.innerHTML = msg;
		bob.style.display = msg ? '' : 'none';	// unhide an element -- set its style property 'display' to '' (an empty string)
    }
}

function StringDecodeJS(t)
{
    var o;
    try 
    { 
	o = decodeURIComponent( t ); 
    } 
    catch(e) 
    { 
	o = unescape( t );
    }
    
    return o;
}

function StringEncodeJS(t)
{
    t = encodeURIComponent( t );
    return t;
}

function StringIsFormedLikeEmailAddress( text )
{
    return text.match(/^[\w\-\.\$\&\+\/\=\{\|\}\~\#]+\@[\w\-\.]+\.\w+$/i) && !text.match(/\@\./) && !text.match(/\.\./);
}

function StringContainsValidText( text )
{
    return !(text.match(/[^\w\- ]/g));
}

function StringMakeValidText( text )
{
	if ( !text ) { return text; }
	
	text = text.toLowerCase();
	text = text.replace(/[^\w\-]/g, '');
	return text;
}

function StringTrimWhitespace( text )
{
	if ( !text ) { return ''; }
	
	text = String( text );
    text = text.replace( /^\s+/, '' );
    text = text.replace( /\s+$/, '' );
    
    return text;
}

function StringMakeHTMLSafe(txt)
{
    if (!txt) return '';
    txt = String(txt);
    txt = txt.replace( /&/g, '&amp;' );
    txt = txt.replace( /\"/g,'&quot;');/*"*/
    txt = txt.replace( /</g, '&lt;' );
    txt = txt.replace( />/g, '&gt;' );
    return txt;
}

function StringConvertToHTML(txt)
{
	if ( !txt ) { return ''; }
	txt = String(txt);
	txt = txt.replace( /\r\n/g,   '<BR>' );
    txt = txt.replace( /[\r\n]/g, '<BR>' );
	return txt;
}

function StringDecode( str, emptyChar )
{
	if ( !str ) 					{ return str; }
	if ( emptyChar === undefined ) 	{ emptyChar = ' '; }
	
	var retStr = '';
	for ( var i=0; i < str.length; ++i ) 
	{
		var val = str.charCodeAt( i );
		if ( val >= 48 && val <= 57 ) //( val >= 0x30 && val <= 0x39 )
		{
			var count = val - 48;
			val = '';
			do
			{
				val += emptyChar;
				--count;
			} while ( count >= 0 );
		}
		else if ( val >= 65 && val <= 90 ) //( val >= 0x41 && val <= 0x5A )
		{
			val = str.charAt( i );
		}
		else if ( val >= 97 && val <= 122 ) //( val >= 0x61 && val <= 0x7A )
		{
			val = (str.charAt( i ) + str.charAt( i )).toUpperCase();
		}
		else
		{
			ErrorOutput( 'Unexpected character: char=' + str.charAt(i) + ' charcode=' + val );
			val = str.charAt( i );
		}

		retStr += val;
	}
	return retStr;
}

function StringEncode( str, emptyChar )
{
	if ( !str ) { return str; }
	if ( emptyChar === undefined ) 	{ emptyChar = ' '; }
	
	var retStr = '';
	for ( var i=0; i < str.length; ++i ) 
	{
		var val = str.charAt( i );
		var next = val;		
		var counter = 0;
		while ( i+1 < str.length )
		{
			next = str.charAt( i+1 );
			if ( next == val ) // repeated character?
			{
				++i;
				if ( next == emptyChar )
				{
					 ++counter;
				}
				else // write one lowercase character for each pair of matching letters
				{
					val = val.toLowerCase();
					break; //only do this in pairs
				}
			}
			else
			{
				break;
			}
		}
		
		if ( val == emptyChar )
		{
			val = '';
			if ( counter > 0 )
			{
				while ( counter > 9 )
				{
					val += '9';
					counter -= 10;
				}
			}
			val += counter.toString();
		}

		retStr += val;			
	}	
	
	return retStr;
}

function StringDecodeNumber( str, emptyChar )
{
	if ( !str ) 					{ return str; }
	if ( emptyChar === undefined ) 	{ emptyChar = '0'; }
	
	var retStr = '';
	for ( var i=0; i < str.length; ++i ) 
	{
		var val = str.charCodeAt( i );
		if ( val >= 65 && val <= 90 ) //( val >= 0x41 && val <= 0x5A )
		{
			var count = val - 65;
			val = '';
			do
			{
				val += emptyChar;
				--count;
			} while ( count >= 0 );
		}
		else if ( val >= 48 && val <= 57 ) //( val >= 0x30 && val <= 0x39 )
		{
			val = str.charAt( i );
		}
//		else if ( val >= 97 && val <= 122 ) //( val >= 0x61 && val <= 0x7A )
//		{
//			val = (str.charAt( i ) + str.charAt( i )).toUpperCase();
//		}
		else
		{
			ErrorOutput( 'Unexpected character: char=' + str.charAt(i) + ' charcode=' + val );
			val = str.charAt( i );
		}

		retStr += val;
	}
	return retStr;
}

function StringEncodeNumber( str, emptyChar )
{
	if ( !str ) { return str; }
	if ( emptyChar === undefined ) 	{ emptyChar = '0'; }
	
	var retStr = '';
	for ( var i=0; i < str.length; ++i ) 
	{
		var val = str.charAt( i );
		var next = val;		
		var counter = 0;
		while ( i+1 < str.length )
		{
			next = str.charAt( i+1 );
			if ( next == val && next == emptyChar ) // repeated character?
			{
				++i;
				++counter;
			}
			else
			{
				break;
			}
		}
		
		if ( val == emptyChar )
		{
			val = '';
			if ( counter > 0 )
			{
				while ( counter > 25 )
				{
					val += 'Z';
					counter -= 26;
				}
			}
			val += String.fromCharCode(65+counter);
		}

		retStr += val;			
	}	
	
	return retStr;
}

function CreateScriptElement( parent, source, id )
{
	if ( !parent ) { return null; }
	var e = document.createElement( 'SCRIPT' );
	e.language = 'JavaScript';
	e.type = 'text/javascript';
	e.src = source;
	e.id = id ? id : source;
	return parent.appendChild( e );
}

function SearchList( list, val, bRange )
{
	if ( !(list && val) ) { return -1; }
	var counter = 0;
	var min = 0, max = list.length, half = Math.floor( max * 0.5 );
	var mid = Math.floor( (max + min) * 0.5 );
	var bDone = false;
	while ( !bDone ) 
	{
		if ( val <= list[mid] ) 
		{
			max = mid;			
		} 
		else 
		{
			min = mid;
		}
//		DebugOutput( "Mid: " + mid.toString() + " Min: " +  min.toString() + " Max: " + max.toString() );

		if ( bRange )
		{
			if ( (max - min) == 1 ) { mid = (val <= list[min] ? min : max); bDone = true; }
			else { mid = Math.floor( (max + min) * 0.5 ); }
		}
		else
		{
			if ( val == list[min] ) 		{ mid = min; bDone = true; }
			else if ( val == list[max] ) 	{ mid = max; bDone = true; }
			else if ( (max - min) == 1 )	{ mid = -1; bDone = true;  }
			else 							{ mid = Math.floor( (max + min) * 0.5 ); }
		}
		++counter;
		if ( counter > half ) 
		{
			ErrorOutput( 'Infinite loop would occur for this value: ' + val.toString() + ', mid=' + mid + ', min=' + min + ', max=' + max + ', list[mid]=' + list[mid] + ', list.length=' + list.length );
			break;
		}
	}
	return mid;
}

function RedirectImmediate( url, bForce )
{
	if ( window.location ) 
	{
		try
		{ 
			if ( url )
			{
				window.location.href = url; 
			}
			else
			{
				if ( !bForce ) { bForce = false; }
				window.location.reload(bForce);
			}
		}
		catch(e)
		{
		/*
			var err = '';
			for (var i in e) 
    		{ 
				err += '\n\t'+i+': '+e[i]; 
			}
			ErrorOutput( 'RedirectImmediate error: ' + url + ', ' + err );
		*/
		}
	}
}

function GetHTTPDomain( bNoEmbeded )
{
	var d = '';
	if ( gEmbeded && bNoEmbeded )
	{
		d = GetDomain();
		d = 'http://' + d.replace( /^mi[nd]i\./i, '' );
	}
	return d;
}

function GetDomain()
{
	var loc = window.location;
	if ( loc )
	{
		var d = loc.hostname;
		return d;
	}
	return '';
}

var gPageArgs;
function Page_GetArgs()
{
	if ( !gPageArgs )
	{
		var s = Location_GetSearch();
		if ( s )
		{
			if ( s.charAt( 0 ) == '?' )
			{
				s = s.substr( 1 );
			}
			//DebugOutput( s );
			gPageArgs = new Object();
			var args = s.split( '&' );
			for ( var i = 0; i < args.length; ++i )
			{
				var val = args[i].split( '=' );
				var key = val[0];
				val = val[1];
				gPageArgs[key.toLowerCase()] = val;
			}
		}
	}
	return gPageArgs;
}

function Location_GetSearch( removeKey )
{
	var s = window.location.search;	
	if ( removeKey )
	{
		s = '';
		var args = Page_GetArgs();
		for ( var i = 0; i < args.length; ++i )
		{
			var key = args[i][0];
			var val = args[i][1];
			if ( ((typeof val) != 'function' ) && key.toLowerCase() != removeKey.toLowerCase() )
			{
				s += (s?'&':'') + key + '=' + value;
			}
		}
	}
	return s;
}

function Search_GetValue( key )
{
	var args = Page_GetArgs();
	if ( args )
	{
		//DebugOutput( args[key.toLowerCase()] );
		return args[key.toLowerCase()];
	}
}

RemoteRequest.NewRequest = function ( url, sendTxt, callbacks, bAsync )
{
	if ( !RemoteRequest.msRequests )
	{
		RemoteRequest.msRequests = new Array();
	}
	
	var index = RemoteRequest.msRequests.length;
	var rr = new RemoteRequest( url, sendTxt, callbacks, bAsync, index );
	RemoteRequest.msRequests.push( rr );
	return rr;
};

RemoteRequest.GlobalCallbackHandler = function ( id, funcName )
{
	if ( !RemoteRequest.msRequests || RemoteRequest.msRequests.length <= 0 ) { ErrorOutput( 'Attempting to delete remote request when no requests in static array.' ); return; }
	var rr = RemoteRequest.msRequests[ id ];
	if ( !rr ) { ErrorOutput( 'No remote request at index=' + id ); return; }
	
	if ( !rr[funcName] ) { ErrorOutput( 'No function named ' + funcName + ' in remote request.' ); return; }
	rr[funcName]();
};

RemoteRequest.DeleteRequest = function ( rr )
{
	if ( !rr ) { return; }
	if ( !RemoteRequest.msRequests || RemoteRequest.msRequests.length <= 0 ) { ErrorOutput( 'Attempting to delete remote request when no requests in static array.' ); return; }
	rr.Delete();
	delete rr;
	RemoteRequest.msRequests[ rr.mID ] = undefined;
};

function RemoteRequest( url, sendTxt, callbacks, bAsync, id )
{
	if ( bAsync === undefined ) { bAsync = true; }
	this.mID = id;
	this.mURL = url;
	this.mSendTxt = sendTxt;
	this.mCallbacks = callbacks;
	this.mbAsync = bAsync;

	this.Delete = function ()
	{
		this.RemoveTimeout();
		this.mCallbacks = undefined;
		this.mHTTP = undefined;
//		DebugOutput('cleared HTTP object since remote request is being deleted');
	};
	
	this.RemoveTimeout = function ()
	{
		if ( this.mTimeoutID )
		{
			window.clearTimeout( this.mTimeoutID );
			this.mTimeoutID = undefined;
		}
	};
		
	this.Issue = function ()
	{
		var bSuccess = false;
		var obj = this;
		var xhttp = GetHTTP();
		if ( !xhttp ) { ErrorOutput( 'Unable to GetHTTP()' ); return bSuccess; }

		try 
		{
			obj.mTimeSent = new Date();
			obj.mHTTP = xhttp;
			var method = !obj.mSendTxt ? 'GET' : 'POST';
			xhttp.open( method, obj.mURL, obj.mbAsync ? true : false );
			if ( obj.mbAsync )
			{
				xhttp.onreadystatechange = obj.GetCallbackHandler();
//				DebugOutput('Set function for async');
			}
			xhttp.send( obj.mSendTxt );
			if ( obj.mCallbacks && obj.mCallbacks.mTimeout )
			{
				var cb = obj.mCallbacks.mTimeout;
				if ( !cb.timeout )
				{
					cb.timeout = 30;
				}
				obj.mTimeoutID = window.setTimeout( 'RemoteRequest.GlobalCallbackHandler('+obj.mID+', \'CallbackHandler_Timeout\');', cb.timeout*1000 );
			}
			
			if ( !obj.mbAsync )
			{
				obj.CallbackHandler();
			}
			bSuccess = true;
//			DebugOutput( 'sending: sendTxt=' + obj.mSendTxt + ' opening: method=' + method + ' url=' + obj.mURL  );
		} 
		catch( e )
		{ 
			ErrorOutput( 'Unable to open or send or get response text' );
		}
		
		return bSuccess;
	};
	
	
	this.CallbackHandler_Timeout = function ()
	{
		this.mTimeoutID = undefined;
		if ( this.mCallbacks && this.mCallbacks.mTimeout )
		{
			var cb = this.mCallbacks.mTimeout;
			var o = cb.obj;
			var funcName = cb.funcName;
			if ( o && o[funcName] )
			{
				o[funcName]( this );
			}
			else
			{
				ErrorOutput( 'No valid object to handle remote request callback: funcName=' + funcName + ', obj=' + cb.obj );
			}
		}
	};
	
	this.GetCallbackHandler = function ()
	{
		var obj = this;
		return function () { obj.CallbackHandler(); }
	};

	this.CallbackHandler = function ()
	{
		var obj = this;
		if ( obj.mHTTP )
		{
//			DebugOutput('Called completion handler with ready state=' + obj.mHTTP.readyState);
		}
		else
		{
//			ErrorOutput('No HTTP object?');
		}		
		
		if ( !obj.mHTTP || (obj.mbAsync && obj.mHTTP.readyState != 4) ) { return; }
		
		var ret = obj.mHTTP.responseText;
		obj.mHTTP = undefined;

		this.RemoveTimeout();
		
		if ( obj.mCallbacks && obj.mCallbacks.mCompletion )
		{
			var cb = obj.mCallbacks.mCompletion;
			ret = ret.replace( /\s*/, '' ); //DebugOutput( 'ret=' + ret );
			if ( typeof( cb ) == 'function' )
			{
				cb( ret, obj );
//				DebugOutput('Called completion function handler for object');
			}
			else
			if ( typeof ( cb ) == 'object' )
			{
				var o = cb.obj;
				var funcName = cb.funcName;
				if ( o && o[funcName] )
				{
					o[funcName]( ret, obj );
//					DebugOutput('Called object function handler for completion: ' + funcName);
				}
				else
				{
					ErrorOutput( 'No valid object to handle remote request callback: funcName=' + funcName + ', obj=' + cb.obj );
				}
			}
			else
			{
				ErrorOutput('unknown callback handler');
			}
		}
		else
		{
			ErrorOutput('no object to handle completion?');
		}
	};
}

function GetHTTP( bDoAlert )
{
	if ( bDoAlert === undefined )
	{
		bDoAlert = true;
	}
	
    var xmlhttp = null;
    try { xmlhttp = new XMLHttpRequest(); } catch(e) { xmlhttp=null; }
    if (xmlhttp) return xmlhttp;
    try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch(e) { xmlhttp=null; }
    if (xmlhttp) return xmlhttp;
    try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch(e) { xmlhttp=null; }
    if (xmlhttp) return xmlhttp;
	
	if ( bDoAlert ) { alert( 'Your web browser is lacking the functionality required for this game:\nXMLHTTP object not present!' ); }
	return null;
}

function GetFile( url, func ) 
{
	if ( !(Boolean(url) && typeof(func) == 'function') ) { ErrorOutput( 'GetFile has bad url or callback func' + url + ' type=' + (typeof func) );return 0; }
	var xhttp = GetHTTP();
	if (!xhttp) { return 0; }
	try 
	{ 
		xhttp.open( 'GET', url, true );
		xhttp.onreadystatechange=function() 
		{
			if (xhttp.readyState==4) 
			{
				//DebugOutput(xhttp.responseText);
				var ret = '';
    			ret = xhttp.responseText;
				func( url, ret );
			}
		}
		xhttp.send(null);
	}
	catch ( e )
	{
		DebugOutput( 'Exception in GetFile.' );
		return 0;
	}
}

function GetHTML_StatusIcon( stat ) // 1==ok, 2==warn, 3=error
{
	var left;
	if ( stat == 2 ) 
	{
		left = -29;
	}
	else if ( stat == 3 )
	{
	 	left = -58;
	}
	else
	{
		left = 0;
	}
	
	return GetHTML_ImageWithOffset( 30, 30, left, 0, '/img/status.png', 87, 30 );
//	var html = '<DIV style="vertical-align:middle; float:left; position:relative; overflow:hidden; width:20px; height:20px;"><IMG src="/img/status.png" style="position:absolute; width:60px; height:20px; left:' + left + '"></DIV>';
//	return html;
}

function GetHTML_Die( val, style )
{
	style = style ? (' style="'+style+'"') : '';
	return '<div class=fig_die'+style+'><img id=fig_die_'+val+' title='+val+' alt='+val+' class=fig_die src=/img/fig-die.png></div>';
}

function GetHTML_OnlineStatusIcon( stat ) // 1==online, 2==offline, 3=exited
{
	var w = 20;
	var left = stat ? (-w * (stat-1)) : 0;
	return GetHTML_ImageWithOffset( w, w, left, 0, '/img/status_online.png', w*4, w );
}

function GetHTML_ImageWithOffset( w, h, offsetLeft, offsetTop, imageFileName, imageW, imageH, className )
{
	return '<DIV style="margin:auto; position:relative; overflow:hidden; width:' + w + 'px; height:' + h + 'px;"><IMG class="'+ (className ? className : '') + '" src="' + imageFileName + '" style="position:absolute; width:' + imageW + 'px; height:' + imageH + 'px; left:' + offsetLeft + 'px; ' + (offsetTop ? 'top:' + offsetTop + 'px;' : '') + '"></DIV>';
}

function GetHTML_LogoSmall( e, menuContents )
{
	var html = '<TABLE style="width:100%""><TR><TD style="width:50px; padding:2px;">';
	if ( menuContents )
	{
		html += '<DIV id="ze_menu" class="wg_embeded_menu_link">MENU&#9660;</DIV>';
	}
	html += '</TD><TD><DIV style="padding:4px;"><A href="'+ GetHTTPDomain( IsEmbededMini() ) +'" target=_blank><IMG src="/img/logo_sm2.gif" style="vertical-align:middle; width:139px; height:20px;"></IMG></A></DIV></TD><TD style="width:50px;"></TD></TR></TABLE>';
	if ( e )
	{
		e.innerHTML = html;
		var m = GetElement( 'ze_menu' );
		if ( m )
		{
			m.onmouseover = function ( evt )
			{
				var obj = this;
				UI_ShowPopupMenu( true, menuContents, obj, 2, 2 );
			}			
		}
	}
	else
	{
		return html;
	}
}

function GetHTML_RoundedFrame_Pre( tstyle )
{
	if ( tstyle ) 	{ tstyle = ' style="'+tstyle+'"'; }
	else			{ tstyle = ''; }
	
    return '<table class=rndfrm'+tstyle+'><tr><td class=rndfrm><div class=rndfrm_subtle3></div><div class=rndfrm_subtle2></div><div class=rndfrm_subtle1></div></td></tr><tr class=rndfrm_subtle0><td style="padding:4px 16px;">'+"\n";
}

function GetHTML_RoundedFrame_Post()
{
    return "</td></tr><tr><td class=rndfrm><div class=rndfrm_subtle1></div><div class=rndfrm_subtle2></div><div class=rndfrm_subtle3></div></td></tr></table>\n";
}

function ImageFilterSet( e )
{
	if ( gIEVersion>=5.5 && gIEVersion<7 && document.body.filters )
    {
		var f_name = 'DXImageTransform.Microsoft.AlphaImageLoader';
		e.style.filter = 'progid:'+f_name+'(src="'+e.src+'",sizingMethod="crop",enabled=1)';
		e.src = '/img/clear.gif';
    }
}

var gDbgTxt = '';
function DebugOutputClear() 
{
	if ( !gbDebug ) { return; }
	var e = GetElement( 'wg_debug' );
	if ( e ) 
	{
		gDbgTxt = '';
		e.innerHTML = '';
	}
}

function DebugOutput(txt, bAlert) 
{
	if ( txt === undefined ) { return; }
	if ( !gbDebug ) { return; }
	
	if ( bAlert ) { alert(txt); }
	var e = GetElement( 'wg_debug' );
	if ( !e ) 
	{
		if ( !document.body )
		{
			alert( txt );
		}
		else
		{
			var button = document.createElement( 'INPUT' );
			button.type = 'button';
			button.value = 'Clear Text';
			button.onclick = function () { DebugOutputClear(); }
			document.body.appendChild( button );		

			e = document.createElement( 'DIV' );
			e.style.overflow ='auto';
			e.style.height = '200px';
			e.style.fontSize = '80%';
			e.id = 'wg_debug';
			document.body.appendChild( e );		
		}
	}
	
	if ( e ) 
	{
		gDbgTxt = txt.toString().replace( /\n/g, '<BR>' ) + '<BR>' + gDbgTxt.substr(0,1000);
		e.innerHTML = gDbgTxt;
	}
}

function ErrorOutput(txt) 
{
	if ( !txt ) { return; }
//	DebugOutput( txt );

	ZOO_ReportError( txt );	
}

function CookieSet( name, value, exp )
{
	document.cookie = name.toUpperCase() + '=' + value + '; domain=.zooescape.com;' + (exp ? (' expires=' + exp +';') : '' );
}

function CookieGet( name ) 
{
    var dc = document.cookie;
    if (dc.length <=0) return '';
    var search = name.toUpperCase() + '=';
    var offset = dc.toUpperCase().indexOf(search);
    if (offset == -1) return '';
    offset += search.length;
    var end = dc.indexOf( ';', offset );
    if (end == -1) end = dc.length;
    return dc.substring(offset, end);
}

function CookieForceExpire( name )
{
	name = name.toUpperCase();
	
    var expired = new Date();
    expired.setTime( expired.getTime() - 24*3600*1000 );
    var expired_str = expired.toGMTString();
    var nn_loops=3;
    while(nn_loops>0)
    {
		var my_cookie = CookieGet(name);
        if (my_cookie.length<=0)
		{
    	    break;
		}
        document.cookie = name + '=' + my_cookie + '; path=/; expires=' + expired_str;
        document.cookie = name + '=' + my_cookie + '; domain=.zooescape.com; expires=' + expired_str;
        document.cookie = name + '=' + my_cookie + '; domain=zooescape.com; expires=' + expired_str;
        document.cookie = name + '=' + my_cookie + '; path=/; domain=.zooescape.com; expires=' + expired_str;
        document.cookie = name + '=' + my_cookie + '; path=/; domain=zooescape.com; expires=' + expired_str;
        document.cookie = name + '=' + my_cookie + '; expires=' + expired_str;

        --nn_loops;
    }
}

function PlayerLink( name, bSpecial, onlineStatus )
{
	if ( !name ) { return; }
	var uid = StringMakeValidText(name);
	name = '<A href="/user-profile.pl?usr='+uid+'">'+name+'</A>';
	var online = '';
	if ( onlineStatus )
	{
		online = '<IMG class="online" src="/img/online.png" onmouseover="UI_ShowPopup(true,\'Player is online. Click to see all players online.\',200,event);" onclick="RedirectImmediate(\'/online.pl\');">';
	}
	
	if ( bSpecial )
	{
		name += ' <IMG class="member-icon" src="/img/member-icon.png" style="cursor:pointer;" onmouseover="UI_ShowPopup(true,\'*Subscriber*<BR>Click for more info\',100,event);" onclick="RedirectImmediate(\'/membership.pl\');">';
	}
	
	if ( online )
	{
		name = '<TABLE style="white-space:nowrap;" border=0 cellpadding=0 cellspacing=0><TR><TD style="text-align:right;border:0px;">'+ online +' </TD><TD style="text-align:left;border:0px;">'+ name +'</TD></TR></TABLE>';
	}
	else
	if ( bSpecial )
	{
		name = '<DIV style="white-space:nowrap;">'+ name + '</DIV>';
	}
	return name;
}

var gAnimatorMgr;

function AnimatorMgr() 
{
	if ( gAnimatorMgr ) { return; } // singleton
	gAnimatorMgr = this;
	
	this.mAnimators = new Array();

	this.mPrevTime = undefined; //GetTimeMS();
//	DebugOutput( 'prev=' + this.mPrevTime );
	this.mAnimateID = window.setInterval( 'gAnimatorMgr.Update()', 1 );
//	this.mAnimateID = window.setTimeout( 'gAnimatorMgr.Update()', 1 );
	
	this.Update = function () 
	{
		var start = GetTimeMS(); 
		if ( !this.mPrevTime )
		{
			this.mPrevTime = start - 1;
		}
		var delta = start - this.mPrevTime; //if ( delta > 200 ) { DebugOutput( 'start=' + start + ' prevTime=' + this.mPrevTime + ' delta=' + delta ); }
		this.mPrevTime = start;
		var bAllAreDone = true;
		for ( var i=0; i < this.mAnimators.length; ++i ) 
		{
			var a = this.mAnimators[i];
			if ( a && a.Update ) 
			{
				if ( !a.mbDone ) 
				{ 
					a.Update( delta ); 
				}
				
				if ( a.mbDone )
				{
					delete this.mAnimators[i];
				}
				else 
				{ 
					bAllAreDone = false; 
				}
			} 
			else 
			{
				delete this.mAnimators[i];
			}
		}
//		this.mAnimateID = window.setTimeout( 'gAnimatorMgr.Update()', 1 );
		if ( bAllAreDone && this.mAnimators.length ) 
		{ 
			delete this.mAnimators; 
			this.mAnimators = undefined; 
			this.Kill(); 
		}
	}
	
	this.Kill = function () 
	{
		this.mPrevTime = 0;
		if ( this.mAnimateID ) 
		{
//			window.clearTimeout( this.mAnimateID );
			window.clearInterval( this.mAnimateID );
			this.mAnimateID = undefined;
		}
		delete gAnimatorMgr;
		gAnimatorMgr = undefined;
	}
}	

var elementWatching;
function Animator( obj, fCallback, nextAnimator ) 
{
	if ( !obj ) { return; }

	if ( !elementWatching )
	{
		elementWatching = obj;
	}
	
	this.mElement = obj;
	this.mRate = 0.0005;
	this.mWaitTime = 0;
	this.mCallback = fCallback;
	this.mbPaused = false;
	this.mNextAnimator = nextAnimator;
}
			
Animator.prototype.Begin = function () 
{
	this.mElapsed = 0;
	this.mCurAnimTime = 0;
	this.mbPaused = false;
	this.mbDone = false;
	if ( gAnimatorMgr == undefined ) 
	{ 
		gAnimatorMgr = new AnimatorMgr(); 
	}
	gAnimatorMgr.mAnimators.push( this );
//	DebugOutput( 'wait=' + this.mWaitTime );
};

Animator.prototype.Update = function ( delta ) 
{
	this.mElapsed += delta;
	if ( !this.mbPaused ) 
	{
		this.mCurAnimTime += delta;
		if ( this.mCurAnimTime > this.mWaitTime ) 
		{
			if ( !this.mUpdateAnimTime ) 
			{ 
				this.mUpdateAnimTime = 0; 
				delta = 1;
			}
			this.mUpdateAnimTime += delta;
			this._Update( delta );
		}
			
		if ( this.IsComplete() )
		{
			this.mUpdateAnimTime = undefined;
			this.mbDone = true;
			this.End();
		}
	}
};
	
Animator.prototype.End = function () 
{
	this.mElapsed = 0;
	this.mCurAnimTime = 0;
		
	if( this.mCallback ) 
	{
		if ( typeof( this.mCallback ) == 'function' )
		{
			this.mCallback( this.mElement );
		}
		else
		if ( typeof ( this.mCallback ) == 'object' )
		{
			var obj = this.mCallback.obj;
			var funcName = this.mCallback.funcName;
			if ( obj && obj[funcName] )
			{
				obj[funcName]( this.mElement );
			}
		}
	}
	if ( this.mNextAnimator )
	{
		this.mNextAnimator.Begin();
	}		
	
	if ( this.mElement == elementWatching )
	{
		elementWatching = undefined;
	}
};

Animator.prototype.Kill = function ()
{
	this.mbDone = true;
	if ( this.mElement == elementWatching )
	{
		elementWatching = undefined;
	}
};
	
Animator.prototype.Pause = function ( bPause )
{
	bPause ? ++this.mbPaused : --this.mbPaused;
	Math.max( this.mbPaused, 0 );
};

Animator_Blink.prototype = new Animator();
Animator_Blink.prototype.constructor = Animator_Blink;
function Animator_Blink( obj, fCallback ) 
{
	if ( !obj ) { ErrorOutput( 'No object passed.' ); return; }
	
	Animator.call( this, obj, fCallback );
	
	this.mAnimLength = 2000;
	this.mRate = 300; //on-off ms
}

Animator_Blink.prototype.Begin = function ( len, rate ) 
{
	if ( !(this.mElement && this.mElement.style) ) { return; }
	
	this.mbVisible = this.mElement.style.visibility == 'visible';
	if ( len > 0 ) 	{ this.mAnimLength = len; }
	if ( rate > 0 ) { this.mRate = rate; }
	Animator.prototype.Begin.call( this );
};
	
Animator_Blink.prototype._Update = function ( delta ) 
{
	if ( this.mCurAnimTime >= this.mRate ) 
	{
		this.mCurAnimTime = 0;
		this.mElement.style.visibility = this.mbVisible ? 'hidden' : 'visible';
		this.mbVisible = !this.mbVisible;
	}
};
	
Animator_Blink.prototype.IsComplete = function () 
{
	return (this.mElapsed >= this.mAnimLength) ? true : false;
};

Animator_Scale.prototype = new Animator();
Animator_Scale.prototype.contstructor = Animator_Scale;
function Animator_Scale( obj, fCallback )
{
//	if ( !obj ) { ErrorOutput( 'No object passed in' ); return; }
	Animator.call( this, obj, fCallback );
	
	this.mAnimLength 	= 1000;
	
	this.mStartWidth	= 0;
	this.mCurWidth 		= 0;
	this.mDestWidth 	= 10;

	this.mStartHeight	= 0;
	this.mCurHeight 	= 0;
	this.mDestHeight 	= 10;

	this.mStartFontSize = 100;
	this.mCurFontSize 	= 100;
	this.mDestFontSize 	= 100;

	this.mStartTop		= 0;
	this.mCurTop 		= 0;
	this.mDestTop 		= 0;

	this.mStartLeft		= 0;
	this.mCurLeft 		= 0;
	this.mDestLeft 		= 0;

	this.mbScaleUp		= true;
}

Animator_Scale.prototype.Begin = function ( w, h, len, fontSize ) // width and height without borders
{
	Animator.prototype.Begin.call( this );
	

	this.mStartWidth 	= this.mCurWidth = this.mElement.clientWidth;
	this.mStartHeight 	= this.mCurHeight = this.mElement.clientHeight;
	this.mDestWidth 	= w;
	this.mDestHeight 	= h;

	this.mBorderWidthW = Math.floor((this.mElement.offsetWidth - this.mStartWidth)*0.5);
	this.mBorderWidthH = Math.floor((this.mElement.offsetHeight - this.mStartHeight)*0.5);

	this.mbScaleUp = this.mCurWidth < w ? true : false;
		
	this.mCurTop = this.mStartTop = this.mElement.offsetTop;
//	if ( this.mElement.id == 'wg_sq0-0' )
//	{
//		DebugOutput( 'Start=' + this.mStartTop + ', destw=' + this.mDestWidth + ', desth=' + this.mDestHeight );
//	}
	this.mDestTop = this.mStartTop - this.mBorderWidthH + ((this.mbScaleUp ? -1 : 1) * Math.floor((this.mbScaleUp?this.mDestHeight:this.mStartHeight)*0.5));
//	if ( this.mElement.id == 'wg_sq0-0' )
//	{
//		DebugOutput( 'Dest=' + this.mDestTop );
//	}
	this.mCurLeft = this.mStartLeft = this.mElement.offsetLeft;
	this.mDestLeft = this.mStartLeft - this.mBorderWidthW + ((this.mbScaleUp ? -1 : 1) * Math.floor((this.mbScaleUp?this.mDestWidth:this.mStartWidth)*0.5));
	
//	DebugOutput( 'top=' + this.mCurTop + ', left=' + this.mCurLeft );
		
	if ( len > 0 ) { this.mAnimLength = len; }
	if ( fontSize >= 0 ) 
	{ 
		var fsize = this.mElement.style.fontSize;
		this.mStartFontSize = this.mCurFontSize = parseInt( fsize.substr(0, fsize.length-1) ); // assumes %
		this.mDestFontSize = fontSize; 
	}
};

Animator_Scale.prototype._Update = function ( delta ) 
{	
//	var rate = delta / this.mAnimLength;
	if ( elementWatching == this.mElement )
	{
//		DebugOutput( 'delta=' + delta );
	}
	var percent = Math.min( (this.mUpdateAnimTime) / this.mAnimLength, 1);
//	DebugOutput( 'percent=' + percent + ', time=' + (this.mCurAnimTime-this.mWaitTime) );
	var f = this.mbScaleUp ? Math.min : Math.max;
	if ( this.mCurWidth != this.mDestWidth )
	{
		//this.mCurWidth += Math.floor( (this.mbScaleUp ? this.mDestWidth : (-1 * this.mStartWidth) ) * rate );
		this.mCurWidth = Math.floor( this.mbScaleUp ? (this.mDestWidth*percent) : ((1-percent) * this.mStartWidth) );
		this.mCurWidth = f( this.mCurWidth, this.mDestWidth );
		this.mElement.style.width = this.mCurWidth.toString() + 'px';
		if ( percent == 1 )
		{
			if ( this.mCurWidth != this.mDestWidth )
			{
				ErrorOutput( 'Anim complete but widths not equal' );
			}
		}
	}
		
	if ( this.mCurHeight != this.mDestHeight )
	{
//		this.mCurHeight += Math.floor( (this.mbScaleUp ? this.mDestHeight : (-1 * this.mStartHeight) ) * rate );
		this.mCurHeight = Math.floor( this.mbScaleUp ? (this.mDestHeight*percent) : ((1-percent) * this.mStartHeight) );
		this.mCurHeight = f( this.mCurHeight, this.mDestHeight );
		this.mElement.style.height = this.mCurHeight.toString() + 'px';
		if ( percent == 1 )
		{
			if ( this.mCurHeight != this.mDestHeight )
			{
				ErrorOutput( 'Anim complete but heights not equal' );
			}
		}
	}					
		
	if ( this.mCurFontSize != this.mDestFontSize )
	{
		this.mCurFontSize = Math.floor( (this.mCurWidth/(this.mbScaleUp?this.mDestWidth:this.mStartWidth)) * (this.mbScaleUp ? this.mDestFontSize : this.mStartFontSize) );
		this.mCurFontSize = f( this.mCurFontSize, this.mDestFontSize );
		this.mElement.style.fontSize = this.mCurFontSize + 'px';
		if ( percent == 1 )
		{
			if ( this.mCurFontSize != this.mDestFontSize )
			{
				ErrorOutput( 'Anim complete but font sizes not equal' );
			}
		}
	}

	f = this.mbScaleUp ? Math.max : Math.min;
	if ( this.mCurTop != this.mDestTop ) // because of borders, when scaling to zero, offsetHeight may never reach zero, so need to be smart about the value to scale to
	{
		if ( this.mCurHeight == this.mDestHeight )
		{
			this.mCurTop = this.mDestTop;
		}
		else
		{
			this.mCurTop = (this.mbScaleUp ? this.mStartTop : this.mDestTop) - Math.floor(this.mElement.offsetHeight*0.5);
			this.mCurTop = f( Math.floor(this.mCurTop), this.mDestTop );
		}
		this.mElement.style.top =  this.mCurTop + 'px';
		if ( percent == 1 )
		{
			if ( this.mCurTop != this.mDestTop )
			{
				ErrorOutput( 'Anim complete but tops not equal' );
			}
		}
	}
		
	if ( this.mCurLeft != this.mDestLeft )
	{
		if ( this.mCurWidth == this.mDestWidth )
		{
			this.mCurLeft = this.mDestLeft;
		}
		else
		{
			this.mCurLeft = (this.mbScaleUp ? this.mStartLeft : this.mDestLeft) - Math.floor(this.mElement.offsetWidth*0.5);
			this.mCurLeft = f( Math.floor(this.mCurLeft), this.mDestLeft );
		}
		this.mElement.style.left = this.mCurLeft + 'px';
		if ( percent == 1 )
		{
			if ( this.mCurLeft != this.mDestLeft )
			{
				ErrorOutput( 'Anim complete but lefts not equal' );
			}
		}
	}

	if ( (this.mUpdateAnimTime) >= (this.mAnimLength) )
	{
		if ( !this.IsComplete() )
		{
			ErrorOutput( 'Time is up but not done! -- percent=' + percent + ', element=' + this.mElement.id + ', time=' + (this.mUpdateAnimTime).toString() );
		}
	}
};

Animator_Scale.prototype.IsComplete = function () 
{	
	return 	( this.mCurTop == this.mDestTop
			&& this.mCurLeft == this.mDestLeft
		 	&& this.mCurWidth == this.mDestWidth 
			&& this.mCurHeight == this.mDestHeight 
			&& this.mCurFontSize == this.mDestFontSize )
			? true : false;
};

Animator_OffScaleOn.prototype = new Animator_Scale();
Animator_OffScaleOn.prototype.constructor = Animator_OffScaleOn;
function Animator_OffScaleOn( obj, fCallback )
{
	if ( !obj ) { ErrorOutput( 'No object passed in' ); return; }
	Animator_Scale.call( this, obj, fCallback );
	this.mbVisible	= false;
}

Animator_OffScaleOn.prototype.Begin = function ( w, h, len, fontSize ) 
{
	this.mbVisible = false;
	this.mElement.style.visibility = 'hidden';
	this.mElement.style.top	 	= Math.floor(this.mElement.offsetTop + this.mElement.offsetHeight*0.5) + 'px';	
	this.mElement.style.left 	= Math.floor(this.mElement.offsetLeft + this.mElement.offsetWidth*0.5) + 'px';	
	this.mElement.style.width 	= '0px';	
	this.mElement.style.height 	= '0px';	
	this.mElement.style.fontSize = '0%';

	Animator_Scale.prototype.Begin.call( this, w, h, len, fontSize );
		
	if ( this.mElement == elementWatching )
	{
//		DebugOutput( 'Staring anim: ' + GetTimeMS() );
//		DebugOutput( 'top=' + this.mCurTop + ', offsetTop=' + this.mElement.offsetTop + ',  left=' + this.mCurLeft );
	}
};
	
Animator_OffScaleOn.prototype._Update = function ( delta ) 
{		
	Animator_Scale.prototype._Update.call( this, delta );
	
	if ( !this.mbVisible && !this.mbPaused && this.mUpdateAnimTime ) 
	{
		this.mElement.style.visibility = 'visible';
//		DebugOutput( 'Animator_OffScaleOn -- Setting to visible' );
		this.mbVisible = true;
	}

	if ( this.mElement == elementWatching )
	{
//		DebugOutput( 'Updating anim: ' + GetTimeMS() );
//		DebugOutput( 'top=' + this.mCurTop + ', offsetTop=' + this.mElement.offsetTop + ',  left=' + this.mCurLeft );
	}

};

Animator_ScaleOff.prototype = new Animator_Scale();
Animator_ScaleOff.prototype.constructor = Animator_ScaleOff;
function Animator_ScaleOff( obj, fCallback )
{
	if ( !obj ) { ErrorOutput( 'No object passed in' ); return; }
	Animator_Scale.call( this, obj, fCallback );
	
	this.mbVisible	= true;	
}

Animator_ScaleOff.prototype.Begin = function ( w, h, len, fontSize )
{
	this.mElement.style.visibility = 'visible';

	Animator_Scale.prototype.Begin.call( this, w, h, len, fontSize );	
};

Animator_ScaleOff.prototype.IsComplete = function ()
{
	var bIsComplete = Animator_Scale.prototype.IsComplete.call( this );
	if ( bIsComplete && this.mbVisible )
	{
		this.mElement.style.visibility = 'hidden';
		this.mbVisible = false;
	}
	return bIsComplete;
};

Animator_TranslateVertical.prototype = new Animator();
Animator_TranslateVertical.prototype.constructor = Animator_TranslateVertical;
function Animator_TranslateVertical( obj, fCallback, nextAnimator ) 
{
	if ( !obj ) { ErrorOutput( 'No object passed in' ); return; }
	Animator.call( this, obj, fCallback, nextAnimator );
	
	this.mStartTop = null;
	this.mCurTop = null;
	this.mEndTop = null;
	this.mType = 0;
	this.mbDown = true;

	this.mRate = 0.0005;
}

Animator_TranslateVertical.prototype.Begin = function ( startTop, endTop, waitTime, rate, type ) // 0=parabolic, 1=linear, 2=stepped
{
	if ( startTop != undefined && startTop != null ) 
	{ 
		this.mStartTop = this.mCurTop = startTop; 
	}
	if ( endTop != undefined && endTop != null ) 
	{ 
		this.mEndTop = endTop; 
	}
		
	this.mbDown = (this.mStartTop <= this.mEndTop) ? true : false;
	if ( waitTime > 0 ) { this.mWaitTime = waitTime; }
	if ( rate > 0 ) { this.mRate = rate; }
	this.mType = type;
	this.mElement.style.top = this.mStartTop + 'px';
	Animator.prototype.Begin.call( this );
};
	
Animator_TranslateVertical.prototype._Update = function ( delta ) 
{
	if ( this.mPreUpdateFunc )
	{
		var obj = this.mPreUpdateFunc.obj;
		var funcName = this.mPreUpdateFunc.funcName;
		if ( obj && obj[funcName] )
		{
			obj[funcName]();
		}
	}

	var prevTop = this.mCurTop;
	if ( this.mType == 2 )
	{
//		if ( this.mCurAnimTime > this.mWaitTime )
		if ( this.mUpdateAnimTime )
		{
			this.mCurAnimTime = 0;
			this.mUpdateAnimTime = undefined;
			this.mCurTop = Math.floor((this.mbDown?1:-1)*this.mRate + this.mCurTop);
		}
	}
	else
	{
		var v = this.mUpdateAnimTime; //this.mCurAnimTime-this.mWaitTime;
		this.mCurTop = Math.floor( this.mStartTop + (this.mbDown?1:-1)*( v*(this.mType==1?1:v)*this.mRate ) );
	}
	
	this.mCurTop = (this.mbDown ? Math.min( this.mCurTop, this.mEndTop ) : Math.max( this.mCurTop, this.mEndTop ));
	this.mElement.style.top = this.mCurTop.toString() + 'px';

	if ( this.mPostUpdateFunc )
	{
		var funcName = this.mPostUpdateFunc.funcName;
		if ( obj && obj[funcName] )
		{
			obj[funcName]();
		}
	}
};
	
Animator_TranslateVertical.prototype.IsComplete = function () 
{
	return (this.mEndTop == this.mCurTop);
};

Animator_ScaleBorder.prototype = new Animator();
Animator_ScaleBorder.prototype.constructor = Animator_ScaleBorder;
function Animator_ScaleBorder( obj, fCallback ) 
{
	if ( !obj ) { ErrorOutput( 'No object passed in' ); return; }
	Animator.call( this, obj, fCallback );

	this.mStartThick 	= 0;
	this.mEndThick 		= 0;	
	this.mCurThick 		= 0;
	
	this.mRate = 300; //delay ms between changes to thickness
}
	
Animator_ScaleBorder.Begin = function ( startThick, endThick, rate, numTimes ) 
{
	if ( startThick != undefined ) 	{ this.mStartThick 	= startThick; this.mCurThick = this.mStartThick; }
	if ( endThick != undefined ) 	{ this.mEndThick 	= endThick; }
	if ( rate > 0 ) 				{ this.mRate = rate; }
	if ( numTimes > 1 )				{ this.mNumTimes = numTimes; }
	this.mElement.style.borderWidth = this.mCurThick.toString() + 'px';
	this.mElement.style.padding = (this.mEndThick - this.mCurThick).toString() + 'px';
	
	Animator.prototype.Begin.call( this );
};
	
Animator_ScaleBorder._Update = function ( delta ) 
{
//	if ( this.mCurAnimTime >= this.mRate )
	if ( this.mUpdateAnimTime >= this.mRate )
	{
		if ( this.mCurThick < this.mEndThick )
		{
			++this.mCurThick;
		}
			
//		this.mCurAnimTime = 0;
		this.mUpdateAnimTime = undefined;
		this.mElement.style.borderWidth = this.mCurThick.toString() + 'px';
		this.mElement.style.padding = (this.mEndThick - this.mCurThick).toString() + 'px';
	}
};
	
Animator_ScaleBorder.prototype.IsComplete = function () 
{
	return (this.mCurThick == this.mEndThick);
};

/*
if ( !IsIE() )
{
    var o = gk_get_el( 'player_note' );
    if (o)
    {
	o.innerHTML = 'Note: the latest version of a compatible media player is required<br>for the sound playback (such as <a href="http://www.apple.com/quicktime/download/" target="_blank">Apple Quicktime</a>, for example)';
    }
    
    if (get_sound_vol()>0)
    {
	get_sound_elem();
    }
}
*/

//ZooSound.mSounds = new Array();
function ZooSound( src, parent )
{
	this.mElement = '';
	this.mSrc = src;
	if ( this.mSrc )
	{
		this.Load( parent );
	}

	if ( !ZooSound.mSounds ) { ZooSound.mSounds = new Array(); }	
	ZooSound.mSounds.push( this );
}

ZooSound.prototype.Play = function ()
{
	var bSoundsOn = ConvertToInt( CookieGet( 'sfx' ) );
	if ( !bSoundsOn ) { return; }

	var volume = 75;
	var bSuccess = false;
	this.Load();
	if ( !this.mElement ) { return bSuccess; }
	var o = this.mElement;	
	if ( IsIE() )
	{
		o.autostart = 'true';
		o.volume = (volume-100)*40;
        o.src = this.mSrc;
		bSuccess = true;
	}
    else
	{
		volume = Math.floor( 255 * volume / 100 );
		try { o.Stop(); } catch(e){}
		try { o.SetVolume( volume ); } catch(e){}
		try { o.Rewind(); } catch(e){}
		try { o.Play(); bSuccess = true;} catch(e) { bSuccess=false; }
		//alert( bSuccess );
		if ( !bSuccess )
		{	
			try { o.volume = (volume-100)*40; } catch(e){}
			try { o.stop(); } catch(e){}
			try { o.rewind(); } catch(e){}
			try { o.play(); bSuccess = true;} catch(e){ bSuccess = false;}
    	}
	}
	return bSuccess;
};

ZooSound.prototype.Load = function ( parent )
{
	var bSoundsOn = ConvertToInt( CookieGet( 'sfx' ) );
	if ( !bSoundsOn ) { return; }

	if ( this.mElement ) { return; }
	
	var parentName = 'zoo_container_sound';
	var name = this.mSrc.replace( /\W/g, '_' );
	
	if ( IsIE() )
	{
    	var o = document.createElement( 'bgsound' );
	    o.id = name;
		if ( parent )
		{
			if ( !parent.appendChild( o ) ) { return; }
		}
		else
		{
			document.body.appendChild( o );
		}
	}
	else
	{
	    var c = GetElement( parentName );
    	if ( !c )
		{
			c = document.createElement( 'DIV' );
			if ( !c ) { return; }
			c.id = parentName;
			if ( parent )
			{
				if ( !parent.appendChild( c ) ) { return; }
			}
			else if ( !document.body.appendChild( c ) )
			{
				ErrorOutput( 'Could not append parent element to document' );
				return;
			}
			c.style.height = '0px';
		}
	
		var div = document.createElement( 'DIV' );
		if ( !div ) { return; }
		div.innerHTML = '<embed id="'+name+'" type="audio/x-wav" EnableJavaScript="true" autostart="false" autoplay="false" loop="false" width=0 height=0 volume=0 src="' + this.mSrc + '"></embed>';
    	if ( !c.appendChild( div ) )
		{
			ErrorOutput( 'Could not append child sound to parent.' );
			return;
		}
	}
	this.mElement = GetElement( name );
};

function ZooOnBlur()
{
//	DebugOutput( 'lost focus' );
	// In IE6, all sounds play when the window goes from minimized to visible so turn all sounds down (and stopped) when losing focus.
	// All sounds are reset to their volume and rewound when played
	
	if ( !ZooSound.mSounds ) { return; }
	
	for ( var i = 0; i < ZooSound.mSounds.length; ++i )
	{
		var s = ZooSound.mSounds[i];
		if ( s )
		{
			if ( IsIE() )
			{
				s.volume = (-100)*40;
			}
    		else
			{
				var bSuccess = true;
				try { s.Stop(); } catch(e){}
				try { s.SetVolume( 0 ); } catch(e){ bSuccess = false; }
				if ( !bSuccess )
				{	
					try { o.volume = (-100)*40; } catch(e){}
					try { o.stop(); } catch(e){ bSuccess = false; }
				}
			}			
		}
	}
}

if ( window.addEventListener )
{
	window.addEventListener( 'blur', ZooOnBlur, false );
} 
else 
if ( window.attachEvent ) 
{
	window.attachEvent( 'onblur', ZooOnBlur );
}

function Flag()
{
	this.mVal = 0;

}
Flag.prototype.Get = function()
{
	return this.mVal;
};
	
Flag.prototype.Set = function( v, bOnOff )
{
	if ( bOnOff !== undefined && !bOnOff )
	{
		this.Clear( v );
	}
	else
	{
		this.mVal |= v;
	}
};

Flag.prototype.Clear = function( v )
{
	this.mVal &= ~v;
};
	
Flag.prototype.Test = function( v )
{
//	DebugOutput( 'Testing:' + this.mVal + ' for ' + v );
	return (this.mVal & v) != 0 ? true : false;
};


//--- Menu handling for main meun that's on every page ---//
//ZEGlobals.mMainMenuMgr = new Object();

function ZE_SurveyChoice(desc,val,tally,bLeader,bSelectionClearsOthers)
{
	this.mValue = val;
	this.mDescription = desc;
	this.mTally = tally;
	this.mbLeader = bLeader ? true : false;
	this.mbSelectionClearsOthers = bSelectionClearsOthers ? true : false;
}

function ZE_Survey( surveyid, bMultiVote )
{
	ZE_Survey.mSingleton = this;
	if (!surveyid) { return; }
	
	this.mSurveyID 	= surveyid;
	this.mDiv 		= document.createElement('DIV');
	this.mDiv.style.display = 'none';
	this.mbMultiVote= bMultiVote;
}

ZE_Survey.OnSubmit = function()
{
	var s = ZE_Survey.mSingleton;
	if ( !(s&&s.mChoices&&s.mSubmitElement) ) { return; }
	
	var num = s.mChoices.length;
	var val = '';
	var bOK = false;
	for ( var i = 0; i < num; ++i )
	{
		var thing = s.mChoices[i];
		if ( !thing ) { continue; }
		thing = thing.mElement;
		if ( !thing ) { continue; }
		
		if ( thing.checked )
		{
			if ( val ) { val += ','; }
			val += thing.value;
			bOK = true;
		}
	}
	
	if ( bOK )
	{
		if ( s.mbMultiVote )
		{
			var el = GetElement( 'ze_survey' );
			if ( el ) { el.value = val; }
		}	
		window.setTimeout( function(){s.mSubmitElement.disabled=true;}, 1 );
	}
	else
	{
		alert( 'You must make a choice before submitting.' );
		return false;
	}
	return true;
};

ZE_Survey.ChoiceOnClick = function(el,i) 
{
	var s = ZE_Survey.mSingleton;
	if ( !(s&&s.mChoices&&el&&s.mSubmitElement&&i>=0) ) { return; }

	var selectionClears = s.mSelectionThatClearsOthers;

	var choice = s.mChoices[i];
	var bUnselectOthers = choice.mbSelectionClearsOthers;
	
	var bDisabled = true;

	// What's checked?  
	var num = s.mChoices.length;
	var val;
	for ( var i = 0; i < num; ++i )
	{
		var thing = s.mChoices[i];
		if ( !thing ) { continue; }
		thing = thing.mElement;
		if ( !thing ) { continue; }
		
		if ( thing.checked )
		{
			bDisabled = false;
			if ( !bUnselectOthers )
			{
				if( selectionClears )
				{
					var blah = selectionClears.mElement;
					if ( blah )
					{
						blah.checked = false;
					}
				}
				break;
			}
			else
			if ( thing != el )
			{
				thing.checked = false;
			}
		}
	}
	
	s.mSubmitElement.disabled = bDisabled;
};

ZE_Survey.prototype.Configure = function( desc, choices, votes, page )
{
	if ( !(desc && choices) ) { return; }
	
	this.mChoices = choices;
	
	this.mbVoted = (votes&&votes.length)?true:false;
		
	var strings = [];
	strings.push('<FORM action="/'+page+'" method=post onsubmit="return ZE_Survey.OnSubmit(this);"><TABLE border=0 cellpadding=0 cellspacing=0 class="survey"><TR><TH>SURVEY</TH></TR>');
	strings.push(	'<TR><TD>'+desc+'</TD></TR>' );
	if ( choices )
	{
		strings.push( '<TR><TD><TABLE border=0 cellpadding=0 cellspacing=0>' );

		for ( var i = 0; i < choices.length; ++i )
		{
			var choice = choices[i];
			if ( !choice ) { continue; }
			
			var vote = this.mbVoted ? votes[choice.mValue] : 0;
			
			if ( choice.mbSelectionClearsOthers )
			{
				this.mSelectionThatClearsOthers = choice;
			}
			
			// error if choice.mDescription or choice.mPercentage or choice.mValue are not defined
			var elementID = 'ze_survey_'+i;
			choice.mElementID = elementID;
			if ( !this.mbVoted ) // allow people to change their vote?
			{
				var type = this.mbMultiVote ? ('type=checkbox id="'+elementID+'" name="'+elementID+'"') : ('type=radio id="'+elementID+'" name="ze_survey"');
				strings.push( 	'<TR><TD><INPUT '+type+' value="'+choice.mValue+'" onclick="ZE_Survey.ChoiceOnClick(this,'+i+');"></TD><TD style="text-align:left;"><LABEL for="ze_survey_'+i+'">'+choice.mDescription+'</LABEL></TD></TR>' );
			}
			else
			{
				var extra = '';
				if ( vote )
				{
					extra = '<SPAN style="font-weight:bold;cursor:pointer;" onmouseover="UI_ShowPopup(true,\'Your vote\',100,event);">&radic;</SPAN>';
				}

				var s = '';
				if ( choice.mbLeader )
				{
					s = ' style="font-weight:bold;"';
				}
				strings.push( 	'<TR><TD style="padding-right:4px; width:40px;" >'+extra+'</TD><TD'+s+'>'+choice.mDescription+'</TD><TD style="width:80px;">'+choice.mTally+'</TD></TR>');
			}
		}
		
		if ( !this.mbVoted )
		{
			strings.push( 	'<TR><TD colspan=2><INPUT id="ze_survey_submit" name="ze_survey_submit" type=submit value="Submit" disabled></TD></TR>' );
		}
		strings.push( '</TABLE></TD></TR>' );
	}
	strings.push(	'</TABLE><INPUT type=hidden name="surveyid" value="'+this.mSurveyID+'">' );
	if ( this.mbMultiVote )
	{
		strings.push( '<INPUT type=hidden name="multivote" value=1><INPUT type=hidden id="ze_survey" name="ze_survey">' );
	}
	strings.push('</FORM>');
	
	this.mDiv.innerHTML = strings.join('');
	
};

ZE_Survey.prototype.Render = function ( attachNode )
{
	if ( !attachNode ) { return; }
	
	attachNode.appendChild(this.mDiv);
	this.mDiv.style.display = '';
	
	// go through and get the elements
	for ( var i = 0; i < this.mChoices.length; ++i )
	{
		var choice = this.mChoices[i];
		if ( !choice ) { continue; }
		
		choice.mElement = GetElement( choice.mElementID );
	}
	
	this.mSubmitElement = GetElement( 'ze_survey_submit' );
};


function ZE_GetDeltaRating(rating1,rating2,score)
{
   var K = 10;
   var SE = 1 / ( 1 + Math.pow(10,(rating2-rating1)/400) );
   
   return K*(score-SE);
}

function ZE_GetDeltaRating_Points(rating1,rating2,score,points)
{
	if ( points && points > 1 )
	{
		--points;
		rating1 -= score * points * 100;
		rating2 -= (1-score) * points * 100;   
	}
	
	return ZE_GetDeltaRating( rating1, rating2, score );
}

function ZE_BG_RatingStakesOnChange( elType, elCube, dst, rating1, rating2 )
{
	if ( !(elType&&elCube&&dst&&rating1&&rating2) ) { ErrorOutput('No ratings select element and/or destination element'); return; }
	
	var type = 1;
	var opts = elType.getElementsByTagName('OPTION');
	for ( var i=0; i < opts.length; ++i )
	{
		var opt = opts[i];
		if ( opt && opt.selected )
		{
			type = opt.value;
			break;
		}
	}
	
	var cube = 1;
	opts = elCube.getElementsByTagName('OPTION');
	for ( var i=0; i < opts.length; ++i )
	{
		var opt = opts[i];
		if ( opt && opt.selected )
		{
			cube = opt.value;
			break;
		}
	}
	
	var win 	= (ZE_GetDeltaRating_Points(rating1,rating2,1,type*cube)).toFixed(2);
	var loss 	= (ZE_GetDeltaRating_Points(rating1,rating2,0,type*cube)).toFixed(2);
//	dst.innerHTML = 'win: ' + win + ', lose: ' + loss;
	dst.innerHTML = win + ' / ' + loss;
}
/*
function ZE_BG_RatingStakesTable( rating1, rating2, multiplier )
{
	if ( !multiplier ) { multiplier = 1; }
	
	var html = '<TABLE border=0 cellpadding=0 cellspacing=0 width=100% class=small>';
	var data = [
		['Regular Win: ', 		], ['Regular Loss: ',		(ZE_GetDeltaRating_Points(rating1,rating2,0,1*multiplier)).toFixed(2)],
		['Gammon Win: ', 		(ZE_GetDeltaRating_Points(rating1,rating2,1,2*multiplier)).toFixed(2)], ['Gammon Loss: ',		(ZE_GetDeltaRating_Points(rating1,rating2,0,2*multiplier)).toFixed(2)],
		['Backgammon Win: ', 	(ZE_GetDeltaRating_Points(rating1,rating2,1,3*multiplier)).toFixed(2)], ['Backgammon Loss: ',	(ZE_GetDeltaRating_Points(rating1,rating2,0,3*multiplier)).toFixed(2)]
	];
	for ( var i = 0; i < data.length; ++i )
	{
		var entry = data[i];
		html += '<TR><TD style="text-align:left;padding-right:4px;">'+entry[0]+'</TD><TD style="padding-left:4px;text-align:right;">'+entry[1]+'</TD></TR>';
	}
	html += '</TABLE>';	
	return html;
}
*/

function Message(id,time,numid,name,msg,bEdited)
{
	this.mID 		= id;
	this.mTime 		= time;
	this.mNumID		= numid;
	this.mName		= name;
	this.mText		= msg;
	this.mbEdited	= bEdited ? true : false;
		
	this.mClass;
	this.mbShowName = true;
}

function MessageList( list )
{
	this.mMessages = list ? list : new Array();	
}

MessageList.prototype.GetNum = function() { return this.mMessages ? this.mMessages.length : 0 };
MessageList.prototype.Get = function( i ) 
{ 
	if ( !(this.mMessages && i>=0 && i < this.mMessages.length) ) { return; }	
	return this.mMessages[i];
};

MessageList.prototype.GetByID = function( id ) 
{ 
	if ( !this.mMessages ) { return; }
	for ( var i = this.mMessages.length-1; i >=0; --i )
	{
		var msg = this.mMessages[i];
		if ( msg && msg.mID == id ) { return msg; }
	}
};

MessageList.prototype.Insert = function( msg )
{
	if ( !msg ) { return; }
	
	if ( !this.mMessages )
	{
		this.mMessages = [];
	}
	
	this.mMessages.push( msg );
};

MessageList.prototype.Update = function( msg )
{
	if ( !(msg&&this.mMessages) ) { return; }

	var id = msg.mID;
	for ( var i = 0; i < this.mMessages.length; ++i )
	{
		var other = this.mMessages[i];
		if ( other && other.mID == id )
		{
			msg.mbEdited = false;
			if ( other && other.mText != msg.mText )
			{
				msg.mbEdited = true;
				this.mMessages[i] = msg;
			}
			return;
		}
	}		
};

MessageList.prototype.Delete = function( msg )
{
	if ( !(msg&&this.mMessages) ) { return; }

	var id = msg.mID;
	for ( var i = 0; i < this.mMessages.length; ++i )
	{
		var other = this.mMessages[i];
		if ( other && other.mID == id )
		{
			this.mMessages.splice(i,1);
			return;
		}
	}		
};

MessageList.prototype.DoesNumIDExist = function( numid )
{
	if ( !(this.mMessages && i>=0 && i < this.mMessages.length) ) { return false; }	
	for ( var i = 0; i < this.mMessages.length; ++i )
	{
		var msg = this.mMessages[i];
		if ( msg && msg.mNumID == numid ) { return true; }
	}
	return false;
};
