
function print_r_HTML( theObj ) {
    if ( theObj.constructor == Array || theObj.constructor == Object ) {
        document.write("<ul>");
        for( var p in theObj ) {
            if ( theObj[p].constructor == Array || theObj[p].constructor == Object ) {
                document.write("<li>["+p+"] => " + typeof(theObj) + "</li>");
                document.write("<ul>")
                print_r(theObj[p]);
                document.write("</ul>")
            }
            else {
                document.write("<li>["+p+"] => "+theObj[p]+"</li>");
            }
        }
        document.write("</ul>");
    }
}

function print_r( theObj, level ) {
    var sout = '';
    if ( theObj.constructor == Array || theObj.constructor == Object ) {
        sout += "\n";
        for( var p in theObj ) {
            if ( theObj[p].constructor == Array || theObj[p].constructor == Object ) {
                sout += "\n" + "\t".repeat(level) + "["+p+"] => " + typeof(theObj);
                sout += print_r(theObj[p], (level+1));
            }
            else {
                sout += "<li>["+p+"] => "+theObj[p];
            }
        }
    }
    return sout;
}



// trim left spaces
String.prototype.ltrim = function() {
    return this.replace(/^\s+/, "");
}

// trim right spaces
String.prototype.rtrim = function() {
    return this.replace(/\s+$/, "");
}

// trim left and right spaces
String.prototype.trim = function() {
    return this.replace(/^\s+|\s+$/g, "");
}

// trim all whitespace (including: spaces, tabs and returns)
String.prototype.trimAll = function() {
    return this.replace( /(?:(?:^|\n)\s+|\s+(?:$|\n))/g, "" );
}

// repeat a string a number of times (this can be used as simply as [["repeat me ".repeat(10);]])
String.prototype.repeat = function( frequency ) {
    // meriam-webster: "frequency":
    //      2 a: the number of times that a periodic function repeats the same
    //      sequence of values during a unit variation of the independent variable
    var o = this, s = '';
    if ( frequency ) { while ( frequency-- ) s += o; } else { s = o; }
    return s;
}

function isArray( mixed_var ) {
    return ( mixed_var instanceof Array );
}

// the prototype function; get (return) any DOM element by ID
/*function $() {
	var elements = new Array();
	for (var i = 0; i < arguments.length; i++) {
		var element = arguments[i];
		if (typeof element == 'string')
			element = document.getElementById(element);
		if (arguments.length == 1)
			return element;
		elements.push(element);
	}
	return elements;
}*/

/*
 * @ description:
 *      add an event handler to an object/element
 *
 * @ returns:
 *      boolean
 *
 * @ notes:
 *      ** BE CAREFUL ** with this method: addEventListener and attachEvent are *NOT* the same
 *      ** this can cause memory leaks (primarily IE/Opera) and can have unexpected results if
 *      ** a parent element also has events attached to it. *ALSO* the usage of the "this" keyword
 *      ** will return a) the element object, in Moz/Opera/etc. and the "window" object in IE!
 *      **
 *      ** see http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/
 *      **
 *      ** and http://evolt.org/article/Mission_Impossible_mouse_position/17/23335/index.html
 *      ** and http://www.quirksmode.org/blog/archives/2005/08/addevent_consid.html
 *      **
 *      **
 *      ** **** USE JQUERY's $(element).ready() and $(element).bind(event, function) methods instead of this!
 *      **
 *
 */
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);
		return r;
	}
	else {
		elm['on' + evType] = fn;
	}
}



/*
 * @ description:
 *      add an event handler to an object/element
 *
 * @ returns:
 *      an object (DOM element)
 *
 * @ example:
 *      alert( getElementsByClassName("my-blue-text-class")[0].nodeType );
 *
 * @ notes:
 *      ** developed by Robert Nyman, http://www.robertnyman.com
 *      ** code/licensing: http://code.google.com/p/getelementsbyclassname/
 *      **
 *      ** *DEPRECIATED* see http://www.drunkenfist.com/304/2008/07/02/say-hello-to-javascripts-native-getelementsbyclassname/
 *
 */
var getElementsByClassName = function (className, tag, elm){
    if (document.getElementsByClassName) {
	getElementsByClassName = function (className, tag, elm) {
	    elm = elm || document;
	    var elements = elm.getElementsByClassName(className),
		nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
		returnElements = [],
		current;
	    for(var i=0, il=elements.length; i<il; i+=1){
		current = elements[i];
		if(!nodeName || nodeName.test(current.nodeName)) {
			returnElements.push(current);
		}
	    }
	    return returnElements;
	};
	
    }
    else if (document.evaluate) {
	getElementsByClassName = function (className, tag, elm) {
	    tag = tag || "*";
	    elm = elm || document;
	    var classes = className.split(" "),
		classesToCheck = "",
		xhtmlNamespace = "http://www.w3.org/1999/xhtml",
		namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
		returnElements = [],
		elements,
		node;
	    for(var j=0, jl=classes.length; j<jl; j+=1){
		classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
	    }
	    try	{
		elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
	    }
	    catch (e) {
		elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
	    }
	    while ((node = elements.iterateNext())) {
		returnElements.push(node);
	    }
	    return returnElements;
	};
    }
    else {
	getElementsByClassName = function (className, tag, elm) {
	    tag = tag || "*";
	    elm = elm || document;
	    var classes = className.split(" "),
		classesToCheck = [],
		elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
		current,
		returnElements = [],
		match;
	    for(var k=0, kl=classes.length; k<kl; k+=1){
		classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
	    }
	    for(var l=0, ll=elements.length; l<ll; l+=1){
		current = elements[l];
		match = false;
		for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
			match = classesToCheck[m].test(current.className);
			if (!match) {
				break;
			}
		}
		if (match) {
			returnElements.push(current);
		}
	    }
	    return returnElements;
	};
    }
    return getElementsByClassName(className, tag, elm);
};



/*
 * @ description:
 *      gets the run-time computed ("active") style of an element
 *
 * @ returns:
 *      computed style object
 *
 * @ example:
 * 	var myDiv = document.getElementById("myDiv");
 * 	var activeWidth = computedStyle(myDiv, "width");
 *      alert( "myDiv current width: " + activeWidth );
 *
 * @ notes:
 *      for hyphenated selectors, use the W3C compatible version, as it will automatically
 *      be converted (if needed) for IE use (ex: 'background-color' not 'backgroundColor')
 *
 */
var computedStyle = function( el, styleName ) {
    
    // TODO: need typeof(el) error checking here
    
    if ( document.defaultView ) {
	//trace('defaultView');
	var cs = document.defaultView.getComputedStyle(el, null);
	return cs.getPropertyValue(styleName);
    }
    else if ( el.currentStyle ) {
	//trace('currentStyle');
	//trace("getting current style of\n\n\t" + el + "\n" + camelSelector(styleName) + "\n\nwhich is: \"" + el.currentStyle[camelSelector(styleName)] + "\"");
	return el.currentStyle[ camelSelector(styleName) ];
    }
    else {
	//trace('epic fail');
	return null;
    }
    
};



/*
 * @ description:
 *      converts standards-compliant CSS selector syntax to evil IE syntax
 *
 * @ returns:
 *      (string) IE-compliant CSS selector
 *
 * @ example:
 * 	var selector = 'background-color';
 * 	var selector = camelSelector(selector);
 * 	// selector is now 'backgroundColor'
 *
 * @ notes:
 *      (none)
 *
 */
var camelSelector = function( s ) {
    for ( var exp = /-([a-z])/; exp.test(s); s = s.replace(exp,RegExp.$1.toUpperCase()) );
    return s;
};


/*
 * @ description:
 *      wrapper function for findPosX() and findPosY()
 *      finds the X and Y coordinates of a DOM element
 *
 * @ returns:
 *      an object, in the form of { x: 0, y: 0 }
 *
 * @ example:
 * 	var myDiv = document.getElementById("myDiv");
 * 	var el_coords = findPos( myDiv );
 * 	alert( 'myDiv X: ' + el_coords.x + "\nmyDiv Y: " + el_coords.y );
 *
 * @ notes:
 *      major props to Peter @ quirksmode
 *      http://www.quirksmode.org/
 *
 */
var findPos = function( el ) {
    return { x: findPosX(el), y: findPosY(el) };
};

var findPosX = function( obj ) {
    var curLeft = 0;
    if ( obj.offsetParent ) {
	while ( 1 ) {
	    curLeft += obj.offsetLeft;
            if ( !obj.offsetParent ) break;
	    obj = obj.offsetParent;
	}
    }
    else if ( obj.x ) {
	curLeft += obj.x;
    }
    return curLeft;
};

var findPosY = function( obj ) {
    var curTop = 0;
    if ( obj.offsetParent ) {
	while ( 1 ) {
	    curTop += obj.offsetTop;
	    if ( !obj.offsetParent ) break;
	    obj = obj.offsetParent;
	}
    }
    else if ( obj.y ) {
	curTop += obj.y;
    }
    return curTop;
};





//function cleanChildNodes(id){
//  // get the element with the id provided
//  var x = document.getElementById(id);
//  // test if the element exists
//  if(x){
//    // regular Expression testing if a string is only whitespace
//    var reg = /s*/mg;
//    // loop over all childNodes of the element
//    for(var i=0;x.childNodes[i];i++){
//      // if the current item only consists of whitespace…
//      var current = x.childNodes[i];
//      if(reg.test(current.nodeValue)){
//      // … remove it
//        current.parentNode.removeChild(current);
//      }
//      // there is no need to check for the node type
//      // as element nodes have a nodeValue of null
//    }
//  }
//}
