document.write("<div id='wsod-green-portfolio'></div>");

setTimeout(function() {





/*
 * todos:
 * 	- Performance metrics against techniques http://www.ajaxpath.com/javascript-inheritance (DONE)
 *  - Support for imports/using/requires other classes. (DONE)
 *  - Dynamically loading classes? - Not going to add this unless we really need it.  ScriptsCache/ScriptsManager is the loader of choice
 *  - Should this remain prototyped onto Function? Should I create my own base class? - Yes (DONE)
 *  - get rid of reserved words (super, extends) as they cause problems in IE. (DONE)
 */

Function.getClassName = function() {
	return "Function";
};


/* Extend from another prototyped Function */
Function.prototype.Extend = function(superClass) {
	this.prototype = new superClass();

	this.prototype.getSuperClass = function() {
		return superClass;
	};
	this.getSuperClass = this.prototype.getSuperClass;
	return this;
};

/*
The Super method allows us to do the constructor (or any super call) chaining more easily.  It looks like this:

var A = function() {
  this.value = ["1"]
}

var B = function() {
  B.Super(this);
  this.value.push("2");
}

Super calls for non constructor methods look like:
Class.Super(this, "methodName", arguments);
*/

Function.prototype.Super = function(context, methodName, args) {
	if (null != methodName) {
		var method = this.getSuperClass().prototype[methodName];
	}
	else {
		var method = this.getSuperClass();
	}

	if (!args) {
		return method.call(context);
	}
	else {
		return method.apply(context, args);
	}
};

/*
Function.Implements
It takes either an instanciated object or a functor, and a list of properties/methods and add
them to the calling functor.  Be careful not to apply methods that call other methods/object in
the passed functor/object that do not exist in the calling functor.
*/
Function.prototype.Implements = function(obj, members) {
	if(typeof obj == "function") {
		obj = obj.prototype;
	}
	var tObj = {}
	for(var i = 0, len = members.length; i < len; ++i) {
		tObj[members[i]] = obj[members[i]] || null;
	}
	var o = WSDOM.Util.copyObject(tObj);
	for(var i in o) {
		this.prototype[i] = o[i];
	}
};

/* Used to be 'hitch'.  Now it works right. */
Function.prototype.Context = function(obj) {
	var fnReference = this;
	return function () {
		return typeof fnReference == "function" ? fnReference.apply(obj, arguments) : obj[fnReference].apply(obj, arguments);
	};
};
Function.prototype.EmptyFunction = function() {};




WSDOM = new function() {
	var loadedClasses = {};
	var usingReferences = [];

	this.defineClass = function(className, superClass, constructor) {
		loadedClasses[className] = constructor;

		if (null != superClass) {
			loadedClasses[className].Extend(superClass);
		}

		// both classes and instances should have references to their names
		loadedClasses[className].prototype.getClassName = function() {
			return className;
		};
		loadedClasses[className].getClassName = loadedClasses[className].prototype.getClassName;

		return loadedClasses[className];
	};

	this.loadClass = function(className) {
		var classDef = parseClassName(className);

		var o = this.getClass(classDef.className);
		if (o) {
			this[o.getClassName()] = o;
			this[o.getClassName()].prototype.namespace = classDef.namespace;
			this[o.getClassName()].prototype.version = classDef.version;
		};
	};

	this.loadSingleton = function(className) {
		var classDef = parseClassName(className);

		var o = this.getClass(classDef.className);
		if (o) {
			this[o.getClassName()] = new o();
			this[o.getClassName()].namespace = classDef.namespace;
			this[o.getClassName()].version = classDef.version;
		};
	};

	this.getClass = function(className) {
		return loadedClasses[className];
	};

	this.getLoadedClasses = function() {
		return loadedClasses;
	};

	this.using = function(originatingClassName, className) {
		usingReferences.push({originatingClassName:originatingClassName, className:className});
	}


	this._processUsingReferences = function() {

		var usingErrors = false;
		for (var x = 0; x < usingReferences.length; x++) {

			var originatingClassName = usingReferences[x].originatingClassName;
			var className = usingReferences[x].className;
			var classDef = parseClassName(className);

			if (!this[classDef.className]) {
				if (this.Console) {
					this.Console.warn("Missing class definition for " + className + ".  Called from " + originatingClassName + ".");
				};
				usingErrors = true;
			} else if (this[classDef.className].version != classDef.version) {
				if (this.Console) {
					this.Console.warn("Version incompatibility for loaded class, " + classDef.className + "." + this[classDef.className].version + ", versus requested class, version " + classDef.version + ".  Called from " + originatingClassName + ".");
				};
				usingErrors = false;
			};

		};
		if (!usingErrors) {
			this.Console.log("WSDOM Framework loaded successfully.");
		};
	};




	/* Light-weight 'onload' for management of 'using' statements */
	this._onload = function() {
		var element = window;
		var eventType = "load";
		var fnHandler = this._processUsingReferences.Context(this);

		if (element.addEventListener) {
			// firefox
			element.addEventListener(eventType, fnHandler, false);
		}
		else if (element.attachEvent) {
			// ie
			element.attachEvent("on" + eventType, fnHandler);
		};
	};
	this._onload();


	function parseClassName(className) {
		var tokens = className.split('.');

		var classDef = {
			namespace:tokens[0],
			className:tokens[1],
			version:tokens[2]
		};

		return classDef;
	};



	this.identity = function(x) { return x };

}();

WSDOM.using("WSDOM", "WSDOM.Console.1");



function msToJsDate(msDate){var jO=new Date(((msDate-25569)*86400000));var tz=jO.getTimezoneOffset();var jO=new Date(((msDate-25569+(tz/(60*24)))*86400000));return jO;}
function jsToMsDate(jsdate) {
	var timezoneOffset=jsdate.getTimezoneOffset()/(60*24);
	var msDateObj=(jsdate.getTime()/86400000)+(25569 - timezoneOffset);
	return msDateObj;
}



/*
Please note:
This is an exact duplicate of asplib/standardlib/recurseObject.asp
with the opening/closing tags stripped out.  Please remember to keep
the ASP and JS versions in sync.

*/

/*
recurseObject(myObject)
Displays formatted properties of an object either server side or client side

Optional properties when passing argument with Object notation
o - object to debug
n - name of object for reference
i - ignore ..showdebuginfo.. - true will still run even if show debug info is not on (Server Side Only).
l - levels to recurse down - int|true - default 15 - true sets no limit
f - show functions - true|false|text - text will show actual function text
t - true/false - to output raw text with no HTML - useful when using Firebug or other HTTP Response tools that don't render HTML
c - color for referencing multiple objects - examples: "red" or "#f00" or "random".
inline - client side only.  Will document.write rather than write to the popup
w/h - client side only. Width and height of popup window
dbg - client side only - true will use JS Debugger (debug.js) window for output rather than the recurseObject popup
firebug/console - output to firebug's consolue (requires Firebug 0.4 or later)
buffer - server side only - surrounds output in JavaScript block comments as to not interfere with Content Buffer ouput
textarea - server side only - surrounds output in <textarea> tags and forces raw text output. This combination is useful for reading output in both a buffered window, and in Firebug's "Response" tab. 
r|nowrite - return results only, don't write anything to the screen (useful for displaying at a later time)
autohide - shows only name of object.  Mouseover to expand.  Click to lock open
clear - clear popup or debug window first
autohide/collapse - wraps output in a click to expand/collapse container.

Example usage (server side or client side):

recurseObject(myObject); // no optional properties, use defaults
recurseObject({o:myObject,n:"My Object",l:5}); // 5 levels down
recurseObject({o:myObject,n:"My Object",c:"green"}); // highlight in green
recurseObject({o:myObject,f:true,t:1}); // show functions and display raw text output
recurseObject({o:myObject,i:1,buffer:1}); // ignore showdebuginfo and output buffer safe content

Use client side by first including this somewhere in your document (note: replace ! with % below)

<script type="text/javascript">
<! recurseObjectClientSide(); !>
</script>

*/

function recurseObject(props) {

	if (typeof props != "object") {
		return;
	}
	if (!props.o) {
		var obj = props;
		props = {o:obj};
	}

	var serverSide = (typeof document == "undefined");

	var showDebugInfoOn = !serverSide ? true : (User.Session("Secure.Flags.ShowDebugInfo") == "on");
	var ignoreShowDebugInfo = props.i || false;
	var objName = props.n || props.name || "Object";
	var bColor = props.c || props.color || "black";
	if (bColor == "random") {
		var colors = ["red","blue","black","green","orange"];
		bColor = colors[(Math.round(Math.random()*(colors.length-1)))];
	}
	var displayText = props.d || props.display || props.text || props.t || false;
	var obj = props.o || props.object || null;
	var showFunctions = props.f || props.functions || false;
	var recurseLevel = props.l || props.level || 15;
	var width = props.w || 500;
	var height = props.h || 500;
	var element = props.element || null;
	var inline = props.inline || false;
	var useDbg = props.debug || props.dbg || false;
	var useFireBug = props.firebug || props.console || false;
		if (useFireBug) { displayText = true; }
	var clearWindow = props.clear || false;

	var returnOnly = props.r || props.nowrite || false;
	var autoHide = (props.autohide && !displayText) || false;

	var contentBuffer = props.buffer || false;
	var textarea = props.textarea || false;
		if (textarea) {
			displayText = true;
			if (textarea === true || (isNaN(textarea) && !/%/.test(textarea))) { textarea = "400px"; }
			if (!isNaN(textarea)) { textarea += "px"; }
		}


	var rand = "Random"+Math.round(Math.random()*100000);


	var outputVals = [];

	function show(obj) {
 		outputVals = [];
		if (typeof obj == "undefined") { outputVals = "recurseObject: Object not defined"; }
		else { recurse(obj); }
		return output();

	}

	function recurse(obj,level) {
		var l = level || 0;
	
		if (l == 0 && typeof obj == "string") {
			displayText = true;
			outputVals.push(obj)
		}
		for (var i in obj) {

			if (typeof obj[i] == "function" && !showFunctions) {
				continue;
			}
			outputVals.push((displayText ?  (indention(l)+i) : ("<blockquote "+((l == 0) ? "style='margin-left:0px;' " : "")  + ">" + "<b>" + i + "</b>")) + " (" + (typeof obj[i]).charAt(0) + (obj[i] && (typeof obj[i] == "object" && obj[i] instanceof Array) ? (":Array("+obj[i].length+")"):"") + "): " + ((typeof obj[i] == "function" && showFunctions != "text") ? "Function" : (!typeof obj[i] == "function" && obj[i] instanceof Object || obj[i] instanceof Array)?"":obj[i])+"\n");
			if (obj[i] && typeof obj[i] != "string" && (recurseLevel === true || l < recurseLevel)) {
				recurse(obj[i],(l+1));
			}
			outputVals.push(displayText ? "" : "</blockquote>");
		}
	}

	function output() {

		var outputTitle = objName + ((!serverSide) ? " (Client Side) " : " (Server Side)");
		var outputS = (displayText) ? ((outputTitle+"\n"+outputVals.join(""))) : ("<hr /><style>div.recurseObject { background:#fefefe; font-size:11px; text-align:left;} pre.recurseObject { white-space:normal; } div.recurseObject blockquote {margin:0px;margin-left:35px;border-bottom:1px solid #EEE;padding-left:5px;} div#recurseObject"+rand+" blockquote {border-left:1px solid "+bColor+";} </style><div id='recurseObject"+rand+"' class='recurseObject'>\n<div style='background:#fcfcfc; padding:2px; border:2px solid "+bColor+"'>"+objName+((!serverSide) ? " (Client Side) " : " (Server Side)")+"</div>\n<pre class='recurseObject'>"+outputVals.join("")+"</pre></div>");

		if (textarea) {
			outputS = "<br /><textarea class='recurseObject' style='width:99%;height:"+textarea+"'>\n" + outputS + "</textarea><br />\n";
		}

		if (autoHide) {
			outputS = "<div style=\"padding:4px; border:1px dashed "+bColor+";\"><div style=\"overflow:hidden; height:1.2em;\">\
			 <div style='cursor:pointer;margin-right:5px;' title='Click to Expand/Collapse' onclick=\"var ROOpen = this.getAttribute('open'); this.parentNode.style.height = ROOpen?'1.2em':'auto'; this.parentNode.style.overflow=ROOpen?'hidden':'auto'; this.parentNode.parentNode.style.borderStyle = ROOpen?'dashed':'solid'; this.setAttribute('open',ROOpen?'':'yes'); \" />\
				"+outputTitle+"</div>\
				"+outputS+"\
			</div></div>";
		}

		if (contentBuffer) {
			outputS = "/*\n"+outputS+"\n*/";
		}

		if (!returnOnly) {
			if (serverSide) { // Server side JScript
				Response.write(outputS);
			}
			else { // Client side JavaScript
				if (inline) {
					document.write("<hr />"+outputS);
				}
				else if (element) {
					try {
						
						if (typeof element == "string") element = document.getElementById(element);
						element.innerHTML += "<hr />"+outputS;
					}
					catch(e) {}
				}
				else if (useDbg) {
					try {
						if (clearWindow) {
							Debug.debugWindow._sdb.clear(null,null,{ pane: "console" })
						}
						dbg(outputS);
					}
					catch(e) {}
				}
				else if (useFireBug) {
					try {
						console.log(outputS);
					}
					catch(e) {}
				}
				else {

					if (!window.dWindow || window.dWindow.closed) { // +Math.round(Math.random()*1000)
						dWindow = window.open('','recurseObject','width='+width+',height='+height+',top=0,left=0,scrollbars=1,resizable=1');
					}
					if (clearWindow) {
						dWindow.document.close();
						dWindow.document.open()
					}
					dWindow.rand = rand;

					//	dWindow.document.write("<a style='position:absolute;top:0px;right:0px;background:#fff;border:1px solid black;font-size:12px;padding:3px;' href='javascript:void(0);' onclick='document.body.innerHTML = \"\";'>Clear Window</a>");
					dWindow.document.write("<hr />"+(new Date)+outputS);
					
					try {
						// scroll to object div
						var dTop = dWindow.document.getElementById("recurseObject"+rand).offsetTop;dWindow.window.scrollTo(0,1000000);
						dWindow.window.scrollTo(0,dTop-40);
					}
					catch(e) {
						dWindow.window.scrollTo(0,1000000)
					}
				}
			}
		}
		return outputS;
		outputVals = [];
		
	}

	function indention(level) {
		var indents = [];
		for (var i=0;i<level;i++) { indents.push("\t") }
		//for (var i=0;i<level;i++) { indents.push("    ") }
		return indents.join("");
	}


	if (serverSide && (ignoreShowDebugInfo || showDebugInfoOn)) { // Server side JScript
		return show(obj)
	}	
	else if (!serverSide && (ignoreShowDebugInfo || showDebugInfoOn)) { // Client side JavaScript
		return show(obj);
	}

	return "";

}

function recurseObjectClientSide() {

	var recurseObjectFunction = recurseObject.toString();

	if (User.Session("Secure.Flags.ShowDebugInfo") == "on") {
		recurseObjectFunction = recurseObjectFunction.replace("var showDebugInfoOn = false;","var showDebugInfoOn = true;");
		Response.write("\n"+recurseObjectFunction+"\n\n");
	}
	else {
		Response.write("\nfunction recurseObject() { \n\/\/please turn on debug or include client side version\n }\n\n");
	}

}



Console_class = function () {
	this._isEnabled = false;

	this._origConsole;
	if (("console" in window) && ("firebug" in console)) {
		this._origConsole = console;
	};

	//delete console;
	//console = null;

	/*this.enable(); // attach all of the firebug methods, so that things don't blow up when we're disabled
	this.disable(); // now, disable everything by default.  We'll re-enable manually, or through showdebuginfo*/

	this._stub();
};

Console_class.prototype.enable = function() {

	if (!this._origConsole && (!("console" in window) || !("firebug" in console))) {
		this._origConsole = this._createBackupConsole();
	};

	/* Firebug's console is a closed instance of a class, so we can't extend from its prototype.  We'll do it by hand instead */
	for (var i in this._origConsole) {
		if (!i.match(/firebug/i)) {
			this[i] = this._origConsole[i];
		};
	};
	i = null;
	delete i;

	/* Now, rename some of the methods that are poorly named */
	delete this.group;
	delete this.groupEnd;
	this.startGroup = this._origConsole.group;
	this.endGroup = this._origConsole.groupEnd;

	delete this.time;
	delete this.timeEnd;
	this.startTime = this._origConsole.time;
	this.endTime = this._origConsole.timeEnd;


};
Console_class.prototype.disable = function() {
	for (var i in this) {
		// Stub all functions, except those prototyped on (we kinda need them)
		if (typeof this[i] == "function" && !this.constructor.prototype[i]) {
			this[i] = function() {};
		};
	};
};
Console_class.prototype._stub = function() {
	var methods = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd", "clear", "open", "close", "startGroup", "endGroup", "startTime", "endTime"];

	for (var x = 0; x < methods.length; x++) {
		this[methods[x]] = function() {};
	};

};
Console_class.prototype.link = function() {
	if(arguments.length == 2){
		var description = arguments[0];
		var link = arguments[1];
	} else if(arguments.length == 1) {
		var description = '';
		var link = arguments[0];
	} else {
		return false;
	}
	var a = document.createElement('a');
		a.setAttribute('href', link);
	this.log(description, a);
}
Console_class.prototype._createBackupConsole = function() {
	var backupConsole = new function(){
			this.log = function()
	        {
	            logFormatted(arguments, "");
	        }

	        this.link = this.log

	        this.debug = function()
	        {
	            logFormatted(arguments, "debug");
	        }

	        this.info = function()
	        {
	            logFormatted(arguments, "info");
	        }

	        this.warn = function()
	        {
	            logFormatted(arguments, "warning");
	        }

	        this.error = function()
	        {
	            logFormatted(arguments, "error");
	        }

	        this.assert = function(truth, message)
	        {
	            if (!truth)
	            {
	                var args = [];
	                for (var i = 1; i < arguments.length; ++i)
	                    args.push(arguments[i]);

	                logFormatted(args.length ? args : ["Assertion Failure"], "error");
	                throw message ? message : "Assertion Failure";
	            }
	        }

	        this.dir = function(object)
	        {
	            var html = [];

	            var pairs = [];
	            for (var name in object)
	            {
	                try
	                {
	                    pairs.push([name, object[name]]);
	                }
	                catch (exc)
	                {
	                }
	            }

	            pairs.sort(function(a, b) { return a[0] < b[0] ? -1 : 1; });

	            html.push('<table>');
	            for (var i = 0; i < pairs.length; ++i)
	            {
	                var name = pairs[i][0], value = pairs[i][1];

	                html.push('<tr>',
	                '<td class="propertyNameCell"><span class="propertyName">',
	                    escapeHTML(name), '</span></td>', '<td><span class="propertyValue">');
	                appendObject(value, html);
	                html.push('</span></td></tr>');
	            }
	            html.push('</table>');

	            logRow(html, "dir");
	        }

	        this.dirxml = function(node)
	        {
	            var html = [];

	            appendNode(node, html);
	            logRow(html, "dirxml");
	        }

	        this.group = function()
	        {
	            logRow(arguments, "group", pushGroup);
	        }

	        this.groupEnd = function()
	        {
	            logRow(arguments, "", popGroup);
	        }

	        this.time = function(name)
	        {
	            timeMap[name] = (new Date()).getTime();
	        }

	        this.timeEnd = function(name)
	        {
	            if (name in timeMap)
	            {
	                var delta = (new Date()).getTime() - timeMap[name];
	                logFormatted([name+ ":", delta+"ms"]);
	                delete timeMap[name];
	            }
	        }

	        this.count = function()
	        {
	            this.warn(["count() not supported."]);
	        }

	        this.trace = function()
	        {
	            this.warn(["trace() not supported."]);
	        }

	        this.profile = function()
	        {
	            this.warn(["profile() not supported."]);
	        }

	        this.profileEnd = function()
	        {
	        }

	        this.clear = function()
	        {
	            consoleBody.innerHTML = "";
	        }

	        this.open = function()
	        {
	            toggleConsole(true);
	        }

	        this.close = function()
	        {
	            if (frameVisible)
	                toggleConsole();
	        }

	    // ********************************************************************************************

	    var consoleFrame = null;
	    var consoleBody = null;
	    var commandLine = null;

	    var frameVisible = false;
	    var messageQueue = [];
	    var groupStack = [];
	    var timeMap = {};

	    var clPrefix = ">>> ";

	    var isFirefox = navigator.userAgent.indexOf("Firefox") != -1;
	    var isIE = navigator.userAgent.indexOf("MSIE") != -1;
	    var isOpera = navigator.userAgent.indexOf("Opera") != -1;
	    var isSafari = navigator.userAgent.indexOf("AppleWebKit") != -1;

	    // ********************************************************************************************

	    function toggleConsole(forceOpen)
	    {
	        frameVisible = forceOpen || !frameVisible;
	        if (consoleFrame)
	            consoleFrame.style.visibility = frameVisible ? "visible" : "hidden";
	        else
	            waitForBody();
	    }

	    function focusCommandLine()
	    {
	        toggleConsole(true);
	        if (commandLine)
	            commandLine.focus();
	    }

	    function waitForBody()
	    {
	        if (document.body)
	            createFrame();
	        else
	            setTimeout(waitForBody, 200);
	    }

	    function createFrame()
	    {
	        if (consoleFrame)
	            return;

	        window.onFirebugReady = function(doc)
	        {
	            window.onFirebugReady = null;

	            var toolbar = doc.getElementById("toolbar");
	            toolbar.onmousedown = onSplitterMouseDown;

	            commandLine = doc.getElementById("commandLine");
	            addEvent(commandLine, "keydown", onCommandLineKeyDown);

	            addEvent(doc, isIE || isSafari ? "keydown" : "keypress", onKeyDown);

	            consoleBody = doc.getElementById("log");
	            layout();
	            flush();
	        }

	        var baseURL = window._WSDOM_Console_URL || "/includes/jslib/WSDOM/firebug";

	        consoleFrame = document.createElement("iframe");
	        consoleFrame.setAttribute("src", baseURL+"/firebug.html");
	        consoleFrame.setAttribute("frameBorder", "0");
	        consoleFrame.style.visibility = (frameVisible ? "visible" : "hidden");
	        consoleFrame.style.zIndex = "2147483647";
	        consoleFrame.style.position = "fixed";
	        consoleFrame.style.width = "100%";
	        consoleFrame.style.left = "0";
	        consoleFrame.style.bottom = "0";
	        consoleFrame.style.height = "200px";
	        document.body.appendChild(consoleFrame);
	    }

	    function getFirebugURL()
	    {
	        var scripts = document.getElementsByTagName("script");
	        for (var i = 0; i < scripts.length; ++i)
	        {
	            if (scripts[i].src.indexOf("firebug.js") != -1)
	            {
	                var lastSlash = scripts[i].src.lastIndexOf("/");
	                return scripts[i].src.substr(0, lastSlash);
	            }
	        }
	    }

	    function evalCommandLine()
	    {
	        var text = commandLine.value;
	        commandLine.value = "";

	        logRow([clPrefix, text], "command");

	        var value;
	        try
	        {
	            value = eval(text);
	        }
	        catch (exc)
	        {
	        }

	        WSDOM.Console.log(value);
	    }

	    function layout()
	    {
	        var toolbar = consoleBody.ownerDocument.getElementById("toolbar");
	        var height = consoleFrame.offsetHeight - (toolbar.offsetHeight + commandLine.offsetHeight);
	        consoleBody.style.top = toolbar.offsetHeight + "px";
	        consoleBody.style.height = height + "px";

	        commandLine.style.top = (consoleFrame.offsetHeight - commandLine.offsetHeight) + "px";
	    }

	    function logRow(message, className, handler)
	    {
	        if (consoleBody)
	            writeMessage(message, className, handler);
	        else
	        {
	            messageQueue.push([message, className, handler]);
	            waitForBody();
	        }
	    }

	    function flush()
	    {
	        var queue = messageQueue;
	        messageQueue = [];

	        for (var i = 0; i < queue.length; ++i)
	            writeMessage(queue[i][0], queue[i][1], queue[i][2]);
	    }

	    function writeMessage(message, className, handler)
	    {
	        var isScrolledToBottom =
	            consoleBody.scrollTop + consoleBody.offsetHeight >= consoleBody.scrollHeight;

	        if (!handler)
	            handler = writeRow;

	        handler(message, className);

	        if (isScrolledToBottom)
	            consoleBody.scrollTop = consoleBody.scrollHeight - consoleBody.offsetHeight;
	    }

	    function appendRow(row)
	    {
	        var container = groupStack.length ? groupStack[groupStack.length-1] : consoleBody;
	        container.appendChild(row);
	    }

	    function writeRow(message, className)
	    {
	        var row = consoleBody.ownerDocument.createElement("div");
	        row.className = "logRow" + (className ? " logRow-"+className : "");
	        row.innerHTML = message.join("");
	        appendRow(row);
	    }

	    function pushGroup(message, className)
	    {
	        logFormatted(message, className);

	        var groupRow = consoleBody.ownerDocument.createElement("div");
	        groupRow.className = "logGroup";
	        var groupRowBox = consoleBody.ownerDocument.createElement("div");
	        groupRowBox.className = "logGroupBox";
	        groupRow.appendChild(groupRowBox);
	        appendRow(groupRowBox);
	        groupStack.push(groupRowBox);
	    }

	    function popGroup()
	    {
	        groupStack.pop();
	    }

	    // ********************************************************************************************

	    function logFormatted(objects, className)
	    {
	        var html = [];

	        var format = objects[0];
	        var objIndex = 0;

	        if (typeof(format) != "string")
	        {
	            format = "";
	            objIndex = -1;
	        }

	        var parts = parseFormat(format);
	        for (var i = 0; i < parts.length; ++i)
	        {
	            var part = parts[i];
	            if (part && typeof(part) == "object")
	            {
	                var object = objects[++objIndex];
	                part.appender(object, html);
	            }
	            else
	                appendText(part, html);
	        }

	        for (var i = objIndex+1; i < objects.length; ++i)
	        {
	            appendText(" ", html);

	            var object = objects[i];
	            if (typeof(object) == "string")
	                appendText(object, html);
	            else
	                appendObject(object, html);
	        }

	        logRow(html, className);
	    }

	    function parseFormat(format)
	    {
	        var parts = [];

	        var reg = /((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/;
	        var appenderMap = {s: appendText, d: appendInteger, i: appendInteger, f: appendFloat};

	        for (var m = reg.exec(format); m; m = reg.exec(format))
	        {
	            var type = m[8] ? m[8] : m[5];
	            var appender = type in appenderMap ? appenderMap[type] : appendObject;
	            var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);

	            parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1));
	            parts.push({appender: appender, precision: precision});

	            format = format.substr(m.index+m[0].length);
	        }

	        parts.push(format);

	        return parts;
	    }

	    function escapeHTML(value)
	    {
	        function replaceChars(ch)
	        {
	            switch (ch)
	            {
	                case "<":
	                    return "&lt;";
	                case ">":
	                    return "&gt;";
	                case "&":
	                    return "&amp;";
	                case "'":
	                    return "&#39;";
	                case '"':
	                    return "&quot;";
	            }
	            return "?";
	        };
	        return String(value).replace(/[<>&"']/g, replaceChars);
	    }

	    function objectToString(object)
	    {
	        try
	        {
	            return object+"";
	        }
	        catch (exc)
	        {
	            return null;
	        }
	    }

	    // ********************************************************************************************

	    function appendText(object, html)
	    {
	        if (objectToString(object).match(/href/gi)) {
	        	html.push(objectToString(object));
	        } else {
	        	 html.push(escapeHTML(objectToString(object)));
	        }
	    }

	    function appendNull(object, html)
	    {
	        html.push('<span class="objectBox-null">', escapeHTML(objectToString(object)), '</span>');
	    }

	    function appendString(object, html)
	    {
	        html.push('<span class="objectBox-string">&quot;', escapeHTML(objectToString(object)),
	            '&quot;</span>');
	    }

	    function appendInteger(object, html)
	    {
	        html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
	    }

	    function appendFloat(object, html)
	    {
	        html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
	    }

	    function appendFunction(object, html)
	    {
	        var reName = /function ?(.*?)\(/;
	        var m = reName.exec(objectToString(object));
	        var name = m ? m[1] : "function";
	        html.push('<span class="objectBox-function">', escapeHTML(name), '()</span>');
	    }

	    function appendObject(object, html)
	    {
	        try
	        {
	            if (object == undefined)
	                appendNull("undefined", html);
	            else if (object == null)
	                appendNull("null", html);
	            else if (typeof object == "string")
	                appendString(object, html);
	            else if (typeof object == "number")
	                appendInteger(object, html);
	            else if (typeof object == "function")
	                appendFunction(object, html);
	            else if (object.nodeType == 1)
	                appendSelector(object, html);
	            else if (typeof object == "object")
	                appendObjectFormatted(object, html);
	            else
	                appendText(object, html);
	        }
	        catch (exc)
	        {
	        }
	    }

	    function appendObjectFormatted(object, html)
	    {
	        var text = objectToString(object);
	        var reObject = /\[object (.*?)\]/;

	        var m = reObject.exec(text);
	        html.push('<span class="objectBox-object">', m ? m[1] : text, '</span>')
	    }

	    function appendSelector(object, html)
	    {
	        html.push('<span class="objectBox-selector">');

	        html.push('<span class="selectorTag">', escapeHTML(object.nodeName.toLowerCase()), '</span>');
	        if (object.id)
	            html.push('<span class="selectorId">#', escapeHTML(object.id), '</span>');
	        if (object.className)
	            html.push('<span class="selectorClass">.', escapeHTML(object.className), '</span>');

	        html.push('</span>');
	    }

	    function appendNode(node, html)
	    {
	        if (node.nodeType == 1)
	        {
	            html.push(
	                '<div class="objectBox-element">',
	                    '&lt;<span class="nodeTag">', node.nodeName.toLowerCase(), '</span>');

	            for (var i = 0; i < node.attributes.length; ++i)
	            {
	                var attr = node.attributes[i];
	                if (!attr.specified)
	                    continue;

	                html.push('&nbsp;<span class="nodeName">', attr.nodeName.toLowerCase(),
	                    '</span>=&quot;<span class="nodeValue">', escapeHTML(attr.nodeValue),
	                    '</span>&quot;')
	            }

	            if (node.firstChild)
	            {
	                html.push('&gt;</div><div class="nodeChildren">');

	                for (var child = node.firstChild; child; child = child.nextSibling)
	                    appendNode(child, html);

	                html.push('</div><div class="objectBox-element">&lt;/<span class="nodeTag">',
	                    node.nodeName.toLowerCase(), '&gt;</span></div>');
	            }
	            else
	                html.push('/&gt;</div>');
	        }
	        else if (node.nodeType == 3)
	        {
	            html.push('<div class="nodeText">', escapeHTML(node.nodeValue),
	                '</div>');
	        }
	    }

	    // ********************************************************************************************

	    function addEvent(object, name, handler)
	    {
	        if (document.all)
	            object.attachEvent("on"+name, handler);
	        else
	            object.addEventListener(name, handler, false);
	    }

	    function removeEvent(object, name, handler)
	    {
	        if (document.all)
	            object.detachEvent("on"+name, handler);
	        else
	            object.removeEventListener(name, handler, false);
	    }

	    function cancelEvent(event)
	    {
	        if (document.all)
	            event.cancelBubble = true;
	        else
	            event.stopPropagation();
	    }

	    function onError(msg, href, lineNo)
	    {
	        var html = [];

	        var lastSlash = href.lastIndexOf("/");
	        var fileName = lastSlash == -1 ? href : href.substr(lastSlash+1);

	        html.push(
	            '<span class="errorMessage">', msg, '</span>',
	            '<div class="objectBox-sourceLink">', fileName, ' (line ', lineNo, ')</div>'
	        );

	        logRow(html, "error");
	    };

	    function onKeyDown(event)
	    {
	        if (event.keyCode == 123)
	            toggleConsole();
	        else if ((event.keyCode == 108 || event.keyCode == 76) && event.shiftKey
	                 && (event.metaKey || event.ctrlKey))
	            focusCommandLine();
	        else
	            return;

	        cancelEvent(event);
	    }

	    function onSplitterMouseDown(event)
	    {
	        if (isSafari || isOpera)
	            return;

	        addEvent(document, "mousemove", onSplitterMouseMove);
	        addEvent(document, "mouseup", onSplitterMouseUp);

	        for (var i = 0; i < frames.length; ++i)
	        {
	            addEvent(frames[i].document, "mousemove", onSplitterMouseMove);
	            addEvent(frames[i].document, "mouseup", onSplitterMouseUp);
	        }
	    }

	    function onSplitterMouseMove(event)
	    {
	        var win = document.all
	            ? event.srcElement.ownerDocument.parentWindow
	            : event.target.ownerDocument.defaultView;

	        var clientY = event.clientY;
	        if (win != win.parent)
	            clientY += win.frameElement ? win.frameElement.offsetTop : 0;

	        var height = consoleFrame.offsetTop + consoleFrame.clientHeight;
	        var y = height - clientY;

	        consoleFrame.style.height = y + "px";
	        layout();
	    }

	    function onSplitterMouseUp(event)
	    {
	        removeEvent(document, "mousemove", onSplitterMouseMove);
	        removeEvent(document, "mouseup", onSplitterMouseUp);

	        for (var i = 0; i < frames.length; ++i)
	        {
	            removeEvent(frames[i].document, "mousemove", onSplitterMouseMove);
	            removeEvent(frames[i].document, "mouseup", onSplitterMouseUp);
	        }
	    }

	    function onCommandLineKeyDown(event)
	    {
	        if (event.keyCode == 13)
	            evalCommandLine();
	        else if (event.keyCode == 27)
	            commandLine.value = "";
	    }

	    window.onerror = onError;
	    addEvent(document, isIE || isSafari ? "keydown" : "keypress", onKeyDown);

	    //if (document.documentElement.getAttribute("debug") == "true")
	        toggleConsole(true);
	}();

	return backupConsole;
};

WSDOM.defineClass("Console", null, Console_class);
WSDOM.loadSingleton("WSDOM.Console.1");



var EventSource = function(type) {
	this.listeners = [];
	this.type = type;
};

EventSource.prototype.addListener = function(listener, context) {
	if (listener instanceof Function) {
		listener = {
			handler: listener,
			context: context
		}
	}

	if (!listener.context) {
		listener.context = window;
	}
	this.listeners.push(listener);
	return listener;
};

EventSource.prototype.removeListener = function(listener) {
	for (var i=0; i<this.listeners.length; i++) {
		if (listener == this.listeners[i]) {
			this.listeners.splice(i,1);
		}
	}
};

EventSource.prototype.removeAll = function() {
	this.listeners = [];
};

EventSource.prototype.fire = function() {
	Array.prototype.unshift.call(arguments, this.type);

	for (var i=0; i<this.listeners.length; i++) {
		this.listeners[i].handler.apply(this.listeners[i].context, arguments);
	}
};

var DOMEventSource = function(type) {
	DOMEventSource.Super(this, null, arguments);
	this.delayTimeouts = [];
	this.typeIE = "on" + this.type;
	this.elements = [];
};
DOMEventSource.Extend(EventSource);

DOMEventSource.prototype._getBrowserEventName = function() {
	switch (this.type) {
		case "load": 	case "change": 	case "reset":
		case "select":	case "submit": 	case "blur":
		case "focus": 	case "resize": 	case "scroll":
		case "abort":	case "error":	case "unload":
			return "HTMLEvents";

		case "mouseover": 	case "mouseout": 	case "click":
		case "dblclick":  	case "mouseup": 	case "mousedown":
		case "mouseenter": 	case "mouseleave":	case "mousemove":
		case "contextmenu": case "dragstart":	case "selectstart":
			return "MouseEvents";

		case "keypress": case "keydown": case "keyup":
			return "UIEvents";

		default:
			return null;
	}
};

DOMEventSource.prototype._validateEvent = function(e, listener){
	if (listener.keyCode && "UIEvents" == this._getBrowserEventName()) {
		return listener.keyCode == e.nativeEvent.keyCode;
	}
	
	return true;
};

DOMEventSource.prototype._createDOMHandlerClosure = function(listener, element) {
	var theDOMEventSource = this;
	for (var i=0, DOMHandler; i<element.length; i++) {
		DOMHandler = function() {
			var el = element[i].node;
			if (listener.delay) {
				return function() {
					var e = window.event || arguments[0];
					
					// because browsers rewrite values after event goes out of scope
					var newEvt = {};
					for (var i in e) {
						newEvt[i] = e[i];
					}
					
					e = new DOMEvent(newEvt);
					
					theDOMEventSource.clearDelayTimeouts();
					theDOMEventSource.delayTimeouts.push(window.setTimeout(
						function() {
							if(theDOMEventSource._validateEvent(e, listener)){
								listener.handler.call(listener.context, e, el, listener.data);
							}
						}
					, listener.delay));
				}
			}
			else {
				return function() {
					var e = new DOMEvent(window.event || arguments[0]);
					if(theDOMEventSource._validateEvent(e, listener)){
						listener.handler.call(listener.context, e, el, listener.data);
					}
				}
			}
		}();

		this._addEventListener(element[i].node, DOMHandler);
		element[i].registeredListeners.push({ DOMHandler: DOMHandler, listener: listener });
	}
};

DOMEventSource.prototype.addElement = function(element /* element or array of elements */, removeIfExisting) {
	if (!(element instanceof Array)) {
		element = [element];
	}

	if (removeIfExisting) {
		this.removeElement(element);
	}

	var elements = [];
	for (var i=0; i<element.length; i++) {
		elements.push({
			node: element[i],
			registeredListeners: []
		});
	}

	for (var i=0; i<this.listeners.length; i++) {
		this._createDOMHandlerClosure(this.listeners[i], elements);
	}

	this.elements = this.elements.concat(elements);
};

DOMEventSource.prototype.removeElement = function(element) {
	var element = [].concat(element);

	for (var i=0, elWrapper; i<this.elements.length; i++) {
		elWrapper = this.elements[i];
		
		if (!element.length) {
			break;
		}
		
		for (var j=0, el; j<element.length; j++) {
			el = element[j];
			
			if (elWrapper.node === el) {
				
				for (var k=0; k<elWrapper.registeredListeners.length; k++) {
					this._removeEventListener(el, elWrapper.registeredListeners[k].DOMHandler);
				}
				
				element.splice(j, 1);
				this.elements.splice(i, 1);
				
				j--;
				i--;
			}
		}
	}

};

DOMEventSource.prototype.removeAll = function() {
	this.removeAllElements();
	this.listeners = [];
};

DOMEventSource.prototype.removeAllElements = function() {
	for (var i=0, el; i<this.elements.length; i++) {
		el = this.elements[i];
		
		for (var j=0; j<el.registeredListeners.length; j++) {
			this._removeEventListener(el.node, el.registeredListeners[j].DOMHandler);
		}
	}
	this.elements = [];
};

DOMEventSource.prototype.addListener = function(listener, context, delay) {
	if (listener instanceof Function) {
		listener = {
			handler: listener,
			context: context,
			delay: delay
		}
	}
	
	if (!listener.context) {
		listener.context = window;
	}
	
	this._createDOMHandlerClosure(listener, this.elements);
	
	this.listeners.push(listener);
	return listener;
};

DOMEventSource.prototype.removeListener = function(listener) {
	for (var i=0, el; i<this.elements.length; i++) {
		el = this.elements[i];
		
		for (var j=0, rl; j<el.registeredListeners.length; j++) {
			rl = el.registeredListeners[j];

			if (rl.listener == listener) {
				this._removeEventListener(el.node, rl.DOMHandler);
				el.registeredListeners.splice(j, 1);
				break;
			}
		}
	}

	for (var i=0, listener; i<this.listeners.length; i++) {
		if (listener == this.listeners[i]) {
			this.listeners.splice(i, 1);
			break;
		}
	}
};

DOMEventSource.prototype.fire = function(element /* optional element or array of elements */) {
	if (undefined == element) {
		// fire on all elements
		for (var i=0; i<this.elements.length; i++) {
			this._dispatchEvent(this.elements[i].node);
		}
	}
	else {
		if (!(element instanceof Array)) {
			element = [element];
		}

		for (var i=0; i<element.length; i++) {
			this._dispatchEvent(element[i]);
		}
	}
};

DOMEventSource.prototype._addEventListener = function(el, handler) {
	if (document.attachEvent) {
		DOMEventSource.prototype._addEventListener = function(el, handler) {
			el.attachEvent(this.typeIE, handler);
		};
	}
	else if (document.addEventListener) {
		DOMEventSource.prototype._addEventListener = function(el, handler) {
			el.addEventListener(this.type, handler, false);
		};
	}
	this._addEventListener = DOMEventSource.prototype._addEventListener;
	this._addEventListener(el, handler);
};

DOMEventSource.prototype._removeEventListener = function(el, handler) {
	if (el.detachEvent) {
		DOMEventSource.prototype._removeEventListener = function(el, handler) {
				el.detachEvent(this.typeIE, handler);
		};
	}
	else if (el.removeEventListener) {
		DOMEventSource.prototype._removeEventListener = function(el, handler) {
			el.removeEventListener(this.type, handler, false);
		};
	}
	this._removeEventListener = DOMEventSource.prototype._removeEventListener;
	this._removeEventListener(el, handler);
};

DOMEventSource.prototype._dispatchEvent = function(el) {
	if (document.createEventObject) {
		DOMEventSource.prototype._dispatchEvent  = function(el) {
			var event = document.createEventObject();
				event.srcElement = el;
				event.type = this.type;

			el.fireEvent(this.typeIE, event);
		};
	}
	else {
		DOMEventSource.prototype._dispatchEvent = function(el) {
			var event = document.createEvent(this._getBrowserEventName(this.type));
				event.initEvent(this.type, true, true);

			el.dispatchEvent(event);
		};
	}
	this._dispatchEvent = DOMEventSource.prototype._dispatchEvent;
	this._dispatchEvent(el);
};

DOMEventSource.prototype.clearDelayTimeouts = function() {
	for (var i=0; i<this.delayTimeouts.length; i++) {
		window.clearTimeout(this.delayTimeouts[i]);
	}
	this.delayTimeouts = [];
};


var DOMEvent = function(nativeEvent) {
	this.nativeEvent = nativeEvent;
};

DOMEvent.prototype.cancel = function() {
	if (this.nativeEvent.stopPropagation) {
		this.nativeEvent.stopPropagation();
	}
	else {
		try { this.nativeEvent.cancelBubble = true; } catch(e) {}
	}
	if (this.nativeEvent.preventDefault) {
		this.nativeEvent.preventDefault();
	}
	else {
		try { this.nativeEvent.returnValue = false; } catch(e) {}
	}


	return this.nativeEvent;
};

DOMEvent.prototype.getTarget = function() {
	var target = this.nativeEvent.srcElement || this.nativeEvent.target;

	this.getTarget = function() {
		return target;
	}
	return this.getTarget();
};

var EventManager = function() {
	this.events = [];
	this.add(window, "unload", this.removeAll, this);
};

EventManager.prototype.KEYCODES = {
	Backspace:8
	,TAB:9
	,ENTER:13
	,SHIFT:16
	,CTRL:17
	,ALT:18
	,CAPS:20
	,ESCAPE:27
	,PAGEUP:33
	,PAGEDOWN:34
	,END:35
	,HOME:36
	,LEFT:37
	,UP:38
	,RIGHT:39
	,DOWN:40
	,INSERT:45
	,DELETE:46
	,SPACE:32
	,COMMAND:224
}

EventManager.prototype.add = function(element /* | or object | or customType */, type, handler, context, data, delay, keyCode) {
	if (arguments.length > 1) {
		var inputs = {
			element: element,
			type: type,
			handler: handler,
			context: context,
			data: data,
			delay: delay,
			keyCode:keyCode
		}
	}
	else if (arguments[0] instanceof Object) {
		var inputs = arguments[0];
	}
	else {
		var inputs = {
			type: arguments[0]
		}
	}

	var listener = { handler: inputs.handler, context: inputs.context, delay: inputs.delay, data: inputs.data, keyCode:inputs.keyCode };

	if (this._isDomEventType(inputs.type)) {
		var e = this._addDOMEvent(inputs.type, listener, inputs.element);
	}
	else {
		var e = this._addCustomEvent(inputs.type, listener);
	}
	this.events.push(e);
	return e;
};

EventManager.prototype._isDomEventType = function (type) {
	if (null == DOMEventSource.prototype._getBrowserEventName.apply({type: type})) {
		return false;
	}
	return true;
};


EventManager.prototype._addDOMEvent = function(type, listener, element) {
	var e = new DOMEventSource(type);
	if (listener.handler) {
		e.addListener(listener);
	}
	if (element) {
		e.addElement(element);
	}
	return e;
};

EventManager.prototype._addCustomEvent = function(type, listener) {
	var e = new EventSource(type);
	if (listener.handler) {
		e.addListener(listener);
	}
	return e;
};

EventManager.prototype.remove = function(e /*element  or event */, listener /*listener or eventType*/) {
	/* Method refactored, as it supports 'new' mode (remove the event+listener) and 'old' mode (remove the event from the element by eventType)*/
	if (e instanceof EventSource) {
		this._removeEvent(e, listener);
	}
	else if (e.nodeName || e instanceof Array) {
		this._removeElement(e, listener);
	}
};

EventManager.prototype._removeEvent = function(e, listener) {
	if (undefined == listener) {
		e.removeAll();
	} else {
		e.removeListener(listener);
	}
	for (var i=0; i<this.events.length; i++) {
		if (e == this.events[i]) {
			this.events.splice(i, 1);
			break;
		}
	}
};
EventManager.prototype._removeElement = function(el, eventType) {
	for (var i=0, event; i<this.events.length; i++) {
		event = this.events[i];
		if (event instanceof DOMEventSource) {
			if (!eventType || (event.type == eventType)) {
				event.removeElement(el);
			}
		}
	}
};

EventManager.prototype.removeAll = function() {
	for (var i=0; i<this.events.length; i++) {
		this.events[i].removeAll();
	}
	this.events = [];
};

EventManager.prototype.cancel = function(e) {
	if(!e) { return; }

	if (e instanceof DOMEvent) {
		e.cancel();
	}
	else if (e.srcElement || e.target) {
		DOMEvent.prototype.cancel.apply({nativeEvent: e});
	}
};

if (window["WSDOM"]) {
	WSDOM.defineClass("Events", null, EventManager);
	WSDOM.loadSingleton("WSDOM.Events.3");
} else {
	var Events = new EventManager(); // backwards compatibility with Events.2
}




/*

############################
Current Differences between WSDOM/Element and jslib/Element
Please maintain these when updating this file:

- Create references WSDOM.Events and looks for that as the property name
- Create's children parameter is looped through, while jslib/Element only calls addChild 

############################

Element.3.js
A library to handle DOM Elements

Documentation at http://dev2.wallst.com/playground/docs/
	and 		 http://wiki.wsod.local/wsodwiki/index.php/Element.3.js_:Dev

Most functions take an element handle or an element's id as a string as the first parameter
"set" functions can also take an array of elements or ids.

Element.get - returns a handle on an element
Element.create - extension of document.createElement. 2nd parameter is properties, 3rd parameter is children.
Element.addChild - appends an element to an element
Element.remove - remove an element from the DOM
Element.setDisplay - sets display: property of element(s)
Element.setVisibility - sets visibility: property of element(s)
Element.remove - removes element(s) from DOM
Element.setHTML - set innerHTML value of element(s).  Optional 3rd parameter to append content
Element.parseSelector - returns list of elements that match CSS selector string
Element.forEach - accepts a CSS selector or array of elements and iterates on each element
Element.setStyle - an inline way to set multiple style properties of an element - example: Element.setStyle(el,"border:2px solid red;width:400px;background:#888;");
Element.removeChildNodes - remove all nodes within an element
Element.cloneNode - extension of el.cloneNode that strips all DOM events
Element.insertBefore - keeps the Element syntax in your code
Element.insertAfter - because the DOM only offers insertBefore
Element.nextElement - returns next sibling of indicated tagname
Element.previousElement - returns previous sibling of indicated tagname
Element.getParent - returns the first parent element of a certain tag name
Element.getXY - returns an {x:,y:} object of an element's position relative to the html body
Element.setXY - set an element(s) position
Element.getSize - returns an {width:,height:} object of an element's total size
Element.getSizeXY  - returns an {x:,y:} object of an element's total size
Element.setSize - set the size of an element(s)
Element.setWidth - set the width of an element(s)
Element.setHeight - set the height of an element(s)
Element.getBorderSize - returns the current border size

Element.addClass  - adds a class attribute
Element.removeClass - removes a class attribute
Element.toggleClass - reverses a class attribute
Element.switchClass - takes a 3rd parameter boolean to turn on/off a class attribute
Element.hasClass - returns if an element is part of a class
Element.getStyle

//////////////////////////
Element Extras (separate file Element.3extras.js)
Element.isInsideOf
Element.isInsideOfNS
Element.isInsideOfEW
Element.debug
Element.setOpacity
Element.setDisabled
Element.setAttribute - same functionality as el.setAttribute but accepts an array of elements
Element.setProperty - sets a JavaScript property to a single or array of elements
Element.getParentBySelector - like getParent but with CSS Selector support
Element.isOnScreen - returns if an element is rendered on the screen.  Traverses up the DOM and checks .display and .visibility
*/

/**
 * @class Element contains functions for working with the DOM in a cross-browser way.  
 * See also: <a href="http://wiki.wsod.local/wsodwiki/index.php/Element.3.js_:Dev">http://wiki.wsod.local/wsodwiki/index.php/Element.3.js_:Dev</a>
 * @static 
 */
var Element_class = function() {

}

// -------------------------------------------------------
// 	DOM Helpers
// -------------------------------------------------------

/**
 * Returns a handle on an element with the specified ID
 * @param {String|| Number} el 
 * @return {element} Native DOM element if found
 */
Element_class.prototype.get = function(el) {
	if (typeof el == "string" || typeof el == "number") el = document.getElementById(el);
	return el;
};

/**
 * Element.create can be used in a variety of ways to create a new HTML element and (optionally) insert it into the DOM
 * @example var el = WSDOM.Element.create("div",{className:"primary",style:"color:red;font-weight:bold;"},"Default Text",document.body) 
 * 
 * @param {String} tag Element tag name such as 'div'
 * @param {Object} [attributes] Element attributes object literal, such as {id:'container3',className:'container'}  Note that 'class' is a reserved word, 
 * 		   be sure to use 'className' to set CSS classes
 * @param {Object || String} [children] Element or String text node to add as children
 * @param {Object} [parent] Element to append newly created node to (optional)
 * @param {Object} [ElementObjectInstance]
 * @return {element} Newly created native DOM element
 */
Element_class.prototype.create = function (tag, attributes, children, parent, ElementObjectInstance) {

	var element = document.createElement(tag);

	// mapping for IE specific attributes
	var attributeMap = {
		"for":["htmlFor"],
		"colspan":["colSpan"],
		"usemap":["useMap"]
	}

	for (var i in attributes)
	{
		if (i == "className" || i == "class")
		{
			element.className = attributes[i];
		}
		else if (document.all && attributeMap[i])
		{
			for (var j = 0; j <attributeMap[i].length; j++) {
				element.setAttribute(attributeMap[i][j], attributes[i]);
			}
			element.setAttribute(i, attributes[i]); // retain original
		}
		else if (i == "style")
		{
			this.setStyle(element,attributes[i]);
		}
		else if (i == "WSDOM.Events" || i == "Events")
		{
			if (typeof WSDOM.Events != "undefined") {
				var elEvents = attributes[i];
				if (!this.isArray(elEvents)) {
					elEvents = [elEvents]
				}

				for (var j = 0; j < elEvents.length; j++) {
					elEvents[j].element = element;
					WSDOM.Events.add(elEvents[j]);
				}
			}
			else {
				//alert(":: DEV ERROR :: \n Location: Element.3.js -- Element_class.prototype.create \n Type: Dependency \n Message: Expecting Events Lib for use of Events in Element.create")
			}
		}
		else
		{
			element.setAttribute(i, attributes[i]);
		};
	};

	// <map> also needs an ID to work correctly
	if (tag.match(/^map$/i) && attributes && attributes.name && !attributes.id) {
		element.setAttribute("id", attributes.name);
	}

	if (arguments.length > 2 && children != undefined && children !== "") {

		// Retain this looping as certain sites have already implemented embedded arrays of objects
		if (typeof children == "object" && children.constructor == Array)
		{
			for (var i = 0; i < children.length; i++)
			{
				this.addChild(element, children[i]);
			};
		}
		else
		{
			this.addChild(element, children);
		};
	};

	if (parent) {
		this.addChild(parent,element);
	}

	return (ElementObjectInstance) ? new ElementObject(element) : element;
};

/**
 * Append an element to another element
 * @param {element} el Parent
 * @param {element || string} child Element or text to append
 */
Element_class.prototype.addChild = function (el, child) {
	el = this.get(el);

	if (!this.isArray(child)) {
		child = [child]
	}
	for (var i=0; i<child.length; i++) {
		if (typeof child[i] == "object") {
			el.appendChild(child[i]);
		}
		else if (typeof child[i] == "string" || typeof child[i] == "number") {
			// element.appendChild(document.createTextNode(children));
			el.innerHTML += child[i];
		};
	}

};



/**
 * Remove an element(s) from the DOM
 * @param {element || string} el Element handle or ID to remove
 */
Element_class.prototype.remove = function(el) {
	el = this.get(el);

	if (!this.isArray(el)) {
		el = [el]
	}
	for (var i=0; i<el.length; i++) {
		el[i].parentNode.removeChild(el[i])
	}
};

/**
 * Sets the display property of an element to the specified value
 * @param {element || array || string} el Element, array of elements, or ID of desired element
 * @param {Object} d 
 */
Element_class.prototype.setDisplay = function(el,d) {

	el = this.get(el);

	if (!this.isArray(el)) {
		el = [el]
	}
	for (var i=0; i<el.length; i++) {
		el[i].style.display = d;
	}
};

/**
 * Sets the visibility property of a desired element
 * @param {element || array || string} el Element, array of elements, or ID of element
 * @param {Object} d
 */
Element_class.prototype.setVisibility = function(el,d) {
	el = this.get(el);

	if (!this.isArray(el)) {
		el = [el]
	}
	for (var i=0; i<el.length; i++) {
		el[i].style.visibility = d;
	}
};


/**
 * Remove all nodes under a specified element
 * @param {element || string} el Element handle or ID of element
 */
Element_class.prototype.removeChildNodes = function(el) {

	el = this.get(el);

	while (el.childNodes.length) {
		el.removeChild(el.firstChild);
	}
	return el;

};

/**
 * An extension of the native cloneNode() which also strips DOM events
 * @param {element} el Element(s) to clone
 * @param {Object} cloneChildren
 */
Element_class.prototype.cloneNode = function(el, cloneChildren) {
	//prevents IE from cloning events
	var cloneChildNodes = (cloneChildren) ? cloneChildren : false;

	if (document.all) {

		var node = el.outerHTML;

		if (cloneChildNodes && el.innerHTML) {
			node.innerHTML = el.innerHTML;
		}

		var container = document.createElement("DIV");
		container.innerHTML = node;

		node = container.firstChild;

	} else {
		var node = el.cloneNode(cloneChildNodes);
	}

	return node;

};

/**
 * Find the first parent with a given tag name
 * @param {Object} el
 * @param {Object} tag
 * @param {Object} includeSelf
 */
Element_class.prototype.getParent = function(el, tag, includeSelf) {

	var el = this.get(el);

	if (!tag) { tag = el.tagName; }

	if (!includeSelf && el.parentNode) { // grab immediate parent
		el = el.parentNode;
	}

	if (el.tagName && el.tagName.match(/^BODY$/i) && !tag.match(/^BODY$/i)) {
		return null;
	}

	if (el.nodeType == 1 && el.tagName.toLowerCase() == tag.toLowerCase()) {
		return el;
	}
	else {
		return this.getParent(el.parentNode, tag, true);
	}
}



/**
 * Set the innerHTML of a node, the optional third parameter allows you to append rather than overwrite
 * @param {element} el Parent node to set 
 * @param {string} v innerHTML string
 * @param {boolean} [appendV] If true, append, else overwrite 
 */
Element_class.prototype.setHTML = function(el,v,appendV) {
	el = this.get(el);

	if (!this.isArray(el)) {
		el = [el]
	}
	for (var i=0; i<el.length; i++) {
			el[i].innerHTML = (appendV) ? (el[i].innerHTML+v) : v;
	}
};

/**
 * parseSelector finds and elements based on the selector string.  You can match based on tag name, attributes, and styles, as well as stack selectors.
 * See <a href="http://wiki.wsod.local/wsodwiki/index.php/Element.parseSelector:Dev">http://wiki.wsod.local/wsodwiki/index.php/Element.parseSelector:Dev</a> 
 * for much more info. 
 * @example WSDOM.Element.parseSelector('tr.highlight', myTable);             // returns all TRs belonging to class highlight within myTable
WSDOM.Element.parseSelector('input[type="checkbox"]', myForm);    // returns all check boxes
WSDOM.Element.parseSelector('div[position=..'absolute'] ', myDiv);   // returns all divs with absolute positioning
 * @param {string} selector The selector string to search for
 * @param {element} [node] The parent element to search under.  It is important to try and specify as small a subset of the DOM as possible by 
 * 		   setting this parent element, as running parseSelector on the entire DOM can get quite slow
 * @param {string || number} [specific] This will allow you to return a specific element from the matched list, 
 * 		   valid options are "first", "last", or any number for the nth match
 */
Element_class.prototype.parseSelector = function() {

	var context = this;
	var SEPERATOR = /\s*,\s*/;
	
	function parseSelector(selector, node, num) {

		node = node || document.documentElement;
		node = this.get(node);

		var argSelectors = selector.split(SEPERATOR);
		var result = [];
		
		for(var i = 0; i < argSelectors.length; i++) {

			// if the selector starts with #, we can use getElementById to improve performance
			// only do this if we're searching from the root (selectors like '.myDiv #myEl' don't make much sense,
			// but should still work as expected).
			if(node == document.documentElement) {
				var matches = argSelectors[i].match(/^\s*#([^\s.:@[~+>]*)\s+(.*)$/); // check for simple #id
				if(matches) {
					node = document.getElementById(matches[1]) || [];
					argSelectors[i] = matches[2];
				}
			}

			var stream = toStream(argSelectors[i]), prevToken;

			if (this.isArray(node)) {
				var nodes = node;
				// remove * and " " put in by toStream if it starts with a non alphanumeric
				if (!argSelectors[i].match(/^[A-Za-z1-9]/)) {
					while (stream[0] && stream[0].match(/[* ]/)) { stream.shift(); }
				}
			}
			else {
				var nodes = [node]
			}

			for(var j = 0;j < stream.length;) {

				var token = stream[j++];

				var args = '';
				if (token == "[") {
					args = stream[j];
					while(stream[j++] != ']' && j < stream.length) { args += stream[j] };
					args = args.slice(0, -1);
					var filter = "";
				}
				else {
					var filter = stream[j++];
				}

				if(stream[j] == '(') {
					while(stream[j++] != ')' && j < stream.length) args += stream[j];
					args = args.slice(0, -1);
				}

				prevToken = token;
				nodes = select(nodes, token, filter, args);
			}
			result = result.concat(nodes);
		}
		
		// simple selection of an individual node
		  if (num != undefined) {

			if (result.length) {
				var REMatch;

				if (num == "first") {
					return result[0]
				}
				else if (num == "last") {
					return result[result.length-1]
				}
				else if (REMatch = String(num).match(/nth\((.*)\)/) || num == "even") { // even is the same as nth(2)
					if (num == "even") num = 2;
					else num = REMatch[1];

					var result2 = [];
					for (var i=0,len=result.length; i<len;i++) {
						if (i%num == 0) { result2.push(result[i]); }
					}
					return result2;
				}
				else if (num == "odd") {
					var result2 = [];
					for (var i=0,len=result.length; i<len;i++) {
						if (i%2 != 0) { result2.push(result[i]); }
					}
					return result2;
				}
				else if (!isNaN(num) && result.length >= num) {
					return result[num]
				}
				else {
					return null; // num passed, but no matches or unsupported type
				}
			}
			else {
				return null;
			}

		  }

		return result;
	}

	var WHITESPACE = /\s*([\s>+~(),]|^|$)\s*/g;
	var IMPLIED_ALL = /([\s>+~,]|[^(]\+|^)([#.:@])/g;
	var STANDARD_SELECT = /^[^\s>+~]/;
	var STREAM = /[\s#.:>+~[\]()@!]|[^\s#.:>+~[\]()@!]+/g;

	function toStream(selector) {
		var stream = selector
			.replace(WHITESPACE, '$1')
			.replace(IMPLIED_ALL, '$1*$2');
		if(STANDARD_SELECT.test(stream)) {
			stream = ' ' + stream;
		}
		return stream.match(STREAM) || [];
	}

	function select(nodes, token, filter, args) {
		return (selectors[token]) ? selectors[token](nodes, filter, args) : [];
	}

	var util = {
		toArray: function(enumerable) {
			var a = [];
			for(var i = 0; i < enumerable.length; i++) a.push(enumerable[i]);
			return a;
		},

		push: function(arr,val) {
			arr.push(val)
      		//for(var i = 1; i < arguments.length; i++) arr[arr.length] = arguments[i];
      		return arr.length;
    	}
	};

	var dom = {
		isTag: function(node, tag) {
			return (tag == '*') || (
				tag.toLowerCase() == node.nodeName.toLowerCase().replace(':html', '')
			);
		},

		previousSiblingElement: function(node) {
			do node = node.previousSibling; while(node && node.nodeType != 1);
			return node;
		},

		nextSiblingElement: function(node) {
			do node = node.nextSibling; while(node && node.nodeType != 1);
			return node;
		},

		hasClass: function(name, node) {
			return (node.className || '').match('(^|\\s)'+name+'(\\s|$)');
		},

		getByTag: function(tag, node) {
			/*	IE5.x does not support document.getElementsByTagName("*")
				therefore we're falling back to element.all */
			if(tag == '*') {
			  var nodes = node.getElementsByTagName(tag);
			  if(nodes.length == 0 && node.all != null) return node.all
			  return nodes;
		  }
			return node.getElementsByTagName(tag);
		}
	};

	var selectors = {
		'#': function(nodes, filter) {
			for(var i = 0; i < nodes.length; i++) {
				if(nodes[i].getAttribute('id') == filter) return [nodes[i]];
			}
			return [];
		},

		' ': function(nodes, filter) {
			var result = [];
			for(var i = 0; i < nodes.length; i++) {
				result = result.concat(util.toArray(dom.getByTag(filter, nodes[i])));
			}
			return result;
		},

		'>': function(nodes, filter) {
			var result = [];
			for(var i = 0, node; i < nodes.length; i++) {
				node = nodes[i];
				for(var j = 0, child; j < node.childNodes.length; j++) {
					child = node.childNodes[j];
					if(child.nodeType == 1 && dom.isTag(child, filter)) {
						result.push(child);
					}
				}
			}
			return result;
		},

		'.': function(nodes, filter) {
			var result = [];
			for(var i = 0, node; i < nodes.length; i++) {
				node = nodes[i];
				if(dom.hasClass([filter], node)) result.push(node);
			}
			return result;
		},

		'!': function(nodes, filter) {
			var result = [];
			for(var i = 0, node; i < nodes.length; i++) {
				node = nodes[i];
				if(!dom.hasClass([filter], node)) result.push(node);
			}
			return result;
		},

		':': function(nodes, filter, args) {
			return (pseudoClasses[filter]) ? pseudoClasses[filter](nodes, args) : [];
		},


		'+': function(nodes, filter) {
			var result = [];
			for(var i = 0, node; i < nodes.length; i++) {
				node = nodes[i];
				var sibling = parseSelector.dom.nextSiblingElement(node);
				if(sibling && parseSelector.dom.isTag(sibling, filter)) {
					result.push(sibling);
				}
			}
			return result;
		},
		'~': function(nodes, filter) {
			var result = [];
			for(var i = 0, node; i < nodes.length; i++) {
				node = nodes[i];
				var sibling = parseSelector.dom.previousSiblingElement(node);
				if(parseSelector.dom.isTag(sibling, filter)) result.push(sibling);
			}


			return result;
		},
		'[': function(nodes, filter, args) { // CSS Attribute
			args = args.replace(/'/g,'"'); // allow single quotes

			var attributeProps = [];
			if (!/[<>=]/.test(args)) { // has operator test
				attributeProps = ["",args,"",""];
			}
			else {
				var params = args.match(/([^!^$*\/.<>=]*)(!\*=|\*=|\$=|!\$=|\^=|\/=|!\/=|<=|>=|<|>|!=|=)(\.*)(i?)(["'`])([^\5]*)(\5)/);
									//   (attName)       (operator)                                 (type)   (caseinsenstive)[quote](value)[quote]
				if (params) { attributeProps = params; }
			}

			//alert(attributeProps )
			attributeProps = {name:attributeProps[1],operator:attributeProps[2],isStyle:attributeProps[3]=="..",isProperty:attributeProps[3]==".",casei:attributeProps[4]?true:false,value:attributeProps[6],isValue:(attributeProps[5]=="`")};

			// Leave this line for debuging purposes
			//alert(args + "\n att: " + attributeProps.name + "\n operator: " + attributeProps.operator + "\n val: "  + attributeProps.value + "\n isStyle: " + attributeProps.isStyle + "\n isProperty: " + attributeProps.isProperty + "\n isValue: " + attributeProps.isValue + "\n casei: "  + attributeProps.casei)

			if (attributeProps.casei) { attributeProps.value = attributeProps.value.toLowerCase(); }

			var result = [];
			for(var i = 0, node, att, val, el; i < nodes.length; i++) {
				node = el = nodes[i];

				if (attributeProps.isStyle) {
					att = context.getStyle(node,attributeProps.name);
					if (!att) continue;
				}
				else if (attributeProps.isProperty) {
					if (node[attributeProps.name] != undefined) {
						var att = node[attributeProps.name];
					}
					else {
						continue;
					}
				}
				else {
					att = node.getAttribute(attributeProps.name);
					if (!att) continue;
				}

				if (/[*^$\/]/.test(attributeProps.operator)) { // so .match complies
					att = String(att)
				}

				if (attributeProps.casei) { att = att.toLowerCase(); }

				val = attributeProps.value;

				//alert("Tag: " + el.tagName + ", ID: " + el.id + " , Att: " + att + ", Operator: " + attributeProps.operator + ", Val: " + val);
				if (attributeProps.isValue) { val = eval(val.replace(/`/g,"'")); }

				if (!attributeProps.operator) {
					result.push(nodes[i])
				}
				else {


					switch(attributeProps.operator){
						case '=': if (att == val) result.push(node); break;
						case '!=': if (att != val) result.push(node); break;
						case '*=': if (att.match(val)) result.push(node); break;
						case '!*=': if (!att.match(val)) result.push(node); break;
						case '^=': if (att.match('^'+val)) result.push(node); break;
						case '!^=': if (!att.match('^'+val)) result.push(node); break;
						case '$=': if (att.match(val+'$')) result.push(node); break;
						case '!$=': if (!att.match(val+'$')) result.push(node); break;
						case '/=': if (att.match(val)) result.push(node); break;
						case '!/=': if (!att.match(val)) result.push(node); break;
						case '>=': if (att >= val) result.push(node); break;
						case '>': if (att > val) result.push(node); break;
						case '<=': if (att <= val) result.push(node); break;
						case '<': if (att < val) result.push(node); break;
					}
				}
			}
			return result;

		}

	};

	parseSelector.selectors			= selectors;
	var pseudoClasses = { };
	parseSelector.pseudoClasses 			= pseudoClasses;
	parseSelector.util 				  = util;
	parseSelector.dom 				  = dom;
	return parseSelector.apply(this,arguments);
};

/*---------------------------------
	is -
	Is an element a selector?
----------------------------------*/

Element_class.prototype.is = function( domNode, selector, parent, propagate ) {

	parent = parent || domNode.parentNode;
	
	var queriedEls = this.parseSelector(selector, parent);
		
	var  i
		,l = queriedEls.length;
	
	while(domNode && domNode !== parent) {
		
		for(i = 0; i < l; i++) {
			if(domNode === queriedEls[i]) {
	
				return true;
			}
		}
		if(propagate) {
			domNode = domNode.parentNode;
			continue;
		}
		break;
	}
	return false;
};

Element_class.prototype.forEach = function(el, callback, context) {

	var returnEls = [];

	if (typeof el == "string") {
		el = this.parseSelector(el);
	}
	else if (!this.isArray(el)) {
		el = [el]
	}

	var success;

	for (var i=0,elLen = el.length; i<elLen; i++) {
		success = context ? callback.call(context,el[i],i,el) : callback(el[i],i,el)
		if (success === false) {
			break;
		}
		returnEls.push(el[i]);
	}

	return returnEls;
}

/**
 * Insert an element before another
 * @param {Object} el
 * @param {Object} sibling
 */
Element_class.prototype.insertBefore = function (el, sibling) {

	el = this.get(el);	if (!el) return;

	sibling = this.get(sibling);

	if (!el || !sibling || !sibling.parentNode)
	{
		return null;
	};

	sibling.parentNode.insertBefore(el, sibling);
};

/**
 * Insert an element after another
 * @param {element} el
 * @param {Object} sibling
 */
Element_class.prototype.insertAfter = function (el, sibling) {

	el = this.get(el);	if (!el) return;

	sibling = this.get(sibling);

	if (!el || !sibling || !sibling.parentNode)
	{
		return null;
	};

	return sibling.nextSibling ? sibling.parentNode.insertBefore(el, sibling.nextSibling) : sibling.parentNode.appendChild(el);
};

//2006-02-16 AR - fixed this so that an null tagName would return the next element
/**
 * Returns the next sibling of a given tagname
 * @param {element} el
 * @param {string} tagName
 * @return {element} The next sibling
 */
Element_class.prototype.nextElement = function(el, tagName) {
	tagName = tagName ? String(tagName).toLowerCase() : null;

	var sibling = this.get(el);
	while(sibling = sibling.nextSibling) {
		if (sibling.nodeType == 1 && ( tagName == null || sibling.tagName.toLowerCase() == tagName ) ) {
			return sibling;
		}
	}
	return null;
}

//2006-02-16 AR - added previousElement
/**
 * Returns the previous sibling of a given tagname
 * @param {element} el
 * @param {string} tagName
 * @return {element} The previous sibling
 */
Element_class.prototype.previousElement = function(el, tagName) {
	tagName = tagName ? String(tagName).toLowerCase() : null;
	var sibling = this.get(el);
	while(sibling = sibling.previousSibling) {
		if (sibling.nodeType == 1 && ( tagName == null || sibling.tagName.toLowerCase() == tagName ) ) {
			return sibling;
		}
	}
	return null;
}

/**
 * Gets the {x: , y: } pair of coordinates for the element relative to the body
 * @param {Object} el
 * @return {Object} {x: , y: } object coordinate position
 */
Element_class.prototype.getXY = function(el) {

	el = this.get(el);	if (!el) return;

	var x = 0, y = 0;

	while (el.offsetParent) {
		x += el.offsetLeft;
		y += el.offsetTop;
		el = el.offsetParent;
	}

	return { x: x, y: y };
};

/**
 * Sets the position of an element relative to the body
 * @param {element} el
 * @param {number} x
 * @param {number} y
 */
Element_class.prototype.setXY = function(el, x, y) {

	el = this.get(el);	if (!el) return;

	if (!this.isArray(el)) {
		el = [el]
	}
	for (var i=0; i<el.length; i++) {
		if (x !== null) el[i].style.left = x + "px";
		if (y !== null) el[i].style.top = y + "px";
	}
};

/**
 * Gets the {width:, height:} object of the element's total size
 * @param {element} el
 * @return {object} {width: height:} size object
 */
Element_class.prototype.getSize = function(el) {

	el = this.get(el);	if (!el) return;

	var height = el.offsetHeight;
	var width = el.offsetWidth;

	return { height: height, width: width };
};

// more useful if in same units as pos
/**
 * Gets the {x: width, y: height} representation of the element's total size
 * @param {element} el
 * @return {object} {x: , y:} size representation
 */
Element_class.prototype.getSizeXY = function(el) {
	var size = this.getSize(el);
	return {x: size.width, y: size.height};
};

/**
 * Sets the size of an element(s)
 * @param {element} el
 * @param {number} width pixel number
 * @param {number} height pixel number
 */
Element_class.prototype.setSize = function(el, width, height) {

	el = this.get(el);	if (!el) return;

	if (!this.isArray(el)) {
		el = [el]
	}
	for (var i=0; i<el.length; i++) {
		this.setWidth(el[i], width);
		this.setHeight(el[i], height);
	}
};

Element_class.prototype.setWidth = function(el, width) {

	el = this.get(el);	if (!el) return;

	if (!this.isArray(el)) {
		el = [el]
	}
	for (var i=0; i<el.length; i++) {
		el[i].style.width = width + "px";
	}
};

Element_class.prototype.setHeight = function(el, height) {

	el = this.get(el);	if (!el) return;

	if (!this.isArray(el)) {
		el = [el]
	}
	for (var i=0; i<el.length; i++) {
		el[i].style.height = height + "px";
	}
};

Element_class.prototype.getBorderSize = function(el) {

	el = this.get(el);

	var height = el.offsetHeight - el.clientHeight;
	var width = el.offsetWidth - el.clientWidth;

	return { height: height, width: width };
}


// -------------------------------------------------------
//  className modifications
// -------------------------------------------------------

/**
 * Changes the className of an element, the optional third parameter will allow you to remove the className
 * @param {element} el
 * @param {string} classname
 * @param {boolean} [b]
 */
Element_class.prototype.switchClass = function(el, classname, b) {

	el = this.get(el);	if (!el) return;

	if (!this.isArray(el)) {
		el = [el]
	}

	if (b) {
		this.addClass(el, classname);
	}
	else {
		this.removeClass(el, classname);
	}

	if (el.length) {
		return el[0].className;
	}

};

/**
 * Removes a CSS class and replaces it with a new class
 * @param {element} el 
 * @param {string} sClassNameOld Old class to remove
 * @param {string} sClassNameNew New class to add
 * @param {boolean} bConditional
 */
Element_class.prototype.replaceClass = function(el, sClassNameOld, sClassNameNew, bConditional) {

	el = this.get(el);	if (!el) return;

	if (!this.isArray(el)) {
		el = [el]
	}

	if(bConditional) {

		for(var i=0;i<el.length;i++) {

			if(this.hasClass(el[i],sClassNameOld)) {

				this.removeClass(el[i],sClassNameOld);
				this.addClass(el[i],sClassNameNew);

			}

		}

	} else{

		this.removeClass(el, sClassNameOld);
		this.addClass(el, sClassNameNew);

	}

	if (el.length) {
		return el[0].className;
	}

};

/**
 * Append a CSS class to an element
 * @param {element} el
 * @param {string} classname
 */
Element_class.prototype.addClass = function(el, classname) {

	el = this.get(el);	if (!el) return;

	if (!this.isArray(el)) {
		el = [el]
	}
	for (var i=0; i<el.length; i++) {
		if (!this.hasClass(el[i], classname)) {
    			el[i].className += (el[i].className?" ":"") + classname;
		}
	}

	if (el.length) {
		return el[0].className;
	}
};

/**
 * Remove a CSS class from an element
 * @param {element} el
 * @param {string} classname
 */
Element_class.prototype.removeClass = function(el, classname) {

	el = this.get(el);

	if (!this.isArray(el)) {
		el = [el]
	}

	var re = this._getClassnameRegEx(classname);

	for (var i=0; i<el.length; i++) {
			el[i].className = el[i].className.replace(re, "$1$3");
	}

	if (el.length) {
		return el[0].className;
	}

};

/**
 * Removes a CSS class if it already exists on an element, else it adds it in
 * @param {element} el 
 * @param {string} classname
 */
Element_class.prototype.toggleClass = function(el, classname) {
	el = this.get(el);
	//alert(el.id)

	if (!this.isArray(el)) {
		el = [el]
	}

	for (var i=0; i<el.length; i++) {
		if (this.hasClass(el[i], classname)) {
			this.removeClass(el[i], classname);
		} else {
			this.addClass(el[i], classname);
		}
	}

	if (el.length) {
		return el[0].className;
	}
};

/**
 * Checks to see if a CSS class exists on an element
 * @param {Object} el
 * @param {Object} classname
 * @return {boolean}
 */
Element_class.prototype.hasClass = function(el, classname) {

	el = this.get(el);

	return (el.className && el.className.match(this._getClassnameRegEx(classname)) != null);
};

Element_class.prototype._getClassnameRegEx = function(classname) {
	return new RegExp("(\\s|^)(" + classname + ")(\\s|$)", "g")
};

// -------------------------------------------------------
//  style gets and sets
// -------------------------------------------------------

/**
 * Gets the computed style
 * @param {element} el
 * @param {string} styleProp
 */
Element_class.prototype.getStyle = function (el, styleProp) {

	el = this.get(el);	if (!el) return;

	if (document.defaultView && document.defaultView.getComputedStyle) { // Mozilla and Safari

		var computedStyle = document.defaultView.getComputedStyle(el, null);
		return (computedStyle) ? computedStyle.getPropertyValue(styleProp) : null;

	} else if (el.currentStyle) { // IE

		styleProp = styleProp.replace(/\-(.)/g, function () {

			return arguments[1].toUpperCase();

		});

		return el.currentStyle[styleProp];

	}

	return null;

}

/**
 * Set the element's inline style with a css string
 * @param {element} el
 * @param {string} styles String style representation like 'width:200px; color: #CCC;'
 */
Element_class.prototype.setStyle = function (el, styles) {

	el = this.get(el);	if (!el) return;

	var pairs = [];
	styles = styles.split(";");
	for (var i=0; i<styles.length; i++) {
		//var nv = styles[i].split(":");
		var nv = styles[i].replace(":","{:}").split("{:}");
		if (nv.length > 1) {
			nv[0] = nv[0].replace(/\-(.)/g, function() {
				return arguments[1].toUpperCase();
			}).replace(/\s/g, "");
			pairs.push({n:nv[0],v:nv[1].replace(/^\s*|\s*$/g, "")});
		}
	}

	if (!this.isArray(el)) {
		el = [el]
	}

	var attributeMap = {
		"float":["cssFloat","styleFloat"]
	}

	for (var i=0; i<el.length; i++) {
		for (var j=0; j<pairs.length; j++) {
			if (attributeMap[pairs[j].n]) {
				for (var k = 0; k <attributeMap[pairs[j].n].length; k++) {
					pairs.push({n:attributeMap[pairs[j].n][k],v:pairs[j].v});
				}
			}
			el[i].style[pairs[j].n] = pairs[j].v;
		}
	}

}



// -------------------------------------------------------
// 	Element Helpers
// -------------------------------------------------------


Element_class.prototype.isArray = function(o) {
	return (o instanceof Array);
};


if (typeof WSDOM != "undefined") {
	WSDOM.using("WSDOM.Element.3", "WSDOM.Events.2");
	WSDOM.defineClass("Element", null, Element_class);
	WSDOM.loadSingleton("WSDOM.Element.3");
}
else {
	Element = new Element_class();
}




// ------------------------------------------------------------------------------------------------------------
/*
Documentation: http://barney.wallst.com/wsodwiki/index.php/Content_Buffer

ContentBuffer()
generic data buffering object

usage:

var c = new ContentBuffer();
c.load({
	url: "data.asp",
	method: "get",
	onload: a,
	debug: true
});

function a (connection) {
	alert("x:" + connection.getResult());
};

*/
// ------------------------------------------------------------------------------------------------------------



function Remoting_class()
{
	this.connections = [];
	this.connectionsMax = 100;
	this.connectionsActive = 0;
	this.connectionsPending = [];
	this.debug = false;
	this.context; // window default contexting moved to context implementations
	this.connectionId = 0;

	if (arguments.length && typeof arguments[0] == "object")
	{
		this.context = arguments[0];
	};
};

//Remoting_class.using("WSDOM.Serializer.3");

// ------------------------------------------------------------------------------------------------------------
// load(contentPackge)
/*

contentPackge:
	.url: page to load in the hidden buffer
	.onload: function reference that gets called on a successful buffer load [optional]
	.onerror: function reference that gets called on an unsuccessful buffer load [optional]
	.method: get|post [optional]
	.data: {name: value} list [optional]
	.[arbitrary]: optional arbitrary parameters that get passed to .callback; allows for state management with an asynch request

*/
// ------------------------------------------------------------------------------------------------------------
Remoting_class.prototype.load = function (contentPackage)
{

	// data validation
	try
	{
		contentPackage.method = contentPackage.method.toLowerCase();

		if (contentPackage.method != "get" && contentPackage.method != "post")
		{
			contentPackage.method = "post";
		};
	}
	catch (e)
	{
		contentPackage.method = "post";
	};

	if (!contentPackage.data)
	{
		contentPackage.data = {};
	};

	// enable cache flushing
	if (document.location.search.match(/\.\.nocache\.\.=on/i))
	{
		contentPackage.data["..nocache.."] = "on";
	};

	// pass debugchartsrv
	var dbgChartSrv = document.location.search.match(/\.\.debugchartsrv\.\.=([a-zA-Z]+)/i);
	if (dbgChartSrv) {
		contentPackage.data["..debugchartsrv.."] = dbgChartSrv[1];
	}

	if (contentPackage.protocolType && contentPackage.protocolType.toString().match(/JsonRPC/gi)) {
		return new JsonRPC_Connection_class(this, this.connectionId++, contentPackage);
	} else {
		return new Connection_class(this, this.connectionId++, contentPackage);
	}

};

// ------------------------------------------------------------------------------------------------------------
// loadXMLHTTP()
// ------------------------------------------------------------------------------------------------------------
Remoting_class.prototype._loadXMLHTTP = function (connection) {

    var thisConnection = connection;
    var contentPackage = thisConnection.contentPackage;

	function stateMonitor () {
		thisBuffer._monitorConnectionState(thisConnection);
	};

	this.connectionsActive++;

    /*
	if (!this.connections.length) {
		if (!this.initConnection()) {
			if (this.debug || contentPackage.debug) {
				dbg("ContentBuffer initialization error", "unsupported", "red");
			};
			return;
		};
	};
    */

	var dataPackage = null;
	var thisBuffer = this;

	thisConnection.active = true;
	//contentPackage.connectionId = this.connectionId++; // necessary?

	contentPackage.params = {};

	if (typeof contentPackage.contentType == "string") {
		contentPackage.params["..contenttype.."] = contentPackage.contentType;
	};

	if (this.debug || contentPackage.debug) {
		WSDOM.Console.startGroup("Remoting");
	};

	// uniquely identify contentbuffer requests
	contentPackage.params["..requester.."] = "ContentBuffer";

	if (contentPackage.method == "post") {

		dataPackage = "";

		WSDOM.Console.dir(contentPackage);
		dataPackage = "inputs=" + this.encode(WSDOM.Serializer.serialize(contentPackage.data));

		for (var i in contentPackage.params) {
			dataPackage += (dataPackage.length ? "&" : "") + this.encode(i) + "=" + this.encode(contentPackage.params[i]);
		};

		if (this.debug || contentPackage.debug) {
			WSDOM.Console.log("ContentBuffer post data", dataPackage);
		};

	} else {
		/*for (var i in contentPackage.data) {
			contentPackage.url += (contentPackage.url.indexOf("?") == -1 ? "?" : "&") + this.encode(i) + "=" + this.encode(contentPackage.data[i]);
		};*/

		contentPackage.url += (contentPackage.url.indexOf("?") == -1 ? "?" : "&") + "data=" + this.encode(WSDOM.Serializer.serialize(contentPackage.data));

	};

	if (this.debug || contentPackage.debug) {
		WSDOM.Console.log("ContentBuffer loading [" + thisConnection.connectionId + "]", contentPackage.url + " [" + contentPackage.method + "]");
	};

	if (this.debug || contentPackage.debug) {

		var debugUrl = contentPackage.url;

		if (dataPackage) {
			debugUrl += (debugUrl.indexOf("?") == -1 ? "?" : "&") + dataPackage;
		};

		debugUrl = debugUrl.replace(/\&?\.\.[^\=\&]*\.\.\=[^\&]*/g, "");

		if (debugUrl.indexOf("/") != 0 && debugUrl.indexOf("http") != 0) {
			var path = String(window.location).replace(/https*:\/\//, "");
			debugUrl = path.substr(path.indexOf("/"), path.lastIndexOf("/") + 1 - path.indexOf("/")) + debugUrl;
		}

		WSDOM.Console.link("ContentBuffer URL", debugUrl);
	};

	try {
		// netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
    		thisConnection.c.open(contentPackage.method.toUpperCase(), contentPackage.url, true);
		thisConnection.c.onreadystatechange = stateMonitor;
	} catch (e) {
		// alert(e);
	};

	if (contentPackage.method == "post") {
		thisConnection.c.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	};

	//thisConnection.contentPackage = contentPackage;
	//dbg(thisConnection.c.send(), "trying connectionId");

	thisConnection.c.send(dataPackage);

	if (this.debug || contentPackage.debug) {
		WSDOM.Console.endGroup("Remoting");
	};

	//return thisConnection;
};

// ------------------------------------------------------------------------------------------------------------
// monitorConnectionState()
// ------------------------------------------------------------------------------------------------------------
Remoting_class.prototype._monitorConnectionState = function (connection) {

	try {

		if (connection.c.readyState == 4) {

			if (connection.c.status != 200) {

				/*if (this.debug || connection.contentPackage.debug) {
					WSDOM.Console.log("ContentBuffer load error", connection.c.status, "red");
					WSDOM.Console.log("ContentBuffer result [" + connection.connectionId + "]", connection.c.responseText);
				};*/

				try {
					var result = connection.c.responseText;
				} catch (e) {
					var result = null;
				};

				connection.contentPackage.result = result;

				if (typeof connection.contentPackage.onerror == "function") {
					connection.contentPackage.onerror.apply(connection.context || window, [connection]);
				};

				return;
			};

			var responseType = connection.contentPackage.contentType || connection.c.getResponseHeader("Content-Type");
			var result = null;


			if (responseType.match(/text\/html/g) || responseType.match(/text\/plain/g)) {
				result = connection.c.responseText;
			} else if (responseType.match(/text\/xml/g)) {
				result = connection.c.responseXML;
			} else if (responseType.match(/text\/javascript/g)) {
				try {
					result = connection.c.responseText;

					if (!connection.contentPackage.preventEval) {

                       connection.context.__evalBuffer = function() {
                           eval(result);
                       }

                       connection.context.__evalBuffer();

					};


				} catch (e) {
					if (this.debug || connection.contentPackage.debug) {
						WSDOM.Console.error("Remoting javascript eval error", e.message);
						WSDOM.Console.dir(e);
						//if (typeof dbgObject != "undefined"){ dbgObject(e); }
					};
				};
			} else if (responseType.match(/application\/json/gi)) {
				try {
					result = connection.c.responseText;
					result = WSDOM.Serializer.deserialize(result);

				} catch (e) {
					if (this.debug || connection.contentPackage.debug) {

						WSDOM.Console.error("Remoting Serializer Error", e.message);
						//if (typeof dbgObject != "undefined"){ dbgObject(e); }
						WSDOM.Console.dir(e);
					};
				};
			};

			connection.contentPackage.result = result;

			if (this.debug || connection.contentPackage.debug) {
				// dbg("ContentBuffer result [" + connection.contentPackage.connectionId + "]", result.replace(/\</g, "&lt;").replace(/\>/g, "&gt;"));
			};

			if (typeof connection.contentPackage.onload == "function") {
				connection.contentPackage.onload.apply(connection.context || window, [connection]);
			};

			this.finishConnection(connection);
		};

	} catch (e) {
		if (this.debug || connection.contentPackage.debug) {
			WSDOM.Console.error("state monitoring error", e.message);
			WSDOM.Console.dir(e);
			//dbg("state monitoring error", e.message, "red");
			//if (typeof dbgObject != "undefined"){ dbgObject(e); }
		};

		this.finishConnection(connection);
	};
};

// ------------------------------------------------------------------------------------------------------------
// isActive
// ------------------------------------------------------------------------------------------------------------
Remoting_class.prototype.isActive = function() {
	for (var i=0; i<this.connections.length; i++) {
		if (this.connections[i].active) {
			return true;
		}
	}

	return false;
}

// ------------------------------------------------------------------------------------------------------------
// abortRequests()
// ------------------------------------------------------------------------------------------------------------
Remoting_class.prototype.abortRequests = function () {
	for (var i = 0; i < this.connections.length; i++) {
		this.connections[i].abort();
	};
}

// ------------------------------------------------------------------------------------------------------------
// abortRequests()
// ------------------------------------------------------------------------------------------------------------
Remoting_class.prototype.abortRequests = function () {
	for (var i = 0; i < this.connections.length; i++) {
		this.connections[i].abort();
	};
}

// ------------------------------------------------------------------------------------------------------------
// encode()
// ------------------------------------------------------------------------------------------------------------
Remoting_class.prototype.encode = function(str) {
	//return escape(str);

	/* escape() doesn't account for the + symbol, which Serializer() sometimes includes in its Base64 encoding.  encodeURIComponent() includes everything escape() does, and includes the + symbol */
	return encodeURIComponent(str);
};

Remoting_class.prototype.finishConnection = function(connection)
{
	if(connection.active)
	{
		this.connectionsActive--;
		connection.active = false;
	}

	if(this.connectionsPending.length)
	{
		this._loadXMLHTTP(this.connectionsPending.shift());
	}

	for (var x=0; x < this.connections.length; x++){
		if (connection === this.connections[x]){
			this.connections.splice(x,1);
			break;
		}
	}
}






function RemotingBase_class() {};
RemotingBase_class.Extend(Remoting_class);








// ------------------------------------------------------------------------------------------------------------
// Connection class
// ------------------------------------------------------------------------------------------------------------
function Connection_class(contentBuffer, id, contentPackage) {
	this.active = false;
	this.parent = contentBuffer;
	this.connectionId = id;
	this.contentPackage = contentPackage;
	this.context = (contentPackage && contentPackage.context) || (this.parent && this.parent.context);
	this._init();
};

Connection_class.prototype._init = function() {

    var c = false;

	try {
		c = new ActiveXObject("Msxml2.XMLHTTP");
	} catch (e) {
		try {
			c = new ActiveXObject("Microsoft.XMLHTTP");
		} catch (f) {
			c = false;
		};
	};

	if (!c && typeof XMLHttpRequest != "undefined") {
		c = new XMLHttpRequest();
	};

	if (c) {
		this.c = c;
	} else {
	   WSDOM.Console.log("Remoting initialization error.", "Not supported by this browser", "red");
	};

	if (this.parent) {
	    if (this.parent.connectionsActive < this.parent.connectionsMax) {
	        this.parent.connections.push(this);
	        this.parent._loadXMLHTTP(this);
	    } else {
	        WSDOM.Console.log("queuing request");
	        this.parent.connectionsPending.push(this);
	    };
	};
};

Connection_class.prototype.getResult = function() {
    return this.contentPackage.result;
};

Connection_class.prototype.status = function() {
	return (this.c.readyState == 4 && this.c.status == 200);
};

Connection_class.prototype.abort = function() {
	if (this.active) {
		try {
			this.c.onreadystatechange = function() {};
			this.c.abort();
		} catch (e) {
			WSDOM.Console.log("connection abort failed", e, "red");
		};

		this.parent.finishConnection(this);
	};
};





function JsonRPC_Connection_class(contentBuffer, id, contentPackage) {
	this.protocolType = "JsonRPC";
	this.active = false;
	this.parent = contentBuffer;
	this.connectionId = id;
	this.contentPackage = contentPackage;
	this.context = (contentPackage && contentPackage.context) || (this.parent && this.parent.context);
	this._init();
};
JsonRPC_Connection_class.Extend(Connection_class);





WSDOM.using("WSDOM.Remoting.1", "WSDOM.Console.1");
WSDOM.using("WSDOM.Remoting.1", "WSDOM.Serializer.3");
WSDOM.defineClass("Remoting", null, Remoting_class);
WSDOM.loadClass("WSDOM.Remoting.1");



// Yep, it slices, dices and serialices!
function Serializer_class() {

	this._nameExclusions = {};
	this._typeExclusions = {};
	// client-side will encode by default unless you set this to false;
	this._encode = true;
	this._strictJson = true;
	this._safeDeserialize = false;

	this._sBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

};

// toss the object into an JS string
Serializer_class.prototype.serialize = function (o) {

	this._data = [];
	this._serializeNode([o], o, 0);
	this._data = this._data.join("");
	this._data = this._data.replace(/,}/g, "}");
	this._data = this._data.replace(/,]/g, "]");
	this._data = this._data.substr(0, this._data.length-1);

	if (this.allowEncoding()) {

		this._data = this.base64encode(this._data);

	}

	return this._data;

}

// exclude certain named elements from serialization
Serializer_class.prototype.addNameExclusion = function () {

	var l = arguments.length;

	for (var i=0; i<l; i++) {

		this._nameExclusions[arguments[i]] = true;

	}

}

// remove exclusion of named elements
Serializer_class.prototype.removeNameExclusion = function () {

	var l = arguments.length;

	for (var i=0; i<l; i++) {

		this._nameExclusions[arguments[i]] = false;

	}

}

// exclude certain data types from serialization
Serializer_class.prototype.addTypeExclusion = function () {

	var l = arguments.length;

	for (var i=0; i<l; i++) {

		this._typeExclusions[arguments[i].toLowerCase()] = true;

	}

}

// remove exclusion of data types
Serializer_class.prototype.removeTypeExclusion = function () {

	var l = arguments.length;

	for (var i=0; i<l; i++) {

		this._typeExclusions[arguments[i].toLowerCase()] = false;

	}

}

// getter/setter specifies whether to follow strict Json serialization
Serializer_class.prototype.requireStrictJson = function (value) {

	if (typeof(value) != "undefined") {

		this._strictJson = value;

	}

	return this._strictJson;

}

// getter/setter specifies whether we need to check for wellformedness before deserializing
Serializer_class.prototype.requireSafeDeserialize = function (value) {

	if (typeof(value) != "undefined") {

		this._safeDeserialize = value;

	}

	return this._safeDeserialize;

}

// getter/setter specifies if results should be encoded
Serializer_class.prototype.allowEncoding = function (value) {

	if (typeof(value) != "undefined") {

		this._encode = value;

	}

	return this._encode;

}

Serializer_class.prototype._unicodeEscape = function (str) {
	var dec = str.charCodeAt(0);
	var hexStr = "\\u";
	var hexVals = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' ];

	var hexPlace;

	// Loop unrolled for speed
	hexPlace = 4096 // 16^3
	hexStr += hexVals[Math.floor(dec / hexPlace)];
	dec = dec % hexPlace;

	hexPlace = 256  // 16^2
	hexStr += hexVals[Math.floor(dec / hexPlace)];
	dec = dec % hexPlace;

	hexPlace = 16   // 16^1
	hexStr += hexVals[Math.floor(dec / hexPlace)];
	dec = dec % hexPlace;

	hexPlace = 1    // 16^0
	hexStr += hexVals[Math.floor(dec / hexPlace)];
	dec = dec % hexPlace;

	return hexStr;
}

// serialize each member of the object
Serializer_class.prototype._serializeNode = function (o, startObj, depth, parentType) {

	var t, f, d1, d2;

	// loop through all of the members
	for (var i in o) {

		if (o[i] === null) {
			t = "null";
		} else {
			t = typeof(o[i]);
		}


		f = t == "object" ? true : false;
		t = t == "object" && typeof(o[i].length) != "undefined" && o[i].constructor == Array ? "array" : t;

		if (!this._typeExclusions[t] && !this._nameExclusions[i] && !(this._strictJson && t == "function")) {

			switch (t) {

				case "string" :

					d1 = "\"";
					d2 = "\"";
					break;

				case "object" :

					d1 = "{";
					d2 = "}";
					break;

				case "array" :

					d1 = "[";
					d2 = "]";
					break;

				default :

					d1 = "";
					d2 = "";
					break;

			 }

			// build the JS string for this node
			if (isFinite(i) && !(parentType && parentType == "object")) {

				this._data.push(d1);

			} else {

				var n = typeof(i) == "string" ? "\"" + i + "\"" : i;
				this._data.push(n + ":" + d1);

			}

			if (f) {

				if (depth == 0 || o[i] !== startObj) {

					this._serializeNode(o[i],null,null,t);

				}

			} else {

				if (t == "string") {

				// Replace all non-printable, non-ASCII, ", and \ characters with their unicode encoding
					this._data.push(o[i].replace(/[^ -~]|[\"\\]/g, this._unicodeEscape));

				} else if (t == "undefined" || t == "null") {

					this._data.push(t);

				} else {

					this._data.push(o[i]);

				}
			}

			this._data.push(d2 + ",");

		}

	}
}

Serializer_class.prototype.deserialize = function (o) {

	try {

		//2007-05-17 AR if it's base64 encoded only decode the first line so
		//  that debuginfo does not get decoded into garbage.
		if (this.hasEncodingLeader(o)) {
			// 2007-06-11 - AR - In certain cases the \r precedes the \n, in others the \n is first.
			// To accomodate this weirdness, we look for them both and use the lesser one as this
			// defines the end of the the B64 encoded string.

			var indexR = o.indexOf('\r');
			var indexN = o.indexOf('\n');
			var index = Math.min(indexR+1 || indexN+1, indexN+1 || indexR+1)-1;

			if (index == -1) {
				o = this.base64decode(o);
			}
			else {
				o = this.base64decode(o.substring(0, index)) + o.substring(index);
			}
		}

		// eval("var x = " + o);

		if (this._safeDeserialize) {
			return this.safeDeserialize(o);
		} else {
			return this.unsafeDeserialize(o);
		}

	} catch(e) {

		WSDOM.Console.log("Serializer.deserialize() error", "", "red");
		WSDOM.Console.dir(e);
		WSDOM.Console.log("Serializer Source", o);

		var x = "";

	}

	return x;

}
Serializer_class.prototype.safeDeserialize = function (o) {
	try {
		var p = new JsonParser_class();
		p.parse(o);
		eval("var x = " + o);
	} catch(e) {
		var x = null;
	}
	return x;
}
Serializer_class.prototype.unsafeDeserialize = function (o) {
	try {
		eval("var x = " + o);
	} catch(e) {
		WSDOM.Console.dir(e);
		var x = null;
	}
	return x;
}

Serializer_class.prototype.hasEncodingLeader = function (s) {

	return s.indexOf("B64ENC") == 0 ? true : false;

}

Serializer_class.prototype.stripLeader = function (s) {

	return s.substr(6, s.length);

}

Serializer_class.prototype.prependLeader = function (s) {

	return "B64ENC" + s;

}

// ripped from /includes/asplib/Base64
Serializer_class.prototype.base64decode = function (sIn) {

	var i;
	var iBits;
	var sOut = [];

	if (this.hasEncodingLeader(sIn)) {

		sIn = this.stripLeader(sIn);

	} else {

		return sIn;

	}

	sIn = sIn.replace(/=/g, "");

	for(i = 0; i < sIn.length; i += 4) {

		iBits = (this._sBase64.indexOf(sIn.charAt(i)) << 18) |
			(this._sBase64.indexOf(sIn.charAt(i + 1)) << 12) |
			((this._sBase64.indexOf(sIn.charAt(i + 2)) & 0xff) << 6) |
			(this._sBase64.indexOf(sIn.charAt(i + 3)) & 0xff);

		/* Removing the below += results in a 90% speed improvement on large objects/long strings */
		/*sOut += String.fromCharCode(iBits >> 16 & 0xff);
		sOut += (i > sIn.length - 3) ? "" : String.fromCharCode(iBits >> 8 & 0xff);
		sOut += (i > sIn.length - 4) ? "" : String.fromCharCode(iBits & 0xff);*/

		sOut.push(String.fromCharCode(iBits >> 16 & 0xff));
		sOut.push((i > sIn.length - 3) ? "" : String.fromCharCode(iBits >> 8 & 0xff));
		sOut.push((i > sIn.length - 4) ? "" : String.fromCharCode(iBits & 0xff));

	}

	return sOut.join("");

}

// ripped from /includes/asplib/Base64
Serializer_class.prototype.base64encode = function (sIn) {

	var i;
	var iBits;
	var sOut = [];

	for(i = 0; i < sIn.length; i += 3) {

		iBits = (sIn.charCodeAt(i) << 16) +
			((sIn.charCodeAt(i + 1) & 0xff) << 8) +
			(sIn.charCodeAt(i + 2) & 0xff);

		/* Removing the below += results in a 90% speed improvement on large objects/long strings */
		/*sOut += this._sBase64.charAt(iBits >> 18 & 0x3f);
		sOut += this._sBase64.charAt(iBits >> 12 & 0x3f);
		sOut += (i > sIn.length - 2) ? "=" : this._sBase64.charAt(iBits >> 6 & 0x3f);
		sOut += (i > sIn.length - 3) ? "=" : this._sBase64.charAt(iBits & 0x3f);*/

		sOut.push(this._sBase64.charAt(iBits >> 18 & 0x3f));
		sOut.push(this._sBase64.charAt(iBits >> 12 & 0x3f));
		sOut.push((i > sIn.length - 2) ? "=" : this._sBase64.charAt(iBits >> 6 & 0x3f));
		sOut.push((i > sIn.length - 3) ? "=" : this._sBase64.charAt(iBits & 0x3f));

	}

	sOut = this.prependLeader(sOut.join(""));

	return sOut;

}


// This is a validating JSON recursive descent parser.  It does not actually
// build a data structure; it merely tests the input string for validity
// according to the JSON grammar.  This greatly simplifies the parser, and also
// allows a few otherwise impossible performance tweaks.  For a description of
// the JSON grammer, see http:// json.org.  For a description of Recursive
// Descent parsers, how they work, and how to write one, see
// http://www.antlr.org/book/byhand.pdf

// The purpose of this parser is to ensure that calling eval() on a serialized
// string will not have any potentially nasty side effects.  This is an
// important safety measure when you don't know who has been serializing the
// strings you are about to deserialize...


function JsonParser_class () {
	this.lexer = null;
	this.tokens = [ ];
}

JsonParser_class.prototype.parse = function (str) {
	this.lexer = new JsonLexer_class(str);

	return this._json();
}

// not really necessary, since JSON seems to be parsable with an LL(1) grammar,
// but defining this now makes it far easier to extend in the future.
JsonParser_class.prototype.lookAhead = function (k) {
	while (this.tokens.length <= k) {
		this.tokens.push(this.lexer.nextToken());
	}
	return this.tokens[k].type;
}

// Remove a token from the token stream.  Since we are only parsing and not
// actually doing anything with the parsed string, we can merely remove the
// token from the stream here, and not worry about building a syntax tree.
JsonParser_class.prototype.consume = function (type) {
	if (this.tokens.length == 0) {
		this.tokens.push(this.lexer.nextToken());
	}

	if (this.tokens[0].type == type) {
		this.tokens.shift();
	} else {
		throw { message: 'JSON: invalid token encountered validating string; Expected '+type+', got '+this.tokens[0].type };
	}
}

// A JSON serialized string consists of exactly one value.
JsonParser_class.prototype._json = function () {
	this._value();
	this.consume('_EOF');
}

// A value can be one of
//   an object
//   an array
//   a string
//   a number
//   true, false, or null
JsonParser_class.prototype._value = function () {
	switch(this.lookAhead(0)) {
		case '_OBJ_OPEN':
			this._object();
			break;
		case '_ARR_OPEN':
			this._array();
			break;
		case '_DIGITS':
		case '_NEG':
			this._number();
			break;
		case '_STRING':
			this.consume('_STRING');
			break;
		case '_TRUE':
			this.consume('_TRUE');
			break;
		case '_FALSE':
			this.consume('_FALSE');
			break;
		case '_NULL':
			this.consume('_NULL');
			break;
	}
}

// An object consists of an open brace, zero or more comma separated
// string/value pairs, and a close brace
JsonParser_class.prototype._object = function () {
	this.consume('_OBJ_OPEN');
	if (this.lookAhead(0) != '_OBJ_CLOSE') {
		this._member();
	}
	while (this.lookAhead(0) != '_OBJ_CLOSE') {
		this.consume('_SEP');
		this._member();
	}
	this.consume('_OBJ_CLOSE');
}

JsonParser_class.prototype._member = function () {
	this.consume('_STRING');
	this.consume('_ASSIGN');
	this._value();
}

// An array consists of an open bracket, zero or more comma separated values,
// and a close bracket
JsonParser_class.prototype._array = function () {
	this.consume('_ARR_OPEN');
	if (this.lookAhead(0) != '_ARR_CLOSE') {
		this._value();
	}
	while (this.lookAhead(0) != '_ARR_CLOSE') {
		this.consume('_SEP');
		this._value();
	}
	this.consume('_ARR_CLOSE');
}

// A number consists of an optional leading '-', any number of digits, followed
// by an optional fractional component and an optional exponential component.
JsonParser_class.prototype._number = function () {
	if (this.lookAhead(0) == '_NEG') {
		this.consume('_NEG');
	}

	this.consume('_DIGITS');

	if (this.lookAhead(0) == '_DOT') {
		this.consume('_DOT');
		this.consume('_DIGITS');
	}

	if (this.lookAhead(0) == '_EXP') {
		this.consume('_EXP');
		if (this.lookAhead(0) == '_POS') {
			this.consume('_POS');
		} else if (this.lookAhead(0) == '_NEG') {
			this.consume('_NEG');
		}
		this.consume('_DIGITS');
	}
}

function JsonLexer_class (input) {
	// since we only care about validity and not the actual value, we can
	// easily reduce these multi-character tokens down to one character now
	// resulting in a significant gain in overall efficiency.
	input = input.replace(/"([^"\\]|\\"|\\)*"/g, 'S');
	input = input.replace(/[0-9]+/g, '0');

	this.input = input;
}

// Tokens represented by a single character
JsonLexer_class.prototype.charTokens = {
								'{': '_OBJ_OPEN',
								'}': '_OBJ_CLOSE',
								'[': '_ARR_OPEN',
								']': '_ARR_CLOSE',
								':': '_ASSIGN',
								',': '_SEP',
								'.': '_DOT',
								'-': '_NEG',
								'+': '_POS',
								'e': '_EXP',
								'E': '_EXP',
								'S': '_STRING',
								'0': '_DIGITS'
							};
// Other Tokens that are scanned for:
// 									 '_TRUE',
// 									 '_FALSE',
// 									 '_NULL',

JsonLexer_class.prototype.nextToken = function () {
	if (this.input.length == 0) {
		return new JsonToken_object("_EOF", null);
	}

	var first = this.input.substr(0,1);
	if (this.charTokens[first]) {
		this.input = this.input.substr(1);
		return new JsonToken_object(this.charTokens[first], first);
	}

	switch (first) {
		case 't':
		case 'T':
			if (this.input.substr(0,4).toLowerCase() == 'true') {
				this.input = this.input.substr(4);
				return new JsonToken_object('_TRUE', true);
			}
			break;

		case 'f':
		case 'F':
			if (this.input.substr(0,5).toLowerCase() == 'false') {
				this.input = this.input.substr(5);
				return new JsonToken_object('_FALSE', true);
			}
			break;

		case 'n':
			if (this.input.substr(0,4) == 'null') {
				this.input = this.input.substr(4);
				return new JsonToken_object('_NULL', true);
			}
			break;
	}

	throw { message: 'JSON: Unexpected character ('+first+') encountered validating string' };
}

// Simple representation of a lexer token
function JsonToken_object (type, value) {
	this.type = type;
	this.value = value;
}






WSDOM.using("WSDOM.Serializer.3", "WSDOM.Console.1");
WSDOM.defineClass("Serializer", null, Serializer_class);
WSDOM.loadSingleton("WSDOM.Serializer.3");





var Dynamo = function(){};

Dynamo.storage = {};

Dynamo.prototype.getContainer = function() {
	return document.documentElement.firstChild;
}
Dynamo.prototype.setContainer = function(el) {
	var element = el;
	this.getContainer = function() {
		return element;
	}
}

Dynamo.prototype.getBase = function() {}
Dynamo.prototype.setBase = function(el) {
	var element = el + " ";
	this.getBase = function() {
		return element;
	}
}

Dynamo.prototype.createCss = function( oArgs, name, callback, context, args ){
	var dysheet;
	if( name && Dynamo.storage[ name ] ) {
		dySheet = Dynamo.storage[ name ]

	} else {
		var sheet = document.createElement("style");
		
		sheet.setAttribute( "type", "text/css" );
		sheet.setAttribute( "media", oArgs.media || "all" );
			
		document.documentElement.firstChild.appendChild( sheet );
		
		dySheet = document.styleSheets[ document.styleSheets.length - 1 ];
		if( name ) {
			Dynamo.storage[ name ] = dySheet;
		};
	};
	
	var counter = dySheet.rules ? dySheet.rules : dySheet.cssRules || [];
	counter = counter.length || 0;
	var base = this.getBase() || "";
	
	var splitRules;
	for( var i in oArgs.rules ) {
		splitRules = i.split(",");
		for(var j=0; j<splitRules.length; j++) {
			if( dySheet.addRule ) {
					dySheet.addRule( base + splitRules[j], oArgs.rules[i], counter );	
	
			} else {
				dySheet.insertRule( [ 
					base, 
					splitRules[j], 
					'{', oArgs.rules[i], '}' 
				].join(''), counter );
			};
			counter++;
		}
	};
	
	if( callback ) {
		context = context || window;
		args = [].concat( args );
		callback = String === callback.constructor? context[ callback ] : callback;
		callback.apply( context, args );
	};

	return dySheet;
};





var Element = WSDOM.Element;
var Events = WSDOM.Events;
var Remoting = WSDOM.Remoting;
var Serializer = WSDOM.Serializer;


/************************
  CrossDomainRequestor
************************/
var CrossDomainRequestor = function() {
	this.globalContext = "window";
	this.requests = [];
};

CrossDomainRequestor.prototype.setGlobalContext = function(value) {
	this.globalContext = value;
};

CrossDomainRequestor.prototype.buildRequestURL = function(params) {
	var path = params.url + "?";
	
	params.data.context = this.globalContext;
	
	var url = [];
	if(params.contentType) { 
		url.push("..contentType..=" + params.contentType);
	}
	for (var i in params.data) {
		url.push(i + "=" + encodeURIComponent(params.data[i]));
	}
	
	return path + url.join('&');
};

CrossDomainRequestor.prototype.load = function(params) {
	var elScript = document.createElement("script");
	elScript.src = this.buildRequestURL(params);
	document.getElementsByTagName("head")[0].appendChild(elScript);
	this.requests.push(elScript);
};

CrossDomainRequestor.prototype.abortRequests = function() {
	for (var i=0; i<this.requests.length; i++) {
		//try {
			this.requests[i].src = "javascript:false;"
			WSDOM.Element.remove(this.requests[i]);
		//} catch (e) {}
	}
	this.requests = [];
};


/************************
  GreenModule
************************/

function GreenModule(oArgs) {
	for(var arg in oArgs) {
		this[arg] = oArgs[arg]
	}
	
	this.goToPortfolio_evt = Events.add({
		type : "click",
		handler : function(e, el) {
			Events.cancel(e);
			window.location.href = GreenModule.PATH.portfolio_location;
		},
		context : this
	});
}

GreenModule.PATH = {};

GreenModule.prototype.init = function() {
	this.build();
}

GreenModule.prototype.build = function() {
	
//	document.write("<div id='" + this.CONTAINER_ID + "'></div>");
	var wsod = Element.get(this.CONTAINER_ID);
	this.addStyle(this.getCSS())
	var content = this.getContent();
	
	Element.addChild(wsod, content);
	this.getElement = function() { return wsod; }
}

GreenModule.prototype.getElement = function() {}

GreenModule.prototype.SUMMARY_LENGTH = 150;

GreenModule.prototype.getContent = function() {

	var summarytext = this.portfolio_summary || null;


	var h2 = Element.create("h2",{className:"module-title"},"Reuters Global Green Portfolio");
	
	var headerbar = Element.create("div",{className:"portfolio-info-header"},[
		Element.create("div",{className:"header-container"},[
			Element.create("div",{className:"performance"},[
				Element.create("div",{className:"change-today-value"},this.todaychange),
				Element.create("div",{className:"change-today-label"},"Today's Change")
			]),
			Element.create("h3",{className:"portfolio-title"},this.portfolio_name),
			Element.create("div",{className:"activity-bar"},[
				Element.create("span",{className:"comments"},
					Element.create("a",{href:GreenModule.PATH.comments_location},this.rollup_TotalComments + " Comment" + (this.comments == 1 ? '' : 's'))
				),
				Element.create("span",{className:"followers"},
					Element.create("a",{href:GreenModule.PATH.followers_location}, this.rollup_Followers + " Follower" + (this.rollup_Followers == 1 ? '' : 's'))
				),
				Element.create("span",{className:"transactions"},
					Element.create("a",{href:GreenModule.PATH.transactions_location},this.rollup_TotalTransactions + " Transaction" + (this.transactions == 1 ? '' : 's'))
				)
			])
		])
	]);
	
	var summary = Element.create("div",{className:"portfolio-summary"});
	if(summarytext) {
		Element.addChild(summary,[
			summarytext.substr(0,this.SUMMARY_LENGTH) + (summarytext.length > this.SUMMARY_LENGTH ? "..." : ""),
			Element.create("a",{href:GreenModule.PATH.portfolio_location},"more")
		]);
	}
	
	var publicEffectiveDate = this.rollup_PublicEffectiveDate;
	var today = jsToMsDate(new Date());
	var defaultTab = 90;
	var tab_choices = {
		30 : '1 Month',
		90 : '3 Month',
		180 : '6 Month',
		365 : '1 Year'
	}

	var tabs = Element.create("ul",{className:"timeframe-tabs"});
	var li, lis = [];
	for(var i in tab_choices) {

		if(today - i <= publicEffectiveDate) { continue; }
		li = Element.create("li",{timeframe:i},Element.create("a",{href:"javascript:void(0)"},tab_choices[i]))
		
		if(i == defaultTab) { Element.addClass(li,"selected"); }
		
		lis.push(li);
	}
	
	Element.addChild(tabs, lis);
	
	Events.add({
		element: lis,
		type : 'click',
		data : lis,
		handler : this.switchTimeFrame,
		context : this
	});
	
	
	var chart = Element.create("div",{
		className:"chart-container"
	});
	this.setChart(chart);
	this.setChartStyle(this.chart_path);
	
	this.goToPortfolio_evt.addElement(chart);
	
	this.loader = Element.create("div",{className:"loader hidden"});	
	Element.addChild(chart, this.loader);
	
	var footer = Element.create("div",{className:"footer"},[
		Element.create("div",{className:"timestamp"},this.date),
		Element.create("div",{className:"marketer"},"Reuters")
	]);
	
	return [
		h2,
		headerbar,
		summary,
		tabs,
		chart,
		footer
	]
}

GreenModule.prototype.getChart = function() { return null; }
GreenModule.prototype.setChart = function(chart) {
	return (this.getChart = function() {
		return chart;
	})()
}

GreenModule.prototype.setChartStyle = function(url) {
	
	var chart = this.getChart();
	if(!chart) { return; }
	
	Element.setStyle(chart, 'background-image:url(' + url + ');\
		background-position: top left;\
		background-repeat: no-repeat');
}

GreenModule.prototype.showLoader = function() {
	if(!this.loader) { return; }
	Element.removeClass(this.loader,"hidden");
}

GreenModule.prototype.hideLoader = function() {
	if(!this.loader) { return; }
	Element.addClass(this.loader,"hidden");
}

GreenModule.prototype.switchTimeFrame = function(e, el, lis) {
	Events.cancel(e);
	Element.removeClass(lis, "selected");
	Element.addClass(el, "selected");
	
	var timeframe = Number(el.getAttribute("timeframe")) || null;
	if(!timeframe) { return; }
	
	this.showLoader();
	
//	this.loadRemoting({
//		url : ,
//		context : this,
//		data : {
//			timeframe : timeframe,
//			container : this.container,
//			benchmark : this.benchmark,
//			start : this.rollup_PublicEffectiveDate
//		},
//		onload : this.switchChart,
//		onerror : this.displayError
//	});
	
	var self = this;
	_WSOD_updateChart = function(response) {
		self.switchChart(filename);
	};
	
	var cdr = new CrossDomainRequestor();

	cdr.load({
		url: GreenModule.PATH.script_location + "getGreenChart.asp",
		data : {
			timeframe : timeframe,
			container : this.container,
			benchmark : this.benchmark,
			start : this.rollup_PublicEffectiveDate,
			callback: "_WSOD_updateChart"
		}
	});
}

GreenModule.prototype.switchChart = function(filename) {
//	var data = Serializer.deserialize(cb.getResult());
//	if(data.errorCode != 1) {
//		cb.contentPackage.onerror.call(this,null,data);
//		return;
//	}

	var base = GreenModule.PATH.base.substr(0,GreenModule.PATH.base.length-1)
	
	this.setChartStyle(base + filename);
	this.hideLoader();
}

GreenModule.prototype.displayError = function(cb, data) {
	var data = data || Serializer.deserialize(cb.getResult());
	alert(data.errorDetails);
	this.hideLoader();
}

GreenModule.prototype.getRemoting  = function() {
	var r = new Remoting();
	return (this.getRemoting = function() {
		return r;
	})();
}

GreenModule.prototype.loadRemoting = function(argsObj,allowSimultaneous) {
	var cb = this.getRemoting();
	
	if(!allowSimultaneous) { cb.abortRequests(); }

	var url = argsObj.url ? GreenModule.PATH.script_location + argsObj.url : "buffer/" + argsObj.page;

	var conn = cb.load({
		debug: true
		,url: url
		,method: "post"
		,contentType: "text/javascript"
		,context:argsObj.context
		,preventEval:true
		,data:argsObj.data
		,onload:  argsObj.onload
		,onerror: argsObj.onerror
	});
}

GreenModule.prototype.getDynamo = function() {
	var dynamo = new Dynamo();
	var container = Element.get(this.CONTAINER_ID);
	dynamo.setContainer(container);
	dynamo.setBase('#' + this.CONTAINER_ID);
	
	this.getDynamo = function() {
		return dynamo;
	}
	return this.getDynamo();
}

//GreenModule.prototype.CONTAINER_ID = 'wsod-green-portfolio';
GreenModule.prototype.STYLE_SHEET_NAME = 'WSODGreenPortfolio';

GreenModule.prototype.addStyle = function(rules, optionalParams) {
	if(!rules) { return; }
	
	var oArgs = {};
	for(var i in optionalParams) {
		oArgs[i] = optionalParams[i];
	}
	
	var thisrule, j, rulelist;
	for(var i in rules) {
		thisrule = rules[i];
		rulelist = [];
		for(j in thisrule) {
			rulelist.push(j + ":" + thisrule[j])
		}
		rules[i] = rulelist.join(';');
	}
	oArgs.rules = rules;
	this.getDynamo().createCss(oArgs,this.STYLE_SHEET_NAME);
}

GreenModule.prototype.getCSS = function() {
	var CSS = {
		'' : {
			'font-size' : '13px',
			'font-family' : 'arial,helvetica,sans',
			'line-height' : '1.2',
			'width' : '490px',
			'margin' : '0 0'
		},
		'.positive' : {
			'color' : '#009B01'
		},
		'.hidden' : {
			'display' : 'none'
		},
		'.negative' : {
			'color' : '#CC0002'
		},
		'.unch' : {
			'color' : '#898989'
		},
		'.positive-arrow' : {
			'color' : '#009B01',
			'padding-left' : '14px',
			'background' : 'url(' + GreenModule.PATH.resources_location + 'image/icons.gif) no-repeat 0 5px'
		},
		'.negative-arrow' : {
			'color' : '#CC0002',
			'padding-left' : '14px',
			'background' : 'url(' + GreenModule.PATH.resources_location + 'image/icons.gif) no-repeat 0 -11px'
		},
		'a' : {
			'color' : '#005A84',
			'text-decoration' : 'none'
		},
		'.portfolio-info-header' : {
			'background-image' : 'url(' + GreenModule.PATH.resources_location + 'image/header-bg.gif)',
			'background-position' : 'top left',
			'background-repeat' : 'repeat-x',
			'padding' : '3px 5px'
		},
		'.portfolio-info-header .header-container' : {
			'border-bottom' : '1px dotted #CCCCCC',
			'padding-bottom' : '4px'
		},
		'.portfolio-info-header .header-container h3.portfolio-title' : {
			'font-size' : '14px',
			'color' : '#333333',
			'margin' : '0px 0px 3px 0px',
			'padding' : '0px 0px'
		},
		'.portfolio-info-header .header-container .performance' : {
			'width' : '110px',
			'float' : 'right',
			'text-align' : 'right'
		},
		'.portfolio-info-header .header-container .performance .change-today-label' : {
			'font-size' : '11px',
			'color' : '#666666'
		},
		'.portfolio-info-header .header-container .performance .change-today-value' : {
			'font-size' : '14px',
			'color' : '#000000',
			'font-weight' : 'bold'
		},
		'.portfolio-info-header .header-container .activity-bar' : {
			'font-size' : '11px'
		},
		'.portfolio-info-header .header-container .activity-bar .comments,\
		 .portfolio-info-header .header-container .activity-bar .followers,\
		 .portfolio-info-header .header-container .activity-bar .transactions' : {
			'padding-left' : '13px',
			'margin-left' : '3px',
			'background-image' : 'url(' + GreenModule.PATH.resources_location + 'image/icons.2.gif)',
			'background-position' : 'left center',
			'background-repeat' : 'no-repeat',
			'margin-right' : '5px'
		},
		'.portfolio-info-header .header-container .activity-bar .comments' : {
			'background-position' : 'left -97px'
		},
		'.portfolio-info-header .header-container .activity-bar .followers' : {
			'background-position' : 'left -118px'
		},
		'.portfolio-info-header .header-container .activity-bar .transactions' : {
			'background-position' : 'left -137px'
		},
		'.portfolio-summary' : {
			'font-size' : '12px',
			'margin-top' : '5px',
			'padding-bottom' : '7px',
			'border-bottom' : '1px solid #CCCCCC'
		},
		'.portfolio-summary a' : {
			'margin-left' : '4px'
		},
		'ul.timeframe-tabs' : {
			'margin' : '3px 0px',
			'padding' : '0px 0px',
			'zoom' : '1'
		},
		'ul.timeframe-tabs:after' : {
			'content' : '"."',
			'display' : 'block',
			'height' : '0',
			'clear' : 'both',
			'visibility' : 'hidden'
		},
		'ul.timeframe-tabs li' : {
			'display' : 'block',
			'float' : 'left',
			'padding' : '2px 6px 2px 6px',
			'margin' : '0px 0px 0px 0px',
			'border-right' : '1px solid #cccccc',
			'font-size' : '11px'
		},
		'ul.timeframe-tabs li.last' : {
			'border-right' : 'none'
		},
		'ul.timeframe-tabs li.selected a' : {
			'font-weight' : 'bold',
			'color' : '#000000'
		},
		'.chart-container' : {
			'border' : '1px solid #CCCCCC',
			'margin-top' : '4px',
			'height' : '250px',
			'cursor' : 'pointer'
		},
		'.footer' : {
			'font-size' : '9px',
			'color' : '#898989',
			'zoom' : '1',
			'margin-top' : '2px'
		},
		'.footer:after' : {
			'content' : '"."',
			'display' : 'block',
			'height' : '0',
			'clear' : 'both',
			'visibility' : 'hidden'
		},
		'.footer .timestamp' : {
			'float' : 'right'
		},
		'.chart-container .loader' : {
			'filter' : 'alpha(opacity=50)',
			'-moz-opacity' : '0.50',
			'opacity' : '0.50',
			'height' : '100%',
			'background' : '#FFFFFF url(' + GreenModule.PATH.resources_location + 'image/load.gif) center center no-repeat'
		}
	}  
	return CSS;
}

GreenModule.PATH = {"script_location":"http://portfolio.us.reuters.com/US/public/script_modules/","resources_location":"http://portfolio.us.reuters.com/resources/portfolio/script_modules/green/","portfolio_location":"http://portfolio.us.reuters.com/US/public/overview.asp?YYY622_tlH/drrjN7X20y0apuI2R/L2xRm1YJdfjanCb/5PqapDd79gf5cCsQ0PU5i2NXhbyi20mUg/oUxw2xK8YQCZvhjXBFGU8oSZk03zViyeWuonkZL3KDSW99iGEt5SO0A6","followers_location":"http://portfolio.us.reuters.com/US/public/overview.asp?activity=followers&YYY622_tlH/drrjN7X20y0apuI2R/L2xRm1YJdfjanCb/5PqapDd79gf5cCsQ0PU5i2NXhbyi20mUg/oUxw2xK8YQCZvhjXBFGU8oSZk03zViyeWuonkZL3KDSW99iGEt5SO0A6","transactions_location":"http://portfolio.us.reuters.com/US/public/overview.asp?activity=transactions&YYY622_tlH/drrjN7X20y0apuI2R/L2xRm1YJdfjanCb/5PqapDd79gf5cCsQ0PU5i2NXhbyi20mUg/oUxw2xK8YQCZvhjXBFGU8oSZk03zViyeWuonkZL3KDSW99iGEt5SO0A6","comments_location":"http://portfolio.us.reuters.com/US/public/overview.asp?activity=comments&YYY622_tlH/drrjN7X20y0apuI2R/L2xRm1YJdfjanCb/5PqapDd79gf5cCsQ0PU5i2NXhbyi20mUg/oUxw2xK8YQCZvhjXBFGU8oSZk03zViyeWuonkZL3KDSW99iGEt5SO0A6","base":"http://portfolio.us.reuters.com/"};
GreenModule.prototype.CONTAINER_ID = "wsod-green-portfolio";
var green = new GreenModule({"chart_path":"http://portfolio.us.reuters.com/cgi-bin/upload.dll/file.png?z01a40f0az4a871ecdcffd4a22b69add8bec25fd28","transactions":-1,"comments":-1,"portfolio_summary":null,"portfolio_name":"Business of Green","date":"Nov 25, 2009 1:42am EDT","path":{"script_location":"http://portfolio.us.reuters.com/US/public/script_modules/","resources_location":"http://portfolio.us.reuters.com/resources/portfolio/script_modules/green/","portfolio_location":"http://portfolio.us.reuters.com/US/public/overview.asp?YYY622_tlH/drrjN7X20y0apuI2R/L2xRm1YJdfjanCb/5PqapDd79gf5cCsQ0PU5i2NXhbyi20mUg/oUxw2xK8YQCZvhjXBFGU8oSZk03zViyeWuonkZL3KDSW99iGEt5SO0A6","followers_location":"http://portfolio.us.reuters.com/US/public/overview.asp?activity=followers&YYY622_tlH/drrjN7X20y0apuI2R/L2xRm1YJdfjanCb/5PqapDd79gf5cCsQ0PU5i2NXhbyi20mUg/oUxw2xK8YQCZvhjXBFGU8oSZk03zViyeWuonkZL3KDSW99iGEt5SO0A6","transactions_location":"http://portfolio.us.reuters.com/US/public/overview.asp?activity=transactions&YYY622_tlH/drrjN7X20y0apuI2R/L2xRm1YJdfjanCb/5PqapDd79gf5cCsQ0PU5i2NXhbyi20mUg/oUxw2xK8YQCZvhjXBFGU8oSZk03zViyeWuonkZL3KDSW99iGEt5SO0A6","comments_location":"http://portfolio.us.reuters.com/US/public/overview.asp?activity=comments&YYY622_tlH/drrjN7X20y0apuI2R/L2xRm1YJdfjanCb/5PqapDd79gf5cCsQ0PU5i2NXhbyi20mUg/oUxw2xK8YQCZvhjXBFGU8oSZk03zViyeWuonkZL3KDSW99iGEt5SO0A6","base":"http://portfolio.us.reuters.com/"},"container":"B0E12123-2CFD-491A-A47E-72861854CAA9","benchmark":"593933","todaychange":"<span class=\u0022positive-arrow\u0022>0.01%</span>","rollup_Followers":30,"rollup_PortfolioName":"Business of Green","rollup_InceptionDate":39875,"rollup_PublicEffectiveDate":39876,"rollup_TotalComments":7,"rollup_TotalTransactions":76,"rollup_Gain1DayAgo":"<span class=\u0022negative-arrow\u0022>-0.01%</span>"}); 
green.init();



},0);