
window.reg = (function(){

var reg = {};
reg.importAll = function() {
	var errStrings = [];
	try { reg.importSelectorAPI(); }
	catch (err) { errStrings.push(err.message); }
	try { reg.importHelperFunctions(); }
	catch (err) { errStrings.push(err.message); }
	try { reg.importEventFunctions(); }
	catch (err) { errStrings.push(err.message); }
	if (errStrings.length > 0) { if (console && console.log) { console.log(errStrings.join("\n")); } }
};
function globalError(name) {
	return "reglib tried to add \""+name+"\" to global namespace but \""+name+"\" already existed.";
}
if (window.Node && Node.prototype && !Node.prototype.contains) {
	Node.prototype.contains = function (arg) {
		return !!(this.compareDocumentPosition(arg) & 16);
	}
}

var expressions = {
	leadSpace:  new RegExp("^\\s+"),
	tagName:    new RegExp("^([a-z_][a-z0-9_-]*)","i"),
	wildCard:   new RegExp("^\\*([^=]|$)"),
	className:  new RegExp("^(\\.([a-z0-9_-]+))","i"),
	id:         new RegExp("^(#([a-z0-9_-]+))","i"),
	att:        new RegExp("^(@([a-z0-9_-]+))","i"),
	matchType:  new RegExp("(^\\^=)|(^\\$=)|(^\\*=)|(^~=)|(^\\|=)|(^=)"),
	spaceQuote: new RegExp("^\\s+['\"]")
};

// constructor
reg.Selector=function(selString) {
	var exp = expressions;
	this.items = []; // for each comma-separated selector, this array has an item
	var itms = []; // this will be added to this.items
	var count = 0;
	var origSel = selString;
	while (selString.length>0) {
		if (count > 100) { throw new Error("failed parsing '"+origSel+"' stuck at '"+selString+"'"); }
		// get rid of any leading spaces
		var leadSpaceChopped = false;
		if (exp.leadSpace.test(selString)) {
			selString=selString.replace(exp.leadSpace,'');
			leadSpaceChopped = true;
		}

		// find tag name
		var tagNameMatch = exp.tagName.exec(selString);
		if (tagNameMatch) {
			if (itms.length > 0 && itms[itms.length-1].name=='tag') { itms.push({name:'descendant'}); }
			itms.push({name:'tag',tagName:tagNameMatch[1].toLowerCase()});
			selString=selString.substring(tagNameMatch[1].length);
			tagNameMatch=null;
			continue;
		}
		// explicit wildcard selector
		if (exp.wildCard.test(selString)) {
			if (itms.length > 0 && itms[itms.length-1].name=='tag') { itms.push({name:'descendant'}); }
			itms.push({name:'tag',tagName:'*'});
			selString = selString.substring(1);
			continue;
		}
		var classMatch = exp.className.exec(selString);
		var idMatch = exp.id.exec(selString);
		var attMatch = exp.att.exec(selString);
		if (classMatch || idMatch || attMatch) {
			// declare descendant if necessary
			if (leadSpaceChopped && itms.length>0 && itms[itms.length-1].name=='tag') { itms.push({name:'descendant'}); }
			// create a tag wildcard * if necessary
			if (itms.length==0 || itms[itms.length-1].name!='tag') { itms.push({name:'tag',tagName:'*'}); }
			var lastTag = itms[itms.length-1];
			// find class name, like .entry
			if (classMatch) {
				if (!lastTag.classNames) {
					lastTag.classNames = [classMatch[2]];
				} else {
					lastTag.classNames.push(classMatch[2]);
				}
				selString=selString.substring(classMatch[1].length);
				classMatch=null;
				continue;
			}
			// find id, like #content
			if (idMatch) {
				lastTag.id=idMatch[2];
				selString=selString.substring(idMatch[1].length);
				idMatch=null;
				continue;
			}
			// find attribute selector, like @src
			if (attMatch) {
				if (!lastTag.attributes) {
					lastTag.attributes = [{name:attMatch[2]}];
				} else {
					lastTag.attributes.push({name:attMatch[2]});
				}
				selString=selString.substring(attMatch[1].length);
				attMatch=null;
				continue;
			}
		}
		// find attribute value specifier
		var mTypeMatch=exp.matchType.exec(selString);
		if (mTypeMatch) {
			// this will determine how the matching is done
			// (lastTag should still be hanging around)
			if(lastTag && lastTag.attributes && !lastTag.attributes[lastTag.attributes.length-1].value){

				var lastAttribute = lastTag.attributes[lastTag.attributes.length-1];
				lastAttribute.matchType = mTypeMatch[0];

				selString=selString.substring(lastAttribute.matchType.length);
				if(selString.charAt(0)!='"'&&selString.charAt(0)!="'"){
					if(exp.spaceQuote.test(selString)){selString=selString.replace(exp.leadSpace,'');}
					else{throw new Error(origSel+" is invalid, single or double quotes required around attribute values");}
				}
				// it is enclosed in quotes, end is closing quote
				var q=selString.charAt(0);
				var lastQInd=selString.indexOf(q,1);
				if(lastQInd==-1){throw new Error(origSel+" is invalid, missing closing quote");}
				while(selString.charAt(lastQInd-1)=='\\'){
					lastQInd=selString.indexOf(q,lastQInd+1);
					if(lastQInd==-1){throw new Error(origSel+" is invalid, missing closing quote");}
				}
				lastAttribute.value=selString.substring(1,lastQInd);
				if      ('~=' == lastAttribute.matchType) { lastAttribute.valuePatt = new RegExp("(^|\\s)"+lastAttribute.value+"($|\\s)"); }
				else if ('|=' == lastAttribute.matchType) { lastAttribute.valuePatt = new RegExp("^"+lastAttribute.value+"($|\\-)"); }
				selString=selString.substring(lastAttribute.value.length+2);// +2 for the quotes
				continue;
			} else {
				throw new Error(origSel+" is invalid, "+mTypeMatch[0]+" appeared without preceding attribute identifier");
			}
			mTypeMatch=null;
		}
		// find child selector
		if (selString.charAt(0) == '>') {
			itms.push({name:'child'});
			selString=selString.substring(1);
			continue;
		}
		// find next sibling selector
		if (selString.charAt(0) == '+') {
			itms.push({name:'nextSib'});
			selString=selString.substring(1);
			continue;
		}
		// find after sibling selector
		if (selString.charAt(0) == '~') {
			itms.push({name:'followingSib'});
			selString=selString.substring(1);
			continue;
		}
		// find the comma separator
		if (selString.charAt(0) == ',') {
			this.items.push(itms);
			itms = [];
			selString = selString.substring(1);
			continue;
		}
		count++;
	}
	this.items.push(itms);
	this.selectorString=origSel;
	// do some structural validation
	for (var a=0;a<this.items.length;a++){
		var itms = this.items[a];
		if (itms.length==0) { throw new Error("illegal structure: '"+origSel+"' contains an empty set"); }
		if (itms[0].name!='tag') { throw new Error("illegal structure: '"+origSel+"' contains a dangling relation"); }
		if (itms[itms.length-1].name!='tag') { throw new Error("illegal structure: '"+origSel+"' contains a dangling relation"); }
		for(var b=1;b<itms.length;b++){
			if(itms[b].name!='tag'&&itms[b-1].name!='tag'){ throw new Error("illegal structure: '"+origSel+"' contains doubled up relations"); }
		}
	}
}

// returns string suitable for querySelector() and querySelectorAll()
function toQuerySelectorString(sel) {
	if (!sel.qss) {
		var itemStrings = [];
		for (var i=0; i<sel.items.length; i++) {
			var result = '';
			var item = sel.items[i];
			for (var j=0; j<item.length; j++) {
				var des = item[j];
				if (des.name=='tag') {
					result += des.tagName;
					if (des.classNames) { result += "." + des.classNames.join("."); }
					if (des.id) { result += '#' + des.id; }
					if (des.targeted) {  result += ':target'; }
					if (des.attributes) {

						for (var k=0; k<des.attributes.length; k++) {
							result += '[' + des.attributes[k].name;
							if (des.attributes[k].matchType) {
								result += des.attributes[k].matchType;
								result += '"'+des.attributes[k].value.replace(/"/,'\\"')+'"';
							}
							result += ']';
						}

					}
				} else if (des.name=='descendant') {
					result += ' ';
					continue;
				} else if (des.name=='child') {
					result += ' > ';
					continue;
				} else if (des.name=='followingSib') {
					result += ' ~ ';
					continue;
				} else if (des.name=='nextSib') {
					result += ' + ';
					continue;
				}
			}
			itemStrings.push(result);
		}
		sel.qss = itemStrings.join(', ');
	}
	return sel.qss;
}

// match against an element
reg.Selector.prototype.matches = function(el) {
	if (!el) { throw new Error('no element provided'); }
	if (el.nodeType != 1) { throw new Error(this.selectorString+' cannot be evaluated against element of type '+el.nodeType); }
	commas:for (var a=0;a<this.items.length;a++) { // for each comma-separated selector
		var tempEl = el;
		var itms = this.items[a];
		for (var b=itms.length-1; b>=0; b--) { // loop backwards through the items
			var itm = itms[b];
			if (itm.name == 'tag') {
				if (!matchIt(tempEl, itm)) {
					// these relational selectors require more extensive searching
					if (tempEl && b < itms.length-1 && itms[b+1].name=='descendant') { tempEl=tempEl.parentNode; b++; continue; }
					else if (tempEl && b < itms.length-1 && itms[b+1].name=='followingSib') { tempEl=tempEl.previousSibling; b++; continue; }
					else { continue commas; } // fail this one
				}
			}
			else if (itm.name == 'nextSib') { tempEl = previousElement(tempEl); }
			else if (itm.name == 'followingSib') { tempEl = previousElement(tempEl); }
			else if (itm.name == 'child') { tempEl = tempEl.parentNode; }
			else if (itm.name == 'descendant') { tempEl = tempEl.parentNode; }
		}
		return true;
	}
	return false;
};

// subroutine for matches() above
function matchIt(el, itm) {
	// try to falsify as soon as possible
	if (!el) { return false; }
	if (el.nodeName.toLowerCase()!=itm.tagName && itm.tagName!='*') { return false; }
	if (itm.classNames) {
		 for (var i=0; i<itm.classNames.length; i++) {
			if (!hasClassName(el, itm.classNames[i])) {
				return false;
			}
		}
	}
	if (itm.id && el.id != itm.id) { return false; }
	if (itm.attributes) {
		for (var i=0; i<itm.attributes.length; i++) {
			var itmAtt = itm.attributes[i];
			if (typeof el.hasAttribute != 'undefined') {
				if (!el.hasAttribute(itmAtt.name)) { return false; }
				var att = el.getAttribute(itmAtt.name);
			}else{
				if(el.nodeType!=1) {return false;}
				var att = el.getAttribute(itmAtt.name,2);//ie6/7 returns fully resolved href but ,2 fixes that
				if(itmAtt.name=='class'){att=el.className;}//todo:remove this line
				else if(itmAtt.name=='for'){att=el.htmlFor;}//todo:and this one
				if(!att){return false;}
			}
			if (itmAtt.value) {
				if (itmAtt.matchType=='^='){
					if (att.indexOf(itmAtt.value)!=0){return false;}
				} else if (itmAtt.matchType=='*='){
					if (att.indexOf(itmAtt.value)==-1){return false;}
				} else if (itmAtt.matchType=='$='){
					var indOf = att.indexOf(itmAtt.value);
					if (indOf===-1||indOf!=att.length-itmAtt.value.length){return false;}
				} else if (itmAtt.matchType=='='){
					if (att!=itmAtt.value){return false;}
				} else if ('|='==itmAtt.matchType || '~='==itmAtt.matchType){
					if (!itmAtt.valuePatt.test(att)){return false;}
				}else{
					if(!itmAtt.matchType){throw new Error("illegal structure, parsed selector cannot have null or empty attribute match type");}
					else{throw new Error("illegal structure, parsed selector cannot have '"+itm.matchType+"' as an attribute match type");}
				}
			}
		}
	}
	return true;
}

// gets the tag names that the selector represents
function getTagNames(sel) {
	var hash = {}; // this avoids dupes
	for (var a=0;a<sel.items.length;a++){
		hash[sel.items[a][sel.items[a].length-1].tagName]=null;
	}
	var result = [];
	for (var tag in hash){if(hash.hasOwnProperty(tag)){result.push(tag);}}
	return result;
}

reg.importSelectorAPI = function() {
	if (window.Selector) { throw new Error(globalError("Selector")); }
	window.Selector = reg.Selector;
};

// #############################################################################
// #### DOM HELPERS ############################################################
// #############################################################################

/*
A bunch of DOM convenience methods (alias names in braces):

CLASSNAMES
- reg.addClassName(el, cName)..............................{acn}
- reg.getElementsByClassName(cNames[, ctxNode[, tagName]]).{gebcn}
- reg.hasClassName(el, cName)..............................{hcn}
- reg.matchClassName(el, regexp)...........................{mcn}
- reg.removeClassName(el, cName)...........................{rcn}
- reg.switchClassName(el, cName1, cName2)..................{scn}
- reg.toggleClassName(el, cName)...........................{tcn}

SELECTORS
- reg.elementMatchesSelector(el, selString)................{matches}
- reg.getElementsBySelector(selString[, ctxNode])..........{gebs}

OTHER
- reg.elementText(el)......................................{elemText}
- reg.getElementById().....................................{gebi}
- reg.getElementsByTagName(tagName[, ctxNode]).............{gebtn}
- reg.getParent(el, selString)
- reg.innerWrap(el, wrapperEl)
- reg.insertAfter(insertMe, afterThis)
- reg.newElement(tagName[, attObj[, contents]])............{elem}
- reg.nextElement(el)......................................{nextElem}
- reg.outerWrap(el, wrapperEl)
- reg.previousElement(el)..................................{prevElem}
*/

var clPatts={};// cache compiled classname regexps
var cSels={};// cache compiled selectors

// TEST FOR CLASS NAME
function hasClassName(element, cName) {
	if (!clPatts[cName]) { clPatts[cName] = new RegExp("(^|\\s)"+cName+"($|\\s)"); }
	return element.className && clPatts[cName].test(element.className);
}

// ADD CLASS NAME
function addClassName(element, cName) {
	if (!hasClassName(element, cName)) {
		element.className += ' ' + cName;
	}
}

// REMOVE CLASS NAME
function removeClassName(element, cName) {
	if (!clPatts[cName]) { clPatts[cName] = new RegExp("(^|\\s+)"+cName+"($|\\s+)"); }
	element.className = element.className.replace(clPatts[cName], ' ');
}

// TOGGLE CLASS NAME
function toggleClassName(element, cName) {
	if (hasClassName(element, cName)) { removeClassName(element, cName); }
	else { addClassName(element, cName); }
}

// SWITCH CLASS NAME A->B, B->A
function switchClassName(element, cName1, cName2) {
	if (cName1 == cName2) { throw new Error("cName1 and cName2 both equal "+cName1); }
	var has1 = hasClassName(element, cName1);
	var has2 = hasClassName(element, cName2);
	if (has1 && has2) { removeClassName(element, cName2); }
	else if (!has1 && !has2) { addClassName(element, cName1); }
	else if (has1) { removeClassName(element, cName1); addClassName(element, cName2); }
	else { removeClassName(element, cName2); addClassName(element, cName1); }
}

// TEST FOR CLASS NAME BY REGEXP
function matchClassName(element, pattern){
	var cNames = element.className.split(' ');
	for (var a=0; a<cNames.length; a++){
		var matches = cNames[a].match(pattern);
		if (matches) { return matches; }
	}
	return null;
}

// TEST AGAINST SELECTOR
function elementMatchesSelector(element, selString){
	if(!cSels[selString]){cSels[selString]=new reg.Selector(selString);}
	return cSels[selString].matches(element);
}

// FIND PREVIOUS ELEMENT
function previousElement(el) {
	var prev = el.previousSibling;
	while(prev && prev.nodeType!=1){prev=prev.previousSibling;}
	return prev;
}

// FIND NEXT ELEMENT
function nextElement(el) {
	var next = el.nextSibling;
	while(next && next.nodeType!=1){next=next.nextSibling;}
	return next;
}

// ADD INNER WRAPPER
function innerWrap(el, wrapperEl) {
	var nodes = el.childNodes;
	while (nodes.length > 0) {
		var myNode = nodes[0];
		el.removeChild(myNode);
		wrapperEl.appendChild(myNode);
	}
	el.appendChild(wrapperEl);
}

// ADD OUTER WRAPPER
function outerWrap(el, wrapperEl) {
	el.parentNode.insertBefore(wrapperEl, el);
	el.parentNode.removeChild(el);
	wrapperEl.appendChild(el);
}

// GET PARENT
function getParent(el, selString) {
	var parsedSel = new reg.Selector(selString);
	while (el.parentNode) {
		el = el.parentNode;
		if (el.nodeType==1 && parsedSel.matches(el)) { return el; }
	}
	return null;
}

// INSERT AFTER
function insertAfter(insertMe, afterThis){
	var beforeThis = afterThis.nextSibling;
	var parent = afterThis.parentNode;
	if (beforeThis) { parent.insertBefore(insertMe, beforeThis); }
	else { parent.appendChild(insertMe); }
}

// SHORTCUT FOR BUILDING ELEMENTS
function newElement(name, atts, content) {
	// name: e.g. 'div', 'div.foo', 'div#bar', 'div.foo#bar', 'div#bar.foo'
	// atts: (optional) e.g. {'href':'page.html','target':'_blank'}
	// content: (optional) either a string, or an element, or an arry of strings or elements
	if (name.indexOf('.') + name.indexOf('#') > -2) {
		var className = (name.indexOf('.') > -1) ? name.replace(/^.*\.([^\.#]*).*$/,"$1") : "";
		var id = (name.indexOf('#') > -1) ? name.replace(/^.*#([^\.#]*).*$/,"$1") : "";
		name = name.replace(/^([^\.#]*).*$/,'$1');
	}
	var e = document.createElement(name);
	if (className) { e.className = className; }
	if (id) { e.id = id; }
	if (atts) {
		for (var key in atts) {
			// setAttribute() has shaky support, try direct methods first
			if (!atts.hasOwnProperty(key)) { continue; }
			if (key == 'class') { e.className = e.className ? e.className += ' ' + atts[key] : atts[key]; }
			else if (key == 'for') { e.htmlFor = atts[key]; }
			else if (key.indexOf('on') == 0) { e[key] = atts[key]; }
			else {
				e.setAttribute(key, atts[key]);
			}
		}
	}
	if (content) {
		if (!(content instanceof Array)) {
			content = [content];
		}
		for (var a=0; a<content.length; a++) {
			if (content[a].nodeType !== undefined) {
				e.appendChild(content[a]);
			}else{
				e.appendChild(document.createTextNode(content[a]));
			}
		}
	}
	if (name.toLowerCase() == 'img' && !e.alt) { e.alt = ''; }
	return e;
}

// GRAB JUST THE TEXTUAL DATA OF AN ELEMENT
function elementText(el) {
	// <a id="foo" href="page.html">click <b>here</b></a>
	// elementText(document.getElementById('foo')) == "click here"
	// warning: recurses through *all* descendants of el
	if(!el){return '';}
	var chlds = el.childNodes;
	var result = '';
	if (reg.matches(el,'img@alt,area@alt')) { result += el.alt; }
	else if (reg.matches(el,'input')) { result += el.value; }
	else {
		for (var a=0; a<chlds.length; a++) {
			if (3 == chlds[a].nodeType) {
				result += chlds[a].data;
			} else if (1 == chlds[a].nodeType) {
				result += elementText(chlds[a]);
			}
		}
	}
	return result;
}

// GET ELEMENT BY ID
function getElementById(id) { return document.getElementById(id); }

// GET ELEMENTS BY TAG NAME
function getElementsByTagName(tag, contextNode) {
	if(!contextNode){contextNode=document;}
	return contextNode.getElementsByTagName(tag);
}

// GET ELEMENTS BY SELECTOR
var classTest = /^\s*([a-z0-9_-]+)?\.([a-z0-9_-]+)\s*$/i;
var idTest = /^\s*([a-z0-9_-]+)?\#([a-z0-9_-]+)\s*$/i;
function getElementsBySelector(selString, contextNode) {
	contextNode = contextNode || window.document.documentElement;
	var result = [];
	var cMat, iMat;
	if (cMat = selString.match(classTest)) {
		var cl = cMat[2];
		var tg = cMat[1];
		result = reg.gebcn(cl, contextNode, tg);
	} else if (iMat = selString.match(idTest)) {
		var id = iMat[2];
		var tg = iMat[1];
		var el = reg.gebi(id);
		if (el && contextNode.contains(el) && reg.matches(el, selString)) { result[0] = el; }
	} else {
		if (!cSels[selString]) { cSels[selString] = new reg.Selector(selString); }
		var sel = cSels[selString];
		if (contextNode.querySelectorAll) {
			var qlist = contextNode.querySelectorAll(toQuerySelectorString(sel));
			for (var i=0; i<qlist.length; i++) {
				result[result.length] = qlist[i];
			}
		} else {
			var tagNames = getTagNames(sel);
			for (var a=0; a<tagNames.length; a++) {
				var els = getElementsByTagName(tagNames[a], contextNode);
				for (var b=0, el; el=els[b++];) {
					if (el.nodeType!=1) { continue; }
					if (sel.matches(el)) { result.push(el); }
				}
			}
		}
	}
	return result;
}

// GET ELEMENTS BY CLASS NAME
function getElementsByClassName(classNames, contextNode, tag) {
	contextNode = (contextNode) ? contextNode : document;
	tag = (tag) ? tag.toLowerCase() : '*';
	var results = [];
	if (document.getElementsByClassName) {
		// traverse natively
		var liveList = contextNode.getElementsByClassName(classNames);
		if (tag != '*') {
			for (var i=0; i<liveList.length; i++) {
				var el = liveList[i];
				if (tag == el.nodeName.toLowerCase()) {
					results.push(el);
				}
			}
		} else {
			for (var i=0; i<liveList.length; i++) { results.push(liveList[i]); }
		}
	} else {
		classNames = classNames.split(/\s+/);
		if (document.evaluate) {
			// traverse w/ xpath
			var xpath = ".//"+tag;
			var len = classNames.length;
			for(var i=0; i<len; i++) {
				xpath += "[contains(concat(' ', @class, ' '), ' " + classNames[i] + " ')]";
			}
			var xpathResult = document.evaluate(xpath, contextNode, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, xpathResult);
			var el;
			while (el = xpathResult.iterateNext()) {
				results.push(el);
			}
		} else {
			// traverse w/ dom
			var els = (tag=='*'&&contextNode.all) ? contextNode.all : getElementsByTagName(tag,contextNode);
			elements:for (var i=0,el;el=els[i++];) {
				for (var j=0; j<classNames.length; j++) {
					if (!hasClassName(el, classNames[j])) { continue elements; }
				}
				results.push(el);
			}
		}
	}
	return results;
}

var helpers = {
	hasClassName:           hasClassName,
	addClassName:           addClassName,
	removeClassName:        removeClassName,
	toggleClassName:        toggleClassName,
	switchClassName:        switchClassName,
	matchClassName:         matchClassName,
	elementMatchesSelector: elementMatchesSelector,
	previousElement:        previousElement,
	nextElement:            nextElement,
	innerWrap:              innerWrap,
	outerWrap:              outerWrap,
	getParent:              getParent,
	insertAfter:            insertAfter,
	newElement:             newElement,
	elementText:            elementText,
	getElementById:         getElementById,
	getElementsByTagName:   getElementsByTagName,
	getElementsBySelector:  getElementsBySelector,
	getElementsByClassName: getElementsByClassName
};

// aliases
helpers.hcn      = helpers.hasClassName;
helpers.acn      = helpers.addClassName;
helpers.rcn      = helpers.removeClassName;
helpers.tcn      = helpers.toggleClassName;
helpers.scn      = helpers.switchClassName;
helpers.mcn      = helpers.matchClassName;
helpers.matches  = helpers.elementMatchesSelector;
helpers.prevElem = helpers.previousElement;
helpers.nextElem = helpers.nextElement;
helpers.elem     = helpers.newElement;
helpers.elemText = helpers.elementText;
helpers.gebi     = helpers.getElementById;
helpers.gebtn    = helpers.getElementsByTagName;
helpers.gebs     = helpers.getElementsBySelector;
helpers.gebcn    = helpers.getElementsByClassName;

// add it globally
reg.importHelperFunctions = function() {
	var errStrings = [];
	for (var func in helpers) {
		if(!helpers.hasOwnProperty(func)) { continue; }
		if (window[func]) { errStrings.push(globalError(func)); }
		else { window[func] = helpers[func]; }
	}
	if (errStrings.length > 0) { throw new Error(errStrings.join("\n")); }
};

// add it to reg
for (var func in helpers) {
	if(!helpers.hasOwnProperty(func)) { continue; }
	if (reg[func]) { throw new Error("Already exists under reg: "+func); }
	else { reg[func] = helpers[func]; }
}

// #############################################################################
// #### X-BROWSER EVENTS #######################################################
// #############################################################################

/*
Event attachment and detachment:
*/

// get the element on which the event occurred
function getTarget(e) {
	if (!e) { e = window.event; }
	if (e.target) { var targ = e.target; }
	else if (e.srcElement) { var targ = e.srcElement; }
	if (targ.nodeType == 3) { targ = targ.parentNode; } // safari hack
	return targ;
}

// get the element on which the event occurred
function getRelatedTarget(e) {
	if (!e) { e = window.event; }
	var rTarg = e.relatedTarget;
	if (!rTarg) {
		if ('mouseover'==e.type) { rTarg = e.fromElement; }
		if ('mouseout'==e.type) { rTarg = e.toElement; }
	}
	return rTarg;
}

// cancel default action
function cancelDefault(e) {
	if (typeof e.preventDefault != 'undefined') { e.preventDefault(); return; }
	e.returnValue=false;
}

// cancel bubble
function cancelBubble(e) {
	if (typeof e.stopPropagation != 'undefined') { e.stopPropagation(); return; }
	e.cancelBubble=true;
}

// event registry
var memEvents = {};
var aMemInd = 0;
function rememberEvent(elmt,evt,handle,cptr,cleanable){
	var memInd = aMemInd++;
	memEvents[memInd+""] = {
		element:   elmt,
		event:     evt,
		handler:   handle,
		capture:   !!cptr,
		cleanable: !!cleanable
	};
	return memInd;
}

// event remover
function removeEvent(memInd) {
	var key = memInd+"";
	var eo = memEvents[key];
	if (eo) {
		var el=eo.element;
		if(el.removeEventListener) {
			el.removeEventListener(eo.event, eo.handler, eo.capture);
			delete memEvents[key];
			return true;
		} else if(el.detachEvent) {
			el.detachEvent('on'+eo.event, eo.handler);
			delete memEvents[key];
			return true;
		}
	}
	return false;
}

// if "all" is true, it nukes all events
// otherwise only those created with "cleanable" flag
function cleanup(all){
	for (var key in memEvents) {
		if (!memEvents.hasOwnProperty(key)) { continue; }
		if (all || (memEvents[key].cleanable && !document.documentElement.contains(memEvents[key].element))) {
			removeEvent(key);
			//console.log("cleaning up event: "+key);
		}
	}
}

//periodically clean up all cleanable events
window.setInterval(function(){
	cleanup(false);
},10000);

// generic event adder, plus memory leak prevention
// returns an int mem that you can use to later remove that event removeEvent(mem)
// cptr defaults false
function addEvent(elmt,evt,handler,cptr,cleanable) {
	if(elmt.addEventListener){
		elmt.addEventListener(evt,handler,cptr);
		return rememberEvent(elmt,evt,handler,cptr,cleanable);
	}else if(elmt.attachEvent){
		var actualHandler = function(){handler.call(elmt,window.event);};
		elmt.attachEvent("on"+evt,actualHandler);
		return rememberEvent(elmt,evt,actualHandler,cptr,cleanable);
	}
}

// try to reduce memory leaks in ie
addEvent(window,'unload',function(){cleanup(true)});

var events = {
	getTarget:        getTarget,
	getRelatedTarget: getRelatedTarget,
	cancelDefault:    cancelDefault,
	addEvent:         addEvent,
	removeEvent:      removeEvent,
	cancelBubble:     cancelBubble
};

reg.importEventFunctions = function() {
	var errStrings = [];
	for (var func in events) {
		if(!events.hasOwnProperty(func)) { continue; }
		if (window[func]) { errStrings.push(globalError(func)); }
		else { window[func] = events[func]; }
	}
	if (errStrings.length > 0) { throw new Error(errStrings.join("\n")); }
};

for (var func in events) {
	if(!events.hasOwnProperty(func)) { continue; }
	if (reg[func]) { throw new Error("Already exists under reg: "+func); }
	else { reg[func] = events[func]; }
}

// #############################################################################
// #### ON(DOM)LOAD ACTIONS ####################################################
// #############################################################################

/*
Add actions to run onload:
- reg.preSetup(func)
- reg.setup(selString, func, firstTimeOnly)
- reg.postSetup(func)

!!! WARNING !!!
On browsers *without* native querySelector() support
reg.setup makes page load time O(MN)
where M is the number of calls to reg.setup()
and N is the number of elements on the page
*/

// these contain lists of things to do
var preSetupQueue=[];
var setupQueue=[];
var setupQueueByTag={};
var postSetupQueue=[];

// traverse and act onload
reg.setup=function(selector, setup, firstTimeOnly){
	firstTimeOnly=!!firstTimeOnly;
	var sqt=setupQueueByTag;
	var parsedSel = new reg.Selector(selector);
	var tagNames=getTagNames(parsedSel);
	var regObj={
		selector:parsedSel,
		setup:setup,
		ran:false,
		firstTimeOnly:firstTimeOnly
	};
	setupQueue.push(regObj);
	for(var a=0;a<tagNames.length;a++){
		var tagName = tagNames[a];
		if(!sqt[tagName]){sqt[tagName]=[regObj];}
		else{sqt[tagName].push(regObj);}
	}
};
// do this before setup
reg.preSetup=function(fn){preSetupQueue.push(fn);};
// do this after setup
reg.postSetup=function(fn){postSetupQueue.push(fn);};

// (re)run setup functions
var runSetupFunctions = reg.rerun = function(el, noClobber){
	function runIt(el, regObj){
		regObj.setup.call(el);
		regObj.ran=true;
	}
	var start = new Date().getTime();
	if (typeof el.clobberable != 'undefined' && el.clobberable && noClobber) { return; }
	var doc=(el)?el:document;
	var sqt=setupQueueByTag;
	var sqtIsEmpty=true;
	for (var tagName in sqt) {
		if(!sqt.hasOwnProperty(tagName)) { continue; }
		sqtIsEmpty = false;
		break;
	}

	if (el.querySelector) {

		//####################################
		//querySelector() branch

		var qSelResults = [];
		for (var i=0; i<setupQueue.length; i++) {
			var regObj = setupQueue[i];
			if (regObj.firstTimeOnly) {
				if (regObj.ran) { continue; }
				try {
					var elmt = el.querySelector(toQuerySelectorString(regObj.selector));
					if (elmt) { qSelResults.push({el:elmt,regObj:regObj}); }
				} catch (ex) {
					console.log("querySelector('"+toQuerySelectorString(regObj.selector)+"') threw "+ex);
					continue;
				}
			} else {
				try {
					var elmts = el.querySelectorAll(toQuerySelectorString(regObj.selector));
					for (var j=0; j<elmts.length; j++) {
						qSelResults.push({el:elmts[j],regObj:regObj});
					}
				} catch (ex) {
					console.log("querySelectorAll('"+toQuerySelectorString(regObj.selector)+"') threw "+ex);
					continue;
				}
			}
		}
		for (var i=0; i<qSelResults.length; i++) {
			runIt(qSelResults[i].el, qSelResults[i].regObj);
		}
	} else if (!sqtIsEmpty) {

		//####################################
		//old branch

		var elsList=getElementsByTagName('*',doc);

		//dump live list to static list
		for (var i=elsList.length-1, els=[]; i>=0; i--) {
			els[i] = elsList[i];
		}

		var qSelResults = [];

		// crawl the dom
		for(var a=0,elmt;elmt=els[a++];){
			if (elmt.nodeType!=1){continue;}//for ie7
			var lcNodeName=elmt.nodeName.toLowerCase();
			var regObjArrayAll=sqt['*'];
			var regObjArrayTag=sqt[lcNodeName];

			// any wildcards?
			if(regObjArrayAll){
				for(var b=0;b<regObjArrayAll.length;b++){
					var regObj=regObjArrayAll[b];
					if(regObj.firstTimeOnly && regObj.ran){continue;}
					var matches = regObj.selector.matches(elmt);
					if(matches){
						qSelResults.push({el:elmt,regObj:regObj});
						regObj.ran = true;
					}
				}
			}

			// any items match this specific tag?
			if(regObjArrayTag){
				for(var b=0;b<regObjArrayTag.length;b++){
					var regObj=regObjArrayTag[b];
					if(regObj.firstTimeOnly && regObj.ran){continue;}
					var matches = regObj.selector.matches(elmt);
					if(matches){
						qSelResults.push({el:elmt,regObj:regObj});
						regObj.ran = true;
					}
				}
			}
		}
		for (var i=0; i<qSelResults.length; i++) {
			runIt(qSelResults[i].el, qSelResults[i].regObj);
		}

	}
	el.clobberable = true;
	var runtime = new Date().getTime() - start;
	if(!reg.setupTime){ reg.setupTime=runtime; }
	reg.lastSetupTime=runtime;
}

var ie6 = navigator.appVersion.indexOf('MSIE 6.0') != -1;
if (!ie6) {
	addClassName(document.documentElement, 'regloading');
}
var loadFuncRan = false;
function loadFunc(e) {
	if (!loadFuncRan) {
		loadFuncRan = true;
		for(var a=0;a<preSetupQueue.length;a++){
			preSetupQueue[a]();
		}
		runSetupFunctions(document, true);
		for(var a=0;a<postSetupQueue.length;a++){
			postSetupQueue[a]();
		}
		if (!ie6) {
			// unfortunately this causes hangs and laborious redraws in ie6
			removeClassName(document.documentElement, 'regloading');
			addClassName(document.documentElement, 'regloaded');
		}
	}
}

// contents of loadFunc only execute once, this sidesteps user agent sniffing
addEvent(window, 'load', loadFunc);
addEvent(window, 'DOMContentLoaded', loadFunc);

// #############################################################################
// #### EVENT DELEGATION #######################################################
// #############################################################################

/*
The main purpose of reglib is event delegation:
- reg.click(selString, handler, depth)
- reg.hover(selString, overHandler, outHandler, depth)
- reg.focus(selString, focusHandler, blurHandler, depth)
- reg.key(selString, downHandler, pressHandler, upHandler, depth)
- reg.submit(selString, handler, depth)
- reg.reset(selString, handler, depth)
- reg.change(selString, handler, depth)
- reg.select(selString, handler, depth)

delegated events are active before page load, and remain
active throughout arbitrary rewrites of the DOM.
*/

// these contain the event handling functions
var clickHandlers = {};
var mDownHandlers = {};
var mUpHandlers = {};
var dblClickHandlers = {};
var mOverHandlers = {};
var mOutHandlers = {};
var focusHandlers = {};
var blurHandlers = {};
var keyDownHandlers = {};
var keyPressHandlers = {};
var keyUpHandlers = {};
var submitHandlers = {};
var resetHandlers = {};
var changeHandlers = {};
var selectHandlers = {};

// returns first arg that's a number
function getDepth(fargs){
	var result = null;
	for (var i=2; i<fargs.length; i++) {
		if (!isNaN(parseInt(fargs[i]))) {
			result = fargs[i];
			break;
		}
	}
	if(result===null){result=-1;}
	if(result<-1){throw new Error("bad arg for depth, must be -1 or higher");}
	return result;
}

// add a handler function
function pushFunc(selStr, handlerFunc, depth, handlers, hoverFlag) {
	if(!handlerFunc || typeof handlerFunc != "function"){return;}
	var parsedSel = new reg.Selector(selStr);
	if(!handlers[selStr]) {handlers[selStr]=[];}
	var selHandler = {
		selector:parsedSel,
		handle:handlerFunc,
		depth:depth,
		hoverFlag:hoverFlag
	};
	handlers[selStr].push(selHandler);
}

reg.click=function(selStr, clickFunc, downFunc, upFunc, doubleFunc){
	var depth = getDepth(arguments);
	pushFunc(selStr, clickFunc,  depth, clickHandlers,    false);
	pushFunc(selStr, downFunc,   depth, mDownHandlers,    false);
	pushFunc(selStr, upFunc,     depth, mUpHandlers,      false);
	pushFunc(selStr, doubleFunc, depth, dblClickHandlers, false);
};
reg.hover=function(selStr, overFunc, outFunc){
	var depth = getDepth(arguments);
	pushFunc(selStr, overFunc, depth, mOverHandlers, true);
	pushFunc(selStr, outFunc,  depth, mOutHandlers,  true);
};
reg.focus=function(selStr, focusFunc, blurFunc){
	var depth = getDepth(arguments);
	pushFunc(selStr, focusFunc, depth, focusHandlers, false);
	pushFunc(selStr, blurFunc,  depth, blurHandlers,  false);
};
reg.key=function(selStr, downFunc, pressFunc, upFunc){
	var depth = getDepth(arguments);
	pushFunc(selStr, downFunc,  depth, keyDownHandlers,  false);
	pushFunc(selStr, pressFunc, depth, keyPressHandlers, false);
	pushFunc(selStr, upFunc,    depth, keyUpHandlers,    false);
};
reg.submit=function(selStr, func) {
	var depth = getDepth(arguments);
	pushFunc(selStr, func, depth, submitHandlers, false);
};
reg.reset=function(selStr, func) {
	var depth = getDepth(arguments);
	pushFunc(selStr, func, depth, resetHandlers, false);
};
reg.change=function(selStr, func) {
	var depth = getDepth(arguments);
	pushFunc(selStr, func, depth, changeHandlers, false);
};
reg.select=function(selStr, func) {
	var depth = getDepth(arguments);
	pushFunc(selStr, func, depth, selectHandlers, false);
};

// workaround for IE's lack of support for bubbling on form events
// set delegation directly on the element in question by co-opting
// the focus event which is guaranteed to happen first
if (document.all && !window.opera) {
	function ieSubmitDelegate(e) {
		delegate(submitHandlers,e);
		cancelBubble(e);
	}
	function ieResetDelegate(e) {
		delegate(resetHandlers,e);
		cancelBubble(e);
	}
	function ieChangeDelegate(e) {
		delegate(changeHandlers,e);
		cancelBubble(e);
	}
	function ieSelectDelegate(e) {
		delegate(selectHandlers,e);
		cancelBubble(e);
	}
	reg.focus('form',function(){
		removeEvent(this._submit_prep);
		this._submit_prep=addEvent(this,'submit',ieSubmitDelegate,false,true);
		removeEvent(this._reset_prep);
		this._reset_prep=addEvent(this,'reset',ieResetDelegate,false,true);
	},function(){
		removeEvent(this._submit_prep);
		removeEvent(this._reset_prep);
	});
	reg.focus('select,input,textarea',function(){
		removeEvent(this._change_prep);
		this._change_prep=addEvent(this,'change',ieChangeDelegate,false,true);
	},function(){
		removeEvent(this._change_prep);
	});
	reg.focus('input,textarea',function(){
		removeEvent(this._select_prep);
		this._select_prep=addEvent(this,'select',ieSelectDelegate,false,true);
	},function(){
		removeEvent(this._select_prep);
	});
}

// the delegator
function delegate(selectionHandlers, event) {
	if (selectionHandlers) {
		var execList = [];
		var targ = getTarget(event);
		for (var sel in selectionHandlers) {
			if(!selectionHandlers.hasOwnProperty(sel)) { continue; }
			for(var a=0; a<selectionHandlers[sel].length; a++) {
				var selHandler=selectionHandlers[sel][a];
				var depth = (selHandler.depth==-1) ? 100 : selHandler.depth;
				var el = targ;
				for (var b=-1; b<depth && el && el.nodeType == 1; b++, el=el.parentNode) {
					if (selHandler.selector.matches(el)) {
						// replicate mouse enter/leave
						if (selHandler.hoverFlag) {
							var relTarg = getRelatedTarget(event);
							if (relTarg && (el.contains(relTarg) || el == relTarg)) {
								break;
							}
						}
						execList.push({"handle":selHandler.handle,"element":el});
						break;
					}
				}
			}
		}
		for (var i=0; i<execList.length; i++) {
			var exec = execList[i];
			var retVal=exec.handle.call(exec.element,event);
			// if they return false from the handler, cancel default
			if(retVal!==undefined && !retVal) {
				cancelDefault(event);
			}
		}
	}
}

if(typeof document.onactivate == 'object'){
	var focusEventType = 'activate';
	var blurEventType = 'deactivate';
}else{
	var focusEventType = 'focus';
	var blurEventType = 'blur';
}

// attach the events
var docEl = document.documentElement;
addEvent(docEl,'click',        function(e){delegate(clickHandlers,   e);});
addEvent(docEl,'mousedown',    function(e){delegate(mDownHandlers,   e);});
addEvent(docEl,'mouseup',      function(e){delegate(mUpHandlers,     e);});
addEvent(docEl,'dblclick',     function(e){delegate(dblClickHandlers,e);});
addEvent(docEl,'keydown',      function(e){delegate(keyDownHandlers, e);});
addEvent(docEl,'keypress',     function(e){delegate(keyPressHandlers,e);});
addEvent(docEl,'keyup',        function(e){delegate(keyUpHandlers,   e);});
addEvent(docEl,focusEventType, function(e){delegate(focusHandlers,   e);},true);
addEvent(docEl,blurEventType,  function(e){delegate(blurHandlers,    e);},true);
addEvent(docEl,'mouseover',    function(e){delegate(mOverHandlers,   e);});
addEvent(docEl,'mouseout',     function(e){delegate(mOutHandlers,    e);});
addEvent(docEl,'submit',       function(e){delegate(submitHandlers,  e);});
addEvent(docEl,'reset',        function(e){delegate(resetHandlers,   e);});
addEvent(docEl,'change',       function(e){delegate(changeHandlers,  e);});
addEvent(docEl,'select',       function(e){delegate(selectHandlers,  e);});

// #############################################################################
// #### CONSOLE.LOG BACKUP #####################################################
// #############################################################################

/*
For backwards compatibility.
Allows console.log() to be called in old clients without errors.
in which case console.contents() fetches logged messages.
*/

var logMessages = [];
var log = function(str) { logMessages.push(str); };
var contents = function() { return logMessages.join("\n")+"\n"; };
if (!window.console) { window.console = { log : log, contents : contents }; }
else {
	if (!window.console.log) {
		window.console.log = log;
		if (!window.console.contents) { window.console.contents = contents; }
	}
}

// #############################################################################
// #### AND... DONE. ###########################################################
// #############################################################################

addClassName(docEl, 'regenabled');
return reg;

})();



reg.importAll();//this adds things like addClassName() to global namespace

// BROWSER SNIFF
var is = new ottosniff();
function ottosniff(){
	var ua = navigator.userAgent.toLowerCase();
	var b = navigator.appName;
	if (b=="Netscape") this.b = "ns";
	else this.b = b;
	this.version = navigator.appVersion;
	this.v = parseInt(this.version);
	this.gecko = /\bgecko\/(20\d\d)(\d\d)(\d\d)/.test(ua);
	this.ns = (this.b=="ns" && this.v>=5);
	this.op = (ua.indexOf('opera')>-1);
	this.safari = (ua.indexOf('safari')>-1 && this.v < 5);
	this.safariAll = (ua.indexOf('safari')>-1);
	this.op7 = (this.op && this.v>=7 && this.v<8);
	this.op78 = (this.op && this.v>=7 || this.op && this.v>=8);
	this.ie5 = (this.version.indexOf('MSIE 5')>-1);
	this.ie6 = (this.version.indexOf('MSIE 6')>-1);
	this.ie7 = (this.version.indexOf('MSIE 7')>-1);
	this.ie8 = (this.version.indexOf('MSIE 8')>-1);
	this.ie56 = (this.ie5||this.ie6);
	this.ie567 = (this.ie5||this.ie6||this.ie7);
	this.ie = (this.ie5||this.ie6||this.ie7||this.ie8);
	this.iewin = (this.ie56 && ua.indexOf('windows')>-1 || this.ie7 && ua.indexOf('windows')>-1);
	this.iemac = (this.ie56 && ua.indexOf('mac')>-1);
	this.moz = (ua.indexOf('mozilla')>-1);
	this.ff = (ua.indexOf('firefox')>-1);
	this.moz13 = (ua.indexOf('mozilla')>-1 && ua.indexOf('1.3')>-1);
	this.oldmoz = (ua.indexOf('sunos')>-1 || this.moz13 && !this.ff || this.moz && ua.indexOf('1.4')>-1 && !this.ff || this.moz && ua.indexOf('1.5')>-1 && !this.ff || this.moz && ua.indexOf('1.6')>-1 && !this.ff);
	this.anymoz = this.gecko;
	this.ns6 = (ua.indexOf('netscape6')>-1);
	this.geckoAtOrAbove=function(vString){
		var gVer = (this.gecko) ? ua.substring(ua.indexOf("; rv:")+5, ua.indexOf(") gecko")) : '';
		var t=gVer.split(".");
		var v=vString.split(".");
		while(t.length<v.length){t.push("0");}
		while(v.length<t.length){v.push("0");}
		for(var i=0;i<v.length;i++){
			var ti=parseInt(t[i]),vi=parseInt(v[i]);
			if(ti==vi){continue;}
			else return (ti>vi);
		}
		return true;
	}
}



// RTL SNIFF
var rtl = (document.documentElement.lang.indexOf('he') > -1 && document.documentElement.lang.indexOf('IL'))? true : false;
if(rtl){
	addClassName(document.documentElement, 'rtl');
}

// ADD BROWSER CLASS TO HTML TAG
if(is.op){var bclass = "browserOpera";}
else if(is.safariAll){var bclass = "browserSafari";}
else if(is.ie56){var bclass = "browserExplorer56 browserExplorer";}
else if(is.ie7){var bclass = "browserExplorer7 browserExplorer";}
else if(is.iemac){var bclass = "browserExplorerMac";}
else if(is.oldmoz){var bclass = "browserOldMoz";}
else {var bclass = "";}
if(is.gecko){bclass += " gecko";}
if(is.safari||is.geckoAtOrAbove("1.9")){bclass += " radius";}else{bclass += " noradius";}
bclass += " jsenabled";
addClassName(document.documentElement, bclass);

// SHUTOFF
if(typeof shutoff=='undefined'){var shutoff={global:false,share:false,pop:false,misc:false};}

// GLOBAL SHUTOFF
if(!shutoff.global){
	reg.setup("div.a1r2 span.toolbarlinks > a,div.a1r2 span.siteid > a",sniffA1);
	reg.setup("div#a5 a",sniffA5);
	reg.focus("input#searchfield,input.searchfield",function(){addClassName(this, 'sfieldfocused');},function(){removeClassName(this, 'sfieldfocused');});
	reg.focus("div#a5 > ul li.hasmenu",function(){addClassName(this,'a5show');gebtn('div',this)[0].style.top=((gebtn('div',this)[0].offsetHeight * -1)) + 4 +'px';},function(){removeClassName(this,'a5show');});
	reg.hover("div#a5 > ul li.hasmenu",function(){addClassName(this,'a5show');gebtn('div',this)[0].style.top=((gebtn('div',this)[0].offsetHeight * -1)) + 4 +'px';},function(){removeClassName(this,'a5show');});
	reg.hover("div.a5menu",function(){addClassName(this.parentNode,'a5show')},function(){removeClassName(this,'a5show');});
	reg.setup("td.navlinks > div",sniffA2);
	reg.hover("ul#mtopics",function(){
		if(!a2['ent']){
			reg.setup("ul#mtopics > li",sniffA2);
			reg.rerun(this);
		}
	});
	reg.focus("ul#mtopics",function(){
		if(!a2['ent']){
			reg.setup("ul#mtopics > li",sniffA2);
			reg.rerun(this);
		}
	});
	if(is.ie56){
		reg.hover("ul#mtopics > li",function(){addClassName(this, 'a2mshow');},function(){removeClassName(this, 'a2mshow');});
		reg.hover("td.navlinks",function(){addClassName(this, 'a2mshow');},function(){removeClassName(this, 'a2mshow');}, 5);
	}

	//  do goto set up for a2v8 if misc is set to false
	if(shutoff.misc){
		reg.preSetup(function(){
			var a2v8 = gebi('a2v8');
			if (!a2v8) { return; }
			reg.setup("select.goto, select.showDiv",sniffGoto);
			reg.setup("ul.goto, ul.showDiv",sniffGotoUL);
		});
	}
}

// POPUP SHUTOFF
if(!shutoff.pop){
	reg.click('.k5, .media-popin',k5Click);
	reg.click('.k5close',k5Close);
	reg.click('.k5softclose',k5SoftClose);
	reg.key('html',function(e){if(27==e.keyCode){k5Close();}});
	reg.setup("@class*='k2ajax-'",sniffK2ajax);
	reg.setup("@class*='k2over', @class*='k2focus', @class*='k2cl', @class*='k2show', @class*='k2hide'",sniffK2);
	reg.setup(".modal-launch",sniffModal);
}

// COPYRIGHT DOUBLE CHECK
reg.preSetup(function(){
	var cpy=gebi('copyDate');
	if(!cpy){return;}
	cpy.innerHTML = "1994-"+new Date().getFullYear()+' ';
});

// BLUR OUT
reg.focus("body",blurOut);
var blurIt=[];
function blurOut(ev){
	var obj = this;
	t = getTarget(ev);
	var b = blurIt;
	blurIt=[];
	for(var i=0; i<b.length; i++){
		if(!hasParent(t,b[i][0])){
			if(b[i][1] == 'hidden'){
				b[i][0].style.visibility='hidden';
			}else if(b[i][1]){
				removeClassName(b[i][0],b[i][1]);
			}else{
				b[i][0].style.display='none';
			}
		}else{
		 	blurIt.push(b[i]);
		}
	}
}

// POP UP
reg.click('a.popup, area.popup, a.media-launch',bubblePop);
function bubblePop(e){
	var link = this;
	if (hasClassName(link, 'media-launch') && !matchClassName(link, '[0-9]+x[0-9]+')){
		addClassName(link,'662x652');
	}
	var popW = '820';
	var popH = '600';
	var param = ['no',0,0,0,0,0,0,'',''];
	var popUrl = link.href;
	if (link.target) { var popTarget = link.target; }
	else { var popTarget = "newpopup"; }
	var cls = link.className.split(' ');
	for (var v=0;v<cls.length;v++){
		if (cls[v].search('[0-9]+x[0-9]+') > -1){
			var f = cls[v].split('x');
			popW = f[0];
			popH = f[1];
		}else if(cls[v].indexOf("name-") == 0){
			var f = cls[v].split('name-');
			popTarget = f[1];
		}else if(cls[v] == "scrolling"){
			var param = ['yes',1,0,0,0,0,0];
		}else if(cls[v] == "full"){
			var param = ['yes',1,1,1,1,1,1];
		}else if(cls[v].indexOf("yes_") == 0 || cls[v].indexOf("no_") == 0){
			var f = cls[v].split('_');
			f[1] = "f"+f[1];
			var param = f[1].split('');
			param[0] = f[0];
		}
		if(link.className.indexOf("centerpop") > 1){
			param[7] = screen.availHeight/2 - popH/2;
			param[8] = screen.availWidth/2 - popW/2;
		}
	}
	openPopup(popUrl,popTarget,popW,popH,param[0],param[1],param[2],param[3],param[4],param[5],param[6],param[7],param[8]);
	cancelDefault(e);
}
function openPopup(url,name,width,height,resizable,scrollbars,menubar,toolbar,location,directories,status,top,left) {
	var tl = (top && left) ? ',top=' + top +',left=' + left : '';
	var popup = window.open(url, name, 'width=' + width + ',height=' + height + ',resizable=' + resizable + ',scrollbars=' + scrollbars	+ ',menubar=' + menubar + ',toolbar=' + toolbar + ',location=' + location + ',directories=' + directories + ',status=' + status+tl);
	popup.focus();
}

// AUTOCLEAR
reg.focus("input.autoclear,input#searchfield,input.searchfield",autoclearFocus,autoclearBlur);
function autoclearFocus(){
	if(this.value == this.defaultValue) {
		this.value = '';
		addClassName(this, 'autocleared');
	}
}
function autoclearBlur(){
	if(this.value=='') {
		this.value = this.defaultValue;
		removeClassName(this, 'autocleared');
	}
}

// DISABLE SEACH IF NO SEARCH STRING
reg.submit("div.a2search form",function(e){
	i = gebs("input.searchfield,input#searchfield",this);
	if (i[0].value == '' || i[0].value == i[0].defaultValue){
		i[0].value = '';
		cancelDefault(e);
	}
});

// A1
var a1 = [];
a1['x'] = 1;
function sniffA1(){
	var link = this;
	oldA1Content(); // LEGACY
	var a1w  = ['<div class="a1menux1"></div>\n<div class="a1menuw2"><div class="a1menuw1">\n','</div><div class="a1menux2"></div></div>'];
	if(!a1['ent']){
		for (key in a1) {
			var d = elem('div');
			d.innerHTML = key;
			a1[d.innerHTML] = a1[key];
		}
		a1['ent'] = true;
	}
	var linkText = link.innerHTML.normalize();
	var a1id = "a1menu"+a1['x'];
	a1['x']++;
	if (hasClassName(link, 'language-select')){
		var d = elem('div.a1menu');
		addClassName(link, 'k2over-languageselector y3 x-10');
		d.id = 'languageselector';
		d.style.width = "170px"
		d.innerHTML = a1w[0]+'<h5></h5><div></div>'+a1w[1];
 		link.parentNode.insertBefore(d,link.nextSibling);
		sniffK2.call(link);
 		sniffSiteSelector(link.parentNode);
	}else if(a1[linkText]){
		var d = elem('div.a1menu');
		addClassName(link, 'karrow');
		addClassName(link, 'k2over-'+a1id+' y3 x-6');
		if (hasClassName(link, "a1cart")){
			link.innerHTML = '<span class="carticon small">'+link.innerHTML+'</span>';
			link.style.paddingLeft = "0px";
		}
		if(a1[linkText].indexOf('a1-2col') > -1){
			var wc = 'a1Large';
		}else if(a1[linkText].indexOf('<p>') > -1){
			var wc = 'a1Medium';
		}else{
			var wc = 'a1Small';
		}
		d.id = a1id;
		addClassName(d,wc);
		d.innerHTML = a1w[0]+a1[linkText]+a1w[1];
		link.parentNode.insertBefore(d,link.nextSibling);
		sniffK2.call(link);
	}
}

// A1 LEGACY
var a1hrefs = [];
var a1menus = [];
function oldA1Content(){
	var k;
	for (k in a1hrefs){
		a1[a1hrefs[k][0]] = a1menus[k][1];
	}
	a1hrefs = a1menus = [];
}

// A2
var a2 = [];
function sniffA2(){
	var fobj = this;
	var sall=(typeof ltxt=='undefined')?seeall:ltxt.seeall;
	if(navmenu['1.0']) oldA2Content(); // LEGACY
 	if(gebi('ip1')) oldA2TableFix(); // LEGACY
	if(!a2['ent']){
		for (key in a2) {
			var d = elem('div');
			d.innerHTML = key;
			a2[d.innerHTML.strip()] = a2[key];
		}
		a2['ent'] = true;
	}
	var firstA = gebtn('a',fobj)[0];
	var n = firstA.innerHTML.normalize();
	if(a2[n]){
		var h = firstA.href;
		addEvent(firstA, 'focus', function(){
			if(this.parentNode.nodeName.toLowerCase() == 'li'){
				addClassName(this.parentNode, 'a2mshow');
				blurIt.push([this.parentNode,'a2mshow']);
			}else{
				addClassName(this.parentNode.parentNode, 'a2mshow');
				blurIt.push([this.parentNode.parentNode,'a2mshow']);
			}
		});
		var d = elem('div.a2m',{});
		d.style.marginLeft = (rtl)?'-'+(204 - fobj.offsetWidth)+'px':'-20px';
		var u = elem('ul',{});
		var a = elem('a',{'href':h});
		a.innerHTML = sall+' &#187;';
		var l =  elem('li',{});
		if (h.indexOf('#') < 0 && h.split('#')[1] != '' && a2[n].indexOf('<!-- no see all -->') < 0) {
			l.appendChild(a);
		}
		u.innerHTML = a2[n];
		u.appendChild(l);
		d.appendChild(u);
		fobj.appendChild(d);
		addClassName(gebtn('li',fobj)[0], 'firstchild');
	}else if(fobj.nodeName.toLowerCase() == 'li'){
		addClassName(fobj, 'a2nomenu');
	}else{
		addClassName(fobj.parentNode, 'a2nomenu');
	}
}

// A2 LEGACY
var navmenu = [];
var oldmenu = [];
function popfly(){}
function closefly(){}
function prepmenus(){}
function printmenus(){}
function oldA2Content(){
	var x = 1;
	while(x < 10){
		if(navmenu[x+'.0'] && !a2[navmenu[x+'.0'].split('|')[0]]){
			var xx = 1;
			var li = '';
			while(navmenu[x+'.'+xx]){
				li += '<li><a href="'+navmenu[x+'.'+xx].split('|')[1]+'">'+navmenu[x+'.'+xx].split('|')[0]+'</a></li>\n';
				xx++;
			}
			a2[navmenu[x+'.0'].split('|')[0]] = li;
		}
		if(oldmenu[x+'.0'] && !a2[oldmenu[x+'.0'].split('|')[0]]){
			var xx = 1;
			var li = '';
			while(oldmenu[x+'.'+xx]){
				li += '<li><a href="'+oldmenu[x+'.'+xx].split('|')[1]+'">'+oldmenu[x+'.'+xx].split('|')[0]+'</a></li>\n';
				xx++;
			}
			a2[oldmenu[x+'.0'].split('|')[0]] = li;
		}
		x++;
	}
	navmenu = oldmenu = [];
}
function oldA2TableFix(){
	var x = 1;
	while (gebi('ip'+x)){
		var td = gebi('ip'+x).parentNode;
		td.parentNode.removeChild(td);
		x++;
	}
}

// A5
var a5 = [];
function sniffA5(){
	var a5w  = ['<div class="a5menuw2"><div class="a5menuw1">\n','</div></div><div class="a5menux2"></div>'];
	if(!a5['ent']){
		for (key in a5) {
			var d = elem('div');
			d.innerHTML = key;
			a5[d.innerHTML] = a5[key];
		}
		a5['ent'] = true;
	}
	var linkText = this.innerHTML.normalize();
	if(a5[linkText]){
		var d = elem('div.a5menu');
		d.innerHTML = a5w[0]+a5[linkText]+a5w[1];
		addClassName(this.parentNode, 'hasmenu');
		this.parentNode.insertBefore(d,this.nextSibling);
	}
}

// K2
ked = [];
function sniffK2(shownow){
	var fobj = this;
	var pdoc = document;
	fobj.prp = [0,0,0,"","",""];
	fobj.className = fobj.className.replace(/(k2over) +/,"$1-");
	fobj.className = fobj.className.replace(/(k2click) +/,"$1-");
	fobj.className = fobj.className.replace(/(k2focus) +/,"$1-");
	fobj.className = fobj.className.replace(/(k2close) +/,"$1-");

	var cls = fobj.className.split(' ');

	if(fobj.className.indexOf("k2ajaxload") > -1 && fobj.href && gebtn('div',document.body)[0] ){
		for (var v=0;v<cls.length;v++){
			if (cls[v].indexOf("k2over") > -1 || cls[v].indexOf("k2click") > -1 || cls[v].indexOf("k2focus") > -1){
				var k2id = cls[v].split('-');
				if (!k2id[2]){
					k2id[2] = k2id[1];
				}
			}
		}
		var link = document.createElement('a');
		link.className = 'loadUrl';
		link.href = fobj.href+'#'+k2id[2];
		if(!gebi(k2id[2])){
			var div = document.createElement('div');
			div.className = 'g32auto';
			div.id = k2id[2];
			div.appendChild(link);
			gebtn('div',document.body)[0].appendChild(div);
		}
	}


	for (var v=0;v<cls.length;v++){
		if (cls[v].indexOf("k2over") > -1 || cls[v].indexOf("k2click") > -1 || cls[v].indexOf("k2focus") > -1){
			var p_objs = fobj.aob = cls[v].split('-');
			if (!p_objs[2]){
				fobj.aob[2] = p_objs[2] = p_objs[1];
				fobj.aob[1] = fobj;
			}
			kpop = gebi(p_objs[2]);
			kpop.kp_objs = p_objs[2];
			kpop.kp_trig = p_objs[1];
		}else if (cls[v].indexOf("k2close") > -1){
			fobj.aob = cls[v].split('-');
		}else if (cls[v].indexOf("x") == 0){
			fobj.prp[0] = (cls[v].substring(1) * 1) + fobj.prp[0];
		}else if (cls[v].indexOf("y") == 0){
			fobj.prp[1] = (cls[v].substring(1) * 1) + fobj.prp[1];
		}else if (cls[v].indexOf("z") == 0){
			fobj.prp[2] = (cls[v].substring(1) * 1);
		}else if (cls[v].indexOf("pAbsolute") == 0){
			fobj.prp[3] = (cls[v].substring(1));
		}else if (cls[v].indexOf("vBottom") == 0 || cls[v].indexOf("vTop") == 0 || cls[v].indexOf("vMiddle") == 0 || cls[v].indexOf("vAlignTopBottom") == 0){
			fobj.prp[4] = cls[v];
		}else if (cls[v].indexOf("hRight") == 0 || cls[v].indexOf("hMiddleRight") == 0 || cls[v].indexOf("hLeft") == 0 || cls[v].indexOf("hMiddleLeft") == 0 || cls[v].indexOf("hMiddle") == 0 || cls[v].indexOf("hAlignRight") == 0){
			fobj.prp[5] = cls[v];
		}
	}
	if (fobj.aob[0].indexOf("k2over") > -1){
		addEvent(fobj,"mouseover",function(){
			showK2(this.aob[2],this.aob[1],this.prp[0],this.prp[1],this.prp[2],this.prp[3],this.prp[4],this.prp[5]);
		});
		if (!hasClassName(fobj, "mOverOff")){
			addEvent(kpop,"mouseover",function(){
				showK2(this.kp_objs);
			});
		}
		addEvent(kpop,"mouseout",function(){
			hideK2(this.kp_objs);
		});
		addEvent(fobj,"mouseout",function(){
			hideK2(this.aob[2]);
		});
		addEvent(fobj,"focus",function(){
			showK2(this.aob[2],this.aob[1],this.prp[0],this.prp[1],this.prp[2],this.prp[3],this.prp[4],this.prp[5]);
			blurIt.push([gebi(this.aob[2]),'hidden']);
		});

		if(shownow){
			showK2(fobj.aob[2],fobj.aob[1],fobj.prp[0],fobj.prp[1],fobj.prp[2],fobj.prp[3],fobj.prp[4],fobj.prp[5]);
			return false;
		}
	}else if (fobj.aob[0] == "k2click"){
		addEvent(fobj,"click",function(e){
			showK2(this.aob[2],this.aob[1],this.prp[0],this.prp[1],this.prp[2],this.prp[3],this.prp[4],this.prp[5]);
			addK2(this.aob[2],this.aob[1],this.prp[0],this.prp[1],this.prp[2],this.prp[3],this.prp[4],this.prp[5]);
			cancelDefault(e);
			return false;
		});
		if(shownow){
			showK2(fobj.aob[2],fobj.aob[1],fobj.prp[0],fobj.prp[1],fobj.prp[2],fobj.prp[3],fobj.prp[4],fobj.prp[5]);
			addK2(fobj.aob[2],fobj.aob[1],fobj.prp[0],fobj.prp[1],fobj.prp[2],fobj.prp[3],fobj.prp[4],fobj.prp[5]);
			return false;
		}
	}else if (fobj.aob[0] == "k2focus"){
		addEvent(fobj,"focus",function(){
			showK2(this.aob[2],this.aob[1],this.prp[0],this.prp[1],this.prp[2],this.prp[3],this.prp[4],this.prp[5]);
			addK2(this.aob[2],this.aob[1],this.prp[0],this.prp[1],this.prp[2],this.prp[3],this.prp[4],this.prp[5]);
		});
		addEvent(fobj,"blur",function(){
			hideK2(this.aob[2],1);
		});
	}else if (fobj.aob[0] == "k2close"){
		addEvent(fobj,"click",function(e){
			hideK2(this.aob[1],1);
			cancelDefault(e);
		});
	}
	fobj.className = fobj.className.replace(/(k2over)-|(k2focus)-|(k2cl...)-/,"$1 ");
}
function showK2(popupID,callerID,Xoffset,Yoffset,Zindex,posy,btmup,ort,etype){
	var popupObj = gebi(popupID);
	if (!popupObj){
		var popupObj = popupID;
	}
	if (callerID){
		var ptop = plft = 0;
		var callerObj = gebi(callerID);
		if (!callerObj){
			var callerObj = callerID;
		}

		if (ort == "hLeft"){
			plft = plft - popupObj.offsetWidth;
		}else if (ort == "hMiddleLeft"){
			plft = plft - popupObj.offsetWidth;
			plft = plft + parseInt(callerObj.offsetWidth / 2);
		}else if (ort == "hMiddle"){
			plft = parseInt(callerObj.offsetWidth / 2);
			plft = plft - parseInt(popupObj.offsetWidth / 2);
		}else if (ort == "hMiddleRight"){
			plft = parseInt(callerObj.offsetWidth / 2);
		}else if (ort == "hRight"){
			plft = callerObj.offsetWidth;
		}else if (ort == "hAlignRight"){
			plft = plft + callerObj.offsetWidth - popupObj.offsetWidth;
		}

		if (btmup == "vTop"){
			ptop = ptop - popupObj.offsetHeight;
		}else if (btmup == "vMiddle"){
			ptop = ptop + parseInt(callerObj.offsetHeight / 2);
			ptop = ptop - parseInt(popupObj.offsetHeight / 2);
		}else if (btmup == "vBottom"){
			ptop = ptop + callerObj.offsetHeight;
		}else if (btmup == "vAlignBottom"){
			ptop = ptop + callerObj.offsetHeight - popupObj.offsetHeight;
		}else if (btmup == "vAlignTopBottom"){
			var scrolltop = 0;
			if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
				scrolltop = document.body.scrollTop;
			}else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop)){
				scrolltop = document.documentElement.scrollTop;
			}
			var winheight = 0;
			if( typeof( window.innerWidth ) == 'number' ) {
				winheight = window.innerHeight;
			} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
				winheight = document.documentElement.clientHeight;
			}
			var alignbottom = callerObj.offsetHeight - popupObj.offsetHeight;
		}
		if (is.safari && posy == "Absolute"){
			if (posy != "Absolute"){
				callerObj.style.position = "relative";
			}
			getXY(callerObj.offsetParent);
		}else{
			getXY(callerObj);
		}

		ptop = ptop + callerObj.Y;
		plft = plft + callerObj.X;
		if (btmup == "vAlignTopBottom" && ptop > scrolltop + (winheight/2)){
			ptop = ptop + alignbottom;
			Yoffset = Yoffset * -1;
		}
		plft = plft + Xoffset;
		ptop = ptop + Yoffset;
		popupObj.style.top=ptop+'px';
		popupObj.style.left=plft+'px';
	}
	if (Zindex){
		popupObj.style.zIndex = Zindex;
	}
	popupObj.style.visibility = "visible";
}
function hideK2(popupID,popcls,fader){
	var popupObj = gebi(popupID);
	if (!popupObj){
		var popupObj = popupID;
	}
	popupObj.style.visibility = "hidden";
	if (popcls){
		ked[popupID] = "";
	}
}
function addK2(p0,p1,p2,p3,p4,p5,p6,p7){
	ked[p0] = [p0,p1,p2,p3,p4,p5,p6,p7];
}
addEvent(window, 'resize', function(){
	var kdp;
	for (kdp in ked){
		if (ked[kdp][0]){
			showK2(ked[kdp][0],ked[kdp][1],ked[kdp][2],ked[kdp][3],ked[kdp][4],ked[kdp][5],ked[kdp][6],ked[kdp][7]);
		}
	}
});

// SETUP -> K2 W/ AJAX
function sniffK2ajax(){
	var fobj = this;
	var containerID = fobj.className.split('k2ajax-')[1].split(' ')[0];
	var fileUrl = gebtn('a',gebi(containerID))[0].href;
	var mvnt = (fobj.className.indexOf('k2over-') > -1) ? 'mouseover' : 'click';
	addEvent(fobj,mvnt,function(){
		if(gebi(containerID).innerHTML.indexOf('getUrl') > -1){
			var fvars = [containerID,fobj];
			getfile(fileUrl,function(rdata,fvar){
				if(rdata.indexOf('contentchunk') > -1){
					rdata = getRequestObject('contentchunk',rdata).innerHTML;
				}
				gebi(fvar[0]).innerHTML = rdata;
				reg.rerun(gebi(fvar[0]));
				sniffK2.call(fvar[1],true);
			},fvars);
		}
	});
}

// SETUP -> K4
function sniffModal(){
	var fobj = this;
	if (hasClassName(fobj, "modal-launch")){
		var matches = fobj.className.match(/launch\-id\-([a-z0-9_-]+)/);
		if (!matches) { return; }
		else { fobj.modalId = matches[1]; }
		fobj.onclick = function(e){
			showK4(this.modalId);
			return false;
		};
	}
}
function showK4(id){
	var div = gebi(id);
	if (!div) { return; }
	removeClassName(div, "k4hidden");
	var inputs = gebtn("input",div);
	for (var a=0;a<inputs.length;a++){
		if (inputs[a].type == 'text'){
			inputs[a].focus();
			break;
		}
	}
	if (is.ie6){
		var selects = gebtn("select");
		for (var a=0;a<selects.length;a++){
			addClassName(selects[a], 'k4in-effect');
		}
	}
}
function hideK4(id){
	var div = gebi(id);
	addClassName(div, "k4hidden");
	if (is.ie6){
		var selects = gebtn("select");
		for (var a=0;a<selects.length;a++){
			removeClassName(selects[a], 'k4in-effect');
		}
	}
}
function modalClose(e){
	var k4 = this.parentNode;
	while (!hasClassName(k4, 'k4') && k4.parentNode) { k4 = k4.parentNode; }
	if (hasClassName(k4, 'k4') && k4.id) { hideK4(k4.id); }
	return false;
}

// SETUP -> COUNTRY & LANGUAGE SELECTOR
function sniffSiteSelector(span) {
	var lnks = gebtn('a',span);
	for (var a=0; a<lnks.length; a++) {
		var lnk = lnks[a];
		if (hasClassName(lnk, 'country-select')) {
			addClassName(lnk,'modal-launch launch-id-country-selector');
			sniffModal.call(lnk);
			var k4 = elem('div',{'class':'k4 k4v1 k4hidden','id':'country-selector'});
			k4.innerHTML = '<div class="k4w1"><div class="k4w2"><div class="k4w3"><div class="k4w4"><div class="k4title"><h2>'
				+'</h2><p class="modal-extra"><a href="" class="modal-close">[X]</a></p></div><div class="k4body">'
				+'</div></div></div></div></div>';
			k4.setTitle=function(txt){gebtn('h2',this)[0].innerHTML=txt;};
			k4.setBody=function(txt){gebtn('div',this)[5].innerHTML=txt;};
			document.body.appendChild(k4);
			addEvent(lnk, 'click', function(){
				var thisHref = this.href;
				try {
					getfile(this.href, function(rdata,fvar){
						try {
							var headingText = elemText(getRequestObject('country-data-title',rdata,'h2'));
							var bodyText = getRequestObject('country-data',rdata).innerHTML;
						} catch (ex) { window.location = thisHref; }
						k4.setTitle(headingText);
						k4.setBody(bodyText);
					});
				} catch (e) { window.location = thisHref; }
			});
		} else if (hasClassName(lnk, 'language-select')) {
			var k2 = gebi('languageselector');
			k2.setTitle=function(txt){gebtn('h5',this)[0].innerHTML=txt;};
			k2.setBody=function(txt){gebtn('div',this)[3].innerHTML=txt;};
			addEvent(lnk, 'mouseover', function(){
				var thisHref = this.href;
				try {
					getfile(this.href, function(rdata,fvar){
						try {
							var headingText = elemText(getRequestObject('language-data-title',rdata,'h2'));
							var bodyText = getRequestObject('language-data',rdata).innerHTML;
						} catch (ex) {
							k2.setTitle('no data');
							return;
						}
						k2.setTitle(headingText);
						k2.setBody(bodyText);
					});
				} catch (e) { window.location = thisHref; }
			});
		}
	}
}

// K5 ONLOAD
reg.postSetup(function(){
	var k5onload = gebi('k5onload');
	if(!k5onload){return;}
	k5Click.call(k5onload);
});

// K5 FUNCTIONS
function pauseAll() {
	window.paused = true;
	addClassName(document.body,'paused');
}
function resumeAll() {
	window.paused = false;
	removeClassName(document.body,'paused');
}

function k5Click() {

	var thisHref = this.href;
	if (reg.matches(this,'div.k5')) { return; }
	k5Close(); // close any open k5s

	// get id ##############################
	var idMatches = matchClassName(this,/^id-(\S+)$/);
	if (idMatches) {
		var id = idMatches[1];
	} else if (thisHref && thisHref.indexOf('#')!=-1) {
		var id = thisHref.substring(thisHref.indexOf('#')+1);
	}else{
		throw new Error('no id value was specified for k5 object. className "id-someId" or URL anchor reference "...page.html#someId"');
	}

	// mode ################################
	var k5DivClass = 'k5 k5empty';
	var isVid,isInf,isLog,isMed,isInterrupt,interruptParent=getParent(this,'.k5interrupt');
	if     (hcn(this,'k5interrupt')||interruptParent){k5DivClass+=' k5interrupt';      isInterrupt=true;}
	if     (hcn(this,'k5vid'))                       {k5DivClass+=' k5vid';            isVid=true;}
	else if(hcn(this,'k5login'))                     {k5DivClass+=' k5login';          isLog=true;}
	else if(hcn(this,'k5media'))                     {k5DivClass+=' k5media hijax-'+id;isMed=true;}
	else if(hcn(this,'k5info'))                      {k5DivClass+=' k5info';           isInf=true;}

	// title string ########################
	var titleText = (this.title) ? this.title : elemText(this);
	if (!titleText) { titleText = ' '; }

	// [x] image ###########################
	if     (isLog){var closeImgAtts={'title':'close','alt':'close','src':imdir+'/k5login_x.gif',         'border':'0','width':'21','height':'21'};}
	else if(isInf){var closeImgAtts={'title':'close','alt':'close','src':imdir+'/k5info_x.gif',          'border':'0','width':'21','height':'21'};}
	else          {var closeImgAtts={'title':'close','alt':'close','src':imdir+'/ic_close_win_big_x.gif','border':'0','width':'30','height':'19'};}

	// #####################################
	if (interruptParent) {
		this.continueTo = interruptParent.continueTo;
		this.submitTo = interruptParent.submitTo;
		this.thankYouHref = interruptParent.thankYouHref;
	}

	// #####################################
	var titleEl = elem('h2.k5title',null,titleText);
	var close = elem('span.'+(isInterrupt?'k5skip':'k5close'),null,elem('img',closeImgAtts));//send them on their way?
	var closePara = elem('p.k5closer',null,close);
	var k5w2 = elem('div.k5w2');
	var k5w1 = elem('div.k5w1',null,[titleEl,closePara,k5w2]);
	var k5Div = elem('div#k5',{'class':k5DivClass},k5w1);
	if (this.continueTo) { k5Div.continueTo = this.continueTo; }
	if (this.submitTo) { k5Div.submitTo = this.submitTo; }
	if (this.thankYouHref) { k5Div.thankYouHref = this.thankYouHref; }

	// #####################################
	k5w1.centerOnScreen = function() {
		if (!this.viewportHeight) { this.viewportHeight = (window.innerHeight) ? window.innerHeight : document.documentElement.clientHeight; }
		if (!this.viewportWidth) { this.viewportWidth = (window.innerWidth) ? window.innerWidth : document.documentElement.clientWidth; }
		var thisHeight = this.offsetHeight;
		var thisWidth = this.offsetWidth;
		var distance = ((this.viewportHeight / 2) - (thisHeight / 2)) * .666;
		if (distance < 0) {
			distance = 0;
			this.style.height = (this.viewportHeight - 20)+'px';
			this.style.overflow = 'auto';
		}
		if (thisWidth > this.viewportWidth) {
			this.style.width = (this.viewportWidth - 40) + 'px';
			this.style.overflow = 'auto';
		}
		this.style.marginTop = distance+"px";
	};

	// #####################################
	k5w1.setContent = function(contentEl) {
		contentEl.style.visibility = 'hidden';
		removeClassName(k5Div, 'k5empty');
		removeClassName(contentEl, 'hidethis');

		var customTitles = gebcn('k5customtitle',contentEl);
		if (customTitles && customTitles.length > 0) {
			var customTitle = customTitles[0];
			var customTitleText = elemText(customTitle);
			customTitle.parentNode.removeChild(customTitle);
			titleEl.firstChild.data = customTitleText;
		}

		var xyMatches = matchClassName(contentEl,/^(\d+)(x(\d+))?$/);
		if (xyMatches) {
			if (!k5w1.style.width) { k5w1.style.width = xyMatches[1] + 'px'; }
			if (xyMatches.length > 3 && xyMatches[3] && !k5w2.style.height) { k5w2.style.height = xyMatches[3] + 'px'; }
		}

		k5w2.innerHTML='';
		k5w2.appendChild(contentEl);
		var newHeight = k5w2.offsetHeight;
		this.centerOnScreen();
		contentEl.style.visibility = '';
	};

	// #####################################
	k5Div.setError = function(title,error,url) {
		removeClassName(this,'k5empty');
		addClassName(this,'k5error');
		k5w1.style.height = 'auto';
		k5w1.style.width = '';
		k5w2.style.height = '';
		error = error || 'Unspecified error';
		title = title || 'Error';
		var titleEl = title ? elem('h5.k5customtitle',{},title) : '';
		var errorEl = elem('p',{},error);
		var urlEl = url ? elem('p',{},""+url) : '';
		k5w1.setContent(elem('div',{'class':'g29 g29v2'},elem('div.g29w1',{},elem('div.g29w2',{},[titleEl,errorEl,urlEl]))));
	};

	// append the node #####################
	k5Div.style.visibility = 'hidden';
	if (is.ie6) {
		var k5ie6bg = elem('div#k5ie6bg');
		document.body.appendChild(k5ie6bg);
	}
	document.body.appendChild(k5Div);
	var xyMatches = matchClassName(this,/^(\d+)(x(\d+))?$/);
	if (xyMatches) {
		k5w1.style.width = xyMatches[1] + 'px';
		if (xyMatches.length > 3 && xyMatches[3]) { k5w2.style.height = xyMatches[3] + 'px'; }
	}
	k5w1.centerOnScreen();
	k5Div.style.visibility = '';

	// set content #########################
	var linkPage = thisHref || location.href;
	if (linkPage.indexOf('http')!==0) { linkPage = resolveUrl(linkPage); }//in case not fully resolved url
	if (linkPage.indexOf('#')!=-1) { linkPage = linkPage.substring(0,linkPage.indexOf('#')); }
	var locPage=location.href;
	if (locPage.indexOf('#')!=-1) { locPage = locPage.substring(0,locPage.indexOf('#')); }
	if (locPage === linkPage) {
		// do local
		var content = gebi(id);
		if (!content) { k5Div.setError('Unable to load content', 'id="'+id+'" not found on this page', linkPage); }
		else { k5w1.setContent(content.cloneNode(true)); }
	} else {
		// do ajax
		try{
			xhr(linkPage, function(responseText){
				// success!
				var content = getElementByIdFromString(responseText, id);
				if (!content) { k5Div.setError('Unable to load content', 'id="'+id+'" not found on remote page', linkPage); }
				else { k5w1.setContent(content); }
			}, function(statusCode, statusText, url){
				// fail!
				k5Div.setError('Unable to load content', statusCode+" "+statusText, url);
			});
		} catch (ex) {
			k5Div.setError('Unable to load content', 'XHR FAIL: '+(ex.message||ex), linkPage);
		}
	}

	// set focus ###########################
	try {
		this.blur();
		var fitems = gebs('input@type="text",button,select,textarea', k5Div);
		if (fitems && fitems.length > 0) {
			fitems[0].focus();
		}
	} catch (ex) {}

	// done ################################
	pauseAll();
	return false;
}

function k5Close(e){
	k5SoftClose();
	return false;
}

function k5SoftClose(e){
	var k5Div = gebi('k5');
	if(k5Div){document.body.removeChild(k5Div);}
	var k5ie6bg = gebi('k5ie6bg');
	if(k5ie6bg){document.body.removeChild(k5ie6bg);}
	resumeAll();
}

(function(){
	var done=false;
	window.k5Onload=function(href, id, title, lf, width, height) {
		if (done) { throw new Error("k5Onload called multiple times"); } else { done = true; }
		if (!href) { href = location.href; }
		if (href.indexOf('#') != -1) {
			if (!id) { id = href.substring(href.indexOf('#')+1); }
			href = href.substring(0,href.indexOf('#'));
		}
		href = href + '#' + id;
		var className = 'k5';
		if (width) { className += ' ' + width; }
		if (height) { className += 'x' + height; }
		if (lf) { className += ' ' + lf; }
		var a = elem('a',{'class':className,'href':href},title);
		reg.postSetup(function(){
			window.setTimeout(function(){k5Click.call(a);},200);
		});
	}
})();

(function(){
	var links, done = false;
	function handleIt(el, continueTo, submitTo, matchUrl) {
		if (!done && (done = true)) {
			links = gebs('link@rel="k5interrupt"', gebtn('head')[0]);
		}
		for (var i=0; i<links.length; i++) {
			var link = links[i];
			var patternAtt = link.getAttribute('match');
			var selector = link.getAttribute('select');
			if (!patternAtt && !selector) { continue; }
			var patternAtt = patternAtt || '.?';
			var selector = selector || '*';
			var pattern = new RegExp(patternAtt);
			if (!patternAtt && !selector) { continue; }
			if (!pattern.test(matchUrl) || !matches(el,selector)) { continue; }
			var href = link.href;
			var title = link.getAttribute('title');
			var thankYouHref = link.getAttribute('thanks');
			var dummyLink = elem('a',{'class':link.className+' k5interrupt','href':href},title);
			dummyLink.continueTo = continueTo;
			dummyLink.submitTo = submitTo;
			dummyLink.thankYouHref = thankYouHref;
			try {
				return k5Click.call(dummyLink);
			} catch (ex) {
				console.log("error while calling k5Click(): "+ex.message);
				return true;
			}
		}
	}
	var protocolPatt = /^https?:/;
	var hostPatt = /^\/\//;
	var rootPatt = /^\//;
	var queryPatt = /^\?/;
	var hashPatt = /^#/;
	var l = location;
	var lindex = l.protocol+'//'+l.host+l.pathname;
	lindex = lindex.substring(0,lindex.lastIndexOf('/')+1);
	function resolveUrl(frag,paramString) {
		frag=frag.strip();
		var result = null;
		if (protocolPatt.test(frag))   { result = frag; }
		else if (hostPatt.test(frag))  { result = l.protocol+frag; }
		else if (rootPatt.test(frag))  { result = l.protocol+'//'+l.host+frag; }
		else if (queryPatt.test(frag)) { result = l.protocol+'//'+l.host+l.pathname+frag; }
		else if (hashPatt.test(frag))  { result = l.protocol+'//'+l.host+l.pathname+l.search+frag; }
		else if (!frag)                { result = l.href; }
		else                           { result = lindex + frag; }
		if (paramString) {
			var qind = result.indexOf('?');
			var hind = result.indexOf('#');
			if (qind!=-1) { result=result.substring(0,qind); }
			if (hind!=-1) { result=result.substring(0,hind); }
			result+='?'+paramString;
		}
		return result;
	}
	window.resolveUrl = resolveUrl;

	// interrupt "nag screen" behavior
	reg.click('@href', function(e){
		try { var rhref = resolveUrl(this.href); }
		catch (ex) { console.log(ex.message); return; }
		return handleIt(this, rhref, null, rhref);
	});
	reg.submit('form', function(e){
		try { var raction = resolveUrl(this.action); }
		catch (ex) { console.log(ex.message); return; }
		return handleIt(this, null, this, raction);
	});

	function getLabel(field) {
		var labelEl = getParent(field,'label');
		var id = field.id || field.name;
		if (!labelEl) {
			var labels = gebtn('label');
			for (var i=0;i<labels.length;i++){
				if (labels[i].htmlFor===id) {
					labelEl = labels[i];
					break;
				}
			}
		}
		return (labelEl) ? elemText(labelEl) : id;
	}

	// ajaxify the nag screen form behavior
	reg.submit('.k5interrupt',function(e){
		cancelDefault(e);
		if (!this.continueTo && !this.submitTo) {
			console.log('no continueTo url or submitTo form');
			return false;
		}
		var continueTo = this.continueTo;
		var submitTo = this.submitTo;
		var thankYouHref = this.thankYouHref;
		var classes = this.className;
		var k5Form = getTarget(e);
		var fargs = getFormData(k5Form);
		var url = resolveUrl(k5Form.action, fargs);
		var k5Div = this;

		var valMess = validateForm(k5Form);

		if (valMess) {
			if (!hcn(k5Form,"failsilent")) {
				alert(valMess);
			} else {
				k5Close();
				continueTo && (location.href=continueTo);
				submitTo && submitTo.submit();
			}
			return;
		}

		if (k5Form.whichSubmit) {
			k5Form.whichSubmit.value = "sending...";
		}
		try {
			//console.log('sending form results: '+url);
			xhr(url, function(){
				//success
				if (thankYouHref) {
					k5Click.call(elem('a',{'href':thankYouHref,'class':classes},'Thank You'));
					window.setTimeout(function(){
						k5Close();
						continueTo && (location.href=continueTo);
						submitTo && submitTo.submit();
					},2700);
				} else {
					k5Close();
					continueTo && (location.href=continueTo);
					submitTo && submitTo.submit();
				}
			}, function(statusCode, statusText){
				//fail
				if (continueTo) {
					var url = continueTo;
				} else if (submitTo) {
					var url = resolveUrl(submitTo.action,getFormData(submitTo));
				}
				k5Form.appendChild(elem('input',{'type':'hidden','name':'redirect_to','value':url}));
				k5Form.appendChild(elem('input',{'type':'hidden','name':'goto','value':url}));
				k5Form.submit();
				window.setTimeout(function(){k5Close();},100);
			},null,fargs);
		} catch (ex) {
			if (continueTo) {
				var url = continueTo;
			} else if (submitTo) {
				var url = resolveUrl(submitTo.action,getFormData(submitTo));
			}
			k5Form.appendChild(elem('input',{'type':'hidden','name':'redirect_to','value':url}));
			k5Form.appendChild(elem('input',{'type':'hidden','name':'goto','value':url}));
			k5Form.submit();
			window.setTimeout(function(){k5Close();},100);
		}
	});
	// they have chosen to skip the nag screen
	reg.click('.k5skip',function(e){
		var k5Div = gebi('k5');
		if (!k5Div || (!k5Div.continueTo && !k5Div.submitTo)) { return; }
		var continueTo = k5Div.continueTo;
		var submitTo = k5Div.submitTo;
		k5Close();
		continueTo && (location.href=continueTo);
		submitTo && submitTo.submit();
		return false;
	});
	// for easy access to clicked submit button later
	reg.click('.k5interrupt form @type="submit"', function(e){
		if (hcn(this,'k5skip')) { return; }
		var form = getParent(this,'form');
		form.whichSubmit = this;
	});
})();

(function(){
	/**
	get the label string associated with a field element
	*/
	function getLabel(field) {
		var labelEl = getParent(field,'label');
		var id = field.id || field.name;
		if (!labelEl) {
			var labels = gebtn('label');
			for (var i=0;i<labels.length;i++){
				if (labels[i].htmlFor===id) {
					labelEl = labels[i];
					break;
				}
			}
		}
		return (labelEl) ? elemText(labelEl) : id;
	}
	/**
	return an error message if there's an error,
	otherwise an empty string
	*/
	function validateForm(form) {
		var valMess = '';
		var inpReq = gebs('input.required@type="text", input.required@type="password", textarea.required',form);
		var chkReq = gebs('input.required@type="checkbox", input.required@type="radio"',form);
		var selReq = gebs('select.required',form);
		for (var i=0; i<inpReq.length; i++) { var f=inpReq[i]; if(!f.value){valMess+='missing: '+getLabel(f)+'\n';} }
		for (var i=0; i<chkReq.length; i++) { var f=chkReq[i]; if(!f.checked){valMess+='must select: '+getLabel(f)+'\n';} }
		for (var i=0; i<selReq.length; i++) { var f=selReq[i]; if(!f.options[f.selectedIndex].value){valMess+='must select: '+getLabel(f)+'\n';} }
		valMess && (valMess="This form is not complete. Please provide the\nrequired information in order to proceed.\n\n"+valMess);
		return valMess;
	}
	window.validateForm = validateForm;
})();

reg.click("@href*='thisURL'",function(e){
	this.href = this.href.replace(/(thisURL)/,encodeURIComponent(document.location));
});


//////////////////////////////////
// GLOBAL OMNITURE LINK TRACKER //
//////////////////////////////////

// GLOBAL COMPONENT HANDLERS
reg.submit("div.a2search form",function(e){	i = gebs("input.searchfield,input#searchfield",this); if (i[0].value != '' && i[0].value != i[0].defaultValue){	oTrack(this,'A2','Search-'+document.getElementById('searchfield').value); }});
reg.click('a#sunlogo',function(){oTrack(this,'A2','SunLogo');});
reg.click('div.a2topiclinks > ul > li > a',function(){oTrack(this,'A2',this.innerHTML);});
reg.click('div.a2m a',function(){oTrack(this,'A2',this.parentNode.parentNode.parentNode.parentNode.getElementsByTagName('a')[0].innerHTML+'-'+this.innerHTML);});
reg.click('div.a1menu a',function(){var p = hasParent(this,'div','a1menu');p = prevElem(p);oTrack(this,'A1',elemText(p)+'-'+elemText(this));});
reg.click('div.a1 span > a',function(){oTrack(this,'A1');});
reg.click('div#a5 > ul > li > a',function(){oTrack(this,'A5');});
reg.click('div#a5 li li a',function(){var p = hasParent(this,'li','hasmenu');oTrack(this,'A5',elemText(p.getElementsByTagName('a')[0])+'-'+elemText(this))});
reg.click('div.k5 a',function(){var type = 'K5';if(hasParent(this,'poweredby')){type = '-poweredby';}else if(hasParent(this,'countries')){type = '-countries';}oTrack(this,type,this.innerHTML)});

// OMNITURE WHITELIST
var omniwhite = {
	'www':['all'],
	'star-wip.eng':['all']
};

// ALL OTHER CUSTOM LINK SETTING FUNCTION
function oTrack(a,comp,atxt,aud) {

	// if omniture exist
	if(window.s_account){

		// get subdomain (kills off port if localhost or IP)
		var l = (typeof document.location.host.split('netcombilisim.net')[0].replace(/\.$/gi,"").split(':')[0] == 'undefined') ?  navigator.userAgent.toLowerCase().normalize('_') : document.location.host.split('netcombilisim.net')[0].replace(/\.$/gi,"").split(':')[0];

		// check subdomain whitelist for component or all
		var gowhite = false;
		if(omniwhite[l]){
			for (var i=0;i<omniwhite[l].length;i++){
				if(omniwhite[l][i] == comp || omniwhite[l][i] == "all"){
					gowhite = true;
				}
			}
		}else if(omniwhite['home']){
			gowhite = true;
		}

		// if whitelisted
		if((gowhite && !a.trackFirst) || (gowhite && a.trackFirst == comp)){

			a.trackFirst = comp;

			if(a.getElementsByTagName('img')[0] && !atxt){
				if(a.getElementsByTagName('img')[0].alt){
					atxt = a.getElementsByTagName('img')[0].alt;
				}else if(a.getElementsByTagName('img')[0].title){
					atxt = a.getElementsByTagName('img')[0].title;
				}else{
					atxt = a.getElementsByTagName('img')[0].src.replace(/.*\/([^\/.]+)\..*$/g,"$1");
				}
			}else if(!atxt){
				atxt = elemText(a);
			}
			atxt = atxt.replace(/\.\.\./gi,"");
			atxt = atxt.normalize();

			s_linkType='o';

			if(!omniwhite['home']){
				s_linkTrackVars = 'prop13,prop14,prop15,prop16,s_eVar37,s_eVar38';
			}else if(omniwhite['home'] && aud && l && atxt && comp){
				s_linkTrackVars = 'prop13,prop14,prop15,prop16,s_eVar37,s_eVar38,eVar30,eVar36';
				s_eVar30 = l+'-'+ comp+'-'+atxt;
				s_eVar36 = l +'-'+aud;
			}else if(omniwhite['home'] && l && atxt && comp){
				s_linkTrackVars = 'prop13,prop14,prop15,prop16,s_eVar37,s_eVar38,eVar30';
				s_eVar30 = l+'-'+ comp+'-'+atxt;
			}

			s_prop13=comp;
			s_prop14=decodeURIComponent(a.href);
			s_prop15=s_pageName;
			s_prop16=atxt;
			s_eVar37=l+'-'+atxt;
			s_eVar38=l+'-'+comp;
			s_linkName=l+':'+comp+':'+atxt;
			// console for testing
			if(omniwhite['console']){
				console.log(
					  '   s_prop13 = '+comp+
					'\n   s_prop14 = '+decodeURIComponent(a.href)+
					'\n   s_prop15 = '+s_pageName+
					'\n   s_prop16 = '+atxt+
					'\n   s_eVar37 = '+l+'-'+atxt+
					'\n   s_eVar38 = '+l+'-'+comp+
					'\n s_linkName = '+l+':'+ comp+':'+atxt
				);
				if(omniwhite['home']){ console.log('\n s_eVar30 = '+l+'-'+ comp+'-'+atxt);}
				if(aud){ console.log('\n s_eVar36 = '+l+'-'+aud);}
			}
			// if any var is null/undefined don't process
			if(s_prop13 && s_prop14 && s_prop15 && s_prop16 && s_eVar37 && s_eVar38){
				s_lnk=s_co(a);
				s_gs(s_account)
			}
			s_prop13 = s_prop14 = s_prop15 = s_prop16 = s_linkTrackVars = s_eVar37 = s_eVar38 = s_eVar30 = s_eVar36 = "";
		}
	}
}

(function(){

	/**
	Pop up a new survey window.
	@param url          (string) url to pop up
	@param nProb        (float >0.0 and <=1.0) probability of survey randomly popping up (default 1.0) (can be expressed as 1/N where N means every "Nth" visitor)
	@param suppressDays (int) don't show again for X days, -1 means never show again, 0 means don't suppress (default 0)
	@param height       (int) height of popup (default 600)
	@param width        (int) width of popup (default 548)
	@param noScrolling  (boolean) suppress scrollbars in popup (default false)
	*/
	window.surveyPop = function(url, nProb, suppressDays, height, width, noScrolling) {
		if (nProb && nProb < Math.random()) { return false; }
		if (beenThereDoneThat(surveyUrl, suppressDays)) { return false; }

		if (!width) { width = 548; }
		if (!height) { height = 600; }
		var args = 'resizable,status,width='+width+',height='+height;
		if (!noScrolling) { args += ',scrollbars'; }
		var newWin = window.open(url, '_surveyWin', args);
		return newWin;
	}

	/**
	Opens a modal dialog for surveys.
	@param dialogUrl    (string) url of survey dialog to pop up (must be same-page or same-domain, with fragment id)
	@param nProb        (float >0.0 and <=1.0) probability of survey randomly popping up (default 1.0) (can be expressed as 1/N where N means every "Nth" visitor)
	@param suppressDays (int) don't show again for X days, -1 means never show again, 0 means don't suppress (default 0)
	*/
	window.surveyDialog = function(dialogUrl, nProb, suppressDays) {
		if (nProb && nProb < Math.random()) { return false; }
		if (beenThereDoneThat(dialogUrl, suppressDays)) { return false; }
		var dummyLink = elem('a',{'class':'k5 k5info','href':dialogUrl},'');
		k5Click.call(dummyLink);
	}

	// private function for cookies
	function beenThereDoneThat(url, suppressDays) {
		var patt = new RegExp('^'+ckName+'_'+uHash+'=seen$');
		var ck = document.cookie;
		var ckName = 'surveyHash';
		var ckArr = ck.split('; ');
		var uHash = url.toLowerCase().replace(/[^a-z0-9_\/]/g,'_');
		var beenThere = false;
		for (var i=0; i<ckArr.length; i++) {
			if (patt.test(ckArr[i])) { return true; }
		}
		if (suppressDays) {
			if (suppressDays < 0) { suppressDays = 9999; }
			var expires = new Date();
			expires.setTime(expires.getTime() + suppressDays * 1000 * 60 * 60 * 24);
			document.cookie = ckName+'_'+uHash+'=seen; expires='+expires.toGMTString();
		}
		return false;
	}

})();


/*
Version 0.9.1: 2009-06-19

Change-log (0.9.1):
* Removed "comApp" from all function names
* Updated suncomExtendedCookieWhiteList

*/

function decodeSunSessionCookie() {
    var lookup = "SASC=";
    var value = "";
    var ca = document.cookie.split(';');
    for(var i=0; i<ca.length;i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1, c.length);
        if (c.indexOf(lookup) == 0) value = c.substring(lookup.length, c.length);
    }
    return decodeURIComponent(value);
}

/** Set session cookie by name/value. */
function setSunSessionCookie(name, value) {
    var decoded = decodeSunSessionCookie();
    var newValue = "";
    var newSubcookie = true;
    if (decoded != "") {
        var nvps = decoded.split('&');
        for(var i=0; i<nvps.length; i++) {
            var nvp = nvps[i].split('=');
            if (nvp[0] == name) {
                nvp[1] = encodeURIComponent(value);
                newSubcookie = false;
            }
            newValue += nvp[0] + "=" + nvp[1] + "&";
        }
        newValue = newValue.substring(0, newValue.length - 1);
    }
    if (newSubcookie) {
        if (newValue != "") newValue += "&";
        newValue += name + "=" + encodeURIComponent(value);
    }
    if (newValue.length > 4080) {
        throw "Out of application session cookie space";
    }
    document.cookie = "SASC="+encodeURIComponent(newValue)+"; path=/";
}

/** Get session cookie by name. */
function getSunSessionCookie(name) {
    var decoded = decodeSunSessionCookie();
    if (decoded != "") {
        var nvps = decoded.split('&');
        for(var i=0; i<nvps.length; i++) {
            var nvp = nvps[i].split('=');
            if (nvp[0] == name) {
                return decodeURIComponent(nvp[1]);
            }
        }
    }
    return null;
}

/** Remove session cookie by name. */
function removeSunSessionCookie(name) {
    var decoded = decodeSunSessionCookie();
    var newValue = "";
    if (decoded != "") {
        var nvps = decoded.split('&');
        for(var i=0; i<nvps.length; i++) {
            var nvp = nvps[i].split('=');
            if (nvp[0] == name) {
                continue; // Skip
            }
            newValue += nvp[0] + "=" + nvp[1] + "&";
        }
        newValue = newValue.substring(0, newValue.length - 1);
    }
    document.cookie = "SASC="+encodeURIComponent(newValue)+"; path=/";
}

function deriveExpirationForAppExtendedCookie() {
    var date = new Date();
    date.setTime(date.getTime()+(365*24*60*60*1000));
    return "; expires="+date.toGMTString();
}

function decodeSunExtendedCookie() {
    var lookup = "SAEC=";
    var value = "";
    var ca = document.cookie.split(';');
    for(var i=0; i<ca.length;i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1, c.length);
        if (c.indexOf(lookup) == 0) value = c.substring(lookup.length, c.length);
    }
    return decodeURIComponent(value);
}

/** Set extended cookie by name/value, with an optional expiration in days. */
function setSunExtendedCookie(name, value, days) {
    if (suncomExtendedCookieWhiteList[name]) {
        // allowed
    } else if (name.length > 4 &&
        name.substring(name.length-4, name.length) == "_exp" &&
        suncomExtendedCookieWhiteList[name.substring(0, name.length - 4)]) {
        // allowed
    } else {
        throw "This cookie name is not supported - " + name;
    }
    var decoded = decodeSunExtendedCookie();
    var newValue = "";
    var newSubcookie = true;
    if (decoded != "") {
        var nvps = decoded.split('&');
        for(var i=0; i<nvps.length; i++) {
            var nvp = nvps[i].split('=');
            if (nvp[0] == name) {
                nvp[1] = encodeURIComponent(value);
                newSubcookie = false;
            }
            newValue += nvp[0] + "=" + nvp[1] + "&";
        }
        newValue = newValue.substring(0, newValue.length - 1);
    }
    if (newSubcookie) {
        if (newValue != "") newValue += "&";
        newValue += name + "=" + encodeURIComponent(value);
    }
    if (newValue.length > 4080) {
        throw "Out of application session cookie space";
    }
    var expires = deriveExpirationForAppExtendedCookie();
    document.cookie = "SAEC="+encodeURIComponent(newValue)+expires+"; path=/";
    if (days) {
        var date = new Date();
        var expiresAt = days + Math.ceil(date.getTime() / 24 / 60 / 60 / 1000);
        setSunExtendedCookie(name + "_exp", expiresAt, null);
    }
}

/** Get extended cookie by name. */
function getSunExtendedCookie(name) {
    var expiresAt = null;
    if (!(name.length > 4 && name.substring(name.length-4, name.length) == "_exp")) {
        expiresAt = getSunExtendedCookie(name+"_exp");
    }
    if (expiresAt != null) {
        var today = Math.ceil(new Date().getTime() / 24 / 60 / 60 / 1000);
        if (today > expiresAt) {
            removeSunExtendedCookie(name);
            return null;
        }
    }
    var decoded = decodeSunExtendedCookie();
    if (decoded != "") {
        var nvps = decoded.split('&');
        for(var i=0; i<nvps.length; i++) {
            var nvp = nvps[i].split('=');
            if (nvp[0] == name) {
                return decodeURIComponent(nvp[1]);
            }
        }
    }
    return null;
}

/** Remove extended cookie by name. */
function removeSunExtendedCookie(name) {
    if (!(name.length > 4 && name.substring(name.length-4, name.length) == "_exp")) {
        removeSunExtendedCookie(name + "_exp");
    }
    var decoded = decodeSunExtendedCookie();
    var newValue = "";
    if (decoded != "") {
        var nvps = decoded.split('&');
        for(var i=0; i<nvps.length; i++) {
            var nvp = nvps[i].split('=');
            if (nvp[0] == name) {
                continue; // Skip
            }
            newValue += nvp[0] + "=" + nvp[1] + "&";
        }
        newValue = newValue.substring(0, newValue.length - 1);
    }
    var expires = deriveExpirationForAppExtendedCookie();
    document.cookie = "SAEC="+encodeURIComponent(newValue)+expires+"; path=/";
}

var suncomExtendedCookieWhiteList = {
//    placeholder1 : true,
//    placeholder2 : true
};




// HP1
reg.click('a.hp1link',showhp1);
function showhp1(){

	// mmmm cookies
	if(this.href.indexOf('audience=') > -1){
		var uuid = this.href.split('audience=')[1].split('?')[0];
 		var sxmnth = new Date();
 		sxmnth.setTime(sxmnth.getTime() + 180 * 24 * 60 * 60 * 1000);
 		document.cookie = 'star-audience='+uuid+';path=/;expires='+sxmnth;
	}

	if(!hasClassName(this.parentNode,'hp1selected')){
		// hide all audiences
		var li = this.parentNode.parentNode.getElementsByTagName('li');
		for (var i=0;i<li.length;i++){
			removeClassName(li[i],'hp1selected');
		}
		if(this.parentNode.getElementsByTagName('div')[0]){
			var imgs = this.parentNode.getElementsByTagName('div')[0].getElementsByTagName('img');
			for (var i=0;i<imgs.length;i++){
				if(hasClassName(imgs[i],'hp1img') || hasClassName(imgs[i],'hp5img')){
					imgs[i].sfade = null;
					setopacity(imgs[i],0);
					sfadein(imgs[i],.025);
				}
			}
		}
		// show selected audience
		addClassName(this.parentNode,'hp1selected');
		// if no audience content fetch
		if(!this.parentNode.getElementsByTagName('div')[0]){
			var link = this;
			var delim = (link.href.indexOf('?') > -1) ? '&' : '?';
			xhr(link.href+delim+"hijax=true", function(rdata,obj){
				// succeed
				var d = elem('div');
				d.innerHTML = rdata;
				var hp1 = d.getElementsByTagName('div')[0];
				if (!hp1){window.location=link.href;}
				link.parentNode.appendChild(hp1);
				reg.rerun(link.parentNode);
			},function(){
				// fail
				window.location=link.href;
			},link);
			return false;
		}
	}
	return false;
}
reg.postSetup(function(){
	var imgs = gebi('hp1').getElementsByTagName('img')
	for (var i=0;i<imgs.length;i++){
		if(hasClassName(imgs[i],'hp1img') || hasClassName(imgs[i],'hp5img')){
			imgs[i].sfade = 1;
			setopacity(imgs[i],1);
		}
	}
});
reg.setup("img.hp1img,img.hp5img",function(){
	this.onload = function(){
		sfadein(this,.025);
	};
});

// HP2
reg.click('a.hp2link',showhp2);
reg.focus("a.hp2link",hideOtherhp2);
reg.click('a.closehp2',hidehp2);
function showhp2(){
	var li = this.parentNode;
	addClassName(li,'hp2iCurrent');
	if(!gebcn("closehp2",li)[0]){
		li.getElementsByTagName('div')[0].insertBefore(elem('a.closehp2',{'href':'#close','title':'Close'}),li.getElementsByTagName('div')[0].getElementsByTagName('p')[0]);
		li.getElementsByTagName('div')[0].insertBefore(elem('span.hp2bigbttn'),li.getElementsByTagName('div')[0].getElementsByTagName('p')[0]);
	}
	sfadein(li.getElementsByTagName('div')[0],.05);
	return false;
}

if(is.ie56){
	reg.hover('div.hp4promo',function(){addClassName(this,'hp4showpromo');},function(){removeClassName(this,'hp4showpromo');});
}

function hideOtherhp2(){
	if(prevElem(this.parentNode)){
		removeClassName(prevElem(this.parentNode),'hp2iCurrent');
	}
}
function hidehp2(){
	removeClassName(this.parentNode.parentNode,'hp2iCurrent');
	return false;
}

////////////////////////////
// OMNITURE LINK TRACKING //
////////////////////////////
omniwhite['home'] = true;

reg.click('a.hp1link',function(){oTrack(this,'HP1',elemText(this),elemText(this))});
reg.click('div#hp1 area',function(){
	var n = this.parentNode.name;
	var m = document.getElementById('hp1').getElementsByTagName('img');
	for (var i = 0;i < m.length;i++){
		if(m[i].useMap == "#"+n && hasClassName(m[i],'hp1img')){
			var aud = hasParent(m[i],'li','hp1selected');
			var dsc = (this.alt) ? m[i].src.replace(/.*\/([^\/.]+)\..*$/g,"$1")+'-'+this.alt : m[i].src.replace(/.*\/([^\/.]+)\..*$/g,"$1")+'-'+this.href.replace(/http:\/\/[^\/]+(.*)$/g,"$1") ;
			oTrack(this,'HP1',elemText(aud.getElementsByTagName('a')[0])+'-'+dsc);
 			break;
		}else if(m[i].useMap == "#"+n && hasClassName(m[i],'hp5img')){
			var aud = hasParent(m[i],'li','hp1selected');
			var dsc = (this.alt) ? m[i].src.replace(/.*\/([^\/.]+)\..*$/g,"$1")+'-'+this.alt : m[i].src.replace(/.*\/([^\/.]+)\..*$/g,"$1")+'-'+this.href.replace(/http:\/\/[^\/]+(.*)$/g,"$1") ;
			oTrack(this,'HP5',elemText(aud.getElementsByTagName('a')[0])+'-'+dsc);
 			break;
		}
	}
});
reg.click('div.hp1w1 a > img',function(){
	var aud = hasParent(this,'li','hp1selected');
	var type = (this.className.indexOf('hp1img') > -1) ? 'HP1' : 'HP5';
	oTrack(this,type,elemText(aud.getElementsByTagName('a')[0])+'-'+this.src.replace(/.*\/([^\/.]+)\..*$/g,"$1"))
});
reg.click('div#hp2 ul ul a',function(){var p = hasParent(this,'li','hp2i');oTrack(this,'HP2',p.getElementsByTagName('h3')[0].innerHTML+'-'+this.innerHTML)});
reg.click('div#hp2 h2 a',function(){oTrack(this,'HP2',this.innerHTML+' Button')});
reg.click('div.hp4 a',function(){
	if (this.className.indexOf('morelink') > -1){
		oTrack(this,'HP4-MORE',elemText(getParent(this,'li').getElementsByTagName('a')[0]));
	}else{
		oTrack(this,'HP4',elemText(this));
	}
});
reg.click('div.hp6 a',function(){oTrack(this,'HP6',elemText(this))});
reg.click('div.hp3 a,div.hp3 area',function(){var p = hasParent(this,'div','hp3');oTrack(this,'HP3',p.getElementsByTagName('img')[0].src.replace(/.*\/([^\/.]+)\..*$/g,"$1"));});

(function(){
	var k5infoloaded = false;
	reg.hover('.k5info',function(e){
		if (!k5infoloaded) {
			document.body.appendChild(elem('div.k5infopreload'));
			k5infoloaded = true;
		}
	});
})();


// ################################ OBJECT HELPERS ###########################

// " foo  " -> "foo"
if(!String.prototype.strip){
	String.prototype.strip=function(){return this.replace(/^\s+|\s+$/g, "");};
}

// " foo   bar  " -> "foo bar"
if(!String.prototype.normalize){
	String.prototype.normalize=function(sp){
		sp=(!sp && sp!=='')?' ':sp;
		return this.strip().replace(/\s+/g,sp);
	};
}

// ###########################################################################
// END REG LIB, BEGIN XMLHTTPREQUEST FUNCTIONS
// ###########################################################################

// GENERIC HTTP REQUEST
function getfile(filepath,ftodo,fvar,ferr,forceText){
	var http_request = false;
	if (window.XMLHttpRequest) {
		http_request = new XMLHttpRequest();
		if (http_request.overrideMimeType && filepath.indexOf('.xml') > -1){
			http_request.overrideMimeType('text/xml');
		}
	}else if (window.ActiveXObject) { // IE
		try { http_request = new ActiveXObject("Msxml2.XMLHTTP");
		}catch(ex1){
			try{
				http_request = new ActiveXObject("Microsoft.XMLHTTP");
			}catch(ex2){}
		}
	}
	if (!http_request) {
		return false;
	}
	http_request.onreadystatechange = function() {
		if (http_request.readyState == 4) {
			if (http_request.status == 200) {
				if (filepath.indexOf('.xml') > -1 && !forceText){
					var rdata = http_request.responseXML.documentElement;
				}else{
					var rdata = http_request.responseText;
				}
				ftodo(rdata,fvar); // SUCCESS
			}else{
				if (ferr) { ferr(fvar,filepath,http_request.status,http_request.statusText); } // FAIL
			}
		}
	};
	http_request.open('GET', filepath, true);
	http_request.send(null);
}

// RETURN OBJECT FROM STRING
function getRequestObject(elementID,rdata,elementTag) {
	if (!elementTag){ elementTag = 'div'; } // elementTag optional, defaults to DIV
	var sudocont = document.createElement(elementTag);
	sudocont.innerHTML = rdata;
	var x = gebtn(elementTag,sudocont);
	var chunk;
	for (var i=0;i<x.length;i++) {
		if (x[i].id == elementID) {
			chunk = x[i];
			break;
		}
	}
	return chunk;
}

// BUILD AN ELEMENT FROM TEXT PULLED FROM XHR
function getElementByIdFromString(textBlob, id) {
	var container = document.createElement('div');
	container.innerHTML = textBlob;
	var tags = gebtn("*",container);
	for (var a=0,tag;tag=tags[a++];){
		if (tag.id == id) { return tag; }
	}
	return null;
}

// GENERIC XML HTTP REQUEST
function xhr(url, successFunc, failFunc, obj, postData){
	/*
	successFunc(responseText, obj)
	failFunc(statusCode, statusText, url, obj)
	*/
	//check whether this is same-domain
	var parts=resolveUrl(url).split(/\/+/g);
	if(parts[0]!==location.protocol||parts[1]!==location.host){
		throw new Error("cross-domain requests not allowed");
	}
	var http_request = false;
	if (window.XMLHttpRequest) {
		http_request = new XMLHttpRequest();
	}else if (window.ActiveXObject) { // IE
		try { http_request = new ActiveXObject("Msxml2.XMLHTTP"); }
		catch(e){
			try{ http_request = new ActiveXObject("Msxml3.XMLHTTP"); }
			catch(ex1){
				try{ http_request = new ActiveXObject("Microsoft.XMLHTTP"); }
				catch(ex2){}
			}
		}
	}
	if (!http_request) { return false; }
	if (!postData) { postData = null; }
	var method = (postData) ? "POST" : "GET";
	http_request.open(method, url, true);
	if (postData) {
		http_request.setRequestHeader('Content-type','application/x-www-form-urlencoded');
		http_request.setRequestHeader("Content-length", postData.length);
		http_request.setRequestHeader("Connection", "close");
	}
	http_request.onreadystatechange = function() {
		if (http_request.readyState == 4) {
			if (http_request.status == 200) {
				successFunc(http_request.responseText, obj);
			}else{
				try { failFunc(http_request.status, http_request.statusText, url, obj); }
				catch (ex) { failFunc('', ex, url, obj); }
			}
		}
	};
	http_request.send(postData);
}

// GET DATA FROM A FORM FOR XHR
function getFormData(thisform) {
	var fargs = [];
	var inps = reg.getElementsBySelector("input, select, textarea",thisform);
	for (var a=0; a<inps.length; a++){
		var inp = inps[a];
		if (matches(inp,'@type="text",@type="hidden",@type="password"')){
			fargs.push(encodeURIComponent(inp.name) + "=" + encodeURIComponent(inp.value));
		}
		if (inp.type == "checkbox"  && inp.checked || inp.type == "radio" && inp.checked){
			fargs.push(encodeURIComponent(inp.name) + "=" + encodeURIComponent(inp.value));
		}
		if (inp.nodeName.toLowerCase()=='select'){
			var selVal = inp.options[inp.selectedIndex].value;
			fargs.push(encodeURIComponent(inp.name) + "=" + encodeURIComponent(selVal));
		}
		if (inp.nodeName.toLowerCase()=='textarea'){
			fargs.push(encodeURIComponent(inp.name) + "=" + encodeURIComponent(inp.value));
		}
	}
	return fargs.join('&');
}

// ###########################################################################
// END XMLHTTPREQUEST FUNCTIONS, BEGIN SUN FUNCTIONS
// ###########################################################################

// HAS PARENT
function hasParent(obj,tag,classname){
	var parent = obj;
	if(classname){
		while (parent = parent.parentNode) {
			if (parent.nodeName.toLowerCase() == tag && hasClassName(parent,classname) || tag == "*" && hasClassName(parent,classname)){
				return parent;
			}
		}
	}else if (typeof tag == 'string') {
		while (parent = parent.parentNode) {
			if (parent.id == tag){
				return parent;
			}
		}
	}else{
		while (parent = parent.parentNode) {
			if (parent == tag){
				return parent;
			}
		}
	}
}

// GET XY OF OBJ
function getXY(obj){
	var o = obj;
	obj.X = obj.Y = 0;
	while(o){
		obj.X = obj.X + o.offsetLeft;
		obj.Y = obj.Y + o.offsetTop;
		o = o.offsetParent;
	}
}

// GET FULL CLASS NAME FROM PARTIAL STRING
function getClassContains(obj,subst){
	var rcl = false;
	var cls = obj.className.split(' ');
	for (var v=0;v<cls.length;v++){
		if (cls[v].indexOf(subst) > -1){
			rcl = cls[v];
		}
	}
	return rcl;
}

// GET CHILD NODES VIA TAG NAME
function getChildNodesByTagName(el, tagName){
	var cn = el.childNodes;
	var nd = [];
	for (var n=0;n<cn.length;n++){
		if(tagName == cn[n].nodeName.toLowerCase()){
			nd.push(cn[n]);
		}
	}
	return nd;
}

// SET OPACITY
function setopacity(id_or_obj,opac){
	if (gebi(id_or_obj)){
		var oobj = gebi(id_or_obj);
	}else if(id_or_obj){
		var oobj = id_or_obj;
	}
	if (oobj){
		if (oobj.filters && oobj.filters.alpha){
			oobj.filters.alpha.opacity = opac * 100;
		}else{
			oobj.style.MozOpacity = opac;
			oobj.style.opacity = opac;
		}
	}
}

// FADEIN
function sfadein(obj,n){
	if(!obj.sfade){ obj.sfade = 0; }
	if(obj.sfade< 1){
		if(is.safariAll){
			obj.sfade = obj.sfade + (n * 5);
		}else{
			obj.sfade = obj.sfade + n;
		}
		setopacity(obj,obj.sfade);
 		setTimeout(function(){sfadein(obj,obj.sfade);},75);
	}else{
		setopacity(obj,1);
		obj.sfade = null;
	}
}


// takes an integer, returns a new month
// if someDate = jan 11 2004 11:04:27 am
// then someDate.diffDay(-9) = jan 2 2004 11:04:27 am
Date.prototype.diffDay = function(days){
	var r = new Date(this.getTime());
	r.setDate(r.getDate()+days);
	return r;
}

// takes an integer, returns a new month
// if someDate = jan 11 2004 11:04:27 am
// then someDate.diffMonth(3) = apr 11 2004 11:04:27 am
Date.prototype.diffMonth = function(months){
	var r=new Date(this.getTime());
	var num = r.getMonth()+months;
	var yearInc = 0;
	// because safari messes up on date.setMonth(-1)
	if (num < 0) { while(num < 0) { num += 12; yearInc--; } }
	else if (num > 11) { while(num > 11) { num -= 12; yearInc++; } }
	r.setMonth(num);
	r.setFullYear(r.getFullYear() + yearInc)
	return r;
}

// pad a string on the left up to a given amount
// foo = "3"
// foo = foo.padLeft("0", 3)
// foo now is "003"
String.prototype.padLeft = function(ch,amount){
	var r=this;
	while(r.length<amount){r=ch+r;}
	return r;
}

/*
takes a format mask and returns a string representation of this date.
enclose escape sequences in single quotes.
new Date().format("DD/MM/YYYY")   // evaluates to "25/11/2008"
new Date().format("'DD'/MM/YYYY") // evaluates to "DD/11/2008"
format flags:
	D		1-31 (day of month)
	DD		01-31 (day of month)
	Dth		1st, 2nd, 3rd... (day of month)
	M		1-12 (month of year)
	MM		01-12 (month of year)
	mon		jan-dec
	month	january-december
	Mon		Jan-Dec
	Month	January-December
	MON		JAN-DEC
	MONTH	JANUARY-DECEMBER
	w		s, m, t, w, t, f, s (weekday)
	we		su-sa (weekday)
	wee		sun-sat (weekday)
	weekday	sunday-saturday
	W		S, M, T, W, T, F, S (weekday)
	We		Su-Sa (weekday)
	Wee		Sun-Sat (weekday)
	Weekday	Sunday-Saturday
	WE		SU-SA (weekday)
	WEE		SUN-SAT (weekday)
	WEEKDAY	SUNDAY-SATURDAY
	YY		2-digit year
	YYYY		4-digit year
	ss		00-59 (seconds)
	mm		00-59 (minutes)
	h		1-12 (hours)
	hh		01-12 (hours)
	H		0-23 (hours)
	HH		00-23 (hours)
	a		am, pm
	A		AM, PM
	X		timezone offset
*/
Date.prototype.format = (function(){
	var pattern =       /(WEEKDAY)|(Weekday)|(weekday)|(WEE)|(Wee)|(wee)|(WE)|(We)|(we)|(W)|(w)|(MONTH)|(Month)|(month)|(MON)|(Mon)|(mon)|(MM)|(M)|(DD)|(Dth)|(D)|(YYYY)|(YY)|(HH)|(hh)|(H)|(h)|(mm)|(ss)|(A)|(a)|(X)/g;
	var dobj;
	function parser(str,  WEEKDAY,  Weekday,  weekday,  WEE,  Wee,  wee,  WE,  We,  we,  W,  w,  MONTH,  Month,  month,  MON,  Mon,  mon,  MM,  M,  DD,  Dth,  D,  YYYY,  YY,  HH,  hh,  H,  h,  mm,  ss,  A,  a,  X){
		var result;
		if (ss)      { return (''+dobj.getSeconds()).padLeft('0',2); }
		if (mm)      { return (''+dobj.getMinutes()).padLeft('0',2); }
		if (H)       { return dobj.getHours()+''; }
		if (HH)      { return (dobj.getHours()+'').padLeft('0',2); }
		if (h)       {
			result=(dobj.getHours()%12)+'';
			if(result=='0'){result='12';}
			return result;
		}
		if (hh)      {
			result=(dobj.getHours()%12)+'';
			if(result=='0'){result='12';}
			result=result.padLeft('0',2);
			return result;
		}
		if (Weekday) { return dayNamesFull[dobj.getDay()]; }
		if (W)       { return dayNames1[dobj.getDay()]; }
		if (We)      { return dayNames2[dobj.getDay()]; }
		if (Wee)     { return dayNames3[dobj.getDay()]; }
		if (WEEKDAY) { return dayNamesFull[dobj.getDay()].toUpperCase(); }
		if (WE)      { return dayNames2[dobj.getDay()].toUpperCase(); }
		if (WEE)     { return dayNames3[dobj.getDay()].toUpperCase(); }
		if (weekday) { return dayNamesFull[dobj.getDay()].toLowerCase(); }
		if (w)       { return dayNames1[dobj.getDay()].toLowerCase(); }
		if (we)      { return dayNames2[dobj.getDay()].toLowerCase(); }
		if (wee)     { return dayNames3[dobj.getDay()].toLowerCase(); }
		if (D)       { return dobj.getDate()+''; }
		if (DD)      { return (dobj.getDate()+'').padLeft('0',2); }
		if (Dth)     {
			result=dobj.getDate()+'';
			if(result.match(/^1\d$/)){result+='th';}
			else if(result.match(/1$/)){result+='st';}
			else if(result.match(/2$/)){result+='nd';}
			else if(result.match(/3$/)){result+='rd';}
			else{result+='th';}
			return result;
		}
		if (YYYY)    { return dobj.getFullYear()+''; }
		if (YY)      { return (dobj.getFullYear()+'').substring(2,4); }
		if (M)       { return (dobj.getMonth()+1)+''; }
		if (MM)      { return ((dobj.getMonth()+1)+'').padLeft('0',2); }
		if (Month)   { return monthNamesFull[dobj.getMonth()]; }
		if (Mon)     { return monthNames3[dobj.getMonth()]; }
		if (MONTH)   { return monthNamesFull[dobj.getMonth()].toUpperCase(); }
		if (MON)     { return monthNames3[dobj.getMonth()].toUpperCase(); }
		if (month)   { return monthNamesFull[dobj.getMonth()].toLowerCase(); }
		if (mon)     { return monthNames3[dobj.getMonth()].toLowerCase(); }
		if (X)       { return (dobj.getTimezoneOffset()/60)+''; }
		if (A)       { return (dobj.getHours()<12)?'AM':'PM'; }
		if (a)       { return (dobj.getHours()<12)?'am':'pm'; }
	}
	return function(fmt) {
		dobj = this;
		var parts = fmt.split("'");
		if (parts.length % 2 == 0) { throw "missing closing single quote in date format \""+fmt+"\"";}
		for (var i=0;i<parts.length;i+=2){
			parts[i]=parts[i].replace(pattern, parser);
		}
		return parts.join('');
	};
})();

// for displaying and manipulating a calendar
// encapsulates a 2d array
// only cares about days, not times
function Calendar(date, startDate, endDate, origDate) {
	this.origDate = (origDate) ? origDate : date.diffDay(0);
	this.startDate = startDate;
	this.endDate = endDate;
	date.setDate(1);
	this.canonicalMonth = date.diffDay(0);

	// init the date 2d array
	this.g = [];
	this.g[0] = [];

	// populate the pre days
	var numPreDays = date.getDay();
	var row = this.g[0];
	for (var a=0;a<numPreDays;a++){
		row[a] = date.diffDay(a-numPreDays);
		row[a].dayClass = 'jscal-before';
		if (startDate && row[a].getTime() < startDate) { row[a].dayClass += ' jscal-outofrange'; }
		else if (endDate && row[a].getTime() > endDate) { row[a].dayClass += ' jscal-outofrange'; }
		else { row[a].dayClass += ' jscal-inrange'; }
	}

	// populate the days
	var todayDateStr = new Date().format("DD/MM/YYYY");
	var curDateStr = this.origDate.format("DD/MM/YYYY");
	while (date.getMonth() == this.canonicalMonth.getMonth()) {
		var curDate = this.g[this.g.length-1][date.getDay()];
		this.g[this.g.length-1][date.getDay()] = date;
		this.g[this.g.length-1][date.getDay()].dayClass = 'jscal-during';
		var dateStr = date.format("DD/MM/YYYY");
		if (dateStr == todayDateStr) {date.dayClass += ' jscal-today';}
		if (dateStr == curDateStr) {date.dayClass += ' jscal-current';}
		if (startDate && date.getTime() < startDate) { date.dayClass += ' jscal-outofrange'; }
		else if (endDate && date.getTime() > endDate) { date.dayClass += ' jscal-outofrange'; }
		else { date.dayClass += ' jscal-inrange'; }
		date = date.diffDay(1);
		if (date.getDay() == 0 && date.getMonth() == this.canonicalMonth.getMonth()) { this.g[this.g.length] = []; }
	}

	// populate the post days
	var row = this.g[this.g.length-1];
	var numPostDays = row.length;
	for (var a=row.length;a<7;a++){
		row[a] = date.diffDay(a-numPostDays);
		row[a].dayClass = 'jscal-after';
		if (startDate && row[a].getTime() < startDate) { row[a].dayClass += ' jscal-outofrange'; }
		else if (endDate && row[a].getTime() > endDate) { row[a].dayClass += ' jscal-outofrange'; }
		else { row[a].dayClass += ' jscal-inrange'; }
	}
}

// how many weeks (i.e. rows) actually exist in this calendar grid?
Calendar.prototype.weeks = function(){
	return this.g.length;
}

// return a date object by coordinates
// getDayAt(0,0) will probably return a day from the month previous
// getDayAt(0,7) is an index out of bounds error since weekday indices are 0-6
Calendar.prototype.getDayAt = function(weekOfMonth,dayOfWeek){
	return this.g[weekOfMonth][dayOfWeek];
}

// return a clone of this calendar but representing a different month
Calendar.prototype.diffMonth = function(months){
	return new Calendar(this.canonicalMonth.diffMonth(months), this.startDate, this.endDate, this.origDate);
}

// return a DOM tree showing a calendar
Calendar.prototype.getCalendarTable=function() {
	var t = elem('table.jscal',{'cellSpacing':'0'});
	var div = elem('div.jscal-x1',{},elem('div.jscal-x2',{},t));

	t.createTHead().insertRow(0);
	t.tHead.rows[0].className = "jscal-mname";
	t.tHead.rows[0].appendChild(elem('th')).colSpan = '7';
	t.tHead.insertRow(1).className = "jscal-dname";
	t.tHead.rows[1].appendChild(elem('th')).appendChild(document.createTextNode(dayNames1[0]));
	t.tHead.rows[1].appendChild(elem('th')).appendChild(document.createTextNode(dayNames1[1]));
	t.tHead.rows[1].appendChild(elem('th')).appendChild(document.createTextNode(dayNames1[2]));
	t.tHead.rows[1].appendChild(elem('th')).appendChild(document.createTextNode(dayNames1[3]));
	t.tHead.rows[1].appendChild(elem('th')).appendChild(document.createTextNode(dayNames1[4]));
	t.tHead.rows[1].appendChild(elem('th')).appendChild(document.createTextNode(dayNames1[5]));
	t.tHead.rows[1].appendChild(elem('th')).appendChild(document.createTextNode(dayNames1[6]));

	t.appendChild(elem('tbody'));
	var m = t.tHead.rows[0].cells[0];
	var closer = elem('span.jscal-closer',{'href':'#','border':'0'},elem('img',{'alt':'[x]','src':imdir+'/ic_close_win_light.gif','title':'close'}));
	var pMonth = elem('a.jscal-mselect',{'title':'previous month'},'\u00AB ');
	var monthYear = elem('span.jscal-monthyear',{},this.canonicalMonth.format('Mon')+' '+this.canonicalMonth.format('YYYY'))
	var nMonth = elem('a.jscal-mselect',{'title':'next month'},' \u00BB');
	pMonth.calendar = nMonth.calendar = div.calendar = this;
	closer.div = pMonth.div = nMonth.div = div;
	m.appendChild(closer);
	m.appendChild(pMonth);
	m.appendChild(monthYear);
	m.appendChild(nMonth);
	addEvent(pMonth,'click',function(e){
		getParent(this,'div.jscal-x1').setCalendar(this.calendar.diffMonth(-1));
		cancelDefault(e);
	});
	addEvent(nMonth,'click',function(e){
		getParent(this,'div.jscal-x1').setCalendar(this.calendar.diffMonth(1));
		cancelDefault(e);
	});
	addEvent(closer,'click',function(e){
		var parentDiv = getParent(this,'div.jscal-x1');
		parentDiv.parentNode.removeChild(parentDiv);
		cancelDefault(e);
	});

	for (var a=0;a<this.weeks();a++){
		t.tBodies[0].insertRow(a);
		for (var b=0;b<7;b++){
			t.tBodies[0].rows[a].insertCell(b);
			var dt = this.getDayAt(a,b);
			if(!dt){throw "empty month date at "+a+","+b;}
			t.tBodies[0].rows[a].cells[b].className = dt.dayClass;
			var lnk = elem('span',{},''+dt.getDate());
			lnk.date = dt;
			t.tBodies[0].rows[a].cells[b].appendChild(lnk);
		}
	}

	div.setCalendar = function(cal) {
		var newDiv = cal.getCalendarTable();
		this.appendChild(newDiv.firstChild);
		this.removeChild(this.firstChild);
	}
	return div;
};


// GET SAFELY ENCODED STRINGS
function getSafelyEncodedString(s) {
	s = encodeURIComponent(s);
	s = s.replace(/&/,"&amp;").replace(/"/,"&quot;").replace(/</,"&lt;").replace(/>/,"&gt;");
	return s;
}

// GETS AMOUNT SCROLLED FROM TOP
function getScrollTop(){
	if(window.pageYOffset !== undefined){
		return window.pageYOffset;
	} else {
		var db = document.body; //IE 'quirks'
		var dd = document.documentElement; //IE with doctype
		var d = (dd.clientHeight)? dd: db;
		return d.scrollTop;
	}
}


