function DBG(conf) {
	conf == undefined || conf.width == undefined
	? this.setDefaultWidth()
	: this.width = conf.width

	conf == undefined || conf.height == undefined
	? this.setDefaultHeight()
	: this.height = conf.height

	conf == undefined || conf.name == undefined
	? this.setDefaultName()
	: this.name = conf.name

	conf == undefined || conf.y == undefined
	? this.setDefaultY()
	: this.y = conf.y

	conf == undefined || conf.x == undefined
	? this.setDefaultX()
	: this.x = conf.x

	this.cssFile = "dbg.css"
	
	this.resizeMainWindow()
	this.openWindow()
	this.createStyle()
	this.createBody()
	this.createTextArea()
	this.focus()
	this.focusMainWindow()
}

	DBG.prototype.setDefaultWidth = function() {
		this.width = window.screen.width > 800
					 ? window.screen.width - 800
					 : 100
	}

	DBG.prototype.setDefaultHeight = function() {
		this.height = window.screen.availHeight
	}

	DBG.prototype.setDefaultName = function() {
		this.name = "dbg"
	}

	DBG.prototype.setDefaultY = function() {
		this.y = 0
	}

	DBG.prototype.setDefaultX = function() {
		this.x = window.screen.availWidth - this.width
	}

	DBG.prototype.openWindow = function() {
		this.wnd = window.open("", this.name
							   , "width=" + this.width
							   + ", height=" + this.height
							   + ", top=" + this.y
							   + ", left=" + this.x)
	}

	DBG.prototype.resizeMainWindow = function() {
		window.moveTo(0, 0)
		window.resizeTo(this.x, this.height)
	}

	DBG.prototype.createStyle = function() {
		this.style = 
		'* { font-size: 9px; font-family: verdana; margin: 0; padding: 0; border: none; }' +
		'body { margin: 5px; _margin-bottom: 40px;  }' +
		'textarea { width: 100%; height: 100%; border: 1px solid silver; }'
	}

	DBG.prototype.createBody = function() {
		this.doc = this.wnd.document
		this.doc.open("text/html", "replace")
		this.doc.write(
			'<html>' +
			'	<head>' +
			'		<title>JS DBG</title>' +
			'		<style>' +
						this.style +
			'		</style>' + 
			'	</head>' +
			'	<body>' +
			'		<textarea name="area" id="area"></textarea>' +
			'	</body>' +
			'</html>'
		)
		this.doc.close()
	}

	DBG.prototype.focus = function() {
		this.wnd.focus()
	}

	DBG.prototype.focusMainWindow = function() {
		this.wnd.opener.focus()
	}

	DBG.prototype.createTextArea = function() {
		this.area = this.doc.getElementById("area")
	}

	DBG.prototype.scroll = function() {
		this.area.scrollTop = this.area.scrollHeight
	}

	// private static method
	DBG.singleton = function() {
		return window.dbg == undefined
			   ? window.dbg = new DBG()
			   : window.dbg
	}

	// public static method
	DBG.trace = function(txt) {
		if(!DBG.enabled) return;
		var dbg = DBG.singleton()
		dbg.area.value += new String(txt) + "\n"
		dbg.scroll()
	}

	// public static method
	DBG.clearTrace = function(txt) {
		if(!DBG.enabled) return;
		var dbg = DBG.singleton()
		DBG.clear();
		DBG.trace(txt);
	}

	// public static method
	DBG.clear = function() {
		if(!DBG.enabled) return;
		var dbg = DBG.singleton()
		dbg.area.value = ""
	}
	
	DBG.dump = function(obj ,maxDepth){
		if (typeof(maxDepth) != 'number'){ maxDepth = 2 }
		DumperMaxDepth = maxDepth; 
		if(!DBG.enabled) return;
		var dbg = DBG.singleton()
		strDump = Dumper(obj,DumperGetArgs(arguments,2))
		dbg.area.value += new String(strDump) + "\n"
		dbg.scroll()
	}

DBG.enabled = document.location.href.indexOf("DBG=1") != -1

	var DumperIndent = 1;
	var DumperIndentText = " ";
	var DumperNewline = "\n";
	var DumperObject = null; // Keeps track of the root object passed in
	var DumperMaxDepth = -1; // Max depth that Dumper will traverse in object
	var DumperIgnoreStandardObjects = true; // Ignore top-level objects like window, document
	var DumperProperties = null; // Holds properties of top-level object to traverse - others are igonred
	var DumperTagProperties = new Object(); // Holds properties to traverse for certain HTML tags

	function DumperGetArgs(a,index) {
		var args = new Array();
		// This is kind of ugly, but I don't want to use js1.2 functions, just in case...
		for (var i=index; i<a.length; i++) {
			args[args.length] = a[i];
		}
		return args;
	}

	function DumperPad(len) {
		var ret = "";
		for (var i=0; i<len; i++) {
			ret += DumperIndentText;
		}
		return ret;
	}

	function Dumper(o) {
		var level = 1;
		var indentLevel = DumperIndent;
		var ret = "";
		if (arguments.length>1 && typeof(arguments[1])=="number") {
			level = arguments[1];
			indentLevel = arguments[2];
			if (o == DumperObject) {
				return "[original object]";
			}
		}
		else {
			DumperObject = o;
			// If a list of properties are passed in
			if (arguments.length>1) {
				var list = arguments;
				var listIndex = 1;
				if (typeof(arguments[1])=="object") {
					list = arguments[1];
					listIndex = 0;
				}
				for (var i=listIndex; i<list.length; i++) {
					if (DumperProperties == null) { DumperProperties = new Object(); }
					DumperProperties[list[i]]=1;
				}
			}
		}

		if (DumperIgnoreStandardObjects) {
			if (o==window || o==window.document) {
				return "[Ignored Object]";
			}
		}
		// NULL
		if (o==null) {
			ret = "[null]";
			return ret;
		}
		// FUNCTION
		if (typeof(o)=="function") {
			ret = "[function]";
			return ret;
		} 
		// BOOLEAN
		if (typeof(o)=="boolean") {
			ret = (o)?"true":"false";
			return ret;
		} 
		// STRING
		if (typeof(o)=="string") {
			ret = "'" + o + "'";
			return ret;
		} 
		// NUMBER	
		if (typeof(o)=="number") {
			ret = o;
			return ret;
		}
		if (DumperMaxDepth != -1 && level > DumperMaxDepth) {
			return o;
		}
		if (typeof(o)=="object") {
			if (typeof(o.length)=="number" ) {
				// ARRAY
				ret = "[";
				for (i=0; i<o.length;i++) {
					if (i>0) {
						ret += "," + DumperNewline + DumperPad(indentLevel);
					}
					else {
						ret += DumperNewline + DumperPad(indentLevel);
					}
					ret += Dumper(o[i],level+1,indentLevel-0+DumperIndent);
				}
				if (i > 0) {
					ret += DumperNewline + DumperPad(indentLevel-DumperIndent);
				}
				ret += "]";
				return ret;
			}
			else {
				// OBJECT
				ret = "{";
				var count = 0;
				for (i in o) {
					if (o==DumperObject && DumperProperties!=null && DumperProperties[i]!=1) {
						// do nothing with this node
					}
					else {
						if (typeof(o[i]) != "unknown") {
							var processAttribute = true;
							// Check if this is a tag object, and if so, if we have to limit properties to look at
							if (typeof(o.tagName)!="undefined") {
								if (typeof(DumperTagProperties[o.tagName])!="undefined") {
									processAttribute = false;
									for (var p=0; p<DumperTagProperties[o.tagName].length; p++) {
										if (DumperTagProperties[o.tagName][p]==i) {
											processAttribute = true;
											break;
										}
									}
								}
							}
							if (processAttribute) {
								if (count++>0) {
									ret += "," + DumperNewline + DumperPad(indentLevel);
								}
								else {
									ret += DumperNewline + DumperPad(indentLevel);
								}
								ret += "'" + i + "' => " + Dumper(o[i],level+1,indentLevel-0+i.length+6+DumperIndent);
							}
						}
					}
				}
				if (count > 0) {
					ret += DumperNewline + DumperPad(indentLevel-DumperIndent);
				}
				ret += "}";
				return ret;
			}
		}
	}