/* This file was generated as a concatenation of other files. DO NOT EDIT. 
 * Go edit the origonal files, as are listed in the source for concat.php */


//--------------------
// file: include.js
//--------------------
//
//SFH (C) COPYRIGHT 2002, Proposal Technologies Network, inc
//  http://www.proposaltech.com. THIS FILE AND ITS CONTENTS ARE AN UNPUBLISHED
//  TRADE SECRET OF PROPOSAL TECHNOLOGIES INC. USE OF THIS MATERIAL WITHOUT 
//  PERMISSION OF PROPOSAL TECHNOLOGIES INC IS A VIOLATION OF US TRADE SECRET LAW.
// 
// Functions in this file may have copyrights that are owned by other parties, 
// as indicated by the comment associated with such functions. 
//
//  $Id: include.js,v 1.5 2005/11/17 23:20:22 uid517 Exp $ EFH

// This javascipt file is included with every page load. 

// Write an include line into the document
function include(path){ 
    document.write('<script language="JavaScript1.2" src="'+path+'"></script>') 
}

// Import a function from a frame's parent.
// Why does this work? The re-defined function actually runs in the parent 
// context
function importFromParent(name){
    var evalStr = name+'=window.parent.'+name;
    eval(evalStr);
}



function popUp(URL,width,height,name,win_name) {

    if(!name){
        name = 'page';
    }

    if(!win_name){
        win_name = 'popup';
    }

    eval(name+" = window.open(URL, '"+win_name+"', "+
         "'toolbar=0,alwaysRaised=1,scrollbars=1,location=0,"+
         "statusbar=1,menubar=1,"+
         "resizable=1,width="+width+",height="+height+"');");
}

// Popup a window containing the contents of an element
// on the calling page. 
function popUpFromElement(element_id,name,width,height,title){

   eval("popup = window.open('', '"+name+"', "+
         "'toolbar=0,alwaysRaised=1,scrollbars=1,location=0,"+
         "statusbar=1,menubar=1,"+
         "resizable=1,width="+width+",height="+height+"');");

   element = document.getElementByID(element_id);

   popup.document.write('<html><head><title>'+title+'</title></head><body>');
   popup.document.write(element.innerHTML);
   popup.document.write('</body></html>');


}

// Use this in an onMouseOver call to pop up a window
//<a href="#"  onMouseOver="popupText('text')" onMouseOut="closePopup()">Open Hover Window</a>
function popupText(text) {
    popupText = open("","hoverwindow","width=300,height=200,left=10,top=10");
    popupText.document.write(text);
}
 

function  closePopup(){
    popupText.close();
}


function selectCheckBoxByName(name){
    var cb = document.getElementById(name );
    if(cb){
        cb.checked = true;
    }
};



//Stolen from http://www.howtocreate.co.uk/tutorials/index.php?tut=0&part=16
function windowSize() {
  var myWidth = 0, myHeight = 0;

  if( typeof( window.innerWidth ) == 'number' ) {
    //Non-IE
    myWidth = window.innerWidth;
    myHeight = window.innerHeight;

  } else if( document.documentElement &&
      ( document.documentElement.clientWidth || 
        document.documentElement.clientHeight ) ) {
    //IE 6+ in 'standards compliant mode'
    myWidth = document.documentElement.clientWidth;
    myHeight = document.documentElement.clientHeight;

  } else if( document.body && ( document.body.clientWidth || 
                                document.body.clientHeight ) ) {
    //IE 4 compatible
    myWidth = document.body.clientWidth;
    myHeight = document.body.clientHeight;

  }

  return [ myWidth,myHeight,screen.width, screen.height];
}

function setSizeInField(element_id){
    element = document.getElementById(element_id);
    var sizes = windowSize();
    element.value = sizes[0]+','+sizes[1]+','+sizes[2]+','+sizes[3];
}

//Stolen from http://www.howtocreate.co.uk/tutorials/index.php?tut=0&part=16
function getScrollXY() {
  var scrOfX = 0, scrOfY = 0;
  if( typeof( window.pageYOffset ) == 'number' ) {
    //Netscape compliant
    scrOfY = window.pageYOffset;
    scrOfX = window.pageXOffset;
  } else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
    //DOM compliant
    scrOfY = document.body.scrollTop;
    scrOfX = document.body.scrollLeft;
  } else if( document.documentElement &&
      ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
    //IE6 standards compliant mode
    scrOfY = document.documentElement.scrollTop;
    scrOfX = document.documentElement.scrollLeft;
  }
  return [ scrOfX, scrOfY ];
}


// Reset the height of the  div with the given name
// relative to the window height
function resizeDiv(div_id,hoffset,other_id) { 
    var path = document.getElementById(div_id);  

    if(other_id){
        var other = document.getElementById(other_id);
        hoffset += other.offsetHeight;
    }

    if(path){
        var xy = windowSize();
        var height = xy[1]-hoffset;
        path.style.height = height+'px';
    }
}


function setDivHeight(id,height){
    var div = document.getElementById(id);
    div.style.height = height+"px";
    div.style.overflow = 'visible';
}

function limitHeight(element,height){

    if(element.offsetHeight > height){
        element.style.height = height+'px';
        element.style.border = '1px solid';
        element.style.overflow = 'auto';
    }

}


// Toggle the div height between it's current value and the value of 'height'
// Note the that id value is the id prefix. The id you assign to the div and 
// image must have a "-div" and "-img" suffix.
function toggleDivHeightEM(id,image_prefix,height){
    
    var div = document.getElementById(id+'-div');

    var re = /(\d+)/;
    var old_height = div.style.height.match(re)[0];
    var new_height = height -old_height;

    div.style.height = new_height+"em";

    var img_mod = '';
    if(new_height > old_height){
        img_mod = 'on';
    } else {
        img_mod = 'off';
    }

    var div = document.getElementById(id+'-img');

    div.src = image_prefix+'-'+img_mod+'.gif';
    
}

function submit(id, ref) {
    // submit the form of the given ID. 
    var form=document.getElementById(id);
    if (ref) {
        form.action = ref;
    }

    // Add an anchor to the URL to take the page back to the last changed
    // question/answer.
    // Putting a '#anchor' on the end of the URL seems natural in this
    // case, but doesn't work.  The browser goes to the anchor before
    // calling a bunch of javascript functions that modifiy the page.
    // The anchor is often no longer visible at the end of the function calls.
    // So... the anchor is supplied as an argument and the last bit of
    // javascript on the new page goes to the anchor.
    var anchor = findCurrentAnchor(ref);
    if (anchor) {
        form.action += "&wjsSave_anchor="+anchor;
    }

    void(form.submit());
}

function leaveDocument(url) {
    var anchor = findCurrentAnchor();
    if (anchor) {
        url += "&wjsSave_anchor="+anchor;
    }
    window.location = url;
}

function change(cf){
  var parts = cf.id.split(/:/g);
  // Usually the "changed" id is the full id with the last token replaced
  // changed.  Forms that use multiple=true for a number or text field need 2
  // trimmed.  To make sure this works in any case, we'll check every
  // possible "changed" id.
  var changed_id='';
  for (i = 0; i < parts.length-1; i++) {
    changed_id += parts[i]+':'
    var elem = document.getElementById(changed_id+'changed');
    if(elem){
      elem.value = 1;
    }
  }
  // Set the changed field in the form 
  var globalChanged = document.getElementsByName('changed').item(0);
  if(globalChanged){
    globalChanged.value = parts[1];
  }
}

function addEvent(elm, evType, fn, useCapture)
// addEvent and removeEvent
// cross-browser event handling for IE5+,  NS6 and Mozilla
// By Scott Andrew
{
  if (elm.addEventListener){
    elm.addEventListener(evType, fn, useCapture);
    return true;
  } else if (elm.attachEvent){
    var r = elm.attachEvent("on"+evType, fn);
    return r;
  } else {
      //alert("include.js::addEvent: Handler could not be removed");
  }
} 


//----------------------------------------------------------------------
// Debugging routines


function showPropNames(obj) {
   var result = "";
   for (var i in obj){
       result +=  "." + i + "\n"; // " = " + obj[i] + "\n";
   }
   return result;
  }

function showProps(obj) {
   var result = "";
   for (var i in obj){
       result +="." + i +  " = " + obj[i]+ "; ";
   }
   return result;
  }

function writeDebug(str){
 
    if(window.debugWindow){
        debugWindow.document.write("<p>"+str+"</p>");
    }
}

function writePropsToId(obj,id){
    var foo = document.getElementById(id);
    var result = '';
    for (var i in obj){
        result += "<p>" + i +  " = " + obj[i] + "\n";
    }
    foo.innerHTML = foo.innerHTML+result;
}

function dumpTree(id,data,level){

    if(!level){
        level =1;
    }

    var foo = document.getElementById(id);
    
    var nc = 0;//nodeCount
    if(data != null){
        var length = data.childNodes.length;
        var i; // if not declared, recursion may be infinite!
        for(i=0;i<data.childNodes.length;i++){
            var child = data.childNodes[i];
            if(data.childNodes[i].nodeType == 1){
                foo.innerHTML = foo.innerHTML+"<p>"+level+' '+length+' '+
                    child.tagName;
                dumpTree(id, child, level+1);                
            } else {
                //foo.innerHTML = foo.innerHTML+"<p>"+child.nodeType+": "+
                //    child.nodeName;

            }
            nc++;
        }
    }
}

    
function debugAlert(str){
    alert(str);
}

function clearDebugCA(){
    elem = document.getElementById('wjs_debug_ca');
    elem.innerHTML = '';
}

function writeDebugCA(str,id){
    if(!id){
        id = 'wjs_debug_ca';
    }
    elem = document.getElementById(id);
    elem.innerHTML = elem.innerHTML + '<p>' + str + '</p>';
}

// For PTDAVHeading (PTDAnswerView). should be moved elsewhere

function registerSection(application){
    WJSToggleDiv.register(application);
    WJSTextArea.register(application);
}

// Warn the user if there are unsaved answers
// THis only works on IE
function warnOnExit(e){

    if(!e){
        var e = window.event;
    }

  var globalChanged = document.getElementsByName('changed').item(0);



  if(globalChanged.value){
      return "You have unsaved answers. Do you want to save your answers before leaving this page?";
  } 
}

// For the Past Answers feature. Copies from a div or a span to 
// an input
function copyPA(from_id, to_id){

    from = document.getElementById(from_id);
    to = document.getElementById(to_id);
    
    to.value = from.innerHTML.replace(/<br>/g,"");

    change(to); // Mark it as changed;
}


// For the Past Answers feature. Copies from a div or a span to 
// an input
function replaceSection(sectionId, answerRowHTML, detailRowHTML){

    tempDiv = document.createElement('div');
    tempDiv.innerHTML = "<table>"+answerRowHTML+"</table>";
    answerRow = document.getElementById("answerRow"+sectionId);
    answerRow.parentNode.replaceChild(
                       tempDiv.firstChild.firstChild.firstChild, answerRow);

    if (detailRowHTML != null) {
        detailRow = document.getElementById("detailRow"+sectionId);
        if (detailRow) {
            tempDiv.innerHTML = "<table>"+detailRowHTML+"</table>";
            detailRow.parentNode.replaceChild(
                        tempDiv.firstChild.firstChild.firstChild, detailRow);
        }
    }

    // Mark it as changed;
    change(document.getElementById("DTOs:"+sectionId+":changed"));

    WJSTextArea.register(window.wjsApplication);
}

// This function will replace the search argument in all of the
// links on the page with the given value.
function alterLinkArgs(key,value,addOK){

    if (typeof addOK == 'undefined') {
        addOK = false;
    }

    var subRe = new RegExp('([\?\&])'+key+'=[^\&]*');
    var prependRe = new RegExp('([\?])');

    var tag = 'a';
    var attr = 'href';

    for( var j = 0; j < 2; j++){

        var elems = document.getElementsByTagName(tag);

        for( var i = 0; i < elems.length; i++){
            var elem = elems[i];

            // Anchors that aren't links should be skipped
            if (tag == 'a' &&
                (elem.href == '' || elem.href.substr(0,6) == 'mailto')) {
                continue;
            }

            if(elem[attr].match(subRe)){
                elem[attr] = elem[attr].replace(subRe,'$1'+key+'='+value);
            } else if (addOK) {
                if(elem[attr].match(prependRe)){
                    elem[attr] = elem[attr].replace(prependRe,'$1'+key+'='+value+'&');
                } else {
                    // If we reach this branch the URL doesn't involve a
                    // session, so we won't worry about it for now.
                }
            }
        }

        tag = 'form';
        attr = 'action';
    }
}

// This function is called when a wjsTextArea is resized. The function 
// has an application dependant calculation, so it is not in wjstextarea.js

function resizeTextArea(area,padding,context){

    var outerDiv=document.getElementById('bodyframe'); 

    if (outerDiv == null) {
        outerDiv=document.getElementById('sizer'); 
    } 

    if (outerDiv == null) {
        outerDiv=document.body; 
    } 

    var oDOW = wjsBrowser.recentValue(outerDiv,'offsetWidth');

    var width;

    if (context == 'table') {
        // Divide the space of the bodyframe by the number of columns.
        // Find the number of columns by working up to a table row.
        var tr = area.parentNode;
        while (tr &&
               (tr.nodeName != 'TR' || tr.getAttribute('wjsresizeignore'))) {
            tr = tr.parentNode;
        }
        var col;
        var cols = 0;
        for (col = tr.firstChild; col; col = col.nextSibling) {
            if (col.nodeName == 'TD') {
                cols++;
            }
        }
        // A single column table can lead to a text area that is too wide
        if (cols == 1) {
            cols = 1.2;
        }
        width = (oDOW - padding)/cols;
    // Compute the amount of width used by table cells that are left/right
    // of the area under consideration.  This includes cells that are
    // to the left/right in the current row as well as cells that are to
    // the left/right in enclosing rows (if the table is in a table).
    } else if (context == 'left') {
        var sibling;
        var siblingOW = 0;
        var tr;
        var stopBefore = area;
        for (tr = area.parentNode;
             tr && tr.id != 'bodyframe';
             tr = tr.parentNode) {
            if (tr.nodeName == 'TR') {
                for (sibling = tr.firstChild;
                     sibling && sibling != stopBefore;
                     sibling = sibling.nextSibling) {
                    if (typeof sibling.offsetWidth != 'undefined') {
                        siblingOW += wjsBrowser.recentValue(sibling,
                                                            'offsetWidth');
                    }
                }
            }
            stopBefore = tr;
        }
        width = oDOW - padding - siblingOW;
    } else if (context == 'right') {
        var sibling;
        var siblingOW = 0;
        var tr;
        var current = area;
        for (tr = area.parentNode;
             tr && tr.id != 'bodyframe';
             tr = tr.parentNode) {
            if (tr.nodeName == 'TR') {
                for (sibling = current.nextSibling;
                     sibling;
                     sibling = sibling.nextSibling) {
                    if (typeof sibling.offsetWidth != 'undefined') {
                        siblingOW += wjsBrowser.recentValue(sibling,
                                                            'offsetWidth');
                    }
                }
            }
            current = tr;
        }
        width = oDOW - padding - siblingOW;
    }

    if(width){
        return width;
    } else {
        return 500;
    }
}

function resizeHomeTextArea(){
    return resizeTextArea(this,80,'left');
}

function resizeSolicitorTextArea(){
    return resizeTextArea(this,20,'left');
}

function resizeRespondentTextArea(){
    return resizeTextArea(this,50,'left');
}

function resizeTableTextArea() {
    return resizeTextArea(this,20,'table');
}

function sizeToc() {
    var x=document.getElementById('toc');
    if (x) {
        // 21 for comfort (12 would be enough for Firefox, but IE needs more)
        var height = windowSize()[1]-21;
        var y;
        for (y=x; y; y=y.offsetParent) {
            height -= y.offsetTop;
        }
        var z=document.getElementById('footer');
        if (z) {
            height -= z.offsetHeight;
        }
        if (height < 30) {
            height = 30;
        }
        x.style.height = height+"px";
    }
}

function sizeBody() {
    var x=document.getElementById('body');
    if (x) {
        // 6 for comfort and more for a scrollbar for firefox
        var width = windowSize()[0]-6-wjsBrowser.offsetScrollbar;
        var height = windowSize()[1]-6-wjsBrowser.offsetForUnknownReason;
        var y;
        for (y=x; y; y=y.offsetParent) {
            width -= y.offsetLeft;
            height -= y.offsetTop;
        }
        var z=document.getElementById('footer');
        if (z) {
            height -= z.offsetHeight;
        }
        x.style.width = width+"px";
        x.style.height = height+"px";
    }
}

// Find the true X and Y positions on the screen by following the
// offsetTeft and offsetTop properties to the top element. IE and 
// Mozilla have different interpretations for offsetLeft and offsetTop
// @RC 20040123ESB This shouldbe combined with WJSElement.computeOffset
function trueXYPosition(elem){

      var left=0,top=0;

      if (elem.offsetParent){
         while(elem.offsetParent){
           left+=elem.offsetLeft;
           top+=elem.offsetTop;  
           elem = elem.offsetParent;
         }
       } else if (elem.x) {
          left=elem.x;
          top=elem.y;
       }

      var out = new Object();
      out.x = left;
      out.y = top;
      
      return out;
}

// Find the position of the given element relative to its 
// containing parent.IE and 
// Mozilla have different interpretations for offsetLeft and offsetTop
// @RC 20040123ESB This shouldbe combined with WJSElement.computeOffset
function relXYPosition(elem){

      var out = new Object();

      if(elem.parentNode != elem.offsetParent){
         var p1 = trueXYPosition(elem);
         var p2 = trueXYPosition(elem.parentNode);
         out.x = p1.x-p2.x;
         out.y = p1.y-p2.y;
      } else {
         out.x = elem.offsetLeft;
         out.y = elem.offsetTop;
      }

      return out;
}

// Find the first anchor that is in the top half of the displayed portion of
// the body or if there is no such anchor,
// find the last anchor that is above the middle of the displayed portion
// of the body.  (unless a ref is supplied that includes a toggler id)
function findCurrentAnchor(ref) {
    // If we're given a ref that includes a toggler id, use that instead
    // of the "middle of the display" algorithm.
    var matches;
    var section_id;
    if (ref &&
        (matches = ref.match(/toggler=(\d+)-sections/)) &&
        (section_id = matches[1])) {
        return 'sec'+section_id;
    }

    var mybody = document.getElementById('body'); 
    if (!mybody) {
        return null;
    }
    var topDisplayedBody=trueXYPosition(mybody).y+mybody.scrollTop;
    var midDisplayedBody=trueXYPosition(mybody).y+mybody.scrollTop+
                   mybody.offsetHeight/2;
    var anchors = document.getElementsByTagName('a');

    var anchor = null;
    var nextAnchor = null;
    var nayp = null; // nayp = next anchor's y position

    for(i=0;i<anchors.length;i++){
        nextAnchor = anchors.item(i);
        if (nextAnchor.name && nextAnchor.name.substr(0,3) == 'sec') {
            nayp = trueXYPosition(nextAnchor).y;
            if (nayp > topDisplayedBody &&
                nayp <= midDisplayedBody > 0) {
                // This "next anchor" is the first anchor in the top half
                // of the displayed portion of the body.  Let's use it.
                anchor = nextAnchor;
                break;
            }
            if (nayp > midDisplayedBody) {
                // This "next anchor" is beyond the middle of the displayed
                // portion of the body.  That's too far.  Let's quit looking
                // and use the anchor before this one.
                break;
            }
            anchor = nextAnchor;
        }
    }
    // Just in case we break on the first opportunity
    if (anchor == null && nextAnchor.name) {
        anchor = nextAnchor;
    }
    if (anchor) {
        return anchor.name;
    }
    return null;
}

function gotoAnchor(anchorName) {
    var mybody = document.getElementById('body'); 
    var anchor = document.getElementsByName(anchorName);
    if (anchor.length) {
        anchor = anchor[0];
        // Sometimes the browser is still rendering when this code is
        // reached and it takes a couple of passes to get the body scrolled
        // to the correct position.  (Actually, it always works with firefox,
        // but sometimes IE has problems.)
        oldAnchorY = 1;
        while ((anchorY = trueXYPosition(anchor).y) != oldAnchorY) {
            // The "-12" is because of the scoring view
            mybody.scrollTop = anchorY - trueXYPosition(mybody).y - 12;
            oldAnchorY = anchorY;
        }
    }
}

// Dynamically change the options in a select list.  Provide the
// id of the <select> and an array/object of value=>text pairs.
function setSelectOptions(id, texts) {
    var select = document.getElementById(id);
    while (child = select.firstChild) {
        select.removeChild(child);
    }
    defaultObj = { };
    for (value in texts) {
        if (typeof defaultObj[value] != 'undefined') {
            continue;
        }
        option = document.createElement('option');
        option.value = value;
        option.appendChild(document.createTextNode(texts[value]));
        select.appendChild(option);
    }
}

function clearRadio(name) {
    radios = document.getElementsByName(name);
    for (i = 0; i < radios.length; i++) {
        radios[i].checked = false;
    }
    change(radios[0]);
}

function appendAnswer(column, index, s_id, i_id){
    var target = document.getElementById('DTOs:'+index+':'+column);
    var ans_span = document.getElementById('ans_'+s_id+'_'+i_id);
    if (target && ans_span) {
        target.value = target.value+"\n"+ans_span.innerHTML;
    }
}

function narrowlist(select_id,full_list_id,text) {
   select = document.getElementById(select_id);
   full_list = document.getElementById(full_list_id);
   text = text.toLowerCase();
   while (child = select.firstChild) {
       select.removeChild(child);
   }
   for (opt = full_list.firstChild; opt; opt = opt.nextSibling) {
       if (opt.innerHTML &&
           opt.innerHTML.toLowerCase().indexOf(text) != -1) {
           option = document.createElement('option');
           option.value = opt.getAttribute('value')
           option.innerHTML = opt.innerHTML;
           select.appendChild(option);
       }
   }
}

//--------------------
// file: vcXMLRPC.js
//--------------------
//
//
//    Copyright (C) 2000, 2001, 2002  Virtual Cowboys info@virtualcowboys.nl
//		
//		Author: Ruben Daniels <ruben@virtualcowboys.nl>
//		Version: 0.91
//		Date: 29-08-2001
//		Site: www.vcdn.org/Public/XMLRPC/
//
//    This program is free software; you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation; either version 2 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program; if not, write to the Free Software
//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


Object.prototype.toXMLRPC = function(){
    var wo = this.valueOf();

    if(wo.toXMLRPC == this.toXMLRPC){
        retstr = "<struct>";
		
        for(prop in this){
            if(typeof wo[prop] != "function"){
                retstr += "<member><name>" + prop + 
                    "</name><value>" + XMLRPC.getXML(wo[prop]) + 
                    "</value></member>";
            }
        }
        retstr += "</struct>";
		
        return retstr;
    }
    else{
        return wo.toXMLRPC();
    }
}

String.prototype.toXMLRPC = function(){
    //<![CDATA[***your text here***]]>
    return "<string><![CDATA[" + this.replace(/\]\]/g, "] ]") + 
        "]]></string>";//.replace(/</g, "&lt;").replace(/&/g, "&amp;")
}

Number.prototype.toXMLRPC = function(){
    if(this == parseInt(this)){
        return "<int>" + this + "</int>";
    }
    else if(this == parseFloat(this)){
        return "<double>" + this + "</double>";
    }
    else{
        return false.toXMLRPC();
    }
}

Boolean.prototype.toXMLRPC = function(){
    // Oddly enough, "if (this)" doesn't work
    if(this != false) {
        return "<boolean>1</boolean>";
    }
    else return "<boolean>0</boolean>";
}

Date.prototype.toXMLRPC = function(){
    //Could build in possibilities to express dates 
    //in weeks or other iso8601 possibillities
    //hmmmm ????
    //19980717T14:08:55
    return "<dateTime.iso8601>" + 
        doYear(this.getUTCYear()) + 
        doZero(this.getMonth()) + 
        doZero(this.getUTCDate()) + 
        "T" + 
        doZero(this.getHours()) + 
        ":" + 
        doZero(this.getMinutes()) + 
        ":" + 
        doZero(this.getSeconds()) + 
        "</dateTime.iso8601>";
	
    function doZero(nr) {
        nr = String("0" + nr);
        return nr.substr(nr.length-2, 2);
    }
	
	function doYear(year) {
            if(year > 9999 || year < 0) 
                XMLRPC.handleError(new Error("Unsupported year: " + year));
			
            year = String("0000" + year)
		return year.substr(year.length-4, 4);
	}
        }


Array.prototype.toXMLRPC = function(){
    var retstr = "<array><data>";
    for(var i=0;i<this.length;i++){
        retstr += "<value>" + XMLRPC.getXML(this[i]) + "</value>";
    }
    return retstr + "</data></array>";
}


/**
 * This is the home end of the remote service
 */
function VirtualService(servername, oRPC){
    this.version = '0.91';
    this.URL = servername;
    this.multicall = false;
    this.autoroute = true;
    this.onerror = null;
	
    this.rpc = oRPC;
    this.receive = {};
	
    this.purge = function(receive){
        return this.rpc.purge(this, receive);
    };
	
    this.revert = function(){
        this.rpc.revert(this);
    };
   
    // Add a new function call to the home end, linked to a function on 
    // the remote service. 
    // name -- name of the remote function
    // alias -- functino name on the home side
    // receive -- ?
    this.add = function(name, alias, receive, shallow){
        if (typeof shallow == 'undefined') {
            shallow = false;
        }

        this.rpc.validateMethodName();
        if(this.rpc.stop){
            this.rpc.stop = false;
            return false;
        }
        
        if(receive) {
            this.receive[name] = receive;
        }

        // Create a new method on this object. 
        this[(alias || name)] = 
            new Function('var args = new Array(), i;for(i=0;i<arguments.length;i++){args.push(arguments[i]);};return this.call("' + name + '", args, ' + shallow + ');');
        return true;
    };
	
    //internal function for sending data
    this.call = function(name, args, shallow){

        if (typeof shallow == 'undefined') {
            shallow = false;
        }

        var info = this.rpc.send(this.URL, name, args, this.receive[name], 
                                 this.multicall, this.autoroute, shallow);
        
        if(info){
            if(!this.multicall) this.autoroute = info[0];
            return info[1];
        }
        else{
            if(this.onerror) this.onerror(XMLRPC.lastError);
            return false;
        }
    };
}


XMLRPC = {
    routeServer : "http://www.vcdn.org/cgi-bin/rpcproxy.cgi",
    autoroute : true,
    multicall : false,

    services : {},
    stack : {},
    queue : new Array(),
    timers : new Array(),
    timeout : 30000,
	
    ontimeout : null,
	
    getService : function(serviceName){
        //serviceNames cannot contain / or .

        // Create new virtual service
        if(/[\/\.]/.test(serviceName)){
            return new VirtualService(serviceName, this);
        }
        // Return one that had been previously created
        else if(this.services[serviceName]){
            return this.services[serviceName];
        }
        // Use JS code to get the class name of a class derived from 
        // VirtualService?
        else{
            try{
                var ct = eval(serviceName);
                this.services[serviceName] = new ct(this);
                return this.services[serviceName];
            }
            catch(e){
                return false;
            }
        }
    },
	
    purge : function(modConst, receive){
        if(this.stack[modConst.URL].length){
            var info = this.send(modConst.URL, "system.multicall", 
                                 [this.stack[modConst.URL]], receive, 
                                 false, modConst.autoroute);
            modConst.autoroute = info[0];
            this.revert(modConst);
			
            if(info){
                modConst.autoroute = info[0];
                return info[1];
            }
            else{
                if(modConst.onerror) modConst.onerror(this.lastError);
                return false;
            }
        }
    },
	
    revert : function(modConst){
        this.stack[modConst.URL] = new Array();
    },

    
    call : function(){
        //[optional info || receive, servername,] functionname, args......
        var args = new Array(), i, a = arguments;
        var servername, methodname, receive, service, info, autoroute, multicall;
		
        if(typeof a[0] == "object"){
            receive = a[0][0];
            servername = a[0][1].URL;
            methodname = a[1];
            multicall = (a[0][1].supportsMulticall && a[0][1].multicall);
            autoroute = a[0][1].autoroute;
            service = a[0][1];
        }
        else if(typeof a[0] == "function"){
            i = 3;
            receive = a[0];
            servername = a[1];
            methodname = a[2];
        }
        else{
            i = 2;
            servername = a[0];
            methodname = a[1];
        }
			
        for(i=i;i<a.length;i++){
            args.push(a[i]);
        }
		
        info = this.send(servername, methodname, args, receive, multicall, 
                         autoroute);
        if(info){
            (service || this).autoroute = info[0];
            return info[1];
        }
        else{
            if(service && service.onerror) service.onerror(this.lastError);
            return false;
        }
		
    },
	
    /***
     * Perform typematching on 'vDunno' and return a boolean value
     * corresponding to the result of the evaluation-match of the
     * mask-value stated in the 2nd argument.  The 2nd argument is
     * optional (none will be treated as a 0-mask) or a sum of
     * several masks as follows:
     * type/s    ->  mask/s
     * --------------------
     * undefined ->  0/1 [default]
     * number    ->  2
     * boolean   ->  4
     * string    ->  8
     * function  -> 16
     * object    -> 32
     * --------------------
     * Examples:
     * Want [String] only: (eqv. (typeof(vDunno) == 'string') )
     *  Soya.Common.typematch(unknown, 8)
     * Anything else than 'undefined' acceptable:
     *  Soya.Common.typematch(unknown)
     * Want [Number], [Boolean] or [Function]:
     *  Soya.Common.typematch(unknown, 2 + 4 + 16)
     * Want [Number] only:
     *  Soya.Common.typematch(unknown, 2)
     **/
    typematch : function (vDunno, nCase){
        var nMask;
        switch(typeof(vDunno)){
        case 'number'  : nMask = 2;  break;
        case 'boolean' : nMask = 4;  break;
        case 'string'  : nMask = 8;  break;
        case 'function': nMask = 16; break;
        case 'object'  : nMask = 32; break;
        default	     : nMask = 1;  break;
        }
        return Boolean(nMask & (nCase || 62));
    },
	
    getNode : function(data, tree){
        var nc = 0;//nodeCount
        //node = 1
        if(data != null){
            var i;
            for(i=0;i<data.childNodes.length;i++){
                if(data.childNodes[i].nodeType == 1){
                    if(nc == tree[0]){
                        data = data.childNodes[i];
                        if(tree.length > 1){
                            tree.shift();
                            data = this.getNode(data, tree);
                        }
                        return data;
                    }
                    nc++
                        }
            }
        }
		
        return false;
    },
	
    // shallow allows putting off what would be recursive processing for later
    toObject : function(data, shallow){
        if (typeof shallow == 'undefined') {
            shallow = false;
        }
        var ret, i;
        switch(data.tagName){
        case "string":
            var s=""
            // Mozilla has many textnodes with a size of 4096 chars each
            // instead of one large one.
            // They all need to be concatenated.
            for(var j=0; j<data.childNodes.length; j++){
               s += new String(data.childNodes.item(j).nodeValue);
            }
            return s;

            break;
        case "int":
        case "i4":
        case "double":
            return (data.firstChild) ? new Number(data.firstChild.nodeValue) : 0;
            break;
        case "dateTime.iso8601":
            /*
              Have to read the spec to be able to completely 
              parse all the possibilities in iso8601
              07-17-1998 14:08:55
              19980717T14:08:55
            */
				
            var sn = (isIE) ? "-" : "/";
				
            if(/^(\d{4})(\d{2})(\d{2})T(\d{2}):(\d{2}):(\d{2})/.test(data.firstChild.nodeValue)){;//data.text)){
            return new Date(RegExp.$2 + sn + RegExp.$3 + sn + 
                            RegExp.$1 + " " + RegExp.$4 + ":" + 
                            RegExp.$5 + ":" + RegExp.$6);
            }
            else{
                return new Date();
            }

            break;
        case "array":
            data = this.getNode(data, [0]);
				
            if(data && data.tagName == "data"){
                ret = new Array();
					
                var i = 0;
                while(child = this.getNode(data, [i++])){
                    if (shallow) {
                        ret.push(child);
                    } else {
                        ret.push(this.toObject(child));
                    }
                }
					
                return ret;
            }
            else{
                this.handleError(new Error("Malformed XMLRPC Message1"));
                return false;
            }
            break;
        case "struct":
            ret = {};
					
            var i = 0;
            while(child = this.getNode(data, [i++])){
                if(child.tagName == "member"){
                    if (shallow) {
                        ret[this.getNode(child, [0]).firstChild.nodeValue] = 
                            this.getNode(child, [1]);
                    } else {
                        ret[this.getNode(child, [0]).firstChild.nodeValue] = 
                            this.toObject(this.getNode(child, [1]));
                    }
                }
                else{
                    this.handleError(new Error("Malformed XMLRPC Message2"));
                    return false;
                }
            }
				
            return ret;
            break;
        case "boolean":
            return Boolean(isNaN(parseInt(data.firstChild.nodeValue)) ? 
                           (data.firstChild.nodeValue == "true") : 
                           parseInt(data.firstChild.nodeValue))

                break;
        case "base64":
            return this.decodeBase64(data.firstChild.nodeValue);
            break;
        case "value":
            child = this.getNode(data, [0]);
            return (!child) ? ((data.firstChild) ? 
                               new String(data.firstChild.nodeValue) : 
                               "") : this.toObject(child, shallow);

            break;
        default:
            this.handleError(new Error("Malformed XMLRPC Message: " + data.tagName));
            return false;
            break;
        }
    },
	
    /*** Decode Base64 ******
     * Original Idea & Code by thomas@saltstorm.net
     * from Soya.Encode.Base64 [http://soya.saltstorm.net]
     **/
    decodeBase64 : function(sEncoded){
        // Input must be dividable with 4.
        if(!sEncoded || (sEncoded.length % 4) > 0)
            return sEncoded;
	
        /* Use NN's built-in base64 decoder if available.
           This procedure is horribly slow running under NN4,
           so the NN built-in equivalent comes in very handy. :) */
	
        else if(typeof(atob) != 'undefined')
            return atob(sEncoded);
	
        var nBits, i, sDecoded = '';
        var base64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
        sEncoded = sEncoded.replace(/\W|=/g, '');
	
        for(i=0; i < sEncoded.length; i += 4){
            nBits =
                (base64.indexOf(sEncoded.charAt(i))   & 0xff) << 18 |
                (base64.indexOf(sEncoded.charAt(i+1)) & 0xff) << 12 |
                (base64.indexOf(sEncoded.charAt(i+2)) & 0xff) <<  6 |
                base64.indexOf(sEncoded.charAt(i+3)) & 0xff;
            sDecoded += String.fromCharCode
                ((nBits & 0xff0000) >> 16, (nBits & 0xff00) >> 8, nBits & 0xff);
        }
	
        // not sure if the following statement behaves as supposed under
        // all circumstances, but tests up til now says it does.
	
        return sDecoded.substring(0, sDecoded.length -
                                  ((sEncoded.charCodeAt(i - 2) == 61) ? 2 :
                                   (sEncoded.charCodeAt(i - 1) == 61 ? 1 : 0)));
    },
	
    getObject : function(type, message){
        if(type == "HTTP"){
            if(isIE){
                obj = new ActiveXObject("microsoft.XMLHTTP"); 
            } else if(isNS) {
                obj = new XMLHttpRequest();
            }
        }
        else if(type == "XMLDOM"){
            
            if(isIE){
                obj = new ActiveXObject("microsoft.XMLDOM"); 
                obj.loadXML(message);
            } else if(isNS) {
                obj = new DOMParser();
                obj = obj.parseFromString(message, "text/xml");
            }            
        }
        else{
            this.handleError(new Error("Unknown Object"));
        }

        return obj;
    },
	
    validateMethodName : function(name){
        /*do Checking:
		
        The string may only contain identifier characters, 
        upper and lower-case A-Z, the numeric characters, 0-9, 
        underscore, dot, colon and slash. 
		
        */
        if(/^[A-Za-z0-9\._\/:]+$/.test(name))
            return true
		else
                    this.handleError(new Error("Incorrect method name"));
    },
	
    getXML : function(obj){
        if(typeof obj == "function"){
            this.handleError(new Error("Cannot Parse functions"));
        } else if(obj == null || typeof obj == "undefined" || 
                 (typeof obj == "number" && !isFinite(obj))) {
            return '<nil/>';
        } else {
            return obj.toXMLRPC();
        }
    },
	
    handleError : function(e){
        if(!this.onerror || !this.onerror(e)){
            //alert("An error has occured: " + e.message);
            throw e;
        }
        this.stop = true;
        this.lastError = e;
    },
	
    cancel : function(id){
        //You can only cancel a request when it was executed async (I think)
        if(!this.queue[id]) return false;
		
        this.queue[id][0].abort();
        return true;
    },
	
    //----------------------------------------------------------------------
    // SEND THE DATA
    // ----------------------------------------------------------------------
    send : function(serverAddress, functionName, args, receive, 
                    multicall, autoroute, shallow){

        if (typeof shallow == 'undefined') {
            shallow = false;
        }

        var id, http;
        //default is sync
        this.validateMethodName();
        if(this.stop){
            this.stop = false; 
            return false;
        }
		
        //setting up multicall
        multicall = (multicall != null) ? multicall : this.multicall;
		
        if(multicall){
            if(!this.stack[serverAddress]) {
                this.stack[serverAddress] = new Array();
            }
            this.stack[serverAddress].push({methodName : functionName, 
                                                params : args});
            return true;
        }
		
        //creating http object
        var http = this.getObject("HTTP");
		
        //setting some things for async/sync transfers
        if(!receive || isNS){
            async = false;
        } else{
            async = true;
            /* The timer functionality is implemented instead of
               the onreadystatechange event because somehow
               the calling of this event crashed IE5.x
            */
            id = this.queue.push([http, receive, null, new Date()])-1;
			
            this.queue[id][2] = new Function
                ("var id='" + id + 
                 "';var dt = new Date(new Date().getTime() - XMLRPC.queue[id][3].getTime());diff = parseInt(dt.getSeconds()*1000 + dt.getMilliseconds());if(diff > XMLRPC.timeout){if(XMLRPC.ontimeout) XMLRPC.ontimeout(); clearInterval(XMLRPC.timers[id]);XMLRPC.cancel(id);return};if(XMLRPC.queue[id][0].readyState == 4){XMLRPC.queue[id][0].onreadystatechange = function(){};XMLRPC.receive(id);clearInterval(XMLRPC.timers[id])}");

            this.timers[id] = setInterval("XMLRPC.queue[" + id + "][2]()", 20);
        }
		
        //setting up the routing
        autoroute = (autoroute || this.autoroute);
		
        //'active' is only set when direct sending the message has failed
        var srv = (autoroute == "active") ? this.routeServer : serverAddress;
		
        try{
            http.open('POST', srv, async);
            http.setRequestHeader("User-Agent", "vcXMLRPC v0.91 (" + 
                                  navigator.userAgent + ")");
            http.setRequestHeader("Host", 
                                  srv.replace(/^https?:\/{2}([:\[\]\-\w\.]+)\/?.*/, 
                                              '$1'));
            http.setRequestHeader("Content-type", "text/xml");
            if(autoroute == "active"){
                http.setRequestHeader("X-Proxy-Request", serverAddress);
                http.setRequestHeader("X-Compress-Response", "gzip");
            }
        }
        catch(e){
            if(autoroute == true){
                //Access has been denied, Routing call.
                autoroute = "active";
                if(id){
                    delete this.queue[id];
                    clearInterval(this.timers[id]);
                }
                return this.send(serverAddress, functionName, args, receive, 
                                 multicall, autoroute);
            }
		
            //Routing didn't work either..Throwing error
            this.handleError(new Error("Could not send XMLRPC Message "+
                                       "(Reason: Access Denied on client)"));
            if(this.stop){this.stop = false;return false}
        }
		
        //Construct the message
        var message = 
            '<?xml version="1.0"?><methodCall><methodName>' + 
            functionName + 
            '</methodName><params>';

   	for(i=0;i<args.length;i++){
            message += '<param><value>' + 
                this.getXML(args[i]) + '</value></param>';
        }
        message += '</params></methodCall>';
		
        var xmldom = this.getObject('XMLDOM', message);

        //DEBUG=true;
        if(self.DEBUG) alert(message);

        try{
            http.send(xmldom);
        }
        catch(e){

            //Most likely the message timed out(what happend to your
            //internet connection?)
            this.handleError(new Error("XMLRPC Message not Sent(Reason: " + 
                                       e.message + ")"));
            if(this.stop){this.stop = false;return false}
        }
		
        if(!async && receive)
            return [autoroute, receive(this.processResult(http, shallow))];
        else if(receive)
            return [autoroute, id];
        else {
            return [autoroute, this.processResult(http, shallow)];
        }
    },
	
    receive : function(id){
        //Function for handling async transfers..
        if(this.queue[id]){
            var data = this.processResult(this.queue[id][0]);
            this.queue[id][1](data);
            delete this.queue[id];
        }
        else{
            this.handleError(new Error("Error while processing queue"));
        }
    },
	
    //20040610ESB Added so the jsrs code can process XMLRPC replies
    // from regular POSTS commands. 
    processXML : function(dom, shallow){

        var rpcErr, main;
        
        //Check for XMLRPC Errors
        rpcErr = dom.getElementsByTagName("fault");
        if(rpcErr.length > 0){
            rpcErr = this.toObject(rpcErr[0].firstChild);
            this.handleError(new Error(rpcErr.faultCode, 
                                       rpcErr.faultString));
            return false;
        }

        //handle method result
        main = dom.getElementsByTagName("param");

        if(main.length == 0) {
             this.handleError(new Error("Got a Malformed XMLRPC Message "));
        }
        
        data = this.toObject(this.getNode(main[0], [0]), shallow);
        //handle receiving
        if(this.onreceive) {
            this.onreceive(data);
        }
        return data;
    },

    processResult : function(http, shallow){
        if (typeof shallow == 'undefined') {
            shallow = false;
        }
        if(self.DEBUG) alert(http.responseText);
        if(http.status == 200){
            //getIncoming message
            dom = http.responseXML;
            if(dom){
                return this.processXML(dom, shallow);
            }

            else{
                this.handleError(new Error("Got a Malformed XMLRPC Message "));
            }
        }
        else{
            this.handleError
                (new Error("HTTP Exception: (" + http.status + ") " + 
                           http.statusText + "\n\n" + http.responseText));
        }
    }
}

//Smell something
ver = navigator.appVersion;
app = navigator.appName;
isNS = Boolean(navigator.productSub);
//moz_can_do_http = (parseInt(navigator.productSub) >= 20010308)

isIE = (ver.indexOf("MSIE 5") != -1 || ver.indexOf("MSIE 6") != -1 || ver.indexOf("MSIE 7") != -1) ? 1 : 0;
isIE55 = (ver.indexOf("MSIE 5.5") != -1) ? 1 : 0;

isOTHER = (!isNS && !isIE) ? 1 : 0;

if(isOTHER) alert("Sorry your browser doesn't support the features of vcXMLRPC");

//--------------------
// file: ieemu.js
//--------------------
//
/*----------------------------------------------------------------------------\
|                                   IE Emu                                    |
|-----------------------------------------------------------------------------|
|                         Created by Erik Arvidsson                           |
|                  (http://webfx.eae.net/contact.html#erik)                   |
|                      For WebFX (http://webfx.eae.net/)                      |
|-----------------------------------------------------------------------------|
| A emulation of Internet Explorer DHTML Object Model for Mozilla             |
|-----------------------------------------------------------------------------|
|                  Copyright (c) 1999 - 2004 Erik Arvidsson                   |
|-----------------------------------------------------------------------------|
| This software is provided "as is", without warranty of any kind, express or |
| implied, including  but not limited  to the warranties of  merchantability, |
| fitness for a particular purpose and noninfringement. In no event shall the |
| authors or  copyright  holders be  liable for any claim,  damages or  other |
| liability, whether  in an  action of  contract, tort  or otherwise, arising |
| from,  out of  or in  connection with  the software or  the  use  or  other |
| dealings in the software.                                                   |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| This  software is  available under the  three different licenses  mentioned |
| below.  To use this software you must chose, and qualify, for one of those. |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| The WebFX Non-Commercial License          http://webfx.eae.net/license.html |
| Permits  anyone the right to use the  software in a  non-commercial context |
| free of charge.                                                             |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| The WebFX Commercial license           http://webfx.eae.net/commercial.html |
| Permits the  license holder the right to use  the software in a  commercial |
| context. Such license must be specifically obtained, however it's valid for |
| any number of  implementations of the licensed software.                    |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| GPL - The GNU General Public License    http://www.gnu.org/licenses/gpl.txt |
| Permits anyone the right to use and modify the software without limitations |
| as long as proper  credits are given  and the original  and modified source |
| code are included. Requires  that the final product, software derivate from |
| the original  source or any  software  utilizing a GPL  component, such  as |
| this, is also licensed under the GPL license.                               |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| MPL - Mozilla Public License                    http://www.mozilla.org/MPL/ |
|                                                                             |
| The contents of this file are subject to the Mozilla Public License Version |
| 1.1 (the "License"); you may not use this file except in compliance with    |
| the License. You may obtain a copy of the License at                        |
| http://www.mozilla.org/MPL/                                                 |
|                                                                             |
| Software distributed under the License is distributed on an "AS IS" basis,  |
| WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License    |
| for the specific language governing rights and limitations under the        |
| License.                                                                    |
|                                                                             |
| The Original Code is IE Emu.                                                |
|                                                                             |
| The Initial Developer of the Original Code is Erik Arvidsson.               |
| Portions created by the Initial Developer are Copyright (C) 1999-2004       |
| the Initial Developer. All Rights Reserved.                                 |
|                                                                             |
| Contributor(s):                                                             |
|                                                                             |
|-----------------------------------------------------------------------------|
| 2002-??-?? | First version                                                  |
| 2004-04-13 | Impreved currentStyle emulation. Updated to not that the code  |
|            |is available under GPL, MPL or WebFX Non-Commercial License     |
|-----------------------------------------------------------------------------|
| Created 2002-??-?? | All changes are in the log above. | Updated 2004-04-13 |
\----------------------------------------------------------------------------*/


var ie = /MSIE/.test(navigator.userAgent);
var moz = !ie && navigator.product == "Gecko";


if (moz) {	// set up ie environment for Moz

	extendEventObject();
	//emulateAttachEvent();
	//emulateFromToElement();
	emulateEventHandlers(["click", "dblclick", "mouseover", "mouseout",
                              "mousedown", "mouseup", "mousemove",
                              "keydown", "keypress", "keyup"]);
	emulateAllModel();
	emulateCurrentStyle();
	emulateDocument(); // 20040611ESB
        emulateXML();

	// It is better to use a constant for event.button
	Event.LEFT = 0;
	Event.MIDDLE = 1;
	Event.RIGHT = 2;
}
else {
	Event = {};
	// IE is returning wrong button number
	Event.LEFT = 1;
	Event.MIDDLE = 4;
	Event.RIGHT = 2;
}




/*
 * Extends the event object with srcElement, cancelBubble, returnValue,
 * fromElement and toElement
 */
function extendEventObject() {
	Event.prototype.__defineSetter__("returnValue", function (b) {
		if (!b) this.preventDefault();
		return b;
	});

	Event.prototype.__defineSetter__("cancelBubble", function (b) {
		if (b) this.stopPropagation();
		return b;
	});

	Event.prototype.__defineGetter__("srcElement", function () {
		var node = this.target;
		while (node.nodeType != 1) node = node.parentNode;
		return node;
	});

	Event.prototype.__defineGetter__("fromElement", function () {
		var node;
		if (this.type == "mouseover")
			node = this.relatedTarget;
		else if (this.type == "mouseout")
			node = this.target;
		if (!node) return;
		while (node.nodeType != 1) node = node.parentNode;
		return node;
	});

	Event.prototype.__defineGetter__("toElement", function () {
		var node;
		if (this.type == "mouseout")
			node = this.relatedTarget;
		else if (this.type == "mouseover")
			node = this.target;
		if (!node) return;
		while (node.nodeType != 1) node = node.parentNode;
		return node;
	});

	Event.prototype.__defineGetter__("offsetX", function () {
		return this.layerX;
	});
	Event.prototype.__defineGetter__("offsetY", function () {
		return this.layerY;
	});

        // 20040603ESB Addition for keycodes
	Event.prototype.__defineGetter__("keyCode", function () {
		return this.which;
	});
        
}

/*
 * Emulates element.attachEvent as well as detachEvent
 */
function emulateAttachEvent() {
	HTMLDocument.prototype.attachEvent =
	HTMLElement.prototype.attachEvent = function (sType, fHandler) {
		var shortTypeName = sType.replace(/on/, "");
		fHandler._ieEmuEventHandler = function (e) {
			window.event = e;
			return fHandler();
		};
		this.addEventListener(shortTypeName, fHandler._ieEmuEventHandler, false);
	};

	HTMLDocument.prototype.detachEvent =
	HTMLElement.prototype.detachEvent = function (sType, fHandler) {
		var shortTypeName = sType.replace(/on/, "");
		if (typeof fHandler._ieEmuEventHandler == "function")
			this.removeEventListener(shortTypeName, fHandler._ieEmuEventHandler, false);
		else
			this.removeEventListener(shortTypeName, fHandler, true);
	};
}

/*
 * This function binds the event object passed along in an
 * event to window.event
 */
function emulateEventHandlers(eventNames) {
	for (var i = 0; i < eventNames.length; i++) {
		document.addEventListener(eventNames[i], function (e) {
			window.event = e;
		}, true);	// using capture
	}
}

/*
 * Simple emulation of document.all
 * this one is far from complete. Be cautious
 */

function emulateAllModel() {
	var allGetter = function () {
		var a = this.getElementsByTagName("*");
		var node = this;
		a.tags = function (sTagName) {
			return node.getElementsByTagName(sTagName);
		};
		return a;
	};
	HTMLDocument.prototype.__defineGetter__("all", allGetter);
	HTMLElement.prototype.__defineGetter__("all", allGetter);
}

function extendElementModel() {
	HTMLElement.prototype.__defineGetter__("parentElement", function () {
		if (this.parentNode == this.ownerDocument) return null;
		return this.parentNode;
	});

	HTMLElement.prototype.__defineGetter__("children", function () {
		var tmp = [];
		var j = 0;
		var n;
		for (var i = 0; i < this.childNodes.length; i++) {
			n = this.childNodes[i];
			if (n.nodeType == 1) {
				tmp[j++] = n;
				if (n.name) {	// named children
					if (!tmp[n.name])
						tmp[n.name] = [];
					tmp[n.name][tmp[n.name].length] = n;
				}
				if (n.id)		// child with id
					tmp[n.id] = n
			}
		}
		return tmp;
	});

	HTMLElement.prototype.contains = function (oEl) {
		if (oEl == this) return true;
		if (oEl == null) return false;
		return this.contains(oEl.parentNode);
	};
}

function emulateCurrentStyle() {
	HTMLElement.prototype.__defineGetter__("currentStyle", function () {
		return this.ownerDocument.defaultView.getComputedStyle(this, null);
		/*
		var cs = {};
		var el = this;
		for (var i = 0; i < properties.length; i++) {
			cs.__defineGetter__(properties[i], encapsulateObjects(el, properties[i]));
		}
		return cs;
		*/
	});
}

function emulateHTMLModel() {

	// This function is used to generate a html string for the
	// text properties/methods It replaces '\n' with "<BR"> as
	// well as fixes consecutive white spaces It also repalaces
	// some special characters
	function convertTextToHTML(s) {
		s = s.replace(/\&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/g, "<BR>");
		while (/\s\s/.test(s))
			s = s.replace(/\s\s/, "&nbsp; ");
		return s.replace(/\s/g, " ");
	}

	HTMLElement.prototype.insertAdjacentHTML = function (sWhere, sHTML) {
		var df;	// : DocumentFragment
		var r = this.ownerDocument.createRange();

		switch (String(sWhere).toLowerCase()) {
			case "beforebegin":
				r.setStartBefore(this);
				df = r.createContextualFragment(sHTML);
				this.parentNode.insertBefore(df, this);
				break;

			case "afterbegin":
				r.selectNodeContents(this);
				r.collapse(true);
				df = r.createContextualFragment(sHTML);
				this.insertBefore(df, this.firstChild);
				break;

			case "beforeend":
				r.selectNodeContents(this);
				r.collapse(false);
				df = r.createContextualFragment(sHTML);
				this.appendChild(df);
				break;

			case "afterend":
				r.setStartAfter(this);
				df = r.createContextualFragment(sHTML);
				this.parentNode.insertBefore(df, this.nextSibling);
				break;
		}
	};

	HTMLElement.prototype.__defineSetter__("outerHTML", function (sHTML) {
	   var r = this.ownerDocument.createRange();
	   r.setStartBefore(this);
	   var df = r.createContextualFragment(sHTML);
	   this.parentNode.replaceChild(df, this);

	   return sHTML;
	});

	HTMLElement.prototype.__defineGetter__("canHaveChildren", function () {
		switch (this.tagName) {
			case "AREA":
			case "BASE":
			case "BASEFONT":
			case "COL":
			case "FRAME":
			case "HR":
			case "IMG":
			case "BR":
			case "INPUT":
			case "ISINDEX":
			case "LINK":
			case "META":
			case "PARAM":
				return false;
		}
		return true;
	});

	HTMLElement.prototype.__defineGetter__("outerHTML", function () {
		var attr, attrs = this.attributes;
		var str = "<" + this.tagName;
		for (var i = 0; i < attrs.length; i++) {
			attr = attrs[i];
			if (attr.specified)
				str += " " + attr.name + '="' + attr.value + '"';
		}
		if (!this.canHaveChildren)
			return str + ">";

		return str + ">" + this.innerHTML + "</" + this.tagName + ">";
	});


	HTMLElement.prototype.__defineSetter__("innerText", function (sText) {
		this.innerHTML = convertTextToHTML(sText);
		return sText;
	});

	var tmpGet;
	HTMLElement.prototype.__defineGetter__("innerText", tmpGet = function () {
		var r = this.ownerDocument.createRange();
		r.selectNodeContents(this);
		return r.toString();
	});

	HTMLElement.prototype.__defineSetter__("outerText", function (sText) {
		this.outerHTML = convertTextToHTML(sText);
		return sText;
	});
	HTMLElement.prototype.__defineGetter__("outerText", tmpGet);

	HTMLElement.prototype.insertAdjacentText = function (sWhere, sText) {
		this.insertAdjacentHTML(sWhere, convertTextToHTML(sText));
	};
}


/*
 * 20040611ESB
 */

function emulateDocument() {
	var docGetter = function () {
            return this.contentDocument;;
	};
	HTMLElement.prototype.__defineGetter__("document", docGetter);

}

function emulateXML(){

    Document.prototype.loadXML = function (s) {

        // parse the string to a new doc   
        var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
        
        // remove all initial children
        while (this.hasChildNodes())
            this.removeChild(this.lastChild);
        
        // insert and import nodes
        for (var i = 0; i < doc2.childNodes.length; i++) {
            this.appendChild(this.importNode(doc2.childNodes[i], true));
        }
    };
    
    Document.prototype.__defineGetter__("xml", function () {
        return (new XMLSerializer()).serializeToString(this);
    });

}

// 20040611ESB I stole this from 
// http://neo.dzygn.com/downloads/importNode.txt. importNode is
// missing from IE. 
if(!document.importNode){

    // The functino is necessary because the assignment to 
    // the document object does not always work.

    // Need to assign the function because ( I think) the function
    // delcaration does not respect the if clause;
    importNode = function(doc,oNode,bImportChildren){
        var oNew;
        
        if(oNode.nodeType == 1){
            oNew = doc.createElement(oNode.nodeName);
            
            for (var i = 0; i < oNode.attributes.length; i++){    
            var attr = oNode.attributes[i];    
            if (attr.nodeValue != null && attr.nodeValue != ''){        
                oNew.setAttribute(attr.name, attr.nodeValue);        
            }
        }
            
            oNew.style.cssText = oNode.style.cssText;
            
            if(bImportChildren && oNode.hasChildNodes()){
                for(var oChild = oNode.firstChild; oChild; 
                    oChild = oChild.nextSibling){
                    oNew.appendChild(importNode(doc,oChild, true));
                }
            }
            
        } else if(oNode.nodeType == 3){
            oNew = doc.createTextNode(oNode.nodeValue);
        }
        
        
        return oNew;
    }

    document.importNode = function(oNode, bImportChildren){
        return importNode(this,oNode,bImportChildren);
    };


} else {

    //if we do have document.importNode, make importNode use it. I hate IE. 
   importNode = function(doc,oNode,bImportChildren){
        return doc.importNode(oNode,bImportChildren);
    }   
}


//--------------------
// file: wjsbrowser.js
//--------------------
//
// Snif the browser and store values for the browser's capabilities
// The contents of the constructor comes from
// http://webreference.com/tools/browser/javascript.html, but I (ESB) 
// put it into the constructor and change vars to use this.

// I also change the names of some value from an "is_" prefix to "has_"
//   has_getElementById 
//   has_getElementsByTagName
//   has_documentElement


function WJSBrowser(){

    // JavaScript Browser Sniffer
    // Eric Krok, Andy King, Michel Plungjan Jan. 31, 2002
    // see http://www.webreference.com/ for more information
    //
    // This program is free software; you can redistribute it and/or modify
    // it under the terms of the GNU General Public License as published by
    // the Free Software Foundation; either version 2 of the License, or
    //  (at your option) any later version.
    //
    // please send any improvements to aking@internet.com and we'll
    // roll the best ones in
    //
    // adapted from Netscape's Ultimate client-side JavaScript client sniffer
    // and andy king's sniffer
    // Revised May 7 99 to add is.nav5up and is.ie5up (see below). (see below).
    // Revised June 11 99 to add additional props, checks
    // Revised June 23 99 added screen props - gecko m6 doesn't support yet - abk
    //                    converted to var is_ from is object to work everywhere
    // 990624 - added cookie forms links frames checks - abk
    // 001031 - ie4 mod 5.0 -> 5. (ie5.5 mididentified - abk)
    //          is_ie4 mod tp work with ie6+ - abk
    // 001120 - ns6 released, document.layers false, put back in
    //        - is_nav6 test added - abk
    // 001121 - ns6+ added, used document.getElementById, better test, dom-compl
    // 010117 - actual version for ie3-5.5 by Michel Plungjan
    // 010118 - actual version for ns6 by Michel Plungjan
    // 010217 - netscape 6/mz 6 ie5.5 onload defer bug docs - abk
    // 011107 - added is_ie6 and is_ie6up variables - dmr
    // 020128 - added link to netscape's sniffer, on which this is based - abk
    //          updated sniffer for aol4-6, ie5mac = js1.4, TVNavigator, AOLTV,
    //          hotjava
    // 020131 - cleaned up links, added more links to example object detection
    // 020131 - a couple small problems with Opera detection. First, when Opera
    //          is set to be compatible with other browsers it will contain their
    //          information in the userAgent strings. Thus, to be sure we have 
    //          Opera we should check for it before checking for the other bigs.
    //          (And make sure the others are !opera.) Also corrected a minor
    //          bug in the is_opera6up assignment.
    // 020214 - Added link for Opera/JS compatibility; added improvements for 
    //          windows xp/2000 id in opera and aol 7 id (thanks to Les
    //          Hill, Les.Hill@getronics.com, for the suggestion).
    // 020531 - Added N6/7 and moz identifiers. 
    // 020605 - Added mozilla guessing, Netscape 7 identification, and cleaner
    //          identification for Netscape 6. (this comment added after code 
    //          changes)
    // 020725 - Added is_gecko. -- dmr
    // 021205 - Added is_Flash and is_FlashVersion, based on Doc JavaScript code. 
    //          Added Opera 7 variables. -- dmr
    // 021209 - Added aol8. -- dmr
    // 030110 - Added is_safari, added 1.5 js designation for Opera 7. --dmr
    // 030128 - Added is_konq, per user suggestion (thanks to Sam Vilain).
    //          Removed duplicate Opera checks left over after last revision. - dmr
    // 031124 - Added is_fb and version. We report this right after the is_moz
    //          report. - dmr
    // 040325 - Added is_fx and version. We report this right after the is_moz
    //          report. - dmr
    // 040421 - Added Debian check to is_moz. Thanks to Patrice Bridoux for
    //          reporting this.
    // 040517 - Added is_fb/is_fx to plugins based flash detection. Thanks to 
    //          Martin Bischoff for pointing out this omission.
    //
    // Everything you always wanted to know about your JavaScript client
    // but were afraid to ask. Creates "is_" variables indicating:
    // (1) browser vendor:
    //     is_nav, is_ie, is_opera
    // (2) browser version number:
    //     is_major (integer indicating major version number: 2, 3, 4 ...)
    //     is_minor (float   indicating full  version number: 2.02, 3.01, 4.04 ...)
    // (3) browser vendor AND major version number
    //     is_nav2, is_nav3, is_nav4, is_nav4up, is_nav5, is_nav5up, 
    //     is_nav6, is_nav6up, is_ie3, is_ie4, is_ie4up, is_ie5up, is_ie6...
    // (4) JavaScript version number:
    //     is_js (float indicating full JavaScript version number: 1, 1.1, 1.2 ...)
    // (5) OS platform and version:
    //     is_win, is_win16, is_win32, is_win31, is_win95, is_winnt, is_win98
    //     is_os2
    //     is_mac, is_mac68k, is_macppc
    //     is_unix
    //        is_sun, is_sun4, is_sun5, is_suni86
    //        is_irix, is_irix5, is_irix6
    //        is_hpux, is_hpux9, is_hpux10
    //        is_aix, is_aix1, is_aix2, is_aix3, is_aix4
    //        is_linux, is_sco, is_unixware, is_mpras, is_reliant
    //        is_dec, is_sinix, is_freebsd, is_bsd
    //     is_vms
    //
    // based in part on 
    // http://www.mozilla.org/docs/web-developer/sniffer/browser_type.html
    // The Ultimate JavaScript Client Sniffer
    // and Andy King's object detection sniffer
    //
    // Note: you don't want your Nav4 or IE4 code to "turn off" or
    // stop working when Nav5 and IE5 (or later) are released, so
    // in conditional code forks, use is_nav4up ("Nav4 or greater")
    // and is_ie4up ("IE4 or greater") instead of is_nav4 or is_ie4
    // to check version in code which you want to work on future
    // versions. For DOM tests scripters commonly used the 
    // is_getElementById test, but make sure you test your code as
    // filter non-compliant browsers (Opera 5-6 for example) as some 
    // browsers return true for this test, and don't fully support
    // the W3C's DOM1.
    //

    // convert all characters to lowercase to simplify testing
    var agt=navigator.userAgent.toLowerCase();
    var appVer = navigator.appVersion.toLowerCase();

    // *** BROWSER VERSION ***

    is_minor = parseFloat(appVer);
    this.is_major = parseInt(this.is_minor);

    this.is_opera = (agt.indexOf("opera") != -1);
    this.is_opera2 = (agt.indexOf("opera 2") != -1 ||
                      agt.indexOf("opera/2") != -1);
    this.is_opera3 = (agt.indexOf("opera 3") != -1 ||
                      agt.indexOf("opera/3") != -1);
    this.is_opera4 = (agt.indexOf("opera 4") != -1 || 
                      agt.indexOf("opera/4") != -1);
    this.is_opera5 = (agt.indexOf("opera 5") != -1 ||
                      agt.indexOf("opera/5") != -1);
    this.is_opera6 = (agt.indexOf("opera 6") != -1 ||
                      agt.indexOf("opera/6") != -1); // new 020128- abk
    this.is_opera7 = (agt.indexOf("opera 7") != -1 ||
                      agt.indexOf("opera/7") != -1); // new 021205- dmr
    this.is_opera5up = (this.is_opera && !this.is_opera2 && !this.is_opera3 && !this.is_opera4);
    this.is_opera6up = (this.is_opera && !this.is_opera2 && !this.is_opera3 
                        && !this.is_opera4 && !this.is_opera5); // new020128
    this.is_opera7up = (this.is_opera && !this.is_opera2 && 
                        !this.is_opera3 && !this.is_opera4 && !this.is_opera5 && !this.is_opera6); 

    // Note: On IE, start of appVersion return 3 or 4
    // which supposedly is the version of Netscape it is compatible with.
    // So we look for the real version further on in the string

    var iePos  = appVer.indexOf('msie');
    if (iePos !=-1) {
        this.is_minor = parseFloat(appVer.substring(iePos+5,appVer.indexOf(';',iePos)))
            this.is_major = parseInt(this.is_minor);
    }

    // ditto Konqueror
                                      
    this.is_konq = false;
    var kqPos   = agt.indexOf('konqueror');
    if (kqPos !=-1) {                 
        this.is_konq  = true;
        this.is_minor = parseFloat(agt.substring(kqPos+10,agt.indexOf(';',kqPos)));
        this.is_major = parseInt(this.is_minor);
    }                                 

    this.has_getElementById   = (document.getElementById) ?
        "true" : "false"; // 001121-abk
    this.has_getElementsByTagName = (document.getElementsByTagName) ?
        "true" : "false"; // 001127-abk
    this.has_documentElement = (document.documentElement) ?
        "true" : "false"; // 001121-abk

    this.is_safari = ((agt.indexOf('safari')!=-1)&&
                      (agt.indexOf('mac')!=-1))?true:false;
    this.is_khtml  = (this.is_safari || this.is_konq);

    this.is_gecko = ((!this.is_khtml)&&(navigator.product)&&
                     (navigator.product.toLowerCase()=="gecko"))?true:false;
    this.is_gver  = 0;
    if (this.is_gecko) this.is_gver=navigator.productSub;

    this.is_moz   = ((agt.indexOf('mozilla/5')!=-1) && (agt.indexOf('spoofer')==-1)
                     &&
                     (agt.indexOf('compatible')==-1) && (agt.indexOf('opera')==-1)
                     &&
                     (agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1)
                     &&
                     (this.is_gecko) && 
                     ((navigator.vendor=="")||(navigator.vendor=="Mozilla")
                      ||(navigator.vendor=="Debian")));

    this.is_fb = ((agt.indexOf('mozilla/5')!=-1) && (agt.indexOf('spoofer')==-1) &&
                  (agt.indexOf('compatible')==-1) && (agt.indexOf('opera')==-1)  &&
                  (agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1)     &&
                  (this.is_gecko) && (navigator.vendor=="Firebird"));
    this.is_fx = ((agt.indexOf('mozilla/5')!=-1) && (agt.indexOf('spoofer')==-1) &&
                  (agt.indexOf('compatible')==-1) && (agt.indexOf('opera')==-1)  &&
                  (agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1)     &&
                  (this.is_gecko) && (navigator.vendor=="Firefox"));
    if ((this.is_moz)||(this.is_fb)||(this.is_fx)) {  // 032504 - dmr
        this.is_moz_ver = (navigator.vendorSub)?navigator.vendorSub:0;
        if(!(this.is_moz_ver)) {
            this.is_moz_ver = agt.indexOf('rv:');
            this.is_moz_ver = agt.substring(this.is_moz_ver+3);
            this.is_paren   = this.is_moz_ver.indexOf(')');
            this.is_moz_ver = this.is_moz_ver.substring(0,this.is_paren);
        }
        this.is_minor = this.is_moz_ver;
        this.is_major = parseInt(this.is_moz_ver);
    }
    this.is_fb_ver = this.is_moz_ver;
    this.is_fx_ver = this.is_moz_ver;

    this.is_nav  = ((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1)
                    && (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1)
                    && (agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1)
                    && (!this.is_khtml) && (!(this.is_moz)) && (!this.is_fb) && (!this.is_fx));

    // Netscape6 is mozilla/5 + Netscape6/6.0!!!
    // Mozilla/5.0 (Windows; U; Win98; en-US; m18) Gecko/20001108 Netscape6/6.0
    // Changed this to use navigator.vendor/vendorSub - dmr 060502   
    // var nav6Pos = agt.indexOf('netscape6');
    // if (nav6Pos !=-1) {
    if ((navigator.vendor)&&
        ((navigator.vendor=="Netscape6")||(navigator.vendor=="Netscape"))&&
        (this.is_nav)) {
        this.is_major = parseInt(navigator.vendorSub);
        // here we need this.is_minor as a valid float for testing. We'll
        // revert to the actual content before printing the result. 
        this.is_minor = parseFloat(navigator.vendorSub);
    }

    this.is_nav2 = (this.is_nav && (this.is_major == 2));
    this.is_nav3 = (this.is_nav && (this.is_major == 3));
    this.is_nav4 = (this.is_nav && (this.is_major == 4));
    this.is_nav4up = (this.is_nav && this.is_minor >= 4);  // changed to this.is_minor for
    // consistency - dmr, 011001
    this.is_navonly      = (this.is_nav && ((agt.indexOf(";nav") != -1) ||
                                            (agt.indexOf("; nav") != -1)) );

    this.is_nav6   = (this.is_nav && this.is_major==6);    // new 010118 mhp
    this.is_nav6up = (this.is_nav && this.is_minor >= 6) // new 010118 mhp

        this.is_nav5   = (this.is_nav && this.is_major == 5 && !this.is_nav6); // checked for ns6
    this.is_nav5up = (this.is_nav && this.is_minor >= 5);

    this.is_nav7   = (this.is_nav && this.is_major == 7);
    this.is_nav7up = (this.is_nav && this.is_minor >= 7);

    this.is_ie   = ((iePos!=-1) && (!this.is_opera) && (!this.is_khtml));

    this.is_ie3  = (this.is_ie && (this.is_major < 4));

    this.is_ie4   = (this.is_ie && this.is_major == 4);
    this.is_ie4up = (this.is_ie && this.is_minor >= 4);
    this.is_ie5   = (this.is_ie && this.is_major == 5);
    this.is_ie5up = (this.is_ie && this.is_minor >= 5);
    
    this.is_ie5_5  = (this.is_ie && (agt.indexOf("msie 5.5") !=-1)); // 020128 new - abk
    this.is_ie5_5up =(this.is_ie && this.is_minor >= 5.5);                // 020128 new - abk
	
    this.is_ie6   = (this.is_ie && this.is_major == 6);
    this.is_ie6up = (this.is_ie && this.is_minor >= 6);

    this.is_ie7   = (this.is_ie && this.is_major == 7);
    this.is_ie7up = (this.is_ie && this.is_minor >= 7);

    // KNOWN BUG: On AOL4, returns false if IE3 is embedded browser
    // or if this is the first browser window opened.  Thus the
    // variables this.is_aol, this.is_aol3, and this.is_aol4 aren't 100% reliable.

    this.is_aol   = (agt.indexOf("aol") != -1);
    this.is_aol3  = (this.is_aol && this.is_ie3);
    this.is_aol4  = (this.is_aol && this.is_ie4);
    this.is_aol5  = (agt.indexOf("aol 5") != -1);
    this.is_aol6  = (agt.indexOf("aol 6") != -1);
    this.is_aol7  = ((agt.indexOf("aol 7")!=-1) || (agt.indexOf("aol7")!=-1));
    this.is_aol8  = ((agt.indexOf("aol 8")!=-1) || (agt.indexOf("aol8")!=-1));

    this.is_webtv = (agt.indexOf("webtv") != -1);
    
    // new 020128 - abk
    
    this.is_TVNavigator = ((agt.indexOf("navio") != -1) || (agt.indexOf("navio_aoltv") != -1)); 
    this.is_AOLTV = this.is_TVNavigator;

    this.is_hotjava = (agt.indexOf("hotjava") != -1);
    this.is_hotjava3 = (this.is_hotjava && (this.is_major == 3));
    this.is_hotjava3up = (this.is_hotjava && (this.is_major >= 3));

    // end new
	
    // *** JAVASCRIPT VERSION CHECK ***
    // Useful to workaround Nav3 bug in which Nav3
    // loads <SCRIPT LANGUAGE="JavaScript1.2">.
    // updated 020131 by dragle
    this.is_js;
    if (this.is_nav2 || this.is_ie3) this.is_js = 1.0;
    else if (this.is_nav3) this.is_js = 1.1;
    else if ((this.is_opera5)||(this.is_opera6)) this.is_js = 1.3; // 020214 - dmr
    else if (this.is_opera7up) this.is_js = 1.5; // 031010 - dmr
    else if (this.is_khtml) this.is_js = 1.5;   // 030110 - dmr
    else if (this.is_opera) this.is_js = 1.1;
    else if ((this.is_nav4 && (this.is_minor <= 4.05)) || this.is_ie4) this.is_js = 1.2;
    else if ((this.is_nav4 && (this.is_minor > 4.05)) || this.is_ie5) this.is_js = 1.3;
    else if (this.is_nav5 && !(this.is_nav6)) this.is_js = 1.4;
    else if (this.is_hotjava3up) this.is_js = 1.4; // new 020128 - abk
    else if (this.is_nav6up) this.is_js = 1.5;

    // NOTE: In the future, update this code when newer versions of JS
    // are released. For now, we try to provide some upward compatibility
    // so that future versions of Nav and IE will show they are at
    // *least* JS 1.x capable. Always check for JS version compatibility
    // with > or >=.

    else if (this.is_nav && (this.is_major > 5)) this.is_js = 1.4;
    else if (this.is_ie && (this.is_major > 5)) this.is_js = 1.3;
    else if (this.is_moz) this.is_js = 1.5;
    else if (this.is_fb||this.is_fx) this.is_js = 1.5; // 032504 - dmr
    
    // what about ie6 and ie6up for js version? abk
    
    // HACK: no idea for other browsers; always check for JS version 
    // with > or >=
    else this.is_js = 0.0;
    // HACK FOR IE5 MAC = js vers = 1.4 (if put inside if/else jumps out at 1.3)
    if ((agt.indexOf("mac")!=-1) && this.is_ie5up) this.is_js = 1.4; // 020128 - abk
    
    // Done with this.is_minor testing; revert to real for N6/7
    if (this.is_nav6up) {
        this.is_minor = navigator.vendorSub;
    }

    // *** PLATFORM ***
    this.is_win   = ( (agt.indexOf("win")!=-1) || (agt.indexOf("16bit")!=-1) );
    // NOTE: On Opera 3.0, the userAgent string includes "Windows 95/NT4" on all
    //        Win32, so you can't distinguish between Win95 and WinNT.
    this.is_win95 = ((agt.indexOf("win95")!=-1) || (agt.indexOf("windows 95")!=-1));

    // is this a 16 bit compiled version?
    this.is_win16 = ((agt.indexOf("win16")!=-1) ||
                     (agt.indexOf("16bit")!=-1) || (agt.indexOf("windows 3.1")!=-1) ||
                     (agt.indexOf("windows 16-bit")!=-1) );

    this.is_win31 = ((agt.indexOf("windows 3.1")!=-1) || (agt.indexOf("win16")!=-1) ||
                     (agt.indexOf("windows 16-bit")!=-1));
	
    this.is_winme = ((agt.indexOf("win 9x 4.90")!=-1));    // new 020128 - abk
    this.is_win2k = ((agt.indexOf("windows nt 5.0")!=-1) || (agt.indexOf("windows 2000")!=-1)); // 020214 - dmr
    this.is_winxp = ((agt.indexOf("windows nt 5.1")!=-1) || (agt.indexOf("windows xp")!=-1)); // 020214 - dmr

    // NOTE: Reliable detection of Win98 may not be possible. It appears that:
    //       - On Nav 4.x and before you'll get plain "Windows" in userAgent.
    //       - On Mercury client, the 32-bit version will return "Win98", but
    //         the 16-bit version running on Win98 will still return "Win95".
    this.is_win98 = ((agt.indexOf("win98")!=-1) || (agt.indexOf("windows 98")!=-1));
    this.is_winnt = ((agt.indexOf("winnt")!=-1) || (agt.indexOf("windows nt")!=-1));
    this.is_win32 = (this.is_win95 || this.is_winnt || this.is_win98 ||
                     ((this.is_major >= 4) && (navigator.platform == "Win32")) ||
                     (agt.indexOf("win32")!=-1) || (agt.indexOf("32bit")!=-1));

    this.is_os2   = ((agt.indexOf("os/2")!=-1) ||
                     (navigator.appVersion.indexOf("OS/2")!=-1) ||
                     (agt.indexOf("ibm-webexplorer")!=-1));

    this.is_mac    = (agt.indexOf("mac")!=-1);
    if (this.is_mac) { this.is_win = !this.is_mac; } // dmr - 06/20/2002
    this.is_mac68k = (this.is_mac && ((agt.indexOf("68k")!=-1) ||
                                      (agt.indexOf("68000")!=-1)));
    this.is_macppc = (this.is_mac && ((agt.indexOf("ppc")!=-1) ||
                                      (agt.indexOf("powerpc")!=-1)));

    this.is_sun   = (agt.indexOf("sunos")!=-1);
    this.is_sun4  = (agt.indexOf("sunos 4")!=-1);
    this.is_sun5  = (agt.indexOf("sunos 5")!=-1);
    this.is_suni86= (this.is_sun && (agt.indexOf("i86")!=-1));
    this.is_irix  = (agt.indexOf("irix") !=-1);    // SGI
    this.is_irix5 = (agt.indexOf("irix 5") !=-1);
    this.is_irix6 = ((agt.indexOf("irix 6") !=-1) || (agt.indexOf("irix6") !=-1));
    this.is_hpux  = (agt.indexOf("hp-ux")!=-1);
    this.is_hpux9 = (this.is_hpux && (agt.indexOf("09.")!=-1));
    this.is_hpux10= (this.is_hpux && (agt.indexOf("10.")!=-1));
    this.is_aix   = (agt.indexOf("aix") !=-1);      // IBM
    this.is_aix1  = (agt.indexOf("aix 1") !=-1);
    this.is_aix2  = (agt.indexOf("aix 2") !=-1);
    this.is_aix3  = (agt.indexOf("aix 3") !=-1);
    this.is_aix4  = (agt.indexOf("aix 4") !=-1);
    this.is_linux = (agt.indexOf("inux")!=-1);
    this.is_sco   = (agt.indexOf("sco")!=-1) || (agt.indexOf("unix_sv")!=-1);
    this.is_unixware = (agt.indexOf("unix_system_v")!=-1);
    this.is_mpras    = (agt.indexOf("ncr")!=-1);
    this.is_reliant  = (agt.indexOf("reliantunix")!=-1);
    this.is_dec   = ((agt.indexOf("dec")!=-1) || (agt.indexOf("osf1")!=-1) ||
                     (agt.indexOf("dec_alpha")!=-1) || (agt.indexOf("alphaserver")!=-1) ||
                     (agt.indexOf("ultrix")!=-1) || (agt.indexOf("alphastation")!=-1));
    this.is_sinix = (agt.indexOf("sinix")!=-1);
    this.is_freebsd = (agt.indexOf("freebsd")!=-1);
    this.is_bsd = (agt.indexOf("bsd")!=-1);
    this.is_unix  = ((agt.indexOf("x11")!=-1) || this.is_sun || this.is_irix || this.is_hpux ||
                     this.is_sco ||this.is_unixware || this.is_mpras || this.is_reliant ||
                     this.is_dec || this.is_sinix || this.is_aix || this.is_linux || this.is_bsd || this.is_freebsd);

    this.is_vms   = ((agt.indexOf("vax")!=-1) || (agt.indexOf("openvms")!=-1));
    // additional checks, abk
    
    this.has_anchors = (document.anchors) ? "true":"false";
    this.has_regexp = (window.RegExp) ? "true":"false";
    this.has_option = (window.Option) ? "true":"false";
    this.has_documentall = (document.all) ? "true":"false";
    // cookies - 990624 - abk
    document.cookie = "cookies=true";
    this.has_cookie = (document.cookie) ? "true" : "false";
    this.has_images = (document.images) ? "true":"false";
    this.has_layers = (document.layers) ? "true":"false"; // gecko m7 bug?
    // new doc obj tests 990624-abk
    this.has_forms = (document.forms) ? "true" : "false";
    this.has_links = (document.links) ? "true" : "false";
    this.has_frames = (window.frames) ? "true" : "false";
    this.has_screen = (window.screen) ? "true" : "false";
    
    // java
    this.has_java = (navigator.javaEnabled());
    
    // Flash checking code adapted from Doc JavaScript information; 
    // see http://webref.com/js/column84/2.html
    
    this.has_flash        = false;
    this.flashVersion = 0;
    
    if ((this.is_nav||this.is_opera||this.is_moz||this.is_fb||this.is_fx)||
        (this.is_mac&&this.is_ie5up)) {

        var plugin =
            (navigator.mimeTypes && 
             navigator.mimeTypes["application/x-shockwave-flash"] &&
             navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin) ?
            navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin : 0;

        if (plugin) {
            this.has_flash = true;
            this.flashVersion = 
                parseInt(plugin.description.substring(plugin.description.indexOf(".")-1));
        }
    }
    
    if (this.is_win&&this.is_ie4up)
        {
            document.write(
                           '<scr' + 'ipt language=VBScript>' + '\n' +
                           'Dim hasPlayer, playerversion' + '\n' +
                           'hasPlayer = false' + '\n' +
                           'playerversion = 10' + '\n' +
                           'Do While playerversion > 0' + '\n' +
                           'On Error Resume Next' + '\n' +
                           'hasPlayer = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash." & playerversion)))' + '\n' +
                           'If hasPlayer = true Then Exit Do' + '\n' +
                           'playerversion = playerversion - 1' + '\n' +
                           'Loop' + '\n' +
                           'this.flashVersion = playerversion' + '\n' +
                           'this.has_Flash = hasPlayer' + '\n' +
                           '<\/sc' + 'ript>'
                           );
        }
    this.offsetForUnknownReason = 0;
    if (this.is_ie) {
        if (this.is_ie7) {
            this.offsetForUnknownReason = 4;
        }
        this.offsetScrollbar = 0;
    } else {
        this.offsetScrollbar = 25;
    }
}

WJSBrowser.prototype.getEvent = function(event) {
    // IE doesn't pass the event.  We must go get it.
    if (!event) {
        event = window.event;
    }
    return event;
}

// Returns the y position of the top of the window, optionally
// taking into account the user's request to scroll.
WJSBrowser.prototype.scrollTop = function() {
    top_pos = 0;
    if (document.body && document.body.scrollTop) {
        top_pos = document.body.scrollTop;
    }
    if (!top_pos && document.documentElement &&
                    document.documentElement.scrollTop) {
        top_pos = document.documentElement.scrollTop; 
    }
    if (!top_pos && window.pageYOffset) {
        top_pos = window.pageYOffset; 
    }
    return top_pos;
}

// @RC 20040122ESB This routine does not belong in this object. 

// While handling a resize, some elements will change width.  Their new
// widths are often based on the new width of a parent.  Under IE, the
// parent changes width as the children change, so earlier updates affect
// later updates within a single resizing.  With the following function, 
// the width value from the begining of the process can be remembered.
WJSBrowser.prototype.recentValue = function(div, what) {
    whatName = 'wjsRecentValue'+what;
    when = window.wjsApplication.resizeCount;
    if (typeof div.wjsRecentValue__When == 'undefined' ||
        div.wjsRecentValue__When != when) {
        div.wjsRecentValue__When = when;
        div[whatName] = div[what];
    }
    return div[whatName];
}

wjsBrowser = new WJSBrowser;

//--------------------
// file: wjshash.js
//--------------------
//
wjsHash = function() {
}

wjsHash.prototype.exists = function(key) {
    return typeof this[key] != 'undefined';
}

wjsHash.prototype.remove = function(key) {
    delete this[key];
}

wjsHash.prototype.foreach = function(functionToCall) {
    defaultObject = new wjsHash;
    for (key in this) {
        if (typeof defaultObject[key] == 'undefined') {
            functionToCall(key, this[key]);
        }
    }
}

//--------------------
// file: wjscolors.js
//--------------------
//
wjsColors = {
    foreground : {
        general : '#000000'
    },
    background : {
        general : '#FFFFFF',
        selectable : '#E0E0E0',
        selected : '#8bbee0'
    }
};

//--------------------
// file: wjstophp.js
//--------------------
//
// Based on code from http://php.cd/cowiki/25.html#A5

function wjsToPHP (variable)
{
    if (variable == null) {
        return 'N;';
    }
    switch (typeof variable)
    {
        case 'number':
            if (Math.round(variable) == variable)
                return 'i:'+variable+';';
            else 
                return 'd:'+variable+';';
        case 'boolean':
            if (variable == true)
                return 'b:1;';
            else
                return 'b:0;';
        case 'string':
             // Remarkably, no replaces need to be done for special characters
             return 's:'+variable.length+':"'+variable+'";';
        case 'object':
            r = '';
            var count = 0;
            for (i in variable) {
                if (typeof variable[i] == 'function') {
                    continue;
                }
                count++;
                r+= wjsToPHP(i)+wjsToPHP(variable[i]);
            }
            return 'a:'+count+':{'+r+'}';
/* This code assumes a non-associative array
            r = 'a:'+variable.length+':{';
            for(i=0; i < variable.length; i++)
            {
                r+= wjsToPHP(i)+wjsToPHP(variable[i]);
            }
            r += '}';
            return r;
*/
            break;
        default:
            return 'unknown type: '+typeof variable;
    }
}

//--------------------
// file: wjsclient.js
//--------------------
//

// WJSClient A Remote scripting client. 
// This code is based on Brent Ashley's JSRS code, 
// but has been modified to be more strongly OO. THe original 
// header is below. 
// May, 2004, Eric Busboom eric@softwarestudio.org

//
//  jsrsClient.js - javascript remote scripting client include
//  
//  Author:  Brent Ashley [jsrs@megahuge.com]
//
//  make asynchronous remote calls to server without client page refresh
//
//  see license.txt for copyright and license information

/*
  see history.txt for full history
  2.0  26 Jul 2001 - added POST capability for IE/MOZ
  2.2  10 Aug 2003 - added Opera support
  2.3(beta)  10 Oct 2003 - added Konqueror support - **needs more testing**
*/


// The WJSClient object will hols the set of contexts and 
// serve as the primary interface to the subsystem. 
// 
function WJSClient(application){

    this.application = application;

}

// Properties 
WJSClient.prototype.contextPoolSize = 0;
WJSClient.prototype.contextMaxPool = 4;
WJSClient.prototype.contextPool = new Array();
WJSClient.prototype.containerName;
WJSClient.prototype.visibility = false;
WJSClient.prototype.nametag = 'wjs';

// Methods

// Create a new context. 
WJSClient.prototype.newContext = function(){

    var contextID = this.nametag + (this.contextPoolSize + 1);
    var context = new WJSClientContext( contextID );
    context.initialize(this);

    this.contextPool[ contextID ] =  context;
    this.contextPoolSize++;

    return  this.contextPool[ contextID ];
}

// Return the context with the given name
WJSClient.prototype.findContext = function(contextID){
    return this.contextPool[contextID];
}

// find the first context in the pool that is free. 
WJSClient.prototype.findFreeContext = function(){

    var context;

    // Look for an existing context
    for (var i = 1; i <= this.contextPoolSize; i++){
        var contextID = this.nametag + i;
        var context = this.findContext(contextID );
        //alert(i+' '+contextID+' '+context.id);

        if ( context && (!context.busy  || context.expired()) ){
            return context;
        }
    }

    return null;
}


// Get a new free context, either by finding a free one, or creating a new one. 
WJSClient.prototype.getContext = function(){

    var context = this.findFreeContext();

    if(context==null){
        // if we got here, there are no existing free contexts
        if ( this.contextPoolSize <= this.contextMaxPool ){
            // create new context
            context = this.newContext();
        } else {
            alert( "Script Client Error:  context pool full" );
            return null;
        }   
    }

    var vis = (this.visibility == null)? false : this.visibility;
    context.setVisibility(vis );

    return context;


}

WJSClient.prototype.get = function(url, callback, func, parms){

    var context = this.getContext();

    context.post( url, callback, func, parms );
  
    return context.id;

}

WJSClient.prototype.post = function(url, callback, func, parms){

    var context = this.getContext();

    context.callback = callback;

    context.post( url, callback, func, parms );
  
    return context.id;

}

// Copy the given form element and post it. 
// if the action is not given, the one in the form will be used
WJSClient.prototype.postForm = function(form, callback, action){

    var context = this.getContext();

    context.callback = callback;

    context.postForm(form,callback, action );
  
    return context.id;

}

// Get the data from the URL, but do not interpret it as a function call.
WJSClient.prototype.fetch = function(url, callback){

    var context = this.getContext();
    context.callback = callback;

    context.fetch(url , callback );
  
    return context.id;
}


// Replace the innerHTML of the element with the given id
// The callback gets called after the routine finishes loading. 
WJSClient.prototype.replace = function(url,id,callback){

    var element =  document.getElementById(id);
    
    this.fetch(url, function(){ 
        var payload = this.getPayload();
        element.innerHTML = payload.innerHTML;
        if(callback){
            element.wjscallback = callback;
            element.wjscallback();
        }
    });
 

}



function jsrsError( contextID, str ){
    alert( unescape(str) );
    jsrsContextPool[ contextID ].busy = false;
}

function jsrsEscapeQQ( thing ){
    return thing.replace(/'"'/g, '\\"');
}

function jsrsUnescape( str ){
    // payload has slashes escaped with whacks
    return str.replace( /\\\//g, "/" );
}



WJSClient.prototype.debugInfo = function (){
    // use for debugging by attaching to f1 (works with IE)
    // with onHelp = "return jsrsDebugInfo();" in the body tag
    var doc = window.open().document;
    doc.open;
    doc.write( 'Pool Size: ' + this.contextPoolSize + 
               '<br><font face="arial" size="2"><b>' );
    for( var i in this.contextPool ){
        var context = this.contextPool[i];
        doc.write( '<hr>' + context.id + ' : ' + 
                   (context.busy ? 'busy' : 'available') + '<br>');
        doc.write( context.container.document.location.pathname + '<br>');
        doc.write( context.container.document.location.search + '<br>');
        doc.write( '<table border="1"><tr><td>' + 
                   context.container.document.body.innerHTML + 
                   '</td></tr></table>' );
    }
    doc.write('</table>');
    doc.close();
    return false;
}

//--------------------
// file: wjscomm.js
//--------------------
//
// A communication object for GET, POST and XMLRPC communication
// with a remote server. 


function WJSComm(application){
    this.application = application;

    this.XMLRPC = XMLRPC;

}

// Statics
WJSComm.thisSchemeAndHost = function(){
    var regex = new RegExp('^(https?://[^\/]*)');
    var str = new String(window.location);
    return str.match(regex)[0];
}

WJSComm.thisSessionId = function(){
    var regex = new RegExp('sessid=([^&]*)');
    var str = new String(window.location);
    return str.match(regex)[1];
}


// Make a GET request and replace elements in the document
// with elements with the same id views as in children 
// of the body of the returned document
WJSComm.prototype.replace = function(url){
    html =this.application.client.fetch
        (url,
         function(){
             var body = this.getPayload();

             if(body){
                 for(i=0; i<body.childNodes.length;i++){
                     var child = body.childNodes.item(i);
                     if(child.nodeType == 1){
                         var origElem = document.getElementById(child.id);
                         if(origElem){
                             var parent = origElem.parentNode;
                             var clone = document.importNode(child,true);
                             parent.replaceChild(clone,origElem);
                         }
                     }
                 }
             }

         });
};

// For each child of the body of the returned document, 
// insert a copy of the child as a child of the element 
// ordering the new child among existing children according to the value
// of the 'wjsrank' attribute
WJSComm.prototype.mergeRank = function(url,elem){
};

// Upload the document given in the INPUT element 
WJSComm.prototype.postDocument = function(url,elem){
};

// The element is a form. Copy the form to an IFRAME and post it. 
// If the server returns XML, it will be interpreted as an XMLRPC response
WJSComm.prototype.postForm = function(elem,cb){
    this.application.client.postForm(elem,cb);
};

// Get a service object for and XMLRPC service
WJSComm.prototype.getService = function(className,url){

    if(!className){
        className = WJSXMLRPCService;
    }

    if(XMLRPC.services[className]){
        return XMLRPC.services[className];
    } else {
        try{
            var ct = eval(className); // test existence of class
            var o =  new ct(this,url);
            XMLRPC.services[className] = o;

            return  o;
        }
        catch(e){
            alert(e);
            return false;
        }
    }
};

//  Make a call to an XMLRPC service without a service object
WJSComm.prototype.call = function(url,serviceName,parameters){

    service = window.wjsApplication.comm.getService(null,url);

    return service.call(serviceName,parameters);
};


//--------------------
// file: wjsxmlrpcservice.js
//--------------------
//
//
// a Service object is a client side wrapper for the methods of
// the server-side xmlRPC service

// Construct from the WJSComm object
function WJSXMLRPCService(comm,url){

    this.base = VirtualService;

    if(comm){ // not set when assigned for a prototype
        this.comm = comm;
        this.application = this.comm.application;    
    }

    if(url){
        this.url = url;
    }

    if(this.url){ // null during proto assign
        if(!this.url.match(/^http/)){
            this.url = WJSComm.thisSchemeAndHost()+this.url;    
        } 

        this.base(this.url,this.comm.XMLRPC);

    } else {
        this.base(null,null);
    }

  
}
// Inherit from the vcXMLRPC VirtualService
WJSXMLRPCService.prototype = new VirtualService;


// Call a service. The name is the complete name of the
// service.
WJSXMLRPCService.prototype._call = function(name,param){
}

//----------------------------------------------------------------------
// The system Service

function WJSSystemService(comm,url){
    this.base = WJSXMLRPCService;
    this.base(comm,url);
    
    this.add("system.listMethods", "listMethods");
    this.add("system.methodHelp", "methodHelp");
    this.add("system.methodSignature", "methodSignature");
    this.add("system.multiCall", "multiCall");
    this.add("system.describeMethods", "describeMethods");
    this.add("system.getCapabilities", "getCapabilities");
}
// Inherit from the vcXMLRPC VirtualService
WJSSystemService.prototype = new WJSXMLRPCService;


//--------------------
// file: wjsapplication.js
//--------------------
//

// WAF JS Application object, a singleton that holds references to other
// objects and performans basic services. 

// include menu.js

// Constructor

function WJSApplication(){

    // Top of screen menu
    //this.topMenu = new Menu();

    this.browser = wjsBrowser;
    this.client = new WJSClient(this);
    this.comm = new WJSComm(this);

    this.menu = new Object();

    this.resizeCount = 0;

    this.windowSize = null;
}

// Array of routines to call from the onload handler
WJSApplication.prototype.onloadCallbacks = new Array();
WJSApplication.prototype.onunloadCallbacks = new Array();
WJSApplication.prototype.onResizeCallbacks = new Array();
WJSApplication.prototype.onAnyResizeCallbacks = new Array();

WJSApplication.prototype.documents = new Array();
WJSApplication.prototype.documentFunctions = new Array();

//----------------------------------------------------------------------
//  Methods

WJSApplication.prototype.addCallback = function(type, cb) { 
    this[type].push(cb); 
}

WJSApplication.prototype.callCallbacks = function(type){
    for(var i=0; i < this[type].length; i++){
        this[type][i]();
    }
}

WJSApplication.prototype.addOnloadCallback = function(cb) { 
    this.addCallback('onloadCallbacks', cb); 
}

WJSApplication.prototype.alreadyLoaded = false;
WJSApplication.prototype.onload = function() { 
    if (this.alreadyLoaded) {
        return;
    }
    this.callCallbacks('onloadCallbacks'); 
    this.alreadyLoaded = true;
    this.windowSize = windowSize();
    if (alterLinkArgs) {
        alterLinkArgs('wjsSave_width',this.windowSize[0],true);
        alterLinkArgs('wjsSave_height',this.windowSize[1],true);
    }
}

WJSApplication.prototype.addOnunloadCallback = function(cb) { 
    this.addCallback('onunloadCallbacks', cb); 
}

WJSApplication.prototype.onunload = function() { 
    this.callCallbacks('onunloadCallbacks'); 
}

// OnResize is supplorted by both Mozilla and IE. These
// are the real regular resize event. It is only called when the
// window actually changes size, unlike the normal case in IE< 
// where onResize gets called when objects on the page change size, event
// if the window does not. 
WJSApplication.prototype.addOnResizeCallback = function(cb) { 
    this.addCallback('onResizeCallbacks', cb); 
}

// onAnyResize is a syntetic event that WJSApplication created 
// to seperate out the resize events that IE generates when 
// objects on the page change size, even if the window has not
// changed size. The WJSApplication::onResize() distinguishes betweem 
// these two events. 
WJSApplication.prototype.addOnAnyResizeCallback = function(cb) { 
    this.addCallback('onAnyResizeCallbacks', cb); 
}

WJSApplication.prototype.onResize = function() { 
    var newWindowSize = windowSize();

    // If this.windowSize is null, we haven't even finished loading the page
    // yet.  It's overkill to be doing a resize at this point.  (IE tries to
    // do so anyway sometimes.)
    if (this.windowSize == null) {
        this.windowSize = newWindowSize;
    }
    if (this.windowSize[0] != newWindowSize[0] ||
        this.windowSize[1] != newWindowSize[1]) {
        this.windowSize = newWindowSize;
        this.resizeCount++;
        this.callCallbacks('onResizeCallbacks'); 
    }
    this.callCallbacks('onAnyResizeCallbacks'); 
}

WJSApplication.prototype.addDocumentFunction = function(functionName) { 
    this.documentFunctions.push(functionName);
    for(var i=0; i < this.documents.length; i++){
        eval("this.documents[i]."+functionName+" = "+functionName+";");
    }
}

WJSApplication.prototype.registerDocument = function(document) { 
    this.documents.push(document);
    for(var i=0; i < this.documentFunctions.length; i++){
        eval("document."+this.documentFunctions[i]+" = "+
             this.documentFunctions[i]+";");
    }
}

// Used by the toggle function of WJSShadowBox. The toggleType 
// defines the name of an attribute of a parent tag that holds children
// that can be opened.
// So, for  a toggleType of "minmax" there are these attributes in 
// an element heirarchy:
//   isminmaxHandler -- Marks the parent of the elements that are toggled
//   minmaxContentType -- Defines the state for which this element is displayed
//   minmaxState -- stores the current toggle state for an element
// 
// This routine is called from, typically, a button or an icon. The
// routine climbs the element tree to find an ancestor element that 
// has a handler for the toggleType. (ie: 'isminmaxHandler') 
// Then, it visits all of the children of the handler element that have a
// state attribute defined ( minmaxState ) that matches the nextState value
// and les them on or off depending on their current condition, 
// ( minmaxContentType )
//
// Note that here "state" means the state of the whole set.
WJSApplication.prototype.toggle = function(element, toggleType, nextState,
                                           levels, withSave) {
    // Somewhere up the tree is an element that holds the options.
    // It has "is{toggleType}Handler=1".  It might even be the element.
    var handler = element;
    while (handler && !handler.getAttribute('is'+toggleType+'Handler')) {
        handler = handler.parentNode;
    }
    element.handler = handler;
    handler[toggleType+'State'] = nextState;
    var parent = handler;
    // How many levels beneath the handler should we try to propagate
    // the new state?  More levels allows fancier features with more
    // easy, but at an exponentially increasing CPU hit.
    if (!levels) {
        levels = 1;
    }
    // Tables have a hidden level of tags
    if (handler.tagName == 'TABLE') {
        levels = levels+1;
    }
    this._doToggle(parent, toggleType, nextState, levels);
    if (withSave) {
        alterLinkArgs('wjsSave_'+handler.id+'_'+toggleType,nextState,true);
    }
}

WJSApplication.prototype._doToggle = function(parent, toggleType, nextState,
                                              levels) {
    var child;
    for (child = parent.firstChild;
         child;
         child = child.nextSibling) {
        var contentType = null;
        if (typeof child.getAttribute != 'undefined') {
            contentType = child.getAttribute(toggleType+'ContentType');
        }
        // Display or make invisible the tag
        if (contentType != null) {
            if (contentType == nextState) {
                // IE doesn't follow the standards for the values of
                // display in tables.  Rather than deal with that, it is
                // easier to just set display to an empty string.  All
                // browsers will "do the right thing".
                child.style.display = '';
            } else {
                child.style.display = 'none';
            }
        } else if (levels > 1) {
            this._doToggle(child, toggleType, nextState, levels-1);
        }
    }
}

// Finds all the form elements whose treeids start with the given treeid
// and concatenates the values into the form element with the given treeid.
WJSApplication.prototype.rollup = function(treeId) {
    var textareas = document.getElementsByTagName('textarea');
    var textarea, textareaTreeId, target, textholder;
    var text = '';
    for (var i=0; i < textareas.length; i++) {
        textarea = textareas[i];
        if ((textareaTreeId = textarea.getAttribute('treeid')) != null) {
            if (textareaTreeId.substr(0,treeId.length) == treeId) {
                if (textareaTreeId == treeId) {
                    target = textarea;
                }
                if (textarea.value != '') {
                    text = text+textarea.value+"\n";
                }
            }
        }
    }
    if (target != null) {
        target.value = text;
        change(target);
    }
}

// Finds all the checkboxes whose treeids are parents of the given
// treeid and sets their values to true
WJSApplication.prototype.checkup = function(treeId) {
    var checkboxes = document.getElementsByTagName('input');
    var checkbox, checkboxTreeId;
    var text = '';
    for (var i=0; i < checkboxes.length; i++) {
        checkbox = checkboxes[i];
        if (checkbox.type == 'checkbox' &&
            (checkboxTreeId = checkbox.getAttribute('treeid')) != null) {
            if (treeId.substr(0,checkboxTreeId.length) == checkboxTreeId) {
                checkbox.checked = 'checked';
            }
        }
    }
}

// Finds all the checkboxes whose treeids are parents of the given
// treeid and sets their values to true
WJSApplication.prototype.checkdown = function(treeId) {
    var checkboxes = document.getElementsByTagName('input');
    var checkbox, checkboxTreeId;
    var text = '';
    for (var i=0; i < checkboxes.length; i++) {
        checkbox = checkboxes[i];
        if (checkbox.type == 'checkbox' &&
            (checkboxTreeId = checkbox.getAttribute('treeid')) != null) {
            if (checkboxTreeId.substr(0,treeId.length) == treeId) {
                checkbox.checked = 'checked';
            }
        }
    }
}



WJSApplication.prototype.setAndCorrectWidth = function(element, width) {
    element.style.width = width;
    element.style.width += width-element.offsetWidth;
}

//----------------------------------------------------------------------
// Create the singleton object. 
//----------------------------------------------------------------------


window.wjsApplication = new WJSApplication();

window.onload = function(){ window.wjsApplication.onload(); }
window.onResize = function(){ window.wjsApplication.onResize(); }

window.wjsApplication.registerDocument(document);

//--------------------
// file: wjsclientcontext.js
//--------------------
//
// WJSClient A Remote scripting client. 
// This code is based on Brent Ashley's JSRS code, 
// but has been modified to be more strongly OO. THe original 
// header is below. 
// May, 2004, Eric Busboom eric@softwarestudio.org

//
//  jsrsClient.js - javascript remote scripting client include
//  
//  Author:  Brent Ashley [jsrs@megahuge.com]
//
//  make asynchronous remote calls to server without client page refresh
//
//  see license.txt for copyright and license information

/*
  see history.txt for full history
  2.0  26 Jul 2001 - added POST capability for IE/MOZ
  2.2  10 Aug 2003 - added Opera support
  2.3(beta)  10 Oct 2003 - added Konqueror support - **needs more testing**
*/

// constructor for context object
function WJSClientContext( contextID ){

    this.id = contextID;
  
    // methods
}

// properties
WJSClientContext.prototype.id = null;
WJSClientContext.prototype.busy = false;
WJSClientContext.prototype.callback = null;
WJSClientContext.prototype.client = null; // will be set in WJSClient::newContext()
WJSClientContext.prototype.expireTime = 3;

// Called after the client creates this object
WJSClientContext.prototype.initialize = function(client){
       
    this.client = client;
    this.container = this.createContainer(this.id );   
    this.setVisibility(false);
}

//  method functions are not privately scoped 
//  because Netscape's debugger chokes on private functions
WJSClientContext.prototype.createContainerIE = function(containerName){
    var container;
    
    this.makeContainer = function(containerName){

        var id = "SPAN" + containerName;

        document.body.insertAdjacentHTML( "afterBegin", 
                                          '<span id="' + id +
                                          '"></span>' );

        var span = document.all(id);
        
        // 20040610ESB The recommended way to do this is to put the onload handler
        // in the body of the document that has been loaded, but that only
        // works if you have control of the site that sends the data to the
        // iframe. I wanted something more general. 
        var html = '<iframe'+
            ' name="' + containerName + '"'+
            ' id="IFRAME' + containerName + '"'+
            ' onload="' + " WJSDataLoadedCB('"+containerName+"' )" + '"'+
            ' src="/blank.html">'+
            '</iframe>';
        
        span.innerHTML = html;
        //span.style.display = 'none';
        return window.frames[ containerName ];
    };
    
    this.reloadURL = function(url){
        this.container.document.location.replace(url);
    };
    
    this.getDocument = function(){
        return window.frames[container.name].document;
    };

    this.setVisibility = function(vis){

        var id = "SPAN" + this.id;

        var span = document.all(id);
        if(span && span.style){
            span.style.display = (vis)? '' : 'none';
        }

    };

    // Create a new document container so we can process the
    // payload as XMLRPC. 
    this.createXMLDOM = function(){
        xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
        xmlDoc.async = false;
        while(xmlDoc.readyState != 4) {}; 
    } ;


    return this.makeContainer(containerName);
}

WJSClientContext.prototype.createContainerMOZ = function(containerName){
    var container;
    
    this.makeContainer = function(containerName){
        
        var span = document.createElement('SPAN');
        span.id = "SPAN" + containerName;
        document.body.appendChild( span );
        var iframe = document.createElement('IFRAME');
        iframe.name = containerName;
        iframe.id = containerName;
        span.appendChild( iframe );

        iframe.onload = function(){
            WJSDataLoadedCB(containerName );
        };

        return iframe;
    }
    
    // Set up a routine that we can call later to reload the
    // iframe
    this.reloadURL = function(url){
        this.container.src = '';
        this.container.src = url;
    };
    
    this.getDocument = function(){
        return this.container.document;
    }; 
    
    this.setVisibility = function(vis){
        var visibility = (vis)? '' : 'hidden';
        document.getElementById("SPAN" + this.id).style.visibility = visibility;
        this.container.width = (vis)? 250 : 0;
        this.container.height = (vis)? 100 : 0;
    }


    // Create a new document container so we can process the
    // payload as XMLRPC. 
    this.createXMLDOM = function(){
        return document.implementation.createDocument("", "", null) ;
    };

    // Setup a closure to call the onload handler. Since Mozilla propagates
    // onload events all the way up the change, we can carete the onload 
    // handler after the iframe is created and put it on a higher level
    // container
   
    return this.makeContainer(containerName);
}


// Return a top level container that holds the 
// contents of the body section, hopefully XML
WJSClientContext.prototype.getXMLDOM = function(){

    return this.container.document;
}

// Return the XMLRPC response
WJSClientContext.prototype.getRPCResponse = function(){

    dom = this.getXMLDOM();
    try {
        if(dom){
            return  XMLRPC.processXML(dom);
        }
    }        
    catch(e){            
    }
}


// Return the body node of the payload
WJSClientContext.prototype.getPayload = function(){

    return  this.container.document.getElementsByTagName('body').item(0);

};



// Slect the sub-method to create the container, based on the browser. 
WJSClientContext.prototype.createContainer = function(containerName){
    // creates hidden container to receive server data 

    if(this.client.application.browser.is_ie){
        return this.createContainerIE(containerName);

    } else {
        return this.createContainerMOZ(containerName);

    }
};


// return true is the call has expired
WJSClientContext.prototype.expired = function(){
    time = (new Date).getTime();

    if(time - this.busy_time > this.expireTime){
        alert("Expired!");
        return true;
    } else {
        return false;
    }

}

// Perform operations that are common to starting any type of call
WJSClientContext.prototype.initCall = function(callback){
    this.busy = true;
    this.busyTime = (new Date).getTime();
    this.callback = callback;
}

// Perform operations that are common to ending any type of cal
WJSClientContext.prototype.endCall = function(){
    this.busy = false;
    this.busyTime = 0;
    this.callback = null;

}


// Execute a regular GET, without the remote method invocation
WJSClientContext.prototype.fetch = function(url, callback ){

    this.initCall(callback);    
    this.reloadURL(url);
}

// Send the remote procedure call to the server via a POST. 
WJSClientContext.prototype.post = function( rsPage,  callback, func, parms ){

    this.initCall(callback);

    var d = new Date();
    var unique = d.getTime() + '' + Math.floor(1000 * Math.random());
    var doc = (this.client.application.browser.is_ie ) ? 
        this.container.document :
        this.container.contentDocument;

    doc.open();
    doc.write('<html><body>');
    doc.write('<form name="jsrsForm" method="post" target="" ');
    doc.write(' action="' + rsPage + '?U=' + unique + '">');
    doc.write('<input type="hidden" name="C" value="' + this.id + '">');

    // func and parms are optional
    if (func != null){
        doc.write('<input type="hidden" name="F" value="' + func + '">');

        if (parms != null){
            if (typeof(parms) == "string"){
                // single parameter
                doc.write( '<input type="hidden" name="P0" '
                           + 'value="[' + jsrsEscapeQQ(parms) + ']">');
            } else {
                // assume parms is array of strings
                for( var i=0; i < parms.length; i++ ){
                    doc.write( '<input type="hidden" name="P' + i + '" '
                               + 'value="[' + jsrsEscapeQQ(parms[i]) + ']">');
                }
            } // parm type
        } // parms
    } // func

    doc.write('</form></body></html>');
    doc.close();
    doc.forms['jsrsForm'].submit();
}

// Post the given form
WJSClientContext.prototype.postForm = function(form, callback,action ){
   
    var doc = this.container.document;

    doc.open();
    doc.write('<html><body id="body"></body></html>');
    doc.close();
    
    var body = doc.getElementById('body');

    // Damn I hate IE. I'd like to have document.importNode already exist. 
    // If not that, I'd like to be able to define a method in document for it.
    // But, no, I have to create a function in ieemu.js
    var dupe = importNode(doc,form,true);
    
    body.appendChild(dupe);    
    //body.inserBefore(dupe,null);

    // Now copy all of the values from the elements in the form
    // NOTE! This will only work if all of the form elements have unique 
    // names. ( or, with change, a unique id )
    var origInputs = form.getElementsByTagName('input');
    for(i=0;i<origInputs.length;i++){
        var elem = origInputs.item(i);
        if(elem.name){  
            //alert(elem.name+' '+elem.value);
            var newElem = doc.getElementsByName(elem.name)[0];
            //var newElem = doc.getElementById(elem.id);
            if(newElem){
                newElem.value = elem.value;
            }
        }
    }  
    
    // Init the call at the end so that if iframe's onLoad handler is called
    // prematurely (and it is ) WJSDataLoadedCB will know to ignore it
    this.initCall(callback);
    dupe.submit();        
}



WJSClientContext.prototype.get = function( rsPage, callback, func, parms ){

    alert("WJSClientContext.prototype.get; deprecated. Use XMLRPC instead");
    this.initCall(callback);

    // build URL to call
    var URL = rsPage;

    // always send context
    URL += "?C=" + this.id;

    // func and parms are optional
    if (func != null){
        URL += "&F=" + escape(func);

        if (parms != null){
            if (typeof(parms) == "string"){
                // single parameter
                URL += "&P0=[" + escape(parms+'') + "]";
            } else {
                // assume parms is array of strings
                for( var i=0; i < parms.length; i++ ){
                    URL += "&P" + i + "=[" + escape(parms[i]+'') + "]";
                }
            } // parm type
        } // parms
    } // func

    // unique string to defeat cache
    var d = new Date();
    URL += "&U=" + d.getTime();
 
    this.container.reloadURL(URL);
}


// fetch sets the context's document's onload handler to this
function WJSDataLoadedCB( contextID ){
    // get context object and invoke callback

    context = window.wjsApplication.client.findContext(contextID);

    // This cb gets called prematurely from the iframe's onLoad handler. 
    // I don't really know why
    if(context.busy){
       
        if( context.callback != null){
            context.callback();
        }
        context.endCall();

    }
}


// end of context constructor



//--------------------
// file: wjsmenu.js
//--------------------
//
// Functions to popup sub-menus using the brainjar.com HTML/CSS/Javascript menus

window.wjsApplication.menu.activeButton = null;

//----------------------------------------------------------------------
// Example code to run the menus. 

// <link rel="stylesheet" type="text/css" href="/css/menus.css">
// <script language="JavaScript1.2" src="/javascript/wjsmenu.js"></script>

// </p><div class="menuBar" style="width: 80%;">
// <a class="menuButton" href="" onclick="return buttonClick(event, 'fileMenu');" 
// onmouseover="buttonMouseover(event, 'fileMenu');">File</a>
// <a class="menuButton" href="" onclick="return buttonClick(event, 'editMenu');" 
// onmouseover="buttonMouseover(event, 'editMenu');">Edit</a>
// </div>


// <!-- File Menu -->
// <div id="fileMenu" class="menu" onmouseover="menuMouseover(event)">
// <a class="menuItem" href="">File Menu Item 1</a>

// <a class="menuItem" href="" onclick="return false;" 
// onmouseover="menuItemMouseover(event, 'fileMenu2');">
// 	  <span class="menuItemText">File Menu Item 2</span>
// 	  <span class="menuItemArrow">▶</span>
// 	</a>

// <div class="menuItemSep"></div>

// <a class="menuItem" 
//    href="http://brainjar.com/dhtml/menubar/blank.html">
// 	File Menu Item 5
//       </a>
// </div>


// <!-- File sub menus. -->

// <div id="fileMenu2" class="menu">
// <a class="menuItem" href="http://brainjar.com/dhtml/menubar/blank.html">File Menu 2 Item 1</a>
// <a class="menuItem" href="http://brainjar.com/dhtml/menubar/blank.html">File Menu 2 Item 2</a>
// </div>


// <!-- Edit Menu -->

// <div id="editMenu" class="menu" onmouseover="menuMouseover(event)">
// <a class="menuItem" href="http://brainjar.com/dhtml/menubar/blank.html">Edit Menu Item 1</a>
// <div class="menuItemSep"></div>
// <a class="menuItem" href="http://brainjar.com/dhtml/menubar/blank.html">Edit Menu Item 2</a>
// <a class="menuItem" href="" onclick="return false;" onmouseover="menuItemMouseover(event, 'editMenu3');"><span class="menuItemText">Edit Menu Item 3</span><span class="menuItemArrow">▶</span></a>
// <a class="menuItem" href="http://brainjar.com/dhtml/menubar/blank.html">Edit Menu Item 4</a>
// <div class="menuItemSep"></div>
// <a class="menuItem" href="http://brainjar.com/dhtml/menubar/blank.html">Edit Menu Item 5</a>
// </div>

// <!-- Edit sub menus. -->

// <div id="editMenu3" class="menu" onmouseover="menuMouseover(event)">
// <a class="menuItem" href="http://brainjar.com/dhtml/menubar/blank.html">Edit Menu 3 Item 1</a>
// <a class="menuItem" href="http://brainjar.com/dhtml/menubar/blank.html">Edit Menu 3 Item 2</a>
// <div class="menuItemSep"></div>

// <a class="menuItem" href="" onclick="return false;" onmouseover="menuItemMouseover(event, 'editMenu3_3');"><span class="menuItemText">Edit Menu 3 Item 3</span>
// <span class="menuItemArrow">▶</span></a>

// <a class="menuItem" href="http://brainjar.com/dhtml/menubar/blank.html">Edit Menu 3 Item 4</a>
// </div>

// <div id="editMenu3_3" class="menu">
// <a class="menuItem" href="http://brainjar.com/dhtml/menubar/blank.html">Edit Menu 3-3 Item 3</a>
// </div>



//----------------------------------------------------------------------------
// Code for handling the menu bar and active button.
//----------------------------------------------------------------------------


// Capture mouse clicks on the page so any active button can be
// deactivated.

function buttonClick(event, menuId) {

  var button;

  // Get the target button element.

  if (window.wjsApplication.browser.is_ie){
    button = window.event.srcElement;
  } else {
    button = event.currentTarget;
  }

  // Blur focus from the link to remove that annoying outline.

  button.blur();

  // Associate the named menu to this button if not already done.
  // Additionally, initialize menu display.

  if (typeof(button.menu) == 'undefined' ||  button.menu == null) {
    button.menu = document.getElementById(menuId);
    if (button.menu.isInitialized == null){
      menuInit(button.menu);
    }
  }

  // Reset the currently active button, if any.

  if (window.wjsApplication.menu.activeButton != null){
    resetButton(window.wjsApplication.menu.activeButton);
  }

  // Activate this button, unless it was the currently active one.

  if (button != window.wjsApplication.menu.activeButton) {
    depressButton(button);
    window.wjsApplication.menu.activeButton = button;
  } else {
    window.wjsApplication.menu.activeButton = null;
  }

  return false;
}



function buttonMouseover(event, menuId) {

  var button;

  // Find the target button element.

  if (window.wjsApplication.browser.is_ie){
    button = window.event.srcElement;
  } else {
    button = event.currentTarget;
  }

  // If any other button menu is active, make this one active instead.

  if (window.wjsApplication.menu.activeButton != null && 
      window.wjsApplication.menu.activeButton != button) {
      buttonClick(event, menuId);
  }
}


function pageMousedown(event) {

  var el;

  // If there is no active button, exit.

  if (typeof(window.wjsApplication.menu.activeButton) == 'undefined' || 
       window.wjsApplication.menu.activeButton == null)
    return;

  // Find the element that was clicked on.

  if (window.wjsApplication.browser.is_ie)
    el = window.event.srcElement;
  else
    el = (event.target.tagName ? event.target : event.target.parentNode);

  // If the active button was clicked on, exit.

  if (el == window.wjsApplication.menu.activeButton)
    return;

  // If the element is not part of a menu, reset and clear the active
  // button.

  if (getContainerWith(el, "DIV", "menu") == null) {
    resetButton(window.wjsApplication.menu.activeButton);
    window.wjsApplication.menu.activeButton = null;
  }
}

function resetButton(button) {

  // Restore the button's style class.

  removeClassName(button, "menuButtonActive");

  // Hide the button's menu, first closing any sub menus.

  if (typeof(button.menu) == 'undefined' || button.menu != null) {
    closeSubMenu(button.menu);
    button.menu.style.visibility = "hidden";
  }
}

function depressButton(button) {

  var x, y;

  // Update the button's style class to make it look like it's
  // depressed.

  button.className += " menuButtonActive";

  // Position the associated drop down menu under the button and
  // show it.

  x = getPageOffsetLeft(button);
  y = getPageOffsetTop(button) + button.offsetHeight;

  // For IE, adjust position.

  if (window.wjsApplication.browser.is_ie) {
    x += button.offsetParent.clientLeft;
    y += button.offsetParent.clientTop;
  }

  button.menu.style.left = x + "px";
  button.menu.style.top  = y + "px";
  button.menu.style.visibility = "visible";
}



//----------------------------------------------------------------------------
// Code to handle the menus and sub menus.
//----------------------------------------------------------------------------


function closeSubMenu(menu) {

    if (menu == null ||  typeof(menu.activeItem) == 'undefined' || 
        menu.activeItem == null){ 
    return;
  }

  // Recursively close any sub menus.


  if (typeof(menu.activeItem.subMenu) != 'undefined' && 
             menu.activeItem.subMenu != null) {
    closeSubMenu(menu.activeItem.subMenu);
    menu.activeItem.subMenu.style.visibility = "hidden";
    menu.activeItem.subMenu = null;
  }

  removeClassName(menu.activeItem, "menuItemHighlight");
  menu.activeItem = null;
}


function menuItemMouseover(event, menuId) {

  var item, menu, x, y;

  // Find the target item element and its parent menu element.

  if (window.wjsApplication.browser.is_ie)
    item = getContainerWith(window.event.srcElement, "A", "menuItem");
  else
    item = event.currentTarget;
  menu = getContainerWith(item, "DIV", "menu");

  // Close any active sub menu and mark this one as active.

  if (menu.activeItem != null){
 