
// ------------------------------------------------------------------------------------------------
//Filename:			cti_lib_javascripts.asp
//Copyright:		Castle Technologies Inc
//Author:			Castle Technologies Inc
//Description:		Cached javascript functions and subroutines.
//Update History:	Created: 2001
//					JE-1: Added AJAX functions, display toggling functions, getFormValues function, popupDiv
//					JE-1: Added javascript calendar function
//					08/01/2006 - jsb
//					1.1  Reactivated open_popup_retrieve for verify button
//					1.2  Incorporated rudimentary line breaks into child_form_add_vertical_row
//					1.3  child_form_add_row and child_form_add_vertical_row:  Added guid to hidden field
//                       for use with grandchildren
//                  10/18/2007 - jae - cleaned up
//
// ------------------------------------------------------------------------------------------------

//**************************************************
//BEGIN - PROGRAMMING STANDARDS (CODING AND COMMENTS)
// Notes: 
//  - cat: categorize functions into BEGIN / END groups, just like this one
//      @@@@@ please note: uncategorized routines have are completely left justified with no tabs for now
//  - comments (function top): use your best judgement as to what's needed
//  - comments (in-line): the more the better
//  - comments (function end): use "}//function_name" at the end
//  - indentation: always use tabs
//  - blank line: use blank lines to group logic
//  - spaces: use spaces liberally
//  - sample code: see setCookie below             
//**************************************************

    //cat   - category (e.g., binding, paging, misc, ...)
    //desc  - description of function
    //usage - where used (e.g. binding, main forms, search forms
    //hist  - (programmer initials, date/first) comment
    //      - (programmer initials, date/last) comment
    //@p1 - parameter 1 description
    //@p2 - parameter 2 description
    //@return - description of what function returns 
    function setCookie( name, value, expires, path, domain, secure )
    {
   	    var today = new Date();
   	    today.setTime( today.getTime() );
   	    
   	    if ( expires ) {
   		    expires = expires * 1000 * 60 * 60 * 24;
   	    }
     
        // in-line comment - put a space above in-line comments that group code
   	    var expires_date = new Date( today.getTime() + (expires) );
   	    document.cookie = name+'='+escape( value ) +
   		    ( ( expires ) ? ';expires='+expires_date.toGMTString() : '' ) + //expires.toGMTString()
   		    ( ( path ) ? ';path=' + path : '' ) +
   		    ( ( domain ) ? ';domain=' + domain : '' ) +
   		    ( ( secure ) ? ';secure' : '' );
    }
//**************************************************
//END - PROGRAMMING STANDARDS (CODING AND COMMENTS)
//**************************************************


//**************************************************
//BEGIN - JAVASCRIPT DECLARATIONS
// Notes:
//  - DO NOT DELETE, THESE ARE VERY IMPORTANT!!!!!!!
//  - @@@@@ should we put all declarations here ????
//**************************************************

    var error_array;
    var browser;
    var sessionLoadingInd = syncPost('cti_retrieve_session.aspx','shortkey=SessionLoadIndicator');
    var error_page;
    var framesetMgrPtr;
    var winId;
    var childAvailable = false;
    
    if(window.parent && window.parent.top_frame)
        framesetMgrPtr = window.parent.framesetMgr;
    else 
        if(window.opener)
            framesetMgrPtr = window.opener.framesetMgrPtr;
    
    //if(window.opener && window.opener.parentFramesetMgr) REMOVED 6/4/09
    //    parentFramesetMgr = window.opener.parentFramesetMgr;

//**************************************************
//END - JAVASCRIPT DECLARATIONS
//**************************************************

//**************************************************
//BEGIN - MOZILLA COMPATIBLE CODE
// Used by:
// Used for: Helper Routines
//    1)DOM parsing, manipulation, traversal
//    2)Binding
//    3)xml parsing
// Developers:
// Notes:
//    - Taken from http://developer.mozilla.org/en/docs/Whitespace_in_the_DOM 8/1/2007
//    - These utilities were written with cross-browser compatibility in mind
//**************************************************

    /**
     * Throughout, whitespace is defined as one of the characters
     *  "\t" TAB \u0009
     *  "\n" LF  \u000A
     *  "\r" CR  \u000D
     *  " "  SPC \u0020
     *
     * This does not use Javascript's "\s" because that includes non-breaking
     * spaces (and also some other characters).
     */


    //cat     - mozilla
    //desc    - Determine whether a node's text content is entirely whitespace.
    //usage   - utility
    //@nod    - A node implementing the CharacterData interface (i.e.Text,Comment, or CDATASection node)
    //@return - True if all of the text content of nod is whitespace, otherwise false.
    function is_all_ws(nod)
    {
      // Use ECMA-262 Edition 3 String and RegExp features
      return !(/[^\t\n\r ]/.test(nod.data));
    }


    //cat     - mozilla
    //desc    - Determines if a node should be ignored by the iterator functions.
    //usage   - utility
    //@nod    - An object implementing the DOM1 |Node| interface.
    //@return - true if node is all whitespace or a comment node, otherwise false
    function is_ignorable(nod)
    {
      return ( nod.nodeType == 8) || // A comment node
             ( (nod.nodeType == 3) && is_all_ws(nod) ); // a text node, all ws
    }


    //cat     - mozilla
    //desc    - Version of nextSibling that skips comment and whitespace nodes
    //usage   - utility
    //@sib    - Reference node
    //@return - Either closest next non-ignorable sibling of sib, or null if none exists
    function node_after(sib) {
        while (sib && (sib = sib.nextSibling)) {
            if (!is_ignorable(sib)) return sib;
        }
        return null;
    }


    //cat     - mozilla
    //desc    - Version of previousSibling that skips comment and whitespace nodes
    //usage   - utility
    //@sib    - Reference node
    //@return - Either closest previous non-ignorable sibling of sib, or null if none exists
     function node_before(sib)
    {
      while ((sib = sib.previousSibling)) {
        if (!is_ignorable(sib)) return sib;
      }
      return null;
    }


    //cat   - mozilla
    //desc  - Version of firstChild that skips comment and whitespace nodes
    //usage - utility
    //@par  - Parent node
    //@return - Either first non-ignorable child of par, or null if none exists
    function first_child(par) {
        var res = par.firstChild;
        while (res) {
            if (!is_ignorable(res)) return res;
            res = res.nextSibling;
        }
        return null;
    }


    //cat   - mozilla
    //desc  - Version of lastChild that skips comment and whitespace nodes
    //usage - utility
    //@par  - Parent node
    //@return - Either last non-ignorable child of par, or null if none exists
    function last_child(par)
    {
      var res=par.lastChild;
      while (res) {
        if (!is_ignorable(res)) return res;
        res = res.previousSibling;
      }
      return null;
    }


    //cat     - mozilla
    //desc    - Version of childNodes.length that ignores comment and whitespace nodes
    //usage   - utility
    //@nod    - Reference node
    //@return - number of non-ignorable children
    function num_children(nod)
    {
      var r = 0;
      if (nod.hasChildNodes()) {
        for (var i = 0, j = nod.childNodes.length; i < j; i++)
          if (!is_ignorable(nod.childNodes[i]))
            r++;
      }
      return r;
    }


    //cat     - mozilla
    //desc    - Version of data that doesn't include whitespace at the beginning
    //          and end and normalizes all whitespace to a single space. Normally
    //          data is a property of text nodes that gives the text of the node.
    //usage   - utility
    //@txt    - The text node whose data should be returned
    //@return - A string giving the contents of the text node with whitespace collapsed.
    function data_of(txt)
    {
      var data = txt.data;
      // Use ECMA-262 Edition 3 String and RegExp features
      data = data.replace(/[\t\n\r ]+/g, " ");
      if (data.charAt(0) == " ")
        data = data.substring(1, data.length);
      if (data.charAt(data.length - 1) == " ")
        data = data.substring(0, data.length - 1);
      return data;
    }
//**************************************************
//END - MOZILLA CODE
//**************************************************


//**************************************************
//BEGIN - UTILITY (MISCELLANEOUS)
//**************************************************
  //cat   - misc
    //desc  - Object representing an associative array.
    //        Javascript does not support a true associative
    //        array structure - accessing via string name (array["name"])
    //        does not put the value in the array.  Rather, it adds a
    //        property dynamically to the array object, which is why it 
    //        appears to function, but if you check the length of the array,
    //        you will see that it is zero.  This object encapsulates the
    //        behavior so that objects are placed in the array and in the 
    //        dynamic property for associative access. 
    //usage - Various, including the popup window manager
    //@n -
    //@return - 
    function assocArray(){

	    this.aAssoc = new Array();

	    this.assocLength = 0;

	    this.assocGetByIndex = function(idx){
		    return this.aAssoc[idx];
	    }
	

	    this.assocGetByName = function(name){
		    return this.aAssoc[name];
	    }
	    
	    this.assocGetIndexByName = function(name){
	       
	        var targ = this.assocGetByName(name);
	        
	        if(targ)
	        {	        
	            for(var i = 0; i < this.assocLength; i++)
	                if(targ == this.aAssoc[i])
	                    return i;
	        }
	                
	        return -1;
	    }

	    this.assocPush = function(obj,name){
		    this.aAssoc.push(obj);

		    this.aAssoc[name] = this.aAssoc[this.assocLength++];
	    }
	    
	    this.assocRemoveByName = function(name){
	        var idx = this.assocGetIndexByName(name);
	        
	        //alert('removing ' + name + ' with idx ' + idx + ' and assocLen:' + this.assocLength);
	        
	        if(idx > -1){	            
	            this.aAssoc.splice(idx,1);
	            
	            delete this.aAssoc[name];
	            
	            this.assocLength--;
	        }   

	    }

	    this.assocSplice = function(pos,del,obj,name){
		    this.aAssoc.splice(pos,del,obj);

		    this.aAssoc[name] = this.aAssoc[pos];

		    this.assocLength += (1 - del);
	    }    
    } // assocArray
            
    
    //cat   - misc
    //desc  - Object representing behavior and attributes at the frameset level
    //usage - window tree traversal
    function ctiFrameset(){
	    //Attributes
	    this.HTTPS = "off";
	    this.DELIMITER = "|";
	    this.DEFAULT_LINK = "";
	    this.global_gen_display_message_type = syncPost('cti_retrieve_session.aspx','shortkey=SessionCurrPage.PageStateMessageDisplayType');
	    this.appName = syncPost('cti_retrieve_session.aspx','shortkey=SessionAppName');
	    this.winMgr = new ctiWindows();
	    this.framesetWin = window;
        //this.frameWin = window.parent; REMOVED 6/4/09

	    this.winCloseNotify = function(id)
	    {
	        //if(id)
	           //alert('Close Notify for ' + id);
	        if(id)
	            this.winMgr.removeWin(id);
	    
	        return;
	    }
    } // ctiFrameset
    
    //cat   - misc
    //desc  - Object representing behavior and attributes at the frameset level
    //usage - window tree traversal
     function ctiWindows(){
	    this.aWins = new assocArray();
	    
	    this.dumpWins = function(newid)
	    {
	        var aTrio;
	        var msg = "recently added" + newid + "\r";
	    
	        for(var i = 0; i < this.aWins.assocLength; i++)
	        {
	            aTrio = this.aWins.assocGetByIndex(i);
	            
	            if(aTrio)
	            {
	                msg += " index " + i + ": len:" + aTrio.length;
	                
	                if(aTrio.length > 1)
	                    msg += (" parent id:" + aTrio[1]);
	            }
	            
	            msg += "\r";
	        }
	        
	        cti_alert(msg);
	    }
	        
	    this.registerWin = function(newWin,parentWinId,bStickaround)
	    {
	        var newWinId = "w" + Math.floor(Math.random()*10000);
	        
	        var level = 0;
	        
	        var idx = -1
	        
	        if(parentWinId)
	        {
	            var idx = this.aWins.assocGetIndexByName(parentWinId);
	            
	            //alert('got idx of ' + idx + ' for parent id of ' + parentWinId + ' overall len:' + this.aWins.assocLength);
	            
	            if(idx > -1)
	                //do
	                {
	                    level = this.aWins.aAssoc[idx][3] + 1;
	                
	                    idx++;

	                } //while((idx < this.aWins.assocLength) && (this.aWins.assocGetByIndex(idx)[1] == parentWinId))

	        }
	        
	        var aInfo = new Array(newWin,parentWinId,bStickaround,level,newWinId);
	        
	        if((idx == -1) || (idx > this.aWins.assocLength)) // first level
	            this.aWins.assocPush(aInfo,newWinId);
	        else
                this.aWins.assocSplice(idx,0,aInfo,newWinId);
                
                
            newWin.winId = newWinId;
                
            //this.dumpWins(newWinId);
                                	        
	        return newWinId;    
        } // registerWin
        
        this.removeWin = function(id)
        {
            this.aWins.assocRemoveByName(id);
                      
            if(parent.right_frame && parent.right_frame.ge('popuptitlediv'))
                parent.right_frame.showPopupTitles();

        }
	        
	        
        this.setWinFocus = function(id)
        {
            var aWin = this.aWins.assocGetByName(id);
	            	            
            if(aWin && (aWin.length > 0) && (!aWin[0].closed))
                aWin[0].focus();
            else
                alert('aWin no good for ' + id);
	    }
	        
	} // ctiWindows

    //cat   - misc
    //desc  - Gets text from node with given tag name and index
    //usage - most of iud routines
    function get_element_text_by_tag_name(host, tagName, index){
	    if(arguments.length < 3)
		    index = 0;

	    if(host && host.hasChildNodes()){
		    var nodes = host.getElementsByTagName(tagName);
    		
		    if(nodes && (nodes.length > index)){
			    var node = nodes[index];
    			
			    var txtNode = getTextNode(node);
    			
			    if(txtNode)
				    return txtNode.nodeValue;
		    }
	    }
	    return "";
    } // get_element_text_by_tag_name

//**************************************************
//END - UTILITY (MISCELLANEOUS)
//**************************************************
    

//**************************************************
//BEGIN - WAIT PAGE
//**************************************************
 
    //cat   - wait page
    //desc  - indicates whether or not to display wait the wait_page
    //      - depends on the following web.config appSettings indicator
    //          <add key="WaitIndicator" value="debug"/>
    //usage - page loads, action (insert, update deletes), ...
    function sessionLoadingDebug ()
    {
      return sessionLoadingInd.toLowerCase() == 'debug'
    }

    //cat   - wait page
    //desc  - pops up the wait page
    //usage - init_gen_form
    //@msg  - 
    //@ret  - 
    function wait( msg, debugOnly )
    {
        var waitpagedims = 'width=400,height=200,top=0,left=0'
        
      /*  if(!(
            (sessionLoadingInd == 'Y' && !debugOnly) || 
            (sessionLoadingDebug() && debugOnly)
            )) return
      */
      
        if(sessionLoadingInd.toLowerCase() == 'n') return
      
      /*
        if(parent && parent.top_frame && parent.top_frame.ge && parent.top_frame.ge('tf_image')) 
        {
            parent.top_frame.ge('tf_image').title = msg
            return;
        }
      */
      
        if(!msg) msg = '<b>Please Wait..........</b>'
      
        var wait_page = window.open('','wait_page','toolbars=no,'+waitpagedims)
        if(wait_page && wait_page.document)
        {
            var d = new Date()
            var time = '('+d.getHours()+':'+d.getMinutes()+':'+d.getSeconds()+') '
            if(wait_page.document.firstChild && wait_page.document.firstChild.firstChild && !wait_page.document.firstChild.firstChild.getElementsByTagName('link').length)
            {
                var html = []
                html.push('<html>');
	            html.push('<head>');
	            html.push('<link rel="stylesheet" href="'+syncPost('cti_retrieve_session.aspx','shortkey=SessionAppCSS')+'"></link>');	
	            html.push('</head>');	
	            html.push('<body class="wait_page">');
	            html.push(time+msg+'<br>');
	            html.push('</body>');
	            html.push('</html>');
	            wait_page.document.write(html.join(''))
            }
            else
            {
                var txt = (typeof msg == 'string' ? wait_page.document.createTextNode(msg) : msg)
                var timestamp = wait_page.document.createTextNode(time)
                var br = wait_page.document.createElement('br')
                wait_page.document.body.appendChild(timestamp)
                wait_page.document.body.appendChild(txt)
                wait_page.document.body.appendChild(br)
                br.scrollIntoView()
               //wait_page.document.write(msg+'<br>')
            }
            wait_page.document.title = msg
            wait_page.focus()
        }
    }

    //desc  - closes the wait page
    //usage - init gen form
    function endWait(button,debugOnly){
        var waitpagedims = 'width=400,height=100,top=0,left=0'
        
      /*
        if(!(
            (sessionLoadingInd == 'Y' && !debugOnly) || 
            (sessionLoadingDebug() && debugOnly)
            )) return
      */
      
        if(sessionLoadingInd.toLowerCase() == 'n') return
        
        var wait_page = window.open('','wait_page','toolbars=no;'+waitpagedims)
	    if(wait_page)
	        if(button)
	            wait('<input type=button onclick="window.close()" value="Click to Close" />')		
		    else
		        wait_page.close();
    } 
//**************************************************
//END - WAIT PAGE
//**************************************************


//**************************************************
//BEGIN - BROWSER COMPATIBILITY ROUTINES 
// Notes:
//  - ctiBrowser: object that manages disparities between browsers.
//**************************************************

    //desc  - converts an XML data island into an xml object and returns the document element of that object.
    //usage - ctiBrowser, ctiBind
    function ctiXBCXML(obj)
    {
        if(obj)
            if(obj.tagName.toLowerCase() == "xml")
                return obj.XMLDocument
            else if(obj.tagName.toLowerCase() == "textarea")
                return makeMozXML(obj.value)
            else
                alert('unrecognized isle element:' + obj.tagName)
        null
    }

    //desc  - provides abstract access to cross-browser functionality
    //usage - subtypes, binding
    function ctiBrowser(){
        if(/Microsoft/.test(navigator.appName))
            return new ctiIEBrowser();
        else
            return new ctiMozBrowser();
        
    }

    //desc  - ie specific browser javascript methods
    function ctiIEBrowser(){

        //old
        this.attachEvent = function(event_name,event_func)
        {
            window.attachEvent(event_name,event_func)
        }
        this.XMLDoc = function(xml_obj)
        {
            return xml_obj.XMLDocument
        }  
        this.XMLDocElement = function(xml_obj)
        {
            return xml_obj.XMLDocument.documentElement
        }
        this.XMLDocText = function(xml_obj)
        {
            return xml_obj.XMLDocument.xml
        }
        this.attachEventTo = function(obj,event_name,event_func)
        {
            obj.attachEvent(event_name,event_func)
        }
        
        this.xmlInnerText = function(xml_node)
        {
            return xml_node.text;
        }
        this.xmlText = function(xml_obj)
        {
            return xml_obj.xml
        }
        this.xPath = function(xml_node,xpath_expression)
        {
            return xml_node.selectNodes(xpath_expression)
        }
        this.xPathSingle = function(xml_node,xpath_expression)
        {
            return xml_node.selectSingleNode(xpath_expression)
        }
        this.fireEvent = function(target,type)
        {
            return target.fireEvent(type)
        }
        this.createRadioButton = function(name)
        {
            return ce('<input type="radio" name="'+name+'">')
        }
        this.isIE = true

    }

    //desc  - cross-browser xml document creation
    //usage - various functions such as InitDrillDown
    function makeXML(sXML)
    {
        if(/Microsoft/.test(navigator.appName))
        {
            x = new ActiveXObject('Microsoft.XMLDOM');
            x.async = false;
            x.loadXML(sXML);
            
            return x;
        }            
        else
            return makeMozXML(sXML);
    } // makeXML

    //desc  - makes an xml document out of a string in firefox
    //usage - ctiMozBrowser
    function makeMozXML(xml_string)
    {
        if(/Microsoft/.test(navigator.appName)) return null;
        
        
        xml_string = xml_string.replace(/\<br\>/ig,"<br />")
        var parser = new DOMParser();
        var xmlDoc = parser.parseFromString(xml_string,"application/xml")
        
        return xmlDoc;
    }

    //desc - js compatibility layer for mozilla/firefox
    function ctiMozBrowser()
    {
        this.eventTranslator = {
            'onload':'load',
            'onchange':'change',
            'onclick':'click'
            }

        //old
        this.attachEvent = function(event_name,event_func)
        {
            if(event_name in this.eventTranslator) event_name = this.eventTranslator[event_name]
            window.addEventListener(event_name,event_func,false)
        }
        
        this.XMLDoc = function(xml_obj)
        {
            return xml_obj
        }
        this.XMLDocElement = function(xml_obj)
        {
            return xml_obj
        }
        this.XMLDocText = function(xml_obj)
        {
            return xml_obj
        }
        this.attachEventTo = function(obj,event_name,event_func)
        {
            if(event_name in this.eventTranslator) event_name = this.eventTranslator[event_name]
            obj.addEventListener(event_name,event_func,false)
        }
        
        this.xmlInnerText = function(xml_node)
        {
            return xml_node.text;
        }
        this.xmlText = function(xml_obj)
        {
            return xml_obj.textContent // does this include the root node?
        }
        this.xPath = function(xml_node,xpath_expression)
        {
            var r = []
            var nodes = xml_node.document.evaluate(xpath_expression, xml_node, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
            var node = nodes.iterateNext();
            while(node)
            {
                r.push(node);
                node = nodes.iterateNext();
            }
            
            return r;
        }
        this.xPathSingle = function(xml_node,xpath_expression)
        {
            try
            {
                var result = xml_node.document.evaluate(xpath_expression, xml_node, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
                if(result)
                    return result.singleNodeValue;
                else return null;
            }
            catch(x)
            {
                alert(xpath_expression+':\n'+x.message);
                return null;
            }
        }
        this.fireEvent = function(target,type)
        {
            var e = document.createEvent("Events")
            e.initEvent(type,true,true)
            return target.dispatchEvent(e)
        }
        this.createRadioButton = function(name)
        {
            var radio = ce('input')
            radio.type = 'radio'
            radio.name = name;
            return radio;
        }
        this.isIE = false;
    } //ctiMozBrowser()
//**************************************************
//END - BROWSER COMPATIBILITY ROUTINES 
//**************************************************


//**************************************************
//BEGIN - UTILITY (DOM MANIPULATION ROUTINES)
// Notes:
//  - common simple operations for DOM manipulations
//  - abbreviated to cut down on verbosity in scripts.
//**************************************************

    //desc  - convert null_to blank (string)
    function cntb(x){
        return (x ? '': x)
    }

    //desc  - append child node to parent
    function ac(n,p){
        return p.appendChild(n)
    }

    //desc  - create node tree
    function cnt(){
        for(var i=0,n=arguments.length;i<n-1;i++)
           ac(arguments[i],arguments[i+1])
    }
    
    //desc - replace child node
    function rcn(n,newnode){
        return n.parentNode.replaceChild(newnode,n);
    }

    //desc - remove node
    function rn(n){
        return n.parentNode.removeChild(n)
    }

    //desc - (document.)_c_reate _e_lement by (_t_ype)
    function ce(t){
        return document.createElement(t)
    }

    //desc - (document.)_create _t_text (node) with (_t_ext)
    function ct(t){
        return document.createTextNode(t)
    }

    //desc - (document.) _g_et elements with _t_ag name (_t_ag)
    function gt(t){
        return document.getElementsByTagName(t)
    }

    //desc - _g_et _e_lement by (_n_ame)
    function ge(n){
	    return document.getElementById(n);
    }

    //desc - _g_et _v_alue by (_n_ame) saves us a lot of ge(n).value calls. propose moving this into $.
    function gv(n){
        var x = ge(n);
        if(x) return x.value; else return x;
    }
//**************************************************
//END - UTILITY (DOM MANIPULATION ROUTINES)
//**************************************************


//**************************************************
//BEGIN - ERROR PAGE ROUTINES
// Notes:
//  - error page functionality
//  - 3 display types
//**************************************************

    //cat   - error handling
    //desc  - 
    //usage - nfg, cti_retrieve, cti_verify
    function display_error_page(error_msg, error_type, caller) {          
	    var sClass;
    		
	    //This logic should be moved to the base form page
        var fMgr = new ctiFrameset();
        
        var msgLoc = fMgr.global_gen_display_message_type;
        var msgType;
                
        if(msgLoc == "popinmid")
            msgType = "popin";
        else
            msgType = msgLoc;
            
        
	    switch (msgType){
    	    
		    case "popin":
		        var basew;
		        
		        if(parent.right_frame)
		            basew = parent.right_frame;
		        else
		            basew = window;
		        
			    var err_htm = "";
			    var errors	= error_msg.split("|");
			    //var button	= "<br><div align='center'><button onClick='error_page = null; parent.right_frame.dismiss(parent.right_frame.ge(\"message_div\"))();' id='err_close_button' >Close</button></div>";
			    //var button	= "<br><button onClick='parent.right_frame.dismiss(parent.right_frame.ge(\"message_div\"))();' id='err_close_button' >Close</button>";
			    var button	= "<br><button onClick='highlight_all_errors(error_array); dismiss(ge(\"message_div\"))();' id='err_close_button' >Close</button>";

			    switch(error_type){
				    case "V":
				        sClass = "err_msg_validation";
					    //err_htm += "<table width='100%' align='center' ID='ErrTable1' style='background-color:yellow;'>";
					    err_htm += "Action failed due to the following reasons:";
					    if(error_msg.indexOf("<a") > -1)
					        err_htm += "<br /><i>(click Close or a link to continue)</i>";
					    err_htm += "<br /><br /><table width='100%' align='center' ID='ErrTable1'>";
					    //err_htm += "<tr><td align='center'>Action failed due to the following reasons:<br><br></td></tr>";
				    break;
    					
				    case "W":
				        sClass = "err_msg_warning";
				        err_htm += "Warning:<br /><br />";
				        err_htm += "<table width='100%' align='center' ID='ErrTable2'>";
					    //err_htm += "<table width='100%' align='center' ID='ErrTable2' style='background-color:orange;'>";
					    //err_htm += "<tr><td align='center'>Warning:<br><br></td></tr>";
				    break;
    				
				    case "E":
				        sClass = "err_msg_error";
				        err_htm += "Please call technical support.<br /><br />";
				        err_htm += "Action failed due to the following error:<br /><br />";
				        err_htm += "<table width='100%' align='center' ID='ErrTable3'>";
					    //err_htm += "<table width='100%' align='center' ID='ErrTable3' style='background-color:Red;'>";
					    //err_htm += "<tr><td align='center'>Please call technical support.<br><br></td></tr>";
					    //err_htm += "<tr><td align='center'>Action failed due to the following error:<br><br></td></tr>";
				    break;
    				
				    case "I":
				        sClass = "err_msg_information";
				        err_htm += "<table width='100%' align='center' ID='ErrTable4'>";
					    //err_htm += "<table width='100%' align='center' ID='ErrTable4' style='background-color:#66cc66;'>";
				    break;
				    
				    default:
				        sClass = "err_msg_error";
				        err_htm += "Please call technical support.<br /><br />";
				        err_htm += "Unknown Message Type for the following error:<br /><br />";
				        err_htm += "<table width='100%' align='center' ID='ErrTable5'>";

			    }
    			
				for(var i=0, l=errors.length;i < l;i++){
				    err_htm += "<tr><td align='center'>";
					err_htm += errors[i] + "<br>";
					err_htm += "</td></tr>";
				}

			    err_htm += "</table>";

                if(error_type != "I")
			        err_htm += button;
    	
			    if(basew.document.getElementById("err_close_button") != null){
				    basew.document.getElementById("err_close_button").click();
			    }
			    
			    var divMsgCont;
			    var divMsg;
    				
    		    if(msgLoc == "popin")
    		    {
    		        try{
    		            divMsgCont = basew.ce('div');
    		            divMsgCont.id   = 'message_div';
    		            divMsgCont.className = "display_message_popin";
    		             
				        divMsg			= basew.ce('div');
    				    divMsg.className = sClass;
	    			    divMsg.innerHTML	= err_htm;
	    			    
	    			    basew.ac(divMsg,divMsgCont);
	    			    
		    		    basew.document.body.insertBefore(divMsgCont,basew.document.body.firstChild);
			    	    divMsgCont.focus();
				        try{ divMsgCont.scrollIntoView(); } catch(ex) {}
			        }//end try
			        catch(error){}
    		    }
    		    else
    		    {
    		        divMsgCont = makeDraggableDiv();
    		        divMsgCont.id   = 'message_div';
    		        divMsgCont.className = "display_message_popinmid";
    		        
    		        divMsg			    = basew.ce('div');
    		        divMsg.className    = sClass;
    		        divMsg.innerHTML    = err_htm;
    		        
    		        basew.ac(divMsg,divMsgCont);
    		        
    		        divMsgCont.style.top = (basew.document.body.scrollTop + ((basew.document.body.clientHeight - divMsgCont.offsetHeight)/2)) + 'px';
                    divMsgCont.style.left = ((basew.document.body.clientWidth - divMsgCont.offsetWidth)/2) + 'px';
                    
                    //alert('ran popinmid logic');
    		    }

			    break;

		    case "alert":
			    error_msg = error_msg.replace(/<a href[^>]*>/mig,'')
		        error_msg = error_msg.replace(/<\/a>/mig,'')
		        error_msg = error_msg.replace(/\|/mig,'\n')
			    alert(error_msg);
			    break;

		    default:
		        var sHeight = screen.height/2;
		        var sWidth  = screen.width/2;

			    var error_page	= window.open("","error_page","toolbars=no,scrollbars=yes,resizable=yes,top=0,left=0,height=" + sHeight + ",width=" + sWidth);
			    var errors		= error_msg.split("|");
			    var button		= "<br><button onClick='window.close()' id='ok_button'>Ok</button>";
			    
			    var head1 = "<head><title>";
			    var head2 = "</title><style>body {text-align:center;margin 0 0 0 0;padding 0 0 0 0;}</style></head>";

			    error_page.document.write("<html>");
			    
			    //error_page.document.write("<head><title>Operation Status</title><style>body {text-align:center;}</style></head>");
    			
			    switch(error_type){
				    case "V":
					    button = "<br><button onClick='try{window.opener.highlight_all_errors(window.opener.error_array);}catch(error){}window.close()'>Ok</button>";
					    error_page.document.write(head1 + "Form Validation Failure" + head2);
					    error_page.document.write("<body bgcolor='yellow'>");
					    error_page.document.write("<table width='100%' align='center'>");
					    error_page.document.write("<tr align='center'><td>Action failed due to the following reasons:</tr></td><br><br>");
				    break;
    					
				    case "W":
				    	error_page.document.write(head1 + "Operation Warning" + head2);
					    error_page.document.write("<body bgcolor='orange'>");
    					
					    error_page.document.write("<table width='100%' align='center'>");
					    error_page.document.write("<tr align='center'><td>Warning:</tr></td><br><br>");
				    break;
    				
				    case "E":
				        error_page.document.write(head1 + "Operation Error" + head2);
					    error_page.document.write("<body bgcolor='Red'>");
					    error_page.document.write("<table width='100%' align='center'>");
					    error_page.document.write("<tr align='center'><td>Please call technical support.</tr></td><br><br>");
					    error_page.document.write("<tr align='center'><td>Action failed due to the following error:</tr></td><br><br>");
    					
				    break;
    				
				    case "I":
				    	error_page.document.write(head1 + "Operation Confirmation" + head2);
					    error_page.document.write("<body bgcolor='#66cc66'>");
					    error_page.document.write("<div style='font-size:smaller;color:#2F2F2F'>Click 'OK' to close this window, or it will close by itself in 10 seconds.</div>")
					    error_page.document.write("<table width='100%' align='center'>");
					    error_page.setTimeout(" document.getElementById('ok_button').click(); ", 10000);
				    break;
				    
				    default:
				        error_page.document.write(head1 + "Unknown Error Type" + head2);
				        error_page.document.write("<body bgcolor='#000077'>");
					    error_page.document.write("<table width='100%' align='center'>");
					    error_page.document.write("<tr><td>Warning:</td></tr>");
				   
			    }

			    for(var i=0;i < errors.length;i++){
			        error_page.document.write("<tr align='center'><td>");
					error_page.document.write(errors[i] + "<br>");
					error_page.document.write("</td></tr>");
				}
    			
			    error_page.document.write("</table>");
			    error_page.document.write(button);
			    
			    //if(!caller)
			      //  caller = "unknown caller";
			        
			    //error_page.document.write("<br />err type:" + error_type + "<br /> caller:" + caller);
			    
			    error_page.document.write("</body>");
			    error_page.document.write("</html>");
			    error_page.document.close();

			    try{error_page.focus();error_page.ok_button.focus()}catch(focus_error){};
			    
	    } // default message type
    } //function display_error_page
    
    
    function clear_error_page()
    {
    
     var basew;
		        
	 if(parent.right_frame)
	     basew = parent.right_frame;
     else
	     basew = window;
	    
	 var  divMsgCont = basew.document.getElementById('message_div');
	 
	 if(divMsgCont)
	    divMsgCont.parentNode.removeChild(divMsgCont);
	    
	     
    }
//**************************************************
//END - ERROR PAGE ROUTINES
//**************************************************


//**************************************************
//BEGIN - VALIDATION ROUTINES
//**************************************************

    //desc  - javascript validation on for expando fields
    //usage - rec_iud, save_form_reload, save_form_no_reload, save_row
    function cti_validate(){
    	
	    var has_atleast_one_field = false,field_counter = 0;
	    var error_msg = "";
    	
	    var fMgr;
	    var w = window;
	    var sDisplayType = "";
    	
	    //var nw = window.opener;
    	
	    //while (nw){
	    //  w = nw;
	    //    nw = nw.opener;
	    //}
    	
        fMgr = new ctiFrameset();
        
        var delim = fMgr.DELIMITER;
        var current_form;
        var current_element;
        var header;

	    //Iterate through all forms on current document
	    for(var i = 0;i < window.document.forms.length;i++){

		    current_form = window.document.forms[i];
		    
		    error_array = new Array(current_form.elements.length);

		    //Iterate through elements on current form
		    for(var j=0, elen=current_form.elements.length;j < elen;j++){
			    current_element = current_form.elements[j];
			        			
			    //No need to validate elements that are not shown/hidden to the user via wrappers
			    if (!check_hidden (current_element)){
    //			    wait('validating ' + current_element.name)
				    if (fMgr.global_gen_display_message_type.indexOf("popin") > -1){
					    header = "<a href='javascript:;' onclick=\"clientMgr.confirmExit = false; highlight_all_errors(error_array);try{error_array[" + j + "].focus();}catch(error){document."+current_form.name+"."+current_element.name+"[0].focus()}; var el = window.ge('err_close_button'); if(el) el.click();\">"+current_element.display_name+"</a>";
				    }
				    else{
					    header = "<a href='javascript:;' onclick=\"window.opener.highlight_all_errors(window.opener.error_array);try{window.opener.error_array[" + j + "].focus()}catch(error){window.opener.document."+current_form.name+"."+current_element.name+"[0].focus()};window.close()\">"+current_element.display_name+"</a>";
				    }
    				    				
				    /************************************
				    required field check
				    has special checks for phone, date ,and
				    SSN types since they are multipart fields
				    on the HTML
				    ************************************/
				    if(current_element.required != null && !check_hidden(current_element)){
    				
					    current_element.required = true;
					    var validation_error;
					    validation_error = false;
    					
					    if(isWhitespace(current_element.value))
						    validation_error = true;				
    					
					    if(current_element.type == 'radio' && !current_element.checked)
					    {
						    validation_error = true;
						    for(var subrad = 0, slen = parent.right_frame.document.forms[0][current_element.name].length; subrad < slen; subrad++)
							    if (parent.right_frame.document.forms[0][current_element.name][subrad].checked) { validation_error = false; }
    							
    						
						    if(validation_error)
							    for( var other_err = 0; other_err < error_array.length; other_err++ )
								    if (error_array[other_err] && error_array[other_err].name == current_element.name) 
									    validation_error = false;
    									
					    }//end if(current_element.type == 'radio' && !current_element.checked)
    						
    					
					    if(validation_error){
						    error_msg += header + " is a required field" + delim;
						    error_array[j] = current_element;
						    continue; // go to next iteration
					    }
				    }
    				
				    if(current_element.phone_ext != null){
					    current_element.phone_ext = true ;
					    if(!isInteger(current_element.value,true)){
						    error_msg += header + " must be numeric" + delim;
						    error_array[j] = current_element;
					    }
					    if(current_element.length > 6){
						    error_msg += header + " must be less than 7 numbers" + delim;
						    error_array[j] = current_element;
					    }
				    }
    				
				    if(current_element.zip_code != null){
					    if(!isZIPCode(current_element.value,true)){
						    error_msg += header + " is not a valid Zip code" + delim;
						    error_array[j] = current_element;
					    }	
				    }
    				
				    if(current_element.year != null){
				        if(!isWhitespace(current_element.value))
				        {
				            if(current_element.value.length != 4){
				                error_msg += header + " must have 4 digits" + delim;
				                error_array[j] = current_element;
				            }
				        }
				    }
				    
				    if(current_element.zip_code_ext != null){
					    if(!isWhitespace(current_element.value)){
						    //alert("value=" + current_element.value + " length =" + current_element.length);
						    if(current_element.value.length != 4){
							    error_msg += header + " must be 4 digits long" + delim;
							    error_array[j] = current_element;
						    }
						    if(!isInteger(current_element.value,true)){
							    error_msg += header + " must be numeric" + delim;
							    error_array[j] = current_element;
						    }
					    }
				    }
    				
				    if(current_element.textarea_max != null){
					    if(current_element.value.length > current_element.textarea_max){
						    error_msg += header + " must be less than " +current_element.textarea_max+ " characters long" + delim;
						    error_array[j] = current_element;
					    }
				    }
    				
				    if(current_element.numeric != null){
					    var is_valid_number = true;
    					
					    if(!isInteger(current_element.value,true)){
						    error_msg += header + " must be numeric" + delim;
						    error_array[j] = current_element;
						    is_valid_number = false;
					    }
    					
					    if(is_valid_number){
						    if(current_element.min_value != null && current_element.date == null){
							    var min			= parseInt(current_element.min_value);
							    var current		= parseInt(current_element.value);
    							
							    if(current < min){
								    error_msg += header + " must be greater than " + min + delim;
								    error_array[j] = current_element;
							    }
						    }
    						
						    if(current_element.max_value != null && current_element.date == null){
							    var max			= parseInt(current_element.max_value);
							    var current		= parseInt(current_element.value);
    							
							    if(current > max){
								    error_msg += header + " must be less than " + max + delim;
								    error_array[j] = current_element;
							    }
						    }
					    }
				    }//end if(current_element.numeric != null) 

                    //needed for type-agnostic datadriven fields
	                if(current_element.min_value != null && current_element.date == null){
		                var min			= parseInt(current_element.min_value);
					    var current		= parseInt(current_element.value);
    					
					    if(current < min){
						    error_msg += header + " must be at least " + min + delim;
						    error_array[j] = current_element;
					    }
				    }
    				
				    if(current_element.max_value != null && current_element.date == null){
					    var max			= parseInt(current_element.max_value);
					    var current		= parseInt(current_element.value);
    					
					    if(current > max){
						    error_msg += header + " must be at most " + max + delim;
						    error_array[j] = current_element;
					    }
				    }

    							
				    if(current_element.decimal != null){
					    if(!isFloat(current_element.value,true)){
						    error_msg += header + " is not a valid decimal point integer" + delim;
						    error_array[j] = current_element;
					    }
				    }
    				
				    if(current_element.alpha != null){
					    if(!isAlphabetic(current_element.value) && !isWhitespace(current_element.value)){
						    error_msg += header + " can only consist of English letters" + delim;
						    error_array[j] = current_element;
					    }
				    }

				    if(current_element.alphanumeric != null){
					    if(!isAlphanumeric(current_element.value)){
						    error_msg += header + " can only consist of letters and numbers" + delim;
						    error_array[j] = current_element;
					    }
				    }
    				
				    if(current_element.compare_to_date != null && !isWhitespace(current_element.compare_to_date)){
					    try{
						    var start_date = new Date(window.document.getElementsByName(current_element.compare_to_date).item(0).value);
						    var end_date = new Date(current_element.value);
    						
						    if(end_date < start_date){
							    error_msg += header + " must be greater than or equal to the [Start Date for Services Requested] " + delim;
							    error_array[j] = current_element;
						    }
					    }
					    catch(error){}
				    }
    				
				    if( (current_element.currency != null) && (!isWhitespace(current_element.value)) ){
					    var money			= stripCharsInBag(current_element.value,",$");
					    var is_valid_curr	= true;
    					
					    if(!isFloat(money,true)){
						    error_msg += header + " is not a valid currency format" + delim;
						    error_array[j] = current_element;
						    is_valid_curr = false;
					    }
					    else{
						    current_element.value = (parseFloat(money)).toFixed(2);
						    this.clientMgr.bindMgr.processChange(current_element);
					    }
    					
					    if(is_valid_curr){
						    if(current_element.min_value != null){
							    var min		= parseFloat(current_element.min_value);
							    var current	= parseFloat(current_element.value);
    							
							    if(current < min){
								    error_msg += header + " must be greater than " + min + delim;
								    error_array[j] = current_element;
							    }
						    }
    						
						    if(current_element.max_value != null){
							    var max		= parseFloat(current_element.max_value);
							    var current	= parseFloat(current_element.value);
    							
							    if(current > max){
								    error_msg += header + " must be less than " + max + delim;
								    error_array[j] = current_element;
							    }
						    }
					    }
				    }
    				
				    /***********************************
				    for combination fields that contain
				    date and time ie.
				    mm/dd/yyyy hh:mm (am or pm)
				    ***********************************/
				    if(current_element.datetime != null){
					    if(!isWhitespace(current_element.value)){
						    var temp_str = "",
							    temp_msg = "";
    							
						    var dt_arr = new Array(3);
    					
						    for(var d = 0;d < current_element.value.length;d++){
    							
							    var c = current_element.value.charAt(d);
    							
							    if(isWhitespace(c)){
    								
								    if((dt_arr[0] == null) || (dt_arr[0] == "")){
									    dt_arr[0] = temp_str;
								    }
								    else{
									    //time
									    dt_arr[1] = temp_str;
								    }
    								
								    temp_str = "";
							    }
							    else{
								    temp_str += c;
							    }
    							
						    }
    					
						    temp_msg = parse_date(dt_arr[0],header,j);
    					
						    if(temp_msg != ""){
							    error_msg += temp_msg;
							    error_array[j] = current_element;
						    }
    					
						    var time_filter		= /^(\d{1,2}):(\d{2})(:(\d{2}))?(\s?(AM|am|PM|pm))?$/;
						    var filter_result	= (dt_arr[1] + temp_str).match(time_filter);
						    if(filter_result == null){
							    error_msg += header + " is not a valid time " + delim;
							    error_array[j] = current_element;
						    }
						    else{
							    var time_arr = (dt_arr[1] + temp_str).split(":");
    							
							    try{
								    var hh = parseInt(time_arr[0]);
								    var mm = parseInt(time_arr[1]);
    								
								    if(hh > 24 || hh < 0){
									    error_msg += header + " is not a valid time " + delim;
									    error_array[j] = current_element;
								    }
    								
								    if(mm > 59 || mm < 0){
									    error_msg += header + " is not a valid time " + delim;
									    error_array[j] = current_element;
								    }
    									
							    }
							    catch(error){
								    error_msg += header + " is not a valid time " + delim;
								    error_array[j] = current_element;
							    }
						    }//end else
					    }//end if !whitespace
				    }//end datetime
    				
				    if(current_element.email != null){
					    if(!isWhitespace(current_element.value)){
						    if(!current_element.value.match(/\b(^(\S+@).+((\.com)|(\.net)|(\.edu)|(\.mil)|(\.gov)|(\.org)|(\..{2,2}))$)\b/gi)){
							    error_msg += header + " is not a valid email address " + delim;
							    error_array[j] = current_element;
						    }
					    }
				    }

				    if(current_element.illegal_value != null){
					    if(current_element.value == current_element.illegal_value){
						    error_msg += header + " cannot have the value " + current_element.illegal_value + delim;
						    error_array[j] = current_element;
					    }
				    }
    				
				    if(current_element.ubound != null){
					    if((!isWhitespace(current_element.value)) && ((parseInt(current_element.value)) > (parseInt(current_element.ubound)))){
    						
						    if(current_element.no_bound_msg != null){ 
							    error_msg += header + " is invalid" + delim;
						    }
						    else{
							    error_msg += header + " can not be greater than " + current_element.ubound + delim;
						    }
    						
						    error_array[j] = current_element;
					    }
				    }
    				
				    if(current_element.lbound != null){
					    if((!isWhitespace(current_element.value)) && ((parseInt(current_element.value)) < (parseInt(current_element.lbound)) )){
						    if(current_element.no_bound_msg != null){ 
							    error_msg += header + " is invalid" + delim;
						    }
						    else{
							    error_msg += header + " can not be less than " + current_element.lbound + delim;
						    }
						    error_array[j] = current_element;
					    }
				    }
    				
				    if(current_element.min_length != null){
					    if(!isWhitespace(current_element.value) && (current_element.value.length < current_element.min_length)){
						    error_msg += header + " must have at least "+ current_element.min_length +" characters" + delim;
							    error_array[j] = current_element;
					    }
				    }
    				
    				// DATE CHECKS
    				var is_valid_date = true;
				    if(current_element.date != null){
					    var temp_msg = "";
    					
					    //current_element.value	= fix_year(current_element.value);
					    temp_msg				= parse_date(current_element.value, header,j);
    					
					    if(temp_msg != ""){
						    error_msg		+= temp_msg;
						    error_array[j]	= current_element;
						    is_valid_date   = false;
					    }
    					
					    if(is_valid_date){
					        var current_date = new Date(current_element.value);
					        
						    if(current_element.min_value != null){
							    var min_date		= new Date(current_element.min_value);

							    if(current_date < min_date)
							    {
							   	    error_msg += header + " must be after " + current_element.min_value + delim;
							   	    error_array[j]	= current_element;
							   	    is_valid_date = false;
							    }
						    }
    					
						    if (is_valid_date && (current_element.max_value != null)){
							    var max_date		= new Date(current_element.max_value);
    							
							    if(current_date > max_date)
							    {
							        error_msg += header + " must be before " + current_element.max_value + delim;
							        error_array[j]	= current_element;
							   	    is_valid_date = false;
							    }
						    }
						    
						    if  (is_valid_date && (current_element.age_date_formatted != null)){
					            var max_date		= new Date(window.document.getElementById(current_element.map_to).value);
    					
					            if(current_date > max_date){
						            //var month = (max_date.getMonth() + 1);
						            //var day   = max_date.getDate();
						            //var year  = max_date.getYear();
    						
						            error_msg += header + " cannot be greater than " + max_date.toString()  + delim ;
						            error_array[j] = current_element;
					            }
				            }
				            
				            if  (is_valid_date && (current_element.unique != null) && clientMgr){
				                var xNode;
				                var xRow;
				               							                
				                var boundPair = clientMgr.bindMgr.getBoundPair(clientMgr.bindMgr.boundDataEls, current_element, 0);
				                
                                if(boundPair){
                                    xNode = boundPair[1];
                                    xRow =  xNode.parentNode;

                                    if(!xRow.getAttribute("changed"))
                                        continue;
                                }
				                
				                if(xRow){
				                    var xRowCand;
				                    var sTxt;
				                    var cand_date;
				                
				                    for(var z = 1, cLen = xRow.parentNode.childNodes.length; z < cLen; z++){
				                        xRowCand = xRow.parentNode.childNodes[z];
				                        
				                        if(xRowCand !== xRow){
				                            sTxt = get_element_text_by_tag_name(xRowCand,xNode.nodeName);
				                            
				                            if(sTxt){
				                                cand_date = new Date(sTxt);
				                                
				                                //alert ('comparing' + current_date + ' and ' + cand_date);
				                                
				                                if((current_date - cand_date) == 0){
				                                    error_msg += header + " date already exists - must be unique" + delim ;
						                            error_array[j] = current_element;
						                            is_valid_date = false;
				                                    break;
				                                }
				                            }
				                        }
				                    } // for 
				                } xRow
				            } // unique
				            
                            /******************************************************
				            The following validations are specific to main form fields only!
				            They assume there is a input hidden or viewable on the form
				            that holds the min/max date allowable for the date field with the corresponding
				            expando attribute.  Seems on the verge of obsolesence.
				            *******************************************************/
				            if(is_valid_date && (current_element.start_date_min != null)){
						        var start_date_min	= new Date(window.document.forms[i].start_date_min.value);
    						
						        if(current_date < start_date_min){
							        error_msg += header + " is before earliest start date allowed"  + delim;
							        error_array[j] = current_element;
							        is_valid_date = false;
						        }
				            }
    				
    				        if(is_valid_date && (current_element.start_date_max != null)){   					
						        var start_date_max	= new Date(window.document.forms[i].start_date_max.value);
    						
						        if(current_date > start_date_max){
							        error_msg += header + " is after latest start date allowed"  + delim;
							        error_array[j] = current_element;
							        is_valid_date = false;							        
						        }
				            }
    			
    			            if(is_valid_date && (current_element.begin_date_min != null)){ 
						        var begin_date_min	= new Date(window.document.forms[i].begin_date_min.value);
    						
						        if(current_date < begin_date_min){
							        error_msg += header + " is before earliest begin date allowed"  + delim;
							        error_array[j] = current_element;
							        is_valid_date = false;							        
						        }
				            }
				            
				            if(is_valid_date && (current_element.begin_date_max != null)){ 
						        var begin_date_max	= new Date(window.document.forms[i].begin_date_max.value);
    						
						        if(current_date > begin_date_max){
							        error_msg += header + " is after latest begin date allowed"  + delim;
							        error_array[j] = current_element;
							        is_valid_date = false;							        
						        }
				            }
    			
    				        if(current_element.end_date_min != null){
 						        var end_date_min	= new Date(window.document.forms[i].end_date_min.value);
    						
						        if(current_date < end_date_min){
							        error_msg += header + " is out of range  "  + delim;
							        error_array[j] = current_element;
							        is_valid_date = false;							        
						        }
				            }
    				
				            if(current_element.end_date_max != null){
    					        var end_date_max	= new Date(window.document.forms[i].end_date_max.value);
    						
						        if(end_date > end_date_max){
							        error_msg += header + " is out of range"  + delim;
							        error_array[j] = current_element;
							        is_valid_date = false;							        
						        }
					        }
				            
				            if(!is_valid_date)
				                continue; // go to next field.  this is a real time saver if we don't have to consider multiple violations on each field.
					    } // is_valid_date
				    } // date
    				
    				
				    if(current_element.ssn != null){
					    if(!isWhitespace(current_element.value)){
						    var formatted_ssn = stripCharsInBag(current_element.value,' -');
    						
						    if(!isSSN(formatted_ssn)){
							    error_msg += header + " is not a valid SSN " + delim ;
							    error_array[j] = current_element;
						    }
						    else{
							    current_element.value = formatted_ssn	;
							    this.clientMgr.bindMgr.processChange(current_element);
						    }
					    }
				    }
    				
				    if(current_element.phone != null){
					    if(!isWhitespace(current_element.value)){
						    var formatted_phone = stripCharsInBag(current_element.value,'()- ');
    						
						    if(!isUSPhoneNumber(formatted_phone)){
							    error_msg += header + " is not a valid phone number " + delim;
							    error_array[j] = current_element;
						    }
						    else{
							    current_element.value = formatted_phone;
							    this.clientMgr.bindMgr.processChange(current_element);
						    }
					    }
				    }
    				
				    /**************************************
				    Strong password checker:
				    1.  check to make sure login is NOT
					    part of the password
					2.  Checks various constraints provided
					    on the form such as:
	                    a.  minumum characters
	                    b.  maximum characters
	                    c.  minimum alphabetical characters
	                    d.  minimum capitalized letters
	                    e.  minimum numeric letters
	                    f.  minimum other (punctuation) characters
				    **************************************/
				    if(current_element.strong_password != null){
				        var candPwd = current_element.value;
				        var isStars = false;
				        var is_valid_pwd = true;

				        if(isWhitespace(candPwd)) {
				            error_msg += header + " can not be blank" + delim;
				            is_valid_pwd = false;
				        }
				        else
				            // all stars is the default setting
				            if (candPwd != "*****") {
				                var iMinChars = 6;
				                var iMaxChars = 10;
				                var iMinAlpha = 1;
				                var iMinAlphaCap = 0;
				                var iMinNumeric = 1;
				                var iMinOther = 0;
				                var aMatches;
				                var iMatches;
				                var plural;
				            
					            var pwd_strength = $sibling(current_element, "pwd_strength");

					            if (pwd_strength && (pwd_strength != "")) {
					                var aParms = pwd_strength.split("|");

    					            var iLen = aParms.length;
	    				            var aPair;
					            	                            
					                for (i = 0; i < iLen; i++) {
					                    aPair = aParms[i].split("=");

					                    switch (aPair[0]) {
					                        case "min_chars":
					                            iMinChars = aPair[1];
					                            break;
    					                    case "max_chars":
	    				                        iMaxChars = aPair[1];
		    			                        break;
			    		                    case "min_alpha":
				    	                        iMinAlpha = aPair[1];
					                            break;
					                        case "min_caps":
					                            iMinAlphaCap = aPair[1];
					                            break;
					                        case "min_numeric":
					                            iMinNumeric = aPair[1];
					                            break;
    					                    case "min_other":
	    				                        iMinOther = aPair[1];
	    				                        break;
	    				                    case "min_unique":
	    				                        break;
			    		                    default:
				    	                        is_valid_pwd = false;
					                            error_msg += header + aPair[0] + " is not a recognized password constraint - contact support " + delim;
					                    }
					                } // for					            					                
					            }
					        					        
    						
						        //----- check length
    						    if((candPwd.length < iMinChars) || (candPwd.length > iMaxChars)){
	    						    error_msg += header + " must be between 6 and 10 characters in length " + delim;
		    					    is_valid_pwd = false;
			    			    }

				    		    //----- check if password contains the login id - need to straighten this out!!!
					    	    var login_id
						        //----- login_id - retreive user id from session var to compare to
						        //----- used when there is no login field on the form ie. like cti_change_password
    						    if (current_element.login_id != null) {
	    					        login_id = current_element.login_id;
		    				    }
			    			    else {
				    		        //----- login_field - retrieve login_id from form input
					    	        //----- used on forms like uapmf where there is a user id field to compare to
						            //----- ie. creating new user
						            if (current_element.login_field != null)
						                login_id = window.document.getElementsByName(current_element.login_field).item(0).value;
						        }
						    
    						    if((current_element.value).indexOf(login_id) >= 0){
	    						    error_msg += header + " cannot contain the user id within it " + delim;
		    					    is_valid_pwd = false;
			    			    }

			    			    //----- check numeric minimum
			    			    var aMatches = candPwd.match(/[0-9]/g);

			    			    if (aMatches)
			    			        iMatches = aMatches.length;
			    			    else
			    			        iMatches = 0;
						    
    						    // negative means don't allow any numbers
	    					    if((iMinNumeric < 0) && (iMatches > 0)){
		    				        error_msg += header + " cannot contain numbers " + delim;
			    			        is_valid_pwd = false;
				    		    }
					    	    else
					    	        if (iMatches < iMinNumeric) {
					    	            if (iMinNumeric > 1)
					    	                plural = "s"
					    	            else
					    	                plural = "";
					    	                
						                error_msg += header + " must contain at least " + iMinNumeric + " number" + plural + delim;
						                is_valid_pwd = false;
						            }
						    						    
    						    //var contains_numeric = false;
        						
		    				    //for(var z = 0;z < (current_element.value).length;z++){
			    				//    var c = (current_element.value).charAt(z);
				    			//    if(isDigit(c))
					    		//	    contains_numeric = true;
						        //}
    						
						        //if(!contains_numeric){
    							//    error_msg += header + " must contain at least one number " + delim;	
	    						//    error_array[j] = current_element;
		    				    //}


						        //----- check alpha minimum
			    			    aMatches = candPwd.match(/[a-zA-Z]/g);
			    			    
			    			    if(aMatches)
			    			        iMatches = aMatches.length;
			    			    else
			    			        iMatches = 0;

			    			    if (iMatches < iMinAlpha) {
			    			        if (iMinAlpha > 1)
			    			            plural = "s"
			    			        else
			    			            plural = "";
			    			            
					                error_msg += header + " must contain at least " + iMinAlpha + " letter" + plural + delim;
					                is_valid_pwd = false;
					            }

					            //----- check alpha cap minimum
    						    aMatches = candPwd.match(/[A-Z]/g);
    						    
    						    if(aMatches)
			    			        iMatches = aMatches.length;
			    			    else
			    			        iMatches = 0;
			    			        
	    					    if (iMatches < iMinAlphaCap) {
		    			            error_msg += header + " must contain at least " + iMinAlphaCap + " capitalized letters " + delim;
			    		            is_valid_pwd = false;
				    	        }
						    
    						    //----- check other minimum
	    					    aMatches = candPwd.match(/^[a-zA-Z0-9\s]/g);

	    					    if (aMatches)
	    					        iMatches = aMatches.length;
	    					    else
	    					        iMatches = 0;
						    
		    				    // negative means don't allow any non-alphanumeric characters
			    			    if((iMinOther < 0) && (iMatches > 0)){
				    		        error_msg += header + " cannot contain special characters " + delim;
					    	        is_valid_pwd = false;
						        }
						        else
					                if (iMatches < iMinOther) {
					                    is_valid_pwd = false;
    					                error_msg += header + " must contain at least " + iMinOther + " punctuation/special characters " + delim;
	    				            }
				            
				            };  // if is not stars

				        if(!is_valid_pwd)
				            error_array[j] = current_element;
				            
				    } // current_element.strong_password != null
				    
				    /**************************************
				    Loose time checker
				    1.  does not check if mins is greater than 59
				    2.	or if hrs is greater than 23
				    **************************************/
				   // if(current_element.time != null){
					 //   if(!isWhitespace(current_element.value)){
					//	    var time_filter		= /^\s*(\d{1,2}):(\d{2})(:(\d{2}))?(\s*(AM|am|PM|pm))?\s*$/;
					//	    var filter_result	= (current_element.value).match(time_filter);
					//	    if(filter_result == null){
					//		    error_msg += header + " is not a valid time " + delim;
					//		    error_array[j] = current_element;
					//	    }
					//	    else{
					//	    } // valid time
					  //  }
				    //} // if time
				    
				    /**************************************
				    Time checker
				    HH:MM AM/PM only - military time not supported
				    **************************************/
				    if(current_element.time != null){
				        var sRawTime = current_element.value;
				        var bIsValid = false;
				        var sReason = "";
				        
					    if(!isWhitespace(sRawTime)){
					        sRawTime = sRawTime.replace(/\s/g,'').toUpperCase();
					                                 
                            var aTime = sRawTime.split(":");
                            
                            if(aTime && aTime.length == 2)
                            {                                
                                var iHr = parseInt(aTime[0],10);
                                
                                // See if sHr is a number - note: the ,10 in the parseint gets around
                                // a bug in parseInt that causes 09 to be parsed to 0 instead of 9.
                                if(!isNaN(iHr))
                                {
                                    if((iHr < 13) && (iHr > 0))
                                    {
                                       var idx = aTime[1].search(/s*(AM|PM)/);
                                       
                                       if(idx > 1)
                                       {
                                        var iMi = parseInt(aTime[1].substring(0,2));
                                        
                                        if(!isNaN(iMi))
                                        {
                                         if((iMi < 60) && (iMi > -1))
                                         {
                                            bIsValid = true;
                                            // check for unique

                                              if ((current_element.unique != null) && clientMgr)
                                              {
                                                var xNode;
				                                var xRow;
				               							                
				                                var boundPair = clientMgr.bindMgr.getBoundPair(clientMgr.bindMgr.boundDataEls, current_element, 0);
				                
                                                if(boundPair){
                                                    xNode = boundPair[1];
                                                    xRow =  xNode.parentNode;

                                                    if(!xRow.getAttribute("changed"))
                                                        continue;
                                                }
				                
				                                if(xRow){
				                                    var xRowCand;
				                                    var sTxt;
				                
				                                    for(var z = 1, cLen = xRow.parentNode.childNodes.length; z < cLen; z++){
				                                        xRowCand = xRow.parentNode.childNodes[z];
				                        
				                                        if(xRowCand !== xRow){
				                                            sTxt = get_element_text_by_tag_name(xRowCand,xNode.nodeName);

				                                            if(sTxt && (sRawTime == sTxt.replace(/\s/g,'').toUpperCase())){
				                                                error_msg += header + " time already exists - must be unique" + delim ;
						                                        error_array[j] = current_element;
				                                                break;
				                                            }
				                                        }
				                                    } // for 
				                                } xRow
                                              } // unique check
                                         } // minutes valid
                                         else
                                            sReason = "minute must be between 0 and 59"
                                        } // minute is number
                                        else
                                            sReason = "hour is not a number"
                                       } // has AM/PM
                                       else
                                            sReason = "AM/PM designation missing"
                                    } // hour valid
                                    else
                                        sReason = "hour must be between 1 and 12"
                                }  // hour is number
                                else
                                    sReason = "hour is not a number"
                            } // has colon
                            else
                                sReason = "colon missing";
                            
                            if(!bIsValid)
                            {
                                error_msg += (header + " is not a valid time " + " - " + sReason + delim);
							    error_array[j] = current_element;
                            }
					    } // whitespace
				    } // if time
				    
    				
				    /*****************************************************
				    zipPlus4 takes in zip and zip ext as one
				    *****************************************************/
				    if( (current_element.zip_plus4 != null) && (!isWhitespace(current_element.value)) ){
					    var zip_code = stripCharsInBag(current_element.value,"- ");
    					
					    //--- has zip code and ext
					    if(zip_code.length == 9){
						    var zip				= zip_code.substr(0,5);
						    var ext				= zip_code.substr(5,4);
						    var is_valid_zip	= true;
    						
						    if(!isZIPCode(zip,true)){
							    error_msg		+= header + " is not a valid zip code plus extension" + delim;
							    error_array[j]	= current_element;
							    is_valid_zip	= false;
						    }
    						
						    if(is_valid_zip){
							    if( (ext.length != 4) || (!isInteger(ext)) ){
								    error_msg		+= header + " is not a valid zip code plus extension" + delim;
								    error_array[j]	= current_element;
							    }
							    else{
							        current_element.value = zip_code;
							        this.clientMgr.bindMgr.processChange(current_element);
							    }
						    }
					    }
					    else{
						    //--- just has zip
						    if(zip_code.length == 5){
							    if(!isZIPCode(zip_code,true)){
								    error_msg		+= header + " is not a valid zip code plus extension" + delim;
								    error_array[j] = current_element;
							    }
							    else{
								    current_element.value = zip_code;
							    }
						    }
						    else{
							    error_msg		+= header + " is not a valid zip code plus extension" + delim;
							    error_array[j] = current_element;
						    }
					    }
    					
				    }//end if(current_element.zipPlus4 != null)
    				    				
				    /*****************************************************
				    used to check that atleast one element on the form has been filled
				    ie. used in cases where the form needs at least element to be filled for a proper submit
				    expando tag [need_flag] --- no value - like 'required' flag
				    ******************************************************/
				    if(current_element.need_flag != null){
					    field_counter++;
					    if(!isWhitespace(current_element.value)){
						    has_atleast_one_field = true;
					    }
				    }
    				
				    if(current_element.validate_condition)
				    {
				        var x = Function("me",current_element.validate_condition)(current_element)
				        if(x)
				        {
				            error_msg += header + x + delim
				            error_array[j] = current_element   
				        }
				    }
			    }//if (!check_hidden (current_element))
		    }//for(var j = 0;j < current_form.elements.length;j++)
	    }//for(var i = 0;i < window.document.forms.length;i++)
    	
	    if(field_counter > 0){
		    if(!has_atleast_one_field)
			    error_msg += "At least one form field MUST BE FILLED before submitting this form" + delim;
	    }
    		
	    if(error_msg == ""){
    	
		    //--- strip illegal characters from textareas if form is valid
		    //--- don't want user to see characters getting stripped
		    strip_textareas();
    		
    		// CHECK THIS CAREFULLY - DO WE REALLY NEED TO DO THIS?
		    //--- set element hidden by wrappers back to default or null if there are no errors
		    for(var j = 0, eLen = current_form.elements.length;j < eLen;j++){
    		
			    var current_element = current_form.elements[j];
    			
			    //No need to validate elements that are not shown/hidden to the user via wrappers
			    if(check_hidden(current_element)){
    			
					    if (current_element.fe_dat_default_value != null && current_element.fe_dat_default_value != undefined){
						    current_element.value = current_element.fe_dat_default_value;
					    }
					    else{
						    //current_element.value = '';
					    }
    				
				    continue; // huh?
			    }
		    }
	    }
	    return error_msg;
    }//function cti_validate

    //takes a list of DOM element references and turns them bright yellow
    //usage - cti_validate
    function highlight_all_errors(error_array){
    	
    	if(!error_array)
    	    return;
    	
	    for(var i=0, eLen = error_array.length;i < eLen; i++){
		    if(error_array[i] != undefined){
			    parse_multi_fields(error_array[i]);
			    //parse_multi_fields(error_array[i].id);
		    }
	    }
    }

    //desc  - determines whether an element has been hidden via css
    //usage - cti_validate, init_gen_form
    function check_hidden(element){ 
	    for(var n = element; n != null && n != document.forms[0]; n = n.parentElement){
		    if(n.currentStyle != null && n.currentStyle != undefined ) {
			    if(n.currentStyle.display == 'none') {
				    if (n.fe_dat_default_value != null && n.fe_dat_default_value != undefined){
					    n.value = n.fe_dat_default_value;
				    }
				    return true;
			    }
		    }
	    }
	    return false;
    }

    //desc  - @@@@@
    //usage - cti_validate, not used anymore (commented out)
    function fix_year(d){
	    var d_arr = d.split("/");
    	
	    if(d_arr.length == 2){
		    var year = (new Date()).getYear();
		    d += "/" + year;
	    }
	    else{
		    if(d_arr.length == 3){
			    if(d_arr[2].length == 2){
				    d_arr[2] = "20" + d_arr[2];
				    d = d_arr[0] + "/" + d_arr[1] + "/" + d_arr[2];
			    }
		    }	
	    }
	    return d;
    }
    
    //***********************************************************************************
    //desc - The following functions:
    //          Used by expandos to define illegal chars and their replacements
    //usage - cti_validate
    //***********************************************************************************
    function strip_textareas(){
	    var error_msg = "";
    	
	    for(var i = 0;i < window.document.forms.length;i++){

		    var current_form = window.document.forms[i];
    		
		    for(var j = 0;j < current_form.elements.length;j++){
			    var e = current_form.elements[j];
    			
			    if(e.filter_out != null && e.replace_with != null){
    			
				    var delimiter = new RegExp(e.filter_out,"gi");		
    				
				    e.value = (e.value).replace(delimiter,e.replace_with);
			    }
		    }
	    }
    }
    
    //usage - parseDate
    function strip_leading_zero(val){
	    if(val.indexOf('0') == 0){
		    val = stripCharsInBag(val,"0");
	    }
	    return val;
    }
    
    //***********************************************************************************
    //desc - The following functions:
    //          are keyfilters, which call filterKeys
    //usage - subtypes, for key validation
    //***********************************************************************************
    function not_currency_key(event){
        return !filterKeys(event || window.event,/[\d\$\,\.]/);
    }

    function not_integer_key(event){
        return !filterKeys(event || window.event,/\d/);
    }

    //
    function not_phone_key(event){
        return !filterKeys(event || window.event,/[\d\0\-\,\(\)]/);
    }

    //
    function not_ssn_key(event){
        return !filterKeys(event || window.event,/[\d-]/);
    }

    //
    function not_zip_plus4_key(event){
        return !filterKeys(event || window.event,/[\d\-]/);
    }

    //desc  - date validation - returns an error message
    //          a return value of '' means the date is OK
    //usage - cti_validate
    function parse_date(d, name,index){
        var fMgr = window.parent.framesetMgr
        if(!fMgr) fMgr = new ctiFrameset()
	    var error_msg = "";
	    try{
		    var d_arr = d.split("/");
		    if(!isWhitespace(d)){
			    if(d_arr.length != 3){
				    error_msg = "["+name+"] is not a valid date" + fMgr.DELIMITER;
				    //window.error_array[index] = d
			    }
			    else{
				    var month	= d_arr[0];
				    var day		= d_arr[1];
				    var year	= d_arr[2];
				    month		= strip_leading_zero(month);
				    day			= strip_leading_zero(day);
    				
				    if(!isDate(year,month,day)){
					    error_msg += "["+name+"] is not a valid date|";
				    }
			    }
		    }
	    }
	    catch(error){
		    error_msg = "["+name+"] is not a valid date" + fMgr.DELIMITER;
	    }	
	    return error_msg;
    }	

    //desc  - date keyfilter
    function not_date_keys(event){
        return !filterKeys(event || window.event,/[\d\/]/);
    }

    //desc  - highlights fields based on their attributes
    //usage - highlight errors
    function parse_multi_fields(element){
    	
	    if((element.length != null) && (element.length!= undefined) && (element.type != "select-one")){
		    for(var i = 0, eLen = element.length;i < eLen;i++){
			    if(!element[i].readonly && !element[i].disabled){
				    element[i].style.backgroundColor = 'yellow';
			    }
		    }
	    }
	    else{
		    if(!element.readonly && !element.disabled)
			    element.style.backgroundColor = 'yellow';
	    }
    }
//**************************************************
//END - VALIDATION ROUTINES
//**************************************************


//**************************************************
//BEGIN - FORMATTING ROUTINES
//**************************************************
    
    //desc  - not strictly needed - any object gets typecast as true unless it is null, undefined, 0, or false anyway - 
    //          if you know it's not an integer or boolean, just use if(object) instead of if(is_form_element(object)
    //usage - cti_validate
    function is_form_element(field){
	    if((field != null) && (field != undefined)){
		    return true;
	    }
	    else{
		    return false;
	    }
    }
    
    //desc - resizes textareas rows depending on character count algorithm
    //usage - subtypes
    function adjust_resize(obj){

	    var val = obj.value;
	    var needed_rows = val.length / obj.cols;
	    var orig_cols = obj.cols;
	    var orig_rows = obj.rows;
	    var e = (event || window.event)
	    obj.rows = parseInt(needed_rows) + (e.type=="onkeydown" ? 2 : 1);
    	
	    //--- try to keep user from pasting something too large in field
	    if(val.length > obj.textarea_max){
		    alert(obj.display_name +" can not be greater than " 
			    + obj.textarea_max + " characters");
		    obj.focus();
		    if(obj.orig_val)
			    obj.value = obj.orig_val;
		    else
			    obj.value = "";
    		
		    obj.cols = orig_cols;
		    obj.rows = orig_rows;
	    }
	    else{
		    for(var i = 0;i <= val.length;i++){
			    if(val.charAt(i) == "\n")
				    obj.rows = obj.rows + 1;
		    }
	    }
	    if(e && (e.which || e.keyCode) == 13) obj.rows += 1
	    var rs = obj.rows
	    var m = obj.getAttribute("max_rows")
	    if(m = parseInt(m))
	        obj.rows = (rs < m ? rs : m)
	    var min = obj.getAttribute("min_rows")
	    if(min = parseInt(min))
	        obj.rows = (rs > min ? rs : min)
    	    
    }

    //desc - calls adjust_resize on all textareas
    //usage - init_gen_form
    function resizeTextAreas()
    {
        var textareas = document.getElementsByTagName('textarea')
        for(var i = 0, nt = textareas.length; i < nt; i++)
            if(textareas[i].value != '')
                adjust_resize(textareas[i])
    }
    
    //desc  - obsolete
    //usage - not used
    //function resize_onload(){
	  //  var textareas = document.body.getElementsByTagName("textarea");
	    //var val;
	    //var needed_rows;
	    //var obj;
    	
	    //if(textareas != null){
		  //  for(var i = 0;i < textareas.length;i++){
			//    obj = textareas[i];
			  //  val = obj.value;
			    //needed_rows = val.length / obj.cols;
    				
			   // obj.rows = parseInt(needed_rows) + 2;
    			
			   // for(var j = 0;j < val.length;j++){
				 //   if(val.charAt(j) == "\n")
				//	    obj.rows = obj.rows + 1;
			   // }
    	
			   // obj.orig_val = obj.value;
		    //}
	    //}
    //}

    //usage - not used
    //function get_checkbox_value(cb){
	  //  return (cb.checked ? 'Y' : 'N');
    //}

    //desc  - used for radio_smart
    //      - determines the skip logic when it is dependent on an answer other than the current question's
    //usage - radio_smarts
    function determine_anchor(ctrl, choices, default_anc)
    {
        var debug = false;
        
        if(debug) alert('question:'+ctrl+'\nchoice list:'+choices+'\ndefault:'+default_anc)
        
            var ans = $root(ctrl)
            
        if(debug) alert('answer:'+ans)
        
            if(ans && ans != '')
            {
                var selectedIdx = choices.indexOf(ans+'=')
                var endIdx = choices.indexOf('|',selectedIdx)
                anschoices = endIdx > 0 ? choices.substring(selectedIdx, endIdx) : choices.substring(selectedIdx)
                
                if(debug) alert('selectedIdx:'+selectedIdx+'\nchoices:'+anschoices)
                if(debug) alert('selectedIdx:'+selectedIdx+'\nendIdx:'+endIdx)
                
                    //see if there is any additional skip logic encoded in the answer
                    selectedIdx = anschoices.indexOf('#')+1
                    if(selectedIdx > 0)
                    {
                        anschoices = anschoices.substring(selectedIdx)
                        if(debug) alert('choices for answer:'+anschoices)
                                    skiplog = anschoices.split("#")
                                    if(skiplog.length > 0)
                                    {
                                        if(skiplog[0] == 'TEXT')
                                            skiplog.splice(0,2)
                        if(debug) alert('skip logic:' + skiplog.join("#"))
                                        var anc = skiplog.shift();
                                        if(anc && anc != '')
                                        {
                        if(debug) alert('anchor found:'+anc)
                                            if(skiplog.length < 1) return anc;
                                            else
                                                for(var i = 0; i < skiplog.length; i+=2)
                                                    if($root(skiplog[i]) == skiplog[i+1]) 
                                                        return anc
                     }
                }
            }
        }
        return default_anc
    }//determine_anchor


    //usage - radio smarts
    function clear_radio_smart(div)
    {
        for(var i in div.childNodes)
        {
            q = div.childNodes[i]
            if(q.checked) q.checked = false;
        }
    }
    
    // usage - removes scroll bar from popup content dive before printing
    function print_popm_content()
    {
	    var d = document.getElementById('popm_content');
	    d.className = "popm_content_print";
	    window.print();
	    d.className = "popm_content";
    }

    //***********************************************************************************
    //desc  - shorthand map highlighting functions
    //***********************************************************************************

    //usage - left frame, to highlight maps on hover
    function maphighlight()
    {
	    event.srcElement.className = 'lf_map_hover'
    }

    //usage - left frame, to restore map highlighting
    function mapunhighlight()
    {
	    event.srcElement.className = 'lf_map'
    }
    
    //desc - toggles highlight of map or tree items
    //usage - left frame for map items on hover
    //      - right frame for tree items on hover
    function toggleHighlight(el, classPrefix){
        var className = el.className;
        var hSuffix   = "_hover";
               
        if(className.indexOf(hSuffix) == -1)
            el.className = classPrefix + hSuffix;
        else
            el.className = classPrefix;
    } // toggleHighlight
    
    //desc  - toggles display of child branches of provided li tree branch
    //usage - right frame for tree branches
    function toggleTreeDisplay(el){  
    //alert('running toggle tree');
        var ul = getFirstChildByNodeName(el.parentNode,"UL");
                
        if(ul && ul.style){
            var oImg = getFirstChildByNodeName(el,"img");
        
            if(ul.style.display == 'none')
                ul.style.display = ''
            else
                ul.style.display = 'none';
                
            // set appropriate icon
            if(oImg){ 
                var fn = (ul.style.display == 'none') ? '../Images/plusbox.gif' : '../Images/minusbox.gif'
            
                //alert('image path is ' + fn);
                oImg.setAttribute("src",(ul.style.display == 'none') ? '../Images/plusbox.gif' : '../Images/minusbox.gif');
                }           
        }
        //else if(!ul)
          //      alert('no child ul found');
            // else
              //  alert('child ul found without a style');
    } // toggleTreeDisplay

    //desc  - display toggle functions for left frame menu
    //usage - left frame, for sections
    function togglemapdisplay(elementname)
    {
        var debugKey = (window.event && window.event.ctrlKey && window.event.shiftKey)
	    var element = document.getElementById(elementname)
	    var ind = document.getElementById('ind_' + elementname)	//the '+' or '-' next to the map name
    	
	    if(element.style.display != 'none')
	    {
		    //update the element display
		    element.style.display = 'none'			
		    //update the session variables
		    var result = syncPost('cti_change_session.aspx', 'key=' + elementname + '&value=N')		
		    if(debugKey) alert(result)
		    //update the expansion indicator
		    ind.innerText = '+'
	    }
	    else
	    {
		    element.style.display = 'block'
		    var result = syncPost('cti_change_session.aspx', 'key=' + elementname + '&value=Y')
		    if(debugKey) alert(result)		
		    ind.innerText = '- '
	    }
    } //togglemapdisplay
//**************************************************
//END - FORMATTING ROUTINES
//**************************************************

//**************************************************
//BEGIN - SYNCPOST ROUTINES
//**************************************************
    
    //desc  - AJAX POST operation. Location is website location, 
    //      - body should be in uri-encodedid=value&id=value... form
    //usage - many many things - 
    //          save, retrieve, verify, client-side session requests, metadata get
    //          domains, drilldowns, rss feeds, mini-debugs,
    //          custom query, search form, navigation, logon,
    //          datadriven fields
    //JAE
    function syncPost(location,body,targetobj,returnXML)
    {

        // 09/04 - noticed that if(fMgr.HTTPS == 'on') was commented out and
        // the check against the location href was added
 
    /*
        var loadingInd = null
    
        if(loadingInd) {
           // loadingInd.style.display = 'block';
        }
        else if(document.body)
        {
            loadingInd = ce('div')
            ac(ct('Loading, please wait...'),loadingInd)
            ac(loadingInd,document.body)
            loadingInd.className = 'syncPost_loading_ind'	    
            loadingInd.style.position = 'absolute'
            loadingInd.style.top = '0px'; //String(Number(document.body.scrollTop || 0) + 250) + 'px'
            loadingInd.style.display = 'none';
        }
    */
        
	    if(window.location.href.indexOf('https') == 0)      //always correct
		    location = location.replace(/http\:/i, "https:")

	    var request
	    if(window.XMLHttpRequest)

	        request = new XMLHttpRequest();
	    else
            request = new ActiveXObject("Microsoft.XMLHTTP")
    	
    	
	    var cType = 'application/x-www-form-urlencoded';
	    //alert('added loading ind with ' + (loadingInd ? loadingInd.className:'???'))
	    //else alert('requesting. please wait a moment.')
        	
	    if(returnXML)
		    cType = 'text/xml';
    	
    /*	
        request.onReadyStateChange=function()
        { 
	        if(loadingInd) {
	            if(this.readyState!=4) 
	                loadingInd.style.display='block';
	         }
	    }
	*/
	    
	    request.open("POST", location, false);
	    request.setRequestHeader('CONTENT-TYPE', cType)
	    if(body) 
	    {
	        request.setRequestHeader("CONTENT-LENGTH", body.length)
    	    request.send(body);
        }
        else
        {
            request.setRequestHeader("CONTENT-LENGTH", 0)
            request.send('');
        }
               
        //if(window.document.body) window.document.body.style.cursor = ''
	    if(gv('debugBox') == 'Y') cti_alert(request.responseText,'syncPost response for '+location+body);
	    if(returnXML && /text\/xml/.test(request.getResponseHeader("CONTENT-TYPE")))
		    return request.responseXML;
	    else{
		    return request.responseText;
        }
    } //syncPost

    //initialize syncpost requests empty
    requests = []
    
    //desc  - AJAX POST operation. 
    //usage - only heartbeat, so far.
    //      --- will be used more
    //JAE   09/10/2007
    //AJAX POST operation. 
    //parameters:
    //  location:       the url to POST to
    //  body:           the xml document or uri-encoded data to send
    //  returnfunc:     function to execute on successful completion of a request.
    //                  should be of the form function(event,request object)
    function asyncPost(name,location,body,xmlBody,returnfunc){
	    if(window.location.href.indexOf('https') == 0)      //always correct
		    location = location.replace(/http\:/i, "https:")
    	
	    var request
	    if(requests[name])
	    {
	        requests[name].abort()
	    }
	    else
	    { 
	        if(window.XMLHttpRequest)
	            requests[name] = new XMLHttpRequest();
	        else
	            requests[name] = new ActiveXObject("Microsoft.XMLHTTP")
	    }
	    request = requests[name]
    	
	    var cType = xmlBody? 'text/xml' : 'application/x-www-form-urlencoded';
	    if(returnfunc) request.onreadystatechange = function(event)	{
    	    //if(gv('debugBox') == 'Y') cti_alert(request.responseText,'syncPost response for '+location+body);
    	    
            //cti_alert('this is\n' + writeObj(this));
            
            /*
            alert(name)
            alert((this === requests[name]) || ((typeof this) +'!=='+(typeof requests[name])))
            */
            
            returnfunc((event || window.event),this);
	    }
	    request.open("POST", location, true);
	    request.setRequestHeader('CONTENT-TYPE', cType)
	    request.setRequestHeader('CONTENT-LENGTH', body? body.length : 0)
	    request.send(body ? body : '')

	    requests[name] = request
	    return request
    } //asyncPost

//**************************************************
//END - SYNCPOST ROUTINES
//**************************************************


//**************************************************
//BEGIN - HEARTBEAT
//**************************************************
    //desc  - monitors connectivity browser session connectivity to the web server
    //      - checks the server periodically (every minute) for session timeout
    //      - display little green session_ok.jpg image at the far right of the action_frame
    //      - if it notices that the session has timed out then it displays the close page with an appropriate error message
    //usage - every form, to verify connection
    function heartbeat(e,r){
        if(r.readyState == 4)
        {
            if(r.responseText == '' || r.status != 200)
                pge_display_cti_close_page2('Your session has either timed out, or, your internet connection was interrupted. Please close your browser and log back in.')
            else
            {
                var x = ge('timeout_warning_div') || ce('div')
                if(!x.parentNode) 
                {
                    ac(x,document.body)
                    x.style.position = 'absolute'
                    x.id = 'timeout_warning_div'
                    if(!x.firstChild)
                    {
                        i = ce('img')
                        i.src = '../Images/session_ok.jpg'
                        ac(i,x)
                    }
                    x.style.width = '8px'
                    x.style.right = '0px'
                    x.style.border = '1px outset'
                    x.style.right = x.style.top = '0px'
                }    
                x.firstChild.alt = 'Your session is active as of ' + (new Date()).toString()
                window.setTimeout(function(){asyncPost('heartbeat','cti_retrieve_session.aspx','shortkey=SessionUserFk',false,heartbeat)},60000)
            }
        }
    }

    //attaches the heartbeat to the document - moved into cti_main_action_frame.aspx.vb
    //ctiBrowser().attachEvent("onload",function(){if(document.body.className == 'af') asyncPost('heartbeat','cti_retrieve_session.aspx','shortkey=SessionUserFk',false,heartbeat)})

//**************************************************
//END - HEARTBEAT ROUTINES
//**************************************************


//**************************************************
//BEGIN - CALENDAR ROUTINES
// Notes:
//  - 
//**************************************************

    //desc  - renders all calendar types
    //usage - calendar html types (not used) 
    function fill_calendars()
    {
        var cals = document.body.getElementsByTagName("div")
        var oCal
        if(cals != null)
        {
            for(var i = 0; i < cals.length; i++)
            {
                oCal = cals[i];
                if(oCal.getAttribute('calendar'))
                    renderDOMEventCalendar(oCal,null,{},oCal.getAttribute('day_names'))
            }
        }
    }

    //renders a calendar using DOM methods, rather than raw html
    //uses cti_calendar.aspx to get calendar events, if you want
    //usage - calendar html types (not used)
    function renderDOMEventCalendar(root,target,date,day_names)
    {
        while(root.hasChildNodes()) root.removeChild(root.firstChild);
        var html = '';
        var d = new Date();
        
	    if(date.day == null) date.day = d.getDate(); else d.setDate(date.day);
        
        if(date.year == null) date.year = d.getFullYear();
       
	    if(date.month == null)
	        date.month = d.getMonth();
	    else 
	        if(date.month == 12)
	        {
		    date.month = 0; date.year = date.year + 1;
	        }
	        else
	        	if(date.month < 0)
	            {
		        date.month = 11; date.year = date.year - 1;
	            }
	    
	    d.setMonth(date.month);
	    
	    d.setYear(date.year);
    	
	    var calendarTable,tbody,tr,td,a
    	
	    calendarTable = ce('table')
	    calendarTable.className = 'event_calendar_scroll'
	    calendarTable.style.width = '100%'
    	
	    tbody = ce('tbody');
    	
    	
	    tr = ce('tr')
    	
	    function appendChanger(tr,inner,monthdirection,yeardirection) 
	    {
	        var td = ce('td')
	        td.style.width='30%'
	        td.style.textAlign='center'
	        a = ce('a')
	        a.href = 'javascript:;'
	        a.onclick = function(){ 
        	    clientMgr.confirmExit = false;
	            renderDOMEventCalendar(root,target,{'month':Number(date.month)+monthdirection,
	                'day':date.day,'year':Number(date.year)+yeardirection},day_names) 
	            }
	        ac(ct(inner),a)
	        ac(a,td)
	        ac(td,tr)
	    }    
    	
	    appendChanger(tr,'<<',0,-1)
	    td = ce('td')
	    td.style.width='40%'
	    td.style.textAlign='center'
	    ac(ct(date.year),td)
	    ac(td,tr)
	    appendChanger(tr,'>>',0,1)
    	
	    ac(tr,tbody)
	    tr = ce('tr')
    	
	    appendChanger(tr,'<<',-1,0)
	    td = ce('td')
	    td.style.width = '40%'
	    td.style.textAlign='center'
	    ac(ct(monthName(date.month)),td)
	    ac(td,tr)
	    appendChanger(tr,'>>',1,0)
    	
	    ac(tr,tbody)
	    ac(tbody,calendarTable);
	    ac(calendarTable,root)
        
	    calendarTable = ce('table')
	    calendarTable.className = 'event_calendar_days'
	    calendarTable.style.width = '100%'
	    tbody = ce('tbody')
	    tr = ce('tr')
        var days
	    if(!day_names || day_names == '') days=['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']
            else days = day_names.split(',')
        for(var i in days)
        {
            td = ce('th');
            ac(ct(days[i]),td);
            ac(td,tr);
        }
        ac(tr,tbody)
        
        var wkcounter = 0;
	    var dycounter = 1;
    	
	    d.setDate(1)
	    var mostartson = d.getDay()
	    var counting = false
	    var today = new Date();
	    
	    var monthDays = calcDaysInMonth(date.month, date.year);
    	
	    var records_by_day = browser.xPathSingle(
	                    syncPost('cti_sp_retrieve.aspx?dest=calendar_records&year='+date.year+'&month='+String(Number(date.month)+1),'<form />',null,true),'//calendar_records_container')
    	
	    while(dycounter <= monthDays)
	    {
		    tr = ce('tr')
		    for(wkcounter = 0; wkcounter < 7; wkcounter++)
		    {
			    td = ce('td')
			    if(wkcounter == mostartson) counting = true;
			    if(counting)
			    {
				    if(dycounter <= monthDays)
				    {
					    if(date.month == today.getMonth() && dycounter == today.getDate() && date.year == today.getFullYear())
						    //td.style.border='2px inset'
						    td.className = 'date_today'
				        td.onmouseover=Function('this.oldClassName = this.className; this.className = "date_hover"')
				        td.onmouseout=Function('this.className = this.oldClassName')
				        td['day'] = dycounter
				        td.onclick=function(){
				            open_popup_window('day_events','cti_nfg.aspx?form_code=calendar_day&date='+String(Number(date.month)+1)+'/'+String(this['day']) + '/' + String(date.year))
				        }
				        ac(ct(dycounter),td)
				        var recNode = browser.xPathSingle(records_by_day,'./calendar_records/date[value() = "'+String(Number(date.month)+1)+'/'+dycounter+'/'+date.year+'"]')
				        if(recNode) recNode = browser.xPathSingle(recNode,'..//records/text()')
				        if(recNode)
				        {
    				        ac(ce('br'),td)
    				        ac(ct(recNode.nodeValue+' event'+(recNode.nodeValue>1?'s':'')),td)
    				        td.className = td.className || 'has_records'
				        }
				    }
				    dycounter++;
			    }
			    ac(td,tr)
		    }
		    ac(tr,tbody)
	    }
	    ac(tbody,calendarTable)
	    ac(calendarTable,root)
	    //root.scrollIntoView();
    }

    //desc  - renders a div containing a calendar 
    //          parameters:
    //                event: the event calling this function
    //               returnelement: the field to populate with data
    //               x,y: coordinates for the div
    //               datestring: the date to start at
    //usage - date fields, for calendar interaction
    function renderCalendarDiv(event,returnelement,x,y,datestring)
    {
        if(!event) event = window.event
	    if(returnelement == null) returnelement = event.target || event.srcElement;
	    if(x == null) x = 0//event.clientX + document.body.scrollLeft
	    if(y == null) y = event.clientY + document.body.scrollTop
    	
	    if(datestring == null) datestring = (event.target || event.srcElement).value 
    	
	    var date_comps = datestring.split('/')
	    var month = null
	    var day = null
	    var year = null
    	
	    if(date_comps.length == 3)
	    {
		    month = date_comps[0]-1
		    day = date_comps[1]
		    year = date_comps[2]
	    }
    	
	    var targetDiv = makeDraggableDiv()
	    if(document.getElementById('calendarDiv'))		//if there is already a calendar, remove it
	    {
		    document.body.removeChild(document.getElementById('calendarDiv'))
	    }

	    targetDiv.id = 'calendarDiv'
	    targetDiv.className = 'popup_calendar'			//no need to put any formatting in the javascript
	    targetDiv.style.left = x;
	    targetDiv.style.top = y;
	    targetDiv.clearTimerID = setTimeout("if(ge('calendarDiv')) document.body.removeChild(ge('calendarDiv'))", 5000)
	    targetDiv.onmouseover = targetDiv.onmouseenter = function(event){clearTimeout(targetDiv.clearTimerID) }
	    targetDiv.ondblclick = function(event){ window.setTimeout(function(){document.body.removeChild(targetDiv)},10) }
 	    targetDiv.onclick = function(event){ 
 	        if(!event) 
 	             event = window.event; 
 	        if((event.srcElement||event.target).className == 'date_hover') 
 	            window.setTimeout(function(){document.body.removeChild(targetDiv)},10) 
 	        else try{ event.stopPropagation() } catch(x) { event.cancelBubble = true; }
 	        }
     	    
 	    targetDiv.oncontextmenu = function(event){ return pickup(this) }
 	    
 	    //add the calendar to the document! very important!   
	    ac(targetDiv,document.body)
	    document.body.onclick = function(event)
	    { 
	        if(targetDiv && targetDiv.parentNode) 
	            window.setTimeout(function(){targetDiv.parentNode.removeChild(targetDiv)},10)
	    } 
	    
 	    renderDOMCalendar(targetDiv,returnelement,{'month':month,'day':day,'year':year}) 	    
 	    try
 	    { 
 	        event.cancelBubble = true; 
 	    } 
 	    catch(x)
 	    { 
 	        try
 	        { 
 	            event.stopPropagation(); 
 	        } 
 	        catch(x)
 	        {}
 	    }
    }

    //desc  - dom-based calendar rendering
    //usage - renderCalendarDiv - this actually renders the calendar
    function renderDOMCalendar(root,target,date)
    {
        while(root.hasChildNodes()) root.removeChild(root.firstChild);
        var html = '';
        
        var d = new Date();
	    //if(date.month == null) date.month = d.getMonth(); else d.setMonth(date.month)
	    //if(date.day == null) date.day = d.getDate(); else d.setDate(date.day)
	    //if(date.year == null) date.year = d.getFullYear(); else d.setYear(date.year)
    	
	    //if(date.month == 12)
	    //{
		//    date.month = 0; date.year = date.year + 1;
	    //}
	    //if(date.month < 0)
	    //{
		//    date.month = 11; date.year = date.year - 1;
		    
	    //}
	    
	    if(date.day == null) date.day = d.getDate(); else d.setDate(date.day);
        
        if(date.year == null) date.year = d.getFullYear();
       
	    if(date.month == null)
	        date.month = d.getMonth();
	    else 
	        if(date.month == 12)
	        {
		    date.month = 0; date.year = date.year + 1;
	        }
	        else
	        	if(date.month < 0)
	            {
		        date.month = 11; date.year = date.year - 1;
	            }
	    
	    d.setMonth(date.month);
	    
	    d.setYear(date.year);
    	
	    var calendarTable,tbody,tr,td,a
        calendarTable = ce('table')
	    applyStyle(calendarTable,{
	        'width':'100%',
	        'right':'0px',
	        'left':'0px',
	        'text-align':'center'})
	    calendarTable.style.width = '100%'
    	
	    tbody = ce('tbody');
    	
	    tr = ce('tr')
    	
	    function appendChanger(tr,inner,monthdirection,yeardirection) 
	    {
	        var td = ce('td')
	        td.style.width='30%'
	        td.style.textAlign='center'
	        a = ce('a')
	        a.href = 'javascript:;'
	        a.onclick = function(){ 
        	    clientMgr.confirmExit = false;
        	            	    
	            renderDOMCalendar(root,target,{'month':Number(date.month)+monthdirection,
	                'day':date.day,'year':Number(date.year)+yeardirection}) 
	            }
	        ac(ct(inner),a)
	        ac(a,td)
	        ac(td,tr)
	    }    
    	
	    appendChanger(tr,'<<',0,-1)
	    td = ce('td')
	    td.style.width='40%'
	    td.style.textAlign='center'
	    ac(ct(date.year),td)
	    ac(td,tr)
	    appendChanger(tr,'>>',0,1)
    	
	    ac(tr,tbody)
	    tr = ce('tr')
    	
	    appendChanger(tr,'<<',-1,0)
	    td = ce('td')
	    td.style.width = '40%'
	    td.style.textAlign='center'
	    ac(ct(monthName(date.month)),td)
	    ac(td,tr)
	    appendChanger(tr,'>>',1,0)
    	
	    ac(tr,tbody)
	    ac(tbody,calendarTable);
	    ac(calendarTable,root)

	    calendarTable = ce('table')
	    calendarTable.style.width = '100%'
	    tbody = ce('tbody')
	    tr = ce('tr')
	    days = ['Su','Mo','Tu','We','Th','Fr','Sa']
        for(var i in days)
        {
            td = ce('th');
            ac(ct(days[i]),td);
            ac(td,tr);
        }
        ac(tr,tbody)
        
        var wkcounter = 0;
	    var dycounter = 1;
    	
	    d.setDate(1)
	    var mostartson = d.getDay()
	    var counting = false
	    var today = new Date()
	    var monthDays = calcDaysInMonth(date.month, date.year);
    	
	    //while(dycounter <= daysInMonth[date.month+1])
	    while(dycounter <= monthDays)
	    {
		    tr = ce('tr')
		    for(wkcounter = 0; wkcounter < 7; wkcounter++)
		    {
			    td = ce('td')
			    if(wkcounter == mostartson) counting = true;
			    if(counting)
			    {
				    //if(dycounter <= daysInMonth[date.month+1])
				    if(dycounter <= monthDays)
				    {
					    if(date.month == today.getMonth() && dycounter == today.getDate() && date.year == today.getFullYear())
						    //td.style.border='2px inset'
						    td.className = 'date_today'
				        td.onmouseover=Function('this.className = "date_hover"')
				        td.onmouseout=Function('this.className = null')
				        td['day'] = dycounter
				        td.onclick=function(){
				            target.value = String(Number(date.month)+1)+'/'+String(this['day']) + '/' + String(date.year);
				            browser.fireEvent(target,'onchange');
				            clientMgr.bindMgr.processChange(target);
				        }
				        ac(ct(dycounter),td)
				    }
				    dycounter++;
			    }
			    ac(td,tr)
		    }
		    ac(tr,tbody)
	    }
	    ac(tbody,calendarTable)
	    ac(calendarTable,root)
    	
    	
	    //root.scrollIntoView();
    } // renderDOMCalendar

    //not used
    //converts month numbers to names. should be a dictionary
    function monthName(month)
    {
	    switch(month)
	    {
		    case 0: return 'January'; break
		    case 1: return 'February'; break
		    case 2: return 'March'; break
		    case 3: return 'April'; break
		    case 4: return 'May'; break
		    case 5: return 'June'; break
		    case 6: return 'July'; break
		    case 7: return 'August'; break
		    case 8: return 'September'; break
		    case 9: return 'October'; break
		    case 10: return 'November'; break
		    case 11: return 'December'; break
	    }
    }

    //generally correct (actually not - 400 year interval IS a leap year)
    //usage - renderdomcalendar
    function days_in_month(month,year)
    {
	    if(month == 1 && year != null) 
	    {
		    if(year % 4 == 0)
		    {
			    if(year % 100 != 0)
				    return 29
			    else if(year % 400 != 0)
				    return 29
		    }
		    else return 28
	    }
	    else return daysInMonth[month];
    	
    }
    
    // calculates number of days in a given month and year - relies on certain date object behavior
    // usage - general, including renderDOMCalendar and renderDOMEventCalendar
    // Note: The Gregorian calendar adds a 29th day to February in all years evenly divisible by 4, 
    // except for centennial years (those ending in '00'), which receive the extra day only if they are 
    // evenly divisible by 400. Thus 1600, 2000 and 2400 are leap years but 1700, 1800, 1900 and 2100 are not.
    function calcDaysInMonth(iMonth, iYear)
    {
        if((iYear != null) && (iMonth != null))
            return 32 - new Date(iYear, iMonth, 32).getDate();
            // When the Date() function is given a day number that is greater than the number of days in the given month & year, 
            // it wraps the date into the next month. getDate() returns the day of the month, starting from the beginning of the 
            // month that the date is in. So, day 32 of March is considered to be day 1 of April.  
            // Subtracting 1 from 32 gives the correct number of days in March, etc...  Leap year handled by the Date object.
        else
            return 0;
    }
    
    
//**************************************************
//END - CALENDAR ROUTINES
//**************************************************

//desc  - ?????
//usage - not used
function get_rownum (el_to_find,tbl_id,ret_neg_one_on_single_row) {
	var tbl = window.document.getElementById(tbl_id);
	
	if (is_form_element(tbl)) {
		var el;
		var i;
		var j;
		var el_coll;
		
		if(arguments.length < 3){
			ret_neg_one_on_single_row = false;
		}
					
		for(i=0;i<tbl.rows.length;i++){

				el_coll = tbl.rows[i].all;
							
				for(j=0;j<el_coll.length;j++){
					el = el_coll[j];
					
					if(el.nodeType == 1) {
										
						//if(el.id == el_to_find.id ){
						if(el_to_find == el){
							if((ret_neg_one_on_single_row) && (tbl.rows.length == 1)) {
								return -1;
							}
							else {
								return i;
							}
						}
					}
				}
		}
	}
	
	return -1;
} // get_rownum

//desc  - ?????
//usage - not used
function align_table_size(tbl_source_id,tbl_target_id){
	var tbl_src = window.document.getElementById(tbl_source_id);

	if (is_form_element(tbl_src)) {
		var tbl_targ = window.document.getElementById(tbl_target_id);
		
		if (is_form_element(tbl_targ)) {
			var cols_src = tbl_src.getElementsByTagName("colgroup")[0].getElementsByTagName("col");
			
			if (is_form_element(cols_src)) {
				var cols_targ = tbl_targ.getElementsByTagName("colgroup")[0].getElementsByTagName("col");
			
				if (is_form_element(cols_targ)) {
					var i;
					var limit = cols_src.length;
					
					if(limit != cols_targ.length){
						limit = 1;
					}
					
					for(i=0;i<limit;i++){
						cols_targ[i].width = cols_src[i].offsetWidth;
					
					}
				}
			}
		
		}
	}
} // align_table_size

//desc  - ?????
//      - should be deprecated - replace with $root
//usage - not used
function get_form_val(el_name, occ){
	if (arguments.length == 1)
		occ = 0;

	var coll_el = document.getElementsByName(el_name);
	
	if ((coll_el.length > 0) && (occ < coll_el.length))
		return coll_el[occ].value;
	else
		return "not found";
}


//**************************************************
//BEGIN - FILL DOMAIN ROUTINES
// Notes:
//  - 
//**************************************************

var DOMdomainCache = []
var domaincachetrace = ''

    //desc  - fills a SELECT element using the specified domain
    //
    //    oSelect: the object to fill
    //    source: the domain to use, in domain_name|p1|p2|p3|value format
    //    unchanged: if true, do NOT fire the onchange event for the select. otherwise, it will
    //    replace: if true, the data for the source of this domain should be replace current cached values
    //
    //usage - domains, chain_selects, datadriven_fields, init_gen_form
    function fill_domain(oSelect,source,unchanged,replace)
    {
        var debugKey = (window.event && window.event.ctrlKey && window.event.shiftKey)
        
       if(!source) source = oSelect.getAttribute("domain");
       
       if(debugKey && !confirm(source)) throw "Error"
            //if(debugKey && !confirm(getRelatedXMLNode(oSelect).xml)) throw "Error"
            
       var params = source.split("|");
       for(var q in params)
       {
        if(params[q].charAt(0) == '#')
            params[q] = $sibling(oSelect, params[q].substring(1))
        if(params[q].charAt(0) == '@')
            params[q] = $root(params[q].substring(1))
        if(debugKey && !confirm(params.join("|"))) throw "Error"
        }
        source = params.join("|")
        
        if(debugKey && !confirm(source)) throw "Error"

                        
        var bindMgr = null;
        
        if(clientMgr && clientMgr.bindMgr)
            bindMgr = clientMgr.bindMgr;
                        
        if(replace)
        {
            delete DOMdomainCache[source];

            if(bindMgr)
                delete bindMgr.dynamicDomains[source];
        }
            
        if(!DOMdomainCache[source])
        {
	        var isle = null;
	        
	        if(!replace)
	            isle = ctiXBCXML(document.getElementById(source))
	            
	        //cross-browser
	        if(!isle && bindMgr) isle = bindMgr.dynamicDomains[source]
	        
	        if(!isle)
            {
                //jae - dynamically acquire domain!!
                //cross-browser
                if(bindMgr && !bindMgr.dynamicDomains[source]) 
                {
                
                    domain_xml = syncPost('cti_domain.aspx?domain='+source+'&preventCache='+Math.floor(Math.random()*10000)
                                          ,null,null,true)
                    if(domain_xml)
                    {
                        if(domain_xml.documentElement.childNodes.length)
                        {
                            blank_node=domain_xml.documentElement.childNodes[0].cloneNode(true);
                            for(var i = 0, cLen = blank_node.childNodes.length; i < cLen; i++)
                                if(first_child(blank_node.childNodes[i]))
                                    blank_node.childNodes[i].removeChild(first_child(blank_node.childNodes[i]))
                            domain_xml.documentElement.insertBefore(blank_node, first_child(domain_xml.documentElement))
                        }
                        bindMgr.dynamicDomains[source] = domain_xml;
                        isle = domain_xml;
                    }
                    else
                        alert('get ' + source + 'failed.')
                }    
                else
                {
                    if(!browser) browser = ctiBrowser();
                    browser.attachEvent("onload", function(){   fill_domain(oSelect,source,unchanged)    })
                }
            }
	        
	        // check again        	
	        if(isle)
	        {
                if(!browser) browser = ctiBrowser();
                oSelect.options.length = 0
                var sDesc;
                var sVal;
                var selectedValue
                var addedZeroField = false;
                var sCurrVal = $sibling(oSelect,oSelect.getAttribute("bindFld"));
                var sDList = "," + sCurrVal + ",";
                var bFirst = true;
        
                var optLen = oSelect.options.length;
                for(var i=optLen; i; i--)
                    oSelect.remove(0);
                    
                //while(oSelect.options.length > 0) oSelect.remove(0);
                
                if(first_child(isle)) 
                    for(var j = 0, cLen = first_child(isle).childNodes.length; j < cLen; j++)
                    {
                        optNode = first_child(isle).childNodes[j];
                        if(optNode.nodeType != 1) continue;  
                    
                        sDesc = browser.xPathSingle(optNode,'./domain_description/text()')
                        sVal = browser.xPathSingle(optNode,'./domain_value/text()')     
                    
                        if(sDesc) sDesc = sDesc.nodeValue; else sDesc = ''
                        if(sVal) sVal = sVal.nodeValue; else sVal = ''
                    
                        sDesc = sDesc.replace(/\&amp;/,'&')
                    
            	        var o=document.createElement('option');
            	        //var o = new Option(sDesc, sVal);
                        o.text=sDesc
                        o.value=sVal
                        
                        try
                        {
                            oSelect.add(o,null); // standards compliant
                        }
                        catch(ex)
                        {
                        oSelect.add(o); // IE only
                        }
                                            
                        if(oSelect.multiple)
                        {                                         
                            if(sDList.indexOf("," + sVal + ",") > -1)
                            {
		                        o.selected = true;
		                    }
                        } 
                        else            	   
	                        if(String(sVal).toUpperCase() == String(sCurrVal).toUpperCase())
		                        selectedValue = sVal;

                    } // for
                    
                if(!oSelect.multiple)
                    oSelect.value = selectedValue;

                if(bindMgr && !unchanged) clientMgr.bindMgr.processChange(oSelect);
                
                DOMdomainCache[source] = oSelect.cloneNode(true);
            }
       }
       else
       {
       
    /*
        oCacheClone = DOMdomainCache[source].cloneNode(true)

        listApply(function(a){oCacheClone.setAttribute(a, oSelect.getAttribute(a))},
                    ['id','bindFld','required','display_name','size'])

        oCacheClone.value = String($sibling(oSelect,oSelect.getAttribute("bindFld"))).toUpperCase()
        spotlightElement(oCacheClone,'yellow',20000)            
        if(clientMgr && clientMgr.bindMgr && clientMgr.bindMgr.boundDataEls)
        {
            var bp = clientMgr.bindMgr.getBoundPair(clientMgr.bindMgr.boundDataEls, oSelect, 0)
            spotlightElement(oCacheClone,'cyan',20000)        
            if(bp) 
            {
                bp[0] = oCacheClone;
                spotlightElement(clientMgr.bindMgr.getBoundPair(clientMgr.bindMgr.boundDataEls, oCacheClone, 0)[0],'lime',20000)
                oSelect.parentNode.replaceChild(oCacheClone,oSelect)    
            }
            else 
            {
                spotlightElement(oSelect,'fuchsia',20000)
                oSelect.parentNode.replaceChild(oCacheClone,oSelect)    
                spotlightElement(oCacheClone,'red',20000)            
            }            
            
        }
    */
       
        oCacheClone = DOMdomainCache[source].cloneNode(true);
                
        // 08/17/09 - take disabled and readonly class name into account
        attribsList = ['domain','name','id','bindFld','required','display_name','size','disabled']
        for(var i in attribsList)
            oCacheClone.setAttribute(attribsList[i], oSelect.getAttribute(attribsList[i]));
            
        oCacheClone.className = oSelect.className;
             
        if(clientMgr && clientMgr.bindMgr)
        {
            var bp = clientMgr.bindMgr.getBoundPair(clientMgr.bindMgr.boundDataEls, oSelect, 0)
            if(bp) bp[0] = oCacheClone;
        }
               
        oCacheClone.cloned = true;    
        oCacheClone.value = String($sibling(oSelect,oSelect.getAttribute("bindFld"))).toUpperCase()
        oSelect.parentNode.replaceChild(oCacheClone,oSelect)
       }
    }

    //desc  - fills all checkbox domains on the form
    //usage - checkbox domains, init_gen_form
    function fill_checkbox_domains()
    {
        var domains = document.body.getElementsByTagName("div")
        var oCheckboxGroup
        var source
        var checkboxtrace = ''
        if(domains != null)
        {
            for(var i = 0; i < domains.length; i++)
            {
                oCheckboxGroup = domains[i];
                if(oCheckboxGroup.getAttribute('checkboxgroup'))
                    fill_checkbox_domain(oCheckboxGroup)
            }
        }
    }

    //desc  - uses fills a checkbox domain. CONSIDER MERGING ALL DOMAIN FILL CODE
    //usage - checkbox domains, init_gen_form
    // Note:  I do not think this is used: there is a reference to oRadioGroup below,
    //        which seems blatantly wrong.
    function fill_checkbox_domain(oCheckboxGroup)
    {
        ge('tbl_'+oCheckboxGroup.getAttribute('bindFld')+'_container').style.display = 'none'
        source = oCheckboxGroup.getAttribute('domain')
        params = source.split("|");
        checkboxtrace = ''    
        
        for(var q in params)
        {
            if(params[q].charAt(0) == '#')
                params[q] = $sibling(oRadioGroup, params[q].substring(1))
            if(params[q].charAt(0) == '@')
                params[q] = $root(params[q].substring(1))
        }
        source = params.join("|")
        
        isle = ctiXBCXML(document.getElementById(source))
	    if(!isle) isle = clientMgr.bindMgr.dynamicDomains[source];
	    
	    var xref = oCheckboxGroup.getAttribute('xref');
	    var xrefDict = []
	    var xrefs = xref.split(',')
	    for(var i in xrefs)
	    {
	        ref = xrefs[i].split(':')
	        xrefDict[ref[0]] = ref[1]
	    }
	    
	    var trigIdx = clientMgr.bindMgr.getBoundTrigIdx(oCheckboxGroup);
	    var bindFld = oCheckboxGroup.getAttribute('bindFld')
        if(isle && first_child(isle))
        {
            var checkboxAction = function(){
                        if(this.checked)
                        {
                            p = []
                            p.push(this.xrefDict['domain_description']+'|'+this.domain_description)
                            p.push(this.xrefDict['domain_value']+'|'+this.domain_val)
                            clientMgr.addRowExternal(this.trigIdx,p);
                        }
                        else
                        {
                            //remove row by value
                            removeVal = this.domain_val
                            xNode = getRelatedXMLNode(this);
                            xRemove = browser.xPathSingle(xNode,'.//'+this.xrefDict['domain_value']+'[text()="'+removeVal+'"]')
                            hRemove = clientMgr.bindMgr.getBoundPair(clientMgr.bindMgr.boundDataEls,xRemove,1)[0]                        
                            clientMgr.deleteRow(hRemove);
                        }
                        ge('tbl_'+box.bindFld+'_container').style.display = 'none'                                
                    }
                    
            var tbl = ce('table'); 
            var tbody = ce('tbody')
            var cols = oCheckboxGroup.getAttribute('cols')
            if(!cols) cols = 1
            else cols = parseInt(cols)
            
            var height = Math.ceil(first_child(isle).childNodes.length/cols)
            for(var i = 0; i < height; i ++)
            {
                var tr = ce('tr')        
                for(var j = 0; j < cols; j++)
                {
                    if(i+j*height < first_child(isle).childNodes.length)
                    {
                        var optionNode = first_child(isle).childNodes[i+j*height];
                        if(optionNode.nodeType == 3) continue;
            	        	        
                        domain_val = browser.xPathSingle(optionNode,'domain_value/text()')
                        domain_desc = browser.xPathSingle(optionNode,'domain_description/text()')
            	        
                        if(domain_val && domain_desc) 
                        {
                            var td = ce('td')
                            var box = ce('input'); box.type = 'checkbox';
                            box.domain_description = domain_desc.nodeValue
                            box.domain_val = domain_val.nodeValue
                            box.onclick = checkboxAction
                            box.xrefDict = xrefDict
                            box.bindFld = bindFld
                            box.trigIdx = trigIdx
                            ac(box,td)                
                            if(browser.xPathSingle(getRelatedXMLNode(oCheckboxGroup),'.//'+xrefDict['domain_value']+'[text()="'+box.domain_val+'"]')) 
                            {
                                box.checked = true;
                                box.defaultChecked = true;  //for ie6
                            }
                            ac(ct(domain_desc.nodeValue),td)
                            ac(td,tr)
	                    }
	                 }
	            }
                ac(tr,tbody)   
            }
            ac(tbody,tbl)
            ac(tbl,oCheckboxGroup)
            
        }
        else{
                if(clientMgr && clientMgr.bindMgr && !clientMgr.bindMgr.dynamicDomains[source]) 
                {
                    clientMgr.bindMgr.dynamicDomains[source] = syncPost('cti_domain.aspx?domain='+source+'#'+Math.random(),null,null,true)
                    if(clientMgr.bindMgr.dynamicDomains[source])
                        fill_checkbox_domain(oCheckboxGroup);
                    else
                        alert('get ' + source + 'failed.')
                }    
                else
                {
                    if(!browser) browser = ctiBrowser();
                    browser.attachEvent("onload", function(){   fill_checkbox_domain(oCheckboxGroup)    })
                }
        }
    }

    //desc  - fills all radio domains on the form.
    //usage - radio_domains, init_gen_form, surveys
    function fill_radio_domains()
    {
        var domains = document.body.getElementsByTagName("div")
        var oRadioGroup
        var source
        var radiotrace = ''
        if(domains != null)
        {
            for(var i = 0; i < domains.length; i++)
            {
                oRadioGroup = domains[i];
                if(oRadioGroup.getAttribute('radiogroup'))
                    fill_radio_domain(oRadioGroup)
            }
        }
    }

var DOMradioCache = []
    
    //desc  - fills a radio domain.
    //      - CONSIDER MERGING ALL DOMAIN FILL CODE
    //usage - surveys, radios
    function fill_radio_domain(oRadioGroup)
    {
        source = oRadioGroup.getAttribute('domain')
        params = source.split("|");
        
        
        radiotrace = ''
        var template = oRadioGroup.getAttribute('template')
        var innerHTML = ''
        
        for(var q in params)
        {
            if(params[q].charAt(0) == '#')
                params[q] = $sibling(oRadioGroup, params[q].substring(1))
            if(params[q].charAt(0) == '@')
                params[q] = $root(params[q].substring(1))
        }
        source = params.join("|")
        
        if(true /*!DOMradioCache[source]*/)
        {
	        isle = ctiXBCXML(document.getElementById(source))
        	
	        if(isle && first_child(isle))
	        {
	            selected_val = String($sibling(oRadioGroup,oRadioGroup.getAttribute("bindFld"))).toUpperCase()
    	        while(oRadioGroup.hasChildNodes()) oRadioGroup.removeChild(oRadioGroup.lastChild);
    	        horizontal = oRadioGroup.getAttribute("horizontal")
	            for(var i = 0; i < first_child(isle).childNodes.length; i++)
	            {
	                optionNode = first_child(isle).childNodes[i];
	                if(optionNode.nodeType == 3) continue;
        	        	        
	                domain_val = browser.xPathSingle(optionNode,'domain_value/text()')
	                domain_desc = browser.xPathSingle(optionNode,'domain_description/text()')
        	        
                    if(domain_val && domain_desc) 
                    {
                        var btn = browser.createRadioButton(oRadioGroup.name)
                        btn.value = domain_val.nodeValue.replace(' ','')
                        btn.bindFld = oRadioGroup.getAttribute("bindFld")
                        btn.onclick = function(){ radio_change(this) } ;
                        oRadioGroup.appendChild(btn)
                        btn.disabled = oRadioGroup.getAttribute("disabled")
                        oRadioGroup.appendChild(ct(domain_desc.nodeValue))
                        if(String(btn.value).toUpperCase() == String(selected_val).toUpperCase() )
                            btn.checked = true;
                        
                        if(!(horizontal == 'y'))
                            oRadioGroup.appendChild(ce('br'))                
                    
    	            }
	            }
	        }
	        DOMradioCache[source] = oRadioGroup.cloneNode(true);
        }
        else
        {
            rad = DOMradioCache[source].cloneNode(true)
            rad.setAttribute("bindFld",oRadioGroup.getAttribute("bindFld"))
            if(oRadioGroup.value)
                for(var i in rad.childNodes)
                    if(rad.childNodes[i].tagName == "input")
                        if(rad.childNodes[i].value == oRadioGroup.value)
                            rad.childNodes[i].checked = true;
            oRadioGroup.parentNode.replaceChild(rad,oRadioGroup);
        }
    } //fill_radio_domain

    //desc  - function for propagating radio values to their containing element
    //usage - fill_radio_domain
    function radio_change(r)
    {
        p = getContainingElementByAttrib(r,'bindFld')
        p.value = r.value; 
        clientMgr.bindMgr.processChange(p);
        //alert([p.getAttribute('bindFld'),$root(p.getAttribute('bindFld'))])
        browser.fireEvent(p,'onclick');
    }

var fill_domains_time_trace = ''
    
    //desc  - fills all domains on the form
    //usage - init_gen_form
    function fill_domains(nodefer,override)      //for testing purposes
    {	
        var start = new Date();
	        var domains = document.body.getElementsByTagName("select");
	        var oSelect;
	        var source;
	        var domaintrace = ''
	        if(domains != null)
	        {
	            var l = domains.length;
	            var formCode = (window.document.forms[0] ? 
	                                (typeof window.document.forms[0].name == 'string' ? 
	                                        window.document.forms[0].name.substring(5) : '') : '')
		        for(var i = 0;i < l;i++)
		        {
			        var oSelect = domains[i];
        			
                    if(oSelect.options.length <= 1 || override)
                    {
                	    var source = oSelect.getAttribute("domain");
                        var params = source.split("|");
                        for(var q in params)
                        {
                            if(params[q].charAt(0) == '#')
                                params[q] = $sibling(oSelect, params[q].substring(1))
                            if(params[q].charAt(0) == '@')
                                params[q] = $root(params[q].substring(1))
                        }
                        source = params.join("|")
                        var cont;// = getContainingElementByAttrib(oSelect,"bindSrc")
                        var isChild;// = (cont ? cont.getAttribute("bindSrc") != formCode : false);
                        if(true) //if(!DOMdomainCache[source])
                            fill_domain(oSelect,source)
                        else
                        {
                            if(isChild || !DOMdomainCache[source])
                                fill_domain(oSelect,source)
                            else
                            {
                                var val;
                                if(isChild) val = String($sibling(oSelect,oSelect.getAttribute("bindFld")))
                                else val = String($root(oSelect.getAttribute("bindFld")))
                                
                                if(val)
                                {
                                    var option = ce('option')
                                    option.value = val
                                    DOMdomainCache[source].value = option.value
                                    if(DOMdomainCache[source].selectedIndex > -1)
                                        option.text = DOMdomainCache[source].options[DOMdomainCache[source].selectedIndex].text
                                    else
                                        alert('could not find value for ' + source + '(' + val + ') in\n\n' + DOMdomainCache[source].outerHTML)
                                    try{
                                        oSelect.add(option,null)
                                    }catch(x){
                                        oSelect.add(option)
                                    }
                                }
                                oSelect.onmouseover = function(){ fill_domain(this);  } 
                            }
                        }
                      }
		        }
	        }
	    var end = new Date();
	    fill_domains_time_trace = end.getTime()-start.getTime();
	    if(gv('debugBox') == 'Y') cti_alert(domaintrace);
    } //fill_domains
//**************************************************
//END - FILL DOMAINS
//**************************************************


//**************************************************
//BEGIN - ACTION FRAME ROUTINES (SAVE, DELETE, ...)
// Notes:
//  - Save, Del, Retrieve
//**************************************************

    //desc  - DELETE on action_frame
    //usage - delete links
    function delete_rec2(isPopup){			
	    window.status = "Deleting Record...";
    		 
	    var result = rec_iud("D");
    	
	    if(result){
		    var eFound = get_element_text_by_tag_name(result, "error_found");
    		
		    if(eFound.toLowerCase() == "n"){
    			
			    new_rec2(null,true,isPopup); //skip confirmations
    			
			    window.status = "Record Deleted.";
    		
		    }
		    else{
			    window.status = "Error Deleting Record.";
		    }
	    }
	    else
		    window.status = "Record not Deleted.";
    } // delete_rec2

    //desc  - Delete Links on right_frame
    //usage - delete links defind in metadata (i.e. md_htm)
    function delete_rec_only(){			
	    window.status = "Deleting Record...";
    		 
	    var result = rec_iud("D");
    	
	    if(result){
		    var eFound = get_element_text_by_tag_name(result, "error_found");
    		
		    if(eFound.toLowerCase() == "n"){
    			
    			
			    window.status = "Record Deleted.";
		        return true;
    			
		    }
		    else{
		        display_error_page(get_element_text_by_tag_name(result,"message"),get_element_text_by_tag_name(result,"error_type"))
			    window.status = "Error Deleting Record.";
			    return false;
		    }
	    }
	    else
		    window.status = "Record not " + sPast + ".";
		    return false;
    }//delete_rec_only
    
    //desc  -  runs when user attempts to exit application
    //usage - default.aspx.vb, onbeforeunload event
    function app_unload(frame_event){
               return;
         
        // outerWidth
        if (event.clientY < 0){
            var w;
    
            if(/Microsoft/.test(navigator.appName))
                w = document.body.clientWidth;
            else
                w = window.outerWidth;
            
        if ((w > event.clientX) && ((w - event.clientX) <  50)){
        
                // default.aspx, frame change conditions met, confirmation note executed yet
                if(!frame_event && ((top.right_frame.clientMgr.changed) && (top.right_frame.clientMgr.confirmExit)) && !top.right_frame.clientMgr.runAppPostProc)
                { alert("defer until frame unload runs");
                    return; }
                    
                // no frame unload fired or second call to app_unload
                if(!frame_event || top.right_frame.clientMgr.runAppPostProc)        
                    alert("offering survey");        

            //try{ window.parent.location='cti_logout.aspx' } catch(x){}
        }
        }
    } // app_unload
    
    function app_unload2(frame_event){
    
    var rid = syncPost('cti_retrieve_session.aspx','shortkey=sessionuser.recordid');
    
    if(frame_event)
        alert("unload2 frame event true");  
    else     
       alert("unload2 frame event false");
    } // app_unload2
    

    //desc  - requests confirmation from user if they really want to leave a form they have made changes to without saving
    //usage - navigation routines, onbeforeunload event
    function frm_confirm_leave2(){
        // determine if they closed the browser
        var bXClose = false;
        var bSurvey = false;
        
        if (event.clientY < 0){
            var w;
            var cX = event.clientX;
                
            if(/Microsoft/.test(navigator.appName))
            {
                w = parent.document.body.clientWidth;
                //cX += (parent.document.body.clientWidth - window.document.body.clientWidth);
            }
            else
            {
                w = parent.outerWidth;
                //cX += (parent.outerWidth - window.outerWidth);
            }
                
                      
            if(w < cX){
                var t = cX;
                cX = w;
                w = t;
            }
            
            //alert("height:" + window.document.body.clientHeight + " y:" + event.clientY + "clientX: " + event.clientX + " cx:" + cX + " w:" + w + " diff:" + (w - cX));
                       
            if (w - cX < 50)
                bXClose = true;
        }
        
         // var msg = parent.right_frame.frm_confirm_leave3();
        var msg = frm_confirm_leave3();
        // msg null if no change or confirm exit is false
               
	    if (msg){
	    
	        if(!bXClose)
	            return msg + "2";
	        else  
                if(mess && confirm('Are you sure you want to close the browser without saving your changes?\n\n'+
                    mess+ '\n\nPress OK to continue, or Cancel to stay on the current page.'))
	                bSurvey = true;
	            else clientMgr.confirmExit = false;
	    }
	    else 
	        if(bXClose)
	            bSurvey = true;
	        else clientMgr.confirmExit = true;  // why?
	        
	    //if(bSurvey)
	      //  alert("fire survey");
	   
    } //frm_confirm_leave2
    
        function frm_confirm_leave3(){
	    if ((clientMgr.changed) && (clientMgr.confirmExit)){
		    mess = "******************************************************************************\n";
		    mess += "  You have made changes to THIS FORM.\n";
		    mess += "  To keep your changes, choose CANCEL and then click SAVE on the form.\n";
		    mess += "  To discard your changes, choose OK (changes will be lost).\n";
		    mess += "******************************************************************************";
		    return mess;
	    }
	    else clientMgr.confirmExit = true;
    } //frm_confirm_leave3

    //desc  - Activates current page on the server
    //usage - open popup window, init gen form
    function frm_activate(){
        //wait('activating ' + clientMgr.getFormCode())
        syncPost('cti_change_session.aspx','key=activatepage&value='+clientMgr.getFormCode())
    }

    //desc  - NEW action_frame item
    //usage - NEW links
    function new_rec2(map_name,skip_confirm,isPopup){

        if(!map_name)
        {
            map_name = syncPost('cti_retrieve_session.aspx','shortkey=SessionMapName')
        }

        if(!skip_confirm) skip_confirm = null
        if(skip_confirm == 'skip_confirm') skip_confirm = true    //@@@@@ (jds 20081201)
        if(skip_confirm == 'confirm') skip_confirm = false        //@@@@@ (jds 20081201)
        
        if(!isPopup) isPopup = null 
        if(isPopup == 'popup') isPopup = true                     //@@@@@ (jds 20081201)
        if(isPopup == 'not_popup') isPopup = false                //@@@@@ (jds 20081201)

	    window.status = "";
    	
	    //if((skip_confirm) || (confirm("Are you sure you want to clear this form?"))){
	    if((skip_confirm) || (confirm("Are you sure you want to create a new record?"))){
		    window.onbeforeunload = frm_confirm_leave2;
		    
		    if(!isPopup)
                loadContent(map_name,'I');
            else {               
                    //var sPage = window.location.pathname 
                    // I prefer the technique below because it includes protocol and host
                    var sPage = window.location.href.substr(0,window.location.href.length - window.location.search.length);
    	
		            var sURL = sPage + "?action=N&id1="
		                                                                
                            if(window.location.search.length > 1){
                            var aSearch = window.location.search.substring(1).split("&");
                            
                            var oCount = 0;
		                    var sMap = "";
		                    var sFormCode = "";
		                    
		                    for(var i = 0, sParm; sParm = aSearch[i]; i++)
		                    {
		                        if((sParm.length  > 4) && (sParm.substring(0,4) == "map=") && (sParm.substring(4).length > 0))
		                             { sMap = sParm; oCount++ }
		                        else
		                            if((sParm.length  > 10) && (sParm.substring(0,10) == "form_code=") && (sParm.substring(10).length > 0))
		                                { sFormCode = sParm; oCount++ }
		                        if(oCount == 2)
		                            break;
		                    }
		                 
		                    sURL += "&" + sMap + "&" + sFormCode;
                         } // if search.length > 1 
    		                                                   

                    //alert('old url was ' + window.location.href + '\r new is:' + sURL);
                    //alert('href:' + window.location.href + '\r protocol:' + window.location.protocol + '\r host:' + window.location.host + '\r hostname:' + window.location.hostname + '\r pathname:' + window.location.pathname + '\r search:' + window.location.search);
                                                     
                    //window.location.href = sTemp;
                    window.location.replace(sURL);
                } // else isPopup

        /*
		    if(!skip_confirm)
		        pge_display_wait_page2();
        */		
        
        /*
            var sPage = window.location.href.substr(0,window.location.href.length - window.location.search.length);

		        //Assumes one form per page
		        window.location = sPage + "?action=N";
                parent.top_frame.top_frame_update();
		        parent.action_frame.location.reload();
	    */
        	
        /*		if(!skip_confirm)
			        pge_close_wait_page2();
        */
	    }
	} // new_rec2

	//desc  - Processes form print
	//usage - PRINT actions, print links
	function print_form() {
	    var rf = parent.right_frame;
	
	    rf.focus();
	    rf.print();

	    var mgr = rf.clientMgr.bindMgr;
	    
	    if(mgr.boundDataEls.length > 0)
	        cti_verify(mgr.boundDataEls[0][0], 'shr_print_log_evf', null, 'asp_id:' + mgr.formId); // ',clear_expression_type:DEMAND'
	}

	//desc - Processes database insert, update or delete
	//usage - SAVE, DELETE action_frame items
    function rec_iud(sAction){
	    //Assumes one form with form_ as a prefix
	    var htmForm = window.document.forms[0];
	    var formNode;
    	
	    if(is_form_element(htmForm))
	    {
	         var form_id = htmForm.name.substring(5);
	         var isle = clientMgr.bindMgr.isle //document.getElementById(form_id);
        	 
	         if(is_form_element(isle)){
	            //var sRecordId ;
	            //if(parent.top_frame)sRecordId = parent.top_frame.gv('record_id');
	            //else sRecordId = $root('id1');
        	    
		        //if(!sRecordId)
		        //    sRecordId = syncPost("cti_retrieve_session.aspx","shortkey=_id1") 
        		    
		        var fMgr;
            
                w = window.opener   //because we may be several popups out
                
                while(w && !w.closed && !fMgr)
                {
                    fMgr = w.parent.framesetMgr;
                    w = w.opener
                }
                if(!fMgr) fMgr =  parent.framesetMgr;

		        //TODO:  If this is a delete, trim all child controls out of the island before transmission	
		        if(gv('debugBox') == 'Y') 
		            cti_alert('requesting ' + fMgr.DEFAULT_LINK + "asp/cti_save.aspx?action=" + sAction + '\n\n\n' +browser.xmlText(isle))        //sanity check
		        var result = syncPost("cti_save.aspx?action=" + sAction, isle, null, true); //DEFAULT LINK declared in cti_sys_ini.vb   //fMgr.DEFAULT_LINK + "asp/ taken out for multiple access scenarios
        		
		        if(result && result.documentElement)
		        {
		            if((result.documentElement.nodeName == "cti_save_response"))
		            {
			            var root = result.documentElement;
            					
			            formNode = root.getElementsByTagName(form_id);
            			
			            if(formNode.length > 0)
			            {
			                formNode = formNode[0];

			                var msgType = get_element_text_by_tag_name(formNode, "message_type");
				                        				
				            if(msgType != "")
				            {
			                    if(msgType != "I")
            		                if(sessionLoadingDebug())
            		                    endWait()
            		                                		                
					            display_error_page(get_element_text_by_tag_name(formNode,"message"), msgType);
		                    }       	        
            					
				            var iudtrace = get_element_text_by_tag_name(formNode, "trace");
            				
				            if(iudtrace && gv('debugBox') == 'Y')
					            cti_alert(browser.xmlText(result)); //DEBUG ONLY
            						
			            }
			            else{
					            alert('Save status for form ' + form_id + ' not found');
					            formNode = null;
			            }
		            }
		            else{
		             alert('Save response not formatted properly...' + result);
		             cti_alert(result);
		            }
		        }
		        else
		        {
		            alert('No result returned from database operation...');
		        }
	         }
	         else
	            alert('isle ' + form_id + ' not found');
	    }
	    else
	        alert('form not found');
    	
	    return formNode;
    } //rec_iud

    //desc - Processes database insert, update or delete
    //usage - SAVE, DELETE action_frame items
    function rec_iud_new(sAction){
	    //Assumes one form with form_ as a prefix
	    var htmForm = window.document.forms[0];
	    var formNode;
    	
	    if(is_form_element(htmForm))
	    {
	         var form_id = htmForm.name.substring(5);
	         var isle = clientMgr.bindMgr.isle //document.getElementById(form_id);
        	 
	         if(is_form_element(isle)){
	            //var sRecordId ;
	            //if(parent.top_frame)sRecordId = parent.top_frame.gv('record_id');
	            //else sRecordId = $root('id1');
        	    
		        //if(!sRecordId)
		        //    sRecordId = syncPost("cti_retrieve_session.aspx","shortkey=_id1") 
        		    
		        var fMgr;
            
                w = window.opener   //because we may be several popups out
                
                while(w && !w.closed && !fMgr)
                {
                    fMgr = w.parent.framesetMgr;
                    w = w.opener
                }
                if(!fMgr) fMgr =  parent.framesetMgr;

		        //TODO:  If this is a delete, trim all child controls out of the island before transmission	
		        if(gv('debugBox') == 'Y') 
		            cti_alert('requesting ' + fMgr.DEFAULT_LINK + "asp/cti_save.aspx?action=" + sAction + '\n\n\n' +browser.xmlText(isle))        //sanity check
		        var result = syncPost("cti_save.aspx?action=" + sAction, isle, null, true); //DEFAULT LINK declared in cti_sys_ini.vb   //fMgr.DEFAULT_LINK + "asp/ taken out for multiple access scenarios
        		
		        if(result && result.documentElement)
		        {
		            if((result.documentElement.nodeName == "cti_save_response"))
		            {
			            var root = result.documentElement;
            					
			            formNode = root.getElementsByTagName(form_id);
            			
			            if(formNode.length > 0)
			            {
				            formNode = formNode[0];
            				
				            var msgType = get_element_text_by_tag_name(formNode, "message_type");
            				
				            if(msgType != "")
				            {
			                    if(msgType != "I")
            		                if(sessionLoadingDebug())endWait()
            		            //Not sure why this routine was calling display_error_page:  was causing duplicate popups
            		            // removed 4/8/09 - jsb
					            //display_error_page(get_element_text_by_tag_name(formNode,"message"), msgType, "rec_iud 1");
		                    }       	        
            					
				            var iudtrace = get_element_text_by_tag_name(formNode, "trace");
            				
				            if(iudtrace && gv('debugBox') == 'Y')
					            cti_alert(browser.xmlText(result)); //DEBUG ONLY
            						
			            }
			            else{
					            alert('Save status for form ' + form_id + ' not found');
					            formNode = null;
			            }
		            }
		            else{
		             alert('Save response not formatted properly...' + result);
		             cti_alert(result);
		            }
		        }
		        else
		        {
		            alert('No result returned from database operation...');
		        }
	         }
	         else
	            alert('isle ' + form_id + ' not found');
	    }
	    else
	        alert('form not found');
    	
	    return formNode;
    } //rec_iud

    //desc  - RETRIEVE action_frame item
    //usage - popupRetrieve boxes
    function retrieve_rec2(sRecordId,isPopup)
    {
	    window.status = "";

	    if(arguments.length == 0)
	    {
	        alert('calling retrieve_rec2 with no parameter');
	        sRecordId = parent.top_frame.gv('record_id')
	        if(!sRecordId) 
	            sRecordId = syncPost("cti_retrieve_session.aspx","shortkey=_id1") //parent.top_frame.gv('record_id');
	    }

	    if(!sRecordId || sRecordId == ""){
		    alert("Please enter a Record ID before selecting retrieve.");
	    }
	    else{
            if(!isPopup)
                loadContent(syncPost('cti_retrieve_session.aspx','shortkey=SessionMapName'),'U',sRecordId)
            else {               
                //var sPage = window.location.pathname 
                // I prefer the technique below because it includes protocol and host
                var sPage = window.location.href.substr(0,window.location.href.length - window.location.search.length);
    	
		        var sURL = sPage + "?action=R&id1=" + sRecordId;
		                                                                
                if(window.location.search.length > 1){
                    var aSearch = window.location.search.substring(1).split("&");
                            
                    var oCount = 0;
		            var sMap = "";
		            var sFormCode = "";
		                    
		            for(var i = 0, sParm; sParm = aSearch[i]; i++)
		            {
		                if((sParm.length  > 4) && (sParm.substring(0,4) == "map=") && (sParm.substring(4).length > 0))
		                { 
		                    sMap = sParm; 
		                    oCount++ ;
		                }
		                else
		                    if((sParm.length  > 10) && (sParm.substring(0,10) == "form_code=") && (sParm.substring(10).length > 0))
		                    { 
		                        sFormCode = sParm; 
		                        oCount++; 
		                     }
		                     if(oCount == 2)
		                        break;
		            } // for
		                 
		            sURL += "&" + sMap + "&" + sFormCode;
                } // if search.length > 1 
    		                                                   

                //alert('old url was ' + window.location.href + '\r new is:' + sURL);
                //alert('href:' + window.location.href + '\r protocol:' + window.location.protocol + '\r host:' + window.location.host + '\r hostname:' + window.location.hostname + '\r pathname:' + window.location.pathname + '\r search:' + window.location.search);
                                                     
                //window.location.href = sTemp;
                window.location.replace(sURL);
            } // else isPopup
	    } // else record id exists
    }//retrieve_rec2
    
    //desc  - Saves the form. Context-sensitive: will work on popups OR main forms
    //usage - actions that run in popups AND main forms
    //returns - whether the save is successful or not.
    function save()
    {
            return (opener ? save_form_no_reload() : save_form_reload())
    }

    //desc  - saves the form without refreshing the page
    //usage - SAVE action_frame item, links
    function save_form_no_reload()
    {
        clientMgr.confirmExit = false;
        if(!sessionLoadingDebug()) wait()

	    window.status = "Validating Record...";
	        	
	    var sMessage = cti_validate();
    	
	    if(sMessage != ""){
		    window.status = "Validation Failed...";
		    if(sessionLoadingDebug()) wait("Validation Failed...",true);
		    endWait();
		    display_error_page(sMessage, "V", "save_form_no_reload 1");
		    return false;
	    }
    	
	    var sRecordId = $root('id1')
	    if(!sRecordId)
	        sRecordId = "";
    	
	    var sAction = "U";
	    var sPresent = "Saving";
	    var sPast = "Saved";
    		
	    if(sRecordId == ""){
		    sAction = "I";
		    sPresent = "Inserting";
		    sPast = "Inserted";
	    }
    							
	    window.status = sPresent + " Record...";
    		 
	    var result = rec_iud(sAction);
    	
	    if(result){
		    var eFound = get_element_text_by_tag_name(result, "error_found");
    		
		    if(eFound.toLowerCase() == "n"){
			    window.status = "Record " + sPast + ".";
			    if(sessionLoadingDebug()) wait("Record " + sPast + ".",true);
    		
			    if(sAction == "I"){
				    var newId = get_element_text_by_tag_name(result, "new_id");
    								
				    if(newId != ""){
				            endWait();
						    return true;
				    }
				    else{
					    window.status = "Record inserted, but no key found.";
					    alert('The record you just saved was inserted into the database, but there was a problem returning the new Record ID.\rTo prevent the record from being duplicated, the form will be cleared.  Use the FIND action to re-retrieve the new record.')
					    new_rec2();								
					    endWait();
					    return false;
				    }
			    }
			    else
			    {
				    return true;
			    }

		    }
		    else{
			    window.status = "Error" + sPresent + " Record." + sRecordId;
			    display_error_page(get_element_text_by_tag_name(result,'message'),get_element_text_by_tag_name(result,'message_type'),"save_form_no_reload 2");
			    if(sessionLoadingDebug())wait("Error" + sPresent + " Record.")
    		    endWait();
			    return false;
		    }
	    }
	    else
	    {
		    window.status = "Record not " + sPast + ".";
		    if(sessionLoadingDebug())wait("Record not " + sPast + ".",true)		
            endWait();
		}
		
        return false;
    } //save_form_no_reload
    
       //desc  - saves the form and refreshes the page
    //usage - SAVE links
    function save_form_reload(isPopup)
    {                
        clientMgr.confirmExit = false;
	    if(!sessionLoadingDebug()) wait()

	    window.status = "Validating Record...";
        if(sessionLoadingDebug()) wait("Validating Record...",true)	
       
	    var sMessage = cti_validate();
    	
	    if(sMessage != ""){
		    window.status = "Validation Failed...";
		    if(sessionLoadingDebug()) wait("Validation Failed...",true)
		    endWait();
		    display_error_page(sMessage, "V");
		    return;
	    }
    	
	    var sRecordId = syncPost("cti_retrieve_session.aspx","shortkey=_id1&form_code="+clientMgr.getFormCode()) 
	    var sAction = "U";
	    var sPresent = "Saving";
	    var sPast = "Saved";
    		
	    if(sRecordId == ""){
		    sAction = "I";
		    sPresent = "Inserting";
		    sPast = "Inserted";
	    }
    				
	    window.status = sPresent + " Record...";
	    if(sessionLoadingDebug()) wait(sPresent + " Record...",true)
    		 
	    var result = rec_iud(sAction);
    	
	    if(result){
		    var eFound = get_element_text_by_tag_name(result, "error_found");
    		
		    if(eFound.toLowerCase() == "n"){
			    window.status = "Record " + sPast + ".";
    		    if(sessionLoadingDebug()) wait("Record " + sPast + ".",true)	
    		
			    if(sAction == "I"){
				    var newId = get_element_text_by_tag_name(result, "new_id");
				        								
				    if(newId != ""){
						    retrieve_rec2(newId,isPopup);
				    }
				    else{
					    window.status = "Record inserted, but no key found.";
					    wait("Record inserted, but no key found.",true)
					    alert('The record you just saved was inserted into the database, but there was a problem returning the new Record ID.\rTo prevent the record from being duplicated, the form will be cleared.  Use the FIND action to re-retrieve the new record.')
					    new_rec2();									
					    endWait()
				    }
			    }
			    else
			    {
				   retrieve_rec2(sRecordId,isPopup);
			    }

		    }
		    else{
			    window.status = "Error " + sPresent + " Record.";
			    // cti_alert(browser.xmlText(result));
    		    if(sessionLoadingDebug())wait("Error" + sPresent + " Record.");
    		    endWait();
		    }
	    }
	    else
	    {
		    window.status = "Record not " + sPast + ".";
		    if(sessionLoadingDebug())wait("Record not " + sPast + ".",true)		
            endWait()		
	    }
	    //if(sessionLoadingDebug()) endWait()	
    } //save_form_reload

    //desc  - saves the form and refreshes the page
    //usage - SAVE links
    function save_form_reload_new(isPopup)
    {                
        var bRes = false;
        var sMsgType = "";
        
        clientMgr.confirmExit = false;
	    if(!sessionLoadingDebug()) wait();
	    
	    var sMsg = "Validating Record..."

	    window.status = sMsg;
        if(sessionLoadingDebug()) wait(sMsg,true);
        
	    var sRetMsg = cti_validate();
	    
	    if(sRetMsg != "")
	    {
	        sMsg = "Validation Failed...";
	        window.status = sMsg;
	        if(sessionLoadingDebug()) wait(sMsg,true);
	        sMsgType = "V";
	    }
	    else
	    {
	        var sRecordId = syncPost("cti_retrieve_session.aspx","shortkey=_id1&form_code="+clientMgr.getFormCode()) 
	        var sAction = "U";
	        var sPresent = "Saving";
	        var sPast = "Saved";
    		
	        if(sRecordId == ""){
    		    sAction = "I";
	    	    sPresent = "Inserting";
		        sPast = "Inserted";
	        }
    				
    	    sMsg = sPresent + " Record...";
	        window.status = sMsg;
	        if(sessionLoadingDebug()) wait(sMsg,true)
    		 
	        var result = rec_iud(sAction);
    	
	        if(result){
		        var eFound = get_element_text_by_tag_name(result, "error_found");
		        sMsgType = get_element_text_by_tag_name(result,'message_type');
			    sRetMsg = get_element_text_by_tag_name(result,'message');
    		
		        if(eFound.toLowerCase() == "n"){
		            bRet = true;
		            
		            sMsg = "Record " + sPast + ".";
			        window.status = sMsg;
    		        if(sessionLoadingDebug()) wait(sMsg,true);
    		
			        if(sAction == "I"){
				        var newId = get_element_text_by_tag_name(result, "new_id");
				        								
				        if(newId != "")
						    retrieve_rec2(newId,isPopup);
				        else{
				            sMsg = "Record inserted, but no key found.";
					        window.status = sMsg;
					        if(sessionLoadingDebug()) wait(sMsg,true);
					        alert('The record you just saved was inserted into the database, but there was a problem returning the new Record ID.\rTo prevent the record from being duplicated, the form will be cleared.  Use the FIND action to re-retrieve the new record.')
					        new_rec2();									
				        }
			        }
			        else			                
				        retrieve_rec2(sRecordId,isPopup);

		        }
		        else
                {
		            sMsg = "Error " + sPresent + " Record.";
			        window.status = sMsg;
			        if(sessionLoadingDebug())wait(sMsg);

			        // cti_alert(browser.xmlText(result));
		        }
	        }
	        else
	        {
	            sMsg = "Record not " + sPast + ".";
		        window.status = sMsg;
		        if(sessionLoadingDebug())wait(sMsg,true);
		        sMsgType = "E";
		        sRetMsg = "No result returned from rec_iud()";
	        }
	    } // else was valid

	    if(sMsgType != "")
	        display_error_page(sRetMsg, sMsgType, "save_form_reload");
	    
	    endWait();
	    
	    return bRes;		
    } //save_form_reload
    
    //desc  - saves a single row
    //
    //    relies on a form code set up to save
    //    src_el: an element in the row to save
    //
    //usage - md_map_edit
    function save_row(src_el)
    {
        var src = getRelatedXMLNode(src_el);
        if(src)
        {
            var code = src.nodeName;
            
            if(/Microsoft/.test(navigator.appName)) src = src.xml
	        else {
	            newsrc = document.implementation.createDocument('','',null);
	            newsrc.appendChild(src.cloneNode(true));
	            src = newsrc;
	        }
	        
	        //alert('verifying:' + code);
	        // Normally, cti_verify is used for retrieves, so we need to have a special form set up in md_form
	        // to store the save procedure in the load procedure field.  The name must end in _save
	        cti_verify(src_el,code+'_save',code);
	    }
    }
    
//**************************************************
//END - ACTION FRAME ROUTINES (SAVE, DELETE, ...)
//**************************************************


//**************************************************
//BEGIN - CHILD FORM ROW PROCESSING ROUTINES
// Notes:
//  -
//**************************************************

    //desc  - Processes child level switches during binding
    //usage - binding - can this go into binding.js?
    function processSwitches(new_tr,new_row,data_node)
    {
	    var fields = getSwitchFields(new_tr);
	    var view_sw;
	    var upd_sw;
	    var sw_el;
	    var fc;
	    var pn;
	        				
	    for(var i=0, flen=fields.length;i < flen;i++){

		    view_sw = fields[i].getAttribute("view_switch");
    		
		    if(new_row)
			    view_sw = fields[i].getAttribute("view_switch_for_new");
    			
		    //	if(new_tr.getAttribute("bindSrc") == "ece_ecemf.ece_pcf_container.ece_pcf")
		    //alert('view_sw:' + view_sw);
    			
		    if(view_sw){
			    if(view_sw.charAt(0) == "@"){
				    sw_el = data_node.getElementsByTagName(view_sw.substring(1));
    				
				    view_sw = "n";
    			
				    if(sw_el.length > 0){
					    sw_el = sw_el[0];
    				
					    if(sw_el.hasChildNodes && first_child(sw_el).nodeType == 3)
						    view_sw = first_child(sw_el).nodeValue;
				    }
			    }
    			
			    //alert('resolved to:' + view_sw);
    			
			    if(view_sw.toLowerCase() == "y")
				    fields[i].style.display = "";
			    else
				    fields[i].style.display = "none";	
		    } // view_sw
    		

    					
		    if(fields[i].style.display != "none"){
			    upd_sw = fields[i].getAttribute("upd_switch");
    		
			    if(new_row)
				    upd_sw = fields[i].getAttribute("upd_switch_for_new"); 

    				
			    //alert('upd_sw:' + upd_sw);
    				
			    if(upd_sw){
			        fc = upd_sw.charAt(0);
    			    
				    if((fc == "@") || (fc == "!")){
				        if(fc == "@")
				            pn = 1;
				        else
				            pn = 2;
    				        
    				
					    sw_el = data_node.getElementsByTagName(upd_sw.substring(pn));
    				
					    upd_sw = "n";					
    								
					    if(sw_el.length > 0){
						    sw_el = sw_el[0];
    				
						    if(sw_el.hasChildNodes && first_child(sw_el).nodeType == 3){
							    upd_sw = first_child(sw_el).nodeValue;
    							
							    if(fc == "!")
							        if(upd_sw.toLowerCase() == "y")
							            upd_sw = "n";
							        else
							            upd_sw = "y";
						    }
					    }
				    }
    				
    		
				    if(upd_sw.toLowerCase() == "y"){
					    fields[i].readOnly = false;
					    fields[i].className = "";
					    if(fields[i].nodeName.toLowerCase() == "select")
					       fields[i].removeAttribute("disabled");
					        
				    }
				    else{
					    fields[i].readOnly = true;
					    fields[i].className = "readonly";
				    }
			    } //upd_sw
		    }
    		
		    // I do not think this is browser compatible
		    fields[i].setAttribute("proc_sw","y");
	    } // for
    } //processSwitches


    //desc  - Returns list of fields that have switch attributes
    //usage - Switch processing
    function getSwitchFields(parent)
    {
	    var coll;
	    var swNames = new Array("view_switch","view_switch_for_new","upd_switch","upd_switch_for_new");
	    var elTags = new Array("textarea","input","select","a");
	    var sWFields = new Array();
	    var sWIdx = 0;
	    var field;

	    for(var t=0, tlen=elTags.length;t < tlen; t++){
		    coll = parent.getElementsByTagName(elTags[t])

		    for(var x=0, clen=coll.length;x < clen; x++){
			    found_sw = false;
    			
			    field = coll[x];
    			
			    if(field.getAttribute("proc_sw") == "y")
			        continue;
    		
			    for(var n=0, swlen=swNames.length;n < swlen; n++){
				    if(field.getAttribute(swNames[n])){
					    found_sw = true;
					    break;
				    }
			    }
    			
			    if(found_sw){
				    sWFields[sWIdx] = coll[x];
				    sWIdx++;
			    }
		    }
	    }
    		
	    return sWFields;
    } // getSwitchFields

//**************************************************
//END - CHILD FORM ROW PROCESSING ROUTINES
//**************************************************


//**************************************************
//BEGIN - DEBUG ROUTINES
// Notes:
//  - DEBUGGING ONLY
//**************************************************

    //desc  - 
    //usage - not used ?????
    //function show_trail(trail){
	  //  for(var i = 0; i < trail.length; i++){
		//    alert('trail entry:' + i + ' datafld:' + trail[i][0] + ' instance:' + trail[i][1] + '\r');
	    //}
    //}

    //desc  - 
    //usage - DEBUGGING ONLY
    function get_isle_val(action_el,stop_id,level, target_col){
	    var form_id = window.document.forms[0].name.substring(5);  // assumes first form named form_ + form_id
	    var n = document.getElementById(form_id).documentElement;
	    var trail = build_trail(action_el.parentNode.parentNode,stop_id);
    		
	    for(var i = (trail.length - 2); n && (i >= level); i--){
		    var n_coll = n.getElementsByTagName(trail[i][0]);
    	
		    if(n_coll.length > trail[i][1]){
			    n = n_coll[trail[i][1]];
		    }
	    }
    	
	    return get_element_text_by_tag_name(n, target_col);
    } //get_isle_val

    //
//usage - DEBUGGING ONLY
    function tbl_has_data(tbl){
	    var form_id = window.document.forms[0].name.substring(5);  // assumes first form named form_ + form_id
	    var n = document.getElementById(form_id).documentElement;
	    var trail = build_trail(tbl.parentNode.parentNode,"tbl_" + form_id);
    		
	    for(var i = (trail.length - 2); n && (i >= 0); i--){
		    var n_coll = n.getElementsByTagName(trail[i][0]);
    	
		    if(n_coll.length > trail[i][1]){
			    n = n_coll[trail[i][1]];
		    }
		    else
			    n = null;
	    }
    	
	    if(n)
		    return (n.childNodes.length > 1);
	    else
		    return false;
    }

    //desc  - 
    //usage - 
    function build_trail(action_el,stop_id){
	    // We assume the action element is inside a td
	    var n = action_el;
	    var trail = new Array();
	    var i = 0;
	    var deduct_thead_rows = true;

	    while(n && (n.id != stop_id)){
		    if(n.nodeName.toLowerCase() == "tr")
			    trail[i] = new Array("",n.rowIndex,null);

		    if(n.nodeName.toLowerCase() == "thead")
			    deduct_thead_rows = false;

		    if((n.nodeName.toLowerCase() == "table") && (n.getAttribute("datafld"))){
			    trail[i][0] = n.getAttribute("datafld");
			    trail[i][2] = n;

			    if(n.tHead && deduct_thead_rows){
				    trail[i][1] -= n.tHead.rows.length;
			    }

			    deduct_thead_rows = true;

			    i++;
		    }

		    n = n.parentNode;
	    }
    	
	    if(n)
		    trail[i][0] = n.id.substring(4);

	    return trail;
    } // build_trail
    
    //desc  - debugging only - utility to show contents of data island
    //usage - used by - JAE
    function show_island(isle){
        if(arguments.length < 1){
    	    var form_id = window.document.forms[0].name.substring(5);  // assumes first form named form_ + form_id
    	    
	        isle = document.getElementById(form_id);
        }
    	
	    if(isle){
		    cti_alert("island contents:\r" + browser.xmlText(isle),'show_island on '+form_id);
	    }
	    else
		    alert("no island found");
    }

    //usage - debugging tools
    function pickup(n){
    //DEBUGGING ONLY
    //uses css to allow drag-and-drop of dom elements.
        n.style.position = 'absolute'
        document.body.onmousemove = function(event){
            event = event || window.event
            n.style.top = Number(event.clientY + (document.body.scrollTop || 0) - 10) + 'px'
            n.style.left = Number(event.clientX + (document.body.scrollLeft || 0) - 25) + 'px'
            
            }
        n.oncontextmenu = function(event){
            event = event || window.event
            document.body.onmousemove = null;
            n.oncontextmenu = function() { return pickup(n) }
            return false;    }
        return false;
    }


    //usage - debugging tools
    function writeObj(obj,f) { 
    //DEBUGGING ONLY
    //parses an object using an arbitrary function
        var x; 
        for(var i in obj){ 
            if(!f)  x += i + '=' + obj[i] + '\n';
            else x += f(i,obj)
        }; 
        return x; 
    };

    //usage - debugging
    function dismiss(o){
    //returns a function which enables deletion of a DOM element
        return function() { o.parentNode.removeChild(o) } 
    }

    //usage - debugging
    function dragMe(o){
    //DEBUGGING ONLY
    //returns an event handler which enables dragging on a DOM element
        return function(){ return pickup(o) }
    }

    //usage - debugging
    function bindValues(src,tar,map,evt)
    //--- not used
    //binds two objects by an arbitrary binding function
    {
        if(!evt) evt='onchange';
        src.attachEvent(evt,function(){ Function('src','tar',map)(src,tar); tar.fireEvent('onchange'); })
    }

    //usage - calendar, debugging
    function makeDraggableDiv(text)
    //used
    //creates a div which can be dragged
    {
        var x = ce('div');
        x.className = 'draggableDiv'
        x.oncontextmenu = dragMe(x)
        x.ondblclick = dismiss(x);
        if(text){
            x.innerHTML = text
        }
        ac(x,document.body)
        return x;
    }

    //usage - debugging
    function makeInspectFunc(view_func,object,property)
    //DEBUGGING ONLY
    //creates an event handler which binds
    //a property of one object to a function on another
    {
        if(!property) property = 'value'
        if(!object[property]) property = 'innerText'
        return function(){
            object[property] = view_func(event.srcElement);
        }
    }

    //usage - debugging - DEBUGGING ONLY
    function makePropertyInspector(property,object,tproperty)

    {
        var func;
        alert(typeof property)
        if(typeof property === "string") func = function(obj){ return obj[property] }
        if(typeof property === "function") func = property
        return makeInspectFunc(func, object, tproperty);
    }

    //usage - debugging
    function makePropertyInspectorDiv(property)
    //DEBUGGING ONLY
    //either makes a div for inspecting properties
    //or appends an inspector to it
    {
        if(typeof property != "function")
            if(property.charAt(0) == '=') 
                property = new Function('obj',"return "+property.substring(1))
        var d
        if(!ge('electricEye'))
        {
            var d = makeDraggableDiv()
            d.id = 'electricEye'
        }
        else 
        {
            d = ge('electricEye')
            ac(ce('br'),d)
        }
        var i = ce('input');
        document.body.attachEvent('onmouseover',makePropertyInspector(property,i))
        ac(ct(property+':'),d);
        ac(i,d);
        ac(d,document.body);
    }//makePropertyInspectorDiv

    //DEBUG ONLY
    //usage - debugging only
    function list_xpath(xpath){ 
        var s = []; 
        var t = ctiBrowser().xPath(clientMgr.bindMgr.isle.documentElement,xpath); 
        for(var i = 0; i<t.length;i++) s.push(t[i].nodeValue); 
        return s.sort().join(" ")
    }
//**************************************************
//END - DEBUG ROUTINES
//**************************************************


//**************************************************
//BEGIN - POPUPS
// Notes:
//  - 
//**************************************************

var childWindows = [];
var childWindowsAll = [];

    //desc  - opens a popup
    //
    //    name: the name of the window to use. Used to prevent too many windows from opening. 
    //    if a window with that name exists, the new window will replace it.
    //    location: the URL of the resource to load in the popup
    //    stickaround: if false, omitted or the text no_stickaround, popup will be closed when the parent form is unloaded.
    //    height,width,top,left:  Optional size and position indicators for the window
    //usage - everywhere. all popups come from this call
    function open_popup_window(name,location,stickaround,height,width,top,left)
    {   
  
        var bSizeOverride = false;
        
        if(arguments.length > 3)
            bSizeOverride = true;
               
        /* NOTE: Offset are optimized for split screens on a (1680x1050) and (1280x1024) pixels on a widescreen monitor */
        if(!height)
            height = screen.height; //jds - height should be ok
            
        if(!width)
            width = (screen.width*.97); //jds - screen.width seems to be wider that half pushing the window to the left. Different resolutions work differently (i.e. 1400x900 versus 2000x1100)
            
        if(!top)
            top = 0;
            
        if(!left)
            left = 0;
            
        if (!bSizeOverride)
        {          
            var currScreenMode = syncPost("cti_retrieve_session.aspx","shortkey=sessionscreenmode");
        
            if(currScreenMode == "SPLIT")
            {
                var left_offset = -8;
                var width_offset = 0;
        
                width = width/2 - width_offset;
                        
                left = parent.screenLeft + (screen.width/2) + left_offset;
            
                //alert('x:' + parent.screenLeft + ' w:' + screen.width + ' left:' + left);
            }
        } //!bSizeOverride
                         
        name = name.replace(/[^A-Za-z0-9\_]/ig,'')
	    var newWin = window.open(location,name,"location=yes,toolbar=no,resizable=yes,scrollbars=yes,height=" + height + ",width=" + width + ",top="+top+",left="+left+",alwaysRaised=yes");
        
        if(parent.right_frame && parent.right_frame.frm_activate) parent.right_frame.frm_activate();
       
        // new window may not be available yet     
        try{
	       newWin.focus();
	       }
	    catch(x){               
	            }
        
        // Don't bother adding popup windows that are not generated forms, because the javascript
        // vars won't be defined.
        if(location.indexOf("nfg.aspx") > -1)
        {
        
        if(!stickaround  || (stickaround == 'no_stickaround')) 
            stickaround = false;
        else
            stickaround = true;
        
        if(!stickaround) 
            childWindows.push(newWin);
            
        childWindowsAll.push(newWin);
        
        // can't set new_window's id directly because it is not yet available.  The child will set our
        // childAvailable variable once its onload is complete.
        var icount = 0;
        var intervalId;
        var newId;
        
        intervalId =    setInterval(function(){
                                        icount++;
        
                                        if(childAvailable || icount > 30)
                                        {
                                            clearInterval(intervalId);
                                                                                
                                            framesetMgrPtr.winMgr.registerWin(newWin,winId,stickaround);

                                            childAvailable = false;

                                            if(framesetMgrPtr.framesetWin.right_frame.ge('popuptitlediv'))
                                                framesetMgrPtr.framesetWin.right_frame.showPopupTitles(); 
                                        } 
                                    },100);
        }
        
        //var newId = framesetMgrPtr.winMgr.registerWin(newWin,winId,stickaround); 
         
    } // open_popup_window
    
    // desc - creates div showing titles of all open popup windows
    // usage - right frame - depends on global array childWindowsAll
    function showPopupTitlesOld(caller)
    {   
        if(caller)
        {   
            setTimeout('showPopupTitles()',300);
            return;
        }      
    
        var d = makeDraggableDiv();
        d.className = 'popupTitles';
        if(ge('popuptitlediv')) dismiss(ge('popuptitlediv'))();
        d.id = 'popuptitlediv';
                
        var cWin;
        var title = "Main Form";
        var oUL = ce('ul');
        var oLI = ce('li');
        var oA = ce('a');
        
        oUL.className = 'popupMenu'
        oA.innerHTML = title;
        oA.setAttribute("href","javascript: dismiss(ge('popuptitlediv'))();");
        ac(oA,oLI);
        
        ac(oLI,oUL);
                    
        for(var i in childWindowsAll)
        {
            cWin = childWindowsAll[i];
                        
            if(!cWin.closed)
            {
                title = cWin.document.title;
                
                if(!title)
                    title = cWin.location.pathname;
                           
                oLI = ce('li');
                oA = ce('a');
                oA.innerHTML = title;
                oA.setAttribute("href","javascript: dismiss(ge('popuptitlediv'))(); var cWin = childWindowsAll[" + i + "]; if(!cWin.closed) cWin.focus();");
                               
                ac(oA,oLI);
                ac(oLI,oUL);
                           
                //ac(ct(title),d);
                //ac(ce('br'),d);
            }
        }
        
        //cti_alert('innerhtm:' + oUL.innerHTML);
        
        ac(oUL,d);
        
        d.style.top = document.body.scrollTop +'px';
        d.style.left = (document.body.clientWidth - d.offsetWidth) + 'px';
        
        //alert('div h/w:' + d.offsetHeight + '/' + d.offsetWidth + ' / scrolltop:' + document.body.scrollTop + ' clientheight: '  + document.body.clientHeight);
                
    } // showPopupTitlesOld
    
    // desc - creates div showing titles of all open popup windows
    // usage - right frame - depends on global object 
    // desc - creates div showing titles of all open popup windows
    // usage - right frame - depends on global object 
    function showPopupTitles(caller)
	{   
        if(caller)
        {   
            setTimeout('showPopupTitles()',300);
            return;
        }     
    
        var d = makeDraggableDiv();
        d.className = 'popupTitles';
        if(ge('popuptitlediv')) dismiss(ge('popuptitlediv'))();
        d.id = 'popuptitlediv';
                
        var cWin;
        var pWin;
        var title = "Main Form";
        var oUL = ce('ul');
        var oLI = ce('li');
        var oA = ce('a');
        var level;
        var winId;
        var lmarg = 0;
        
        oUL.className = 'popupMenu'
        oA.innerHTML = title;
        oA.setAttribute("href","javascript: dismiss(ge('popuptitlediv'))();");
        ac(oA,oLI);
            
        ac(oLI,oUL);
                
        var winMgr = framesetMgrPtr.winMgr;
        
        //alert('assocLength:' + winMgr.aWins.assocLength);
                    
        for(var i = 0, alen = winMgr.aWins.assocLength; i < alen; i++ )
        {                    
            var aWin = winMgr.aWins.assocGetByIndex(i);
                            
            cWin = aWin[0];
            pWinId = aWin[1]; 
            level = aWin[3];
                       
            if(!pWinId)
                pWinId = "No Parent";
                        
            if(!cWin.closed)
            {
                winId = cWin.winId; //aWin[4];
            
                var title = cWin.document.title;
                
                if(!title)
                    title = cWin.location.pathname;
                            
                        //alert('processing title of ' + title);
                                               
                    oLI = ce('li');
                    lmarg = level * 8;
                    oLI.style.paddingLeft = lmarg + "px";
                    
                    oA = ce('a');
                    oA.innerHTML = title; // + "(" + level + ")" + ":" + winId + ":" + pWinId;
                    oA.setAttribute("href","javascript:framesetMgrPtr.winMgr.setWinFocus('" + winId + "');//dismiss(ge('popuptitlediv'))();"); 
                               
                    ac(oA,oLI);
                    ac(oLI,oUL);
            }
        }
        
        //cti_alert('innerhtm:' + oUL.innerHTML);
        
        ac(oUL,d);
        
        d.style.top = document.body.scrollTop +'px';
        d.style.left = (document.body.clientWidth - d.offsetWidth) + 'px';
        
         //alert('div h/w:' + d.offsetHeight + '/' + d.offsetWidth + ' / scrolltop:' + document.body.scrollTop + ' clientheight: '  + document.body.clientHeight);    
    } // showPopupTitles
    

    //desc  - EMBEDDED CODE
    //usage - popup windows, closes them on navigation away
    ctiBrowser().attachEvent("onunload",function(){
        for(var i in childWindows)
            if(!childWindows[i].closed)
                childWindows[i].close()
                
        
        if(framesetMgrPtr && winId)
            try{
                framesetMgrPtr.winCloseNotify(winId);
            }
            catch(x){ // trapping for Can't execute code from a freed script on a frameset refresh
                return;
            }
        //else alert('parentFramesetMgr not defined'); NOTE: unload event called at least 6 times on a refresh
               
    })
    
    
//**************************************************
//END - POPUPS
//**************************************************



//**************************************************
//BEGIN - NFG FORM - INITIALIZATION AND GENERATION ROUTINES
// Notes:
//  - 
//**************************************************

    //desc  - probably an experiment for non-bound forms
    //usage - not sure
    function init_gen_formx()
    {
        var form_id = window.document.forms[0].getAttribute('name').substring(5);
        var tbl_form = document.getElementById("tbl_" + form_id);

        tbl_form.style.display = '';
    }

    //desc  - onload function for generated forms.  Executes databinding.
    //usage - nfg
    function init_gen_form()
    {
        //alert('init_gen_form');
	    var tstart = new Date();

	    var form_id = window.document.forms[0].getAttribute('name').substring(5);  // assumes first form named form_ + form_id
    	
	    //syncPost('cti_change_session.aspx','key=stamp&value='+ form_id); //METRICS CALCULATION - 08/07
    	
	    var tbl_form = document.getElementById("tbl_" + form_id);
    	
	    if(parent.top_frame && parent.top_frame.ge && parent.top_frame.ge('incorrect_header')) parent.top_frame.location.reload()
    	
	    if(sessionLoadingDebug()) 
	        wait("Loading data...",true)
	    else
	        wait("Loading information....")
	        	    
	    if(sessionLoadingDebug()) 
		    wait("Binding data...",true)
    	else
	        wait("Displaying page...")
        
	    clientMgr.bind();
    	
	    tbl_form.style.display = '';
	    
	    cti_format();
    	
	    // The following call is causing the bindMgr attributes to go out of scope
	    //cti_update_javascripts();
    	
        if(sessionLoadingDebug()) wait("Loading domains...",true)
        //fill_domains(null,true);
	    fill_radio_domains();
	    fill_checkbox_domains();
	    fill_calendars();
	    loadRSSFields()
	    setDynamicAnchors(document)
	    fireGraphs();
	    resizeTextAreas()
	    transformListTransforms();
	    makeDrilldownMenus();
        if(sessionLoadingDebug()) 
            wait("Load complete!",true)
                    
	    if($root('id6') && $root('id6') != '') {goToAnchor($root('id6'))} // what is this???
            	           
        browser.attachEvent("onfocus", frm_activate)
        frm_activate();
        
        if(syncPost('cti_retrieve_session.aspx','shortkey=_run_mode') == 'I')
        {
            var validateEl =    function(n) {
	                            if( (!/(input|select|textarea)/i.test(n.tagName)) ||
	                                (n.type == "hidden") || 
	                                (n.readonly) || 
	                                (n.disabled) ||
	                                (n.className == "readonly") ||
	                                (check_hidden(n))) 
	                                return false; 
	                            else
	                                return true;
	                     };

    	    // look for the first bound field on the form

    	    var notFound = true;
    	    
    	    for(var i=0, len=clientMgr.bindMgr.boundDataEls.length; ((i < len) && notFound); i++)
    	    {
    	        cand = clientMgr.bindMgr.boundDataEls[i][0];
    	        
    	        if(validateEl(cand))
    	            notFound = false;
    	    }
    	    
    	    if(!notFound)
    	        try{
	                //cti_alert('putting focus on ' + cand.id + ' of type ' + cand.type);
                    cand.focus();
	            }
	            catch(x){
	                cti_alert('could not put focus on ' + cand.getAttribute("bindFld") + '\r' + x.message);
	            }
    	   
	    } // If Insert Mode
    	
	    var anchor = syncPost('cti_retrieve_session.aspx','shortkey=SessionCurrPage.PageStateAnchor')	
	    if(anchor != '')
	        goToAnchor(anchor)
	    if(error_page && !error_page.closed) error_page.ok_button.focus()
    	
	    var tfin = new Date();   
    		 
        clientMgr.bindMgr.times.push(new Array("init_gen_form",tstart,tfin));
    	
        if(window.opener)
            window.opener.childAvailable = true;
    	
        //clientMgr.bindMgr.dumpTimes();
        endWait()
    } // init_gen_form
//**************************************************
//END - NFG FORM - INITIALIZATION AND GENERATION ROUTINES
//**************************************************

//**************************************************
//BEGIN - NFG FORM ROUTINES - MISCELLANEOUS
// Notes:
//  - 
//**************************************************

    //desc  - creates all dynamic anchors
    //usage - addRow & init_gen_form
    function setDynamicAnchors(root)
    {
        var anchors = root.getElementsByTagName('a')
        for(var i = 0,numanchors = anchors.length; i < numanchors; i++)
        {
            var anchor = anchors[i]            
            if(anchor && anchor.getAttribute && anchor.getAttribute('namesrcfield') && anchor.getAttribute('namesrcfield') != '')
            {
                var nameSrcField = anchor.getAttribute('namesrcfield')
                var anchorname = (/\@/.test(nameSrcField)?$root(nameSrcField.substring(1)):$sibling(anchor,nameSrcField.substring(1)))
                anchor.outerHTML = ''.anchor(anchorname) //ie
            }
        }
    }

    //fires all graphs (if they request it)
    //usage - form initialization
    function fireGraphs()
    {
        var graphs = document.getElementsByTagName('img')
        for(var i = 0, ng = graphs.length; i < ng; i++)
            if(graphs[i].getAttribute && graphs[i].getAttribute('graph_on_load') == 'y')
                fire_graph(graphs[i])
    }

    //refreshes a graph
    //usage - form initialization, graphs, graph refresh
    function fire_graph(img)
    {
        map = img.getAttribute('map')
        args = subpopup(img,img.getAttribute('args'))
        atts = ['graph_sp','title','x_title','y_title','x_interval','y_interval','x_units','y_units','dataset_titles','link_mapping']
        qstr = ''
        for(var i in atts)
        {
            a = atts[i]
            x = img.getAttribute(a)
            if(x)
                qstr += '&'+a+'='+x
        }
        qstr += args
        img.src = ''
        
        //alert('calling ' + qstr.substring(1) + ' map:' + map);
        
        img.src = 'cti_graph.aspx?'+qstr.substring(1)
        if(map)
        {      
            node_before(img).innerHTML = syncPost('cti_graph_map.aspx?'+qstr.substring(1),null,null,null)
            if(first_child(node_before(img)))
                img.useMap = '#'+first_child(node_before(img)).name
        }
    }
    
    // desc - executes dynamic mailto link
    // usage - email subcontrol
    function fire_mailto(sib,addr)
    {
        var aMT = ce('a');
        
        aMT.href = 'mailto:' + addr;
        aMT.style.display = 'none';
        
        ac(aMT,sib.parentNode);
        
        aMT.click();
        
    } // fire_mailto

    // Renumbers row labels in child forms
    //usage - @sb?
    //function renumber_child_rows(ctbl,del_index,ascending,proc_switches,cont_node){
	  //  var row_label_coll;
	    //var j;
//	    var textNode;
//	    var tHeadRC = 0;
//	    var startIdx;
//	    var endIdx;
//	    var rowNum;
//	    var childi = 0;
    	
//	    if(arguments.length < 4)
//		    proc_switches = false;
    	
//	    if(ctbl.tHead)
//		    tHeadRC = ctbl.tHead.rows.length;
    		
//	    if(ascending){
//		    startIdx = del_index;
//		    endIdx = ctbl.rows.length;
//	    }
//	    else{
//		    startIdx = tHeadRC; // thead plus seed row
//		    endIdx = del_index;
//	    }
    	
//	    if(proc_switches){
//		    if(cont_node.hasChildNodes && (first_child(cont_node).hasChildNodes) && (first_child(first_child(cont_node)).nodeType == 3))
//			    childi = 1;
//	    }
    	
//	    //alert('renumber:  start:' + startIdx + ', end:' + endIdx + ' tablelen:' + ctbl.rows.length);
    	
//	    for(var i= startIdx;i < endIdx;i++){
    	
//		    if(proc_switches){
//			    processSwitches(ctbl.rows[i],false,cont_node.childNodes[childi]);
//			    childi++;
//		    }
    	
//		    row_label_coll = ctbl.rows[i].getElementsByTagName("span");
    			
//		    for(j=0;j < row_label_coll.length; j++){
//			    if(row_label_coll[j].className == "rowlabel"){
//				    textNode = getTextNode(row_label_coll[j]);
  //  									
	//			    if(textNode){
	//				    if(ascending)
	//					    rowNum = ((i + 1) - tHeadRC);
	//				    else
	//					    rowNum = (ctbl.rows.length - i);
    //				
	//				    textNode.nodeValue = "(# " + rowNum + ")";
	//			    }
    				
	//			    break; // exit for j loop
	//		    }	
	//	    }
	  //  }				
   // } // renumber_child_rows

    // desc  - if table is ready then display it
    function handleReadyStateChange(tbl){
	    if(tbl.readyState == 'complete'){
    	
	    if (tbl_has_data(tbl)){
		    tbl.style.display = ''
		    //alert('table: ' + tbl.id + ' set to display');
	    }
	    else{
		    tbl.style.display = 'none';
		    //alert('table: ' + tbl.id + ' hidden');
	    }
    		
	    //setTimeout('init_gen_form()',100);
	    }
    }

    //desc  - pops up a window with a texarea in it: beats alerts
    //usage - embedded debugging code
    function cti_alert(text,name)
    {
        if(name == null) name = ''
	    p = window.open('','_blank','');
	    ta = p.document.body.appendChild(p.document.createElement('textarea')) //('<textarea style="width:100%;height:100%;">'+text+'</textarea>');
	    ta.style.width = '100%'
	    ta.style.height = '100%'
	    ta.value = text
	    p.document.title = name;
	    p.focus();
	    return p;
    }
        
    //desc  - formats all fields based on their formatting attributes
    //usage - form initialization, formatting subtypes
    function cti_format()
    {
	    var els = clientMgr.bindMgr.boundDataEls
    	
	    for(var el in els)
	    {
		    var e = els[el][0]
		    if(e.formatregex)
		    {
			    var r = e.formatregex.split(" | ");
			    var x = new RegExp(r[0], "ig");
			    var f = r[1]
			    e.value = e.value.replace(x,f);
		    }
    		
	    }
    }

    //desc  - used to update javascripts for backwards compatability
    //usage - form initialization
    //      - not really needed anymore
    function cti_update_javascripts()
    {
        var toreplace = [];
        var updjstrace = []
        
        
        for(var tar in toreplace)
        {
        
            var els = document.getElementsByTagName('script');
            for(var i in els)
            {
                var el = els[i];
                if(el.text && !/ctiClient/.test(el.text))
                {
                    //trace.append('\n----------from-------------\n' + el.text)
                    el.text = el.text.replace(tar, toreplace[tar]);
                    //trace.append('\n-----------to--------------\n' + el.text);
                    //trace.append('\n\n\n\n')
                }
            }
        }
        //cti_alert(trace.join("\n"));
    }
//**************************************************
//END - NFG FORM ROUTINES - MISCELLANEOUS
//**************************************************


//**************************************************
//BEGIN - NFG FORM - GET ELEMENT ROUTINES
// Notes:
//  - 
//**************************************************

    //desc  - Get Elements By Attribute
    //usage - not used, nice idea, but SLOW
    //function  getEBArecursive (list, node, att) {
    //    for (var i=node.childNodes.length-1; i>=0; i--)
    //    {
    //        var child = node.childNodes.item(i);
    //            if ( child.nodeType == 1 ) 
    //            {
    //                if ( child.getAttribute(att) ) 
    //                {
    //                   list.push(child);
    //                }
    //            this.getEBArecursive(list, child, att);
    //            }
    //    }
    //  }
      
    //desc  - Gets the lowest level DOM element that contains the 
    //        given source element and has the target attribute defined.
    //usage - binding code
    function getContainingElementByAttrib(srcEl, targAttrib){
	    var n = srcEl;
        if(!n) return n;
	    while(n.parentNode && n.parentNode.getAttribute && (!n.parentNode.getAttribute(targAttrib)))
		    n = n.parentNode;

	    return n.parentNode;
    }
      
    //desc  - Gets the lowest level DOM element that contains the 
    //        given source element and has the target tag name.
    //usage - binding code
    function getContainingElementByTagName(srcEl, targName){
	    var n = srcEl;
	    targName = targName.toLowerCase();
        
        if(!n) return n;
	    while(n.parentNode && n.parentNode.nodeName.toLowerCase() != targName)
		    n = n.parentNode;

	    return n.parentNode;
    }

    //desc  - Gets all elements below the reference node that contain a specific attribute
    //usage - binding code
    //      - each one of these calls should be replaceable with
    //           getElementsByAttributIterTest2(node,attribute,'*')
    function getElementsByAttributeIter(node, attribute, maxInstance, traceOn)
    {
        var aEls = getElementsByAttributeIterTest2b(node,attribute,'*')[0];
        if(maxInstance)
            return aEls.slice(0,maxInstance)
        else
            return aEls
    } //getElementsByAttributeIter

    //desc  - Gets all elements below the reference node that contain a specific attribute
    //usage - binding code
    function getElementsByAttributeIterTest(node, attribute, eligEls, maxInstance, traceOn, validFun)
    {
        var rv = [];
        var tnode = node;
        var tracestring = '';
        var allEligible = false;
        var numVisits = 0;
        
        if(!tnode)
            return rv;
        
        if(arguments.length < 5)
            traceOn = false;
        
        if(arguments.length < 4)
            maxInstance = 9999; // all
            
        if(arguments.length < 3)
            eligEls = "all"
            
        if(!traceOn)
            tracestring = 'Trace Not Turned On';
            
        if(eligEls = "all")
            allEligible = true;
        
        do
        {
            if(tnode.nodeType == 1){
                if((allEligible) || (eligEls.indexOf(tnode.nodeName) > -1)){               
                    if(tnode.getAttribute(attribute)){
                        if((arguments.length < 6) || (validFun(tnode))){
                            rv.push(tnode);
                            if(rv.length == maxInstance)
                                return rv;
                        }
                    }
                }
            }
                                    
            if(first_child(tnode))
            {
                tnode = first_child(tnode); numVisits++;
                if(traceOn)
                    tracestring += 'Went down to ' + tnode.nodeName + '\n'
            }
            else if(tnode == tnode.parentNode.lastChild || !tnode.nextSibling )
            {
                do
                {
                    tnode = tnode.parentNode; numVisits++;
                    if(traceOn)
                        tracestring += 'Went up to ' + tnode.nodeName + '\n'
                }
                while(tnode && !tnode.nextSibling && tnode != node)
                if(tnode != node)
                {
                    tnode = tnode.nextSibling; numVisits++;
                    if(traceOn)
                        tracestring += 'Went right to ' + tnode.nodeName + '\n'
                }                
            }   
            else
            {
                tnode = tnode.nextSibling; numVisits++;
                if(traceOn)
                    tracestring += 'Went right to ' + tnode.nodeName + '\n'
            }
        }
        while(tnode && tnode != node)
        return rv;
    } //getElementsByAttributeIterTest


    //desc  - Gets all elements below the reference node that contain a specific attribute/attribute value
    //usage - binding code
    //each of these should be replaceable with a call to
    //  getElementsByAttributeIterTest2(node,attributes,'*',attValTarget)   
    function getElementsByAttributeIterTest3b(node, attributes, attValTarget, elIdxs)
    {
    
        var rv = new Array();
        var re = new Array();
        var ri = new Array();
        var elIdx;
        if(!attributes) return rv;
        
        var atts = attributes.split('|')
        
        for(var i=0, aLen=atts.length; i < aLen; i++)
        {
            if(elIdxs && (elIdxs.length > i))
                elIdx = elIdxs[i];
            else
                elIdx = null;
        
            var res = getElementsByAttributeIterTest2b(node,atts[i],'*',attValTarget,elIdx);
            
            re.push(res[0]);
            ri.push(res[1]);
        }
        
        rv[0] = re;
        rv[1] = ri;
        
        return rv;
        
    } //getElementsByAttributeIterTest3b

    // desc - Gets all elements below the reference node that contain a specific attribute/attribute value
    // attValTarget - optional.  Specific attribute target value to look for
    // elIdxs - optional.  List of node indexes to use instead of searching against attributes again.
    // iNodes - optional.  If you have the nodes to search, don't need to get them again
    function getElementsByAttributeIterTest2b(node, attribute, eligEls, attValTarget, elIdxs, iNodes)
    {
        var rv = new Array();
        var re = new Array();
        var ri;
        
        var tnode;
        var elList = eligEls.split("|");
        var iLen = 0;
        
        if(!node)
            return rv;
            
        if(arguments.length < 4)
            attValTarget = null;
                        
        // mainly used for subcontrols - depends on elList, re and tnode vars and attValTarget, attribute parms
        // from getElementsByAttributeIterTest2
        function secondLevel()
        {
            var attVal2;
            var iNodes2 = tnode.getElementsByTagName(elList[1]);
            
            if(iNodes2.length > 0){
                var tparent = iNodes2[0].parentNode;
                
                if((tparent.nodeName == "thead") && (iNodes2.length > 1))
                    tparent = iNodes2[1].parentNode;
                    
                iNodes2 = tparent.childNodes;
                
                //if(attValTarget && (attValTarget == 'phr_family_history_only.phr_family_history_subcontrol_container.phr_family_history_subcontrol.phr_family_history_child_form_put_button_container.phr_family_history_child_form_put_button.phr_family_history_diagnosis_child_form_put_button_container'))
                //    alert('checking for tds...' + iNodes2.length);
                for (var i2=0, n2= iNodes2.length; i2 < n2; i2++){
                        if(is_all_ws(iNodes2[i2])) continue;
                        
                        attVal2 = iNodes2[i2].getAttribute(attribute);
                    
                        if(attVal2 && ((!attValTarget) || (attValTarget && (attValTarget == attVal2))))
                        {
                            //alert('found our td at node ' + i2);
                            re.push(iNodes2[i2]);
                        }
                } // for
            }   
        } // secondLevel
        
        if(!iNodes){
            var elName = elList[0];
                    
            iNodes = node.getElementsByTagName(elName);
            
            // makes search inclusive of target node without going up to parent
            if(((elName == "*") || (elName == node.nodeName)) && (node.getAttribute(attribute))){
                var tempNodes = iNodes;
                
                iNodes = new Array();
                
                iNodes.push(node)
                
                // getElementsByTagName node list is not an actual array.
                for (var i=0, n=tempNodes.length; i < n; i++)
                    iNodes.push(tempNodes[i]);
            }
            
        } // !iNodes
            
        if(elIdxs)
            iLen = elIdxs.length;
        
        var bSL = false;
        if(elList.length > 1)
            bSL = true;
            
        if(iLen > 0)
        {          
            
            for(var i=0; i < iLen; i++)
            {
                tnode = iNodes[elIdxs[i]];
                re.push(tnode);
                
                if(bSL)
                    secondLevel();
            } //for
            
            ri = elIdxs;
        }
        else
        {
                
            ri = new Array();

            for (var i=0, n=iNodes.length; i < n; i++)
            {
                tnode = iNodes[i];
                attVal = tnode.getAttribute(attribute);
                if(attVal && ((!attValTarget) || (attValTarget && (attValTarget == attVal))))
                {
                    re.push(tnode);
                    ri.push(i);            
                }
 
                if(bSL)
                    secondLevel();

            } //for
        } // else
                 
        rv[0] = re;
        rv[1] = ri;
        
        return rv;
    } //getElementsByAttributeIterTest2b

    //desc  - Gets all elements below the reference node that contain a specific attribute and value
    //usage - recently replaced in renumber rows
    //function getElementsByAttributeValue (node, att, value){
    //    var rv = getElementsByAttributeIter(node, att);

    //    if(rv.length > 0)
	//	    for(var i = rv.length - 1; i >= 0; i--){
	//		    if(rv[i].getAttribute(att) != value)
	//			    rv.splice(i,1);
//		    }
//	    return rv;
  //  }
    
    //desc - Gets first occurrence of child with given nodeName
    //usage - utility routines such as toggleTreeDisplay
    function getFirstChildByNodeName(host, nn){
        if(host && host.hasChildNodes()){
            for(var i=0, kid; kid = host.childNodes[i]; i++){
                    if(kid.nodeName == nn.toUpperCase())
                        return kid;
            }
        }
        return null;
    } //getFirstChildByNodeName(

    //desc  - Finds text node of a given node
    //usage - binding code
    function getTextNode(host){
	    if(host && host.hasChildNodes()){
		    for(var i=0, len=host.childNodes.length;i < len;i++){
			    if(host.childNodes[i].nodeType == 3)
				    return host.childNodes[i];
		    }
	    }
	    return null;
    }
//**************************************************
//END - NFG FORM - GET ELEMENT ROUTINES
//**************************************************


//**************************************************
//BEGIN - SEARCH FORMS
// Notes:
//  - Runs and is used by the search forms
//**************************************************
 
    //desc  - cleaned up call to cti_retrieve
    //usage - not used yet.
    function getForm(form_code,page_num,page_size,record_element)
    {
       return cti_retrieve(null,form_code,null,page_num,page_size,record_element)
    }

    //desc  - for dynamic report section retrieval
    //
    //    src_element_name:not used
    //    dest_element_name: the form_code to retrieve
    //    sp_name: not used
    //    page_num: the page number (for paging)
    //    page_size: the page size (for paging)
    //    record_count_element_name: for driving the record count
    //    replacingMain: not used
    //
    //usage - search forms
    function cti_retrieve(src_element_name, dest_element_name, sp_name, page_num, page_size, record_count_element_name,replacingMain)
    {
        var debugKey = (window.event && window.event.shiftKey && window.event.ctrlKey)
        
        if(sessionLoadingDebug())
            wait('Retrieving results...')
        else
            wait()
        //alert('calling cti_retrieve with '+arguments)
	    var src = clientMgr.bindMgr.isle;
        var fMgr;
        
        w = window.opener   //because we may be several popups out
        while(w && !fMgr)
        {
            fMgr = w.parent.framesetMgr;
            w = w.opener
        }
        if(!fMgr) fMgr =  parent.framesetMgr;
    	
	    var req = 'cti_sp_retrieve.aspx?dest='+dest_element_name;
    	
	    if(page_num) req += '&page_num='+page_num
	    if(page_size) req += '&page_size='+page_size
    	
	    if(gv('debugBox') == 'Y' || debugKey) 
	        cti_alert('Posting to '+req+'\n\n'+(src.xml || src),'requesting '+dest_element_name)
    	
	    var response = syncPost(req, src, null, true);
    	
	    if(gv('debugBox') == 'Y' || debugKey) 
	        alert(response);
	    
	    var responseXML = response.documentElement;
    	
	    if(responseXML)
	    {
	        //alert(browser.xPathSingle(responseXML,'/response/data/total_duration'))
	        var responseXML = browser.xPathSingle(response.documentElement,('/response/data'))
            
            if(record_count_element_name) {
	            clientMgr.bindMgr.setXMLValue(record_count_element_name,responseXML.getAttribute("totalRecords"),clientMgr.bindMgr.isle);
	            browser.fireEvent(ge(clientMgr.getFormCode()+'_'+record_count_element_name),"onpropertychange")
	        }
	        /*else
	        {
	           alert('did not fire onchange on ' + clientMgr.bindMgr.getFormCode()+'_'+record_count_element_name + '('+ge(clientMgr.bindMgr.getFormCode()+'_'+record_count_element_name)+')')
	        }*/
	        //var xml = document.getElementsByTagName('xml')[0];
    	    
	        if(gv('debugBox') == 'Y' || debugKey) show_island(responseXML);
    	    
	        if(gv('debugBox') == 'Y' || debugKey) alert('calling addFrag with ' + first_child(responseXML).nodeName,'response for '+dest_element_name);

    	    
	        if(responseXML)
	        {
	                var error_found = responseXML.getAttribute('error_found')
	                var err_type = responseXML.getAttribute('message_type')
    	            var err_msg = responseXML.getAttribute('message')
    	            if(err_msg) display_error_page(err_msg,err_type)
	                datanode = browser.xPathSingle(responseXML,'//data/*')
	    	        if(datanode) 
   	    	        {
                        if(sessionLoadingDebug()) wait('Got results!',true)
                        if(sessionLoadingDebug()) wait('Binding results...',true)
	    	            clientMgr.bindMgr.addFrag(datanode);
	    	            if (sessionLoadingDebug()) wait('Complete!', true);
	    	            // reapply_titlebreaks defined in subtype for script_js titlebreaks
	    	            if (typeof reapply_titlebreaks == 'function')
	    	                reapply_titlebreaks();
	    	        }
	        }else{
	            if(sessionLoadingDebug()) wait('No Records Returned!',true)
	        }
        }else{
            alert('no responsexml')
        }
        endWait()
    }//cti_retrieve
//**************************************************
//END - CTI_RETRIEVE
//**************************************************


//**************************************************
//BEGIN - CTI_VERIFY ROUTINES
// Notes:
//  - Runs and is used by Verify Forms and Single-Row Saves
//**************************************************
//desc  - 
//      - src_el - the html element related to the xml data island to grab your verify data from (mandatory)
//      - verify_form_code - the form_code in weba.md_form whose lf_sp_name is the sp you want to run
//      - tcfc - Target Child Form Code - the target_form_code that you want to pull the xref relationship from
//      - args - a subpopup-formatted set of arguments
//usage - written for verify forms  
function cti_verify(src_el, verify_form_code, tcfc, args)
{
    var debug = false
	var src = getRelatedXMLNode(src_el);
	if(/Microsoft/.test(navigator.appName)) src = src.xml
	else {
	    newsrc = document.implementation.createDocument('','',null)
	    newsrc.appendChild(src.cloneNode(true))
	    src = newsrc
	}
	if(!tcfc) tcfc = clientMgr.getFormCode()
	var target_row = clientMgr.bindMgr.getBoundTrigIdx(src_el)
	
	var fMgr;
	
    if(window.opener)
    {
      if(!window.opener.closed)
        fMgr = window.opener.parent.framesetMgr;
    }
    else
      fMgr =  parent.framesetMgr;
	
	if(!fMgr) fMgr = new ctiFrameset();
	    
	var req = 'cti_sp_retrieve.aspx?dest='+verify_form_code;
	req += '&xref_name_htm='+src_el.id
	req += '&target_child_form_code='+tcfc
	if(args) req += subpopup(src_el,args)

	if(debug || gv('debugBox') == 'Y')
	//if (verify_form_code == 'share_email_reminder_evf')
	    cti_alert('Posting to '+req+'\n\n'+src,'verify request for ' + verify_form_code)
	
	var response = syncPost(req, src, null, true);
	if(debug || gv('debugBox') == 'Y')
	    alert(response.xml);
	
	if(response.documentElement)
	{
	    var seedXML
        if(/Microsoft/.test(navigator.appName))
            seedXML         = browser.xPathSingle(response.documentElement,'/response/seedData/*')
	    else
            seedXML         = browser.xPathSingle(response.documentElement,'//textarea')
    
        var responseXML     = browser.xPathSingle(response.documentElement,'/response/data')

	    if(debug || gv('debugBox') == 'Y') show_island(responseXML);
	    if(debug || gv('debugBox') == 'Y') show_island(seedXML);
	    
        var err_found = responseXML.getAttribute('error_found')
	    var err_type = responseXML.getAttribute('message_type')
	    var err_msg = responseXML.getAttribute('message')
	    
	    if(err_msg && err_msg != '')
	        display_error_page(err_msg,err_type)

	    if(responseXML && seedXML)
	    {
    	    if(debug || gv('debugBox') == 'Y') cti_alert(responseXML.xml,'verify response for '+verify_form_code)
    	   
    	    var insert_data = browser.xPathSingle(responseXML,'.//'+verify_form_code)
    	    var seed_data = browser.xPathSingle(seedXML,'.//'+verify_form_code)
    	    if(insert_data && seed_data)
    	    {
    	        //if (debug || gv('debugBox') == 'Y')
    	        if (verify_form_code == 'prvdr_objective_vf')
    	        cti_alert('inserted data\n\n'+browser.xmlText(insert_data),'data inserted for '+verify_form_code+' target ' + target_row)
    	        insert_form_data(insert_data,seed_data,target_row)
    	    }
	    }
	    if(err_found == 'Y') return false; else return true;
	    
    }
    return false;
}//cti_verify

//desc  - Initiates ajax call to cti_sp_retrieve, returning status and any associated data as xml
//      - src_el - the html element related to the xml data island to grab your verify data from (mandatory)
//      - verify_form_code - the form_code in weba.md_form whose lf_sp_name is the sp you want to run
//      - args - a subpopup-formatted set of arguments to be passed to cti_sp_retrieve
//usage - verify forms requiring some  data to be returned and used by caller
function cti_verify2(src_el,verify_form_code,args)
{
    var src = getRelatedXMLNode(src_el);
    var browser = ctiBrowser();
    var isIE = browser.isIE;
    var bOkay = false;
    var returnXML;
    
    if(isIE)
        src = src.xml
	else 
	    {
	    newsrc = document.implementation.createDocument('','',null)
	    newsrc.appendChild(src.cloneNode(true))
	    src = newsrc
	    }
	
	var req = 'cti_sp_retrieve.aspx?dest='+verify_form_code;
	
	if(args) 
	    req += subpopup(src_el,args)
	
    //cti_alert('Posting to '+req+'\n\n'+src,'verify request for ' + verify_form_code)
	
	var response = syncPost(req, src, null, true);
	
    //alert(response.xml);
	
    if(response.documentElement)
	{   
        var responseXML     = browser.xPathSingle(response.documentElement,'/response/data')
    
        var err_found = responseXML.getAttribute('error_found')
	    var err_type = responseXML.getAttribute('message_type')
	    var err_msg = responseXML.getAttribute('message')
	    
	    if(err_msg && err_msg != '')
	        display_error_page(err_msg,err_type)

	    if(responseXML)
	    {
    	    //cti_alert(responseXML.xml,'verify response for '+verify_form_code);
    	   
    	    returnXML = browser.xPathSingle(response.documentElement,'.//'+verify_form_code);
    	    
    	    //cti_alert('xpath single for ' + '/response/data/'+verify_form_code +  ' is ' + returnXML.xml);
	    }
	    
	    if(err_found == 'N') 
	        bOkay = true;
    }
    var aRet = new Array(bOkay,returnXML);
    
    return aRet;
} // cti_verify2

//**************************************************
//END - CTI_VERIFY ROUTINES
//**************************************************

//**************************************************
//BEGIN - XML
// Notes:
//  - 
//**************************************************

    //element cross-reference components

    //--- not tested
    //usage - not used
    function $parent(node,key)       //grab from parent record
    {
        var myParentsSibling = null
        
        var parent = getRelatedXMLNode(node).parentNode
        if(parent && key && key != '') 
        {
            parentsiblings = parent.getElementsByTagName(key);
            if(parentsiblings.length) myParentSibling = parentsiblings[0];
        }
        
        if(myParentsSibling)
        {
            if(myParentsSibling.nodeType == 3 && myParentsSibling.nodeValue != undefined) return myParentsSibling.nodeValue;
            if(myParentsSibling.nodeType == 1 && first_child(myParentsSibling)
                   && first_child(myParentsSibling).nodeType == 3 && first_child(myParentsSibling).nodeValue != undefined) return first_child(myParentsSibling).nodeValue;
        }
        return '';
    }

    //gets sibling value using a node and a column name
    // helper routine - xml
    //usage - $sibling, gethtmlsibling
    //Note:  Since getRelatedXMLNode is dependent on the binding manager, why not just
    // use the binding manager's getXMLSibling instead?
    function sibling(node,key)
    {
        var siblings = getRelatedXMLNode(node)
        if(siblings && key && key != '') 
        {   
            siblings = siblings.getElementsByTagName(key);
            
            if(siblings.length) return siblings[0];
        }
        return null;
    }

    //usage - subpopup, anywhere you need to get a sibling value
    // Note: Since sibling depends on the binding manager, why not just
    // use the binding manager's getXMLSiblingVal instead?
    function $sibling(node,key)      //grab from sibling
    {
        var mySibling = sibling(node,key)
        
        if(mySibling)
        {
            if(mySibling.nodeType == 3 && mySibling.nodeValue != undefined) return mySibling.nodeValue;
            if(mySibling.nodeType == 1 && first_child(mySibling)
                   && first_child(mySibling).nodeType == 3 && first_child(mySibling).nodeValue != undefined) return first_child(mySibling).nodeValue;
        }
        return '';
    }

    //grabs a value from the topmost form
    //usage - subpopup, anywhere you need to refer to a root value
    //Note: In what case would clientMgr and bindMgr not be defined?
    // consider replacing this with a similar method in bindMgr
    // Also, code is suspect because get_element_text_by_tag_name uses
    // getElementsByTagName, so if the key actually exists in a child
    // but not the main form, this routine will return that child value.
    function $root(key)
    {
        var rootxml
        if(clientMgr && clientMgr.bindMgr)
            rootxml = clientMgr.bindMgr.isle
        else
            rootxml = ctiXBCXML(ge(window.document.forms[0].name.substring(5)))
        if(rootxml){
            return get_element_text_by_tag_name(rootxml, key);
        }
        return null;
    }
//**************************************************
//END - XML
//**************************************************

//desc  - returns a reference to the xml node in the island which contains the value for the html node passed
//usage - domains, verify forms - use version in bind manager instead
function getRelatedXMLNode(html_element)
{
    var rowEl = getContainingElementByAttrib(html_element, "bindSrc");
    if(rowEl && clientMgr){
        var boundPair = clientMgr.bindMgr.getBoundPair(clientMgr.bindMgr.boundContEls, rowEl, 0);
        if(boundPair)
        {
            return boundPair[1];
        }
    }
}

//desc  - returns a reference to the html node in the DOM which contains the value for the xml node passed
//usage - debugging, get htmlsibling
function getRelatedHTMLNode(xml_element)
{
    if(xml_element){
        var boundPair = clientMgr.bindMgr.getBoundPair(clientMgr.bindMgr.boundDataEls, xml_element, 1);
        if(boundPair)
        {
            return boundPair[0];
        }
    }
}

//desc  - gets the sibling element of el which contains the column indicated
//usage - verify forms, chained selects
function getHTMLSibling(el,key)
{
    if(el)
        return getRelatedHTMLNode(sibling(el,key))
    else return null;
}

//desc  - converts an xml node into an array of name|value pairs for use passing down from lookup and verify forms
//usage - makeColDefForAddRows
function parseXMLtoColDef(xmlNode)
{
    var colDef = []
    if(xmlNode)
        for(var i = 0, clen = xmlNode.childNodes.length; i < clen; i++)
        {
            var col = xmlNode.childNodes[i];
            var seedNodes = ctiXBCXML(ge(xmlNode.tagName)).getElementsByTagName(col.nodeName)
            if(seedNodes.length)
                colDef.push(seedNodes[0].getAttribute('xref_target_field') + '|' +
                    (first_child(col) && first_child(col).nodeType == 3  ?    //text node
                     first_child(col).nodeValue : ''))
            
        }

    colDef.push('space_holder')
    return colDef
}

//desc -  accepts triggering button or link and returns array of name|value pairs for use passing down from lookup and verify forms
//usage - subtype parent_add/ Client Manager addRowExternal
function makeColDefForAddRows(html_element) {
    return parseXMLtoColDef(getRelatedXMLNode(html_element))
}


//**************************************************
//BEGIN - CEDAR
// Notes:
//  - 
//**************************************************

    //desc  - grabs data in the form of js objects out of a domain
    //usage - inline select add buttons (for cedar) (not used anymore)
    function getDomainEntry(oSelect,selectedIndices)
    {
        if(!selectedIndices){ 
            selectedIndices = []
            if(oSelect.selectedIndex)
                selectedIndices.push(oSelect.selectedIndex);
        }
        var returnDict = []
        var returnDictArray = []
        if(!oSelect) return returnDict;
        sDomain = oSelect.getAttribute('domain')
        params = sDomain.split("|");
        for(var q in params)
        {
            if(params[q].charAt(0) == '#')
                params[q] = $sibling(oSelect, params[q].substring(1))
            if(params[q].charAt(0) == '@')
                params[q] = $root(params[q].substring(1))
        }
        sDomain = params.join("|")
        
        oDomain = ctiXBCXML(ge(sDomain))
        if(!oDomain) oDomain = clientMgr.bindMgr.dynamicDomains[sDomain]
        
        for(var idx in selectedIndices)
        {
            returnDict = new Object();
            oEntry = browser.xPathSingle(oDomain,'.//domain_value[text()="'+oSelect.options[selectedIndices[idx]].value+'"]')
            if(oEntry) oEntry = oEntry.parentNode
            if(oEntry)
                for(var i = 0; i < oEntry.childNodes.length; i++)
                {
                    oNode = oEntry.childNodes[i];
                    var sValue = (oNode.firstChild ? oNode.firstChild.nodeValue : null);
                    returnDict[oNode.tagName] = sValue
                }
            returnDictArray.push(returnDict);
        }
        return returnDictArray
    }

    //desc  - converts a domain value into an add row, to add to a child, for inline add forms
    //usage - inline select add buttons (for cedar)(not used anymore)
    function domainToAddRow(oSelect,xref)
    {
        var selected = getSelectedIndices(oSelect)
        if(selected.length)
        {
            var optionDicts = getDomainEntry(oSelect,selected);
            var returnArrays = []
            var xDict = {}
            var xrefs = xref.split(',')
            for(var i in xrefs)
            {
                ref = xrefs[i].split(':')
                xDict[ref[0]] = ref[1]
            }
            
            for(var d in optionDicts)
            {
                var optionDict = optionDicts[d]
                returnArray = []
                for(var i in optionDict)
                    returnArray.push(xDict[String(i)]+'|'+String(optionDict[i]))
                returnArrays.push(returnArray)
            }
            return returnArrays;
       }
       return null;
    }

    //desc  - used for multiple adds, for inline add forms
    //usage - cedar(not used anymore)
    function getSelectedIndices(oSelect)
    {
        var o = oSelect.options;
        var s = []
        for(var i = 0, oLen = o.length; i < oLen; i++)
            if(o[i].selected)
                s.push(i);
        return s;
    }

    //desc  - the execution of inline add forms
    //usage - cedar(not used anymore)
    function addSelectToChild(xref,oSelect,oButton)
    {
        var addData = domainToAddRow(oSelect,xref)
        var trigIdx = clientMgr.bindMgr.getBoundTrigIdx(oButton)
        for(var i in addData)
            clientMgr.addRowExternal(trigIdx,addData[i]);
    }


    //usage - verify forms, to insert sibling data instead of a row
    function insert_form_data(obj,seedData,target_row)
    //inserts either a child row or form data, using obj as a data source
    //target_row serves as a flag for internal population
    //if specified, obj should be an xml node
    {

        var xml
        if(target_row != null)
            xml = obj
        else
            xml = getRelatedXMLNode(obj)
            
        if(xml)
        {
            if(gv('debugBox') == 'Y') alert('insert_form_data:\n\n'+xml.xml)
            var seedXml 
            
            if(!seedData)
                seedXml = ge(xml.tagName).documentElement
            else
                seedXml = seedData
            
            if(seedXml)
            {
                for(var i = 0; i < seedXml.childNodes.length; i++)
                {
                    var n = seedXml.childNodes[i];
                    var target = n.getAttribute('xref_target_field');
                    var source = get_element_text_by_tag_name(xml,n.tagName)
                    if(gv('debugBox') == 'Y') alert('assigning '+ n.tagName +'='+ source + ' to ' + target)
                    if(source != null && target != null)
                    {
                        if((target_row != null) && (target_row > -1))
                        {
                            clientMgr.setXMLValueExternal(target,source,target_row)
                            x = clientMgr.bindMgr.boundTrigEls[target_row][1];
		                    while(x != clientMgr.bindMgr.isle.documentElement)           			            
			                {
		                        x.setAttribute("changed","changed")			            
			                    x = x.parentNode
		                    }    
                        }
                        else
                            window.opener.clientMgr.setXMLValueExternal(target,source,$root('target_row'));
                    }
                }
            }
        }
    }

//**************************************************
//END - CEDAR
//**************************************************

//desc  - hides dom nodes for root 
//      - if they are repeating nodes
//      - only works for bound roots
//usage - search forms and others
function apply_linebreaks(root)
{
    if(!root) return
    var vals = [];
    var tblRow;
    
    for(var i = 0, rlen = root.childNodes.length; i < rlen; i++)
        
        tblRow = root.childNodes[i];
        
        for(var j = 0, clen = tblRow.childNodes.length; j < rlen; j++) 
        {
            var x = tblRow.childNodes[j];
            if(x.firstChild)
                if(x.firstChild.nodeValue != undefined && vals[x.tagName] != x.firstChild.nodeValue)
                    vals[x.tagName] = x.firstChild.nodeValue
                else
                {
                    var h = clientMgr.bindMgr.getBoundPair(clientMgr.bindMgr.boundDataEls,x,1) 
                    if(h)
                        h[0].style.display = 'none'
                }
        }
}

//desc  - clears all other checkboxes in sibling records
//      - only works for databound tables
//usage - not sure?
function clear_others(obj)
{
    if(!obj) return
    root = getRelatedXMLNode(obj).parentNode
    for(var i = 0; i < root.childNodes.length; i++)
    {
        var x = root.childNodes[i].getElementsByTagName(obj.bindFld)[0];
        var h = clientMgr.bindMgr.getBoundPair(clientMgr.bindMgr.boundDataEls,x,1) 
        if(x && (h[0] != obj))
        {
            if(x.firstChild)
                x.firstChild.nodeValue = 'N'
            h[0].checked = false;
        }
    }
}

//desc  - applies title breaks to given form
//usage - search forms (see dpf1)
function apply_titlebreaks(root, num_columns, form_code)
{
    var debugKey = (window.event && window.event.ctrlKey && window.event.shiftKey)
    num_columns = parseInt(num_columns)
    var table_name = 'tbl_' + form_code;
    
    var tblTarg = ge(table_name);
    
    // new table creation does not seem to retain id properly
    if(!tblTarg)
    {
        var tblCont = ge(table_name + "_container");
        
        if(tblCont)
        {
            tblTarg = tblCont.getElementsByTagName("table")[0];
        }
    }
           
    if(!tblTarg) return;
    if(tblTarg.rows.length == 0) return; //not doing anything if there's no tHead (ie no results returned)
    var width = tblTarg.tHead.rows[0].cells.length; //now get the new width of the table
	
  /*
    for (var i = 0; i < num_columns; i++) //first kill off the headers
	{
		tblTarg.tHead.rows[0].cells[i + 1].innerHTML = '';
	}
  */
		
    var vals = [];
    var num_added_rows = 0;
    var new_row_id = -1;
   
	for(var i = 1, n = root.childNodes.length; i < n; i++)
	{
		for(var j = 0; j < num_columns; j++)
		{
			var x = root.childNodes[i].childNodes[j];
			if(x.firstChild)
			{
                if(x.firstChild.nodeValue != undefined && vals[x.tagName] != x.firstChild.nodeValue)
                {
                    vals[x.tagName] = x.firstChild.nodeValue;
                    if(i == 0) new_row_id = i + num_added_rows + 1;
                    else new_row_id = i + num_added_rows;
                    
                    tblTarg.insertRow(new_row_id);
                    var row = tblTarg.rows[new_row_id]
                    
                    row.insertCell(0);
                    var cell = row.cells[0]
                    
                    cell.colSpan = width;
                    cell.align = 'center';
                    cell.width = '100%';
                    cell.className = 'title_break_l' + (j+1);
                    cell.innerHTML = '<b>' + x.firstChild.nodeValue + '</b>';
                    num_added_rows = num_added_rows + 1;
                    if(debugKey) wait('inserting level ' + (j + 1) + ' title break at row ' + new_row_id)
                }
            }
            var h = clientMgr.bindMgr.getBoundPair(clientMgr.bindMgr.boundDataEls,x,1)
            
            if(h)
                h[0].style.display = 'none';
		}

	}
} // apply_titlebreaks

//desc  - takes CSS class from the span of each column and applies it to the containing td elements
//        I have no idea why
//usage - search forms 
function apply_style_classes(form_code)
{
    var table_name = 'tbl_' + form_code;
    
    var tblTarg = ge(table_name);
    
    // new table creation does not seem to retain id properly
    if(!tblTarg)
    {
        var tblCont = ge(table_name + "_container");
        
        if(tblCont)
        {
            tblTarg = tblCont.getElementsByTagName("table")[0];
        }
    }
           
    if(!tblTarg) return;
    
    var num_rows = tblTarg.rows.length;  
    
    if(num_rows == 0) return; //not doing anything if no results returned
       
    var tblRow;
    var tblCol;
    
	for(var i = 0; i < num_rows; i++)
	{
	    tblRow = tblTarg.rows[i];
	    
		for(var j = 0, num_cols = tblRow.cells.length; j < num_cols; j++)
		{
		    tblCol = tblRow.cells[j];
		
		    if(tblCol.getElementsByTagName("span").length == 1)
		    {
		        var class_name = tblCol.getElementsByTagName("span")[0].className;
		        if(class_name) tblCol.className = class_name;
		    }
		   
		}
	}
} // apply_style_classes

//desc  - creates a popup which fires retrieve_rec2
//  text is the text in the object
//  btntext is the text on the button
//usage - RETRIEVE link
function popupRetrieveBox(keys,text,btntext)
{
    var d = makeActionDiv(
        parent.right_frame.retrieve_rec2,
        (text? text:'Record Id:'),
        (btntext? btntext:'Retrieve'))
    d.className = 'retrieveDiv'
    d.parentNode.removeChild(d);
    if(keys=='alpha')
        keys = /./i;
    else
        keys = /\d/i;
    
    document.body.insertBefore(d,document.body.firstChild)
    d.focus();
    d.firstChild.nextSibling.focus();
    d.firstChild.nextSibling.onkeypress = function(event){ return filterKeys(event,keys) }
    
   //return d
}


//desc  - takes a function of one variable and pops up a div to activate it once.
//usage - debugging
function makeActionDiv(func,text,btntext,x,y,draggable)
{
    var d = makeDraggableDiv();
    
    if(text) ac(ct(text),d)
    
    var i = ce('input')
    i.type = 'text'
    ac(i,d)
    
    var b = ce('input')
    b.type = 'button'
    b.className = 'button';
    if(btntext) b.value = btntext
    b.onclick = function(){ func(i.value); document.body.removeChild(d) }
    ac(b,d)
    
    var c = ce('input')
    c.type = 'button'
    c.className = 'button';
    c.style.textAlign = 'center';
    c.value = 'Close'
    c.onclick = function(){ document.body.removeChild(d) }
    ac(c,d)
    
    if(x != null && y != null)
    {
        d.style.position = 'absolute'
        d.style.left = x
        d.style.top = y
    }

    ac(d, document.body)
    i.onkeydown = function(event){ event = event||window.event; if((event.keyCode||event.which) == 13) b.click(); }
    return d    
}//makeActionDiv

//desc  - filters keys based on a regular expression
//usage - all key filters for subtypes
function filterKeys(event,pat)
{
    if(!event) event = window.event
    key = event.keyCode ? event.keyCode:event.which
    if(key < 17) return true;   //allow things like enter, tab, and delete to go through
    return pat.test(String.fromCharCode(key))
}

//usage - search forms
function altcolors(form_name)
//goes through a table by name and 
//sets up alternating css row styles
{
    var tbl = ge('tbl_'+form_name);
     
    // new table creation does not seem to retain id properly
    if(!tbl)
    {
        var tblCont = ge('tbl_' + form_name + "_container");
        
        if(tblCont)
        {
            tbl = tblCont.getElementsByTagName("table")[0];
        }
    }
           
    if(tbl)
    {
        //tbl.className = 'popup_table_list'
        var rows = tbl.rows
        if(!rows) rows = tbl.tBodies[0].rows;
        var lighter = true;
        var tblRow;
        var tblCol;
        
        for(var i in rows)
        {
            lighter = !lighter;
            
            tblRow = rows[i];
            
            if(lighter)
                for(var j in tblRow.cells)
                {
                    tblCol = tblRow.cells[j];
                
                    if(!/title_break/.test(tblCol.className))
                        tblCol.className = 'lighter'
                }
        }
                    
   }
}

    // used by - ALL NAVIGATION goes through this function! if you
    // are navigating without this function, beware your state!!!!
function loadContent(target_map_filename, run_type, id1, id2, id3, id4, id5, id6, id7){
//function loadContent(target_map_filename){
   //alert('loading content for map' + target_map_filename + ' with run_type ' + run_type + ' and id1 ' + id1);
   
   // The following logic detects if the current window is a child/popup and passes the call along until it arrives
   // at the parent, which will be one of the frames.
   if(opener && opener.loadContent)
   {
        switch(loadContent.arguments.length)
        {
            case 0: opener.loadContent(); break;
            case 1: opener.loadContent(target_map_filename); break;
            case 2: opener.loadContent(target_map_filename, run_type); break;
            case 3: opener.loadContent(target_map_filename, run_type, id1); break;
            case 4: opener.loadContent(target_map_filename, run_type, id1, id2); break;
            case 5: opener.loadContent(target_map_filename, run_type, id1, id2, id3); break;
            case 6: opener.loadContent(target_map_filename, run_type, id1, id2, id3, id4); break;
            case 7: opener.loadContent(target_map_filename, run_type, id1, id2, id3, id4, id5); break;
            case 8: opener.loadContent(target_map_filename, run_type, id1, id2, id3, id4, id5, id6); break;
            case 9: opener.loadContent(target_map_filename, run_type, id1, id2, id3, id4, id5, id6, id7); break;   
        }
        return;
   }
    
   // Any logic below this point will be executed on a frame window.
   
    // jsb 07/07/08
    // If this method is being called from the right frame or left frame, and the page in the right frame is
    // generated, then execute the confirm leave routine on the right frame.  Otherwise, if this method is
    // being called by a popup main form, then execute the confirm leave on the current window.
    // this logic is duplicated in verify_person_select
    if(window.parent.right_frame) // this should always be true
    {
        try // external page will give permission error on checking the class name
        {
            if(parent.right_frame.document.body.className == 'rf')
            {
                var mess = parent.right_frame.frm_confirm_leave3()
                //if(mess && !confirm('loadcontent1:' + 'Are you sure you want to navigate away from this page?\n\n'+
                if(mess && !confirm('Are you sure you want to navigate away from this page?\n\n'+
                    mess+ '\n\nPress OK to continue, or Cancel to stay on the current page.')) return;
                else parent.right_frame.clientMgr.confirmExit = false;
            }
        }
        catch(x)
        {
                //alert('oops:\n'+x.message);
        }
    }


    	switch(loadContent.arguments.length){
		case 1:
			run_type = ""; //breaks left out intentionally
		
		case 2:
			id1			= "";
		
		case 3:
			id2			= "";
		
		case 4:
			id3			= "";
		
		case 5:
			id4			= "";
		
		case 6:
			id5			= ""; 
		
		case 7:
			id6			= "";
			
	    case 8:
			id7			= "";
		break;
	}
       
    var sParms = "";
    
    if(run_type != "")
       sParms += "&run_type=" + run_type;
     
    if(id1 != "") sParms += "&id1=" + id1;
    if(id2 != "") sParms += "&id2=" + id2;
    if(id3 != "") sParms += "&id3=" + id3;        
    if(id4 != "") sParms += "&id4=" + id4;        
    if(id5 != "") sParms += "&id5=" + id5;        
    if(id6 != "") sParms += "&id6=" + id6;        
      
    //if(gv('debugbox') == 'Y') 
    //alert("map_filename=" + target_map_filename + sParms)  
    var sResult = syncPost("cti_nav.aspx","map_filename=" + target_map_filename + sParms);
    
    if(sParms != "")
        sParms = "?activated=y" + sParms;
    
    //alert("ctinav: map_filename=" + target_map_filename + sParms + " result:" + sResult);
    
    var asResults = sResult.split(":");
    var sRoot = "";
       
    if(asResults[0] == "all"){
        //alert("reload...")
        //loader_link(target_map_filename,false, run_type, id1, id2);
        var asContent = asResults[1].split("|")
        var asPair = asContent[0].split("=")
        if(asPair[0] == "root")
            sRoot = asPair[1];
        try{
            parent.window.location = sRoot + 'default.aspx' + sParms;
        }catch(x){}
        //var loader_cmd		= "loader_cmd=cti_loader.aspx?location=../default.aspx|map_name=|message_1=|type=load|map_filename=" + target_map_filename;
	    //window.location		= "cti_loader_ext.aspx?" + loader_cmd;         
    }
    else{     
        if(asResults[0] == "content"){
            var asContent = asResults[1].split("|");
            var sFile = "";
            
            for(var i = 0; i < asContent.length; i++){
                var asPair = asContent[i].split("=")
                
                if(asPair[0] == "root")
                    sRoot = asPair[1];
                    
                if(asPair[0] == "first")
                    sFile = asPair[1];
            }
            // Update the remaining three frames        
            //alert('navigating to ' + sRoot + sFile + sParms);
                    try
        {
            if(gv('debugbox') == 'Y') alert("loadContent location:" + sRoot + sFile + sParms + " result:" + asResults[1])
            parent.right_frame.location = sRoot + sFile + sParms;
        }
        catch(x)
        {
            alert('navigation error:' + x.message);
        }
            
                       
            parent.action_frame.location = sRoot + "asp/cti_main_action_frame.aspx?mycaller=javascript";
            
            //if(parent.top_frame.location.href.indexOf("blank.aspx") != -1) 
                parent.top_frame.location = sRoot + "asp/cti_main_top_frame.aspx"; 
            //else
            //    parent.top_frame.top_frame_update();
        }
       else
            alert(sResult);
    }
    
} // loadContent

//KILLS YOUR SESSION AND KICKS YOU OUT
//usage - security functions, in NFG
function pge_display_cti_close_page2(close_message){
    if(window.opener && !window.opener.closed){
        if(window.opener.clientMgr) window.opener.clientMgr.confirmExit = false
        window.opener.parent.location = "cti_close.aspx?msg=" + close_message;
        window.close();
    }
    else{
        if(window.clientMgr) clientMgr.confirmExit = false
        parent.window.location = "cti_close.aspx?msg=" + close_message;
    }
} // pge_display_cti_close_page


//desc  - refreshes child forms in parent windows. useful if you save on a popup
//usage - popup saves; updates parent forms to reflect changes made in popup
//note: update dict is an object with the following format:
//      'parent_form_code1':'form_to_update_1,form_to_update_2'
//      'parent_form_code2':'form_to_update_3,form_to_update_4'
function update_parents(update_dict)
{
    //alert('in update_parents');

    var w = window;
    while(w)
    {
        form_code = w.clientMgr.getFormCode(); //bindMgr.isle.documentElement.nodeName
        
        //alert('form code is:' + form_code);
                
        if(update_dict[form_code])
        {
            children = update_dict[form_code].split(',')
            for(var i in children){
                //w.focus()
                //alert('updating ' + children[i] + ' on ' + form_code)                    
                w.cti_retrieve(form_code, children[i], null, 1, 'all')
            }
        }
        if(w.opener) 
            w = w.opener;
        else
            w = null;
    }
}

//desc  - executes logic for datadriven field types
//usage - binding, vitals
//notes: dataDrive expects an object with up to 4 parameters:
//  truebase is used by transformBase to take a data column and transform the HTML element into another HTML tag specified by that column
//  base_type_column and subtype_column are used by applySubtypes to specify columns which specify subtypes
//  datadriven_attributes is used by applyDatadrivenAttributes to apply HTML attributes to the element
function dataDrive(obj)
{
    obj = transformBase(obj)
    applySubtypes(obj)
    applyDatadrivenAttributes(obj)
    if(obj && obj.getAttribute && $sibling(obj,obj.getAttribute('truebase')) == 'select') fill_domain(obj)
}

//desc  - changes the base html tag of an object without changing its location in the DOM or any of its properties
//usage - datadriven fields
function transformBase(obj)
{
    if(obj && obj.getAttribute)
    {
        base = $sibling(obj,obj.getAttribute('truebase'))
        if(base && base != '')
        {
            newObj = ce(base)
            for(var i in obj)
            {
                try{newObj[i] = obj[i] }catch(x){}
            }
            obj.parentNode.replaceChild(newObj,obj)
            return newObj
        }
    }
    return obj
}

//desc  - applies subtyped properties to an object (parameterized subtypes won't work)
//usage - datadriven fields
function applySubtypes(obj,b,s)
{
    if(obj && obj.getAttribute)
    {
        if(!b) b = $sibling(obj,obj.getAttribute('base_type_column'))
        if(!s) s = $sibling(obj, obj.getAttribute('subtype_column'))
        if(b && b != '')
        {
            x = syncPost('cti_get_subtype.aspx?base_type='+b+'&subtype='+s)
            o = eval(x)
            for(var i in o)
            {
                if(i.indexOf('on') == 0)
                {
                    o[i] = new Function(o[i])
                }
                obj.setAttribute(i,o[i]);
                
                if(i == 'fe_atr_expandos')
                {
                    var ex = o[i].split("|");
                    
                    for(var j in ex)
                        obj.setAttribute(ex[j],ex[j]);                       
                }
                //alert('setting ' + i + ' to ' + o[i])
            }
        }       
    }
}

//desc  - applies datadriven attributes to an object
//usage - datadriven fields
function applyDatadrivenAttributes(obj)
{
    if(obj && obj.getAttribute)
    {
        var sAttr = obj.getAttribute('datadriven_attributes')
        
        if(sAttr != "")
        {
            var aList = subpopup(obj,sAttr).split("&");
            
            for(var i in aList)
            {
                if(aList[i].indexOf("=") > -1)
                {
                    pair = aList[i].split("=");
                    obj.setAttribute(pair[0],pair[1]);
                }
            }
        }
                        
    }
    
} // applyDatadrivenAttributes

// desc  - Removes top and left frames to give more screen real estate to the user
// usage - toolbar
function toggleFullScreen(triggerId, expandedSizeRows, expandedSizeCols, normalRows, normalCols, shrinkText, expandText) {
    
    //alert('toggling screen size');
    
	switch(arguments.length){ //breaks left out intentionally
	    case 0:
	        triggerId = "";
	    case 1:
	        expandedSizeRows = "0,*,25"; // default value only
	    case 2:
	        expandedSizeCols = "0,*" // default value only
	    case 3:
	        normalRows = "92,*,25"; // 3/29/2010 - default value only
		    //normalRows = "77,*,30";
	    case 4:
	        normalCols = "225,*"; // - default value only
		case 5:
		    shrinkText = "Shrink";
		case 6:
            expandText = "Expand";
        break;
	}
	
	var triggerObj;
	
	if(triggerId != "")
	    triggerObj = document.getElementById(triggerId);
	    
	    
	var isExpanded = syncPost("cti_retrieve_session.aspx","shortkey=sessioncurrpage.pagestateexpanded"); 
    if(isExpanded == "true"){
        parent.content_frames.cols = normalCols;
        parent.message_frames.rows = normalRows;
        
        //update the session variables
		syncPost("cti_change_session.aspx", "key=sessioncurrpage.pagestateexpanded&value=false");
        
        if(triggerObj)
            triggerObj.innerText = expandText;
    }
    else{
        parent.content_frames.cols = expandedSizeCols;      
        parent.message_frames.rows = expandedSizeRows;
        
        syncPost("cti_change_session.aspx", "key=sessioncurrpage.pagestateexpanded&value=true");
        
        if(triggerObj)
            triggerObj.innerText = shrinkText; 
    }
    
    parent.action_frame.location.reload();
} //toggleFullScreen

// desc  - Causes left frame to disappear or reappear
function toggleLeftFrame(){
    //alert('cols:' + parent.content_frames.cols);
    var divC = parent.left_frame.document.getElementById('lf_container');
    var divR = parent.left_frame.document.getElementById('lf_restore');
    //var imgR = parent.left_frame.document.getElementById('lf_header_restore');

    if (parent.content_frames.cols.indexOf("15,") == -1)
    {
        divC.style.display = 'none';
        //imgR.style.top = ((parent.left_frame.document.body.clientHeight/2) - 13) + "px";
        divR.style.display = '';       
                    
        parent.content_frames.cols = "15,*";
    }
    else
    {
        divR.style.display = 'none';
        divC.style.display = '';
        parent.content_frames.cols = "225,*";
    }
        
    parent.action_frame.location.reload();
} // toggleLeftFrame
   

//desc  - briefly changes the color of an element
//usage - debugging
function spotlightElement(elem,highlightColor,fadeTime) 
{
    if(!highlightColor) highlightColor = 'yellow'
    if(!fadeTime) fadeTime = 1000
    if(elem && elem.style)
    {
         elem.origColor = cntb(elem.style.backgroundColor)
         elem.style.backgroundColor = highlightColor
         window.setTimeout(function(){elem.style.backgroundColor = elem.origColor },fadeTime)
    }
}

//debugs the page state (used for mini-debugs)
function pageStateDebugDiv(style)
{
    d = makeDraggableDiv()
    d.className = style
    d.style.top = document.body.scrollTop+'px'
    if(ge('pagestatedebugdiv')) dismiss(ge('pagestatedebugdiv'))()
    d.id = 'pagestatedebugdiv'
    function g(x){
        return syncPost('cti_retrieve_session.aspx','shortkey='+x)
    }
    
    function appendItem(name,value)
    {
        ac(ct(name+":"+value),d)
        ac(ce('br'),d)
    }
    
    appendItem("Map",g("SessionMapName"))
    appendItem("Form Code",g("SessionCurrPage.PageStateFormCode"))
    appendItem("Form View Code",g("SessionCurrPage.PageStateFormViewCode"))    
    appendItem("Mode",g("_run_mode"))
    appendItem("ID1", g("_id1"))
    appendItem("ID2", g("_id2"))
    appendItem("ID3",g("_id3"))
    appendItem("ID4",g("_id4"))
    appendItem("ID5",g("_id5"))
    appendItem("Session ID",g("SessionId"))
    appendItem("User ID",g("SessionUserFK"))
    
}

//populates a div with the output of some function
//usage - debugging only
function updateMonitorDiv(name,object,monitorfunction)
{
    var id = name+'_monitor_div'
    var x = ge(id)
    if(!x){
        x = makeDraggableDiv();
        x.id = id
        x.className = 'monitorDiv'
        }
    x.innerHTML = ''
    monitorfunction(x,object);
}

//runs some monitor function to keep an eye on some variables
//usage - debugging only
function runMonitorDiv(name,object,interval,monitorfunction)
{
    window.setInterval(function(){updateMonitorDiv(name,object,monitorfunction)},interval)
}

//monitors the status the data island
//usage - debugging only
function runBindingDiv(arrayname){
    runMonitorDiv(  arrayname+'_debug',
                    clientMgr.bindMgr[arrayname],
                    1000,function(x,array)
                    {
                          for(var i in array)
                            {
                                q = array[i]
                                ac(ct((q[0].id || '<'+q[0].tagName+'>')+':'+q[1].nodeName),x)
                                ac(ce('br'),x)
                            }
                    }
                 )
}

//creates a function which runs cti_retrieve and all its accoutrements
//usage - search forms
function searchScript(  search_form_code,
                        parent_form_code,
                        search_sp,
                        paging_ind,
                        linebreaks_ind,
                        titlebreaks_ind,
                        num_titlebreaks,
                        altcolors_ind)
{
    //alert('search:' + search_form_code + ' parent:' + parent_form_code + ' sp:' + search_sp);
    
    return function(pagenum,pagesize){
        if(ge(parent_form_code+'_search_pagesize').type == 'hidden'){
           pagesize = '' 
        }; 
                
        if(pagesize == 0)
            pagesize = '';
    
        var pw = document.getElementById('sf_please_wait');  
        var rootxml = clientMgr.bindMgr.isle; 
        
        if(pagenum < 0){ pagenum = 1; };
        var rc = $root('search_record_count');

        if(rc){ 
            if(rc/pagesize < pagenum) {
                 pagenum = Math.round(rc/pagesize+.4999999) 
             }
        } 
        
        clientMgr.bindMgr.setXMLValue('search_page',(pagenum?pagenum:''),rootxml); 
        clientMgr.bindMgr.setXMLValue('search_pagesize',(pagesize?pagesize:'all'),rootxml); 
        /*getForm(    search_form_code,
                    (pagenum ? pagenum : 1),
                    (pagesize ? pagesize : 'all'),
                    'search_record_count')
                    */
        cti_retrieve(parent_form_code,
                        search_form_code,
                            search_sp,
                            (pagenum ? pagenum : 1),
                            (pagesize ? pagesize : 'all'),
                            'search_record_count'); 
                            
        if(pw)  pw.style.display='none';  
        paging_func = Function(search_form_code+'_search(this.page_num'+(pagesize && pagesize!=''?','+pagesize:'')+')');
        if(paging_ind.toUpperCase() != 'Y') { write_query_paging_menu(ge('paging_menu'),pagenum,paging_func,pagesize,$root('search_record_count'));};
        ge(parent_form_code+'_sf_search_total_label').style.display = 'block';
        if(linebreaks_ind.toUpperCase() == 'Y'){apply_linebreaks(ge(parent_form_code).getElementsByTagName(search_form_code+'_container')[0]); };
        if(titlebreaks_ind.toUpperCase() == 'Y') {apply_titlebreaks(ge(parent_form_code).getElementsByTagName(search_form_code+'_container')[0], num_titlebreaks, search_form_code);};
        apply_style_classes(search_form_code);
        resizeTextAreas()
        if(altcolors_ind.toLowerCase() != 'n') altcolors(search_form_code)
        }
} //searchScript

//generates a search script 
//usage - not used anymore
//function searchScript_old(  search_form_code,
  //                      parent_form_code,
    //                    search_sp,
      //                  paging_ind,
        //                linebreaks_ind,
          //              titlebreaks_ind,
            //            num_titlebreaks,
              //          altcolors_ind)
//{
//##search_form_code##_search
  //  func = "\n\
    //if(ge('"+parent_form_code+"_search_pagesize').type == 'hidden'){\n\
      //     pagesize = '' \n\
//    }; \n\
  //  \n\
    //var pw = document.getElementById('sf_please_wait');  \n\
//    var rootxml = clientMgr.bindMgr.isle; \n\
  //  \n\
    //if(pagenum < 0){ pagenum = 1; } \n\
//    var rc = $root('search_record_count'); \n\
  //  \n\
    //if(rc){ \n\
      //  if(rc/pagesize < pagenum) {\n\
        //     pagenum = Math.round(rc/pagesize+.4) \n\
         //} \n\
    //} \n\
    //\n\
    //clientMgr.bindMgr.setXMLValue('search_page',(pagenum?pagenum:''),rootxml); \n\
//    clientMgr.bindMgr.setXMLValue('search_pagesize',(pagesize?pagesize:'all'),rootxml); \n\
  //  cti_retrieve('"+parent_form_code+"',\n\
    //                '"+search_form_code+"',\n\
      //                  '"+search_sp+"',\n\
        //                (pagenum ? pagenum : 1),\n\
          //              (pagesize ? pagesize : 'all'),\n\
            //            'search_record_count');  \n\
              //          \n\
//    if(pw)  pw.style.display='none';  \n\
  //  paging_func = Function('"+search_form_code+"_search(this.page_num'+(pagesize && pagesize!=''?','+pagesize:'')+')'); \n\
    //if('"+paging_ind+"'.toUpperCase() != 'Y') { write_query_paging_menu(ge('paging_menu'),pagenum,paging_func,pagesize,$root('search_record_count'));};\n\
//    /*if('"+paging_ind+"'.toUpperCase() != 'Y') {write_paging_menu(ge('paging_menu'), '"+search_form_code+"_search',pagesize,$root('search_record_count'));}*/ \n\
  //  ge('"+parent_form_code+"_sf_search_total_label').style.display = 'block'; \n\
    //if('"+linebreaks_ind+"'.toUpperCase() == 'Y'){apply_linebreaks(ge('"+parent_form_code+"').getElementsByTagName('"+search_form_code+"_container')[0]); }; \n\
//    if('"+titlebreaks_ind+"'.toUpperCase() == 'Y') {apply_titlebreaks(ge('"+parent_form_code+"').getElementsByTagName('"+search_form_code+"_container')[0], '"+num_titlebreaks+"', '"+search_form_code+"');}; \n\
  //  apply_style_classes('"+search_form_code+"'); \n\
    //if('"+altcolors_ind+"'.toLowerCase() != 'n') altcolors('"+search_form_code+"') \n\
//"
  //  return new Function("pagenum","pagesize",func)
//}

//**************************************************
//BEGIN - EMR/PHR HEALTH NEWS RSS FEED ROUTINES
// Notes:
//  - 
//**************************************************

    //loads all rss fields on the form
    //usage - rss fields
    function loadRSSFields()
    {
        var domains = document.body.getElementsByTagName("select")
        var oRadioGroup
        var source
        var rsstrace = ''
        if(domains != null)
        {
            for(var i = 0, dlen = domains.length; i < dlen; i++)
            {
                oDomain = domains[i];
                if(oDomain.getAttribute('rss'))
                    getRSS(oDomain.value,oDomain.nextSibling)
            }
        }
    }

    //loads an rss feed into an object
    //usage - rss fields
    function getRSS(url,targetObj)
    {
        var req
        var retfunc = function(e,r){
            if(req)
            {
                while(targetObj.childNodes.length>0) targetObj.removeChild(targetObj.firstChild)
                if(req.readyState == 4)
                    if(req.status == 200){
                        x = req.responseXML
                        b = browser || ctiBrowser();
                        channel = b.xPathSingle(x,'/rss/channel')
                        channel_title = b.xPathSingle(channel,'title/text()')
                        channel_link = b.xPathSingle(channel,'link/text()')
                        channel_description = b.xPathSingle(channel,'description/text()')
                        header = ce('a')
                        if(channel_link) header.href = 'javascript:open_popup_window("rss","'+channel_link.nodeValue+'")'
                        if(channel_title){
                            ac(ct(channel_title.nodeValue),header)
                            ac(header,targetObj)
                            ac(ce('br'),targetObj)
                        }
                        if(channel_description) ac(ct(channel_description.nodeValue),targetObj)
                        ul = ce('ul')
                        items = b.xPath(channel,'item')
                        for(var i = 0, ilen = items.length; i < ilen; i++)
                        {
                            var item = items[i];
                            item_li = ce('li')
                            item_title = b.xPathSingle(item,'./title/text()')
                            item_link = b.xPathSingle(item,'./link/text()')
                            item_description = b.xPathSingle(item,'./description/text()')
                            item_header = ce('a')
                            if(item_link) item_header.href = 'javascript:open_popup_window("rss","'+item_link.nodeValue+'")'
                            if(item_title) ac(ct(item_title.nodeValue),item_header)
                            ac(item_header,item_li)
                            ac(ce('br'),item_li)
                            oDescr = ce('span')
                            if(item_description) oDescr.innerHTML = item_description.nodeValue
                            ac(oDescr,item_li) 
                            ac(item_li,ul)
                        }
                        ac(ul,targetObj)
                    }
                    else switch(req.readyState)
                    {
                   case 1:
                        targetObj.innerHTML = 'Requesting...'; break;
                   case 2:
                        targetObj.innerHTML = 'Request sent, waiting for response...'; break;
                   case 3:
                        targetObj.innerHTML = 'Downloading RSS feed...'; break;
                   }
               }
            }
        req = asyncPost(targetObj.previousSibling.id||url,'cti_proxy.aspx','url='+encodeURIComponent(url),false,retfunc)
    }

//**************************************************
//END - HEALTH NEWS RSS FEED ROUTINES
//**************************************************


// goes to an anchor and saves your location in the session
// used by - ALL anchors! if you don't use this, you won't save your last anchor!
function goToAnchor(anchor)
{
    syncPost('cti_change_session.aspx','key=SessionCurrPage.PageStateAnchor&value='+anchor)
    var anchorname = anchor.replace('#','')
    var oa = ge(anchorname);
    
    if(oa && oa.className == 'closed')
        if(oa.id.indexOf('xxsection_label') > -1)
            {
                var td = oa.parentNode;
                
                td.style.display = '';
                
                var secTbl = td.parentNode.parentNode;
                
                var tblList = secTbl.getElementsByTagName("table");
                
                for(i in tblList)
                {
                        if(tblList[i].style)
                        {
                            alert('setting style for table ' + tblList[i].id);
                            tblList[i].style.display = '';
                        }
                        else alert('table ' + tblList[i].id + ' got no style');
                } 
                
                //var scTbl = td.parentNode.nextSibling.firstChild.firstChild;
                
                //scTbl.style.display = '';
            }
        else
            oa.click();
    
    location.hash = '#'+anchorname;
    
}

function goToAnchorPopup(anchor){
    if(anchor){
        anchor = anchor.substring(1); // remove #
        
        var oCDiv = document.getElementById('popm_content');
        
        if(oCDiv){       
            //var oA = document.getElementById(anchor);
            var oA = document.getElementsByName(anchor)[0];
                            
            if(oA && oA.offsetParent){            
                
                if(oA.className == 'closed')
                    oA.click();
                
                var curtop = oCDiv.offsetTop * -1; // Account for height of title and action divs
                    
                //var oADiv = document.getElementById('popm_action');
                                    
               // if(oADiv){ alert('action offset' + oADiv.offsetTop);
               //     curtop = (oADiv.offsetHeight * -1) // account for action bar 
               // }
                
                do {
                        curtop += oA.offsetTop;
                } while (oA = oA.offsetParent);
                                                                       
                oCDiv.scrollTop = curtop; //oA.offsetParent.offsetTop;

            } // oA && oA.offset
        } //oCDiv
     } // anchor
} // goToAnchorPopup


//**************************************************
//BEGIN - DEVTOOLS
// Notes:
//  - 
//**************************************************

    //generates a help row, and the dev tools panel
    //usage - form generator
    function show_helprow(innerhtml,form_code,fe_seq)
    {
        var e = event||window.event
        var devTools = (e && e.shiftKey && e.ctrlKey)
        var o = e.srcElement
        var tr = o;
        if(!innerhtml)
            innerhtml = mdFetch(form_code,fe_seq).fe_tooltip
        
        //desc  - opens the map metadata editor
    //usage - left and action frames
        function mdMapEdit(map_name)
        {
            popMap('map_md_map_edit','md_map_edit','no_stickaround','&id1=' + map_name);
            //open_popup_window('map_edit','cti_nfg.aspx?form_code=md_map_edit&id1='+map_name)
            return false;
        }
    
        function mdEditElement(o,form_code,fe_seq)
        {
            if(form_code && fe_seq) 
            {
                popMap('map_md_htm_edit','md_htm_edit','no_stickaround','&md_form_code=' + form_code + '&fe_seq=' + fe_seq);
                //open_popup_window(form_code+fe_seq+'_edit','cti_nfg.aspx?form_code=md_htm_edit&md_form_code='+form_code+'&fe_seq='+fe_seq,true)
                return;
            }
                
            var ta = ce('textarea')
            ta.cols = '80'
            ta.rows = '10'
            ta.value = o.innerHTML
            ta.onkeypress = function(){adjust_resize(this)};
            o.parentNode.replaceChild(ta,o)
            var b = ce('button')
            b.value = 'Save'
            b.onclick = function()
            {
                var n = ce('div')
                n.innerHTML = ta.value        
                ta.parentNode.replaceChild(n,ta)
                n.onclick = function(){ editElement(n)};
                dismiss(b)();
            }
            ta.parentNode.insertBefore(b,ta)
        }
        
        //(jds) --- The following is a shortcut to "Edit Row" using (ctrl and right-click only) on a label ---
        //if(e && e.ctrlKey && !devTools)
        //{
        //    mdEditElement(o,form_code,fe_seq);
        //    return false;
        //}
        
        while(tr && tr.tagName.toUpperCase() != 'TR') 
        {
            tr=tr.parentNode;
        }
        if(o.helprow) dismiss(o.helprow)();
        var div = ce('div');
        if(innerhtml && innerhtml != '')
        {
            if(innerhtml.substr(0,4) == 'htm:')
            {
                div.innerHTML = innerhtml.substring(4)
            }
            else if(innerhtml.substr(0,4) == 'txt:')
            {
                var x;
                x = ce('textarea')
                x.value = innerhtml.substring(4)
                x.cols = 140
                adjust_resize(x)
                x.onkeydown = function(){ adjust_resize(this); }
                x.readOnly = true;
                ac(x,div)
            }
            else
                div.innerHTML = innerhtml
        }
        else
        {
            div.innerHTML = 'There is no tooltip defined for this label.(' + o.innerText + ')'
        }
        
        var td = ac(div,ce('td')).parentNode
        function makeEditButton(btntext,editfunc)
        {
            var b = ce('button')
            b.target = div
            b.value = btntext
            b.onclick = editfunc
            return b
        }
                
        function createMdEditForm(target,form_code,fe_seq)
        {
            ac(ce('hr'),td)
            var tbl = ac(ce('tbody'),ac(ce('table'),target))
            function row(tbl){ return ac(ce('tr'),tbl) }
            function cell(tbltr){ return ac(ce('td'),tbltr) }
            var tbltr = row(tbl)
            var tbltd = cell(tbltr)
            
            // ----- Edit Row -----
            ac(ct('Row'),tbltd)
            tbltd = cell(tbltr)
            ac(ct(fe_seq),tbltd)
            
            tbltd = cell(tbltr)
            ac(makeEditButton('Edit Row',function(){ mdEditElement(this.target,form_code,fe_seq); })
                ,tbltd)
                
            // ----- Edit Form -----
            tbltr = row(tbl)
            tbltd = cell(tbltr)
            ac(ct('Form'),tbltd)
            tbltd = cell(tbltr)
            ac(ct(form_code),tbltd)
            tbltd = cell(tbltr)
            ac(makeEditButton('Edit Form',function(){
                 if(form_code)
                    popMap('map_md_form_edit','md_form_edit','no_stickaround','&md_form_code=' + form_code);
                 //   open_popup_window(form_code+'_form_edit','cti_nfg.aspx?form_code=md_form_edit&md_form_code='+form_code,true)
               }),tbltd)
            ac(makeEditButton('Edit LF SP',function(){
                if(form_code)
                    open_popup_window('lf_sp','cti_md_get.aspx?form_code='+form_code+'&sp=lf')
                }),tbltd)
            ac(makeEditButton('Edit PF SP',function(){
                if(form_code)
                    open_popup_window('pf_sp','cti_md_get.aspx?form_code='+form_code+'&sp=pf')
                }),tbltd)
            
            // ----- Edit Map -----
            //desc  - opens the map metadata editor
            //usage - left and action frames
            
            // If this is a popup get the map_name from the data island, if not get it from server
            //if(window.opener && !window.opener.closed)
            if(window.opener) {
                var map_name = $root('map')
                // most popups have no map
                if (map_name == '') map_name = 'No Map';
            }
            else
                var map_name =  syncPost('cti_retrieve_session.aspx','shortkey=SessionMapName')

            tbltr = row(tbl)
            tbltd = cell(tbltr)    
            ac(ct('Map Name'),tbltd)
            tbltd = cell(tbltr)    
            ac(ct(map_name),tbltd)
            tbltd = cell(tbltr)    
     
            if (map_name != 'No Map') 
                ac(makeEditButton('Edit Map',function(){ mdMapEdit(map_name); }),tbltd)
            
            // ----- Display ID -----
            tbltr = row(tbl)
            tbltd = cell(tbltr)    
            var kcn = mdFetch(form_code).key_col_name
            ac(ct('ID('+kcn+')'),tbltd)            
            tbltd = cell(tbltr)
            tbltd.colSpan = 2
            if(kcn && kcn != '')
                ac(ct($sibling(o,kcn)),tbltd)
            else
                ac(ct('unknown'),tbltd)
            
            tbltr = row(tbl)
            tbltd = cell(tbltr)
            tbltd.colSpan = 3
            tbltd.align = 'center'
            var a = ce('a')
            a.href = "javascript:open_popup_window('portal','cti_nfg.aspx?form_code=md_dev_portal')"
            ac(ct('Go to dev portal'),a)
            ac(a,tbltd)
            
            JSONtoDOM(row(tbl),
            [
                'td',[
                    'colSpan','3',
                    'a',[
                        'href','javascript:makeJSConsole()',
                        '#text','JS Console'
                    ],
                    'a',[
                        'href','javascript:show_templates();',
                        'style',{
                            'marginLeft':'2em'
                        },
                        '#text','Templates'
                    ],
                    'a',[
                        'href','javascript:showDomains()',
                        'style',{
                            'marginLeft':'2em'
                        },
                        '#text','Domains'
                    ],
                    'a',[
                        'href','javascript:show_island()',
                          'style',{
                            'marginLeft':'2em'
                        },
                        '#text','Data Island'
                    ],
                    'a',[
                        'href','javascript:;',
                        'onclick',function(){cti_alert(getRelatedXMLNode(o).xml)},
                        'style',{
                            'marginLeft':'2em'
                        },
                        '#text','Data Island (Local)'
                    ]
                ]
            ])
            JSONtoDOM(row(tbl),
            ['td',[
                'colSpan','3',
                'a',[
                        'href','javascript:pageStateDebugDiv("mini_debug")',
                        'style',{
                            'marginLeft':'2em'
                        },
                        '#text','Mini-Debug'
                    ],
                    'a',[
                        'href',"javascript:open_popup_window('debug','../debug295.aspx?download=Y')",
                        'style',{
                            'marginLeft':'2em'
                        },
                        '#text','Debug'
                    ],
                    'a',[
                        'href',"javascript:popMap('map_md_domain_htm_index')",
                        'style',{
                            'marginLeft':'2em'
                        },
                        '#text','md_htm'
                    ],
                    'a',[
                        'href',"javascript:popMap('map_md_domain_htm_types_form')",
                        'style',{
                            'marginLeft':'2em'
                        },
                        '#text','htm types'
                    ]
                ]
            ])
        } //function createMdEditForm
        
        function promptForDevPassword(td)
        {
            d = ce('div')
            ac(ce('hr'),d)
            ac(ct('Enter developer password to access dev tools:'),d)
            ac(ce('br'),d)
            pass = ce('input'); pass.type='password'
            ac(pass,d)
            ac(ce('br'),d)        
            var b = ac(ce('button'),d)
            b.onclick = function()
            {
                syncPost('cti_change_session.aspx','key=reqauthtoken&value=p_dev_tools/'+pass.value)
                dismiss(this.parentNode)()
                if(/Y/.test(syncPost('cti_retrieve_session.aspx','checkauthtoken=p_dev_tools')))
                    createMdEditForm(td,form_code,fe_seq)
            }
            b.value = 'Submit'
            ac(d,td)
        } //function promptForDevPassword
        
        //(jds 20080710) - Changed the line below so that any user can access devtools. They still need to know the password to access devtools.
        //if(devTools && /\|p_dev_tools\|/.test(syncPost('cti_retrieve_session.aspx','shortkey=permissions')))
        if(devTools)
            if(/Y/.test(syncPost('cti_retrieve_session.aspx','checkauthtoken=p_dev_tools')))
                createMdEditForm(td,form_code,fe_seq)
            else
                promptForDevPassword(td)
        
        var cols = tr.parentNode.parentNode.firstChild.firstChild.childNodes.length
        td.colSpan = cols > 2 ? cols : 2
        td.align = 'center';
        td.className = 'helprow'
        var newrow = ac(td,ce('tr')).parentNode
        newrow.oncontextmenu = function(){ dismiss(this)(); return false; }
      
        if(tr.nextSibling)
            tr.parentNode.insertBefore(newrow,tr.nextSibling)
        else
            ac(newrow,tr.parentNode)
            
        spotlightElement(newrow,null,500)
        o.helprow = newrow;
        try{
            e.cancelBubble = true;
        }catch(x){}
        return false;
    } //function show_helprow
    
    //usage - debugging only
    function makeJSConsole()
    //DEBUGGING ONLY
    //provides javascript console functionality
    {
        if(!ge('jsconsole'))
        {
            var jsconsole = ce('div');      jsconsole.id = 'jsconsole';
            var console = ce('div');        console.id = 'console';
            var input = ce('textarea');     input.id = 'inputarea';
            var evalbutton = ce('input');         evalbutton.type = 'button';
            var closebutton = ce('input');          closebutton.type = 'button';
            var debugBox = ce('input');     debugBox.type = 'checkbox'; debugBox.id = 'debugBox';
            var opacity = ce('input');      opacity.type = 'text'; opacity.id = 'opacity';
            var inspector= ce('div');     inspector.id = 'inspector';
            console.style.backgroundColor = 'blue';
            console.style.height = '200px';
            console.style.overflow = 'auto';

            input.cols = 140
            input.rows = 10

            input.style.display = 'block';
            input.style.backgroundColor='blue';
            input.style.color='white'
            input.style.border='none'
            
            jsconsole.style.border = '4px inset';
            jsconsole.style.position = 'absolute';
            jsconsole.style["float"] = 'right'
            jsconsole.backgroundColor = 'white'
            jsconsole.style.top = document.body.scrollTop
            jsconsole.style.filter = "alpha(opacity=70)"
            jsconsole.oncontextmenu = function(){ return pickup(jsconsole); }
    //        jsconsole.style["-moz-opacity"] = .50
    //        jsconsole.style.opacity = .50;
            evalbutton.value = 'Evaluate'
            evalbutton.onclick = function(){
                var usertext = input.value;
                var responsetext;
                
                try{
                    responsetext = eval(usertext);
                } catch(x) {
                    responsetext = x.message
                }
                
                var userta = ce('textarea');
                var responseta = ce('textarea');
                
                userta.value = '>>>     ' + usertext;
                responseta.value = responsetext;
                
                userta.cols = 140
                userta.style.overflow = 'visible';
                userta.style.display = 'block';
                userta.style.backgroundColor='blue';
                userta.style.color='white'
                userta.style.border='none'
                
                responseta.cols = 140;
                
                responseta.style.overflow = 'visible';
                responseta.style.display = 'block';
                responseta.style.backgroundColor='blue';
                responseta.style.color='#00FFFF'
                responseta.style.border='none'
                
                ac(userta,console)
                ac(responseta,console)
                ac(ce('hr'),console)
                
                console.scrollTop = console.scrollHeight
            }    

            var monitorbutton = ce('input'); monitorbutton.type = 'button'
            monitorbutton.value = "Create Binding Monitor"
            monitorbutton.onclick = function(){ runBindingDiv(input.value)}


            debugBox.value = 'N'
            debugBox.onclick = function() { debugBox.value = debugBox.checked ? 'Y' : 'N' }
            
            closebutton.onclick = function() { document.body.removeChild(jsconsole) }
            closebutton.value = 'Close Console';
            
            opacity.onchange = function(){ jsconsole.style.filter='alpha(opacity='+opacity.value +')' }
            opacity.value = 70
            
            ac(console,jsconsole)
            ac(input,jsconsole)
            ac(ce('br'),jsconsole);
            ac(evalbutton,jsconsole)
            ac(monitorbutton,jsconsole)
            ac(closebutton,jsconsole)
            ac(debugBox,jsconsole)
            ac(opacity,jsconsole)
            ac(inspector,jsconsole)
            document.body.insertBefore(jsconsole, document.body.firstChild);
        }
    }

    //usage - toolbar
    //      - DEVELOPERS ONLY
    function quickLogon()
    {
        var d = makeDraggableDiv();
        
        var uid = ce('input')
        uid.type = 'text'
        
        var pwd = ce('input')
        pwd.type = 'password'
        
        var btn = ce('input')
        btn.type = 'button'
        btn.value = 'Logon'
        btn.onclick = function(){ 
            syncPost('cti_checklogon.aspx','UID='+uid.value+'&PW='+pwd.value)
            parent.top.location = parent.top.location
        }
        
        ac(uid,d);ac(ce('br'),d)
        ac(pwd,d);ac(ce('br'),d)
        ac(btn,d)
        
        d.style.left = ''
        d.style.right = 0;
        d.style.top = 0;
        d.onkeydown = function()
        {
            if(event.keyCode == 13){ btn.click() }
        }  
        ac(d,document.body);
    }//quickLogon

    //desc  - opens the requested stored procedure
    //usage - md edit
    function spFetch(sp_name)
    {
        open_popup_window(sp_name.replace(/\./ig,'_'),'cti_md_get.aspx?sp='+sp_name)
    }

    //desc  - returns the metadata for a row or form as a javascript object
    //usage - md edits
    function mdFetch(form_code,fe_seq)
    {
        return eval('('+syncPost('cti_md_get.aspx?#'+String(Math.random()),'form_code='+form_code+(fe_seq?'&fe_seq='+fe_seq:''))+')')
    }


    //DEBUG ONLY
    //opens a file on the local network
    //usage - dev portal
    function openFile(filename,args)
    {
        var path = syncPost('cti_retrieve_session.aspx','shortkey=sessionrootpath')
        var f = '\\\\cti-100\\Webservices'+path.replace(/\//g,'\\')+filename
        var oShell = (new ActiveXObject("Shell.Application"))
        oShell.ShellExecute(f,(args?args:''),"","open","1")
    }
    
    function show_templates(){
	    //alert('inside show templates');
    	
	    //var isle = clientMgr.bindMgr.isle;
    	
	    //var n = isle.documentElement.getElementsByTagName("ctncf_container");
    	
	    //if(n.length > 0){
	      //  var c = n[0].cloneNode(true);
    	    
	        //var note = c.getElementsByTagName("change_note")[0];
    	    
	        //if(note){
	          //  var nt = getTextNode(note);
    	        
	        //if(nt)
	          //  nt.nodeValue = "This is the new version!";
    	        
	           // alert('calling addfrag with text:' + nt.nodeValue);
    	        
	            //clientMgr.bindMgr.addFrag(c);
	        //}
    	    
	    //}
    	
	    for(var i = 0; i < clientMgr.bindMgr.bindTemplates.length; i++){
	    //alert('i = ' + i);
		    var templ = clientMgr.bindMgr.bindTemplates[i];
		    var newDiv = document.createElement("div");
		    newDiv.className = templ[0];
		    newDiv.innerHTML = "<hr>Template index:" + i + " Template Name:"  + templ[0] + "<hr>" + templ[1].outerHTML + "<hr>";
		    //newDiv.appendChild(templ[1].cloneNode(true));
		    //alert('template info:' + templ[0] + templ[1].nodeName);
		    document.forms[0].appendChild(newDiv);
	    }
    }
    
//**************************************************
//END - DEVTOOLS
//**************************************************

//**************************************************
//BEGIN - TOOLTIPS
// Notes: This was disabled, but no note as to when or why
//  -
//**************************************************

    //creates tooltip at the current mouse position using the provided html
    //usage - tooltips
    function show_tooltip(innerhtml)
    {
        return;
        var x;
        if(innerhtml.substr(0,4) == 'htm:')
            x = makeDraggableDiv(innerhtml.substring(4))
        else if(innerhtml.substr(0,4) == 'txt:')
        {
            x = ce('textarea')
            x.value = innerhtml.substring(4)        
            adjust_resize(x)
            x.onkeydown = function(){ adjust_resize(this); }
            x.readOnly = true;
            x = ac(x,makeDraggableDiv()).parentNode
        }
        else
            x = makeDraggableDiv(innerhtml)
            
        if(ge('tooltip')) dismiss(ge('tooltip'))()
        tooltip_timer = 0
        tooltip_fade = 0
        window.setTimeout("if(tooltip_fade && ge('tooltip') ) dismiss(ge('tooltip'))(); else tooltip_timer = 1",1000)
        x.id = 'tooltip'
        e = event||window.event
        o = e.srcElement
        x.style.position = 'absolute'
        x.style.top = document.body.scrollTop+e.y
        x.style.left = e.x
        x.className = 'tooltip'
        spotlightElement(x,null,500)
        o.onmouseout = function(){ if(tooltip_timer) dismiss(x)(); else tooltip_fade = 1 } 
    }
//**************************************************
//END - TOOLTIPS
//**************************************************

//desc  - substitutes value for named form field 
//usage - miscellaneous subtype properties and post calls
function resolveParm(trig, p, assumeSibling){
    if(arguments.length < 3)
        assumeSibling = false;
        
    if(p.charAt(0) == "@")
        return $root(p.substring(1));
        
    if(p.charAt(0) == "#")
        return $sibling(trig,p.substring(1));
        
    var n = $sibling(trig,p);
    
    //if(assumeSibling)
    //    return n  This was ignoring literals when assumeSibling was true
    //else{       
    //    if(!n)
    //        n = $root(p);
            
    if(!n && !assumeSibling)
        n = $root(p);
               
        if(n)
            return n;
        else
            return p;
    //}    
}

//**************************************************
//BEGIN - FILE ATTACHMENTS
// Notes:
//  -
//**************************************************

    //desc  - downloads the file indicated by id
    //usage - file download subtype
    function downloadFile(id,app)
    {
        var loc = "cti_file_download.aspx"    
        syncPost('cti_change_session.aspx','key=selected_file_id&value='+id)
        
        if(app)
            loc += ("?app=" + app);
            
        open_popup_window('download',loc)
    }

    //desc  - executes a query returning a file id, then downloads the file
    //usage - custom queries
    function execQueryForFile(type)
    {
        //type = type || 'xhtml'
               
        browser = ctiBrowser();
        
        response = syncPost('cti_query_report.aspx?output='+type,clientMgr.bindMgr.isle,null,true);
               
        results_file = browser.xPathSingle(response,'//results_file_id/text()')
        if(results_file && results_file.nodeValue)
            downloadFile(results_file.nodeValue)
    }
//**************************************************
//END - FILE ATTACHMENTS
//**************************************************

//**************************************************
//BEGIN - QUERIES AND REPORTS
// Notes:
//  - 
//**************************************************

    //desc  - used by 'Exec Query' in the action bar of QMF
    //usage - custom queries
    function runQuery(targetId,pageElementId,pagenum,pagesizeId)
    {
        var b = ctiBrowser()
        var loc = 'cti_query_report.aspx?page='+pagenum
        loc += '&page_size=' + gv(pagesizeId)
        var response = syncPost(loc,clientMgr.bindMgr.isle,null,true)
        
        ge(targetId).innerHTML = response.xml;
        if(response)
        {
            var num_records = b.xPathSingle(response,'//@rowcount')
            if(num_records)
            {
                num_records = num_records.nodeValue 
                
                var search_func = Function("clientMgr.confirmExit=false;runQuery('"+targetId+"','"+pageElementId+"',this.page_num,'"+pagesizeId+"')")
               /* write_query_paging_menu(ge(pageElementId+'_top'), 
                        pagenum,
                        search_func,
                        gv(pagesizeId),num_records)*/
                write_query_paging_menu(ge(pageElementId+'_bottom'),pagenum,search_func,gv(pagesizeId),num_records)
            }
            scrollTo(0);
        }
    }

    //desc  - Writes a paging menu into element
    //usage - runQuery
    //note:   We do not use any other functions for paging - we can rename it to illustrate this,
    //  the other paging menu functions can be removed
    //parameters
    //  element - the element to write the paging menu into
    //  pagenum - the page selected by the user
    //  search_function - a Function object to call for each paging link
    //  page_size - the size of each page
    //  num_records - the number of records selected
    function write_query_paging_menu(element,pagenum,search_function,page_size,num_records)
    {
        
        while(element.hasChildNodes()) element.removeChild(element.firstChild)
        if(!pagenum) pagenum = 1
        if(page_size && !isNaN(page_size) && Number(page_size) < Number(num_records))
        {
            var page_link = ce('a')
            page_link.href = 'javascript:;'
            page_link.onclick = search_function
            make_query_paging_menu(element,pagenum,page_link,page_size,num_records)
            ac(ce('br'),element)
            //var html =  make_paging_menu(page_link,page_size,num_records) + "<br>"
            
            if(pagenum > 1)
            {
                var prev_link = ce('a')
                prev_link.href = page_link.href
                ac(ct('Prev'),prev_link)
                prev_link.page_num = pagenum-1
                prev_link.onclick = search_function
                ac(prev_link,element)            
                ac(ct(' '),element)
            }
            if($root('search_page') < num_records/page_size)
            {
                var next_link = ce('a')
                next_link.href = page_link.href
                ac(ct('Next'),next_link)
                next_link.page_num = pagenum+1
                next_link.onclick = search_function
                ac(next_link,element)
            }
        }   
    }

    //usage - custom queries
    //we do not use any other functions for paging
    function make_query_paging_menu(element,pagenum,page_link,page_size,num_records)
    {
        var num_pages = num_records/page_size;
        if(num_records % page_size) num_pages++;
        //alert('pagenum='+pagenum)
        for(var i = 1; i <= num_pages; i++)
        {
            var l = ce('a')
            if(i == pagenum) 
                l.style.color = 'red';
            else
            {
                l.href = page_link.href
                l.onclick = page_link.onclick            
            }
            l['page_num'] = i
            ac(ct(i),l)
            ac(l,element)
            ac(ct(' '),element)
        }
    }
//**************************************************
//END - QUERIES AND REPORTS
//**************************************************


//punts you back to the logon page, using a clever sequence of syncposts
//usage - cedar after changing password
function returnToLogon()
{
    app = syncPost('cti_retrieve_session.aspx','shortkey=SessionAppName')
    map = syncPost('cti_retrieve_session.aspx','shortkey=SessionMapName')
    syncPost('cti_logout.aspx'); 
    syncPost('../default.aspx?app='+app);
    syncPost('cti_nav.aspx','map_filename='+map)
    top.action_frame.location.reload();
    top.right_frame.location='cti_nfg.aspx?form_code=logon'; 
}

//desc  - Opens a given url in a new browser instance
//usage - EHR link
function new_browser(url){
    var o = window;
    while(o.opener) o=o.opener;
    var sLoc = o.parent.framesetMgr.DEFAULT_LINK + url
    
    if(window.location.href.indexOf('https:') > -1){
        sLoc = sLoc.replace(/http\:/i, "https:");
        
        if(sLoc.indexOf('https:') == -1)
            sLoc = sLoc.replace(/www\./i, "https://www.");
            
        if(sLoc.indexOf('https:') == -1)
            sLoc = "https://www." + sLoc;
    }    
			
    try{ 
        var oShell = new ActiveXObject("Shell.Application");
        
 	    oShell.ShellExecute("iexplore.exe", sLoc, "", "open","1");
 	} 
 	catch(e){
 	    var msg = "BROWSER CREATION ERROR.\nUnable to create new instance of browser (" + e.message + ")\n\n"
 	    msg += "To make this feature work, please modify the following Web Browser settings:\na) Add https://www.web-aide.com to the list of Trusted Sites.\n"
 	    msg += "b) In the 'Custom Level' security settings for trusted sites, under 'ActiveX controls and plug-ins,' set 'Intialize and script ActiveX controls not marked as safe' to 'Enable'"
 	
 	    alert(msg);
    }
}

//desc - sets browser to full screen on IE only
//usage - bottom frame
function toggleFullScreenMode()
{
        var key = "key=session.sessionscreenmode&value="
               
        try {
        var obj = new ActiveXObject("Wscript.shell");
        
        obj.SendKeys("{F11}");
        }
        catch(e){
 	        var msg = "BROWSER MODE ERROR.\nUnable to place browser in Full Screen Mode (" + e.message + ")\n\n"
 	        msg += "To make this feature work, please modify the following Web Browser settings:\na) Add https://www.web-aide.com to the list of Trusted Sites.\n"
 	        msg += "b) In the 'Custom Level' security settings for trusted sites, under 'ActiveX controls and plug-ins,' set 'Intialize and script ActiveX controls not marked as safe' to 'Enable'"
 	
 	        alert(msg);
        }
        
        var currMode = syncPost("cti_retrieve_session.aspx","shortkey=sessionscreenmode");
        
        if(currMode == "FULL")
        {
            var prevMode = syncPost("cti_retrieve_session.aspx","shortkey=sessionscreenmodeprev");
        
            key += prevMode;           
        }
        else
            key += "FULL";
            
        syncPost("cti_change_session.aspx", key);
}

//desc - sets browser to half screen size
function toggleSplitScreenMode(triggerId, splitText, unsplitText, currMode)
{  
    var top_x           = 0;
    var top_y           = 0;
    var width_offset    = 0;
    var height_offset   = 0;
    var linkText;
    

    if(!triggerId)
        triggerId = "";
	
	if(!splitText)
	    splitText = "SplitScreen";
	    
	if(!unsplitText)
	    unsplitText = "SplitScreen"; //jds 1/29/2009 - used to be UndoSplitScreen
	    
    if(!currMode)
        currMode = syncPost("cti_retrieve_session.aspx","shortkey=sessionscreenmode");
       
    if(currMode == "FULL")
        alert('Browser is in Full Screen Mode.  To go into Split Screen Mode, come out of Full Screen Mode first, then choose Split Screen.')
    else
    {
        var triggerObj;
	
	    if(triggerId != "")
	        triggerObj = document.getElementById(triggerId);
        
        var key = "key=session.sessionscreenmode&value="
        
        if(currMode == "SPLIT")
        {
            key += "NORMAL";
            
            if(/Microsoft/.test(navigator.appName))
            {
                top.moveTo(top_x,top_y); //moves to left monitor in dual monitor setup  - uncommented per Justin 12/29/08
                top.resizeTo(screen.width - width_offset, screen.height - height_offset);
            }
            else
            {
                top.screenX = top_x;    // uncommented per Justin 12/29/08
                top.screenY = top_y;    // uncommented per Justin 12/29/08
                top.outerWidth = screen.width - width_offset;
                top.outerHeight = screen.height - width_offset;
            }
            
            linkText = splitText;
            
        }
        else
        {
            key += "SPLIT";
            
            if(/Microsoft/.test(navigator.appName))
            {
                top.moveTo(top_x,top_y); //moves to left monitor in dual monitor setup - uncommented per Justin 12/29/08
                top.resizeTo(screen.width/2, screen.height);
            }
            else
            {
                top.screenX = top_x;    // uncommented per Justin 12/29/08
                top.screenY = top_y;    // uncommented per Justin 12/29/08
                top.outerWidth = screen.width/2;
                top.outerHeight = screen.height;
            }
                
           linkText = unsplitText;
        }
        
        if(parent.action_frame)
            parent.action_frame.location.reload(); // resizes action frame to appropriate size
        
        syncPost("cti_change_session.aspx", key);
         
        if(triggerObj)
            triggerObj.innerText = linkText; 
         
    } // Not FULL
    
} // toggleSplitScreenMode

//desc  - gets all of the section labels with the specified class name
//usage - section hiding
function getAllSections(className)
{
    if(!className) className = 'label_section'
    var as = [];
       
    for(var i in document.anchors)
    {
       
        var a = document.anchors[i]       
        if(a.className == className)
            as.push(a.id);
    }
        
    return as
}

//desc  - creates a ul with links to all of the anchors in the document in it
//usage - debugging page
function showPageLinksMenu()
{
    var as = [];
    for(var i in document.anchors) 
    {
        var a = document.anchors[i]
        if(a.name && !a.href)
            as.push("<li><a href='#"+a.name+"'>"+a.innerHTML+"</a></li>");
    }
    return '<ul>'+as.join("\n")+'</ul>'
}

// temporary - put this in the metadata
function set_objective(sel) {
    if (sel.value != '') {
        var xParent = getRelatedXMLNode(sel);

        clientMgr.bindMgr.setXMLValue('objective_broad', sel.options[sel.selectedIndex].text, xParent);
        
        var aRes = cti_verify2(sel, 'prvdr_objective_vf', 'goal_objective_id:' + sel.value);

        if (aRes[0]) {
            var xNode = browser.xPathSingle(aRes[1], './objective_specific');
            var txtNode = getTextNode(xNode);
            if (txtNode)            
                clientMgr.bindMgr.setXMLValue('objective_specific', txtNode.nodeValue, xParent);
        }
    }
}


//desc  - triggers domain refills for all the selects requests
//usage - dynamic select lists
function chain_selects(o,list)
{
    var debugKey = (window.event && window.event.ctrlKey && window.event.shiftKey)
    clientMgr.processChange(o);
    var l = list.split(",")
    for(var i in l)
    {
        var target = l[i];
        var sib = getHTMLSibling(o,target)
        if(sib) // rev 9.8
        {
            if(debugKey) 
            {
                alert('my value='+$sibling(o,o.bindFld))
                alert("sib's domain="+sib.domain)
                //cti_alert(clientMgr.bindMgr.getBoundPair(clientMgr.bindMgr.boundDataEls,sib,0)[1].parentNode.xml)
                //spotlightElement(o)
            }
            fill_domain(sib);
            browser.fireEvent(sib,'onchange');
        }
    }
}

//desc  - renders a list out according to an HTML template, replacing $_ with the values in the list
//usage - list_transform types
function listTransform(list,template)
{
    l = list.split(',')
    ret = []
    for(var x in l)
    {
        ret.push(template.replace(/\$\_/ig,l[x]))
    }
    return ret.join("")
}

//desc  - runs all list transformations in the document
//usage - form initalization
function transformListTransforms()
{
    var ds = gt('div')
    for(var i in ds){
        var d = ds[i]
        if(d.getAttribute && d.getAttribute('list_transform'))
        {
            spotlightElement(d)
            d.innerHTML = listTransform($sibling(d,d.getAttribute('bindFld')),d.getAttribute('template'))
            alert($sibling(d,d.getAttribute('bindFld')))
            alert(d.getAttribute('template'))
            alert(d.innerHTML)
        }
    }
}

//desc  - renders a rank-2 delimited list out according to an html template
//      - replaces $n with the nth member of each sub-list
//usage - right-click menus
function listTransform2(list,template)
{
    l = list.split(';')
    ret = []
    for(var x in l)
    {
        a = l[x].split(':')
        var t = template
        for(var i in a)
        {
            t = t.replace("$"+i,a[i],"ig")
        }
        ret.push(t)
    }
    return ret.join("")
}

//**************************************************
//BEGIN - DIV MENU
// Notes:
//  - @@@@@ put clendar divs here also
//**************************************************

    //desc  -  - creates a popup menu div on right-click
    //usage - right-click menus (i.e. patient search, encounter search )
    // note:  items should come in rank-2 delimited format using ; and :
    //example: Select:loadContent('map_record',$sibling(this,'record_fk'));Delete:clientMgr.bindMgr.deleteRow(this)
    function createMenu(items)
    {
        if(ge('popupMenu')) dismiss(ge('popupMenu'))()
        x=makeDraggableDiv()
        x.id = 'popupMenu'
        x.className = 'popupMenu'
//        cti_alert(items,'items')
        var listHTML = listTransform2(items,"<li><a style='margin-left:$2em;' href='javascript:;' onclick='$1'>$0</a></li>").replace(/this/ig,'this.parentNode.parentNode.parentNode.target')
//        cti_alert(listHTML,'list html')
        x.innerHTML="<ul class='popupMenu'>"+listHTML+"</ul>"
        e = (event || window.event)
        x.style.left = e.clientX
        x.style.top = e.clientY+document.body.scrollTop
        x.target = e.srcElement    
        x.onclick = dismiss(x)
        x.oncontextmenu = dismiss(x)
        return x;
    }

    //desc - creates a popup menu based on actions in a map
    //usage - right-click menus 
    function actionMenu(map) {
        var menu = syncPost('cti_action_menu.aspx?map=' + map)
        try {
            var menuDiv = createMenu(menu)
        } catch (x) {
            var menuDiv = createMenu('could not create menu for ' + map)
            menuDiv.style.backgroundColor = 'red'
        }
    }

//**************************************************
//END - DIV MENU
//**************************************************


//**************************************************
//BEGIN - EMR/PHR HEALTH RESOURCES ROUTINES
// Notes:
//  - custom drilldown aspx page EMR/PHR Health Resources)
//**************************************************
    
    //desc  - returns a DIV with the drilldownmenu rendered into it.
    //usage - drilldowns (health resources)
    function initDrillDownMenu(menuXml,selectedNode,menuInd)
    {
        var div = ce('div')
        div.className = 'drilldown_menu'
        
        if(!selectedNode)   selectedNode = menuXml.documentElement.firstChild
        if(!menuInd) menuInd = '&raquo;'
        
        function refreshMenu(obj,m)
        //onclick event for links, to re-render the node
        {
            div.parentNode.replaceChild(initDrillDownMenu(menuXml,obj.relatedXML,m),div)
        }
        function createLink(node)
        {
            var link = ce('a')
            link.relatedXML = node                
            link.href = 'javascript:;'
            
            var linkText = node.getAttribute("link");
            
            if(linkText && (linkText != ""))
            {
                ac(ct(node.getAttribute('text')),link)     
                link.onclick = function()
                               {
                                var myLink = this.title;                           
                                var sXML = '<shr_ubehavior_save><behavior_type_code>DDMLINK</behavior_type_code><value>';
                                    sXML += myLink + '</value></shr_ubehavior_save>'
                                var result = syncPost("cti_save.aspx?action=I&form_type=dynamic", makeXML(sXML), null, true);  //ignore status for now
                                
                                //cti_alert('result:' + ctiBrowser().xmlText(result));
                                //open_popup_window('',this.relatedXML.getAttribute("link")) 
                                open_popup_window('',myLink);
                               }
                link.className = 'link';
                link.title = linkText;
            }
            else
            {
                link.onclick = function(){refreshMenu(this)}
                link.oncontextmenu = function(){ refreshMenu(this,'&hearts;'); return false;}
                link.className = 'menu'
                link.innerHTML = node.getAttribute('text')+'&nbsp;'+menuInd+'&nbsp;'
            }
            return link
        }
        //assemble breadcrumbs (parent hierarchy of Node)
        var topbox = ce('div')
        topbox.className = 'top'
        //climb dom tree, building links as you go
        
        if(/\|dev\|/.test(syncPost('cti_retrieve_session.aspx','shortkey=permissions')))
        {
            var p = ce('span')
            p.className = 'dev_path'
            //get path
            var path = []
            var n = selectedNode;
            while(n!=menuXml.documentElement && n.getAttribute('menu'))
            {
                path.push('/*[@menu="'+n.getAttribute('menu')+'"]')
                n=n.parentNode;
            }
            ac(ct('/'+path.reverse().join("")),p)
          
            ac(p,topbox)
            
        }
        
        var n = selectedNode.parentNode;
        var crumbs = []
        while(n != menuXml.documentElement)        
        {
            crumbs.push(createLink(n))
            n = n.parentNode;
        }
        crumbs.reverse();
        for(var i in crumbs)
            ac(crumbs[i],topbox)
        var current = ce('span')
        current.className = 'current'
        ac(ct(selectedNode.getAttribute('text')),current)
        ac(current,topbox)
        
        ac(topbox,div)
        
        
        //assemble left menu (siblings of Node)
        var leftbox = ce('div')
        leftbox.className = 'left'
        for(var i=0,t=selectedNode.parentNode.childNodes.length;i<t;i++)
        {
            var n = createLink(selectedNode.parentNode.childNodes[i])
            var d = ce('div')
            if(selectedNode.parentNode.childNodes[i] == selectedNode)
            {
                d.style.backgroundColor = 'white'
                d.style.position = 'relative'
                d.style.right = '-1px'            
                if(i!=0)
                    d.style.borderTop = '1px solid navy'
                d.style.borderBottom = '1px solid navy'         
                d.style.borderLeft = '1px solid navy'   
            }
            else
            {
                d.onmouseover = function(){ this.className = 'hover' }
                d.onmouseout = function(){ this.className = '' }
            }
            ac(n,d)
            ac(d,leftbox)
        }  
          
        //assemble right menu (children of Node)
        var rightbox = ce('div')
        rightbox.className = 'right'
        for(var i=0,t=selectedNode.childNodes.length;i<t;i++)
        {
            var node = selectedNode.childNodes[i]
            var n = createLink(node)
            var d = ce('div')
            ac(n,d)
            
            var descr = node.getAttribute("description")
            if(descr && descr != "")
            {
                var descrdiv = ce('div')
                ac(ct(descr),descrdiv)
                descrdiv.className = 'description'
                ac(descrdiv,d)
            }
                
            var link = node.getAttribute("link")
            if(link && link != "")
            {
                var linkdiv = ce('div')
                ac(ct(link),linkdiv)
                linkdiv.className = 'address'
                ac(linkdiv,d)
            }
            ac(d,rightbox)
        }
        ac(leftbox,div)
        ac(rightbox,div)
        return div.parentNode
    }

    //usage - cannot find reference
    //function makeDrillDown(menu_name,sp,args)
    //{
    //    return initDrillDownMenu(getDrillDownXml(menu_name,sp,args))
    //}

    //usage - form initialization
    function getDrillDownXml(menu_name,sp,args)
    {
        var xmltext = syncPost('cti_drilldown_menu.aspx','menu_name='+menu_name+    (    sp?'&sp='+sp+(args?'&'+args:''):''    )    )   
        var x = makeXML(xmltext)
        return x
    }

    //usage - form initialization
    function makeDrilldownMenus()
    {
        var ds = gt('div')
        for(var i in ds){
            var d = ds[i]
            if(d.getAttribute && d.getAttribute('drilldown_menu'))
            {
                var xml = getDrillDownXml($sibling(d,d.getAttribute('bindFld')))
                var path = $sibling(d,d.getAttribute('selected_node_col'))
                if(path != '') var node = ctiBrowser().xPathSingle(xml,path)
                var menu = initDrillDownMenu(xml,node)
                ac(menu,d)
            }   
        }
    }
//**************************************************
//END - HEALTH RESOURCES ROUTINES
//**************************************************


//desc  - highlights a TR
//usage - binding, for new rows
function highlightTR(tr,color)
{
    if(tr)
    {
        //listApply((function(a){ if(a.style) a.style.backgroundColor = (color?color:'#FFFFCC')}),tr.childNodes)    //light yellow
        listApply((function(a){ if(a.style) a.style.backgroundColor = (color?color:'#FFCCCC')}),tr.childNodes)      //jds - pink - background for modified rows
    }
}

//usage - various (very generic)
//applies function F to each item in list L
function listApply(f,l)
{
    for(var i in l) 
        f(l[i]);
}

//desc  - applies function f to each pair of elements in r
//      - executes a left fold operation
//usage - various (very generic)
function fold(f,l,r) 
{
    for(var i in l)
        r = f(r,l[i])
    return r    
}

//desc  - 
//usage - loads a form based on map metadata
function popMap(map,name,stickaround,args)
{
    var fc = '';

    if(!name || (name == 'no_name')) name = ''
    if(!map || (map == 'no_map') || (map == 'map_default_popup'))
    {
        map = 'map_default_popup';
        fc = name; //empty map means use name as form code and use default popup map so we don't have to define skeleton maps
    }
    
    if(!stickaround  || (stickaround == 'no_stickaround')) 
        stickaround = false;
    else
        stickaround = true;
    
    //if(!stickaround) stickaround = null
    //if(stickaround == 'stickaround') stickaround = true        //@@@@@ (jds 20081002)
    //if(stickaround == 'no_stickaround') stickaround = false    //@@@@@ (jds 20081002)
    
    if(!args || (args == 'no_args')) args = ''
    
    // Note:  this call may return more than just the form code.
    if(fc == '')
        fc = syncPost('cti_load_form_map.aspx?map='+map) // May not need this
    
    //alert('args are:' + args + '\r form_code:' + fc + '\r map:' + map);
    
    return open_popup_window(name,'cti_nfg.aspx?map=' + map + '&form_code='+fc+args,stickaround)
}


//**************************************************
//BEGIN - SORTING (CLIENT-SIDE)
// Notes:
//  -
//**************************************************

    var sorts = {}

    //sorts a child form given a column name
    function sortHTML(form_code,name_htm,asc)
    {            
        var a = [];
        var bHybrid;
        var layout;
        var bValid = false;
        var e = (event || window.event)
        var debugKey;
        if(e) debugKey = (e.ctrlKey && e.shiftKey)
        
        var contHTM = getContainingElementByAttrib(e.srcElement,'layout');
                        
        if(contHTM)
        {       
            layout = contHTM.getAttribute('layout');
               
            var bP = clientMgr.bindMgr.getBoundPair(clientMgr.bindMgr.boundContEls, contHTM, 0);
		           
		    if(bP)
		    {
		        contX = bP[1];
		        
		        bValid = true;
		    }
         }
                       
        if(!bValid)
        {
            if(debugKey) alert(-1);
            return; //subcontrol
        }
        
        if(debugKey) alert(0);
        
        //var xp  = ctiBrowser().xPath(clientMgr.bindMgr.isle,'//'+form_code+'/'+name_htm);       
        var xp  = ctiBrowser().xPath(contX,'./'+form_code+'/'+name_htm);
        
        for(var i=0,n=xp.length;i<n;i++)
            a.push(xp[i]);

        var pol = asc?-1:1
        function valComp(x,y)
        {
            var dx = new Date(x)
            var dy = new Date(y)
            if(!isNaN(dx) && !isNaN(dy))
                return dx < dy ? 1 : -1
            else if(!isNaN(x) && !isNaN(y))
                return Number(x) < Number(y) ? 1 : -1
            else if((typeof x === 'string') && (typeof y === 'string'))
                return x.toLowerCase() < y.toLowerCase() ? 1 : -1
            else
                return x < y ? 1 : -1
        }
        a = a.sort(function(x,y)
            { 
                if(x.firstChild && y.firstChild)
                    return pol*valComp(x.firstChild.nodeValue,y.firstChild.nodeValue)
                else if(x.firstChild && !y.firstChild)
                    return pol;
                else if(y.firstChild && !x.firstChild)
                    return -pol;
                else
                    return 0;
            }
        )

        var h = []
        if(/hybrid/ig.test(layout))
            bHybrid = true;
            
        var tr;
        for(var i in a)
        {
            var pair = clientMgr.bindMgr.getBoundPair(clientMgr.bindMgr.boundDataEls,a[i],1)
            if(pair)
            {
                tr = getContainingElementByAttrib(pair[0],'bindSrc');
                
                if(bHybrid)
                    h.push([tr,node_after(tr)]);
                else
                    h.push(tr);
            }
        } // for

        if(h[0])
        {
            var tbody = (bHybrid ? h[0][0].parentNode:h[0].parentNode);
            
            if(sorts[form_code]) sorts[form_code].className = ''
            if(e && e.srcElement)
                    e.srcElement.className= 'sort_'+ (e.srcElement.asc ? 'desc' : 'asc')
            if(e) sorts[form_code] = e.srcElement
            
            while(tbody.childNodes.length) tbody.removeChild(tbody.childNodes[0])
            for(var i in h)
                if(bHybrid)
                {
                    ac(h[i][0],tbody);
                    ac(h[i][1],tbody);
                }
                else
                    ac(h[i],tbody);
        }
        else
        {
            var e = (event || window.event);
            if(e && e.srcElement)
                spotlightElement(e.srcElement,null,250);
        }
    }
//**************************************************
//END - SORTING ROUTINES (CLIENT-SIDE)
//**************************************************


//**************************************************
//BEGIN - TOGGLE (HIDE AND SHOW)
// Notes:
//      - We need some way of keeping track of what has been shown and hidden 
//      - so that we don't have to do DOM traversal every time we want to find
//      - something and we don't have to do explicit grouping
//**************************************************

    //desc  - used for section-based hiding
    function forceSectionDisplays(sectionList,force)
    {
       listApply(function(n){ var x = ge(n); if(x && x.className != force) x.click();},sectionList)
    }

    //used for section-based hiding
    function openSection(s)
    //s is a section element. (<A> tag)
    {
            if(!s) return;
            s.click();
            var p
            if((p = s.parentNode) && p.style && p.style.display == 'none')
                p.style.display = 'block'
    }

    function toggleSectionDisplay(tableList,labelList)
    {
        var e,el,x,force;
        e = (event||window.event)
        el = e?e.srcElement:null;
        if(el && el.getAttribute('force')) force = el.getAttribute('force')
        if(el && el.tagName.toLowerCase() == 'div') el = el.parentNode
                
        if(force == 'open' || (el && el.className == 'open'))
        {
            el.className = 'closed'
            x = el.firstChild
            if(x && x.tagName && x.tagName.toLowerCase() == 'div') x.innerText = 'Show'
            if(x.parentNode.getAttribute('hide_section'))        
            {
                var xpp = x.parentNode.parentNode;
                if(xpp && xpp.style && xpp.style.display != 'none')
                    x.parentNode.parentNode.style.display = 'none'  
            }
        }
        else if(force == 'closed' || (el && el.className == 'closed'))
        {
            el.className = 'open'
            x = el.firstChild
            
            //20090415 - jds - DO NOT DELETE !!!
            // Changed the following line so that javascript validation will always run on
            //   opened sections. The text 'Hide' is no longer displayed. This is needed if
            //   so that if a change is made to something in the section, the client-side validation will run.
            // NOTE: Can we detect if something has changed in the section, If NOT then execute
            //if(x && x.tagName && x.tagName.toLowerCase() == 'div') x.innerText = 'Hide'
            //20090622 - jsd - determined that change is not required
            if(x && x.tagName && x.tagName.toLowerCase() == 'div') x.innerText = ''
            
            if(x.parentNode.getAttribute('hide_section'))
            {
                var xpp = x.parentNode.parentNode;
                if(xpp && xpp.style && xpp.style.display == 'none')
                    xpp.style.display = 'block'
            }
        }
        listApply(toggleTableDisplay,tableList)
        listApply(toggleDisplay,labelList)
    }

    function toggleDisplay(name)
    {
        var o = ge(name)
        
        if(o && o.style)
        {
            if(o.style.display == 'none')
                o.style.display = 'block';
            else
                o.style.display = 'none';
        }    
    }

    function toggleTableDisplay(name)
    {
        //alert('table name to toggle:' + name);
        
        if(name.indexOf('sc:') == 0){
            name = name.replace('sc:','');
            
            var o = ge('tbl_'+ name);
        }
        else{
            //alert('table name:' + name);
        
            var o = ge('tbl_'+name+'_container');
            }
        
        if(o && o.style)
        {
            if(o.style.display == 'none')
            {
                o.style.display = 'block';
                var b = ge(name+'_defer_button')
                if(b) b.click();
            }
            else
                o.style.display = 'none';
        }
    }


    function toggleAll(o,action_id)
    {
        var sHide = 'Hide';
        var sShow = 'Show';
    
        // See if the caller is action frame - handles anchors with javascript in the href
        if(!o){
            o = parent.action_frame.document.getElementById(action_id);
        }
    
        if(!o.force)
            o.force = 'open';
                        
        forceSectionDisplays(getAllSections(o.force == 'open' ? 'closed' : 'open'),o.force); 
        o.force = (o.force == 'open' ? 'closed' : 'open');
        
        var newTxt = o.innerText;
        
        if(o.force == 'closed')
        {
            if (newTxt.indexOf('SHOW') > -1)
                sHide = sHide.toUpperCase();
                
            newTxt = newTxt.replace(/show/ig,sHide);
            
            // 20090626 - jsb blank out text to remove hide capability
            newTxt = "";
        }
        else if(o.force == 'open')
             {
                if (newTxt.indexOf('HIDE') > -1)
                    sShow = sShow.toUpperCase();
                
                newTxt = newTxt.replace(/hide/ig,sShow)
             }
                
        o.innerText = newTxt;
    } // toggleAll

//**************************************************
//END - HIDING AND SHOWING ROUTINES
//**************************************************


function inArr(item,arr)
{
    for(var i in arr) 
        if(arr[i] == item) 
            return true;
    return false;
}

function showDomain(domain) //debug only
{
    var x = makeDraggableDiv(); 
    ac(DOMdomainCache[domain].cloneNode(true),x)        
}

function showDomains()
{
    var x = makeDraggableDiv()
    for(var i in DOMdomainCache)
    {
        a = ce('a')
        ac(ct(i),a)
        a.href = 'javascript:;'
        a.onclick = function()
        {
            showDomain(this.innerText)
        }
        a.style.fontSize = '14px'   
        ac(a,x) 
        ac(ce('br'),x)
    }
}

function applyStyle(el,s)
{
    for(var i in s)
        el.style[i] = s[i]
}

//converts a nested list of arrays into a DOM structure, rendering them into tag
/*
    tag: an object reference to a DOM node to put the resulting structure into
    o: a nested list of arrays, where 
        index 2(n-1) is the tagname nth element, and 
        index 2n-1 is an array containing the attributes or children of the nth element
    used by show_helprow as an example; can be used further for cleaning up DOM-intensive code
*/
function JSONtoDOM(tag,o)
{
    var el = (typeof tag == 'string' ? ce(tag) : tag)
    for(var i = 0, l = o.length; i < l; i+=2)
    {
        var n = o[i]
        var v = o[i+1]
        if(typeof v == 'object' && !(n == 'style'))
            ac(JSONtoDOM(ce(n),v),el)
        else
            if(n == '#text')
                ac(ct(v),el)
            else if(n == 'style')
                applyStyle(el,v)
            else
                el[n] = v
    }
    return el
}

//tests the function JSONtoDOM
//not used
function testJTD()  //debug only
{
    var j = [
            'td',[
                'a',[
                    'href','javascript:makeJSConsole()',
                    '#text','JS Console'
                ]
            ],
            'td',[
                'a',[
                    'href','javascript:show_island()',
                    '#text','Data Island'
                ],
                'a',[
                    'href','javascript:;',
                    'onclick',function(){cti_alert(getRelatedXMLNode(o).xml)},
                    'style',{
                        'marginLeft':'2em'
                    },
                    '#text','Data Island (Local)'
                ]
            ],
            'td',[
                'a',[
                    'href','javascript:show_templates();',
                    '#text','JS Console'
                ],
                'a',[
                    'href','javascript:showDomains()',
                    'style',{
                        'marginLeft':'2em'
                    },
                    '#text','Domains'
                ]
            ]
        ]
        
    JSONtoDOM(makeDraggableDiv(),j);  
}

//recursively calls spotlight on the html nodes associated with an xml document
function spotlightXML(root,color,fadeTime)
{
    if(root)
        spotlightElement(getRelatedHTMLNode(root),color,fadeTime)
    if(root && root.childNodes && root.childNodes.length)
        for(i=0,n=root.childNodes.length;i<n;i++)
            spotlightXML(root.childNodes[i],color,fadeTime)
}



//**************************************************
//BEGIN - NOT USED
//**************************************************

    //cat   - not used
    //desc  - 
    //usage - not used
    //function autoTab(input,len,next) {
      //  if(input.value.length >= len){
	    //    next.focus()
        //}
//}

//usage - used by subtypes
function searchFormUpdateTotals()
//hack
//updates the record count for a search form. This should really be a part of the control prototype (script_js)
{
    if (ge('search_total_records_display') && ge('sf_search_record_count'))
        ge('search_total_records_display').innerText = 'Records Found: ' + gv('sf_search_record_count')
}
      
//**************************************************
//END - NOT USED
//**************************************************


//**************************************************
//BEGIN - Application Dependent Routines
//
// NOTE - (jds 20080826)
//        These routines are doubly defined and in md_htm fe_spc_p1.
//        They are defined here again only for debugging purposes.
//        They should be deleted out of this library when debugging is done.
//**************************************************
function verify_person_selection(o,map,mode,id)
{
    //alert('in library version of verify_person_selection');

    if(!mode)mode='U';if(!id)id='cdpm_person_id';
    
    // jsb 09/18/08 -- lifted from load_content to prevent person selection if they cancel it.
    // 
    // If this method is being called from the right frame or left frame, and the page in the right frame is
    // generated, then execute the confirm leave routine on the right frame.  Otherwise, if this method is
    // being called by a popup main form, then execute the confirm leave on the current window.
    var w = window.opener.parent;
       
    if(w && w.right_frame) // this should always be true
    {
        var rf = w.right_frame;
    
        if(rf.document.body.className == 'rf')
        {
        
        var mess = rf.frm_confirm_leave3()
        //if(mess && !confirm('loadcontent1:' + 'Are you sure you want to navigate away from this page?\n\n'+
        if(mess && !confirm('Are you sure you want to navigate away from this page.?\n\n'+
           mess+ '\n\nPress OK to continue, or Cancel to stay on the current page.')) return false;
        else rf.clientMgr.confirmExit = false;
        }
    }
    

    if(!cti_verify(o,'person_select_verify','','cdpm_person_id:#cdpm_person_id'))
    {
        alert('verify failed'); return false;
    } 
    else 
    {
        //if(confirm('About to Load Content Continue?\n'))       
            loadContent(map,mode,$sibling(o,id)); 
    }  
    return true;
}

/* jds 20081211 - select encounter is currently defined in MD_HTM fe_spc_p1 so the code below should not matter
*/
function select_encounter(o,map,mode)
{
    if(!cti_verify(o,'enc_elmf_select_verify','','encounter_id:#add_encounter_fk'))
    {
        alert('verify encounter failed'); return false;
    };
    if(opener) opener.loadContent(map,mode); else loadContent(map,mode); }


//**************************************************
//END - Application Dependent Routines
//**************************************************


