      var Gogo = 
      {                
        load_chainers: { }, 
            
        /** Load a  .js/.css or image file, with chaining.
         *
         *  Used primarily as a "require_once" type of deal for javascript
         *  files.  If you call "load" (or "then_load") multiple times
         *  for one file it will only be loaded once.  But all "execute" 
         *  (or "then_execute") events will be called, even if they are 
         *  attached after the file is loaded.
         *         
         * Example:
         *  Gogo.load('foo.js')
         *      .then_load('bla.js')         
         *      .then_execute(function() { alert('done'); })
         *      .then_load('some_image.jpg')
         *      .then_execute(function(theImg) { document.body.appendChild(theImg); })
         *      .then_load('narf.css');
         *
         * More realistic example:
         *
         *  function do_something() { alert('Both js and css are loaded now.'); }
         *
         *  Gogo.load('Example.js')         
         *      .execute(do_something)
         *      .load('Example.css');
         *     
         * @param string Url of the resourse to load.
         * @param string Mimetype (optional, will guess at it based on file extention otherwise)
         * @param boolean If the load should start.  If false, then you must call the "start" 
         *   method on the object which is returned by the load method.
         *
         */
         
        load: function(url, type, delay)
        {
          if(typeof this.load_chainers[url] == 'undefined')
          {
            this.load_chainers[url] = 
            {
              element     : null ,
              nowLoaded   : false,
              stackRunTo  : 0    ,
              onLoadStack : [ ]  ,
              
              // Chain an include
              //  Gogo.load('somescript.js').load('someother.js')
              load: function(url, type)
              {
                var nextChain = Gogo.load(url,type,true);
                this.onLoadStack[this.onLoadStack.length] = 
                  function() 
                  { 
                    nextChain.start();
                    return true;
                  }
                  
                return nextChain;
              },
              
              execute: function(fn,scope,bonus)
              {
                this.onLoadStack[this.onLoadStack.length] = function() { var retval = fn.call(scope,bonus); return (typeof retval == 'undefined') ? true : retval; }
                this.run_stack();
                
                return this;
              },
              
              // Syntactic sugar
              then_load:    function(url) { return this.load(url); } ,              
              then_execute: function(fn,scope,bonus) { return this.execute(fn,scope,bonus); } ,
              
              run_stack: function()
              {
                if(!this.nowLoaded) 
                {
                  return false;
                }
                
                for( ; this.stackRunTo < this.onLoadStack.length ; )
                {
                  this.stackRunTo++;
                  if(!this.onLoadStack[this.stackRunTo-1](this.element)) 
                  {                    
                    return false;
                  }
                }
                
                return true;
              },
              
              start: function() 
              {                  
                  if(!type)
                  {
                    switch(url.replace(/.*\./, '').toLowerCase())
                    {
                      case 'js' : type = 'text/javascript'; break;
                      case 'css': type = 'text/css';        break;
                      case 'jpg': type = 'image/jpeg';      break;
                      case 'gif': type = 'image/gif';       break;
                      case 'png': type = 'image/png';       break;
                      default   : type = 'text/javascript'; break;
                    }
                  }
                 
                  if(type == 'text/javascript' && navigator.appVersion.toLowerCase().indexOf("webkit"))
                  { // Safari is stupid and doesn't fire onload/readystatechange events on dynamic script
                    // so we have to do it by ajax, be warned, with this it means Safari cannot load an 
                    // external script :-(                                          
                    Gogo.GET(url, 
                             function(responseText) 
                             {                                                                
                               window.setTimeout(responseText + "; Gogo.load_chainers['"+url+"'].nowLoaded = true;  Gogo.load_chainers['"+url+"'].run_stack();" , 0);                                
                             }
                            );
                  }
                  else
                  {
                    var scope    = this;
                    var callback = function() { scope.nowLoaded = true; scope.run_stack(); }
             
                    var s;
                    switch(type)
                    {
                      case 'text/javascript':
                        s = document.createElement("script");
                        s.type = "text/javascript";
                        s.src = url;     
                        break;
                        
                      case 'text/css':
                        s = document.createElement('link');
                        s.rel   = 'stylesheet';
                        s.type  = 'text/css';              
                        s.href  = url;       
                        break;
                        
                      default:
                        s = new Image();
                        s.src = url;                
                        break;
                    }
          
                    scope.element        = s;
                    
                    // Moz etc
                    s.onload             = function() { callback.call(scope); s.onload = null; }
                    
                    // IE etc
                    s.onreadystatechange = function()
                    {              
                      if(!(/loaded|complete/.test(s.readyState))) 
                      {
                        return;
                      }
                      s.onload();
                      s.onreadystatechange = null;
                    }
        
                    if(type.match(/javascript|css/))
                    {                    
                      document.getElementsByTagName("head")[0].appendChild(s);
                      
                      // dynamic css inclusion does not fire an event in some browsers
                      // so we'll force it in 1 second, it won't matter if it's not 
                      // loaded in the majority of cases since CSS is basically
                      // load-and-forget anyway
                      if(type.match(/css/))
                      {
                        window.setTimeout(callback, 1000);
                      }
                    }
                  }
              }                            
            }
            if(!delay) this.load_chainers[url].start();
          }
          
          return this.load_chainers[url];
        }
      
        
      }

      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.addOnLoad = function(fn) { window.add_onload(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 =
      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 if (req.status == 0)
              {
                return;
              }
              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.POST =
      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 if (req.status == 0)
              {
                return;
              }
              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'
        );

        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);
      }
      
      Gogo.firstChildElement = function(elm)
      {
        var firstChild = elm.firstChild;
        if(elm && elm.nodeType != 1) return Gogo.nextElement(elm);
        return elm;
      }
      
      /*
      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));
}

    Gogo.unrealPath = function(url)
    {
        var proto = '';    
        if(url.match(/^([a-z]+\/\/)(.*)$/))
        {
          proto = RegExp.$1;
          url   = RegExp.$2;
        }
        
        if(!url.length)
        {
          return proto;
        }
    
        var qs = '';
        if(url.match(/^([^?]*)(\?.*)$/))
        {
          url = RegExp.$1;
          qs = RegExp.$2;
        }
    
        var parts = url.split('/');
        
        var leader = (url.match(new RegExp('^/')) ? true : false);
        var closer = (url.match(new RegExp('/$')) ? true : false);
    
        url = [ ];
        for(var i = 0; i < parts.length; i++)
        {
          var part = parts[i];
          if(!part.length || part == '.')
          {
            continue;
          }
    
          if(part == '..' )
          {
            if(url.length && url[url.length-1] != '..')
            {
              url.length = url.length-1;
            }
            else
            {
              url[url.length] = '..';
            }
            continue;
          }
    
          url[url.length] = part;
        }
    
        url = url.join('/');
        if(leader) url = '/' + url;
        if(closer) url = url + '/';
        return proto + url + qs;
    }
    
    Gogo.addClassToOwnAnchor = function(className)
    {            
      var anchors  = document.getElementsByTagName('a');
      
      //   var prefixer = document.location.pathname;
      //   prefixer = prefixer.replace(/\/[^\/]*$/, '/');
      //   if(!prefixer.match(/\/$/))
      //   {
      //     // We must be a file in the root
      //     prefixer = '/';
      //   }
      //   
      //   var compareTo = document.location.href.replace(/^[a-z]+:\/\/[^/]+/, '');
      //   var d = '';
      
      for(var i = 0; i < anchors.length; i++)
      {
        // Apparently, this is sufficient.  Tidy.
        if(anchors[i].href == document.location.href)
        {
          anchors[i].className += ' ' + className;          
        }
        continue;
        
        // ========= BELOW HERE NOT NEEDED, WE JUST HAVE TO TEST THE ABOVE 
        // ========= KEEPING IT ANYWAY JUST IN CASE SOME BROWSER CAUSES A PROBLEM
        // ========= IN THE FUTURE
        
        //  var a = anchors[i];
        //  
        //  var href = a.getAttribute('href');
        //
        //  if(a.href.match(/^#/))
        //  {
        //    // Shortcut this
        //    a.className += ' ' + className;
        //    continue;
        //  }
        //  
        //  // Are we on this server
        //  if(href.match(/^[a-z]:\/\/([^\/:]+)/i))
        //  {
        //    if(document.location.hostname.toLowerCase() != (RegExp.$1).toLowerCase())
        //    {
        //      continue;
        //    }
        //    
        //    href = href.replace(/^[a-z]:\/\/([^\/:]+)/i, '');
        //  }
        //  
        //  // is it relative to here,
        //  if(!href.match(/^\//))
        //  {
        //    // Yes, make it unrelative
        //    href = Gogo.unrealPath(prefixer+href);
        //  }
        //  
        //  // Ok, at this point, we should be able to test for sameness
        //  d += href + '\n';
        //  if(compareTo == href)
        //  {
        //    a.className += ' ' + className;
        //  }
      }
            
    }
  