﻿if (document.all){document.write("<style>.hideImgs img {visibility:hidden;}</style>");}
if (document.all){document.write("<style>.lightBox {visibility:hidden;}</style>");}// stop foc in IE
/*ON DOM READY FUNCTIONS*/
window.initiated=false;
function init()	{
	if (window.initiated)	{
		return;
	}
	window.initiated=true;
	popup(); //progressively enhance 'popup' links to open a popup window
	printpage(); // progressively enhance print buttons
	setupExpandableAreas();
	setupExpandableFromSelect();
	switchExpand();
	colClears(2,"product2col","li","product2colitem");
	limitSelectionNumber("product2col","select");
	unselectForm();
	gallery("mainPic","thumbs","standard"); //progressively enhance a picture gallery to show different views
	greyOut();
	//productSummary("summaryHead", "summaryDescription");
	applySifr();
	//your account functions
	accountNamesTruncate(); //cuts account names in the panel title
	inputBorders();   //add border onto input field on focus, specific to your account
	clearFocus(); //clear a field of its initial value on focus
	clearOnClick();//clears a group of fields when a specified link is clicked
	contextualHelp(); //progressively enhances the help paragraphs for field focus
	Validator.init();  //validate form inputs
	dependentFields();//
	passwordStrengthCheck();
	paginate(); //turn specified areas into paginated sections
	Lightbox.init(); //set up lightboxes	
	imgSwap(); //progressively enhanced image rollovers
	sum(); //client-side addition of user inputs to get a total
	barChart(); // take a table with currency value and add a bar chart
	toggleView(); //enable switching of displayed content using grouped links
	calendar(); //progressively enhanced calendars
	billSavePrint(); // handle AJAX requests on the save or print bill lightbox
	trHovers();  //background change on mouse over a table row
	inputFocusOnLoad();//find any inputs to focus on when load, do this last
}



// ondomready code

if (!/Opera/i.test(navigator.userAgent)){
	if (document.addEventListener) {document.addEventListener("DOMContentLoaded", init, null);}
}	else	{
	G_wk = setInterval(function(){if (document.getElementById("Page")) {clearInterval(G_wk);delete G_wk;init();}},1000);
}
if (/WebKit/i.test(navigator.userAgent)){G_wk = setInterval(function(){if (/loaded|complete/.test(document.readyState)) {clearInterval(G_wk);delete G_wk;init();}},50);}
/* DO NOT REMOVE THIS SECTION - IE CONDITIONAL COMPILATION */
/*@cc_on @*/
/*@if (@_win32)
document.write("<script id=el_ie defer src=blank.js><\/script>");var script = document.getElementById("el_ie");script.onreadystatechange = function() {
if (this.readyState == "complete") {init();}}
/*@end @*/
/* IE CONDITIONAL COMPILATION ENDS */
//failsafe
window.onload=init;
/* - */
/*END ON DOM READY FUNCTIONS*/

//onload event
function addLoadEvent(func) {
  var oldonload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      oldonload();
      func();
    }
  }
}

window.onunload = function(){
	//kill all event handlers for fields
	var inputs=document.getElementsByTagName("input");
	var selects=document.getElementsByTagName("select");
	for(var i=0;i<inputs.length;i++){
		inputs[i].onblur=null;
		inputs[i].onclick=null;
		inputs[i].onfocus=null;
	}
	for(var s=0;s<selects.length;s++){
		selects[s].onblur=null;
		selects[s].onclick=null;
		selects[s].onfocus=null;
	}
}

/*
Gives focus to a specified element when the page loads.
Focuses on the first one found from input, select then anchor.  If there is more than one, that is a logic error so subsequent elements are ignored
REQUIRED
	focusable element (input, select, anchor) with class 'PE_focusOnLoad'
*/
function inputFocusOnLoad(){
	var el_focus = fuzzyClassName("input","PE_focusOnLoad");
	if(!el_focus){el_focus = fuzzyClassName("select","PE_focusOnLoad")};
	if(!el_focus){el_focus = fuzzyClassName("a","PE_focusOnLoad");}
	if(el_focus.length == 0){return;}
	el_focus[0].focus();
}

// -------------------------------- 
// Rollver code for images
function MM_findObj(n, d) { //v4.01
  var p,i,x;  if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
    d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
  if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
  for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document);
  if(!x && d.getElementById) x=d.getElementById(n); return x;
}

function MM_swapImgRestore() { //v3.0
  var i,x,a=document.MM_sr; for(i=0;a&&i<a.length&&(x=a[i])&&x.oSrc;i++) x.src=x.oSrc;
}

function MM_preloadImages() { //v3.0
  var d=document; if(d.images){ if(!d.MM_p) d.MM_p=new Array();
    var i,j=d.MM_p.length,a=MM_preloadImages.arguments; for(i=0; i<a.length; i++)
    if (a[i].indexOf("#")!=0){ d.MM_p[j]=new Image; d.MM_p[j++].src=a[i];}}
}

function MM_swapImage() { //v3.0
  var i,j=0,x,a=MM_swapImage.arguments; document.MM_sr=new Array; for(i=0;i<(a.length-2);i+=3)
   if ((x=MM_findObj(a[i]))!=null){document.MM_sr[j++]=x; if(!x.oSrc) x.oSrc=x.src; x.src=a[i+2];}
}




// -------------------------------- 
// Clear Input box 
function ClearBox(myObj, myText)
{
	if(myObj.value == myText) myObj.value='';
}




// -------------------------------- 
// Sort code
var autoFocusOn = true;

function autofocus(field, limit, next ) {
	if(autoFocusOn){
		if(next != 'LAST'){
		   	limit = 2;
			if (field.value.length == limit) {
			    if(field.form.elements[next]){field.form.elements[next].focus();}
		    	}
		}else{
			autoFocusOn = false;
		}
	}
}



/*GALLERY
generic gallery code, origins: Mobile
*/
function gallery(mainPicDiv,thumbsDiv,largeNaming){
//allow for many galleries on one page.
	var galleries=getElementsByClassName(document,"div","gallery");
	for(var i=0;i<galleries.length;i++){
		var picArea=getElementsByClassName(galleries[i],"div",mainPicDiv)[0];
		if(!picArea){return;}
		
		var gal_Div=getElementsByClassName(galleries[i],"div",thumbsDiv)[0];
		if(!gal_Div){return;}
		gal_Div.style.display="block";
		var gal_imgs=gal_Div.getElementsByTagName("img");
		var firstImg=gal_imgs[0].src;
		gal_imgs[0].className+=" selected";
		var picMain=picArea.getElementsByTagName("img")[0];
		if(!picMain){picMain=picArea.firstChild;}
		var picObj=document.createElement("img");
		picObj.alt=picMain.alt;
		picObj.src=firstImg.substring(0,firstImg.lastIndexOf("_")+1) + largeNaming + firstImg.substring(firstImg.lastIndexOf("."));
		picArea.replaceChild(picObj,picMain);
		picArea.style.display="block";
		for(var j=0;j<gal_imgs.length;j++){
			var domAnchor=document.createElement("a");
			domAnchor.href="#";
			domAnchor.appendChild(gal_imgs[j].cloneNode(true));
			gal_Div.replaceChild(domAnchor,gal_imgs[j]);
			domAnchor.onclick=function(){
				for(var k=0;k<gal_imgs.length;k++){
					gal_imgs[k].className=gal_imgs[k].className.replace(/selected/g,"");
				}
				this.childNodes[0].className+=" selected";
				var src=this.childNodes[0].src;
				var imgRoot=src.substring(0,src.lastIndexOf("_")+1);
				var imgType=src.substring(src.lastIndexOf("."));
				var fullImg=imgRoot + largeNaming + imgType;
				var picMain=picArea.getElementsByTagName("img")[0];
				var picObj=document.createElement("img");
				picObj.alt="";
				picObj.src=fullImg;
				picArea.replaceChild(picObj,picMain);
				return false;
			}
			domAnchor.onfocus=domAnchor.onclick;
		}
	}
}

function getSelectBoxTotals(parent){
	var totalCount=0;
	var selBoxes=parent.getElementsByTagName("select");
		for(var j=0;j<selBoxes.length;j++){
			totalCount=totalCount + parseInt(selBoxes[j].options[selBoxes[j].selectedIndex].value);
		}
	return totalCount;
}
function getSelectBoxPotential(selBoxes)	{
	var highest=0;
	for (var j=0;j<selBoxes.length;j++)	{
		// get the highest POTENTIAL value of each item - this dictates the maximum number of handsets allowed
		var curQuan=(selBoxes[j].options[selBoxes[j].length-1].value);
		if (curQuan>highest){highest=curQuan;}
	}
	return highest;
}
function limitSelectionNumber(containerId,elemType){
	var container=document.getElementById(containerId);
	if(!container){return;}
	var countInputs=container.getElementsByTagName(elemType);
	var maxCount=getSelectBoxPotential(countInputs);
	for(var j=0;j<countInputs.length;j++){
		countInputs[j].containerParent=container;
		countInputs[j].elemType=elemType;
		countInputs[j].maxCount=maxCount;
		(countInputs[j].addEventListener) ? (countInputs[j].addEventListener("change",boxChange,true)) : 
(countInputs[j].attachEvent("onchange",boxChange));
	}
}

function boxChange(evt){
	var elem=(evt.target) ? (evt.target) : (evt.srcElement);
	var errDivs=getElementsByClassName(elem.containerParent,"div","error");
	for(var k=0;k<errDivs.length;k++){
		errDivs[k].innerHTML="<!--error-->";
		errDivs[k].style.display="none";
	}
	if(elem.elemType=="select"){
		var totals=getSelectBoxTotals(elem.containerParent);
	}
	else{
		var totals=0; //ERROR
		alert("DEVELOPER ERROR - elemType not received, or not accounted for");
	}
	if(totals>elem.maxCount){
		var errormsg="Sorry, you can only select up to " + elem.maxCount + ".  You currently have " + totals + " selected";
		var parent=elem.parentNode;
		while(getElementsByClassName(parent,"div","error").length=="0"){
			parent=parent.parentNode;
			if(!parent || parent.nodeName=="#document"){break;}
		}
		var errDiv=getElementsByClassName(parent,"div","error")[0];
		if(typeof errDiv == "undefined"){return;}
		errDiv.innerHTML=errormsg;
		errDiv.style.display="block";
	}
}

function unselectForm(){
	var aUnsel=getElementsByClassName(document,"p","unselect");
	for(var i=0;i<aUnsel.length;i++){
		var frm=getParentByTagName(aUnsel[i],"form");
		var unselectInput=getElementsByClassName(aUnsel[i],"input","reset");
		for(j=0;j<unselectInput.length;j++){
			var unselectText=unselectInput[j].value;
			aUnsel[i].removeChild(unselectInput[j]);
			var unselectLink=document.createElement("a");
				unselectLink.appendChild(document.createTextNode(unselectText));
				unselectLink.href="#";
				unselectLink.onclick=function(){
					frm.reset();
					//safari does not reset dropdowns
					var selBoxes = document.getElementsByTagName("select");
					for(var k=0;k<selBoxes.length;k++){
						selBoxes[k].selectedIndex=selBoxes[k].options[0];
						if(selBoxes[k].onclick){selBoxes[k].onclick();}
						if(selBoxes[k].onchange){selBoxes[k].onchange();}
					}
					//remove error messages
					var allErrDivs=getElementsByClassName(document,"div","error");
					for(var m=0;m<allErrDivs.length;m++){
						allErrDivs[m].innerHTML="<!--error-->";
						allErrDivs[m].style.display="none";
					}
					return false;
				}
			aUnsel[i].appendChild(unselectLink);
		}
	}
}
function colClears(col,parentID,elemType,elemClass){
	var container=document.getElementById(parentID);
	if(!container){return;}
	var elems=getElementsByClassName(container,elemType,elemClass);
	for(var i=0;i<elems.length;i++){
		if(i % col == 0){
			var clrdiv=document.createElement("div");
			clrdiv.className="clear";
			if(!document.createComment){var clrTxt=document.createTextNode(" ");}
			else{var clrTxt=document.createComment("clear");}
			clrdiv.appendChild(clrTxt);
			elems[i].parentNode.insertBefore(clrdiv,elems[i]);
		}
	}
	return;
}



function greyOut (){
		greyAreas = getElementsByClassName(document, 'div', 'pcodeSearch');
		//assign ability to grey out to link that greys out areas
		for (i=0;i<greyAreas.length;i++){
			var imgrey = getElementsByClassName(document, 'a', 'showGrey');
			for (var j=0;j<imgrey.length;j++){
				function doGrey(){
					greyThese = getElementsByClassName(document, 'input', 'greyMe');
					for(var k=0;k<greyThese.length;k++)
					{
						if(greyThese[k].className == 'greyMe inputWidth4'){
							greyThese[k].disabled = true;
							greyThese[k].className = 'greyMe disabl';
						}
						else {
							greyThese[k].disabled = false;
							greyThese[k].className = 'greyMe inputWidth4';
						}
					}
				}
				imgrey[j].addEventListener ? (imgrey[j].addEventListener("click",doGrey,false)) : (imgrey[j].attachEvent("onclick",doGrey));
			}
		}
}

/* EXPANDABLE CONTENT FUNCTIONS */
// -------------------------------- 
// Show or hide state of a div and alter the associated icons accordingly
function expandArea(img1,divObj,img2){
	
	// editable information......
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~
	imgPrefix = "../img/buttons/";    // this is the path to the images... 
	hiddenClass = "hiddenArea";
	showingClass = "unhiddenArea";
	
	// images  - these are hard coded image file names.
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	expandIcon = "btn_expand_collapse_right_10x10.gif"; // this is the right facing triangle
	collapseIcon = "btn_expand_collapse_down_10x10.gif"; // this is the downfacing triangle
	minimizeIcon = "btn_info_close_10x11.gif"; // this is the X icon
	infoIcon = 'btn_info_10x11.gif'; // this is the i icon
	//~~~~~~~~~~~ no need to edit below ~~~~~~~~~~~~~~~
	
	//~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~	
	d = document.getElementById(divObj);
	openArray = new Array(collapseIcon,showingClass,minimizeIcon);// stuf showing when div is open
	closedArray = new Array(expandIcon,hiddenClass,infoIcon); // stuf showing when div is closed
	currentClass = d.className;
	if(currentClass == 'hiddenArea') { //alert('div is closed');
		d.className = openArray[1];
		if(document.getElementById(img1)){
			document.getElementById(img1).src = imgPrefix + openArray[0];
			}
		if(document.getElementById(img2)){
			document.getElementById(img2).src = imgPrefix + openArray[2];
			}
	}else if(currentClass == 'unhiddenArea'){//alert('div is open');
		d.className = closedArray[1];
		if(document.getElementById(img1)){
			document.getElementById(img1).src = imgPrefix + closedArray[0];
			}
		if(document.getElementById(img2)){
			document.getElementById(img2).src = imgPrefix + closedArray[2];
			}
	}
}

//function switchClass(obj,newClass){
//	obj.className = newClass;
//	return true;
//	}

// -------------------------------- 
// Show/hide divs
function expandArea1(divShow,divHide){
	d1 = document.getElementById(divShow);
	d2 = document.getElementById(divHide);
	currentClass = d1.className;
	if(currentClass == 'hiddenArea') {
		d1.className = 'unhiddenArea';
		d2.className = 'hiddenArea';
	} else {
		d1.className = 'hiddenArea';
		d2.className = 'unhiddenArea';
	}
}
// -------------------------------- 
// -------------------------------- 
// Show divs
function showArea(divShow){
	d1 = document.getElementById(divShow);
	currentClass = d1.className;
	if(currentClass == 'hiddenArea') {
		d1.className = 'unhiddenArea';
	}
}
// -------------------------------- 
// -------------------------------- 
// Hide divs
function hideArea(divShow){
	d1 = document.getElementById(divShow);
	currentClass = d1.className;
	if(currentClass == 'unhiddenArea') {
		d1.className = 'hiddenArea';
	} 
}
function setupExpandableAreas () {
	//find all expandable areas on page
	expandableAreas=fuzzyClassName("div","expandableContent");

	for (var i=0;i<expandableAreas.length;i++)	{
		expandableAreas[i].id = "expandableArea_"+i;
		//update: DB 2008-01-10: added in handling of minimum number of areas to have before expandable handling is activated

		if(getPEClassInfo(expandableAreas[i],"expandableContent") != ""){
			var classInfo = getPEClassInfo(expandableAreas[i],"expandableContent")
			var relatedAreas = 	fuzzyClassName("div","expandableContent("+classInfo+")");
			if(classInfo.indexOf("min-") != -1){
				var minTrigger = classInfo.substring(classInfo.indexOf("-")+1);
				if(relatedAreas.length < minTrigger){
					continue;
				}
			}
		}
		//collapse all expandable areas unless set to open by default
		//update: DB 2008-01-09: added in handling for defaultToOpen
		//update: DB 2008-01-09: changed straight rewrite of classname to appending.
		document.getElementById(expandableAreas[i].id).className += " expandableContentCollapsed";
		if(expandableAreas[i].className.indexOf("defaultToOpen") !=-1){
			document.getElementById(expandableAreas[i].id).className += " expandableContentShow";
		}
				
		//remove link from anchor, assign id
		expandableAreaAnchor = getElementsByClassName(expandableAreas[i], 'div', 'shortDesc')[0].getElementsByTagName("a")[0];
		if (typeof expandableAreaAnchor != "undefined") {
			expandableAreaAnchor.id = "expandableAreaAnchor_"+i;
			expandableAreaAnchor.removeAttribute("href");
		}

		//updated: DB 2008-01-09: if there is no content in the open/close link, add open/close buttons
		if(expandableAreaAnchor.innerHTML == "&nbsp;"){
			expandableAreaAnchor.isDynamicText = true;
			if(document.getElementById(expandableAreas[i].id).className.indexOf("expandableContentShow") != -1){
				expandableAreaAnchor.innerHTML = "<span>Close</span>";
			}
			else{
				expandableAreaAnchor.innerHTML = "<span>Open</span>";
			}
		}
		
		//remove 'for' attribute from label
		expandableAreaLabel = getElementsByClassName(expandableAreas[i], 'div', 'shortDesc')[0].getElementsByTagName("label")[0];

		if(typeof expandableAreaLabel != "undefined" && expandableAreaLabel != null) {
			expandableAreaLabel.removeAttribute("for");
		}

		//assign onclick function to open / close expandable areas
		expandableAreaAnchor.onclick = function () {
			elementId = this.id.split("_").reverse()[0]; //puts the element id number at the front of array
			if(this.isDynamicText){
				if(this.innerHTML == "<span>Close</span>"){
					this.innerHTML = "<span>Open</span>";
				}
				else if(this.innerHTML == "<span>Open</span>"){
					this.innerHTML = "<span>Close</span>";
				}
			}
			openOrCloseExpandableContent("expandableArea_" + elementId );
		}
	}
}
function setupExpandableFromSelect(){
	//find all expandable areas on page
	expandableRows=fuzzyClassName("table","expandableTable");
	
	for (var i=0;i<expandableRows.length;i++)	{
		expandableRows[i].id = "expandableRows_"+i;
		//collapse all expandable areas
		document.getElementById(expandableRows[i].id).className = "expandableTable expandableTableCollapsed";
		//assign onchange function to correct select option
		var findIt = expandableRows[i].getElementsByTagName('td');
		for (var l=0;l<findIt.length;l++){
			var tessi = findIt[l].childNodes;
			for (var j=0;j<tessi.length;j++){
				if (tessi[j].className){
					if(tessi[j].className.indexOf('selectExpand') != -1){
						var toop = tessi[j];
						var theElement = expandableRows[i];
						toop.onchange = function() {
							var myindex  = toop.selectedIndex;
							var SelValue = toop.options[myindex].className;
							if (SelValue.indexOf('expandOption') != -1){								
								elementId = theElement.id.split("_").reverse()[0]; //puts the element id number at the front of array
								var whas = ("expandableRows_" + elementId );
								document.getElementById(whas).className = "expandableTable expandableContentShow";
							}
							else{
								elementId = theElement.id.split("_").reverse()[0]; //puts the element id number at the front of array
								var whas = ("expandableRows_" + elementId );
								document.getElementById(whas).className = "expandableTable expandableContentCollapsed";
								
							}
						}
					}
				}
			}
		}
	}
}
function switchExpand (){
	//find all switch expand areas on page
	switchAreas = fuzzyClassName("div","switchableContent");
	var count = 0;
	for (var i=0;i<switchAreas.length;i++)	{
		switchAreas[i].id = "switchArea_"+i;
		//collapse all expandable areas
		document.getElementById(switchAreas[i].id).className = "switchArea hideBothSwitch";	
			
		//assign checked to radio buttons within area
		var allinputs = switchAreas[i].getElementsByTagName('input').length;
		var radios = getElementsByClassName(switchAreas[i], 'input', 'aswitch');
		var theElement = switchAreas[i];
		radios[0].onclick = function(){
			elementId = theElement.id.split("_").reverse()[0]; //puts the element id number at the front of array
			var whas = ("switchArea_" + elementId );
			document.getElementById(whas).className = "switchArea showfirstswitch";
		}
		radios[1].onclick = function(){
			elementId = theElement.id.split("_").reverse()[0]; //puts the element id number at the front of array
			var whas = ("switchArea_" + elementId );
			document.getElementById(whas).className = "switchArea showsecondswitch";
		}
	}
}

//update: DB 2008-01-09: changed handling of classes so that they are appended not overwritten 
//update: DB 2008-01-09: changed conditional logic to detect expandableContentShow
function openOrCloseExpandableContent (id) {
	accountTotalLine(id);
	document.getElementById(id).className=document.getElementById(id).className.replace(" defaultToOpen","");
	if (document.getElementById(id).className.indexOf("expandableContentShow") == -1) {
		document.getElementById(id).className += " expandableContentShow";
	} else {
		document.getElementById(id).className = document.getElementById(id).className.replace(" expandableContentShow","");	
	}
} 



//special case for your account make a payment where border on an adjoining div must be removed when a div is collapsed
function accountTotalLine(id){
	var nextSib = document.getElementById(id).nextSibling;
	while(nextSib){
		if(nextSib.nodeName.toLowerCase() == "div"){
			if(nextSib.className.indexOf("accountTotal") != -1){
				if(nextSib.className.indexOf("collapsed") !=-1){
					nextSib.className = nextSib.className.replace("collapsed","");
				}
				else{
					nextSib.className += " collapsed";
				}
			}		
			break;return;
		}
		nextSib = nextSib.nextSibling;
	}	
}

//mandates
function mandateType(clicked, showme, selected){
	//First hide day of month dropdown
	var hideMe=document.getElementById(showme);
	if(!hideMe){return;}
	hideMe.className='hidden';
	//If correct mandate type, show day of month dropdown
	var fromMe=document.getElementById(clicked);
	fromMe.onchange = function() {
		var myindex  = fromMe.selectedIndex;
		var SelValue = fromMe.options[myindex].value;
		if (SelValue == selected){
			hideMe.className='show';
		}
		else{
			hideMe.className='hidden';
		}
	}	
}
/* end expandable content functions */



/* Pop-up windows */
function openPopup(href)
{
	var rand="window"+Math.floor(Math.random()*9999999999)
	var newWin = window.open(href,rand,"width=600,height=500,titlebar=no,scrollbars=yes");
	newWin.focus();
	return false;
}
function popup(){
	var els=fuzzyClassName("a","popup:");
	for (var i=0;i<els.length;i++)	{
		els[i].onclick = function ()
		{
			this.removeAttribute("target");
			var cc=this.className;var cs=cc.substr(cc.indexOf("popup:")+6,cc.length);
			// QAS variant specifically for this process
			if (cs.indexOf("qas")==0) {
				var dma=(cs.substr(4,cs.indexOf(")")-1)).split(",");
				// get fields
				var grandparent=getParentByTagName(this.parentNode,"div");
				var supp=(grandparent.id=="id_div_sec2")?"_sec2":"";
				window.QAS_opener=(supp=="")?"_sec1":"_sec2";
				var postcode=document.getElementById(window.VF_postcode+supp).value;
				var house=document.getElementById(window.VF_house+supp).value;
				var extras="?postcode="+postcode+"&house="+house;
			}	else	{
				var dma=(cs.substr(1,cs.indexOf(")")-1)).split(",");
				var extras="";
			}
			window.open(this.href+extras,'popupwindow','width='+dma[0]+',height='+dma[1]+',resizable=1,scrollbars=1,true,true');
			return false;
		}
	}
}
/* End Pop-up windows */

//Check for Parallel processing
var processing = false;
function checkprocessing(form) {
    if(!processing) {
        processing = true;
	if (document.getElementById('BtnContinue') != null) {
		document.getElementById('BtnContinue').disabled=true;
	}
        return true;
    } else {
        //alert("Parallel processing not allowed.");
        return false;
    }
}



/*function productSummary(clickme, showme){
	//First hide product description
	var showMe=document.getElementById(showme);
	if(!showMe){
		return;
	}
	showMe.className='hidden';-->
	//If product description clicked
	var clickMe=document.getElementById(clickme);
	if(!clickMe){
		return;
	}
	clickMe.onclick = function(){
		if(showMe.className == 'hidden'){
			showMe.className='show';
			clickMe.firstChild.className='openSummary';
		}
		else{
			showMe.className='hidden';
			clickMe.firstChild.className='show';
		}
	}
}*/

/*applies sifr to targeted elements*/
function applySifr(){
	if(typeof sIFR == "function"){
	    sIFR.setup();
		sIFR();
		sIFR.replaceElement("h2.PE_sifr", named({sFlashSrc: "../img/newbt.swf", sColor: "#64379b",sWmode: "transparent"}))
	};
	
}

/*your account 2007/08 DB*/

/* truncate the name of the account that appears in the title area, make the full name appear in the li's title attribute and change the cursor to the pointer
REQUIRED
	li with classname 'PE_accountName'
*/
function accountNamesTruncate(){
	var titleArea = document.getElementById("titleContainer_panel");
	if(!titleArea){return false;}
	var accountNames = getElementsByClassName(titleArea,"li","PE_accountName");
	for(var i=0;i<accountNames.length;i++){
		var newName = truncate(accountNames[i].innerHTML,14);
		accountNames[i].title = accountNames[i].innerHTML;
		accountNames[i].className += " handCursor";
		accountNames[i].innerHTML = newName;
	}
}
/* apply class that adds purple borders to form fields on focus and remove on blur
REQUIRED
	body with class 'youraccount'
EXCEPTIONS
	only text, password or file inputs get the border, other types look bad
 */
function inputBorders(){
	//only apply to your account and SSO pages
	if(getElementsByClassName(document,"body","youraccount").length < 1 && getElementsByClassName(document,"body","sso").length < 1){return;}
	var inputs = document.getElementsByTagName("input");
	var selects = document.getElementsByTagName("select");
	for(var i=0;i<inputs.length;i++){
		if(inputs[i].type != "text" && inputs[i].type != "password" && inputs[i].type != "file"){continue;}
		addEvent(inputs[i],'focus',fieldActive);
		addEvent(inputs[i],'blur',fieldOff);
	}
	for(var s=0;s<selects.length;s++){
		addEvent(selects[s],'focus',fieldActive);
		addEvent(selects[s],'blur',fieldOff);
	}
	function fieldActive(){
		if(this.className.indexOf("active")==-1){
			this.className += " active";
		}
	}
	function fieldOff(){
		this.className = this.className.replace("active","");
	}
}

function clearFocus(){
	var clearInputs = getElementsByClassName(document,"input","PE_clearFocus");
	for(var i=0;i<clearInputs.length;i++){
		clearInputs[i].initValue = clearInputs[i].value;
		addEvent(clearInputs[i],"focus",function(){
			if(this.value == this.initValue){
				this.value = "";
			}
		});
	}
}

/* clearOnClick
clears all fields within the same wrapping div
REQUIRED
	<a> with class PE_clearFields inside same div as wraps the fields to be cleared
	<div> with class PE_clearFields that wraps the fields to be cleared
*/
function clearOnClick(){
	var clearLinks = getElementsByClassName(document,"a","PE_clearFields");
	for(var i=0,j=clearLinks.length;i<j;i++){
		clearLinks[i].wrapper = getParentByClassName(clearLinks[i],"PE_clearFields");
		if(!clearLinks[i].wrapper){continue;}
		clearLinks[i].inputs = clearLinks[i].wrapper.getElementsByTagName("input");
		clearLinks[i].selects = clearLinks[i].wrapper.getElementsByTagName("select");
		clearLinks[i].onclick = function(){
			for(var k=0,m=this.inputs.length;k<m;k++){
				if(this.inputs[k].type == "radio"){
					this.inputs[k].checked = false;
				}
				else if(this.inputs[k].type == "checkbox"){
					this.inputs[k].checked = false;
				}
				else{
					this.inputs[k].value = "";
				}
			}
			for(var k=0,m=this.selects.length;k<m;k++){
				this.selects[k].value = "";
			}
			return false;
		}
	}
}

/*contextualHelp finds all paragraphs with the class name PE_help, gets their parent div to find out which field to attach them to, hides and visually enhances them,  and shows them onfocus and hides them onblur 
REQUIRED:
	<p> with class 'PE_help' nested inside a div which also contains the relevant input or select
*/
function contextualHelp(){
	var helpPs = getElementsByClassName(document,"p","PE_help");
	for(var i=0;i<helpPs.length;i++){
		//get parent div before progressively enhancing with more divs
		var parentDiv = getParentByTagName(helpPs[i],"div");
		//help div top
		var helpDiv = document.createElement("div");
			helpDiv.className = "helpDiv";
		var helpDivTop = document.createElement("div");
			helpDivTop.className = "helpDiv-top";
		var helpDivTopL = document.createElement("div");
			helpDivTopL.className = "helpDiv-top-left";
			helpDivTop.appendChild(helpDivTopL);
		var helpDivTopR = document.createElement("div");
			helpDivTopR.className = "helpDiv-top-right";
			helpDivTopL.appendChild(helpDivTopR);
		helpDiv.appendChild(helpDivTop);			
		//help div middle
		var helpDivL = document.createElement("div");
			helpDivL.className = "helpDiv-left";
		var helpDivR = document.createElement("div");
			helpDivR.className = "helpDiv-right";
			helpDivL.appendChild(helpDivR);
			helpDivR.appendChild(helpPs[i]);
		helpDiv.appendChild(helpDivL);	
		//help div base
		var helpDivBase = document.createElement("div");
			helpDivBase.className = "helpDiv-base";
		var helpDivBaseL = document.createElement("div");
			helpDivBaseL.className = "helpDiv-base-left";
			helpDivBase.appendChild(helpDivBaseL);
		var helpDivBaseR = document.createElement("div");
			helpDivBaseR.className = "helpDiv-base-right";
			helpDivBaseL.appendChild(helpDivBaseR);
		helpDiv.appendChild(helpDivBase);
		//hide the help
		helpDiv.className+=" hidden";
		//get all contained fields
		var inputs = parentDiv.getElementsByTagName("input");
		var selects = parentDiv.getElementsByTagName("select");
		function showHelp(){
			var parent = this.offsetParent;
			var parentRelativeTop = 0;
			while(parent){
				if(parent.nodeName=="#document"){break;}
				if(getStyle(parent,"position") == "relative"){
					parentRelativeTop += parent.offsetTop;
				}
				parent = parent.offsetParent;
			}

			var fieldTop = getAbsoluteY(this) - parentRelativeTop;
			this.helpP.className = this.helpP.className.replace(" hidden","");
			//for IE5, parentRelativeTop gets wrong value
			/*@cc_on @*/
			/*@if (@_jscript_version < 5.6)
			return;
			/*@end @*/		
			this.helpP.style.top = fieldTop+"px";
		}
		function hideHelp(){
			this.helpP.className += " hidden";
		}
		function hideAllHelp(){
		
			var helpDivs = getElementsByClassName(document,"div","helpDiv");
			for(var a=0;a<helpDivs.length;a++){
				if(helpDivs[a].className.indexOf("hidden") ==-1){
					helpDivs[a].className += " hidden";
				}
			}
			if(this.helpP.className.indexOf("hidden") != -1){
				var parentRelativeTop = 0;
				var parent = this.helpP.parentNode;
				while(parent){
					if(parent.nodeName=="#document"){break;}
					if(getStyle(parent,"position") == "relative"){
						parentRelativeTop += parent.offsetTop;
					}
					parent = parent.parentNode;
				}
				var fieldTop = getAbsoluteY(this) - parentRelativeTop;
				this.helpP.style.top = fieldTop+"px";
				this.helpP.className = this.helpP.className.replace("hidden","");
			}
		}
		//add event handlers for fields
		for(var n=0;n<inputs.length;n++){
			inputs[n].helpP = helpDiv;
			if(/WebKit/i.test(navigator.userAgent)){  //safari doesn't focus/blur radio or checkboxes
				if(inputs[n].type == "radio" || inputs[n].type == "checkbox"){
					addEvent(inputs[n],'click',hideAllHelp);
				}
				else{
					addEvent(inputs[n],'focus',hideAllHelp);
				}
			}
			else{
				addEvent(inputs[n],'focus',showHelp);
			}
			addEvent(inputs[n],'blur',hideHelp);
		}
		for(var s=0;s<selects.length;s++){
			selects[s].helpP = helpDiv;
			if(/WebKit/i.test(navigator.userAgent)){  //safari doesn't focus/blur radio or checkboxes
				addEvent(selects[s],'focus',hideAllHelp);
			}
			else{
				addEvent(selects[s],'focus',showHelp);
			}
			addEvent(selects[s],'blur',hideHelp);
		}
		parentDiv.appendChild(helpDiv);
	}
}

/*
dependentFields deals with fields that are dependent on another field having a value.  if it has no value, the fields are disabled so the user does not input unnecessary data and the fields are not validated
REQUIRED
	input or select with class PE_depended(identifer)
	div wrapping the affected fields with class PE_dependent(identifier)
*/
function dependentFields(){
	var inputs = fuzzyClassName("input","PE_depended");
	var selects = fuzzyClassName("select","PE_depended");
	for(var i=0,j=inputs.length;i<j;i++){
		if(inputs[i].value == ""){
			updateDependence.call(inputs[i]);
		}
		addEvent(inputs[i],"keyup",updateDependence)//only if length is 0 or 1
	}
	for(var k=0,m=selects.length;k<m;k++){
		if(selects[k].value == ""){
			updateDependence.call(selects[k]);
		}
		addEvent(selects[k],"change",updateDependence);
	}
	
	function updateDependence(){
		var identifier = getPEClassInfo(this,"PE_depended");
		var wrapperDivs = fuzzyClassName("div","PE_dependent("+identifier+")");
		if(this.value == ""){
			for(var a=0,b=wrapperDivs.length;a<b;a++){
				Validator.disableChildFields(wrapperDivs[a],true);
				//clear error divs
				var errDivs = fuzzyClassNameBlock(wrapperDivs[a],"div","PE_error");
				for(var er=0;er<errDivs.length;er++){
					Validator.clearError(errDivs[er]);
				}
			}
		}
		else{
			for(var a=0,b=wrapperDivs.length;a<b;a++){
				Validator.disableChildFields(wrapperDivs[a],false);
			}
		}
		//run so that if a dependent field is a nestparent, nests are dealt with too
		Validator.nestedValidation();
	}
}


/*	VALIDATION
if a field has an error, the class PE_error will be added to its parent div

REQUIRED:
	div around the field with class PE_validate(type) where type is one of the entries 

	if there is no entry it will be checked for blank content only
	
	if the field can be either a specific type OR blank the the classname should end 'sometype_or_empty' where sometype matches the types in validationData
OPTIONAL:
	LIGHTBOX DISPLAY ON SUBMIT
	class "PE_lightboxIfInvalid(id_of_lightbox)" on the same div as carries the PE_validate(type) class to display a lightbox on form submission if a field is invalid
		
	NESTED VALIDATION
	nested validation means that some fields should only be validated if a 'parent' field is checked
	IMPLEMENTATION:
		the radio or checkbox that is the parent should have the class 'PE_nestValidation'
		the nested fields should be contained in a div with class 'PE_nestedValidation(id_of_parentCheckboxOrRadio)'
		
	ONE IN GROUP MUST BE VALID
	this checks that at least one entry in a specified group of fields has content.  use for groups of fields like textboxes, radio groups are already handled by their name
	IMPLEMENTATION:
		wrapping div with class PE_validOneInGroup
*/
Validator = {
	
	//hash of error checking functions and messages
	//max err message length 42-48 characters
	validationData : function() { 
		//generic checking for empty fields, message string determined by field type
		this.empty={
			"errormsg" : {
				"radio" : "Please choose an option",
				"checkbox" : "Please check this box",
				"checkbox-group" : "Please check at least one box",
				"text" : "Mandatory field",
				"password" : "Mandatory field",
				"file" : "Mandatory field",
				"select-one" : "Mandatory field",
				"select-multiple" : "Mandatory field",
				"group" : "Please fill in at least one field"
			},
			"logic" : Validator.valtype_empty
		};
		this.match = {
			"errormsg" : "Does not match",
			"logic" : Validator.valtype_match
		};
   		this.globalError={
			"errormsg" : "Please ensure all required information is complete. See below for details.",
			"logic" : "n/a"
		};
		this.bt_account={
			"errormsg" : "Not a valid BT account number",
			"logic" : Validator.valtype_bt_account
		};
		this.card_expiry={  //to ensure date is in the future
			"errormsg" : "Expiry date must be in the future",
			"logic" : Validator.valtype_cardExpiry
		};
		this.card_start={ // to ensure date is in the past
			"errormsg" : "Start date must be in the past",
			"logic" : Validator.valtype_cardStart
		};
		this.currency={
			"errormsg" : "Please enter in the format pounds.pence",
			"logic" : Validator.valtype_currency
		};
		this.ddate={
			"errormsg" : "That is not a valid date",
			"logic" : Validator.valtype_date
		};
		this.daterange={
			"errormsg" : "Invalid date range",
			"logic" : Validator.valtype_daterange
		};
		this.email={
			"errormsg" : "Please enter a valid email address",
			"logic" : Validator.valtype_email
		};
		this.fullname={
			"errormsg" : "Please enter your name",
			"logic" : Validator.valtype_names
		};
		this.number={
			"errormsg" : "Please enter numbers only",
			"logic" : Validator.valtype_number
		};
		this.password_min6={
			"errormsg" : "Your password must be at least 6 characters long",
			"logic" : Validator.valtype_minlength_6
		};
		this.postcode={
			"errormsg" : "Not a postcode",
			"logic" : Validator.valtype_postcode
		};
		this.securitycode={
			"errormsg" : "Please enter your 3 or 4 digit security code",
			"logic" : Validator.valtype_securitycode
		};
		this.sortcode_threepart={
			"errormsg" : "Please enter your 6-digit sortcode",
			"logic" : Validator.valtype_sortcode_threepart
		};
		this.telephone={
			"errormsg" : "Not a phone number",
			"logic" : Validator.valtype_phone
		};
	},
	// handle nested validation by disabling nested fields inside unchecked or disabled inputs

	nestedValidation : function(){
		for(var n=0;n<Validator.nestParents.length;n++){
			var nests = fuzzyClassName("div","PE_nestedValidation(" + Validator.nestParents[n].id + ")");
			if(nests.length > 0){
				var nest = nests[0];
				Validator.disableChildFields(nest,!Validator.nestParents[n].checked);
				if(Validator.nestParents[n].disabled == true){Validator.disableChildFields(nest,true);}
				// if parent is not checked or is disabled, clear error messages
				if(!Validator.nestParents[n].checked || Validator.nestParents[n].disabled == true){
					var errDivs = fuzzyClassNameBlock(nest,"div","PE_error");
					for(var er=0;er<errDivs.length;er++){
						Validator.clearError(errDivs[er]);
					}
				}
			}
		}
	},
	//takes parent element and true (to disable) or false (to enable) as args
	disableChildFields : function(el,bool){
		var inputs = el.getElementsByTagName("input");
		var selects = el.getElementsByTagName("select");
		for(var i=0;i<inputs.length;i++){
			inputs[i].disabled = bool;
			if(inputs[i].type == "checkbox" || inputs[i].type == "radio"){
				continue;
			}
			if(!bool){
				inputs[i].className = inputs[i].className.replace("disabled","");
			}
			else if(inputs[i].className.indexOf("disabled") == -1){
				inputs[i].className += " disabled";
			}
		}
		for(var s=0;s<selects.length;s++){
			selects[s].disabled = bool;
			if(!bool){
				selects[s].className = selects[s].className.replace("disabled","");
			}
			else if(selects[s].className.indexOf("disabled") == -1){
				selects[s].className += " disabled";
			}
		}
	},
	//set up nestParent changes, field blur and form submit event handlers to handle validation
	validationEventTriggers : function(){
		//nestParent clicks
		
		for(var n=0;n<Validator.nestParents.length;n++){
			//if nestParent is a radio button, there may be other related radio buttons without nested fields 
			if(Validator.nestParents[n].type == "radio"){
				var radios = getByAttribute(document,"input","name",Validator.nestParents[n].name);
				for(var i=0;i<radios.length;i++){
					//using addEvent in IE runs a lot of CPU for this command.  make this the primary function of these buttons.
					radios[i].onclick = Validator.nestedValidation;
				}
			}
			else{
				Validator.nestParents[n].onclick = Validator.nestedValidation;
			}
		}		
		//field blurs
		var validateParentDivs = fuzzyClassName("div","PE_validate");
		for(var d=0;d<validateParentDivs.length;d++){
			var inputs = validateParentDivs[d].getElementsByTagName("input");
			var selects = validateParentDivs[d].getElementsByTagName("select");
			for(var i=0;i<inputs.length;i++){
				inputs[i].validateType = getPEClassInfo(validateParentDivs[d],"PE_validate");
				if(inputs[i].validateType.indexOf("_or_empty") != -1){
					inputs[i].allowEmpty = true;
					inputs[i].validateType = inputs[i].validateType.replace("_or_empty","");
				}
				if(inputs[i].validateType.indexOf("match=") != -1){
					var regexpMatch = /match=([^,\)]+)[,]?/gi;
					var fieldMatch = inputs[i].validateType.match(regexpMatch).toString();
					inputs[i].matchToField = fieldMatch.replace(regexpMatch,"$1");
					inputs[i].validateType = inputs[i].validateType.replace(regexpMatch,"");
				}
				
				inputs[i].parentDiv = validateParentDivs[d];
				if(inputs.length > 1){
					inputs[i].allSiblings = inputs;
				}
				addEvent(inputs[i],'focus',Validator.clearError);
				addEvent(inputs[i],'blur',Validator.validate);
				if(inputs[i].matchToField) {
					var fieldMatch = document.getElementById(inputs[i].matchToField);
					fieldMatch.matchBind = inputs[i];
					addEvent(fieldMatch,'blur',function(){
						Validator.validate.apply(this.matchBind);
					});
				}
				if((inputs[i].type=="radio" || inputs[i].type=="checkbox") && (/WebKit/i.test(navigator.userAgent))){  //safari doesn't focus/blur radio or checkboxes
					addEvent(inputs[i],'click',Validator.validate);
				}
			}
			for(var s=0;s<selects.length;s++){
				selects[s].validateType = getPEClassInfo(validateParentDivs[d],"PE_validate");
				if(selects[s].validateType.indexOf("_or_empty") != -1){
					selects[s].allowEmpty = true;
					selects[s].validateType = selects[s].validateType.replace("_or_empty","");
				}
				if(selects[s].validateType.indexOf("match=") != -1){
					var regexpMatch = /match=([^,\)]+)[,]?/gi;
					var fieldMatch = selects[s].validateType.match(regexpMatch).toString();
					selects[s].matchToField = fieldMatch.replace(regexpMatch,"$1");
					selects[s].validateType = selects[s].validateType.replace(regexpMatch,"");
				}
				selects[s].parentDiv = validateParentDivs[d];
				if(selects.length > 1){
					selects[s].allSiblings = selects;
				}
				addEvent(selects[s],'focus',Validator.clearError);
				addEvent(selects[s],'blur',Validator.validate);
			}
		}
		//form submit
		//1 - validate only ENABLED fields If anything returns as invalid, isAllValid flag is set to false
		//1b - show lightboxes (where set) to display if the result is invalid
		//2 - scrub data from disabled fields so they are not passed to the server
		//3 - return false if not all enabled fields are valid
		var forms = document.getElementsByTagName("form");
		for(var f=0;f<forms.length;f++){
			forms[f].onsubmit = function(){
				var isAllValid=true;	
				for(var d=0;d<validateParentDivs.length;d++){
					var inputs = validateParentDivs[d].getElementsByTagName("input");
					var selects = validateParentDivs[d].getElementsByTagName("select");
					for(var i=0;i<inputs.length;i++){
						if(inputs[i].disabled != true){
							if(Validator.validate.call(inputs[i]) == false){
								if(validateParentDivs[d].className.indexOf("PE_lightboxIfInvalid") != -1){
									var thisLightbox = document.getElementById(getPEClassInfo(validateParentDivs[d],"PE_lightboxIfInvalid"));
									Lightbox.tintBg();
									Lightbox.showLightbox(thisLightbox);
								}
								isAllValid = false;
							}
						}
						else{
							inputs[i].value="";
							inputs[i].checked=false;
						}
					}
					for(var s=0;s<selects.length;s++){
						if(selects[s].disabled != true){
							if(Validator.validate.call(selects[s]) == false){
								if(validateParentDivs[d].className.indexOf("PE_lightboxIfInvalid") != -1){
									var thisLightbox = document.getElementById(getPEClassInfo(validateParentDivs[d],"PE_lightboxIfInvalid"));
									Lightbox.tintBg();
									Lightbox.showLightbox(thisLightbox);
								}
								isAllValid = false;
							}
						}
						else{
							selects[s].selectedIndex = 0;
						}
					}
				}				
				//handle validation on 'standalone' inputs not in one container validation div
				//built for handling grouped inputs, such as radio buttons or checkboxes sharing a name
				var validateInputs = fuzzyClassName("input","PE_validate");
				var groupName = "";
				for(var s=0;s<validateInputs.length;s++){
					if(validateInputs[s].disabled == true){continue;}//don't validate disabled fields
					validateInputs[s].validateType = getPEClassInfo(validateInputs[s],"PE_validate");
					if(validateInputs[s].validateType.indexOf("_or_empty") != -1){
						validateInputs[s].allowEmpty = true;
						validateInputs[s].validateType = validateInputs[s].validateType.replace("_or_empty","");
					}
					if(groupName == validateInputs[s].name){continue;}
					if(!validateInputs[s].parentDiv){
						var errTop = document.createElement("div");
							errTop.className = "errorTop";
						validateInputs[s].parentNode.insertBefore(errTop,validateInputs[s]);
						validateInputs[s].parentDiv = errTop;
					}
					groupName = validateInputs[s].name;
					if(Validator.validate.call(validateInputs[s]) == false){
						isAllValid = false;
						var groupFields = getByAttribute(document,"input","name",groupName);
						for(var g=0;g<groupFields.length;g++){
							groupFields[g].parentDiv = validateInputs[s].parentDiv;
							addEvent(groupFields[g],'blur',Validator.validate);
							if((/WebKit/i.test(navigator.userAgent))){ //safari doesn't focus/blur radio or checkboxes
								addEvent(groupFields[g],'click',Validator.validate);
							}
						}
					}
				}
				//testing a section to see that at least one element is filled in
				var sections = fuzzyClassName("div","PE_validOneInGroup");
				for(var i=0;i<sections.length;i++){
					if(!sections[i].errorDiv){
						var errTop = document.createElement("div");
						errTop.className = "errorTop";
						sections[i].insertBefore(errTop,sections[i].firstChild);
						sections[i].errorDiv = errTop;
					}
					if(!Validator.validateGroup(sections[i])){
						isAllValid = false;
					}
				}
				
				if(!isAllValid && !Lightbox.active){
					//get first error and jump to it
					var firstError = getElementsByClassName(document,"div","PE_error")[0];
					var firstErrorYPos = getAbsoluteY(firstError);
					window.scrollTo(0,firstErrorYPos-20);				
				}
				return isAllValid;
			}
		}
	},
	//validate a field and its siblings if it has them
	validate : function(){
		if(this == window){return;} //prevent calls of validate without a field object
		var isValid = true;
		//if it is empty and is allowed to be empty, stop validating and return true
		if(this.allowEmpty && validData["empty"].logic(this)){return true;}
		isValid = !validData["empty"].logic(this);
		var emptyMessage = this.type;  //error message for blank depends on type
		if(this.type == "checkbox"){
			var checkboxes = getByAttribute(document,"input","name",this.name);
			if(checkboxes.length > 1){
				emptyMessage = "checkbox-group";
			}
		}

		var errorMessage = validData["empty"].errormsg[emptyMessage];
		//check siblings for empty now otherwise we might get a misleading error message
		if(isValid && this.allSiblings){
			for(var s=0;s<this.allSiblings.length;s++){
				if(this == this.allSiblings[s]){continue;}//skip self
				if(this.allSiblings[s].type == "image" || this.allSiblings[s].type == "submit" || this.allSiblings[s].type == "clear" || this.allSiblings[s].type == "button"){continue;}
				var isValid = !validData["empty"].logic(this.allSiblings[s]);
				if(!isValid){break;}
			}
		}
		
		if(isValid && this.validateType){
			isValid = validData[this.validateType].logic(this);
			errorMessage = validData[this.validateType].errormsg;
			if(isValid && this.allSiblings){
				for(var s=0;s<this.allSiblings.length;s++){
					if(this == this.allSiblings[s]){continue;}//skip self
					if(this.allSiblings[s].type == "image" || this.allSiblings[s].type == "submit" || this.allSiblings[s].type == "clear" || this.allSiblings[s].type == "button"){continue;}
					isValid = validData[this.allSiblings[s].validateType].logic(this.allSiblings[s]);
					if(!isValid){
						errorMessage = validData[this.allSiblings[s].validateType].errormsg;
						break;
					}
				}
			}
		}
		if(isValid && this.matchToField){
			isValid = validData["match"].logic(this);
			errorMessage = validData["match"].errormsg;
		}
		if(!isValid) {Validator.writeError(this.parentDiv,errorMessage);return false;}
		else {Validator.clearError(this.parentDiv);return true;}
		
	},
	//check a whole group for at least one filled-in field
	validateGroup : function(wrapper){
		var isValid = false;
		var sectionInputs = wrapper.getElementsByTagName("input");
		var sectionSelects = wrapper.getElementsByTagName("select");
		for(var i=0;i<sectionInputs.length;i++){
			if(!validData["empty"].logic(sectionInputs[i])){isValid=true;break;}
		}
		for(var s=0;i<sectionSelects.length;s++){
			if(!validData["empty"].logic(sectionSelects[s])){isValid=true;break;}
		}
		if(!isValid){Validator.writeError(wrapper.errorDiv,validData["empty"].errormsg["group"]);return false;}
		else{Validator.clearError(wrapper.errorDiv);return true;}
	},
	//takes parent div of input as argument
	//write out error if one isn't already there
	writeError : function(el,msg){
		if(el.className.indexOf("PE_error") != -1){
			var message = getElementsByClassName(el,"span","PE_error")[0];
			//check if error text needs updating
			if(message.innerHTML.indexOf(msg) == -1){
				var messageAsString = message.innerHTML.toLowerCase()
				var regx = /(<img[^>]+?>).+/gi;
				message.innerHTML = messageAsString.replace(regx,"$1" + msg);
			}
			return;
		}

		var errImg = document.createElement("img");
			errImg.src = "../img/icons/ico_alert_ya.gif";
			errImg.alt = "Error: ";
		var errMsgTxt = document.createTextNode(msg);
		var errMsg = document.createElement("span");
			errMsg.className = "PE_error clearfix";
			errMsg.appendChild(errImg);
			errMsg.appendChild(errMsgTxt);
		el.className += " PE_error";
		var errMsgDiv = document.createElement("div");
			errMsgDiv.className = "PE_errWrapper clearfix";
			errMsgDiv.appendChild(errMsg);
		el.insertBefore(errMsgDiv,el.firstChild);
	},

	//takes parent div of input as argument
	//remove error if one is there
	clearError : function(el){
		if(el.target || el.srcElement){
			var target = (el.target) ? el.target : el.srcElement;
			el = target.parentDiv;
		}
		if(el.className.indexOf("PE_error") == -1){return;}
		var errMsg = getElementsByClassName(el,"div","PE_errWrapper")[0];
		el.removeChild(errMsg);
		el.className = el.className.replace("PE_error","");
	},
	
	//VALID TYPES

	//returns true if it is a checkbox which is unchecked or a checkbox group with none checked, or a radio button group with none selected or a field with an empty value
	valtype_empty : function(field){
		if(field.type=="checkbox"){
			var checkboxes = getByAttribute(document,"input","name",field.name);
			if(checkboxes.length > 1){
				for(var i=0;i<checkboxes.length;i++){
					if(checkboxes[i].checked == true){return false;}
				}
			}
			if(field.checked){return false;}
			return true;
		}
		else if(field.type=="radio"){
			var radios = getByAttribute(document,"input","name",field.name);
			for(var i=0;i<radios.length;i++){
				if(radios[i].checked == true){return false;}
			}
			return true;
		}
		else{
			if(field.value==""){return true;}	
		}
		return false;
	},
	//checks one field matches another
	//return true if the field is not found so user can continue but alert developer
	valtype_match : function(field){
		if(!field.matchToField){alert("DEV ERROR - matching field not set");return true;}
		var matchingField = document.getElementById(field.matchToField);
		if(!matchingField){alert("DEV ERROR - matching field not found");return true;}
		return(field.value == matchingField.value);
	},
	//accept characters that can go in a name
	valtype_names : function(field){
		var rexp=/^([a-z\-\x80-\xFF]+(. )?[ ']?)+$/i;
		if(field.value.search(rexp)!=-1){return true;}
		return false;
	},
	//ensures a field is at least 6 characters long
	valtype_minlength_6 : function(field){
		return(field.value.length >= 6);		
	},
	//check for valid postcode format
	valtype_postcode : function(field){
		var rexp=/(^gir\s0aa$)|(^[a-pr-uwyz]((\d{1,2})|([a-hk-y]\d{1,2})|(\d[a-hjks-uw])|([a-hk-y]\d[abehmnprv-y]))\s?\d[abd-hjlnp-uw-z]{2}$)/i; // optional space in postcode validation
		if(field.value.search(rexp)!=-1){return true;}
		return false;
	},
	//check contains only numbers
	valtype_number : function(field){
		var rexp = /^\d+$/;
		if(field.value.search(rexp)!=-1){return true;}
		return false;
	},
	//check contains only letters and spaces
	valtype_letters : function(field){
		var rexp = /^[a-z ]+$/i;
		if(field.value.search(rexp)!=-1){return true;}
		return false;
	},
	//check for valid email address
	valtype_email : function(field)	{
		var rexp=/^[a-z[\w\.-]*[a-z0-9]@[a-z0-9][\w\.-]*[a-z0-9]\.[a-z][a-z\.]*[a-z]$/i;
		if(field.value.search(rexp)!=-1){return true;}
		return false;
	},
	//check for valid UK phone numbers
	valtype_phone : function(field)	{
		var rexp=/^((\(?0\d{5}\)?\s?\d{5})|(\(?0\d{4}\)?\s?\d{3}\s?\d{3})|(\(?0\d{3}\)?\s?\d{3}\s?\d{4})|(\(?0\d{2}\)?\s?\d{4}\s?\d{4}))+$/;
		if(field.value.search(rexp)!=-1){return true;}
		return false;
	},
	//test for a valid BT account number
	valtype_bt_account : function(field)	{
		var rexp=/^([a-z]{2})?\d{8}$/i;
		if(field.value.search(rexp)!=-1){return true;}
		return false;
	},
	//test for 3-char minimum digit security code (amex has 4)
	valtype_securitycode : function(field){
		var rexp=/^([\d]{3,4})$/i;
		if(field.value.search(rexp)!=-1){return true;}
		return false;
	},
	//test for date before today
	valtype_cardStart : function(field){
		var fieldsToTest = field.parentDiv.getElementsByTagName("select");
		if(Validator.compareSelectedDateToNow(fieldsToTest) == "isPast"){
			return true;		
		}
		return false;
	},
	//test for date after today
	valtype_cardExpiry : function(field){
		var fieldsToTest = field.parentDiv.getElementsByTagName("select");
		if(Validator.compareSelectedDateToNow(fieldsToTest) == "isFuture"){
			return true;		
		}
		return false;
	},
	//check for a valid UK sort code, user input split into 3 fields
	valtype_sortcode_threepart : function(field){
		var rexp=/^\d{2}$/i;
		if(field.value.search(rexp)!=-1){return true;}
		return false;
	},
	//check for something which could represent money
	//pattern - optional £, 1 or more numbers, optional '.' followed by 2 numbers
	valtype_currency : function(field){
		var rexp=/^\£?\d+(\.\d{2})?$/i;
		if(field.value.search(rexp)!=-1){return true;}
		return false;
	},
	//test a selection of fields for a valid date
	
	valtype_date : function(field){
		var inputs = field.parentDiv.getElementsByTagName(field.tagName);
		if(inputs.length > 1){//handles 3 inputs, either selects or text
			for(var i=0;i<inputs.length;i++){
				if(inputs[i].id.indexOf("date") != -1){
					var fDate = inputs[i].value;
				}
				else if(inputs[i].id.indexOf("month") != -1){
					var fMonth = inputs[i].value;
				}
				else if(inputs[i].id.indexOf("year") != -1){
					var fYear = inputs[i].value;
				}
			}
		}
		if(typeof fDate == "undefined"){
			var fDate = "01";	
		} 
		if (typeof fMonth == "undefined") {
			var fMonth = "01" 
		}
		if(typeof fYear == "undefined"){
			fYear = new Date().getFullYear().toString();
		}
		return (Validator.createDate(fDate,fMonth,fYear) ? true : false);
	},
	// test that a start date is before an end date
	valtype_daterange : function(field){
		var fieldsToTest = field.parentDiv.getElementsByTagName("input");
		for(var i=0,j=fieldsToTest.length;i<j;i++){
			var dateRegExp = /^\d{1,2}(([\.\-\/\s])\d{1,2}\2)(\d{2}|\d{4})$/gi;
			//
			if(fieldsToTest[i].className.indexOf("PE_daterange_start") != -1){
				var start = fieldsToTest[i].value.toString();
				dateRegExp.lastIndex = 0;
				var startRegExp = dateRegExp.exec(start);
				if(startRegExp == null){return false;}
				var aStart = start.split(startRegExp[2]);
				var startDay = aStart[0];
				var startMonth = aStart[1];
				var startYear = aStart[2];
				var startDate = Validator.createDate(startDay,startMonth,startYear);
				if(!startDate){return false;}
			}
			else if(fieldsToTest[i].className.indexOf("PE_daterange_end") != -1){
				var end = fieldsToTest[i].value.toString();
				dateRegExp.lastIndex = 0;
				var endRegExp = dateRegExp.exec(end);
				if(endRegExp == null){return false;}
				var aEnd = end.split(endRegExp[2]);
				var endDay = aEnd[0];
				var endMonth = aEnd[1];
				var endYear = aEnd[2];
				var endDate = Validator.createDate(endDay,endMonth,endYear);
				if(!endDate){return false;}
			}
		}
		if(startDate <= endDate){
			return true;
		}
		return false;
	},
	//date creation - does not allow junk data input
	createDate : function(fDate,fMonth,fYear){
		var regexpDM = /^\d{1,2}$/;
		var regexpY = /^(\d{2}|\d{4})$/;
		if(regexpDM.test(fDate)==-1 || regexpDM.test(fMonth)==-1 || regexpY.test(fYear)==-1){return false;}
		fDate = parseInt(fDate,10);
		fMonth = parseInt(fMonth,10);
		fYear = parseInt(fYear,10);
		if(fMonth < 1 || fMonth > 12){return false;}
		var isLeapYear = (fYear % 4 == 0 && (fYear % 100 != 0 || fYear % 400 == 0)) ? true : false;
		
		var lastDate = 31;
		if(fMonth,10 == 2){
			lastDate = (isLeapYear) ? 29 : 28;			
		}
		
		if (fMonth == 4 || fMonth == 6 || fMonth == 9 || fMonth == 11) {
			lastDate = 30;
		}
		if(fDate > lastDate){
			return false;
		}

		var ddate = new Date(fYear,fMonth-1,fDate);
		return ddate;
	},
	// internal function an array of select boxes, goes and gets all select boxes within its parent div
	compareSelectedDateToNow : function(allFields){
		var now = new Date();
		var ddate = 01;
		for(var i=0;i<allFields.length;i++){
			if(allFields[i].name.indexOf("date") != -1){
				ddate = allFields[i].options[allFields[i].selectedIndex].value;
			}
			else if(allFields[i].name.indexOf("month") != -1){
				var month = allFields[i].options[allFields[i].selectedIndex].value;
			}
			else if(allFields[i].name.indexOf("year") != -1){
				var year = allFields[i].options[allFields[i].selectedIndex].value;
			}
		}
		//will work correctly until the year 2090
		if(year.length === ""){return false;} //interrupt to stop undefined being converted to 1900
		if(year.length == 2){
			year = (year < 90) ? "20" + year : "19" + year;
		}
		if(month === ""){return false;} //interrupt to stop undefined being converted to 0 (January)
		var uInput = Validator.createDate(ddate,month,year);
		if(uInput < now){
			return "isPast";
		}
		else if(uInput > now){
			return "isFuture";
		}
	},
	//run
	init : function(){
		this.nestParents = fuzzyClassName("input","PE_nestValidation");
		window.validData = new Validator.validationData();
		Validator.nestedValidation();
		Validator.validationEventTriggers();	
	}
}

/*LIGHTBOX
	a lightbox is a box of content that sits above the main area, which is usually faded out
	designed as an object because validation needs to access some of its functions.
	setting up the tint bg element at init phase works around a obscure IE bug
	REQUIRED:
		class 'PE_lightBox'  (NB case-sensitive) on the div to become a lightbox, this area must also have an id
		class 'PE_lightboxOpen(id_of_lightbox)' on the anchor that triggers the lightbox if triggered by a link
		class 'PE_lightboxIfInvalid(id_of_lightbox)' on the div with the PE_validate() class if the lightbox is triggered by an invalid field (see validate section comments for further details)
*/

Lightbox = {
	active : false,
	init : function(){
		var pageDiv = document.getElementById("Page");
		var lightboxes = fuzzyClassName("div","PE_lightBox");
		var lightboxLinks = fuzzyClassName("a","PE_lightboxOpen");
		for(var i=0;i<lightboxes.length;i++){
			lightboxes[i].style.visibility = "visible";  //remove styles from IE foc prevention
			//take out of position in HTML and insert at end of page, necessary for placing above the tinted background in IE

			var lightbox = lightboxes[i].parentNode.removeChild(lightboxes[i]);
			pageDiv.insertBefore(lightbox,document.getElementById("Footer"));

			lightbox.className += " hasJS";
			Lightbox.hideLightbox(lightbox);
			Lightbox.addBoxStyles(lightbox);
			Lightbox.addBoxClose(lightbox);
			Lightbox.setUpTintBg();
		}
		for(var h=0;h<lightboxLinks.length;h++){
			lightboxLinks[h].className = lightboxLinks[h].className.replace("hidden","");
			lightboxLinks[h].onclick=function(){
				var thisLightbox = document.getElementById(getPEClassInfo(this,"PE_lightboxOpen"));
				if(typeof thisLightbox == "undefined"){alert("DEV ERROR: no element with ID specified in link's class");return;}
				Lightbox.tintBg();
				Lightbox.showLightbox(thisLightbox);
				
				return false;
			}
		}
	},
	addBoxStyles : function(elem_lightbox){
		//middle - take all children of lightbox and put them into the boxRight div
		var boxRight = document.createElement("div");
			boxRight.className = "lightbox-right";
		while(elem_lightbox.childNodes.length > 0){
			boxRight.appendChild(elem_lightbox.firstChild);
		}
		var boxMain = document.createElement("div");
			boxMain.className = "lightbox-main";
			boxMain.appendChild(boxRight);
		elem_lightbox.appendChild(boxMain);
		//top
		var boxTop = document.createElement("div");
			boxTop.className = "lightbox-top"
		var boxTopLeft = document.createElement("div");
			boxTopLeft.className = "lightbox-top-left";
		var boxTopRight = document.createElement("div");
			boxTopRight.className = "lightbox-top-right";
			boxTopLeft.appendChild(boxTopRight);
			boxTopLeft.appendChild(boxTop);
			elem_lightbox.insertBefore(boxTopLeft,elem_lightbox.firstChild);
		//base
		var boxBase = document.createElement("div");
			boxBase.className = "lightbox-base";
		var boxBaseLeft = document.createElement("div");
			boxBaseLeft.className = "lightbox-base-left";
		var boxBaseRight = document.createElement("div");
			boxBaseRight.className = "lightbox-base-right";
			boxBaseLeft.appendChild(boxBaseRight);
			boxBaseLeft.appendChild(boxBase);
			elem_lightbox.appendChild(boxBaseLeft);
	},
	addBoxClose : function(elem_lightbox){
		var closeLinkImg = document.createElement("img");
			closeLinkImg.src = "../img/buttons/btn_close.gif";
			closeLinkImg.alt = "Close this window.";
		var closeLinkTxt = document.createTextNode("Close");
		closeLink = document.createElement("a");
			closeLink.href = "#";
			closeLink.id = "close_" + elem_lightbox.id;
			closeLink.className = "closeBtn clearfix";
			closeLink.onclick = function(){
				Lightbox.hideLightbox(elem_lightbox);
				Lightbox.removeTintBg();
				//accessibility aid: refocus on the link or validated field that triggered the lightbox
				var lightboxTrigger = fuzzyClassName("a","PE_lightboxOpen(" + elem_lightbox.id + ")")[0];
				if(!lightboxTrigger){
					var lightboxDiv = fuzzyClassName("div","PE_lightboxIfInvalid(" + elem_lightbox.id + ")")[0];
					if(lightboxDiv){lightboxTrigger = lightboxDiv.getElementsByTagName("input")[0];}
				}
				if(lightboxTrigger){lightboxTrigger.focus();}
				return false;
			}
		closeLink.appendChild(closeLinkTxt);
		closeLink.appendChild(closeLinkImg);
		var lightboxHeading = getElementsByClassName(elem_lightbox,"*","heading")[0];
		lightboxHeading.insertBefore(closeLink,lightboxHeading.firstChild);
		lightboxHeading.className += " clearfix";
		//accessibility aid: add hidden close at bottom of lightbox
		var closeLinkHidden = document.createElement("a");
			closeLinkHidden.appendChild(document.createTextNode("End of in page popup. Close using this link to return to main content."));
			closeLinkHidden.href = "#";
			closeLinkHidden.className = "hidden";
			closeLinkHidden.onclick = closeLink.onclick;
		elem_lightbox.appendChild(closeLinkHidden);
		elem_lightbox.closeButtons = [closeLink,closeLinkHidden];
		//detect cancel buttons in HTML and use those too
		var cancelLinks = fuzzyClassNameBlock(elem_lightbox,"a","PE_closeLightbox");
		for(var i=0;i<cancelLinks.length;i++){
			cancelLinks[i].onclick = closeLink.onclick;
			elem_lightbox.closeButtons.push(cancelLinks[i]);
		}
	},
	setUpTintBg : function(){
		/*@cc_on @*/
		/*@if (@_jscript_version < 5.6)
			return; // impossible in IE5
		/*@end @*/
		var pageDiv = document.getElementById("Page");
		var tint = document.createElement("div");
		tint.className = "tintedBg";
		pageDiv.insertBefore(tint,pageDiv.firstChild);
	},
	tintBg : function(){
		var tint = getElementsByClassName(document,"div","tintedBg")[0];
		if(!tint){return;}
		tint.style.height = "0px";
		tint.style.width = document.body.offsetWidth +"px";
		tint.style.height = document.body.offsetHeight +"px";
		
	},
	removeTintBg : function(){
		var tint = getElementsByClassName(document,"div","tintedBg")[0];
		if(!tint){return;}
		tint.style.width = "0px";
		tint.style.height = "0px";
	},
	showLightbox : function(elem_lightbox){
		/*@cc_on @*/
		/*@if (@_jscript_version <= 5.6)
			Lightbox.hideSelects(elem_lightbox); //hide select boxes due to buggy IE6 handling of them
		/*@end @*/
		elem_lightbox.className = elem_lightbox.className.replace(" hide","");
		//set the lightbox in the vertical center of the page, account for relatively-positioned parents
		// if the lightbox is bigger than the viewport, set its top to the top of the viewable screen
		var viewPortCenter = Math.round(getViewPortHeight() / 2);
		var scrolledTop = getScrollTop();
		var userViewCenter = parseInt(viewPortCenter) + parseInt(scrolledTop);
		var lightboxCenter = elem_lightbox.offsetHeight / 2;
		var lightboxRelativeTop = 0;
		var parent = elem_lightbox.parentNode;
		while(parent){
			if(parent.nodeName=="#document"){break;}
			if(getStyle(parent,"position") == "relative"){
				lightboxRelativeTop += parent.offsetTop;
			}
			parent = parent.parentNode;
		}
		if(getViewPortHeight() < elem_lightbox.offsetHeight){
			elem_lightbox.style.top = scrolledTop - lightboxRelativeTop + "px";
		}
		else{
			elem_lightbox.style.top = userViewCenter - lightboxCenter - lightboxRelativeTop + "px";
		}
		Lightbox.active = true;
		//accessibility aid: send cursor to close button on the lightbox
		var closebtn = document.getElementById("close_" + elem_lightbox.id);
		var hiddenFocusLink = document.getElementById("hiddenFocus_" + elem_lightbox.id);
		if(!hiddenFocusLink){
			var hiddenFocusLink = document.createElement("a");
				hiddenFocusLink.href = "#";
				hiddenFocusLink.onclick = function(){return false;}
				hiddenFocusLink.id = "hiddenFocus_" + elem_lightbox.id;
				hiddenFocusLink.appendChild(document.createTextNode("In page pop-up layer.  Use close links to return to main content."));
			closebtn.parentNode.insertBefore(hiddenFocusLink,closebtn);
		}
		hiddenFocusLink.focus();
		hiddenFocusLink.className = "hidden";
	},
	hideLightbox : function(elem_lightbox){
		/*@cc_on @*/
		/*@if (@_jscript_version <= 5.6)
			Lightbox.showSelects();
		/*@end @*/
		elem_lightbox.className += " hide";
		var hiddenFocusLink = document.getElementById("hiddenFocus_" + elem_lightbox.id);
		if(hiddenFocusLink){hiddenFocusLink.className = hiddenFocusLink.className.replace("hidden","");}
		Lightbox.active = false;
	},
	//hide select boxes due to buggy IE<7 handling of them
	hideSelects : function(){
		var selects = document.getElementsByTagName("select");
		for(var i=0;i<selects.length;i++){
			selects[i].style.visibility = "hidden";
		}
	},
	showSelects : function(){
		var selects = document.getElementsByTagName("select");
		for(var i=0;i<selects.length;i++){
			selects[i].style.visibility = "visible";
		}
	}
}

/* PAGINATION 

main 'PE_paginate' function detects elements for pagination and runs the relevant function if found
REQUIRED:
	element with class 'PE_paginate' and arguments specifying how to determine how content should be split up into 'pages'
	UL takes an integer so that the ul is split into several uls with that number of list items in them
*/
function paginate(){
	if(fuzzyClassName("ul","PE_paginate").length > 0){
		paginateUnorderedList();
	}
	
	function paginateUnorderedList(){
		var ul_toPaginate = fuzzyClassName("ul","PE_paginate");
		for(var i=0;i<ul_toPaginate.length;i++){
			var splitAtItem = parseInt(getPEClassInfo(ul_toPaginate[i],"PE_paginate"));
			if(isNaN(splitAtItem)){return false;}
			var listItems = ul_toPaginate[i].getElementsByTagName("li");
			if(listItems.length <= splitAtItem){return false;}
			var uls = [ul_toPaginate[i]];
			var lastUL = "";
			while(listItems.length > splitAtItem){
				var newUL = document.createElement("ul");
					newUL.className = ul_toPaginate[i].className.replace("PE_("+splitAtItem+")","");
					newUL.className += " hidden";
				for(var t=splitAtItem;t<splitAtItem*2;t++){
					if(!listItems[splitAtItem]){break;}
					var moveLi = listItems[splitAtItem].parentNode.removeChild(listItems[splitAtItem]);
					newUL.appendChild(moveLi);
				}
			
				if(!lastUL){lastUL = ul_toPaginate[i];}
				if(lastUL.nextSibling){
					ul_toPaginate[i].parentNode.insertBefore(newUL,lastUL.nextSibling);
				}
				else{
					ul_toPaginate[i].parentNode.appendChild(newUL);
				}
				lastUL = newUL;
				uls.push(newUL);
			}

			function goPrev(){
				this.nextBtn.className = this.nextBtn.className.replace("nodisplay","");
				for(var p=0;p<this.uls.length;p++){
					if(this.uls[p].className.indexOf("hidden") == -1){
						if(p == 0){break;}
						this.uls[p].className += " hidden";
						this.uls[p-1].className = this.uls[p-1].className.replace("hidden","");
						if(p-1 == 0){this.className += " nodisplay";}
						break;
					}
				}
				return false;
			}
			function goNext(){
				this.prevBtn.className = this.prevBtn.className.replace("nodisplay","");
				for(var n=0;n<this.uls.length;n++){
					if(this.uls[n].className.indexOf("hidden") == -1){
						if(n == this.uls.length-1){break;}
						this.uls[n].className += " hidden";
						this.uls[n+1].className = this.uls[n+1].className.replace("hidden","");
						if(n+1 == this.uls.length-1){this.className += " nodisplay";}
						break;
					}
				}
				return false;
			}
			
			var buttonsDiv = document.createElement("div");
			buttonsDiv.className = "paginationButtons clearfix";
			var prevBtn = prevPage(goPrev);
				prevBtn.className += " nodisplay";
			var nextBtn = nextPage(goNext);
			prevBtn.nextBtn = nextBtn;
			nextBtn.prevBtn = prevBtn;
			buttonsDiv.appendChild(prevBtn);
			buttonsDiv.appendChild(nextBtn);
			prevBtn.uls = nextBtn.uls = uls;
			ul_toPaginate[i].parentNode.insertBefore(buttonsDiv,lastUL.nextSibling);
		}
	}
	//returns a DOM object of 'next' image inside a hyperlink
	function nextPage(clickFunc){
		var img = document.createElement("img");
			img.src = "../img/buttons/btn_next_white_off.gif";
			img.className = "PE_swap";
			img.alt = "Next.";
		var a = document.createElement("a");
			a.href="#";
			a.appendChild(img);
			a.onclick = clickFunc;
			return a;
	}
	//returns a DOM object of 'previous' image inside a hyperlink
	function prevPage(clickFunc){
		var img = document.createElement("img");
			img.src = "../img/buttons/btn_previous_white_off.gif";
			img.className = "PE_swap";
			img.alt = "Previous.";
		var a = document.createElement("a");
			a.href="#";
			a.appendChild(img);
			a.onclick = clickFunc;
			return a;
	}
}

/*PASSWORD STRENGTH CHECKER*/
/*
Requirements:
	Wrapper:
				div with class 'checkPasswordStrength' (around strength message and image)
	Fields:		password field with id 'password'
	Message:	div with class 'strengthmessage' to show the message text
	Image:		image with id 'passwordStrengthBar' to show the indicator
				6 image files for the strength indicator:
				bar_pcheckstrength_0.gif, bar_pcheckstrength_1.gif, bar_pcheckstrength_2.gif, bar_pcheckstrength_3.gif, bar_pcheckstrength_4.gif and bar_pcheckstrength_5.gif
*/


function passwordStrengthCheck(){
	var checkStrength = fuzzyClassName("div","checkPasswordStrength");
	if(checkStrength.length == 0){return;}
	BindStrengthCheck();
	PasswordStrengthChecker.setMinLength(6); // set minimum number of characters entered until checker activates
	// put strength checking on keystroke event
	document.getElementById('password').onkeyup = OutputStrengthMessage; //get password input
	
}

function OutputStrengthMessage()
{
	var pwd_el = document.getElementById('password'); //get password input

	var strength = pwd_el.CheckStrength();
	var message = '';
	switch(strength.keyMessage)
	{
	case PasswordStrength.returnValues.levelZero: message='';color='#ffffff';break;
	case PasswordStrength.returnValues.levelOne: message='Vulnerable';color='#fc0303';break;
	case PasswordStrength.returnValues.levelTwo: message='Weak';color='#ff6600';break;
	case PasswordStrength.returnValues.levelThree: message='Try harder';color='#cc9900';break;
	case PasswordStrength.returnValues.levelFour: message='Better';color='#CADB2A';break;
	case PasswordStrength.returnValues.levelFive: message='Excellent';color='#69be28';break;
	}
	
	var strengthmessage = getElementsByClassName(document,'div','strengthmessage')[0]; //get strength message text area

	strengthmessage.innerHTML=message; 
	strengthmessage.style.color=color; 
	
	// change colour;
	var i=new Image();
	i.src='../img/icons/bar_pcheckstrength_'+strength.strength+'.gif';
	var pswImg=document.getElementById('passwordStrengthBar'); //get strength image
	pswImg.src=i.src;
	
}



function BindStrengthCheck()
{
	var pswd=document.getElementById('password'); //get password input
	PasswordStrengthChecker.BindPasswordField(pswd);
		
}

// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
// The strength checker stuff
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
// return values;

var PasswordStrength = new Object();

PasswordStrength.returnValues = {
	// Return values;
	levelZero: 'levelZero',
	levelOne: 'levelOne', 
	levelTwo: 'levelTwo', 
	levelThree: 'levelThree',
	levelFour: 'levelFour',
	levelFive: 'levelFive'
}

// the global strength checker object:
var PasswordStrengthChecker = {
	min_valid_length: 2,
	input_el_compare: new Array(),
	// default validation checks;
	//regular expressions to determine strength of password based on patterns
	// level 1: user has put in only one case of letters or only numbers or only symbols
	// OR		user has first letter upper case, the rest lower case
	// level 2: user has one case letters and numbers on the end
	// OR		user has mixed case letters but no numbers or symbols
	// OR		user has 2+ upper case letters at the start then lower case, but no numbers or symbols
	// level 3: user has mixed case letters with numbers on the end
	// OR		user has 2+ upper case letters then lower case then numbers on the end
	// OR		user has mixed case letters with symbol on the end
	// OR		user has 2+ upper case letters then lower case then symbol on the end
	// level 4:	user has numbers mixed in the middle of letters
	// OR		user has symbols mixed in the middle of letters
	// level 5: user has both numbers and symbols in the middle of letters
	// OR		user has symbols in the middle of letters and numbers at the end
	default_checks: [
					[/(^[a-z]+$) | (^[A-Z]+$) | (^[0-9]+$) | (^[!%&#~_-]+$) /g, 1, PasswordStrength.returnValues.levelOne],
					[/([a-z]|[A-Z])+[0-9]+/g, 2, PasswordStrength.returnValues.levelTwo],
					[/[a-z]+[A-Z]+/g, 2, PasswordStrength.returnValues.levelTwo],
					[/[A-Z]{2,}[a-z]+/g, 2, PasswordStrength.returnValues.levelTwo],
					[/[a-z]+[A-Z]+[0-9]+$/g, 3, PasswordStrength.returnValues.levelThree],
					[/[A-Z]{2,}[a-z]+[0-9]+$/g, 3, PasswordStrength.returnValues.levelThree],
					[/[a-z]+[A-Z]+[!%&#~_\-]+$/g, 3, PasswordStrength.returnValues.levelThree],	
					[/[A-Z]{2,}[a-z]+[!%&#~_\-]+$/g, 3, PasswordStrength.returnValues.levelThree],	
					[/[a-zA-Z]+[0-9]+[a-zA-Z]+/g, 4, PasswordStrength.returnValues.levelFour],
					[/[a-zA-Z]+[!%&#~_-]+[a-zA-Z]+/g, 4, PasswordStrength.returnValues.levelFour],
					[/[a-zA-Z]+[!%&#~_-]+[a-zA-Z]*[0-9]+[a-zA-Z]+/g, 5, PasswordStrength.returnValues.levelFive],
					[/[a-zA-Z]+[0-9]+[a-zA-Z]*[!%&#~_-]+[a-zA-Z]+/g, 5, PasswordStrength.returnValues.levelFive],
					[/[a-zA-Z]+[!%&#~_-]+[a-zA-Z]*[0-9]+/g, 5, PasswordStrength.returnValues.levelFive]
				],
				//!%&#~_-
	// public methods;
	// adds an input field required for comparison;
	AddCompareInput: function(input_el)
		 {this.input_el_compare.push(input_el);},
	
	// binds events to a password field;
	BindPasswordField: function(input_el) 
	{
		input_el.CheckStrength = function() {return PasswordStrengthChecker._CheckStrength(input_el);};		
	},
	
	// check the strength of a password;
	_CheckStrength: function(input_el) 
	{	
		var input_val = (input_el.value) ? input_el.value : "";
		var ret_val = {strength: 1, keyMessage: PasswordStrength.returnValues.levelOne}; 
		if (input_val.length < this.min_valid_length) 
		{
			ret_val.strength = 0;
			ret_val.keyMessage = PasswordStrength.returnValues.levelZero;
		}
		else 
		{
			this._CheckCompare(input_val, ret_val);
			this._CheckDefault(input_val, ret_val);

		}	
		ret_val.strength = (ret_val.strength<0)?0:ret_val.strength;
		
		return ret_val;
	},
	
	// check against default checks;
	_CheckDefault: function(input_val, ret_val) 
	{
		var def_strength = 0;
		for (var i=0; i < this.default_checks.length; i++) 
		{

			if (input_val.match(this.default_checks[i][0]))
			{
				ret_val.strength = this.default_checks[i][1];
				ret_val.keyMessage = this.default_checks[i][2];
			}
		}
	},
	// check against other input fields to see if there is any crossover; 
	_CheckCompare: function(input_val, ret_val)
	{
		var input_val_lc = input_val.toLowerCase();

		for (var i=this.input_el_compare.length-1; i>=0; i--) 
		{
			var ck_val = this.input_el_compare[i].value.toLowerCase();
			
			if (ck_val.length)
				if (input_val.indexOf(ck_val) > -1)
				{
					ret_val.strength = 1;
					ret_val.keyMessage = PasswordStrength.returnValues.levelOne;
				}
		}
	},

	
	// public: set properties;
	setMinLength: function(min_valid_length) {this.min_valid_length = min_valid_length;}
}


/*END PASSWORD STRENGTH CHECKER*/


/*  SUM

used for calculating the sum of the values of a group of fields and writing them to 1 or more related elements

REQUIRED
	input or select boxes with class 'PE_sum(fooName)'
	area for sum total with class 'PE_sumTotal(name=fooName,format=[float|int|currency])'
	

*/
function sum(){
	var sumTotals = fuzzyClassName("span","PE_sumTotal");
	for(var i=0;i<sumTotals.length;i++){
		getPEHash(sumTotals[i],getPEClassInfo(sumTotals[i],"PE_sumTotal"));
		var sumAddends = fuzzyClassName("input","PE_sum("+sumTotals[i]['name']+")");
		var selectAddends = fuzzyClassName("select","PE_sum("+sumTotals[i]['name']+")");
		for(var c=0;c<selectAddends.length;c++){
			sumAddends.push(selectAddends[c]);
		}
		var tallyTotal = 0;
		for(var s=0;s<sumAddends.length;s++){
			if(!isNaN(parseFloat(sumAddends[s].value))){
				tallyTotal = parseFloat(tallyTotal) + parseFloat(sumAddends[s].value);
			}
			if(!sumAddends[s].outputs){
				sumAddends[s].outputs = new Array();
			}
			sumAddends[s].outputs.push(sumTotals[i]);
			sumAddends[s].addends = sumAddends;
			sumAddends[s].onkeyup = function(){
				var tally = 0;
				for(var a=0;a<this.addends.length;a++){
					if(!isNaN(parseFloat(this.addends[a].value))){
						tally = parseFloat(tally) + parseFloat(this.addends[a].value);
					}
				}
				for(var o=0;o<this.outputs.length;o++){
					tally = parseFloat(tally);
					if(this.outputs[o]['format'] == "currency"){
						tally = "&pound;" + tally.toFixed(2);
					}
					this.outputs[o].innerHTML = tally;
				}
			};
			sumAddends[s].onchange = sumAddends[s].onkeyup;
		}	
		if(sumTotals[i]['format'] == "currency"){
			tallyTotal = "&pound;" + tallyTotal.toFixed(2);
		}
		else if(sumTotals[i]['format'] == "int"){
			tallyTotal = parseInt(tallyTotal);
		}
		sumTotals[i].innerHTML = tallyTotal;
	}
}

/*
BAR CHART
	creates a bar chart from table data and a scale based on the highest value in the data, a given number of markers on the scale and rounds to multiples of 5 (to change, see code below)
REQUIRED:
	table with class 'PE_hasBarChart'
	if a text scale is required, th for the column with class PE_chartScale(x) where x is the number of steps
	numeric values to be used wrapped in a span element with class 'PE_chartValue'
	td for bar to be displayed in to have class 'PE_chartDisplay'
	bar background div with class bar_bg
 */

function barChart(){
	var chartTable = getElementsByClassName(document,"table","PE_hasBarChart");
	for (var i = 0; i < chartTable.length; i++) {
		chartTable[i].className += " barchart";
		var valueSpan = getElementsByClassName(chartTable[i],"span","PE_chartValue");
		if(valueSpan.length === 0){return;}
		var chartDisplay = getElementsByClassName(chartTable[i],"div","bar_bg")[0];
		var chartDisplayTd = getParentByTagName(chartDisplay,"td");
		chartDisplayTd.className += " barchart"
		var chartDisplay_width = parseInt(chartDisplay.offsetWidth,10);
		var maxValue = 1;
		//determine largest item for chart
		for (var v = 0; v < valueSpan.length; v++) {
			if (Math.ceil(valueSpan[v].innerHTML) > maxValue) {
				maxValue = Math.ceil(valueSpan[v].innerHTML);
			}
		}
		var scale = maxValue; //default to largest value

		//calculate values and layout of scale
		var scaleHeader = fuzzyClassNameBlock(chartTable[i],"th","PE_chartScale")[0];
		if(scaleHeader){
			var scaleInner = document.createElement("div");
			scaleInner.className = "chartScale";
			var scaleNoOfSteps = parseInt(getPEClassInfo(scaleHeader,"PE_chartScale"));
			var scaleRound = 5;
			//determine scale maxValue / steps on graphic rounded to highest rounding value
			//rounded so that the scale does not include pence
			var maxValueToNearestRound = Math.ceil(maxValue / scaleRound) * scaleRound;
			var scaleStep = Math.ceil(maxValueToNearestRound / scaleNoOfSteps);
			
			//only round step value to nearest rounding value if maximum is greater than round * steps, otherwise the scale end will be determinded by number of steps multiplied by rounding value
			if(maxValueToNearestRound / scaleRound >= scaleNoOfSteps){
				scaleStep = Math.ceil(scaleStep / scaleRound) * scaleRound;
			}
			scale = scaleStep * scaleNoOfSteps;
			var scaleHeaderWidth = scaleHeader.offsetWidth;
			var paddingHoriz = parseInt(getStyle(scaleHeader,"padding-right")) + parseInt(getStyle(scaleHeader,"padding-left"));
			scaleHeaderWidth -= paddingHoriz;
			for(var s=0;s<=scaleNoOfSteps;s++){
				var newStep = document.createElement("div");
				newStep.className = "chartScaleStep";
				//step value
				var stepNumber = document.createTextNode("\u00A3" + s * scaleStep);
				newStep.appendChild(stepNumber);
				newStep.title = "\u00A3" + s * scaleStep;
				//step dynamic styles. width split equally between divs
				//position set to middle of div on steps equivalent %
				//e.g. 4 steps, 1st step is 25%, 25% of scale width is converted to px and div is positioned so its midpoint is there

				newStep.style.width = Math.floor(scaleHeaderWidth / (scaleNoOfSteps+1)) + "px";
				if(s < scaleNoOfSteps){
					var newStepCentre = parseInt(parseInt(newStep.style.width) / 2);
					var newStepPercent = 100 / scaleNoOfSteps * s;
					var newStepPercentAsPx = scaleHeaderWidth * (newStepPercent / 100);
					var newPos = Math.floor(newStepPercentAsPx - newStepCentre);
					if(newPos == 0 - newStepCentre){ 
						newPos += 5;
					}
					newStep.style.left =  newPos+"px";
					scaleInner.appendChild(newStep);
				}
				if(s == scaleNoOfSteps){
					scaleHeader.appendChild(scaleInner);
					newStep.className = "chartScaleStepLast";
					scaleHeader.appendChild(newStep);
				}

			}
			
		}
		//write out bars
		for(v = 0; v < valueSpan.length; v++){
			var barWidth = parseInt(valueSpan[v].innerHTML / scale * chartDisplay_width);
			var tr = getParentByTagName(valueSpan[v],"tr");
			var chartDisplay = getElementsByClassName(tr,"td","PE_chartDisplay");
			if(chartDisplay.length === 0){continue;}
			chartDisplay[0].className += " barchart";
			var chartBar = document.createElement("div");
			
				chartBar.style.width = barWidth + "px";
				chartBar.className = "bar";
			var chartBarWrapper = document.createElement("div");
				chartBarWrapper.className = "barWrap";
				chartBarWrapper.style.width = chartDisplay_width + "px";
			var chartBarImg = document.createElement("div");
			var chartBarEnd = document.createElement("div");
				chartBarEnd.className = "end";
			chartBarImg.appendChild(chartBarEnd);
			chartBarWrapper.appendChild(chartBarImg);
			chartBar.appendChild(chartBarWrapper);
			chartDisplay[0].lastChild.appendChild(chartBar);

		}
	}
}
/*
toggleView allows specified content to be displayed and hidden depending on one of a group of links being clicked.
the content is hidden using nodisplay, which means it is not available to screenreaders when hidden
REQUIRED:
	toggling content grouped inside a div with class PE_toggleView
	toggling text in span element with class PE_toggler(uid)
	block element wrapping the content to be toggled with class PE_toggle(uid)
	the toggler for the starting toggle view has no link around it, all the other togglers do

*/
function toggleView(){
	var toggleViewDiv = getElementsByClassName(document,"div","PE_toggleView");
	for(var i=0,j=toggleViewDiv.length;i<j;i++){
		toggleViewDiv[i].style.display = "block";
		toggleViewDiv[i].style.visibility = "visible";
		var toggles = fuzzyClassNameBlock(toggleViewDiv[i],"span","PE_toggler");
		for(var k=0,m=toggles.length;k<m;k++){
			//are spans, onclick will hide other and show given and create link around other
			toggles[k].allToggles = toggles;
			var toggleViewMarker = getPEClassInfo(toggles[k],"PE_toggler");
			var toggleViews = fuzzyClassName("*","PE_toggle("+toggleViewMarker+")");
			if(toggleViews.length == 0){continue;}
			toggles[k].toggleView = toggleViews[0];
			toggles[k].parentNode.toggle = toggles[k];
			if(toggles[k].parentNode.tagName.toLowerCase() == "a"){
				hideToggleView(toggles[k].toggleView);
				toggles[k].parentNode.onclick = toggle;
			}
		}
	}
	function toggle(){
		showToggleView(this.toggle.toggleView);
		for(var n=0,p=this.toggle.allToggles.length;n<p;n++){
			if(this.toggle.allToggles[n] == this.toggle){
				this.parentNode.insertBefore(this.toggle,this);
				this.parentNode.removeChild(this);
			}
			else{
				hideToggleView(this.toggle.allToggles[n].toggleView);
				if(this.toggle.allToggles[n].parentNode.tagName.toLowerCase() != "a"){
					var toggleLink = document.createElement("a");
					toggleLink.href="#";
								this.toggle.allToggles[n].parentNode.insertBefore(toggleLink,this.toggle.allToggles[n]);
					toggleLink.appendChild(this.toggle.allToggles[n]);
					toggleLink.toggle = this.toggle.allToggles[n];
					toggleLink.onclick = toggle;
				}
			}
		}
		return false;
	}
	function hideToggleView(el){
		if(el.className.indexOf("nodisplay") == -1){
			el.className += " nodisplay";
		}
	}
	function showToggleView(el){
		 el.className = el.className.replace("nodisplay","");
	}
}

/*
select boxes - hide for IE6

calendar
	brings up a calendar div lying over the page
REQUIRED:
	input field with class "PE_calendar"
	span with class "PE_lastBillDate" containing the date the last bill was sent out in format yyyy/mm/dd
*/

function calendar(){
	var calendarFields = getElementsByClassName(document,"input","PE_calendar");
	for(var i=0,j=calendarFields.length;i<j;i++){
		var calendarDiv = document.createElement("div");
		calendarDiv.id = "div_"+calendarFields[i].id;
		calendarDiv.className = "calendar_wrapper";
		var nextSibling = calendarDiv.nextSibling;
		if(nextSibling){
			calendarFields[i].parentNode.insertBefore(calendarDiv,nextSibling);
			}
		else{
			calendarFields[i].parentNode.appendChild(calendarDiv);
		}
		calendarFields[i].calendarDivID = calendarDiv.id;
		
		var lastBill = getElementsByClassName(document,"span","PE_lastBillDate");
		if(lastBill.length > 0){calendarFields[i].lastBillEnd = new Date(lastBill[0].innerHTML);}
		else{//last bill date defaults to yesterday as a fail-safe
			calendarFields[i].lastBillEnd = new Date();
			calendarFields[i].lastBillEnd.setDate(calendarFields[i].lastBillEnd.getDate()-1);
		}
		
		addEvent(calendarFields[i],'click',newCalendar);
	}
	function newCalendar(){
		var newCal = new CalendarPopup(this.calendarDivID);
		newCal.setWeekStartDay(1);
		newCal.dayHeaders = new Array("S","M","T","W","T","F","S");
		for(var m=0;m<newCal.monthNames.length;m++){
			newCal.monthNames[m] = newCal.monthNames[m].toUpperCase();
		}
		var now = new Date();
		var tomorrow = new Date();
		tomorrow.setDate(now.getDate()+1);
		newCal.offsetX = 0;
		newCal.addDisabledDates(null, formatDate(this.lastBillEnd,"yyyy-MM-dd"));
		
		newCal.addDisabledDates(formatDate(tomorrow,"yyyy-MM-dd"),null);
		
		newCal.lastMonthLink = '<img src="../img/buttons/buttons_ya/btn_calendar_prev.gif" alt="Previous month" />';
		newCal.nextMonthLink = '<img src="../img/buttons/buttons_ya/btn_calendar_next.gif" alt="Next month" />';
		newCal.select(this,this.id,'dd/MM/yyyy');  //call last
	}
}
/*
TODO: what to plug ajax into?  need BT and TechM's help
billSavePrint is an ajax call that retrieves the dynamically-created bill in the user's chosen format and type
REQUIRED:
	div with class "xhr_loading" for loading status
	div with class "xhr_result" for displaying results
	div with class "actionButtons" that hold the input buttons that send the form
	div with class "options" that contains the radio inputs with data in them that goes into making the url to create the file
*/
function billSavePrint(){
	var actionButtonsDivs = getElementsByClassName(document,"div","actionButtons");
	for(var i=0,j=actionButtonsDivs.length;i<j;i++){
		var buttons = actionButtonsDivs[i].getElementsByTagName("input");
		for(var a=0,b=buttons.length;a<b;a++){
			buttons[a].onclick = function(){
				var thisLightBox = getParentByClassName(this,"lightBox");
				Lightbox.active = true; //ensure is true for non-CSS users
				//get which type of bill is selected
				var optionsDiv = getElementsByClassName(thisLightBox,"div","options");
				if(optionsDiv.length === 0){return;}
				var options = optionsDiv[0].getElementsByTagName("input");
				for(var y=0,z=options.length;y<z;y++){
					if(options[y].checked){
						var billID = options[y].value;
						break;
					}
				}
				if(!billID){return;}
				var url = "somefile.jsp?filename=" + billID + "&format=" + this.value;
				url="../img/retail/pdf2.pdf";	
				url="../img/retail/p.pdf";
				billXHR(thisLightBox,url)
				return false;
			}
			var billLinks = getElementsByClassName(document,"a","PE_getBill");
			for(var c=0,d=billLinks.length;c<d;c++){
				billLinks[c].onclick = function(){
					Lightbox.active = true; //ensure is true for non-CSS users
					var thisLightBox = getParentByClassName(this,"lightBox");
					billXHR(thisLightBox,this.href);
					return false;
				}
			}
		}
	}
	
	function billXHR(container,url){
		var xhr_loadings = getElementsByClassName(container,"div","xhr_loading");
		if(xhr_loadings.length === 0){return;}
		var xhr_loading = xhr_loadings[0];
		var xhr_results = getElementsByClassName(container,"div","xhr_results");
		if(xhr_results.length === 0){return;}
		var xhr_result = xhr_results[0];
		show(xhr_loading);
		hide(getElementsByClassName(container,"div","billEmail")[0]);
		hide(xhr_result);

		var xhReq = createXMLHttpRequest();
		xhReq.open("GET", url, true);
		for(var g=0,h=container.closeButtons.length;g<h;g++){
			addEvent(container.closeButtons[g],"click",function(){
				xhReq.abort();
				xhReq.onreadystatechange = function(){return false;}
				hide(xhr_loading);
				hide(xhr_result);
				show(getElementsByClassName(container,"div","billEmail")[0]);
			});
		}
		xhReq.onreadystatechange = function() {
			if(!Lightbox.active){return false;}
			if (xhReq.readyState != 4)  { return false; }
			hide(xhr_loading);
			
			if (xhReq.status != 200)  { 
				//HTTP response (e.g. 404 page not found, 500 server error) error handling
				bill_error(xhr_result,"Sorry, there was a problem creating your file.");
				return false;
			}
			var xhrResponse = xhReq.responseText;
			//extract file
			var file = "ddd";
			bill_complete(xhr_result,file);
		}
		xhReq.send(null);
	}
	function buffer(){
		var bufferReset = document.getElementById("bufferReset");
		if(!bufferReset){
			var bufferReset = document.createElement("input");
			bufferReset.type="hidden";
			bufferReset.name="bufferReset";
			bufferReset.value=1;
			bufferReset.id="bufferReset";
			document.body.appendChild(bufferReset);
		}
		bufferReset.value++;
	}
	function show(xhr_area){
		if(!xhr_area){return;}
		xhr_area.className = xhr_area.className.replace("nodisplay","");
	}
	function hide(xhr_area){
		if(!xhr_area){return;}
		if(xhr_area.className.indexOf("nodisplay") == -1){
			xhr_area.className += " nodisplay";
		}
	}
	function bill_error(xhr_result,msg){
		var thisLightbox = getParentByClassName(xhr_result,"lightBox");
		var err = document.createElement("p");
			err.className = "warning";
		var errLink = document.createElement("a");
			errLink.className = "warning";
			errLink.href="#";
			errLink.onclick = function(){Lightbox.hideLightbox(thisLightbox);Lightbox.removeTintBg();}
		var errMsg = document.createTextNode(msg);
		errLink.appendChild(errMsg);
		err.appendChild(errLink);
		xhr_result.innerHTML = "";
		xhr_result.appendChild(err);
		show(xhr_result);
		buffer();
		errLink.focus();
	}
	function bill_complete(xhr_result,billURL){
		var head = document.createElement("h4");
		var headTxt = document.createTextNode("Your bill is ready to view");
		head.appendChild(headTxt);
		var billLink = document.createElement("a");
			billLink.href=billURL;
		var billLinkImg = document.createElement("img");
			billLinkImg.src = "../img/buttons/buttons_ya/btn_viewbill_blue_off.gif";
			billLinkImg.alt="View bill";
			billLinkImg.className = "PE_swap";
		billLink.appendChild(billLinkImg);
		xhr_result.innerHTML = "";
		xhr_result.appendChild(head);
		xhr_result.appendChild(billLink);
		show(xhr_result);
		buffer();
		billLink.focus();
	}
}
/*
TRHOVERS
	trHovers will detect a mouse over out on a table row and change the background of its tds by adding the class 'hover' to the tr, and remove that class on mouse out.
REQUIRED:
	table with class "PE_trHovers"
*/
function trHovers(){
	var hoverTables = getElementsByClassName(document,"table","PE_trHovers");
	for(var i=0,j=hoverTables.length;i<j;i++){
		var trs = hoverTables[i].getElementsByTagName("tr");
		for(var t=0,u=trs.length;t<u;t++){
			if(trs[t].parentNode.nodeName.toLowerCase() == "thead"){continue;}
			trs[t].onmouseover = function(){
				if(this.className.indexOf("hover") == -1){
					this.className += " hover";
				}
			}
			trs[t].onmouseout = function(){
				this.className = this.className.replace("hover","");
			}
		}
	}
}

/*
PRINT PAGE
	buttons to trigger the print dialog for the user to print the page.  these are hidden with CSS and re-displayed with javascript so that non-js users don't see a button they cannot use.
REQUIRED:
	<a> or <input> with class 'print' on it
*/
function printpage(){
	var printBtns = getElementsByClassName(document,"a","PE_print");
	for(var i=0;i<printBtns.length;i++){
		if(window.print){printBtns[i].style.display = "block";}
		printBtns[i].onclick = function(){
			if(window.print){window.print();}
			return false;
		};
	}
}

/* ROLLOVERS	
Will change an image when the user mouses over or focuses on an image, and change it back to the original when the user mouses out or blurs
REQUIRED:
	2 nearly identically named images, with _off at the end of the file name for normal state and _over at the end of the file name for over state
	
	input or image with 'swap' in the classname
	
	e.g. <img src="myfile_off.gif" class="PE_swap" /> where you also have myfile_over.gif
	
ORIGINS: your account 07/08
*/

function imgSwap(){
var swapImgs=getElementsByClassName(document,"*","PE_swap");
	for(var i=0;i<swapImgs.length;i++){
		swapImgs[i].onmouseover=function(){
				var newImg=this.src.replace("_off.","_over.");
				this.src=newImg;
			};
			swapImgs[i].onmouseout=function(){
				var newImg=this.src.replace("_over.","_off.");
				this.src=newImg;
			};
			swapImgs[i].onfocus=swapImgs[i].onmouseover;
			swapImgs[i].onblur=swapImgs[i].onmouseout;
		}
}

/*truncate text and add an ellipsis
takes a string and an integer for how long to make the string*/
function truncate(str,length){
	if(str.length > length){
		str = str.substr(0,length);
		str += "...";
	}
	return str;
}

/* XML DATA REQUEST AND MANIPULATION FUNCTIONS */
/*
Required:   div with class 'xhr_results' to display the feedback/errors/results from the request
			div with class 'xhr_loading' to display the loading message to the user while the request is running.
*/
// returns a cross-browser XMLHTTPRequest object
function createXMLHttpRequest() {
   try { return new XMLHttpRequest(); } catch(e) {}
   try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) {}
   try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {}
   alert("XMLHttpRequest not supported");
   return null;
 } 


//takes a responseText or xml string argument, strips out any content before the xml declaration (e.g. vignette timestamp) and returns an XML object
function stringToValidXML(xmlString){
	if(xmlString.indexOf("<?xml ")>0){
		xmlString=xmlString.substring(xmlString.indexOf("<?xml "));
	}
	if(window.ActiveXObject){
		doc = new ActiveXObject("Microsoft.XMLDOM");
        doc.async="false";
        doc.loadXML(xmlString);
	}
	else if(document.implementation.createDocument){
		var parser = new DOMParser();
        doc = parser.parseFromString(xmlString, "text/xml");
	}
	return doc;
}


/*Generic DOM functions*/
function getElementsByClassName(oElm, strTagName, strClassName){
	var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
	var arrReturnElements = new Array();
	strClassName = strClassName.replace(/\-/g, "\\-");
	var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
	var oElement;
	for(var i=0; i<arrElements.length; i++){
		oElement = arrElements[i];		
		if(oRegExp.test(oElement.className)){
			arrReturnElements.push(oElement);
		}	
	}
	return (arrReturnElements);
}

function getParentByTagName(el,tagName){
	var parent=el.parentNode;
	while(tagName.toLowerCase()!=parent.nodeName.toLowerCase()){
		parent=parent.parentNode;
		if(!parent || parent.nodeName=="#document"){return false;}
	}
	return parent;
}
//returns the first parent node of oElm that has strClassName in its class attribute
//classname is 'fuzzy'
function getParentByClassName(oElm,strClassName){
	var parent=oElm.parentNode;
	while(parent.className.indexOf(strClassName)==-1){
		parent=parent.parentNode;		
		if(!parent || parent.nodeName=="#document"){return false;}

	}
	return parent;
}
//finds the elements in oElm's block that has a specified attribute with a specified value
//CAVEAT: IE6 and below has patchy support for class attribute, don't use for that
function getByAttribute(oElm,strTagName,attribName,attribValue){
	var sEls=oElm.getElementsByTagName(strTagName);
	var aElms=new Array();
	for(var s=0;s<sEls.length;s++){
		if(sEls[s].getAttribute(attribName)==attribValue){
			aElms.push(sEls[s]);
		}
	}
	return aElms;
}
function fuzzyClassName(tag,fClass)	{
	var el = (tag == "*" && document.all) ? document.all : document.getElementsByTagName(tag);
	var o=new Array();
	for (var i=0;i<el.length;i++)	{
		if (el[i].className.indexOf(fClass)!=-1)	{
			o.push(el[i]);
		}
	}
	return o;
}
//as fuzzyClassName, but restriced to self and children of a specific DOM object
function fuzzyClassNameBlock(block,tag,fClass)	{
	var el = (tag == "*" && block.all) ? block.all : block.getElementsByTagName(tag);

	var o=new Array();
	for (var i=0;i<el.length;i++)	{
		if (el[i].className.indexOf(fClass)!=-1)	{
			o.push(el[i]);
		}
	}
	if(block.className.indexOf(fClass)!=-1){
		o.push(block);
	}
	return o;
}
//get the contents between ( and ) marks attached to a classname that starts with a given marker
function getPEClassInfo(el,marker){
	var fullClass = el.className;
	var info = fullClass.substring(fullClass.indexOf(marker+"(")+marker.length+1);
	info = info.substring(0,info.indexOf(")"));
	return info;
}

//takes an object and a string of key-value pairs seperated by commas
//adds the key-value pairs as expandos to the object
function getPEHash(el,str){
	var arr = str.split(",")
	for(var i=0;i<arr.length;i++){
		var keyVal = arr[i].split("=");
		el[keyVal[0]] = keyVal[1];
	}
}

//handle cross-browser reading of CSS-set styles
function getStyle(el,stylename){
	if(el.style[stylename]){
		return el.style[stylename];
	}
	else if(el.currentStyle){
		//handle IE's style-name to styleName convention
		if(stylename.indexOf("-") != -1 && !el.currentStyle[stylename]){
			//get 1st char after -, uppercase, rem -
			var preHyphen = stylename.substr(0,stylename.indexOf("-"));
			var postHyphenFirstLetter = stylename.substr(stylename.indexOf("-")+1,1).toUpperCase();
			var postHyphenRemainder = stylename.substr(stylename.indexOf("-")+2);
			stylename = preHyphen + postHyphenFirstLetter + postHyphenRemainder;
		}
		return el.currentStyle[stylename];
	}
	else if(document.defaultView && document.defaultView.getComputedStyle){
		return document.defaultView.getComputedStyle(el,null).getPropertyValue(stylename);
	}
	else{return false;}
}
//handle cross-browser viewport height
function getViewPortHeight(){
	if(window.innerHeight){
		return window.innerHeight;
	}
	else if(document.documentElement && document.documentElement.clientHeight){
		return document.documentElement.clientHeight;
	}
	else if(document.body){
		return document.body.clientHeight;
	}
	else{return false;}
}
//handle cross-browser retrieval of how far user has scrolled down
function getScrollTop(){
	if(window.pageYOffset){
		return window.pageYOffset;
	}
	else if(document.documentElement && document.documentElement.scrollTop){
		return document.documentElement.scrollTop;
	}
	else if(document.body){
		return document.body.scrollTop;
	}
	else{return false;}
}

//handle cross-browser adding events
function addEvent(obj,evt,fn){
	if(document.addEventListener){
		addEvent = function(obj,evt,fn){
			obj.addEventListener(evt,fn,false);
		}
	}
	else if(document.attachEvent){
		addEvent = function(obj,evt,fn){
			obj["e"+evt+fn] = fn;
			obj[evt+fn] = function() { obj["e"+evt+fn]( window.event ); }
			obj.attachEvent( "on"+evt, obj[evt+fn] );
		}
	}
	else{
		return false;
	}
	addEvent(obj,evt,fn);
}

// returns an absolute x position of the given element object 'o'.
function getAbsoluteX(o) {
	oLeft=o.offsetLeft;            
	while(o.offsetParent!=null) { 
		oParent=o.offsetParent;
		oLeft+=oParent.offsetLeft;
		o=oParent;
	}
	return oLeft;
}
// returns an absolute y position of the given element object 'o'.
function getAbsoluteY(o) {
	oTop=o.offsetTop;            
	while(o.offsetParent!=null) { 
		oParent=o.offsetParent;
		oTop+=oParent.offsetTop;
		o=oParent;
	}
	return oTop;
}
/*End Generic DOM functions*/
// -------------------------------- 
// Detect IE5 Mac 
function isIE5Mac() {
	var ua = navigator.userAgent;
	if (ua.indexOf("Mac") != -1 && ua.indexOf("MSIE 5") != -1) {
		return true;
	} else {
		return false;
	}
}

/*IE5.0 ARRAY PROTOTYPE PUSH*/
if(typeof Array.prototype.push=="undefined"){
	Array.prototype.push=function(item){
		return this[this.length] = item;
	};
}
