/*
 * File: methods.js
 * Created: Sept 27, 2006
 * Author: Wes Jones
 * Purpose: To provide functions that are used on a consistent 
 *    basis or that do not belong to any particular class
 */

String.prototype.ucfirst = function(){
     return this.toLowerCase().replace(/\w+/g,function(s){
          return s.charAt(0).toUpperCase() + s.substr(1);
     })
}

String.prototype.ucwords = function(){
     return this.toLowerCase().replace(/\w+/g,function(s){
          var a = s.split(' ');
          for(var i = 0; i < a.length; ++i) {
             s = s.replace(a[i],a[i].ucfirst());
          }
          return s;
     })
}

String.prototype.charpac = function(n){
      var str = '';
      for(var i = 0; i < n; ++i) { str += this; }
      return str;
}

String.prototype.trim = function() {
    str = this != window? this : str;
    return str.replace(/^\s+/, '').replace(/\s+$/, '');
}

// depricated use toFixed and toPrecision
Number.prototype.decimals = function(n){
   return this.toFixed(n);
}

function clone (obj,deep,simplify) {
  /*
   * Since javascript passes by reference it can be difficult to get a copy
   * of something. This will return a copy. You must pass 1 or 2 parameters.
   * the first parameter is the object you want to clone. The second is weather
   * or not you want to copy the whole thing or just the top level of it.
   * if you just copy the top level the other elements in the array will still
   * be associated by reference. 
   */
  var objectClone = (simplify != null ? new Object() : new obj.constructor());
  for (var property in obj)
    if (!deep) {
      objectClone[property] = obj[property];
    } else if (typeof obj[property] == 'object') {
      objectClone[property] = clone(obj[property],deep);
    } else if(simplify == null || typeof(obj[property]) != 'function') {
      objectClone[property] = obj[property];
    }
  return objectClone;
}

var LOADQUEUE = new OnLoadQueue();
window.onload = LOADQUEUE.start;
function OnLoadQueue() {
	this.list = new Array();
	this.add = function (fr) {
		if(typeof(fr) == 'function') {
			this.list.push(fr);
		} else {
			alert('You can only pass function references to LOADQUEUE');
		}
	}
	this.start = function() {
		for(var i in LOADQUEUE.list) {
			LOADQUEUE.list[i]();
		}
	}
}

function getPageWidth() {
   /*
    * get the width of the page. Cross Browser compatible.
    */
   return getPageDimensions().width;
}

function getPageHeight() {
   /*
    * get the height of the page. Cross Browser compatible.
    */
   return getPageDimensions().height;
}

function getPageDimensions() {
   /*
    * must be executed after body tag
    * this is used by getPageWidth and getPageHeight to get the actual dimentions
    * of the current window. It checks browser versions to be compatible.
    */
   if (parseInt(navigator.appVersion)>3) {
       if (navigator.appName=="Netscape") {
         winW = window.innerWidth;
         winH = window.innerHeight;
       }
       if (navigator.appName.indexOf("Microsoft")!=-1) {
         winW = document.body.offsetWidth;
         winH = document.body.offsetHeight;
      }
   }
   return new Object({'width':winW,'height':winH});
}

function getDocumentWidth() {
	return getPageSizeWithScroll()[0];
}

function getDocumentHeight() {
	return getPageSizeWithScroll()[1];
}

function getPageSizeWithScroll(){
	if (window.innerHeight && window.scrollMaxY) {// Firefox
		yWithScroll = window.innerHeight + window.scrollMaxY;
		xWithScroll = window.innerWidth + window.scrollMaxX;
	} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
		yWithScroll = document.body.scrollHeight;
		xWithScroll = document.body.scrollWidth;
	} else { // works in Explorer 6 Strict, Mozilla (not FF) and Safari
		yWithScroll = document.body.offsetHeight;
		xWithScroll = document.body.offsetWidth;
  	}
	arrayPageSizeWithScroll = new Array(xWithScroll,yWithScroll);
	//alert( 'The height is ' + yWithScroll + ' and the width is ' + xWithScroll );
	return arrayPageSizeWithScroll;
}

function count(__object__){
   /*
    * php has a nice function for determining the length of an object.
    * so I made one so javascript could do the same.
    */
   var len = 0; for(var i in __object__) { len += 1; }; return len;
}

function WTimer(stat,ms,loops) {
	/*
	 * for setting a start and end time for something to run.
	 * also the interval at witch onTimerStatus is called
	 * overwrite onTimerStatus and onTimerFinished to use this class
	 * functions are: start(),stop(),resume(),getTime(),getLoop(),finish(),run(),onStat();
	 * To really get the use you want out of this function you should delcare
	 * timer.onTimerStatus = funciton ()... and timer.onTimerFinished = function () ...
	 * so that you can do what you want based on the updates or the finish of the
	 * timer.
	 */
	this.stat = stat; // string obj name 'plyr.timer';
	this.ms = ms;
	this.intv;
	this.intv_count;
	this._finish = loops;

	this.onTimerStatus = function () {}
	this.onTimerFinished = function () {}

	this.start = function () {
		this.intv_count = 0;
		this.run();
	}

	this.stop = function () {
		if(this.intv) {
			window.setInterval ? clearInterval(this.intv) : clearTimeout(this.intv);
		}
	}

	this.resume = function () {
		this.run();
	}

	this.getTime = function () {
		return this.intv_count*this.ms;
	}

	this.getLoop = function () {
		return this.intv_count;
	}

	this.finish = function () {
		this._finish = this.getLoop();
		this.onStat();
	}

	this.run = function () {
		if(window.setInterval) {
			this.intv = setInterval(this.stat+'.onStat()',this.ms);
		} else { // mobile IE
			this.intv = setTimeout(this.stat+'.onStat()',this.ms);
		}
	}

	this.onStat = function () {
		this.intv_count+=1;
		if(this.intv_count >= this._finish && this._finish) {
			this.stop();
			this.onTimerFinished();
		} else {
			this.onTimerStatus();
			!window.setInterval ? this.intv = setTimeout(this.stat+'.onStat()',this.ms) : null; 
		}
	}
}

// GLOBALS this is used to hold global variables between functions
// this allows functions to have variables when returned from AJAX
var GLOBALS = new Object(); 
var PO = new ParseObj();
var DW = new DivWindow();

function DivWindow() {
	/*
	 * Use this to launch a div window. Once the object is created you can keep
	 * resetting the data without having to pass all of the options to divWindowBeta
	*/
	this.div = null;
	this.headerImg = null;
	this.closeImgPath = null;
	this.intro = null;
	
	this._width = 0;
	this._height = 0;
	
	this.launch = function (title,html,width,height,callBack) {
		var errstr = '';
		for(var i in this) {
			if(this[i] == null && typeof(this[i]) != 'function') {
				errstr += i+' is required for this item'+"\n";
			}
		}
		if(errstr.length) {
			alert(errstr);
		} else {
			this._width = width;
			this._height = height;
			divWindowBeta(this.div,this.headerImg,this.intro+title,html,width,height,(getPageWidth()/2)-(width/2),(getPageHeight()/2)-(height/2),(callBack ? callBack : null),this.closeImgPath);
			this.repositionPopup();
		}
	}
	this.close = function () {
		divClose(this.div);
	}
	this.setContent = function (str) {
		document.getElementById('divpopwin_content').innerHTML = str;
	}
	this.repositionPopup = function(){
		/*
		* reposition the popup div and set the background img
		*/
		var win = document.getElementById('divpopwin');
		if(win){
			win.style.top = document.body.scrollTop + parseInt(win.style.top,10);
			//calculate the scrollHeight and set the background transparency to that hieght
			document.getElementById('divpopwinbg').style.height = document.all ? Math.max(Math.max(document.documentElement.offsetHeight, document.documentElement.scrollHeight), Math.max(document.body.offsetHeight, document.body.scrollHeight)) : (document.body ? document.body.scrollHeight : ((document.documentElement.scrollHeight != 0) ? document.documentElement.scrollHeight : 0));
		}
	}
	
	this.loadDivs = function () {
		this.dpwDiv = document.getElementById('divpopwin');
		this.frameDiv = document.getElementById(this.dpwDiv.id+'_frame');
		this.containerDiv = document.getElementById(this.dpwDiv.id+'_container');
		this.contentDiv = document.getElementById(this.dpwDiv.id+'_content');
		this.hdrDiv = document.getElementById(this.dpwDiv.id+'_hdr');
		this.hdrImgDiv = document.getElementById(this.dpwDiv.id+'_hdrImg');
		this.closeDiv = document.getElementById(this.dpwDiv.id+'_close');
	}
	
	
	this.getWidth = function () { return this._width; }
	this.setWidth = function (value) {
		this._width = value;
		this.loadDivs();
		var ws = this._width+'px';
		this.dpwDiv.style.width = ws;
		this.frameDiv.style.width = ws;
		this.containerDiv.style.width = ws;
		this.contentDiv.style.width = ws;
		this.hdrDiv.style.width = (document.all ? this._width-7 : this._width+1)+'px';
		this.hdrImgDiv.style.width = (document.all ? this._width-7 : this._width+1)+'px';
		this.closeDiv.style.left = (this._width-13)+'px';
	}
	
	this.getHeight = function () { return this._height; }
	this.setHeight = function (value) {
		this._height = value;
		this.loadDivs();
		var hs = this._height+'px';
		this.dpwDiv.style.height = hs;
		this.frameDiv.style.height = hs;
		this.containerDiv.style.height = hs;
		this.contentDiv.style.height = (this._height-20)+'px';
		this.hdrDiv.style.height = '20px';
	}
}

function traceAry(obj) {
   /*
    * Like print_p() in php except this ones is on the javascript side.
    * this is mainly used for a debugging function to view your objects.
    * use alert(traceAry(myObject)); to see how it works.
    */
   return PO.traceIt(obj);
}

function getAjaxInput(divid,db_table,id,field,value,callBackStr,target,style,inputStyleName,rows,cols) {
   /*
    * Using Javascript you can crate an editable div that will save text to a database field.
    * It creates the same result as using AJAX.0.1.class.php except this is done using Javascript
    * instead of html and javascript written by the php script.
    */
   return AJAX.writeEditText(divid,db_table,id,field,value,callBackStr,target,style,inputStyleName,rows,cols);
}

function divWindow (dw,img,hdr,str,w,h,x,y,onclose,dir) {
/*
 * Purpose: to simulate a popup window with a div layer
 * dw is the a div object
 */
   // if dw is a string make it become the object assuming it is the id for the object
   var dw = document.getElementById(dw);
   var w = parseInt(w) > 100 ? parseInt(w) : 400;
   var h = parseInt(h) > 50 ? parseInt(h) : 400;
   dw.style.position = 'absolute';
   dw.style.display = 'block';
   dw.style.width = w+'px';
   dw.style.height = h+'px';
   dw.style.left = (typeof(x) ? x : screen.width/2 - w/2)+'px';
   dw.style.top = (typeof(y) ? y : screen.height/2 - h/2)+'px';
   dw.style.zIndex = 100;
   dw.style.backgroundColor = '#ffffff';
   dw.onclose = function () {
      this.innerHTML = '';
      this.style.position = 'absolute';
      this.style.left = '0px';
      this.style.top = '0px';
      this.style.width = '1px';
      this.style.height = '1px';
   }
   dw.path = typeof(dir) ? dir : '';
   dw.innerHTML = '<IFRAME id="'+dw.id+'_frame" style="position:absolute;background-color:'+dw.style.backgroundColor+';width:'+(typeof(is_nav) ? w+8 : w)+'px;height:'+(typeof(is_nav) ? h+8 : 8)+'px;" frameborder=0 scrolling=no marginwidth=0 src="" marginheight=0></iframe>'+
                  '<div style="position:absolute;border:4px ridge;background-color:'+dw.style.backgroundColor+';width:'+w+'px;height:'+h+'px;">'+
                     '<div id="'+dw.id+'_content" style="position:absolute;margin-top:20px;width:'+(BROWSER.name == 'ie' ? w-8 : w)+'px;height:'+((BROWSER.name == 'ie' ? h-8 : h)-20)+'px;overflow:auto;">'+str+'</div>'+
                  '</div>'+
                  '<div id="'+dw.id+'_hdr" style="position:absolute;top:4px;left:4px;background-image:url('+img+');width:'+(document.all ? w-7 : w+1)+'px;height:20px;color:#ffffff;"><img id="'+dw.id+'_hdrImg" src="'+img+'" style="width:'+(document.all ? w-7 : w+1)+'px;height:20;position:absolute;">'+hdr+'</div>'+
                  '<div id="'+dw.id+'_close" align="center" style="position:absolute;top:6px;left:'+(w-(BROWSER.name == 'ie' ? 20 : 13))+'px;width:16px;height:16px;display:table-cell;vertical-align:middle;text-align:center;"><a href="javascript:divClose(\''+dw.id+'\');"><img src="'+dw.path+'images/close.gif" border="0" width="16" height="14"></a></div>';
str = '';
for(var i in dw.style) {
   str+= i+' = '+dw.style[i]+'<br>';
}
   makeDraggable(document.getElementById(dw.id+'_hdr'),dw);
}

function divWindowBeta (dw,img,hdr,str,w,h,x,y,onclose,dir) {
/*
 * Purpose: to simulate a popup window with a div layer
 * dw is the a div object. This is like a modal window. It darkens the background
 * behind it so that nothing around it can be clicked on.
 */
   // if dw is a string make it become the object assuming it is the id for the object
   var origional_id = dw;
   document.getElementById(origional_id).style.display='block';
   var windisable = document.getElementById(dw);
   windisable.innerHTML = (detectMacXFF() ? 
                             '<div id="divpopwinbg" style="position:absolute;width:100%;height:100%;z-index:999;"><img src="../images/disabled_bg.png" border="0" width="100%" height="100%"></div>'
                             :
                             '<div id="divpopwinbg" style="position:absolute;background-color:#000000;width:100%;height:100%;filter:alpha(opacity=50);-moz-opacity:.50;opacity:.50;z-Index:999;"></div>'
                          )+
                          '<div id="divpopwin" style="position:absolute;z-Index:1000;"></div>';
   dw = 'divpopwin';
   var dw = document.getElementById(dw);
   var w = parseInt(w) > 100 ? parseInt(w) : 400;
   var h = parseInt(h) > 50 ? parseInt(h) : 400;
   dw.style.position = 'absolute';
   dw.style.display = 'block';
   dw.style.width = w+'px';
   dw.style.height = h+'px';
   dw.style.left = (typeof(x) ? x : screen.width/2 - w/2)+'px';
   dw.style.top = (typeof(y) ? y : screen.height/2 - h/2)+'px';
   dw.style.zIndex = 1000;
   dw.style.backgroundColor = '#ffffff';
   dw.origional_id = origional_id;
   dw.onCloseEvent = onclose;
   dw.closed = 0;
   dw.onclose = function () {
      this.innerHTML = '';
      this.style.position = 'absolute';
      this.style.left = '0px';
      this.style.top = '0px';
      this.style.width = '1px';
      this.style.height = '1px';
      document.getElementById(this.origional_id).innerHTML = '';
      if(typeof(this.onCloseEvent) == 'function' && !this.closed) {
         this.closed = 1;
         this.onCloseEvent();
      }
   }
   windisable.dw = dw;
   windisable.onclose = function () {
      dw.onclose();
   }
   dw.path = typeof(dir) ? dir : 'images/close.gif';
   dw.innerHTML += '<IFRAME id="'+dw.id+'_frame" style="position:absolute;background-color:'+dw.style.backgroundColor+';width:'+w+'px;height:'+h+'px;" frameborder=0 scrolling=no marginwidth=0 src="" marginheight=0></iframe>'+
                  '<div id="'+dw.id+'_container" style="position:absolute;border:4px ridge;background-color:'+dw.style.backgroundColor+';width:'+w+'px;height:'+h+'px;">'+
                     '<div id="'+dw.id+'_content" style="position:absolute;margin-top:20px;width:'+w+'px;height:'+(h-20)+'px;overflow:auto;">'+str+'</div>'+
                  '</div>'+
                  '<div id="'+dw.id+'_hdr" style="position:absolute;top:4px;left:4px;background-image:url('+img+');width:'+w+'px;height:20px;color:#ffffff;"><img id="'+dw.id+'_hdrImg" src="'+img+'" style="width:'+(document.all ? w-7 : w+1)+'px;height:20px;position:absolute;"><div style="position:absolute;">'+hdr+'</div>'+hdr+'</div>'+
                  '<div id="'+dw.id+'_close" align="center" style="position:absolute;top:6px;left:'+(w-13)+'px;width:16px;height:16px;display:table-cell;vertical-align:middle;text-align:center;"><a href="javascript:divClose(\''+dw.id+'\');"><img src="'+dw.path+'" border="0" width="16" height="14"></a></div>';
   str = '';
   for(var i in dw.style) {
      str+= i+' = '+dw.style[i]+'<br>';
   }
   makeDraggable(document.getElementById(dw.id+'_hdr'),dw);
}


function divClose(dw) {
   /*
    * Close the div window created by divWindow or divWindowBeta. It requires
    * that you pass it the id of the div to close so you can have multiple
    * windows at once.
    */
   var dw = document.getElementById(dw);
   if(dw.onclose) {
      dw.onclose();
   }
}

function detectMacXFF() {
  /*
   * There was one time that I needed to know if it was a FireFox Browser on a Mac.
   * well this function will tell you if it is that.
   */
  var userAgent = navigator.userAgent.toLowerCase();
  if (userAgent.indexOf('mac') != -1 && userAgent.indexOf('firefox')!=-1) {
    return true;
  }
}

function getCookie(cookieName) {
   /*
    * get a cookie by it's name. returns an object.
    */
   var nameEQ = name + "=";
   var cstr = document.cookie+'';
   cstr = cstr.replace(/\;(\s?|\n?|\r?)/,';'); // get rid of trailing space
   var obj = PO.parseIt(cstr,';');
   if(exists(obj,cookieName)) {
      return obj[cookieName];
   } else if (exists(obj,' '+cookieName)) {
      return obj[' '+cookieName];
   }
   return null;
}

function setCookie(cookieName,cookieValue,nDays) {
   /*
    * set a cookie. Name, value, and how many days it will stay in memory.
    */
   cookieName = cookieName.trim();
   deleteCookie(cookieName);
   var today = new Date();
   var expire = new Date();
   if (nDays==null || nDays==0) nDays=1;
   expire.setTime(today.getTime() + 3600000*24*nDays);
   document.cookie = cookieName+"="+escape(cookieValue)+ ";expires="+expire.toGMTString();
}

function deleteCookie(cookieName) {
   /*
    * delete a cookie by name
    */
   var c = new Date();
   document.cookie = cookieName+'=1;expires='+c.toGMTString()+';'+';';
}


function escapeHtml(str) {
   /*
    * Used like htmlspecial chars in php. It will convert most html special characters to their ascii format.
    */
   if(typeof(str) == 'string') {
      str = str.replace(/\</gi,'&lt;');
      str = str.replace(/\>/gi,'&gt;');
      str = str.replace(/\"/gi,'&quot;');
      str = str.replace(/\&/gi,'&amp;');
      str = str.replace(/\-/gi,'&ndash;');
      str = str.replace(/\_/gi,'&mdash;');
      str = str.replace(/\'/gi,'&lsquo;');
   }
   return str;
}

function unescapeHtml(str) {
   /*
    * Decode a string that is encoded using escapeHtml.
    */
   if(typeof(str) == 'string') {
      str = str.replace(/\&lt\;/gi,'<');
      str = str.replace(/\&gt\;/gi,'>');
      str = str.replace(/\&quot\;/gi,'"');
      str = str.replace(/\&amp\;/gi,'&');
      str = str.replace(/\&ndash\;/gi,'-');
      str = str.replace(/\&mdash\;/gi,'_');
      str = str.replace(/\&lsquo\;/gi,'\'');
      str = str.replace(/\&rsquo\;/gi,'\'');
   }
   return str;
}


function daysInMonth(year,month) {
   /*
    * Pass the year and month. It will tell you how many days are in that month.
    * Months are 0-11
    */
   var d= new Date();
   year = year ? year : d.getFullYear();
   var days = new Array(31,((year%4==0&& year%100!=0)||year%400==0?29:28),31,30,31,30,31,31,30,31,30,31);
   if (!isNaN(month)) { return days[month]; }
   else { return days; }
}

function getMonthName(month,chars) {
   /*
    * Get the name of the month. If you want it truncated then pass the limit of chars.
    */
   var months = new Array('January','February','March','April','May','June','July','August','September','October','November','December');
   return months[month].substr(0,(parseInt(chars) > 0 ? chars : months[month].length));
}

function startTime(divid) {
   /*
    * pass a divid and it will put in an incrementing timer.
    */
   var today=new Date()
   var h=today.getHours()
   var m=today.getMinutes()
   var s=today.getSeconds()
   // add a zero in front of numbers<10
   h=dd(h);
   m=dd(m)
   s=dd(s)
   document.getElementById(divid).innerHTML=h+":"+m+":"+s
   t=setTimeout('startTime()',1000)
}

function dd(i,digits){ 
   /*
    * return double digits of numbers. Such as 01, 02, 03, ...
    */
   digits = digits ? digits : 2;
   i = i+'';
   i = charpac('0',digits-i.length)+i;
   return i;
}

function charpac(s,n) {
   /*
    * return a string with the s string repeated n times.
    */
   var str = '';
   for(var i = 0; i < n; ++i) { str += s; }
   return str;
}

function getMilliseconds() {
   /*
    * returns the milliseconds of todays date. This is handy for passing as a random number to the end of a url
    * when you want to keep that url from caching or if you want to give something a unique id. Since no id previous
    * or after will be the same and it changes 1000 times a second. As many as you want to call it should
    * never give you a duplicate number.
    */
   var d = new Date();
   var n = 0;
   n += d.getHours()*60*60*1000;
   n += d.getMinutes()*60*1000;
   n += d.getSeconds()*1000;
   n += d.getMilliseconds();
   return n;
}

function preInput(type,id,txt,rows,cols,style,keyupStr) {
   /*
    * return an input text or textarea field that has greyed out text in it. Then
    * when you click on it the text will dissapear and what you type will be dark.
    * if you delete everything in the field and blur then it will put the grey text
    * back into it. This makes it so that you can label fields without having to 
    * make room for the labels.
    */
   if(type == 'text' || type == 'input') {
      return '<input type="text" name="'+id+'" id="'+id+'" value="'+txt+'" style="'+(style ? style : 'color:#999999;width:230px;font-family:arial;font-size:11px;')+'" onfocus="preInputText(\''+txt+'\',this,\'focus\');" onblur="preInputText(\''+txt+'\',this,\'blur\');AJAX.dispatchEvent(\'PREINPUT_BLUR\',{id:this.id,name:this.name,value:this.value});" onKeyUp="'+(keyupStr ? keyupStr : 'AJAXQue.onKeyUp(this,event)')+'">';
   } else if(type == 'textarea') {
      return '<textarea  name="'+id+'" id="'+id+'" rows="'+rows+'" cols="'+cols+'" style="'+(style ? style : 'color:#999999;width:230px;font-family:arial;font-size:11px;')+'" onfocus="preInputText(\''+txt+'\',this,\'focus\');" onblur="preInputText(\''+txt+'\',this,\'blur\');AJAX.dispatchEvent(\'PREINPUT_BLUR\',{id:this.id,name:this.name,value:this.value});" onKeyUp="'+(keyupStr ? keyupStr : 'AJAXQue.onKeyUp(this,event)')+'">'+txt+'</textarea>';
   }
}

function preInputText(str,obj,cmd) {
   /*
    * This is the processing function of preInput. Use preInput and to create your text field.
    */
   if(cmd == 'focus') {
      if(obj.value == str) {
         obj.style.color = '#000000';
         obj.value = '';
      }
   } else if (cmd == 'blur') {
      if(obj.value == '') {
         obj.style.color = '#999999';
         obj.value = str;
      }
   }
}

function PopUp () {
   /*
    * Create a popup window. Specify the parameters you want.
    * it will alert if the popup is blocked letting the user know that their
    * popup blocker in enabled.
    */
   this.name = 'popup';
   this.toolbar = 'no';
   this.scrollbars = 'yes';
   this.status = 'no';
   this.resizable = 'no';
   this.menubar = 'no';
   this.width = 320;
   this.height = 240;
   this.win = null;
   this.url = null;
   this.go = function (url) {
      this.url = url;
      var reWork = new RegExp('object','gi');
      try {
         this.win=window.open(url,this.name,'toolbar='+this.toolbar+',scrollbars='+this.scrollbar+',status='+this.status+',resizable='+this.resizable+',menubar='+this.menubar+',width='+this.width+',height='+this.height);
      } catch (e) { }
      if(!reWork.test(String(this.win))) {
         alert('Your popup blocker is enabled.');
      } 
   }
   this.write = function (str) {
      this.win.document.write(str);
   }
}


function exists(obj,attribute) {
   /*
    * used to check if an attribute exists in an object. Use this if trying to
    * check by if(object.attribute) is throwing an error.
    */
   var e = false;
   for(var i in obj) {
      if(i == attribute) {
         e = true;
         break;
      }
   }
   return e;
}


function hideUnhide(divid) {
   /*
    * pass the divid and this will toggle that element displayable or not.
    * this is ideal for making menus that you want to conceal until they are clicked.
    */
   var div = document.getElementById(divid);
   div.style.display = div.style.display == 'inline' || div.style.display == 'block' ? 'none' : 'block';
}


function CreateBookmarkLink(title) {
   /*
    * Allow people to bookmark the page. <a href="javascript:CreateBookmarkLink('Your Title');">Clickk Here</a>
    */
   url = document.location;

   if (window.sidebar) { // Mozilla Firefox Bookmark
      window.sidebar.addPanel(title, url,"");
   } else if( window.external ) { // IE Favorite
      window.external.AddFavorite( url, title);
   } else if(window.opera && window.print) { // Opera Hotlist
      return true;
   }
}

function getKeyCode (e) {
   /*
    * returns the keyCode of a key pressed in IE or Mozilla Browsers
    */
   if(window.event) { // IE
      return e.keyCode;
   } else if (e.which) { // Netscape/Firefox/Opera
      return e.which;
   }
}

function secondstostr (s,chop) {
   /*
    * Pass a number of seconds to this and it will return it in a 
    * Y-m-d H:i:s format. Works great for a timer. secondstostr(90,1) = 1:30
    * if you pass the chop it will only show you what is there.
    * if you don't pass the chop it will show you the whole string. 0000-00-00 00:00:00
    */
   // convert a time in seconds to Y-m-d H:i:s
   if(s == 0) { return 0; }
   else {
      var negative = '';
      if(s<0) { s = Math.abs(s); negative='-'; }
      var tl = s;
      s = dd(s%60);
         tl = (tl-s)/60;
      var i = dd(tl%60);
         tl = (tl-i)/60;
      var h = dd(tl%24);
         tl = (tl-h)/24;
      var mydate = new Date();
         dim = daysInMonth(mydate.getFullYear(),mydate.getMonth());
      var d = dd(tl%dim);
         tl = (tl-d)/dim;
      var m = dd(tl%12); 
         tl = (tl-m)/12;
      var y = dd(tl);
      if(!chop) {
         return negative+y+'-'+m+'-'+d+' '+h+':'+i+':'+s;
      } else {
         str='';
         if(y>0||str){ str+=y+'-'; }
         if(m>0||str){ str+=m+'-'; }
         if(d>0||str){ str+=d+' '; }
         if(h>0||str){ str+=h+':'; }
         if(i>0||str){ str+=i+':'; }
         str+=s;
         return negative+str;
      }
   }
}

function ByteSize(bytes) {  
   /*
    * format sizes of bytes. Just pass a number and it will convert it to byte
    * notation. ByteSize(1048576) = 2MB;
    */
   size = bytes / 1024;  
   if(size < 1024){
       // kilobytes
       size = (parseInt((size)*100)/100)+'kb';  
   } else {  
       if(size / 1024 < 1024) {
           // megabytes
           size = size/1024;
           size = (parseInt((size)*100)/100)+'mb';  
       } else if(size/1024/1024 < 1024) {
           // gigabytes
           size = size/1024/1024;
           size = (parseInt((size)*100)/100)+'gb';  
       } else {  
           // terrabytes
           size = size/1024/1024/1024;  
           size = (parseInt((size)*100)/100)+'tb';  
       }  
   }  
   return size;  
}

function URLRequest() {
	/*
	 * Receives all of the arguments that need to be put into an object
	 * this will go through and pair each of the items to an object
	 */
	var obj = new Object();
	for(var i=0; i<arguments.length; i+=2) {
		obj[arguments[i]] = arguments[i+1];
	}
	return obj;
}

function ParseObj() {
/*
 * ParseObj.js
 * Created Sept 26, 2006
 * Author: Wes Jones
 * Purpose: take any url or query string and parse it into a hiearchal object return as array of objects
 * PO is already defined in this script so you don't define it. You just use
 * it.
 * Example: gets variables out of a query string
 *   var str = 'test=hello&user[id]=1&user[level]=2';
 *   var obj = PO.parseIt(str);
 *   alert(traceIt(obj)); // traces like print_r in php
 * Example 2: gets variables out of the url
 *   var urlvars = PO.getURL();
 *   alert(traceIt(urlvars));
 * Example 3: use the PO.toString(obj) to convert items to a url encoded string.
 * all objects passed through ajax are encoded this way automatically.
 */
   this.obj = new Object();
   this.unique_keys = new Object(); // for avoiding recursion when toString()
   this.getURL = function () { // get url and parseIt
      var str = document.location+'';
      var spobj = new Object();
      var sp = str.split('?');
      spobj.url = sp[0];
      spobj.query = this.parseIt(sp[1]);
      return spobj;
   }
   this.parseIt = function (vars,chr) {
      // parese query string into variable object and return it
      this.obj = new Object();
      chr = chr ? chr : '&';
      vars = (vars+'').trim();
      if(typeof(vars) != 'string') { vars = vars+''; }
      var v = vars.split(chr);
      for(var i in v) {
         v[i] = v[i].toString().split('=');
         var tmp = v[i][0].toString().split('[');
         if (tmp.length > 1) {
            if (this.obj[tmp[0]] == undefined) {
               this.obj[tmp[0]] = new Object();
            }
            var keys = v[i][0].toString().split('[');
            keys = keys.splice(1,keys.length-1);
            for(var j in keys) {
               keys[j] = keys[j].toString().replace(']','');
            }
            this.obj[tmp[0]] = this.addKV(this.obj[tmp[0]],keys,v[i][1]);
         } else {
            if (v[i][0]) {
               this.obj[v[i][0]] = unescape(v[i][1]);
            }
         }
      }
      return this.obj;
   }
   this.addKV = function (obj,keys,val) {
      // add sub child objects recursivly
      if(keys.length > 1) {
         if(!obj[keys[0]]) {
            obj[keys[0]] = new Object();
         }
         obj[keys[0]] = this.addKV(obj[keys[0]],keys.splice(1,keys.length-1),val);
      } else {
         val = unescape(val);
         if(!isNaN(val)) {
         	val = parseFloat(val);
         	val = isNaN(val) ? 0 : val;
         } else if (val.toLowerCase() == 'true') {
         	val = true;
         } else if (val.toLowerCase() == 'false') {
         	val = false;
         }
         obj[keys[0]] = val;
      }
      return obj;
   }
   this.charPac = function (c,d) {
      // add spacing for legibility
      var str = '';
      for(var i = 0; i < d; ++i) { str += c; }
      return str;
   }
   this.traceIt = function (obj,depth) {
      // recursivly trace the array and ouput in hiearchal string
      var str = '';
      depth = depth ? parseInt(depth) : 0;
      if((typeof(obj)+'').toLowerCase() == 'array') { //.length) {
         for(var i=0; i < obj.length; ++i) {
         	str += this.traceStr(obj,i,depth);
         }
      } else {
         for(var i in obj) {
            str += this.traceStr(obj,i,depth);
         }
      }
      return str;
   }
   this.traceStr = function (obj,i,depth) {
      str = '';
      type = (typeof(obj[i])+'').toLowerCase();
      var unique = true;//!exists(this.unique_keys,i);
      str += this.charPac('---',depth+1)+'['+i+'] '+(type == 'object' && unique  ? '= Object (\n'+this.traceIt(obj[i],depth+2) : ' = '+obj[i]+',')+'\n';
      str += type == 'object' && unique  ? this.charPac('---',depth+1)+'),\n' : '';
      if(type == 'object') { this.unique_keys[i] = 1; }
      return str;
   }
   this.toString = function (obj,name) {
      // make a query string
      // this will remove all functions that are in the object
      // since only simple objects can be passed.
      var str = '';
      for (i in obj) {
         if (typeof(obj[i]) != 'function') {
            if(typeof(obj[i]) == 'object' || typeof(obj[i]) == 'array') {
               if(!name) { // single dimentional
                  str += this.toString(obj[i],i);
               } else { // multi dimentional
	              str += this.toString(obj[i],name+'['+i+']');
               }
            } else if (name) {
               str += name+'['+i+']='+escape(obj[i])+'&';
            } else {
               str += i+'='+escape(obj[i])+'&';
            }
         }
      }
      return str;
   }
}

function flashImageUploader(id,w,h,jspath,posturl,callback,type) {
   /*
    * Requires uploader.0.2.swf to be put in the js directory. This will pass
    * files to a php script for uploading files through this flash uploader so
    * that you can see a progress bar as you are uploading files. This function
    * is essential when uploading larger files.
    */
   v = 8;
   swf = jspath+'uploader.0.2.swf';

   type = type ? type : 'image';

   var fobj = document.getElementById(id);
   fobj.style.width = w+'px';
   fobj.style.height = h+'px';

   // generate unique id
   var d = new Date();
   var fpid = Date.parse(d); // milliseconds since January 1, 1970

   var fproxy = new FlashProxy(fpid, jspath+'JavaScriptFlashGateway.swf');
   fobj.fproxy = fproxy;
   var version = deconcept.SWFObjectUtil.getPlayerVersion();
   if (version['major']<v) {
      fobj.innerHTML = " We have not detected a Flash Player or your current version of "+version['major']+" is not sufficient to view this site.<br />Please <a href=\"http://www.adobe.com/shockwave/download/download.cgi\" target=\"_blank\" class=\"a_sml\">CLICKING HERE</a> to download the latest Flash Player.<br />";
   } else {
      var tag = new FlashTag(swf, 150, 100, '#000000'); // last two arguments are height and width
      tag.setFlashvars('lcId='+fpid);
      tag.addParam('wmode','transparent');
      tag.addParam('scale','noscale');
      tag.addParam('salign','lt');
      tag.addVariable('path',escape(posturl));
      tag.addVariable('type',type);
      tag.addVariable('callback',escape(callback));
      tag.write(id);
   }
}

function uploadStarted(str) {
   /*
    * DO NOT USE. This function is depricated.
    */ 
}

function copy_clip(meintext) {
   /*
    * This is a mean little script. It depends on the browser if you can get away
    * with it. But it will keep copying a blank space to your clipboard so that
    * if the user tries to copy anything while they have this window open (including
    * your images) they won't be able to get them. All they will ever get it a blank
    * space.
    */
   if (window.clipboardData) {
      // the IE-manier
      window.clipboardData.setData("Text", meintext);
   } else if (window.netscape) { 
      // you have to sign the code to enable this, or see notes below 
      netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
      // maak een interface naar het clipboard
      var clip = Components.classes['@mozilla.org/widget/clipboard;1']
                 .createInstance(Components.interfaces.nsIClipboard);
      if (!clip) return;
         // maak een transferable
         var trans = Components.classes['@mozilla.org/widget/transferable;1']
                  .createInstance(Components.interfaces.nsITransferable);
      if (!trans) return;
         // specificeer wat voor soort data we op willen halen; text in dit geval
         trans.addDataFlavor('text/unicode');
         var str = new Object();
         var len = new Object();
   
         var str = Components.classes["@mozilla.org/supports-string;1"]
                .createInstance(Components.interfaces.nsISupportsString);
   
         var copytext=meintext;
   
         str.data=copytext;
   
         trans.setTransferData("text/unicode",str,copytext.length*2);
   
         var clipid=Components.interfaces.nsIClipboard;
   
         if (!clip) return false;

         clip.setData(trans,null,clipid.kGlobalClipboard);
      }
      return false;
}

function getXY() {
   /*
    * returns an object with the x and y of the users mouse.
    */
   var obj = new Object();
   obj.x = mouseX ? mouseX : 0;
   obj.y = mouseY ? mouseY : 0;
   return obj;
}

var IE = document.all?true:false;
if(!IE) document.addEventListener(Event.MOUSEMOVE,getMouseXY,false);
document.onmousemove = getMouseXY;
var mouseX = 0;
var mouseY = 0;
function getMouseXY(e) {
   /*
    * Calculates the mouse X and Y based off of the users browser. Use
    * getXY to get the mouseX and mouseY.
    */
   if (IE && event) { // grab the x-y pos.s if browser is IE
      mouseX = event.clientX + document.body.scrollLeft;
      mouseY = event.clientY + document.body.scrollTop;
   } else {  // grab the x-y pos.s if browser is NS
      mouseX = e.pageX;
     mouseY = e.pageY;
   }  
   if (mouseX < 0){mouseX = 0;}
   if (mouseY < 0){mouseY = 0;}  
   return true;
}

function addslashes(str) {
   /*
    * Similar to the php addslashses before quotes. You should use escape and unescape instead.
    */
   str=str.replace(/\'/g,'\\\'');
   str=str.replace(/\"/g,'\\"');
//   str=str.replace(/\\/g,'\\\\');
   str=str.replace(/\0/g,'\\0');
   return str;
}

function stripslashes(str) {
   /*
    * removes slashes from quotes.
    */
   str=str.replace(/\\'/g,'\'');
   str=str.replace(/\\"/g,'"');
   str=str.replace(/\\\\/g,'\\');
   str=str.replace(/\\0/g,'\0');
   return str;
}

function plural(n) {
   /*
    * Gramar weather to say 1 set or 2 sets. You would pass to this in a string
    * num+' set'+plural(num)+' and it will return an s if you need it.
    */
   // pass a number if == 1 it will return an 's'
   if(typeof(n)!='number') { n=parseFloat(n); }
   return n==1 ? '' : 's';
}

function protonDateFormat(showdatestr) {
   /*
    * takes date in yyyy-mm-dd hh:ii:ss format and converts 
    * it to Sunday June 17 @ 6pm EST
    */

      var dayname = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
      var monthnames = ['January','February','March','April','May','June','July','August','September','October','November','December'];

      var sdary = showdatestr.split(' ');
      sdary[0] = sdary[0].toString().split('-')
      sdary[1] = sdary[1].toString().split(':');
      for(var i=0;i<sdary[0].length;++i) {
         sdary[0][i] = parseFloat(sdary[0][i]);
         sdary[1][i] = parseFloat(sdary[1][i]);
      }

      var mydate = new Date();
      mydate.setYear(sdary[0][0]);
      mydate.setMonth(sdary[0][1]-1); // js reads months as 0-11
      mydate.setDate(sdary[0][2]);
      mydate.setHours(sdary[1][0]);
      mydate.setMinutes(sdary[1][1]);
      mydate.setSeconds(sdary[1][2]);
      pm = mydate.getHours()>=12 ? 1 : 0;

      return dayname[mydate.getDay()]+' '+monthnames[(mydate.getMonth())]+' '+mydate.getDate()+', '+mydate.getFullYear()+' @ '+((mydate.getHours()%12) == 0 ? '12' : mydate.getHours()%12)+''+(pm ? 'PM' : 'AM')+' EST';
}

function getLimitTextArea(id,limit,txt,style) {
    /*
     * returns a textarea that will count with every character that you type and
     * will not allow you to type more than the limit of characters. They can
     * see the counter running below as well as the limit.
     */
	str = '<textarea id="'+id+'" style="'+(style ? style : 'color:#999999;width:230px;font-family:arial;font-size:9pt;')+'" onKeyDown="javascript:limitText(\''+id+'\',\''+id+'Count\','+limit+');" onfocus="preInputText(\''+txt+'\',this,\'focus\');" onBlur="javascript:preInputText(\''+txt+'\',this,\'blur\');limitText(\''+id+'\',\''+id+'Count\','+limit+');">'+txt+'</textarea><br />'+"\n"+
		'<font>(Limit: '+limit+') Characters Left: </font><input type="text" id="'+id+'Count" value="0" disabled>';
	return str;
}

function limitText(fieldId, limitCountId, limitNum) {
	/*
	 * Limit the number of characters in a text field. Text fiels will be truncated so 
	 * this lets user know where they will be so.
	 */
	var fld = document.getElementById(fieldId);
	var limitCount = document.getElementById(limitCountId);
	if (fld.value.length > limitNum) {
		fld.value = fld.value.substring(0, limitNum);
	} else {
		limitCount.value = limitNum - fld.value.length;
	}
}
	
function updateDateSelect(id,type) {
    /*
     * The id that you pass is setup as a hidden text field. The other elements are created
     * with id's instead of names. So you can add this to a form and all that you will get is
     * a string for the date they picked in Y-m-d H:i:s format. You can pass
     * the parameters you want them to choose from. Such as you can allow them to pick the
     * year, month, and date, but not the hour, minute, or seconds.
     */
	var dsinput = document.getElementById(id);
	var dsio = new Object({'y':0,'m':0,'d':0,'h':0,'i':0,'s':0,'a':0});
	for(var i in dsio) {
		var dsidiv = document.getElementById(id+'_'+i);
		if(dsidiv) {
			dsio[i] = dsidiv;
		}
	}
	if(type=='y' || type=='m') {
		var d = daysInMonth(dsio.y.value,parseFloat(dsio.m.value));
		dsio.d.options.length=1;
		for(var i = 1; i <= d; ++i) {
			dsio.d.options[dsio.d.options.length]=new Option(i,dd(i));
		}
	}
	dsinput.value = '';
	var date = new Date();
	dsinput.value += (dsio.y ? dsio.y.value : date.getFullYear())+'-';
	dsinput.value += (dsio.m ? dd(parseFloat(dsio.m.value)+1) : dd(date.getMonth()))+'-';
	dsinput.value += (dsio.d ? dsio.d.value : dd(date.getDate()))+' ';
	dsinput.value += (dsio.h ? (dsio.a && dsio.a.value == 'am' ? dsio.h.value : dd((parseFloat(dsio.h.value)%12)+12)) : '12')+':';
	dsinput.value += (dsio.i ? dsio.i.value : '00')+':';
	dsinput.value += (dsio.s ? dsio.s.value : '00');
}

function bubbleSort(inputArray, start, rest) {
	start = start == null ? 0 : start;
	rest = rest == null ? inputArray.length : rest;
	for (var i = rest - 1; i >= start;  i--) {
		for (var j = start; j <= i; j++) {
			if (inputArray[j+1] < inputArray[j]) {
				var tempValue = inputArray[j];
				inputArray[j] = inputArray[j+1];
				inputArray[j+1] = tempValue;
      		}
   		}
	}
	return inputArray;
}

/************************************** BASE CLASS *******************************/
/**
 * Base class for inherriting event, and ajax call functions.
 */
var Base = function() {
	if (arguments.length) {
		if (this == window) { // cast an object to this class
			Base.prototype.extend.call(arguments[0], arguments.callee.prototype);
		} else {
			this.extend(arguments[0]);
		}
	}
};

Base.version = "1.0.1";

Base.prototype = {
	eventListeners: new Array(),
	
	extend: function(source, value) {
		var extend = Base.prototype.extend;
		if (arguments.length == 2) {
			var ancestor = this[source];
			// overriding?
			if ((ancestor instanceof Function) && (value instanceof Function) &&
				ancestor.valueOf() != value.valueOf() && /\bbase\b/.test(value)) {
				var method = value;
			//	var _prototype = this.constructor.prototype;
			//	var fromPrototype = !Base._prototyping && _prototype[source] == ancestor;
				value = function() {
					var previous = this.base;
				//	this.base = fromPrototype ? _prototype[source] : ancestor;
					this.base = ancestor;
					var returnValue = method.apply(this, arguments);
					this.base = previous;
					return returnValue;
				};
				// point to the underlying method
				value.valueOf = function() {
					return method;
				};
				value.toString = function() {
					return String(method);
				};
			}
			return this[source] = value;
		} else if (source) {
			var _prototype = {toSource: null};
			// do the "toString" and other methods manually
			var _protected = ["toString", "valueOf"];
			// if we are prototyping then include the constructor
			if (Base._prototyping) _protected[2] = "constructor";
			for (var i = 0; (name = _protected[i]); i++) {
				if (source[name] != _prototype[name]) {
					extend.call(this, name, source[name]);
				}
			}
			// copy each of the source object's properties to this object
			for (var name in source) {
				if (!_prototype[name]) {
					extend.call(this, name, source[name]);
				}
			}
		}
		return this;
	},

	base: function() {
		// call this method from any other method to invoke that method's ancestor
	},
	
	
	addEventListener: function (eventType,objectReference,objectFunction) {
		/**
		 * Add event listeners to this oject.
		 */
		this.eventListeners.push({'type':eventType,'ref':objectReference,'fctn':objectFunction});
	},
	
	dispatchEvent: function (eventType,params) {
		/**
		 * Dispatch an event for this object
		 */
		params = typeof(params) == 'object' ? params : null;
		var evt = {'type':eventType,'params':params,'target':this};
		for(var i in this.eventListeners) {
			if(this.eventListeners[i].type == eventType) {
				var itm = this.eventListeners[i];
				if(typeof(itm.ref[itm.fctn]) == 'function') {
					if(typeof(AJAXQue) != 'undefined' && AJAXQue.debug) {
						AJAXQue.addDebug('&nbsp;&nbsp;&nbsp;<font style="color:#0000ff;">'+(typeof(this['class']) == 'string' ? this['class'] : this.name)+'::dispatchEvent({type:'+eventType+',params:'+params+',target:'+this+'});</font>');
					}
					itm.ref[itm.fctn](evt)
				};
			}
		}
	}
};

Base.extend = function(_instance, _static) {
	var extend = Base.prototype.extend;
	if (!_instance) _instance = {};
	// build the prototype
	Base._prototyping = true;
	var _prototype = new this;
	extend.call(_prototype, _instance);
	var constructor = _prototype.constructor;
	_prototype.constructor = this;
	delete Base._prototyping;
	// create the wrapper for the constructor function
	var klass = function() {
		if (!Base._prototyping) constructor.apply(this, arguments);
		this.constructor = klass;
	};
	klass.prototype = _prototype;
	// build the class interface
	klass.extend = this.extend;
	klass.implement = this.implement;
	klass.toString = function() {
		return String(constructor);
	};
	extend.call(klass, _static);
	// single instance
	var object = constructor ? klass : _prototype;
	// class initialisation
	if (object.init instanceof Function) object.init();
	return object;
};

Base.implement = function(_interface) {
	if (_interface instanceof Function) _interface = _interface.prototype;
	this.prototype.extend(_interface);
};

var Core = Base.extend({
	type: "",
	
	constructor: function(c,cn) {
		this['class'] = typeof(c) == 'string' ? c : 'core';
		this['classname'] = typeof(cn) == 'string' ? cn : 'CORE';
	},
	
	call: function (divid,ur,callbkStr,disable) {
		/**
		 * This is how all ajax calls should be made for a class. pass the divid you want the data to be written to if you want it written to a div when the data comes back.
		 * If you do not then pass null to the divid. 
		 * ur is your parameters. It must always contain a type parameter.
		 * callbk is the function that you want called when your ajax call returns data. If you pass a divid you most likely wont use this.
		 * if you do not pass a divid this would be how you use the data that is returned.
		 */
		ur['class'] = this['class'];
		ur['classname'] = this['classname'];
		if(typeof(ur.type) != 'undefined') {
			AJAXQue.add(divid,DIRECTOR_PATH,ur,callbkStr,disable,this);
		} else {
			alert('type cannot be null '+traceAry(ur));
		}
	},
	
	callLater: function (fctn) {
		/**
		 * Pass a function to this and it will call this function after all other functions in the queue have processed.
		 * this is mainly used if you need to make multiple ajax calls and need something to happen once all of those are done
		 * you would call each of those an then call this one.
		 */
		if(fctn) {
			var ur = new URLRequest('type','wait');
			this.call(null,ur,fctn);
		}
	}
	
});


/*EXAMPLE 
(no examples)
*/