// OK, here goes... this code is horribly compacted by the way, and intented for fast
// execution rather than easy understanding. You might want to run my codetrimmer script
// over it before deployment to get rid of comments for better performance.

// *** BROWSER DETECTION VARIABLES ***
// Requires: None.

// isDOM: DOM-compatible browser? (IE5+, NS6+, others like Opera, Konqueror, etc...)
// isIE: Internet Explorer (v4 and up), also Opera emulating it.
// isIE4, isNS4: Each of the 4-series browsers (not DOM compatible).
// isOp: Any Opera version (useful as Opera emulates IE above).
// isWin: True is Windows, false if Mac/Linux etc.
// isDyn: Any DHTML-capable browser.

var isDOM=document.getElementById?1:0;
var isIE=document.all?1:0;
var isNS4=navigator.appName=='Netscape'&&!isDOM?1:0;
var isIE4=isIE&&!isDOM?1:0;
var isOp=window.opera?1:0;
var isDyn=isDOM||isIE||isNS4;
var isWin=navigator.platform.indexOf('Win')!=-1?1:0;



// *** DOCUMENT OBJECT MODEL (DOM) REFERENCE FUNCTIONS ***
// Requires: Brower Detection Variables

// Get a reference to an element by its ID, and optionally a parent element/frame.
// Pass a parameter 'par' as either null to find a element in the current document,
// a reference to a parent element using another getRef call or similar,
// or reference to another window (e.g. parent.content) for frames usage.
function getRef(id, par)
{
 par=!par?document:(par.navigator?par.document:par);
 return isIE ? par.all[id] :
  (isDOM ? (par.getElementById?par:par.ownerDocument).getElementById(id) :
  (isNS4 ? par.layers[id] : null));
}

// Returns a reference to the .style property of an element, same parameters.
function getSty(id, par)
{
 var r=getRef(id, par);
 return r?(isNS4?r:r.style):null;
}



// *** LAYER OBJECT CONSTRUCTOR ***
// Requires: DOM Reference Functions.

// For complex scripts, wraps up the above in one object and defines a few useful methods.
// This is built to be light and quick to download -- my major priority.
// You must pass an ID, and optionally a reference to a parent layer for NS4, like getRef().
// Usage: var xyz = getLyr('layerID'); or for frames, = getLyr('layerID', parent.content);
// You can then access xyz.ref or .sty, which are reference from the functions above, or
// other functions of the layer object defined below, e.g. xyz.vis('visible').

// Only create a class if one is not defined already (for easy script combination).
if (!window.LayerObj) var LayerObj = new Function('id', 'par',
 'this.ref=getRef(id, par); this.sty=getSty(id, par); return this');

// Keep the same 'var x = getXXX' syntax for all functions...
function getLyr(id, par) { return new LayerObj(id, par) }

function LyrFn(fn, fc)
{
 LayerObj.prototype[fn] = new Function('var a=arguments,p=a[0],px=isNS4||isOp?0:"px"; ' +
  'with (this) { '+fc+' }');
}



// *** FUNCTIONS OF LAYER OBJECT ***
// Requires: Layer Object Constructor.

// These functions add abilities to the layer object defined above.
// You can include only the ones you need, e.g. positioning and colours but no others.
// For many, calling with a parameter will set the value, while calling without will
// return the current value for the element, e.g. layer.x() returns the left position.
// NOTE: These are not meant to be perfect, just using them does not guarantee your
// code will work in any given browser. Be sure to test thoroughly!

// Sets or gets the position of the layer, pass a number to set or nothing to get.
LyrFn('x','if (!isNaN(p)) sty.left=p+px; else return parseInt(sty.left)');
LyrFn('y','if (!isNaN(p)) sty.top=p+px; else return parseInt(sty.top)');

// Sets the dimensions, or gets the layer's document dimensions. Note that NS4/Op5&6 can't
// resize properly, so they just reclip. Two versions are provided -- one without Opera 5
// support but works in Opera 6+, and a commented one with Opera 5 support if needed.

LyrFn('w','if (p) (isNS4?sty.clip:sty).width=p+px; ' +
 'else return (isNS4?ref.document.width:ref.offsetWidth)');
LyrFn('h','if (p) (isNS4?sty.clip:sty).height=p+px; ' +
 'else return (isNS4?ref.document.height:ref.offsetHeight)');
//LyrFn('w','if (p) (isNS4?sty.clip:sty)[isOp?"pixelWidth":"width"]=p+px; ' +
// 'else return isNS4?ref.document.width:(isOp?sty.pixelWidth:ref.offsetWidth)');
//LyrFn('h','if (p) (isNS4?sty.clip:sty)[isOp?"pixelHeight":"height"]=p+px; ' +
// 'else return isNS4?ref.document.height:(isOp?sty.pixelHeight:ref.offsetHeight)');

// Sets or gets the visibility. Accepted values: 'visible', 'inherit', 'hidden'.
// There are two versions -- a setter only, and a commented out setter/getter..
LyrFn('vis','sty.visibility=p');
//LyrFn('vis','if (p) sty.visibility=p; ' +
// 'else { var v=sty.visibility; return (v=="show"?"visible": (v=="hide"?"hidden":v)) }');

// Set the element background -- pass an empty string '' to set it to transparent.
// Note that setting and removing both colours and images on one div has issues in Opera,
// and it also seems to have an intense dislike of transparency. Background images are
// not supported by Opera 5, but can be set in Opera 6.
LyrFn('bgColor','if (isNS4) sty.bgColor=p?p:null; ' +
 'else sty.background=p?p:"transparent"');
LyrFn('bgImage','if (isNS4) sty.background.src=p?p:null; ' +
 'else sty.background=p?"url("+p+")":"transparent"');
// Experimental, both rolled up into one.
//LyrFn('bg','var img=p.indexOf(".")>-1; if (isNS4) if (img) sty.background.src=p?p:null; ' +
// 'else sty.bgColor=p?p:null; else sty.background=p?(img?"url("+p+")":p):"transparent"');

// Sets the clipping area of the div -- pass x1,y1,x2,y2.
// Works in IE5+/Mac, IE4+/Win, NS4/6+ all platforms, Opera 5/6 is unsupported.
LyrFn('clip','if (isNS4) with(sty.clip){left=a[0];top=a[1];right=a[2];bottom=a[3]} ' +
 'else sty.clip="rect("+a[1]+"px "+a[2]+"px "+a[3]+"px "+a[0]+"px)" ');

// Replace the contents of the layer/div. Pass it a string. Doesn't work in Opera yet.
LyrFn('write','if (isNS4) with (ref.document){write(p);close()} else ref.innerHTML=p');

// Sets the opacity of the div. Cool, but don't overuse, a little buggy in Mozilla (NS6), and
// it doesn't work in NS4 or IE/Mac. Pass it a percentage (0 to 100) to set, or null to remove.
LyrFn('alpha','var f=ref.filters,d=(p==null); if (f) {' +
 'if (!d&&sty.filter.indexOf("alpha")==-1) sty.filter+=" alpha(opacity="+p+")"; ' +
 'else if (f.length&&f.alpha) with(f.alpha){if(d)enabled=false;else{opacity=p;enabled=true}} }' +
 'else if (isDOM) sty.MozOpacity=d?"":p+"%"');


// *** DYNAMIC LAYER CREATION ROUTINE ***
// Requires: Layer Object Constructor, 'vis','x' and 'y' Layer Functions.

// Create a new layer dynamically. You must pass an initial visibility: 'visible', 'inherit' or
// 'hidden'. Optionally also pass layer width in pixels, and a reference to a parent layer/frame
// within which this layer will be created. This isn't supported by Opera 5 or 6.
function setLyr(lVis, docW, par)
{
 if (!setLyr.seq) setLyr.seq=0;
 if (!docW) docW=0;
 var obj = (!par ? (isNS4 ? window : document.body) :
  (!isNS4 && par.navigator ? par.document.body : par));
 var IA='insertAdjacentHTML', AC='appendChild', newID='_js_layer_'+setLyr.seq++;

 if (obj[IA]) obj[IA]('beforeEnd', '<div id="'+newID+'" style="position:absolute"></div>');
 else if (obj[AC])
 {
  var newL=document.createElement('div');
  obj[AC](newL); newL.id=newID; newL.style.position='absolute';
 }
 else if (isNS4)
 {
  var newL=new Layer(docW, obj);
  newID=newL.id;
 }

 var lObj=getLyr(newID, par);
 with (lObj) if (ref) { vis(lVis); x(0); y(0); sty.width=docW+(isNS4?0:'px') }
 return lObj;
}


// *** PAGE OBJECT***
// Requires: Browser detection variables.

// Use this to determine current window dimensions. It automatically creates an
// object called 'page', usage:  var xyz = page.scrollY();
// You can set page.minW and page.minH as minimum values for the dimension functions.
// page.win can point to the window whose properties are returned, useful for framesets.

// CSSMode detects strict doctype compliance, needed for IE6 in compliant mode.
var CSSmode=document.compatMode;
CSSmode=(CSSmode&&CSSmode.indexOf('CSS')!=-1)||isDOM&&!isIE||isOp?1:0;

if (!window.page) var page = { win: window, minW: 0, minH: 0, MS: isIE&&!isOp,
 db: CSSmode?'document.documentElement':'body' }

// Get the current area of the visible window, check against minima.
page.winW=function()
 { with (this) return Math.max(minW, MS?win.document[db].clientWidth:win.innerWidth) }
page.winH=function()
 { with (this) return Math.max(minH, MS?win.document[db].clientHeight:win.innerHeight) }

// Get the scroll position of the window. No real minima needed here.
page.scrollX=function()
 { with (this) return MS?win.document[db].scrollLeft:win.pageXOffset }
page.scrollY=function()
 { with (this) return MS?win.document[db].scrollTop:win.pageYOffset }

// Get the current document size, check versus minimum dimensions.
page.docW=function()
 { with (this) return Math.max(minW, isNS4?win.document[db].width:win.document.body.offsetWidth) }
page.docH=function()
 { with (this) return Math.max(minH, isNS4?win.document[db].height:win.document.body.offsetHeight) }




// *** MULTIPLE EVENT MANAGER ***
// Requires: Browser Detection Variables
// (although you can replace the one 'isNS4' with 'document.layers' and have it work).

// Usage notes: Pass either a string or a function reference as the 3rd parameter.
// The first parameter must be a reference to an object like window or document that contains
// the event, and the second must be the name of the event in quotes (e.g. 'onmouseover').
// The third parameter must be a string / function reference that is called/eval'd on firing.
// The last parameter enables captureEvents() in NS4, only needed for document events.
// Functions called are passed the correct browser event object, strings evaluated as events
// have a variable called 'e' they can use to access event properties.
// See the example in the demo script below if this doesn't make sense.

if (!window.gusEvts) var gusEvts=new Array();

function addEvent(obj, eName, fn, cap)
{
 var g=gusEvts, n=g.length, old=obj[eName], i=old?old.toString().indexOf('gEvtId'):-1;
 if (!old||i==-1){obj[eName]=new Function('e','var gEvtId='+n+'; return runEvent(e,gEvtId,'+
  !obj.navigator+')'); g[n]=[obj]; if (old) g[n][1]=old}
 else n=parseInt(old.toString().substring(i+7));
 g[n][g[n].length]=fn;
 if (isNS4&&cap) obj.captureEvents(Event[eName.substring(2).toUpperCase()]);
}

function runEvent(e, num, rval)
{
 var ret=1, fns=gusEvts[num], e=e?e:window.event;
 for (var i=1;i<fns.length;i++)
  ret=((typeof(fns[i])=='string' ? new Function('e',fns[i]) : fns[i])(e)!=false)&&ret;
 if (rval) return (ret ? (isNS4?fns[0].routeEvent(e):true) : false);
}

