

function getElementsByClassName( className, tag, n ) {

    n = n || document;
    var r = [],
        ns = n.getElementsByTagName(tag);
    for( var i=0; i<ns.length; i++ ) {
        if( hasClass(ns[i], className) )
            r.push( ns[i] );
    }
    return r;
}


function removeClass( n, className ) {

    if (! hasClass(n, className))
        return;
    var re = new RegExp( '(^|\\s+)'+className+'($|\\s+)' );
    n.className = n.className.replace( re, ' ' );
}


function addClass( n, className ) {

    if( hasClass(n, className) )
        return;
    n.className = [n.className, className].join(' ');
}


function hasClass( n, className ) {

    var re = new RegExp( '(^|\\s)'+className+'($|\\s)' );
    return n.className && n.className.match( re );
}


function offsetXY( n, rel ) {

    var x=0, y=0, c=n;
    while( c && (c != rel) ) {
        x += c.offsetLeft;
        y += c.offsetTop;
        if( gecko() ||   webkit() ) {
            x += parseInt( css(c, 'border-left-width') );
            y += parseInt( css(c, 'border-top-width') );
        }
        c = c.offsetParent;
    }
    if( gecko() ||   webkit() ) {
        x -= parseInt( css(n, 'border-left-width') );
        y -= parseInt( css(n, 'border-top-width') );
    }
    return {x: x, y: y};
}


function $( id ) {
    
    return   typeof id == 'string'   ? document.getElementById(id)   : id;
}


function noBubble( e ) {

    e.cancelBubble = true;
    if ( e.stopPropagation )
        e.stopPropagation();
}


function wh( el ) {

    var els = {};
    if( css(el, 'display') == 'none' ) {
        if (! els[el.tagName]) {
            var tmp = document.createElement(el.tagName);
            document.body.appendChild( tmp );
            var display = css( tmp, 'display' );
            document.body.removeChild( tmp );
            els[ el.tagName ] = display;
        }

        var oldVisibility = css(el, 'visibility');
        css( el, 'visibility', 'hidden' );
        css( el, 'display', els[el.tagName] );
        
        var r = { w: el.offsetWidth, h: el.offsetHeight };
        
        css( el, 'display', 'none' );
        css( el, 'visibility', oldVisibility );
        return r;
    } else
        return { w: el.offsetWidth, h: el.offsetHeight };
}


function isParent( parent, el ) {

    while( el ) {
        if( el.parentNode == parent )
            return true;
        el = el.parentNode;
    }
    return false;
}


function empty( el ) {

    while( el.childNodes.length )
        el.removeChild( el.firstChild );
}


function gecko() {

    return document.getBoxObjectFor != undefined;
}


function webkit(){
    return   ! navigator.taintEnabled;
}



function css( e, p, v ) {

    if( arguments.length == 3 )
        return e.style[ camelCase(p) ] = v;
        
    if( e.currentStyle )
        return e.currentStyle[ camelCase(p) ];
    var computed = document.defaultView.getComputedStyle( e, null );
    return   computed &&   computed.getPropertyValue([ p ]);

    function camelCase( s ) {

        return s.replace(/-\D/g, function(match){
            return match.charAt(1).toUpperCase();
        });
    }
}


function htmlScrollTop() {

    return document.documentElement.scrollTop ||   document.body.scrollTop;
}


function subelements( n ) {
	
	var r = [],
		children = n.childNodes;
	for( var i=0; i<children.length; i++ )
		if( children[i].nodeType == 1 )
			r.push( children[i] );
	return r;
}


function subelement( n, i ) {
	
	i = i || 0;
	n = n.firstChild;
	if( n &&   n.nodeType != 1 )
		n = nxt( n );
	while( --i >= 0 ) {
		n = nxt( n );
	} 
    return n;
}


function firstElement( n ) {
	
	return subelement( n );
}


function nxt( n ) {

    do {
        n = n.nextSibling;
    } while( n && n.nodeType != 1 )
    return n;
}


function prv( n ) {

    do {
        n = n.previousSibling;
    } while( n && n.nodeType != 1 )
    return n;
}


Function.prototype.bind = function( o ) {

    var f = this,
        args = Array.prototype.slice.call( arguments, 0 );
    return function() {
        f.apply( o, args );
    }
}
