// Pragmeta Menu System, 1.0d
// October-November 2002 by rds
//
// See containing page for details.

var reject_browsers = [ "amaya", "arena", "cyberdog", "dillo", "galeon", "hotjava", "icab", "konquerer", "links", "lynx", "mosiac", "nautilus", "netpositive", "webtv" ];

var _browser = 0;       // "Netscape", "IE", "Opera", etc.
var _version = 0;       // Integer for major version number.
var _revision = 0;      // String for revision.

// CREATION //////////////////////////////////////////////////////////////////////////////////////

var _menus = [];        // Store all added menus in this array.
var _temp = [];         // All generic global variables.

// int _contemplate_menu(*menu, int recurse);
//
// The first pass in building a menu.  This will create and position the base menu element, then
// recursively filter down through all of the subelements and calculate their inheritances.  It
// also sets some tags for later use.
//
// Returns 1 for success.  On error, it will try to go to the sitemap, or at least write a nice
// error message (alert).  Returns 0 in these cases, although if it successfully moves to the
// sitemap, current thread execution will cease.

function _contemplate_menu(menu, recurse)
{
  if(!recurse) {                                      // Base menu element; check data and set defaults.
    if(!document.layers) {
      menu.base = document.createElement("div");
      menu.base.style.position = "absolute";
    }
    else menu.base = new Layer(0);                    // Netscape 4.x takes an entirely different route.
    menu.element = 0;
    if(!menu.name)
      menu.name = "Menu base";
    if(!menu.left)
      menu.left = 0;
    if(!menu.top)
      menu.top = 0;
    if(!menu.anchor)
      menu.anchor = "top";
    else if(_member(menu.anchor, [ "top", "bottom", "left", "right" ]) == -1) {  // We're anchoring to an element.
      var anchor = 0;
      if(!document.layers) {
        if(!(anchor = _find_anchor(menu.anchor))) {
          if(!_debug("Could not find element '" + menu.anchor + "'!  Cannot anchor menu " + menu.name + ".", [ "#000000", "#ff0000" ])) {
            if(menu.sitemap)
              window.location.href = menu.sitemap;
            else alert("Internal anchoring error; menus are disabled.");
          }
          return(0);
        }
      }
      else if(!(anchor = _find_anchor(menu.anchor))) {
        if(!_debug("Could not find layer '" + menu.anchor + "'!  Cannot anchor menu " + menu.name + ".", [ "#000000", "#ff0000" ])) {
          if(menu.sitemap)
            window.location.href = menu.sitemap;
          else alert("Internal anchoring error; menus are disabled.");
        }
        return(0);
      }
      menu.anchor = anchor;
      menu.offset_left = _offsetLeft(anchor);
      menu.offset_top = _offsetTop(anchor);
      if(window.onresize != _reanchor_menus) {        // Put a hook into window.onresize.
        _temp.onresize = window.onresize;
        window.onresize = _reanchor_menus;
      }
    }
    if(!document.layers) {
      menu.base.style.left = (menu.left + (menu.offset_left?menu.offset_left:0)) + "px";
      menu.base.style.top = (menu.top + (menu.offset_top?menu.offset_top:0)) + "px";
      document.body.appendChild(menu.base);
    }
    else {
      menu.base.left = menu.left + (menu.offset_left?menu.offset_left:0);
      menu.base.top = menu.top + (menu.offset_top?menu.offset_top:0);
    }
  }
  else {                                              // Menu element; check data and set defaults.
    if(!menu.name)
      menu.name = "<unnamed>";
    menu.base = 0;
    menu.element = 1;
  }
  if(menu.elements) {                                 // Process menu elements (children).
    for(var i = 0; i < menu.elements.length; i++) {
      if(!menu.elements[i]) {                         // Remove empty element entries (caused by trailing commas).
        menu.elements.splice(i--, 1);
        continue;
      }
      menu.elements[i].parent = menu;                 // Allow our children to refer to us directly.
      menu.elements[i].previous = i?menu.elements[i - 1]:menu; // Point to previous element in menu heirarchy.
                                                      // This is used to calculate incremental positioning.
      if(menu.elements[i].width == null)              // If dimensions are not explicitly set, allow inheritance.
        menu.elements[i].width = menu.elements[i].previous.width;
      if(menu.elements[i].height == null)
        menu.elements[i].height = menu.elements[i].previous.height;
      if(menu.elements[i].image == null) {
        menu.elements[i].image = menu.elements[i].previous.image;
        if(menu.elements[i].alt_image == null)        // Only inherit if main setting inherited.
          menu.elements[i].alt_image = menu.elements[i].previous.alt_image;
      }
      if(menu.elements[i].background == null) {
        menu.elements[i].background = menu.elements[i].previous.background;
        if(menu.elements[i].alt_background == null)
          menu.elements[i].alt_background = menu.elements[i].previous.alt_background;
      }
      if(menu.elements[i].bgcolor == null) {
        menu.elements[i].bgcolor = menu.elements[i].previous.bgcolor;
        if(menu.elements[i].alt_bgcolor == null)
          menu.elements[i].alt_bgcolor = menu.elements[i].previous.alt_bgcolor;
      }
      if(menu.elements[i].fade == null)
        menu.elements[i].fade = menu.elements[i].previous.fade;
      if(menu.elements[i].cursor == null)
        menu.elements[i].cursor = menu.elements[i].previous.cursor;
      else if(menu.elements[i].cursor == "pointer" && _browser == "IE" && _version == 5 && _revision == 0)
        menu.elements[i].cursor = "hand";             // Correct for proprietary setting.
      if(menu.elements[i].left == null)
        menu.elements[i].left = 0;
      if(menu.elements[i].top == null)
        menu.elements[i].top = 0;
      if(menu.elements[i].anchor == null)
        menu.elements[i].anchor = (typeof(menu.elements[i].previous.anchor) == "object")?"top":menu.elements[i].previous.anchor;
      if(menu.elements[i].arrows == null)
        menu.elements[i].arrows = menu.elements[i].previous.arrows;
      if(menu.elements[i].force_arrows == null && menu.base)
        menu.elements[i].force_arrows = menu.elements[i].previous.force_arrows;
      if(!_contemplate_menu(menu.elements[i], 1))     // Recurse.
        return(0);
    }
  }
  return(1);
}

// int _fabricate_menu(*menu);
//
// The second pass in building a menu.  This creates the individual menu items, and sets their
// default positions.  It will also create elements for images, arrows, etc, etc.  Recurses.
//
// Returns 1 for success, technically, but there are no error-checking sections in the function
// right now, so basically it'll return 1 or the whole script will error out.

function _fabricate_menu(menu)
{
  if(menu.base) {
    if(document.layers || (_browser == "Netscape" && _version == 6)) {
      _temp.min_x = _temp.min_y = _temp.max_x = _temp.max_y = null;
      _temp.top_min_x = _temp.top_min_y = _temp.top_max_x = _temp.top_max_y = null;
    }
  }
  else {
    for(var root = menu.parent; !root.base; root = root.parent);
    _cache(menu);                                     // Pre-load images for quicker displaying.
    if(!document.layers) {
      menu.object = document.createElement("div");    // Create the actual element object.
      menu.object.pragmeta = menu;
      menu.object.style.visibility = "hidden";        // Keep everything out of sight until the menu is built.
      menu.object.style.position = "absolute";
      menu.object.style.overflow = "hidden";
      menu.object.style.width = menu.width + "px";
      menu.object.style.height = menu.height + "px";
      if(menu.zindex)
        menu.object.style.zIndex = menu.zindex;
      else {                                          // Set default zIndex.
        for(zincount = 0, zin = menu.parent; zin; zin = zin.parent)
          zincount++;
        menu.object.style.zIndex = zincount * 10;
      }
      if(_browser == "Netscape" || _browser == "Mozilla") {
        menu.object.onmouseover = _netscape_mouseover;
        menu.object.onmouseout = _netscape_mouseout;
        menu.object.onclick = function() { _mouseclick(menu); };
      }
      else {
        menu.object.onmouseover = _ie_mouseover;
        menu.object.onmouseout = _ie_mouseout;
        menu.object.onclick = function() { _mouseclick(menu); };
      }
      if(menu.bgcolor)
        menu.object.style.backgroundColor = menu.bgcolor;
      menu.img = document.createElement("img");
      menu.img.style.position = "absolute";
      menu.img.style.left = "0px";
      menu.img.style.top = "0px";
      menu.img.style.width = menu.width + "px";
      menu.img.style.height = menu.height + "px";
      if(menu.image)
        menu.img.src = menu._image.src;
      else menu.img.style.visibility = "hidden";
      if(menu.cursor)
        menu.object.style.cursor = menu.cursor;
      menu.object.appendChild(menu.img);
      root.base.appendChild(menu.object);
      if(menu.background)
        menu.object.style.backgroundImage = "url('" + menu._background.src + "')";
      if(menu.arrows && menu.elements && (menu.parent.element || menu.force_arrows)) {
        var mid = parseInt(menu.height / 2);          // Draw arrows to indicate child menus.
        menu.arrow = document.createElement("img");
        menu.arrow.style.position = "absolute";
        if(menu.elements[0].anchor == "top") {
          menu.arrow.style.left = menu.width - (menu.arrows.down.x_offset + menu.arrows.down.width) + "px";
          menu.arrow.style.top = parseInt(mid - (menu.arrows.down.height / 2)) + "px";
          menu.arrow.style.width = menu.arrows.down.width + "px";
          menu.arrow.style.height = menu.arrows.down.height + "px";
          menu.arrow.src = menu.arrows.down.src;
        }
        if(menu.elements[0].anchor == "bottom") {
          menu.arrow.style.left = menu.width - (menu.arrows.up.x_offset + menu.arrows.up.width) + "px";
          menu.arrow.style.top = parseInt(mid - (menu.arrows.up.height / 2)) + "px";
          menu.arrow.style.width = menu.arrows.up.width + "px";
          menu.arrow.style.height = menu.arrows.up.height + "px";
          menu.arrow.src = menu.arrows.up.src;
        }
        else if(menu.elements[0].anchor == "left") {
          menu.arrow.style.left = menu.width - (menu.arrows.right.x_offset + menu.arrows.right.width) + "px";
          menu.arrow.style.top = parseInt(mid - (menu.arrows.right.height / 2)) + "px";
          menu.arrow.style.width = menu.arrows.right.width + "px";
          menu.arrow.style.height = menu.arrows.right.height + "px";
          menu.arrow.src = menu.arrows.right.src;
        }
        else if(menu.elements[0].anchor == "right") {
          menu.arrow.style.left = menu.arrows.left.x_offset + "px";
          menu.arrow.style.top = parseInt(mid - (menu.arrows.left.height / 2)) + "px";
          menu.arrow.style.width = menu.arrows.left.width + "px";
          menu.arrow.style.height = menu.arrows.left.height + "px";
          menu.arrow.src = menu.arrows.left.src;
        }
        menu.object.appendChild(menu.arrow);
      }
      if(!menu.previous.base)
        menu.left += menu.previous.left;              // Inherit starting position, factoring in existing offset.
      if(!menu.previous.base)
        menu.top += menu.previous.top;
      if(menu.previous.element) {
        if(menu.anchor == "top")                      // Calculate our cascade in accordance with the anchors.
          menu.top += menu.previous.object.offsetHeight;
        else if(menu.anchor == "left")
          menu.left += menu.previous.object.offsetWidth;
        else if(menu.anchor == "bottom")
          menu.top -= menu.object.offsetHeight;
        else menu.left -= menu.object.offsetWidth;
      }
      menu.object.style.left = menu.left + "px";
      menu.object.style.top = menu.top + "px";
    }
    else {                                            // Netscape 4.x.
      menu.object = new Layer(0, root.base);
      menu.object.pragmeta = menu;
      if(menu.zindex)
        menu.object.zIndex = menu.zindex;
      else {
        for(zincount = 0, zin = menu.parent; zin; zin = zin.parent)
          zincount++;
        menu.object.zIndex = zincount * 10;
      }
      if(!menu.previous.base)
        menu.left += menu.previous.left;              // Calculate starting position.
      if(!menu.previous.base)
        menu.top += menu.previous.top;
      menu.object.resizeTo(menu.width, menu.height);
      if(menu.previous.element) {
        if(menu.anchor == "top")                      // Cascade.
          menu.top += menu.previous.height;
        else if(menu.anchor == "left")
          menu.left += menu.previous.width;
        else if(menu.anchor == "bottom")
          menu.top -= menu.height;
        else menu.left -= menu.width;
      }
      menu.object.left = menu.left;
      menu.object.top = menu.top;
      if(menu.background)
        menu.object.background.src = menu._background.src;
      if(menu.bgcolor)
        menu.object.bgColor = menu.bgcolor;
      if(menu.image || menu.alt_image) {
        menu.object.img = new Layer(0, menu.object);
        menu.object.img.pragmeta = menu;
        menu.object.img.resizeTo(menu.width, menu.height);
        menu.object.img.visibility = "inherit";
        if(menu.image)
          menu.object.img.background.src = menu._image.src;
      }
      menu.object.onmouseover = _netscape_mouseover;
      menu.object.onmouseout = _netscape_mouseout;
      menu.object.captureEvents(Event.MOUSEUP);
      menu.object.onmouseup = function() { _mouseclick(menu); };
      if(menu.arrows && menu.elements && (menu.parent.element || menu.force_arrows)) {
        var mid = parseInt(menu.height / 2);          // Draw arrows to indicate child menus.
        menu.arrow = new Layer(0, menu.object);
        if(menu.elements[0].anchor == "top") {
          menu.arrow.resizeTo(menu.arrows.down.width, menu.arrows.down.height);
          menu.arrow.left = parseInt(menu.width - (menu.arrows.down.x_offset + menu.arrows.down.width));
          menu.arrow.top = parseInt(mid - (menu.arrows.down.height / 2));
          menu.arrow.background.src = menu.arrows.down.src;
        }
        if(menu.elements[0].anchor == "bottom") {
          menu.arrow.resizeTo(menu.arrows.up.width, menu.arrows.up.height);
          menu.arrow.left = parseInt(menu.width - (menu.arrows.up.x_offset + menu.arrows.up.width));
          menu.arrow.top = parseInt(mid - (menu.arrows.up.height / 2));
          menu.arrow.background.src = menu.arrows.up.src;
        }
        else if(menu.elements[0].anchor == "left") {
          menu.arrow.resizeTo(menu.arrows.right.width, menu.arrows.right.height);
          menu.arrow.left = parseInt(menu.width - (menu.arrows.right.x_offset + menu.arrows.right.width));
          menu.arrow.top = parseInt(mid - (menu.arrows.right.height / 2));
          menu.arrow.background.src = menu.arrows.right.src;
        }
        else if(menu.elements[0].anchor == "right") {
          menu.arrow.resizeTo(menu.arrows.left.width, menu.arrows.left.height);
          menu.arrow.left = parseInt(menu.arrows.left.x_offset);
          menu.arrow.top = parseInt(mid - (menu.arrows.left.height / 2));
          menu.arrow.background.src = menu.arrows.left.src;
        }
        menu.arrow.visibility = "inherit";
      }
    }
    if(document.layers || (_browser == "Netscape" && _version == 6)) { // Note largest and smallest menu areas.
      if(menu.left < _temp.min_x || _temp.min_x == null)
        _temp.min_x = menu.left;
      if(menu.left + menu.width > _temp.max_x || _temp.max_x == null)
        _temp.max_x = menu.left + menu.width;
      if(menu.top < _temp.min_y || _temp.min_y == null)
        _temp.min_y = menu.top;
      if(menu.top + menu.height > _temp.max_y || _temp.max_y == null)
        _temp.max_y = menu.top + menu.height;
      if(menu.parent.base) {
        if(menu.left < _temp.top_min_x || _temp.top_min_x == null)
          _temp.top_min_x = menu.left;
        if(menu.left + menu.width > _temp.top_max_x || _temp.top_max_x == null)
          _temp.top_max_x = menu.left + menu.width;
        if(menu.top < _temp.top_min_y || _temp.top_min_y == null)
          _temp.top_min_y = menu.top;
        if(menu.top + menu.height > _temp.top_max_y || _temp.top_max_y == null)
          _temp.top_max_y = menu.top + menu.height;
      }
    }
  }
  if(menu.elements)                                   // Recurse.
    for(var i = 0; i < menu.elements.length; i++)
      if(!_fabricate_menu(menu.elements[i]))
        return(0);
  return(1);
}

// int _assemble_menu(*menu);
//
// The third pass in building a menu, and in a perfect world this wouldn't exist.  It basically
// corrects errors and quirks in certain browsers, like dynamically changing the base element size
// in Netscape 6 so we get proper mouseover events without overshadowing menus with a lower
// zIndex.
//
// Returns 1 for success, technically, but there are no error-checking sections in the function
// right now, so basically it'll return 1 or the whole script will error out.

function _assemble_menu(menu)
{
  if(menu.base) {
    if(document.layers || (_browser == "Netscape" && _version == 6)) {
      menu.base.clip_min_left = _temp.top_min_x;      // Record the results of the area-size tracking.
      menu.base.clip_min_right = _temp.top_max_x;
      menu.base.clip_min_top = _temp.top_min_y;
      menu.base.clip_min_bottom = _temp.top_max_y;
      menu.base.clip_max_left = _temp.min_x;
      menu.base.clip_max_right = _temp.max_x;
      menu.base.clip_max_top = _temp.min_y;
      menu.base.clip_max_bottom = _temp.max_y;
      if(document.layers) {
        menu.base.resizeTo(_temp.top_max_x - _temp.top_min_x, _temp.top_max_y - _temp.top_min_y);
        _reclip_layer(menu.base, 0);
      }
      else if(_browser == "Netscape" && _version == 6)
        _rethink_base(menu, 0);
    }
  }
  else {
  }
  if(menu.elements)                                   // Recurse.
    for(var i = 0; i < menu.elements.length; i++)
      if(!_assemble_menu(menu.elements[i]))
        return(0);
  return(1);
}

// EXTERNAL //////////////////////////////////////////////////////////////////////////////////////

// See containing page.

function build_menu(menu, debug)
{
  if(_temp.sol)
    return(0);
  if(!_menus.length) {                                // First time we're called, so initialize data.
    _build_array_prototypes();
    _detect_browser();
    if(debug)
      document.title = document.title + ", mutating for " + _browser + ((_version > 0)?(" " + _version + (_revision?"." + _revision:"")):"") + " ["+ navigator.userAgent + "]";
    if((_browser != "IE" || _version < 5) && (_browser != "Netscape" || _version < 4) && _browser != "Mozilla") {
      _temp.sol = 1;
      if(menu.sitemap) {
        alert("Your browser cannot handle our menuing system; redirecting to sitemap.");
        window.location.href = menu.sitemap;
      }
      else alert("Your browser cannot handle our menuing system; menus are disabled.");
      return(0);
    }
    _temp.onload = window.onload;
    _temp.unload = window.onunload;
    window.onload = _document_loaded;
    window.onunload = _document_unloaded;
  }
  if(debug && !_temp.debug_window) {
    _temp.debug_window = window.open("", 0, "width=300,height=400,left=700,top=300,scrollbars=yes" + ((_browser == "Netscape" && _version == 6)?",dependent=yes":""));
    if(_browser == "Netscape" && _version == 6)
      _temp.debug_window.document.close();
    _temp.debug_window.document.write("<html><head><title>Debug</title></head><body bgcolor='#000000' text='#ffffff'><font size='2'>");
    _debug("Browser: " + _browser + " " + _version + (_revision?"." + _revision:"") + "<br><font size=1 color='#d0d0d0'>[" + navigator.userAgent+ "]</font>", [ "#ffffff", "#a000a0" ]);
    _temp.debug_window.focus();
  }
  _menus.push(menu);
  return(1);
}

// See containing page.

function show_menu(menu)
{
  if(!menu.base)                                      // We haven't actually built it yet.
    menu.visibility = "visible";
  else {
    for(var i = 0; i < menu.elements.length; i++) {
      if(!document.layers)
        menu.elements[i].object.style.visibility = "visible";
      else menu.elements[i].object.visibility = "visible";
    }
    if(document.layers)
      menu.base.visibility = "visible";
  }
}

// See containing page.

function hide_menu(menu)
{
  if(!menu.base)                                      // Haven't built it yet.
    menu.visibility = "hidden";
  else {
    for(var ptr = _temp.hover; ptr && !ptr.base; ptr = ptr.parent);
    if(ptr && ptr == menu) {                          // Close the menu before we hide it, to reset all images.
      _temp.hover = 0;
      _close_menus();
    }
    for(var i = 0; i < menu.elements.length; i++)
      if(!document.layers)
        menu.elements[i].object.style.visibility = "hidden";
      else menu.elements[i].object.visibility = "hidden";
    if(document.layers)
      menu.base.visibility = "hidden";
  }
}

// SUPPORT ///////////////////////////////////////////////////////////////////////////////////////

function _build_array_prototypes()                    // Correct for flaws in IE 5-.
{
  if(Array.prototype.push && ([0].push(true) == true))
    Array.prototype.push = null;
  if(!Array.prototype.push) {
    function _array_push() {
      for(i = 0; i < arguments.length; i++)
        this[this.length] = arguments[i];
      return(this.length);
    }
    Array.prototype.push = _array_push;
  }
  if(!Array.prototype.pop) {
    function _array_pop() {
      lastElement = this[this.length - 1];
      this.length = Math.max(this.length - 1,0);
      return(lastElement);
    }
    Array.prototype.pop = _array_pop;
  }
  if(Array.prototype.splice && typeof([0].splice(0)) == "number")
    Array.prototype.splice = null;
  if(!Array.prototype.splice) {
    function _array_splice(ind, cnt) {
      if(arguments.length == 0)
        return(ind);
      if(typeof ind != "number")
        ind = 0;
      if(ind < 0)
        ind = Math.max(0, this.length + ind);
      if(ind > this.length) {
        if(arguments.length > 2)
          ind = this.length;
        else return([]);
      }
      if(arguments.length < 2)
        cnt = this.length - ind;
      cnt = (typeof cnt == "number")?Math.max(0, cnt):0;
      removeArray = this.slice(ind, ind + cnt);
      endArray = this.slice(ind + cnt);
      this.length = ind;
      for(i = 2; i < arguments.length; i++)
        this.push(arguments[i]);
      for(i = 0; i < endArray.length; i++)
        this.push(endArray[i]);
      return(removeArray);
    }
    Array.prototype.splice = _array_splice;
  }
}

function _find_anchor(name)                           // This is ridiculous, I can't believe IE
{                                                     // doesn't support document.anchors["name"]...
  for(var i = 0; i < document.anchors.length; i++)
    if(document.anchors[i].name == name)
      return(document.anchors[i]);
}

function _offsetLeft(element)                         // Calculate the total left offset of an element.
{
  if(!document.layers) {
    for(var x = 0; element; element = element.offsetParent)
      x += element.offsetLeft;
    return(x);
  }
  return(element.x);
}

function _offsetTop(element)                          // Calculate the total top offset of an element.
{
  if(!document.layers) {
    for(var y = 0; element; element = element.offsetParent)
      y += element.offsetTop;
    return(y);
  }
  return(element.y);
}

function _rethink_base(menu, max, offset_left, offset_top)  // Netscape 6.x dynamic base resizing.
{
  if(max == -1) {                                     // Recursing.
    menu.object.style.left = (menu.left - offset_left) + "px";
    menu.object.style.top = (menu.top - offset_top) + "px";
    if(menu.elements)
      for(var i = 0; i < menu.elements.length; i++)
        _rethink_base(menu.elements[i], -1, offset_left, offset_top);
    return;
  }
  if(menu.maximized == null) {                        // Initialize all submenus.
    if(menu.elements)
      for(i = 0; i < menu.elements.length; i++)
        if(menu.elements[i].elements)
          for(j = 0; j < menu.elements[i].elements.length; j++)
            _rethink_base(menu.elements[i].elements[j], -1, menu.base.clip_max_left, menu.base.clip_max_top);
    menu.maximized = !max;
  }
  if(max != menu.maximized) {
    menu.base.style.width = (max?(menu.base.clip_max_right - menu.base.clip_min_left):(menu.base.clip_min_right - menu.base.clip_min_left)) + "px";
    menu.base.style.height = (max?(menu.base.clip_max_bottom - menu.base.clip_max_top):(menu.base.clip_min_bottom - menu.base.clip_min_top)) + "px";
    menu.base.style.left = ((menu.offset_left?menu.offset_left:0) + menu.left + (max?menu.base.clip_max_left:menu.base.clip_min_left)) + "px";
    menu.base.style.top = ((menu.offset_top?menu.offset_top:0) + menu.top + (max?menu.base.clip_max_top:menu.base.clip_min_top)) + "px";
    menu.maximized = max;
    if(menu.elements)
      for(i = 0; i < menu.elements.length; i++) {
        menu.elements[i].object.style.left = (menu.elements[i].left - (max?menu.base.clip_max_left:menu.base.clip_min_left)) + "px";
        menu.elements[i].object.style.top = (menu.elements[i].top - (max?menu.base.clip_max_top:menu.base.clip_min_top)) + "px";
      }
  }
}

function _reclip_layer(layer, max)                    // Netscape 4.x dynamic clipping.
{
  layer.clip.left = max?layer.clip_max_left:layer.clip_min_left;
  layer.clip.right = max?layer.clip_max_right:layer.clip_min_right;
  layer.clip.top = max?layer.clip_max_top:layer.clip_min_top;
  layer.clip.bottom = max?layer.clip_max_bottom:layer.clip_min_bottom;
}

function _cache(menu)                                 // Pre-load images.
{
  var cached;
  if(menu.image) {
    cached = new Image();
    cached.src = menu.image;
    menu._image = cached;
  }
  if(menu.alt_image) {
    cached = new Image();
    cached.src = menu.alt_image;
    menu._alt_image = cached;
  }
  if(menu.background) {
    cached = new Image();
    cached.src = menu.background;
    menu._background = cached;
  }
  if(menu.alt_background) {
    cached = new Image();
    cached.src = menu.alt_background;
    menu._alt_background = cached;
  }
}

function _detect_browser(display)                     // Browser sniffer - see note below.
//
// DO NOT COPY THIS BROWSER SNIFFER, you plagiarizing bastard.
// Er, sorry, what I mean is: This is not a robust browser sniffer
// by any definition, and in fact can misidentify browsers that I
// know are menu-system compatible with certain other browsers.
//
{
  var agent = navigator.userAgent.toLowerCase();
  var major = parseInt(navigator.appVersion);
  for(var i = 0; i < reject_browsers.length; i++)
    if(agent.indexOf(reject_browsers[i]) != -1) {
      _browser = reject_browsers[i];
      return;
    }
  if(agent.indexOf("opera") != -1) {
    _browser = "Opera";
    if(agent.indexOf("opera 6") != -1 || agent.indexOf("opera/6") != -1)
      _version = 6;
    else if(agent.indexOf("opera 5") != -1 || agent.indexOf("opera/5") != -1)
      _version = 5;
    else if(agent.indexOf("opera 4") != -1 || agent.indexOf("opera/4") != -1)
      _version = 4;
    else if(agent.indexOf("opera 3") != -1 || agent.indexOf("opera/3") != -1)
      _version = 3;
    else if(agent.indexOf("opera 2") != -1 || agent.indexOf("opera/2") != -1)
      _version = 2;
    else if(agent.indexOf("opera 1") != -1 || agent.indexOf("opera/1") != -1)
      _version = 1;
    else {
      _version = 6;
      _revision = "+";
    }
  }
  else if(agent.indexOf("msie") != -1) {
    _browser = "IE";

    if(major < 4)
      _version = 3;
    else if(agent.indexOf("msie 4") != -1)
      _version = 4;
    else if(agent.indexOf("msie 5.") != -1) {
      _version = 5;
      if(agent.indexOf("msie 5.5") != -1)
        _revision = 5;
    }
    else if(agent.indexOf("msie 6.") != -1)
      _version = 6;
    else {
      _version = 6;
      _revision = "+";
    }
  }
  else if(agent.indexOf("gecko") != -1 && agent.indexOf("netscape") == -1) {
    _browser = "Mozilla";
    if(agent.indexOf("rv:0") != -1)
      _version = 0;
    else if(agent.indexOf("rv:1.0") != -1)
      _version = 1;
    else if(agent.indexOf("rv:1.1") != -1) {
      _version = 1;
      _revision = 1;
    }
    else if(agent.indexOf("rv:1.2") != -1) {
      _version = 1;
      _revision = 2;
    }
    else {
      _version = 1;
      _revision = "2+";
    }
  }
  else if(agent.indexOf('mozilla') != -1) {
    _browser = "Netscape";
    if(major < 2)
      _version = 1;
    else if(major < 5)
      _version = major;
    else if(major == 5 && agent.indexOf("netscape/7") == -1)
      _version = 6;
    else if(major == 5 && agent.indexOf("netscape/7") != -1)
      _version = 7;
    else {
      _version = 7;
      _revision = "+";
    }
  }
}

// RUNTIME ///////////////////////////////////////////////////////////////////////////////////////

var _opened_menus = [];   // Keep track of all opened menus for error-correction.
var _highlights = [];     // Same deal with highlighted elements.
var _mouse_leaving = 0;   // Netscape error-correction.  Half this frickin' page is Netscape error-correction.

function _document_loaded()                           // This actually initiates building of the menus.
{
  for(var index = 0; index < _menus.length; index++) {
_debug("<font color='#a0a0a0'>Menu:</font> " + (_menus[index].name?_menus[index].name:"[unnamed]"));
_debug("Contemplate", "#008f00", 1);
    if(_contemplate_menu(_menus[index])) {
_debug(" / fabricate", "#00bf00", 1);
      if(_fabricate_menu(_menus[index])) {
_debug(" / assemble", "#00ef00", 1);
        if(_assemble_menu(_menus[index])) {
          if(_menus[index].visibility == "visible") {
            show_menu(_menus[index]);
_debug(" OK <font color='a0a0a0'>[show]</font>", "#00ff00");
          }
else _debug(" OK <font color='a0a0a0'>[hide]</font>", "#00ff00");
        }
      }
    }
  }
  if(document.layers) {
    _temp.innerWidth = innerWidth;                    // Track actual size for spoofed onresizes.
    _temp.innerHeight = innerHeight;
  }
  if(_temp.onload)                                    // Call function we've overridden.
    _temp.onload();
}

function _ie_mouseover()                              // Mouse entered a menu element.
{
  for(var fromElm = window.event.fromElement; fromElm && !fromElm.pragmeta; fromElm = fromElm.offsetParent);
  for(var toElm = window.event.toElement; toElm && !toElm.pragmeta; toElm = toElm.offsetParent);
  if(fromElm == toElm)                                // If we're moving between menu elements, ignore the mouseover.
    return;
  if(!fromElm || !fromElm.pragmeta)                   // We're entering the menuing system.
    _mouseover(toElm.pragmeta);
}

function _ie_mouseout()                               // Mouse left a menu element.
{
  for(var fromElm = window.event.fromElement; fromElm && !fromElm.pragmeta; fromElm = fromElm.offsetParent);
  for(var toElm = window.event.toElement; toElm && !toElm.pragmeta; toElm = toElm.offsetParent);
  if(fromElm == toElm)                                // If we're moving between menu elements, ignore the mouseout.
    return;
  if(fromElm)
    _mouseout(fromElm.pragmeta, toElm?toElm.pragmeta:0);
  if(toElm)                                           // We're moving between menu items.
    _mouseover(toElm.pragmeta);
}

function _netscape_mouseover(event)                   // Mouse entered a menu element.
{
  if(!document.layers) {
    for(var over = event.target; over && !over.pragmeta; over = over.parentNode);
    for(var old = event.relatedTarget; old && !old.pragmeta; old = old.parentNode);
    if(old == over)
      return(false);
  }
  else for(var over = event.target; over && !over.pragmeta; over = over.parentLayer);
  if(!over)
    return(false);
  document.onmousemove = 0;
  if(_mouse_leaving && _mouse_leaving != over.pragmeta) {
    _mouseout(_mouse_leaving, over.pragmeta);
    _mouse_leaving = 0;
  }
  _mouseover(over.pragmeta);
  return(true);
}

function _netscape_mouseout(event)                    // Mouse left a menu element.
{
  if(!document.layers) {
    for(var over = event.target; over && !over.pragmeta; over = over.parentNode);
    for(var old = event.relatedTarget; old && !old.pragmeta; old = old.parentNode);
    if(old == over)
      return;
  }
  else for(var over = event.target; over && !over.pragmeta; over = over.parentLayer);
  if(!over || _temp.hover != over.pragmeta)
    return(true);
  _mouse_leaving = over.pragmeta;
  if(document.layers)
    document.captureEvents(Event.MOUSEMOVE);
  document.onmousemove = _netscape_mousemove;
  window.setTimeout("_netscape_correct();", 0);       // If they move the mouse quickly out of the window,
  return(true);                                       // we don't get a final mousemove, so correct for it.
}

function _netscape_mousemove(event)                   // Test if we're leaving a menu item by tracking movement.
{
  if(_mouse_leaving) {
//_debug("MM: ", "#a0a0a0", 1);
    _mouseout(_mouse_leaving);
    _mouse_leaving = 0;
  }
  document.onmousemove = 0;
}

function _netscape_correct()                          // Correct deficiency in Netscape's mouseout tracking.
{
  if(_mouse_leaving) {
//_debug("NSC: ", "#a0a0a0", 1);
    _mouseout(_mouse_leaving);
    _mouse_leaving = 0;
  }
}

function _mouseover(menu)                             // The mouse has gone over a menu element.
{
//_debug("Mouseover " + menu.name + "<font color='#a0a0a0'>" + (menu.bgcolor?" BGC":"") + (menu.alt_bgcolor?" aBGC":"") + (menu.background?" BG":"") + (menu.alt_background?" aBG":"") + (menu.image?" I":"") + (menu.alt_image?" aI":"") + (menu.status?" status":"") + (menu.href?" href":"") + (menu.elements?" sub":"") + (menu.mouseover?" html":"") + "</font>", "#00ff00");
  if(document.layers) {
    if(menu.parent.base)
      _reclip_layer(menu.parent.base, 1);
  }
  else if(_browser == "Netscape" && _version == 6 && menu.parent.base)
    _rethink_base(menu.parent, 1);
  if(menu.status)
    window.status = menu.status;
  else if(menu.href)
    window.status = menu.href;
  _temp.hover = menu;
  _highlight(menu);
  if(menu.mouseover)
    eval(menu.mouseover);
}

function _mouseout(menu, next_menu)                   // The mouse has left the buil[H[H[H[Hmenu element.
{
//_debug("Mouseout " + menu.name + "<font color='#a0a0a0'>" + (menu.mouseout?" html":""), "#ff0000");
  if(menu.status || menu.href)
    window.status = "";
  if(next_menu && next_menu.parent != menu)
    _unhighlight(menu);
  _temp.hover = next_menu?next_menu:0;
  _close_menus();
  if(!next_menu && (document.layers || (_browser == "Netscape" && _version == 6))) {
    for(var walker = menu; walker.parent; walker = walker.parent);
    if(document.layers)                               // Gotta reclip/resize.
      _reclip_layer(walker.base, 0);
    else _rethink_base(walker, 0);
  }
  if(menu.mouseout)
    eval(menu.mouseout);
}

function _mouseclick(menu, pop)                       // A menu hath been clicked upon.
{
//_debug("Mouseclick " + menu.name, "#ffff00");
  if(menu.mouseclick)
    eval(menu.mouseclick);
  if(menu.href)
    window.location.href = menu.href;
}

function _highlight(menu)                             // Change a menu to its highlighted state.
{
  _highlights.push(menu);
  if(menu.alt_image != null) {
    if(!document.layers) {
      if(menu.alt_image) {
        menu.img.src = menu._alt_image.src;
        if(!menu.image)
          menu.img.style.visibility = "inherit";
      }
      else menu.img.style.visibility = "hidden";
    }
    else menu.object.img.background.src = menu.alt_image?menu._alt_image.src:null;
  }
  if(menu.alt_background != null) {
    if(!document.layers)
      menu.object.style.backgroundImage = menu.alt_background?"url('" + menu._alt_background.src + "')":"";
    else menu.object.background.src = menu.alt_background?menu._alt_background.src:null;
  }
  if(menu.alt_bgcolor != null) {
    if(!document.layers)
      menu.object.style.backgroundColor = menu.alt_bgcolor?menu.alt_bgcolor:((_browser == "Netscape" && _version == 6)?0:"");
    else menu.object.bgColor = menu.alt_bgcolor?menu.alt_bgcolor:null;
  }
  if(menu.elements) {
    for(var i = 0; i < menu.elements.length; i++)     // Display child menu.
      if(!document.layers) {
        if(menu.elements[i].fade) {
          if(menu.elements[i].object.style.MozOpacity != null) {
            menu.elements[i].object.style.MozOpacity = 0.0;
            window.setTimeout(_opacity_fade, menu.elements[i].fade, menu.elements[i]);
          }
          else {
//          menu.elements[i].object.style.filter = "alpha(opacity = 40)";
          }
        }
        menu.elements[i].object.style.visibility = "visible";
      }
      else menu.elements[i].object.visibility = "visible";
    _opened_menus.push(menu);
  }
}

function _unhighlight(menu)                           // Reset a menu to its original state.
{
  var i;
  if((i = _member(menu, _highlights)) != -1)
    _highlights.splice(i, 1);
  if(menu.alt_image != null) {
    if(!document.layers) {
      if(menu.image) {
        menu.img.src = menu._image.src;
        if(menu.alt_image == 0)
          menu.img.style.visibility = "inherit";
      }
      else menu.img.style.visibility = "hidden";
    }
    else menu.object.img.background.src = menu.image?menu._image.src:null;
  }
  if(menu.alt_background != null) {
    if(!document.layers)
      menu.object.style.backgroundImage = menu.background?"url('" + menu._background.src + "')":"";
    else menu.object.background.src = menu.background?menu._background.src:0;
  }
  if(menu.alt_bgcolor != null) {
    if(!document.layers)
      menu.object.style.backgroundColor = menu.bgcolor?menu.bgcolor:((_browser == "Netscape" && _version == 6)?0:"");
//
// Just a little rant here, and who can blame me?  You have NO IDEA how long it took me to track
// this 'quirk' down.  The symptom was that submenus wouldn't animate, amongst a few other things,
// in Netscape 6.  I completely took this thing apart and spent hours looking for the cause, and
// finally came up with this: In all Netscapes besides 6, you set the background color to empty
// (transparent) with an empty string (""), and it will give non-immediate errors if you set it to
// 0.  That's fine, but in Netscape 6 they decided it would be fun to make you set it to 0, and
// give non-immediate errors with the "".  What the hell were they thinking?
//
// Netscape sucks my left nutsicle.
//
    else menu.object.bgColor = menu.bgcolor?menu.bgcolor:null;
  }
}

function _close_menus()                               // Close any invalid opened menus.
{
  var valid_menus = new Array();
  for(var walker = _temp.hover; walker; walker = walker.parent)
    valid_menus.push(walker);                         // There must be some joke here.
  for(var i = _highlights.length; i-- > 0;)           // Unhighlight invalid elements.
    if(_member(_highlights[i], valid_menus) == -1)
      _unhighlight(_highlights[i]);
  for(var i = _opened_menus.length; i-- > 0;)         // Close invalid opened menus, deepest first.
    if(_member(_opened_menus[i], valid_menus) == -1) {
      for(var j = 0; j < _opened_menus[i].elements.length; j++)
        if(!document.layers)
          _opened_menus[i].elements[j].object.style.visibility = "hidden";
        else _opened_menus[i].elements[j].object.visibility = "hidden";
      _opened_menus.splice(i, 1);
    }
}

function _reanchor_menus()                            // We've been resized.
{
//_debug("Reanchoring menus.", "#ff00ff");
  if(document.layers) {
    if(innerWidth != _temp.innerWidth || innerHeight != _temp.innerHeight) // Fuckin' Netscape.
      location.reload();
    return;
  }
  for(var i = 0; i < _menus.length; i++)
    if(typeof(_menus[i].anchor) == "object") {
      _menus[i].base.style.left = (_offsetLeft(_menus[i].anchor) + _menus[i].left) + "px";
      _menus[i].base.style.top = (_offsetTop(_menus[i].anchor) + _menus[i].top) + "px";
    }
  if(_temp.onresize)                                  // Call function we've overridden.
    _temp.onresize();
}

function _document_unloaded()                         // Clean up after ourselves.
{
  if((_browser != "Netscape" || _version != 6) && _temp.debug_window && !_temp.debug_window.closed)
    _temp.debug_window.close();
  if(_temp.unload)                                    // Call function we've overridden.
    _temp.unload();
}

function _opacity_fade(menu)
{
  if(menu.object.style.MozOpacity != null) {
    if(menu.object.style.visibility == "visible") {
      menu.object.style.MozOpacity = parseFloat(menu.object.style.MozOpacity) + 0.1;
      if(menu.object.style.MozOpacity < 1.0)
        window.setTimeout(_opacity_fade, menu.fade, menu);
      else menu.object.style.MozOpacity = 1.0;
    }
  }
  else {
  }
}

// HEDGELSCHNOZZHER //////////////////////////////////////////////////////////////////////////////

function _member(el, arr)                             // Return an element's index in an array, or -1.
{
  if(!arr || typeof(arr) != "object")
    alert("Invalid array argument to _member().");
  else for(var i = 0; i < arr.length; i++)
    if(arr[i] == el)
      return(i);
  return(-1);
}

function _debug(str, color, raw)                      // Write to the debug window.
{
  if(_temp.debug_window && !_temp.debug_window.closed) {
    if(!color)
      color = "#ffffff";
    if(typeof(color) == "object") {
      str = "<table border=0 cellpadding=0 cellspacing=0 bgcolor='" + color[1] + "' width='100%'><tr><td align='center'><font color='" + color[0] + "'>" + str + "</font></td></tr></table>";
      raw = 1;
    }
    else str = "<font color='" + color + "'>" + str + "</font>";
    _temp.debug_window.document.write(str + (raw?"":"<br>"));
    _temp.debug_window.scrollTo(0, 0x0fffffff);
//    _temp.debug_window.focus();
  }
  else return(0);
//  else alert(str);
  return(1);
}
