﻿if (d3) throw( "d3 object has already been instantiated!  d3.base.js should be first script." );
var d3 = new Object();
d3.env = 
{
	HAS_ACTIVEX : (typeof(ActiveXObject) != "undefined"),
	IS_IE : (typeof(window) != "undefined" && typeof(ActiveXObject) != "undefined"),
	IS_BROWSER : (typeof(window) != "undefined" && typeof(document) != "undefined"),
	IS_MOZILLA : (typeof(window) != "undefined" && typeof(XMLSerializer) != "undefined"),
	IS_ASP : (typeof(Server) != "undefined" && typeof(Request) != "undefined"),
	IS_WSCRIPT : (typeof(WScript) != "undefined")
};

d3._about = "d3methods modular utility class";
Object.prototype.about = function ( tab, recurse, alt )
{
	var s = "";
	var object = (alt ? alt : this);
	var aFunc = new Array(), aProp = new Array;
	if (object._about) aProp.push( object._about );
	if (!recurse) recurse = (object.about && object.about.recurse);
	for (var item in object)
	{
		if (item.substring(0,1) == "_" || item == "about") continue;	// skip internal use onlys
		try
		{
			switch (typeof( object[item] ))
			{
				case "function":
				{
					s = item + "( ";
					for (var i = 0; i < object[item].length; i++)
						s += ((i == 0) ? "" : ", ") + String.fromCharCode( "a".charCodeAt(0) + i);
					aFunc.push( s += " )" );
					break;
				}
				case "object":
				{
					s = item;
					if (d3.isNull(object[item]))
						s += " = null";
					else if ( recurse  )
 						s += ": "+ object[item].about( d3.ifNot(tab,"") + item + ".", recurse );
					else 
						s += " = [object]";
					aProp.push( s );
					break;
				}
				default:
				{
					aProp.push( item + " = "+ object[item] );
				}
			}
		}
		catch (e)
		{
			aProp.push( item + ": [unknown type]" );
		}
	}
	s = ((typeof(tab)=="string")? tab : "");
	return s + aProp.concat( aFunc ).sort().join( "\n"+ s );
};

/* general utility functions */
d3.isNull = function( x )
{
	return (x == null);
};

d3.isNumeric = function( x )
{
	if (x == null) return false;
	return !isNaN( x );
}

d3.ifNot = function( x, y )
{
	return (!x) ? y : x;
};

d3.ifNull = function( x, y )
{
	return (x == null) ? y : x;
};

d3.min = function( )
{
	if (arguments.length < 1) return null;
	var x = arguments[0];
	for (var k = 1; k < arguments.length; k++)
		if (arguments[k] < x) x = arguments[k];
	return x;
}
d3.max = function( )
{
	if (arguments.length < 1) return null;
	var x = arguments[0];
	for (var k = 1; k < arguments.length; k++)
		if (arguments[k] > x) x = arguments[k];
	return x;
}

d3.nullIfEqual = function( x, y )
{
	if (typeof( x ) != typeof( y )) return x;
	if (typeof( x ) == "string") return (x.compare( y ) == 0) ? null : x;
	return (x == y) ? null : x;
};

d3.nullIfNotEqual = function( x, y )
{
	if (typeof( x ) != typeof( y )) return null;
	if (typeof( x ) == "string") return (this.textCompare( x, y ) == 0) ? x : null;
	return (x == y) ? x : null;
};

d3.Enumerator = function( list )
{
	var k = 0;
	if (typeof(list.length) != "number") throw "Enumerator requires a colleciton";
	var _l = list;
	var _len = _l.length;
	
	this.reset = function () { this.position = k = 0; }
	this.position = k;
	this.length = _len;
	this.moveNext = function () 
	{
		if (k < _len) k++;
		return this.item();
	}
	this.item = function ()
	{
		var x;
		if (k < _len) 
		{
			x = _l.item(k);
			this.position = k;
		}
		else
			this.position = x;
		this.length = _len;
		return x;
	}
	this.atEnd = function () { return k >= _len; }
};

/* built-in type extensions */
String.prototype.contains = function ( search )
{
	if (typeof(search) == "string")
		return (this.indexOf( search ) > -1);
	else
		return (this.search( search ) > -1);
}

String.prototype.startsWith = function ( fragment )
{
	if (typeof(fragment) != "string") return false;
	return (this.substring(0,fragment.length) == fragment);
}
String.prototype.endsWith = function ( fragment )
{
	if (typeof(fragment) != "string") return false;
	return (this.substring(this.length - fragment.length) == fragment);
}
String.prototype.dropTrailing = function ( fragment )
{
	return this.endsWith( fragment ) ? this.substr( 0, this.length - (fragment.length) ) : this;
}



String.truncate = function ( obj, len )
{
	var s = new String(obj);
	if (!len || len < 0 || s.length < len) return s;
	return s.substring( 0, len - 1 ) + "…";
}

Date.prototype._toString = Date.prototype.toString;	
Date.prototype.toString = function ( format )
{
	if (typeof(format) != "string") return this._toString();
	var sDate = "", sTime = "", pad;
	// normalize the format
	var fmt = format.toLowerCase().replace( "year","yyyy" ).replace( "month","mm" ).replace( "day","dd" ).replace( "hour|hr","hh" ).replace( "min", "mm" ).replace( "sec", "ss" ).replace( "am/pm|pm", "am" ).replace("a/p|p","a").replace("pm","am");

	var iso = fmt.contains( /(iso|xml)/i );
	if (iso) fmt = "yyyy-mm-ddThh:mm:ss"
	else if (fmt == "date") fmt = "mm/dd/yyyy";
	else if (fmt == "time") fmt = "hh:mmam";
	else if (fmt == "datetime") fmt = "mm/dd/yyyy hh:mmam";
	var delim = (iso || fmt.contains( "-" )) ? "-" : "/";
	if (fmt.contains( /(yy|year)[\-\/]/i ))
	{
		sDate = this.getFullYear().toString() + delim + 
			(this.getMonth() + 1).zeroPad(2) + delim +
			(this.getDate()).zeroPad(2);	// dates with leading year always have 2 digit month and day and full year
	}
	else if (fmt.contains( /d/i ))
	{
		pad = fmt.contains( /(mm|dd)[-\/]/i ) ? 2 : 1;
		sDate = (this.getMonth() + 1).zeroPad(pad) + "/" +
			(this.getDate()).zeroPad(pad);
		if (fmt.contains(/y/i))
		{
			var year = this.getFullYear();
			if (!fmt.contains( /(yyyy|year)/i )) year = year % 100;
			sDate += "/" + year.zeroPad(2); 
		}
	}
	
	if (fmt.contains( /h/i ))
	{
		pad = (iso || fmt.contains( /(hh)/i )) ? 2 : 1;
		var hour = this.getHours(), ampm = "";
		if (fmt.contains( /(a|p)/i ))
		{
			ampm = (hour >= 12) ? "p" : "a";
			if (hour == 0) hour = 12; else if (hour > 12) hour -= 12;
			if (fmt.contains( /(am|pm)/i )) ampm += "m";
			if (format.contains( /(AM|PM)/ )) ampm = ampm.toUpperCase();
			if (fmt.contains( /( a)|( p)/i )) ampm = " "+ ampm;
		}
		sTime = hour.zeroPad(pad) + ":" +
			this.getMinutes().zeroPad(2);
		if (iso || fmt.contains( /s/i )) sTime += ":"+ this.getSeconds().zeroPad(pad);
		sTime += ampm;
	}
	if (iso) return sDate +	"T" + sTime;
	if (sDate == "") return sTime;
	if (sTime == "") return sDate;
	if (fmt.search( "d" ) < fmt.search( /h/i )) return sDate + " " + sTime;
	return sTime + " " + sDate;
};

Array.fromCollection = function( collection )
{
	var a = new Array();
	for (var k = 0; k < collection.length; k++)
		a.push( collection.item( k ) );
	return a;
};

String.bellChar = String.fromCharCode( 7 );
String.prototype._indexOf = String.prototype.indexOf;
String.prototype.indexOf = function( subString, startIndex, caseSensitive )
{
	if (typeof(caseSensitive) == "undefined") caseSensitive = true;
	if (caseSensitive) 
		return this._indexOf( subString, startIndex );
	return this.toLowerCase()._indexOf( (new String(subString)).toLowerCase(), startIndex );
};

Array.prototype.find = function ( item, caseSensitive )
{
	if (this.length < 1) return -1;
	if (caseSensitive == true && typeof(item) == "string")
	{
		var itemL = item.toLowerCase();
		for (var k = this.length; k >= 0; k--)
			if (itemL == (new String(this[k])).toLowerCase()) return k;
	}
	else
		for (var k = this.length; k >= 0; k--)
			if (this[k] == item) return k;
	return -1;
}

Array.prototype.has = function ( item, caseSensitive )
{
	if (this.length < 1) return false;
	if (typeof(item) == "string")
	{
		var s = String.bellChar + this.join( String.bellChar ) + String.bellChar;
		return (s.indexOf( String.bellChar + item + String.bellChar, 0, caseSensitive ) > -1);
	}

	for (var k = this.length; k >= 0; k--)
		if (this[k] == item) return true;
	return false;
};

Array.prototype.item = function ( idx )
{
	return this[idx];
};

String.prototype.replaceAll = function( search, replace )
{
	return this.replace( new RegExp( search, "g" ), replace );
};

String.prototype.splitAt = function( at )
{
	if (typeof(at) == "number")
		return [ this.substring( 0, Math.floor(at) ), this.substring( Math.floor(at) + 1 ) ];
	if (typeof(at) != "string") return [ this ];
	var k = this.indexOf( at );
	if (k < 0) return [ this ];
	return [ this.substring( 0, k ), this.substring( k + (at.length) )];
};

String.prototype.trim = function( scope )
{
	if (scope === undefined) 
		return this.replace(/(^\s*)|(\s*$)/g, "");
	var s = (new String(scope)).substr( 0, 1 ).toLowerCase();
	if (s == "s" || s == "l" || s == "t")	// 'start', 'left', true
		return this.replace(/^\s*/g, "");
	else
		return this.replace(/\s*$/g, "");
};

String.compareText = function( a, b )
{
	if (a == null || b == null) return null;
	if (typeof(a) == "undefined" || typeof(b) == "undefined") return undefined;
	var a1 = (new String(a)).trim().toLowerCase();
	var b1 = (new String(b)).trim().toLowerCase();
	if (a1 == b1) return 0;
	if (a1 < b1) return -1; else return 1;
};

String.prototype.compare = function( b )
{
	return String.compareText( this, b );
};

String.prototype.escapeHtml = function()
{
	return this.replace( /\&/g, "&amp;" )
		.replace( /\</g, "&lt;" );
};

String.prototype.unescapeHtml = function()
{
	return this.replace(/&amp;/g,"&")
		.replace(/&lt;/g,"<");
};

String.prototype.escapeXml = function()
{
	return this.replace( /\&/g, "&amp;" )
		.replace( /\</g, "&lt;" ).replace( /\>/g, "&gt;" )
		.replace( /\"/g, "&quot;" ).replace( /\'/g, "&apos;" );
};

String.prototype.unescapeXml = function()
{
	return this.replace(/&amp;/g,"&")
		.replace(/&lt;/g,"<").replace(/&gt;/g,">")
		.replace(/&quot;/g,"\"").replace(/&apos;/g,"'");
};

String.prototype.token = function( delim, idx )
{
	if (this.length == 0) return "";
	var a = this.split( delim );
	if (typeof(idx) == "string")
	{
		if (idx == "last") return a[a.length - 1];
		if (idx == "first") return a[0];
		idx = parseInt( idx );
	}
	if (typeof(idx) != "number") return undefined;
	if (idx < 0 || idx >= a.length) return undefined;
	return a[idx];
};

String.prototype.isEmailAddress = function ()
{
	return (this.search( /^[a-zA-Z0-9._+&*# -]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*$/ ) == 0);
}
Number.prototype.zeroPad = function ( pad )
{
	var s = this.toString();
	if (s.length < pad)
		s = "00000000000000".substring( 0, pad - s.length ) + s;
	return s;
};

Math._round = Math.round;
Math.round = function( num , dec )
{
	if (typeof(dec) == "undefined") dec = 0; else dec = Math.floor( dec );
	if (isNaN(num + dec) || dec < 0 || dec > 12) return Math._round( num );
	var n = Math.pow( 10, dec );
	return Math._round( num * n ) / n;
}

Math.bracket = function( num, min, max )
{
	if (num < min) return min;
	if (num > max) return max;
	return num;
}

// all numerics aren't Numbers by default so a static method will be created instead
Number.format = function ( num, format )
{
	if (isNaN( num )) return "?";
	if (typeof(format) != "string") return num.toString( format );
	num = new Number( num );

	var parens = format.contains("\\(");
	if (parens) format = format.replaceAll( "\\(", "" ).replaceAll( "\\)", "" );
	if (format.contains("money|currency")) format = "$,9.99";
	format = format.trim();
	var comma = format.contains(",");
	if (comma) format = format.replaceAll( ",", "" );
	var dollar = format.contains("\\$");
	if (dollar) format = format.replaceAll( "\\$", "" );	
	var zero = (format.substr(0,1) == "0");
		
	var w = 0, f = 0;
	var a = format.split(".");
	if (a.length > 2) return "?" + num.toString();
	if (a.length > 1) f = a[1].length;
	w = a[0].length;
	
	var s = Math.abs( num ).toFixed( (f > 20 ? 20 : f) );
	a = s.split( "." );
	if (comma)
	{
		for (var k = a[0].length - 3; k > 0; k -= 3)
		{
			a[0] = a[0].substr( 0, k ) + "," + a[0].substr( k );
		}
		w += Math.floor((w + 1) / 3);
		zero = false;
	}
	if (dollar) 
	{
		a[0] = "$"+ a[0];
		w += 1;
		zero = false;
	}
	if (num < 0)
		if (parens)
		{
			a[0] = "("+ a[0];
			a[a.length - 1] += ")";
			zero = false;
		}
		else
		{
			a[0] = "-"+ a[0];
		}

	w -= a[0].length;
	if (w > 0)
		a[0] = (zero ? "00000000000000000000" : "                  ").substr(0,w) + a[0].toString();
		
	return a.join( "." ).trim();
};

Date.parseDate = function ( text )	// supports dates in yyyy-mm-dd order
{
	var dt = new Date( text );
	if (isNaN( dt ))
	{
		dt = new String( text );
		var time = "";
		var k = dt.search( /[\sT]/ );	// whitespace or T seperates date from time
		if (k > -1) 
		{
			time = dt.substring( k + 1 );
			dt = dt.substring( 0, k );
		}
		if (dt.indexOf(":") > -1 && time == "") 
		{	// input is time only
			time = dt;
			dt = "";
		}
		if (dt == "")
			dt = new Date();
		else
		{
			dt += "----";
			var a = text.split( "-" );
			dt = new Date( parseInt( a[0], 10 ), parseInt( a[1], 10 ) - 1, parseInt( a[2], 10 ) );		}		if (!isNaN( dt ) && time != "")		{			dt = (dt.getMonth()+ 1) + "/"+ dt.getDate() + "/"+ dt.getFullYear() + " "+ time;			dt = new Date( dt );		}	}
	return dt;
};


d3.NameValue = function( name, value )
{
	this.name = name; this.value = value;
	if (typeof(value) == "undefined" && typeof(name) == "string")
	{
		var x = name.splitAt("=");
		if (x.length == 2) 
		{
			this.name = x[0];
			this.value = x[1];
		}
		else
		{
			this.name = value;
			this.value = name;
		}
	}
}

d3.NameValue.prototype.toString = function()
{
	return this.name + "="+ this.value;
}

d3.HashTable = function( )
{
	this.clear();
}

d3.HashTable.prototype.add = function( name, value )
{
	var nv;
	if (name instanceof d3.NameValue)
		nv = name;
	else
		nv = new d3.NameValue( name, value );
	var n = this._getIndex( nv.name );
	if (n > -1)
		this._data[n] = nv;
	else
		this._data.push( nv );
	this.length = this._data.length;
	return nv;
}

d3.HashTable.prototype.clear = function() 
{
	this._data = [];
	this.length = 0;
}

d3.HashTable.prototype.toArray = function()
{
	var a = [];
	for (var k = 0; k < this._data.length; k++)
	{
		var nv = this._data[k];
		a.push( new d3.NameValue( nv.name, nv.value ) );
	}
}

d3.HashTable.prototype.remove = function( name )
{
	var n = this._getIndex( name );
	if (n > -1) 
	{
		this.length = this._data.length - 1;
		return this._data( n, 1 );
	}
	return null;
}
d3.HashTable.prototype._getIndex = function( id )
{
	for (var k = 0; k < this._data.length; k++)
		if (this._data[k].name == id) return k;
	return -1;
}
d3.HashTable.prototype.item = function( id )
{
	if (typeof(id) == "number") return this._data[ parseInt(id) ];
	return this._data[ this._getIndex( id ) ];
}

d3.StringBuilder =  function( )
{
	this._data = [];
	this.append( arguments );
}
d3.StringBuilder.prototype.append = function( oneOrMoreArguments )
{
	for (var k = 0; k < arguments.length; k++)
		this._data.push( new String(arguments[k]) );
}
d3.StringBuilder.prototype.toString = function()
{
	return this._data.join("");
}
d3.StringBuilder.prototype.clear = function()
{
	this._data = [];
}
d3.StringBuilder.prototype.getLength = function()
{
	var l = 0;
	for (var k = 0; k < this._data.length; k++)
		l += this._data[k].length;
	return l;
}

d3.Uri = function( url, relative )
{
	var b = d3.ifNot( url, "" );
	this.scheme = "";
	this.hostName = "";
	this.path = "";
	this.file = "";
	this.queryString = "";
	
	if (d3.env.IS_BROWSER && b == "") b = document.URL; else b = new String( b );
	
	var isLocal = (b.indexOf( "\\" ) > -1);
	if (isLocal)
		b = b.split( "\\" ).join( "/" );
	b = b.splitAt( "#" )[0];		// dump any anchor
	var a = b.splitAt( "?" );
	if (a.length == 2) this.queryString = a[1];
	b = a[0];		// text before ?
	a = b.splitAt( "//" );
	if (a.length == 2) this.scheme = a[0].toLowerCase();	// text before //
	b = a[a.length - 1];	// text after //
	
	if (this.scheme != "" || b.indexOf( ":" ) == 1) 
	{
		a = b.splitAt( "/" );
		// hostNames are only used if a transport is specified, for file://, hostName will be drive letter
		this.hostName = a[0];
		b = (a.length > 1) ? "/"+ a[1] : "";
	}

	a = b.split("/");		// all directories
	
	this.file = a[a.length - 1];
	a[a.length - 1] = "";
	this.path = a.join("/");
	
	if (typeof(relative) != "undefined") return this.getRelative( relative );
}

d3.Uri.prototype.toString = function()
{
	var a = new Array();
	if (this.scheme != "") a.push( this.scheme + "//" );
	a.push( this.hostName );
	a.push( this.path );
	a.push( this.file );
	if (this.queryString != "") a.push( "?" + this.queryString );
	return a.join("");
}

d3.Uri.prototype.toSecure = function( secure )
{
	if (this.scheme == "") return null;
	this.scheme = (secure == true) ? "https:" : "http:";
	return this;
}

d3.Uri.prototype.getRelative = function( relativeUrl )
{	
	var rel = null;
	if (relativeUrl)
	{
		if (relativeUrl instanceof d3.Uri)
			rel = relativeUrl;
		else
			rel = new d3.Uri( new String( relativeUrl ) );
	}
	if (rel == null) return new d3.Uri( this.toString() );

	if (rel.scheme == "") rel.scheme = this.scheme;
	if (rel.hostName == "") rel.hostName = this.hostName;
	if (rel.path == "")
	{
		rel.path = this.path;
		if (rel.file == "") rel.file = this.file;
	}
	else 
	{
		if (rel.path.substring(0,1) != "/") 
			rel.path = this.path + rel.path;
	}
	// queryString of base url is not used for relative url
	
	return rel;
}

Array.prototype.toNameValueList = function(  )
{
	var a = new Array();
	for (var k = 0; k < this.length; k++)
	{
		var x = this[k];
		if (x.name && typeof(x.value) != "undefined")
			a.push( new d3.NameValue( x.name, x.value ) );
		else 
			a.push( new d3.NameValue( x ) );
	}
	return a;
}

if (d3.env.HAS_ACTIVEX)
{
	d3._getVersionedActiveX = function( versions )
	{
		for (var k = 0; k < versions.length; k++)
			try
			{
				var x = new ActiveXObject( versions[k] );
				DEBUG$( "versionedActiveX is "+ versions[k] );
				return x;
			}
			catch (e)
			{
			}
		return null;
	};
}

/* d3 logger */
d3.LOG_ERROR = 3;
d3.LOG_WARNING = 2;
d3.LOG_INFORMATION = 1;
d3.LOG_DEBUG = 0;
d3.LOG_NONE = -1;
d3.Logger = function( options )
{ 
	this._about = "d3methods Logger class, v1.2.000, 1/29/2006";
	this._levelText = [ "debug", "info", "warning", "error" ];
	this._target = null;
	this._prefix = "";
	this.initialize( options );
	this._queue = new Array();
}

d3.Logger.prototype.initialize = function( options )
{
	if (typeof(this.minimumLevel) != "number") this.minimumLevel = d3.LOG_ERROR;
	if (typeof(this.defaultLevel) != "number") this.defaultLevel = d3.LOG_DEBUG;
	if ((!options)) return;
	if (typeof(options.minimumLevel) == "number")
	{
		if (options.minimumLevel < this._levelText.length && options.minimumLevel >= 0) this.minimumLevel = options.minimumLevel;
	}
	if (typeof(options.defaultLevel) == "number")
	{
		if (options.defaultLevel < this._levelText.length && options.defaultLevel >= 0) this.defaultLevel = options.defaultLevel;
	}
	if (typeof(options.prefix) == "string")
		this._prefix = "["+ options.prefix + "] ";
	this.name = (typeof(options.name) == "string") ? options.name : "";
	if (!options.target) return;
	if (typeof( options.target ) == "string")
	{
		if (d3.env.IS_BROWSER)
		{
			this._target = document.getElementById( options.target );
		}
		else if (d3.env.IS_WSCRIPT && options.target.toLowerCase() == "#screen")
		{
			this._target = options.target;
			this._write = this._writeScreen;
		}
		else if (d3.env.HAS_ACTIVEX)
		{
			this._fso = new ActiveXObject( "Scripting.FileSystemObject" );
			this._target = options.target;
			this._write = this._writeFile;
		}
	}
	else if (typeof(options.target.tagName) == "string")
		this._target = options.target;
		
	if (!this._target) return;
	if (d3.env.IS_BROWSER && !this._write)
	{
		this._write = this._writeHtml;
		var s = d3.ifNot( this._target.className, "d3-log" );
		if (s.indexOf("d3-log") < 0) s += " d3-log";
		this._target.className = s;
		if (!this._target.ondblclick) this._target.ondblclick = function() { d3.log.clear(); };
	}
}

d3.Logger.prototype.append = function( message, level )
{
	level = (typeof(level) == "number") ? level : this.defaultLevel;
	if (level < this.minimumLevel || level >= this._levelText.length || level < 0 ) return;
	var q = this._queue.length;
	if (!this._target) 
	{
		this._queue[q] = { message : "[preload] "+ message, level : level };
		return;
	}
	else if (q > 0)
	{
		for (var k = 0; k < q; k++)
		{
			var item = this._queue[k];
			this._write( this._prefix + item.message, item.level );
		}
		this._queue = new Array();
	}
	this._write( this._prefix + message, level );
}

d3.Logger.prototype._writeHtml = function( message, level )
{
	var s = (new String( message )).escapeHtml();
	var e = document.createElement( "DIV" );
	if (this.name != "") s = "["+ name + "] "+ s;
	e.innerHTML = "<span class='log-time'>"+ (new Date()).toString( "hh:mm:ss" ) + "</span> "
		+ "<span class='log-level'>"+ this._levelText[ level ] + "</span> "
		+ "<span class='log-message'>"+ s + "</span>";
	this._setClass( e, "d3-"+ this._levelText[ level ], true );
	this._target.appendChild( e );
}

d3.Logger.prototype._writeFile = function( message, level )
{
	var f = this._fso.OpenTextFile( this._target, 8, true );
	f.WriteLine( (new Date()).toString( "yyyy-mm-dd hh:mm:ss" ) + "\t"+ this._levelText[ level ] + "\t"+ message );
	f.Close();
}

d3.Logger.prototype._writeScreen = function( message, level )
{
	WScript.echo( "::" + this._levelText[ level ] + ": "+ message );
}

d3.Logger.prototype.clear = function( )
{
	if (!this._target) return;
	this._target.innerHTML = "";
}

d3.Logger.prototype.display = function( level, visible, only )
{
	if ((!this._target) || level >= this._levelText.length || level < 0 ) return;
	for (var k = level; k < this._levelText.length; k++)
	{
		this._setClass( 'hide-'+ this._levelText, !(visible == true) );
		if (only == true) break;
	}
}

d3.Logger.prototype._setClass = function ( obj, cls, enable )
{
	var className = " " + obj.className + " ";
	var k = className.indexOf( " " + cls + " " );
	if (enable && k < 0) 
		className += cls;
	else if ((!enable) && k > -1) 
		className = className.split( " "+ cls + " ").join( " " );
	else
		return;
	obj.className = className.replace(/(^\s*)|(\s*$)/g, "");
	return;
}
	
d3.log = new d3.Logger( { minimumLevel : d3.LOG_DEBUG, defaultLevel : d3.LOG_DEBUG, name: "d3-global" } );	
function LOG$( a, b ) { d3.log.append( a, b ); }
function INFO$( a ) { d3.log.append( a, d3.LOG_INFORMATION ); }
function WARN$( a ) { d3.log.append( a, d3.LOG_WARNING ); }
function ERROR$( a ) { d3.log.append( a, d3.LOG_ERROR ); }
function DEBUG$( a ) { d3.log.append( a, d3.LOG_DEBUG ); }

function $() {
	var a = new Array();
	for (var i = 0; i < arguments.length; i++) 
	{
		var e = arguments[i];
		if (typeof(e) == 'string')
			e = document.getElementById(e);
		if (arguments.length == 1)
			return e;
		a.push(e);
	}
	return a;
}

if (d3.env.IS_BROWSER)
{
	LOG$( "adding browser stuff" );

	d3.html = {};	
	d3.html.loadJavascript = function( scriptName )
	{
		if (typeof(scriptName) != "string") return;
		var scripts = document.getElementsByTagName("HEAD")[0].getElementsByTagName("SCRIPT");
		var basePath = "";
		var name = scriptName.toLowerCase();
		for (var es = new d3.Enumerator( scripts ); !es.atEnd(); es.moveNext() )
		{
			var script = es.item();
			var s = script.src.toLowerCase();
			if (s == name || s.contains( "/"+ name )) return;
			if (s.contains("d3.base.js")) basePath = s.splitAt("d3.base.js")[0];
		}
		var script = document.createElement("SCRIPT");
		script.setAttribute("type","text/javascript");
		script.setAttribute("language","javascript");
		script.setAttribute("src", basePath + scriptName);
		
		document.getElementsByTagName("HEAD")[0].appendChild( script );
	}

	Object.fromDomNode = function( node, recurse )
	{
		if (!node || !node.attributes || !node.attributes.length) return null;
		var o = new Object();
		for (var k = 0; k < node.attributes.length; k++)
		{
			var a = node.attributes[k];
			if (!a.nodeName) return null;
			o[ a.nodeName ] = a.nodeValue;
		}
		o['name()'] = node.nodeName;
		o['.'] = node;
		if (recurse == true)
		{
			for (var k = 0; k < node.childNodes; k++)
			{
				var c = node.childNodes[k];
				o[c.nodeName] = Object.fromDomNode( c );
			}
		}
		return o;	
	};

	d3.html.insertAfter = function (parent, node, referenceNode) 
	{
		parent.insertBefore(node, referenceNode.nextSibling);
	}
	
	d3.html.getChildElements = function( node )
	{
		if (!node || !node.childNodes) return null;
		var a = [];
		for (var x = new d3.Enumerator( node.childNodes ); !x.atEnd(); x.moveNext())
			if (x.item().tagName) a.push( x.item() );
		return a;
	}
	
	d3.html.getElementsByTagName = function( object, tags )
	{
		var a = [];
		object = $(object);
		if (!object || !object.getElementsByTagName || !tags) return null;
		if (!(tags instanceof Array)) tags = [ tags ];
		for (var k = 0; k < tags.length; k++)
		{
			var tag = tags[k];
			var elements = object.getElementsByTagName( tag );
			for (var j = 0; j < elements.length; j++)
			{
				a.push( elements[j] );
				d3.html.getElementsByTagName( elements[j], tag );
			}
		}
		return a;
	}
	
	d3.html.getTagsWithAttributes = function( object, tags, attributes )
	{
		var elements = d3.html.getElementsByTagName( object, tags );
		if (!elements) return elements;
		//alert( "gebtn ["+ tags.join(",") + "] -> "+ elements.length );
		elements.concat( [ object ] );
		if (!(attributes instanceof Array)) attributes = [ attributes ];
		var a = [];
		for (var k = 0; k < elements.length; k++)
			for (var j = 0; j < attributes.length; j++)
			{
				if (elements[k].getAttribute( attributes[j] )) 
				{
					a.push(elements[k]);
					break;
				}
			}
		//alert( "gtwa ["+ tags.join(",") + "], ["+ attributes.join(",") + "] -> "+ a.length );
		return a;
	}

	d3.html.getOffset = function ( obj )
	{
		var left = obj.offsetLeft;
		var top = obj.offsetTop;
		var o = obj;
		while ( o.offsetParent )
		{
			o = o.offsetParent;
			left += o.offsetLeft;
			top += o.offsetTop;
		}
		return { left : left, top: top, right : left + obj.offsetWidth, bottom : top + obj.offsetHeight };
	}
	
	d3.html.getWindowSize = function()
	{
		if (typeof(window.innerHeight) != "undefined")
			return { height: window.innerHeight, width: window.innerWidth,
							scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset };
		var body;
		if (document.documentElement.clientHeight > 0) body = document.documentElement; else body = document.body;
	
		return { height: body.clientHeight,	width: body.clientWidth,
						scrollTop: body.scrollTop, scrollLeft: body.scrollLeft }	
	}

	d3.html.toggleDisplay = function (obj) {
		var el = document.getElementById(obj);
		if ( el.style.display != 'none' ) {
			el.style.display = 'none';
		}
		else {
			el.style.display = '';
		}
	}

	d3.html.toggleClass = function( obj, cls )
	{
		if (typeof(cls) == "string") cls = new Array( cls );
		if (!cls instanceof Array) return;
		obj = $( obj );
		if (!obj) return;
		var className = " " + obj.className + " ";
		
		for (var j = 0; j < cls.length; j++)
		{
			var c = cls[j];
			var k = className.indexOf( " "+ c + " " );
			if ( k < 0) 
				className = obj.className + " "+ c;
			else
				className = className.substr( 0, k ) + className.substr( k + c.length + 1 );
		}
		obj.className = className.replace(/(^\s*)|(\s*$)/g, "");
	}

	d3.html.setClass = function( obj, cls, enable )
	{
		if (typeof(cls) != "string") return;
		enable = (enable == true || [ "true","y","yes"].has( enable, false ));
		obj = $( obj );
		if (!obj) return;
		
		var className = " " + obj.className + " ";
		var k = className.indexOf( " " + cls + " " );
		if (enable && k < 0) 
			className += cls;
		else if ((!enable) && k > -1) 
			className = className.split( " "+ cls + " ").join( " " );
		else
			return;

		obj.className = className.replace(/(^\s*)|(\s*$)/g, "");
		return;
	}
	
	d3.html.getFrameWindow = function( frameId )
	{
		var f = $(frameId);
		if (f.contentWindow) return f.contentWindow;
		return null;
	}
	
	d3.html.setSelectToValue = function( select, value )
	{
		var select = $(select);
		if (!select || !select.options) return null;
		for (var k = 0; k < select.options.length; k++)
			if (select.options[k].value == value)
			{
				select.selectedIndex = k;
				return true;
			}
		return false;
	}

	Object.fromHtmlForm = function( form )
	{
		if (!form || !form.elements) return null;
		var o = new Object();
		for (var k = 0; k < form.elements.length; k++)
		{
			var f = form.elements[k];
			var type = d3.ifNot( f.type, "" ).toLowerCase();
			if (["button","submit","reset"].has(type)) continue;
			var n = d3.ifNot( f.id, d3.ifNot( f.name, "item" ) );
			var s = f.value;
			if (type == "checkbox") s = f.checked.toString();
			o[ n ] = s;
		}
		return o;
	};	

	d3.cookies = {};
	/* cookie functions from Dustin Diaz since they were more robust than prior versions */
	d3.cookies.getName = function ( name ) {
		var start = document.cookie.indexOf( name + "=" );
		var len = start + name.length + 1;
		if ( ( !start ) && ( name != document.cookie.substring( 0, name.length ) ) ) {
			return null;
		}
		if ( start == -1 ) return null;
		var end = document.cookie.indexOf( ";", len );
		if ( end == -1 ) end = document.cookie.length;
		return unescape( document.cookie.substring( len, end ) );
	}
		
	d3.cookies.setName = function ( name, value, options ) {
		var today = new Date();
		today.setTime( today.getTime() );
		if ( expires ) {
			expires = expires * 1000 * 60 * 60 * 24;
		}
		if (!options) options = { };
		var expires_date = new Date( today.getTime() + (options.expires) );
		document.cookie = name+"="+escape( value ) +
			( ( options.expires ) ? ";expires="+expires_date.toGMTString() : "" ) + //expires.toGMTString()
			( ( options.path ) ? ";path=" + options.path : "" ) +
			( ( options.domain ) ? ";domain=" + options.domain : "" ) +
			( ( options.secure ) ? ";secure" : "" );
	}
		
	d3.cookies.deleteName = function( name, options ) {
		if (!options) options = {};
		if ( getCookie( name ) ) document.cookie = name + "=" +
				( ( options.path ) ? ";path=" + options.path : "") +
				( ( options.domain ) ? ";domain=" + options.domain : "" ) +
				";expires=Thu, 01-Jan-1970 00:00:01 GMT";
	}

	d3.events = {};
	d3.events.preventDefault = function( evt )
	{
		if (!evt) evt = window.event;
		if (evt.preventDefault)
			evt.preventDefault();
		else
			evt.returnValue = false;
	}
	d3.events.stopPropagation = function( evt )
	{
		if (!evt) evt = window.event;
		if (evt.stopPropagation)
			evt.stopPropagation();
		else
			evt.cancelBubble = true;
	}

	d3.events.getTarget = function( evt )
	{
		if (!evt) evt = window.event;
		return d3.ifNot( evt.srcElement, evt.target );
	}

	// following event stuff is from DustinDiaz.com
	function addEvent(elm, evType, fn, useCapture) {
		if (elm.addEventListener) { 
		elm.addEventListener(evType, fn, useCapture); 
		return true; 
		}
		else if (elm.attachEvent) { 
		var r = elm.attachEvent('on' + evType, fn); 
		EventCache.add(elm, evType, fn);
		return r; 
		}
		else {
		elm['on' + evType] = fn;
		}
	}
	
	function getEventSrc(e) {
		if (!e) e = window.event;

		if (e.originalTarget)
		return e.originalTarget;
		else if (e.srcElement)
		return e.srcElement;
	}
	function addLoadEvent(func) {
	var oldonload = window.onload;
		if (typeof window.onload != 'function') {
		window.onload = func;
		} else {
		window.onload = 
			function() {
			oldonload();
			func();
			}
		}
	}
	var EventCache = function(){
		var listEvents = [];
		return {
			listEvents : listEvents,
		
			add : function(node, sEventName, fHandler, bCapture){
				listEvents.push(arguments);
			},
		
			flush : function(){
				var i, item;
				for(i = listEvents.length - 1; i >= 0; i = i - 1){
					item = listEvents[i];
					
					if(item[0].removeEventListener){
						item[0].removeEventListener(item[1], item[2], item[3]);
					};
					
					/* From this point on we need the event names to be prefixed with 'on" */
					if(item[1].substring(0, 2) != "on"){
						item[1] = "on" + item[1];
					};
					
					if(item[0].detachEvent){
						item[0].detachEvent(item[1], item[2]);
					};
					
					item[0][item[1]] = null;
				};
			}
		};
	}();

	addEvent(window,'unload',EventCache.flush, false);	
}
LOG$("d3 OK " );
