// GLM Framework Version 1.0 
// Copyright 2006-2007 Jason Graves (GodLikeMouse)
// This file is free to use and distribute under the GNU open source
// license so long as this header remains intact.
// For more information please visit http://www.godlikemouse.com
// To have changes incorporated into the GLM Framework please contact godlikemouse@godlikemouse.com
// Supported Browsers: IE 6.0+, Mozilla based browsers

var GLM = {
    String:     String,
    Array:      Array,
    Debug:      Object,
    Event:      Object,
    DOM:        Object,
    AJAX:       Object,
    Collection: Object,
    XML:        Object,
    Object:     Object,
    UI:         Object
};

var PAJ = {
    Security:	Object
};

/************************************/
/* GLM.String                       */
/************************************/

/// <name>GLM.String</name>
/// <summary>Class for performing ehanced string operations.  Inherits from original String class</summary>
/// <returns>The new GLM.String object</returns>
/// <example>var s = new GLM.String("hello world");</example>
GLM.String;

/// <name type="function">GLM.String.replaceQueryString</name>
/// <summary>Method for replacing a querystring parameter or appending it
/// correctly if it does not exist.</summary>
/// <param name="parameterName">The parameter name to replace the value of.</param>
/// <param name="parameterValue">The value used in the replacement.</param>
/// <returns>The querystring with the replaced values</returns>
/// <example>var s = new GLM.String(document.location.search);
/// var sUrl = s.replaceQueryString("param1","value1");</example>
GLM.String.prototype.replaceQueryString = function(parameterName, parameterValue){
    var thisString = this;
	
    if(this.indexOf("?") < 0){
        //new param
        thisString += "?" + parameterName + "=" + parameterValue;
    }
    else{
        //existing querystring
        var n1 = thisString.indexOf(parameterName);
        if(n1 >= 0){
            n1 += parameterName.length + 1;
            var n2 = n1;
            var c = this.charAt(n2++);
            while(n2 < thisString.length){
                c = this.charAt(n2++);
                if(c == "&"){
                    n2--;
                    break;
                }//end if
            }//end while
            thisString = thisString.substring(0,n1) + parameterValue + thisString.substring(n2,thisString.length);
        }
        else{
            thisString += "&" + parameterName + "=" + parameterValue;
        }//end if
    }//end if
	
    return thisString;
}//end replaceQueryString()


/// <name type="function">GLM.String.removeQueryString</name>
/// <summary>Method for removing a querystring parameter.</summary>
/// <param name="parameterName">The parameter name to remove.</param>
/// <returns>The querystring with the removed values</returns>
/// <example>var s = new GLM.String(document.location.search);
/// var sUrl = s.removeQueryString("param1");</example>
GLM.String.prototype.removeQueryString = function(parameterName){
    var thisString = this;
    var n1 = thisString.indexOf(parameterName);
    if(n1 >= 0){
        var n2 = n1;
        var c = this.charAt(n2++);
        while(n2 < thisString.length){
            var c = this.charAt(n2++);
            if(c == "&"){
                n2--;
                n1--;
                break;
            }//end if
        }//end while
        thisString = thisString.substring(0,n1) + thisString.substring(n2,thisString.length);
                
        if(!thisString.count("?"))
            thisString = thisString.replace("&","?");
    }//end if
	
    return thisString;
}//end removeQueryString()

/// <name type="function">GLM.String.getQueryString</name>
/// <summary>Method for returning the querystring value 
/// corresponding to the specified parameter name.</summary>
/// <param name="parameterName">The parameter to return the value of.</param>
/// <returns>The querystring value of the specified parameterName</returns>
/// <example>var s = new GLM.String(document.location.search);
/// var sValue = s.getQueryString("param1");</example>
GLM.String.prototype.getQueryString = function(parameterName){
    var thisString = this;
	
    thisString = thisString.replace("?","");
    var params = thisString.split("&");
	
    for(var i=0; i<params.length; i++){
        var pair = params[i].split("=");
        if(pair[0] == parameterName)
            return pair[1];
    }//end for
	
    return null;
}//end getQueryString()

/// <name type="function">GLM.String.count</name>
/// <summary>Method for returning the occurance count of any of the
/// string parameters passed into the count function.</summary>
/// <param name="param1, param2, ... paramN">Unlimited parameters, the string or
/// strings to count the occurance of.</param>
/// <returns>The occurance count.</returns>
/// <example>var s = new GLM.String("hello world");
/// s.count("e","l"); //returns 4</example>
GLM.String.prototype.count = function(/* unlimited params */){
    var thisString = this;
    var c = 0;
    
    for(var i=0; i<arguments.length; i++){
        var n = 0;
        
        while( (n = thisString.indexOf(arguments[i], n)) >= 0){
            c++;
            n++;
        }//end while
    }//end for
    
    return c;
}//end count()

/// <name type="function">GLM.String.contains</name>
/// <summary>Method for determining if a string contains
/// the instance of another string.</summary>
/// <param name="s">The string to search for.</param>
/// <returns>True if the value exists, otherwise false.</returns>
/// <example>var s = new GLM.String("hello world");
/// var b = s.contains("hello") //returns true</example>
GLM.String.prototype.contains = function(s){
    return this.indexOf(s) >= 0;
}//end contains()

/// <name type="function">GLM.String.trim</name>
/// <summary>Method for removing white space from the
/// beginning and end of the string.</summary>
/// <returns>The trimmed string.</returns>
/// <example>var s = new GLM.String("  hello world  ");
/// var b = s.trim(); //returns "hello world"</example>
GLM.String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g,"");
}//end trim()

/// <name type="function">GLM.String.ltrim</name>
/// <summary>Method for removing white space from the
/// beginning of the string.</summary>
/// <returns>The left trimmed string.</returns>
/// <example>var s = new GLM.String("  hello world  ");
/// var b = s.ltrim(); //returns "hello world  "</example>
GLM.String.prototype.ltrim = function() {
	return this.replace(/^\s+/,"");
}//end ltrim()

/// <name type="function">GLM.String.rtrim</name>
/// <summary>Method for removing white space from the
/// end of the string.</summary>
/// <returns>The right trimmed string.</returns>
/// <example>var s = new GLM.String("  hello world  ");
/// var b = s.ltrim(); //returns "  hello world"</example>
GLM.String.prototype.rtrim = function() {
	return this.replace(/\s+$/,"");
}//end rtrim()

/************************************/
/* GLM.Array                        */
/************************************/

/// <name type="function">GLM.Array.Remove</name>
/// <summary>Method for removing an object from the
/// array.</summary>
/// <example>var a = new GLM.Array();
/// var s1 = "hello";
/// var s2 = "world";
/// a.push(s1);
/// a.push(s2);
/// a.remove(s1); //"hello" has been removed</example>
GLM.Array.prototype.remove = function(element){
        var len = this.length;
        var j = 0;
        
        for(var i=0; i<len; i++){
            if(element != this[i])
                this[i] = this[j++];
        }//end for
        this.pop();
}//end remove()


/************************************/
/* GLM.Debug                        */
/************************************/

/// <name type="function">GLM.Debug.DisplayProperties</name>
/// <summary>Method for displaying the debug properties of a 
/// source object (event, document, object, etc).</summary>
/// <param name="source">The source object to display the
/// properties of.</param>
/// <example>GLM.Debug.DisplayProperties(window); //displays all the window properties</example>
GLM.Debug.DisplayProperties = function(source){
    var sourceType = typeof source;
    switch(source){
        case window:
            sourceType = "Window";
            break;
        case top:
            sourceType = "Window";
            break;
        case document:
            sourceType = "Document";
            break;
        case history:
            sourceType = "History";
            break;
    }//end switch
    
    var s = "<table width=\"100%\">";
    s += "<tr>";
    s += "<th colspan=\"3\" style=\"background-color: gray; color: white;\">Property Information For " + source + " (" + (sourceType) + ")</th>";
    s += "</tr>";
    s += "<tr>";
    s += "<th style=\"background-color: #CFCFCF;\">Property Name</th>";
    s += "<th style=\"background-color: #CFCFCF;\">Value</th>";
    s += "<th style=\"background-color: #CFCFCF;\">Type</th>";
    s += "</tr>";
    
    var arr = new Array();
    for(var i in source){
        var s1 = "";
        s1 += "<tr>";
        s1 += "<td style=\"background-color: #EFEFEF;\">" +  i + "</td>";
        s1 += "<td style=\"background-color: #EFEFEF;\">";
        try{ s1 += source[i]; } catch(ex){}
        s1 += "</td>";
        s1 += "<td style=\"background-color: #EFEFEF;\">";
        try{ s1 += typeof source[i]; } catch(ex){};
        s1 += "</td>";
        s1 += "</tr>";
        arr.push(s1);
    }//end for
    
    arr.sort();
    
    for(var i in arr){
        s += arr[i];
    }//end for
    
    
    s += "</table>";

    var div = document.createElement("DIV");
    document.body.appendChild(div);
    div.innerHTML = s;
}//end DisplayProperties()


/************************************/
/* GLM.Event                        */
/************************************/

/// <name type="function">GLM.Event.CancelEvents</name>
/// <param name="event">(Optional) Event object to use on a static call.</param>
/// <summary>Method for cancelling all following events.</summary>
/// <example>function myOnClick(event){
///     return GLM.Event.CancelEvents(event); //cancel all cascading events.
/// }
///
/// GLM.Event.AddEventHandler("document", "click", myOnClick); //add event handler</example>
GLM.Event.CancelEvents = function(event){
    if(GLM.DOM.isInternetExplorer)
        event = window.event;
    try{event.cancelBubble = true;}catch(ex){}
    try{event.stopPropagation();}catch(ex){}
    try{event.cancel = true;}catch(ex){}
    try{event.preventDefault();}catch(ex){}
    return false;
}//end CancelEvents()

/// <name type="function">GLM.Event.AddEventHandler</name>
/// <summary>Method for adding an event handler to an element.</summary>
/// <param name="element">The element to add the event handler to.</param>
/// <param name="eventName">The event name to subscribe to.</param>
/// <param name="handlerFunction">The function to handle the event.</param>
/// <example>function myOnClick(){
///     alert("myOnClick called.);
/// }
///
/// GLM.Event.AddEventHandler("document", "click", myOnClick); //add event handler</example>
GLM.Event.AddEventHandler = function(element, eventName, handlerFunction){
    
    if(GLM.DOM.isInternetExplorer)
        element.attachEvent("on" + eventName, handlerFunction);
    else
        element.addEventListener(eventName, handlerFunction, false);
}//end AddEventHandler()

/// <name type="function">GLM.Event.RemoveEventHandler</name>
/// <summary>Method for removing an event handler from an element.</summary>
/// <param name="element">The element to remove the event handler from.</param>
/// <param name="eventName">The event name to remove.</param>
/// <param name="handlerFunction">The function to handle the event.</param>
/// <example>function myOnClick(){
///     alert("myOnClick called.);
/// }
///
/// GLM.Event.RemoveEventHandler("document", "click", myOnClick); //remove event handler</example>
GLM.Event.RemoveEventHandler = function(element, eventName, handlerFunction){
    
    if(GLM.DOM.isInternetExplorer)
        element.detachEvent("on" + eventName, handlerFunction);
    else
        element.removeEventListener(eventName, handlerFunction, false);
}//end RemoveEventHandler()



/************************************/
/* GLM.DOM                          */
/************************************/

/// <name>GLM.DOM.isInternetExplorer</name>
/// <summary>Boolean variable for determining if the client browser is Internet Explorer.</summary>
/// <returns>True if the client browser is Internet Explorer, otherwise false</returns>
/// <example>if(GLM.DOM.isInternetExplorer){
///     alert("You're using IE");
/// }</example>
GLM.DOM.isInternetExplorer = new GLM.String(navigator.userAgent).contains("MSIE");

/// <name>GLM.DOM.isMozilla</name>
/// <summary>Boolean variable for determining if the client browser is Mozilla.</summary>
/// <returns>True if the client browser is Mozilla, otherwise false</returns>
/// <example>if(GLM.DOM.isMozilla){
///     alert("You're using Mozilla");
/// }</example>
GLM.DOM.isMozilla = new GLM.String(navigator.userAgent).contains("Gecko");

/// <name>GLM.DOM.isOpera</name>
/// <summary>Boolean variable for determining if the client browser is Opera.</summary>
/// <returns>True if the client browser is Opera, otherwise false</returns>
/// <example>if(GLM.DOM.isOpera){
///     alert("You're using Opera");
/// }</example>
GLM.DOM.isOpera = new GLM.String(navigator.userAgent).contains("Opera");

/// <name>GLM.DOM.isSafari</name>
/// <summary>Boolean variable for determining if the client browser is Safari.</summary>
/// <returns>True if the client browser is Safari, otherwise false</returns>
/// <example>if(GLM.DOM.isSafari){
///     alert("You're using Safari");
/// }</example>
GLM.DOM.isSafari = (navigator.userAgent.indexOf("Safari") >= 0);

/// <name>GLM.DOM.Cookie</name>
/// <summary>Class for handling browser cookies.</summary>
/// <returns>A new GLM.DOM.Cookie object.</returns>
/// <example>var cookie = new GLM.DOM.Cookie("mycookie");
/// cookie.setValue("firstvalue","hello world"); //set firstvalue name to "hello world"
/// var firstvalue = cookie.getValue("firstvalue"); //retrieve firstvalue.
/// cookie.removeCookie(); //remove the cookie from the client machine.</example>
GLM.DOM.Cookie = function(cookieName){
	
    var cname = cookieName;
    var expires = null;
    var path = null;
    var domain = null;
    var secure = null;
    
    /// <name type="function">GLM.DOM.Cookie.setValue</name>
    /// <summary>Method for setting a cookie name value pair.</summary>
    /// <param name="name">The name of the cookie value to set.</param>
    /// <param name="value">The value of the cookie value to set.</param>
    /// <example>var cookie = new GLM.DOM.Cookie("mycookie");
    /// cookie.setValue("firstvalue","hello world"); //set firstvalue name to "hello world"
    /// var firstvalue = cookie.getValue("firstvalue"); //retrieve firstvalue.
    /// cookie.removeCookie(); //remove the cookie from the client machine.</example>
    this.setValue = function(name, value){
        var nv = getNameValuePairs();
                
        for(var i=0; i<nv.length; i++){
            if(nv[i].name == name){
                nv[i].value = value;
                break;
            }//end if
        }//end for
		
        if(!this.getValue(name))
            nv.push({name: name, value: value});
                
        saveNameValuePairs(nv);
    }//end setValue()

    /// <name type="function">GLM.DOM.Cookie.getValue</name>
    /// <summary>Method for returning the cookie value by name.</summary>
    /// <param name="name">The name of the cookie value to retrieve.</param>
    /// <returns>The value associated with the name.</returns>
    /// <example>var cookie = new GLM.DOM.Cookie("mycookie");
    /// cookie.setValue("firstvalue","hello world"); //set firstvalue name to "hello world"
    /// var firstvalue = cookie.getValue("firstvalue"); //retrieve firstvalue.
    /// cookie.removeCookie(); //remove the cookie from the client machine.</example>
    this.getValue = function(name){
        var nv = getNameValuePairs();

        for(var i=0; i<nv.length; i++){
            if(nv[i].name == name)
                return nv[i].value;
        }//end for
                
        return null;
    }//end getValue()
	
    /// <name type="function">GLM.DOM.Cookie.setExpiration</name>
    /// <summary>Method for setting the expiration date of a cookie.</summary>
    /// <param name="expirationDate">The Date object expiration</param>
    /// <example>var cookie = new GLM.DOM.Cookie("mycookie");
    /// cookie.setValue("firstvalue","hello world"); //set firstvalue name to "hello world"
    /// cookie.setExpiration( new Date() ); //sets the expiration to now</example>
    this.setExpiration = function(expirationDate){
        expires = expirationDate;
        saveNameValuePairs(getNameValuePairs);
    }//end setExpiration()
	
    /// <name type="function">GLM.DOM.Cookie.setPath</name>
    /// <summary>Method for setting the cookie path.</summary>
    /// <param name="p">The cookie path.</param>
    /// <example>var cookie = new GLM.DOM.Cookie("mycookie");
    /// cookie.setValue("firstvalue","hello world"); //set firstvalue name to "hello world"
    /// cookie.setPath("/"); //sets the path to root</example>
    this.setPath = function(p){
        path = p;
    }//end setPath()
	
    /// <name type="function">GLM.DOM.Cookie.setDomain</name>
    /// <summary>Method for setting the cookie domain.</summary>
    /// <param name="d">The cookie domain.</param>
    /// <example>var cookie = new GLM.DOM.Cookie("mycookie");
    /// cookie.setValue("firstvalue","hello world"); //set firstvalue name to "hello world"
    /// cookie.setDomain("www.mysite.com"); //sets the domain to www.mysite.com</example>
    this.setDomain = function(d){
        domain = d;
    }//end setDomain()
	
    /// <name type="function">GLM.DOM.Cookie.setSecure</name>
    /// <summary>Method for setting whether a cookie is secure for SSL.</summary>
    /// <param name="isSecure">Boolean specifying whether the cookie is secure for SSL.</param>
    /// <example>var cookie = new GLM.DOM.Cookie("mycookie");
    /// cookie.setValue("firstvalue","hello world"); //set firstvalue name to "hello world"
    /// cookie.setSecure(true); //sets the cookie for SSL use</example>
    this.setSecure = function(isSecure){
        secure = isSecure;
    }//end setSecure
	
    /// <name type="function">GLM.DOM.Cookie.removeCookie</name>
    /// <summary>Method for removing the cookie from the client browser.</summary>
    /// <example>var cookie = new GLM.DOM.Cookie("mycookie");
    /// cookie.setValue("firstvalue","hello world"); //set firstvalue name to "hello world"
    /// var firstvalue = cookie.getValue("firstvalue"); //retrieve firstvalue.
    /// cookie.removeCookie(); //remove the cookie from the client machine.</example>
    this.removeCookie = function(){
        var d = new Date();
        d.setDate(d.getDate()-1);
        document.cookie = cname + "=; expires=" + d.toGMTString() + "; ";
    }//end removeCookie()
	
    // Method for returning the name value pairs of the cookie.
    var getNameValuePairs = function(){
        var nameValues = new Array();
        var pairs = document.cookie.split(";");
                
        for(var i=0; i<pairs.length; i++){
            var nv = pairs[i].split("=");

            if(nv[0] == null || nv[0] == "")
                continue;
            
            switch(nv[0]){
                case "path":
                case "domain":
                case "secure":
                    continue;
                    
                case cname:
                    //iterate cookie values
                    var vp = nv[1].split("|");
                    for(var j=0; j<vp.length; j++){
                        var rnv = vp[j].split("`");
                        if(rnv[0] == null || rnv[0] == "")
                            continue;
                        
                        nameValues.push({name: rnv[0], value: rnv[1]});
                    }//end for
                    
                    break;
            }//end switch
                        
        }//end for
		
        return nameValues;
    }//end getNameValuePairs()
	
    // Method for saving the name value pairs to the cookie.
    var saveNameValuePairs = function(nameValues){
        var s = cname + "=";
                
        for(var i=0; i<nameValues.length; i++){
            s += nameValues[i].name + "`" + nameValues[i].value + "|";
        }//end for
        s += "; ";
                
        if(expires)
            s += "expires=" + expires + "; ";
        
        if(path)
            s += "path=" + path + "; ";
        
        if(domain)
            s += "domain=" + domain + "; ";
        
        if(secure)
            s += "secure";
        
        document.cookie = s;
    }//end saveNameValuePairs()
	
}//end GLM.DOM.Cookie

/// <name type="function">GLM.DOM.GetElement</name>
/// <summary>Method for returning an element by id or name.
/// The element will first try to be obtained by the id, then fall
/// back to the name.</summary>
/// <example>var element = GLM.DOM.GetElement("myTextBox");</example>
/// <returns>The matching element</returns>
GLM.DOM.GetElement = function(idOrName){
    var el = null;
    try{ el = document.getElementById(idOrName); }catch(ex){}
    if(!el){ 
        try{ el = document.getElementsByName(idOrName)[0]; }catch(ex){} 
    }//end if
    if(!el){
        try{ el = eval(idOrName); }catch(ex){}
    }//end if
    return el;
}//end GetElement()

/// <name type="function">GLM.DOM.GetElementPosition</name>
/// <summary>Method for returning an elements absolute position.</summary>
/// <returns>The structure {x,y}</returns>
/// <example>var pos = GLM.DOM.GetElementPosition(el);
/// alert(pos.x + " " + pos.y);</example>
GLM.DOM.GetElementPosition = function(element){
    var left = 0;
    var top = 0;

    if (element.offsetParent){
        left = element.offsetLeft;
        top = element.offsetTop;

        while (element = element.offsetParent) {
            left += element.offsetLeft;
            top += element.offsetTop;
        }//end while
    }//end if

    return {x:left, y:top};
}//end GetElementPosition()

/// <name type="function">GLM.DOM.GetChildrenByTagName</name>
/// <param name="element">The parent element.</param>
/// <param name="tagName">the tag name to find.</param>
/// <summary>Method for returning all children of an element that match the tag name specified.</summary>
/// <returns>An array of matching child elements.</returns>
/// <example>var el = document.getElementById("myDiv");
/// var nodes = GetChildrenByTagName(el, "span"); //get all span children
/// </example>
GLM.DOM.GetChildrenByTagName = function(element, tagName){
    
    var arr = new Array();
    var len = element.childNodes.length;
    for(var i=0; i<len; i++){
        var el = element.childNodes[i];
        if(el.tagName && el.tagName.toLowerCase() == tagName)
            arr.push(el);
    }//end for
    
    return arr;
}//end GetChildrenByTagName()

/// <name type="function">GLM.DOM.GetChildrenByNodeType</name>
/// <param name="element">The parent element.</param>
/// <param name="nodeType">the node type to find.</param>
/// <summary>Method for returning all children of an element that match the node type specified.</summary>
/// <returns>An array of matching child elements.</returns>
/// <example>var el = document.getElementById("myDiv");
/// var nodes = GetChildrenByNodeType(el, 3); //get all text node children
/// </example>
GLM.DOM.GetChildrenByNodeType = function(element, nodeType){
    var nodes = new Array();
    for(var i in element.childNodes){
        var node = element.childNode;
        if(node && node.nodeType == nodeType)
            nodes.push(node);
    }//end for
    return nodes;
}//end GetChildrenByNodeType()

/// <name type="function">GLM.DOM.NumericMask</name>
/// <param name="element">The input element.</param>
/// <summary>Method for ensuring that the user input is numeric.</summary>
/// <example>
/// &lt;input type="text" onchange="NumericMask(this)" /&gt;
/// </example>
GLM.DOM.NumericMask = function(element){
    var s = element.value;
    for(var i=0; i<s.length; i++){
        if(s.charCodeAt(i) < 48 || s.charCodeAt(i) > 57)
            element.value = element.value.replace(s.chatAt(i),"");
    }//end for
}//end GLM.DOM.NumericMask()

/// <name type="function">GLM.DOM.NumericRangeMask</name>
/// <param name="element">The input element.</param>
/// <param name="lowRange">The lowest range value.</param>
/// <param name="highRange">The highest range value.</param>
/// <summary>Method for ensuring that the user input is numeric within a specified range.</summary>
/// <example>
/// &lt;input type="text" onchange="NumericRangeMask(this, 0, 255)" /&gt;
/// </example>
GLM.DOM.NumericRangeMask = function(element, lowRange, highRange){
    if(parseInt(element.value) > highRange)
        element.value = highRange;
    if(parseInt(element.value) < lowRange)
        element.value = lowRange;
}//end GLM.DOM.NumericRangeMask()

/// <name>GLM.DOM.Validator</name>
/// <summary>Class for handling input validation.</summary>
/// <returns>The new GLM.DOM.Validator object.</returns>
/// <example>var v = new GLM.DOM.Validator();
/// v.addRequiredField("txtFirstName");
/// v.validate(); //validate all required fields.
/// if(!v.isValid){ //check for failures
///     var violations = v.getViolations(); //return all failures
///     var s = "";
///     for(var i=0; i&lt;violations.length; i++){
///             s += violations[i].text + "\n";
///     }
/// 
/// alert(s); //alert all violations
/// }</example>
GLM.DOM.Validator = function(){
	
    var controls = new Array();
    
    var ValidType = {
        REQUIRED: 0,
        CUSTOM: 1,
        VALUE: 2
    };
	
    // Flag for determining if the validation succeeded for failed.
    this.isValid = true;
	
    /// <name type="function">GLM.DOM.Validator.addRequiredField</name>
    /// <summary>Method for adding a required field for validation.</summary>
    /// <param name="controlID">The control identifier of the input field to validate.  This can also be the name for types such as radio.</param>
    /// <param name="errorText">The error message to associate with the required field.</param>
    /// <param name="controlType">(Optional) The control type, default is "text".  Valid types are select, text, radio and checkbox.</param>
    /// <param name="args">(Optional) Any additional information to be retrieved from the getVioloations method.</param>
    /// <example>var v = new GLM.DOM.Validator();
    /// v.addRequiredField("txtFirstName", "First Name is required.");
    /// v.validate(); //validate all required fields.
    /// if(!v.isValid){ //check for failures
    ///     var violations = v.getViolations(); //return all failures
    ///     var s = "";
    ///     for(var i=0; i&lt;violations.length; i++){
    ///             s += violations[i].text + "\n";
    ///     }
    /// 
    /// alert(s); //alert all violations
    /// }</example>
    this.addRequiredField = function(controlID, errorText, controlType, args){
        if(!controlType)
            controlType = "text";
        controls.push({id: controlID, text: errorText, valid: true, type: controlType, args: args, validType: ValidType.REQUIRED});
    }//end addRequiredFiled()
    
    /// <name type="function">GLM.DOM.Validator.addCustomField</name>
    /// <summary>Method for adding a custom field for validation.</summary>
    /// <param name="controlID">The control identifier of the input field to validate.  This can also be the name for types such as radio.</param>
    /// <param name="errorText">The error message to associate with the required field.</param>
    /// <param name="validationFunction">The user defined custom validation function.</param>
    /// <param name="controlType">(Optional) The control type, default is "text".  Valid types are select, text, radio and checkbox.</param>
    /// <param name="args">(Optional) Any additional information to be retrieved from the getVioloations method.</param>
    /// <example>var v = new GLM.DOM.Validator();
    ///
    /// function nameValidator(controlToValidate){
    ///     if(controlToValidate.value.length > 0)
    ///         return true; //passes validation
    ///     else
    ///         return false; //fails validation
    /// }//end nameValidator()
    ///
    /// v.addCustomField("txtFirstName", "First Name is required.", nameValidator);
    /// v.validate(); //validate all required fields.
    /// if(!v.isValid){ //check for failures
    ///     var violations = v.getViolations(); //return all failures
    ///     var s = "";
    ///     for(var i=0; i&lt;violations.length; i++){
    ///             s += violations[i].text + "\n";
    ///     }
    /// 
    /// alert(s); //alert all violations
    /// }</example>
    this.addCustomField = function(controlID, errorText, validationFunction, controlType, args){
        if(!controlType)
            controlType = "text";
        controls.push({id: controlID, text: errorText, valid: true, customValidator: validationFunction, type: controlType, args: args, validType: ValidType.CUSTOM});
    }//end addCustomField()
    
    /// <name type="function">GLM.DOM.Validator.addValueField</name>
    /// <summary>Method for adding a value field for validation.</summary>
    /// <param name="controlID">The control identifier of the input field to validate.  This can also be the name for types such as radio.</param>
    /// <param name="errorText">The error message to associate with the required field.</param>
    /// <param name="value">The value required to pass validation.</param>
    /// <param name="controlType">(Optional) The control type, default is "text".  Valid types are select, text, radio and checkbox.</param>
    /// <param name="args">(Optional) Any additional information to be retrieved from the getVioloations method.</param>
    /// <example>var v = new GLM.DOM.Validator();
    ///
    /// v.addValueField("txtFirstName", "First Name is required.", "Henry"); //txtFirstName must contain the value "Henry"
    /// v.validate(); //validate all required fields.
    /// if(!v.isValid){ //check for failures
    ///     var violations = v.getViolations(); //return all failures
    ///     var s = "";
    ///     for(var i=0; i&lt;violations.length; i++){
    ///             s += violations[i].text + "\n";
    ///     }
    /// 
    /// alert(s); //alert all violations
    /// }</example>
    this.addValueField = function(controlID, errorText, value, controlType, args){
        if(!controlType)
            controlType = "text";
        
        controls.push({id: controlID, text: errorText, valid: true, value: value, type: controlType, args: args, validType: ValidType.VALUE});
    }//end addValueField()
	
    /// <name type="function">GLM.DOM.Validator.validate</name>
    /// <summary>Method for validating all required fields. Sets the GLM.DOM.Validator.isValid flag.</summary>
    /// <example>var v = new GLM.DOM.Validator();
    /// v.addRequiredField("txtFirstName");
    /// v.validate(); //validate all required fields.
    /// if(!v.isValid){ //check for failures
    ///     var violations = v.getViolations(); //return all failures
    ///     var s = "";
    ///     for(var i=0; i&lt;violations.length; i++){
    ///             s += violations[i].text + "\n";
    ///     }
    /// 
    ///     alert(s); //alert all violations
    /// }</example>
    this.validate = function(){
        this.isValid = true;
        
        var controlsLength = controls.length;
        
        for(var i=0; i<controlsLength; i++){
            var c = controls[i];
            
            c.valid = true;
            
            if(c.validType == ValidType.REQUIRED){
                //required field validation
                
                switch(c.type){
                    case "text":

                        var control = document.getElementById(c.id);
			
                        var value = control.value;
                        if(value == null || value == ""){
                            c.valid = false;
                            this.isValid = false;
                        }//end if
                        break;
                    case "radio":
                        var cs = document.getElementsByName(c.id);
                        c.valid = false;
                        var len = cs.length;
                        for(var j=0; j<len; j++){
                            if(cs[j].checked){
                                c.valid = true;
                                break;
                            }//end if
                        }//end for
                    
                        if(!c.valid)
                            this.isValid = false;
                        break;
                    case "checkbox":
                        var control = document.getElementById(c.id);
                    
                        c.valid = control.checked;
                        if(!c.valid)
                            this.isValid = false;
                        break;
                    case "select":
                        var control = document.getElementById(c.id);
                    
                        var value = new GLM.String(control.options[control.selectedIndex].value);
                        value = value.trim();
                        c.valid = value.length > 0;
                    
                        if(!c.valid)
                            isValid = false;
                        break;
                }//end switch
            }
            else if(c.validType == ValidType.CUSTOM){
                //custom field validation
                
                switch(c.type){
                    case "text":
                    case "checkbox":
                    case "select":
                        var control = document.getElementById(c.id);
			c.valid = c.customValidator(control);
                        if(!c.valid)
                            this.isValid = false;
                        break;
                    case "radio":
                        var cs = document.getElementsByName(c.id);
                        c.valid = c.customValidator(cs);
                        if(!c.valid)
                            this.isValid = false;
                        break;
                }//end switch
            }
            else if(c.validType == ValidType.VALUE){
                switch(c.type){
                    case "text":
                        var control = document.getElementById(c.id);
                        c.valid = control.value == c.value;
                        if(!c.valid)
                            this.isValid = false;
                        break;
                    case "checkbox":
                        var control = document.getElementById(c.id);
                        c.valid = (control.checked && control.value == c.value);
                        if(!c.valid)
                            this.isValid = false;
                        break;
                    case "select":
                        var control = document.getElementById(c.id);
			c.valid = control.options[control.selectedIndex].value == c.value;
                        if(!c.valid)
                            this.isValid = false;
                        break;
                    case "radio":
                        var cs = document.getElementsByName(c.id);
                        
                        c.valid = false;
                        var len = cs.length;
                        for(var j=0; j<len; j++){
                            if(cs[j].checked && cs[j].value == c.value){
                                c.valid = true;
                                break;
                            }//end if
                        }//end for
                        
                        if(!c.valid)
                            this.isValid = false;
                        break;
                }//end switch
            }//end if
        }//end for
        
    }//end validate()
	
    /// <name type="function">GLM.DOM.Validator.getViolations</name>
    /// <summary>Method for returning a list of the validation failures.  Each returned validation failure has
    /// two properties, "text" the error text associated with the required field and "id", the control id
    /// of the required field, "args" additional information passed in.</summary>
    /// <returns>The collection of validation failures.</returns>
    /// <example>var v = new GLM.DOM.Validator();
    /// v.addRequiredField("txtFirstName");
    /// v.validate(); //validate all required fields.
    /// if(!v.isValid){ //check for failures
    ///     var violations = v.getViolations(); //return all failures
    ///     var s = "";
    ///     for(var i=0; i&lt;violations.length; i++){
    ///             s += violations[i].text + "\n";
    ///     }
    /// 
    ///     alert(s); //alert all violations
    /// }</example>
    this.getViolations = function(){
        var errors = new Array();
        for(var i=0; i<controls.length; i++){
            if(!controls[i].valid){
                errors.push({id: controls[i].id, text: controls[i].text, args: controls[i].args});
            }//end if
        }//end for
        return errors;
    }//end getViolations()
    
    /// <name type="function">GLM.DOM.Validator.getControls</name>
    /// <summary>Method for returning the current controls list.</summary>
    /// <returns>The collection of controls.</returns>
    /// <example>var v = new GLM.DOM.Validator();
    /// v.addRequiredField("txtFirstName");
    /// var controls = v.getControls(); //returns controls collection containing txtFirstName.</example>
    this.getControls = function(){
        return controls;
    }//end getControls()
	
    return this;
}//end GLM.DOM.Validator

/// <name>GLM.DOM.Animate</name>
/// <summary>Starts an animation on an element.</summary>
/// <example>GLM.DOM.Animate("menu", 200, 30, {height:function(pc){return Math.floor(300*pc)}, null);</example>
/// <param name="elements">An element to animate, or an array of elements, or the name(s) of the elements.</param>
/// <param name="time">The duration in ms of the animation.</param>
/// <param name="frameCount">The maximum frame count of the animation.</param>
/// <param name="params">An object (or array of objects) containing the animation procedures.
/// If an array is passed, each item is used to animate the corresponding element from the elements parameter.
/// Each field of the array is a function, and each field's name is a style parameter.  
/// On each frame of the animation, each function is called and the return value is assigned to the style parameter.
/// A value from 0 to 1 indicating the progress of the animation is passed into each function.
/// Instead of a function, a string may be passed: this string is eval'ed in a context where the completion is represented by "pc" or "complete".
/// The field "opacity" may be used to set the opacity, even though it isn't portable.</param>
/// <param name="finish">An optional function to call when the animation is complete.</param>
/// <returns>A context object that may be used to query the progress of the animation, cancel the animation, or proceed to the completed state.
/// This object represents the context of subsequent, nested animations as well.</returns>
GLM.DOM.Animate = function(elements, time, frameCount, params, finish)
{
    if (!(elements instanceof Array)) 
        elements = [ elements ];

    for(var i = 0; i < elements.length; i++) {
        if (typeof elements[i] == "string") 
            elements[i] = document.getElementById(elements[i]);
    }
    
    if (!(params instanceof Array)) 
        params = [ params ];

    var frameTime = time/frameCount;
    var framesTotal = 0;
    var startTime = new Date();
    var myContext = GLM.DOM.Animate.CurrentContext || {isAnimationContext: true};
    myContext.cancel = cancel;
    myContext.jumpToEnd = jumpToEnd;
    myContext.inProgress = inProgress;
	
    update();
    var handle = setInterval(update, frameTime);
    return myContext;
	
    function update() {
		
        var elapsed = new Date() - startTime;
        var complete = elapsed / time;
        if (complete > 1) complete = 1;
		
        framesTotal++;
		
        var eLength = elements.length;
        for(var i = 0; i < eLength; i++) {
            var paramSet = params[i];
            for(param in paramSet) {
                var val = paramSet[param](complete);
				
                if (param == "opacity") {
                    GLM.DOM.SetOpacity(elements[i], val);
                } else {
                    elements[i].style[param] = val;
                }
            }
        }
		
        if (complete >= 1) {
            finishInterval();
        }		
    }
	
    function finishInterval()
    {
        if (handle) clearInterval(handle);
        if (finish) {
            GLM.DOM.Animate.CurrentContext = myContext;
            finish();
            GLM.DOM.Animate.CurrentContext = undefined;
        }
        handle = 0;
        elements = null;
        params = null;
        
        var endTime = new Date();
    }	
	
    function cancel()
    {		
        if (handle) clearInterval(handle);
        handle = 0;
        elements = null;
        params = null;
    }
	
    function jumpToEnd()
    {
        cancel();
        finishInterval();
    }
	
    function inProgress()
    {
        return handle != 0;
    }
}

/// <name>GLM.DOM.Animate.Grow</name>
/// <param name="min">The minimum starting size</param>
/// <param name="max">The maximum ending size</param>
/// <summary>Canned growing effect.</summary>
/// <example>var growWidth = new GLM.DOM.Animate.Grow(50, 100); //grow width starting at 50 and ending at 100
/// GLM.DOM.Animate(myElement, 500, 100, {width: growWidth.animate}, null);</example>
GLM.DOM.Animate.Grow = function(min, max){
    this.animate = function(n){
        return min + d*n;
    }//end animate()
    
    var d = max-min;
}//end Grow

/// <name>GLM.DOM.Animate.FadeOut</name>
/// <param name="startAlpha">The starting alpha value</param>
/// <summary>Canned fade out effect.</summary>
/// <example>var fadeOut = new GLM.DOM.Animate.FadeOut(.5); //fade out from 50% to 0%
/// GLM.DOM.Animate(myElement, 500, 100, {opacity: fadeOut.animate}, null);</example>
GLM.DOM.Animate.FadeOut = function(startAlpha){
    
    this.animate = function(n){
        return 1 - startAlpha*n;
    }//end animate()

    startAlpha /= 1;
}//end FadeOut()

/// <name>GLM.DOM.Animate.FadeIn</name>
/// <param name="startAlpha">The starting alpha value</param>
/// <summary>Canned fade in effect.</summary>
/// <example>var fadeIn = new GLM.DOM.Animate.FadeOut(.5); //fade in from 50% to 100%
/// GLM.DOM.Animate(myElement, 500, 100, {opacity: fadeIn.animate}, null);</example>
GLM.DOM.Animate.FadeIn = function(startAlpha){
    
    this.animate = function(n){
        return startAlpha + d*n;
    }//end animate()
    
    var d = 1-startAlpha;
}//end FadeIn()

/// <name type="function">GLM.DOM.SetOpacity</name>
/// <summary>Sets the opacity of an element.</summary>
/// <example>GLM.Animation.SetOpacity(menuHeader, 0.5);</example>
/// <param name="element">An element to adjust.</param>
// <param name="val">Opacity, from 0 to 1.</param>
GLM.DOM.SetOpacity = document.all ? 
function(element, val)
{
    element.style.filter = val == 1 ? "" : "alpha(opacity=" + Math.floor(val * 100) + ")";
} :
function(element, val)
{
    element.style.opacity = val;
};


/// <name>GLM.DOM.DragAndDrop</name>
/// <summary>Class for handling drag and drop interaction.  The
/// class by default looks for the "handle" attribute on the element
/// to be dragged.  Once found it will look through the parent including
/// the initial mouse down element to find the "drag" attribute.  It will
/// then move the element where the "drag" attribute is specified.</summary>
/// <example>var dnd = new DragAndDrop();
/// function OnBeginDrag(source){
///     alert("source element is: " + source.tagName);
/// }//end OnBeginDrag()
///
/// function OnDrag(source, dest){
///     if(dest)
///         alert("drop target: " + dest.tagName);
/// }//end OnDrag()
///
/// function OnDrop(source, dest){
///     alert("source is: " + source.tagName);
///     alert("dest is: " + dest.tagName);
/// }//end OnDrop()
/// 
/// dnd.setBeginDragCallback(OnBeginDrag);
/// dnd.setDragCallback(OnDrag);
/// dnd.setDropCallback(OnDrop);
/// </example>
GLM.DOM.DragAndDrop = function(){
    
    var dropAttribute = "drop";
    var dragAttribute = "drag";
    var handleAttribute = "handle";
    
    var element = null;
    var elementOffsetX = 0;
    var elementOffsetY = 0;
    var copyElement = false;
    var absolute = false;
    var absoluteX = 0;
    var absoluteY = 0;
    var event = null;
    
    var onBeginDrag = function(srcElement){}
    var onDrop = function(srcElement, toElement){}
    var onDrag = function(srcElement, toElement){}
    
    //public functions
    
    /// <name type="function">GLM.DOM.DragAndDrop.setBeginDragCallback</name>
    /// <param name="callback">The callback method</param>
    /// <summary>Method for setting the begin drag callback.  This method
    /// is called at the very beginning of the drag event.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// </example>
    this.setBeginDragCallback = function(callback){
        onBeginDrag = callback;
    }//end this.setBeginDragCallback()
    
    /// <name type="function">GLM.DOM.DragAndDrop.getBeginDragCallback</name>
    /// <summary>Method for returning the begin drag callback.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// dnd.alert(getBeginCallback());
    /// </example>
    this.getBeginDragCallback = function(){
        return onBeginDrag;
    }//end this.getBeginDragCallback()
    
    /// <name type="function">GLM.DOM.DragAndDrop.setDragCallback</name>
    /// <param name="callback">The callback method</param>
    /// <summary>Method for setting the drag callback. This is invoked when once 
    /// the actual dragging occurs.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// </example>
    this.setDragCallback = function(callback){
        onDrag = callback;
    }//end this.setDragCallback()
    
    /// <name type="function">GLM.DOM.DragAndDrop.getDragCallback</name>
    /// <summary>Method for returning the drag callback.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// alert(dnd.getDragCallback());
    /// </example>
    this.getDragCallback = function(){
        return onDrag;
    }//end this.getDragCallback()
    
    /// <name type="function">GLM.DOM.DragAndDrop.setDropCallback</name>
    /// <param name="callback">The callback method</param>
    /// <summary>Method for setting the drop callback. This is invoked when once 
    /// the drop occurs.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// </example>
    this.setDropCallback = function(callback){
        onDrop = callback;
    }//end this.setDropCallback()
    
    /// <name type="function">GLM.DOM.DragAndDrop.getDropCallback</name>
    /// <summary>Method for returning the drop callback.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// alert(dnd.getDropCallback());
    /// </example>
    this.getDropCallback = function(){
        return onDrop;
    }//end this.getDropCallback()
    
    
    /// <name type="function">GLM.DOM.DragAndDrop.setDragOffset</name>
    /// <param name="x">The x offset</param>
    /// <param name="y">The y offset</param>
    /// <summary>Method for setting the drag offset.  This is the
    /// offset from the actual drag location to place the dragged
    /// element.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// dnd.setDragOffset(10,10);
    /// </example>
    this.setDragOffset = function(x, y){
        elementOffsetX = x;
        elementOffsetY = y;
    }//end this.setDragOffset()
    
    /// <name type="function">GLM.DOM.DragAndDrop.getDragOffsetX</name>
    /// <summary>Method for returning the x drag offset.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// dnd.setDragOffset(10,10);
    /// alert(dnd.getDragOffsetX());
    /// </example>
    this.getDragOffsetX = function(){
        return elementOffsetX;
    }//end this.getDragOffsetX()
    
    /// <name type="function">GLM.DOM.DragAndDrop.getDragOffsetY</name>
    /// <summary>Method for returning the y drag offset.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// dnd.setDragOffset(10,10);
    /// alert(dnd.getDragOffsetY());
    /// </example>
    this.getDragOffsetY = function(){
        return elementOffsetY;
    }//end this.getDragOffsetY()
    
    /// <name type="function">GLM.DOM.DragAndDrop.setDropAttributeName</name>
    /// <param name="name">The attribute name (default "drop")</param>
    /// <summary>Method for setting/changing the drop attribute name.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// dnd.setDropAttributeName("drop_target");
    /// </example>
    this.setDropAttributeName = function(name){
        dropAttribute = name;
    }//end this.setDropAttribute()
    
    /// <name type="function">GLM.DOM.DragAndDrop.getDropAttributeName</name>
    /// <summary>Method for returning the drop attribute name.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// alert(dnd.getDropAttributeName()); //displays "drop"
    /// </example>
    this.getDropAttributeName = function(){
        return dropAttribute;
    }//end this.getDropAttributeName()
    
    /// <name type="function">GLM.DOM.DragAndDrop.setDragAttributeName</name>
    /// <param name="name">The attribute name (default "drag")</param>
    /// <summary>Method for setting the drag attribute name.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// dnd.setDragAttributeName("dragable");
    /// </example>
    this.setDragAttributeName = function(name){
        dragAttribute = name;
    }//end this.setDragAttributeName()
    
    /// <name type="function">GLM.DOM.DragAndDrop.getDragAttributeName</name>
    /// <summary>Method for returning the drag attribute name.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// alert(dnd.getDragAttributeName()); //displays "drag"
    /// </example>
    this.getDragAttributeName = function(){
        return dragAttribute;
    }//end this.getDragAttributeName()
    
    /// <name type="function">GLM.DOM.DragAndDrop.setHandleAttributeName</name>
    /// <param name="name">The attribute name (default "handle")</param>
    /// <summary>Method for setting the handle attribute name.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// dnd.setHandleAttributeName("grab");
    /// </example>
    this.setHandleAttributeName = function(name){
        handleAttribute = name;
    }//end this.setHandleAttributeName()
    
    /// <name type="function">GLM.DOM.DragAndDrop.getHandleAttributeName</name>
    /// <summary>Method for returning the handle attribute name.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// alert(dnd.getHandleAttributeName()); //displays "handle"
    /// </example>
    this.getHandleAttributeName = function(){
        return handleAttribute;
    }//end this.getHandleAttributeName()
    
    /// <name type="function">GLM.DOM.DragAndDrop.setCopyElement</name>
    /// <param name="copy">true to create a copy of the drag source element, false to drag original (default false). </param>
    /// <summary>Method for setting whether or not to copy the drag source element.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// dnd.setCopyElement(true); //a copy element will be used.
    /// </example>
    this.setCopyElement = function(copy){
        copyElement = copy;
    }//end this.setCopyElement()
    
    /// <name type="function">GLM.DOM.DragAndDrop.getCopyElement</name>
    /// <summary>Method for returning whether or not to copy the drag source element.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// alert(dnd.getCopyElement()); //displays false
    /// </example>
    this.getCopyElement = function(){
        return copyElement;
    }//end this.getCopyElement()
    
    /// <name type="function">GLM.DOM.DragAndDrop.setAbsolute</name>
    /// <param name="abs">true to use abosolute positioning, false to use top left cursor positioning (default false)</param>
    /// <summary>Method for setting whether or not to use absolute positioning when dragging.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// dnd.setAbsolute(true); //use absolute positioning
    /// </example>
    this.setAbsolute = function(abs){
        absolute = abs;
    }//end setAbsolute()
    
    /// <name type="function">GLM.DOM.DragAndDrop.getAbsolute</name>
    /// <summary>Method for returning whether or not to use absolute positioning when dragging.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// alert(dnd.getAbsolute()); //displays false
    /// </example>
    this.getAbsolute = function(){
        return absolute;
    }//end getAbsolute()
    
    /// <name type="function">GLM.DOM.DragAndDrop.getElement</name>
    /// <summary>Method for returning the source drag element.  If a copy is being used, this is the original source.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     alert("original is: " + dnd.getElement().tagName);
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// dnd.setCopyElement(true);
    /// </example>
    this.getElement = function(){
        return element;
    }//end getElement()
    
    /// <name type="function">GLM.DOM.DragAndDrop.getEvent</name>
    /// <summary>Method for returning the last/curent event.</summary>
    /// <example>var dnd = new DragAndDrop();
    /// function OnBeginDrag(source){
    ///     var e = dnd.getEvent(); //get mousedown event
    ///     alert("source element is: " + source.tagName);
    /// }//end OnBeginDrag()
    ///
    /// function OnDrag(source, dest){
    ///     var e = dnd.getEvent(); //get mousemove event
    ///     if(dest)
    ///         alert("drop target: " + dest.tagName);
    /// }//end OnDrag()
    ///
    /// function OnDrop(source, dest){
    ///     var e = dnd.getEvent(); //get mouseup event
    ///     alert("source is: " + source.tagName);
    ///     alert("dest is: " + dest.tagName);
    /// }//end OnDrop()
    /// 
    /// dnd.setBeginDragCallback(OnBeginDrag);
    /// dnd.setDragCallback(OnDrag);
    /// dnd.setDropCallback(OnDrop);
    /// </example>
    this.getEvent = function(){
        return event;
    }//end getEvent()
    
    
    //private functions
    var onMouseDown = function(e){
        try{
            if(element)
                return true;
				
            e = e ? e : window.event;
            var el = e.srcElement ? e.srcElement : e.target;
            event = e;
            
            //check for handle attribute
            if(!el.attributes[handleAttribute])
                return;
            
            if(!el.attributes[handleAttribute].value)
                return;
            
            var firstPass = true;
            
            //iterate all parents for drag attribute
            while(el != null){
                
                if(el.attributes[dragAttribute] && el.attributes[dragAttribute].value == "true"){
                    
                    if(absolute){
                        var elPos = GLM.DOM.GetElementPosition(el);
                        absoluteX = e.clientX - elPos.x + elementOffsetX;
                        absoluteY = e.clientY - elPos.y + elementOffsetY;
                    }
                    
                    onBeginDrag(el);
					
                    if(copyElement){
                        el = el.cloneNode(true);
                        document.body.appendChild(el);
                        el.style.display = "none";
                    }//end if
					
                    element = el;
                    if(!absolute)
                        element.style.position = "absolute";
                    
                    return true;
                }//end if
                
                el = el.parentNode;
                firstPass = false;
            }//end while
            
            el = null;
        }
        catch(ex){
            throw "Error in DragAndDrop.js at method onMouseDown: " + ex;
        }//end tc
    }//end onMouseDown()
    
    var onMouseUp = function(e){
        try{
            if(!element)
                return true;
        
            e = e ? e : window.event;
            event = e;
            var el = e.srcElement ? e.srcElement : e.target;
            
            //determine good or bad drop
            var parentEl = el;
            
            try{
                while(parentEl != null){
                    if(parentEl.getAttribute(dropAttribute) && parentEl.getAttribute(dropAttribute) == "true")
                        break;
                    parentEl = parentEl.parentNode;
                }//end while
            }
            catch(ex){
                parentEl = null;
            }//end tc
			
            if(parentEl)
                el = parentEl;
            
            if(el.attributes[dropAttribute] && el.attributes[dropAttribute].value)
                onDrop(element, el);
            else
                onDrop(element, null);
            
            if(copyElement){
                if(element.parentNode)
                    element.parentNode.removeChild(element);
            }
            
            element = null;
            el = null;
        }
        catch(ex){
            throw "Error in DragAndDrop.js at method onMouseDown: " + ex;
        }//end tc
    }//end onMouseUp()
    
    var onMouseMove = function(e){
        try{
			
            if(!element)
                return true;
            
            e = e ? e : window.event;
            event = e;
        
            //make element moveable
            element.style.position = "absolute";
            
            var scrollTop = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop;
            var scrollLeft = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft;
            
            if(absolute){
                element.style.left = (e.clientX + scrollLeft - absoluteX) + "px";
                element.style.top = (e.clientY + scrollTop - absoluteY) + "px";
            }
            else{
                element.style.left = (e.clientX + elementOffsetX + scrollLeft) + "px";
                element.style.top = (e.clientY + elementOffsetY + scrollTop) + "px";
            }//end if
            
            if(copyElement)
                element.style.display = "";
        
            //determine over good or bad drop
            var el = null;
            if(e.srcElement)
                el = e.srcElement;
            else
                el = e.target;
                
            var parentEl = el;
            
            try{
                while(parentEl != null){
                    if(parentEl.attributes[dropAttribute] && parentEl.attributes[dropAttribute].value)
                        break;
                    parentEl = parentEl.parentNode;
                }//end while
            }
            catch(ex){
                parentEl = null;
            }//end tc
            
            if(parentEl)
                el = parentEl;
            
            if(el.attributes[dropAttribute] && el.attributes[dropAttribute].value)
                onDrag(element, el);
            else
                onDrag(element, null);
        }
        catch(ex){
            throw "Error in DragAndDrop.js at method onMouseDown: " + ex;
        }//end tc
        
    }//end onMouseMove()
        
    
    //constructor
    GLM.Event.AddEventHandler(document, "mousedown", onMouseDown);
    GLM.Event.AddEventHandler(document, "mouseup", onMouseUp);
    GLM.Event.AddEventHandler(document, "mousemove", onMouseMove);
    
    return this;
}//end DragAndDrop()


/************************************/
/* GLM.XML                          */
/************************************/

/// <name>GLM.XML.XMLDocument</name>
/// <summary>Class for cross browser XML.</summary>
/// <returns>The new GLM.XML.XMLDocument object.</returns>
/// <example>var xml = new GLM.XML.XMLDocument();
/// xml.load("xml/test.xml");
/// var node = xml.selectSingleNode("/xml/nodes/node");
/// alert(node.nodeName); //alert the node name
/// </example>
GLM.XML.XMLDocument = function(){
    
    var xmlDocument = null;
    var async = false;
    
    /// <name>GLM.XML.XMLDocument.setOnLoadCallback</name>
    /// <summary>Method for setting the on load callback method.</summary>
    /// <param name="callback">The callback function</param>
    /// <example>var xml = new GLM.XML.XMLDocument();
    /// 
    /// function XmlOnLoad(){
    ///     alert("xml loaded");
    /// }//end XmlOnLoad()
    ///
    /// xml.setOnLoadCallback(XmlOnLoad);
    /// xml.load("xml/test.xml");
    /// </example>
    this.setOnLoadCallback = function(callback){
        if(GLM.DOM.isInternetExplorer){
            xmlDocument.onreadystatechange = function(){
                if(xmlDocument.readyState == 4)
                    callback();
            };
        }//end if
            
        if(GLM.DOM.isMozilla)    
            xmlDocument.onload = callback;
    }//end setOnLoadCallback()
    
    /// <name>GLM.XML.XMLDocument.load</name>
    /// <param name="url">The url of the xml file to load.</param>
    /// <summary>Method for loading an xml file into the XMLDocument.</summary>
    /// <example>var xml = new GLM.XML.XMLDocument();
    /// xml.load("xml/test.xml"); //loads test.xml into the XMLDocument
    /// </example>
    this.load = function(url){
        var load = false;
        try{load = xmlDocument.loadXML;}catch(ex){}
        try{load = xmlDocument.load;}catch(ex){}
        
        if(load)
            return xmlDocument.load(url);
        else{
            if(XMLHttpRequest){
                var ao = new XMLHttpRequest();
            
                ao.onreadystatechange = function(){
                    if(ao.readyState==4 || ao.readyState=="complete"){
                        xmlDocument = ao.responseXML;
                        return xmlDocument;
                    }//end if
                };
                
                ao.open("GET", url, async);
                ao.send();
            }//end if
        }//end if
    }//end load()
    
    /// <name>GLM.XML.XMLDocument.loadXML</name>
    /// <param name="xml">The XML string to load into the XMLDocument.</param>
    /// <summary>Method for loading an XML string into the XMLDocument.</summary>
    /// <example>var xml = new GLM.XML.XMLDocument();
    /// xml.loadXML("&lt;xml&gt;&lt;nodes&gt;&lt;node&gt;hello world&lt;/node&gt;&lt;/nodes&gt;&lt;/xml&gt;");</example>;
    this.loadXML = function(xml){
        if(GLM.DOM.isInternetExplorer){
            xmlDocument.loadXML(xml);
        }
        else{
            var parser = new DOMParser();
            xmlDocument = parser.parseFromString(xml, "text/xml");
        }//end if
    }//end loadXML()
    
    /// <name>GLM.XML.XMLDocument.getXML</name>
    /// <summary>Method for returning the xml string.</summary>
    /// <returns>The xml string.</returns>
    /// <example>var xml = new GLM.XML.XMLDocument();
    /// xml.load("xml/test.xml");
    /// alert(xml.getXML()); //displays the XML of the test.xml file</example>
    this.getXML = function(){
        if(GLM.DOM.isInternetExplorer)
            return xmlDocument.xml;
        if(GLM.DOM.isMozilla)
            return new XMLSerializer().serializeToString(xmlDocument);
    }//end getXML()
    
    /// <name>GLM.XML.XMLDocument.getDocument</name>
    /// <summary>Method for returning the browser specific form of the XML document object.</summary>
    /// <returns>The browser specific XML document object.</returns>
    /// <example>var xml = new GLM.XML.XMLDocument();
    /// xml.load("xml/test.xml");
    /// alert(xml.getDocument().async); //display the async property of the XML document object</example>
    this.getDocument = function(){
        return xmlDocument;
    }//end getDocument()
    
    /// <name>GLM.XML.XMLDocument.selectNodes</name>
    /// <param name="xpath">The xpath statement to evaluate.</param>
    /// <returns>The array of selected elements.</returns>
    /// <summary>Method for executing a select nodes xpath statement.</summary>
    /// <example>var xml = new GLM.XML.XMLDocument();
    /// xml.load("xml/test.xml");
    /// var nodes = xml.selectNodes("//node") //return all node elements.</example>
    this.selectNodes = function(xpath){
        if(GLM.DOM.isInternetExplorer)
            return xmlDocument.selectNodes(xpath);
        else{
            if(xmlDocument.childNodes.length-1 < 0)
                return null;
            
            var xr = xmlDocument.evaluate(xpath, xmlDocument.childNodes[xmlDocument.childNodes.length-1], null, XPathResult.ANY_TYPE, null);
            var r = new Array();
            while(item = xr.iterateNext()){
                r.push(item);
            }//end while
            return r;
        }//end if
    }//end selectNodes()
    
    /// <name>GLM.XML.XMLDocument.selectSingleNode</name>
    /// <param name="xpath">The xpath statement to evaluate.</param>
    /// <summary>Method for executing a select single node xpath statement.</summary>
    /// <returns>The first selected element.</returns>
    /// <example>var xml = new GLM.XML.XMLDocument();
    /// xml.load("xml/test.xml");
    /// var nodes = xml.selectSingleNode("//node") //returns the first node element.</example>
    this.selectSingleNode = function(xpath){
        if(GLM.DOM.isInternetExplorer)
            return xmlDocument.selectSingleNode(xpath);
        else{
            if(xmlDocument.childNodes.length-1 < 0)
                return null;
            
            var xr = xmlDocument.evaluate(xpath, xmlDocument.childNodes[xmlDocument.childNodes.length-1], null, XPathResult.ANY_TYPE, null);
            var item = xr.iterateNext();
            return item;
        }//end if
    }//end selectSingleNode()
    
    /// <name>GLM.XML.XMLDocument.setAsync</name>
    /// <param name="async">Set to true to use asynchronous behavior, else set to false.</param>
    /// <summary>Method for setting the asynchronous load flag.</summary>
    /// <example>var xml = new GLM.XML.XMLDocument();
    ///
    /// function XmlOnLoad(){
    ///     alert(xml.getXML()); //display the xml string
    /// }//end XmlOnLoad()
    ///
    /// xml.setOnLoadCallback(XmlOnLoad);
    /// xml.setAsync(true); //use asynchronous behavior
    /// xml.load("xml/test.xml");</example>
    this.setAsync = function(async){
        xmlDocument.async = async;
    }//end setAsync()
    
    /// <name>GLM.XML.XMLDocument.getAsync</name>
    /// <returns>Whether or not the XML document is using asynchronous mode.</returns>
    /// <summary>Returns whether or not the XML document is using asynchronous mode.</summary>
    /// <example>var xml = new GLM.XML.XMLDocument();
    /// alert(xml.getAsync());</example>
    this.getAsync = function(){
        return xmlDocument.async;
    }//end getAsync()
    
    function initialize(){
        
        if(GLM.DOM.isInternetExplorer){
            xmlDocument = new ActiveXObject("Microsoft.XMLDOM");
        }
        else if(document.implementation && document.implementation.createDocument){
            xmlDocument = document.implementation.createDocument("","",null);
        }//end if
        
        xmlDocument.async = async;
    }//end initialize()
    
    initialize();
}//end GLM.XML.XMLDocument()

/// <name type="function">GLM.XML.GetAttribute</name>
/// <summary>Method for retrieving an XML attribute value.</summary>
/// <param name="node">The node to retrieve the attribute value from</param>
/// <param name="attributeName">The name of the attribute to retrieve</param>
/// <returns>The attribute value</returns>
/// <example>var xmlDoc = new GLM.XML.XMLDocument();
/// xmlDoc.setAsync(false);
/// xmlDoc.loadXML("test.xml");
/// var node = xmlDoc.selectSingleNode("//node");
/// alert(GLM.XML.GetAttribute(node, "name"));
/// </example>
GLM.XML.GetAttribute = function(node, attributeName){
    var attr = null;
    
    if(node.attributes){
        attr = node.attributes.getNamedItem(attributeName);
    }
    else{
        attr = node.getAttribute(attributeName);
    }//end if
    
    if(attr)
        attr = attr.value;
    return attr;
}//end GetAttribute()

/************************************/
/* PAJ.Security                     */
/************************************/

/// <name>PAJ.Security.MD4</name>
/// <summary>Class for handling MD4 encryption.</summary>
/// <returns>The new PAJ.Security.MD4 object.</returns>
/// <example>var md4 = new PAJ.Security.MD4();
/// var s = "hello world"; //create a string to encrypt
/// alert( md4.toHash(s) ); //display the hashed value</example>
PAJ.Security.MD4 = function(){
    
    /// <name type="function">PAJ.Security.MD4.toHash</name>
    /// <summary>Method for converting a string to a hex string.</summary>
    /// <param name="s">The string to hash</param>
    /// <returns>The hashed value.</returns>
    /// <example>var md4 = new PAJ.Security.MD4();
    /// var s = "hello world"; //create a string to encrypt
    /// alert( md4.toHash(s) ); //display the hashed value</example>
    this.toHash = function(s){
        return binl2hex(core(str2binl(s), s.length*chrsz));
    }//end toHex()
    
    /// <name type="function">PAJ.Security.MD4.toHashSet</name>
    /// <summary>Method for converting a string to a hex string.</summary>
    /// <param name="key">The key to hash.</param>
    /// <param name="value">The value to hash.</param>
    /// <returns>The hashed value.</returns>
    /// <example>var md4 = new PAJ.Security.MD4();
    /// var key = "hello"; //create a key string to encrypt
    /// var value = "world"; //create a value string to encrypt
    /// alert( md4.toHashSet(key,value) ); //display the hashset value</example>
    this.toHashSet = function(key, value){
        return binl2hex(hmac(key, value));
    }//end toHashSet()

    /// <name type="function">PAJ.Security.MD4.toBase64</name>
    /// <summary>Method for converting a string to a base 64 string.</summary>
    /// <param name="s">The value to base64 encode.</param>
    /// <returns>The hashed value.</returns>
    /// <example>var md4 = new PAJ.Security.MD4();
    /// var s = "hello world"; //create a string to encrypt
    /// alert( md4.toBase64(s) ); //display the base64 value</example>    
    this.toBase64 = function(s){
        return binl2b64(core(str2binl(s), s.length*chrsz));
    }//end toBase64()
    
    /// <name type="function">PAJ.Security.MD4.toBase64Set</name>
    /// <summary>Method for converting a key value pair to a base 64 string.</summary>
    /// <param name="key">The key to base64 encode.</param>
    /// <param name="value">The value to base64 encode.</param>
    /// <returns>The hashed value.</returns>
    /// <example>var md4 = new PAJ.Security.MD4();
    /// var key = "hello"; //create a key to encrypt
    /// var value = "world"; //create a value to encrypt
    /// alert( md4.toBase64Set(key,value) ); //display the base64 value</example>    
    this.toBase64Set = function(key, value){
        return binl2b64(hmac(key, value));
    }//end toBase64Set()
    
    /// <name type="function">PAJ.Security.MD4.toString</name>
    /// <summary>Method for converting the value to a string.</summary>
    /// <param name="s">The hashed value.</param>
    /// <returns>The hashed value.</returns>
    /// <example>var md4 = new PAJ.Security.MD4();
    /// var s = "hello world"; //create a string to encrypt
    /// alert( md4.toString(s) ); //display the string hash version</example>    
    this.toString = function(s){
        return binl2str(core(str2binl(s), s.length*chrsz));
    }//end toString()
    
    /// <name type="function">PAJ.Security.MD4.toStringSet</name>
    /// <summary>Method for converting a key value pair to a string.</summary>
    /// <param name="key">The key to hash.</param>
    /// <param name="value">The value to hash.</param>
    /// <returns>The hashed value.</returns>
    /// <example>var md4 = new PAJ.Security.MD4();
    /// var key = "hello"; //create a key to encrypt
    /// var value = "world"; //create a value to encrypt
    /// alert( md4.toStringSet(key, value) ); //display the string hashset version</example>    
    this.toStringSet = function(key, value){
        return binl2str(hmac(key, value));
    }//end toStringSet()
    
    //Internal Only
    
    var hexcase = 0;
    var b64pad = "";
    var chrsz = 8;
    
    //Method for converting a string to an array of little-endian words
    //If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
    var str2binl = function(str){
        var bin = Array();
        var mask = (1 << chrsz) - 1;
        for(var i = 0; i < str.length * chrsz; i += chrsz)
            bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
        return bin;
    }//end str2binl()
    
    //Method for converting an array of little-endian words to a string
    var binl2str = function(bin){
        var str = "";
        var mask = (1 << chrsz) - 1;
        for(var i = 0; i < bin.length * 32; i += chrsz)
            str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
        return str;
    }//end bin2str()
    
    //Method for converting an array of little-endian words to a hex string.
    var binl2hex = function(binarray){
        var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
        var str = "";
        for(var i = 0; i < binarray.length * 4; i++)
        {
            str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
                hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
        }
        return str;
    }//end binl2hex()
    
    //Method for converting an array of little-endian words to a base-64 string.
    var binl2b64 = function(binarray)
    {
        var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        var str = "";
        for(var i = 0; i < binarray.length * 4; i += 3)
        {
            var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
            | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
            |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
            for(var j = 0; j < 4; j++)
            {
                if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
                else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
            }
        }
        return str;
    }//end binl2b64()
    
    //Bitwise rotate a 32-bit number to the left.
    var bit_rol = function(num, cnt){
        return (num << cnt) | (num >>> (32 - cnt));
    }//end bit_rol()
        
    //Add integers, wrapping at 2^32. This uses 16-bit operations internally
    //to work around bugs in some JS interpreters.
    var safe_add = function(x, y){
        var lsw = (x & 0xFFFF) + (y & 0xFFFF);
        var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
        return (msw << 16) | (lsw & 0xFFFF);
    }//end safe_add()
        
    var cmn = function(q, a, b, x, s, t){
        return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
    }//end cmn()
        
    var ff = function(a, b, c, d, x, s, t){
        return cmn((b & c) | ((~b) & d), a, b, x, s, t);
    }//end ff()
        
    var gg = function(a, b, c, d, x, s, t){
        return cmn((b & d) | (c & (~d)), a, b, x, s, t);
    }//end gg()
        
    var hh = function(a, b, c, d, x, s, t){
        return cmn(b ^ c ^ d, a, b, x, s, t);
    }//end hh()
        
    var ii = function(a, b, c, d, x, s, t){
        return cmn(c ^ (b | (~d)), a, b, x, s, t);
    }//end ii()
        
    //Calculate the HMAC-MD5, of a key and some data
    var hmac = function(key, data){
        var bkey = str2binl(key);
        if(bkey.length > 16) bkey = core(bkey, key.length * chrsz);

        var ipad = Array(16), opad = Array(16);
        for(var i = 0; i < 16; i++) 
        {
            ipad[i] = bkey[i] ^ 0x36363636;
            opad[i] = bkey[i] ^ 0x5C5C5C5C;
        }//end for

        var hash = core(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
        return core(opad.concat(hash), 512 + 128);
    }//end hmac()
    
    //Core converstion function
    var core = function(x, len){
        
        /* append padding */
        x[len >> 5] |= 0x80 << (len % 32);
        x[(((len + 64) >>> 9) << 4) + 14] = len;
  
        var a =  1732584193;
        var b = -271733879;
        var c = -1732584194;
        var d =  271733878;

        for(var i = 0; i < x.length; i += 16)
        {
            var olda = a;
            var oldb = b;
            var oldc = c;
            var oldd = d;

            a = ff(a, b, c, d, x[i+ 0], 3 );
            d = ff(d, a, b, c, x[i+ 1], 7 );
            c = ff(c, d, a, b, x[i+ 2], 11);
            b = ff(b, c, d, a, x[i+ 3], 19);
            a = ff(a, b, c, d, x[i+ 4], 3 );
            d = ff(d, a, b, c, x[i+ 5], 7 );
            c = ff(c, d, a, b, x[i+ 6], 11);
            b = ff(b, c, d, a, x[i+ 7], 19);
            a = ff(a, b, c, d, x[i+ 8], 3 );
            d = ff(d, a, b, c, x[i+ 9], 7 );
            c = ff(c, d, a, b, x[i+10], 11);
            b = ff(b, c, d, a, x[i+11], 19);
            a = ff(a, b, c, d, x[i+12], 3 );
            d = ff(d, a, b, c, x[i+13], 7 );
            c = ff(c, d, a, b, x[i+14], 11);
            b = ff(b, c, d, a, x[i+15], 19);

            a = gg(a, b, c, d, x[i+ 0], 3 );
            d = gg(d, a, b, c, x[i+ 4], 5 );
            c = gg(c, d, a, b, x[i+ 8], 9 );
            b = gg(b, c, d, a, x[i+12], 13);
            a = gg(a, b, c, d, x[i+ 1], 3 );
            d = gg(d, a, b, c, x[i+ 5], 5 );
            c = gg(c, d, a, b, x[i+ 9], 9 );
            b = gg(b, c, d, a, x[i+13], 13);
            a = gg(a, b, c, d, x[i+ 2], 3 );
            d = gg(d, a, b, c, x[i+ 6], 5 );
            c = gg(c, d, a, b, x[i+10], 9 );
            b = gg(b, c, d, a, x[i+14], 13);
            a = gg(a, b, c, d, x[i+ 3], 3 );
            d = gg(d, a, b, c, x[i+ 7], 5 );
            c = gg(c, d, a, b, x[i+11], 9 );
            b = gg(b, c, d, a, x[i+15], 13);

            a = hh(a, b, c, d, x[i+ 0], 3 );
            d = hh(d, a, b, c, x[i+ 8], 9 );
            c = hh(c, d, a, b, x[i+ 4], 11);
            b = hh(b, c, d, a, x[i+12], 15);
            a = hh(a, b, c, d, x[i+ 2], 3 );
            d = hh(d, a, b, c, x[i+10], 9 );
            c = hh(c, d, a, b, x[i+ 6], 11);
            b = hh(b, c, d, a, x[i+14], 15);
            a = hh(a, b, c, d, x[i+ 1], 3 );
            d = hh(d, a, b, c, x[i+ 9], 9 );
            c = hh(c, d, a, b, x[i+ 5], 11);
            b = hh(b, c, d, a, x[i+13], 15);
            a = hh(a, b, c, d, x[i+ 3], 3 );
            d = hh(d, a, b, c, x[i+11], 9 );
            c = hh(c, d, a, b, x[i+ 7], 11);
            b = hh(b, c, d, a, x[i+15], 15);

            a = safe_add(a, olda);
            b = safe_add(b, oldb);
            c = safe_add(c, oldc);
            d = safe_add(d, oldd);

        }
        return Array(a, b, c, d);

    }//end core()
    
}//end PAJ.Security.MD4

/// <name>PAJ.Security.MD5</name>
/// <summary>Class for handling MD5 encryption.</summary>
/// <returns>The new PAJ.Security.MD5 object.</returns>
/// <example>var md5 = new PAJ.Security.MD5();
/// var s = "hello world"; //create a string to encrypt
/// alert( md5.toHash(s) ); //display the hashed value</example>
PAJ.Security.MD5 = function(){
    
    /// <name type="function">PAJ.Security.MD5.toHash</name>
    /// <summary>Method for converting a string to a hex string.</summary>
    /// <param name="s">The string to hash</param>
    /// <returns>The hashed value.</returns>
    /// <example>var md5 = new PAJ.Security.MD5();
    /// var s = "hello world"; //create a string to encrypt
    /// alert( md5.toHash(s) ); //display the hashed value</example>
    this.toHash = function(s){
        return binl2hex(core(str2binl(s), s.length*chrsz));
    }//end toHex()
    
    /// <name type="function">PAJ.Security.MD5.toHashSet</name>
    /// <summary>Method for converting a string to a hex string.</summary>
    /// <param name="key">The key to hash.</param>
    /// <param name="value">The value to hash.</param>
    /// <returns>The hashed value.</returns>
    /// <example>var md5 = new PAJ.Security.MD5();
    /// var key = "hello"; //create a key string to encrypt
    /// var value = "world"; //create a value string to encrypt
    /// alert( md5.toHashSet(key,value) ); //display the hashset value</example>
    this.toHashSet = function(key, value){
        return binl2hex(hmac(key, value));
    }//end toHashSet()
    
    /// <name type="function">PAJ.Security.MD5.toBase64</name>
    /// <summary>Method for converting a string to a base 64 string.</summary>
    /// <param name="s">The value to base64 encode.</param>
    /// <returns>The hashed value.</returns>
    /// <example>var md5 = new PAJ.Security.MD5();
    /// var s = "hello world"; //create a string to encrypt
    /// alert( md5.toBase64(s) ); //display the base64 value</example>   
    this.toBase64 = function(s){
        return binl2b64(core(str2binl(s), s.length*chrsz));
    }//end toBase64()
    
    /// <name type="function">PAJ.Security.MD5.toBase64Set</name>
    /// <summary>Method for converting a key value pair to a base 64 string.</summary>
    /// <param name="key">The key to base64 encode.</param>
    /// <param name="value">The value to base64 encode.</param>
    /// <returns>The hashed value.</returns>
    /// <example>var md5 = new PAJ.Security.MD4();
    /// var key = "hello"; //create a key to encrypt
    /// var value = "world"; //create a value to encrypt
    /// alert( md5.toBase64Set(key,value) ); //display the base64 value</example>  
    this.toBase64Set = function(key, value){
        return binl2b64(hmac(key, value));
    }//end toBase64Set()
    
    /// <name type="function">PAJ.Security.MD5.toString</name>
    /// <summary>Method for converting the value to a string.</summary>
    /// <param name="s">The hashed value.</param>
    /// <returns>The hashed value.</returns>
    /// <example>var md5 = new PAJ.Security.MD5();
    /// var s = "hello world"; //create a string to encrypt
    /// alert( md5.toString(s) ); //display the string hash version</example>  
    this.toString = function(s){
        return binl2str(core(str2binl(s), s.length*chrsz));
    }//end toString()
    
    /// <name type="function">PAJ.Security.MD5.toStringSet</name>
    /// <summary>Method for converting a key value pair to a string.</summary>
    /// <param name="key">The key to hash.</param>
    /// <param name="value">The value to hash.</param>
    /// <returns>The hashed value.</returns>
    /// <example>var md5 = new PAJ.Security.MD5();
    /// var key = "hello"; //create a key to encrypt
    /// var value = "world"; //create a value to encrypt
    /// alert( md5.toStringSet(key, value) ); //display the string hashset version</example> 
    this.toStringSet = function(key, value){
        return binl2str(hmac(key, value));
    }//end toStringSet()
    
    //Internal Only
    
    var hexcase = 0;
    var b64pad = "";
    var chrsz = 8;
    
    //Method for converting a string to an array of little-endian words
    //If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
    var str2binl = function(str){
        var bin = Array();
        var mask = (1 << chrsz) - 1;
        for(var i = 0; i < str.length * chrsz; i += chrsz)
            bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
        return bin;
    }//end str2binl()
    
    //Method for converting an array of little-endian words to a string
    var binl2str = function(bin){
        var str = "";
        var mask = (1 << chrsz) - 1;
        for(var i = 0; i < bin.length * 32; i += chrsz)
            str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
        return str;
    }//end bin2str()
    
    //Method for converting an array of little-endian words to a hex string.
    var binl2hex = function(binarray){
        var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
        var str = "";
        for(var i = 0; i < binarray.length * 4; i++)
        {
            str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
                hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
        }
        return str;
    }//end binl2hex()
    
    //Method for converting an array of little-endian words to a base-64 string.
    var binl2b64 = function(binarray)
    {
        var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        var str = "";
        for(var i = 0; i < binarray.length * 4; i += 3)
        {
            var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
            | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
            |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
            for(var j = 0; j < 4; j++)
            {
                if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
                else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
            }
        }
        return str;
    }//end binl2b64()
    
    //Bitwise rotate a 32-bit number to the left.
    var bit_rol = function(num, cnt){
        return (num << cnt) | (num >>> (32 - cnt));
    }//end bit_rol()
        
    //Add integers, wrapping at 2^32. This uses 16-bit operations internally
    //to work around bugs in some JS interpreters.
    var safe_add = function(x, y){
        var lsw = (x & 0xFFFF) + (y & 0xFFFF);
        var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
        return (msw << 16) | (lsw & 0xFFFF);
    }//end safe_add()
        
    var cmn = function(q, a, b, x, s, t){
        return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
    }//end cmn()
        
    var ff = function(a, b, c, d, x, s, t){
        return cmn((b & c) | ((~b) & d), a, b, x, s, t);
    }//end ff()
        
    var gg = function(a, b, c, d, x, s, t){
        return cmn((b & d) | (c & (~d)), a, b, x, s, t);
    }//end gg()
        
    var hh = function(a, b, c, d, x, s, t){
        return cmn(b ^ c ^ d, a, b, x, s, t);
    }//end hh()
        
    var ii = function(a, b, c, d, x, s, t){
        return cmn(c ^ (b | (~d)), a, b, x, s, t);
    }//end ii()
        
    //Calculate the HMAC-MD5, of a key and some data
    var hmac = function(key, data){
        var bkey = str2binl(key);
        if(bkey.length > 16) bkey = core(bkey, key.length * chrsz);

        var ipad = Array(16), opad = Array(16);
        for(var i = 0; i < 16; i++) 
        {
            ipad[i] = bkey[i] ^ 0x36363636;
            opad[i] = bkey[i] ^ 0x5C5C5C5C;
        }//end for

        var hash = core(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
        return core(opad.concat(hash), 512 + 128);
    }//end hmac()
    
    //Core converstion function
    var core = function(x, len){
        
        x[len >> 5] |= 0x80 << ((len) % 32);
        x[(((len + 64) >>> 9) << 4) + 14] = len;
  
        var a =  1732584193;
        var b = -271733879;
        var c = -1732584194;
        var d =  271733878;

        for(var i = 0; i < x.length; i += 16)
        {
            var olda = a;
            var oldb = b;
            var oldc = c;
            var oldd = d;
 
            a = ff(a, b, c, d, x[i+ 0], 7 , -680876936);
            d = ff(d, a, b, c, x[i+ 1], 12, -389564586);
            c = ff(c, d, a, b, x[i+ 2], 17,  606105819);
            b = ff(b, c, d, a, x[i+ 3], 22, -1044525330);
            a = ff(a, b, c, d, x[i+ 4], 7 , -176418897);
            d = ff(d, a, b, c, x[i+ 5], 12,  1200080426);
            c = ff(c, d, a, b, x[i+ 6], 17, -1473231341);
            b = ff(b, c, d, a, x[i+ 7], 22, -45705983);
            a = ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
            d = ff(d, a, b, c, x[i+ 9], 12, -1958414417);
            c = ff(c, d, a, b, x[i+10], 17, -42063);
            b = ff(b, c, d, a, x[i+11], 22, -1990404162);
            a = ff(a, b, c, d, x[i+12], 7 ,  1804603682);
            d = ff(d, a, b, c, x[i+13], 12, -40341101);
            c = ff(c, d, a, b, x[i+14], 17, -1502002290);
            b = ff(b, c, d, a, x[i+15], 22,  1236535329);

            a = gg(a, b, c, d, x[i+ 1], 5 , -165796510);
            d = gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
            c = gg(c, d, a, b, x[i+11], 14,  643717713);
            b = gg(b, c, d, a, x[i+ 0], 20, -373897302);
            a = gg(a, b, c, d, x[i+ 5], 5 , -701558691);
            d = gg(d, a, b, c, x[i+10], 9 ,  38016083);
            c = gg(c, d, a, b, x[i+15], 14, -660478335);
            b = gg(b, c, d, a, x[i+ 4], 20, -405537848);
            a = gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
            d = gg(d, a, b, c, x[i+14], 9 , -1019803690);
            c = gg(c, d, a, b, x[i+ 3], 14, -187363961);
            b = gg(b, c, d, a, x[i+ 8], 20,  1163531501);
            a = gg(a, b, c, d, x[i+13], 5 , -1444681467);
            d = gg(d, a, b, c, x[i+ 2], 9 , -51403784);
            c = gg(c, d, a, b, x[i+ 7], 14,  1735328473);
            b = gg(b, c, d, a, x[i+12], 20, -1926607734);

            a = hh(a, b, c, d, x[i+ 5], 4 , -378558);
            d = hh(d, a, b, c, x[i+ 8], 11, -2022574463);
            c = hh(c, d, a, b, x[i+11], 16,  1839030562);
            b = hh(b, c, d, a, x[i+14], 23, -35309556);
            a = hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
            d = hh(d, a, b, c, x[i+ 4], 11,  1272893353);
            c = hh(c, d, a, b, x[i+ 7], 16, -155497632);
            b = hh(b, c, d, a, x[i+10], 23, -1094730640);
            a = hh(a, b, c, d, x[i+13], 4 ,  681279174);
            d = hh(d, a, b, c, x[i+ 0], 11, -358537222);
            c = hh(c, d, a, b, x[i+ 3], 16, -722521979);
            b = hh(b, c, d, a, x[i+ 6], 23,  76029189);
            a = hh(a, b, c, d, x[i+ 9], 4 , -640364487);
            d = hh(d, a, b, c, x[i+12], 11, -421815835);
            c = hh(c, d, a, b, x[i+15], 16,  530742520);
            b = hh(b, c, d, a, x[i+ 2], 23, -995338651);

            a = ii(a, b, c, d, x[i+ 0], 6 , -198630844);
            d = ii(d, a, b, c, x[i+ 7], 10,  1126891415);
            c = ii(c, d, a, b, x[i+14], 15, -1416354905);
            b = ii(b, c, d, a, x[i+ 5], 21, -57434055);
            a = ii(a, b, c, d, x[i+12], 6 ,  1700485571);
            d = ii(d, a, b, c, x[i+ 3], 10, -1894986606);
            c = ii(c, d, a, b, x[i+10], 15, -1051523);
            b = ii(b, c, d, a, x[i+ 1], 21, -2054922799);
            a = ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
            d = ii(d, a, b, c, x[i+15], 10, -30611744);
            c = ii(c, d, a, b, x[i+ 6], 15, -1560198380);
            b = ii(b, c, d, a, x[i+13], 21,  1309151649);
            a = ii(a, b, c, d, x[i+ 4], 6 , -145523070);
            d = ii(d, a, b, c, x[i+11], 10, -1120210379);
            c = ii(c, d, a, b, x[i+ 2], 15,  718787259);
            b = ii(b, c, d, a, x[i+ 9], 21, -343485551);

            a = safe_add(a, olda);
            b = safe_add(b, oldb);
            c = safe_add(c, oldc);
            d = safe_add(d, oldd);
        }//end for
        
        return Array(a, b, c, d);
    }//end core()
}//end PAJ.Security.MD5

/// <name>PAJ.Security.SHA1</name>
/// <summary>Class for handling MD5 encryption.</summary>
/// <returns>The new PAJ.Security.SHA1 object.</returns>
/// <example>var sha1 = new PAJ.Security.SHA1();
/// var s = "hello world"; //create a string to encrypt
/// alert( sha1.toHash(s) ); //display the hashed value</example>
PAJ.Security.SHA1 = function(){
    
    /// <name type="function">PAJ.Security.SHA1.toHash</name>
    /// <summary>Method for converting a string to a hex string.</summary>
    /// <param name="s">The string to hash</param>
    /// <returns>The hashed value.</returns>
    /// <example>var sha1 = new PAJ.Security.SHA1();
    /// var s = "hello world"; //create a string to encrypt
    /// alert( sha1.toHash(s) ); //display the hashed value</example>
    this.toHash = function(s){
        return binl2hex(core(str2binl(s), s.length*chrsz));
    }//end toHex()
    
    /// <name type="function">PAJ.Security.SHA1.toHashSet</name>
    /// <summary>Method for converting a string to a hex string.</summary>
    /// <param name="key">The key to hash.</param>
    /// <param name="value">The value to hash.</param>
    /// <returns>The hashed value.</returns>
    /// <example>var sha1 = new PAJ.Security.SHA1();
    /// var key = "hello"; //create a key string to encrypt
    /// var value = "world"; //create a value string to encrypt
    /// alert( sha1.toHashSet(key,value) ); //display the hashset value</example>
    this.toHashSet = function(key, value){
        return binl2hex(hmac(key, value));
    }//end toHashSet()
    
    /// <name type="function">PAJ.Security.SHA1.toBase64</name>
    /// <summary>Method for converting a string to a base 64 string.</summary>
    /// <param name="s">The value to base64 encode.</param>
    /// <returns>The hashed value.</returns>
    /// <example>var sha1 = new PAJ.Security.SHA1();
    /// var s = "hello world"; //create a string to encrypt
    /// alert( sha1.toBase64(s) ); //display the base64 value</example>   
    this.toBase64 = function(s){
        return binl2b64(core(str2binl(s), s.length*chrsz));
    }//end toBase64()
    
    /// <name type="function">PAJ.Security.SHA1.toBase64Set</name>
    /// <summary>Method for converting a key value pair to a base 64 string.</summary>
    /// <param name="key">The key to base64 encode.</param>
    /// <param name="value">The value to base64 encode.</param>
    /// <returns>The hashed value.</returns>
    /// <example>var sha1 = new PAJ.Security.SHA1();
    /// var key = "hello"; //create a key to encrypt
    /// var value = "world"; //create a value to encrypt
    /// alert( sha1.toBase64Set(key,value) ); //display the base64 value</example> 
    this.toBase64Set = function(key, value){
        return binl2b64(hmac(key, value));
    }//end toBase64Set()
    
    /// <name type="function">PAJ.Security.SHA1.toString</name>
    /// <summary>Method for converting the value to a string.</summary>
    /// <param name="s">The hashed value.</param>
    /// <returns>The hashed value.</returns>
    /// <example>var sha1 = new PAJ.Security.SHA1();
    /// var s = "hello world"; //create a string to encrypt
    /// alert( sha1.toString(s) ); //display the string hash version</example> 
    this.toString = function(s){
        return binl2str(core(str2binl(s), s.length*chrsz));
    }//end toString()
    
    /// <name type="function">PAJ.Security.SHA1.toStringSet</name>
    /// <summary>Method for converting a key value pair to a string.</summary>
    /// <param name="key">The key to hash.</param>
    /// <param name="value">The value to hash.</param>
    /// <returns>The hashed value.</returns>
    /// <example>var sha1 = new PAJ.Security.SHA1();
    /// var key = "hello"; //create a key to encrypt
    /// var value = "world"; //create a value to encrypt
    /// alert( sha1.toStringSet(key, value) ); //display the string hashset version</example> 
    this.toStringSet = function(key, value){
        return binl2str(hmac(key, value));
    }//end toStringSet()
    
    //Internal Only
    
    var hexcase = 0;
    var b64pad = "";
    var chrsz = 8;
    
    //Method for converting a string to an array of little-endian words
    //If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
    var str2binl = function(str){
        var bin = Array();
        var mask = (1 << chrsz) - 1;
        for(var i = 0; i < str.length * chrsz; i += chrsz)
            bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
        return bin;
    }//end str2binl()
    
    //Method for converting an array of little-endian words to a string
    var binl2str = function(bin){
        var str = "";
        var mask = (1 << chrsz) - 1;
        for(var i = 0; i < bin.length * 32; i += chrsz)
            str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
        return str;
    }//end bin2str()
    
    //Method for converting an array of little-endian words to a hex string.
    var binl2hex = function(binarray){
        var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
        var str = "";
        for(var i = 0; i < binarray.length * 4; i++)
        {
            str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
                hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
        }
        return str;
    }//end binl2hex()
    
    //Method for converting an array of little-endian words to a base-64 string.
    var binl2b64 = function(binarray)
    {
        var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        var str = "";
        for(var i = 0; i < binarray.length * 4; i += 3)
        {
            var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
            | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
            |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
            for(var j = 0; j < 4; j++)
            {
                if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
                else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
            }
        }
        return str;
    }//end binl2b64()
    
    //Bitwise rotate a 32-bit number to the left.
    var bit_rol = function(num, cnt){
        return (num << cnt) | (num >>> (32 - cnt));
    }//end bit_rol()
        
    //Add integers, wrapping at 2^32. This uses 16-bit operations internally
    //to work around bugs in some JS interpreters.
    var safe_add = function(x, y){
        var lsw = (x & 0xFFFF) + (y & 0xFFFF);
        var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
        return (msw << 16) | (lsw & 0xFFFF);
    }//end safe_add()
        
    var cmn = function(q, a, b, x, s, t){
        return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
    }//end cmn()
        
    var ff = function(a, b, c, d, x, s, t){
        return cmn((b & c) | ((~b) & d), a, b, x, s, t);
    }//end ff()
        
    var gg = function(a, b, c, d, x, s, t){
        return cmn((b & d) | (c & (~d)), a, b, x, s, t);
    }//end gg()
        
    var hh = function(a, b, c, d, x, s, t){
        return cmn(b ^ c ^ d, a, b, x, s, t);
    }//end hh()
        
    var ii = function(a, b, c, d, x, s, t){
        return cmn(c ^ (b | (~d)), a, b, x, s, t);
    }//end ii()
        
    //Calculate the HMAC-MD5, of a key and some data
    var hmac = function(key, data){
        var bkey = str2binl(key);
        if(bkey.length > 16) bkey = core(bkey, key.length * chrsz);

        var ipad = Array(16), opad = Array(16);
        for(var i = 0; i < 16; i++) 
        {
            ipad[i] = bkey[i] ^ 0x36363636;
            opad[i] = bkey[i] ^ 0x5C5C5C5C;
        }//end for

        var hash = core(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
        return core(opad.concat(hash), 512 + 128);
    }//end hmac()
    
    //Method for performaing the appropriate triplet combination function for the current
    //iteration
    var ft = function(t, b, c, d)
    {
        if(t < 20) return (b & c) | ((~b) & d);
        if(t < 40) return b ^ c ^ d;
        if(t < 60) return (b & c) | (b & d) | (c & d);
        return b ^ c ^ d;
    }//end ft()

    //Method for determining the appropriate additive constant for the current iteration
    var kt = function(t){
        return (t < 20) ?  1518500249 : (t < 40) ?  1859775393 :
        (t < 60) ? -1894007588 : -899497514;
    }//end kt()
    
    //core conversion function
    var core = function(x, len){
        /* append padding */
        x[len >> 5] |= 0x80 << (24 - len % 32);
        x[((len + 64 >> 9) << 4) + 15] = len;

        var w = Array(80);
        var a =  1732584193;
        var b = -271733879;
        var c = -1732584194;
        var d =  271733878;
        var e = -1009589776;

        for(var i = 0; i < x.length; i += 16)
        {
            var olda = a;
            var oldb = b;
            var oldc = c;
            var oldd = d;
            var olde = e;

            for(var j = 0; j < 80; j++)
            {
                if(j < 16) w[j] = x[i + j];
                else w[j] = bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
                var t = safe_add(safe_add(bit_rol(a, 5), ft(j, b, c, d)),
                                 safe_add(safe_add(e, w[j]), kt(j)));
                e = d;
                d = c;
                c = bit_rol(b, 30);
                b = a;
                a = t;
            }

            a = safe_add(a, olda);
            b = safe_add(b, oldb);
            c = safe_add(c, oldc);
            d = safe_add(d, oldd);
            e = safe_add(e, olde);
        }
        return Array(a, b, c, d, e);

    }//end core()
    
    
}//end PAJ.Security.SHA1


/************************************/
/* GLM.Collection                   */
/************************************/

/// <name>GLM.Collection.Map</name>
/// <summary>Map class for holding key value pairs.</summary>
/// <returns>The new GLM.Collection.Map object.</returns>
/// <example>var m = new GLM.Collection.Map();
/// m.add("name1","value1");
/// m.add("name2","value2");
/// alert( m.get("name1") ); //alerts "value1"</example>
GLM.Collection.Map = function(){
    var len = 0;
    var keys = new Array();
    var values = new Array();

    /// <name type="function">GLM.Collection.Map.get</name>
    /// <summary>Method for returning the value associated with a key.</summary>
    /// <param name="key">The key to return the associated value of.</param>
    /// <returns>The value associated with the key.</returns>
    /// <example>var m = new GLM.Collection.Map();
    /// m.add("name1","value1");
    /// m.add("name2","value2");
    /// alert( m.get("name1") ); //alerts "value1"</example>
    this.get = function(key){
        var val = null;
        for(var i=0; i<len; i++){
            if(keys[i] == key){
                val = values[i];
                break;
            }//end if
        }//end for

        return val;
    }//end get()

    /// <name type="function">GLM.Collection.Map.put</name>
    /// <summary>Method for storing an associated key value.</summary>
    /// <param name="key">The key to associate with the value.</param>
    /// <param name="value">The value associated with the key.</param>
    /// <example>var m = new GLM.Collection.Map();
    /// m.add("name1","value1");
    /// m.add("name2","value2");
    /// alert( m.get("name1") ); //alerts "value1"</example>
    this.put = function(key, value){
        keys[len] = key;
        values[len++] = value;
    }//end put()

    /// <name type="function">GLM.Collection.Map.length</name>
    /// <summary>Method for returning the count of items in the map.</summary>
    /// <returns>The count of items in the map.</returns>
    /// <example>var m = new GLM.Collection.Map();
    /// m.add("name1","value1");
    /// m.add("name2","value2");
    /// alert( m.length ); //alerts 2</example>
    this.length = function(){
        return len;
    }//end length()

    /// <name type="function">GLM.Collection.Map.contains</name>
    /// <summary>Method for determining if the map contains a specific key.</summary>
    /// <param name="key">The key to search for.</param>
    /// <returns>True if the map contains the key, otherwise false.</returns>
    /// <example>var m = new GLM.Collection.Map();
    /// m.add("name1","value1");
    /// m.add("name2","value2");
    /// alert( m.contains("name1") ); //alerts true</example>
    this.contains = function(key){
        var con = false;
        for(var i=0; i<len; i++){
            if(keys[i] == key){
                con = true;
                break;
            }//end if
        }//end for

        return con;
    }//end contains()

    /// <name type="function">GLM.Collection.Map.remove</name>
    /// <summary>Method for removing a key value pair by key name.</summary>
    /// <param name="key">The key to search for.</param>
    /// <example>var m = new GLM.Collection.Map();
    /// m.add("name1","value1");
    /// m.add("name2","value2");
    /// m.remove("name1");
    /// alert( m.contains("name1") ); //alerts false</example>
    this.remove = function(key){
        var keyArr = new Array();
        var valArr = new Array();
        var l = 0;
        for(var i=0; i<len; i++){
            if(keys[i] != key){
                keyArr[l] = keys[i];
                valArr[l++] = values[i];
            }//end if
        }//end for

        keys = keyArr;
        values = valArr;
        len = l;
    }//end remove()        
    
}//end GLM.Collection.Map


/************************************/
/* GLM.AJAX                         */
/************************************/

/// <name>GLM.AJAX</name>
/// <summary>Class for performing AJAX.</summary>
/// <returns>The new GLM.AJAX object.</returns>
/// <example>var ajax = new GLM.AJAX();
/// 
/// function ajaxCallback(content){
///     alert(content); //displays the contents of the page.
/// }
///
/// ajax.callPage("myPage.html", ajaxCallback); //call myPage.html and pass the contents to ajaxCallback.</example>
GLM.AJAX = function(){

    var nameSpace = "http://tempuri.org/";
    var map = new GLM.Collection.Map();
    
    //private method for returning an ajax enabled
    //object specific to a browser
    var ajaxObject = function(){
        try{return new XMLHttpRequest();}catch(ex){};
        try{return new ActiveXObject("Microsoft.XMLHTTP");}catch(ex){};
        try{return new SOAPCall();}catch(ex){};
    }//end ajaxObject()
    
    /// <name type="function">GLM.AJAX.onError</name>
    /// <summary>Method for handling ajax errors.</summary>
    /// <example>var ajax = new GLM.AJAX();
    /// 
    /// function ajaxCallback(content){
    ///         alert(content); //displays the contents of the page
    /// }
    ///
    /// function ajaxError(error){
    ///         alert(error); //alert the error
    /// }
    ///
    /// ajax.onErrror = ajaxError; //assign error handler
    /// ajax.callPage("myPage.html", ajaxCallback); //call myPage.html and pass the contents to ajaxCallback</example>
    this.onError = function(error){
        alert(error);
    }//end onError()

    /// <name type="function">GLM.AJAX.callPage</name>
    /// <summary>Method for calling a page using AJAX.</summary>
    /// <param name="url">The url of the page to call.</param>
    /// <param name="callbackFunction">The function to call when the AJAX call succeeds.</param>
    /// <param name="method">(Optional) GET or POST, default is GET</param>
    /// <param name="args">(Optional) POST arguments.</param>
    /// <param name="async">(Optional) Specify synchronous/asynchronous mode, default is true.</param>
    /// <example>var ajax = new GLM.AJAX();
    /// 
    /// function ajaxCallback(content){
    ///         alert(content); //displays the contents of the page.
    /// }
    ///
    /// ajax.callPage("myPage.html", ajaxCallback); //call myPage.html and pass the contents to ajaxCallback.</example>
    this.callPage = function(url, callbackFunction, method, args, async){        
        try{
            var ao = ajaxObject();
                
            ao.onreadystatechange = function(){
                if(ao.readyState==4 || ao.readyState=="complete"){
                    callbackFunction(ao.responseText);
                }
            };
                
            if(!method) method = "GET";
            if(!args) args = null;
            if(async == null) async = true;
                
            ao.open(method, url, async);
                
            if(method == "POST")
                ao.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                
            ao.send(args);
            
            if(GLM.DOM.isMozilla && !async)
                callbackFunction(ao.responseText);
        }
        catch(ex){
            this.onError(ex);
        }//end tc
    }//end callPage()
	

    /// <name type="function">GLM.AJAX.callService</name>
    /// <summary>Method for calling a webservice using AJAX.</summary>
    /// <param name="serviceUrl">The url of the service to call.</param>
    /// <param name="soapMethod">The method of the service to call.</param>
    /// <param name="callbackFunction">The function to call when the AJAX call succeeds.</param>
    /// <param name="param1, param2 ... paramN">Optional parameters passed to the webservice.  Parameters must be in the 
    /// form of "name=value".</param>
    /// <example>var ajax = new GLM.AJAX();
    /// 
    /// function ajaxCallback(content){
    ///         alert(content); //displays the contents of the page.
    /// }
    ///
    /// ajax.callPage("myService.asmx", "myMethod", ajaxCallback); //call myService.asmx and pass the contents to ajaxCallback.</example>
    this.callService = function(serviceUrl, soapMethod, callbackFunction /*, unlimited params */){
        
        var callServiceError = this.onError;
        
        var ao = ajaxObject();
        
        if(!ao.encode){
            if(serviceUrl.indexOf("http://") < 0)
                serviceUrl = "http://" + serviceUrl;
            serviceUrl += "?WSDL";
            
            var soapEnvelope = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
            soapEnvelope += "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">";
            soapEnvelope += "<soap:Body>";
            soapEnvelope += "<" + soapMethod + " xmlns=\"" + nameSpace + "\">";
            
            if(arguments.length > 3){
                for (var i = 3; i < arguments.length; i++)
                {
                    var params = arguments[i].split("=");
                    soapEnvelope += "<" + params[0] + ">";
                    soapEnvelope += params[1];
                    soapEnvelope += "</" + params[0] + ">";
                }//end for
            }//end if
			
            soapEnvelope += "</" + soapMethod + ">";
            soapEnvelope += "</soap:Body>";
            soapEnvelope += "</soap:Envelope>";
            
            ao.onreadystatechange = function(){
            
                if(ao.readyState == 4){
                    
                    try{
                        var response = ao.responseXML.getElementsByTagName(soapMethod + "Result")[0];
                        if(!response)
                            response = ao.responseXML.getElementsByTagName(soapMethod + "Response")[0];
                        if(!response){
                            callServiceError("WebService does not contain a Result/Response node");
                            return;
                        }//end if
                        
                        if(response.textContent)
                            callbackFunction(response.textContent);
                        else if(response.text)
                            callbackFunction(response.text);
                    }
                    catch(ex){
                        callServiceError(ex);
                    }//end if
                }//end if
            };
            
            ao.open("POST", serviceUrl, true);			
            ao.setRequestHeader("Content-Type", "text/xml");
            ao.setRequestHeader("SOAPAction", nameSpace + soapMethod);
            try{
                ao.send(soapEnvelope);
            }
            catch(ex){
                serviceCallError(ex);
            }//end tc
        }
        else{
            var soapParams = new Array();
            var headers = new Array();
            var soapVersion = 0;
            var object = nameSpace;
            
            if(serviceUrl.indexOf("http://") < 0)
                serviceUrl = document.location + serviceUrl;
            
            ao.transportURI = serviceUrl;
            ao.actionURI = nameSpace + soapMethod;
            
            for(var i=3; i<arguments.length; i++){
                var params = arguments[i].split("=");
                soapParams.push( new SOAPParameter(params[1],params[0]) );
            }//end for
            
            try{
                ao.encode(soapVersion, soapMethod, object, headers.length, headers, soapParams.length, soapParams);
            }
            catch(ex){
                serviceCallError(ex);
            }//end tc
		
            try{
                netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
            } 
            catch(ex){
                return false;
            }//end tc
            
            try{
                ao.asyncInvoke(
                    function(resp,call,status){

                    if(resp.fault)
                        return callServiceError(resp.fault);
                    if(!resp.body){
                        callServiceError("Service " + call.transportURI + " not found.");
                    }
                    else{
                        try{
                            callbackFunction(resp.body.firstChild.firstChild.firstChild.data);
                        }
                        catch(ex){
                            callServiceError(ex);
                        }//end tc
                    }//end if
                }
                );
            }
            catch(ex){
                serviceCallError(ex);
            }//end tc
                        
        }//end if
		
    }//end callService()
	
    /// <name type="function">GLM.AJAX.setNameSpace</name>
    /// <summary>Method for setting the name space of the service call.</summary>
    /// <param name="ns">The service name space.</param>
    /// <example>var ajax = new GLM.AJAX();
    /// 
    /// function ajaxCallback(content){
    /// alert(content); //displays the contents of the page.
    /// }
    ///
    /// ajax.setNameSpace("mynamespace");
    /// ajax.callPage("myService.asmx", "myMethod", ajaxCallback); //call myService.asmx and pass the contents to ajaxCallback</example>
    this.setNameSpace = function(ns){
        nameSpace = ns;
    }//end setNameSpace()
	
    /// <name type="function">GLM.AJAX.getNameSpace</name>
    /// <summary>Method for returning the name space of the service call.</summary>
    /// <returns>The namespace of the service call.</returns>
    /// <example>var ajax = new GLM.AJAX();
    /// 
    /// function ajaxCallback(content){
    /// alert(content); //displays the contents of the page.
    /// }
    ///
    /// var ns = ajax.getNameSpace(); //returns the name space
    /// ajax.callPage("myService.asmx", ajaxCallback); //call myService.asmx and pass the contents to ajaxCallback</example>
    this.getNameSpace = function(){
        return ns;
    }//end getNameSpace()
	
}//end GLM.AJAX()


/************************************/
/* GLM.Object                       */
/************************************/

/// <name type="function">GLM.Object.BaseMethods</name>
/// <param name="instance">The class instance</param>
/// <summary>Method for returning the public base methods of a super class.</summary>
/// <returns>A pseudo structure containing the available base methods.</returns>
/// <example>var base = GLM.Object.BaseMethods(this); //assume inside a class.</example>
GLM.Object.BaseMethods = function(instance){
    var base = {};
    for(var i in instance)
        base[i] = instance[i];
    return base;
}//end BaseMethods()


/************************************/
/* GLM.UI                           */
/************************************/

/************************************/
/* GLM.UI.MenuBar                   */
/************************************/

/// <name>GLM.UI.Menubar</name>
/// <param name="menuBarID">The id of the tag to use as a menubar.</param>
/// <summary>Class for creating a menu bar.</summary>
/// <returns>The new GLM.UI.MenuBar object</returns>
/// <example>//Assume a tag exists: <div id="myMenuBar"></div>
/// var menuBar = new GLM.UI.MenuBar("myMenuBar");
/// 
/// var fileMenu = new GLM.UI.Menu();
/// var fileMenu.setTitle("File"); //create a file menu.
/// var fileMenu.add( {Title: "Open", Tooltip: "Open file", Action: "FileOpen_Click()"} ); //create an "Open" menu item.
/// menuBar.add(fileMenu); //add the file menu to the menu bar.
/// menuBar.render(); //renders the control at the tag location.</example>
GLM.UI.MenuBar = function(menuBarID){
    
    var id = menuBarID;
    var menus = new Array();
    
    /// <name type="function">GLM.UI.Menubar.add</name>
    /// <param name="menu">The menu object to add.</param>
    /// <summary>Method for adding a menu object to the menu bar.</summary>
    /// <example>//Assume a tag exists: <div id="myMenuBar"></div>
    /// var menuBar = new GLM.UI.MenuBar("myMenuBar");
    /// 
    /// var fileMenu = new GLM.UI.Menu();
    /// fileMenu.setTitle("File"); //create a file menu.
    /// fileMenu.add( {Title: "Open", Tooltip: "Opens a file", Action: "FileOpen_Click()"} ); //create an "Open" menu item.
    /// menuBar.add(fileMenu); //add the file menu to the menu bar.
    /// menuBar.render(); //renders the control at the tag location.</example>
    this.add = function(menu){
        menus.push(menu);
    }//end add()
    
    /// <name type="function">GLM.UI.Menubar.render</name>
    /// <summary>Method rendering the menu bar.</summary>
    /// <example>//Assume a tag exists: <div id="myMenuBar"></div>
    /// var menuBar = new GLM.UI.MenuBar("myMenuBar");
    /// 
    /// var fileMenu = new GLM.UI.Menu();
    /// fileMenu.setTitle("File"); //create a file menu.
    /// fileMenu.add( {Title: "Open", Tooltip: "Open file", Action: "FileOpen_Click()"} ); //create an "Open" menu item.
    /// menuBar.add(fileMenu); //add the file menu to the menu bar.
    /// menuBar.render(); //renders the control at the tag location.</example>
    this.render = function(){
        var shadow = document.createElement("div");
        document.body.appendChild(shadow);
        shadow.className = "MenuShadow";
        shadow.id = menuBarID + "_shadow";
        
        var output = "";
        var len = menus.length;
        for(var i=0; i<len; i++){
            output += menus[i].render();
        }
        
        document.getElementById(id).innerHTML = output;
    }//end render()
    
    function initialize(){
        var menuBar = document.getElementById(id);
        menuBar.className = "MenuBar";
    }//end initialize()
    
    initialize();
    
    return this;
}//end class MenuBar

/// <name type="function">GLM.UI.Menubar.ShowMenu</name>
/// <param name="event">The event object.</param>
/// <param name="menu_id">The menu id of the menu to show.</param>
/// <param name="source_id">The source id of the source menu bar item.</param>
/// <param name="show">show menu flag, true to show, false to hide.</param>
/// <summary>Static method for handling show/hide menu functionality (used internally by MenuBar).</summary>
GLM.UI.MenuBar.ShowMenu = function(event, menu_id, source_id, show){
    GLM.Event.CancelEvents(event);
    
    var menu = document.getElementById(menu_id);
    var source = document.getElementById(source_id);
    
    if(GLM.UI.MenuBar.currentMenu != menu){
        //hide all
        GLM.UI.MenuBar.HideMenus(true);
    }
    
    var menuBar = source.parentNode;
    var shadow = document.getElementById(menuBar.id + "_shadow");
    
    if(show){
        
        source.className = "MenuLinkActive";
        
        GLM.UI.MenuBar.currentMenu = menu;
        
        var left = 0;
        var top = source.offsetHeight;

        var pos = GLM.DOM.GetElementPosition(source);
        left = pos.x;
        top += pos.y;
    
        menu.style.display = "block";
        menu.style.left = left + "px";
        menu.style.top = top + "px";
        menu.style.zIndex = 100000;
        
        shadow.style.left = (left+5) + "px";
        shadow.style.top = (top+5) + "px";
        shadow.style.width = menu.offsetWidth + "px";
        shadow.style.height = menu.offsetHeight + "px";
        shadow.style.zIndex = menu.style.zIndex-1;
        shadow.style.display = "block";
        
        var h = menu.offsetHeight;
        
        GLM.DOM.Animate([menu,shadow], 200, 60, [{dummy: function(n){ GLM.DOM.SetOpacity(menu,1*n)}},{dummy: function(n){ GLM.DOM.SetOpacity(shadow,.5*n)}}], null);
    }
    else{
        menu.style.display = "none";
    }//end if
}//end ShowMenu()

/// <name>GLM.UI.Menubar.currentMenu</name>
/// <summary>Static current menu object (used internally by MenuBar).</summary>
GLM.UI.MenuBar.currentMenu = null;

/// <name type="function">GLM.UI.Menubar.ShowMenu</name>
/// <param name="forceHide">forceHide flag, true to ensure menus are hidden, false for check.</param>
/// <summary>Static method for handling hiding all window application menus (used internally by MenuBar).</summary>
GLM.UI.MenuBar.HideMenus = function(forceHide){
    
    var source = GLM.UI.MenuBar.currentElement;
    
    try{
        while(source){
            if(source.className == "Menu" && !forceHide)
                return;
            source = source.parentNode;
        }//end while
    }
    catch(ex){}
    
    var els = document.getElementsByTagName("div");
    for(var i in els){
        if(!els[i])
            continue;
        
        if(els[i].className == "Menu"){
            els[i].style.display = "none";
        }//end if
        
        if(els[i].className == "MenuBar"){
            for(var j in els[i].childNodes){
                if(els[i].childNodes[j].className == "MenuLinkActive")
                    els[i].childNodes[j].className = "MenuLink";
            }//end for
            
            var shadow = document.getElementById(els[i].id + "_shadow");
            shadow.style.display = "none";
        }//end if
    }//end for
    
    GLM.UI.MenuBar.currentMenu = null;

}//end HideMenus()


/************************************/
/* GLM.UI.Menu                      */
/************************************/

/// <name>GLM.UI.Menu</name>
/// <summary>Class for creating a menu.</summary>
/// <returns>The new GLM.UI.Menu object</returns>
/// <example>//Assume a tag exists: <div id="myMenuBar"></div>
/// var menuBar = new GLM.UI.MenuBar("myMenuBar");
/// 
/// var fileMenu = new GLM.UI.Menu();
/// fileMenu.setTitle("File"); //create a file menu.
/// fileMenu.add( {Title: "Open", Tooltip: "Open file", Action: "FileOpen_Click()"} ); //create an "Open" menu item.
/// menuBar.add(fileMenu); //add the file menu to the menu bar.
/// menuBar.render(); //renders the control at the tag location.</example>
GLM.UI.Menu = function(){
    
    var items = new Array();
    var title = "";
    var menu_id = null;
    var source_id = null;
    var menu = null;
    
    /// <name type="function">GLM.UI.Menu.setTitle</name>
    /// <param name="title">The title of the menu.</param>
    /// <summary>Method for setting the title of the menu.</summary>
    /// <example>//Assume a tag exists: <div id="myMenuBar"></div>
    /// var menuBar = new GLM.UI.MenuBar("myMenuBar");
    /// 
    /// var fileMenu = new GLM.UI.Menu();
    /// fileMenu.setTitle("File"); //create a file menu.
    /// fileMenu.add( {Title: "Open", Tooltip: "Open file", Action: "FileOpen_Click()"} ); //create an "Open" menu item.
    /// menuBar.add(fileMenu); //add the file menu to the menu bar.
    /// menuBar.render(); //renders the control at the tag location.</example>
    this.setTitle = function(menuTitle){
        title = menuTitle;
    }//end setTitle()
    
    /// <name type="function">GLM.UI.Menu.getTitle</name>
    /// <summary>Method for returning the title of the menu.</summary>
    /// <example>//Assume a tag exists: <div id="myMenuBar"></div>
    /// var menuBar = new GLM.UI.MenuBar("myMenuBar");
    /// 
    /// var fileMenu = new GLM.UI.Menu();
    /// fileMenu.setTitle("File"); //create a file menu.
    /// alert(fileMenu.getTitle); //alerts "File"</example>
    this.getTitle = function(){
        return title;
    }//end getTitle()
    
    /// <name type="function">GLM.UI.Menu.add</name>
    /// <param name="menuItem">The menu item to add to the menu.</param>
    /// <summary>Method for adding a menu item to the menu.</summary>
    /// <example>//Assume a tag exists: <div id="myMenuBar"></div>
    /// var menuBar = new GLM.UI.MenuBar("myMenuBar");
    /// 
    /// var fileMenu = new GLM.UI.Menu();
    /// fileMenu.setTitle("File"); //create a file menu.
    /// fileMenu.add( {Title: "Open", Tooltip: "Open file", Action: "FileOpen_Click()"} ); //create an "Open" menu item.
    /// menuBar.add(fileMenu); //add the file menu to the menu bar.
    /// menuBar.render(); //renders the control at the tag location.</example>
    this.add = function(menuItem){
        items.push(menuItem);
    }//end add()
    
    this.addSeparator = function(){
        items.push("-");
    }//end addSeparator()
    
    /// <name type="function">GLM.UI.Menu.render</name>
    /// <summary>Method for rendering a menu item (used internally by Menu).</summary>
    this.render = function(){
        
        var s = "";
        var len = items.length;
        for(var i=0; i<len; i++){
            var item = items[i];
            
            if(item == "-"){
                s += "<div class=\"MenuItem, Separator\"></div>";
            }
            else{
                if(item.Action)
                    s += "<div class=\"MenuItem\" style=\"overflow-x:hidden;\"><a style=\"display:block;background-image: url(" + item.Image + "); background-repeat: no-repeat; background-position: 4px center;\" href=\"javascript:void(0);\" onclick=\"GLM.UI.MenuBar.HideMenus(true);" + item.Action + "\" title=\"" + item.Tooltip + "\" class=\"MenuAnchor\">" + item.Title + "</a></div>";
                else
                    s += "<div class=\"MenuItem\" style=\"overflow-x:hidden;\"><span style=\"background-image: url(" + item.Image + ");background-repeat: no-repeat; background-position: 4px center;\">" + item.Title + "</span></div>";
            }//end if
        }//end for
        
        menu.innerHTML = s;
        
        return "<a class=\"MenuLink\" id=\"" + source_id + "\" tabindex=\"0\" href=\"javascript:void(0);\" onmouseover=\"if(GLM.UI.MenuBar.currentMenu){onclick();}\" onclick=\"GLM.UI.MenuBar.HideMenus();GLM.UI.MenuBar.ShowMenu(event, '" + menu_id + "', '" + source_id + "', true);\">" + title + "</a>";
    }//end render()
    
    function initialize(){
        menu_id = "Menu_" + top.GetUniqueID();
        source_id = "MenuItem_" + top.GetUniqueID();
        
        menu = document.createElement("div");
        document.body.appendChild(menu);
        menu.className = "Menu";
        menu.id = menu_id;
        
        GLM.Event.AddEventHandler(document, "click", GLM.UI.MenuBar.HideMenus);
        
        menu.onmouseout = function(event){
            if(!event)
                event = window.event;
            
            var source = null
            if(event.srcElement)
                source = event.srcElement;
            else
                source = event.target;
            
            if(source.className.indexOf("Menu") < 0)
                setTimeout("GLM.UI.MenuBar.HideMenus()", 250);
        };
    }//end initialize()
    
    initialize();
    
    return this;
}//end class Menu


/************************************/
/* GLM.UI.ToolBar                   */
/************************************/

/// <name>GLM.UI.ToolBar</name>
/// <param name="toolBarID">The id of the tag to use as a toolbar.</param>
/// <summary>Class for creating a tool bar.</summary>
/// <returns>The new GLM.UI.ToolBar object</returns>
/// <example>//Assume a tag exists: <div id="myToolBar"></div>
/// var toolBar = new GLM.UI.ToolBar("myToolBar");
/// 
/// toolBar.add( {Image: "images/Toolbar_FileNew.gif", Tooltip: "Create new file", Action: "FileNew_Click()"} ); //create a new file item.
/// toolBar.add( {Image: "images/Toolbar_FileOpen.gif", Tooltip: "Open file", Action: "FileOpen_Click()"} ); //create an open file item.
/// toolBar.add( {Image: "images/Toolbar_FileSave.gif", Tooltip: "Save file", Action: "FileSave_Click()"} ); //create an save file item.
/// toolBar.render(); //renders the control at the tag location.</example>
GLM.UI.ToolBar = function(toolBarID){
    
    var id = toolBarID;
    var items = new Array();
    
    /// <name type="function">GLM.UI.Toolbar.add</name>
    /// <param name="item">The toolbar item to add</param>
    /// <summary>Method for adding a toolbar item</summary>
    /// <example>//Assume a tag exists: <div id="myToolBar"></div>
    /// var toolBar = new GLM.UI.ToolBar("myToolBar");
    /// 
    /// toolBar.add( {Image: "images/Toolbar_FileNew.gif", Tooltip: "Create new file", Action: "FileNew_Click()"} ); //create a new file item.
    /// toolBar.add( {Image: "images/Toolbar_FileOpen.gif", Tooltip: "Open file", Action: "FileOpen_Click()"} ); //create an open file item.
    /// toolBar.add( {Image: "images/Toolbar_FileSave.gif", Tooltip: "Save file", Action: "FileSave_Click()"} ); //create an save file item.
    /// toolBar.render(); //renders the control at the tag location.</example>
    this.add = function(item){
        items.push(item);
    }//end add()
    
    this.addSeparator = function(){
        items.push("|");
    }//end addSeparator()
    
    this.render = function(){
        var s = "";
        var len = items.length;
        for(var i=0; i<len; i++){
            var item = items[i];
            if(item == "|")
                s += '<div class="Separator"></div>'
            else
                s += '<a href="javascript:void(0);" tabindex="0" title="' + item.Tooltip + '" onclick="' + item.Action + '"><img src="' + item.Image + '" border="0" /></a>';
        }//end for
    
        document.getElementById(id).innerHTML = s;
    }//end render()
    
    function initialize(){
        var toolbar = document.getElementById(id);
        toolbar.className = "ToolBar";
    }//end initialize()
    
    initialize();
    
    return this;
}//end class Toolbar

/// <name>GLM.UI.Canvas</name>
/// <param name="id">The id of the DIV element tag</param>
/// <summary>Class for creating a GLM.UI.Canvas.</summary>
/// <returns>An instance of of the GLM.UI.Canvas.</returns>
/// <example>//Assume a DIV tag with id="myCanvas" exists
/// var myCanvas = new GLM.UI.Canvas("myCanvas");
/// myCanvas.getStyle().border = "solid 1px black";
/// myCanvas.render();
/// </example>
GLM.UI.Canvas = function(id){
    var _tag = null;
    var _id = null;
    var _styleElement = null;
    
    /// <name>GLM.UI.Canvas.setID</name>
    /// <param name="id">The id of the DIV element tag</param>
    /// <summary>Method for setting the tag id.</summary>
    /// <example>//Assume a DIV tag with id="myCanvas" exists
    /// var myCanvas = new GLM.UI.Canvas();
    /// myCanvas.setID("myCanvas");
    /// myCanvas.render();
    /// </example>
    this.setID = function(id){
        _id = id;
    }//end setID()
    
    /// <name>GLM.UI.Canvas.getID</name>
    /// <returns>Thid id of the DIV element tag</returns>
    /// <summary>Method for returning the tag id.</summary>
    /// <example>//Assume a DIV tag with id="myCanvas" exists
    /// var myCanvas = new GLM.UI.Canvas("myCanvas");
    /// alert(myCanvas.getID()); //alerts "myCanvas"
    /// myCanvas.render();
    /// </example>
    this.getID = function(){
        return _id;
    }//end getID()
    
    /// <name>GLM.UI.Canvas.setTag</name>
    /// <param name="tag">The tag element</param>
    /// <summary>Method for setting the tag element.</summary>
    /// <example>//Assume a DIV tag with id="myCanvas" exists
    /// var myCanvas = new GLM.UI.Canvas("myCanvas");
    /// myCanvas.render();
    /// myCanvas.setTag(document.getElementById("myCanvas2");
    /// </example>
    this.setTag = function(tag){
        _tag = tag;
    }//end setTag()
    
    /// <name>GLM.UI.Canvas.getTag</name>
    /// <returns>The tag element</returns>
    /// <summary>Method for returning the tag element.</summary>
    /// <example>//Assume a DIV tag with id="myCanvas" exists
    /// var myCanvas = new GLM.UI.Canvas("myCanvas");
    /// myCanvas.getTag().innerHTML = "hello world"; //set the innerHTML
    /// myCanvas.render();
    /// </example>
    this.getTag = function(){
        return _tag;
    }//end getTag()
    
    /// <name>GLM.UI.Canvas.setStyle</name>
    /// <param name="style">The style attribute</param>
    /// <summary>Method for setting the style attribute.</summary>
    /// <example>//Assume a DIV tag with id="myCanvas" exists
    /// var myCanvas = new GLM.UI.Canvas("myCanvas");
    /// myCanvas.setStyle( document.getElementById("myCanvas2").style );
    /// myCanvas.render();
    /// </example>
    this.setStyle = function(style){
        _styleElement.style = style;
    }//end setStyle()
    
    /// <name>GLM.UI.Canvas.getStyle</name>
    /// <returns>The style attribute</returns>
    /// <summary>Method for returning the style attribute.</summary>
    /// <example>//Assume a DIV tag with id="myCanvas" exists
    /// var myCanvas = new GLM.UI.Canvas("myCanvas");
    /// myCanvas.getStyle().border = "solid 1px black";
    /// myCanvas.render();
    /// </example>
    this.getStyle = function(){
        return _styleElement.style;
    }//end getStyle()
    
    /// <name>GLM.UI.Canvas.render</name>
    /// <summary>Method for rendering the canvas.</summary>
    /// <example>//Assume a DIV tag with id="myCanvas" exists
    /// var myCanvas = new GLM.UI.Canvas("myCanvas");
    /// myCanvas.getStyle().border = "solid 1px black";
    /// myCanvas.render();
    /// </example>
    this.render = function(){
        if(!_tag)
            _tag = document.getElementById(_id);
        _tag.style.cssText = _styleElement.style.cssText;
    }//end render()
    
    function constructor(){
        _id = id;
        _styleElement = document.createElement("div");
    }//end constructor()
    
    this.toString = function(){
        return "GLM.UI.Canvas";
    }//end toString()

    constructor();
    return this;
}//end Canvas()

/// <name>GLM.UI.Accordian</name>
/// <param name="id">The id of the DIV element tag</param>
/// <summary>Class for creating a GLM.UI.Accordian.</summary>
/// <returns>An instance of of the GLM.UI.Accordian.</returns>
/// <example>//Assume 
/// //&lt;div id="myAccordian"&gt;
/// //&lt;div&gt;
/// //&lt;div&gt;Title 1&lt;/div&gt;
/// //&lt;div&gt;Item 1&lt;/div&gt;
/// //&lt;div&gt;Item 2&lt;/div&gt;
/// //&lt;div&gt;Item 3&lt;/div&gt;
/// //&lt;/div&gt;
/// //&lt;div&gt;
/// //&lt;div&gt;Title 2&lt;/div&gt;
/// //&lt;div&gt;Item 1&lt;/div&gt;
/// //&lt;div&gt;Item 2&lt;/div&gt;
/// //&lt;div&gt;Item 3&lt;/div&gt;
/// //&lt;/div&gt;
/// //&lt;/div&gt;
///
/// var myAccordian = new GLM.UI.Accordian("myAccordian");
/// myAccordian.render();
/// </example>
GLM.UI.Accordian = function(id){
    GLM.UI.Accordian.prototype = new GLM.UI.Canvas;
    var _base = GLM.Object.BaseMethods(this);
    var _instance = this;
    var _accordianType = null;
    var _displayNode = null;
    var _expandCallback = null;
    
    /// <name>GLM.UI.Accordian.setExpandCallback</name>
    /// <param name="callback">The callback function</param>
    /// <summary>Method for setting the expand event callback.</summary>
    /// <example>//Assume 
    /// //&lt;div id="myAccordian"&gt;
    /// //&lt;div&gt;
    /// //&lt;div&gt;Title 1&lt;/div&gt;
    /// //&lt;div&gt;Item 1&lt;/div&gt;
    /// //&lt;div&gt;Item 2&lt;/div&gt;
    /// //&lt;div&gt;Item 3&lt;/div&gt;
    /// //&lt;/div&gt;
    /// //&lt;div&gt;
    /// //&lt;div&gt;Title 2&lt;/div&gt;
    /// //&lt;div&gt;Item 1&lt;/div&gt;
    /// //&lt;div&gt;Item 2&lt;/div&gt;
    /// //&lt;div&gt;Item 3&lt;/div&gt;
    /// //&lt;/div&gt;
    /// //&lt;/div&gt;
    ///
    /// var myAccordian = new GLM.UI.Accordian("myAccordian");
    ///
    /// function Accordian_ExpandNode(section){
    /// alert(section.innerHTML);
    /// }
    ///
    /// myAccordian.setExpandCallback(Accordian_ExpandNode);
    /// myAccordian.render();
    /// </example>
    this.setExpandCallack = function(callback){
        _expandCallback = callback;
    }//end setExpandCallback()
    
    /// <name>GLM.UI.Accordian.setAccordianType</name>
    /// <param name="accordianType">The GLM.UI.Accordian.AccordianType (Standard, Outlook)</param>
    /// <summary>Method for setting the accordian type.</summary>
    /// <example>//Assume 
    /// //&lt;div id="myAccordian"&gt;
    /// //&lt;div&gt;
    /// //&lt;div&gt;Title 1&lt;/div&gt;
    /// //&lt;div&gt;Item 1&lt;/div&gt;
    /// //&lt;div&gt;Item 2&lt;/div&gt;
    /// //&lt;div&gt;Item 3&lt;/div&gt;
    /// //&lt;/div&gt;
    /// //&lt;div&gt;
    /// //&lt;div&gt;Title 2&lt;/div&gt;
    /// //&lt;div&gt;Item 1&lt;/div&gt;
    /// //&lt;div&gt;Item 2&lt;/div&gt;
    /// //&lt;div&gt;Item 3&lt;/div&gt;
    /// //&lt;/div&gt;
    /// //&lt;/div&gt;
    ///
    /// var myAccordian = new GLM.UI.Accordian("myAccordian");
    /// myAccordian.setAccordianType(GLM.UI.Accordian.AccordianType.Outlook);
    /// myAccordian.render();
    /// </example>
    this.setAccordianType = function(accordianType){
        _accordianType = accordianType;
    }//end setAccordianType()
    
    function renderSectionTitle(sectionTitle){
        var canvas = new GLM.UI.Canvas();
        canvas.setTag(sectionTitle);
        
        with(canvas.getStyle()){
            cursor = "pointer";
        }//end with
        
        var tag = canvas.getTag();
        tag.onclick = function(){
            sctionTitle_OnClick(this.parentNode);
        }//end onclick()
        
        canvas.render();
    }//end renderSectionTitle()
    
    function renderSection(section){
        var canvas = new GLM.UI.Canvas();
        canvas.setTag(section);
        canvas.render();
        
        var childNodes = canvas.getTag().childNodes;
        var bTitle = false;
        for(var i in childNodes){
            var node = childNodes[i];
            if(node.tagName == "DIV"){
                if(!bTitle){
                    bTitle = true;
                    renderSectionTitle(node);
                }//end if
            }//end if
        }//end for
    }//end renderSection()
    
    function sctionTitle_OnClick(section){
        
        if(_expandCallback)
            _expandCallback(section);
        
        switch(_accordianType){
            case GLM.UI.Accordian.AccordianType.Standard:
                var childNodes = _instance.getTag().childNodes;
                for(var i in childNodes){
                    var node = childNodes[i];
                    if(node.tagName == "DIV"){
                        if(node != section)
                            collapseSection(node);
                        else
                            expandSection(node);
                    }//end if
                }//end for
                break;
            case GLM.UI.Accordian.AccordianType.Outlook:
                _displayNode.innerHTML = section.innerHTML;
                expandSection(_displayNode);
                break;
        }//end switch
        
    }//end sctionTitle_OnClick()
    
    function expandSection(section){
        var childNodes = section.childNodes;
        var bTitle = false;
        for(var i in childNodes){
            var node = childNodes[i];
            if(node.tagName == "DIV"){
                if(!bTitle){
                    bTitle = true;
                }
                else{
                    node.style.display = "";
                }//end if
            }//end if
        }//end for
    }//end expandSection()
    
    function collapseSection(section){
        var childNodes = section.childNodes;
        var bTitle = false;
        for(var i in childNodes){
            var node = childNodes[i];
            if(node.tagName == "DIV"){
                if(!bTitle){
                    bTitle = true;
                }
                else{
                    node.style.display = "none";
                }//end if
            }//end if
        }//end for
    }//end collapseSection()
    
    /// <name>GLM.UI.Accordian.render</name>
    /// <summary>Method for rendering the accordian.</summary>
    /// <example>//Assume 
    /// //&lt;div id="myAccordian"&gt;
    /// //&lt;div&gt;
    /// //&lt;div&gt;Title 1&lt;/div&gt;
    /// //&lt;div&gt;Item 1&lt;/div&gt;
    /// //&lt;div&gt;Item 2&lt;/div&gt;
    /// //&lt;div&gt;Item 3&lt;/div&gt;
    /// //&lt;/div&gt;
    /// //&lt;div&gt;
    /// //&lt;div&gt;Title 2&lt;/div&gt;
    /// //&lt;div&gt;Item 1&lt;/div&gt;
    /// //&lt;div&gt;Item 2&lt;/div&gt;
    /// //&lt;div&gt;Item 3&lt;/div&gt;
    /// //&lt;/div&gt;
    /// //&lt;/div&gt;
    ///
    /// var myAccordian = new GLM.UI.Accordian("myAccordian");
    /// myAccordian.render();
    /// </example>
    this.render = function(){
        
        this.setID(id);
        _base.render();
        
        var childNodes = this.getTag().childNodes;
        
        switch(_accordianType){
            case GLM.UI.Accordian.AccordianType.Standard:
                
                var bFirst = false;
                for(var i in childNodes){
                    var node = childNodes[i];
                    if(node.tagName == "DIV"){
                        renderSection(node);
                
                        if(!bFirst)
                            bFirst = true;
                        else
                            collapseSection(node);
                    }//end if
                }//end for
                break;
            case GLM.UI.Accordian.AccordianType.Outlook:
                
                var bFirst = false;
                var refNode = null;
                for(var i in childNodes){
                    var node = childNodes[i];
                    if(node.tagName == "DIV"){
                        
                        renderSection(node);
                        if(!bFirst){
                            bFirst = true;
                            refNode = node;
                        }//end if
                        collapseSection(node);
                    }//end if
                }//end for
                
                if(refNode && !_displayNode){
                    _displayNode = document.createElement("DIV");
                    this.getTag().insertBefore(_displayNode, refNode);
                    _displayNode.className = refNode.className;
                    _displayNode.innerHTML = refNode.innerHTML;
                    expandSection(_displayNode);
                    //_displayNode.style.height = "100%";
                }//end if
                
                break;
        }//end switch
    }//end render()
    
    function constructor(){
        _accordianType = GLM.UI.Accordian.AccordianType.Standard;
    }//end constructor()
    
    this.toString = function(){
        return "GLM.UI.Accordian";
    }//end toString()
    
    constructor();
    return this;
}//end Accordian()
GLM.UI.Accordian.prototype = new GLM.UI.Canvas;

GLM.UI.Accordian.AccordianType = {
    Standard: 0,
    Outlook: 1
};

/// <name>GLM.UI.Tree</name>
/// <param name="id">The id of the DIV element tag</param>
/// <summary>Class for creating a GLM.UI.Tree.</summary>
/// <returns>An instance of of the GLM.UI.Tree.</returns>
/// <example>//Assume 
/// &lt;div id="myTree"&gt;
/// &lt;ul&gt;
/// &lt;div&gt;Root 1&lt;/div&gt;
/// &lt;ul&gt;
/// &lt;div&gt;Node 1&lt;/div&gt;
/// &lt;ul&gt;
/// &lt;div&gt;SubNode 1&lt;/div&gt;
/// &lt;div&gt;SubNode 2&lt;/div&gt;
/// &lt;/ul&gt;
/// &lt;div&gt;Node 2&lt;/div&gt;
/// &lt;ul&gt;
/// &lt;div&gt;SubNode 1&lt;/div&gt;
/// &lt;div&gt;SubNode 2&lt;/div&gt;
/// &lt;/ul&gt;
/// &lt;/ul&gt;
/// &lt;/ul&gt;
/// &lt;/div&gt;
///
/// var myTree = new GLM.UI.Tree("myTree");
/// myTree.render();
/// </example>
GLM.UI.Tree = function(id){
    GLM.UI.Tree.prototype = new GLM.UI.Canvas;
    var _base = GLM.Object.BaseMethods(this);
    var _expandCallback = null;
    
    /// <name>GLM.UI.Tree.setExpandCallback</name>
    /// <param name="callback">The callback method</param>
    /// <summary>Sets the expand node event callback.</summary>
    /// <example>//Assume 
    /// &lt;div id="myTree"&gt;
    /// &lt;ul&gt;
    /// &lt;div&gt;Root 1&lt;/div&gt;
    /// &lt;ul&gt;
    /// &lt;div&gt;Node 1&lt;/div&gt;
    /// &lt;ul&gt;
    /// &lt;div&gt;SubNode 1&lt;/div&gt;
    /// &lt;div&gt;SubNode 2&lt;/div&gt;
    /// &lt;/ul&gt;
    /// &lt;div&gt;Node 2&lt;/div&gt;
    /// &lt;ul&gt;
    /// &lt;div&gt;SubNode 1&lt;/div&gt;
    /// &lt;div&gt;SubNode 2&lt;/div&gt;
    /// &lt;/ul&gt;
    /// &lt;/ul&gt;
    /// &lt;/ul&gt;
    /// &lt;/div&gt;
    ///
    /// var myTree = new GLM.UI.Tree("myTree");
    /// myTree.render();
    /// 
    /// function Tree_ExpandNode(node){
    /// alert("clicked: " + node.innerHTML);
    /// }
    ///
    /// myTree.setExpandCallback(Tree_ExpandNode);
    /// </example>
    this.setExpandCallback = function(callback){
        _expandCallback = callback;
    }//end setExpandCallback()
    
    function expandChildren(parentNode){
        
        if(_expandCallback)
            _expandCallback(parentNode);
        
        var node = parentNode.nextSibling;
        if(!node)
            return;
        
        while(node && node.nodeType == 3)
            node = node.nextSibling;
        
        if(!node)
            return;
        
        if(node.tagName == "UL"){
            if(node.style.display == "none")
                node.style.display = "";
            else
                node.style.display = "none";
        }//end if
    }//end expandChildren()
    
    function renderRootNodes(rootNode){
        var childNodes = rootNode.childNodes;
        for(var i in childNodes){
            var node = childNodes[i];
            if(node.tagName == "DIV"){
                
                node.onclick = function(){
                    expandChildren(this);
                }//end onclick    
                node.style.cursor = "pointer";
            }
            else if(node.tagName == "UL"){
                node.style.display = "none";
            }//end if
            renderNodes(node);
        }//end for
    }//end renderRootNodes()
    
    function renderNodes(parentNode){
        var childNodes = parentNode.childNodes;
        for(var i in childNodes){
            var node = childNodes[i];
            if(node.tagName == "UL"){
                node.style.display = "none";
                renderNodes(node);
            }
            else if(node.tagName == "DIV"){

                node.onclick = function(){
                    expandChildren(this);
                }//end onclick    
                node.style.cursor = "pointer";
                
                renderNodes(node);
            }//end if
        }//end for
    }//end renderNodes()
    
    /// <name>GLM.UI.Tree.render</name>
    /// <summary>Method for rendering the tree.</summary>
    /// <example>//Assume 
    /// &lt;div id="myTree"&gt;
    /// &lt;ul&gt;
    /// &lt;div&gt;Root 1&lt;/div&gt;
    /// &lt;ul&gt;
    /// &lt;div&gt;Node 1&lt;/div&gt;
    /// &lt;ul&gt;
    /// &lt;div&gt;SubNode 1&lt;/div&gt;
    /// &lt;div&gt;SubNode 2&lt;/div&gt;
    /// &lt;/ul&gt;
    /// &lt;div&gt;Node 2&lt;/div&gt;
    /// &lt;ul&gt;
    /// &lt;div&gt;SubNode 1&lt;/div&gt;
    /// &lt;div&gt;SubNode 2&lt;/div&gt;
    /// &lt;/ul&gt;
    /// &lt;/ul&gt;
    /// &lt;/ul&gt;
    /// &lt;/div&gt;
    ///
    /// var myTree = new GLM.UI.Tree("myTree");
    /// myTree.render();
    /// </example>
    this.render = function(){
        this.setID(id);
        _base.render();
        
        var childNodes = this.getTag().childNodes;
        for(var i in childNodes){
            var node = childNodes[i];
            if(node.tagName == "UL"){
                renderRootNodes(node);
            }//end if
        }//end for
    }
    
    return this;
}//end Tree()
GLM.UI.Tree.prototype = new GLM.UI.Canvas;