/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * Portions created by the Initial Developer are Copyright (C) 2005
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */


function IEerBug(){

//////////////////////////////////////////////////////////////////////////////////////////////////
// setting
var scriptParams = {
	debug: true,
	showJSErrors : true,
	stopJSErrors : true
};

//////////////////////////////////////////////////////////////////////////////////////////////////
// set window.console
if(window.console && !scriptParams.debug)
{
	return;
}

window.console = new FireBugConsole();

// set error handler
function ScriptError(msg, src, num)
{
	this.errorMessage = msg;
	this.sourceName = src;
	this.lineNumber = num;
}

if(scriptParams.showJSErrors){
	window.onerror = function(message, file, num){
		var caller = arguments.callee.caller;
		//if(caller) caller = caller.caller;

		var s = new ScriptError(message, file, num);
		s.errorStackTrace = new StackTrace(caller);
		console.logRelay(s, "consoleError");
		return scriptParams.stopJSErrors;
	}
}


//////////////////////////////////////////////////////////////////////////////////////////////////
// firebug.js
function TestFireBug()
{
  this.console=new FireBugConsoleView();
  this.stringCropLength=100;
}
var FireBug=new TestFireBug();

//
function SourceLink(href, line)
{
	this.href = href;
	this.line = line;
}

function StackTrace(frame)
{
	this.frames = [];
	
	// IEerBug: 
	function getFuncName(f){
		if(!f){
			return "null";
		}
		
		var s;
		try{
			s = ("" + f).match(/function (\w*)/)[1];
		}
		catch(e){}
		return (s == null || s.length == 0) ? "[anonymous]" : s;
	}

	// IEerBug: get stack trace using arguments.callee
	var i = 0;
	for (; frame; frame = frame.caller)
	{
		this.frames.push({
			functionName: getFuncName(frame),
			fileName: null,
			line: null
		});
		i++;

		if(i > 50) break;
	}

	// IEerBug: toplevel null function must be added
	if(this.frames.length == 0){
		this.frames.push({functionName: "null", fileName : null, line : null});
	}
}


//////////////////////////////////////////////////////////////////////////////////////////////////
// consoleAPI.js
function FireBugConsole()
{
	this.firebug = "0.4";
	var context = null;  // context is not implemented in IEerBug... by nitoyon
	var queue = [];
	var timeCounters;
	var frameCounters;

	// ieerbug : Until FireBug.console is defined, stock the arguments to queue.
	this.flushQueue = function(){
		if(queue){
			for(var i = 0; i < queue.length; i++){
				var q = queue[i];
				FireBug.console.log(q[0], q[1], q[2], q[3]);
			}
			queue = null;
		}
	}

	this.logRelay = function(args, rowClass, rowFunc, context){
		if(typeof FireBug == "object" && FireBug.console){
			if(queue){
				this.flushQueue();
			}

			FireBug.console.log(args, rowClass, rowFunc, context);
		}
		else{
			queue.push(arguments);
		}
	}

	this.log = function()
	{
		this.logRelay(arguments, "log", FireBug_logFormattedRow);
	}


	this.logAssert = function(messages, caption)
	{
		//FireBug.increaseErrorCount(context);

		if (!messages || !messages.length)
			messages = ["Assertion Failure"];

		this.logRelay([messages, caption], "assert", FireBug_logFormattedRows, context, true);

		/* ieerbug : comment out
		if (win && typeof(win.onassert) == "function")
		{
			// XXXjoe Convert args to a string
			win.onassert(message, caption);
		}*/
	}

	this.debug = function()
	{
		this.logRelay(arguments, "debug", FireBug_logFormattedRow, context, true);
	}

	this.info = function()
	{
		this.logRelay(arguments, "info", FireBug_logFormattedRow, context, true);
	}

	this.warn = function()
	{
		this.logRelay(arguments, "warn", FireBug_logFormattedRow, context, true);
	}

	this.error = function()
	{
		this.logRelay(arguments, "error", FireBug_logFormattedRow, context, true);
	}

//	this.fail = function()
//	{
//		this.logAssert(arguments, null);
//  }

	this.assert = function(x)
	{
		if (!x)
			this.logAssert(sliceArray(arguments, 1), ["%o", x]);
	}

	this.assertEquals = function(x, y)
	{
		if (x != y)
			this.logAssert(sliceArray(arguments, 2), ["%o != %o", x, y]);
	}

	this.assertNotEquals = function(x, y)
	{
		if (x == y)
			this.logAssert(sliceArray(arguments, 2), ["%o == %o", x, y]);
	}

	this.assertGreater = function(x, y)
	{
		if (x <= y)
			this.logAssert(sliceArray(arguments, 2), ["%o <= %o", x, y]);
	}

	this.assertNotGreater = function(x, y)
	{
		if (!(x > y))
			this.logAssert(sliceArray(arguments, 2), ["!(%o > %o)", x, y]);
	}

	this.assertLess = function(x, y)
	{
		if (x >= y)
			this.logAssert(sliceArray(arguments, 2), ["%o >= %o", x, y]);
	}

	this.assertNotLess = function(x, y)
	{
		if (!(x < y))
			this.logAssert(sliceArray(arguments, 2), ["!(%o < %o)", x, y]);
	}

	this.assertContains = function(x, y)
	{
		if (!(x in y))
			this.logAssert(sliceArray(arguments, 2), ["!(%o in %o)", x, y]);
	}

	this.assertNotContains = function(x, y)
	{
		if (x in y)
			this.logAssert(sliceArray(arguments, 2), ["%o in %o", x, y]);
	}

	this.assertTrue = function(x)
	{
		this.assertEquals(x, true);
	}

	this.assertFalse = function(x)
	{
		this.assertEquals(x, false);
	}

	this.assertNull = function(x)
	{
		this.assertEquals(x, null);
	}

	this.assertNotNull = function(x)
	{
		this.assertNotEquals(x, null);
	}

	this.assertUndefined = function(x)
	{
		this.assertEquals(x, undefined);
	}

	this.assertNotUndefined = function(x)
	{
		this.assertNotEquals(x, undefined);
	}

	this.assertInstanceOf = function(x, y)
	{
		if (!(x instanceof y))
			this.logAssert(sliceArray(arguments, 2), ["!(%o instanceof %o)", x, y]);
	}

	this.assertNotInstanceOf = function(x, y)
	{
		if (x instanceof y)
			this.logAssert(sliceArray(arguments, 2), ["%o instanceof %o", x, y]);
	}

	this.assertTypeOf = function(x, y)
	{
		if (typeof(x) != y)
			this.logAssert(sliceArray(arguments, 2), ["typeof(%o) != %o", x, y]);
	}

	this.assertNotTypeOf = function(x)
	{
		if (typeof(x) == y)
			this.logAssert(sliceArray(arguments, 2), ["typeof(%o) == %o", x, y]);
	}

	this.group = function(name)
	{
	  this.warn(["group() not supported."]);
	}

	this.groupEnd = function(name)
	{
	 this.warn(["groupEnd() not supported."]);
	}
	
	this.profile = function(name)
	{
	  this.warn(["profile() not supported."]);
	}
	
    this.profileEnd = function(name)
	{
	 this.warn(["profileEnd() not supported."]);
	}
	this.dir = function(name)
	{
	 this.warn(["dir() not supported."]);
	}
	this.dirxml = function(name)
	{
	 this.warn(["dirxml() not supported."]);
	}
	
	this.time = function(name, reset)
	{
		if (!name)
			return;

		var time = new Date().getTime();

		if (!timeCounters)
			timeCounters = {};

		if (!reset && name in timeCounters)
			return;

		timeCounters[name] = time;
	}
	
 	this.timeEnd = function(name)
	{
		var time = new Date().getTime();

		if (!timeCounters)
			return;

		var timeCounter = timeCounters[name];
		if (timeCounter)
		{
			var diff = time - timeCounter;
			var label = name + ": " + diff + "ms";
			FireBug.console.log(label, "time", FireBug_logTextRow, context, true, true);

			delete timeCounters[name];
		}
	}

	this.count = function(key)
	{
		var frameId = "";  // ieerbug
		//var frameId = FireBugUtils.getStackFrameId();
		//if (frameId)
		{
			if (!frameCounters)
				frameCounters = {};

			if (key != undefined)
				frameId += key;

			var frameCounter = frameCounters[frameId];
			if (!frameCounter)
			{
				var logRow = FireBug.console.log("", "count", FireBug_logTextRow, context,
					true, true);

				frameCounter = {logRow: logRow, count: 1};
				frameCounters[frameId] = frameCounter;
			}
			else
				++frameCounter.count;

			var label = key == undefined
				? frameCounter.count
				: key + " " + frameCounter.count;

			frameCounter.logRow.firstChild.firstChild.nodeValue = label;
			
			//__framecounter.logrow//
			
		}
	}

	this.trace = function()
	{
		//var trace = new StackTrace(arguments.callee.caller);
		//FireBug.console.log(trace, "stackTrace", FireBug_logObjectRow, context);
		this.warn(["trace() not supported."]);
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////////
// console.js
function FireBugConsoleView()
{

}

FireBugConsoleView.prototype.log = function(args, rowClass, rowFunc, context){
	var logRow =this.createLogRow(rowClass);

	if (!rowFunc)
		rowFunc = FireBug_logObjectRow;

	var canceled = rowFunc.apply(this, [args, logRow, context]);
	if(canceled) return null;

    this.appendLogRow(logRow);//__appendLogRow//
    
	return logRow;
}

FireBugConsoleView.prototype.createLogRow = function(rowClass){
	var logDocument = window.document;

    var div = logDocument.createElement("div");

	div.className = "logRow logRow-" + rowClass;
	return div;
}


//////////////////////////////////////////////////////////////////////////////////////////////////
// loggers.js
FireBug_objectFormatMap =
{
	"text": FireBug_logText,
	"undefined": FireBug_logUndefined,
	"null": FireBug_logNull,
	"number": FireBug_logPrimitive,
	"string": FireBug_logString,
	"element": FireBug_logElement,
	"document": FireBug_logDocument,
	"textNode": FireBug_logTextNode,
	"object": FireBug_logObject,
	"array": FireBug_logArray,
	"consoleError": FireBug_logConsoleError,
	"function": FireBug_logFunction,
	"sourceLink": FireBug_logSourceLink,
	"stackTrace": FireBug_logStackTrace
};

FireBug_appendObject = function(object, logRow, precision, partial)
{
	var format;
	try
	{
		format = FireBug_getFormatForObject(object);
	}
	catch (exc)
	{
		format = FireBug_defaultObjectFormat;
	}

	var formatter = FireBug_objectFormatMap[format];
	formatter.apply(this, [object, logRow, precision, partial]);
}

FireBug_getFormatForObject = function(object)
{
	var type = typeof(object);

	if (type == "undefined")
		return "undefined";

	else if (object == null)
		return "null";

	else if (type == "object")
	{
		// Cross-browser class check (IE doesn't support "object instanceof Window") by nitoyon
		if(object instanceof ScriptError){
			return "consoleError";
		}

		if ("innerHTML" in object && typeof(object.innerHTML) == "string"
		 && "tagName" in object && typeof(object.tagName) == "string"
		 && "attributes" in object && typeof(object.attributes) == "object"
		 && "length" in object.attributes && typeof(object.attributes.length) == "number")
			return "element";
		else if ("location" in object && typeof(object.location) == "object"
		 && "write"  in object && "writeln" in object && "open" in object && "close" in object)
			return "document";
		else if ("setTimeout" in object && "setInterval"  in object && "history" in object)
			return "object";
		else if ("nodeType" in object && typeof(object.nodeType) == "number"
		 && object.nodeType == 3) // TEXT_NODE
			return "textNode";
		else if ("length" in object && typeof(object.length) == "number")
			return "array";
		else if (object instanceof SourceLink)
			return "sourceLink";
		else if (object instanceof StackTrace)
			return "stackTrace";
		return "object";
	}
	else if (type == "function")
		return "function";

	else if (type == "number" || type == "boolean")
		return "number";

	else if (type == "string")
		return "string";

	else
		return "object";
}

// Row Loggers
function FireBug_logFormattedRow(objects, logRow, context){
	FireBug_appendFormatted(objects, logRow);
}

function FireBug_logFormattedRows(objects, logRow, context)
{
	for (var i = 0; i < objects.length; ++i)
	{
		if (objects[i])
		{
			var objectRow = logRow.ownerDocument.createElement("div");
			objectRow.className = "row" + (i+1);
			FireBug_appendFormatted(objects[i], objectRow);
			logRow.appendChild(objectRow);
		}
	}
}

FireBug_appendFormatted = function(objects, logRow)
{
	if (!objects || !objects.length)
		return;

	var format = objects[0];
	var objIndex = 0;
	if (typeof(format) != "string"){
		format = "";
		objIndex = -1;
	}

	var formatParts = FireBug_parseFormat(format);
	for (var i = 0; i < formatParts.length; ++i){
		var formatPart = formatParts[i];
		if (formatPart && typeof(formatPart) == "object"){
			var object = objects[++objIndex];
			formatPart.func.apply(this, [object, logRow, formatPart.precision]);
		}
		else
			FireBug_logText(formatPart, logRow);
	}

	for (var i = objIndex+1; i < objects.length; ++i)
	{
		FireBug_logText(" ", logRow);
		FireBug_appendObject(objects[i], logRow, 0, false);
	}
}

// Object Loggers
function FireBug_logAnything(object, logRow, precision, partial)
{
	if (!precision || partial)
		FireBug_appendObject(object, logRow, precision, partial);
	else if (precision == -1)
		FireBug_logKeys(object, logRow);
	else
		FireBug_logDOM(object, logRow, precision, partial);
}

function FireBug_logNull(value, logRow, precision, partial)
{
	var doc = logRow.ownerDocument;

	var objectBox = FireBugUtils.createObjectSpan(doc, value, "null");
	logRow.appendChild(objectBox);
}

function FireBug_logUndefined(value, logRow, precision, partial)
{
	var doc = logRow.ownerDocument;

	var objectBox = FireBugUtils.createObjectSpan(doc, value, "undefined");
	logRow.appendChild(objectBox);
}

FireBug_parseFormat = function(format)
{
	var formatParts = [];

	var reg = /((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/;
	var index = 0;

	for (var m = reg.exec(format); m; m = reg.exec(format))
	{
		var type = m[8] ? m[8] : m[5];
		var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);

		var func = null;
		switch (type)
		{
			case "s":
				func = FireBug_logText;
				break;
			case "f":
			case "i":
			case "d":
				func = FireBug_logPrimitive;
				break;
			case "o":
				func = FireBug_logAnything;
				break;
			//case "x":
			//	func = FireBug_logElementFull;
				break;
		}

		formatParts.push(format.substr(0, m[0].charAt(0) == "%" ? m.index : m.index+1)); // m[0][0] -> m[0].charAt(0) by nitoyon
		formatParts.push({func: func, precision: precision});

		format = format.substr(m.index+m[0].length);
	}

	formatParts.push(format);

	return formatParts;
}

function FireBug_logText(value, logRow, precision, partial){
	var doc = logRow.ownerDocument;
 //   alert("_LogText:"+value);
	var objectBox = FireBugUtils.createObjectSpan(doc, value, value, "text");
	logRow.appendChild(objectBox);
}

function FireBug_logPrimitive(value, logRow, precision, partial){
	var doc = logRow.ownerDocument;

	var objectBox = FireBugUtils.createObjectSpan(doc, value, value);
	logRow.appendChild(objectBox);
}

function FireBug_logString(value, logRow, precision, partial)
{
	var doc = logRow.ownerDocument;

	if (partial)
	{
		if (value.length >= FireBug.stringCropLength)
			value = value.substr(0, FireBug.stringCropLength) + "...";

		value = FireBugUtils.escapeNewLines(value);
	}

	value = '"' + value + '"';

	var objectBox = FireBugUtils.createObjectSpan(doc, value, value);
	logRow.appendChild(objectBox);
}

// Row Loggers
function FireBug_logTextRow(object, logRow, context)
{
	FireBug_logText(object, logRow);
}

function FireBug_logObjectRow(object, logRow, context)
{
	FireBug_appendObject(object, logRow, 0, false);
}

// Object Loggers
function FireBug_logObject(object, logRow, precision, partial)
{
	if (!precision || partial)
	{
		var caption = FireBug.getObjectTitle(object);

		var logLink = withDocument(logRow.ownerDocument, function() {
			return FireBugUtils.createObjectLink(object, caption);
		});
		logRow.appendChild(logLink);
	}
	else if (precision == -1)
		FireBug_logKeys(object, logRow);
	else
		FireBug_logDOM(object, logRow, precision, partial);
}

function FireBug_logKeys(object, logRow)
{
	var names = [];
	for (var name in object)
		names.push(name);

	FireBug_logArray(names, logRow);
}

function FireBug_logFunction(fn, logRow, precision, partial)
{
	var doc = logRow.ownerDocument;

	// ieerbug : regex IE support
	//var fnRegex = /(function [^(]*\([^)]*\) )\{(.*?)\}$/;
	var fnRegex = /(function[^(]*\([^)]*\))/;

	var fnText = new String(fn).replace("\n", " ", "g");

	var m = fnRegex.exec(fnText);
	//if (m)
		//fnText = m[1] + " {...}";//comment by qinghai
	if (m)
	   fnText=fn.toString();

	var objectBox = FireBugUtils.createObjectSpan(doc, fnText);
	logRow.appendChild(objectBox);
}

function FireBug_logArray(array, logRow, precision, partial)
{
	var doc = logRow.ownerDocument;

	withDocument(doc, function()
	{
		logRow.appendChild(SPAN({"class": "arrayLeftBracket"}, "["));

		if (partial)
			logRow.appendChild(SPAN({"class": "arrayItem"}, array.length));

		else
		{
			for (var i = 0; i < array.length; ++i)
			{
				if (i > 0)
					logRow.appendChild(SPAN({"class": "arrayComma"}, ","));

				var itemNode = SPAN({"class": "arrayItem"});
				logRow.appendChild(itemNode);

				FireBug_appendObject(array[i], itemNode, 0, false);
			}
		}

		logRow.appendChild(SPAN({"class": "arrayRightBracket"}, "]"));
	});
}

function FireBug_logElement(element, logRow, precision, partial)
{
	if (!isElement(element))
		return;

	//logRow.title = FireBugUtils.getElementXPath(element);

	var html = FireBugUtils.getElementLineLabel(element, partial);
	var logLink = withDocument(logRow.ownerDocument, function() {
		return FireBugUtils.createObjectLink(element, html);
	});

	logRow.appendChild(logLink);
}

function FireBug_logDocument(doc, logRow, precision, partial)
{
	var caption = "[Document] " + doc.location;
	var logLink = withDocument(logRow.ownerDocument, function() {
		return FireBugUtils.createObjectLink(doc, caption);
	});
	logRow.appendChild(logLink);
}

function FireBug_logTextNode(textNode, logRow, precision, partial)
{
	var nodeValue = FireBugUtils.escapeNewLines(textNode.nodeValue);

	var caption = "[Text] \"" + nodeValue + "\"";
	var logLink = withDocument(logRow.ownerDocument, function() {
		return FireBugUtils.createObjectLink(textNode, caption);
	});
	logRow.appendChild(logLink);
}

function FireBug_logConsoleError(scriptError, logRow, precision, partial)
{
	var sourceName = scriptError.sourceName;
	var fromCommandLine = false;
	//var showStackTrace = false;
	//var fromCommandLine = sourceName.indexOf(FireBugCommandLine.evalScript) != -1;
	var showStackTrace = !fromCommandLine && scriptError.errorStackTrace;
	var titleBox = withDocument(logRow.ownerDocument, function() {
		return DIV({"class": "errorTitle"}, [
			showStackTrace ? TWISTY({onclick: onDiscloseError}) : null,
			TEXT(scriptError.errorMessage)
		]);
	});
	logRow.appendChild(titleBox);

	if (showStackTrace)
		logRow.errorStackTrace = scriptError.errorStackTrace;

	scriptError.errorStackTrace = null;

	if (scriptError.lineNumber && !fromCommandLine)
	{
		FireBugUtils.setClass(logRow, "logRow-sourceLink");
		var sourceLink = new SourceLink(sourceName, scriptError.lineNumber);
		FireBug_appendObject(sourceLink, logRow);
	}

	if (scriptError.sourceLine)
	{
		var sourceBox = withDocument(logRow.ownerDocument, function() {
			return DIV({"class": "errorSource"}, [TEXT(scriptError.sourceLine)]);
		});
		logRow.appendChild(sourceBox);
	}
}

function onDiscloseError()
{
	var titleBox = this.parentNode;
	var logRow = titleBox.parentNode;

	//var twisty = FireBugUtils.getChildByClassName(titleBox, "twisty");
	var twisty = titleBox.getElementsByTagName("img")[0];
	var body = FireBugUtils.getChildByClassName(logRow, "errorStack");

	if (!body)
	{
		body = withDocument(this.ownerDocument, function() {
			return DIV();
		});
		body.className = "disclosure errorStack";
		logRow.appendChild(body);

		FireBug_logStackTrace(logRow.errorStackTrace, body);
	}

	var closed = body.style.display != "block";
	twisty.src = pathToScript + (closed ? "twistyOpen.gif" : "twistyClosed.gif");
	body.style.display = closed ? "block" : "none";
}

function FireBug_logSourceLink(sourceLink, logRow, precision, partial)
{
	var fileName = FireBugUtils.parseFileNameFromURL(sourceLink.href);
	var linkTitle = fileName + " (line " + sourceLink.line + ")";

	var logLink = withDocument(logRow.ownerDocument, function() {
		return FireBugUtils.createObjectLink(sourceLink, linkTitle);
	});

	logLink.title = sourceLink.href;

	logRow.appendChild(logLink);
}

function FireBug_logStackTrace(stackTrace, logRow, precision, partial)
{
	for (var i = 0; i < stackTrace.frames.length; ++i)
	{
		var frame = stackTrace.frames[i];

		var functionName = frame.functionName ? frame.functionName : "null";

		var itemRow = withDocument(logRow.ownerDocument, function() {
			return DIV({"class": "stackFrame"}, [
				SPAN({"class": "stackFunctionName"}, functionName),
			]);
		});

		// IEerBug: arguments.callee callstack cannot support fileName & line...
		//var sourceLink = new SourceLink(frame.fileName, frame.line);
		//FireBug_logSourceLink(sourceLink, itemRow);

		logRow.appendChild(itemRow);
	}
}

function FireBug_logSourceString(sourceString, logRow, precision, partial)
{
	sourceString = FireBugUtils.escapeHTML(sourceString);

	// Split the source by line breaks
	var lines = sourceString.split(/\r\n|\r|\n/);

	var maxLines = (lines.length + "").length;
	var html = [];

	withDocument(logRow.ownerDocument, function() {
		for (var i = 0; i < lines.length; ++i)
		{
			// Make sure all line numbers are the same width (with a fixed-width font)
			var lineNo = (i+1) + "";
			while (lineNo.length < maxLines)
				lineNo = " " + lineNo;

			html.push('<div class="sourceRow"><a class="sourceLine">');
			html.push(lineNo);
			html.push('</a><span class="sourceRowText">');
			html.push(lines[i]);
			html.push('</span></div>');
		}
	});

	// Believe it or not, using innerHTML is 10x faster (no exaggeration) than constructing
	// DOM elements and inserting them one by one
	logRow.innerHTML = html.join("");
}

function FireBug_logDOM(object, logRow, precision, partial)
{
	var doc = logRow.ownerDocument;

	function isFunction(value) { return (typeof value) == "function"; }
	function isNotFunction(value) { return (typeof value) != "function"; }

	precision = precision > 0 ? precision-1 : 0;

	var objectType = typeof(object);
	if (objectType == "function")
	{
		FireBug_logSourceString(object+"", logRow);
	}
	else if (objectType == "string")
	{
		FireBug_logSourceString(object, logRow);
	}
	else if (objectType == "object")
	{
		var table = doc.createElement("table");

		/* ieerbug */
		table.style.width = "100%";
		table.style.tableLayout = "fixed";

		var col = doc.createElement("col");
		col.style.width = "200px";
		table.appendChild(col);
		var col = doc.createElement("col");
		table.appendChild(col);

		var tbody = doc.createElement("tbody");	// IE needs tbody tag.
		table.appendChild(tbody);
		/* ieerbug end */

		for (var name in object)
		{
			try
			{
				FireBug_createObjectRow(name, object[name], isNotFunction, tbody, precision);
			}
			catch (exc) {}
		}

		for (var name in object)
		{
			try
			{
				FireBug_createObjectRow(name, object[name], isFunction, tbody, precision);
			}
			catch (exc) {}
		}

		logRow.appendChild(table);
	}
}

function FireBug_createObjectRow(name, value, filter, table, precision)
{
	if ((filter && !filter(value)))
		return;

	var isFunction = typeof(value) == "function";
	var isConstant = FireBugUtils.isAllUpperCase(name);

	var doc = table.ownerDocument;
	var tr = doc.createElement("tr");
	tr.className = "propertyRow" +
		(isFunction ? " propertyRow-function" : "") +
		(isConstant ? " propertyRow-constant" : "");

	var td = doc.createElement("td");
	td.setAttribute("vAlign", "top");
	td.className = "propertyLabel";

	// Create the property name
	var labelElt = doc.createElement("span");
	labelElt.className = "propertyName";
	var labelText = doc.createTextNode(name);
	labelElt.appendChild(labelText);
	tr.appendChild(td);

	// Create the twisty if the value is an object
	var valueType = typeof(value);
	if (valueType == "function" || (valueType == "object" && value != null)
		|| (valueType == "string" && value.length > FireBug.stringCropLength))
	{
		td.className += " propertyContainerLabel"
		labelElt.className += " propertyContainerName"

		var twisty = doc.createElement("img");
		twisty.src = "blank.gif";
		twisty.className = "twisty propertyTwisty";
		td.appendChild(twisty);

		var self = this;
		labelElt.onclick = function() { FireBug_toggleObjectRow(value, tr); }
		twisty.onclick = function() { FireBug_toggleObjectRow(value, tr); }
	}

	td.appendChild(labelElt);

	// Create the property value
	td = doc.createElement("td");
	td.className = "propertyValue";
	td.setAttribute("valign", "top");

	FireBug_appendObject(value, td, 0, true);

	tr.appendChild(td);
	table.appendChild(tr);

	if (valueType == "object" && value != null && precision > 0)
		FireBug_toggleObjectRow(value, tr, precision);
}

function FireBug_toggleObjectRow(object, tr, precision)
{
	var doc = tr.ownerDocument;

	var twisty = tr.firstChild.firstChild;

	if (tr.nextSibling && tr.nextSibling.className == "propertyChildRow")
	{
		FireBugUtils.removeClass(twisty, "open");

		tr.parentNode.removeChild(tr.nextSibling);
	}
	else
	{
		FireBugUtils.setClass(twisty, "open");

		var td = doc.createElement("td");
		td.className = "propertyChildBox";
		td.setAttribute("colSpan", 2);	// colspan -> colSpan

		FireBug_logDOM(object, td, precision);

		var newRow = doc.createElement("tr");
		newRow.className = "propertyChildRow";
		newRow.appendChild(td);

		if (tr.nextSibling)
			tr.parentNode.insertBefore(newRow, tr.nextSibling);
		else
			tr.parentNode.appendChild(newRow);
	}
}


//////////////////////////////////////////////////////////////////////////////////////////////////
// util.js
var FireBugUtils = {};

FireBugUtils.isAllUpperCase = function(str)
{
	return str.search(/[A-Z]/) >= 0 && str.search(/[a-z]/) == -1;
}

FireBugUtils.getElementLineLabel = function(element, partial)
{
	var tagName = element.tagName.toLowerCase();

	var html = "&lt;<span class=\"nodeTag\">" + tagName + "</span>";

	if (partial)
		html += this.getElementPartialAttributes(element);
	else
		html += this.getElementFullAttributes(element);

	html += "&gt;";

	return html;
}

FireBugUtils.getElementFullAttributes = function(element)
{
	var html = "";

	for (var i = 0; i < element.attributes.length; ++i)
	{
		var attr = element.attributes[i];

		// Hide attributes set by FireBug
		if ((attr.localName || attr.nodeName).indexOf("firebug-") == 0)
			continue;

		// filter for IE by nitoyon
		if(attr.nodeValue == null || attr.nodeValue == "")
			continue;

		html += " " + (attr.localName || attr.nodeName)
			+ '="<span class="nodeAttr" targetAttr="' + attr.localName + '">'
			+ attr.nodeValue + '</span>"';
	}

	return html;
}

FireBugUtils.getElementPartialAttributes = function(element)
{
	var html = "";

	if (element.id)
		html += ' id="<span class="nodeAttr" targetAttr="id">' + element.id + '</span>"';
	if (element.className)
		html += ' class="<span class="nodeAttr" targetAttr="class">'
				+ element.className + '</span>"';

	return html;
}

FireBugUtils.parseFileNameFromURL = function(url)
{
	if (!url)
		return "";

	var lastSlash = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));
	var fileName = url.substr(lastSlash+1);
	if (fileName.length == 0)
		fileName = url;
	if (fileName.length > 17)
		fileName = fileName.substr(0, 17) + "...";

	return fileName;
}

FireBugUtils.createObjectSpan = function(doc, object, title, format)
{
	if (!format)
		format = FireBug_getFormatForObject(object);

	var span = doc.createElement("span");
	span.className = "objectBox objectBox-"+format;

	var text = doc.createTextNode(title ? title : object);
	span.appendChild(text);

	return span;
}

FireBug.getObjectTitle = function(object)
{
	if (typeof(object) == "undefined")
	{
		return "undefined";
	}
	else if (object == null)
	{
		return "null";
	}
	// deleted (i.e. "if(object instanceof Window)") by nitoyon
	else
		return object;
}

FireBugUtils.createObjectLink = function(object, title, className, onClick)
{
	var link = contextDocument.createElement("a");
	if (className)
		link.className = className;

	this.makeObjectLink(object, title, link, onClick);

	return link;
}

FireBugUtils.makeObjectLink = function(object, title, linkElt, onClick)
{
	var format = FireBug_getFormatForObject(object);
	FireBugUtils.setClass(linkElt, "objectLink objectLink-"+format);

	linkElt.linkObject = object;

	if (!linkElt.firstChild)
		linkElt.innerHTML = title;
	else
		linkElt.firstChild.nodeValue = title;

	linkElt.href = "#";
/*	linkElt.onmouseover = function(event)
	{
		FireBug.highlightObject(object);
	}

	linkElt.onmouseout = function(event)
	{
		FireBug.highlightObject(null);
	}*/

	linkElt.onclick = function(event)
	{
		var event = event || window.event

//		if (event.button == 0 && !event.ctrlKey && !event.shiftKey &&
//			!event.altKey && !event.metaKey)
//		{
			if (onClick)
				onClick.apply(linkElt);
			else
				FireBug.browseObject(object);
//		}
//		else if (event.metaKey || event.ctrlKey)
//			FireBug.visitObject(object);
	}
}

FireBugUtils.escapeNewLines = function(value)
{
	return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n");
}

FireBugUtils.escapeHTML = function(value)
{
	return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
}

FireBugUtils.hasClass = function(node, name)
{
	return node && node.className && node.className.indexOf(name) != -1;
}

FireBugUtils.setClass = function(node, name)
{
	if (node && !this.hasClass(node, name))
		node.className += " " + name;
}

FireBugUtils.removeClass = function(node, name)
{
	if (node && node.className)
	{
		var index = node.className.indexOf(name);
		if (index >= 0)
		{
			var size = name.length;
			node.className = node.className.substr(0,index-1) + node.className.substr(index+size);
		}
	}
}

FireBugUtils.toggleClass = function(elt, name)
{
	if (this.hasClass(elt, name))
		this.removeClass(elt, name);
	else
		this.setClass(elt, name);
}

FireBugUtils.getChildByClassName = function(node, className)
{
	for (var child = node.firstChild; child; child = child.nextSibling)
	{
		if (this.hasClass(child, className))
			return child;
	}

	return null;
}

//
var contextDocument = document;

FireBugUtils.createElement = function(name, attrs, content)
{
	var node = contextDocument.createElement(name);

	if (attrs)
	{
		for (var name in attrs)
		{
			var value = attrs[name];
			if (typeof(value) == "function")
				node[name] = value;
			else
				node.setAttribute(name, value);
		}
	}

	if (content != null && content != undefined)
	{
		// IEerBug: commented out
		//if (content instanceof Node)
		//	node.appendChild(content);
		if(content instanceof Array)
			appendNodes(node, content);
		else
			node.innerHTML = content;
	}

	return node;
}

function H1(attrs, text) { return FireBugUtils.createElement("h1", attrs, text); }
function H2(attrs, text) { return FireBugUtils.createElement("h2", attrs, text); }
function H3(attrs, text) { return FireBugUtils.createElement("h3", attrs, text); }
function DIV(attrs, text) { return FireBugUtils.createElement("div", attrs, text); }
function PRE(attrs, text) { return FireBugUtils.createElement("pre", attrs, text); }
function SPAN(attrs, text) { return FireBugUtils.createElement("span", attrs, text); }
function IMG(attrs, text) { return FireBugUtils.createElement("img", attrs, text); }
function HR(attrs, text) { return FireBugUtils.createElement("hr", attrs, text); }
function LI(attrs, text) { return FireBugUtils.createElement("li", attrs, text); }
function A(attrs, text) { return FireBugUtils.createElement("a", attrs, text); }
//function TWISTY(attrs) { attrs["class"] = "twisty"; attrs["src"] = "blank.gif"; return IMG(attrs); }
function TWISTY(attrs) { var i = IMG(attrs); i.src = "twistyClosed.gif"; i.style.verticalAlign = "middle"; return i; }
function TEXT(text) { return contextDocument.createTextNode(text); }

function withDocument(doc, fn)
{
	var previousDocument = contextDocument;
	contextDocument = doc;

	var result = fn();

	contextDocument = previousDocument;

	return result;
}

function appendNodes(parent, nodes)
{
	for (var i in nodes)
	{
		var content = nodes[i];

		// IEerBug changed.
		var type = FireBug_getFormatForObject(content);
		//if (content instanceof Node)
		if (type == "textNode" || type == "element"){
			parent.appendChild(content);}
		else if (content instanceof Array)
			appendNodes(parent, content);
		else if (content != null && content != undefined)
			parent.appendChild(parent.ownerDocument.createTextNode(content));
	}

	return parent;
}

function isElement(o)
{
	try{
		// edited by nitoyon
		if(typeof(o.innerHTML) == "string"){
			return true;
		}
	}
	catch (ex) {
		return false;
	}
}

function sliceArray(array, index)
{
	var slice = [];
	for (var i = index; i < array.length; ++i)
		slice.push(array[i]);

	return slice;
}
}

IEerBug();
