Weewar Suite

By pluto2 Last update Jun 22, 2008 — Installed 380 times. Daily Installs: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

the source is over 100KB, syntax highlighting in the browser is too slow

// ==UserScript==
// @name           Weewar Suite
// @namespace      http://www.weewarscripts.info
// @include        http://*weewar.com/game/*
// ==/UserScript==


///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////// WARNING /////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
// This script uses UNSAFE access to the web page's window object - there is     //
// *potential* for malicious scripts on the page to use this script for SINISTER //
// purposes - for details, see doc at http://wiki.greasespot.net/UnsafeWindow    //
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////

// portions of this script were helped by information found at http://www.webwargaming.com 

///////////////////////////////////////////////////////////////////////////////////

/*

  TODO list
  
  create a range class for encapsulating all of the range code?!
  create a class that encapsulates all of the attack range assistant code? maybe all of the functionality should be done as classes?
  update the metadata in any and all relevant objects *as* the player takes their turn - i.e. update hex data if units are moved to and from them, etc.

	code on link to remove game: "return oamSubmitForm('content:j_id244','content:j_id244:removeGameLink');" id="content:j_id244:removeGameLink"

*/

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////// START OF WEEWAR-SPECIFIC SCRIPT /////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//const m_UpdateURL = "http://www.weewarscripts.info/updates/check.aspx?sid={0}&iid={1}";
const m_UpdateURL = "http://www.sapientdevelopment.com/dotnetnuke/weewar/report.aspx?sid={0}&iid={1}";
const m_ScriptId = "33363384-02D7-F4B6-A501-DF15E700E6AC";
const m_ScriptVersion = 0.5;

// other global variables
var m_ConfigurationSettings;	// stores all of the user's preferences for the suite of features
var m_UnsafeWeewarMap;        // this is the object that Weewar developers use on the client for storing data
var m_WeewarMap;              // this is our version of the map object
var m_CtrlKeyDepressed;       // boolean flag to help with the attack range assistant functionality
var m_ShiftKeyDepressed; 
var m_DefaultClickFunction;   // stores the default click function to help us hijack default behavior
var m_StaticMetadata;         // organizes metadata about the game, map, etc. that will not change during a game
var m_GameId;                 // game Id number
var m_GameServer;					// need this for API calls because you might not be logged into the main weewar.com server which would make the call fail
var m_CommandToolbarStart;		// handle for inserting command links into the toolbar



// function onunload() {	
	// try {
		// saveConfigurationSettings(); // save the user's settings
	// } catch(e) {
		// GM_log(e.message);
		// GM_log(e.lineNumber);
	// }
// }

///////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////
///////////////////// START OF OPTIONS TOOLBAR DRAWING ////////////////////////////
///////////////////////////////////////////////////////////////////////////////////

function drawToolbar() {

	////// The main toolbar ////////////////////////////////////////////////
	var gameMap = document.getElementById("game");	
	m_CommandToolbarStart = A({"id":"suiteToolbar", "style":"font-size: 0.85em;"}, "Weewar Suite Commands: ");
	var commandsToolbar = DIV({"title":"Weewar Suite Commands", "style":"background-color: #EEE; padding: 3px 3px 5px 3px; margin: 7px 0px 0px 0px;"}, m_CommandToolbarStart);
	insertSiblingNodesBefore(gameMap, commandsToolbar);
	
}

///////////////////////////////////////////////////////////////////////////////////
/////////////////////// END OF OPTIONS TOOLBAR DRAWING ////////////////////////////
///////////////////////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////////////////////
/////////////////////////// START OF GENERAL AESTHETICS////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////

function doGeneralAesthetics() {

	///// map resizing ///////////////////////////////////////
	///// need to resize the map window to account for the toolbar	
	var mapWindow = $('game');
	fixWindow();
	
	// steal the onresize event so we get the right resizing everytime
	unsafeWindow.onresize = function() { unsafeWindow.resize();	}

	// tell the normal resize function to call the fixWindow function after it is done
	var resizeFunction = unsafeWindow.resize;
	unsafeWindow.resize = function() {
		resizeFunction();		
		fixWindow();
	}
	
	// cuts off 20px from the map window to account for the 25px toolbar and the extra margin already on the window
	function fixWindow() {
		var oldMapHeight = mapWindow.style.height.replace("px", "");
		mapWindow.style.height = oldMapHeight - 20 + 'px';	
	}
	
	
	///// shrink main left margin ////////////////////////////////
	/////	to give more room for everything.  30px is a bit too much
	$('wrap').style.marginLeft = "10px";
	$('wrap').style.marginTop = "15px";
	
	
	///// delete the inspector //////////////////////////////////
	/////	Not really that useful for experienced players
	$("inspector").style.display = "none";
	
	
	///// automatically turn off email notification /////////////////
	///// because it is annoying
	var emailNotificaitonBox = $('emailNotification');
	if (emailNotificaitonBox.checked) {
			emailNotificaitonBox.checked = false; // uncheck the box
			unsafeWindow.command('email_no', m_GameId); // send in the command to the server
	}
	
	// add in option to display old hovercraft
	
	// can also apply "skins" here
}


///////////////////////////////////////////////////////////////////////////////
/////////////////////// END OF GENERAL AESTHETICS ////////////////////////////
///////////////////////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////////////////////
/////////////////////////// START OF END GAME MENU ////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////



function startEndOfGameMenu() {
	var endRoundLinkId = "endRoundLink";
	var originalEndRoundLink = $(endRoundLinkId); // <a href="#" onClick="countdown( this, 'End your turn?', finishTurn );" id="">End your turn?</a>
	var safeEndRoundLink = A({href:"#", id:"safeEndRoundLink", style:"margin-left: 5px;"}, "Safely?");
	var immediateEndRoundLink = A({href:"#", id:"immediateEndRoundLink", style:"margin-left: 5px;"}, "Immediately?");
	var endRoundLinks = SPAN({id:endRoundLinkId}, SPAN({}, "End your turn:"), safeEndRoundLink, immediateEndRoundLink);
	swapDOM(originalEndRoundLink, endRoundLinks);

	var DoCountdown = function(link) {
		var countdownLinkText = link.innerHTML;
		if (link.innerHTML.indexOf("abort") > -1) { 
			unsafeWindow.clearTimeout(unsafeWindow.countdownTimeout); 
			unsafeWindow.countingLink.innerHTML = unsafeWindow.countdownLinkText; 
		} else { 
			unsafeWindow.seconds = 4; 
			unsafeWindow.countdownFunction = unsafeWindow.finishTurn; 
			unsafeWindow.countdownLinkText = countdownLinkText; 
			unsafeWindow.countingLink = link; 
			unsafeWindow.countdownUpdate(); 
		} 
	}

	connect(safeEndRoundLink, "onclick", function(e) {
	  //TODO: this would be a good place to signal that this is happening and let observers take care of things
	  e.preventDefault(); // prevents the hash (#) from being tacked onto the URL
	  DoCountdown(safeEndRoundLink);
	});
	
	connect(immediateEndRoundLink, "onclick", function(e) {
	  //TODO: this would be a good place to signal that this is happening and let observers take care of things
	  e.preventDefault(); // prevents the hash (#) from being tacked onto the URL
	  unsafeWindow.finishTurn();
	});

}


///////////////////////////////////////////////////////////////////////////////////
//////////////////////////// END OF END GAME MENU /////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////////
////////////////////////////// START OF BANKER/////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////

// just the toolbar for now
function enableBanker() {
	var bankerLink = A({"id":"bankerLink", "href":"#", "style":"font-size: 0.85em; padding-left: 8px; color: #00BF00; text-decoration: none;"},
					IMG({"id":"bankerLinkImage", "width":"16", "height":"16", "src":"http://www.plutosforge.com/images/money_dollar.png"}),"Banker");	
	insertSiblingNodesAfter(m_CommandToolbarStart,bankerLink);
	
	connect(bankerLink, "onclick", partial(showBankerLoading)); // event handler for starting the auto repair
}

//create an array to associate the player number with base color
var colorIndex = {
0 : "blue",
1 : "red",
2 : "purple",
3 : "yellow",
4 : "green",
5 : "white"};

var unitCosts = {
"001.png" : 75,
"002.png" : 150,
"003.png" : 200,
"004.png" : 450,
"005.png" : 200,
"006.png" : 600,
"007.png" : 900,
"008.png" : 400,
"009.png" : 600,
"010.png" : 1200,
"antiair.png" : 300,
"hovercraft.png" : 300,
"heli.png" : 600,
"jet.png" : 800,
"bomber.png" : 900,
"speedboat.png" : 200,
"destroyer.png" : 900,
"sub.png" : 1000,
"battleship.png" : 2000
}
/* 
m_GameId = (/game\/([0-9]*)/g).exec(window.location.href)[1];
m_GameServer = (/http:\/\/([a-z.0-9]*)/g).exec(window.location.href)[1]; */

var playerColors = new Array();
var playerTotalCredits = new Array();
var playerRounds = new Array();
var playerBuilds = new Array();
var playerBaseCount = new Array();
var numPlayers;

var totalRounds = parseInt(getElementsByClassName(document, 'span', 'round')[0].textContent.substr(getElementsByClassName(document, 'span', 'round')[0].textContent.indexOf(' ')+1));
var gameRounds = new Array(/* totalRounds+1 */);

/* //add a $ sign next to the history controls for loading the script
var commandBoxChild = document.getElementById('infoLine');
var startBankerLink = createDOMElement("a", {id:"startBankerLink", href:"#", innerHTML:"Banker"}, {color:"#00BF00"});
//commandBoxChild.parentNode.insertBefore(startBankerLink, commandBoxChild);
appendChildren(commandBoxChild,startBankerLink);

startBankerLink.addEventListener("click", function(e) {
	showBankerLoading();
    e.preventDefault();
  }, false); */
			
function showBankerLoading()
{
	//make the barber shop pole come up just like when loading a history file
	//document.getElementById('historyLinks').style.display='none;';
	//document.getElementById('loadingHistory').style.display='';
	//document.getElementById('loadingHistory').getElementsByTagName('a')[0].style.display='none;';

	GM_log('getting map info');
	getMapInfo();	
}

var gameId = document.getElementById('menuForm').getAttribute('action');
gameId = gameId.substr(gameId.lastIndexOf('/')+1);
var initialCredits;
var perBaseIncome;

//first API call to get the initial credits and per base income for the game
function getMapInfo()
{
	GM_xmlhttpRequest(
	{
		method: 'GET',
		url: 'http://' + m_GameServer + '/api1/game/' + m_GameId,
		headers: {
			'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey/0.3',
			'Accept': 'application/atom+xml,application/xml,text/xml',},
		onload: function(responseDetails)
		{
			//GM_log(responseDetails.responseText);
			var parser = new DOMParser();
			var dom = parser.parseFromString(responseDetails.responseText,"application/xml");
			//GM_log("initial credits: " + dom.getElementsByTagName('initialCredits')[0].textContent + ", per base income: " + dom.getElementsByTagName('creditsPerBase')[0].textContent);
			
			initialCredits = parseInt(dom.getElementsByTagName('initialCredits')[0].textContent) ;
			perBaseIncome = parseInt(dom.getElementsByTagName('creditsPerBase')[0].textContent);	
			GM_log("initial credits: " + initialCredits + ", per base income: " + perBaseIncome);
			
			startBanker();		
		}
	});
}

//makes a call to the weewar ajax controller to get the history file
function startBanker()
{		
	var url =  'http://' + m_GameServer + '/ajax/click.jsp';
	var pars = 'method=initialState&object=' + m_GameId;
	pars+= '&tbUid=' + (new Date()).getTime();
	var infoURL = url + '?' + pars;
	GM_log(infoURL);
	GM_xmlhttpRequest(
	{
		method: 'GET',
		url: infoURL,
		headers: { 
			'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey/0.3',
			'Accept': 'application/atom+xml,application/xml,text/xml'},
		onload: function(responseDetails)
		{
			GM_log('status,' + responseDetails.status + 'statusText,' + responseDetails.statusText + 'responseHeaders,' + responseDetails.responseHeaders + 'readyState,' + responseDetails.readyState + 'text,' + responseDetails.responseText );
			
			//for some games there is no history file and you get that java.lang error
			if(responseDetails.responseText.search('error') > -1)
			{
				GM_log('did not work - outputting error')
				outputError();
			}	
			else
			{
				parseHistory(responseDetails);
				GM_log('did work - outputting data')
				outputData();
			}
			
					//when done parsing and outputting, put the history controls back 
				//	document.getElementById('historyLinks').style.display='';
				//	document.getElementById('loadingHistory').style.display='none;';
				//	document.getElementById('loadingHistory').getElementsByTagName('a')[0].style.display='';
		}
	}); 
}

function parseHistory(originalResponse)
{
	GM_log('starting history file parse...');
	var parser = new DOMParser();
	var responseXML = parser.parseFromString(originalResponse.responseText,"application/xml");
			
	//initialize the data storage arrays
	initArrays();
	
	var playerCounter = 0;
	//GM_log("num playres: " + numPlayers + ", pcl: " + playerColors.length);	
	
	//figure out the starting base positions from the first field in the history file
	GM_log('finding starting bases...');
	findStartingBases(responseXML.getElementsByTagName('fields')[0]);
		//make a little parser for the html that describes each event
		//var eventHTML = document.createElement(eventHTML);
	//loop through all the events in the history file and parse them out
	GM_log('looping through ' + responseXML.getElementsByTagName('event').length + ' history events...');
 	for(var i = 0; i < responseXML.getElementsByTagName('event').length; i++)
	{		
		//eventHTML.innerHTML = responseXML.getElementsByTagName('event')[i].getElementsByTagName('html')[0].textContent; 
		var eventType = getEventType(responseXML.getElementsByTagName('event')[i]);  //eventHTML.getElementsByTagName('div')[0].nextSibling.textContent;
 		var eventField = responseXML.getElementsByTagName('event')[i].getElementsByTagName('field')[0];
		var player = playerColors[colorIndex[playerCounter]]; //getEventPlayer(eventHTML);
		GM_log("event #: " + responseXML.getElementsByTagName('event')[i].getAttribute('id') + ", event type: " + eventType + ", current player: " + player + "(" + playerCounter + ")");
		//add up each time a player finishes a round
		if(eventType == 'round')
		{
			playerRounds[player]++;
			//after a round is done, go to the next player
			if (playerCounter < numPlayers -1 ) playerCounter++;
			else playerCounter = 0;
		}
		//each time a player captures a base, save it to gameRounds with the round it occured and the coordinates of the base
		if(eventType == 'capture')
		{			
			GM_log("event #: " + responseXML.getElementsByTagName('event')[i].getAttribute('id') +" - right after round: " + playerRounds[player] +  ", player: " + player + " captured a base at: " + eventField.getAttribute('x') + ", " + eventField.getAttribute('y'));
			var baseKey = "x:" + eventField.getAttribute('x') + ",y:" + eventField.getAttribute('y');
			gameRounds[playerRounds[player]+2][baseKey] = player; // +1 is the current round, but +2 is the next round where the new base income actually starts to acrue
		}
		//add up the total costs of all the stuff the player built
		if(eventType == 'build')
		{
			var unitImageFile = eventField.getElementsByTagName('unit')[0].textContent;
			var unitType = unitImageFile.substr(unitImageFile.indexOf('_')+1);
			//GM_log(player + " built a _" + unitType + "_ in round " + (playerRounds[player] + 1 ));
			playerBuilds[player] += unitCosts[unitType];
		} 
	}
}

function getEventType(event) {
	//GM_log("event id: " + event.getAttribute('id'));
	
	if(event.getElementsByTagName('setAllBright').length > 0) {
		//GM_log('end turn event');
		return "round";
	} 
	else if(event.getElementsByTagName('terrain').length > 0) {
		var x = event.getElementsByTagName('terrain')[0].parentNode.getAttribute('x');
		var y = event.getElementsByTagName('terrain')[0].parentNode.getAttribute('y');
		var baseImageFile = event.getElementsByTagName('terrain')[0].textContent;
		var baseColor = baseImageFile.substr(0,baseImageFile.indexOf('_'));
		var baseType = baseImageFile.substr(baseImageFile.indexOf('_')+1);
		
		if(baseType == "city.png") {
			GM_log('capture of a: ' + baseColor + " " + baseType + " at x: " + x + ", y: " + y );		
			return "capture";	
		}
	}
	else if(event.getElementsByTagName('field').length == 1 && event.getElementsByTagName('unit').length > 0 && event.getElementsByTagName('info').length > 0 ) {
		var x = event.getElementsByTagName('unit')[0].parentNode.getAttribute('x');
		var y = event.getElementsByTagName('unit')[0].parentNode.getAttribute('y');
		var unitImageFile = event.getElementsByTagName('unit')[0].textContent;
		var unitColor = unitImageFile.substr(0,unitImageFile.indexOf('_'));
		var unitType = unitImageFile.substr(unitImageFile.indexOf('_')+1);
		
		if(unitType != "capturing.gif") {
			//GM_log('build of a: ' + unitColor + " " + unitType + " at x: " + x + ", y: " + y );
			return "build";
		}
	}
	
	else {
		//GM_log('other event');
		return "other";
	}
	
	return "error";

}

function getEventPlayer(eHTML)
{
	var imageFile = firstEvent.getElementsByTagName('terrain')[f].textContent;
	var baseColor = baseImageFile.substr(0,baseImageFile.indexOf('_'));
	var baseType = baseImageFile.substr(baseImageFile.indexOf('_')+1);
	GM_log("found an initial base at x: " + x + ", y: " + y + ", which is a: " + baseColor + " " + baseType + ", for: " + playerColors[baseColor]);
	if (baseType == "city.png")
		gameRounds[1][baseKey] = playerColors[baseColor];	
}

function findStartingBases(firstEvent)
{
	for(var f = 0; f < firstEvent.getElementsByTagName('terrain').length; f++)
	{
		var x = firstEvent.getElementsByTagName('terrain')[f].parentNode.getAttribute('x');
		var y = firstEvent.getElementsByTagName('terrain')[f].parentNode.getAttribute('y');
		var baseKey = "x:" + x + ",y:" + y;
		var baseImageFile = firstEvent.getElementsByTagName('terrain')[f].textContent;
		var baseColor = baseImageFile.substr(0,baseImageFile.indexOf('_'));
		var baseType = baseImageFile.substr(baseImageFile.indexOf('_')+1);
		if (baseType == "city.png") {
			gameRounds[1][baseKey] = playerColors[baseColor];	
			GM_log("found an initial base at x: " + x + ", y: " + y + ", which is a: " + baseColor + " " + baseType + ", for: " + playerColors[baseColor]);
		}
	}	
}



function initArrays()
{	
	var playerList = getElementsByClassName(getElementsByClassName(document, 'ul', 'playerlist')[1], 'div', 'player');
	//GM_log("in init arrays: player list length " + playerList.length);
	numPlayers = playerList.length;
	for(var p=0; p < numPlayers; p++)
	{
		var player = playerList[p].childNodes[0].getAttribute('href');
		player = player.substr(player.lastIndexOf('/')+1);
		//GM_log("player num " + p + " is " + player);
		if(player == "") player = "Unknown Player";
		playerRounds[player] = 0;
		playerBaseCount[player] = 0;
		playerBuilds[player] = 0;
		playerTotalCredits[player] = initialCredits;
		playerColors[colorIndex[p]] = player;
	}
	for(var r = 1; r <=totalRounds+1; r++)
	{
		gameRounds[r] = new Array();
	}
}

function outputData()
{
/* 	for(var r=1; r<=totalRounds; r++)
	{
		for(var b in gameRounds[r])
		{
			if(r > 1 && gameRounds[r-1][b] != undefined && gameRounds[r][b] != gameRounds[r-1][b])
			{
				if(playerBaseCount[gameRounds[r-1][b]] > 0) playerBaseCount[gameRounds[r-1][b]]--;
			}
			if(r <= playerRounds[gameRounds[r][b]]) playerBaseCount[gameRounds[r][b]]++;
			if(r < totalRounds && !gameRounds[r+1][b]) gameRounds[r+1][b] = gameRounds[r][b];
		}
		for(var p in playerBaseCount)
		{
			playerTotalCredits[p] += playerBaseCount[p] * perBaseIncome;
			playerBaseCount[p] = 0;
		}
	} 
	var playerDivs = getElementsByClassName(getElementsByClassName(document, 'ul', 'playerlist')[1], 'div', 'player');
	var playerDivCount = 0;
	for(var pp in playerTotalCredits)
	{
		playerDivs[playerDivCount].innerHTML += ", b:$" + (playerTotalCredits[pp] - playerBuilds[pp]);
		playerDivCount++;		
	} */
	 var playerTurnIncome = new Array();
	
	//now to calculate the current credits from all the parsed data
	//first, loop through each round and figure out who owns what base
	for(var r=1; r<=totalRounds; r++)
	{
		//now go through each base owned per round
		for(var b in gameRounds[r])
		{
			GM_log("in round: " + r + ", " + gameRounds[r][b] + " has a base at: " + b );
			//if a base was previously owned by another player, then subtract a base from that player's base count
			if(r > 1 && gameRounds[r-1][b] != undefined && gameRounds[r][b] != gameRounds[r-1][b])
			{
				GM_log("base steal: " + gameRounds[r][b] + " took " + gameRounds[r-1][b] + "'s base at: " + b + " in round: " + r );
				if(playerBaseCount[gameRounds[r-1][b]] > 0) playerBaseCount[gameRounds[r-1][b]]--;
			}
			//then this base to the current player's base count
			if(r <= playerRounds[gameRounds[r][b]]) playerBaseCount[gameRounds[r][b]]++;
			//then mark the base as being owned by the player next turn as well as long as it was not captured the next turn by someone else
			if(r < totalRounds && !gameRounds[r+1][b]) gameRounds[r+1][b] = gameRounds[r][b];
		}
		//now for each round, multiply all the bases by the perbaseincome and add that up for each round
		//var basestring = "in round: " + r + ": ";
		for(var p in playerBaseCount)
		{
			if(r <= playerRounds[p])
			{
				playerTurnIncome[p] = playerBaseCount[p] * perBaseIncome;
				playerTotalCredits[p] += playerTurnIncome[p];
			}
			//basestring += p + " has: " + playerBaseCount[p] + " bases, ";
			playerBaseCount[p] = 0;
		} //GM_log(basestring); 
	} 
	//finally, just output the data to the playerlist in the game
	var playerDivs = getElementsByClassName(getElementsByClassName(document, 'ul', 'playerlist')[1], 'div', 'player');
	var playerDivCount = 0;
	for(var pp in playerTotalCredits)
	{
		GM_log(pp + " earned " + playerTotalCredits[pp] + " credits, and spent " + playerBuilds[pp] + " for a net of: " + (playerTotalCredits[pp] - playerBuilds[pp]));
		playerDivs[playerDivCount].innerHTML += "in:" + playerTurnIncome[pp] + ", $" + (playerTotalCredits[pp] - playerBuilds[pp]);
		playerDivCount++;		
	} 

	/* var roundsString = '';
	for(var player in playerRounds)
	{
		roundsString += player + " rounds:" + playerRounds[player] + ", ";
	}
	GM_log("player rounds - " + roundsString); */
}

function outputError()
{
	var playerDivs = getElementsByClassName(getElementsByClassName(document, 'ul', 'playerlist')[1], 'div', 'player');
	var playerDivCount = 0;
	for(var pp = 0; pp < playerDivs.length; pp++)
	{
		playerDivs[playerDivCount].innerHTML += "bad history file";
		playerDivCount++;		
	}
}

function getElementsByClassName(oElm, strTagName, strClassName)
{
	var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
	var arrReturnElements = new Array();
	strClassName = strClassName.replace(/\-/g, "\\-");
	var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
	var oElement;
	for(var i=0; i<arrElements.length; i++){
		oElement = arrElements[i];
		if(oRegExp.test(oElement.className)){
			arrReturnElements.push(oElement);
		}
	}
	return (arrReturnElements)
}

function addGlobalStyle(css)
{
	var head, style;
	head = document.getElementsByTagName('head')[0];
	if (!head) { return; }
	style = document.createElement('style');
	style.type = 'text/css';
	style.innerHTML = css;
	head.appendChild(style);
}
function createDOMElement(name, attrs, styleList) { 
  var domElement = document.createElement(name);
  for(var prop in attrs) { domElement[prop] = attrs[prop]; }
  SetStyle(domElement, styleList);
  return domElement; 
}
function SetStyle(element, styleList) {
  for(var styleName in styleList) { element.style[styleName] = styleList[styleName]; }
}
function appendChildren(element /*, list of children*/) {
  for(var i = 1; i < arguments.length; i++) element.appendChild(arguments[i]);
}
///////////////////////////////////////////////////////////////////////////////////
/////////////////////////////// END OF BANKER /////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////
//////////////////////////// START OF ENHANCED HISTORY  ///////////////////////////
///////////////////////////////////////////////////////////////////////////////////

var continuePlaying = true;

function startEnhancedHistory() {

	GM_log("start history");
	// replay speed variables
	var replaySpeed = unsafeWindow.speed;
	const speedDefault = replaySpeed;
	const speedIncrement = 250;

	// DOM elements in the game where the history controls are
	// these are intially hidden until you start a history replay
	var stopReplayControl = $("stopReplay");
	var replayControlDiv = $("activeReplay");
	
	// new command links to add to the elements above
	var increaseReplaySpeedLink = A({id:"increaseReplaySpeedLink", href:"#", style:"font-size: 0.85em; padding: 0px 5px 0px 5px; color: #00BF00; text-decoration: none;"},"+ inc speed");
	var decreaseReplaySpeedLink = A({id:"decreaseReplaySpeedLink", href:"#", style:"font-size: 0.85em; padding-right: 5px; color: #BF0000; text-decoration: none;"},"- dec speed");
	var speedDisplay = A({id:"speedDisplay", href:"#", style:"font-size: 0.85em; padding-right: 5px; text-decoration: none"}, "speed: " + replaySpeed);
	var pauseLink = A({id:"myPause", href:"#", style:"font-size: 0.85em; color: #BF0000; padding-right: 5px; border-right: 1px solid #000000; text-decoration: none;"}, "pause");
	
	// insert the new command links in the DOM
	var historyEnhancerControls = SPAN({id:"historyEnhancerControls"}, pauseLink, increaseReplaySpeedLink, decreaseReplaySpeedLink, speedDisplay);	
	insertSiblingNodesBefore(stopReplayControl,historyEnhancerControls);
	
	// need to make the main DIV holding all this stuff a little bigger to fit it all
	replayControlDiv.style.width = "450px";
	
	connect(increaseReplaySpeedLink, "onclick", function(e) {
		if((unsafeWindow.speed - speedIncrement) >= 0){
			unsafeWindow.speed -= speedIncrement;
			speedDisplay.innerHTML = "speed: " + unsafeWindow.speed;
		}	
		e.preventDefault();
	});

	connect(decreaseReplaySpeedLink, "onclick", function(e) {
		unsafeWindow.speed += speedIncrement;
		speedDisplay.innerHTML = "speed: " + unsafeWindow.speed;	
		e.preventDefault();	
	});

	// TODO: reset the speed display to the default after a replay finishes.
	connect(speedDisplay, "onclick", function(e) {
		unsafeWindow.speed = speedDefault;
		speedDisplay.innerHTML = "speed: " + unsafeWindow.speed;
		e.preventDefault();
	});
	
	connect(pauseLink, "onclick", function(e) {
		if(continuePlaying){
			continuePlaying = false;
			pauseLink.innerHTML = "play";
			pauseLink.style.color = "green";
		} else {			
			continuePlaying = true;
			pauseLink.innerHTML = "pause";
			pauseLink.style.color = "red";
			unsafeWindow.playContinuously();
		}
	    e.preventDefault();
	});
	
}

unsafeWindow.playContinuously = function(){
	unsafeWindow.weewarHistory.play();
	var forward = unsafeWindow.weewarHistory.forward();
	if( forward && continuePlaying )
	{
		var timeout = window.setTimeout(function(){unsafeWindow.playContinuously()}, unsafeWindow.speed );
	}
	else if(forward && !continuePlaying)
	{		
		unsafeWindow.weewarHistory.stop();
	}
	else
	{
		unsafeWindow.weewarMap.setClickFunction( oldClick );
		unsafeWindow.showReplayLinks();
	}
}

///////////////////////////////////////////////////////////////////////////////////
/////////////////////////////// END OF ENHANCED HISTORY /////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////
//////////////////////////// START OF AUTO REPAIR /////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
function startAutoRepair() { 
	var autoRepairLink = A({"id":"autoRepairLink", "title":"**Warning** Cannot be undone!", "href":"#", "style":"font-size: 0.85em; padding-left: 8px; color: #00BF00; text-decoration: none;"},
						IMG({"width":"16", "height":"16", "src":"http://www.plutosforge.com/images/wrench.png"}),"Auto-Repair");	
	insertSiblingNodesAfter(m_CommandToolbarStart,autoRepairLink); // add a link and icon to the commands tool bar	
	connect(autoRepairLink, "onclick", partial(repairAllUnits)); // event handler for starting the auto repair
}

////////////////////////////////////////////////////
///// stuff that should be a part of the framework

// a list of player order - unit color associations 
var colorIndex = {
	0 : "blue",
	1 : "red",
	2 : "purple",
	3 : "yellow",
	4 : "green",
	5 : "white"
};

// function to get the current player - don't want to try and repair your opponents' units
function findCurrentPlayer(){
	var currentPlayerNode = $$(".playerlist .current")[0];
	return ({ 
		"colorIndex0 current": 0,
   	"colorIndex1 current": 1,
   	"colorIndex2 current": 2,
   	"colorIndex3 current": 3,
   	"colorIndex4 current": 4,
   	"colorIndex5 current": 5
   })[getNodeAttribute(currentPlayerNode, "class")];
}

///////////////////////////////////////////////////////

var listOfRepairs = new Array(); // an array for storing the cordinates of units to be repaired

// this function sorts through the image elements on the map to pull out the hex x,y location info as well as the hitpoint values for each unit
// it will then make a list of all the units that can be repaired - i.e. they are yours and not already repaired (still to do: check whether aircraft are on an airbase first)
// it then calls off to the sendRepairCommand function to talk to the weewar servers
// ** much of the data here should probably go into the framework
function repairAllUnits(e){
	var mapUnitImages = document.getElementById("map").getElementsByTagName("img"); // a list of the unit image elements on the map 
	var currentPlayerColor = colorIndex[findCurrentPlayer()];  // need the current player color so you don't try and repair your opponents' units
	for(var i = 0; i < mapUnitImages.length; i++){	
		if(mapUnitImages[i].id.split("_").length == 3) {
			var unitX = mapUnitImages[i].id.split("_")[0];
			var unitY = mapUnitImages[i].id.split("_")[1];
			var imageType = mapUnitImages[i].id.split("_")[2];
			if(imageType == "unitQuantity"){
				var unitQuantity = (/images\/([0-9]*)/).exec(document.getElementById(mapUnitImages[i].id).src)[1];
				var unitColor = (/images\/([a-z]*)/).exec(document.getElementById(unitX+"_"+unitY+"_unit").src)[1];
				var unitType = (/images\/([a-z_]*)/).exec(document.getElementById(unitX+"_"+unitY+"_unit").src)[1].split("_")[1];				
				var unitTerrain = getFileImageType(unsafeWindow.weewarMap.getTerrain(unitX, unitY));
				// check to make sure that the unit has not already been repaired or moved(i.e. is already shaded out) and if it is one of yours and that it is not a capturing unit
				if(unitQuantity < 10 && !($(unitX+"_"+unitY+"_shader") || $(unitX+"_"+unitY+"_halfShader")) && unitColor == currentPlayerColor && unitType != "capturing"){
					if(unitType == "jet" || unitType == "bomber" || unitType == "heli") {
						if( unitTerrain == "airfield.png") {					
							GM_log("---- sending aircraft repair command for: x: " + unitX + " y: " + unitY + " Image type: " + imageType + " quant: " + unitQuantity  + " color: " + unitColor + " unit type: " + unitType + " -on: " + unitTerrain);					
							listOfRepairs.push(unitX+"_"+unitY);
						}
					}else {		
						GM_log("---- sending repair command for: x: " + unitX + " y: " + unitY + " Image type: " + imageType + " quant: " + unitQuantity  + " color: " + unitColor + " unit type: " + unitType + " -on: " + unitTerrain);					
						listOfRepairs.push(unitX+"_"+unitY);				
					}
				}
			}
		}
	}	
	//GM_log("list of repairs" + listOfRepairs);	
	if(listOfRepairs.length > 0) sendRepairCommand(listOfRepairs.pop());  // now talk to the servers	
	e.preventDefault();
}


// this is a recursive function because the units must be repaired one by one, so you have to wait for the first one to finish before going on to the next one.
function sendRepairCommand(coords){
 	var baseURL = format("http://{0}/ajax/click.jsp?method=", m_GameServer);
	var clickURL = format("{0}gameClick&object={1}&xy={2}&tbUid={3}", baseURL, m_GameId, coords, (new Date()).getTime()); 
	GM_log("baseURL: " + baseURL + "clickURL: " + clickURL);
 	GM_xmlhttpRequest({method: "GET",url: clickURL,headers: {},onload: function(responseDetails){
		var repairURL = baseURL + "gameCommand&object=" + m_GameId +"&command=repair&tbUid=" + (new Date()).getTime();
		GM_xmlhttpRequest({method: "GET",url: repairURL,headers: {},onload: function(responseDetails){
			// after the repair call, first parse out the response to get the resultant new unit hitpoints
			var parser = new DOMParser();
			var dom = parser.parseFromString(responseDetails.responseText,"application/xml");
			var repairedUnit = dom.getElementsByTagName("unit")[0];
			var repairedUnitQuantity = repairedUnit.getAttribute("quantity");
			var repairedUnitX = repairedUnit.parentNode.getAttribute("x");
			var repairedUnitY = repairedUnit.parentNode.getAttribute("y");
			var repairedUnitImg = repairedUnit.textContent;
			// then call the weewar map functions to update the hitpoints and apply the shader
			unsafeWindow.weewarMap.setUnit(repairedUnitX,repairedUnitY,repairedUnitImg,repairedUnitQuantity);
			unsafeWindow.weewarMap.setDark(repairedUnitX,repairedUnitY);
			// once this is all done, recursively call the function to repair the next unit
			if(listOfRepairs.length > 0) sendRepairCommand(listOfRepairs.pop());
		}}); 
	}}); 
}
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////// END OF AUTO REPAIR //////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////////
//////////////////////////// START OF CHAT STAMP //////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
/*
function startChatStamps() {

	////// add button to toolbar //////////////////////////////////////////////////
	var chatStampsLink = A({"id":"chatStampsLink", "title":"Chat Time Stamps Options", "href":"#", "style":"font-size: 0.85em; padding-left: 8px; color: #00BF00; text-decoration: none;"},
						IMG({"width":"16", "height":"16", "src":"http://www.plutosforge.com/images/clock_edit.png"}),"Chat Stamps");	
	insertSiblingNodesAfter(m_CommandToolbarStart,chatStampsLink); // add a link and icon to the commands tool bar	


	////// draw up options window //////////////////////////////////////////////////
	// saved settings
	var m_ShowChatStamps = m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.EnableDateTimeStamps;	
	var m_ShowTimeStamps = m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.IncludeTime;
	var m_TimeStampType = m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.TimeStampType;	
	var m_ShowDateStamps = m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.IncludeDate;
	var m_DateStampType = m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.DateStampFormat;
	
	// links for setting the options		   
	var chatStampToggle = A({"href":"#", "style":"text-decoration:none; color:#000000;"},((m_ShowChatStamps == true) ? "[x]" : "[ ]"));
	var timeStampToggle = A({"href":"#", "style":"text-decoration:none; color:#000000;"},((m_ShowTimeStamps == true) ? "[x]" : "[ ]"));	
	var dateStampToggle = A({"href":"#", "style":"text-decoration:none; color:#000000;"},((m_ShowDateStamps == true) ? "[x]" : "[ ]"));
	
	//more specific options for the date and time stamps
	var timeStampOptionLink = A({"href":"#", "style":"text-decoration:none; color:#000000;"},format(" - {0}: {1}","time stamp type", timeStampTypes[m_TimeStampType]));
	var timeStampOptionRow = TR(((m_ShowTimeStamps == true) ? null : {"style":"display:none;"}),TD(null,timeStampToggle),TD({"align":"left"},timeStampOptionLink));
	connect(timeStampOptionLink, "onclick", partial(cycleStampTypes, timeStampOptionLink, "time"));	
	var dateStampOptionLink = A({"href":"#", "style":"text-decoration:none; color:#000000;"},format(" - {0}: {1}","date stamp type", dateStampFormats[m_DateStampType]));
	var dateStampOptionRow = TR(((m_ShowTimeStamps == true) ? null : {"style":"display:none;"}),TD(null,dateStampToggle),TD({"align":"left"},dateStampOptionLink));
	connect(dateStampOptionLink, "onclick", partial(cycleStampTypes, dateStampOptionLink, "date"));	
	
	// event handlers assigned to the option-setting links
	connect(chatStampToggle,"onclick",function(e){
										optionToggle(chatStampToggle,"ChatStamps",e);
										if(m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.EnableDateTimeStamps){timeStampOptionRow.style.display = "";	dateStampOptionRow.style.display = "";	}
										else{ timeStampOptionRow.style.display = "none;"; dateStampOptionRow.style.display = "none;"; }});	
	connect(timeStampToggle,"onclick",partial(optionToggle, timeStampToggle,"TimeStamps"));
	connect(dateStampToggle,"onclick",partial(optionToggle, dateStampToggle,"DateStamps"));
	
	// the actual options window 
	// the table to present all the options
	var optionsTable = TABLE(null,
						TR(null, TD({"style":"text-decoration:underline;"},"show"),    TD({"width":"250","style":"text-decoration:underline;"},"feature")),
						TR(null, TD({"align":"center"},chatStampToggle),    	 	   TD({"align":"left"},"Chat Time Stamps")),
						dateStampOptionRow,timeStampOptionRow);
	// link for closing the options window					
	var closeOptionsLink = A({"href":"#", "style":"text-decoration:none;"}, "Save and Close");
	// the options window which is a Div element that floats on top of everything					
	var optionsWindow = DIV({"id":"optionsWindow","style":"position:absolute; top: 45px; left: 500px; padding: 0px 5px 5px 0px; border: 1px solid #000000; z-index:99; display:none; background-color:#EEEEEE;"},
						  P({"style":"text-decoration:underline;"}, "Chat Time Stamp Options"), 
						  optionsTable,
						  P(null,closeOptionsLink));	
	insertSiblingNodesAfter(document.getElementById("header"),optionsWindow);
	// event handlers for opening and closing options window
	connect(chatStampsLink, "onclick", function(e) {
		e.preventDefault();
		optionsWindow.style.display = "";
	});
	connect(closeOptionsLink, "onclick", function(e) {
		e.preventDefault();
		optionsWindow.style.display = "none";
	});	
	
	
	///// finally add in the wanted functionality //////////////////////////////////////////////////
	if(m_ConfigurationSettings.ChatEnhancer.Enabled) {
		var chatSettings = m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings;
		if(chatSettings.EnableDateTimeStamps) {
			insertChatStampFunctionality();
		}
	}
}

// toggles the settings on or off  //////////////////////////////////////////////////
function optionToggle(option, key, e) {
	var newState;
	switch(key){
			case "ChatStamps":
				newState = m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.EnableDateTimeStamps = !m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.EnableDateTimeStamps;
				break;
			case "TimeStamps":
				newState = m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.IncludeTime = !m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.IncludeTime;
				break;
			case "DateStamps":
				newState = m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.IncludeDate = !m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.IncludeDate;
				break;
	}	
	option.innerHTML = ((newState == true) ? "[x]" : "[&nbsp;&nbsp;]");
	e.preventDefault();
}

// variables and functions for cycling through the time stamp types  //////////////////////////////////////////////////
var nextKeyIndexCounter = 0;
var dateStampFormats = { "{0}/{1}":"m/d", "{0}-{1}":"m-d", "{0}.{1}":"m.d" };
var timeStampTypes = { 12: "h:mm AM/PM (12hr)", 24: "h:mm (24hr)" };

function cycleStampTypes(option, type, e) {
	e.preventDefault();
	if(type == "date") {
		var keyArray = keys(dateStampFormats);
		var currentKey = m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.DateStampFormat;
		var currentKeyIndex = findValue(keyArray, currentKey);
		nextKeyIndexCounter = ((currentKeyIndex + 1) % 3);
		m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.DateStampFormat = keyArray[nextKeyIndexCounter];
		option.innerHTML = format(" - {0}: {1}", "date stamp type", dateStampFormats[m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.DateStampFormat]);
	} else {
		var currentTimeType = m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.TimeStampType;
		currentTimeType = (currentTimeType == 12) ? 24 : 12;
		m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.TimeStampType = currentTimeType;
		option.innerHTML = format(" - {0}: {1}", "time stamp type", timeStampTypes[currentTimeType]);
	}
}

// takes over the sendmessage function for inserting time stamps //////////////////////////////////////////////////
function insertChatStampFunctionality() {
	connect("outputList", "onchange", function(){
		GM_log($("outputList").innerHTML);
	});
	var sendMessageFunction = unsafeWindow.sendMessage; // grab the intended function and hold onto it for a moment  
	unsafeWindow.sendMessage = function(id) { // we are going to hijack the intended function's pointer and insert ourselves into the call chain
		var currentDateTime = new Date(); // get the current date and time	
		// we are going to use the current UTC value for the date and time that we place into the chat 
		// window - our script will then parse these into the correct date and time based on the user's timezone and settings
		var day = currentDateTime.getUTCDate();
		var month = currentDateTime.getUTCMonth() + 1;
		var year = currentDateTime.getUTCFullYear();
		var hours = currentDateTime.getUTCHours();
		var minutes = currentDateTime.getUTCMinutes();
		minutes = (minutes <= 9) ? ("0" + minutes) : minutes;
		var chatMessageTextbox = document.getElementById("chatMessage");  		
		chatMessageTextbox.value = format("({0}): {1}", format("{0}/{1}/{2} {3}:{4}", month, day, year, hours, minutes), chatMessageTextbox.value); // set the value of the text box to the combination of our time stamp and the original message
		sendMessageFunction(id); // manually pass event back to the intended function, which we have stored temporarily in this pointer called "sendMessageFunction" 
	}
}

// modifies the postPendingMessages function for inserting time stamps //////////////////////////////////////////////////
unsafeWindow.postPendingMessages = function() { 
	try {
		for (unsafeWindow.n = 0; unsafeWindow.n < unsafeWindow.chatMessageQueue.size(); unsafeWindow.n++) { 
			var msg = unsafeWindow.chatMessageQueue.get(unsafeWindow.n); 
			var styleClass = unsafeWindow.chatMessageStyleQueue.get(unsafeWindow.n); 
			var currentId = unsafeWindow.chatMessageIdQueue.get(unsafeWindow.n); 
			unsafeWindow.oLi = unsafeWindow.document.createElement("li"); 
			unsafeWindow.oLi.className = styleClass;
			var regex = /&#40;([0-9]{1,2})\/([0-9]{1,2})\/([0-9]{4})\s{1}([0-9]{1,2}):([0-9]{2})&#41;/;
			if(regex.test(msg)) {
				var results = regex.exec(msg);
				// extract the time stamp from the message
				var utcDate = new Date(Date.UTC(results[3], (results[1] - 1), results[2], results[4], results[5]));
				var day = utcDate.getDate();
				var month = utcDate.getMonth() + 1;
				var hours = utcDate.getHours();
				var minutes = utcDate.getMinutes();
				minutes = (minutes <= 9) ? ("0" + minutes) : minutes;
				var meridian = (hours >= 12) ? "PM" : "AM";
				var chatSettings = m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings;
				var dateTimeStamp = "";
				if(chatSettings.EnableDateTimeStamps && chatSettings.IncludeDate) {
					dateTimeStamp = format(chatSettings.DateStampFormat, month, day);
				}
				if(chatSettings.EnableDateTimeStamps && chatSettings.IncludeTime) {
					dateTimeStamp = dateTimeStamp.concat((chatSettings.IncludeDate) ? "," : "");
					if(chatSettings.TimeStampType == 12) {
						hours = (hours == 12) ? 12 : hours % 12;
						dateTimeStamp = dateTimeStamp.concat(format("{0}:{1} {2}", hours, minutes, meridian));
					} else if (chatSettings.TimeStampType == 24) {
						dateTimeStamp = dateTimeStamp.concat(format("{0}:{1}", hours, minutes));
					}
				}
				if (dateTimeStamp.length > 0) {
					unsafeWindow.oLi.innerHTML = msg.replace(results[0], format("({0})", dateTimeStamp));
				} else {
					unsafeWindow.oLi.innerHTML = msg.replace(results[0], "");
				} 
			} else {
				unsafeWindow.oLi.innerHTML = msg;
			}

			//////////////////////////////////////////////////
			unsafeWindow.outputList.appendChild(unsafeWindow.oLi); 
			unsafeWindow.outputList.scrollTop = unsafeWindow.outputList.scrollTop + 100; 
			unsafeWindow.listedChatIds.add(currentId); 
		} 
		unsafeWindow.chatMessageQueue = new unsafeWindow.CCollection; 
		unsafeWindow.chatMessageIdQueue = new unsafeWindow.CCollection;
	} catch(e) {
		GM_log(e.message);
	} 
}
*/
///////////////////////////////////////////////////////////////////////////////////
////////////////////////////// END OF CHAT STAMP //////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////////
/////////////////// START OF CHAT WINDOW SIZE ADJUSTER ///////////////////////
///////////////////////////////////////////////////////////////////////////////////
// common function for both adjusters
function changeWindowSize(myWindow, settingStorageObject, key, amount, e) {
	GM_log("call made to changeWindowSize with these params:");
	GM_log(format("settingStorageObject:{0}, key:{1}, amount:{2}", serializeJSON(settingStorageObject), key, amount));
	if(amount < 0 && +(myWindow.style.height.replace("px", "")) <= 100) {
		amount = 0;
	}
	GM_log("current height: " + myWindow.style.height);
	GM_log("new height: " + ((+(myWindow.style.height.replace("px", "")) + amount) + "px"));
	myWindow.style.height = (+(myWindow.style.height.replace("px", "")) + amount) + "px";
	settingStorageObject[key] = myWindow.style.height; // store this since it is different than the default size
	e.preventDefault();
} 
function startChatSizeAdjuster() { 
	var chatSettings = m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings;
	try {
		var chatList = document.getElementById("outputList");
		chatList.style.height = (chatSettings.GameSizeMap[m_GameId] || chatSettings.DefaultWindowHeight);		
		var increaseChatSizeLink = A({"id":"increaseChatSizeLink", "href":"#", "style":"font-size: 0.85em; color: #00BF00; text-decoration: none;"},"+ increase ");
		var decreaseChatSizeLink = A({"id":"increaseChatSizeLink", "href":"#", "style":"font-size: 0.85em; color: #BF0000; text-decoration: none;"},"- decrease ");
		var chatSizeChanger = DIV({"title":"chatSizeChanger","style":"background-color: #EEE; padding: 3px 3px 5px 3px;"},
									A({"id":"chatSizeLabel","style":"font-size: 0.85em;"}, "Adjust Chat Size: "),
									increaseChatSizeLink,
									decreaseChatSizeLink);
		insertSiblingNodesBefore(chatList, chatSizeChanger);
		connect(increaseChatSizeLink, "onclick", partial(changeWindowSize, chatList, chatSettings.GameSizeMap, m_GameId, chatSettings.SizeChangeIncrement));
		connect(decreaseChatSizeLink, "onclick", partial(changeWindowSize, chatList, chatSettings.GameSizeMap, m_GameId, -1 * chatSettings.SizeChangeIncrement));
	}
	catch(e){
		// NOTE: "extensions.firebug.showChromeMessages must be set to 
		// true for GM_log messages to show up in the Firebug console"
		GM_log(format("{0} {1}","Chat Size Adjuster failed because: ",e));
	} 
}
///////////////////////////////////////////////////////////////////////////////////
///////////////////// END OF CHAT WINDOW SIZE ADJUSTER ///////////////////////
///////////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////////
//////////////////////// START OF ATTACK RANGE ASSISTANT //////////////////////////
///////////////////////////////////////////////////////////////////////////////////

function getFileImageColor(imageFile) {
	return imageFile.substr(0,imageFile.indexOf('_'));
}

function getFileImageType(imageFile) {
	if(imageFile.indexOf('_') < 0)
		return imageFile;
	else
		return imageFile.substr(imageFile.indexOf('_')+1);
}

////// add button to toolbar //////////////////////////////////////////////////
/* function addAllRangesToolbar() {
	var allRangesLink = A({"id":"allRangesLink", "title":"display all ranges", "href":"#", "style":"font-size: 0.85em; padding-left: 8px; color: #00BF00; text-decoration: none;"},
						IMG({"width":"16", "height":"16", "src":"http://www.plutosforge.com/images/keyboard_add.png"}),"all ranges");	
	insertSiblingNodesAfter(m_CommandToolbarStart,allRangesLink); // add a link and icon to the commands tool bar	
	connect(allRangesLink, "onclick", partial(showAllRanges)); // event handler for starting the auto repair
} */

function showAllRanges(x, y) {
	
	var clickedUnitImageFile = unsafeWindow.weewarMap.getUnit(x,y);
	var clickedUnitColor = getFileImageColor(clickedUnitImageFile);
	var clickedUnitType = getFileImageType(clickedUnitImageFile);	
	
	for (var x = 0; x < unsafeWindow.bWidth; x++)
	{
		for (var y = 0; y < unsafeWindow.bHeight; y++)
		{
			var unitImageFile = unsafeWindow.weewarMap.getUnit(x,y);			
			if(unitImageFile) 
			{
				var unitColor = getFileImageColor(unitImageFile);
				var unitType = getFileImageType(unitImageFile);
				if( clickedUnitColor == unitColor && clickedUnitType == unitType)
					enableAttackRangeAssistant(x, y);				
			}
		}
	}
}

function enableAttackRangeAssistant(x, y) {
	var unitType = m_WeewarMap.getMapHex(x, y).UnitType;
	showRange(x, y, m_StaticMetadata.UnitAttackRangeDictionary[unitType].start, 
                  m_StaticMetadata.UnitAttackRangeDictionary[unitType].end);
}

// both of the following functions are based on work I did with the information found at http://www.webwargaming.com
function getDistanceBetweenHexes(x1, y1, x2, y2) {
	return ((Math.abs(x2 - x1) > Math.abs(y2 - y1)) ? (Math.abs(x2 - x1) / 2) : (( Math.abs(x2 - x1) + Math.abs(y2 - y1)) / 4));
}
function getHexagonGridCoordinates(x, y) {
	return ((y == 0 || y % 2 == 0) ? {"x":((y * 2) + 2),"y":((x * 4) + 6)} : {"x":((y * 2) + 2),"y":((x + 1) * 4) + 4});		
}
function isWithinRange(originX, originY, targetX, targetY, maximumDistance) {
	var originCoords = getHexagonGridCoordinates(originX, originY);
	var targetCoords = getHexagonGridCoordinates(targetX, targetY);
	var targetDistanceFromOrigin = getDistanceBetweenHexes(originCoords.x, originCoords.y, targetCoords.x, targetCoords.y);
	return (targetDistanceFromOrigin <= maximumDistance);
}
function getSurroundingHexField(xCoord, yCoord, range) {
	var surroundingHexList = [];
	// Heuristics explanation:
	// We are creating a list of _suggested_ hexes that surround the target - these are then checked 
	// to see if they really *are* within the right range; if they are, we keep them around in a list
	for(var y = -(range); y <= range + 0; y++) {
		for(var x = -(range); x <= range + 0; x++) { 
			if(m_WeewarMap.getMapHex((xCoord + x), (yCoord + y)).HexOnMap && isWithinRange(xCoord, yCoord, (xCoord + x), (yCoord + y), range)) {
				surroundingHexList.push({"x":(xCoord + x), "y":(yCoord + y)});				
			}
		}		
	}
	return surroundingHexList;
}
function showRange(xCoord, yCoord, startingRange, endingRange) {
  var smallerHexField = getSurroundingHexField(xCoord, yCoord, startingRange - 1);
  var largerHexField = getSurroundingHexField(xCoord, yCoord, endingRange);
  var list = subtractHexFields(largerHexField, smallerHexField); 
  for(var i in list) m_UnsafeWeewarMap.setMarked(list[i].x, list[i].y);
  var intervalId; 
  intervalId = setInterval(function() {
  	if(!m_CtrlKeyDepressed && !m_ShiftKeyDepressed) {
		clearInterval(intervalId);
		m_UnsafeWeewarMap.clearMarked();
	}
  }, 500);
}
function subtractHexFields(hexArrayToSubtractFrom, hexArrayToSubtractWith) {
	for(var i = 0; i < hexArrayToSubtractWith.length; i++) {
		for(var y = 0; y < hexArrayToSubtractFrom.length; y++) {
			if(hexArrayToSubtractWith[i].x == hexArrayToSubtractFrom[y].x && hexArrayToSubtractWith[i].y == hexArrayToSubtractFrom[y].y) {
				hexArrayToSubtractFrom.splice(y, 1);
				break;
			}
		}
	}
	return hexArrayToSubtractFrom;
}
///////////////////////////////////////////////////////////////////////////////////
////////////////////////// END OF ATTACK RANGE ASSISTANT //////////////////////////
///////////////////////////////////////////////////////////////////////////////////




///////////////////////////////////////////////////////////////////////////////////
////////////////////////// START OF BATTLE SIMULATOR //////////////////////////
////////////////////////// adpted from Pluto's script ////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////

function startBattleSimulator() { 
	GM_log('starting battle sim');
	var battleSimLink = A({"id":"battleSimLink", "href":"#", "style":"font-size: 0.85em; padding-left: 8px; color: #00BF00; text-decoration: none;"},
						IMG({"width":"16", "height":"16", "src":"http://www.plutosforge.com/images/calculator.png"}),"Battle Simulator");	
	insertSiblingNodesAfter(m_CommandToolbarStart,battleSimLink); // add a link and icon to the commands tool bar	
	connect(battleSimLink, "onclick", partial(displaySim)); // event handler for starting the auto repair
}

//initialize unit info with defaults
var myAtkUnit = "_001.";
var myAtkNumber = 10;
var myAtkTerrain = "plain.png";

var myDefUnit = "_001.";
var myDefNumber = 10;
var myDefTerrain = "plain.png";

var myBouns = 0;

// the number of times to run the battle simulation - more runs is more accurate, but takes longer
const SIM_NUM = 1000;

// var showHideKey = ("battleSim_" + ((/game\/([0-9]*)/g).exec(window.location.href)[1]));
// if(!document.getElementById('previewForm'))
// {
	// drawSim();
	// if(GM_getValue(showHideKey,'show') == 'hide') toggleSim('hide');
// }

//////////////////////////// Drawing and DOM modification /////////////////////////////////

var attackerTerrainImg;
var attackerUnitImg; 
var attackerQuantImg; 
var defenderTerrainImg;
var defenderUnitImg; 
var defenderQuantImg;

var simDisplayed = false;
drawSim();  // the simwindow will be drawn, but hidden at first

function displaySim() {
	if (!simDisplayed) {
		$("simWindow").style.display = "";
		simDisplayed = true;
	} else {
		$("simWindow").style.display = "none";
		simDisplayed = false;
		unsafeWindow.weewarMap.setClickFunction( oldClick );
		document.getElementById('enterSimMode').style.display = '';
		document.getElementById('exitSimMode').style.display = 'none;';	
		document.getElementById('startBattle').style.display = 'none;';
	}
}
	
function drawSim()
{
	var chatContainer = document.getElementById('chat').parentNode;
	var simWindow = createDOMElement("div",{id:"simWindow", title:"Weewar Battle Simulator (GM) - by Pluto, 2008"},{height:"115px",position:"relative",border:"1px solid #DDDDDD",marginBottom:"10px", display:"none"});
	
	var commandLinks = createDOMElement("div",{id:"commandLinks",innerHTML:'<a id="enterSimMode" href="#" onclick="enterSimMode();return false;" style="text-decoration:none; color:#00BF00; margin: 0px 10px 0px 0px;">Enter Sim Mode  </a>' +
																			'<a id="exitSimMode"  href="#" onclick="exitSimMode();return false;"style="text-decoration:none; display:none; color:#BF0000; margin: 0px 10px 0px 0px;">  Exit Sim Mode  </a>' +
																			'<a id="startBattle"  href="#" onclick="startBattle();return false;" style="text-decoration:none; display:none;">Battle! (+0)</a>'+
																			'<a id="simTitle" href="#" style="text-decoration:none; display:none;"> Weewar Battle Simulator (GM)  </a>'
																		//	+
																		//	'<a id="hideSim" href="#" onclick="toggleSim(' + "'hide'" + ');return false;" style="text-decoration:none; position:absolute; margin: 0px 0px 0px 142px;"> Hide </a>'+
																		//	'<a id="secondHideSim" href="#" onclick="toggleSim(' + "'secondHide'" + ');return false;" style="text-decoration:none; position:absolute; margin: 0px 0px 0px 82px; display:none;"> Hide </a>'+
																		//	'<a id="showSim" href="#" onclick="toggleSim(' + "'show'" + ');return false;" style="text-decoration:none; margin: 0px 0px 0px 57px; display:none;"> Show </a>'
																			},
												{backgroundColor:"#EEE", padding:"3px 3px 5px 3px"});

	var unitsDiv = createDOMElement("div",{innerHTML:'units:'},{position:"absolute",borderBottom:"1px solid #808080",margin:"2.5px 0px 0px 2px",width:"273px", zIndex:"1"});
	
	var attackerImages = createDOMElement("div",{id:'attackerImages'},{position:"absolute",margin:"20px 0px 0px 2px", zIndex:"1"});
		attackerTerrainImg = createDOMElement("img",{id:'attackerTerrain'},{position:"absolute", zIndex:"2"});
		attackerUnitImg = createDOMElement("img",{id:'attackerUnit'},{position:"absolute", zIndex:"3"}); 
		attackerQuantImg = createDOMElement("img",{id:'attackerQuant'},{position:"absolute", zIndex:"4"});
		appendChildren(attackerImages,attackerTerrainImg,attackerUnitImg,attackerQuantImg);
		
	var defenderImages = createDOMElement("div",{id:'defenderImages'},{position:"absolute",margin:"54px 0px 0px 2px", zIndex:"1"});
		defenderTerrainImg = createDOMElement("img",{id:'defenderTerrain'},{position:"absolute", zIndex:"2"});
		defenderUnitImg = createDOMElement("img",{id:'defenderUnit'},{position:"absolute", zIndex:"3"}); 
		defenderQuantImg = createDOMElement("img",{id:'defenderQuant'},{position:"absolute", zIndex:"4"});
		appendChildren(defenderImages,defenderTerrainImg,defenderUnitImg,defenderQuantImg);
		
		defenderUnitImg.src = "/images/red_001.png";
		defenderTerrainImg.src = "/images/plain.png";
		defenderQuantImg.src = "/images/10.png";

		attackerUnitImg.src = "/images/blue_001.png";
		attackerTerrainImg.src = "/images/plain.png";
		attackerQuantImg.src = "/images/10.png";	
	
	var headerRow = buildTableRow([0,1,2,3,4,5,6,7,8,9,10],0,'th','Bonus');
	var attackerResultsRow = buildTableRow([0,0,0,0,0,0,0,0,0,0,0],32,'td','Attacker');
	var defenderResultsRow = buildTableRow([0,0,0,0,0,0,0,0,0,0,0],32,'td','Defender');
	
	var resultsTable = createDOMElement('div',{id:'resultsTable'},{position:"absolute",marginLeft:'32px',fontSize:'0.95em',zIndex:"9"});
		resultsTable.innerHTML = '<table><tbody>' + 
									'<tr id="headerRow">' + headerRow + '</tr>' + 
									'<tr id="attackerResultsRow">' + attackerResultsRow + '</tr>' +
									'<tr id="defenderResultsRow">' + defenderResultsRow + '</tr>' +
								 '</tbody></table>';
	
	var resultsSection = createDOMElement('div',{id:'resultsSection'});
	appendChildren(resultsSection,unitsDiv,attackerImages,defenderImages,resultsTable);
	appendChildren(simWindow,commandLinks,resultsSection);
	chatContainer.parentNode.insertBefore(simWindow,chatContainer);

}
function buildTableRow(contents,height,cellType,side)
{
	var rowString = '';
	for(var col=0; col <= 10; col++)
	{	
		rowString += '<' + cellType + ' width="22" height="' + height + '" align="center">' + '<a href="#" onclick="set' + side + 'Quant(' + col + ');return false;" style="text-decoration:none; color:#000000;">' + contents[col]  +'</a>'+ '</' + cellType + '>';
	}	
	return rowString;
}

function createDOMElement(name, attrs, styleList) { 
  var domElement = document.createElement(name);
  for(var prop in attrs) { domElement[prop] = attrs[prop]; }
  setStyle(domElement, styleList);
  return domElement; 
}
function setStyle(element, styleList) {
  for(var styleName in styleList) { 
  element.style[styleName] = styleList[styleName]; }
}
function appendChildren(element /*, list of children*/) {
  for(var i = 1; i < arguments.length; i++) element.appendChild(arguments[i]);
}

////////////////////////////// Game Interaction ///////////////////////////////

//function registration
unsafeWindow.setAttackerQuant = setAttackerQuant;
unsafeWindow.setDefenderQuant = setDefenderQuant;
unsafeWindow.setBonusQuant = setBonusQuant;
//unsafeWindow.toggleSim = toggleSim;
unsafeWindow.enterSimMode = enterSimMode;	
unsafeWindow.exitSimMode = exitSimMode;	
unsafeWindow.startBattle = startBattle;	
unsafeWindow.startSimMode = startSimMode;
unsafeWindow.cordGrabber = cordGrabber;
unsafeWindow.weewarMap._tooltip = unsafeWindow.weewarMap.tooltip;
unsafeWindow.weewarMap.tooltip = unsafeWindow.cordGrabber;

/* function toggleSim(state)
{
	 if(state == 'hide')
	{
	//	document.getElementById('hideSim').style.display = 'none;';
		document.getElementById('resultsSection').style.display = 'none;';
		document.getElementById('showSim').style.display = '';	
		document.getElementById('enterSimMode').style.display = 'none;';
		document.getElementById('simTitle').style.display = '';
		GM_setValue(showHideKey,'hide');
		
	}
	else if(state == 'show')
	{
		document.getElementById('hideSim').style.display = '';
		document.getElementById('resultsSection').style.display = '';
		document.getElementById('showSim').style.display = 'none;';	
		document.getElementById('simTitle').style.display = 'none;';
		document.getElementById('enterSimMode').style.display = '';
		GM_setValue(showHideKey,'show');
	} 
	else //second hide
	{
		document.getElementById('simTitle').style.display = '';
		document.getElementById('secondHideSim').style.display = 'none;';
		document.getElementById('showSim').style.display = '';	
		unsafeWindow.weewarMap.setClickFunction( oldClick );
		document.getElementById('exitSimMode').style.display = 'none;';	
		document.getElementById('startBattle').style.display = 'none;';
		document.getElementById('resultsSection').style.display = 'none;';
		GM_setValue(showHideKey,'hide');
	}
	return false;
}
*/
var oldClick;	
function enterSimMode()
{
	setBonusQuant(0);
	oldClick=unsafeWindow.weewarMap.getClickFunction();
	unsafeWindow.weewarMap.setClickFunction( startSimMode );
	document.getElementById('enterSimMode').style.display = "none";
	document.getElementById('exitSimMode').style.display = '';	
	document.getElementById('startBattle').style.display = '';
//	document.getElementById('hideSim').style.display = 'none;';
//	document.getElementById('secondHideSim').style.display = '';
	return false;
}
function exitSimMode()
{	
	unsafeWindow.weewarMap.setClickFunction( oldClick );
	document.getElementById('enterSimMode').style.display = '';
	document.getElementById('exitSimMode').style.display = "none";	
	document.getElementById('startBattle').style.display = "none";
//	document.getElementById('hideSim').style.display = '';
//	document.getElementById('secondHideSim').style.display = 'none;';
	return false;
}

var xcord;
var ycord;
function cordGrabber( x, y ) 
{
	xcord = x;
	ycord = y;
	unsafeWindow.weewarMap._tooltip( x,y );
}

var defender = true;
function startSimMode()
{
	defender = !defender;
	var unitTerrain = unsafeWindow.weewarMap.getTerrain(xcord,ycord);
	var unitType = unsafeWindow.weewarMap.getUnit(xcord,ycord)
	var unitQuantId = xcord + '_' + ycord + '_' + 'unitQuantity';
	var unitQuant;
	if(document.getElementById(unitQuantId))
	{
		unitQuant = document.getElementById(unitQuantId).src;
		unitQuant = unitQuant.substring(unitQuant.lastIndexOf('/')+1);
	}
	GM_log('defender?: ' + defender + 'terrain: ' + unitTerrain + ', unit: ' + unitType + ', number: ' + unitQuant);
	
	if(defender)
	{
		defenderUnitImg.src = "/images/" + unitType;
		defenderTerrainImg.src = "/images/" + unitTerrain;
		defenderQuantImg.src = "/images/" + unitQuant;
		
		myDefUnit = unitType;
		myDefNumber = parseInt(unitQuant.substring(0,unitQuant.indexOf('.')));
		myDefTerrain = unitTerrain;
	}
	else
	{
		attackerUnitImg.src = "/images/" + unitType;
		attackerTerrainImg.src = "/images/" + unitTerrain;
		attackerQuantImg.src = "/images/" + unitQuant;
		
		myAtkUnit = unitType;
		myAtkNumber = parseInt(unitQuant.substring(0,unitQuant.indexOf('.')));
		myAtkTerrain = unitTerrain;
	}
}

function setAttackerQuant(newQuant)
{
	attackerQuantImg.src = "/images/" + newQuant + ".png";
	myAtkNumber = newQuant;
}
function setDefenderQuant(newQuant)
{	
	defenderQuantImg.src = "/images/" + newQuant + ".png";
	myDefNumber = newQuant;
}
function setBonusQuant(newQuant)
{
	document.getElementById('startBattle').innerHTML = 'Battle! (+' + newQuant +')'
	myBonus = newQuant;
}

//////////////////////////////// Unit Stats ///////////////////////////////////

var softType_colIndex = 0;
var hardType_colIndex = 1;
var airType_colIndex = 2;
var speedboatType_colIndex = 3;
var amphibicType_colIndex = 4;
var subType_colIndex = 5;
var boatType_colIndex = 6;
var defenseStrength_colIndex = 7; 

var terrainAtkStats = new Array();  
terrainAtkStats["airfield"] =  [  2,  0,  3,  0,  0, -2,  0];
terrainAtkStats["city"] =      [  2,  0,  0,  0,  0,  0,  0];
terrainAtkStats["desert"] =    [ -1,  0,  0,  0,  0,  0,  0];
terrainAtkStats["harbor"] =    [  2,  0,  0,  0,  0, -2,  0];
terrainAtkStats["mountain"] =  [  2,-10,  0,  0,  0,  0,  0];
terrainAtkStats["plain"] =     [  0,  0,  0,  0,  0,  0,  0];
terrainAtkStats["repairshop"] =[  0,  0,  0,  0,  0,  0,  0];
terrainAtkStats["swamp"] =     [ -1, -1,  0,  0,  0,  0,  0];
terrainAtkStats["water"] =     [-10,-10,  0,  0,  0,  0,  0];
terrainAtkStats["forest"] =    [  2,  0,  0,  0,  0,  0,  0];

var terrainDefStats = new Array(); 
terrainDefStats["airfield"] =  [  2, -1,  3,  0, -1, -1, -1];
terrainDefStats["city"] =      [  2, -1,  0,  0,  0,  0,  0];
terrainDefStats["desert"] =    [ -1,  0,  0,  0,  0,  0,  0];
terrainDefStats["harbor"] =    [  2, -1,  0,  0, -1, -1, -1];
terrainDefStats["mountain"] =  [  4,-10,  0,  0,  0,  0,  0];
terrainDefStats["plain"] =     [  0,  0,  0,  0,  0,  0,  0];
terrainDefStats["repairshop"] =[ -6, -6,  0,  0,  0,  0,  0];
terrainDefStats["swamp"] =     [ -2, -2,  0,  0,  0,  0,  0];
terrainDefStats["water"] =     [-10,-10,  0,  0,  0,  0,  0];
terrainDefStats["forest"] =    [  3, -3,  0,  0,  0,  0,  0];

var attackStats = new Array();
							   //soft,   hard,    air, speed, amph,   sub,   boat,     def
attackStats["antiair"] =   	   [  8,  3,  9,  3,  3,  0,  3,  4]; // antiair
attackStats["004"] = 		   [  8,  6,  6,  6,  6,  0,  6,  6]; // assault artillery
attackStats["battleship"] =    [ 10, 14,  6, 14, 14,  4, 14, 14]; // battleship
attackStats["007"] =  		   [ 14, 16,  0, 14, 14,  0, 14, 14]; // berserker
attackStats["bomber"] =        [ 14, 14,  0, 14, 14,  0, 14, 10]; // bomber
attackStats["010"] =           [ 16, 14,  0, 14, 14,  0, 14,  4]; // DFA
attackStats["destroyer"] =     [ 10, 10, 12, 12, 12, 16, 10, 12]; // destroyer
attackStats["009"] =  		   [ 12, 10,  0, 10, 10,  0, 10,  4]; // heavy artillery
attackStats["006"] =   		   [ 10, 12,  0, 10, 10,  0, 10, 14]; // heavy tank
attackStats["002"] =   		   [  6,  8,  6,  8,  8,  0,  8,  6]; // heavy trooper
attackStats["heli"] =  		   [ 16, 10,  6, 12, 12,  0,  8, 10]; // helicopter
attackStats["hovercraft"] =    [ 10,  6,  0,  8, 10,  0,  6,  8]; // hovercraft
attackStats["jet"] =           [  6,  8, 16,  6,  6,  0,  6, 12]; // jet
attackStats["008"] = 		   [ 10,  4,  0,  4,  4,  0,  4,  3]; // light artillery
attackStats["003"] =   	       [ 10,  4,  4,  4,  8,  0,  4,  8]; // raider
attackStats["speedboat"] =     [  8,  6,  6, 10, 16,  0,  6,  6]; // speedboat
attackStats["sub"] =           [  0,  0,  0,  0,  0, 10, 16, 10]; // sub
attackStats["005"] =           [ 10,  7,  0,  7,  7,  0,  7, 10]; // tank
attackStats["001"] =   	       [  6,  3,  0,  3,  3,  0,  3,  6]; // trooper
attackStats["capturing"] =     [  0,  0,  0,  0,  0,  0,  0,  2]; // capturing

function getUnitTypeCol(thisUnit)
{
	var unitType_colIndex;
	if (thisUnit.indexOf("antiair") > -1 || thisUnit.indexOf("004") > -1 || thisUnit.indexOf("007") > -1 || thisUnit.indexOf("010") > -1 || thisUnit.indexOf("009")  > -1 || thisUnit.indexOf("006") > -1 || thisUnit.indexOf("008") > -1 || thisUnit.indexOf("003") > -1 || thisUnit.indexOf("005") > -1){
		unitType_colIndex = hardType_colIndex;
	}
	else if (thisUnit.indexOf("002") > -1 || thisUnit.indexOf("001") > -1 ||  thisUnit.indexOf("capturing") > -1){
		unitType_colIndex = softType_colIndex;
	}
	else if (thisUnit.indexOf("hovercraft") > -1){
		unitType_colIndex = amphibicType_colIndex;
	}
	else if (thisUnit.indexOf("battleship") > -1 || thisUnit.indexOf("destroyer") > -1 ){
		unitType_colIndex = boatType_colIndex;
	}
	else if (thisUnit.indexOf("bomber") > -1 || thisUnit.indexOf("heli") > -1 || thisUnit.indexOf("jet") > -1){
		unitType_colIndex = airType_colIndex;
	}
	else if (thisUnit.indexOf("sub") > -1){
		unitType_colIndex = subType_colIndex;
	}
	else if (thisUnit.indexOf("speedboat") > -1){
		unitType_colIndex = speedboatType_colIndex;
	}
	else{
		GM_log("did not find a unit type in fucntion getUnitTypeCol");
	}
		
	return unitType_colIndex;
}

////////////////////////////// Simulation Algorithms ////////////////////////////////////
 
//arrays for storing battle results
var attackerUnitsLeft = new Array();
var defenderUnitsLeft = new Array();

function clean(fileName)
{
	return fileName.substring(fileName.indexOf('_')+1,fileName.indexOf('.'))
}

function startBattle()
{
	var attackerAttackStrength = attackStats[clean(myAtkUnit)][getUnitTypeCol(myDefUnit)];
	var defenderAttackStrength = attackStats[clean(myDefUnit)][getUnitTypeCol(myAtkUnit)]; 

	var attackerTerrainAttackStat = terrainAtkStats[clean(myAtkTerrain)][getUnitTypeCol(myAtkUnit)];
	var attackerTerrainDefenseStat = terrainDefStats[clean(myAtkTerrain)][getUnitTypeCol(myAtkUnit)]; 

	var defenderTerrainAttackStat = terrainAtkStats[clean(myDefTerrain)][getUnitTypeCol(myDefUnit)];
	var defenderTerrainDefenseStat = terrainDefStats[clean(myDefTerrain)][getUnitTypeCol(myDefUnit)]; 

	var attackerDefense = attackStats[clean(myAtkUnit)][defenseStrength_colIndex];  
	var defenderDefense = attackStats[clean(myDefUnit)][defenseStrength_colIndex];  
	
	var attackerAttackP = 0.05 * (((attackerAttackStrength + attackerTerrainAttackStat) - (defenderDefense + defenderTerrainDefenseStat)) + myBonus) + 0.5;
	var defenderAttackP = 0.05 * (((defenderAttackStrength + defenderTerrainAttackStat) - (attackerDefense + attackerTerrainDefenseStat))) + 0.5;

	if (attackerAttackP < 0 || myAtkUnit.indexOf("capturing") > -1){ attackerAttackP = 0; } 
	else if (attackerAttackP > 1){ attackerAttackP = 1;	}
	
	if (defenderAttackP < 0 || myDefUnit.indexOf("capturing") > -1){ defenderAttackP = 0; } 
	else if (defenderAttackP > 1){ defenderAttackP = 1;	}
 
	// initialize the units-left storage arrays
	attackerUnitsLeft = [0,0,0,0,0,0,0,0,0,0,0];
	defenderUnitsLeft = [0,0,0,0,0,0,0,0,0,0,0];
	
	//run the battle algorithm as many times as specified in SIM_NUM
	for (var i = 0; i < SIM_NUM; i++)
	{
		attackerUnitsLeft[runHitSim(defenderAttackP,myDefNumber,myAtkNumber)]++;
		defenderUnitsLeft[runHitSim(attackerAttackP,myAtkNumber,myDefNumber)]++;
	}
	
	GM_log(attackerUnitsLeft + '|' + defenderUnitsLeft);	
	
	for(var r = 0; r <= 10; r++)
	{
		attackerUnitsLeft[r] = Math.round(attackerUnitsLeft[r]/SIM_NUM*100);		
		defenderUnitsLeft[r] = Math.round(defenderUnitsLeft[r]/SIM_NUM*100);
	}
	document.getElementById('attackerResultsRow').innerHTML = buildTableRow(attackerUnitsLeft,32,'td','Attacker');
	document.getElementById('defenderResultsRow').innerHTML = buildTableRow(defenderUnitsLeft,32,'td','Defender');			
 
	return false;
}

// the actual game algorithm caps the random number to two decimal points
const  DECIMAL_CAP = 100;  

function runHitSim(thisPvalue,atkNum,defNum)
{	
	var defenderUnitLoss = 0;	
	
	for (var attackerSubUnit = 1; attackerSubUnit <= atkNum; attackerSubUnit++)
	{	// per attacker subunit, the attacker will try out six hits on the defender
		var attackerHits = 0;		
		for (var h = 1; h <= 6; h++)
		{	// a hit is registered if the attacker's pValue is larger than a random number n, where 0.00 < n <= 1.00
			if (Math.floor(Math.random()*(DECIMAL_CAP + 1))/DECIMAL_CAP < thisPvalue){ attackerHits++; }
		}		
		//then the total number of defender units lost is the number of attacker hits divided by 6;
		defenderUnitLoss += attackerHits / 6;		
	}
	//then the total number of defender units left over is the number of starting units minus the number of units lost, rounded down - because you can't destroy a fraction of something.
	var defenderUnitsLeft = defNum - Math.floor(defenderUnitLoss);
	
	if (defenderUnitsLeft < 0){ defenderUnitsLeft = 0; }   // if less than 0, set to 0 to avoid error
	
	return defenderUnitsLeft;
}


///////////////////////////////////////////////////////////////////////////////////
////////////////////////// END OF BATTLE SIMULATOR //////////////////////////
///////////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////////
////////////////////////// START OF STATS ///////////////////////////////////////
////////////////////////// adpted from Tracy's script ////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////

function showStatsToggle() { 
	var statsToggleLink = A({"id":"statsToggleLink", "href":"#", "style":"font-size: 0.85em; padding-left: 8px; color: #00BF00; text-decoration: none;"},
						IMG({"width":"16", "height":"16", "src":"http://www.plutosforge.com/images/layout_content.png"}),"Stats");	
	insertSiblingNodesAfter(m_CommandToolbarStart,statsToggleLink); // add a link and icon to the commands tool bar	
	connect(statsToggleLink, "onclick", partial(toggleStats)); // event handler for starting the auto repair
}

var statsDisplayed = true;

function toggleStats() {
	if (!statsDisplayed) {
		$("newstats").style.display = "";
		statsDisplayed = true;
	} else {
		$("newstats").style.display = "none";
		statsDisplayed = false;
	}
}


var ScriptVersion = '1.2';

//------------------------------------
// functions
//------------------------------------
function getElementsByClassName(oElm, strTagName, strClassName){
	var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
	var arrReturnElements = new Array();
	strClassName = strClassName.replace(/\-/g, "\\-");
	var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
	var oElement;
	for(var i=0; i<arrElements.length; i++){
		oElement = arrElements[i];
		if(oRegExp.test(oElement.className)){
			arrReturnElements.push(oElement);
		}
	}
	return (arrReturnElements)
}

function ShowUnitInfo(intUnitId)
{
	alert(intUnitId);
}

//alert ('init');

var s, allElements, thisElement, imgCount;
var arrUnits, sID, sSRC, jj, idxUnit, strWikiBase;
var blnError, strError, sColors, arrUnitInfo;
var lngUnitCount, lngStrength;

// init error handling
blnError = false;
strError = '';
strWikiBase = 'http://www.weewar.info/weewar/show/';
// get document elements
allElements = document.evaluate(
	'//*[@src]',
	document,
	null,
	XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
	null);

imgCount = 0;

// create unit arrays
arrUnits = new Array();
arrUnitInfo = new Array();
for (jj = 0; jj < 35; jj++)
{
	arrUnits[jj] = new Array();
	arrUnitInfo[jj] = new Array();

}
arrUnitInfo[1][0] = 'Trooper';
arrUnitInfo[1][1] = 'Trooper';
arrUnitInfo[1][2] = 75;
arrUnitInfo[2][0] = 'Heavy Trooper';
arrUnitInfo[2][1] = 'Heavy+Trooper';
arrUnitInfo[2][2] = 150;
arrUnitInfo[3][0] = 'Raider';
arrUnitInfo[3][1] = 'Raider';
arrUnitInfo[3][2] = 200;
arrUnitInfo[4][0] = 'Assault Atillery';
arrUnitInfo[4][1] = 'Assault+Artillery';
arrUnitInfo[4][2] = 450;
arrUnitInfo[5][0] = 'Tank';
arrUnitInfo[5][1] = 'Tank';
arrUnitInfo[5][2] = 300;
arrUnitInfo[6][0] = 'Heavy Tank';
arrUnitInfo[6][1] = 'Heavy+Tank';
arrUnitInfo[6][2] = 600;
arrUnitInfo[7][0] = 'Berserker';
arrUnitInfo[7][1] = 'Berserker';
arrUnitInfo[7][2] = 900;
arrUnitInfo[8][0] = 'Light Artillery';
arrUnitInfo[8][1] = 'Light+Artillery';
arrUnitInfo[8][2] = 200;
arrUnitInfo[9][0] = 'Heavy Artillery';
arrUnitInfo[9][1] = 'Heavy+Artillery';
arrUnitInfo[9][2] = 600;
arrUnitInfo[10][0] = 'Death From Above';
arrUnitInfo[10][1] = 'Death+From+Above';
arrUnitInfo[10][2] = 1200;
arrUnitInfo[11][0] = 'Anti-Aircraft';
arrUnitInfo[11][1] = 'AA-Guns';
arrUnitInfo[11][2] = 400;
arrUnitInfo[12][0] = 'Hovercraft';
arrUnitInfo[12][1] = 'Hovercraft';
arrUnitInfo[12][2] = 300;
arrUnitInfo[13][0] = 'Helicopter';
arrUnitInfo[13][1] = 'Helicopters';
arrUnitInfo[13][2] = 600;
arrUnitInfo[14][0] = 'Jet';
arrUnitInfo[14][1] = 'Jets';
arrUnitInfo[14][2] = 800;
arrUnitInfo[15][0] = 'Bomber';
arrUnitInfo[15][1] = 'Bomber';
arrUnitInfo[15][2] = 900;
arrUnitInfo[16][0] = 'Speedboat';
arrUnitInfo[16][1] = 'Speedboats';
arrUnitInfo[16][2] = 200;
arrUnitInfo[17][0] = 'Destroyer';
arrUnitInfo[17][1] = 'Destroyer';
arrUnitInfo[17][2] = 900;
arrUnitInfo[18][0] = 'Sub';
arrUnitInfo[18][1] = 'Subs';
arrUnitInfo[18][2] = 1000;
arrUnitInfo[19][0] = 'Battleship';
arrUnitInfo[19][1] = 'Battleship';
arrUnitInfo[19][2] = 2000;

arrUnitInfo[26][0] = 'Capturing';
arrUnitInfo[26][1] = 'Terrain';
arrUnitInfo[26][2] = 0;
arrUnitInfo[27][0] = 'Harbor';
arrUnitInfo[27][1] = 'Terrain';
arrUnitInfo[27][2] = 0;
arrUnitInfo[28][0] = 'Airfield';
arrUnitInfo[28][1] = 'Terrain';
arrUnitInfo[28][2] = 0;
arrUnitInfo[29][0] = 'City';
arrUnitInfo[29][1] = 'Terrain';
arrUnitInfo[29][2] = 0;


// init army colors
sColors = new Array();
sColors[0] = '#81B7F5';
sColors[1] = '#FA5950';
sColors[2] = '#CE90C9';
sColors[3] = '#FFF22C';
sColors[4] = '#9FE07C';
sColors[5] = '#F4F7F2';

// init unit counts
for (jj = 0; jj < 35; jj++)
{
	arrUnits[0][jj] = 0;
	arrUnits[1][jj] = 0;
	arrUnits[2][jj] = 0;
	arrUnits[3][jj] = 0;
	arrUnits[4][jj] = 0;
	arrUnits[5][jj] = 0;
}

//alert ('scan images');

try
{
// scan images to find units
for (var ii = 0; ii < allElements.snapshotLength; ii++) {
    thisElement = allElements.snapshotItem(ii);  
    switch (thisElement.nodeName.toUpperCase()) {
        case 'A':
		// this is a link, do something
		break;  // 'A'

        case 'IMG':
		sID = thisElement.getAttribute('id');
		sSRC = thisElement.getAttribute('src');
		idxUnit = 0;

		// units
		if (sSRC.indexOf('_001') > -1) { idxUnit = 1 }
		if (sSRC.indexOf('_002') > -1) { idxUnit = 2 }
		if (sSRC.indexOf('_003') > -1) { idxUnit = 3 }
		if (sSRC.indexOf('_004') > -1) { idxUnit = 4 }
		if (sSRC.indexOf('_005') > -1) { idxUnit = 5 }
		if (sSRC.indexOf('_006') > -1) { idxUnit = 6 }
		if (sSRC.indexOf('_007') > -1) { idxUnit = 7 }
		if (sSRC.indexOf('_008') > -1) { idxUnit = 8 }
		if (sSRC.indexOf('_009') > -1) { idxUnit = 9 }
		if (sSRC.indexOf('010') > -1) { idxUnit = 10 }
		if (sSRC.indexOf('antiair') > -1) { idxUnit = 11 }
		if (sSRC.indexOf('hovercraft') > -1) { idxUnit = 12 }
		if (sSRC.indexOf('heli') > -1) { idxUnit = 13 }
		if (sSRC.indexOf('jet') > -1) { idxUnit = 14 }
		if (sSRC.indexOf('bomber') > -1) { idxUnit = 15 }
		if (sSRC.indexOf('speedboat') > -1) { idxUnit = 16 }
		if (sSRC.indexOf('destroyer') > -1) { idxUnit = 17 }
		if (sSRC.indexOf('sub') > -1) { idxUnit = 18 }
		if (sSRC.indexOf('battleship') > -1) { idxUnit = 19 }

		// currently no values for 20 to 25 ... left for future units

		// capturing
		if (sSRC.indexOf('capturing') > -1) { idxUnit = 26 }

		// bases
		if (sSRC.indexOf('_harbor') > -1) { idxUnit  = 27 }
		if (sSRC.indexOf('_airfield') > -1) { idxUnit  = 28 }
		if (sSRC.indexOf('_city') > -1) { idxUnit  = 29 }


		// get the strength of the army
		lngStrength = 0;
		if ((idxUnit > 0) && (idxUnit < 20))
		{
			ii++;
			thisElement = allElements.snapshotItem(ii);  
			sID = thisElement.getAttribute('src');
			if (sID.indexOf('1.png') > -1) { lngStrength = 1 }
			if (sID.indexOf('2.png') > -1) { lngStrength = 2 }
			if (sID.indexOf('3.png') > -1) { lngStrength = 3 }
			if (sID.indexOf('4.png') > -1) { lngStrength = 4 }
			if (sID.indexOf('5.png') > -1) { lngStrength = 5 }
			if (sID.indexOf('6.png') > -1) { lngStrength = 6 }
			if (sID.indexOf('7.png') > -1) { lngStrength = 7 }
			if (sID.indexOf('8.png') > -1) { lngStrength = 8 }
			if (sID.indexOf('9.png') > -1) { lngStrength = 9 }
			if (sID.indexOf('10.png') > -1) { lngStrength = 10 }
		}  // calc strength of army

		
		if (idxUnit > 0)
		{
			if (sSRC.indexOf('blue') > -1)
			{
				arrUnits[0][idxUnit]++;
				arrUnits[0][0]++;
				arrUnits[0][32] = arrUnits[0][32] + (lngStrength * arrUnitInfo[idxUnit][2]);
				arrUnits[0][33] = arrUnits[0][33] + (10 * arrUnitInfo[idxUnit][2]);
				arrUnits[0][34] = arrUnits[0][32] / arrUnits[0][33] *100;
				//GM_log('Blue ' + arrUnitInfo[idxUnit][0] + ': ' + lngStrength + ' * ' + arrUnitInfo[idxUnit][2]);
			}
			if (sSRC.indexOf('red') > -1)
			{
				arrUnits[1][idxUnit]++;
				arrUnits[1][0]++;
				arrUnits[1][32] = arrUnits[1][32] + (lngStrength * arrUnitInfo[idxUnit][2]);
				arrUnits[1][33] = arrUnits[1][33] + (10 * arrUnitInfo[idxUnit][2]);
				arrUnits[1][34] = arrUnits[1][32] / arrUnits[1][33] *100;
				//GM_log('Red ' + arrUnitInfo[idxUnit][0] + ': ' + lngStrength + ' * ' + arrUnitInfo[idxUnit][2]);
			}
			if (sSRC.indexOf('purple') > -1)
			{
				arrUnits[2][idxUnit]++;
				arrUnits[2][0]++;
				arrUnits[2][32] = arrUnits[2][32] + (lngStrength * arrUnitInfo[idxUnit][2]);
				arrUnits[2][33] = arrUnits[2][33] + (10 * arrUnitInfo[idxUnit][2]);
				arrUnits[2][34] = arrUnits[2][32] / arrUnits[2][33] *100;
				//GM_log('Purple ' + arrUnitInfo[idxUnit][0] + ': ' + lngStrength + ' * ' + arrUnitInfo[idxUnit][2]);
			}
			if (sSRC.indexOf('yellow') > -1)
			{
				arrUnits[3][idxUnit]++;
				arrUnits[3][0]++;
				arrUnits[3][32] = arrUnits[3][32] + (lngStrength * arrUnitInfo[idxUnit][2]);
				arrUnits[3][33] = arrUnits[3][33] + (10 * arrUnitInfo[idxUnit][2]);
				arrUnits[3][34] = arrUnits[3][32] / arrUnits[3][33] *100;
				//GM_log('Yellow ' + arrUnitInfo[idxUnit][0] + ': ' + lngStrength + ' * ' + arrUnitInfo[idxUnit][2]);
			}
			if (sSRC.indexOf('green') > -1)
			{
				arrUnits[4][idxUnit]++;
				arrUnits[4][0]++;
				arrUnits[4][32] = arrUnits[4][32] + (lngStrength * arrUnitInfo[idxUnit][2]);
				arrUnits[4][33] = arrUnits[4][33] + (10 * arrUnitInfo[idxUnit][2]);
				arrUnits[4][34] = arrUnits[4][32] / arrUnits[4][33] *100;
				//GM_log('Green ' + arrUnitInfo[idxUnit][0] + ': ' + lngStrength + ' * ' + arrUnitInfo[idxUnit][2]);
			}
			if (sSRC.indexOf('white') > -1)
			{
				arrUnits[5][idxUnit]++;
				arrUnits[5][0]++;
				arrUnits[5][32] = arrUnits[5][32] + (lngStrength * arrUnitInfo[idxUnit][2]);
				arrUnits[5][33] = arrUnits[5][33] + (10 * arrUnitInfo[idxUnit][2]);
				arrUnits[5][34] = arrUnits[5][32] / arrUnits[5][33] *100;
				//GM_log('White ' + arrUnitInfo[idxUnit][0] + ': ' + lngStrength + ' * ' + arrUnitInfo[idxUnit][2]);
			}

			imgCount++;
		}
		break;   // 'IMG'

        default:
		// do something with other kinds of HTML elements
    }  // switch on element type
}  // for ii to scan through elements
}
catch (eRR)
{
	blnError = true;
	strError = eRR + '<br>idxUnit: ' + idxUnit + '<br>Color: ' + sSRC + '<br>';
}

//alert ('build table');
var lngCount, sUnits, sTemp, lRows, kk;
var sRows, dArmyStr;

// init display rows for armies & total the playable units for each army
sRows = new Array();
lRows = 1;
for (kk = 0; kk < 6; kk++)  
{
	sRows[kk] = ''
	// get a the number of playable units of each army
	arrUnits[kk][31] = arrUnits[kk][0] - arrUnits[kk][26] - arrUnits[kk][27] - arrUnits[kk][28] - arrUnits[kk][29];
	// count active armies for the Rowspan to show "STATS"
	if (arrUnits[kk][0] > 0) { lRows++ }
	
	// cut the unit strength down
	arrUnits[kk][32] = arrUnits[kk][32] / 10;
	arrUnits[kk][33] = arrUnits[kk][33] / 10;
	//GM_log(kk + " army strength: " + arrUnits[kk][32] + "army potential: " + arrUnits[kk][33] + "army health: " + arrUnits[kk][34]);
}

s = '<table border=1>';
sUnits = '';

for (jj = 1; jj < 35; jj++) 
{
	lngCount = arrUnits[0][jj] + arrUnits[1][jj] + arrUnits[2][jj] + arrUnits[3][jj]+ arrUnits[4][jj]+ arrUnits[5][jj];
	try
	{
	if (lngCount > 0)   // if there are any units or bases of this type, add this column to the table
	{

		// unit headers
		// onmouseover='dtc(1,""Some Text About 9Kinds."",""9K Title""); return true;' onmouseout='nd(); return true;'
		sTemp = "<a href='" + strWikiBase + arrUnitInfo[jj][1] + "'><img src='/images/red_";
		//sTemp = "<img src='/images/red_";

		// units
		if (jj < 10) { sTemp = sTemp + "00" + jj + ".png'>" }
		else if (jj == 10) { sTemp = sTemp + "0" + jj + ".png'>" }
		else if (jj == 11) { sTemp = sTemp + "antiair.png'>" }
		else if (jj == 12) { sTemp = sTemp + "hovercraft.png'>" }
		else if (jj == 13) { sTemp = sTemp + "heli.png'>" }
		else if (jj == 14) { sTemp = sTemp + "jet.png'>" }
		else if (jj == 15) { sTemp = sTemp + "bomber.png'>" }
		else if (jj == 16) { sTemp = sTemp + "speedboat.png'>" }
		else if (jj == 17) { sTemp = sTemp + "destroyer.png'>" }
		else if (jj == 18) { sTemp = sTemp + "sub.png'>" }
		else if (jj == 19) { sTemp = sTemp + "battleship.png'>" }
		// capturing
		else if (jj == 26) { sTemp = sTemp + "capturing.gif'>" }
		// bases
		else if (jj == 27) { sTemp = sTemp + "harbor.png'>" }
		else if (jj == 28) { sTemp = sTemp + "airfield.png'>" }
		else if (jj == 29) { sTemp = sTemp + "city.png'>" }
		// total
		else if (jj == 31) { sTemp = "Total<br>Units" }   // idx 0 = units + bases + capturing; idx 31 = playable units only
		else if (jj == 32) { sTemp = "Army<br>Strength" }   
		else if (jj == 33) { sTemp = "Army<br>Potential" }   
		else if (jj == 34) { sTemp = "Health (%)" }
		else { sTemp = "Unknown" }
		
		if (jj < 31)
		{
			sTemp = sTemp + "</a>";
		}

		// display the unit image
		
		if (jj < 29) {
			sUnits = sUnits + "<td bgcolor='white' class='extraStats' style='display: none;'>" + sTemp + "</td>";			
		} else {
			sUnits = sUnits + "<td  align='center' width='45' bgcolor='white' >" + sTemp + "</td>";
		}

		// unit counts
		for (kk = 0; kk < 6; kk++)
		{
			if (arrUnits[kk][0] > 0)  // if this army has any units or bases, add data to the row
			{
				//GM_log(arrUnits[kk][jj]);
				
				var currStat = arrUnits[kk][jj];
				sRows[kk] += '<th width="32" bgcolor="' + sColors[kk] + '"';
				
				if (jj < 29)
				{
					sRows[kk] += 'class="extraStats" style="display: none;"';
				}
				if (jj < 32 || jj > 33)
				{
					sRows[kk] += 'align="center">';
				}
				else
				{
					sRows[kk] += 'align="right">';
				}
				
				sRows[kk] += currStat.toFixed(0) + '</th>';
			}
		}  // for kk
	} // if lngCount > 0
	}
	catch (eRR)
	{
		GM_log(eRR);
	}
}

unsafeWindow.expandStats = expandStats;
unsafeWindow.hideStats = hideStats;

sUnits = 	'<tr><td rowspan="' + lRows + '" valign="middle" align="center">' +
				'<a id="expandStatsLink" href="#" onclick="expandStats();return false;" style="text-decoration:none;"> S<br>T<br>A<br>T<br>S </a>' +
				'<a id="hideStatsLink" href="#" onclick="hideStats();return false;" style="text-decoration:none; display: none;"> S<br>T<br>A<br>T<br>S </a>' +
			'</td>' + sUnits + '</tr>';


s = s + sUnits;
for (kk = 0; kk < 6; kk++)
{
	sRows[kk] = '<tr>' + sRows[kk] + '</tr>';
	if (arrUnits[kk][0] > 0) 
	{
		s = s + sRows[kk];
	}
}



s = s + '</table>';


if (blnError) 
{
	s = '<table align="center" border="1" bgcolor="' + sColors[0] + '"><tr><td bgcolor="' + sColors[1] + '">WeeWar Stats encountered an error:<br>&nbsp;&nbsp;&nbsp;<b>' + strError + '</b><br>Please report this error.</td></tr></table>'
}
/*
else
{
	s = s + '<form id="stats"><input type="text" name="UnitInfo" size="100" value=""></form>'
}
*/

//s = s + '<br><font size="1" color="#606060">WeeWar Stats - v' + ScriptVersion + '</font><br>'
//alert ('find game summary');
// display the stats table before the Gamer Summary section
var main, newElement;
//main = document.getElementById('playing_field');
main = document.getElementById('game');

var chatContainer = document.getElementById('chat').parentNode;
if (main) {
	var newStats = document.createElement("div");

	//newStats.innerHTML = "<div id='overDiv' style='position:absolute; visibility:hide; z-index:1;'></div><script LANGUAGE='JavaScript' src='http://www.9kinds.com/scripts/overlib.js'></script>"
	try
	{
	newStats.innerHTML = "<div id='newstats' style='position: relative; margin-bottom: 10px; z-index: 15;>'" + s + "</div>";

	chatContainer.parentNode.insertBefore(newStats,chatContainer);
	//main.parentNode.insertBefore(newStats, main.nextSibling);
	}
	catch (eRR)
	{
		alert (eRR);
	}
}

var hiddenStats_TH = getElementsByClassName(newStats, "th", "extraStats");
var hiddenStats_TD = getElementsByClassName(newStats, "td", "extraStats");

function expandStats() {
	//GM_log(hiddenStats.length);
	for (var i = 0; i < hiddenStats_TH.length; i++) {
		hiddenStats_TH[i].style.display = "";
	}
	for (var i = 0; i < hiddenStats_TD.length; i++) {
		hiddenStats_TD[i].style.display = "";
	}
	$('expandStatsLink').style.display = "none";
	$('hideStatsLink').style.display = "";
}

function hideStats() {
	//GM_log(hiddenStats.length);
	for (var i = 0; i < hiddenStats_TH.length; i++) {
		hiddenStats_TH[i].style.display = "none";
	}
	for (var i = 0; i < hiddenStats_TD.length; i++) {
		hiddenStats_TD[i].style.display = "none";
	}
	$('expandStatsLink').style.display = "";
	$('hideStatsLink').style.display = "none";
}

/*
try {
var blnDone = false;
var elemInfo;

elemInfo = getElementsByClassName(document.getElementById("001.png"), "p", "note");

elemInfo[0].innerHTML = "Move 1-3 / Range 1 / Attack Sf:3, Hr:1, Air:1, SBoat:1, Hover:1, Sub:0, Boat:1";

}
catch (eRR)
{
	//alert (eRR);
}
*/

function ShowUnitStats(idxUnit)
{
	var elSpan;
	//elSpan = document.getElementById('UnitStats');
	alert ('Unit # ');
}
///////////////////////////////////////////////////////////////////////////////////
////////////////////////// END OF STATS //////////////////////////
///////////////////////////////////////////////////////////////////////////////////



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////// END OF WEEWAR-SPECIFIC SCRIPT //////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////// START OF GENERAL PURPOSE LIBRARIES & FUNCTIONS //////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MochiKit goes here
/***
    Custom Subset of MochiKit 1.4
    See <http://mochikit.com/> for documentation, downloads, license, etc.
    (c) 2005 Bob Ippolito.  All rights Reserved.
***/
if(typeof (MochiKit)=="undefined"){ MochiKit={}; }
if(typeof (MochiKit.Base)=="undefined"){ MochiKit.Base={}; }
if(typeof (MochiKit.__export__) == "undefined"){ MochiKit.__export__ = true; }
MochiKit.Base.VERSION="1.4";
MochiKit.Base.NAME="MochiKit.Base";
MochiKit.Base.update=function(_1,_2){
if(_1===null||_1===undefined){ _1={}; }
for(var i=1;i<arguments.length;i++){
var o=arguments[i];
if(typeof (o)!="undefined"&&o!==null){
for(var k in o){ _1[k]=o[k]; } 
} } return _1; };
MochiKit.Base.update(MochiKit.Base,{__repr__:function(){
return "["+this.NAME+" "+this.VERSION+"]";
},toString:function(){
return this.__repr__();
},camelize:function(_6){
var _7=_6.split("-");
var cc=_7[0];
for(var i=1;i<_7.length;i++){
cc+=_7[i].charAt(0).toUpperCase()+_7[i].substring(1);
}
return cc;
},counter:function(n){
if(arguments.length===0){
n=1;
}
return function(){
return n++;
};
},clone:function(_b){
var me=arguments.callee;
if(arguments.length==1){
me.prototype=_b;
return new me();
}
},_deps:function(_d,_e){
if(!(_d in MochiKit)){
MochiKit[_d]={};
}
for(var i=0;i<_e.length;i++){
if(!(_e[i] in MochiKit)){
throw "MochiKit."+_d+" depends on MochiKit."+_e[i]+"!";
}
}
},_flattenArray:function(res,lst){
for(var i=0;i<lst.length;i++){
var o=lst[i];
if(o instanceof Array){
arguments.callee(res,o);
}else{
res.push(o);
}
}
return res;
},flattenArray:function(lst){
return MochiKit.Base._flattenArray([],lst);
},flattenArguments:function(lst){
var res=[];
var m=MochiKit.Base;
var _18=m.extend(null,arguments);
while(_18.length){
var o=_18.shift();
if(o&&typeof (o)=="object"&&typeof (o.length)=="number") {
for(var i=o.length-1;i>=0;i--){
_18.unshift(o[i]);
}
}else{
res.push(o);
}
}
return res;
},extend:function(_1b,obj,_1d){
if(!_1d){
_1d=0;
}
if(obj){
var l=obj.length;
if(typeof (l)!="number"){
if(typeof (MochiKit.Iter)!="undefined"){
obj=MochiKit.Iter.list(obj);
l=obj.length;
}else{
throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
}
}
if(!_1b){
_1b=[];
}
for(var i=_1d;i<l;i++){
_1b.push(obj[i]);
}
}
return _1b;
},updatetree:function(_20,obj){
if(_20===null||_20===undefined){
_20={};
}
for(var i=1;i<arguments.length;i++){
var o=arguments[i];
if(typeof (o)!="undefined"&&o!==null){
for(var k in o){
var v=o[k];
if(typeof (_20[k])=="object"&&typeof (v)=="object"){
arguments.callee(_20[k],v);
}else{
_20[k]=v;
}
}
}
}
return _20;
},setdefault:function(_26,obj){
if(_26===null||_26===undefined){
_26={};
}
for(var i=1;i<arguments.length;i++){
var o=arguments[i];
for(var k in o){
if(!(k in _26)){
_26[k]=o[k];
}
}
}
return _26;
},keys:function(obj){
var _2c=[];
for(var _2d in obj){
_2c.push(_2d);
}
return _2c;
},values:function(obj){
var _2f=[];
for(var _30 in obj){
_2f.push(obj[_30]);
}
return _2f;
},items:function(obj){
var _32=[];
var e;
for(var _34 in obj){
var v;
try{
v=obj[_34];
}
catch(e){
continue;
}
_32.push([_34,v]);
}
return _32;
},_newNamedError:function(_36,_37,_38){
_38.prototype=new MochiKit.Base.NamedError(_36.NAME+"."+_37);
_36[_37]=_38;
},operator:{truth:function(a){
return !!a;
},lognot:function(a){
return !a;
},identity:function(a){
return a;
},not:function(a){
return ~a;
},neg:function(a){
return -a;
},add:function(a,b){
return a+b;
},sub:function(a,b){
return a-b;
},div:function(a,b){
return a/b;
},mod:function(a,b){
return a%b;
},mul:function(a,b){
return a*b;
},and:function(a,b){
return a&b;
},or:function(a,b){
return a|b;
},xor:function(a,b){
return a^b;
},lshift:function(a,b){
return a<<b;
},rshift:function(a,b){
return a>>b;
},zrshift:function(a,b){
return a>>>b;
},eq:function(a,b){
return a==b;
},ne:function(a,b){
return a!=b;
},gt:function(a,b){
return a>b;
},ge:function(a,b){
return a>=b;
},lt:function(a,b){
return a<b;
},le:function(a,b){
return a<=b;
},seq:function(a,b){
return a===b;
},sne:function(a,b){
return a!==b;
},ceq:function(a,b){
return MochiKit.Base.compare(a,b)===0;
},cne:function(a,b){
return MochiKit.Base.compare(a,b)!==0;
},cgt:function(a,b){
return MochiKit.Base.compare(a,b)==1;
},cge:function(a,b){
return MochiKit.Base.compare(a,b)!=-1;
},clt:function(a,b){
return MochiKit.Base.compare(a,b)==-1;
},cle:function(a,b){
return MochiKit.Base.compare(a,b)!=1;
},logand:function(a,b){
return a&&b;
},logor:function(a,b){
return a||b;
},contains:function(a,b){
return b in a;
}},forwardCall:function(_76){
return function(){
return this[_76].apply(this,arguments);
};
},itemgetter:function(_77){
return function(arg){
return arg[_77];
};
},typeMatcher:function(){
var _79={};
for(var i=0;i<arguments.length;i++){
var typ=arguments[i];
_79[typ]=typ;
}
return function(){
for(var i=0;i<arguments.length;i++){
if(!(typeof (arguments[i]) in _79)){
return false;
}
}
return true;
};
},isNull:function(){
for(var i=0;i<arguments.length;i++){
if(arguments[i]!==null){
return false;
}
}
return true;
},isUndefinedOrNull:function(){
for(var i=0;i<arguments.length;i++){
var o=arguments[i];
if(!(typeof (o)=="undefined"||o===null)){
return false;
}
}
return true;
},isEmpty:function(obj){
return !MochiKit.Base.isNotEmpty.apply(this,arguments);
},isNotEmpty:function(obj){
for(var i=0;i<arguments.length;i++){
var o=arguments[i];
if(!(o&&o.length)){
return false;
}
}
return true;
},isArrayLike:function(){
for(var i=0;i<arguments.length;i++){
var o=arguments[i];
var typ=typeof (o);
if((typ!="object"&&!(typ=="function"&&typeof (o.item)=="function"))||o===null||typeof (o.length)!="number"||o.nodeType===3||o.nodeType===4){
return false;
}
}
return true;
},isDateLike:function(){
for(var i=0;i<arguments.length;i++){
var o=arguments[i];
if(typeof (o)!="object"||o===null||typeof (o.getTime)!="function"){
return false;
}
}
return true;
},xmap:function(fn){
if(fn===null){
return MochiKit.Base.extend(null,arguments,1);
}
var _8a=[];
for(var i=1;i<arguments.length;i++){
_8a.push(fn(arguments[i]));
}
return _8a;
},map:function(fn,lst){
var m=MochiKit.Base;
var itr=MochiKit.Iter;
var _90=m.isArrayLike;
if(arguments.length<=2){
if(!_90(lst)){
if(itr){
lst=itr.list(lst);
if(fn===null){
return lst;
}
}else{
throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
}
}
if(fn===null){
return m.extend(null,lst);
}
var _91=[];
for(var i=0;i<lst.length;i++){
_91.push(fn(lst[i]));
}
return _91;
}else{
if(fn===null){
fn=Array;
}
var _93=null;
for(i=1;i<arguments.length;i++){
if(!_90(arguments[i])){
if(itr){
return itr.list(itr.imap.apply(null,arguments));
}else{
throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
}
}
var l=arguments[i].length;
if(_93===null||_93>l){
_93=l;
}
}
_91=[];
for(i=0;i<_93;i++){
var _95=[];
for(var j=1;j<arguments.length;j++){
_95.push(arguments[j][i]);
}
_91.push(fn.apply(this,_95));
}
return _91;
}
},xfilter:function(fn){
var _98=[];
if(fn===null){
fn=MochiKit.Base.operator.truth;
}
for(var i=1;i<arguments.length;i++){
var o=arguments[i];
if(fn(o)){
_98.push(o);
}
}
return _98;
},filter:function(fn,lst,_9d){
var _9e=[];
var m=MochiKit.Base;
if(!m.isArrayLike(lst)){
if(MochiKit.Iter){
lst=MochiKit.Iter.list(lst);
}else{
throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
}
}
if(fn===null){
fn=m.operator.truth;
}
if(typeof (Array.prototype.filter)=="function"){
return Array.prototype.filter.call(lst,fn,_9d);
}else{
if(typeof (_9d)=="undefined"||_9d===null){
for(var i=0;i<lst.length;i++){
var o=lst[i];
if(fn(o)){
_9e.push(o);
}
}
}else{
for(i=0;i<lst.length;i++){
o=lst[i];
if(fn.call(_9d,o)){
_9e.push(o);
}
}
}
}
return _9e;
},_wrapDumbFunction:function(_a2){
return function(){
switch(arguments.length){
case 0:
return _a2();
case 1:
return _a2(arguments[0]);
case 2:
return _a2(arguments[0],arguments[1]);
case 3:
return _a2(arguments[0],arguments[1],arguments[2]);
}
var _a3=[];
for(var i=0;i<arguments.length;i++){
_a3.push("arguments["+i+"]");
}
return eval("(func("+_a3.join(",")+"))");
};
},methodcaller:function(_a5){
var _a6=MochiKit.Base.extend(null,arguments,1);
if(typeof (_a5)=="function"){
return function(obj){
return _a5.apply(obj,_a6);
};
}else{
return function(obj){
return obj[_a5].apply(obj,_a6);
};
}
},method:function(_a9,_aa){
var m=MochiKit.Base;
return m.bind.apply(this,m.extend([_aa,_a9],arguments,2));
},compose:function(f1,f2){
var _ae=[];
var m=MochiKit.Base;
if(arguments.length===0){
throw new TypeError("compose() requires at least one argument");
}
for(var i=0;i<arguments.length;i++){
var fn=arguments[i];
if(typeof (fn)!="function"){
throw new TypeError(m.repr(fn)+" is not a function");
}
_ae.push(fn);
}
return function(){
var _b2=arguments;
for(var i=_ae.length-1;i>=0;i--){
_b2=[_ae[i].apply(this,_b2)];
}
return _b2[0];
};
},bind:function(_b4,_b5){
if(typeof (_b4)=="string"){
_b4=_b5[_b4];
}
var _b6=_b4.im_func;
var _b7=_b4.im_preargs;
var _b8=_b4.im_self;
var m=MochiKit.Base;
if(typeof (_b4)=="function"&&typeof (_b4.apply)=="undefined"){
_b4=m._wrapDumbFunction(_b4);
}
if(typeof (_b6)!="function"){
_b6=_b4;
}
if(typeof (_b5)!="undefined"){
_b8=_b5;
}
if(typeof (_b7)=="undefined"){
_b7=[];
}else{
_b7=_b7.slice();
}
m.extend(_b7,arguments,2);
var _ba=function(){
var _bb=arguments;
var me=arguments.callee;
if(me.im_preargs.length>0){
_bb=m.concat(me.im_preargs,_bb);
}
var _bd=me.im_self;
if(!_bd){
_bd=this;
}
return me.im_func.apply(_bd,_bb);
};
_ba.im_self=_b8;
_ba.im_func=_b6;
_ba.im_preargs=_b7;
return _ba;
},bindMethods:function(_be){
var _bf=MochiKit.Base.bind;
for(var k in _be){
var _c1=_be[k];
if(typeof (_c1)=="function"){
_be[k]=_bf(_c1,_be);
}
}
},registerComparator:function(_c2,_c3,_c4,_c5){
MochiKit.Base.comparatorRegistry.register(_c2,_c3,_c4,_c5);
},_primitives:{"boolean":true,"string":true,"number":true},compare:function(a,b){
if(a==b){
return 0;
}
var _c8=(typeof (a)=="undefined"||a===null);
var _c9=(typeof (b)=="undefined"||b===null);
if(_c8&&_c9){
return 0;
}else{
if(_c8){
return -1;
}else{
if(_c9){
return 1;
}
}
}
var m=MochiKit.Base;
var _cb=m._primitives;
if(!(typeof (a) in _cb&&typeof (b) in _cb)){
try{
return m.comparatorRegistry.match(a,b);
}
catch(e){
if(e!=m.NotFound){
throw e;
}
}
}
if(a<b){
return -1;
}else{
if(a>b){
return 1;
}
}
var _cc=m.repr;
throw new TypeError(_cc(a)+" and "+_cc(b)+" can not be compared");
},compareDateLike:function(a,b){
return MochiKit.Base.compare(a.getTime(),b.getTime());
},compareArrayLike:function(a,b){
var _d1=MochiKit.Base.compare;
var _d2=a.length;
var _d3=0;
if(_d2>b.length){
_d3=1;
_d2=b.length;
}else{
if(_d2<b.length){
_d3=-1;
}
}
for(var i=0;i<_d2;i++){
var cmp=_d1(a[i],b[i]);
if(cmp){
return cmp;
}
}
return _d3;
},registerRepr:function(_d6,_d7,_d8,_d9){
MochiKit.Base.reprRegistry.register(_d6,_d7,_d8,_d9);
},repr:function(o){
if(typeof (o)=="undefined"){
return "undefined";
}else{
if(o===null){
return "null";
}
}
try{
if(typeof (o.__repr__)=="function"){
return o.__repr__();
}else{
if(typeof (o.repr)=="function"&&o.repr!=arguments.callee){
return o.repr();
}
}
return MochiKit.Base.reprRegistry.match(o);
}
catch(e){
if(typeof (o.NAME)=="string"&&(o.toString==Function.prototype.toString||o.toString==Object.prototype.toString)){
return o.NAME;
}
}
try{
var _db=(o+"");
}
catch(e){
return "["+typeof (o)+"]";
}
if(typeof (o)=="function"){
_db=_db.replace(/^\s+/,"").replace(/\s+/g," ");
var idx=_db.indexOf("{");
if(idx!=-1){
_db=_db.substr(0,idx)+"{...}";
}
}
return _db;
},reprArrayLike:function(o){
var m=MochiKit.Base;
return "["+m.map(m.repr,o).join(", ")+"]";
},reprString:function(o){
return ("\""+o.replace(/(["\\])/g,"\\$1")+"\"").replace(/[\f]/g,"\\f").replace(/[\b]/g,"\\b").replace(/[\n]/g,"\\n").replace(/[\t]/g,"\\t").replace(/[\r]/g,"\\r");
},reprNumber:function(o){
return o+"";
},registerJSON:function(_e1,_e2,_e3,_e4){
MochiKit.Base.jsonRegistry.register(_e1,_e2,_e3,_e4);
},evalJSON:function(){
return eval("("+MochiKit.Base._filterJSON(arguments[0])+")");
},_filterJSON:function(s){
var m=s.match(/^\s*\/\*(.*)\*\/\s*$/);
if(m){
return m[1];
}
return s;
},serializeJSON:function(o){
var _e8=typeof (o);
if(_e8=="number"||_e8=="boolean"){
return o+"";
}else{
if(o===null){
return "null";
}
}
var m=MochiKit.Base;
var _ea=m.reprString;
if(_e8=="string"){
return _ea(o);
}
var me=arguments.callee;
var _ec;
if(typeof (o.__json__)=="function"){
_ec=o.__json__();
if(o!==_ec){
return me(_ec);
}
}
if(typeof (o.json)=="function"){
_ec=o.json();
if(o!==_ec){
return me(_ec);
}
}
if(_e8!="function"&&typeof (o.length)=="number"){
var res=[];
for(var i=0;i<o.length;i++){
var val=me(o[i]);
if(typeof (val)!="string"){
val="undefined";
}
res.push(val);
}
return "["+res.join(", ")+"]";
}
try{
_ec=m.jsonRegistry.match(o);
if(o!==_ec){
return me(_ec);
}
}
catch(e){
if(e!=m.NotFound){
throw e;
}
}
if(_e8=="undefined"){
throw new TypeError("undefined can not be serialized as JSON");
}
if(_e8=="function"){
return null;
}
res=[];
for(var k in o){
var _f1;
if(typeof (k)=="number"){
_f1="\""+k+"\"";
}else{
if(typeof (k)=="string"){
_f1=_ea(k);
}else{
continue;
}
}
val=me(o[k]);
if(typeof (val)!="string"){
continue;
}
res.push(_f1+":"+val);
}
return "{"+res.join(", ")+"}";
},objEqual:function(a,b){
return (MochiKit.Base.compare(a,b)===0);
},arrayEqual:function(_f4,arr){
if(_f4.length!=arr.length){
return false;
}
return (MochiKit.Base.compare(_f4,arr)===0);
},concat:function(){
var _f6=[];
var _f7=MochiKit.Base.extend;
for(var i=0;i<arguments.length;i++){
_f7(_f6,arguments[i]);
}
return _f6;
},keyComparator:function(key){
var m=MochiKit.Base;
var _fb=m.compare;
if(arguments.length==1){
return function(a,b){
return _fb(a[key],b[key]);
};
}
var _fe=m.extend(null,arguments);
return function(a,b){
var rval=0;
for(var i=0;(rval===0)&&(i<_fe.length);i++){
var key=_fe[i];
rval=_fb(a[key],b[key]);
}
return rval;
};
},reverseKeyComparator:function(key){
var _105=MochiKit.Base.keyComparator.apply(this,arguments);
return function(a,b){
return _105(b,a);
};
},partial:function(func){
var m=MochiKit.Base;
return m.bind.apply(this,m.extend([func,undefined],arguments,1));
},listMinMax:function(_10a,lst){
if(lst.length===0){
return null;
}
var cur=lst[0];
var _10d=MochiKit.Base.compare;
for(var i=1;i<lst.length;i++){
var o=lst[i];
if(_10d(o,cur)==_10a){
cur=o;
}
}
return cur;
},objMax:function(){
return MochiKit.Base.listMinMax(1,arguments);
},objMin:function(){
return MochiKit.Base.listMinMax(-1,arguments);
},findIdentical:function(lst,_111,_112,end){
if(typeof (end)=="undefined"||end===null){
end=lst.length;
}
if(typeof (_112)=="undefined"||_112===null){
_112=0;
}
for(var i=_112;i<end;i++){
if(lst[i]===_111){
return i;
}
}
return -1;
},mean:function(){
var sum=0;
var m=MochiKit.Base;
var args=m.extend(null,arguments);
var _118=args.length;
while(args.length){
var o=args.shift();
if(o&&typeof (o)=="object"&&typeof (o.length)=="number"){
_118+=o.length-1;
for(var i=o.length-1;i>=0;i--){
sum+=o[i];
}
}else{
sum+=o;
}
}
if(_118<=0){
throw new TypeError("mean() requires at least one argument");
}
return sum/_118;
},median:function(){
var data=MochiKit.Base.flattenArguments(arguments);
if(data.length===0){
throw new TypeError("median() requires at least one argument");
}
data.sort(compare);
if(data.length%2==0){
var _11c=data.length/2;
return (data[_11c]+data[_11c-1])/2;
}else{
return data[(data.length-1)/2];
}
},findValue:function(lst,_11e,_11f,end){
if(typeof (end)=="undefined"||end===null){
end=lst.length;
}
if(typeof (_11f)=="undefined"||_11f===null){
_11f=0;
}
var cmp=MochiKit.Base.compare;
for(var i=_11f;i<end;i++){
if(cmp(lst[i],_11e)===0){
return i;
}
}
return -1;
},nodeWalk:function(node,_124){
var _125=[node];
var _126=MochiKit.Base.extend;
while(_125.length){
var res=_124(_125.shift());
if(res){
_126(_125,res);
}
}
},nameFunctions:function(_128){
var base=_128.NAME;
if(typeof (base)=="undefined"){
base="";
}else{
base=base+".";
}
for(var name in _128){
var o=_128[name];
if(typeof (o)=="function"&&typeof (o.NAME)=="undefined"){
try{
o.NAME=base+name;
}
catch(e){
}
}
}
},queryString:function(_12c,_12d){
if(typeof (MochiKit.DOM)!="undefined"&&arguments.length==1&&(typeof (_12c)=="string"||(typeof (_12c.nodeType)!="undefined"&&_12c.nodeType>0))){
var kv=MochiKit.DOM.formContents(_12c);
_12c=kv[0];
_12d=kv[1];
}else{
if(arguments.length==1){
if(typeof (_12c.length)=="number"&&_12c.length==2){
return arguments.callee(_12c[0],_12c[1]);
}
var o=_12c;
_12c=[];
_12d=[];
for(var k in o){
var v=o[k];
if(typeof (v)=="function"){
continue;
}else{
if(MochiKit.Base.isArrayLike(v)){
for(var i=0;i<v.length;i++){
_12c.push(k);
_12d.push(v[i]);
}
}else{
_12c.push(k);
_12d.push(v);
}
}
}
}
}
var rval=[];
var len=Math.min(_12c.length,_12d.length);
var _135=MochiKit.Base.urlEncode;
for(var i=0;i<len;i++){
v=_12d[i];
if(typeof (v)!="undefined"&&v!==null){
rval.push(_135(_12c[i])+"="+_135(v));
}
}
return rval.join("&");
},parseQueryString:function(_136,_137){
var qstr=(_136.charAt(0)=="?")?_136.substring(1):_136;
var _139=qstr.replace(/\+/g,"%20").split(/\&amp\;|\&\#38\;|\&#x26;|\&/);
var o={};
var _13b;
if(typeof (decodeURIComponent)!="undefined"){
_13b=decodeURIComponent;
}else{
_13b=unescape;
}
if(_137){
for(var i=0;i<_139.length;i++){
var pair=_139[i].split("=");
var name=_13b(pair.shift());
if(!name){
continue;
}
var arr=o[name];
if(!(arr instanceof Array)){
arr=[];
o[name]=arr;
}
arr.push(_13b(pair.join("=")));
}
}else{
for(i=0;i<_139.length;i++){
pair=_139[i].split("=");
var name=pair.shift();
if(!name){
continue;
}
o[_13b(name)]=_13b(pair.join("="));
}
}
return o;
}});
MochiKit.Base.AdapterRegistry=function(){
this.pairs=[];
};
MochiKit.Base.AdapterRegistry.prototype={register:function(name,_141,wrap,_143){
if(_143){
this.pairs.unshift([name,_141,wrap]);
}else{
this.pairs.push([name,_141,wrap]);
}
},match:function(){
for(var i=0;i<this.pairs.length;i++){
var pair=this.pairs[i];
if(pair[1].apply(this,arguments)){
return pair[2].apply(this,arguments);
}
}
throw MochiKit.Base.NotFound;
},unregister:function(name){
for(var i=0;i<this.pairs.length;i++){
var pair=this.pairs[i];
if(pair[0]==name){
this.pairs.splice(i,1);
return true;
}
}
return false;
}};
MochiKit.Base.EXPORT=["flattenArray","noop","camelize","counter","clone","extend","update","updatetree","setdefault","keys","values","items","NamedError","operator","forwardCall","itemgetter","typeMatcher","isCallable","isUndefined","isUndefinedOrNull","isNull","isEmpty","isNotEmpty","isArrayLike","isDateLike","xmap","map","xfilter","filter","methodcaller","compose","bind","bindMethods","NotFound","AdapterRegistry","registerComparator","compare","registerRepr","repr","objEqual","arrayEqual","concat","keyComparator","reverseKeyComparator","partial","merge","listMinMax","listMax","listMin","objMax","objMin","nodeWalk","zip","urlEncode","queryString","serializeJSON","registerJSON","evalJSON","parseQueryString","findValue","findIdentical","flattenArguments","method","average","mean","median"];
MochiKit.Base.EXPORT_OK=["nameFunctions","comparatorRegistry","reprRegistry","jsonRegistry","compareDateLike","compareArrayLike","reprArrayLike","reprString","reprNumber"];
MochiKit.Base._exportSymbols=function(_149,_14a){
if(!MochiKit.__export__){
return;
}
var all=_14a.EXPORT_TAGS[":all"];
for(var i=0;i<all.length;i++){
_149[all[i]]=_14a[all[i]];
}
};
MochiKit.Base.__new__=function(){
var m=this;
m.noop=m.operator.identity;
m.forward=m.forwardCall;
m.find=m.findValue;
if(typeof (encodeURIComponent)!="undefined"){
m.urlEncode=function(_14e){
return encodeURIComponent(_14e).replace(/\'/g,"%27");
};
}else{
m.urlEncode=function(_14f){
return escape(_14f).replace(/\+/g,"%2B").replace(/\"/g,"%22").rval.replace(/\'/g,"%27");
};
}
m.NamedError=function(name){
this.message=name;
this.name=name;
};
m.NamedError.prototype=new Error();
m.update(m.NamedError.prototype,{repr:function(){
if(this.message&&this.message!=this.name){
return this.name+"("+m.repr(this.message)+")";
}else{
return this.name+"()";
}
},toString:m.forwardCall("repr")});
m.NotFound=new m.NamedError("MochiKit.Base.NotFound");
m.listMax=m.partial(m.listMinMax,1);
m.listMin=m.partial(m.listMinMax,-1);
m.isCallable=m.typeMatcher("function");
m.isUndefined=m.typeMatcher("undefined");
m.merge=m.partial(m.update,null);
m.zip=m.partial(m.map,null);
m.average=m.mean;
m.comparatorRegistry=new m.AdapterRegistry();
m.registerComparator("dateLike",m.isDateLike,m.compareDateLike);
m.registerComparator("arrayLike",m.isArrayLike,m.compareArrayLike);
m.reprRegistry=new m.AdapterRegistry();
m.registerRepr("arrayLike",m.isArrayLike,m.reprArrayLike);
m.registerRepr("string",m.typeMatcher("string"),m.reprString);
m.registerRepr("numbers",m.typeMatcher("number","boolean"),m.reprNumber);
m.jsonRegistry=new m.AdapterRegistry();
var all=m.concat(m.EXPORT,m.EXPORT_OK);
m.EXPORT_TAGS={":common":m.concat(m.EXPORT_OK),":all":all};
m.nameFunctions(this);
};
MochiKit.Base.__new__();
if(MochiKit.__export__){
compare=MochiKit.Base.compare;
compose=MochiKit.Base.compose;
serializeJSON=MochiKit.Base.serializeJSON;
mean=MochiKit.Base.mean;
median=MochiKit.Base.median;
}
MochiKit.Base._exportSymbols(this,MochiKit.Base);
MochiKit.Base._deps("Async",["Base"]);
MochiKit.Async.NAME="MochiKit.Async";
MochiKit.Async.VERSION="1.4";
MochiKit.Async.__repr__=function(){
return "["+this.NAME+" "+this.VERSION+"]";
};
MochiKit.Async.toString=function(){
return this.__repr__();
};
MochiKit.Async.Deferred=function(_152){
this.chain=[];
this.id=this._nextId();
this.fired=-1;
this.paused=0;
this.results=[null,null];
this.canceller=_152;
this.silentlyCancelled=false;
this.chained=false;
};
MochiKit.Async.Deferred.prototype={repr:function(){
var _153;
if(this.fired==-1){
_153="unfired";
}else{
if(this.fired===0){
_153="success";
}else{
_153="error";
}
}
return "Deferred("+this.id+", "+_153+")";
},toString:MochiKit.Base.forwardCall("repr"),_nextId:MochiKit.Base.counter(),cancel:function(){
var self=MochiKit.Async;
if(this.fired==-1){
if(this.canceller){
this.canceller(this);
}else{
this.silentlyCancelled=true;
}
if(this.fired==-1){
this.errback(new self.CancelledError(this));
}
}else{
if((this.fired===0)&&(this.results[0] instanceof self.Deferred)){
this.results[0].cancel();
}
}
},_resback:function(res){
this.fired=((res instanceof Error)?1:0);
this.results[this.fired]=res;
this._fire();
},_check:function(){
if(this.fired!=-1){
if(!this.silentlyCancelled){
throw new MochiKit.Async.AlreadyCalledError(this);
}
this.silentlyCancelled=false;
return;
}
},callback:function(res){
this._check();
if(res instanceof MochiKit.Async.Deferred){
throw new Error("Deferred instances can only be chained if they are the result of a callback");
}
this._resback(res);
},errback:function(res){
this._check();
var self=MochiKit.Async;
if(res instanceof self.Deferred){
throw new Error("Deferred instances can only be chained if they are the result of a callback");
}
if(!(res instanceof Error)){
res=new self.GenericError(res);
}
this._resback(res);
},addBoth:function(fn){
if(arguments.length>1){
fn=MochiKit.Base.partial.apply(null,arguments);
}
return this.addCallbacks(fn,fn);
},addCallback:function(fn){
if(arguments.length>1){
fn=MochiKit.Base.partial.apply(null,arguments);
}
return this.addCallbacks(fn,null);
},addErrback:function(fn){
if(arguments.length>1){
fn=MochiKit.Base.partial.apply(null,arguments);
}
return this.addCallbacks(null,fn);
},addCallbacks:function(cb,eb){
if(this.chained){
throw new Error("Chained Deferreds can not be re-used");
}
this.chain.push([cb,eb]);
if(this.fired>=0){
this._fire();
}
return this;
},_fire:function(){
var _15e=this.chain;
var _15f=this.fired;
var res=this.results[_15f];
var self=this;
var cb=null;
while(_15e.length>0&&this.paused===0){
var pair=_15e.shift();
var f=pair[_15f];
if(f===null){
continue;
}
try{
res=f(res);
_15f=((res instanceof Error)?1:0);
if(res instanceof MochiKit.Async.Deferred){
cb=function(res){
self._resback(res);
self.paused--;
if((self.paused===0)&&(self.fired>=0)){
self._fire();
}
};
this.paused++;
}
}
catch(err){
_15f=1;
if(!(err instanceof Error)){
err=new MochiKit.Async.GenericError(err);
}
res=err;
}
}
this.fired=_15f;
this.results[_15f]=res;
if(cb&&this.paused){
res.addBoth(cb);
res.chained=true;
}
}};
MochiKit.Base.update(MochiKit.Async,{evalJSONRequest:function(req){
return MochiKit.Base.evalJSON(req.responseText);
},succeed:function(_167){
var d=new MochiKit.Async.Deferred();
d.callback.apply(d,arguments);
return d;
},fail:function(_169){
var d=new MochiKit.Async.Deferred();
d.errback.apply(d,arguments);
return d;
},getXMLHttpRequest:function(){
var self=arguments.callee;
if(!self.XMLHttpRequest){
var _16c=[function(){
return new XMLHttpRequest();
},function(){
return new ActiveXObject("Msxml2.XMLHTTP");
},function(){
return new ActiveXObject("Microsoft.XMLHTTP");
},function(){
return new ActiveXObject("Msxml2.XMLHTTP.4.0");
},function(){
throw new MochiKit.Async.BrowserComplianceError("Browser does not support XMLHttpRequest");
}];
for(var i=0;i<_16c.length;i++){
var func=_16c[i];
try{
self.XMLHttpRequest=func;
return func();
}
catch(e){
}
}
}
return self.XMLHttpRequest();
},_xhr_onreadystatechange:function(d){
var m=MochiKit.Base;
if(this.readyState==4){
try{
this.onreadystatechange=null;
}
catch(e){
try{
this.onreadystatechange=m.noop;
}
catch(e){
}
}
var _171=null;
try{
_171=this.status;
if(!_171&&m.isNotEmpty(this.responseText)){
_171=304;
}
}
catch(e){
}
if(_171==200||_171==201||_171==204||_171==304||_171==1223){
d.callback(this);
}else{
var err=new MochiKit.Async.XMLHttpRequestError(this,"Request failed");
if(err.number){
d.errback(err);
}else{
d.errback(err);
}
}
}
},_xhr_canceller:function(req){
try{
req.onreadystatechange=null;
}
catch(e){
try{
req.onreadystatechange=MochiKit.Base.noop;
}
catch(e){
}
}
req.abort();
},sendXMLHttpRequest:function(req,_175){
if(typeof (_175)=="undefined"||_175===null){
_175="";
}
var m=MochiKit.Base;
var self=MochiKit.Async;
var d=new self.Deferred(m.partial(self._xhr_canceller,req));
try{
req.onreadystatechange=m.bind(self._xhr_onreadystatechange,req,d);
req.send(_175);
}
catch(e){
try{
req.onreadystatechange=null;
}
catch(ignore){
}
d.errback(e);
}
return d;
},doXHR:function(url,opts){
var self=MochiKit.Async;
return self.callLater(0,self._doXHR,url,opts);
},_doXHR:function(url,opts){
var m=MochiKit.Base;
opts=m.update({method:"GET",sendContent:""},opts);
var self=MochiKit.Async;
var req=self.getXMLHttpRequest();
if(opts.queryString){
var qs=m.queryString(opts.queryString);
if(qs){
url+="?"+qs;
}
}
if("username" in opts){
req.open(opts.method,url,true,opts.username,opts.password);
}else{
req.open(opts.method,url,true);
}
if(req.overrideMimeType&&opts.mimeType){
req.overrideMimeType(opts.mimeType);
}
req.setRequestHeader("X-Requested-With","XMLHttpRequest");
if(opts.headers){
var _182=opts.headers;
if(!m.isArrayLike(_182)){
_182=m.items(_182);
}
for(var i=0;i<_182.length;i++){
var _184=_182[i];
var name=_184[0];
var _186=_184[1];
req.setRequestHeader(name,_186);
}
}
return self.sendXMLHttpRequest(req,opts.sendContent);
},_buildURL:function(url){
if(arguments.length>1){
var m=MochiKit.Base;
var qs=m.queryString.apply(null,m.extend(null,arguments,1));
if(qs){
return url+"?"+qs;
}
}
return url;
},doSimpleXMLHttpRequest:function(url){
var self=MochiKit.Async;
url=self._buildURL.apply(self,arguments);
return self.doXHR(url);
},loadJSONDoc:function(url){
var self=MochiKit.Async;
url=self._buildURL.apply(self,arguments);
var d=self.doXHR(url,{"mimeType":"text/plain","headers":[["Accept","application/json"]]});
d=d.addCallback(self.evalJSONRequest);
return d;
},wait:function(_18f,_190){
var d=new MochiKit.Async.Deferred();
var m=MochiKit.Base;
if(typeof (_190)!="undefined"){
d.addCallback(function(){
return _190;
});
}
var _193=setTimeout(m.bind("callback",d),Math.floor(_18f*1000));
d.canceller=function(){
try{
clearTimeout(_193);
}
catch(e){
}
};
return d;
},callLater:function(_194,func){
var m=MochiKit.Base;
var _197=m.partial.apply(m,m.extend(null,arguments,1));
return MochiKit.Async.wait(_194).addCallback(function(res){
return _197();
});
}});
MochiKit.Async.DeferredLock=function(){
this.waiting=[];
this.locked=false;
this.id=this._nextId();
};
MochiKit.Async.DeferredLock.prototype={__class__:MochiKit.Async.DeferredLock,acquire:function(){
var d=new MochiKit.Async.Deferred();
if(this.locked){
this.waiting.push(d);
}else{
this.locked=true;
d.callback(this);
}
return d;
},release:function(){
if(!this.locked){
throw TypeError("Tried to release an unlocked DeferredLock");
}
this.locked=false;
if(this.waiting.length>0){
this.locked=true;
this.waiting.shift().callback(this);
}
},_nextId:MochiKit.Base.counter(),repr:function(){
var _19a;
if(this.locked){
_19a="locked, "+this.waiting.length+" waiting";
}else{
_19a="unlocked";
}
return "DeferredLock("+this.id+", "+_19a+")";
},toString:MochiKit.Base.forwardCall("repr")};
MochiKit.Async.DeferredList=function(list,_19c,_19d,_19e,_19f){
MochiKit.Async.Deferred.apply(this,[_19f]);
this.list=list;
var _1a0=[];
this.resultList=_1a0;
this.finishedCount=0;
this.fireOnOneCallback=_19c;
this.fireOnOneErrback=_19d;
this.consumeErrors=_19e;
var cb=MochiKit.Base.bind(this._cbDeferred,this);
for(var i=0;i<list.length;i++){
var d=list[i];
_1a0.push(undefined);
d.addCallback(cb,i,true);
d.addErrback(cb,i,false);
}
if(list.length===0&&!_19c){
this.callback(this.resultList);
}
};
MochiKit.Async.DeferredList.prototype=new MochiKit.Async.Deferred();
MochiKit.Async.DeferredList.prototype._cbDeferred=function(_1a4,_1a5,_1a6){
this.resultList[_1a4]=[_1a5,_1a6];
this.finishedCount+=1;
if(this.fired==-1){
if(_1a5&&this.fireOnOneCallback){
this.callback([_1a4,_1a6]);
}else{
if(!_1a5&&this.fireOnOneErrback){
this.errback(_1a6);
}else{
if(this.finishedCount==this.list.length){
this.callback(this.resultList);
}
}
}
}
if(!_1a5&&this.consumeErrors){
_1a6=null;
}
return _1a6;
};
MochiKit.Async.gatherResults=function(_1a7){
var d=new MochiKit.Async.DeferredList(_1a7,false,true,false);
d.addCallback(function(_1a9){
var ret=[];
for(var i=0;i<_1a9.length;i++){
ret.push(_1a9[i][1]);
}
return ret;
});
return d;
};
MochiKit.Async.maybeDeferred=function(func){
var self=MochiKit.Async;
var _1ae;
try{
var r=func.apply(null,MochiKit.Base.extend([],arguments,1));
if(r instanceof self.Deferred){
_1ae=r;
}else{
if(r instanceof Error){
_1ae=self.fail(r);
}else{
_1ae=self.succeed(r);
}
}
}
catch(e){
_1ae=self.fail(e);
}
return _1ae;
};
MochiKit.Async.EXPORT=["AlreadyCalledError","CancelledError","BrowserComplianceError","GenericError","XMLHttpRequestError","Deferred","succeed","fail","getXMLHttpRequest","doSimpleXMLHttpRequest","loadJSONDoc","wait","callLater","sendXMLHttpRequest","DeferredLock","DeferredList","gatherResults","maybeDeferred","doXHR"];
MochiKit.Async.EXPORT_OK=["evalJSONRequest"];
MochiKit.Async.__new__=function(){
var m=MochiKit.Base;
var ne=m.partial(m._newNamedError,this);
ne("AlreadyCalledError",function(_1b2){
this.deferred=_1b2;
});
ne("CancelledError",function(_1b3){
this.deferred=_1b3;
});
ne("BrowserComplianceError",function(msg){
this.message=msg;
});
ne("GenericError",function(msg){
this.message=msg;
});
ne("XMLHttpRequestError",function(req,msg){
this.req=req;
this.message=msg;
try{
this.number=req.status;
}
catch(e){
}
});
this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
m.nameFunctions(this);
};
MochiKit.Async.__new__();
MochiKit.Base._exportSymbols(this,MochiKit.Async);
MochiKit.Base._deps("DOM",["Base"]);
MochiKit.DOM.NAME="MochiKit.DOM";
MochiKit.DOM.VERSION="1.4";
MochiKit.DOM.__repr__=function(){
return "["+this.NAME+" "+this.VERSION+"]";
};
MochiKit.DOM.toString=function(){
return this.__repr__();
};
MochiKit.DOM.EXPORT=["removeEmptyTextNodes","formContents","currentWindow","currentDocument","withWindow","withDocument","registerDOMConverter","coerceToDOM","createDOM","createDOMFunc","isChildNode","getNodeAttribute","removeNodeAttribute","setNodeAttribute","updateNodeAttributes","appendChildNodes","insertSiblingNodesAfter","insertSiblingNodesBefore","replaceChildNodes","removeElement","swapDOM","BUTTON","TT","PRE","H1","H2","H3","BR","CANVAS","HR","LABEL","TEXTAREA","FORM","STRONG","SELECT","OPTION","OPTGROUP","LEGEND","FIELDSET","P","UL","OL","LI","DL","DT","DD","TD","TR","THEAD","TBODY","TFOOT","TABLE","TH","INPUT","SPAN","A","DIV","IMG","getElement","$","getElementsByTagAndClassName","addToCallStack","addLoadEvent","focusOnLoad","setElementClass","toggleElementClass","addElementClass","removeElementClass","swapElementClass","hasElementClass","escapeHTML","toHTML","emitHTML","scrapeText","isParent","getFirstParentByTagAndClassName","makeClipping","undoClipping","makePositioned","undoPositioned","getFirstElementByTagAndClassName"];
MochiKit.DOM.EXPORT_OK=["domConverters"];
MochiKit.DOM.DEPRECATED=[["computedStyle","MochiKit.Style.getStyle","1.4"],["elementDimensions","MochiKit.Style.getElementDimensions","1.4"],["elementPosition","MochiKit.Style.getElementPosition","1.4"],["hideElement","MochiKit.Style.hideElement","1.4"],["setElementDimensions","MochiKit.Style.setElementDimensions","1.4"],["setElementPosition","MochiKit.Style.setElementPosition","1.4"],["setDisplayForElement","MochiKit.Style.setDisplayForElement","1.4"],["setOpacity","MochiKit.Style.setOpacity","1.4"],["showElement","MochiKit.Style.showElement","1.4"],["Coordinates","MochiKit.Style.Coordinates","1.4"],["Dimensions","MochiKit.Style.Dimensions","1.4"]];
MochiKit.DOM.getViewportDimensions=new Function(""+"if (!MochiKit[\"Style\"]) {"+"    throw new Error(\"This function has been deprecated and depends on MochiKit.Style.\");"+"}"+"return MochiKit.Style.getViewportDimensions.apply(this, arguments);");
MochiKit.Base.update(MochiKit.DOM,{currentWindow:function(){
return MochiKit.DOM._window;
},currentDocument:function(){
return MochiKit.DOM._document;
},withWindow:function(win,func){
var self=MochiKit.DOM;
var _1bb=self._document;
var _1bc=self._window;
var rval;
try{
self._window=win;
self._document=win.document;
rval=func();
}
catch(e){
self._window=_1bc;
self._document=_1bb;
throw e;
}
self._window=_1bc;
self._document=_1bb;
return rval;
},formContents:function(elem){
var _1bf=[];
var _1c0=[];
var m=MochiKit.Base;
var self=MochiKit.DOM;
if(typeof (elem)=="undefined"||elem===null){
elem=self._document.body;
}else{
elem=self.getElement(elem);
}
m.nodeWalk(elem,function(elem){
var name=elem.name;
if(m.isNotEmpty(name)){
var _1c5=elem.tagName.toUpperCase();
if(_1c5==="INPUT"&&(elem.type=="radio"||elem.type=="checkbox")&&!elem.checked){
return null;
}
if(_1c5==="SELECT"){
if(elem.type=="select-one"){
if(elem.selectedIndex>=0){
var opt=elem.options[elem.selectedIndex];
var v=opt.value;
if(!v){
var h=opt.outerHTML;
if(h&&!h.match(/^[^>]+\svalue\s*=/i)){
v=opt.text;
}
}
_1bf.push(name);
_1c0.push(v);
return null;
}
_1bf.push(name);
_1c0.push("");
return null;
}else{
var opts=elem.options;
if(!opts.length){
_1bf.push(name);
_1c0.push("");
return null;
}
for(var i=0;i<opts.length;i++){
var opt=opts[i];
if(!opt.selected){
continue;
}
var v=opt.value;
if(!v){
var h=opt.outerHTML;
if(h&&!h.match(/^[^>]+\svalue\s*=/i)){
v=opt.text;
}
}
_1bf.push(name);
_1c0.push(v);
}
return null;
}
}
if(_1c5==="FORM"||_1c5==="P"||_1c5==="SPAN"||_1c5==="DIV"){
return elem.childNodes;
}
_1bf.push(name);
_1c0.push(elem.value||"");
return null;
}
return elem.childNodes;
});
return [_1bf,_1c0];
},withDocument:function(doc,func){
var self=MochiKit.DOM;
var _1ce=self._document;
var rval;
try{
self._document=doc;
rval=func();
}
catch(e){
self._document=_1ce;
throw e;
}
self._document=_1ce;
return rval;
},registerDOMConverter:function(name,_1d1,wrap,_1d3){
MochiKit.DOM.domConverters.register(name,_1d1,wrap,_1d3);
},coerceToDOM:function(node,ctx){
var m=MochiKit.Base;
var im=MochiKit.Iter;
var self=MochiKit.DOM;
if(im){
var iter=im.iter;
var _1da=im.repeat;
var map=m.map;
}
var _1dc=self.domConverters;
var _1dd=arguments.callee;
var _1de=m.NotFound;
while(true){
if(typeof (node)=="undefined"||node===null){
return null;
}
if(typeof (node)=="function"&&typeof (node.length)=="number"&&!(node instanceof Function)){
node=im.list(node);
}
if(typeof (node.nodeType)!="undefined"&&node.nodeType>0){
return node;
}
if(typeof (node)=="number"||typeof (node)=="boolean"){
node=node.toString();
}
if(typeof (node)=="string"){
return self._document.createTextNode(node);
}
if(typeof (node.__dom__)=="function"){
node=node.__dom__(ctx);
continue;
}
if(typeof (node.dom)=="function"){
node=node.dom(ctx);
continue;
}
if(typeof (node)=="function"){
node=node.apply(ctx,[ctx]);
continue;
}
if(im){
var _1df=null;
try{
_1df=iter(node);
}
catch(e){
}
if(_1df){
return map(_1dd,_1df,_1da(ctx));
}
}
try{
node=_1dc.match(node,ctx);
continue;
}
catch(e){
if(e!=_1de){
throw e;
}
}
return self._document.createTextNode(node.toString());
}
return undefined;
},isChildNode:function(node,_1e1){
var self=MochiKit.DOM;
if(typeof (node)=="string"){
node=self.getElement(node);
}
if(typeof (_1e1)=="string"){
_1e1=self.getElement(_1e1);
}
if(typeof (node)=="undefined"||node===null||node===self._document){
return false;
}
do{
if(node===_1e1){
return true;
}
var _1e3=node.tagName;
node=node.parentNode;
if(!_1e3){
break;
}
_1e3=_1e3.toUpperCase();
}while(_1e3!="BODY"&&_1e3!="HTML");
return false;
},setNodeAttribute:function(node,attr,_1e6){
var o={};
o[attr]=_1e6;
try{
return MochiKit.DOM.updateNodeAttributes(node,o);
}
catch(e){
}
return null;
},getNodeAttribute:function(node,attr){
var self=MochiKit.DOM;
var _1eb=self.attributeArray.renames[attr];
node=self.getElement(node);
try{
if(_1eb){
return node[_1eb];
}
return node.getAttribute(attr);
}
catch(e){
}
return null;
},removeNodeAttribute:function(node,attr){
var self=MochiKit.DOM;
var _1ef=self.attributeArray.renames[attr];
node=self.getElement(node);
try{
if(_1ef){
return node[_1ef];
}
return node.removeAttribute(attr);
}
catch(e){
}
return null;
},updateNodeAttributes:function(node,_1f1){
var elem=node;
var self=MochiKit.DOM;
if(typeof (node)=="string"){
elem=self.getElement(node);
}
if(_1f1){
var _1f4=MochiKit.Base.updatetree;
if(self.attributeArray.compliant){
for(var k in _1f1){
var v=_1f1[k];
if(typeof (v)=="object"&&typeof (elem[k])=="object"){
if(k=="style"&&MochiKit.Style){
MochiKit.Style.setStyle(elem,v);
}else{
_1f4(elem[k],v);
}
}else{
if(k.substring(0,2)=="on"){
if(typeof (v)=="string"){
v=new Function(v);
}
elem[k]=v;
}else{
elem.setAttribute(k,v);
}
}
}
}else{
var _1f7=self.attributeArray.renames;
for(var k in _1f1){
v=_1f1[k];
var _1f8=_1f7[k];
if(k=="style"&&typeof (v)=="string"){
elem.style.cssText=v;
}else{
if(typeof (_1f8)=="string"){
elem[_1f8]=v;
}else{
if(typeof (elem[k])=="object"&&typeof (v)=="object"){
if(k=="style"&&MochiKit.Style){
MochiKit.Style.setStyle(elem,v);
}else{
_1f4(elem[k],v);
}
}else{
if(k.substring(0,2)=="on"){
if(typeof (v)=="string"){
v=new Function(v);
}
elem[k]=v;
}else{
elem.setAttribute(k,v);
}
}
}
}
}
}
}
return elem;
},appendChildNodes:function(node){
var elem=node;
var self=MochiKit.DOM;
if(typeof (node)=="string"){
elem=self.getElement(node);
}
var _1fc=[self.coerceToDOM(MochiKit.Base.extend(null,arguments,1),elem)];
var _1fd=MochiKit.Base.concat;
while(_1fc.length){
var n=_1fc.shift();
if(typeof (n)=="undefined"||n===null){
}else{
if(typeof (n.nodeType)=="number"){
elem.appendChild(n);
}else{
_1fc=_1fd(n,_1fc);
}
}
}
return elem;
},insertSiblingNodesBefore:function(node){
var elem=node;
var self=MochiKit.DOM;
if(typeof (node)=="string"){
elem=self.getElement(node);
}
var _202=[self.coerceToDOM(MochiKit.Base.extend(null,arguments,1),elem)];
var _203=elem.parentNode;
var _204=MochiKit.Base.concat;
while(_202.length){
var n=_202.shift();
if(typeof (n)=="undefined"||n===null){
}else{
if(typeof (n.nodeType)=="number"){
_203.insertBefore(n,elem);
}else{
_202=_204(n,_202);
}
}
}
return _203;
},insertSiblingNodesAfter:function(node){
var elem=node;
var self=MochiKit.DOM;
if(typeof (node)=="string"){
elem=self.getElement(node);
}
var _209=[self.coerceToDOM(MochiKit.Base.extend(null,arguments,1),elem)];
if(elem.nextSibling){
return self.insertSiblingNodesBefore(elem.nextSibling,_209);
}else{
return self.appendChildNodes(elem.parentNode,_209);
}
},replaceChildNodes:function(node){
var elem=node;
var self=MochiKit.DOM;
if(typeof (node)=="string"){
elem=self.getElement(node);
arguments[0]=elem;
}
var _20d;
while((_20d=elem.firstChild)){
elem.removeChild(_20d);
}
if(arguments.length<2){
return elem;
}else{
return self.appendChildNodes.apply(this,arguments);
}
},createDOM:function(name,_20f){
var elem;
var self=MochiKit.DOM;
var m=MochiKit.Base;
if(typeof (_20f)=="string"||typeof (_20f)=="number"){
var args=m.extend([name,null],arguments,1);
return arguments.callee.apply(this,args);
}
if(typeof (name)=="string"){
var _214=self._xhtml;
if(_20f&&!self.attributeArray.compliant){
var _215="";
if("name" in _20f){
_215+=" name=\""+self.escapeHTML(_20f.name)+"\"";
}
if(name=="input"&&"type" in _20f){
_215+=" type=\""+self.escapeHTML(_20f.type)+"\"";
}
if(_215){
name="<"+name+_215+">";
_214=false;
}
}
var d=self._document;
if(_214&&d===document){
elem=d.createElementNS("http://www.w3.org/1999/xhtml",name);
}else{
elem=d.createElement(name);
}
}else{
elem=name;
}
if(_20f){
self.updateNodeAttributes(elem,_20f);
}
if(arguments.length<=2){
return elem;
}else{
var args=m.extend([elem],arguments,2);
return self.appendChildNodes.apply(this,args);
}
},createDOMFunc:function(){
var m=MochiKit.Base;
return m.partial.apply(this,m.extend([MochiKit.DOM.createDOM],arguments));
},removeElement:function(elem){
var e=MochiKit.DOM.getElement(elem);
e.parentNode.removeChild(e);
return e;
},swapDOM:function(dest,src){
var self=MochiKit.DOM;
dest=self.getElement(dest);
var _21d=dest.parentNode;
if(src){
src=self.getElement(src);
_21d.replaceChild(src,dest);
}else{
_21d.removeChild(dest);
}
return src;
},getElement:function(id){
var self=MochiKit.DOM;
if(arguments.length==1){
return ((typeof (id)=="string")?self._document.getElementById(id):id);
}else{
return MochiKit.Base.map(self.getElement,arguments);
}
},getElementsByTagAndClassName:function(_220,_221,_222){
var self=MochiKit.DOM;
if(typeof (_220)=="undefined"||_220===null){
_220="*";
}
if(typeof (_222)=="undefined"||_222===null){
_222=self._document;
}
_222=self.getElement(_222);
var _224=(_222.getElementsByTagName(_220)||self._document.all);
if(typeof (_221)=="undefined"||_221===null){
return MochiKit.Base.extend(null,_224);
}
var _225=[];
for(var i=0;i<_224.length;i++){
var _227=_224[i];
var cls=_227.className;
if(!cls){
continue;
}
var _229=cls.split(" ");
for(var j=0;j<_229.length;j++){
if(_229[j]==_221){
_225.push(_227);
break;
}
}
}
return _225;
},_newCallStack:function(path,once){
var rval=function(){
var _22e=arguments.callee.callStack;
for(var i=0;i<_22e.length;i++){
if(_22e[i].apply(this,arguments)===false){
break;
}
}
if(once){
try{
this[path]=null;
}
catch(e){
}
}
};
rval.callStack=[];
return rval;
},addToCallStack:function(_230,path,func,once){
var self=MochiKit.DOM;
var _235=_230[path];
var _236=_235;
if(!(typeof (_235)=="function"&&typeof (_235.callStack)=="object"&&_235.callStack!==null)){
_236=self._newCallStack(path,once);
if(typeof (_235)=="function"){
_236.callStack.push(_235);
}
_230[path]=_236;
}
_236.callStack.push(func);
},addLoadEvent:function(func){
var self=MochiKit.DOM;
self.addToCallStack(self._window,"onload",func,true);
},focusOnLoad:function(_239){
var self=MochiKit.DOM;
self.addLoadEvent(function(){
_239=self.getElement(_239);
if(_239){
_239.focus();
}
});
},setElementClass:function(_23b,_23c){
var self=MochiKit.DOM;
var obj=self.getElement(_23b);
if(self.attributeArray.compliant){
obj.setAttribute("class",_23c);
}else{
obj.setAttribute("className",_23c);
}
},toggleElementClass:function(_23f){
var self=MochiKit.DOM;
for(var i=1;i<arguments.length;i++){
var obj=self.getElement(arguments[i]);
if(!self.addElementClass(obj,_23f)){
self.removeElementClass(obj,_23f);
}
}
},addElementClass:function(_243,_244){
var self=MochiKit.DOM;
var obj=self.getElement(_243);
var cls=obj.className;
if(cls==undefined||cls.length===0){
self.setElementClass(obj,_244);
return true;
}
if(cls==_244){
return false;
}
var _248=cls.split(" ");
for(var i=0;i<_248.length;i++){
if(_248[i]==_244){
return false;
}
}
self.setElementClass(obj,cls+" "+_244);
return true;
},removeElementClass:function(_24a,_24b){
var self=MochiKit.DOM;
var obj=self.getElement(_24a);
var cls=obj.className;
if(cls==undefined||cls.length===0){
return false;
}
if(cls==_24b){
self.setElementClass(obj,"");
return true;
}
var _24f=cls.split(" ");
for(var i=0;i<_24f.length;i++){
if(_24f[i]==_24b){
_24f.splice(i,1);
self.setElementClass(obj,_24f.join(" "));
return true;
}
}
return false;
},swapElementClass:function(_251,_252,_253){
var obj=MochiKit.DOM.getElement(_251);
var res=MochiKit.DOM.removeElementClass(obj,_252);
if(res){
MochiKit.DOM.addElementClass(obj,_253);
}
return res;
},hasElementClass:function(_256,_257){
var obj=MochiKit.DOM.getElement(_256);
var cls=obj.className;
if(!cls){
return false;
}
var _25a=cls.split(" ");
for(var i=1;i<arguments.length;i++){
var good=false;
for(var j=0;j<_25a.length;j++){
if(_25a[j]==arguments[i]){
good=true;
break;
}
}
if(!good){
return false;
}
}
return true;
},escapeHTML:function(s){
return s.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
},toHTML:function(dom){
return MochiKit.DOM.emitHTML(dom).join("");
},emitHTML:function(dom,lst){
if(typeof (lst)=="undefined"||lst===null){
lst=[];
}
var _262=[dom];
var self=MochiKit.DOM;
var _264=self.escapeHTML;
var _265=self.attributeArray;
while(_262.length){
dom=_262.pop();
if(typeof (dom)=="string"){
lst.push(dom);
}else{
if(dom.nodeType==1){
lst.push("<"+dom.tagName.toLowerCase());
var _266=[];
var _267=_265(dom);
for(var i=0;i<_267.length;i++){
var a=_267[i];
_266.push([" ",a.name,"=\"",_264(a.value),"\""]);
}
_266.sort();
for(i=0;i<_266.length;i++){
var _26a=_266[i];
for(var j=0;j<_26a.length;j++){
lst.push(_26a[j]);
}
}
if(dom.hasChildNodes()){
lst.push(">");
_262.push("</"+dom.tagName.toLowerCase()+">");
var _26c=dom.childNodes;
for(i=_26c.length-1;i>=0;i--){
_262.push(_26c[i]);
}
}else{
lst.push("/>");
}
}else{
if(dom.nodeType==3){
lst.push(_264(dom.nodeValue));
}
}
}
}
return lst;
},scrapeText:function(node,_26e){
var rval=[];
(function(node){
var cn=node.childNodes;
if(cn){
for(var i=0;i<cn.length;i++){
arguments.callee.call(this,cn[i]);
}
}
var _273=node.nodeValue;
if(typeof (_273)=="string"){
rval.push(_273);
}
})(MochiKit.DOM.getElement(node));
if(_26e){
return rval;
}else{
return rval.join("");
}
},removeEmptyTextNodes:function(_274){
_274=MochiKit.DOM.getElement(_274);
for(var i=0;i<_274.childNodes.length;i++){
var node=_274.childNodes[i];
if(node.nodeType==3&&!/\S/.test(node.nodeValue)){
node.parentNode.removeChild(node);
}
}
},makeClipping:function(_277){
_277=MochiKit.DOM.getElement(_277);
var _278=_277.style.overflow;
if((MochiKit.Style.getStyle(_277,"overflow")||"visible")!="hidden"){
_277.style.overflow="hidden";
}
return _278;
},undoClipping:function(_279,_27a){
_279=MochiKit.DOM.getElement(_279);
if(!_27a){
return;
}
_279.style.overflow=_27a;
},makePositioned:function(_27b){
_27b=MochiKit.DOM.getElement(_27b);
var pos=MochiKit.Style.getStyle(_27b,"position");
if(pos=="static"||!pos){
_27b.style.position="relative";
if(/Opera/.test(navigator.userAgent)){
_27b.style.top=0;
_27b.style.left=0;
}
}
},undoPositioned:function(_27d){
_27d=MochiKit.DOM.getElement(_27d);
if(_27d.style.position=="relative"){
_27d.style.position=_27d.style.top=_27d.style.left=_27d.style.bottom=_27d.style.right="";
}
},getFirstElementByTagAndClassName:function(_27e,_27f,_280){
var self=MochiKit.DOM;
if(typeof (_27e)=="undefined"||_27e===null){
_27e="*";
}
if(typeof (_280)=="undefined"||_280===null){
_280=self._document;
}
_280=self.getElement(_280);
var _282=(_280.getElementsByTagName(_27e)||self._document.all);
if(typeof (_27f)=="undefined"||_27f===null){
return _282[0];
}
for(var i=0;i<_282.length;i++){
var _284=_282[i];
var _285=_284.className.split(" ");
for(var j=0;j<_285.length;j++){
if(_285[j]==_27f){
return _284;
}
}
}
},getFirstParentByTagAndClassName:function(elem,_288,_289){
var self=MochiKit.DOM;
elem=self.getElement(elem);
if(typeof (_288)=="undefined"||_288===null){
_288="*";
}else{
_288=_288.toUpperCase();
}
if(typeof (_289)=="undefined"||_289===null){
_289=null;
}
var _28b="";
var _28c="";
while(elem&&elem.tagName){
elem=elem.parentNode;
if(_288=="*"&&_289===null){
return elem;
}
_28b=elem.className.split(" ");
_28c=elem.tagName.toUpperCase();
if(_289===null&&_288==_28c){
return elem;
}else{
if(_289!==null){
for(var i=0;i<_28b.length;i++){
if(_288=="*"&&_28b[i]==_289){
return elem;
}else{
if(_288==_28c&&_28b[i]==_289){
return elem;
}
}
}
}
}
}
return elem;
},isParent:function(_28e,_28f){
if(!_28e.parentNode||_28e==_28f){
return false;
}
if(_28e.parentNode==_28f){
return true;
}
return MochiKit.DOM.isParent(_28e.parentNode,_28f);
},__new__:function(win){
var m=MochiKit.Base;
if(typeof (document)!="undefined"){
this._document=document;
var _292="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
this._xhtml=(document.documentElement&&document.createElementNS&&document.documentElement.namespaceURI===_292);
}else{
if(MochiKit.MockDOM){
this._document=MochiKit.MockDOM.document;
}
}
this._window=win;
this.domConverters=new m.AdapterRegistry();
var _293=this._document.createElement("span");
var _294;
if(_293&&_293.attributes&&_293.attributes.length>0){
var _295=m.filter;
_294=function(node){
return _295(_294.ignoreAttrFilter,node.attributes);
};
_294.ignoreAttr={};
var _297=_293.attributes;
var _298=_294.ignoreAttr;
for(var i=0;i<_297.length;i++){
var a=_297[i];
_298[a.name]=a.value;
}
_294.ignoreAttrFilter=function(a){
return (_294.ignoreAttr[a.name]!=a.value);
};
_294.compliant=false;
_294.renames={"class":"className","checked":"defaultChecked","usemap":"useMap","for":"htmlFor","readonly":"readOnly","colspan":"colSpan","bgcolor":"bgColor","cellspacing":"cellSpacing","cellpadding":"cellPadding"};
}else{
_294=function(node){
return node.attributes;
};
_294.compliant=true;
_294.renames={};
}
this.attributeArray=_294;
var _29d=function(_29e,arr){
var _2a0=arr[1].split(".");
var str="";
var obj={};
str+="if (!MochiKit."+_2a0[1]+") { throw new Error(\"";
str+="This function has been deprecated and depends on MochiKit.";
str+=_2a0[1]+".\");}";
str+="return MochiKit."+_2a0[1]+"."+arr[0];
str+=".apply(this, arguments);";
obj[_2a0[2]]=new Function(str);
MochiKit.Base.update(MochiKit[_29e],obj);
};
for(var i;i<MochiKit.DOM.DEPRECATED.length;i++){
_29d("DOM",MochiKit.DOM.DEPRECATED[i]);
}
var _2a3=this.createDOMFunc;
this.UL=_2a3("ul");
this.OL=_2a3("ol");
this.LI=_2a3("li");
this.DL=_2a3("dl");
this.DT=_2a3("dt");
this.DD=_2a3("dd");
this.TD=_2a3("td");
this.TR=_2a3("tr");
this.TBODY=_2a3("tbody");
this.THEAD=_2a3("thead");
this.TFOOT=_2a3("tfoot");
this.TABLE=_2a3("table");
this.TH=_2a3("th");
this.INPUT=_2a3("input");
this.SPAN=_2a3("span");
this.A=_2a3("a");
this.DIV=_2a3("div");
this.IMG=_2a3("img");
this.BUTTON=_2a3("button");
this.TT=_2a3("tt");
this.PRE=_2a3("pre");
this.H1=_2a3("h1");
this.H2=_2a3("h2");
this.H3=_2a3("h3");
this.BR=_2a3("br");
this.HR=_2a3("hr");
this.LABEL=_2a3("label");
this.TEXTAREA=_2a3("textarea");
this.FORM=_2a3("form");
this.P=_2a3("p");
this.SELECT=_2a3("select");
this.OPTION=_2a3("option");
this.OPTGROUP=_2a3("optgroup");
this.LEGEND=_2a3("legend");
this.FIELDSET=_2a3("fieldset");
this.STRONG=_2a3("strong");
this.CANVAS=_2a3("canvas");
this.$=this.getElement;
this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
m.nameFunctions(this);
}});
MochiKit.DOM.__new__(((typeof (window)=="undefined")?this:window));
if(MochiKit.__export__){
withWindow=MochiKit.DOM.withWindow;
withDocument=MochiKit.DOM.withDocument;
}
MochiKit.Base._exportSymbols(this,MochiKit.DOM);
MochiKit.Base._deps("Style",["Base","DOM"]);
MochiKit.Style.NAME="MochiKit.Style";
MochiKit.Style.VERSION="1.4";
MochiKit.Style.__repr__=function(){
return "["+this.NAME+" "+this.VERSION+"]";
};
MochiKit.Style.toString=function(){
return this.__repr__();
};
MochiKit.Style.EXPORT_OK=[];
MochiKit.Style.EXPORT=["setStyle","setOpacity","getStyle","getElementDimensions","elementDimensions","setElementDimensions","getElementPosition","elementPosition","setElementPosition","setDisplayForElement","hideElement","showElement","getViewportDimensions","getViewportPosition","Dimensions","Coordinates"];
MochiKit.Style.Dimensions=function(w,h){
this.w=w;
this.h=h;
};
MochiKit.Style.Dimensions.prototype.__repr__=function(){
var repr=MochiKit.Base.repr;
return "{w: "+repr(this.w)+", h: "+repr(this.h)+"}";
};
MochiKit.Style.Dimensions.prototype.toString=function(){
return this.__repr__();
};
MochiKit.Style.Coordinates=function(x,y){
this.x=x;
this.y=y;
};
MochiKit.Style.Coordinates.prototype.__repr__=function(){
var repr=MochiKit.Base.repr;
return "{x: "+repr(this.x)+", y: "+repr(this.y)+"}";
};
MochiKit.Style.Coordinates.prototype.toString=function(){
return this.__repr__();
};
MochiKit.Base.update(MochiKit.Style,{getStyle:function(elem,_2ab){
var dom=MochiKit.DOM;
var d=dom._document;
elem=dom.getElement(elem);
_2ab=MochiKit.Base.camelize(_2ab);
if(!elem||elem==d){
return undefined;
}
if(_2ab=="opacity"&&elem.filters){
var _2ae=(MochiKit.Style.getStyle(elem,"filter")||"").match(/alpha\(opacity=(.*)\)/);
if(_2ae&&_2ae[1]){
return parseFloat(_2ae[1])/100;
}
return 1;
}
var _2af=elem.style?elem.style[_2ab]:null;
if(!_2af){
if(d.defaultView&&d.defaultView.getComputedStyle){
var css=d.defaultView.getComputedStyle(elem,null);
_2ab=_2ab.replace(/([A-Z])/g,"-$1").toLowerCase();
_2af=css?css.getPropertyValue(_2ab):null;
}else{
if(elem.currentStyle){
_2af=elem.currentStyle[_2ab];
}
}
}
if(_2ab=="opacity"){
_2af=parseFloat(_2af);
}
if(/Opera/.test(navigator.userAgent)&&(MochiKit.Base.find(["left","top","right","bottom"],_2ab)!=-1)){
if(MochiKit.Style.getStyle(elem,"position")=="static"){
_2af="auto";
}
}
return _2af=="auto"?null:_2af;
},setStyle:function(elem,_2b2){
elem=MochiKit.DOM.getElement(elem);
for(var name in _2b2){
if(name=="opacity"){
MochiKit.Style.setOpacity(elem,_2b2[name]);
}else{
elem.style[MochiKit.Base.camelize(name)]=_2b2[name];
}
}
},setOpacity:function(elem,o){
elem=MochiKit.DOM.getElement(elem);
var self=MochiKit.Style;
if(o==1){
var _2b7=/Gecko/.test(navigator.userAgent)&&!(/Konqueror|AppleWebKit|KHTML/.test(navigator.userAgent));
elem.style["opacity"]=_2b7?0.999999:1;
if(/MSIE/.test(navigator.userAgent)){
elem.style["filter"]=self.getStyle(elem,"filter").replace(/alpha\([^\)]*\)/gi,"");
}
}else{
if(o<0.00001){
o=0;
}
elem.style["opacity"]=o;
if(/MSIE/.test(navigator.userAgent)){
elem.style["filter"]=self.getStyle(elem,"filter").replace(/alpha\([^\)]*\)/gi,"")+"alpha(opacity="+o*100+")";
}
}
},getElementPosition:function(elem,_2b9){
var self=MochiKit.Style;
var dom=MochiKit.DOM;
elem=dom.getElement(elem);
if(!elem||(!(elem.x&&elem.y)&&(!elem.parentNode===null||self.getStyle(elem,"display")=="none"))){
return undefined;
}
var c=new self.Coordinates(0,0);
var box=null;
var _2be=null;
var d=MochiKit.DOM._document;
var de=d.documentElement;
var b=d.body;
if(!elem.parentNode&&elem.x&&elem.y){
c.x+=elem.x||0;
c.y+=elem.y||0;
}else{
if(elem.getBoundingClientRect){
box=elem.getBoundingClientRect();
c.x+=box.left+(de.scrollLeft||b.scrollLeft)-(de.clientLeft||0);
c.y+=box.top+(de.scrollTop||b.scrollTop)-(de.clientTop||0);
return c;
}else{
if(elem.offsetParent){
c.x+=elem.offsetLeft;
c.y+=elem.offsetTop;
_2be=elem.offsetParent;
if(_2be!=elem){
while(_2be){
c.x+=_2be.offsetLeft;
c.y+=_2be.offsetTop;
_2be=_2be.offsetParent;
}
}
var ua=navigator.userAgent.toLowerCase();
if((typeof (opera)!="undefined"&&parseFloat(opera.version())<9)||(ua.indexOf("AppleWebKit")!=-1&&self.getStyle(elem,"position")=="absolute")){
c.x-=b.offsetLeft;
c.y-=b.offsetTop;
}
}
}
}
if(typeof (_2b9)!="undefined"){
_2b9=arguments.callee(_2b9);
if(_2b9){
c.x-=(_2b9.x||0);
c.y-=(_2b9.y||0);
}
}
if(elem.parentNode){
_2be=elem.parentNode;
}else{
_2be=null;
}
while(_2be){
var _2c3=_2be.tagName.toUpperCase();
if(_2c3==="BODY"||_2c3==="HTML"){
break;
}
var disp=self.getStyle(_2be,"display");
if(disp.search(/^inline|table-row.*$/i)){
c.x-=_2be.scrollLeft;
c.y-=_2be.scrollTop;
}
if(_2be.parentNode){
_2be=_2be.parentNode;
}else{
_2be=null;
}
}
return c;
},setElementPosition:function(elem,_2c6,_2c7){
elem=MochiKit.DOM.getElement(elem);
if(typeof (_2c7)=="undefined"){
_2c7="px";
}
var _2c8={};
var _2c9=MochiKit.Base.isUndefinedOrNull;
if(!_2c9(_2c6.x)){
_2c8["left"]=_2c6.x+_2c7;
}
if(!_2c9(_2c6.y)){
_2c8["top"]=_2c6.y+_2c7;
}
MochiKit.DOM.updateNodeAttributes(elem,{"style":_2c8});
},getElementDimensions:function(elem){
var self=MochiKit.Style;
var dom=MochiKit.DOM;
if(typeof (elem.w)=="number"||typeof (elem.h)=="number"){
return new self.Dimensions(elem.w||0,elem.h||0);
}
elem=dom.getElement(elem);
if(!elem){
return undefined;
}
var disp=self.getStyle(elem,"display");
if(disp!="none"&&disp!==""&&typeof (disp)!="undefined"){
return new self.Dimensions(elem.offsetWidth||0,elem.offsetHeight||0);
}
var s=elem.style;
var _2cf=s.visibility;
var _2d0=s.position;
s.visibility="hidden";
s.position="absolute";
s.display="";
var _2d1=elem.offsetWidth;
var _2d2=elem.offsetHeight;
s.display="none";
s.position=_2d0;
s.visibility=_2cf;
return new self.Dimensions(_2d1,_2d2);
},setElementDimensions:function(elem,_2d4,_2d5){
elem=MochiKit.DOM.getElement(elem);
if(typeof (_2d5)=="undefined"){
_2d5="px";
}
var _2d6={};
var _2d7=MochiKit.Base.isUndefinedOrNull;
if(!_2d7(_2d4.w)){
_2d6["width"]=_2d4.w+_2d5;
}
if(!_2d7(_2d4.h)){
_2d6["height"]=_2d4.h+_2d5;
}
MochiKit.DOM.updateNodeAttributes(elem,{"style":_2d6});
},setDisplayForElement:function(_2d8,_2d9){
var _2da=MochiKit.Base.extend(null,arguments,1);
var _2db=MochiKit.DOM.getElement;
for(var i=0;i<_2da.length;i++){
_2d9=_2db(_2da[i]);
if(_2d9){
_2d9.style.display=_2d8;
}
}
},getViewportDimensions:function(){
var d=new MochiKit.Style.Dimensions();
var w=MochiKit.DOM._window;
var b=MochiKit.DOM._document.body;
if(w.innerWidth){
d.w=w.innerWidth;
d.h=w.innerHeight;
}else{
if(b.parentElement.clientWidth){
d.w=b.parentElement.clientWidth;
d.h=b.parentElement.clientHeight;
}else{
if(b&&b.clientWidth){
d.w=b.clientWidth;
d.h=b.clientHeight;
}
}
}
return d;
},getViewportPosition:function(){
var c=new MochiKit.Style.Coordinates(0,0);
var d=MochiKit.DOM._document;
var de=d.documentElement;
var db=d.body;
if(de&&(de.scrollTop||de.scrollLeft)){
c.x=de.scrollLeft;
c.y=de.scrollTop;
}else{
if(db){
c.x=db.scrollLeft;
c.y=db.scrollTop;
}
}
return c;
},__new__:function(){
var m=MochiKit.Base;
this.elementPosition=this.getElementPosition;
this.elementDimensions=this.getElementDimensions;
this.hideElement=m.partial(this.setDisplayForElement,"none");
this.showElement=m.partial(this.setDisplayForElement,"block");
this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
m.nameFunctions(this);
}});
MochiKit.Style.__new__();
MochiKit.Base._exportSymbols(this,MochiKit.Style);
MochiKit.Base._deps("Signal",["Base","DOM","Style"]);
MochiKit.Signal.NAME="MochiKit.Signal";
MochiKit.Signal.VERSION="1.4";
MochiKit.Signal._observers=[];
MochiKit.Signal.Event=function(src,e){
this._event=e||window.event;
this._src=src;
};
MochiKit.Base.update(MochiKit.Signal.Event.prototype,{__repr__:function(){
var repr=MochiKit.Base.repr;
var str="{event(): "+repr(this.event())+", src(): "+repr(this.src())+", type(): "+repr(this.type())+", target(): "+repr(this.target());
if(this.type()&&this.type().indexOf("key")===0||this.type().indexOf("mouse")===0||this.type().indexOf("click")!=-1||this.type()=="contextmenu"){
str+=", modifier(): "+"{alt: "+repr(this.modifier().alt)+", ctrl: "+repr(this.modifier().ctrl)+", meta: "+repr(this.modifier().meta)+", shift: "+repr(this.modifier().shift)+", any: "+repr(this.modifier().any)+"}";
}
if(this.type()&&this.type().indexOf("key")===0){
str+=", key(): {code: "+repr(this.key().code)+", string: "+repr(this.key().string)+"}";
}
if(this.type()&&(this.type().indexOf("mouse")===0||this.type().indexOf("click")!=-1||this.type()=="contextmenu")){
str+=", mouse(): {page: "+repr(this.mouse().page)+", client: "+repr(this.mouse().client);
if(this.type()!="mousemove"){
str+=", button: {left: "+repr(this.mouse().button.left)+", middle: "+repr(this.mouse().button.middle)+", right: "+repr(this.mouse().button.right)+"}}";
}else{
str+="}";
}
}
if(this.type()=="mouseover"||this.type()=="mouseout"||this.type()=="mouseenter"||this.type()=="mouseleave"){
str+=", relatedTarget(): "+repr(this.relatedTarget());
}
str+="}";
return str;
},toString:function(){
return this.__repr__();
},src:function(){
return this._src;
},event:function(){
return this._event;
},type:function(){
return this._event.type||undefined;
},target:function(){
return this._event.target||this._event.srcElement;
},_relatedTarget:null,relatedTarget:function(){
if(this._relatedTarget!==null){
return this._relatedTarget;
}
var elem=null;
if(this.type()=="mouseover"||this.type()=="mouseenter"){
elem=(this._event.relatedTarget||this._event.fromElement);
}else{
if(this.type()=="mouseout"||this.type()=="mouseleave"){
elem=(this._event.relatedTarget||this._event.toElement);
}
}
if(elem!==null){
this._relatedTarget=elem;
return elem;
}
return undefined;
},_modifier:null,modifier:function(){
if(this._modifier!==null){
return this._modifier;
}
var m={};
m.alt=this._event.altKey;
m.ctrl=this._event.ctrlKey;
m.meta=this._event.metaKey||false;
m.shift=this._event.shiftKey;
m.any=m.alt||m.ctrl||m.shift||m.meta;
this._modifier=m;
return m;
},_key:null,key:function(){
if(this._key!==null){
return this._key;
}
var k={};
if(this.type()&&this.type().indexOf("key")===0){
if(this.type()=="keydown"||this.type()=="keyup"){
k.code=this._event.keyCode;
k.string=(MochiKit.Signal._specialKeys[k.code]||"KEY_UNKNOWN");
this._key=k;
return k;
}else{
if(this.type()=="keypress"){
k.code=0;
k.string="";
if(typeof (this._event.charCode)!="undefined"&&this._event.charCode!==0&&!MochiKit.Signal._specialMacKeys[this._event.charCode]){
k.code=this._event.charCode;
k.string=String.fromCharCode(k.code);
}else{
if(this._event.keyCode&&typeof (this._event.charCode)=="undefined"){
k.code=this._event.keyCode;
k.string=String.fromCharCode(k.code);
}
}
this._key=k;
return k;
}
}
}
return undefined;
},_mouse:null,mouse:function(){
if(this._mouse!==null){
return this._mouse;
}
var m={};
var e=this._event;
if(this.type()&&(this.type().indexOf("mouse")===0||this.type().indexOf("click")!=-1||this.type()=="contextmenu")){
m.client=new MochiKit.Style.Coordinates(0,0);
if(e.clientX||e.clientY){
m.client.x=(!e.clientX||e.clientX<0)?0:e.clientX;
m.client.y=(!e.clientY||e.clientY<0)?0:e.clientY;
}
m.page=new MochiKit.Style.Coordinates(0,0);
if(e.pageX||e.pageY){
m.page.x=(!e.pageX||e.pageX<0)?0:e.pageX;
m.page.y=(!e.pageY||e.pageY<0)?0:e.pageY;
}else{
var de=MochiKit.DOM._document.documentElement;
var b=MochiKit.DOM._document.body;
m.page.x=e.clientX+(de.scrollLeft||b.scrollLeft)-(de.clientLeft||0);
m.page.y=e.clientY+(de.scrollTop||b.scrollTop)-(de.clientTop||0);
}
if(this.type()!="mousemove"){
m.button={};
m.button.left=false;
m.button.right=false;
m.button.middle=false;
if(e.which){
m.button.left=(e.which==1);
m.button.middle=(e.which==2);
m.button.right=(e.which==3);
}else{
m.button.left=!!(e.button&1);
m.button.right=!!(e.button&2);
m.button.middle=!!(e.button&4);
}
}
this._mouse=m;
return m;
}
return undefined;
},stop:function(){
this.stopPropagation();
this.preventDefault();
},stopPropagation:function(){
if(this._event.stopPropagation){
this._event.stopPropagation();
}else{
this._event.cancelBubble=true;
}
},preventDefault:function(){
if(this._event.preventDefault){
this._event.preventDefault();
}else{
if(this._confirmUnload===null){
this._event.returnValue=false;
}
}
},_confirmUnload:null,confirmUnload:function(msg){
if(this.type()=="beforeunload"){
this._confirmUnload=msg;
this._event.returnValue=msg;
}
}});
MochiKit.Signal._specialMacKeys={3:"KEY_ENTER",63289:"KEY_NUM_PAD_CLEAR",63276:"KEY_PAGE_UP",63277:"KEY_PAGE_DOWN",63275:"KEY_END",63273:"KEY_HOME",63234:"KEY_ARROW_LEFT",63232:"KEY_ARROW_UP",63235:"KEY_ARROW_RIGHT",63233:"KEY_ARROW_DOWN",63302:"KEY_INSERT",63272:"KEY_DELETE"};
(function(){
var _2f1=MochiKit.Signal._specialMacKeys;
for(i=63236;i<=63242;i++){
_2f1[i]="KEY_F"+(i-63236+1);
}
})();
MochiKit.Signal._specialKeys={8:"KEY_BACKSPACE",9:"KEY_TAB",12:"KEY_NUM_PAD_CLEAR",13:"KEY_ENTER",16:"KEY_SHIFT",17:"KEY_CTRL",18:"KEY_ALT",19:"KEY_PAUSE",20:"KEY_CAPS_LOCK",27:"KEY_ESCAPE",32:"KEY_SPACEBAR",33:"KEY_PAGE_UP",34:"KEY_PAGE_DOWN",35:"KEY_END",36:"KEY_HOME",37:"KEY_ARROW_LEFT",38:"KEY_ARROW_UP",39:"KEY_ARROW_RIGHT",40:"KEY_ARROW_DOWN",44:"KEY_PRINT_SCREEN",45:"KEY_INSERT",46:"KEY_DELETE",59:"KEY_SEMICOLON",91:"KEY_WINDOWS_LEFT",92:"KEY_WINDOWS_RIGHT",93:"KEY_SELECT",106:"KEY_NUM_PAD_ASTERISK",107:"KEY_NUM_PAD_PLUS_SIGN",109:"KEY_NUM_PAD_HYPHEN-MINUS",110:"KEY_NUM_PAD_FULL_STOP",111:"KEY_NUM_PAD_SOLIDUS",144:"KEY_NUM_LOCK",145:"KEY_SCROLL_LOCK",186:"KEY_SEMICOLON",187:"KEY_EQUALS_SIGN",188:"KEY_COMMA",189:"KEY_HYPHEN-MINUS",190:"KEY_FULL_STOP",191:"KEY_SOLIDUS",192:"KEY_GRAVE_ACCENT",219:"KEY_LEFT_SQUARE_BRACKET",220:"KEY_REVERSE_SOLIDUS",221:"KEY_RIGHT_SQUARE_BRACKET",222:"KEY_APOSTROPHE"};
(function(){
var _2f2=MochiKit.Signal._specialKeys;
for(var i=48;i<=57;i++){
_2f2[i]="KEY_"+(i-48);
}
for(i=65;i<=90;i++){
_2f2[i]="KEY_"+String.fromCharCode(i);
}
for(i=96;i<=105;i++){
_2f2[i]="KEY_NUM_PAD_"+(i-96);
}
for(i=112;i<=123;i++){
_2f2[i]="KEY_F"+(i-112+1);
}
})();
MochiKit.Signal.Ident=function(_2f4){
this.source=_2f4.source;
this.signal=_2f4.signal;
this.listener=_2f4.listener;
this.isDOM=_2f4.isDOM;
this.objOrFunc=_2f4.objOrFunc;
this.funcOrStr=_2f4.funcOrStr;
this.connected=_2f4.connected;
};
MochiKit.Signal.Ident.prototype={};
MochiKit.Base.update(MochiKit.Signal,{__repr__:function(){
return "["+this.NAME+" "+this.VERSION+"]";
},toString:function(){
return this.__repr__();
},_unloadCache:function(){
var self=MochiKit.Signal;
var _2f6=self._observers;
for(var i=0;i<_2f6.length;i++){
if(_2f6[i].signal!=="onload"&&_2f6[i].signal!=="onunload"){
self._disconnect(_2f6[i]);
}
}
},_listener:function(src,sig,func,obj,_2fc){
var self=MochiKit.Signal;
var E=self.Event;
if(!_2fc){
if(typeof (func.im_self)=="undefined"){
return MochiKit.Base.bind(func,obj);
}else{
return func;
}
}
obj=obj||src;
if(typeof (func)=="string"){
if(sig==="onload"||sig==="onunload"){
return function(_2ff){
obj[func].apply(obj,[new E(src,_2ff)]);
var _300=new MochiKit.Signal.Ident({source:src,signal:sig,objOrFunc:obj,funcOrStr:func});
MochiKit.Signal._disconnect(_300);
};
}else{
return function(_301){
obj[func].apply(obj,[new E(src,_301)]);
};
}
}else{
if(sig==="onload"||sig==="onunload"){
return function(_302){
func.apply(obj,[new E(src,_302)]);
var _303=new MochiKit.Signal.Ident({source:src,signal:sig,objOrFunc:func});
MochiKit.Signal._disconnect(_303);
};
}else{
return function(_304){
func.apply(obj,[new E(src,_304)]);
};
}
}
},_browserAlreadyHasMouseEnterAndLeave:function(){
return /MSIE/.test(navigator.userAgent);
},_mouseEnterListener:function(src,sig,func,obj){
var E=MochiKit.Signal.Event;
return function(_30a){
var e=new E(src,_30a);
try{
e.relatedTarget().nodeName;
}
catch(err){
return;
}
e.stop();
if(MochiKit.DOM.isChildNode(e.relatedTarget(),src)){
return;
}
e.type=function(){
return sig;
};
if(typeof (func)=="string"){
return obj[func].apply(obj,[e]);
}else{
return func.apply(obj,[e]);
}
};
},_getDestPair:function(_30c,_30d){
var obj=null;
var func=null;
if(typeof (_30d)!="undefined"){
obj=_30c;
func=_30d;
if(typeof (_30d)=="string"){
if(typeof (_30c[_30d])!="function"){
throw new Error("'funcOrStr' must be a function on 'objOrFunc'");
}
}else{
if(typeof (_30d)!="function"){
throw new Error("'funcOrStr' must be a function or string");
}
}
}else{
if(typeof (_30c)!="function"){
throw new Error("'objOrFunc' must be a function if 'funcOrStr' is not given");
}else{
func=_30c;
}
}
return [obj,func];
},connect:function(src,sig,_312,_313){
src=MochiKit.DOM.getElement(src);
var self=MochiKit.Signal;
if(typeof (sig)!="string"){
throw new Error("'sig' must be a string");
}
var _315=self._getDestPair(_312,_313);
var obj=_315[0];
var func=_315[1];
if(typeof (obj)=="undefined"||obj===null){
obj=src;
}
var _318=!!(src.addEventListener||src.attachEvent);
if(_318&&(sig==="onmouseenter"||sig==="onmouseleave")&&!self._browserAlreadyHasMouseEnterAndLeave()){
var _319=self._mouseEnterListener(src,sig.substr(2),func,obj);
if(sig==="onmouseenter"){
sig="onmouseover";
}else{
sig="onmouseout";
}
}else{
var _319=self._listener(src,sig,func,obj,_318);
}
if(src.addEventListener){
src.addEventListener(sig.substr(2),_319,false);
}else{
if(src.attachEvent){
src.attachEvent(sig,_319);
}
}
var _31a=new MochiKit.Signal.Ident({source:src,signal:sig,listener:_319,isDOM:_318,objOrFunc:_312,funcOrStr:_313,connected:true});
self._observers.push(_31a);
if(!_318&&typeof (src.__connect__)=="function"){
var args=MochiKit.Base.extend([_31a],arguments,1);
src.__connect__.apply(src,args);
}
return _31a;
},_disconnect:function(_31c){
if(!_31c.connected){
return;
}
_31c.connected=false;
if(!_31c.isDOM){
return;
}
var src=_31c.source;
var sig=_31c.signal;
var _31f=_31c.listener;
if(src.removeEventListener){
src.removeEventListener(sig.substr(2),_31f,false);
}else{
if(src.detachEvent){
src.detachEvent(sig,_31f);
}else{
throw new Error("'src' must be a DOM element");
}
}
},disconnect:function(_320){
var self=MochiKit.Signal;
var _322=self._observers;
var m=MochiKit.Base;
if(arguments.length>1){
var src=MochiKit.DOM.getElement(arguments[0]);
var sig=arguments[1];
var obj=arguments[2];
var func=arguments[3];
for(var i=_322.length-1;i>=0;i--){
var o=_322[i];
if(o.source===src&&o.signal===sig&&o.objOrFunc===obj&&o.funcOrStr===func){
self._disconnect(o);
if(!self._lock){
_322.splice(i,1);
}else{
self._dirty=true;
}
return true;
}
}
}else{
var idx=m.findIdentical(_322,_320);
if(idx>=0){
self._disconnect(_320);
if(!self._lock){
_322.splice(idx,1);
}else{
self._dirty=true;
}
return true;
}
}
return false;
},disconnectAllTo:function(_32b,_32c){
var self=MochiKit.Signal;
var _32e=self._observers;
var _32f=self._disconnect;
var _330=self._lock;
var _331=self._dirty;
if(typeof (_32c)==="undefined"){
_32c=null;
}
for(var i=_32e.length-1;i>=0;i--){
var _333=_32e[i];
if(_333.objOrFunc===_32b&&(_32c===null||_333.funcOrStr===_32c)){
_32f(_333);
if(_330){
_331=true;
}else{
_32e.splice(i,1);
}
}
}
self._dirty=_331;
},disconnectAll:function(src,sig){
src=MochiKit.DOM.getElement(src);
var m=MochiKit.Base;
var _337=m.flattenArguments(m.extend(null,arguments,1));
var self=MochiKit.Signal;
var _339=self._disconnect;
var _33a=self._observers;
var i,_33c;
var _33d=self._lock;
var _33e=self._dirty;
if(_337.length===0){
for(i=_33a.length-1;i>=0;i--){
_33c=_33a[i];
if(_33c.source===src){
_339(_33c);
if(!_33d){
_33a.splice(i,1);
}else{
_33e=true;
}
}
}
}else{
var sigs={};
for(i=0;i<_337.length;i++){
sigs[_337[i]]=true;
}
for(i=_33a.length-1;i>=0;i--){
_33c=_33a[i];
if(_33c.source===src&&_33c.signal in sigs){
_339(_33c);
if(!_33d){
_33a.splice(i,1);
}else{
_33e=true;
}
}
}
}
self._dirty=_33e;
},signal:function(src,sig){
var self=MochiKit.Signal;
var _343=self._observers;
src=MochiKit.DOM.getElement(src);
var args=MochiKit.Base.extend(null,arguments,2);
var _345=[];
self._lock=true;
for(var i=0;i<_343.length;i++){
var _347=_343[i];
if(_347.source===src&&_347.signal===sig&&_347.connected){
try{
_347.listener.apply(src,args);
}
catch(e){
_345.push(e);
}
}
}
self._lock=false;
if(self._dirty){
self._dirty=false;
for(var i=_343.length-1;i>=0;i--){
if(!_343[i].connected){
_343.splice(i,1);
}
}
}
if(_345.length==1){
throw _345[0];
}else{
if(_345.length>1){
var e=new Error("Multiple errors thrown in handling 'sig', see errors property");
e.errors=_345;
throw e;
}
}
}});
MochiKit.Signal.EXPORT_OK=[];
MochiKit.Signal.EXPORT=["connect","disconnect","signal","disconnectAll","disconnectAllTo"];
MochiKit.Signal.__new__=function(win){
var m=MochiKit.Base;
this._document=document;
this._window=win;
this._lock=false;
this._dirty=false;
try{
this.connect(window,"onunload",this._unloadCache);
}
catch(e){
}
this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
m.nameFunctions(this);
};
MochiKit.Signal.__new__(this);
if(MochiKit.__export__){
connect=MochiKit.Signal.connect;
disconnect=MochiKit.Signal.disconnect;
disconnectAll=MochiKit.Signal.disconnectAll;
signal=MochiKit.Signal.signal;
}
MochiKit.Base._exportSymbols(this,MochiKit.Signal);
MochiKit.Base._deps("Iter",["Base"]);
MochiKit.Iter.NAME="MochiKit.Iter";
MochiKit.Iter.VERSION="1.4";
MochiKit.Base.update(MochiKit.Iter,{__repr__:function(){
return "["+this.NAME+" "+this.VERSION+"]";
},toString:function(){
return this.__repr__();
},registerIteratorFactory:function(name,_34c,_34d,_34e){
MochiKit.Iter.iteratorRegistry.register(name,_34c,_34d,_34e);
},iter:function(_34f,_350){
var self=MochiKit.Iter;
if(arguments.length==2){
return self.takewhile(function(a){
return a!=_350;
},_34f);
}
if(typeof (_34f.next)=="function"){
return _34f;
}else{
if(typeof (_34f.iter)=="function"){
return _34f.iter();
}
}
try{
return self.iteratorRegistry.match(_34f);
}
catch(e){
var m=MochiKit.Base;
if(e==m.NotFound){
e=new TypeError(typeof (_34f)+": "+m.repr(_34f)+" is not iterable");
}
throw e;
}
},count:function(n){
if(!n){
n=0;
}
var m=MochiKit.Base;
return {repr:function(){
return "count("+n+")";
},toString:m.forwardCall("repr"),next:m.counter(n)};
},cycle:function(p){
var self=MochiKit.Iter;
var m=MochiKit.Base;
var lst=[];
var _35a=self.iter(p);
return {repr:function(){
return "cycle(...)";
},toString:m.forwardCall("repr"),next:function(){
try{
var rval=_35a.next();
lst.push(rval);
return rval;
}
catch(e){
if(e!=self.StopIteration){
throw e;
}
if(lst.length===0){
this.next=function(){
throw self.StopIteration;
};
}else{
var i=-1;
this.next=function(){
i=(i+1)%lst.length;
return lst[i];
};
}
return this.next();
}
}};
},repeat:function(elem,n){
var m=MochiKit.Base;
if(typeof (n)=="undefined"){
return {repr:function(){
return "repeat("+m.repr(elem)+")";
},toString:m.forwardCall("repr"),next:function(){
return elem;
}};
}
return {repr:function(){
return "repeat("+m.repr(elem)+", "+n+")";
},toString:m.forwardCall("repr"),next:function(){
if(n<=0){
throw MochiKit.Iter.StopIteration;
}
n-=1;
return elem;
}};
},next:function(_360){
return _360.next();
},izip:function(p,q){
var m=MochiKit.Base;
var self=MochiKit.Iter;
var next=self.next;
var _366=m.map(self.iter,arguments);
return {repr:function(){
return "izip(...)";
},toString:m.forwardCall("repr"),next:function(){
return m.map(next,_366);
}};
},ifilter:function(pred,seq){
var m=MochiKit.Base;
seq=MochiKit.Iter.iter(seq);
if(pred===null){
pred=m.operator.truth;
}
return {repr:function(){
return "ifilter(...)";
},toString:m.forwardCall("repr"),next:function(){
while(true){
var rval=seq.next();
if(pred(rval)){
return rval;
}
}
return undefined;
}};
},ifilterfalse:function(pred,seq){
var m=MochiKit.Base;
seq=MochiKit.Iter.iter(seq);
if(pred===null){
pred=m.operator.truth;
}
return {repr:function(){
return "ifilterfalse(...)";
},toString:m.forwardCall("repr"),next:function(){
while(true){
var rval=seq.next();
if(!pred(rval)){
return rval;
}
}
return undefined;
}};
},islice:function(seq){
var self=MochiKit.Iter;
var m=MochiKit.Base;
seq=self.iter(seq);
var _372=0;
var stop=0;
var step=1;
var i=-1;
if(arguments.length==2){
stop=arguments[1];
}else{
if(arguments.length==3){
_372=arguments[1];
stop=arguments[2];
}else{
_372=arguments[1];
stop=arguments[2];
step=arguments[3];
}
}
return {repr:function(){
return "islice("+["...",_372,stop,step].join(", ")+")";
},toString:m.forwardCall("repr"),next:function(){
var rval;
while(i<_372){
rval=seq.next();
i++;
}
if(_372>=stop){
throw self.StopIteration;
}
_372+=step;
return rval;
}};
},imap:function(fun,p,q){
var m=MochiKit.Base;
var self=MochiKit.Iter;
var _37c=m.map(self.iter,m.extend(null,arguments,1));
var map=m.map;
var next=self.next;
return {repr:function(){
return "imap(...)";
},toString:m.forwardCall("repr"),next:function(){
return fun.apply(this,map(next,_37c));
}};
},applymap:function(fun,seq,self){
seq=MochiKit.Iter.iter(seq);
var m=MochiKit.Base;
return {repr:function(){
return "applymap(...)";
},toString:m.forwardCall("repr"),next:function(){
return fun.apply(self,seq.next());
}};
},chain:function(p,q){
var self=MochiKit.Iter;
var m=MochiKit.Base;
if(arguments.length==1){
return self.iter(arguments[0]);
}
var _387=m.map(self.iter,arguments);
return {repr:function(){
return "chain(...)";
},toString:m.forwardCall("repr"),next:function(){
while(_387.length>1){
try{
var _388=_387[0].next();
return _388;
}
catch(e){
if(e!=self.StopIteration){
throw e;
}
_387.shift();
var _388=_387[0].next();
return _388;
}
}
if(_387.length==1){
var arg=_387.shift();
this.next=m.bind("next",arg);
return this.next();
}
throw self.StopIteration;
}};
},takewhile:function(pred,seq){
var self=MochiKit.Iter;
seq=self.iter(seq);
return {repr:function(){
return "takewhile(...)";
},toString:MochiKit.Base.forwardCall("repr"),next:function(){
var rval=seq.next();
if(!pred(rval)){
this.next=function(){
throw self.StopIteration;
};
this.next();
}
return rval;
}};
},dropwhile:function(pred,seq){
seq=MochiKit.Iter.iter(seq);
var m=MochiKit.Base;
var bind=m.bind;
return {"repr":function(){
return "dropwhile(...)";
},"toString":m.forwardCall("repr"),"next":function(){
while(true){
var rval=seq.next();
if(!pred(rval)){
break;
}
}
this.next=bind("next",seq);
return rval;
}};
},_tee:function(_393,sync,_395){
sync.pos[_393]=-1;
var m=MochiKit.Base;
var _397=m.listMin;
return {repr:function(){
return "tee("+_393+", ...)";
},toString:m.forwardCall("repr"),next:function(){
var rval;
var i=sync.pos[_393];
if(i==sync.max){
rval=_395.next();
sync.deque.push(rval);
sync.max+=1;
sync.pos[_393]+=1;
}else{
rval=sync.deque[i-sync.min];
sync.pos[_393]+=1;
if(i==sync.min&&_397(sync.pos)!=sync.min){
sync.min+=1;
sync.deque.shift();
}
}
return rval;
}};
},tee:function(_39a,n){
var rval=[];
var sync={"pos":[],"deque":[],"max":-1,"min":-1};
if(arguments.length==1||typeof (n)=="undefined"||n===null){
n=2;
}
var self=MochiKit.Iter;
_39a=self.iter(_39a);
var _tee=self._tee;
for(var i=0;i<n;i++){
rval.push(_tee(i,sync,_39a));
}
return rval;
},list:function(_3a1){
var rval;
if(_3a1 instanceof Array){
return _3a1.slice();
}
if(typeof (_3a1)=="function"&&!(_3a1 instanceof Function)&&typeof (_3a1.length)=="number"){
rval=[];
for(var i=0;i<_3a1.length;i++){
rval.push(_3a1[i]);
}
return rval;
}
var self=MochiKit.Iter;
_3a1=self.iter(_3a1);
var rval=[];
var _3a5;
try{
while(true){
_3a5=_3a1.next();
rval.push(_3a5);
}
}
catch(e){
if(e!=self.StopIteration){
throw e;
}
return rval;
}
return undefined;
},reduce:function(fn,_3a7,_3a8){
var i=0;
var x=_3a8;
var self=MochiKit.Iter;
_3a7=self.iter(_3a7);
if(arguments.length<3){
try{
x=_3a7.next();
}
catch(e){
if(e==self.StopIteration){
e=new TypeError("reduce() of empty sequence with no initial value");
}
throw e;
}
i++;
}
try{
while(true){
x=fn(x,_3a7.next());
}
}
catch(e){
if(e!=self.StopIteration){
throw e;
}
}
return x;
},range:function(){
var _3ac=0;
var stop=0;
var step=1;
if(arguments.length==1){
stop=arguments[0];
}else{
if(arguments.length==2){
_3ac=arguments[0];
stop=arguments[1];
}else{
if(arguments.length==3){
_3ac=arguments[0];
stop=arguments[1];
step=arguments[2];
}else{
throw new TypeError("range() takes 1, 2, or 3 arguments!");
}
}
}
if(step===0){
throw new TypeError("range() step must not be 0");
}
return {next:function(){
if((step>0&&_3ac>=stop)||(step<0&&_3ac<=stop)){
throw MochiKit.Iter.StopIteration;
}
var rval=_3ac;
_3ac+=step;
return rval;
},repr:function(){
return "range("+[_3ac,stop,step].join(", ")+")";
},toString:MochiKit.Base.forwardCall("repr")};
},sum:function(_3b0,_3b1){
if(typeof (_3b1)=="undefined"||_3b1===null){
_3b1=0;
}
var x=_3b1;
var self=MochiKit.Iter;
_3b0=self.iter(_3b0);
try{
while(true){
x+=_3b0.next();
}
}
catch(e){
if(e!=self.StopIteration){
throw e;
}
}
return x;
},exhaust:function(_3b4){
var self=MochiKit.Iter;
_3b4=self.iter(_3b4);
try{
while(true){
_3b4.next();
}
}
catch(e){
if(e!=self.StopIteration){
throw e;
}
}
},forEach:function(_3b6,func,self){
var m=MochiKit.Base;
if(arguments.length>2){
func=m.bind(func,self);
}
if(m.isArrayLike(_3b6)){
try{
for(var i=0;i<_3b6.length;i++){
func(_3b6[i]);
}
}
catch(e){
if(e!=MochiKit.Iter.StopIteration){
throw e;
}
}
}else{
self=MochiKit.Iter;
self.exhaust(self.imap(func,_3b6));
}
},every:function(_3bb,func){
var self=MochiKit.Iter;
try{
self.ifilterfalse(func,_3bb).next();
return false;
}
catch(e){
if(e!=self.StopIteration){
throw e;
}
return true;
}
},sorted:function(_3be,cmp){
var rval=MochiKit.Iter.list(_3be);
if(arguments.length==1){
cmp=MochiKit.Base.compare;
}
rval.sort(cmp);
return rval;
},reversed:function(_3c1){
var rval=MochiKit.Iter.list(_3c1);
rval.reverse();
return rval;
},some:function(_3c3,func){
var self=MochiKit.Iter;
try{
self.ifilter(func,_3c3).next();
return true;
}
catch(e){
if(e!=self.StopIteration){
throw e;
}
return false;
}
},iextend:function(lst,_3c7){
if(MochiKit.Base.isArrayLike(_3c7)){
for(var i=0;i<_3c7.length;i++){
lst.push(_3c7[i]);
}
}else{
var self=MochiKit.Iter;
_3c7=self.iter(_3c7);
try{
while(true){
lst.push(_3c7.next());
}
}
catch(e){
if(e!=self.StopIteration){
throw e;
}
}
}
return lst;
},groupby:function(_3ca,_3cb){
var m=MochiKit.Base;
var self=MochiKit.Iter;
if(arguments.length<2){
_3cb=m.operator.identity;
}
_3ca=self.iter(_3ca);
var pk=undefined;
var k=undefined;
var v;
function fetch(){
v=_3ca.next();
k=_3cb(v);
}
function eat(){
var ret=v;
v=undefined;
return ret;
}
var _3d2=true;
var _3d3=m.compare;
return {repr:function(){
return "groupby(...)";
},next:function(){
while(_3d3(k,pk)===0){
fetch();
if(_3d2){
_3d2=false;
break;
}
}
pk=k;
return [k,{next:function(){
if(v==undefined){
fetch();
}
if(_3d3(k,pk)!==0){
throw self.StopIteration;
}
return eat();
}}];
}};
},groupby_as_array:function(_3d4,_3d5){
var m=MochiKit.Base;
var self=MochiKit.Iter;
if(arguments.length<2){
_3d5=m.operator.identity;
}
_3d4=self.iter(_3d4);
var _3d8=[];
var _3d9=true;
var _3da;
var _3db=m.compare;
while(true){
try{
var _3dc=_3d4.next();
var key=_3d5(_3dc);
}
catch(e){
if(e==self.StopIteration){
break;
}
throw e;
}
if(_3d9||_3db(key,_3da)!==0){
var _3de=[];
_3d8.push([key,_3de]);
}
_3de.push(_3dc);
_3d9=false;
_3da=key;
}
return _3d8;
},arrayLikeIter:function(_3df){
var i=0;
return {repr:function(){
return "arrayLikeIter(...)";
},toString:MochiKit.Base.forwardCall("repr"),next:function(){
if(i>=_3df.length){
throw MochiKit.Iter.StopIteration;
}
return _3df[i++];
}};
},hasIterateNext:function(_3e1){
return (_3e1&&typeof (_3e1.iterateNext)=="function");
},iterateNextIter:function(_3e2){
return {repr:function(){
return "iterateNextIter(...)";
},toString:MochiKit.Base.forwardCall("repr"),next:function(){
var rval=_3e2.iterateNext();
if(rval===null||rval===undefined){
throw MochiKit.Iter.StopIteration;
}
return rval;
}};
}});
MochiKit.Iter.EXPORT_OK=["iteratorRegistry","arrayLikeIter","hasIterateNext","iterateNextIter"];
MochiKit.Iter.EXPORT=["StopIteration","registerIteratorFactory","iter","count","cycle","repeat","next","izip","ifilter","ifilterfalse","islice","imap","applymap","chain","takewhile","dropwhile","tee","list","reduce","range","sum","exhaust","forEach","every","sorted","reversed","some","iextend","groupby","groupby_as_array"];
MochiKit.Iter.__new__=function(){
var m=MochiKit.Base;
if(typeof (StopIteration)!="undefined"){
this.StopIteration=StopIteration;
}else{
this.StopIteration=new m.NamedError("StopIteration");
}
this.iteratorRegistry=new m.AdapterRegistry();
this.registerIteratorFactory("arrayLike",m.isArrayLike,this.arrayLikeIter);
this.registerIteratorFactory("iterateNext",this.hasIterateNext,this.iterateNextIter);
this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
m.nameFunctions(this);
};
MochiKit.Iter.__new__();
if(MochiKit.__export__){
reduce=MochiKit.Iter.reduce;
}
MochiKit.Base._exportSymbols(this,MochiKit.Iter);
MochiKit.Base._deps("DateTime",["Base"]);
MochiKit.DateTime.NAME="MochiKit.DateTime";
MochiKit.DateTime.VERSION="1.4";
MochiKit.DateTime.__repr__=function(){
return "["+this.NAME+" "+this.VERSION+"]";
};
MochiKit.DateTime.toString=function(){
return this.__repr__();
};
MochiKit.DateTime.isoDate=function(str){
str=str+"";
if(typeof (str)!="string"||str.length===0){
return null;
}
var iso=str.split("-");
if(iso.length===0){
return null;
}
return new Date(iso[0],iso[1]-1,iso[2]);
};
MochiKit.DateTime._isoRegexp=/(\d{4,})(?:-(\d{1,2})(?:-(\d{1,2})(?:[T ](\d{1,2}):(\d{1,2})(?::(\d{1,2})(?:\.(\d+))?)?(?:(Z)|([+-])(\d{1,2})(?::(\d{1,2}))?)?)?)?)?/;
MochiKit.DateTime.isoTimestamp=function(str){
str=str+"";
if(typeof (str)!="string"||str.length===0){
return null;
}
var res=str.match(MochiKit.DateTime._isoRegexp);
if(typeof (res)=="undefined"||res===null){
return null;
}
var year,_3ea,day,hour,min,sec,msec;
year=parseInt(res[1],10);
if(typeof (res[2])=="undefined"||res[2]===""){
return new Date(year);
}
_3ea=parseInt(res[2],10)-1;
day=parseInt(res[3],10);
if(typeof (res[4])=="undefined"||res[4]===""){
return new Date(year,_3ea,day);
}
hour=parseInt(res[4],10);
min=parseInt(res[5],10);
sec=(typeof (res[6])!="undefined"&&res[6]!=="")?parseInt(res[6],10):0;
if(typeof (res[7])!="undefined"&&res[7]!==""){
msec=Math.round(1000*parseFloat("0."+res[7]));
}else{
msec=0;
}
if((typeof (res[8])=="undefined"||res[8]==="")&&(typeof (res[9])=="undefined"||res[9]==="")){
return new Date(year,_3ea,day,hour,min,sec,msec);
}
var ofs;
if(typeof (res[9])!="undefined"&&res[9]!==""){
ofs=parseInt(res[10],10)*3600000;
if(typeof (res[11])!="undefined"&&res[11]!==""){
ofs+=parseInt(res[11],10)*60000;
}
if(res[9]=="-"){
ofs=-ofs;
}
}else{
ofs=0;
}
return new Date(Date.UTC(year,_3ea,day,hour,min,sec,msec)-ofs);
};
MochiKit.DateTime.toISOTime=function(date,_3f2){
if(typeof (date)=="undefined"||date===null){
return null;
}
var hh=date.getHours();
var mm=date.getMinutes();
var ss=date.getSeconds();
var lst=[((_3f2&&(hh<10))?"0"+hh:hh),((mm<10)?"0"+mm:mm),((ss<10)?"0"+ss:ss)];
return lst.join(":");
};
MochiKit.DateTime.toISOTimestamp=function(date,_3f8){
if(typeof (date)=="undefined"||date===null){
return null;
}
var sep=_3f8?"T":" ";
var foot=_3f8?"Z":"";
if(_3f8){
date=new Date(date.getTime()+(date.getTimezoneOffset()*60000));
}
return MochiKit.DateTime.toISODate(date)+sep+MochiKit.DateTime.toISOTime(date,_3f8)+foot;
};
MochiKit.DateTime.toISODate=function(date){
if(typeof (date)=="undefined"||date===null){
return null;
}
var _3fc=MochiKit.DateTime._padTwo;
return [date.getFullYear(),_3fc(date.getMonth()+1),_3fc(date.getDate())].join("-");
};
MochiKit.DateTime.americanDate=function(d){
d=d+"";
if(typeof (d)!="string"||d.length===0){
return null;
}
var a=d.split("/");
return new Date(a[2],a[0]-1,a[1]);
};
MochiKit.DateTime._padTwo=function(n){
return (n>9)?n:"0"+n;
};
MochiKit.DateTime.toPaddedAmericanDate=function(d){
if(typeof (d)=="undefined"||d===null){
return null;
}
var _401=MochiKit.DateTime._padTwo;
return [_401(d.getMonth()+1),_401(d.getDate()),d.getFullYear()].join("/");
};
MochiKit.DateTime.toAmericanDate=function(d){
if(typeof (d)=="undefined"||d===null){
return null;
}
return [d.getMonth()+1,d.getDate(),d.getFullYear()].join("/");
};
MochiKit.DateTime.EXPORT=["isoDate","isoTimestamp","toISOTime","toISOTimestamp","toISODate","americanDate","toPaddedAmericanDate","toAmericanDate"];
MochiKit.DateTime.EXPORT_OK=[];
MochiKit.DateTime.EXPORT_TAGS={":common":MochiKit.DateTime.EXPORT,":all":MochiKit.DateTime.EXPORT};
MochiKit.DateTime.__new__=function(){
var base=this.NAME+".";
for(var k in this){
var o=this[k];
if(typeof (o)=="function"&&typeof (o.NAME)=="undefined"){
try{
o.NAME=base+k;
}
catch(e){
}
}
}
};
MochiKit.DateTime.__new__();
if(typeof (MochiKit.Base)!="undefined"){
MochiKit.Base._exportSymbols(this,MochiKit.DateTime);
}else{
(function(_406,_407){
if((typeof (JSAN)=="undefined"&&typeof (dojo)=="undefined")||(MochiKit.__export__===false)){
var all=_407.EXPORT_TAGS[":all"];
for(var i=0;i<all.length;i++){
_406[all[i]]=_407[all[i]];
}
}
})(this,MochiKit.DateTime);
}
MochiKit.Base._deps("Selector",["Base","DOM","Iter"]);
MochiKit.Selector.NAME="MochiKit.Selector";
MochiKit.Selector.VERSION="1.4";
MochiKit.Selector.__repr__=function(){
return "["+this.NAME+" "+this.VERSION+"]";
};
MochiKit.Selector.toString=function(){
return this.__repr__();
};
MochiKit.Selector.EXPORT=["Selector","findChildElements","findDocElements","$$"];
MochiKit.Selector.EXPORT_OK=[];
MochiKit.Selector.Selector=function(_3d0){
this.params={classNames:[],pseudoClassNames:[]};
this.expression=_3d0.toString().replace(/(^\s+|\s+$)/g,"");
this.parseExpression();
this.compileMatcher();
};
MochiKit.Selector.Selector.prototype={__class__:MochiKit.Selector.Selector,parseExpression:function(){
function abort(_3d1){
throw "Parse error in selector: "+_3d1;
}
if(this.expression==""){
abort("empty expression");
}
var repr=MochiKit.Base.repr;
var _3d3=this.params;
var expr=this.expression;
var _3d5,_3d6,_3d7,rest;
while(_3d5=expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!^$*]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)){
_3d3.attributes=_3d3.attributes||[];
_3d3.attributes.push({name:_3d5[2],operator:_3d5[3],value:_3d5[4]||_3d5[5]||""});
expr=_3d5[1];
}
if(expr=="*"){
return this.params.wildcard=true;
}
while(_3d5=expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+(?:\([^)]*\))?)(.*)/i)){
_3d6=_3d5[1];
_3d7=_3d5[2];
rest=_3d5[3];
switch(_3d6){
case "#":
_3d3.id=_3d7;
break;
case ".":
_3d3.classNames.push(_3d7);
break;
case ":":
_3d3.pseudoClassNames.push(_3d7);
break;
case "":
case undefined:
_3d3.tagName=_3d7.toUpperCase();
break;
default:
abort(repr(expr));
}
expr=rest;
}
if(expr.length>0){
abort(repr(expr));
}
},buildMatchExpression:function(){
var repr=MochiKit.Base.repr;
var _3da=this.params;
var _3db=[];
var _3dc,i;
function childElements(_3de){
return "MochiKit.Base.filter(function (node) { return node.nodeType == 1; }, "+_3de+".childNodes)";
}
if(_3da.wildcard){
_3db.push("true");
}
if(_3dc=_3da.id){
_3db.push("element.id == "+repr(_3dc));
}
if(_3dc=_3da.tagName){
_3db.push("element.tagName.toUpperCase() == "+repr(_3dc));
}
if((_3dc=_3da.classNames).length>0){
for(i=0;i<_3dc.length;i++){
_3db.push("MochiKit.DOM.hasElementClass(element, "+repr(_3dc[i])+")");
}
}
if((_3dc=_3da.pseudoClassNames).length>0){
for(i=0;i<_3dc.length;i++){
var _3df=_3dc[i].match(/^([^(]+)(?:\((.*)\))?$/);
var _3e0=_3df[1];
var _3e1=_3df[2];
switch(_3e0){
case "root":
_3db.push("element.nodeType == 9 || element === element.ownerDocument.documentElement");
break;
case "nth-child":
case "nth-last-child":
case "nth-of-type":
case "nth-last-of-type":
_3df=_3e1.match(/^((?:(\d+)n\+)?(\d+)|odd|even)$/);
if(!_3df){
throw "Invalid argument to pseudo element nth-child: "+_3e1;
}
var a,b;
if(_3df[0]=="odd"){
a=2;
b=1;
}else{
if(_3df[0]=="even"){
a=2;
b=0;
}else{
a=_3df[2]&&parseInt(_3df)||null;
b=parseInt(_3df[3]);
}
}
_3db.push("this.nthChild(element,"+a+","+b+","+!!_3e0.match("^nth-last")+","+!!_3e0.match("of-type$")+")");
break;
case "first-child":
_3db.push("this.nthChild(element, null, 1)");
break;
case "last-child":
_3db.push("this.nthChild(element, null, 1, true)");
break;
case "first-of-type":
_3db.push("this.nthChild(element, null, 1, false, true)");
break;
case "last-of-type":
_3db.push("this.nthChild(element, null, 1, true, true)");
break;
case "only-child":
_3db.push(childElements("element.parentNode")+".length == 1");
break;
case "only-of-type":
_3db.push("MochiKit.Base.filter(function (node) { return node.tagName == element.tagName; }, "+childElements("element.parentNode")+").length == 1");
break;
case "empty":
_3db.push("element.childNodes.length == 0");
break;
case "enabled":
_3db.push("(this.isUIElement(element) && element.disabled === false)");
break;
case "disabled":
_3db.push("(this.isUIElement(element) && element.disabled === true)");
break;
case "checked":
_3db.push("(this.isUIElement(element) && element.checked === true)");
break;
case "not":
var _3e4=new MochiKit.Selector.Selector(_3e1);
_3db.push("!( "+_3e4.buildMatchExpression()+")");
break;
}
}
}
if(_3dc=_3da.attributes){
MochiKit.Base.map(function(_3e5){
var _3e6="MochiKit.DOM.getNodeAttribute(element, "+repr(_3e5.name)+")";
var _3e7=function(_3e8){
return _3e6+".split("+repr(_3e8)+")";
};
switch(_3e5.operator){
case "=":
_3db.push(_3e6+" == "+repr(_3e5.value));
break;
case "~=":
_3db.push(_3e6+" && MochiKit.Base.findValue("+_3e7(" ")+", "+repr(_3e5.value)+") > -1");
break;
case "^=":
_3db.push(_3e6+".substring(0, "+_3e5.value.length+") == "+repr(_3e5.value));
break;
case "$=":
_3db.push(_3e6+".substring("+_3e6+".length - "+_3e5.value.length+") == "+repr(_3e5.value));
break;
case "*=":
_3db.push(_3e6+".match("+repr(_3e5.value)+")");
break;
case "|=":
_3db.push(_3e6+" && "+_3e7("-")+"[0].toUpperCase() == "+repr(_3e5.value.toUpperCase()));
break;
case "!=":
_3db.push(_3e6+" != "+repr(_3e5.value));
break;
case "":
case undefined:
_3db.push(_3e6+" != null");
break;
default:
throw "Unknown operator "+_3e5.operator+" in selector";
}
},_3dc);
}
return _3db.join(" && ");
},compileMatcher:function(){
this.match=new Function("element","if (!element.tagName) return false;                 return "+this.buildMatchExpression());
},nthChild:function(_3e9,a,b,_3ec,_3ed){
var _3ee=MochiKit.Base.filter(function(node){
return node.nodeType==1;
},_3e9.parentNode.childNodes);
if(_3ed){
_3ee=MochiKit.Base.filter(function(node){
return node.tagName==_3e9.tagName;
},_3ee);
}
if(_3ec){
_3ee=MochiKit.Iter.reversed(_3ee);
}
if(a){
var _3f1=MochiKit.Base.findIdentical(_3ee,_3e9);
return ((_3f1+1-b)/a)%1==0;
}else{
return b==MochiKit.Base.findIdentical(_3ee,_3e9)+1;
}
},isUIElement:function(_3f2){
return MochiKit.Base.findValue(["input","button","select","option","textarea","object"],_3f2.tagName.toLowerCase())>-1;
},findElements:function(_3f3,axis){
var _3f5;
if(axis==undefined){
axis="";
}
function inScope(_3f6,_3f7){
if(axis==""){
return MochiKit.DOM.isChildNode(_3f6,_3f7);
}else{
if(axis==">"){
return _3f6.parentNode==_3f7;
}else{
if(axis=="+"){
return _3f6==nextSiblingElement(_3f7);
}else{
if(axis=="~"){
var _3f8=_3f7;
while(_3f8=nextSiblingElement(_3f8)){
if(_3f6==_3f8){
return true;
}
}
return false;
}else{
throw "Invalid axis: "+axis;
}
}
}
}
}
if(_3f5=MochiKit.DOM.getElement(this.params.id)){
if(this.match(_3f5)){
if(!_3f3||inScope(_3f5,_3f3)){
return [_3f5];
}
}
}
function nextSiblingElement(node){
node=node.nextSibling;
while(node&&node.nodeType!=1){
node=node.nextSibling;
}
return node;
}
if(axis==""){
_3f3=(_3f3||MochiKit.DOM.currentDocument()).getElementsByTagName(this.params.tagName||"*");
}else{
if(axis==">"){
if(!_3f3){
throw "> combinator not allowed without preceeding expression";
}
_3f3=MochiKit.Base.filter(function(node){
return node.nodeType==1;
},_3f3.childNodes);
}else{
if(axis=="+"){
if(!_3f3){
throw "+ combinator not allowed without preceeding expression";
}
_3f3=nextSiblingElement(_3f3)&&[nextSiblingElement(_3f3)];
}else{
if(axis=="~"){
if(!_3f3){
throw "~ combinator not allowed without preceeding expression";
}
var _3fb=[];
while(nextSiblingElement(_3f3)){
_3f3=nextSiblingElement(_3f3);
_3fb.push(_3f3);
}
_3f3=_3fb;
}
}
}
}
if(!_3f3){
return [];
}
var _3fc=MochiKit.Base.filter(MochiKit.Base.bind(function(_3fd){
return this.match(_3fd);
},this),_3f3);
return _3fc;
},repr:function(){
return "Selector("+this.expression+")";
},toString:MochiKit.Base.forwardCall("repr")};
MochiKit.Base.update(MochiKit.Selector,{findChildElements:function(_3fe,_3ff){
return MochiKit.Base.flattenArray(MochiKit.Base.map(function(_400){
var _401="";
return MochiKit.Iter.reduce(function(_402,expr){
if(match=expr.match(/^[>+~]$/)){
_401=match[0];
return _402;
}else{
var _404=new MochiKit.Selector.Selector(expr);
var _405=MochiKit.Iter.reduce(function(_406,_407){
return MochiKit.Base.extend(_406,_404.findElements(_407||_3fe,_401));
},_402,[]);
_401="";
return _405;
}
},_400.replace(/(^\s+|\s+$)/g,"").split(/\s+/),[null]);
},_3ff));
},findDocElements:function(){
return MochiKit.Selector.findChildElements(MochiKit.DOM.currentDocument(),arguments);
},__new__:function(){
var m=MochiKit.Base;
this.$$=this.findDocElements;
this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
m.nameFunctions(this);
}});
MochiKit.Selector.__new__();
MochiKit.Base._exportSymbols(this,MochiKit.Selector);

//////////////////////////////////////////////////////////////////////////////////////////////
// home-grown stuff

// for decoding HTML-encoded text
function unescapeHTML(html) {
   var htmlNode = document.createElement("DIV");
   htmlNode.innerHTML = html;
   return (htmlNode.innerText || htmlNode.textContent);
}

function getElementsByXPath(xpath){
	var elements = [];
	var matchingElements = document.evaluate(xpath, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
	var count = matchingElements.snapshotLength;
	while (count > 0) { 
		elements[count - 1] = matchingElements.snapshotItem(--count);
	}
   return elements;
}

function format(formatString /*, argument list */) { // this is a naive implementation of the .NET framework's string.Format() method
   for (var i = 0; i < arguments.length - 1; i++) {
      formatString = formatString.replace(new RegExp("\\{[" + i.toString() + "]{1}\\}" , "g"), arguments[i + 1].toString());
   }
   return formatString;
}

function getGUID() {
	var fourChars = function(){ return (((1 + Math.random()) * 0x10000)|0).toString(16).substring(1).toUpperCase(); }
	return format("{0}{1}-{2}-{3}-{4}-{5}{6}{7}", fourChars(),fourChars(),fourChars(),fourChars(),fourChars(),fourChars(),fourChars(),fourChars());
}

//////////////////////////////////////////////////////////////////////////////////////////////
// Timer object - used to do basic performance profiling. 
// Usage: 
//        var t = new Timer("loading data");
//        t.start();
//        // code that you want to time here
//        t.stop();
//
//        the indentifer you specified will show in the console with the elapsed time appended
//        e.g. loading data: 44 ms
//////////////////////////////////////////////////////////////////////////////////////////////
function Timer(identifier) {
   var startTime = null;
   var endTime = null;
   this.start = function() {
      startTime = new Date();
   };
   this.stop = function() {
      endTime = new Date();
      GM_log(format("{0}: {1}ms", identifier, (endTime - startTime)));
   }
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////// END OF GENERAL PURPOSE LIBRARIES & FUNCTIONS ///////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////
// This function is used to hijack Weewar's default map click behavior - if there is
// any other map-based click functionality we want to override, we do it in this
//////////////////////////////////////////////////////////////////////////////////////
function mapOnClickHandler(x, y, gameId) {
	if(m_CtrlKeyDepressed) {
		enableAttackRangeAssistant(x, y);
	} else if(m_ShiftKeyDepressed) {
		showAllRanges(x, y);
	} else {
		// this block of code essentially restores the default behavior of the click
		// for the duration of this one click, since we haven't hijacked it at this point
		m_UnsafeWeewarMap.setClickFunction(m_DefaultClickFunction);
		m_UnsafeWeewarMap.clickFunction(x,y);
		m_UnsafeWeewarMap.setClickFunction(mapOnClickHandler);
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////     Model    ///////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////

// meant to serve as an organized way of storing static data
function StaticMetadata() {

  this.MapImagesSubPath = "/images/maps/";  // used to help us find the map in all of the images on the page

  this.PixelsOfImagePaddingOnLeft = 16;     // weewar's images for the game maps are padded with whitespace on the left and bottom
  this.PixelsOfImagePaddingOnBottom = 2;    // weewar's images for the game maps are padded with whitespace on the left and bottom
  this.PixelsOfImagePaddingOnTop = 0;       // this is only here to be explicit in other code
  this.PixelWidthOfHex = 32;                // hopefully this is self-explanatory
  this.AdjustedPixelHeightOfHex = 26.5333;  // this is the essential "height" of each hex when y > 1 because of overlap


  this.UnitImageDictionary = {
    "001" : "Trooper", "002" : "Heavy Trooper", "003" : "Raider", "004" : "Assault Atillery", "005" : "Tank",
    "006" : "Heavy Tank", "007" : "Berserker", "008" : "Light Artillery", "009" : "Heavy Artillery", "010" : "Death From Above", 
    "airfield" : "Airfield", "antiair" : "Anti-Aircraft", "battleship" : "Battleship", "bomber" : "Bomber", "capturing" : "Capturing", 
    "city" : "City", "destroyer" : "Destroyer", "harbor" : "Harbor", "heli" : "Helicopter", "hovercraft" : "Hovercraft", 
    "jet" : "Jet", "speedboat" : "Speedboat", "sub" : "Sub"
  };

  this.UnitAttackRangeDictionary = {
    "Trooper" : {start:1, end:1}, "Heavy Trooper" : {start:1, end:1}, "Raider" : {start:1, end:1}, "Assault Atillery" : {start:1, end:2}, "Tank" : {start:1, end:1}, 
    "Heavy Tank" : {start:1, end:1}, "Berserker" : {start:1, end:1}, "Light Artillery" : {start:2, end:3}, "Heavy Artillery" : {start:3, end:4}, "Death From Above" : {start:2, end:5}, 
    "Anti-Aircraft" : {start:1, end:3}, "Battleship" : {start:1, end:4}, "Bomber" : {start:1, end:1}, 
    "Destroyer" : {start:1, end:3}, "Helicopter" : {start:1, end:1}, "Hovercraft" : {start:1, end:1}, 
    "Jet" : {start:1, end:1}, "Speedboat" : {start:1, end:1}, "Sub" : {start:1, end:2}
  };

  this.UnitMoveRangeDictionary = {
    "Trooper" : {start:1, end:1}, "Heavy Trooper" : {start:1, end:1}, "Raider" : {start:1, end:1}, "Assault Atillery" : {start:1, end:1}, "Tank" : {start:1, end:1}, 
    "Heavy Tank" : {start:1, end:1}, "Berserker" : {start:1, end:1}, "Light Artillery" : {start:1, end:1}, "Heavy Artillery" : {start:1, end:1}, "Death From Above" : {start:1, end:1}, 
    "Anti-Aircraft" : {start:1, end:1}, "Battleship" : {start:1, end:1}, "Bomber" : {start:1, end:1}, 
    "Destroyer" : {start:1, end:1}, "Helicopter" : {start:1, end:1}, "Hovercraft" : {start:1, end:1}, 
    "Jet" : {start:1, end:1}, "Speedboat" : {start:1, end:1}, "Sub" : {start:1, end:1}
  };
}

// this class defines (if not already, will eventually) everything we need to know about a hex on the map
function MapHex(x, y, staticMetadata, unsafeWeewarMap) {

	// these properties are implemented as functions so as to prevent from tampering 
	this.X = function() { return x; };
	this.Y = function() { return y; };
	
	// provides both coordinates together in object with x and y properties
	this.getHexCoordinates = function() {
		return {"x":x, "y":y};
	};
	
	// provides the upper-left pixel coordinates for the rectangle that surrounds the hex (used for images)
  this.getPixelCoordinates = function() {
    return {
      "x" : ((x * 32) + ((y == 0 || y % 2 == 0) ? 0 : 16)) + staticMetadata.PixelsOfImagePaddingOnLeft,
      "y" : (y * 26) + staticMetadata.PixelsOfImagePaddingOnTop
    };
  };
  
  //////////////////////////////////////////////////////////////////////////////////
  // get unit type data if available (i.e. if a unit, like a tank or infantry unit)
  var unitType = null;
  var unitImage = unsafeWeewarMap.getUnit(x,y); // returns the image's file name
  if(unitImage != null && typeof(unitImage) == "string") {
    unitType = unitImage.replace(".png", "");
    var unitRegEx = new RegExp("([a-zA-Z]{3,})_([0-9]{3}|[a-zA-Z]{3,})", "g");
    unitType = staticMetadata.UnitImageDictionary[unitRegEx.exec(unitType)[2]];
  }
  this.UnitType = unitType;
  //////////////////////////////////////////////////////////////////////////////////

  //////////////////////////////////////////////////////////////////////////////////
  // Set terrain type
  var terrainType = null;
  var terrainImage = unsafeWeewarMap.getTerrain(x, y);
  if(terrainImage != null && typeof(terrainImage) == "string") {
    terrainType = terrainImage.replace(".png", "");
  }
  this.TerrainType = terrainType;
  //////////////////////////////////////////////////////////////////////////////////

  // other potentially useful properties
  this.HexOnMap = (!(this.UnitType == null && this.TerrainType == null));

}

// this object will hold all of our metadata for the map and provide access to it
function WeewarMap(staticMetadata, unsafeWeewarMap) {
  bindMethods(this);
  this.StaticMetadata = staticMetadata;
  this.UnsafeWeewarMap = unsafeWeewarMap;
  this.__init__();
};

update(WeewarMap.prototype, {

	__init__ : function() {
	
    // initialize values
		this.HexDimensions = this.getMapHexDimensions();
		
		var hexes = [];
		for(var x = 0; x < this.HexDimensions.x; x++) {
			hexes[x] = [];
			for(var y = 0; y < this.HexDimensions.y; y++) {				
				hexes[x][y] = new MapHex(x, y, this.StaticMetadata, this.UnsafeWeewarMap);
			}
		}
		this.Hexes = hexes; // make publicly-accessible
	},
	
	getMapImagePixelDimensions : function() {
		var images = getElementsByXPath("//img[@src]");
		var mapImage = null;
		for(var i in images) {
			if(images[i].src.indexOf(this.StaticMetadata.MapImagesSubPath) != -1 && images[i].src.indexOf("grey") != -1) {
	      	mapImage = images[i];
	      	break;
			}
		}
	  return {x:mapImage.width, y:mapImage.height};
	},

	getMapHexDimensions : function() {
	  // to find out how many hexes are on the map, we do the math using the map image and the knowledge of 
	  // the size of a hex (32px wide, 26.5px high taking into account the dove-tailing overlap effect of hexes)
	  var mapPixelDimensions = this.getMapImagePixelDimensions();
	  var maximumX = ((mapPixelDimensions.x - this.StaticMetadata.PixelsOfImagePaddingOnLeft) / this.StaticMetadata.PixelWidthOfHex);
	  var maximumY = Math.round((mapPixelDimensions.y - this.StaticMetadata.PixelsOfImagePaddingOnBottom) / this.StaticMetadata.AdjustedPixelHeightOfHex);
	  return {x:maximumX, y:maximumY};
	},
	
  getMapHex : function(x, y) {
    return (this.Hexes[x] && this.Hexes[x][y]) ? this.Hexes[x][y] : { HexOnMap : false, TerrainType : "none", UnitType : "none" };
  }
  
});

//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// START OF CONFIGURATION-RELATED CODE /////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
function getConfigurationSettings() {
	
	//TODO: make this code more robust - we need to check the version of the settings so that we can update them if needed
	//TODO: change code so that it can work with our settings web service
	
	// check to see if the settings exist - if not, instantiate new settings object
	var configurationSettingsString = GM_getValue("ConfigurationSettings", "");
	if(!configurationSettingsString) {
		// no settings saved - create new ones and save them (Alternatively, we could fetch them from server if the user stores them with our settings web service)
		configurationSettingsString = serializeJSON(new ConfigurationSettings());
	//	GM_setValue("ConfigurationSettings", configurationSettingsString);
	}
	return evalJSON(configurationSettingsString);
}

function saveConfigurationSettings() {
//	GM_setValue("ConfigurationSettings", serializeJSON(m_ConfigurationSettings));
}

function ConfigurationSettings() {
	///////////////////////////////////////////////////////////////
	this.SettingsVersion = 1.0; // needed for upgrading user settings in subsequent versions
	///////////////////////////////////////////////////////////////
	// below this line, list all features this script is capable of providing
	this.AttackRangeAssistant = 	new Feature("AttackRangeAssistant", true, null, "game/[0-9]");
	this.HistoryEnhancer = 			new Feature("HistoryEnhancer", true, null, "game/[0-9]");
	this.MapEnhancer = 				new Feature("MapEnhancer", true, new MapFeatures(), "game/[0-9]");
	this.ChatEnhancer = 			new Feature("ChatEnhancer", true, new ChatFeatures(), "playersReadyToPlay", "headquarters/games/open", "game/[0-9]");
	this.AutoRepair = 				new Feature("AutoRepair", true, null, "game/[0-9]");
	///////////////////////////////////////////////////////////////
	// now build an object consisting of RegExp-to-Feature-List mappings
	var urlRegExpMap = {};
	for(var prop in this) {
		if(this[prop].constructor == Feature) {
			var that = this;
			forEach(this[prop].UrlRegExps, function(regExp) {
				if(!urlRegExpMap[regExp]) {
					urlRegExpMap[regExp] = [];
				}
				urlRegExpMap[regExp].push(that[prop].Name);
			});
		}
	}
	this.UrlRegExpMap = urlRegExpMap;
	///////////////////////////////////////////////////////////////
}
// usage: new Feature("FeatureName", true, {Foo:3, Bar:"Baz"}, "oneRegex/String", "another", etc.); 
function Feature(name, enabled, featureSpecificSettings/*, 0...n regular expression strings */) {
	this.Name = name;
	this.Enabled = enabled;
	this.FeatureSpecificSettings = featureSpecificSettings; 
	this.UrlRegExps = list(arguments).slice(3); // allows the client code to pass in as many comma-delimited Regexs as they want to
}
function MapFeatures() {
	// map window size settings
	this.EnableSizeAdjuster = true;
	this.DefaultWindowHeight = "300px";
	this.SizeChangeIncrement = 50;
	this.GameSizeMap = {}; // a map of the sizes of each game's map window (when different from the global setting) 
}

function ChatFeatures() {
	// chat message settings
	this.EnableDateTimeStamps = true;
	this.IncludeDate = true;
	this.IncludeTime = true;
	this.DateStampFormat = "{0}/{1}";
	this.TimeStampType = 12; // indicate 12 or 24 hour clock
	// chat window size settings
	this.EnableSizeAdjuster = true;
	this.DefaultWindowHeight = "200px";
	this.SizeChangeIncrement = 50;
	this.GameSizeMap = {}; // a map of the sizes of each game's chat window (when different from the global setting) 
}
function loadAppropriateFunctionality(url) { //TODO: see if there is a better way of doing this
	// depending on the page we are currently on, we initialize the variables that will be needed for that page's functionality
	var pageInitFunctions = {
		"game/[0-9]" : loadGameFunctionality, 
		"headquarters/games$" : loadHQFunctionality,
		"headquarters/archive$" : loadGameArchiveFunctionality, 
		"headquarters/games/open" : loadOpenGameFunctionality, 
		"playersReadyToPlay" : loadAvailablePlayersFunctionality,
		"ladder$" : loadTopPlayersFunctionality,
		"chat$" : loadExpandedChatFunctionality
	};
	for(var regexp in pageInitFunctions) {
		console.log(regexp);
		console.log((new RegExp(regexp)).test(url));
		if((new RegExp(regexp)).test(url)) {
			pageInitFunctions[regexp]();
		}
	}
}
function loadHQFunctionality() {
	GM_log("Execute functions that provide functionality for the Headquarters page.");
}
function loadGameArchiveFunctionality() {
	GM_log("Execute functions that provide functionality for the Game Archive tab on the Headquarters page.");
}
function loadOpenGameFunctionality() {
	GM_log("Execute functions that provide functionality for the Open Games page.");
	if(m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.EnableDateTimeStamps) startChatStamps();
}
function loadAvailablePlayersFunctionality() {
	GM_log("Execute functions that provide functionality for the Available Players page.");
	if(m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.EnableDateTimeStamps) startChatStamps();
}
function loadTopPlayersFunctionality() {
	GM_log("Execute functions that provide functionality for the Top Players page.");
	if(m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.EnableDateTimeStamps) startChatStamps();
}
function loadExpandedChatFunctionality() {
	GM_log("Execute functions that provide functionality for the Expanded Chat page.");
	if(m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings.EnableDateTimeStamps) startChatStamps();
}
function loadGameFunctionality() {
	
	m_GameId = (/game\/([0-9]*)/g).exec(window.location.href)[1];
	m_GameServer = (/http:\/\/([a-z.0-9]*)/g).exec(window.location.href)[1];	

	// get all of the metadata available for the page //TODO: Make sure to update this *as* the player plays their turns and as other players play their turns!!! (when the player ends their turn, currently the page refreshes - does this happen when other players finish their turns as well?!)
	m_WeewarMap = new WeewarMap(m_StaticMetadata, m_UnsafeWeewarMap); 
	
	// we assume the CTRL key isn't being held down during the loading of this script
	m_CtrlKeyDepressed = false;
	m_ShiftKeyDepressed = false;
	
	// get the originally-defined (by weewar) click function
	m_DefaultClickFunction = m_UnsafeWeewarMap.getClickFunction();
	
	// set the click function to *our* click function
	m_UnsafeWeewarMap.setClickFunction(mapOnClickHandler);
	//////////////////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////////////////
	// Setup the hooks into the keyboard events - these set global variables used by 
	// various parts of our application to determine functionality
	//////////////////////////////////////////////////////////////////////////////////////
	var keyHandler = function(e) { 
								m_CtrlKeyDepressed = e.modifier().ctrl; 
								m_ShiftKeyDepressed = e.modifier().shift; };
	connect(window, "onkeydown", keyHandler);
	connect(window, "onkeyup", keyHandler);
	connect(window, "onkeypress", keyHandler);
	connect("map", "onclick", function(e) { if(m_CtrlKeyDepressed || m_ShiftKeyDepressed) e.stop(); });
	//////////////////////////////////////////////////////////////////////////////////////

	drawToolbar();
	doGeneralAesthetics();
	//startChatStamps();
	startChatSizeAdjuster();
	//addOtherToggleOptions();
	//addAllRangesToolbar();
	showStatsToggle();
	
	// chat stuff
/* 	if(m_ConfigurationSettings.ChatEnhancer.Enabled) {
		var chatSettings = m_ConfigurationSettings.ChatEnhancer.FeatureSpecificSettings;
		if(chatSettings.EnableDateTimeStamps) {
			startChatStamps();
		}
		if (chatSettings.EnableSizeAdjuster) {
	  		startChatSizeAdjuster();
		}		
	} */
	
	/*if(m_ConfigurationSettings.MapEnhancer.Enabled && m_ConfigurationSettings.MapEnhancer.FeatureSpecificSettings.EnableSizeAdjuster) {
		startMapSizeAdjuster();
	} */

	startBattleSimulator();
	startAutoRepair();
	startEnhancedHistory();
	enableBanker();
	startEndOfGameMenu();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// this function checks for updates to the script by checking with our server
function checkForUpdate(callbackFunction) {
/*	var updateAvailable = false;
	try {
		var todaysDateInMilliseconds = Date.parse((new Date()).toDateString()); // we don't care about the time portion of this
		if(GM_getValue("InstallId") == null || GM_getValue("InstallId") == "") {
			GM_setValue("InstallId", getGUID());
			GM_log(GM_getValue("InstallId"));
			GM_setValue("LastUsed", todaysDateInMilliseconds);
		}
		if(todaysDateInMilliseconds > GM_getValue("LastUsed")) {
			var serverUrl = format(m_UpdateURL, m_ScriptId, GM_getValue("InstallId"));
			GM_xmlhttpRequest({method:"GET", url:serverUrl, headers:{"User-Agent":navigator.userAgent}, onload:function(response) {
					if(response.status == 200) {
						var responseObject = evalJSON(response.responseText); // { version : 1.0 } or { error : 'Unknown script.' } or { error : 'Bad request.' } or { error : 'Server error.' }
						updateAvailable = (responseObject.version && responseObject.version > m_ScriptVersion); 
					} else {
						// there was an error that was possibly caused by network or server issues...should we do anything about this?
						// for now, let's not - we will assume that if there are problems with the server, and we are still actively
						// developing this script that we will be checking the server to make sure it is working, etc., blah, blah, blah
					}
					callbackFunction(updateAvailable);
				}
			});
		} else {
			// already checked for an update today
			callbackFunction(updateAvailable);
		}		
	} catch(e) {
		// oh well, no biggie - something blew up - maybe we should try to insert something into the DOM here as well?!
		GM_log(e.message);
		GM_log("Update check failed - you can manually check for updates by visiting http://www.sapientdevelopment.com/weewar!");
		callbackFunction(updateAvailable);
	}*/
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// END OF CONFIGURATION-RELATED CODE /////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
// put all code that you want to execute when the page loads within this function - it is attached to the window's onload
// event by a line of code near the end of this file; all of the other code defined needs to load before we call this
//function onload() {
//}
	
	// this next line is for development purposes - for clearing out the settings data
	// if you want to clear your settings, uncomment this line
	//GM_setValue("ConfigurationSettings", "");
	
	try {
		///////////////////////////////////////////////////////
		// Initialize global variables
		m_UnsafeWeewarMap = unsafeWindow.weewarMap; 
		unsafeWindow.urchinTracker = function(){}; // helps prevent some errors (FireBug is always complaining that this function is NOT defined, so I defined it!)
		
		// contains exactly what it sounds like it contains
		m_StaticMetadata = new StaticMetadata();
		
		// load the settings for determining features
		m_ConfigurationSettings = getConfigurationSettings();
		///////////////////////////////////////////////////////
		
		// this gets everything going
		loadAppropriateFunctionality(window.location.href);
		
		// check for updates to the script and indicate if there are with visual cue
		checkForUpdate(function(updateAvailable) {
			if(updateAvailable) {
				$("optionsMenuLink").title = "Update available - please visit www.weewarscripts.info to download latest version.";
				var toggleValue = 1;
				setInterval(function() {
					$("optionsMenuLink").style.color = (toggleValue++ % 2) ? "#FF0000" : "#FF8888";
				}, 1500);
			} 
		});
		
	} catch(e) {
		GM_log(e.message);
		GM_log(e.lineNumber);
	}

//connect(window, "onload", onload); //function "onload" is defined at top of this script
//connect(window, "onunload", onunload); //function "onunload" is defined at top of this script