      // IE doesn't have prototypes for nodes or elements, so we
      // have no choice but to attach all our methods right to Object.
      // Sucky.
      Gogo = { };

      Gogo.listenEvent = function(elm, ev, fn)
      {
        if(elm.addEventListener)
        {
          elm.addEventListener(ev,  fn , false);
        }
        else if(elm.attachEvent)
        {
          elm.attachEvent('on' + ev,  fn , false);
        }
      }
      Gogo.listen = Gogo.listenEvent;

      Gogo.triggerEvent = function(elm, ev)
      {
        if(elm.dispatchEvent)
        {
          var event = document.createEvent('HTMLEvents');
          event.initEvent(ev, true, true);
          elm.dispatchEvent(event);
        }
        else if(elm.fireEvent)
        {
          elm.fireEvent('on' + ev);
        }
      }
      Gogo.trigger = Gogo.triggerEvent;

      Gogo.getElementsByClassName =
        function(className)
        {
          function _gEBCN_xPath(needle)
          {
            var xpathResult = document.evaluate('//*[contains(@class = needle)]', document, null, 0, null);
            var outArray = new Array();
            while ((outArray[outArray.length] = xpathResult.iterateNext()))
            {
              alert(outArray[outArray.length - 1]);
            }
            return outArray;
          }

          function _gEBCN_treeWalker(needle)
          {
            needle = new RegExp('(^| )' + needle + '( |$)');

            function acceptNode(node)
            {
              if (node.hasAttribute("class"))
              {
                 if (node.className.match(needle))
                   return NodeFilter.FILTER_ACCEPT;
              }
              return NodeFilter.FILTER_SKIP;
            }

            var treeWalker = document.createTreeWalker(document.documentElement,
                                                       NodeFilter.SHOW_ELEMENT,
                                                       acceptNode,
                                                       true);
            var outArray = new Array();
            var node = treeWalker.nextNode();
            while (node) {
              outArray.push(node);
              node = treeWalker.nextNode();
            }

            return outArray;
          }

          function _gEBCN_domScan(needle)
          {
            needle = new RegExp('(^| )' + needle + '( |$)');

            function _GetElementsByClass(outArray, seed, needle)
            {
              while (seed) {
                if (seed.nodeType == Node.ELEMENT_NODE) {
                  if (seed.hasAttribute("class"))
                  {
                    if (node.className.match(needle))
                      outArray.push(seed);
                  }
                  _GetElementsByClass(outArray, seed.firstChild, needle)
                }
                seed = seed.nextSibling;
              }
            }

            var outArray = new Array();
            _GetElementsByClass(outArray, document.documentElement, needle);
            return outArray;
          }

          function _geBCN_lastResort(needle)
          {
            var         my_array = document.all ? document.all : document.getElementsByTagName("*");
            var         retvalue = new Array();
            var        i;
            var        j;

            for (i = 0, j = 0; i < my_array.length; i++)
            {
              var c = " " + my_array[i].className + " ";
              if (c.indexOf(" " + needle + " ") != -1)
                retvalue[j++] = my_array[i];
            }
            return retvalue;
          }

          // Try treeWalker first this should work in gecko
          try
          {
            return _gEBCN_treeWalker(className);
          }
          catch(e)
          {

          }

          // try xPath next, this should work in IE
          try
          {
            return _gEBCN_xPath(className);
          }
          catch(e)
          {

          }


          // if those fail, try traversing the dom manually
          try
          {
            return _gEBCN_domScan(className);
          }
          catch(e)
          {

          }

          // and if that fails then get all tags and check for ones with the right classname
          return _geBCN_lastResort(className);
        }

      Gogo.getElementsByTagAndClass =
        function(tag, className, beneath)
        {
          if(typeof beneath == 'undefined') beneath = typeof this != undefined ? this : document;

          var re = new RegExp('(^| )' + className + '( |$)');
          var ret = new Array();
          var elms = new Array();
          if(tag.match(','))
          {
            var tags = tag.split(',');
            for(var y = 0; y < tags.length; y++)
            {
              var tagelms = beneath.getElementsByTagName(tags[y]);
              for(var i = 0; i < tagelms.length; i++)
              {
                elms[elms.length] = tagelms[i];
              }
            }
          }
          else
          {
            elms = beneath.getElementsByTagName(tag);
          }

          for(var x = 0; x < elms.length; x++)
          {
            if(elms[x].className && elms[x].className.match(re)) ret[ret.length] = elms[x];
          }
          return ret;
        }

      Gogo.dumpVariable = function(v)
      {
        var w = window.open('about:blank', 'dbgwin', 'width=320,height=260');
        if(w)
        {
          w.document.open('text/html');
          w.document.write('<html><body><textarea id="x" style="width:100%;height:240px;"></textarea></body></html>');
          w.document.close();
          var ta = w.document.getElementById('x');

          for(var i in v)
          {
            ta.value += i + ': ' + v[i] + '\n';
          }
        }
      }


      if(typeof window.dump == 'undefined')
        window.dump       = Gogo.dumpVariable;
      
      if(typeof window.listen == 'undefined')
        window.listen     = Gogo.listenEvent;
      
      if(typeof window.trigger == 'undefined')
        window.trigger    = Gogo.triggerEvent;
      
      if(typeof window.add_onload == 'undefined')
        window.add_onload = function(fn)
          {
            if(typeof window._gogo_loadStack == 'undefined')
            {
              window._gogo_loadStack = [ ];
              var _execute_loadStack = function(event)
              {
                for(var i = 0; i < window._gogo_loadStack.length; i++)
                {
                  window._gogo_loadStack[i](event);
                }
              }
              window.listen(window, 'load', _execute_loadStack);
            }
            window._gogo_loadStack[window._gogo_loadStack.length] = fn;
          }

      Gogo.stack_dom0_event = function(el, ev, fn)
      {
        if(typeof el['_gogo_'+ev+'Stack'] == 'undefined')
        {
          el['_gogo_'+ev+'Stack'] = [ ];
          if(typeof el['on'+ev] == 'function')
          {
            el['_gogo_'+ev+'Stack'][el['_gogo_'+ev+'Stack'].length] = el['on'+ev];            
          }
          
          el['on'+ev] = function(event)
          {
            for(var i = 0; i < el['_gogo_'+ev+'Stack'].length; i++)
            {
              if(el['_gogo_'+ev+'Stack'][i](event)) continue;              
              return false;
            }
            return true;
          }
        }
        el['_gogo_'+ev+'Stack'][el['_gogo_'+ev+'Stack'].length] = fn;
      }
          
      if(typeof(document.getElementsByClassName) == 'undefined')
      {
        document.getElementsByClassName = Gogo.getElementsByClassName;
      }

      if(typeof document.getElementsByTagAndClass == 'undefined')
      {
        document.getElementsByTagAndClass = Gogo.getElementsByTagAndClass;
      }

      Gogo.get_url_content = function(url, handler)
      {
        var req = null;
        if(typeof ActiveXObject != 'undefined')
        {
         req = new ActiveXObject("Microsoft.XMLHTTP");
        }
        else
        {
         req = new XMLHttpRequest();
        }

        if(handler)
        {
          function callBack()
          {
            if(req.readyState == 4)
            {
              if(req.status == 200 || req.status == 304)
              {
                handler(req.responseText, req);
              }
              else
              {
               // alert('An error has occurred: ' + req.status);
              }
            }
          }

          req.onreadystatechange = callBack;
          req.open('GET', url, true);
          req.send(null);
        }
        else
        {
          req.open('GET', url, false);
          req.send(null);
          if(req.status == 200)
          {
            return req.responseText;
          }
          else
          {
            return '';
          }
        }
      }

      Gogo.postback = function(url, data, handler)
      {
        var req = null;
        if(typeof ActiveXObject != 'undefined')
        {
         req = new ActiveXObject("Microsoft.XMLHTTP");
        }
        else
        {
         req = new XMLHttpRequest();
        }
      
        var content = '';
        for(var i in data)
        {
          content += (content.length ? '&' : '') + i + '=' + encodeURIComponent(data[i]);
        }
      
        if(handler)
        {
          function callBack()
          {
            if(req.readyState == 4)
            {
              if(req.status == 200 || req.status == 304)
              {
                if(typeof handler == 'function')
                handler(req.responseText, req);
              }
              else
              {
               // alert('An error has occurred: ' + req.status);
              }
            }
          }
        
          req.onreadystatechange = callBack;
        }
        
        req.open('POST', url, true);
        req.setRequestHeader
        (
            'Content-Type',
            'application/x-www-form-urlencoded; charset=UTF-8'
        );

        req.send(content);
      }

      Gogo.emptySelect = function(select)
      {
        for(var x = select.options.length - 1; x >= 0; x--)
        {
          select.options[x] = null;
        }
      }
      
      Gogo.previousElement = function(elm)
      {
        if(!elm.previousSibling) return null;
        if(elm.previousSibling.nodeType == 1) return elm.previousSibling;
        return Gogo.previousElement(elm.previousSibling);
      }
      
      Gogo.nextElement = function(elm)
      {
        if(!elm.nextSibling) return null;
        if(elm.nextSibling.nodeType == 1) return elm.nextSibling;
        return Gogo.nextElement(elm.nextSibling);
      }
      
      /*
      try
      {
        Element.prototype.listen = Gogo.listenEvent;
        Element.prototype.trigger = Gogo.triggerEvent;
      }
      catch(e)
      {
        //alert('TRY THIS');
        window.add_onload(function () {
          var allTags = document.all ? document.all : document.getElementsByTagName('*');
          for(var i = 0; i < allTags.length; i++)
          {
            var Element = allTags[i];
            Element.listen  = Gogo.listenEvent;
            Element.trigger = Gogo.triggerEvent;
          }

          // IE doesn't have Element, or even Node!
          document.ieSucksCreateElement = document.createElement;
          document.createElement = function(el)
          {
            var Element = this.ieSucksCreateElement(el);
            if(Element)
            {
              Element.listen  = Gogo.listenEvent;
              Element.trigger = Gogo.triggerEvent;
            }
            return Element;
          }
        });
      }
      */
      

/** 
 * Position a given layer (absolute positioned element) near the given element, with the given options.
 *
 * Pretty much ripped from jscalendar.
 */      
 
Gogo.positionLayerAtElement = function (layer, el, opts) 
{
  var getAbsolutePos = function(el) 
  {
    var SL = 0, ST = 0;
    var is_div = /^div$/i.test(el.tagName);
    if (is_div && el.scrollLeft)
      SL = el.scrollLeft;
    if (is_div && el.scrollTop)
      ST = el.scrollTop;
    var r = { x: el.offsetLeft - SL, y: el.offsetTop - ST };
    if (el.offsetParent) {
      var tmp = getAbsolutePos(el.offsetParent);
      r.x += tmp.x;
      r.y += tmp.y;
    }
    return r;
  }
  
	var p = getAbsolutePos(el);
  
	if (!opts || typeof opts != "string") {  
    var s = layer.style;
    s.left = p.x + "px";
    s.top =  p.y + el.offsetHeight + "px";		
		return true;
	}
  
	function fixPosition(box) 
  {
		if (box.x < 0)
			box.x = 0;
		if (box.y < 0)
			box.y = 0;
		var cp = document.createElement("div");
		var s = cp.style;
		s.position = "absolute";
		s.right = s.bottom = s.width = s.height = "0px";
		document.body.appendChild(cp);
		var br = Calendar.getAbsolutePos(cp);
		document.body.removeChild(cp);
		if (typeof document.body.scrollTop != 'undefined') { // Was Calendar.is_ie
			br.y += document.body.scrollTop;
			br.x += document.body.scrollLeft;
		} else {
			br.y += window.scrollY;
			br.x += window.scrollX;
		}
		var tmp = box.x + box.width - br.x;
		if (tmp > 0) box.x -= tmp;
		tmp = box.y + box.height - br.y;
		if (tmp > 0) box.y -= tmp;
	}
  
	Calendar.continuation_for_the_fucking_khtml_browser = function() {
		var w = layer.offsetWidth;
		var h = layer.offsetHeight;
		
		var valign = opts.substr(0, 1);
		var halign = "l";
		if (opts.length > 1) {
			halign = opts.substr(1, 1);
		}
		// vertical alignment
		switch (valign) {
		    case "T": p.y -= h; break;
		    case "B": p.y += el.offsetHeight; break;
		    case "C": p.y += (el.offsetHeight - h) / 2; break;
		    case "t": p.y += el.offsetHeight - h; break;
		    case "b": break; // already there
		}
		// horizontal alignment
		switch (halign) {
		    case "L": p.x -= w; break;
		    case "R": p.x += el.offsetWidth; break;
		    case "C": p.x += (el.offsetWidth - w) / 2; break;
		    case "l": p.x += el.offsetWidth - w; break;
		    case "r": break; // already there
		}
		p.width = w;
		p.height = h + 40;		
    
		fixPosition(p);
    layer.style.left = p.x + "px";
    layer.style.top =  p.y + "px";				
	};
  
	if (/Konqueror|Safari|KHTML/i.test(navigator.userAgent))
		setTimeout("Calendar.continuation_for_the_fucking_khtml_browser()", 10);
	else
		Calendar.continuation_for_the_fucking_khtml_browser();
};

Gogo.setCookie = function(cookieName,cookieValue,nDays) 
{
 var today = new Date();
 var expire = new Date();
 if (nDays==null || nDays==0) nDays=1;
 expire.setTime(today.getTime() + 3600000*24*nDays);
 document.cookie = cookieName+"="+escape(cookieValue)
                 + ";expires="+expire.toGMTString();
}

Gogo.getCookie = function(cookieName) 
{
 var theCookie=""+document.cookie;
 var ind=theCookie.indexOf(cookieName);
 if (ind==-1 || cookieName=="") return ""; 
 var ind1=theCookie.indexOf(';',ind);
 if (ind1==-1) ind1=theCookie.length; 
 return unescape(theCookie.substring(ind+cookieName.length+1,ind1));
}
