  function Ajax(containerID,handleFinished,handleLoading,handleLoaded,onFinish)
  {
    if(containerID != undefined) {
      this._containerID = containerID;
    }
    if (handleFinished != undefined && handleFinished!=1) {
      this._handleFinished=handleFinished;
    }
    if (handleLoading != undefined) {
      if (handleLoading==0) {
        this._handleLoading=function() {};
      } else {
        this._handleLoading=handleLoading;
      }
    }
    if (handleLoaded != undefined) {
      if (handleLoaded==0) {
        this._handleLoaded=function() {};
      } else {
        this._handleLoaded=handleLoaded;
      }
    }
    if (onFinish !=undefined) {
      this.onFinish=onFinish;
    }
  }

  // *** DEFAULT PROPERTIES

  // the HTTP request method
  Ajax.prototype._method = "GET";

  //where to load the data from
  Ajax.prototype._dataURL = "default.txt";

  //var to hold an instance of the XMLHTTPRequest object
  Ajax.prototype._request = undefined;

  //ID for the html div we will create to display the data
  Ajax.prototype._containerID = null;

  // Default content as a parameter for ::send()
  Ajax.prototype._content=null;

  //name of the css class for the HTML container
//  Ajax.prototype._containerClass = "ml_container";


  // *** PUBLIC METHODS

  Ajax.prototype.retrieve = function(url,method,content)
  {
    //get a new XMLHTTPRequest and store it in an instance var.
    this._request = this._getRequest();

    //set the var so we can scope the callback
    var _this = this;

    if(url != undefined) {
      this._dataURL = url;
    }
    if (method!=undefined) {
      this._method=method;
    }
    if (content!=undefined) {
      this._content=content;
    }
    //callback will be an anonymous function that calls back into our class
    //this allows the call back in which we handle the response (_onData())
    // to have the correct scope.
    this._request.onreadystatechange = function(){_this._readystatechange()};
    this._request.open(this._getMethod(), this._getUrl(), true);
//     alert(this._getSendContent());
    this._request.send(this._getSendContent());
  }

  // *** PRIVATE METHODS

  // The default handler for a successfull request

  Ajax.prototype._handleFinished = function(content)
  {
  //	var content = document.getElementById(this._containerID);
  //		content.appendChild(document.createTextNode(title));
    this.checkLoginPage(content);
    if (this._containerID!=null) {
      try {
        document.getElementById(this._containerID).innerHTML=content;
      } catch (e) {
//         alert("Warning: Invalid container id in the Ajax object. Note that it should be the ID of an existing DOM element, which supports the innerHTML property.Terminaing script.");
      }
      this.executeJS();
      this.removeStylesheets();
    } else {
      alert("Ajax.prototype._handleFinished:\n You are using the default handler for rendering the response, but haven't specified an ID for the destination container.");
    }
  }

  // The default handler for the 'loading' state

  Ajax.prototype._handleLoading=function()
  {
    if (!this.loadingTab) {
      this.loadingTab=document.createElement("DIV");
      this.loadingTab.id="_Ajax_loading_"+this._containerID;
      this.loadingTab.innerHTML="Loading";
      this.loadingTab.style.cssText="position:absolute;top:"+parseInt(getScrollY()+3)+"px;right:"+parseInt(getScrollX()+3)+"px;color:red;background:#EEEEEE;width:6em;padding-left:5px;";
      document.body.appendChild(this.loadingTab);
      // Suspension points
      this.loadingTab.addSuspensionPoints=function(loadingTabId) {
        var loadingTab=document.getElementById(loadingTabId);
        if (loadingTab.dotCounter == undefined || loadingTab.dotCounter==3) {
          loadingTab.dotCounter=0;
          loadingTab.innerHTML='Loading';
        }
        loadingTab.innerHTML+=".";
        loadingTab.dotCounter++;
        loadingTab.timeoutHolder=setTimeout("document.getElementById('"+loadingTabId+"').addSuspensionPoints('"+loadingTabId+"')",200);
      }
      this.loadingTab.addSuspensionPoints(this.loadingTab.id);
  //     this.loadingTabId=loadingTab.id;
    }
  }

  // The default handler for the 'loaded' state

  Ajax.prototype._handleLoaded=function()
  {
    clearTimeout(this._getLoadingTab().timeoutHolder);
    document.body.removeChild(this._getLoadingTab());
    delete this.loadingTab;
  }



  // *** INSIDE GETTERS

  //returns an XMLHTTPRequest instance (based on browser)

  Ajax.prototype._getRequest = function() {
    var xmlHttp;
    try {
      xmlHttp = new ActiveXObject("Msxml2.XMLHttp");
    }
    catch(e) {
      try {
        xmlHttp = new ActiveXObject("Microsoft.XMLHttp");
      }
      catch(e2) {
        // Not much we can say here...
      }
    }

    if(xmlHttp == undefined && (typeof XMLHttpRequest != 'undefined')) {
      xmlHttp = new XMLHttpRequest();
    }

    if (!xmlHttp) {
      alert("Critical error. Your browser does not have the XMLHttpRequest object implemented. Consider upgrading your browser to Firefox 1.x+ / Internet Explorer 5.x+");
    }

    return xmlHttp;
  }

  //return the URL from which the data will be loaded
  Ajax.prototype._getUrl = function()
  {
    return this._dataURL;
  }

  // return the request method
  Ajax.prototype._getMethod=function()
  {
    return this._method;
  }

  // return the DOM object that says Loading...
  Ajax.prototype._getLoadingTab=function()
  {
    return this.loadingTab;
  }

  Ajax.prototype._getSendContent=function()
  {
    return this._content;
  }


  // callback for when the XMLHttpRequest object changes status

  Ajax.prototype._readystatechange = function()
  {
    if(this._request.readyState == 4) {
      if(this._request.status == "200") {
        this._handleFinished(this._request.responseText);

        if(this.onFinish != undefined) {
          this.onFinish();
        }
      } else {
        //check if an error callback handler has been defined

/*        if(this.onError != undefined) {
          //pass an object to the callback handler with info
          //about the error
          this.onError({status:this_request.status,
              statusText:this._request.statusText});
        }*/
      }
      //clean up
      delete this._request;

    } else if (this._request.readyState==1) {
      this._handleLoading();
    } else if (this._request.readyState==2) {
      this._handleLoaded();
    }
  }

  // Other useful functions

  Ajax.prototype.checkLoginPage=function(content)
  {
    if (content.match(/<title>(.+)Login(.*)<\/title>/im)) {
      window.location=window.location;
      // Insert any kind script-terminating statement below
      error;
    }
  }

  Ajax.prototype.executeJS=function()
  {
  	//     alert("getting here");
  	//if (containerId==undefined) {
  	  containerId=this._containerID;
  	//}
  	var tags=document.getElementById(containerId).getElementsByTagName('SCRIPT');
  	var bSaf = (navigator.userAgent.indexOf('Safari') != -1);
  	var bOpera = (navigator.userAgent.indexOf('Opera') != -1);
  	var bMoz = (navigator.appName == 'Netscape');
  	var strExec;
  	//     alert(tags.length);
  	head=document.getElementsByTagName('HEAD')[0];
  	var allScriptTags=head.getElementsByTagName('SCRIPT');
  	for(var i=0;i<tags.length; i++) {
  		if (bSaf) {
  			strExec = tags[i].innerHTML;
  		}
  		else if (bOpera) {
  			strExec = tags[i].text;
  		}
  		else if (bMoz) {
  			strExec = tags[i].textContent;
  		}
  		else {
  			strExec = tags[i].text;
  		}
  		try {
  			       //console.log(tags[i]);
//  			       alert("Evaluating "+strExec);
  			scriptTag=document.createElement("SCRIPT");
  			alreadyHaveIt=false;
  			if (strExec) {
  				//         eval(strExec);
  				if (bSaf) {
  					scriptTag.innerHTML = strExec;
  				}
  				else if (bOpera) {
  					scriptTag.text=strExec;
  				}
  				else if (bMoz) {
  					scriptTag.textContent=strExec;
  				} else {
  					scriptTag.text=strExec;
  				}
  				//         head=document.getElementsByTagName('head').item(0);

  				//         console.log(tags[i])
  				//         if (!document.getElementById(tags[i].id)) {
  				//         alert('aha'+tags[i].src);
  				//           head.appendChild(scriptTag);
  				//         alert(scriptTag.textContent);
  				//         }
  			} else {
  				for (j=0;j<allScriptTags.length;j++) {
  					if (allScriptTags[j].id && allScriptTags[j].id==tags[i].id) {
  						alreadyHaveIt=true;
  						break;
  					}
  				}
  				scriptTag.setAttribute("id",tags[i].id);
  				scriptTag.setAttribute("src",tags[i].src);
//  				scriptTag.onload=function() {alert("I'm DONE "+this.src);}
  				//         alert(alreadyHaveIt+" "+tags[i].id);
  			}

  			if (!alreadyHaveIt) {
  				head=document.getElementsByTagName('HEAD').item(0);
  		    head.appendChild(scriptTag);

//  				console.log(scriptTag);
  			}
  		} catch(e) {
  			alert("In Ajax::executeJS():\n"+e.message);
  		}
  	}
  	return(strExec);
//
//
////     alert("getting here");
//    var tags=document.getElementById(this._containerID).getElementsByTagName('SCRIPT');
//    var bSaf = (navigator.userAgent.indexOf('Safari') != -1);
//    var bOpera = (navigator.userAgent.indexOf('Opera') != -1);
//    var bMoz = (navigator.appName == 'Netscape');
//    var strExec;
////     alert(tags.length);
//    for(var i=0;i<tags.length; i++) {
//      if (bSaf) {
//        strExec = tags[i].innerHTML;
//      }
//      else if (bOpera) {
//        strExec = tags[i].text;
//      }
//      else if (bMoz) {
//        strExec = tags[i].textContent;
//      }
//      else {
//        strExec = tags[i].text;
//      }
//     try {
//       eval(strExec);
//     } catch(e) {
//       alert("In Ajax::executeJS():\n"+e);
//     }
//    }
//    return(strExec);
  }

  Ajax.prototype.removeStylesheets=function()
  {
    var tags=document.getElementById(this._containerID).getElementsByTagName('link');
    for (i=0;i<tags.length;i++) {
      if (tags[i].rel.toUpperCase()=='STYLESHEET') {
        tags[i].parentNode.removeChild(tags[i]);
      }
    }
  }

  // A few helpful functions

  if (typeof getScrollX!='function') {
    function getScrollX()
    {
      var scrOfX = 0, scrOfY = 0;
      if (typeof( window.pageYOffset ) == 'number' ) {
        //Netscape compliant
        scrOfX = window.pageXOffset;
      } else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
        //DOM compliant
        scrOfX = document.body.scrollLeft;
      } else if( document.documentElement &&
          ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
        //IE6 standards compliant mode
        scrOfX = document.documentElement.scrollLeft;
      }
      return(scrOfX);
    }
  }

  if (typeof getScrollY!='function') {
    function getScrollY()
    {
      var scrOfX = 0, scrOfY = 0;
      if (typeof( window.pageYOffset ) == 'number' ) {
        //Netscape compliant
        scrOfY = window.pageYOffset;
      } else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
        //DOM compliant
        scrOfY = document.body.scrollTop;
      } else if( document.documentElement &&
          ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
        //IE6 standards compliant mode
        scrOfY = document.documentElement.scrollTop;
      }
      return(scrOfY);
    }
  }

  function writeCookie(name, value, hours)
  {
     var expire = "";
     if(hours != null)
     {
       expire = new Date((new Date()).getTime() + hours * 3600000);
       expire = "; expires=" + expire.toGMTString();
     }
     cookieData=name + "=" + escape(value) + expire + '; path=/';
     document.cookie = cookieData;
  }

  function readCookie(name)
  {
     var cookieValue = "";
     var search = name + "=";
     if(document.cookie.length > 0)
     {
       offset = document.cookie.indexOf(search);
       if (offset != -1)
       {
         offset += search.length;
         end = document.cookie.indexOf(";", offset);
         if (end == -1) end = document.cookie.length;
         cookieValue = unescape(document.cookie.substring(offset, end))
       }
     }
     return cookieValue;
  }

