(function() {
    if(!window.gs) {
        return;
    }
    gs.util = {
        /** The following functions are from
         *  http://blogs.wdevs.com/Sukumar/archive/2005/05/10/3335.aspx
         *
         *  These functions are used to detect whether a variable meets certain conditions provided by the name of the function itself:
         *      isUndefined - sees whether a variable is undefined
         *      isNull - whether a variable is null
         *      isIEObject - whether a variable is an object in IE
         *      isObject -  whether a variable is an object
         *      isFunction - whether a variable is a function
         *      isArray - whether a variable is an array
         *      isEmpty - whether a variable contains other members (applies to objects, functions, arrays)
         *      isNumber - whether a variable is a number (NaN) and not infinite
         *      isString - whether a variable is a string
         *      isBoolean - whether a variable is a boolean
         */
        isUndefined: function(a) { return typeof a == 'undefined'; },
        
        isNull: function(a) { return typeof a == 'object' && !a; },
        
        isIEObject: function(a) { return gs.util.isObject(a) && typeof a.constructor != 'function'; },
        
        isObject: function(a)
        {
            if (a == null || a == undefined) return false;
            return (typeof a == 'object' && !!a) || gs.util.isFunction(a);
        },
        
        isFunction: function(a) { return typeof a == 'function'; },
        
        isArray: function(a) { return gs.util.isObject(a) && a.constructor == Array; },
        
        isEmpty: function(o) {
            if (gs.util.isObject(o)) {
                for (var i in o) {
                    return false;
                }
            }
            return true;
        },
        
        isNumber: function(a) { return typeof a == 'number' && isFinite(a); },
        
        isString: function(a) { return typeof a == 'string'; },
        
        isBoolean: function(a) { return typeof a == 'boolean'; },
        
        /**
         *  uses fisher-yates algorithm to randomly shuffle an array
         */
        shuffle: function( myArray )
        {
            var i = myArray.length;
            if ( i == 0 ) return false;
            while ( --i ) {
                var j = Math.floor( Math.random() * ( i + 1 ) );
                var tempi = myArray[i];
                var tempj = myArray[j];
                myArray[i] = tempj;
                myArray[j] = tempi;
            }
            return myArray;
        },
        
        /**
         * like the php function, makes sure the variable 'arr' is an array
         * formally: ensure_array
         */
        arrayEnsure: function(arr)
        {
            return (isArray(arr)) ? arr : [arr];
        },
        
        /** 
         * give array of what you want replaced, and what you want to replace it with and the text you want to be changed
         * formally: str_replace
        **/
        strReplace: function(arrSearch, strReplace, subject)
        {
            if(subject=='') return subject;
            arrSearch = arrayEnsure(arrSearch);
            strReplace = arrayEnsure(strReplace);
            var length = arrSearch.length;
            for(var i=0; i<length; i++) {
                subject = subject.replace(arrSearch[i], strReplace[i]);
            }
            return subject;
        },
        
        /**
         *  remove all children from a dom object
         **/
        removeChildren: function(element)
        {
            if(!element) return;
            var node;
            while ((node = element.lastChild)) {
                element.removeChild(node);
            }
        },
        
        /**
         * force browser to redraw a given element
         * formally: obj_redraw
         */
        objRedraw: function(obj)
        {
            obj = obj || document.body;
            if(obj && obj.style) {
                var t = obj.style.display;
                obj.style.display = 'none';
                obj.style.display = t;
                // ensure safari redraws too
                obj.className += '';
            }
        },
        
        /**
         * Returns {X,Y} coordinate position of DOM object
         */
        getPosition: function(objDoc)
        {
            var left = 0;
            var top  = 0;
        
            while (objDoc.offsetParent){
                left += objDoc.offsetLeft;
                top  += objDoc.offsetTop;
                objDoc = objDoc.offsetParent;
            }
        
            left += objDoc.offsetLeft;
            top  += objDoc.offsetTop;
        
            return {x:left, y:top};
        },
        
        /**
         *  fix ie memory leak (http://javascript.crockford.com/memory/leak.html)
         */
        purge: function(d)
        {
            var a = d.attributes, i, l, n;
            if (a) {
                l = a.length;
                for (i = 0; i < l; i += 1) {
                    n = a[i].name;
                    if (typeof d[n] === 'function') {
                        d[n] = null;
                    }
                }
            }
            a = d.childNodes;
            if (a) {
                l = a.length;
                for (i = 0; i < l; i += 1) {
                    gs.util.purge(d.childNodes[i]);
                }
            }
        },
        
        /**
         * Get the position of the mouse and will place the mouse X and Y value to the corresponding parameters.
         * formally: trackmouse
         */
        getMouse: function(event)
        {
            event = event || window.event;
            var posx =  posy = 0;
            if (event.pageX || event.pageY)     {
                posx = event.pageX;
                posy = event.pageY;
            } else if (event.clientX || event.clientY)  {
                posx = event.clientX + document.body.scrollLeft
                    + document.documentElement.scrollLeft;
                posy = event.clientY + document.body.scrollTop
                    + document.documentElement.scrollTop;
            }
            return {x:posx, y:posy};
        },
        
        EVENT_TRUE: true,
        EVENT_FALSE: false,
        stopEvent: function(event, preventDefault, preventBubble)
        {
            event = event || window.event;
            preventDefault = preventDefault || gs.util.STOP_EVENT_TRUE;
            preventBubble  = preventBubble || gs.util.STOP_EVENT_TRUE;
            
            if(preventDefault) {
                event.returnValue = false;
                if(event.preventDefault) { event.preventDefault(); }    
            }
            
            if(preventBubble) {
                if(event.stopPropagation) { event.stopPropagation(); }
                event.cancelBubble = true;
            }
        },
        stopEventBubble: function(event){
            gs.util.stopEvent(event, null, gs.util.EVENT_FALSE);
        },
        stopEventDefault: function(event){
            gs.util.stopEvent(event, gs.util.EVENT_FALSE, null);
        },

        getScrollPosition: function() {
            var x = 0, y = 0;
            if(window.pageYOffset || window.pageXOffset) {
                x = window.pageXOffset;
                y = window.pageYOffset;
            } else if(document.body && (document.body.scrollLeft || document.body.scrollTop)) {
                x = document.body.scrollLeft;
                y = document.body.scrollTop;
            } else if(document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
                x = document.documentElement.scrollLeft;
                y = document.documentElement.scrollTop;
            }
            return [x, y];
        },
        
        empty: null
    };
})();
