var IE;
var ua = navigator.userAgent.toLowerCase();
if (window.ActiveXObject)
	IE = ua.match(/msie ([\d.]+)/)[1]


/**页面初始化调用JS**/
function initPage() {
	if(g_spaceIDs!=""){
		window.setTimeout(checkNewMsg,2000) ;
		window.setInterval(checkNewMsg,30000);		
	}
	spacePointerControl();
}

/**
*显示/隐藏空间
**/
function spaceShowControl(obj) {
	var endPoint="/bfapp";
	var buffalo = new Buffalo(endPoint);
	var flag = 0;
	
	//判断浏览器和版本
	//var Sys = {};
	//var ua = navigator.userAgent.toLowerCase();
	//if (window.ActiveXObject){
	//	Sys.ie = ua.match(/msie ([\d.]+)/)[1]
	//}
	if(obj) {
		if($("wdSpaceList_all")) {
			if($("wdSpaceList_all").style.display=='none') {
				flag = 1;						
			}else{							
				flag = 0;			
			}
			//更新cache
			buffalo.remoteCall("UserPrint.updateSpaceShowFlag",[parseInt(g_accountID),flag], function(reply) {
				var pos1 = getElementPos("spaceShowControl");
				var pos2 = getElementPos("header_spaceList");
				var x = pos1.x-pos2.x-120;
			
				if (reply.getResult()==1){
					obj.innerHTML='<img src="/images/b.gif" width="19" height="19" border="0" align="absmiddle" />';
					//if(Sys.ie == 6){ 
					//	$("development").style.margintop = "2px";
					//}
					$("wdSpaceList_all").style.display='';
					$("defaultSpaceList_all").style.display='';
					$("hidespace_newfeed").style.display='none';
					$("wdSpaceList").style.display='';
					$("wdSpaceList").style.left=x + 'px' ;
				}else if(reply.getResult()==0) {
					obj.innerHTML='<img src="/images/a.gif" width="19" height="19" border="0" align="absmiddle" />';
					//if(Sys.ie == 6){ 
					//	$("development").style.margintop = "2px";
					//}
					$("wdSpaceList_all").style.display='none';
					$("defaultSpaceList_all").style.display='none';
					$("hidespace_newfeed").style.display='';
					$("wdSpaceList").style.display='none';
				}
				//设置空间指针
				spacePointerControl();				
		    });										
		}
	}
}


function spacePointerControl() {
	return;
	//当前空间定位
	if ($("head_spaceName_" + g_mySpaceID) != null && $("head_spaceName_" + g_mySpaceID).parentNode.style.display=='') {
		if(g_mySpaceID == g_fSpaceIDs){
			//计算指向目标中间位置的坐标
			var pos = getElementPos("head_spaceName_" + g_mySpaceID);
			var x = pos.x;
			var y = pos.y;	
			//alert("111");
			
			//alert($("head_spaceName_" + g_mySpaceID).innerHTML);
			//if($("head_spaceName_" + g_mySpaceID).innerHTML == "<a href='/app/weibo.jsp'>我的新浪微博</a><span id='weibofeed' hasNew=0><img src='/images/blank12.gif' align='absmiddle' /></span>"){
			//	alert("asasas");
			//	$("pt-header").style.left = (x+32) + 'px' ;
			//}
			//else{
				
			//}
		}
		
		
		var _ox = pub_findPosX($("header_spaceList")) ;
		var _oy = pub_findPosY($("header_spaceList")) ;
		var _ow = $("header_spaceList").offsetHeight ;
		var _x = pub_findPosX($("head_spaceName_" + g_mySpaceID)) - _ox ;
		var _y = pub_findPosY($("head_spaceName_" + g_mySpaceID)) - _oy - 4 ;
		var _w = $("head_spaceName_" + g_mySpaceID).offsetWidth ;
		var _h = $("head_spaceName_" + g_mySpaceID).offsetHeight ;
		if (((_ow - _y - _h -1)) > 20){
			$("pt-line").style.display = '' ;
			$("pt-line").style.height = (_ow - _y - _h -1) + 'px' ;
		} else {
			$("pt-line").style.display = 'none' ;
		}
		$("pt-line").style.top = (_y + _h + 10) + 'px' ;
		$("pt-line").style.left = (_x + _w /2 - 7) + 'px' ;
	}else{
		if($("pt-line")) {
			$("pt-line").style.display = 'none';
		}
	}
}
//显示状态修改列表
function SH_ShowState(obj,evt) {
	var _x = pub_findPosX(obj) ;
	var _y = pub_findPosY(obj) ;
	$('stateMenu').style.left = (_x - 20) + 'px' ;
	$('stateMenu').style.top = (_y + 15) + 'px' ;
	$('stateMenu').style.display = '' ;
	evt.cancelBubble=true;
}
//显示搜索选项列表
function SH_ShowSearchOpt(obj,evt) {
	var _x = pub_findPosX(obj) ;
	var _y = pub_findPosY(obj) ;
	$('searchOpts').style.left = (_x - 150) + 'px' ;
	$('searchOpts').style.top = (_y + 20) + 'px' ;
	$('searchOpts').style.display = '' ;
	evt.cancelBubble=true;
}
//修改状态
function SH_SetState(state) {
	sh_loginState = state ;
	//修改_friend_datas中的空间在线状态值
	for (var k = 0 ; k < _friend_datas.length ; k ++) {
		var group= _friend_datas[k];		
		if(group.cid == g_mySpaceID){
			group.imstatus = state ;				
		}
	}
	//将空间设置的在线状态保存到Cookie中
	setCookie("TIXA_IMSTATUS_USERSPACE"+g_mySpaceID, state);
	scriptConn(imServerUrl+"updatestatus?uids="+g_mySpaceID + ":" + state +"&clientype=1&callback=SH_StateCallBack");
   	$('stateMenu').style.display = 'none' ;
}
//修改状态回调方法
function SH_StateCallBack() {
	//设置显示状态
	if (sh_loginState == "1") {
		$("tip_state").innerHTML = '<img src="/images/img-online.gif" align="absmiddle"/><a id="sh-state" href="#" onclick="SH_ShowState(this,event)">我在线</a>' ;
	} else if (sh_loginState == "3") {
		$("tip_state").innerHTML = '<img src="/images/img-hide.gif" align="absmiddle"/><a id="sh-state" href="#" onclick="SH_ShowState(this,event)">我隐身</a>' ;
	} else if (sh_loginState == "2") {
		$("tip_state").innerHTML = '<img src="/images/img-busy.gif" align="absmiddle"/><a id="sh-state" href="#" onclick="SH_ShowState(this,event)">我忙碌</a>' ;
	} else if (sh_loginState == "4") {
		$("tip_state").innerHTML = '<img src="/images/img-left.gif" align="absmiddle"/><a id="sh-state" href="#" onclick="SH_ShowState(this,event)">我离开</a>' ;
	}
	//设置状态列表中对勾的显示
	for (var i = 1 ; i <= 4 ; i++) {
		if ((i+'') == sh_loginState) {
			$("sh_state_" + i).innerHTML = '√' ;
		} else {
			$("sh_state_" + i).innerHTML = '' ;
		}
	}
	//设置IM窗口内的状态显示
	if ($('statusselect' + g_mySpaceID) != null) {
		$('statusselect' + g_mySpaceID).value = sh_loginState ;
	}
}

//创建背景
function createBgDiv(stuffix){
	var bgDiv = document.createElement("div");
	bgDiv.setAttribute("id", "fullBgDiv" + stuffix);
	bgDiv.style.position = "absolute";
	bgDiv.style.background = "#ffffff";
	bgDiv.style.filter = "progid:DXImageTransform.Microsoft.Alpha(style=3,opacity=20,finishOpacity=100";
	bgDiv.style.opacity = "0.6";
	bgDiv.style.top = "0px";
	bgDiv.style.left = "0px";
	bgDiv.style.width = "100%";
	bgDiv.style.height = "100%";
	bgDiv.style.zIndex = 100; 
	bgDiv.onclick = function(event) {
		evt =  event || window.event ;
		evt.cancelBubble = true ;
	}
	document.body.appendChild(bgDiv);
	return bgDiv;
}

//删除背景
function removeBgDiv(stuffix){
	var bgDiv = document.getElementById('fullBgDiv' + stuffix) ;
	if (bgDiv != null) {
		document.body.removeChild(bgDiv);
	}
}

function pub_findPosX(obj) {
	var curleft = 0;
	if (obj) {
		if (obj.offsetParent) {
			while (obj.offsetParent) {
				curleft += obj.offsetLeft;
				obj = obj.offsetParent;
			}
		} else {
			if (obj.x) {
				curleft += obj.x;
			}
		}
	}
	return curleft;
}
function pub_findPosY(obj) {
	var curtop = 0;
	if (obj) {
		if (obj.offsetParent) {
			while (obj.offsetParent) {
				curtop += obj.offsetTop;
				obj = obj.offsetParent;
			}
		} else {
			if (obj.y) {
				curtop += obj.y;
			}
		}
	}
	return curtop;
}
function set_Info(p_byId,p_msg,p_display,p_class){
   var div_o = get_obj(p_byId);
   if(div_o==null || div_o=='undefined'){
     //alert(div_o +" p_msg:"+ p_msg);
     return ;
   }
   try{
       div_o.innerHTML = p_msg;
       if(isEmpty(p_class)==true){
       		div_o.className=p_class;
       }
       div_o["style"]["display"]=p_display;
       }catch(e){}
}
String.prototype.isSpecialStr = function () {
	var SPECIAL_STR = "~^*;'\"><[]{}\\|\u2018,.\u201c[]{}@#$%&";
	var result = new Array(2);
	result[0] = "false";
	result[1] = "";
	for (i = 0; i < this.length; i++) {
		if (SPECIAL_STR.indexOf(this.charAt(i)) != -1) {
			result[0] = "true";
			result[1] = this.charAt(i);
			return result;
		}
	}
	return result;
}
// #go# 表单验证—————————————————————————————————————————————————————————————
	/**
	*  判断是否为空
	*/
	function isEmpty(str){
	       if(str.toString().replace(/^\s+|\s+$/g,'')==''){
	          return false;
	       }else{
	          return true;
	       }
	}
	
	/**
	*  把空格去掉
	*/
	function clearBlankSpace(txt){
		return txt.replace(/^\s+|\s+$/g,'');
	}
	
	/**
	*  替换
	*/
	function replace_all(str,p_reg,rep){
	    var regx = new RegExp(p_reg,"gi");
		return str.replace(regx,rep);
	}
	
   	/**
	*  替换所有html标记
	*  可以继续完善
	*/
	function replace_html(txt){
		return txt.replace(/(<[^>]*>)|&nbsp;+/g,'');
	}
	
	/*
	 * 截去字符串最后一个逗号
	 */
	function cutLastlyComma(s){
		var str = s;
	       //截去字符串最后一个逗号
	       if(s.indexOf(",")!=-1){
	    	   var size = s.length;
	    	   var comma = s.substring(size-1,size);
	    	   if(clearBlankSpace(comma)==","){
	    		   str = s.substring(0,size-1);
	    	   }
	       }
	       return str;
	}
	
	    /**
	     * 
	     * @param file    图片路径
	     * @param index   构建名称
	     * @param defaultPath 无效时返回内容
	     * @return
	     */
	    function getNewPath(file,index,defaultPath){
	    	if(isEmpty(file)==false){
	    		return defaultPath;
	    	}
        	var   FileLength = file.length;
    	  	var   beginIndex   =   file.lastIndexOf("."); 
    	  	var   fileTypes   =   file.substring(beginIndex,FileLength);
    		var   midFile = file.substring(0,beginIndex) + index +fileTypes;
    		return midFile;
	    }
	    
	/**
	*  整数判断
	*/
	function isInt(values){
		var reg = /^(0|[1-9]|[1-9][0-9]+)$/;
	    if(reg.test(values.toString())){
			return true;// is int type
		}else{
			return false;
		}
	}
	
	
	/**
	*  是否大于零
	*/
	function gt_zero(values){
		if(parseInt(values,10)<=0){
			return false;
		}else{
			return true;
		}
	}
	
	/**
	*  浮点数判断
	*/
	function isdouble(values){
	     //var reg = /^(0|[1-9]{1}|[1-9][0-9]{1,16})\.([0-9]{1,2})$/;
		 var reg = /^(0|[1-9]{1}|[1-9][0-9]+)\.([0-9]+)$/;//小数点后的位数验证到外面验证
	    if(reg.test(values.toString())){
			return true;// is double type
		}else{
			return false;
		}
	}
	
	/**
	*  浮点数的 小数位数 和 整数部分 长度判断
	*/
	function floatLengthVa(values,maxLengths,bit){
			var e = values.lastIndexOf(".");
			var floatEnd = values.substring(e+1, values.length); //小数点后面的长度的内容 .[00]
			if(floatEnd.length>bit){
				return "pointLengthErr";//如果输入的小数位，大于指定的小数位那么不让通过
			}
			var floatBegin = values.substring(0, e); //小数点前面的数 1234.
			if(floatBegin.length>(maxLengths-bit)){
				
				return "intLengthErr";//如果输入的小数的整数部分长度超过了规定之下的整数长度
			}
	}
	
	
	
	/**
	*    文件类型判断 如果不是返回 false 是 返回 true
	*/
	function isfiletype(filepath){
	       //var re=/^(.)*(\.)?(doc|ppt|rar|jpg|gif)$/i;
	       var re=/^(.)*(\.)(doc|ppt|rar|jpg|gif)$/;
			if(!re.test(filepath.toLowerCase())){	
				return false;
			}else{
				return true;
			}
	}
	
	
	/**
	*    文件类型判断 如果不是返回 false 是 返回 true
	*/
	function isImgype(filepath){
	       //var re=/^(.)*(\.)?(doc|ppt|rar|jpg|gif)$/i;
	       var re=/^(.)*(\.)(jpg|gif)$/;
			if(!re.test(filepath.toLowerCase())){	
				return false;
			}else{
				return true;
			}
	}
	
	/**
	*    文件类型判断 如果不是返回 false 是 返回 true
	*/
	function isImgype2(filepath){
	       var re=/^(.)*(\.)(jpg|gif|bmp)$/;
			if(!re.test(filepath.toLowerCase())){	
				return false;
			}else{
				return true;
			}
	}
	
	/**
	*    判断路径是否是　[c,d...]:\ 开头文件
	*/
	function existPath(p_path){
	       var re=/^(([a-zA-Z]:\\){1}?)|(([a-zA-Z]:\/){1}?)/;
			if(!re.test(p_path)){
				return false;
			}else{
				return true;
			}
	}
	
	
	/**
	*    电子邮件格式判断 如果不是返回 false 是 返回 true
	*/
	function isEmail(mail){
			var zenzeStr=/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/;
	        var bol = (new RegExp(zenzeStr).test(mail));
	        if(bol==true){
	 			return true;
	        }else{
	    		return false;
	        }  
	}
	
	/**
	*    支持带中文参数域名判断
	*/
	function isHttp(url){
	       var re=/^(http:\/\/){1}([\w-]+\.)+[\w-]+(\/[\u4e00-\u9fa5A\w-   .\/?%&=]*)?/;
			if(!re.test(url)){
				return false;
			}else{
				return true;
			}
	}
	
	/**
	*    电话验证
	*    支持 
	*    (010)66333132
	*         66333124
	*     0728－66333120
	*     0728-66333120
	*/
	function isPhone(str){
		
		var reg=/^(([0-9]{3,4}[\-|\－]{1})|([0-9]{3,4}))?[0-9]{7,8}$/;
		
	  	var bol = reg.test(str);
		
	        if(bol==true){
	 			return true;
	        }else{
	    		return false;
	        } 
	}
	
	/**
	*    手机格式模糊验证
	*/
	function likeMobile(mob){
		
		//var reg=/^((13[0-9]+)|(159[0-9]+))$/;
		var reg=/^((13[0-9]+)|(15[0-9]+)|(18[0-9]+))$/;
	  	var bol = reg.test(mob);
		
	        if(bol==true){
	 			return true;
	        }else{
	    		return false;
	        } 
	        //alert(bol);
	}
	
	/**
	*    手机格式验证
	*/
	function isMobile(mob){
		
		//var reg=/^((13[0-9]{9})|(159[0-9]{8}))$/;
		var reg=/^((\+{0,1}86){0,1})1[0-9]{10}$/;
	  	var bol = reg.test(mob);
		
	        if(bol==true){
	 			return true;
	        }else{
	    		return false;
	        } 
	        //alert(bol);
	}
	
		/**
	*    手机he电话格式验证
	*/
	function isTel(str){
		if(isPhone(str)==true || isMobile(str)==true)
			return true;
		return false;	
	}
	
	
	/**
	*    短日期格式验证 2005-02-01
	*/
	function isShotdate(str){
		
		var reg=/^[0-9]{1,4}\-([0-1][0-2]|[0][0-9])\-([0-3][2]|[0-2][0-9])$/;
		
	  	var bol = reg.test(str);
		
	        if(bol==true){
				
	 			return true;
				
	        }else{
				
	    		return false;
				
	        } 	
			
	    return bol;
	}
	
	/**
	*    短时间验证 22:59:59
	*/
	function isShottime(str){
		
		var reg=/^[0-2]?[0-3]\:[0-5]?[0-9]\:[0-5]?[0-9]$/;
		
	  	var bol = reg.test(str);
		
	        if(bol==true){
				
	 			return true;
				
	        }else{
				
	    		return false;
				
	        } 	
			
	    return bol;
	}
	
	/**
	*    长日期验证 2005-02-01 22:59:59
	*/
	function islongdate(str){
		
		var reg=/^[0-9]{1,4}\-([0-1][0-2]|[0][0-9])\-([0-3][2]|[0-2][0-9])\s[0-2]?[0-3]\:[0-5]?[0-9]\:[0-5]?[0-9]$/;
		
	  	var bol = reg.test(str);
		
	        if(bol==true){
				
	 			return true;
				
	        }else{
				
	    		return false;
				
	        } 	
			
	    return bol;
	}
	
	/**
	*   传进来一个以XX号分割的字符串，返回一个数组
	* 
	*/
	function spli(str,f){
		var list = str.split(f);
		if(list==null){
			return null;
		}else{
			return list;
		}
	}
	
	/**
	*  1. 插入排序->直接插入法排序
	*   传一个数组过来
	*/
	function InsertSort(arr) {
		
	  //var st = new Date();
	  
	  var temp, j;
	  
	  for(var i=1; i<arr.length; i++) {
	  	
	   if((parseInt(arr[i],10)) < (parseInt(arr[i-1],10))) {
	   	
	    temp = arr[i];
		
	    j = i-1;
		
	    do {
			
	     arr[j+1] = arr[j];
		 
	     j--;
		 
	    }while (j>-1 && parseInt(temp,10) < parseInt(arr[j],10));
		
	    arr[j+1] = temp;
		
	   }//endif
	   
	  }
	  
	  //status = (new Date() - st) + ' ms';
	  
	  return arr;
	}
	
	
	/**
	*   交换排序->冒泡排序
	*   传一个数组过来
	*/
	function bubbleSort(arr) {
	 // var st = new Date();
	  var temp;
	  //var exchange;
	  for(var i=0; i<arr.length; i++) {
	  	
	  // exchange = false;
	   for(var j=arr.length-2; j>=i; j--) {
	   	
	    if(parseInt(arr[j+1],10) < parseInt(arr[j],10)) {
			
	     temp = arr[j+1];
	     arr[j+1] = arr[j];
	     arr[j] = temp;
	     exchange = true;
		 
	    }
		
	   }
	   
	  // if(!exchange) break;
	  
	  }
	  
	 // status = (new Date() - st) + ' ms';
	 
	  return arr;
	}
	
	/**
	*   选择排序->直接选择排序
	*   传一个数组过来
	*/
	function selectSort(arr) {
	  //var st = new Date();
	  var temp;
	  
	  for(var i=0; i<arr.length; i++) {
	  	
	   	   var k = i;
		   
		   for(var j=i+1; j<arr.length; j++) {
		   	
		    if(parseInt(arr[j],10) < parseInt(arr[k],10))  k = j;
			 
		   }
		   
		   if (k != i){
		    temp = arr[i];
		    arr[i] = arr[k];
		    arr[k] = temp;
		   }
		   
	  }
	  //status = (new Date() - st) + ' ms';
	  return arr;
	}
	 
	/**
	*   删除重复记录[(1,2,1,2,3 = 1,2,3)(a,b,a,c,d = a,b,c,d)]
	*   传一个数组过来
	*/
	function getUnique(someArray){
		
	 	tempArray=someArray.slice(0);//复制数组到临时数组
	 
		 for(var i=0;i<tempArray.length;i++){
		 	
			  for(var j=i+1;j<tempArray.length;){
			  	
				   if(tempArray[j]==tempArray[i]){
				   	
				   //后面的元素若和待比较的相同，则删除并计数；
				   //删除后，后面的元素会自动提前，所以指针j不移动
				   
				    tempArray.splice(j,1);
					
				   }else{
				   	
				    j++;
					
				   }
				   
				   //不同，则指针移动
			  }
		  
		 }
	 
	 return tempArray;
	 
	}
	 
	 
	  //把 -换成　""
	function replaceTxt(txt){
		return txt.replace(/\-/g,"");
	}
	 //把 /换成　""
	function replaceTxt2(txt){
		return txt.replace(/\//g,"");
	}
	 //把 \换成　/
	function replaceTxt3(txt){
		return txt.replace(/\\/g,"/");
	}
	
	 //把 *换成　x
	function replaceTxt4(txt){
	    var s = "  "+txt+" ";
	    
		var ss = s.replace(/\*/g,"x");
		alert(ss);
		return ss;
	}
	
	 //把 \换成　/
	function replaceTxtTrim(txt){
		return txt.replace(/\" "/g,"");
	}
	
	/**
	*   传一个提示语，返回 true | false
	*/
	function yesORno(msg){
	   var bol = confirm(msg);
	   return bol;
	}
	
	//reload form
	function cleraFm(fmName){
		document.forms[fmName].reset();
	}
	
	//iframe提交 然后刷新iframe上层父窗口
	function reload_iframe_parent(){
		window.parent.location.reload();
	}


// #go# 取对象 ——————————————————————————————————————————————————————————————

	/**
	 * @author sunkh
	 */
	//form表单的name的名称
	function setFmName(form_Name){
		fmName = form_Name;
	}
	
	//得到ID对象
	function get_obj(obj_Id){
		try{
			if(document.getElementById(obj_Id)!=null){
				return document.getElementById(obj_Id);
			}
		//alert("getId_obj(obj_Id) return null! at byidobj.js")
		}catch(e){
			return null;
		}
	}
	
	//得到ID对象
	function getId_obj(obj_Id){
		try{
			if(document.getElementById(obj_Id)!=null){
				return document.getElementById(obj_Id);
			}
		//alert("getId_obj(obj_Id) return null! at byidobj.js")
		}catch(e){
			return null;
		}
		
	}
	
	//得到列表表单对象
	function getListObj(byname){
		if(document.getElementsByName(byname)!=null){
			return document.getElementsByName(byname);
		}
		alert("getListObj(byname) return null! at byidobj.js")
		return null;
	}
	
	//得到FORM对象
	function getfm_obj(fm_name){
		if(document.forms[fm_name]!=null){
			return document.forms[fm_name];
		}
		//alert("getfm_obj(fm_name) return null! at byidobj.js")
		return null;
	}
	
	//得到document.all对象
	function getAll_obj(obj_name){
		if(document.all[obj_name]!=null)
			return document.all[obj_name];
		else{
			alert("getAll_obj(obj_name) return null! at byidobj.js")
			return null;
		}	
	}



// #go# 下拉操作—————————————————————————————————————————————————————————————

	function get_select(by_Id){
	    var selectValue="";
		var obj = get_obj(by_Id);
			for(var i=0;i<obj.length;i++){
			   if(obj.options[i].selected){
				  selectValue = obj.options[i].value;
				}
			 }
			 return selectValue;
	}
	
	/**
	 * 适应控件 下拉列表
	*@method defaultValue　下拉默认选中
	*@param obj_Id　下拉ID
	*@param indexValue　要被选中那一项的值
	*/
	function selectIndexc(obj_Id,indexValue){
		var obj = get_obj(obj_Id);
		for(var i=0;i<obj.length;i++){
			var v =obj.options[i].value;
			if(v==indexValue){
				obj.options[i].selected=true;
			}
		}
	}
	
	/**
	 * 适应控件 下拉列表
	*@method defaultValue　下拉默认选中
	*@param obj_Id　下拉ID
	*@param indexValue　要被选中那一项的值
	*/
	function selectIndexcText(obj_Id,indexText){
		var obj = get_obj(obj_Id);
		if(obj==null || obj=="undefined")
		  return ;
		  
		for(var i=0;i<obj.length;i++){
			var temp_text =obj.options[i].text;
			//alert(temp_text+" "+indexText)
			if(temp_text==indexText){
				obj.options[i].selected=true;
			}
		}
	}
	
	/**
	 * 适应控件 下拉列表
	 * @method get_selectedIndex　得到下拉选中项索引值
	 * @param  obj_Id　下拉ID
	*/
	function get_selectedIndex(obj_Id){
	        var obj = get_obj(obj_Id);
			if(obj!=null){
				return obj.selectedIndex;
			}
	}
	
	/**
	 * 适应控件 下拉列表
	 * @method get_selected　得到下拉当前选中的值
	 * @param  obj_Id　    下拉ID
	*/
	function get_selectedtext(by_Id){
		var backtrack="";
		var obj = get_obj(by_Id);
		if(obj!=null){
			for(var i=0;i<obj.length;i++){
			   if(obj.options[i].selected){
				  backtrack = obj.options[i].text;
				}
			 }
		}
			  return backtrack;
	}
	
// #go# checkbox操作————————————————————————————————————————————————————————

	/*
	判断是否有选中的项目
	boxName 名称
	过时
	*/
	function if_selectCheckBox(boxName){
		return exist_checked(boxName);
	}
	
	/*
	判断是否有选中的项目
	boxName 名称
	*/
	function exist_checked(boxName){
		var obj=getListObj(boxName) 
		for(var i=0;i<obj.length;i++){
				if(obj[i].checked == true)
					return true;
		}
		return false;
	}

	/*
	判断是否有没有选中的，如果有没有选中的返回 false 否则 true
	boxName 名称
	*/
	function is_checked_all(boxName){
		var obj=getListObj(boxName) 
		for(var i=0;i<obj.length;i++){
				// 是否存在未选中的
				if(obj[i].checked == false)
					return false;
		}
		return true;
	}

	/*
	适应控件  CheckBox 全部选中
	boxName 名称
	*/
	function allselectedobj(boxName){
		var obj=getListObj(boxName) 
		for(var i=0;i<obj.length;i++){
			if(obj[i].disabled==true)continue;
				obj[i].checked = true;
		}
		return "-1";
	}
	
	/*
	适应控件  CheckBox 全部不选中
	boxName 名称
	*/
	function allNotSelect(boxName){
		var transit=getListObj(boxName) 
		for(var i=0;i<transit.length;i++){ 
				transit[i].checked = false;
		}
		return 0;
	}
	
	/*
	CheckBox
	返回checkbox选中的值和未选中的值，未选中的值用1代替,选中了的直接取checkbox的value
	reason_chk_name 名称
	*/
	function getSelectOrNotSelectValue(reason_chk_name){
		  var apend_str = "";   
	      var chklist=getListObj(reason_chk_name);   
	      for(var i=0;i<chklist.length;i++){
	      		if(chklist[i].checked){
	      			apend_str += chklist[i].value+",";//取选中的值  
	      		}else{
	      		    apend_str += "1,";//未选中的值  
	      		}
	      }
	      //截去字符串最后一个逗号
	      apend_str = cutLastlyComma(apend_str);
	      return apend_str; 
	}
	
	/*
	CheckBox
	将选中的checkbox　拼成字符串
	reason_chk_name 名称
	*/
	function checkboxvalue(reason_chk_name){
		  var apend_str = "";   
	      var chklist=getListObj(reason_chk_name);   
	      for(var i=0;i<chklist.length;i++){
	      		if(chklist[i].checked)
	      			apend_str += chklist[i].value+",";//取选中的值  
	      }
	      //截去字符串最后一个逗号
	      apend_str = cutLastlyComma(apend_str);
	      return apend_str; 
	}
	
	/*
	CheckBox
	将未选中的checkbox　拼成字符串
	reason_chk_name 名称
	*/
	function not_checked_value(reason_chk_name){
		  var apend_str = "";   
	      var chklist=getListObj(reason_chk_name);   
	      for(var i=0;i<chklist.length;i++){
	      		if(chklist[i].checked==false)
	      			apend_str += chklist[i].value+",";//取选中的值  
	      }
	      //截去字符串最后一个逗号
	      apend_str = cutLastlyComma(apend_str);
	      return apend_str; 
	}

		
	/*
	判断是否全选，全选返回 0 否则返回选中以逗号分割的串连ID号
	radioName 名称
	radioValue 值
	*/
	function isAllNotAllselect(boxName){
		
		var chklist=getListObj(boxName);
		var lengs = chklist.length; 
		var j=0;
		for(var i=0;i<chklist.length;i++)
		{ 
			if(chklist[i].checked) 
				j++;
		}
		//alert(lengs+"  "+j);
		if(lengs==j || j==0)
			return 0;
		else
			return checkboxvalue(boxName);
	}
	/*
	判断复选框是否有选定值，若无返回0，否则返回选中以逗号分割的串连ID号
	radioName 名称
	radioValue 值
	*/
	function isAllNotAllselect1(boxName)
	{
		
		var box = document.getElementsByName(boxName)
	      if(box)
		  {
			  var tmp = new Array();
			  for(var i=0;i<box.length;i++)
			  {
					if(box[i].checked)
					{
						tmp.push(box[i]);
					}	       
			  }
			  if(tmp.length > 0)
			  {
			      return checkboxvalue(boxName);
			  }else
			  {
				  return 0;
			  }
		  }else
		  {
			  alert(boxName + "不存在");
		  }
	}
	/*
	加载默认选中的checkbox
	checkbox_name 名称
	str 用逗号分割的字符串
	*/
	function ischecked(checkbox_name,str){
		//alert(str);
		var tmp = str.split(",");
		for(var i=0;i<tmp.length;i++){
			radioChecked(checkbox_name,tmp[i])
		}
	}

// #go# radio操作———————————————————————————————————————————————————————————
	/**
	 *   适应控件 radio
		 取radio默认选中值
		*@method byname　radio组名称
	*/
	function getselectedvalue(byname){
		var radioobj=getListObj(byname); 
		//alert(transit.length);
		for(var i=0;i<radioobj.length;i++){ 
			if(radioobj[i].checked) 
				return radioobj[i].value;
		}
		return "-1";
	}
	
	/**
	 *   适应控件 radio
		 取radio默认选中值
		*@method byname　radio组名称
	*/
	function getRadioEd(byname){
	    var value = "";
		var radioobj=getListObj(byname); 
		//alert(transit.length);
		for(var i=0;i<radioobj.length;i++){ 
			if(radioobj[i].checked) {
				value = radioobj[i].value;
				break;
			}
		}
		return value;
	}
	
	/*
	默认选中某个radio或者CheckBox
	radioName 名称
	radioValue 值
	*/
	function radioChecked(radioName,radioValue){
		var transit=getListObj(radioName) 
		for(var i=0;i<transit.length;i++){ 
			if(transit[i].value==radioValue){
				transit[i].checked = true;
			}
		}
		return 0;
	}
	
	function subCNString (str,len,app){
	var j = 0;
	if (typeof(app) == 'undefined') {
		app = '...' ;
	}
	for (var i = 0; i < str.length; i++) {
		if (str.charCodeAt(i) > 255) {
			j += 2;
		} else {
			j++;
		}
		if (j > len && (i+1) != str.length) {
			return str.substring(0, i) + app ;
		}
	}
	return str;
}	
	
// #go# 页面提示DIV，等待并自动消失[1]——————————————————————————————————————————
    // 前提条件是DIV必须有 filter:alpha(Opacity=0); position: absolute;
	var pub_clearTimeObj = null;	
	
	function pub_setOpacity_action(p_div_obj){
	    pub_opacity_wait =0;
	    if(p_div_obj==null || p_div_obj=='undefined')
	    return ;
	    
		if(document.all) {
	        p_div_obj.filters.alpha.opacity = 100;
		}else{
			p_div_obj.style.opacity = 1;
		}
	
	    window.setTimeout(function(){pub_setOpacity(p_div_obj)}, 250);
	}
	
	function pub_setOpacity(p_div_obj) {

			var stopTime = false;
	
			if(document.all) {
	
				if(p_div_obj.filters.alpha.opacity > 0) {
					p_div_obj.filters.alpha.opacity -= 5;
				}else{
					stopTime = true;
				}
	
			} else {
	
				if(p_div_obj.style.MozOpacity > 0) {
					p_div_obj.style.MozOpacity -= 0.05;
				}else{
					stopTime = true;
				}
			}
			
			if(stopTime==true) {
				window.clearTimeout(pub_clearTimeObj);
				p_div_obj.style["display"] = "none";
			}else{
				pub_clearTimeObj = window.setTimeout(function(){pub_setOpacity(p_div_obj)}, 250);
			}
	}
// #go# 页面提示DIV，等待并自动消失[2]——————————————————————————————————————————
	function set_display_action(p_div_obj){

	    if(p_div_obj==null || p_div_obj=='undefined')
	    return ;

	    window.setTimeout(function(){set_display(p_div_obj)}, 3000);
	}
	function set_display(p_obj){
	    p_obj.style["display"] = "none";
	}
// #go# 其它操作———————————————————————————————————————————————————————————
	/*
	*隐藏显示DIV
	*/
	function s(s){if (!$(s)) return; $(s).style.display = "block";}
	function h(s){if (!$(s)) return; $(s).style.display = "none";}
	function sh(s){if (!$(s)) return; $(s).style.display = $(s).style.display == "none"?"block":"none";}
	function hs(s){if (!$(s)) return; $(s).style.display = $(s).style.display == "block"?"none":"block";}
	function vv(s){if (!$(s)) return; $(s).style.visibility = "visible";}
	function vh(s){if (!$(s)) return; $(s).style.visibility = "hidden";}
	
//TRIM Begin
function LTrim(str) {
	var whitespace = new String(" \t\n\r");
	var s = new String(str);
	if (whitespace.indexOf(s.charAt(0)) != -1) {
		var j = 0, i = s.length;
		while (j < i && whitespace.indexOf(s.charAt(j)) != -1) {
			j++;
		}
		s = s.substring(j, i);
	}
	return s;
}
function RTrim(str) {
	var whitespace = new String(" \t\n\r");
	var s = new String(str);
	if (whitespace.indexOf(s.charAt(s.length - 1)) != -1) {
		var i = s.length - 1;
		while (i >= 0 && whitespace.indexOf(s.charAt(i)) != -1) {
			i--;
		}
		s = s.substring(0, i + 1);
	}
	return s;
}
function Trim(str) {
	return RTrim(LTrim(str));
}
//TRIM End
//获取字符串占多少字节
String.prototype.getBytesNum = function () {
	var ret = true;
	var len = 0;
	for (var i = 0; i < this.length; i++) {
		len++;
		if (this.charCodeAt(i) >= 255) {
			len++;
		}
	}
	return len;
}
//浅复制 
function clone(cloneObj){ 
	var newObj = new Object(); 
	for(elements in cloneObj){ 
		newObj[elements] = this[elements]; 
	} 
	return newObj; 
}
//深复制 
function cloneAll(cloneObj){ 
	function clonePrototype(){} 
	clonePrototype.prototype = cloneObj; 
	var obj = new clonePrototype(); 
	for(var ele in obj){ 
		if(typeof(obj[ele])=="object") obj[ele] = cloneAll(obj[ele]); 
	} 
	return obj; 
}
//将带有PX单位的值转为数值
function doParseInt(val,defaultVal) {
	var backVal = 0 ;
	val = val + '' ;
	try{
		val = val.replace('px','') ;
		backVal = parseInt(val,10) ;
	} catch(ex) {
		backVal = defaultVal ;
	}
	return backVal ;
}
//div显示信息
function toAlert(prefix,vals,num) {
	if (!num) num = 1 ;
	if (document.getElementById('toAlertBG'))
		top.document.body.removeChild(document.getElementById(prefix + 'toAlertBG')) ;
	var bgObject = top.document.createElement("div");
	bgObject.setAttribute("id", prefix + "toAlertBG");
	bgObject.style.position = "fixed";
	bgObject.style.top = "0px";
	bgObject.style.background = "#f0f";
	bgObject.style.left = ((num-1) * 200) + "px";
	bgObject.style.width = "200px";
	bgObject.style.height = "auto";
	bgObject.style.zIndex = 10000 ;
	top.document.body.appendChild(bgObject);
	if (vals) {
		var dis = '' ;
		for (var i = 0 ; i < vals.length ; i++) {
			dis += vals[i] + '<br/>' ;
		}
		bgObject.innerHTML = prefix+'<br/>' + dis ;
	} else {
		bgObject.innerHTML = prefix+'<br/>'+vals ;
	}
}

/**.浏览器判断--->公共方法*/
function this_browser(){
       
	   if(navigator.userAgent.indexOf("MSIE")>0)return 1;
	   if(isFirefox=navigator.userAgent.indexOf("Firefox")>0)return 2;
	   if(isSafari=navigator.userAgent.indexOf("Safari")>0)return 3;
	   if(isCamino=navigator.userAgent.indexOf("Camino")>0)return 4;
	   if(isMozilla=navigator.userAgent.indexOf("Gecko/")>0)return 5;
	   return 0;
}

/***********************************
 * prototype.js 开始
 ***********************************/
/*  Prototype JavaScript framework, version 1.5.1
 *  (c) 2005-2007 Sam Stephenson
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the Prototype web site: http://www.prototypejs.org/
 *
/*--------------------------------------------------------------------------*/

var Prototype = {
  Version: '1.5.1',

  Browser: {
    IE:     !!(window.attachEvent && !window.opera),
    Opera:  !!window.opera,
    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1
  },

  BrowserFeatures: {
    XPath: !!document.evaluate,
    ElementExtensions: !!window.HTMLElement,
    SpecificElementExtensions:
      (document.createElement('div').__proto__ !==
       document.createElement('form').__proto__)
  },

  ScriptFragment: '<script[^>]*>([\u0001-\uFFFF]*?)</script>',
  JSONFilter: /^\/\*-secure-\s*(.*)\s*\*\/\s*$/,

  emptyFunction: function() { },
  K: function(x) { return x }
}

var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}

var Abstract = new Object();

Object.extend = function(destination, source) {
  for (var property in source) {
    destination[property] = source[property];
  }
  return destination;
}

Object.extend(Object, {
  inspect: function(object) {
    try {
      if (object === undefined) return 'undefined';
      if (object === null) return 'null';
      return object.inspect ? object.inspect() : object.toString();
    } catch (e) {
      if (e instanceof RangeError) return '...';
      throw e;
    }
  },

  toJSON: function(object) {
    var type = typeof object;
    switch(type) {
      case 'undefined':
      case 'function':
      case 'unknown': return;
      case 'boolean': return object.toString();
    }
    if (object === null) return 'null';
    if (object.toJSON) return object.toJSON();
    if (object.ownerDocument === document) return;
    var results = [];
    for (var property in object) {
      var value = Object.toJSON(object[property]);
      if (value !== undefined)
        results.push(property.toJSON() + ': ' + value);
    }
    return '{' + results.join(', ') + '}';
  },

  keys: function(object) {
    var keys = [];
    for (var property in object)
      keys.push(property);
    return keys;
  },

  values: function(object) {
    var values = [];
    for (var property in object)
      values.push(object[property]);
    return values;
  },

  clone: function(object) {
    return Object.extend({}, object);
  }
});

Function.prototype.bind = function() {
  var __method = this, args = $A(arguments), object = args.shift();
  return function() {
    return __method.apply(object, args.concat($A(arguments)));
  }
}

Function.prototype.bindAsEventListener = function(object) {
  var __method = this, args = $A(arguments), object = args.shift();
  return function(event) {
    return __method.apply(object, [event || window.event].concat(args));
  }
}

Object.extend(Number.prototype, {
  toColorPart: function() {
    return this.toPaddedString(2, 16);
  },

  succ: function() {
    return this + 1;
  },

  times: function(iterator) {
    $R(0, this, true).each(iterator);
    return this;
  },

  toPaddedString: function(length, radix) {
    var string = this.toString(radix || 10);
    return '0'.times(length - string.length) + string;
  },

  toJSON: function() {
    return isFinite(this) ? this.toString() : 'null';
  }
});

Date.prototype.toJSON = function() {
  return '"' + this.getFullYear() + '-' +
    (this.getMonth() + 1).toPaddedString(2) + '-' +
    this.getDate().toPaddedString(2) + 'T' +
    this.getHours().toPaddedString(2) + ':' +
    this.getMinutes().toPaddedString(2) + ':' +
    this.getSeconds().toPaddedString(2) + '"';
};

var Try = {
  these: function() {
    var returnValue;

    for (var i = 0, length = arguments.length; i < length; i++) {
      var lambda = arguments[i];
      try {
        returnValue = lambda();
        break;
      } catch (e) {}
    }

    return returnValue;
  }
}

/*--------------------------------------------------------------------------*/

var PeriodicalExecuter = Class.create();
PeriodicalExecuter.prototype = {
  initialize: function(callback, frequency) {
    this.callback = callback;
    this.frequency = frequency;
    this.currentlyExecuting = false;

    this.registerCallback();
  },

  registerCallback: function() {
    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  stop: function() {
    if (!this.timer) return;
    clearInterval(this.timer);
    this.timer = null;
  },

  onTimerEvent: function() {
    if (!this.currentlyExecuting) {
      try {
        this.currentlyExecuting = true;
        this.callback(this);
      } finally {
        this.currentlyExecuting = false;
      }
    }
  }
}
Object.extend(String, {
  interpret: function(value) {
    return value == null ? '' : String(value);
  },
  specialChar: {
    '\b': '\\b',
    '\t': '\\t',
    '\n': '\\n',
    '\f': '\\f',
    '\r': '\\r',
    '\\': '\\\\'
  }
});

Object.extend(String.prototype, {
  gsub: function(pattern, replacement) {
    var result = '', source = this, match;
    replacement = arguments.callee.prepareReplacement(replacement);

    while (source.length > 0) {
      if (match = source.match(pattern)) {
        result += source.slice(0, match.index);
        result += String.interpret(replacement(match));
        source  = source.slice(match.index + match[0].length);
      } else {
        result += source, source = '';
      }
    }
    return result;
  },

  sub: function(pattern, replacement, count) {
    replacement = this.gsub.prepareReplacement(replacement);
    count = count === undefined ? 1 : count;

    return this.gsub(pattern, function(match) {
      if (--count < 0) return match[0];
      return replacement(match);
    });
  },

  scan: function(pattern, iterator) {
    this.gsub(pattern, iterator);
    return this;
  },

  truncate: function(length, truncation) {
    length = length || 30;
    truncation = truncation === undefined ? '...' : truncation;
    return this.length > length ?
      this.slice(0, length - truncation.length) + truncation : this;
  },

  strip: function() {
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
  },

  stripTags: function() {
    return this.replace(/<\/?[^>]+>/gi, '');
  },

  stripScripts: function() {
    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
  },

  extractScripts: function() {
    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
    return (this.match(matchAll) || []).map(function(scriptTag) {
      return (scriptTag.match(matchOne) || ['', ''])[1];
    });
  },

  evalScripts: function() {
    return this.extractScripts().map(function(script) { return eval(script) });
  },

  escapeHTML: function() {
    var self = arguments.callee;
    self.text.data = this;
    return self.div.innerHTML;
  },

  unescapeHTML: function() {
    var div = document.createElement('div');
    div.innerHTML = this.stripTags();
    return div.childNodes[0] ? (div.childNodes.length > 1 ?
      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
      div.childNodes[0].nodeValue) : '';
  },

  toQueryParams: function(separator) {
    var match = this.strip().match(/([^?#]*)(#.*)?$/);
    if (!match) return {};

    return match[1].split(separator || '&').inject({}, function(hash, pair) {
      if ((pair = pair.split('='))[0]) {
        var key = decodeURIComponent(pair.shift());
        var value = pair.length > 1 ? pair.join('=') : pair[0];
        if (value != undefined) value = decodeURIComponent(value);

        if (key in hash) {
          if (hash[key].constructor != Array) hash[key] = [hash[key]];
          hash[key].push(value);
        }
        else hash[key] = value;
      }
      return hash;
    });
  },

  toArray: function() {
    return this.split('');
  },

  succ: function() {
    return this.slice(0, this.length - 1) +
      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
  },

  times: function(count) {
    var result = '';
    for (var i = 0; i < count; i++) result += this;
    return result;
  },

  camelize: function() {
    var parts = this.split('-'), len = parts.length;
    if (len == 1) return parts[0];

    var camelized = this.charAt(0) == '-'
      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
      : parts[0];

    for (var i = 1; i < len; i++)
      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);

    return camelized;
  },

  capitalize: function() {
    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
  },

  underscore: function() {
    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
  },

  dasherize: function() {
    return this.gsub(/_/,'-');
  },

  inspect: function(useDoubleQuotes) {
    var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
      var character = String.specialChar[match[0]];
      return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
    });
    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
  },

  toJSON: function() {
    return this.inspect(true);
  },

  unfilterJSON: function(filter) {
    return this.sub(filter || Prototype.JSONFilter, '#{1}');
  },

  evalJSON: function(sanitize) {
    var json = this.unfilterJSON();
    try {
      if (!sanitize || (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(json)))
        return eval('(' + json + ')');
    } catch (e) { }
    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
  },

  include: function(pattern) {
    return this.indexOf(pattern) > -1;
  },

  startsWith: function(pattern) {
    return this.indexOf(pattern) === 0;
  },

  endsWith: function(pattern) {
    var d = this.length - pattern.length;
    return d >= 0 && this.lastIndexOf(pattern) === d;
  },

  empty: function() {
    return this == '';
  },

  blank: function() {
    return /^\s*$/.test(this);
  }
});

if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
  escapeHTML: function() {
    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
  },
  unescapeHTML: function() {
    return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
  }
});

String.prototype.gsub.prepareReplacement = function(replacement) {
  if (typeof replacement == 'function') return replacement;
  var template = new Template(replacement);
  return function(match) { return template.evaluate(match) };
}

String.prototype.parseQuery = String.prototype.toQueryParams;

Object.extend(String.prototype.escapeHTML, {
  div:  document.createElement('div'),
  text: document.createTextNode('')
});

with (String.prototype.escapeHTML) div.appendChild(text);

var Template = Class.create();
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
Template.prototype = {
  initialize: function(template, pattern) {
    this.template = template.toString();
    this.pattern  = pattern || Template.Pattern;
  },

  evaluate: function(object) {
    return this.template.gsub(this.pattern, function(match) {
      var before = match[1];
      if (before == '\\') return match[2];
      return before + String.interpret(object[match[3]]);
    });
  }
}

var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead');

var Enumerable = {
  each: function(iterator) {
    var index = 0;
    try {
      this._each(function(value) {
        iterator(value, index++);
      });
    } catch (e) {
      if (e != $break) {
      //throw e;
      }
    }
    return this;
  },

  eachSlice: function(number, iterator) {
    var index = -number, slices = [], array = this.toArray();
    while ((index += number) < array.length)
      slices.push(array.slice(index, index+number));
    return slices.map(iterator);
  },

  all: function(iterator) {
    var result = true;
    this.each(function(value, index) {
      result = result && !!(iterator || Prototype.K)(value, index);
      if (!result) throw $break;
    });
    return result;
  },

  any: function(iterator) {
    var result = false;
    this.each(function(value, index) {
      if (result = !!(iterator || Prototype.K)(value, index))
        throw $break;
    });
    return result;
  },

  collect: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      results.push((iterator || Prototype.K)(value, index));
    });
    return results;
  },

  detect: function(iterator) {
    var result;
    this.each(function(value, index) {
      if (iterator(value, index)) {
        result = value;
        throw $break;
      }
    });
    return result;
  },

  findAll: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      if (iterator(value, index))
        results.push(value);
    });
    return results;
  },

  grep: function(pattern, iterator) {
    var results = [];
    this.each(function(value, index) {
      var stringValue = value.toString();
      if (stringValue.match(pattern))
        results.push((iterator || Prototype.K)(value, index));
    })
    return results;
  },

  include: function(object) {
    var found = false;
    this.each(function(value) {
      if (value == object) {
        found = true;
        throw $break;
      }
    });
    return found;
  },

  inGroupsOf: function(number, fillWith) {
    fillWith = fillWith === undefined ? null : fillWith;
    return this.eachSlice(number, function(slice) {
      while(slice.length < number) slice.push(fillWith);
      return slice;
    });
  },

  inject: function(memo, iterator) {
    this.each(function(value, index) {
      memo = iterator(memo, value, index);
    });
    return memo;
  },

  invoke: function(method) {
    var args = $A(arguments).slice(1);
    return this.map(function(value) {
      return value[method].apply(value, args);
    });
  },

  max: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (result == undefined || value >= result)
        result = value;
    });
    return result;
  },

  min: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (result == undefined || value < result)
        result = value;
    });
    return result;
  },

  partition: function(iterator) {
    var trues = [], falses = [];
    this.each(function(value, index) {
      ((iterator || Prototype.K)(value, index) ?
        trues : falses).push(value);
    });
    return [trues, falses];
  },

  pluck: function(property) {
    var results = [];
    this.each(function(value, index) {
      results.push(value[property]);
    });
    return results;
  },

  reject: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      if (!iterator(value, index))
        results.push(value);
    });
    return results;
  },

  sortBy: function(iterator) {
    return this.map(function(value, index) {
      return {value: value, criteria: iterator(value, index)};
    }).sort(function(left, right) {
      var a = left.criteria, b = right.criteria;
      return a < b ? -1 : a > b ? 1 : 0;
    }).pluck('value');
  },

  toArray: function() {
    return this.map();
  },

  zip: function() {
    var iterator = Prototype.K, args = $A(arguments);
    if (typeof args.last() == 'function')
      iterator = args.pop();

    var collections = [this].concat(args).map($A);
    return this.map(function(value, index) {
      return iterator(collections.pluck(index));
    });
  },

  size: function() {
    return this.toArray().length;
  },

  inspect: function() {
    return '#<Enumerable:' + this.toArray().inspect() + '>';
  }
}

Object.extend(Enumerable, {
  map:     Enumerable.collect,
  find:    Enumerable.detect,
  select:  Enumerable.findAll,
  member:  Enumerable.include,
  entries: Enumerable.toArray
});
var $A = Array.from = function(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) {
    return iterable.toArray();
  } else {
    var results = [];
    for (var i = 0, length = iterable.length; i < length; i++)
      results.push(iterable[i]);
    return results;
  }
}

if (Prototype.Browser.WebKit) {
  $A = Array.from = function(iterable) {
    if (!iterable) return [];
    if (!(typeof iterable == 'function' && iterable == '[object NodeList]') &&
      iterable.toArray) {
      return iterable.toArray();
    } else {
      var results = [];
      for (var i = 0, length = iterable.length; i < length; i++)
        results.push(iterable[i]);
      return results;
    }
  }
}

Object.extend(Array.prototype, Enumerable);

if (!Array.prototype._reverse)
  Array.prototype._reverse = Array.prototype.reverse;

Object.extend(Array.prototype, {
  _each: function(iterator) {
    for (var i = 0, length = this.length; i < length; i++)
      iterator(this[i]);
  },

  clear: function() {
    this.length = 0;
    return this;
  },

  first: function() {
    return this[0];
  },

  last: function() {
    return this[this.length - 1];
  },

  compact: function() {
    return this.select(function(value) {
      return value != null;
    });
  },

  flatten: function() {
    return this.inject([], function(array, value) {
      return array.concat(value && value.constructor == Array ?
        value.flatten() : [value]);
    });
  },

  without: function() {
    var values = $A(arguments);
    return this.select(function(value) {
      return !values.include(value);
    });
  },

  indexOf: function(object) {
    for (var i = 0, length = this.length; i < length; i++)
      if (this[i] == object) return i;
    return -1;
  },

  reverse: function(inline) {
    return (inline !== false ? this : this.toArray())._reverse();
  },

  reduce: function() {
    return this.length > 1 ? this : this[0];
  },

  uniq: function(sorted) {
    return this.inject([], function(array, value, index) {
      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
        array.push(value);
      return array;
    });
  },

  clone: function() {
    return [].concat(this);
  },

  size: function() {
    return this.length;
  },

  inspect: function() {
    return '[' + this.map(Object.inspect).join(', ') + ']';
  },

  toJSON: function() {
    var results = [];
    this.each(function(object) {
      var value = Object.toJSON(object);
      if (value !== undefined) results.push(value);
    });
    return '[' + results.join(', ') + ']';
  }
});

Array.prototype.toArray = Array.prototype.clone;

function $w(string) {
  string = string.strip();
  return string ? string.split(/\s+/) : [];
}

if (Prototype.Browser.Opera){
  Array.prototype.concat = function() {
    var array = [];
    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
    for (var i = 0, length = arguments.length; i < length; i++) {
      if (arguments[i].constructor == Array) {
        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
          array.push(arguments[i][j]);
      } else {
        array.push(arguments[i]);
      }
    }
    return array;
  }
}
var Hash = function(object) {
  if (object instanceof Hash) this.merge(object);
  else Object.extend(this, object || {});
};

Object.extend(Hash, {
  toQueryString: function(obj) {
    var parts = [];
    parts.add = arguments.callee.addPair;

    this.prototype._each.call(obj, function(pair) {
      if (!pair.key) return;
      var value = pair.value;

      if (value && typeof value == 'object') {
        if (value.constructor == Array) value.each(function(value) {
          parts.add(pair.key, value);
        });
        return;
      }
      parts.add(pair.key, value);
    });

    return parts.join('&');
  },

  toJSON: function(object) {
    var results = [];
    this.prototype._each.call(object, function(pair) {
      var value = Object.toJSON(pair.value);
      if (value !== undefined) results.push(pair.key.toJSON() + ': ' + value);
    });
    return '{' + results.join(', ') + '}';
  }
});

Hash.toQueryString.addPair = function(key, value, prefix) {
  key = encodeURIComponent(key);
  if (value === undefined) this.push(key);
  else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value)));
}

Object.extend(Hash.prototype, Enumerable);
Object.extend(Hash.prototype, {
  _each: function(iterator) {
    for (var key in this) {
      var value = this[key];
      if (value && value == Hash.prototype[key]) continue;

      var pair = [key, value];
      pair.key = key;
      pair.value = value;
      iterator(pair);
    }
  },

  keys: function() {
    return this.pluck('key');
  },

  values: function() {
    return this.pluck('value');
  },

  merge: function(hash) {
    return $H(hash).inject(this, function(mergedHash, pair) {
      mergedHash[pair.key] = pair.value;
      return mergedHash;
    });
  },

  remove: function() {
    var result;
    for(var i = 0, length = arguments.length; i < length; i++) {
      var value = this[arguments[i]];
      if (value !== undefined){
        if (result === undefined) result = value;
        else {
          if (result.constructor != Array) result = [result];
          result.push(value)
        }
      }
      delete this[arguments[i]];
    }
    return result;
  },

  toQueryString: function() {
    return Hash.toQueryString(this);
  },

  inspect: function() {
    return '#<Hash:{' + this.map(function(pair) {
      return pair.map(Object.inspect).join(': ');
    }).join(', ') + '}>';
  },

  toJSON: function() {
    return Hash.toJSON(this);
  }
});

function $H(object) {
  if (object instanceof Hash) return object;
  return new Hash(object);
};

// Safari iterates over shadowed properties
if (function() {
  var i = 0, Test = function(value) { this.key = value };
  Test.prototype.key = 'foo';
  for (var property in new Test('bar')) i++;
  return i > 1;
}()) Hash.prototype._each = function(iterator) {
  var cache = [];
  for (var key in this) {
    var value = this[key];
    if ((value && value == Hash.prototype[key]) || cache.include(key)) continue;
    cache.push(key);
    var pair = [key, value];
    pair.key = key;
    pair.value = value;
    iterator(pair);
  }
};
ObjectRange = Class.create();
Object.extend(ObjectRange.prototype, Enumerable);
Object.extend(ObjectRange.prototype, {
  initialize: function(start, end, exclusive) {
    this.start = start;
    this.end = end;
    this.exclusive = exclusive;
  },

  _each: function(iterator) {
    var value = this.start;
    while (this.include(value)) {
      iterator(value);
      value = value.succ();
    }
  },

  include: function(value) {
    if (value < this.start)
      return false;
    if (this.exclusive)
      return value < this.end;
    return value <= this.end;
  }
});

var $R = function(start, end, exclusive) {
  return new ObjectRange(start, end, exclusive);
}

var Ajax = {
  getTransport: function() {
    return Try.these(
      function() {return new XMLHttpRequest()},
      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
    ) || false;
  },

  activeRequestCount: 0
}

Ajax.Responders = {
  responders: [],

  _each: function(iterator) {
    this.responders._each(iterator);
  },

  register: function(responder) {
    if (!this.include(responder))
      this.responders.push(responder);
  },

  unregister: function(responder) {
    this.responders = this.responders.without(responder);
  },

  dispatch: function(callback, request, transport, json) {
    this.each(function(responder) {
      if (typeof responder[callback] == 'function') {
        try {
          responder[callback].apply(responder, [request, transport, json]);
        } catch (e) {}
      }
    });
  }
};

Object.extend(Ajax.Responders, Enumerable);

Ajax.Responders.register({
  onCreate: function() {
    Ajax.activeRequestCount++;
  },
  onComplete: function() {
    Ajax.activeRequestCount--;
  }
});

Ajax.Base = function() {};
Ajax.Base.prototype = {
  setOptions: function(options) {
    this.options = {
      method:       'post',
      asynchronous: true,
      contentType:  'application/x-www-form-urlencoded',
      encoding:     'UTF-8',
      parameters:   ''
    }
    Object.extend(this.options, options || {});

    this.options.method = this.options.method.toLowerCase();
    if (typeof this.options.parameters == 'string')
      this.options.parameters = this.options.parameters.toQueryParams();
  }
}

Ajax.Request = Class.create();
Ajax.Request.Events =
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
  _complete: false,

  initialize: function(url, options) {
    this.transport = Ajax.getTransport();
    this.setOptions(options);
    this.request(url);
  },

  request: function(url) {
    this.url = url;
    this.method = this.options.method;
    var params = Object.clone(this.options.parameters);

    if (!['get', 'post'].include(this.method)) {
      // simulate other verbs over post
      params['_method'] = this.method;
      this.method = 'post';
    }

    this.parameters = params;

    if (params = Hash.toQueryString(params)) {
      // when GET, append parameters to URL
      if (this.method == 'get')
        this.url += (this.url.include('?') ? '&' : '?') + params;
      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
        params += '&_=';
    }

    try {
      if (this.options.onCreate) this.options.onCreate(this.transport);
      Ajax.Responders.dispatch('onCreate', this, this.transport);

      this.transport.open(this.method.toUpperCase(), this.url,
        this.options.asynchronous);

      if (this.options.asynchronous)
        setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);

      this.transport.onreadystatechange = this.onStateChange.bind(this);
      this.setRequestHeaders();

      this.body = this.method == 'post' ? (this.options.postBody || params) : null;
      this.transport.send(this.body);

      /* Force Firefox to handle ready state 4 for synchronous requests */
      if (!this.options.asynchronous && this.transport.overrideMimeType)
        this.onStateChange();

    }
    catch (e) {
      this.dispatchException(e);
    }
  },

  onStateChange: function() {
    var readyState = this.transport.readyState;
    if (readyState > 1 && !((readyState == 4) && this._complete))
      this.respondToReadyState(this.transport.readyState);
  },

  setRequestHeaders: function() {
    var headers = {
      'X-Requested-With': 'XMLHttpRequest',
      'X-Prototype-Version': Prototype.Version,
      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
    };

    if (this.method == 'post') {
      headers['Content-type'] = this.options.contentType +
        (this.options.encoding ? '; charset=' + this.options.encoding : '');

      /* Force "Connection: close" for older Mozilla browsers to work
       * around a bug where XMLHttpRequest sends an incorrect
       * Content-length header. See Mozilla Bugzilla #246651.
       */
      if (this.transport.overrideMimeType &&
          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
            headers['Connection'] = 'close';
    }

    // user-defined headers
    if (typeof this.options.requestHeaders == 'object') {
      var extras = this.options.requestHeaders;

      if (typeof extras.push == 'function')
        for (var i = 0, length = extras.length; i < length; i += 2)
          headers[extras[i]] = extras[i+1];
      else
        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
    }

    for (var name in headers)
      this.transport.setRequestHeader(name, headers[name]);
  },

  success: function() {
    return !this.transport.status
        || (this.transport.status >= 200 && this.transport.status < 300);
  },

  respondToReadyState: function(readyState) {
    var state = Ajax.Request.Events[readyState];
    var transport = this.transport, json = this.evalJSON();

    if (state == 'Complete') {
      try {
        this._complete = true;
        (this.options['on' + this.transport.status]
         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
         || Prototype.emptyFunction)(transport, json);
      } catch (e) {
        this.dispatchException(e);
      }

      var contentType = this.getHeader('Content-type');
      if (contentType && contentType.strip().
        match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
          this.evalResponse();
    }

    try {
      (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
      Ajax.Responders.dispatch('on' + state, this, transport, json);
    } catch (e) {
      this.dispatchException(e);
    }

    if (state == 'Complete') {
      // avoid memory leak in MSIE: clean up
      this.transport.onreadystatechange = Prototype.emptyFunction;
    }
  },

  getHeader: function(name) {
    try {
      return this.transport.getResponseHeader(name);
    } catch (e) { return null }
  },

  evalJSON: function() {
    try {
      var json = this.getHeader('X-JSON');
      return json ? json.evalJSON() : null;
    } catch (e) { return null }
  },

  evalResponse: function() {
    try {
      return eval((this.transport.responseText || '').unfilterJSON());
    } catch (e) {
      this.dispatchException(e);
    }
  },

  dispatchException: function(exception) {
    (this.options.onException || Prototype.emptyFunction)(this, exception);
    Ajax.Responders.dispatch('onException', this, exception);
  }
});

Ajax.Updater = Class.create();

Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
  initialize: function(container, url, options) {
    this.container = {
      success: (container.success || container),
      failure: (container.failure || (container.success ? null : container))
    }

    this.transport = Ajax.getTransport();
    this.setOptions(options);

    var onComplete = this.options.onComplete || Prototype.emptyFunction;
    this.options.onComplete = (function(transport, param) {
      this.updateContent();
      onComplete(transport, param);
    }).bind(this);

    this.request(url);
  },

  updateContent: function() {
    var receiver = this.container[this.success() ? 'success' : 'failure'];
    var response = this.transport.responseText;

    if (!this.options.evalScripts) response = response.stripScripts();

    if (receiver = $(receiver)) {
      if (this.options.insertion)
        new this.options.insertion(receiver, response);
      else
        receiver.update(response);
    }

    if (this.success()) {
      if (this.onComplete)
        setTimeout(this.onComplete.bind(this), 10);
    }
  }
});

Ajax.PeriodicalUpdater = Class.create();
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
  initialize: function(container, url, options) {
    this.setOptions(options);
    this.onComplete = this.options.onComplete;

    this.frequency = (this.options.frequency || 2);
    this.decay = (this.options.decay || 1);

    this.updater = {};
    this.container = container;
    this.url = url;

    this.start();
  },

  start: function() {
    this.options.onComplete = this.updateComplete.bind(this);
    this.onTimerEvent();
  },

  stop: function() {
    this.updater.options.onComplete = undefined;
    clearTimeout(this.timer);
    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
  },

  updateComplete: function(request) {
    if (this.options.decay) {
      this.decay = (request.responseText == this.lastText ?
        this.decay * this.options.decay : 1);

      this.lastText = request.responseText;
    }
    this.timer = setTimeout(this.onTimerEvent.bind(this),
      this.decay * this.frequency * 1000);
  },

  onTimerEvent: function() {
    this.updater = new Ajax.Updater(this.container, this.url, this.options);
  }
});
function $(element) {
  if (arguments.length > 1) {
    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
      elements.push($(arguments[i]));
    return elements;
  }
  if (typeof element == 'string')
    element = document.getElementById(element);
  return Element.extend(element);
}

if (Prototype.BrowserFeatures.XPath) {
  document._getElementsByXPath = function(expression, parentElement) {
    var results = [];
    var query = document.evaluate(expression, $(parentElement) || document,
      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    for (var i = 0, length = query.snapshotLength; i < length; i++)
      results.push(query.snapshotItem(i));
    return results;
  };

  document.getElementsByClassName = function(className, parentElement) {
    var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
    return document._getElementsByXPath(q, parentElement);
  }

} else document.getElementsByClassName = function(className, parentElement) {
  var children = ($(parentElement) || document.body).getElementsByTagName('*');
  var elements = [], child;
  for (var i = 0, length = children.length; i < length; i++) {
    child = children[i];
    if (Element.hasClassName(child, className))
      elements.push(Element.extend(child));
  }
  return elements;
};

/*--------------------------------------------------------------------------*/

if (!window.Element) var Element = {};

Element.extend = function(element) {
  var F = Prototype.BrowserFeatures;
  if (!element || !element.tagName || element.nodeType == 3 ||
   element._extended || F.SpecificElementExtensions || element == window)
    return element;

  var methods = {}, tagName = element.tagName, cache = Element.extend.cache,
   T = Element.Methods.ByTag;

  // extend methods for all tags (Safari doesn't need this)
  if (!F.ElementExtensions) {
    Object.extend(methods, Element.Methods),
    Object.extend(methods, Element.Methods.Simulated);
  }

  // extend methods for specific tags
  if (T[tagName]) Object.extend(methods, T[tagName]);

  for (var property in methods) {
    var value = methods[property];
    if (typeof value == 'function' && !(property in element))
      element[property] = cache.findOrStore(value);
  }

  element._extended = Prototype.emptyFunction;
  return element;
};

Element.extend.cache = {
  findOrStore: function(value) {
    return this[value] = this[value] || function() {
      return value.apply(null, [this].concat($A(arguments)));
    }
  }
};

Element.Methods = {
  visible: function(element) {
    return $(element).style.display != 'none';
  },

  toggle: function(element) {
    element = $(element);
    Element[Element.visible(element) ? 'hide' : 'show'](element);
    return element;
  },

  hide: function(element) {
    $(element).style.display = 'none';
    return element;
  },

  show: function(element) {
    $(element).style.display = '';
    return element;
  },

  remove: function(element) {
    element = $(element);
    element.parentNode.removeChild(element);
    return element;
  },

  update: function(element, html) {
    html = typeof html == 'undefined' ? '' : html.toString();
    $(element).innerHTML = html.stripScripts();
    setTimeout(function() {html.evalScripts()}, 10);
    return element;
  },

  replace: function(element, html) {
    element = $(element);
    html = typeof html == 'undefined' ? '' : html.toString();
    if (element.outerHTML) {
      element.outerHTML = html.stripScripts();
    } else {
      var range = element.ownerDocument.createRange();
      range.selectNodeContents(element);
      element.parentNode.replaceChild(
        range.createContextualFragment(html.stripScripts()), element);
    }
    setTimeout(function() {html.evalScripts()}, 10);
    return element;
  },

  inspect: function(element) {
    element = $(element);
    var result = '<' + element.tagName.toLowerCase();
    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
      var property = pair.first(), attribute = pair.last();
      var value = (element[property] || '').toString();
      if (value) result += ' ' + attribute + '=' + value.inspect(true);
    });
    return result + '>';
  },

  recursivelyCollect: function(element, property) {
    element = $(element);
    var elements = [];
    while (element = element[property])
      if (element.nodeType == 1)
        elements.push(Element.extend(element));
    return elements;
  },

  ancestors: function(element) {
    return $(element).recursivelyCollect('parentNode');
  },

  descendants: function(element) {
    return $A($(element).getElementsByTagName('*')).each(Element.extend);
  },

  firstDescendant: function(element) {
    element = $(element).firstChild;
    while (element && element.nodeType != 1) element = element.nextSibling;
    return $(element);
  },

  immediateDescendants: function(element) {
    if (!(element = $(element).firstChild)) return [];
    while (element && element.nodeType != 1) element = element.nextSibling;
    if (element) return [element].concat($(element).nextSiblings());
    return [];
  },

  previousSiblings: function(element) {
    return $(element).recursivelyCollect('previousSibling');
  },

  nextSiblings: function(element) {
    return $(element).recursivelyCollect('nextSibling');
  },

  siblings: function(element) {
    element = $(element);
    return element.previousSiblings().reverse().concat(element.nextSiblings());
  },

  match: function(element, selector) {
    if (typeof selector == 'string')
      selector = new Selector(selector);
    return selector.match($(element));
  },

  up: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(element.parentNode);
    var ancestors = element.ancestors();
    return expression ? Selector.findElement(ancestors, expression, index) :
      ancestors[index || 0];
  },

  down: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return element.firstDescendant();
    var descendants = element.descendants();
    return expression ? Selector.findElement(descendants, expression, index) :
      descendants[index || 0];
  },

  previous: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
    var previousSiblings = element.previousSiblings();
    return expression ? Selector.findElement(previousSiblings, expression, index) :
      previousSiblings[index || 0];
  },

  next: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
    var nextSiblings = element.nextSiblings();
    return expression ? Selector.findElement(nextSiblings, expression, index) :
      nextSiblings[index || 0];
  },

  getElementsBySelector: function() {
    var args = $A(arguments), element = $(args.shift());
    return Selector.findChildElements(element, args);
  },

  getElementsByClassName: function(element, className) {
    return document.getElementsByClassName(className, element);
  },

  readAttribute: function(element, name) {
    element = $(element);
    if (Prototype.Browser.IE) {
      if (!element.attributes) return null;
      var t = Element._attributeTranslations;
      if (t.values[name]) return t.values[name](element, name);
      if (t.names[name])  name = t.names[name];
      var attribute = element.attributes[name];
      return attribute ? attribute.nodeValue : null;
    }
    return element.getAttribute(name);
  },

  getHeight: function(element) {
    return $(element).getDimensions().height;
  },

  getWidth: function(element) {
    return $(element).getDimensions().width;
  },

  classNames: function(element) {
    return new Element.ClassNames(element);
  },

  hasClassName: function(element, className) {
    if (!(element = $(element))) return;
    var elementClassName = element.className;
    if (elementClassName.length == 0) return false;
    if (elementClassName == className ||
        elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
      return true;
    return false;
  },

  addClassName: function(element, className) {
    if (!(element = $(element))) return;
    Element.classNames(element).add(className);
    return element;
  },

  removeClassName: function(element, className) {
    if (!(element = $(element))) return;
    Element.classNames(element).remove(className);
    return element;
  },

  toggleClassName: function(element, className) {
    if (!(element = $(element))) return;
    Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
    return element;
  },

  observe: function() {
    Event.observe.apply(Event, arguments);
    return $A(arguments).first();
  },

  stopObserving: function() {
    Event.stopObserving.apply(Event, arguments);
    return $A(arguments).first();
  },

  // removes whitespace-only text node children
  cleanWhitespace: function(element) {
    element = $(element);
    var node = element.firstChild;
    while (node) {
      var nextNode = node.nextSibling;
      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
        element.removeChild(node);
      node = nextNode;
    }
    return element;
  },

  empty: function(element) {
    return $(element).innerHTML.blank();
  },

  descendantOf: function(element, ancestor) {
    element = $(element), ancestor = $(ancestor);
    while (element = element.parentNode)
      if (element == ancestor) return true;
    return false;
  },

  scrollTo: function(element) {
    element = $(element);
    var pos = Position.cumulativeOffset(element);
    window.scrollTo(pos[0], pos[1]);
    return element;
  },

  getStyle: function(element, style) {
    element = $(element);
    style = style == 'float' ? 'cssFloat' : style.camelize();
    var value = element.style[style];
    if (!value) {
      var css = document.defaultView.getComputedStyle(element, null);
      value = css ? css[style] : null;
    }
    if (style == 'opacity') return value ? parseFloat(value) : 1.0;
    return value == 'auto' ? null : value;
  },

  getOpacity: function(element) {
    return $(element).getStyle('opacity');
  },

  setStyle: function(element, styles, camelized) {
    element = $(element);
    var elementStyle = element.style;

    for (var property in styles)
      if (property == 'opacity') element.setOpacity(styles[property])
      else
        elementStyle[(property == 'float' || property == 'cssFloat') ?
          (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
          (camelized ? property : property.camelize())] = styles[property];

    return element;
  },

  setOpacity: function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1 || value === '') ? '' :
      (value < 0.00001) ? 0 : value;
    return element;
  },

  getDimensions: function(element) {
    element = $(element);
    var display = $(element).getStyle('display');
    if (display != 'none' && display != null) // Safari bug
      return {width: element.offsetWidth, height: element.offsetHeight};

    // All *Width and *Height properties give 0 on elements with display none,
    // so enable the element temporarily
    var els = element.style;
    var originalVisibility = els.visibility;
    var originalPosition = els.position;
    var originalDisplay = els.display;
    els.visibility = 'hidden';
    els.position = 'absolute';
    els.display = 'block';
    var originalWidth = element.clientWidth;
    var originalHeight = element.clientHeight;
    els.display = originalDisplay;
    els.position = originalPosition;
    els.visibility = originalVisibility;
    return {width: originalWidth, height: originalHeight};
  },

  makePositioned: function(element) {
    element = $(element);
    var pos = Element.getStyle(element, 'position');
    if (pos == 'static' || !pos) {
      element._madePositioned = true;
      element.style.position = 'relative';
      // Opera returns the offset relative to the positioning context, when an
      // element is position relative but top and left have not been defined
      if (window.opera) {
        element.style.top = 0;
        element.style.left = 0;
      }
    }
    return element;
  },

  undoPositioned: function(element) {
    element = $(element);
    if (element._madePositioned) {
      element._madePositioned = undefined;
      element.style.position =
        element.style.top =
        element.style.left =
        element.style.bottom =
        element.style.right = '';
    }
    return element;
  },

  makeClipping: function(element) {
    element = $(element);
    if (element._overflow) return element;
    element._overflow = element.style.overflow || 'auto';
    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
      element.style.overflow = 'hidden';
    return element;
  },

  undoClipping: function(element) {
    element = $(element);
    if (!element._overflow) return element;
    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
    element._overflow = null;
    return element;
  }
};

Object.extend(Element.Methods, {
  childOf: Element.Methods.descendantOf,
  childElements: Element.Methods.immediateDescendants
});

if (Prototype.Browser.Opera) {
  Element.Methods._getStyle = Element.Methods.getStyle;
  Element.Methods.getStyle = function(element, style) {
    switch(style) {
      case 'left':
      case 'top':
      case 'right':
      case 'bottom':
        if (Element._getStyle(element, 'position') == 'static') return null;
      default: return Element._getStyle(element, style);
    }
  };
}
else if (Prototype.Browser.IE) {
  Element.Methods.getStyle = function(element, style) {
    element = $(element);
    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
    var value = element.style[style];
    if (!value && element.currentStyle) value = element.currentStyle[style];

    if (style == 'opacity') {
      if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
        if (value[1]) return parseFloat(value[1]) / 100;
      return 1.0;
    }

    if (value == 'auto') {
      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
        return element['offset'+style.capitalize()] + 'px';
      return null;
    }
    return value;
  };

  Element.Methods.setOpacity = function(element, value) {
    element = $(element);
    var filter = element.getStyle('filter'), style = element.style;
    if (value == 1 || value === '') {
      style.filter = filter.replace(/alpha\([^\)]*\)/gi,'');
      return element;
    } else if (value < 0.00001) value = 0;
    style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') +
      'alpha(opacity=' + (value * 100) + ')';
    return element;
  };

  // IE is missing .innerHTML support for TABLE-related elements
  Element.Methods.update = function(element, html) {
    element = $(element);
    html = typeof html == 'undefined' ? '' : html.toString();
    var tagName = element.tagName.toUpperCase();
    if (['THEAD','TBODY','TR','TD'].include(tagName)) {
      var div = document.createElement('div');
      switch (tagName) {
        case 'THEAD':
        case 'TBODY':
          div.innerHTML = '<table><tbody>' +  html.stripScripts() + '</tbody></table>';
          depth = 2;
          break;
        case 'TR':
          div.innerHTML = '<table><tbody><tr>' +  html.stripScripts() + '</tr></tbody></table>';
          depth = 3;
          break;
        case 'TD':
          div.innerHTML = '<table><tbody><tr><td>' +  html.stripScripts() + '</td></tr></tbody></table>';
          depth = 4;
      }
      $A(element.childNodes).each(function(node) { element.removeChild(node) });
      depth.times(function() { div = div.firstChild });
      $A(div.childNodes).each(function(node) { element.appendChild(node) });
    } else {
      element.innerHTML = html.stripScripts();
    }
    setTimeout(function() { html.evalScripts() }, 10);
    return element;
  }
}
else if (Prototype.Browser.Gecko) {
  Element.Methods.setOpacity = function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1) ? 0.999999 :
      (value === '') ? '' : (value < 0.00001) ? 0 : value;
    return element;
  };
}

Element._attributeTranslations = {
  names: {
    colspan:   "colSpan",
    rowspan:   "rowSpan",
    valign:    "vAlign",
    datetime:  "dateTime",
    accesskey: "accessKey",
    tabindex:  "tabIndex",
    enctype:   "encType",
    maxlength: "maxLength",
    readonly:  "readOnly",
    longdesc:  "longDesc"
  },
  values: {
    _getAttr: function(element, attribute) {
      return element.getAttribute(attribute, 2);
    },
    _flag: function(element, attribute) {
      return $(element).hasAttribute(attribute) ? attribute : null;
    },
    style: function(element) {
      return element.style.cssText.toLowerCase();
    },
    title: function(element) {
      var node = element.getAttributeNode('title');
      return node.specified ? node.nodeValue : null;
    }
  }
};

(function() {
  Object.extend(this, {
    href: this._getAttr,
    src:  this._getAttr,
    type: this._getAttr,
    disabled: this._flag,
    checked:  this._flag,
    readonly: this._flag,
    multiple: this._flag
  });
}).call(Element._attributeTranslations.values);

Element.Methods.Simulated = {
  hasAttribute: function(element, attribute) {
    var t = Element._attributeTranslations, node;
    attribute = t.names[attribute] || attribute;
    node = $(element).getAttributeNode(attribute);
    return node && node.specified;
  }
};

Element.Methods.ByTag = {};

Object.extend(Element, Element.Methods);

if (!Prototype.BrowserFeatures.ElementExtensions &&
 document.createElement('div').__proto__) {
  window.HTMLElement = {};
  window.HTMLElement.prototype = document.createElement('div').__proto__;
  Prototype.BrowserFeatures.ElementExtensions = true;
}

Element.hasAttribute = function(element, attribute) {
  if (element.hasAttribute) return element.hasAttribute(attribute);
  return Element.Methods.Simulated.hasAttribute(element, attribute);
};

Element.addMethods = function(methods) {
  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;

  if (!methods) {
    Object.extend(Form, Form.Methods);
    Object.extend(Form.Element, Form.Element.Methods);
    Object.extend(Element.Methods.ByTag, {
      "FORM":     Object.clone(Form.Methods),
      "INPUT":    Object.clone(Form.Element.Methods),
      "SELECT":   Object.clone(Form.Element.Methods),
      "TEXTAREA": Object.clone(Form.Element.Methods)
    });
  }

  if (arguments.length == 2) {
    var tagName = methods;
    methods = arguments[1];
  }

  if (!tagName) Object.extend(Element.Methods, methods || {});
  else {
    if (tagName.constructor == Array) tagName.each(extend);
    else extend(tagName);
  }

  function extend(tagName) {
    tagName = tagName.toUpperCase();
    if (!Element.Methods.ByTag[tagName])
      Element.Methods.ByTag[tagName] = {};
    Object.extend(Element.Methods.ByTag[tagName], methods);
  }

  function copy(methods, destination, onlyIfAbsent) {
    onlyIfAbsent = onlyIfAbsent || false;
    var cache = Element.extend.cache;
    for (var property in methods) {
      var value = methods[property];
      if (!onlyIfAbsent || !(property in destination))
        destination[property] = cache.findOrStore(value);
    }
  }

  function findDOMClass(tagName) {
    var klass;
    var trans = {
      "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
      "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
      "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
      "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
      "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
      "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
      "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
      "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
      "FrameSet", "IFRAME": "IFrame"
    };
    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
    if (window[klass]) return window[klass];
    klass = 'HTML' + tagName + 'Element';
    if (window[klass]) return window[klass];
    klass = 'HTML' + tagName.capitalize() + 'Element';
    if (window[klass]) return window[klass];

    window[klass] = {};
    window[klass].prototype = document.createElement(tagName).__proto__;
    return window[klass];
  }

  if (F.ElementExtensions) {
    copy(Element.Methods, HTMLElement.prototype);
    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
  }

  if (F.SpecificElementExtensions) {
    for (var tag in Element.Methods.ByTag) {
      var klass = findDOMClass(tag);
      if (typeof klass == "undefined") continue;
      copy(T[tag], klass.prototype);
    }
  }

  Object.extend(Element, Element.Methods);
  delete Element.ByTag;
};

var Toggle = { display: Element.toggle };

/*--------------------------------------------------------------------------*/

Abstract.Insertion = function(adjacency) {
  this.adjacency = adjacency;
}

Abstract.Insertion.prototype = {
  initialize: function(element, content) {
    this.element = $(element);
    this.content = content.stripScripts();

    if (this.adjacency && this.element.insertAdjacentHTML) {
      try {
        this.element.insertAdjacentHTML(this.adjacency, this.content);
      } catch (e) {
        var tagName = this.element.tagName.toUpperCase();
        if (['TBODY', 'TR'].include(tagName)) {
          this.insertContent(this.contentFromAnonymousTable());
        } else {
          throw e;
        }
      }
    } else {
      this.range = this.element.ownerDocument.createRange();
      if (this.initializeRange) this.initializeRange();
      this.insertContent([this.range.createContextualFragment(this.content)]);
    }

    setTimeout(function() {content.evalScripts()}, 10);
  },

  contentFromAnonymousTable: function() {
    var div = document.createElement('div');
    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
    return $A(div.childNodes[0].childNodes[0].childNodes);
  }
}

var Insertion = new Object();

Insertion.Before = Class.create();
Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
  initializeRange: function() {
    this.range.setStartBefore(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.parentNode.insertBefore(fragment, this.element);
    }).bind(this));
  }
});

Insertion.Top = Class.create();
Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
  initializeRange: function() {
    this.range.selectNodeContents(this.element);
    this.range.collapse(true);
  },

  insertContent: function(fragments) {
    fragments.reverse(false).each((function(fragment) {
      this.element.insertBefore(fragment, this.element.firstChild);
    }).bind(this));
  }
});

Insertion.Bottom = Class.create();
Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
  initializeRange: function() {
    this.range.selectNodeContents(this.element);
    this.range.collapse(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.appendChild(fragment);
    }).bind(this));
  }
});

Insertion.After = Class.create();
Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
  initializeRange: function() {
    this.range.setStartAfter(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.parentNode.insertBefore(fragment,
        this.element.nextSibling);
    }).bind(this));
  }
});

/*--------------------------------------------------------------------------*/

Element.ClassNames = Class.create();
Element.ClassNames.prototype = {
  initialize: function(element) {
    this.element = $(element);
  },

  _each: function(iterator) {
    this.element.className.split(/\s+/).select(function(name) {
      return name.length > 0;
    })._each(iterator);
  },

  set: function(className) {
    this.element.className = className;
  },

  add: function(classNameToAdd) {
    if (this.include(classNameToAdd)) return;
    this.set($A(this).concat(classNameToAdd).join(' '));
  },

  remove: function(classNameToRemove) {
    if (!this.include(classNameToRemove)) return;
    this.set($A(this).without(classNameToRemove).join(' '));
  },

  toString: function() {
    return $A(this).join(' ');
  }
};

Object.extend(Element.ClassNames.prototype, Enumerable);
/* Portions of the Selector class are derived from Jack Slocum鈥檚 DomQuery,
 * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
 * license.  Please see http://www.yui-ext.com/ for more information. */

var Selector = Class.create();

Selector.prototype = {
  initialize: function(expression) {
    this.expression = expression.strip();
    this.compileMatcher();
  },

  compileMatcher: function() {
    // Selectors with namespaced attributes can't use the XPath version
    if (Prototype.BrowserFeatures.XPath && !(/\[[\w-]*?:/).test(this.expression))
      return this.compileXPathMatcher();

    var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
        c = Selector.criteria, le, p, m;

    if (Selector._cache[e]) {
      this.matcher = Selector._cache[e]; return;
    }
    this.matcher = ["this.matcher = function(root) {",
                    "var r = root, h = Selector.handlers, c = false, n;"];

    while (e && le != e && (/\S/).test(e)) {
      le = e;
      for (var i in ps) {
        p = ps[i];
        if (m = e.match(p)) {
          this.matcher.push(typeof c[i] == 'function' ? c[i](m) :
    	      new Template(c[i]).evaluate(m));
          e = e.replace(m[0], '');
          break;
        }
      }
    }

    this.matcher.push("return h.unique(n);\n}");
    eval(this.matcher.join('\n'));
    Selector._cache[this.expression] = this.matcher;
  },

  compileXPathMatcher: function() {
    var e = this.expression, ps = Selector.patterns,
        x = Selector.xpath, le,  m;

    if (Selector._cache[e]) {
      this.xpath = Selector._cache[e]; return;
    }

    this.matcher = ['.//*'];
    while (e && le != e && (/\S/).test(e)) {
      le = e;
      for (var i in ps) {
        if (m = e.match(ps[i])) {
          this.matcher.push(typeof x[i] == 'function' ? x[i](m) :
            new Template(x[i]).evaluate(m));
          e = e.replace(m[0], '');
          break;
        }
      }
    }

    this.xpath = this.matcher.join('');
    Selector._cache[this.expression] = this.xpath;
  },

  findElements: function(root) {
    root = root || document;
    if (this.xpath) return document._getElementsByXPath(this.xpath, root);
    return this.matcher(root);
  },

  match: function(element) {
    return this.findElements(document).include(element);
  },

  toString: function() {
    return this.expression;
  },

  inspect: function() {
    return "#<Selector:" + this.expression.inspect() + ">";
  }
};

Object.extend(Selector, {
  _cache: {},

  xpath: {
    descendant:   "//*",
    child:        "/*",
    adjacent:     "/following-sibling::*[1]",
    laterSibling: '/following-sibling::*',
    tagName:      function(m) {
      if (m[1] == '*') return '';
      return "[local-name()='" + m[1].toLowerCase() +
             "' or local-name()='" + m[1].toUpperCase() + "']";
    },
    className:    "[contains(concat(' ', @class, ' '), ' #{1} ')]",
    id:           "[@id='#{1}']",
    attrPresence: "[@#{1}]",
    attr: function(m) {
      m[3] = m[5] || m[6];
      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
    },
    pseudo: function(m) {
      var h = Selector.xpath.pseudos[m[1]];
      if (!h) return '';
      if (typeof h === 'function') return h(m);
      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
    },
    operators: {
      '=':  "[@#{1}='#{3}']",
      '!=': "[@#{1}!='#{3}']",
      '^=': "[starts-with(@#{1}, '#{3}')]",
      '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
      '*=': "[contains(@#{1}, '#{3}')]",
      '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
      '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
    },
    pseudos: {
      'first-child': '[not(preceding-sibling::*)]',
      'last-child':  '[not(following-sibling::*)]',
      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',
      'empty':       "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
      'checked':     "[@checked]",
      'disabled':    "[@disabled]",
      'enabled':     "[not(@disabled)]",
      'not': function(m) {
        var e = m[6], p = Selector.patterns,
            x = Selector.xpath, le, m, v;

        var exclusion = [];
        while (e && le != e && (/\S/).test(e)) {
          le = e;
          for (var i in p) {
            if (m = e.match(p[i])) {
              v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m);
              exclusion.push("(" + v.substring(1, v.length - 1) + ")");
              e = e.replace(m[0], '');
              break;
            }
          }
        }
        return "[not(" + exclusion.join(" and ") + ")]";
      },
      'nth-child':      function(m) {
        return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
      },
      'nth-last-child': function(m) {
        return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
      },
      'nth-of-type':    function(m) {
        return Selector.xpath.pseudos.nth("position() ", m);
      },
      'nth-last-of-type': function(m) {
        return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
      },
      'first-of-type':  function(m) {
        m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
      },
      'last-of-type':   function(m) {
        m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
      },
      'only-of-type':   function(m) {
        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
      },
      nth: function(fragment, m) {
        var mm, formula = m[6], predicate;
        if (formula == 'even') formula = '2n+0';
        if (formula == 'odd')  formula = '2n+1';
        if (mm = formula.match(/^(\d+)$/)) // digit only
          return '[' + fragment + "= " + mm[1] + ']';
        if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
          if (mm[1] == "-") mm[1] = -1;
          var a = mm[1] ? Number(mm[1]) : 1;
          var b = mm[2] ? Number(mm[2]) : 0;
          predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
          "((#{fragment} - #{b}) div #{a} >= 0)]";
          return new Template(predicate).evaluate({
            fragment: fragment, a: a, b: b });
        }
      }
    }
  },

  criteria: {
    tagName:      'n = h.tagName(n, r, "#{1}", c);   c = false;',
    className:    'n = h.className(n, r, "#{1}", c); c = false;',
    id:           'n = h.id(n, r, "#{1}", c);        c = false;',
    attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
    attr: function(m) {
      m[3] = (m[5] || m[6]);
      return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
    },
    pseudo:       function(m) {
      if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
      return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
    },
    descendant:   'c = "descendant";',
    child:        'c = "child";',
    adjacent:     'c = "adjacent";',
    laterSibling: 'c = "laterSibling";'
  },

  patterns: {
    // combinators must be listed first
    // (and descendant needs to be last combinator)
    laterSibling: /^\s*~\s*/,
    child:        /^\s*>\s*/,
    adjacent:     /^\s*\+\s*/,
    descendant:   /^\s/,

    // selectors follow
    tagName:      /^\s*(\*|[\w\-]+)(\b|$)?/,
    id:           /^#([\w\-\*]+)(\b|$)/,
    className:    /^\.([\w\-\*]+)(\b|$)/,
    pseudo:       /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s|(?=:))/,
    attrPresence: /^\[([\w]+)\]/,
    attr:         /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/
  },

  handlers: {
    // UTILITY FUNCTIONS
    // joins two collections
    concat: function(a, b) {
      for (var i = 0, node; node = b[i]; i++)
        a.push(node);
      return a;
    },

    // marks an array of nodes for counting
    mark: function(nodes) {
      for (var i = 0, node; node = nodes[i]; i++)
        node._counted = true;
      return nodes;
    },

    unmark: function(nodes) {
      for (var i = 0, node; node = nodes[i]; i++)
        node._counted = undefined;
      return nodes;
    },

    // mark each child node with its position (for nth calls)
    // "ofType" flag indicates whether we're indexing for nth-of-type
    // rather than nth-child
    index: function(parentNode, reverse, ofType) {
      parentNode._counted = true;
      if (reverse) {
        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
          node = nodes[i];
          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
        }
      } else {
        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
      }
    },

    // filters out duplicates and extends all nodes
    unique: function(nodes) {
      if (nodes.length == 0) return nodes;
      var results = [], n;
      for (var i = 0, l = nodes.length; i < l; i++)
        if (!(n = nodes[i])._counted) {
          n._counted = true;
          results.push(Element.extend(n));
        }
      return Selector.handlers.unmark(results);
    },

    // COMBINATOR FUNCTIONS
    descendant: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        h.concat(results, node.getElementsByTagName('*'));
      return results;
    },

    child: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
          if (child.nodeType == 1 && child.tagName != '!') results.push(child);
      }
      return results;
    },

    adjacent: function(nodes) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        var next = this.nextElementSibling(node);
        if (next) results.push(next);
      }
      return results;
    },

    laterSibling: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        h.concat(results, Element.nextSiblings(node));
      return results;
    },

    nextElementSibling: function(node) {
      while (node = node.nextSibling)
	      if (node.nodeType == 1) return node;
      return null;
    },

    previousElementSibling: function(node) {
      while (node = node.previousSibling)
        if (node.nodeType == 1) return node;
      return null;
    },

    // TOKEN FUNCTIONS
    tagName: function(nodes, root, tagName, combinator) {
      tagName = tagName.toUpperCase();
      var results = [], h = Selector.handlers;
      if (nodes) {
        if (combinator) {
          // fastlane for ordinary descendant combinators
          if (combinator == "descendant") {
            for (var i = 0, node; node = nodes[i]; i++)
              h.concat(results, node.getElementsByTagName(tagName));
            return results;
          } else nodes = this[combinator](nodes);
          if (tagName == "*") return nodes;
        }
        for (var i = 0, node; node = nodes[i]; i++)
          if (node.tagName.toUpperCase() == tagName) results.push(node);
        return results;
      } else return root.getElementsByTagName(tagName);
    },

    id: function(nodes, root, id, combinator) {
      var targetNode = $(id), h = Selector.handlers;
      if (!nodes && root == document) return targetNode ? [targetNode] : [];
      if (nodes) {
        if (combinator) {
          if (combinator == 'child') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (targetNode.parentNode == node) return [targetNode];
          } else if (combinator == 'descendant') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (Element.descendantOf(targetNode, node)) return [targetNode];
          } else if (combinator == 'adjacent') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (Selector.handlers.previousElementSibling(targetNode) == node)
                return [targetNode];
          } else nodes = h[combinator](nodes);
        }
        for (var i = 0, node; node = nodes[i]; i++)
          if (node == targetNode) return [targetNode];
        return [];
      }
      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
    },

    className: function(nodes, root, className, combinator) {
      if (nodes && combinator) nodes = this[combinator](nodes);
      return Selector.handlers.byClassName(nodes, root, className);
    },

    byClassName: function(nodes, root, className) {
      if (!nodes) nodes = Selector.handlers.descendant([root]);
      var needle = ' ' + className + ' ';
      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
        nodeClassName = node.className;
        if (nodeClassName.length == 0) continue;
        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
          results.push(node);
      }
      return results;
    },

    attrPresence: function(nodes, root, attr) {
      var results = [];
      for (var i = 0, node; node = nodes[i]; i++)
        if (Element.hasAttribute(node, attr)) results.push(node);
      return results;
    },

    attr: function(nodes, root, attr, value, operator) {
      if (!nodes) nodes = root.getElementsByTagName("*");
      var handler = Selector.operators[operator], results = [];
      for (var i = 0, node; node = nodes[i]; i++) {
        var nodeValue = Element.readAttribute(node, attr);
        if (nodeValue === null) continue;
        if (handler(nodeValue, value)) results.push(node);
      }
      return results;
    },

    pseudo: function(nodes, name, value, root, combinator) {
      if (nodes && combinator) nodes = this[combinator](nodes);
      if (!nodes) nodes = root.getElementsByTagName("*");
      return Selector.pseudos[name](nodes, value, root);
    }
  },

  pseudos: {
    'first-child': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        if (Selector.handlers.previousElementSibling(node)) continue;
          results.push(node);
      }
      return results;
    },
    'last-child': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        if (Selector.handlers.nextElementSibling(node)) continue;
          results.push(node);
      }
      return results;
    },
    'only-child': function(nodes, value, root) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
          results.push(node);
      return results;
    },
    'nth-child':        function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root);
    },
    'nth-last-child':   function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, true);
    },
    'nth-of-type':      function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, false, true);
    },
    'nth-last-of-type': function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, true, true);
    },
    'first-of-type':    function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, "1", root, false, true);
    },
    'last-of-type':     function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, "1", root, true, true);
    },
    'only-of-type':     function(nodes, formula, root) {
      var p = Selector.pseudos;
      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
    },

    // handles the an+b logic
    getIndices: function(a, b, total) {
      if (a == 0) return b > 0 ? [b] : [];
      return $R(1, total).inject([], function(memo, i) {
        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
        return memo;
      });
    },

    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
    nth: function(nodes, formula, root, reverse, ofType) {
      if (nodes.length == 0) return [];
      if (formula == 'even') formula = '2n+0';
      if (formula == 'odd')  formula = '2n+1';
      var h = Selector.handlers, results = [], indexed = [], m;
      h.mark(nodes);
      for (var i = 0, node; node = nodes[i]; i++) {
        if (!node.parentNode._counted) {
          h.index(node.parentNode, reverse, ofType);
          indexed.push(node.parentNode);
        }
      }
      if (formula.match(/^\d+$/)) { // just a number
        formula = Number(formula);
        for (var i = 0, node; node = nodes[i]; i++)
          if (node.nodeIndex == formula) results.push(node);
      } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
        if (m[1] == "-") m[1] = -1;
        var a = m[1] ? Number(m[1]) : 1;
        var b = m[2] ? Number(m[2]) : 0;
        var indices = Selector.pseudos.getIndices(a, b, nodes.length);
        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
          for (var j = 0; j < l; j++)
            if (node.nodeIndex == indices[j]) results.push(node);
        }
      }
      h.unmark(nodes);
      h.unmark(indexed);
      return results;
    },

    'empty': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        // IE treats comments as element nodes
        if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
        results.push(node);
      }
      return results;
    },

    'not': function(nodes, selector, root) {
      var h = Selector.handlers, selectorType, m;
      var exclusions = new Selector(selector).findElements(root);
      h.mark(exclusions);
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!node._counted) results.push(node);
      h.unmark(exclusions);
      return results;
    },

    'enabled': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!node.disabled) results.push(node);
      return results;
    },

    'disabled': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (node.disabled) results.push(node);
      return results;
    },

    'checked': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (node.checked) results.push(node);
      return results;
    }
  },

  operators: {
    '=':  function(nv, v) { return nv == v; },
    '!=': function(nv, v) { return nv != v; },
    '^=': function(nv, v) { return nv.startsWith(v); },
    '$=': function(nv, v) { return nv.endsWith(v); },
    '*=': function(nv, v) { return nv.include(v); },
    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
    '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
  },

  matchElements: function(elements, expression) {
    var matches = new Selector(expression).findElements(), h = Selector.handlers;
    h.mark(matches);
    for (var i = 0, results = [], element; element = elements[i]; i++)
      if (element._counted) results.push(element);
    h.unmark(matches);
    return results;
  },

  findElement: function(elements, expression, index) {
    if (typeof expression == 'number') {
      index = expression; expression = false;
    }
    return Selector.matchElements(elements, expression || '*')[index || 0];
  },

  findChildElements: function(element, expressions) {
    var exprs = expressions.join(','), expressions = [];
    exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
      expressions.push(m[1].strip());
    });
    var results = [], h = Selector.handlers;
    for (var i = 0, l = expressions.length, selector; i < l; i++) {
      selector = new Selector(expressions[i].strip());
      h.concat(results, selector.findElements(element));
    }
    return (l > 1) ? h.unique(results) : results;
  }
});

function $$() {
  return Selector.findChildElements(document, $A(arguments));
}
var Form = {
  reset: function(form) {
    $(form).reset();
    return form;
  },

  serializeElements: function(elements, getHash) {
    var data = elements.inject({}, function(result, element) {
      if (!element.disabled && element.name) {
        var key = element.name, value = $(element).getValue();
        if (value != null) {
         	if (key in result) {
            if (result[key].constructor != Array) result[key] = [result[key]];
            result[key].push(value);
          }
          else result[key] = value;
        }
      }
      return result;
    });

    return getHash ? data : Hash.toQueryString(data);
  }
};

Form.Methods = {
  serialize: function(form, getHash) {
    return Form.serializeElements(Form.getElements(form), getHash);
  },

  getElements: function(form) {
    return $A($(form).getElementsByTagName('*')).inject([],
      function(elements, child) {
        if (Form.Element.Serializers[child.tagName.toLowerCase()])
          elements.push(Element.extend(child));
        return elements;
      }
    );
  },

  getInputs: function(form, typeName, name) {
    form = $(form);
    var inputs = form.getElementsByTagName('input');

    if (!typeName && !name) return $A(inputs).map(Element.extend);

    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
      var input = inputs[i];
      if ((typeName && input.type != typeName) || (name && input.name != name))
        continue;
      matchingInputs.push(Element.extend(input));
    }

    return matchingInputs;
  },

  disable: function(form) {
    form = $(form);
    Form.getElements(form).invoke('disable');
    return form;
  },

  enable: function(form) {
    form = $(form);
    Form.getElements(form).invoke('enable');
    return form;
  },

  findFirstElement: function(form) {
    return $(form).getElements().find(function(element) {
      return element.type != 'hidden' && !element.disabled &&
        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
    });
  },

  focusFirstElement: function(form) {
    form = $(form);
    form.findFirstElement().activate();
    return form;
  },

  request: function(form, options) {
    form = $(form), options = Object.clone(options || {});

    var params = options.parameters;
    options.parameters = form.serialize(true);

    if (params) {
      if (typeof params == 'string') params = params.toQueryParams();
      Object.extend(options.parameters, params);
    }

    if (form.hasAttribute('method') && !options.method)
      options.method = form.method;

    return new Ajax.Request(form.readAttribute('action'), options);
  }
}

/*--------------------------------------------------------------------------*/

Form.Element = {
  focus: function(element) {
    $(element).focus();
    return element;
  },

  select: function(element) {
    $(element).select();
    return element;
  }
}

Form.Element.Methods = {
  serialize: function(element) {
    element = $(element);
    if (!element.disabled && element.name) {
      var value = element.getValue();
      if (value != undefined) {
        var pair = {};
        pair[element.name] = value;
        return Hash.toQueryString(pair);
      }
    }
    return '';
  },

  getValue: function(element) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    return Form.Element.Serializers[method](element);
  },

  clear: function(element) {
    $(element).value = '';
    return element;
  },

  present: function(element) {
    return $(element).value != '';
  },

  activate: function(element) {
    element = $(element);
    try {
      element.focus();
      if (element.select && (element.tagName.toLowerCase() != 'input' ||
        !['button', 'reset', 'submit'].include(element.type)))
        element.select();
    } catch (e) {}
    return element;
  },

  disable: function(element) {
    element = $(element);
    element.blur();
    element.disabled = true;
    return element;
  },

  enable: function(element) {
    element = $(element);
    element.disabled = false;
    return element;
  }
}

/*--------------------------------------------------------------------------*/

var Field = Form.Element;
var $F = Form.Element.Methods.getValue;

/*--------------------------------------------------------------------------*/

Form.Element.Serializers = {
  input: function(element) {
    switch (element.type.toLowerCase()) {
      case 'checkbox':
      case 'radio':
        return Form.Element.Serializers.inputSelector(element);
      default:
        return Form.Element.Serializers.textarea(element);
    }
  },

  inputSelector: function(element) {
    return element.checked ? element.value : null;
  },

  textarea: function(element) {
    return element.value;
  },

  select: function(element) {
    return this[element.type == 'select-one' ?
      'selectOne' : 'selectMany'](element);
  },

  selectOne: function(element) {
    var index = element.selectedIndex;
    return index >= 0 ? this.optionValue(element.options[index]) : null;
  },

  selectMany: function(element) {
    var values, length = element.length;
    if (!length) return null;

    for (var i = 0, values = []; i < length; i++) {
      var opt = element.options[i];
      if (opt.selected) values.push(this.optionValue(opt));
    }
    return values;
  },

  optionValue: function(opt) {
    // extend element because hasAttribute may not be native
    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
  }
}

/*--------------------------------------------------------------------------*/

Abstract.TimedObserver = function() {}
Abstract.TimedObserver.prototype = {
  initialize: function(element, frequency, callback) {
    this.frequency = frequency;
    this.element   = $(element);
    this.callback  = callback;

    this.lastValue = this.getValue();
    this.registerCallback();
  },

  registerCallback: function() {
    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  onTimerEvent: function() {
    var value = this.getValue();
    var changed = ('string' == typeof this.lastValue && 'string' == typeof value
      ? this.lastValue != value : String(this.lastValue) != String(value));
    if (changed) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  }
}

Form.Element.Observer = Class.create();
Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.Observer = Class.create();
Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  getValue: function() {
    return Form.serialize(this.element);
  }
});

/*--------------------------------------------------------------------------*/

Abstract.EventObserver = function() {}
Abstract.EventObserver.prototype = {
  initialize: function(element, callback) {
    this.element  = $(element);
    this.callback = callback;

    this.lastValue = this.getValue();
    if (this.element.tagName.toLowerCase() == 'form')
      this.registerFormCallbacks();
    else
      this.registerCallback(this.element);
  },

  onElementEvent: function() {
    var value = this.getValue();
    if (this.lastValue != value) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  },

  registerFormCallbacks: function() {
    Form.getElements(this.element).each(this.registerCallback.bind(this));
  },

  registerCallback: function(element) {
    if (element.type) {
      switch (element.type.toLowerCase()) {
        case 'checkbox':
        case 'radio':
          Event.observe(element, 'click', this.onElementEvent.bind(this));
          break;
        default:
          Event.observe(element, 'change', this.onElementEvent.bind(this));
          break;
      }
    }
  }
}

Form.Element.EventObserver = Class.create();
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.EventObserver = Class.create();
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  getValue: function() {
    return Form.serialize(this.element);
  }
});
if (!window.Event) {
  var Event = new Object();
}

Object.extend(Event, {
  KEY_BACKSPACE: 8,
  KEY_TAB:       9,
  KEY_RETURN:   13,
  KEY_ESC:      27,
  KEY_LEFT:     37,
  KEY_UP:       38,
  KEY_RIGHT:    39,
  KEY_DOWN:     40,
  KEY_DELETE:   46,
  KEY_HOME:     36,
  KEY_END:      35,
  KEY_PAGEUP:   33,
  KEY_PAGEDOWN: 34,

  element: function(event) {
    return $(event.target || event.srcElement);
  },

  isLeftClick: function(event) {
    return (((event.which) && (event.which == 1)) ||
            ((event.button) && (event.button == 1)));
  },

  pointerX: function(event) {
    return event.pageX || (event.clientX +
      (document.documentElement.scrollLeft || document.body.scrollLeft));
  },

  pointerY: function(event) {
    return event.pageY || (event.clientY +
      (document.documentElement.scrollTop || document.body.scrollTop));
  },

  stop: function(event) {
    if (event.preventDefault) {
      event.preventDefault();
      event.stopPropagation();
    } else {
      event.returnValue = false;
      event.cancelBubble = true;
    }
  },

  // find the first node with the given tagName, starting from the
  // node the event was triggered on; traverses the DOM upwards
  findElement: function(event, tagName) {
    var element = Event.element(event);
    while (element.parentNode && (!element.tagName ||
        (element.tagName.toUpperCase() != tagName.toUpperCase())))
      element = element.parentNode;
    return element;
  },

  observers: false,

  _observeAndCache: function(element, name, observer, useCapture) {
    if (!this.observers) this.observers = [];
    if (element.addEventListener) {
      this.observers.push([element, name, observer, useCapture]);
      element.addEventListener(name, observer, useCapture);
    } else if (element.attachEvent) {
      this.observers.push([element, name, observer, useCapture]);
      element.attachEvent('on' + name, observer);
    }
  },

  unloadCache: function() {
    if (!Event.observers) return;
    for (var i = 0, length = Event.observers.length; i < length; i++) {
      Event.stopObserving.apply(this, Event.observers[i]);
      Event.observers[i][0] = null;
    }
    Event.observers = false;
  },

  observe: function(element, name, observer, useCapture) {
    element = $(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
      (Prototype.Browser.WebKit || element.attachEvent))
      name = 'keydown';

    Event._observeAndCache(element, name, observer, useCapture);
  },

  stopObserving: function(element, name, observer, useCapture) {
    element = $(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
        (Prototype.Browser.WebKit || element.attachEvent))
      name = 'keydown';

    if (element.removeEventListener) {
      element.removeEventListener(name, observer, useCapture);
    } else if (element.detachEvent) {
      try {
        element.detachEvent('on' + name, observer);
      } catch (e) {}
    }
  }
});

/* prevent memory leaks in IE */
if (Prototype.Browser.IE)
  Event.observe(window, 'unload', Event.unloadCache, false);
var Position = {
  // set to true if needed, warning: firefox performance problems
  // NOT neeeded for page scrolling, only if draggable contained in
  // scrollable elements
  includeScrollOffsets: false,

  // must be called before calling withinIncludingScrolloffset, every time the
  // page is scrolled
  prepare: function() {
    this.deltaX =  window.pageXOffset
                || document.documentElement.scrollLeft
                || document.body.scrollLeft
                || 0;
    this.deltaY =  window.pageYOffset
                || document.documentElement.scrollTop
                || document.body.scrollTop
                || 0;
  },

  realOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.scrollTop  || 0;
      valueL += element.scrollLeft || 0;
      element = element.parentNode;
    } while (element);
    return [valueL, valueT];
  },

  cumulativeOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
    } while (element);
    return [valueL, valueT];
  },

  positionedOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
      if (element) {
        if(element.tagName=='BODY') break;
        var p = Element.getStyle(element, 'position');
        if (p == 'relative' || p == 'absolute') break;
      }
    } while (element);
    return [valueL, valueT];
  },

  offsetParent: function(element) {
    if (element.offsetParent) return element.offsetParent;
    if (element == document.body) return element;

    while ((element = element.parentNode) && element != document.body)
      if (Element.getStyle(element, 'position') != 'static')
        return element;

    return document.body;
  },

  // caches x/y coordinate pair to use with overlap
  within: function(element, x, y) {
    if (this.includeScrollOffsets)
      return this.withinIncludingScrolloffsets(element, x, y);
    this.xcomp = x;
    this.ycomp = y;
    this.offset = this.cumulativeOffset(element);

    return (y >= this.offset[1] &&
            y <  this.offset[1] + element.offsetHeight &&
            x >= this.offset[0] &&
            x <  this.offset[0] + element.offsetWidth);
  },

  withinIncludingScrolloffsets: function(element, x, y) {
    var offsetcache = this.realOffset(element);

    this.xcomp = x + offsetcache[0] - this.deltaX;
    this.ycomp = y + offsetcache[1] - this.deltaY;
    this.offset = this.cumulativeOffset(element);

    return (this.ycomp >= this.offset[1] &&
            this.ycomp <  this.offset[1] + element.offsetHeight &&
            this.xcomp >= this.offset[0] &&
            this.xcomp <  this.offset[0] + element.offsetWidth);
  },

  // within must be called directly before
  overlap: function(mode, element) {
    if (!mode) return 0;
    if (mode == 'vertical')
      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
        element.offsetHeight;
    if (mode == 'horizontal')
      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
        element.offsetWidth;
  },

  page: function(forElement) {
    var valueT = 0, valueL = 0;

    var element = forElement;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;

      // Safari fix
      if (element.offsetParent == document.body)
        if (Element.getStyle(element,'position')=='absolute') break;

    } while (element = element.offsetParent);

    element = forElement;
    do {
      if (!window.opera || element.tagName=='BODY') {
        valueT -= element.scrollTop  || 0;
        valueL -= element.scrollLeft || 0;
      }
    } while (element = element.parentNode);

    return [valueL, valueT];
  },

  clone: function(source, target) {
    var options = Object.extend({
      setLeft:    true,
      setTop:     true,
      setWidth:   true,
      setHeight:  true,
      offsetTop:  0,
      offsetLeft: 0
    }, arguments[2] || {})

    // find page position of source
    source = $(source);
    var p = Position.page(source);

    // find coordinate system to use
    target = $(target);
    var delta = [0, 0];
    var parent = null;
    // delta [0,0] will do fine with position: fixed elements,
    // position:absolute needs offsetParent deltas
    if (Element.getStyle(target,'position') == 'absolute') {
      parent = Position.offsetParent(target);
      delta = Position.page(parent);
    }

    // correct by body offsets (fixes Safari)
    if (parent == document.body) {
      delta[0] -= document.body.offsetLeft;
      delta[1] -= document.body.offsetTop;
    }

    // set position
    if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
    if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
    if(options.setWidth)  target.style.width = source.offsetWidth + 'px';
    if(options.setHeight) target.style.height = source.offsetHeight + 'px';
  },

  absolutize: function(element) {
    element = $(element);
    if (element.style.position == 'absolute') return;
    Position.prepare();

    var offsets = Position.positionedOffset(element);
    var top     = offsets[1];
    var left    = offsets[0];
    var width   = element.clientWidth;
    var height  = element.clientHeight;

    element._originalLeft   = left - parseFloat(element.style.left  || 0);
    element._originalTop    = top  - parseFloat(element.style.top || 0);
    element._originalWidth  = element.style.width;
    element._originalHeight = element.style.height;

    element.style.position = 'absolute';
    element.style.top    = top + 'px';
    element.style.left   = left + 'px';
    element.style.width  = width + 'px';
    element.style.height = height + 'px';
  },

  relativize: function(element) {
    element = $(element);
    if (element.style.position == 'relative') return;
    Position.prepare();

    element.style.position = 'relative';
    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);

    element.style.top    = top + 'px';
    element.style.left   = left + 'px';
    element.style.height = element._originalHeight;
    element.style.width  = element._originalWidth;
  }
}

// Safari returns margins on body which is incorrect if the child is absolutely
// positioned.  For performance reasons, redefine Position.cumulativeOffset for
// KHTML/WebKit only.
if (Prototype.Browser.WebKit) {
  Position.cumulativeOffset = function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      if (element.offsetParent == document.body)
        if (Element.getStyle(element, 'position') == 'absolute') break;

      element = element.offsetParent;
    } while (element);

    return [valueL, valueT];
  }
}

Element.addMethods(); 
/***********************************
 * prototype.js 结束
 ***********************************/
 
 
 /***********************************
 * buffalo.js 结束
 ***********************************/
 var Buffalo = Class.create();
Buffalo.BOCLASS="_BUFFALO_OBJECT_CLASS_";
Buffalo.VERSION="2.0";

Buffalo.prototype = {
	initialize: function(gateway, async, events, options) {
		this.gateway = gateway;
		this.transport = null;
		if (typeof(async) == 'undefined') {
			this.async = true;
		} else {
			this.async = async;
		}
		this.currentCallback = new Function();
		this.setEvents(events);
		this.queue = [];
		this.requesting = false;
		this.options = {timeout:30000};
		Object.extend(this.options, options || {});
	},
	
	getGateway : function() { return this.gateway;},

	setEvents: function(events) {
		this.events = {
			onLoading: Buffalo.Default.showLoading,
			onFinish: new Function(),
			onException: null,
			onError: Buffalo.Default.showError,
			onTimeout: new Function()
		};
		Object.extend(this.events, events || {});
	},
	
	_remoteCall: function(url, buffaloCall, callback) {
		this.requesting = true;
		this.transport = XmlHttp.create();
		try {
			this.transport.open("POST", url, this.async);
			this.transport.setRequestHeader("X-Buffalo-Version", Buffalo.VERSION);
			this.transport.setRequestHeader("Content-Type", "text/xml;charset=utf-8");
			this.transport.send(buffaloCall.xml());
		} catch (e) {
			this.events.onError(this.transport);
			this.events["onLoading"](false);
			return;
		}
		this.requestTime = new Date();
		this.timeoutHandle = new PeriodicalExecuter(this._timeoutChecker.bind(this), 0.5);
		this.currentCallback = callback;
		if (this.async) {
			this.transport.onreadystatechange = this.onStateChange.bind(this);
			this.events["onLoading"](true);
		} else { 
			this.response();
		}
	},
	
	_timeoutChecker: function() {
		if ((new Date() - this.requestTime) > this.options.timeout)	{
			this.events["onTimeout"]();
			this.timeoutHandle.stop();
		}
	},

	nextRemoteCall : function() {
		if (this.queue.length <= 0) return ;
		
		var command = this.queue.shift();
		this._remoteCall(command.url, command.call, command.callback);
	},

	remoteCall: function(service, params, callback) {
		var serviceMethodPair = this._splitServiceMethod(service);
		var newUrl = this.gateway+"/buffalo/"+serviceMethodPair[0];
		var call = new Buffalo.Call(serviceMethodPair[1]);
		for (var i = 0; i < params.length; i++) {
			call.addParameter(params[i]);
		}

		this.queue.push({url:newUrl, call: call, callback: callback});
		
		if (!this.requesting) {
			this.nextRemoteCall();
		}
	},
	
	_splitServiceMethod: function(service) {
		var idx = service.lastIndexOf(".");
		
		var serviceId = service.substring(0,idx);
		var method = service.substring(idx+1,service.length);

		return [serviceId, method];
	},
	
	onStateChange: function(){
		if (this.transport.readyState == 4) {
			this.response();
		}
	},
	
	response : function() {
		this.timeoutHandle.stop();
		this.events["onLoading"](false);
		if (this.transport.responseText && this.transport.status == '200') {
			var reply = new Buffalo.Reply(this.transport);
			if (reply.isFault()) {
			  if (this.events["onException"]) {
			    this.events["onException"](reply.getResult());
			  } else {
			    Buffalo.Default.showException(reply.getResult());
			    this.currentCallback(reply);  
			  }
			} else {
			  this.currentCallback(reply);  
			}
			this.events["onFinish"](reply);
			this.requesting = false;
			this.nextRemoteCall();
		} else {
			this.events["onLoading"](false);
			this.events["onError"](this.transport);
			this.requesting = false;
		}
	}
}

Buffalo.Default = {
	loadingPane: null,
	errorPane: null,
	exceptionPane: null,
	
	showLoading : function(state) {
	/** 1???±μìoading??
		this.loadingPane = $("buffalo_loading");
		if (this.loadingPane == null) {
			var el = document.createElement('DIV');
			el.setAttribute("id","buffalo_loading");
			el.style.cssText="display:none;font-family:Verdana;font-size:11px;border:1px solid #00CC00;background-color:#A4FFA4;padding:1px;position:absolute; right:1px; top:1px; width:110px; height:14px; z-index:10000";
			el.innerHTML="buffalo loading... ";
			document.body.appendChild(el);
			this.loadingPane = el;
		}
		if (state) {
			this.loadingPane.style.display="block";
			this.loadingPane.style.top = document.body.scrollTop+1;
		} else {
			this.loadingPane.style.display="none";
		}
	**/
	},
	
	showError: function(transport) {
	/** 1???￠Д?
		this.errorPane = $("buffalo_error");
		if (this.errorPane == null) {
			var el = document.createElement('DIV');
			el.setAttribute("id","buffalo_error");
			el.style.cssText="font-size:11px;border:4px solid #FF3333;background-color:#fff;padding:4px;position:absolute;overflow:auto; right:10px; top:10px; width:500px; height:300px; z-index:1";
			el.innerHTML="<h2>Error: " + transport.status+" - "+transport.statusText+"</h2>";
			el.innerHTML+="<textarea style='width:96%;height:80%'>"+transport.responseText.stripTags()+"</textarea>";
      		el.onclick=function(){ el.style.display="none"; }
			document.body.appendChild(el);
			this.errorPane = el;
		} else {
			this.errorPane.style.display = "block";
		}
	**/
	},
	
	showException: function(faultObj) {
	/**
		this.exceptionPane = $("buffalo_exception");
		if (this.exceptionPane == null) {
			var el = document.createElement('DIV');
			el.setAttribute("id","buffalo_exception");
			el.style.cssText="font-size:11px;border:4px solid #FFFF33;background-color:#fff;padding:4px;position:absolute;overflow:auto; right:10px; top:10px; width:300px; height:100px; z-index:1";
			el.innerHTML ="<h2>Exception: " + faultObj.code+"</h2>";
			el.innerHTML += "Code: "+faultObj.code+"<br/>";
			el.innerHTML += "Message: "+faultObj.message+"<br/>";
			el.innerHTML += "Detail: " + faultObj.detail;
      		el.onclick=function(){ el.style.display="none"; }
			document.body.appendChild(el);
			this.exceptionPane = el;
		} else {
			this.exceptionPane.style.display = "block";
		}
	**/
	},
	
	showTimeout: function() {
		alert("timeout!");
	}
}

function getDomDocumentPrefix() {
	if (getDomDocumentPrefix.prefix)
		return getDomDocumentPrefix.prefix;
	
	var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
	var o;
	for (var i = 0; i < prefixes.length; i++) {
		try {
			// try to create the objects
			o = new ActiveXObject(prefixes[i] + ".DomDocument");
			return getDomDocumentPrefix.prefix = prefixes[i];
		}
		catch (ex) {};
	}
	
	throw new Error("Could not find an installed XML parser");
}

function getXmlHttpPrefix() {
	if (getXmlHttpPrefix.prefix)
		return getXmlHttpPrefix.prefix;
	
	var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
	var o;
	for (var i = 0; i < prefixes.length; i++) {
		try {
			o = new ActiveXObject(prefixes[i] + ".XmlHttp");
			return getXmlHttpPrefix.prefix = prefixes[i];
		}
		catch (ex) {};
	}
	
	throw new Error("Could not find an installed XMLHttp object");
}

function XmlHttp() {}

XmlHttp.create = function () {
	try {
		if (window.XMLHttpRequest) {
			var req = new XMLHttpRequest();
			if (req.readyState == null) {
				req.readyState = 1;
				req.addEventListener("load", function () {
					req.readyState = 4;
					if (typeof req.onreadystatechange == "function")
						req.onreadystatechange();
				}, false);
			}
			
			return req;
		}
		if (window.ActiveXObject) {
			return new ActiveXObject(getXmlHttpPrefix() + ".XmlHttp");
		}
	}
	catch (ex) {}
	throw new Error("Your browser does not support XmlHttp objects");
};

function XmlDocument() {}
XmlDocument.create = function () {
	try {
		if (document.implementation && document.implementation.createDocument) {
			var doc = document.implementation.createDocument("", "", null);
			if (doc.readyState == null) {
				doc.readyState = 1;
				doc.addEventListener("load", function () {
					doc.readyState = 4;
					if (typeof doc.onreadystatechange == "function")
						doc.onreadystatechange();
				}, false);
			}
			
			return doc;
		}
		if (window.ActiveXObject)
			return new ActiveXObject(getDomDocumentPrefix() + ".DomDocument");
	}
	catch (ex) {}
	throw new Error("Your browser does not support XmlDocument objects");
};

if (window.DOMParser &&
	window.XMLSerializer &&
	window.Node && Node.prototype && Node.prototype.__defineGetter__) {

	Document.prototype.loadXML = function (s) {
		
		var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
		
		while (this.hasChildNodes())
			this.removeChild(this.lastChild);
		for (var i = 0; i < doc2.childNodes.length; i++) {
			this.appendChild(this.importNode(doc2.childNodes[i], true));
		}
	};
	
	Document.prototype.__defineGetter__("xml", function () {
		return (new XMLSerializer()).serializeToString(this);
	});
}
Buffalo.Call = Class.create();
Buffalo.Call.prototype = {
	initialize: function(methodname){
		this.method = methodname;
		this.params = [];
        this._objects = [];
	},

	addParameter: function(data){
		if (typeof(data) == 'undefined') return;
		this.params[this.params.length] = data;
	},

	xml: function(){
        this._objects = [];
		var xmlstr = "<buffalo-call>\n";
		xmlstr += "<method>" + this.method+ "</method>\n";
		for (var i = 0; i < this.params.length; i++) {
		  var data = this.params[i];
		  xmlstr += this.getParamXML(this.dataTypeOf(data),data) + "\n";
		}
		xmlstr += "</buffalo-call>";
		return xmlstr; 
	},
	
	/* Guess the type of an javascript object */
	dataTypeOf: function (o){
		if (o == null) {
			return "null";
		}
		var type = typeof(o);
		type = type.toLowerCase();
		switch(type){
		  case "number":
			type = this._getNumberType(o);
			break;
		  case "object":
			var con = o.constructor;
			if (con == Date) type = "date";
			else if (con == Array) type = "list";
			else type = "map";
			break;
		}
		return type;
	},
    
    _getNumberType: function(o) {
        if (Math.round(o) == o) 
            return "int";
	    else 
            return "double";
    },
	
	doValueXML: function(type,data){
		var xml, str = data;
		if (typeof(data) == "string") {
			str = str.replace(/&/g,"&amp;");
			str = str.replace(/</g,"&lt;");
			str = str.replace(/>/g,"&gt;");
			xml = "<" + type + ">" + str + "</" + type + ">";
		} else {
			xml = "<" + type + ">" + data + "</" + type + ">";
		}
				
		return xml;
	},

	doBooleanXML:function(data){
		var value = (data==true)?1:0;
		var xml = "<boolean>" + value + "</boolean>";
		return xml;
	},
	
	doDateXML: function(data){
		var xml = "<date>";
		xml += dateToISO8609(data);
		xml += "</date>";
		return xml;
	},
	
	doArrayXML : function(data){
		var ref = this._checkRef(data);
        if (ref != -1) return "<ref>" + ref + "</ref>";
        this._objects[this._objects.length] = data;
        
        var xml = "<list>\n";
		var boClass = data[Buffalo.BOCLASS];
		var boType = boClass ? boClass : this.arrayType(data);
		xml += "<type>" +boType+ "</type>\n";
		xml += "<length>" +data.length+ "</length>\n";
		for (var i = 0; i < data.length; i++){
			xml += this.getParamXML(this.dataTypeOf(data[i]),data[i]) + "\n";
		}
		xml += "</list>\n";
		return xml;
	},
	
	arrayType: function(arr) {
		if (arr.length == 0) return "";
		var type = "";
		var obj = arr;
		while(this.isArray(obj)) {
            var obj0 = obj[0];
			var canBeArray = true;
			for(var i = 0; i < obj.length; i++) {
                var obji = obj[i];
				if (typeof(obji) != typeof(obj0)) {
					canBeArray = false;
					break;
				} else {
					if (typeof(obji) == 'object') {
						if (obj0[Buffalo.BOCLASS] != obji[Buffalo.BOCLASS]) {
							canBeArray = false;
							break;
						}
					} 
                    
                    if (typeof(obji) == 'number') {
                        if (this._getNumberType(obji) != this._getNumberType(obj0)) {
                            canBeArray = false;
                            break;
                        }
                    }
				}
			}
			if (canBeArray) {
				type+="[";	
				obj = obj[0];
			} else {
				break;
			}
		}
		if (type.indexOf("[") == -1) return "";
		var componentType = obj[Buffalo.BOCLASS] || typeof(obj);
		if (componentType == 'object') return "";
        if (componentType == 'number') componentType = this._getNumberType(obj);
		return type+componentType;
	},
	
	isArray: function(obj) {
		return typeof(obj) == 'object' && obj.constructor == Array; 
	},
    
    _checkRef: function(obj) {
        var ref = -1;
        for (var i = 0; i < this._objects.length; i++) {
            if (obj === this._objects[i]) {
                ref = i; break;   
            }
        }
        return ref;
    },
	
	doStructXML : function(data){
        var ref = this._checkRef(data);
        if (ref != -1) return "<ref>" + ref + "</ref>";
        this._objects[this._objects.length] = data;
        
		var boType = data[Buffalo.BOCLASS] || "java.util.HashMap";
		var xml = "<map>\n";
		xml += "<type>" +boType+ "</type>\n";

		for (var i in data){
			if (data[i] != boType) { 
				if (typeof(data[i]) == "function") continue; /* the function shouldn't transfered. */
				xml += this.getParamXML(this.dataTypeOf(i),i)+"\n";
				xml += this.getParamXML(this.dataTypeOf(data[i]),data[i]) + "\n";
			}
		}
		xml += "</map>\n";
		return xml;
	},
	
	doNullXML : function() {
		return "<null></null>";
	},

	getParamXML: function(type,data){
		var xml;
		switch (type){
			case "date": xml = this.doDateXML(data); break;
			case "list": xml = this.doArrayXML(data); break;
			case "map": xml = this.doStructXML(data); break;
			case "boolean": xml = this.doBooleanXML(data); break;
			case "null": xml = this.doNullXML(); break;
			default: xml = this.doValueXML(type,data); break;
		}
		return xml;
	}
}

function dateToISO8609(date){
	var year = date.getYear();
	/* Fix for Y2K */
	if (year < 2000) {
		year += 1900;
	}
	var month = leadingZero(new String(date.getMonth()+1));
	var day = leadingZero(new String(date.getDate()));
	var time = leadingZero(new String(date.getHours())) + leadingZero(new String(date.getMinutes())) + leadingZero(new String(date.getSeconds()));

	var converted = year+month+day+"T"+time+"Z";
	return converted;
} 

function leadingZero(n){
	if (n.length==1) n = "0" + n;
	return n;
}
Buffalo.Reply = Class.create();
Buffalo.Reply.prototype = {
	initialize: function(xhr) {		
		this._isFault = false;
		this._type = "null";
		this._objects = [];
		this._objectNodes = [];
    this._source = xhr.responseText;

    var root = xhr.responseXML ? xhr.responseXML.documentElement :
              this.constructNodeFromXmlStringInIEOrFF(this._source);
    
		this.dataNode = root.firstChild;
		this._type = this._getType(this.dataNode);
	},
	
	constructNodeFromXmlStringInIEOrFF: function(xmlString) {
		var xmldoc = XmlDocument.create();
		xmldoc.async=false;
		xmldoc.loadXML(xmlString);
		return xmldoc.documentElement;
	}, 

	getType: function() { return this._type; },
	
	getResult : function() { return this.deserialize(this.dataNode); },
	
	isFault : function() { return (this._type == "fault"); },
	
	isNull: function() { return (this._type == "null"); },
	
	getSource : function() { return this._source; },
	
	deserialize: function(dataNode) {
		var ret;
		var type = this._getType(dataNode);
		switch (type) {
			case "boolean": ret = this.doBoolean(dataNode); break;
			case "date": ret = this.doDate(dataNode); break;
			case "double": ret = this.doDouble(dataNode); break;
			case "int": 
			case "long": 
				ret = this.doInt(dataNode);
				break;
			case "list": ret = this.doList(dataNode); break;
			case "map": ret = this.doMap(dataNode); break;
			case "null": ret = this.doNull(dataNode); break;
			case "ref": ret = this.doRef(dataNode); break;
			case "string": ret = this.doString(dataNode);break;
			case "xml": ret = this.doXML(dataNode); break;
			case "fault": ret = this.doFault(dataNode); break;
			default: ;
		}

		return ret;
	},
	
	_getType : function(dataNode) {
	   var temp = "";
	   try{
		temp = dataNode.tagName.toLowerCase();
		}catch(e){
		
		}
		return temp;
	},
	
	getNodeText :function(dataNode) {
		if (dataNode && dataNode.hasChildNodes()) {
			var s = "";
			for (var i = 0; i < dataNode.childNodes.length; i++) {
				s += new String(dataNode.childNodes.item(i).nodeValue);
			}
			return s;
		} else {
			return null;
		}
	},

	doBoolean : function (dataNode) {
		var value = this.getNodeText(dataNode);
		return (value == "1");
	},
	
	doDate : function (dataNode) {

		var dateStr = this.getNodeText(dataNode);
		var year = parseInt(dateStr.substring(0,4),"10");
		var month = parseInt(dateStr.substring(4,6),"10") - 1;
		var day = parseInt(dateStr.substring(6,8),"10");
		var hour = parseInt(dateStr.substring(9,11),"10");
		var minute = parseInt(dateStr.substring(11,13),"10");
		var second = parseInt(dateStr.substring(13,15),"10");
		
		var d = new Date(year, month, day, hour, minute, second);
		return d;
	},
	
	doDouble : function (dataNode) {
		var value = this.getNodeText(dataNode);
		return parseFloat(value);
	},
	
	doInt: function (dataNode) {
		var value = this.getNodeText(dataNode);
		return parseInt(value);
	},
	
	doList: function (dataNode) {
		var arr = new Array();
		this._objects[this._objects.length] = arr;
    
    var children = dataNode.childNodes;
    arr[Buffalo.BOCLASS] = this.getNodeText(children[0]);
		for (var i=2; i < children.length; i++) {
			arr[arr.length] = this.deserialize(children[i]);
		}

		return arr;
	},

	doMap: function (dataNode) {
	
		var obj = new Object();
		this._objects[this._objects.length] = obj;

		var attrs = dataNode.childNodes;
		obj[Buffalo.BOCLASS] = this.getNodeText(attrs[0]);
		for (var i = 1; i < attrs.length; i+=2) {
			obj[this.getNodeText(attrs[i])] = this.deserialize(attrs[i+1]);
		}
		
		return obj;
	},
	
	doNull: function (dataNode) { return null;	},
	
	doRef: function (dataNode) {
		var value = this.getNodeText(dataNode);
		var idx = parseInt(value);
		
		return this._objects[idx];
	},
	
	doString: function (dataNode) {
		var value = this.getNodeText(dataNode);
		if (value == null) {
			return "";
		}
		return (value);
	},
	
	doXML : function (dataNode) {
		var value = this.getNodeText(dataNode);
		return unescape(value);
	},
	
	doFault : function (dataNode) {
		var code = this.getNodeText(dataNode.childNodes[1]);
		var msg = this.getNodeText(dataNode.childNodes[3]);
		var detail = this.deserialize(dataNode.childNodes[5]);
		return new Buffalo.Fault(code, msg, detail);
	}
}

Buffalo.Fault = Class.create();
Buffalo.Fault.prototype = {
	initialize: function(code, message, detail) {
		this.code = code;
		this.message = message;
		this.detail = detail;
	},
	toString: function() {
		return "Buffalo.Fault:[code=" + this.code + ", message=" + this.message + ", detail=" + this.detail+"]";
	}
}
Object.extend(Buffalo.prototype, {
	bindReply : function(service, params, bindElemId, options) {
		this.remoteCall(service, params, function(reply) {
			Buffalo.Bind.bind(bindElemId, reply.getResult(), options);
		})
	}
});

Buffalo.Bind = {
	bind : function(elementId, bindValue, options) {
		var elem = $(elementId);
		switch(elem.tagName) {
			case "INPUT": 
				switch (elem.type.toLowerCase()) {
					
					case "text": ;
					case "hidden": ;
					case "password": Buffalo.BindFactory.bindText(elem, bindValue); break;

					case "checkbox": ;
					case "radio": Buffalo.BindFactory.bindRadioOrCheckbox(elem, bindValue); break;
				}
				break;
			case "TEXTAREA":
				Buffalo.BindFactory.bindText(elem, bindValue);
				break; 
			case "TABLE": 
				Buffalo.BindFactory.bindTable(elem, bindValue);
				break; 
			case "SELECT": 
				Buffalo.BindFactory.bindSelect(elem, bindValue, options);
				break; 
			case "DIV":
			case "SPAN":
				elem.innerHTML = bindValue;
				break;
			case "FORM":
				Buffalo.Form.bindForm(elem, bindValue);
		}
	}
}

Buffalo.BindFactory = {
	reportError: function(elem, value, msg) { 
		throw "Data bind failed: "+msg;
	},
	
	bindText: function(elem, value) { 
		elem.value = value;
	},
	
	bindRadioOrCheckbox: function(elem, value) {
		elem.checked = Buffalo.BindFactory.checkTrue(value);
	},

	bindSelect : function(elem, value, options) {
		//TODO: Check the data type
		if (typeof(value) != "object" || value.constructor != Array) {
			this.reportError(elem,value,"Array Type Needed for binding select!");
		}
		while (elem.childNodes.length > 0) {
			elem.removeChild(elem.childNodes[0]);
		}
		
		// bind data
		for (var i = 0; i < value.length; i++) {
			
			var option = document.createElement("OPTION");
			
            if (options && options.binder) {
                options.binder(value, option, i);
            } else {
                var data = value[i];
    			if (typeof(data) != 'object') {
    				option.value = data;
    				option.text = data;
    			} else {
    				option.value = data[elem.getAttribute("jvalue")];
    				option.text = data[elem.getAttribute("jtext")];
    				if (Buffalo.BindFactory.checkTrue(data.selected)) {
    					option.selected = true;	
    				}
    			}
            }
  		
			elem.options.add(option);
		}
	},

	bindTable: function(elem, value) {
		var jHeight = parseInt(elem.getAttribute("jheight"));
		var dataHeader = [];
		var tBody = elem.getElementsByTagName("TBODY")[0];
		
		// clear the generated rows
		if (elem.getElementsByTagName("TBODY").length > 0) {
			while (tBody.rows.length > jHeight) {
					tBody.deleteRow(jHeight);
			}
		}

		if (jHeight == 0) { // if table is null, push the data to the tables.

			for (var x in value[0] ) {
				dataHeader[dataHeader.length] = x;
			}

			var hTr = elem.insertRow(elem.rows.length);
			for (var i = 0; i < dataHeader.length; i++) {
				var td = hTr.insertCell(hTr.cells.length);
				td.innerHTML = dataHeader[i];
			}
			
			for (var i = 0; i < value.length; i++) {
				var tr = elem.insertRow(elem.rows.length);
				var data = value[i];
				for (x in data ) {
					var td = tr.insertCell(tr.cells.length);
					td.innerHTML = data[x];
				}
			}	
		}
		
		if (jHeight == 1) { // if there is only one line, first line is header(every td indicate by a jtext property)
			var headerTR = tBody.rows[0];

			for (var i = 0; i < headerTR.cells.length ; i++ ) {
				dataHeader[dataHeader.length] = headerTR.cells[i].getAttribute("jtext");
			}
			
			for (var i = 0; i < value.length; i++) {
				var tr = tBody.insertRow(tBody.rows.length);
				var data = value[i];
				for (var j = 0; j < dataHeader.length; j++ ) {
					var td = tr.insertCell(tr.cells.length);
					td.innerHTML = data[dataHeader[j]];
				}
			}	
		}

		if (jHeight == 2) { // two lines, first line is header, the second is style

			var headerTR = tBody.rows[0];

			for (var i = 0; i < headerTR.cells.length ; i++ ) {
				dataHeader[dataHeader.length] = headerTR.cells[i].getAttribute("jtext");
			}

			for (var i = 0; i < value.length; i++) {
				
				var tr;
				
				if (i == 0) { // if the first row
					tr = elem.rows[1];
				} else { // else copy the first row
					tr = elem.rows[1].cloneNode(true);
				}

				if (i > 0) 	{
					tBody.appendChild(tr);
				}

				var data = value[i];
				for (var j = 0; j < tr.cells.length; j++ ) {
					var td = tr.cells[j];
					
					td.innerHTML = data[dataHeader[j]];
				}
				
			}	
		}

		if (jHeight >= 3) { // more than 3 rows, first header, second and third is odd/even style, other lines ommited.
			var headerTR = tBody.rows[0];
			for (var i = 0; i < headerTR.cells.length ; i++ ) {
				dataHeader[dataHeader.length] = headerTR.cells[i].getAttribute("jtext");
			}
			for (var i = 0; i < value.length; i++) {
				var tr;
				
				if (i == 0) { // 1st row
					tr = tBody.rows[1];
				} else if (i == 1) 	{ // 2nd row
					tr = tBody.rows[2];
				} else if ( i % 2 == 0) { // get the 1st row
					tr = tBody.rows[1].cloneNode(true);
				} else if (i % 2 == 1) { // the 2nd row
					tr = tBody.rows[2].cloneNode(true);
				}

				
				if (i > 1) 	{
					tBody.appendChild(tr);
				}

				var data = value[i];
				
				for (var j = 0; j < tr.cells.length; j++ ) {
					var td = tr.cells[j];	
					td.innerHTML = data[dataHeader[j]];
				}
			}	
		}
		
	},
	
	checkTrue: function(value) {
		var ret = false;
		switch (typeof(value)) {
			case 'boolean': ret = value; break;
			case 'string': ret = (value == true || value == "1" || value == "true" || value == "yes"); break;
			case 'number': ret = (parseInt(value) == 1); break;
			default: ret = false;
		}
		return ret; 
	}
}
Buffalo.bind = Buffalo.Bind.bind; /*capable with the old version, deprecated*/
Buffalo.View = Class.create();

Buffalo.View.LAST_VIEWNAME = null;
Buffalo.View.CURRENT_VIEW = null;
Buffalo.View.HOME_VIEW = null;
Buffalo.View.HISTORY_IFRAME_ID = "buffalo-view-history-iframe";

Buffalo.View.iframeLoaded = function(loc) {
	var url = loc.href;
	
	var idx = url.indexOf("?");
	var viewName = "";
	if (idx > -1) {
		viewName = url.substring(idx+1);
	}
	
	if (viewName == "") {
		viewName = Buffalo.View.HOME_VIEW;
	}

	if (Buffalo.View.CURRENT_VIEW != null) {
		Buffalo.View.CURRENT_VIEW.doSwitchPart(viewName);
	}
}

Buffalo.View.prototype = {

	initialize:function(buffaloObj) {
		this.buffalo = buffaloObj;
	},

	switchPart: function(partId, viewName, addToHistory) {
		this.partId = partId;
		this.viewName = viewName;
		if (typeof(addToHistory) == "undefined" || addToHistory == true) {
			this.addToHistory = true;
		} else {
			this.addToHistory = false;
		}
		
		if (Buffalo.View.LAST_VIEWNAME == null) {
			/* the first visit view is home view */
			Buffalo.View.HOME_VIEW = viewName;
			/* The first view, don't add to history */
			this.doSwitchPart(viewName);
			Buffalo.View.LAST_VIEWNAME = viewName;
			return;
		}

		Buffalo.View.CURRENT_VIEW = this;

		if (this.addToHistory) {
			if ($(Buffalo.View.HISTORY_IFRAME_ID)) {
				var iframesrc=$(Buffalo.View.HISTORY_IFRAME_ID).src;
				var newUrl = iframesrc;
				var idx = iframesrc.indexOf("?");
				if (idx > -1) {
					newUrl = iframesrc.substr(0,idx);
				}
				newUrl += "?" + viewName;
				$(Buffalo.View.HISTORY_IFRAME_ID).src = newUrl;
			} else {
				var msg = "It seems that you havent add the buffalo-blank.html as an Iframe for browser history.";
				msg += "\nSo this view cannot add to browser history.";
				msg += "\n\nTo prevent this dialog, use buffalo.switchPart(partId, viewName, false) or ";
				msg += "add the buffalo-blank.html to your main page with id 'buffalo-view-history-iframe'.";

				alert(msg);
			}
		} 

		this.doSwitchPart(viewName);
		
		Buffalo.View.LAST_VIEWNAME = viewName;
		
	},
	
	doSwitchPart: function(viewName) {

		if (Buffalo.View.LAST_VIEWNAME == viewName) {
			return ;
		}

		this.transport = XmlHttp.create();
		var nonCachedViewName = viewName;
		try {
			/*Fix for the IE cache*/
			if (/MSIE/.test(navigator.userAgent)) {
				var bfViewHackKey = "_bfviewhackkey_=" + (new Date()).getTime();
				if (viewName.indexOf('?') > -1)	{
					nonCachedViewName += "&" + bfViewHackKey;
				} else {
					nonCachedViewName += "?" + bfViewHackKey;
				}
			}
			this.transport.open("GET", nonCachedViewName, this.buffalo.async);/*use get for static page*/
		} catch (e) {
			var msg = "Buffalo View Error: \n\n Cannot find view with name: " + "[" + viewName + "]";
			alert(msg);	
		}
		
		this.transport.send(null);
		if (this.buffalo.async) {
			this.transport.onreadystatechange = this._viewHandle.bind(this);
			this.buffalo.events["onLoading"](true);
		} else { 
			this._processView();
		}

		Buffalo.View.LAST_VIEWNAME = viewName;

	},

	_viewHandle : function(){
		this._processView();
	},

	_processView : function() {
		this.buffalo.events["onLoading"](false);
		if (this.transport.readyState == 4) {
			if (this.transport.status == '200') {
				var data = this.transport.responseText;
				this._showView(this.partId, this.viewName, data);
			} else {
				this.buffalo.events["onError"](this.transport);
			}
		}
	},

	_showView: function(partId, viewPath, viewData) {
		
		var regexp1 = /<script(.|\n)*?>(.|\n|\r\n)*?<\/script>/ig;
		var regexp2 = /<script(.|\n)*?>((.|\n|\r\n)*)?<\/script>/im;
		
		/* draw the html first */
		$(partId).innerHTML = viewData.replace(regexp1, "");
		
		var result = viewData.match(regexp1);
		if (result) {
			for (var i = 0; i < result.length; i++) {
				var realScript = result[i].match(regexp2);
				this._executeScript(realScript[2], partId);
				/* Note: do not try to write more than one <script> in your view.*/
				/* break;  process only one script element */
			}
		}
		
	},
	
	_executeScript : function(scriptFrag, partId) {
		var scriptContainerId = partId + "_SCRIPT_CONTAINER";
		var obj = $(scriptContainerId);
		var ss = document.getElementsByTagName("SCRIPT");
		if (obj != null) {
			document.body.removeChild(obj);
		}
		var scriptContainer = document.createElement('SCRIPT');
		scriptContainer.setAttribute("id", scriptContainerId);
		scriptContainer.text = scriptFrag;
		document.body.appendChild(scriptContainer);
	} 

}

Object.extend(Buffalo.prototype, {

	switchView: function(viewName, container) {
		container = container ? container : "body";
		this.switchPart(container, viewName, true);
	},
	
	switchPart : function(partId, viewName, addToHistory) {		
		new Buffalo.View(this).switchPart(partId, viewName, addToHistory);
	}
});
Buffalo.Form = {
	formToBean : function(form, boClass, ignoreButton) {
		var object = {};
		if (boClass) { object[Buffalo.BOCLASS] = boClass; } else{
			object[Buffalo.BOCLASS] = "java.util.Map";
		}
		if (typeof(ignoreButton) == "undefined" || ignoreButton == true) {
			ignoreButton = true;
		} else {
			ignoreButton = false;
		}
		
		form = $(form);
		var elements = form.elements;
		for (var i = 0; i < elements.length;i++) {
			var element = elements[i];
			if (!element.type) continue;
			switch (element.type) {
			case "radio" : 
				if (element.checked) { 
					object[element.name]=element.value
				} 
				break;
			case "checkbox" : 
				if (!form[element.name].length) {
					if (element.checked) object[element.name]=element.value ;
					else object[element.name]="";
				} else {
					if (!object[element.name]) {object[element.name] = new Array()};
    				if (element.checked) {object[element.name].push(element.value);}
				}
				break;
			case "select-one" : 
				var value = '', opt, index = element.selectedIndex;
				if (index >= 0) {
					opt = element.options[index];
					value = opt.value;
					if (!value && !('value' in opt)) value = opt.text;
				}
				object[element.name] = value;
				break;
			case "select-multiple" :
				if (!object[element.name]) {object[element.name] = new Array()};
				for (var j = 0; j < element.options.length; j++) {
					var opt = element.options[j];
					if (opt.selected) {
						var optValue = opt.value;
						if (!optValue && !('value' in opt)) optValue = opt.text;
						object[element.name].push(optValue);
					}
			    }
			    break;
			default :
				if (ignoreButton) {
					if (element.type != "submit" && element.type != "button" 
						&& element.type != "reset") {
						object[element.name] = element.value;
					}
				} else {
					object[element.name] = element.value;
				}
				break;
			}
		}
		
		return object;
	},
	
	bindForm: function(form, data) {
		form = $(form);
		for (var i = 0; i < form.elements.length;i++) {
			var element = form.elements[i];
			if (!data[element.name]) continue;
			var val = data[element.name];
			switch (element.type) {
			case "text": ;
			case "hidden": ;
			case "password": element.value = val; break;
			case "radio" : 
			case "checkbox" : 
				if (val instanceof Array) element.checked = (val.indexOf(element.value) > -1);
				else element.checked = (element.value ==val);
				break;
			case "select-one" : 
			case "select-multiple" : 
				for (var j = 0; j < element.options.length; j++) {
					var option = element.options[j];
					if (val instanceof Array) {
						option.selected = (val.indexOf(option.value) > -1);
					} else {
						option.selected = (option.value == val);
					}
				}
				break;
			}
		}
	}
}
 /***********************************
 * buffalo.js 结束
 ***********************************/
   
/**JS工具类代码块 BEGIN （SKH）***********************************/
function TXUtil(){} // 静态工具类构造方法

TXUtil.create = function (pro) {
    // alert(pro)
	if(pro==null || pro.flag==undefined){
		alert('tixa.js TXUitl.create 无效对象');
		return null;
	}
	var newElement = document.createElement(pro.flag); 
    if(pro.id)         newElement.id = pro.id ;
    // input属性
    if(pro.name)       newElement.name = pro.name ;
    if(pro.type)       newElement.type = pro.type ;
    
    if(pro.position)   newElement.style.position = pro.position;
    if(pro.display)    newElement.style.display  = pro.display;
    if(pro.top)        newElement.style.top      = (pro.top);
    if(pro.left)       newElement.style.left     = (pro.left);
    if(pro.width)      newElement.style.width    = (pro.width);
    if(pro.height)     newElement.style.height   = (pro.height); 
    if(pro.iheight)    newElement.style.lineHeight = (pro.iheight);
    if(pro.index)      newElement.style.zIndex   = (pro.index);
    if(pro.border)     newElement.style.border   = (pro.border);//+'px solid #333333';
    if(pro.text)       newElement.appendChild(document.createTextNode(pro.text));
    if(pro.background) newElement.style.background = pro.background ;
    if(pro.fsize)      newElement.style.fontSize   = pro.fsize ;
    if(pro.talign)     newElement.style.textAlign  = pro.talign ;

    if(pro.mleft)      newElement.style.marginLeft   = pro.mleft ;
    if(pro.mright)     newElement.style.marginRight  = pro.mright ;
    if(pro.mtop)       newElement.style.marginTop    = pro.mtop ;
    if(pro.mbottom)    newElement.style.marginBottom = pro.mbottom ;
    
    if(pro.pleft)     newElement.style.paddingLeft   = pro.pleft ;
    if(pro.pright)    newElement.style.paddingRight  = pro.pright ;
    if(pro.ptop)      newElement.style.paddingTop    = pro.ptop ;
    if(pro.pbottom)   newElement.style.paddingBottom = pro.pbottom ;

    if(pro.float){
        if(TXUtil.browser().name=="ie")    
    	newElement.style.styleFloat = pro.float ;
    	else if(TXUtil.browser().name=="ff")   
        newElement.style.cssFloat = pro.float ;
    }
    
    if(pro.sy)         newElement.style.overflowY = pro.sy;//sy:"auto";
    if(pro.sx)         newElement.style.overflowX = pro.sx;
    if(pro.cs)         newElement.className        = pro.cs ;
    

    if(pro.frameBorder) newElement.frameBorder=pro.frameBorder; // iframe是否显示边框newElement.frameBorder="no";
    
    if(pro.alpha){
        if(document.all){
	       newElement.style.filter = "alpha(opacity="+(pro.alpha*100)+");"
	    } else {
	       newElement.style.MozOpacity='0.6'; 
	    }
    }
    return newElement;
}

TXUtil.browser = function () {
	var name = navigator.appName.toLowerCase();
	var version = navigator.appVersion.toLowerCase();
	var agent = navigator.userAgent.toLowerCase();
    //alert("name :\n "+name +"\n version:\n"+version +"\n agent: \n"+agent)
	var json={};
	//var versions = version.split(";");
	//var ver = versions[1].replace(/[ ]/g,"");
	//// alert(navigator.appName.toLowerCase() +"  "+navigator.appVersion.split(";")[0].replace(/[ ]/g,""))
	if(name=="microsoft internet explorer" && agent.indexOf("msie 7.0") > -1){
	  json={ name:'ie' , version:'7' };
	} else if(name=="microsoft internet explorer" && agent.indexOf("msie 6.0") > -1){
      json={ name:'ie' , version:'6' };
	} else if(name=="netscape" && agent.indexOf("firefox") > -1){
      json={ name:'ff' , version:'3.1' };
	}
	return json;
}

TXUtil.point = function (el) {
	//if ( el.length != 1 || el == null ) {
	//       return null;
	//}
    var left = el.offsetLeft;
	var top  = el.offsetTop;
	var width  = el.offsetWidth;
	var height = el.offsetHeight;

	var em = el.offsetParent;
	while (em != null){
		if ( em.style.position == 'absolute' || ( em.style.overflow != 'visible' && em.style.overflow != '' ) ){
		        break;
		}
		left += em.offsetLeft;
		top  += em.offsetTop;
		em    = em.offsetParent;
	}
	//alert("left:"+ left +"  top:"+ top + "  width:"+width + "  height:" + height);
	return {"left":left,"top":top,"width":width,"height":height,"right":width+left, "bottom":height+top};
}

TXUtil.request = function () {
	var request = false;
	if (window.XMLHttpRequest) { //Mozilla browser
		request = new XMLHttpRequest();
	} else if (window.ActiveXObject) { // IE browser
		try {
			request = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				request = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {}
		}
	}
	return request;
}

TXUtil.Hashtable = function () {
	var me = this;
	me.map = new Object() ;
	me.add = function ( key , value ) {	 
		if ( typeof(key)!="undefined") {
			   if ( me.contains( key ) == false ) {
			   me.map[key] = typeof( value ) == "undefined" ? null : value ;
			   return true;
			   }
		}
		return false;  
	}
 
	me.remove = function(key){
		delete me.map[key];
	}
	
	me.del = function(index){
		me.map.splice(index,1);
		return true ;
	}
	
	me.count = function() {
		var i=0;
		for ( var k in me.map ) {
			i++;
		} 
		return i;
	}
	
	me.get = function ( key ) {
		return me.map[key];
	}
	
	me.contains = function ( key ) { 
		return typeof( me.map[key] ) != "undefined";
	}
}

TXUtil.get = function (byId) {
	try {
		if(document.getElementById(byId)!=null){
			return document.getElementById(byId);
		}
	} catch(e) {}
	return null;
}

TXUtil.cutLastComman = function (s) {
	return (TXUtil.isEmpty(s)) ? "" : cutLastlyComma(s);
}
// 空:true 非:false
TXUtil.isEmpty = function(str){
   return (str==null || str.toString().replace(/^\s+|\s+$/g,'')=='');
}

TXUtil.setChecked = function( groupName , p_value , bool ){
	var list=document.getElementsByName(groupName);
	if(list==null){
		alert( groupName +" is null,TXUtil.set_checked()" );
		return;
	}
	for(var i=0;i<list.length;i++){ 
		if(list[i].value==p_value){
			list[i].checked = bool;
		}
	}
}

// 处理字符串比如：,,,,1,,2,,3,,,, 改成 1,2,3
TXUtil.stringRevamp = function (ids) {
       if(TXUtil.isEmpty(ids))return "" ;
       if(ids.indexOf(",")==-1)return ids ;
	   var temp = "";
	   var array = ids.split(",");
	   for ( var i=0; i<array.length; i++ ) {
	      if(TXUtil.isEmpty(array[i]))continue;
	      temp += array[i]+",";
	   }
	   return TXUtil.cutLastComman(temp);
}
TXUtil.bugcount=0;
TXUtil.bug = function (info,isappend) {
    var pro = {'flag':"div",'id':'txbugId','position':"absolute",'display':"block",'top':"300px",'left':"200px",'width':"300px",'height':"165px",sy:"auto",'border':"1px solid #CAD9EA",'index':"9997",'background':"#FFFFFF"};
    if(TXUtil.get('txbugId')==null){
    document.body.appendChild(TXUtil.create(pro));
	}
	isappend=(isappend==null || isappend==undefined)?true:isappend;
	if(isappend)
	TXUtil.get('txbugId').innerHTML = "["+(TXUtil.bugcount++)+"] "+info + "<br>" + TXUtil.get('txbugId').innerHTML;
	else
    TXUtil.get('txbugId').innerHTML = info ;
}
/**JS工具代码块 End （SKH）***********************************/
//解除表单某些fields的disabled(提交的时候使用)
function enableFields(fields,form) {
    for(var i=0;i<fields.length;i++) {
        var field = fields[i];
        if (field instanceof(Array)) {
            for (var j=0;j<field.length;j++) {
            	if(field[j].disabled == true) {
					field[j].disabled = false;
					form.style.display = "none";
				}
            }
        } else {
			if (field.disabled) {
				field.disabled = false;
				form.style.display = "none";
			}
        }
    }
}	

//根据浏览器获取元素的位置
function getElementPos(elementId) {
	var ua = navigator.userAgent.toLowerCase();
	var isOpera = (ua.indexOf('opera') != -1);
	var isIE = (ua.indexOf('msie') != -1 && !isOpera); // not opera spoof
	var el = document.getElementById(elementId);
	if(el.parentNode === null || el.style.display == 'none')
	{
		return false;
	}
	var parent = null;
	var pos = [];
	var box;
	if(el.getBoundingClientRect) //IE
	{
		box = el.getBoundingClientRect();
		var scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
		var scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
		return {x:box.left + scrollLeft, y:box.top + scrollTop};
	}
	else if(document.getBoxObjectFor) // gecko
	{
		box = document.getBoxObjectFor(el);
		var borderLeft = (el.style.borderLeftWidth)?parseInt(el.style.borderLeftWidth):0;
		var borderTop = (el.style.borderTopWidth)?parseInt(el.style.borderTopWidth):0;
		pos = [box.x - borderLeft, box.y - borderTop];
	}
	else // safari & opera
	{
		pos = [el.offsetLeft, el.offsetTop];
		parent = el.offsetParent;
		if (parent != el) {
			while (parent) {
			pos[0] += parent.offsetLeft;
			pos[1] += parent.offsetTop;
			parent = parent.offsetParent;
			}
		}

		if (ua.indexOf('opera') != -1|| ( ua.indexOf('safari') != -1 && el.style.position == 'absolute' ))
		{
			pos[0] -= document.body.offsetLeft;
			pos[1] -= document.body.offsetTop;
		}
	}
	if (el.parentNode) 
	{ 
		parent = el.parentNode; 
	}
	else 
	{ 
		parent = null; 
	}

	while (parent && parent.tagName != 'BODY' && parent.tagName != 'HTML')
	{ // account for any scrolled ancestors
		pos[0] -= parent.scrollLeft;
		pos[1] -= parent.scrollTop;
		if (parent.parentNode) { parent = parent.parentNode; }
		else { parent = null; }
	}
	return {x:pos[0], y:pos[1]};
}
var toolDiv = null;
function ShowToolDiv(){
    if(toolDiv == null){
    	toolDiv = document.createElement("div");
        toolDiv.id ="toolDiv";
        toolDiv.style.position = "absolute";
        toolDiv.style.backgroundColor = "white";
        toolDiv.style.border = "1px solid #6fb9c6";
        toolDiv.style.width = "113px";
        toolDiv.style.zIndex = "999";
        toolDiv.style.display = "none";
        toolDiv.onmouseover = function(){ShowSelf("block");}
        toolDiv.onmouseout = function(){ShowSelf("none");}
        toolDiv.innerHTML = $("toolDivModdle").innerHTML;   
        document.body.appendChild(toolDiv);
    }
    var pos = getElementPos("toolDivParent");
	var x = pos.x;
	var y = pos.y;	
	
	if(IE){
		toolDiv.style.top = (y+25) + 'px' ;
		toolDiv.style.left = (x-23) + 'px';
	}
	else{
		toolDiv.style.top = (y+25) + 'px' ;
		toolDiv.style.left = (x-23) + 'px';
	}
    $("toolDiv").style.display = "block";
}
function ShowSelf(arg){
	$("toolDiv").style.display = arg;
}
function ShowAndCloseDiv_1(divId,imgId){
	if($(divId).style.display=="none"){
		$(divId).style.display = "block";
		$(imgId).src="/images/bt-n031.jpg";
		
	}
	else{
		$(divId).style.display = "none";
		$(imgId).src="/images/bt-n03.jpg";
	}	
}
function ShowAndCloseDiv_2(divId,imgId,bottomImgId){
	if(bottomImgId!=""){
		if(document.getElementById(divId).style.display=="none"){
			document.getElementById(divId).style.display = "block";
			document.getElementById(imgId).src="/images/bt-n041.jpg";
			document.getElementById(bottomImgId).src="/images/bg-n053.jpg";
			
		}
		else{
			document.getElementById(divId).style.display = "none";
			document.getElementById(imgId).src="/images/bt-n04.jpg";
			document.getElementById(bottomImgId).src="/images/bg-n052.jpg";
		}	
	}
	else{
		if(document.getElementById(divId).style.display=="none"){
			document.getElementById(divId).style.display = "block";
			document.getElementById(imgId).src="/images/bt-n041.jpg";			
		}
		else{
			document.getElementById(divId).style.display = "none";
			document.getElementById(imgId).src="/images/bt-n04.jpg";
		}
	}
}
