//=============================================================================== GLOBAL PATH VARIABLES AND BROWSER DETECTION
//this file contains javascript functions and variables for use on both sides of the site (consumer and admin)

//MODPOINT: modify subdirectory path as needed
var rawPat=document.location.href;
var pat=rawPat.substring(0,rawPat.indexOf("/",8));//at this point, pat = domain name with http:// at the front. this is done this in order to maintain consistency with "www." or lack thereof

var lcPat=rawPat.toLowerCase();
if(lcPat.indexOf("thelabellab.com/exp")!=-1){
	pat=pat+"/exp/";//for use in admin mode
	var cookieDomain="thelabellab.com";
}
else{
	pat="http://wigmag.com/";
	var cookieDomain="wigmag.com";//MODPOINT: modify cookie domain to match the basic domain name of the site (without subdomains, like "www." and without any subdirectories -- just domain name)
}

pat=replacer(pat,"www.","");//inconsistent subdomains can mess up ajax transfers ... so enforce no "www." throughout

//MODPOINT: length of session before timeout in seconds
var sessionInterval=1800;

//browser detection
var ff=false;
var sf=false;
var ie=false;
var op=false
var browserID=navigator.userAgent.toLowerCase();
if(browserID.indexOf("firefox")!=-1||browserID.indexOf("netscape")!=-1)ff=true;
if(browserID.indexOf("safari")!=-1)sf=true;
if(browserID.indexOf("msie")!=-1)ie=true;
if(browserID.indexOf("opera")!=-1){
	op=true;
	ie=false;
}
var sfmac=false;
var sfVer=0;
var sf13=false;
if(sf){
	var plat=navigator.platform;
	if(plat.indexOf("Mac")==0)sfmac=true;
	sfVer=navigator.appVersion;
	sfVer=sfVer.split("WebKit/")[1];
	sfVer=parseFloat(sfVer);
	if(sfVer<400)sf13=true;
}

//idArr schema: [0]=acctID; [1]=profileID; [2]=profUID; [3]=siteList; [4] defaultDir; [5]=user name; [6]=access permission levels
//perm schema: [0]=member, [1]=student, [2]=subscriber, [3]=premium


//============================================================================== COMMENTS

//add user comment to list of related comments (slot [42] in events schema). this is done with an ajax call
function submitComment(){
	var ttl=grab("ttlInput").value;
	var bod=grab("commentBody").value;
	if(idArr.length<4){
		alert("One problem: you must be logged in to comment. Please copy your comment before you log in, since it will be lost when you log in.");//this is rare, only if conducted after timeout
		var commStr=ttl+"~|~"+bod;
		setCookie("commentRescue",commStr);
		return true;
	}
	var aut=idArr[5];
	var src=document.location.href;
	var pagTyp=src.substring(pat.length,src.indexOf(".",pat.length));
	var contentID=src.split("=")[1];
	if(contentID.indexOf("&")!=-1)contentID=contentID.split("&")[0];
	var profileID=0;
	if(idArr.length>2)profileID=idArr[1];
	var commStr=ttl+"~|~"+aut+"~|~"+bod+"~|~"+pagTyp+"~|~"+contentID+"~|~"+profileID;
	var res=doAjax("uploadUserCommentData.php",commStr,finishUserCommentDataUpload);
}

function deleteComment(num){
	var res=doAjax("userCommentDelete.php",num,finishUserCommentDelete);
}

function setComments(){
	var ttlInp=grab("ttlInput");
	var bodInp=grab("commentBody");
	if(ttlInp)ttlInp.value="";
	if(bodInp)bodInp.value="";
}

function drawRelatedComments(wid,hit,max,ownerID){
	var userID=idArr[1];
	if(isNaN(parseInt(userID)))userID=-1;
	if(!max)max=12;
	var txt="<br>";
	var dat=relatedCommentsDat;
	if(dat!=""&&typeof(dat)=="object"){
		uniSort=0;
		dat=dat.sort(reverseUniSort);
		var lim=dat.length;
		if(lim>max)lim=max;
		for(var d=0;d<lim;d++){
			var ttl=dat[d][4];
			var aut=dat[d][6];
			var bod=dat[d][5];
			var img=dat[d][7];
			img=verifyImagePath(img);
			var lnk=dat[d][3];
			var pub=secsToMidStr(dat[d][11]);
			var tim=showTimeofDay(dat[d][11]);
			txt+="<table cellpadding=0 cellspacing=0 border=0><tr><td width=60 valign=top align=center>";
			txt+="<a href=members.php?id="+lnk+"><img style=width:50;height:50;border-color:black src="+img+"></a>";
			txt+="</td><td width="+(wid-70)+">";
			txt+="<span class=navlink style=position:relative;left:0;width:"+(wid-70)+";color:black>"+ttl+"</span><br>";
			txt+="<span class=copy style=position:relative;left:0;width:"+(wid-70)+">From <a href=members.php?id="+lnk+" class=redlinkbold> "+aut+"</a><br>On "+pub+" at "+tim+"</span><p>";
			txt+="<div class=copy style=position:relative;left:0;width:"+(wid-70)+">"+bod+"</div><br><p>";
			var authorID=lnk;
			if((ownerID==userID||authorID==userID)&&(ownerID!=""&&userID!=""&&authorID!=""))txt+="<div class=copy style=position:relative;left:0;width:"+(wid-70)+";color:red;cursor:pointer onclick=deleteComment("+dat[d][0]+")>DELETE</div><br><p>";
			txt+="</td></tr></table>";
			if(d!=dat.length-1)txt+="<img src=images/black.gif width="+wid+" height=1><p>";
		}
	}
	txt+="<img src=images/black.gif width="+wid+" height=1><p>";
	if(typeof(idArr)=="object"&&idArr.length>3){
		txt+="<span class=head style=position:relative;left:10>Add a comment</span><p>";
		txt+="<span class=subtitle style=position:relative;left:10>Title <input id=ttlInput type=text style=position:relative;left:35;width:"+(wid-85)+" value=\"\"></span><p>";
		txt+="<textarea id=commentBody style=position:relative;left:10;width:"+(wid-20)+";height:"+(hit-75)+" class=topbox value=\"\"></textarea><p>";
		txt+="<input id=submitComment type=button style=position:relative;left:"+(wid-160)+"; onclick=submitComment() value=' Send Comment '><br><br><br>";
	}
	else txt+="<center><span class=head>Log in to add a comment</span></center><p>";
	txt="<div class=topbox style=width:"+(wid)+">"+drawHeaderBox("Comments:",txt,(wid),hit)+"</div>";
	return txt;
}


// ============================================================= GENERATE DEFAULT CLASSIFICATION ARRAYS
//MODPOINT: to select which 8 default classifications will be used on this site, adjust the numbers as noted within the loadClassifications() function
//these numbers refer to the numeric position of the various classifications entered and displayed in the superadmin classifciation manager workspace

var classA=new Array();
var classB=new Array();
var classC=new Array();
var classD=new Array();
var classE=new Array();
var classF=new Array();
var classG=new Array();
var classH=new Array();
var classAName="";
var classBName="";
var classCName="";
var classDName="";
var classEName="";
var classFName="";
var classGName="";
var classHName="";

function loadClassifications(){
	if(allClassifications!=""&&typeof(allClassifications)!="undefined"&&allClassifications!="~|~"){
		allClassifications=replacer(allClassifications,"<br />","");
		allClassifications=destring(allClassifications);
		var classADat=allClassifications[6];//MODPOINT: the value 0 is arbitrary, pick the classification you want to assign to classA by number
		if(typeof(classADat)=="object"){
			classAName=classADat[0];
			classAName=replacer(classAName,"_"," ");
			classAValues=classADat[1].toString().split(";");
			for(var c=0;c<classAValues.length;c++){
				classA[c]=new Array(classAValues[c],classAValues[c]);
			}
		}
		var classBDat=allClassifications[7];//MODPOINT: the value 1 is arbitrary, pick the classification you want to assign to classB by number
		if(typeof(classBDat)=="object"){
			classBName=classBDat[0];
			classBName=replacer(classBName,"_"," ");
			classBValues=classBDat[1].toString().split(";");
			for(var c=0;c<classBValues.length;c++){
				classB[c]=new Array(classBValues[c],classBValues[c]);
			}
		}
		var classCDat=allClassifications[2];//MODPOINT: the value 2 is arbitrary, pick the classification you want to assign to classC by number
		if(typeof(classCDat)=="object"){
			classCName=classCDat[0];
			classCName=replacer(classCName,"_"," ");
			classCValues=classCDat[1].toString().split(";");
			for(var c=0;c<classCValues.length;c++){
				classC[c]=new Array(classCValues[c],classCValues[c]);
			}
		}
		var classDDat=allClassifications[3];//MODPOINT: the value 3 is arbitrary, pick the classification you want to assign to classD by number
		if(typeof(classDDat)=="object"){
			classDName=classDDat[0];
			classDName=replacer(classDName,"_"," ");
			classDValues=classDDat[1].toString().split(";");
			for(var c=0;c<classDValues.length;c++){
				classD[c]=new Array(classDValues[c],classDValues[c]);
			}
		}
		var classEDat=allClassifications[4];//MODPOINT: the value 4 is arbitrary, pick the classification you want to assign to classE by number
		if(typeof(classEDat)=="object"){
			classEName=classEDat[0];
			classEName=replacer(classEName,"_"," ");
			classEValues=classEDat[1].toString().split(";");
			for(var c=0;c<classEValues.length;c++){
				classE[c]=new Array(classEValues[c],classEValues[c]);
			}
		}
		var classFDat=allClassifications[5];//MODPOINT: the value 5 is arbitrary, pick the classification you want to assign to classF by number
		if(typeof(classFDat)=="object"){
			classFName=classFDat[0];
			classFName=replacer(classFName,"_"," ");
			classFValues=classFDat[1].toString().split(";");
			for(var c=0;c<classFValues.length;c++){
				classF[c]=new Array(classFValues[c],classFValues[c]);
			}
		}
		var classGDat=allClassifications[6];//MODPOINT: the value 6 is arbitrary, pick the classification you want to assign to classG by number
		if(typeof(classGDat)=="object"){
			classGName=classGDat[0];
			classGName=replacer(classGName,"_"," ");
			classGValues=classGDat[1].toString().split(";");
			for(var c=0;c<classGValues.length;c++){
				classG[c]=new Array(classGValues[c],classGValues[c]);
			}
		}
		var classHDat=allClassifications[7];//MODPOINT: the value 7 is arbitrary, pick the classification you want to assign to classH by number
		if(typeof(classHDat)=="object"){
			classHName=classHDat[0];
			classHName=replacer(classHName,"_"," ");
			classHValues=classHDat[1].toString().split(";");
			for(var c=0;c<classHValues.length;c++){
				classH[c]=new Array(classHValues[c],classHValues[c]);
			}
		}
	}
	return true;
}

//========================================================= SORTABLE TABLES
//utilities for sortable tables used in admin menues. key to parameters for getFullTableHTML() is as follows:
//nam=handle for table; typ=name of workspace (i.e Account, Story); srcArrLit=literal name of global src array; colWids=array of column widths; colNames=array of column names; 
//slotNums=array of col numbers for src data; opps=literal name for processing function, blank if none; sortCol=number of the column in the src array that the data should be sorted by

var sortDirs=new Array();

function getFullTableHTML(nam,typ,srcArrLit,colWids,colNames,slotNums,opps,sortCol){
	if(!sortCol)sortCol=0;
	sortDirs=new Array();
	sortDirs[sortCol]=1;
	var wid=0;
	for(var c=0;c<colWids.length;c++){
		wid+=colWids[c];
	}
	var hed=getTableHeaderHTML(nam,colWids,colNames,slotNums);
	var bod=getTableBodyHTML(nam,typ,srcArrLit,colWids,slotNums,opps,sortCol,1);
	txt="<br><span class=copy style=position:relative;left:30px;cursor:pointer;color:red onclick=load"+typ+"Workspace('new')>NEW "+typ.toUpperCase()+"</span><br>";
	txt+=hed;
	txt+="<div id="+nam+"TableHolder class=tablebodyholder>";
	txt+=bod;
	txt+="</div>";
	txt+="<input type=hidden id="+nam+"typ value='"+typ+"'>";
	txt+="<input type=hidden id="+nam+"srcArrLit value='"+srcArrLit+"'>";
	txt+="<input type=hidden id="+nam+"colWids value='"+colWids.toString()+"'>";
	txt+="<input type=hidden id="+nam+"colNames value='"+colNames.toString()+"'>";
	txt+="<input type=hidden id="+nam+"slotNums value='"+slotNums.toString()+"'>";
	txt+="<input type=hidden id="+nam+"opps value='"+opps.toString()+"'>";
	return txt;
}

function getTableHeaderHTML(nam,colWids,colNames,slotNums){
	var txt="<table id="+nam+"TableHeader cellpadding=0 cellspacing=5 border=0 style=position:relative;left:25><tr><td class=subtitle width=39> &nbsp; </td><td class=subtitle width=26> &nbsp; </td>";
	for(var c=0;c<colWids.length;c++){
		txt+="<td class=tablehead width="+colWids[c]+" onclick=sortTable('"+nam+"',"+slotNums[c]+")>"+colNames[c]+"</td>";
	}
	txt+="</tr></table>";
	return txt;
}

function getTableBodyHTML(nam,typ,srcArrLit,colWids,slotNums,opps,sortCol,dir){
	var arr=eval(srcArrLit);
	uniSort=sortCol;
	if(dir==1)arr=arr.sort(uniSorter);
	else arr=arr.sort(reverseUniSort);
	var txt="<table cellpadding=0 cellspacing=5 border=0 style=position:relative;left:25>";
	for(var a=0;a<arr.length;a++){
		var rowDat=arr[a];
		txt+="<tr>";
		var uID="0";
		if(typ=="Story")uID=rowDat[35];
		if(typ=="Event")uID=rowDat[43];
		if(typ=="Account")uID=rowDat[2];
		if(uID=="")uID=0;
		txt+="<td class=copy width=39 align=center style=color:red;cursor:pointer onclick='delete"+typ+"("+rowDat[0]+","+uID+")'>DELETE</td>";
		if(typ=="Account")uID=rowDat[44];
		txt+="<td class=copy width=26 align=center style=color:red;cursor:pointer onclick='setup"+typ+"Edit("+rowDat[0]+","+uID+")'>EDIT</td>";
		for(var w=0;w<colWids.length;w++){
			var cont=rowDat[slotNums[w]];
			if(opps[w]!=""){
				cont=eval(opps[w]+"(\""+cont+"\")");
			}
			if(cont=="")cont="&nbsp;";
			txt+="<td class=menucell width="+colWids[w]+"><nobr>"+cont+"</nobr></td>";
		}
		txt+="</tr>";
	}
	txt+="</table>";
	return txt;
}

function sortTable(nam,sortCol){
	sortCol=parseInt(sortCol);
	var dir=sortDirs[sortCol];
	if(typeof(dir)=="undefined"||!dir||dir==-1)dir=1;
	else dir=-1;
	sortDirs[sortCol]=dir;
	var typ=grab(nam+"typ").value;
	var srcArrLit=grab(nam+"srcArrLit").value;
	var colWids=grab(nam+"colWids").value.split(",");
	var colNames=grab(nam+"colNames").value.split(",");
	var slotNums=grab(nam+"slotNums").value.split(",");
	var opps=grab(nam+"opps").value.split(",");
	var newTableGuts=getTableBodyHTML(nam,typ,srcArrLit,colWids,slotNums,opps,sortCol,dir);
	var tableHolder=grab(nam+"TableHolder");
	tableHolder.innerHTML=newTableGuts;
	return true;
}


// =============================================================== CONSUMER PAGE ELEMENTS

function drawSearchWidget(cA,cANam,cB,cBNam,cC,cCNam,srcMod){
	var txt="<img src=images/blank.gif width=700 height=10><br>";
	txt+="<div id=searchWidget style=position:relative;width:781;height:85;background-color:A80201>";
	var resultHeader="Search Results "+termView;
	if(srcMod=="events")resultHeader="Events";
	if(srcMod=="stories")resultHeader="Journals";
	if(srcMod=="members")resultHeader="Members";
	if(srcMod=="bands")resultHeader="Bands";
	txt+="<div id=blackTitle class=blacktitle style=position:relative;width:782;height:30><span style=position:relative;top:6;left:12;>"+resultHeader+"</span></div>";
	txt+=getTextEntryHTML("keywordSearch","Keywords",10,39,165,22,1,"",'',"");
	if(cA){
		var newA=new Array(new Array(-1,"")).concat(cA);
		txt+=getDropdownHTML("classASearch",cANam,185,39,165,20,1,-1,newA,"");
	}
	if(cB){
		var newB=new Array(new Array(-1,"")).concat(cB);
		txt+=getDropdownHTML("classBSearch",cBNam,360,39,165,20,1,-1,newB,"");
	}
	if(cC){
		var newC=new Array(new Array(-1,"")).concat(cC);
		txt+=getDropdownHTML("classCSearch",cCNam,535,39,165,20,1,-1,newC,"");
	}
	txt+="<input type=button value='Search' style=position:absolute;left:705;top:51;height:22 onclick=doSearch()>";
	txt+="</div>";
	var pageLengthDropdownHTML=getDropdownHTML("pageLength","",700,4,65,20,1,defPageLength,pageLengths,"setPageLength");
	txt+="<div style=position:relative;background-color:A80201>";
	txt+="<span class=subtitle><nobr><img src=images/blank.gif width:10 height=18>Display by </span>";
	txt+="<span class=redlinkbold>";
	txt+="  <span onclick=doNewestSort()>Newest</span> | <span onclick=doNameSort()>Name A-Z</span>";
	txt+="</span>";
	txt+="<span class=subtitle style=position:absolute;left:585;top:7>Results per Page </span>";
	txt+=pageLengthDropdownHTML;
	txt+="</nobr><br><img src=images/blank.gif width:700 height=10><br>";
	txt+="<img src=images/black.gif width=781 height=1>";
	txt+="</div>";
	return txt;
}

function drawHeaderBox(hed,bod,wid,hit){
	var txt="<table width="+wid+" height="+hit+" cellpadding=0 cellspacing=0 border=0>";
	txt+="<tr><td class=headerboxhead height=28 valign=middle>&nbsp; "+hed+"</td></tr>";
	txt+="<tr><td valign=top>"+bod+"</td></tr>";
	txt+="</table>";
	return txt;
}

function drawHeaderBoxCentered(hed,bod,wid,hit){
	var txt="<center><div class=topbox style=width:"+wid+";height:"+hit+";text-align:left;overflow-y:hidden><table width="+wid+" height="+hit+" cellpadding=0 cellspacing=0 border=0>";
	txt+="<tr><td class=headerboxhead height=28 valign=middle align=center>&nbsp; "+hed+"</td></tr>";
	txt+="<tr><td valign=top>"+bod+"</td></tr>";
	txt+="</table></div></center>";
	return txt;
}

//hilite navigation tabs on the user admin page
function hiliteUserTabs(tb){
	for(var t=0;t<3;t++){
		var curTab=document.getElementById("userTab"+t);
		if(t!=tb)curTab.style.borderBottomColor="black";
		else curTab.style.borderBottomColor="EE6D1A";
	}
}

//================================================================= DISPLAYS BASED ON CLASSIFICATION DATA
//the term "cat" is frequently misused to refer to classifications
//this had some weirdness left over from an earlier version ... originally, all class arrays had a literal of their source array in the [0] position. 
//they still do in some cases, but the src array is sent along separately now. array names are filtered out below, if/when they appear in the [0] position

function drawCatColumn(){
	var txt="<div leftNavHolder style=position:relative;left:0;top:0;height:550>";
	txt+="<div class=sectionhead style=position:relative;left:10;top:15;color:white>W.i.g Directory:<br></div>";
	txt+="<div style=position:relative;left:10;top:15>";
	var linkStyle=" class=redbullet";
	var listStyle="";
	if(ie){
		linkStyle="";
		listStyle=" class=redbullet";
	}
	for(var c=0;c<classA.length;c++){
		txt+="<a href='search.php?mod=all&term=&clsA="+classA[c][1]+"&clsB='"+linkStyle+"><br><span"+listStyle+">"+classA[c][1]+"</span></a>";
	}
	txt+="<div style=position:relative;left:10;top:15;border-color:black><a href=http://www.twitter.com/wigmag><img src=/images/twittericon.png border=0></a><a href=feed.php>&nbsp;&nbsp;&nbsp;<img src=/images/rss.png border=0></a></div>";
	txt+="<div style=position:relative;left:10;top:15;border-color:black><a href=http://www.emailbrain.com/rwcode/subscribe.asp?SiteID=106548&amp;Mode=subscribe target=_blank><br><font face=arial size=2 color=red><b>Sign-up for our FREE <br>Weekly Newsletter</b></font></a></div>";
	txt+="</div>";
	txt+="</div>";
	
	return txt;
}

function drawTourColumn(tour){
	var dates=tour.split(",");
	var txt="";
	for(var d=0;d<dates.length;d++){
		var da=dates[d];
		if(da!="classA"&&da!="classB"&&da!="classC"&&da!="classD"&&da!="classE"&&da!="classF"&&da!="classG"&&da!="classH"){
			txt+="<a href='search.php?mod=all&clsA="+da+"'>"+da+"</a><br>";
		}
	}
	return txt;
}

function drawBandColumn(bands){
	var bands=bands.split(",");
	var txt="";
	for(var b=0;b<bands.length;b++){
		var ba=bands[b];
		if(ba!="classA"&&ba!="classB"&&ba!="classC"&&ba!="classD"&&ba!="classE"&&ba!="classF"&&ba!="classG"&&ba!="classH"){
			txt+="<a href='search.php?mod=all&clsB="+ba+"'>"+ba+"</a><br>";
		}
	}
	return txt;
}

function getCatNames(cats,src){
	if(typeof(cats)!="string"||cats=="")return "";
	cats=cats.split(",");
	if(typeof(cats)!="object"||cats.length<2)return "";
	if(!src)src=eval(cats[0]);
	var txt="";
	if(typeof(src)!="undefined"){
		for(var s=1;s<cats.length;s++){
			if(typeof(src[cats[s]])=="object"){
				var testTerm=src[cats[s]][1];
				if(testTerm!="classA"&&testTerm!="classB"&&testTerm!="classC"&&testTerm!="classD"&&testTerm!="classE"&&testTerm!="classF"&&testTerm!="classG"&&testTerm!="classH"){
					txt+=src[cats[s]][1];
					if(s!=cats.length-1)txt+=" - ";
				}
			}
		}
	}
	return txt;
}


// ================================================================ AJAX TESTING AND MONITORING FUNCTIONS
//there is a problem on IE only with ajax uploads leading to failed transfers about 15% of the time. 
//this has been patched by using monitoring functions that reinitiate failed transfers
//there is a large amount of monitoring code left in place in case further testing is required

//the following monitoring variables and functions are necessary:

var ajaxClockID=0;
var ajaxSafeData=new Array();

function startAjaxClock(fName,paramStr,callback){
	ajaxSafeData[0]=fName;
	ajaxSafeData[1]=paramStr;
	ajaxSafeData[2]=callback;
	ajaxClockID=setTimeout("resetAjaxCall()",3000);
}

function stopAjaxClock(){
	clearTimeout(ajaxClockID);
	ajaxClockID=0;
	ajaxSafeData=new Array();
}

function resetAjaxCall(){
	var res=req.abort();
	req=false;
	doAjax(ajaxSafeData[0],ajaxSafeData[1],ajaxSafeData[2]);
	doAjaxReport("K","RESET");
}

//the following test reporting variables and functions may be removed, but they are integrated throughout the ajax code, so do so carefully

var ajaxReport="";
var aST=0;

function doAjaxReport(let,val){
	if(typeof(val)=="undefined")val="";
	if(typeof(val)=="string")val=val.substring(0,1000);
	if(let=="A"){
		aST=Math.round((new Date().getTime())/1000);
		ajaxReport="A("+val+")0: ";
	}
	else{
		var aCT=Math.round((new Date().getTime())/1000);
		aCT=aCT-aST;
		ajaxReport+=let+"("+val+")"+aCT+": ";
	}
}

function showAjaxReport(){
	alert(ajaxReport);
}


// ================================================================ AJAX TRANSFERS

var req=false;

//this function conducts all ajax transfers. all data is uploaded in a single string (paramStr) which is captured by a server variable called "dat"
function doAjax(fName,paramStr,callback){
	document.close();
	if(!callback)return true;
	if(ie)startAjaxClock(fName,paramStr,callback)
	//doAjaxReport("A");
	req=false;
	if(window.XMLHttpRequest)req=new XMLHttpRequest(); 
	else if(window.ActiveXObject)req=new ActiveXObject("MSXML2.XMLHTTP.3.0");
	//doAjaxReport("B");
	var ajaxURL=pat+fName;
	if(fName.indexOf("control/data/")==-1)ajaxURL=pat+"control/data/"+fName;
	paramStr="dat="+paramStr;
	//doAjaxReport("C");
	req.open("POST",ajaxURL,true);
	req.timeout=10000;
	req.onreadystatechange=callback;
	req.setRequestHeader("Content-type","application/x-www-form-urlencoded");
	req.setRequestHeader("Content-length",paramStr.length);
	req.setRequestHeader("Connection", "close");
	//doAjaxReport("D");
	req.send(paramStr);
	//doAjaxReport("E");
	return true;
}

//the following functions are ajax callback functions, which capture and process data returned from ajax calls
//they contain lots of testing and monitoring code, some of which is non-essential, but harmless to leave in place
//to diagnose problems with an ajax call, uncomment the alert statement in the related callback function to 
//see data coming back from the server

function finishGetSingleAccount(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G",req.status);
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I",req.readyState);
		return false;
	}
	doAjaxReport("J",res);
	stopAjaxClock();
	//alert("raw single account data: "+res)
	var rawDat=res.split("%");
	var accountDat=destring(rawDat[0]);
	var profileDat=destring(rawDat[1]);
	accountsSrc=accountDat[0];
	profilesSrc=profileDat[0];
	var res=loadAccountWorkspace('old');
}

function finishGetSingleStory(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G",req.status);
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I",req.readyState);
		return false;
	}
	doAjaxReport("J",res);
	stopAjaxClock();
	var storyDat=destring(res);
	storiesSrc=storyDat[0];
	var res=loadStoryWorkspace('old');
}

function finishGetSingleEvent(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G",req.status);
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I",req.readyState);
		return false;
	}
	doAjaxReport("J",res);
	stopAjaxClock();
	var eventDat=destring(res);
	eventsSrc=eventDat[0];
	var res=loadEventWorkspace('old');
}

function finishGetSingleComment(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G",req.status);
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I",req.readyState);
		return false;
	}
	doAjaxReport("J",res);
	stopAjaxClock();
	var commentDat=destring(res);
	commentsSrc=commentDat[0];
	var res=loadCommentWorkspace('old');
}

function finishUserCommentDelete(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G",req.status);
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I",req.readyState);
		return false;
	}
	doAjaxReport("J",res);
	stopAjaxClock();
	//alert("From delete user comment: "+res);
	location.reload();
}

function finishAddMyName(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G",req.status);
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I",req.readyState);
		return false;
	}
	doAjaxReport("J",res);
	stopAjaxClock();
	//alert("From addMyName(): "+res);
	location.reload();
}

function finishUserCommentDataUpload(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G",req.status);
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I",req.readyState);
		return false;
	}
	doAjaxReport("J",res);
	//alert(res);
	stopAjaxClock();
	location.reload();
}

function finishStoryDataUpload(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G",req.status);
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I",req.readyState);
		return false;
	}
	doAjaxReport("J",res);
	stopAjaxClock();
	if(res){
		allStories=destring(res);
		//allStories=clearDupes(allStories,35);
	}
	var res=loadStoryMenu();
}

function finishConsumerStoryDataUpload(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G",req.status);
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I",req.readyState);
		return false;
	}
	doAjaxReport("J",res);
	stopAjaxClock();
	//alert(res);
	relStories=destring(res);
	relStories=clearDupes(relStories,35);
	var res=loadStoryMenu();
}

function finishAccountDataUpload(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G");
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I");
		return false;
	}
	doAjaxReport("J");
	stopAjaxClock();
	//alert(res);
	res=res.split("@|@");
	allAccounts=destring(res[0]);
	allProfiles=destring(res[1]);
	allProfiles=clearDupes(allProfiles,44);
	var res=loadProfileMenu();
}

function finishConsumerAccountDataUpload(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G");
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I");
		return false;
	}
	doAjaxReport("J");
	stopAjaxClock();
	//alert(res);
	if(res=="Bad account name."){
		alert("Oh yeah, sorry. Account name must be 3 characters or longer.");
		return true;
	}
	if(res=="Bad password."){
		alert("Oh yeah, sorry. Password must be 6 characters or longer.");
		return true;
	}
	if(res!=""&&res!=""){
		res=res.split("@|@");
		acctDat=destring(res[0]);
		acctDat=acctDat[0];
		profDat=destring(res[1]);
		profDat=profDat[0];
		var newProfUID=profDat[44];
		idArr[2]=newProfUID;
		//idStr schema: [0]=acctID; [1]=profileID; [2]=profUID; [3]=siteList; [4] defaultDir; [5]=user name; [6]=access permission levels
		idStr=idArr[0]+"~|~"+idArr[1]+"~|~"+idArr[2]+"~|~"+idArr[3]+"~|~"+idArr[4]+"~|~"+idArr[5]+"~|~"+idArr[6];
		setCookie("idStr2",idStr);
		setupProfilePreview();
	}
}

function finishAccountDelete(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G");
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I");
		return false;
	}
	doAjaxReport("J");
	stopAjaxClock();
	//alert(res);
	if(res=="no such account.")alert("Account does not exist.");
	else{
		res=res.split("@|@");
		allAccounts=destring(res[0]);
		allProfiles=destring(res[1]);
		allProfiles=clearDupes(allProfiles,44);
	}
	var res=loadProfileMenu();
}

function finishPhotoDataUpload(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G");
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I");
		return false;
	}
	doAjaxReport("J");
	stopAjaxClock();
	//alert(res);
	allPhotos=destring(res);
	var res=loadPhotoMenu();
}

function finishPhotoDelete(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G");
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I");
		return false;
	}
	doAjaxReport("J");
	stopAjaxClock();
	//alert(res);
	allPhotos=destring(res);
	var res=loadPhotoMenu();
}

function finishStoryDelete(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G");
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I");
		return false;
	}
	doAjaxReport("J");
	stopAjaxClock();
	//alert("Deleted story, result: "+res);
	if(res){
		allStories=destring(res);
		allStories=clearDupes(allStories,35);
	}
	var res=loadStoryMenu();
}

function finishConsumerStoryDelete(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G");
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I");
		return false;
	}
	doAjaxReport("J");
	stopAjaxClock();
	//alert("Deleted consumer story, result: "+res);

	relStories=destring(res);
	var res=loadStoryMenu();
}

function finishEventDataUpload(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G");
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I");
		return false;
	}
	doAjaxReport("J");
	stopAjaxClock();
	//alert(res);
	if(res){
		allEvents=destring(res);
		allEvents=clearDupes(allEvents,43);
	}
	var res=loadEventMenu();
}

function finishEventDelete(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G");
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I");
		return false;
	}
	doAjaxReport("J");
	stopAjaxClock();
	//alert(res);
	if(res){
		allEvents=destring(res);
		allEvents=clearDupes(allEvents,43);
	}
	var res=loadEventMenu();
}

function finishCommentDataUpload(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G");
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I");
		return false;
	}
	doAjaxReport("J");
	stopAjaxClock();
	//alert(res);
	allComments=destring(res);
	var res=loadCommentMenu();
}

function finishCommentDelete(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G");
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I");
		return false;
	}
	doAjaxReport("J");
	stopAjaxClock();
	//alert(res);
	allComments=destring(res);
	var res=loadCommentMenu();
}

function finishCreateNewClassification(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G");
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I");
		return false;
	}
	doAjaxReport("J");
	stopAjaxClock();
	//alert("Result from creating new classification: "+res);
	allClassifications=destring(res);
	var res=loadClassificationManager();
}

function finishUpdateClassification(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G");
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I");
		return false;
	}
	doAjaxReport("J");
	stopAjaxClock();
	res=replacer(res,"\n","");
	//alert(res);
	allClassifications=destring(res);
	var res=loadClassificationManager();
}

function finishClassificationDelete(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G");
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I");
		return false;
	}
	doAjaxReport("J");
	stopAjaxClock();
	//alert(res);
	allClassifications=destring(res);
	var res=loadClassificationManager();
}

function finishCreateNewDirectory(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G");
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I");
		return false;
	}
	doAjaxReport("J");
	stopAjaxClock();
	//alert(res);
	dirList[dirList.length]=new Array(res,res);
	var cont=grab("chooseImageDirDiv");
	var txt=getDropdownGuts("chooseImageDir","","","",320,22,12,res,dirList,"getImageDirContents");
	cont.innerHTML=txt;
}

function finishGetFilesInDir(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G");
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I");
		return false;
	}
	doAjaxReport("J");
	stopAjaxClock();
	//alert(res);
	res=destring(res);
	var fileArr=res[0];
	var pat=res[1];
	var resArr=new Array();
	for(var f=0;f<fileArr.length;f++){
		var fNam=fileArr[f];
		if(fNam)resArr[resArr.length]=new Array(f,pat+"/"+fileArr[f],fileArr[f]);
	}
	imgLibrary=resArr;
	var ret=showNewImageGallery(resArr);
}

function finishSettingSiteList(){
	doAjaxReport("F");
	if(req.readyState==4){
		if(req.status==200){
			doAjaxReport("G");
			var res=req.responseText;
			if(res=="Empty upload")return true;
		}
		else{
			doAjaxReport("H");
			return false;
		}
	}
	else{
		doAjaxReport("I");
		return false;
	}
	doAjaxReport("J");
	stopAjaxClock();
	alert("Finished setting site list: "+res);
	activeSiteList=replacer(res,"\n","");
	location.reload();
}


// =============================================================== MISCELLANEOUS UTILITIES

function verifyImagePath(imgPat){
	if(!imgPat||imgPat=="-1"||imgPat==-1||imgPat.toString().indexOf("blank.gif")!=-1)imgPat="images/fakeIcon.gif";
	return imgPat;
}

//idArr schema: [0]=acctID; [1]=profileID; [2]=profUID; [3]=siteAccess; [4] defaultDir; [5]=user name; [6] access permissions
//perm schema: [0]=member, [1]=student, [2]=subscriber, [3]=premium

//on loading of page, establish idArr, an array of user identity data, and perm, an array of permissions
var idArr="";
var perm="";

function getUserData(){
	var now=new Date();
	now=now.getTime();
	var newEndTime=now+(sessionInterval*1000);

	//alert("Getting user data, starting with idStr="+idStr);

	idArr=idStr.split("~|~");

	//alert("Getting user data. idArr is: [0]="+idArr[0]+", [1]="+idArr[1]+", [2]="+idArr[2]+", [3]="+idArr[3]+", [4]="+idArr[4]+", [5]="+idArr[5]+", [6]="+idArr[6]); 

	if(typeof(idArr)=="object"&&idArr.length>3&&typeof(idArr[5])!="undefined"&&idArr[5]!=""){//if valid data from server

		//alert("1. Received valid data from server, setting cookie idStr2 to "+idStr+"; and setting sessExp2 to "+newEndTime);

		var ret=setCookie("idStr2",idStr);//save id data
		var ret=setCookie("sessExp2",newEndTime);//set new expiration time
		drawLoginStatus();
	}
	else{//if not valid data from server

		//alert("2. Received no data from server, getting cookie idStr2, it is: "+getCookie("idStr2")+"; and getting sessExp2, it is: "+getCookie("sessExp2"));

		var storedEndTime=getCookie("sessExp2");//get stored end time
		if(!storedEndTime)storedEndTime=0;
		if(now>storedEndTime){//if expired
			var res=drawPasswordUI();
			var pwdInput=grab("pwdInput");
			var usrInput=grab("nameInput");
			var selInput=pwdInput;
			if(usrInput.value=="")selInput=usrInput;
			selInput.select();
			selInput.focus();
			idArr=new Array("NODAT",0);
			var curLoc=document.location.href;
			if(curLoc.indexOf("main.php")!=-1||curLoc.indexOf("account.php")!=-1){
				alert("Session has timed out.");
				document.location.href="index.php";
			}
		}
		else{//if not expired
			var ret=setCookie("sessExp2",newEndTime);//set new expiration time
			idStr=getCookie("idStr2");
			idArr=idStr.split("~|~");
			drawLoginStatus();
		}
	}
	var reason=idArr[1];
	if(reason=="BADPASS")alert("It appears your password was incorrect. Do give it another try.");
	if(reason=="NOACCT")alert("Unfortunately, we don't have an account by that name. Perhaps you mistyped it?");
	if(reason=="NOVERIFY")alert("Sorry for the inconvenience, but we must still verify your account. Please check your e-mail for a message containing a verification link.");
	perm=setPerms(idArr[6]);
	return true;
}

//this converts the integer storage version of the permission value into a perm array
function setPerms(pVal){
	var resArr=new Array;
	var pStr=integerDecode(pVal);
	for(var r=0;r<8;r++){
		if(pStr.indexOf(r.toString())!=-1)resArr[r]=1;
	}
	return resArr;
}

//this returns true only if the "offense" permission array has a 1 at every position where the "defense" permission array requires one
function matchPerms(off,def){
	if(typeof(off)=="undefined")off=new Array(0);
	var res=true;
	for(var d=0;d<def.length;d++){
		if(def[d]==1&&off[d]!=1)res=false;
	}
	return res;
}

//when data comes down to super admin from multiple sites, there may be multiple listings of content with identical uIDs
//this function removes the duplicates
function clearDupes(arr,col){
	var newArr=new Array();
	if(typeof(arr)!="object")return newArr;
	uniSort=col;
	arr=arr.sort(uniSorter);
	var n=0;
	var oldTestTerm="khdsb9i8576vkdnrtglkfhb";
	for(var a=0;a<arr.length;a++){
		var curArr=arr[a];
		var newTestTerm=curArr[col];
		if(newTestTerm!=oldTestTerm&&typeof(curArr)=="object"){
			newArr[n]=curArr;
			n++;
			oldTestTerm=newTestTerm;
		}
	}
	return newArr;
}

function grab(cont){
	return document.getElementById(cont);
}

function kd(ev,x,y){
	//this function does nothing and is not needed. but it is called occasionally by Safari browsers, so it remains, 99% sure it can be safely remoived from iPage.html
}

//returns the array position number of an item in an array that has a value in the zero position matching the given key
function getIndexByKey(arr,key){
	for(var a=0;a<arr.length;a++){
		if(arr[a][0]==key)return a;
	}
	return -1;
}

function getIndexBySlotValue(arr,slot,key){
	for(var a=0;a<arr.length;a++){
		if(arr[a][slot]==key)return a;
	}
	return -1;
}

//returns a full row from an array with a value in the zero position matching the given key
function getRowByKeyTerm(arr,key){
	for(var a=0;a<arr.length;a++){
		if(arr[a][0]==key)return arr[a];
	}
	return -1;
}

function getRowBySlotValue(arr,slot,key){
	for(var a=0;a<arr.length;a++){
		if(arr[a][slot]==key)return arr[a];
	}
	return -1;
}

//unpacks serialized 2-level array from server. Always returns a 2-level array, even if a 1-level array string was passed to it.
function destring(str){
	if(!str)return "";
	str=str.toString();
	str=unescape(str);
	str=deleteBadChars(str);
	var resArr=new Array;
	if(str.indexOf("^|^")!=-1){
		str=str.split("^|^");
		for(var s=0;s<str.length;s++){
			resArr[s]=str[s].split("~|~");
		}
	}
	else resArr[0]=tempArr=str.split("~|~");
	return resArr;
}

function startup(){
}

function deleteBadChars(txt){
	var bad=String.fromCharCode(65533);
	if(txt.indexOf(bad)!=-1)txt=replacer(txt,bad,"\'");
	return txt;
}

//shortens a string to no more than maximum length
function truncator(str,len){
	if(typeof(str)!="string")return str;
	if(str.length<len)return str;
	return str.substring(0,len-4)+ " ...";
}

//shortens a string to no more than maximum length, showing the end only
function endTruncator(str,len){
	if(typeof(str)!="string")return str;
	if(str.length<len)return str;
	var diff=str.length-len;
	return "... "+str.substring(diff+4);
}

//shortens a string to no more than maximum length, and rounds to last space, adds ellipsis points
function spaceTrunc(str,len){
	if(typeof(str)!="string")return str;
	if(str.length<len)return str;
	var shortStr=str.substring(0,len-3);
	shortStr=shortStr.substring(0,shortStr.lastIndexOf(" "));
	return shortStr+ " ...";
}

//shortens a string to no more than maximum length, and rounds to last space, without ellipsis points
function chopTrunc(str,len){
	if(typeof(str)!="string")return str;
	if(str.length<len)return str;
	var shortStr=str.substring(0,len-3);
	shortStr=shortStr.substring(0,shortStr.lastIndexOf(" "));
	return shortStr;
}

function midTrunc(txt){
	return truncator(txt,40);
}

function pathTrunc(txt){
	return endTruncator(txt,35);
}

function shortTrunc(txt){
	return truncator(txt,25);
}

function midEndTrunc(txt){
	return endTruncator(txt,40);
}

function longEndTrunc(txt){
	return endTruncator(txt,60);
}

function idTrunc(idNum){
	var txt=idNum.toString();
	var len=txt.length;
	if(len>=6)txt=txt.substring(len-6);
	else{
		for(var c=0;c<6;c++){
			txt="0"+txt;
			if(txt.length>=6)break;
		}
	}
	return txt;
}

//replaces specified characters ... there may be a better version of this in SVC code
function replacer(srcStr,oldStr,newStr){
	if(typeof(srcStr)!="string")return srcStr;
	var oldLen=oldStr.length
	var diff=oldLen-newStr.length;
	for(var s=srcStr.length-oldLen;s>=0;s--){
		var testStr=srcStr.substring(s,s+oldLen);
		if(testStr==oldStr)srcStr=srcStr.substring(0,s)+newStr+srcStr.substring((s+oldLen),srcStr.length);
	}
	return srcStr;
}

//used to prevent ugly shit from getting into into the client javascript
function javafilt(txt){
	if(txt=="\'\'")return txt;
	txt=replacer(txt,"'","’");
	return txt;
}

//used to prevent ugly shit from going up into the database -- but can also be used to prevent bad javascript
function safer(txt){
	//txt=replacer(txt,"\\","");
	//txt=replacer(txt,"&","&amp;");
	txt=replacer(txt,"'","\'");
	txt=replacer(txt,"’","\'");
	txt=replacer(txt,"”","\"");
	txt=replacer(txt,"“","\"");
	//txt=replacer(txt,"<","&lt;");
	//txt=replacer(txt,">","&gt;");
	return txt;
}

//convert stories with escaped HTML into real HTML
function convertToHTML(txt){
	txt=replacer(txt,"&lt;","<");
	txt=replacer(txt,"&gt;",">");
	txt=replacer(txt,"&quot;","'");
	return txt;
}

//removes HTML code from text ... primarily for displaying story summaries
function removeHTML(str){
	if(typeof(str)!="string"||str=="")return "";
	var txt="";
	for(var s=str.length-1;s>=0;s--){
		if(str.charAt(s)=="<"){
			var ep=str.lastIndexOf(">");
			str=str.substring(0,s)+str.substring(ep+1);
		}
	}
	return str;
}

//removes bracketed image numbers from text
function removeBrackets(str){
	if(typeof(str)!="string"||str=="")return "";
	var txt="";
	for(var s=str.length-1;s>=0;s--){
		if(str.charAt(s)=="["){
			var ep=str.lastIndexOf("]");
			str=str.substring(0,s)+str.substring(ep+1);
		}
	}
	return str;
}

//removes HTML that has been converted to safe HTML by use of &gt; and &lt;
function removeFakeHTML(str){
	if(typeof(str)!="string"||str=="")return "";
	var txt="";
	for(var s=str.length-1;s>=0;s--){
		if(str.substring(s,s+4)=="&lt;"){
			var ep=str.lastIndexOf("&gt;");
			str=str.substring(0,s)+str.substring(ep+4);
		}
	}
	return str;
}

//converts seconds into fullmonth date, year (4-digit)
function secsToStr(secs){
	secs=parseInt(secs);
	if(isNaN(secs))return "";
	secs=secs*1000;
	var dat=new Date(secs);
	var mon=dat.getMonth();
	mon=months[mon];
	var num=dat.getDate();
	var yer=dat.getYear();
	if(yer<200)yer+=1900;
	return mon+" "+num+", "+yer;
}

//converts seconds into abbrvmonth date, year (2-digit)
function secsToMidStr(secs){
	secs=parseInt(secs);
	if(isNaN(secs))return "";
	secs=secs*1000;
	var dat=new Date(secs);
	var mon=dat.getMonth();
	mon=months[mon];
	mon=mon.substring(0,3);
	var num=dat.getDate();
	var yer=dat.getYear();
	yer=yer.toString().substring(2,4);
	if(yer.length==1)yer="0"+yer;
	return mon+" "+num+", "+yer;
}

//converts seconds into abbrvmonth-date
function secsToShortStr(secs){
	secs=parseInt(secs);
	if(isNaN(secs))return "";
	secs=secs*1000;
	var dat=new Date(secs);
	var mon=dat.getMonth();
	mon=months[mon];
	mon=mon.substring(0,3);
	var num=dat.getDate();
	return mon+"-"+num;
}

//convert seconds into time of day
function showTimeofDay(secs){
	var dat=new Date(secs*1000);
	var hr=dat.getHours();
	var mn=dat.getMinutes();
	if(mn<10)mn="0"+mn;
	var mr="AM";
	if(hr>12){
		hr-=12;
		var mr="PM";
	}
	if(hr==0)hr=12;
	return hr+":"+mn+" "+mr;
}


// ======================= login widget

//this adds HTML for appropriate log-in widget to a dedicated container in the masthead
function drawLoginStatus(){
	var holder=grab("passHolder");
	var tp=21;
	var lf=-196;
	var txt="<div class=whitesubtitle style=position:absolute;top:"+tp+";left:"+lf+";width:395;text-align:right;><nobr>Logged in as "+idArr[5]+". &nbsp;<input  style=position:absolute;top:-6; type=button value='Log out' onclick=logout()></div></nobr>";
	if(holder)holder.innerHTML=txt;
	var res=showAccountLink();
}

//this adds the link to "My Account" in the nav bar when a user is logged in
function showAccountLink(){

	//idArr schema: [0]=acctID; [1]=profileID; [2]=profUID; [3]=siteAccess; [4] defaultDir; [5]=user name; [6] access permissions
	//alert("About to draw account link. idArr is: [0]="+idArr[0]+", [1]="+idArr[1]+", [2]="+idArr[2]+", [3]="+idArr[3]+", [4]="+idArr[4]+", [5]="+idArr[5]+", [6]="+idArr[6]); 

	var acctLink=document.getElementById("accountLink");
	if(acctLink)acctLink.innerHTML="&nbsp;| <a href="+pat+"account.php?acct="+idArr[0]+"&prof="+idArr[2]+" class=staticnavlink>My Account</a>";
}

function drawPasswordUI(act){
	var holder=grab("passHolder");
	var tp=0;
	var lf=0;
	if(!act)act=document.location.href;
	var txt="<div class=subtitle style=position:absolute;top:"+tp+";left:"+lf+";>";
	var lftPt0=0;
	var lftPt1=85;
	if(sf){
		lftPt0=-15;
		lftPt1=70;
	}
	var savedUserName=getCookie("savedUserName");
	if(!savedUserName)savedUserName="";
	txt+="<form id=loginForm action="+act+" method=post onsubmit=storeUserName()>";
	txt+="<span style=position:absolute;left:"+lftPt0+";top:3><nobr>User: </nobr></span><input id=nameInput type=text name=usr style=position:absolute;left:"+lftPt1+";top:0 class=passinput value="+savedUserName+"><p>";
	txt+="<span style=position:absolute;left:"+lftPt0+";top:21><nobr>Password: </nobr></span><input id=pwdInput type=password name=pwd style=position:absolute;left:"+lftPt1+";top:22 class=passinput><p>";
	//txt+="<span style=position:absolute;left:210;top:3;><nobr><a href=createNewAccount.php class=subtitle>New Account</a></nobr></span>";
	txt+="<input type=submit style=position:absolute;left:210;top:19 value='Log in'>";
	txt+="</form>";
	txt+="</div>";
	if(holder)holder.innerHTML=txt;
	return true;
}

function logout(){
	var res=setCookie("sessExp2",0);
	var res=setCookie("idStr2","");
	document.location.href="index.php";
	var acctLink=document.getElementById("accountLink");
	if(acctLink)acctLink.innerHTML="";
}

function storeUserName(){
	var namHolder=grab("nameInput");
	var userName=namHolder.value;
	setCookie("savedUserName",userName);
	return true;
}

// ================ gallery image selection function

function selectImage(num){
	var imgPath=imgLibrary[num][1];
	if(imgPath.substring(0,3)=="../")imgPath=pat+imgPath.substring(3);
	var str="<img src=\""+imgPath+"\">";
	var editFrame=grabEditSpaceContent();
	var storyBody=editFrame.document.body.innerHTML;
	storyBody=unescape(storyBody);
	storyBody+=str;
	editFrame.document.body.innerHTML=storyBody;
}

function addImageToEditSpace(){
	var fNam=getFileUploadValue("editSpaceUploader");
	imgPath=pat+"uploads/"+fNam;
	var str="<img src=\""+imgPath+"\">";
	var editFrame=grabEditSpaceContent();
	var storyBody=editFrame.document.body.innerHTML;
	storyBody=unescape(storyBody);
	storyBody+=str;
	editFrame.document.body.innerHTML=storyBody;
}


// ================================================================ CALENDAR WIDGET

function dayClick(d,nam){
	for(var c=0;c<33;c++){
		var cel=document.getElementById("calCel"+nam+c);
		if(cel)cel.style.backgroundColor="white";
	}
	var cel=document.getElementById("calCel"+nam+d);
	cel.style.backgroundColor="green";
	var dayBox=document.getElementById(nam+"Form1");
	if(d<10)d="0"+d;
	dayBox.value=d;
	var cal=document.getElementById(nam+"CalendarDiv");
	var frm=document.getElementById(nam+"InputDiv");
	frm.style.visibility="visible";
	cal.style.visibility="hidden";
}

function newCalView(dir,nam){
	var curMo=document.getElementById(nam+"Form0").value-1;
	var curYr=document.getElementById(nam+"Form2").value;
	curMo+=parseInt(dir);
	if(curMo>11){
		curMo=0;
		curYr++;
	}
	if(curMo<0){
		curMo=11;
		curYr--;
	}
	var now=new Date(curYr,curMo,1);
	now=now.getTime();
	var cl=document.getElementById(nam+"CalendarDiv");
	var tp=parseInt(cl.style.top);
	var lf=parseInt(cl.style.left);
	var wd=parseInt(cl.style.width);
	var ht=parseInt(cl.style.width)-20;
	var txt=getCalendarGridHTML(nam,tp,lf,wd,ht,0,"",now,0);
	cl.innerHTML=txt;
	var cf=document.getElementById(nam+"InputDiv");
	var txt=getCalendarFormHTML(nam,tp,lf,wd,ht,0,"",now,0);
	cf.innerHTML=txt;
}

function toggleCal(nam,tp,lf,wd,ht,tab,cap,def){
	var cal=document.getElementById(nam+"CalendarDiv");
	var frm=document.getElementById(nam+"InputDiv");
	if(frm.style.visibility=="visible"){
		var mo=parseInt(document.getElementById(nam+"Form0").value)-1;
		var dt=parseInt(document.getElementById(nam+"Form1").value);
		var yr=parseInt(document.getElementById(nam+"Form2").value);
		var dat=new Date(yr,mo,dt);
		dat=dat.getTime();
		var txt=getCalendarGridHTML(nam,tp,lf,wd,ht,tab,cap,dat,0);
		cal.innerHTML=txt;
		frm.style.visibility="hidden";
		cal.style.visibility="visible";
	}
	else{
		frm.style.visibility="visible";
		cal.style.visibility="hidden";
	}
}

// ================================================================= UNIVERSAL SORTING

//this global variable defines which column to sort. it has to be global because you can't pass additional values to the sort Method
var uniSort=2;

function uniSorter(a,b){
	if(typeof(a)!="object"||typeof(b)!="object")return 0;
	var valA=a[uniSort];
	var valB=b[uniSort];
	if(!isNaN(valA))valA=parseFloat(valA);
	if(!isNaN(valB))valB=parseFloat(valB);
	if(valA>valB)return 1;
	if(valA<valB)return -1;
	return 0;
}

function reverseUniSort(a,b){
	if(typeof(a)!="object"||typeof(b)!="object")return 0;
	var valA=a[uniSort];
	var valB=b[uniSort];
	if(!isNaN(valA))valA=parseInt(valA);
	if(!isNaN(valB))valB=parseInt(valB);
	if(valA>valB)return -1;
	if(valA<valB)return 1;
	return 0;
}


// ========================================================================= COOKIE HANDLERS:

function setCookie(nam,value,lifeSpan){
	if(!lifeSpan&&lifeSpan!=0)lifeSpan=365;
	var dat=new Date();
	dat.setTime(dat.getTime()+Math.round(lifeSpan*(60*60*24*1000)));
	var expString="; expires="+dat.toGMTString();
	var domString="; domain="+cookieDomain;
	document.cookie=nam+"="+escape(value)+expString+domString;
	return true;
}

function getCookie(nam){
	var res="";
	var cook=" "+document.cookie+";";
	var searchName=" "+nam+"=";
	var startOfCookie=cook.indexOf(searchName);
	if(startOfCookie!=-1){
		startOfCookie+=searchName.length;
		var endOfCookie=cook.indexOf(";",startOfCookie);
		res=unescape(cook.substring(startOfCookie,endOfCookie));
	}
	if(!res||res=="null")res="";
	return res;
}

// =============================================================== INTEGER ENCODING

//this converts a comma delimted string of values equalling 1 or 0 (indicating results for an array of up to 8 t/f choices), into an integer for storage in an INT slot
function integerEncode(str){
	str=unescape(str);
	var arr=str.split(",");
	var num=0;
	for(var a=0;a<arr.length;a++){
		var val=parseInt(arr[a]);
		if(val==0)num+=1;
		if(val==1)num+=2;
		if(val==2)num+=4;
		if(val==3)num+=8;
		if(val==4)num+=16;
		if(val==5)num+=32;
		if(val==6)num+=64;
		if(val==7)num+=128;
	}
	return num;
}

//this converts integers less than 256 into a comma delimited string of numbers indicating which slots are positive, eg: 1,3,7 is equivalent to 0,1,0,1,0,0,0,1
function integerDecode(num){
	num=parseInt(num);
	str="";
	if(num>=128){
		str+=7+",";
		num-=128;
	}
	if(num>=64){
		str+=6+",";
		num-=64;
	}
	if(num>=32){
		str+=5+",";
		num-=32;
	}
	if(num>=16){
		str+=4+",";
		num-=16;
	}
	if(num>=8){
		str+=3+",";
		num-=8;
	}
	if(num>=4){
		str+=2+",";
		num-=4;
	}
	if(num>=2){
		str+=1+",";
		num-=2;
	}
	if(num>=1){
		str+=0+",";
	}
	if(str.charAt(str.length-1)==",")str=str.substring(0,str.length-1);
	return str;
}




