function $(item){
	return document.getElementById(item);
}
function $N(name){ return document.getElementsByName(name);}
isUndef  = function(a){ return typeof a == "undefined";};

String.prototype.trim   =   function(){
    return   this.replace(/(^\s*)|(\s*$)/g,   "");
}
String.prototype.escapeHTML   =   function(){
    return   this.replace(/<.+?>/mig, "");
}
String.prototype.bytesLength = function(){
	var cArr = this.match(/[^\x00-\xff]/ig);
	return this.length + (cArr == null ? 0 : cArr.length);
} 
String.prototype.strip = function(){
	var temp = this;
	temp = temp.replace(/&/ig, "&amp;"); 
	temp = temp.replace(/</ig, "&lt;");
	temp = temp.replace(/>/ig, "&gt;");
	temp = temp.replace(/\"/ig, "&quot;");
	temp = temp.replace(/\'/ig, "&#39;");
	temp = temp.replace(/ /ig, "&nbsp;");
	temp = temp.replace(/(\r?\n)|\r/ig, "<br />");
	return temp;
}
function getCookie(name){
    return (document.cookie.match(new RegExp("(^"+name+"| "+name+")=([^;]*)"))==null)?"":decodeURIComponent(RegExp.$2);
}

function setCookie(name,value,hours,isBaseDomain){
	if(arguments.length>2){
		var expireDate=new Date(new Date().getTime()+hours*3600000);
		if(isBaseDomain != undefined && isBaseDomain == 1){
			document.cookie = name + "=" + encodeURIComponent(value) + "; path=/; domain=xunlei.com; expires=" + expireDate.toGMTString() ;
		}else{
			document.cookie = name + "=" + encodeURIComponent(value) + "; path=/; domain=vip.xunlei.com; expires=" + expireDate.toGMTString() ;
		}
	}else
		document.cookie = name + "=" + encodeURIComponent(value) + "; path=/; domain=vip.xunlei.com"; 
}

// 获取形如  &name=test  的url参数
function getParam(url, param) {  
    var reg = "/^.*[\\?|\\&]" + param + "\\=([^\\&]*)/";  
    reg = eval(reg);  
      
    var ret = url.match(reg);  
    if (ret != null) {  
        return decodeURIComponent(ret[1]);  
    } else {
        return "";  
    }     
}  

//获取形如  /xf/1  的url参数
function getURLParam(url, param) {
    var reg = "/^.*\\/" + param + "\\/([^/?&]*)/";
    reg = eval(reg);  
      
    var ret = url.match(reg);  
    if (ret != null) {  
        return decodeURIComponent(ret[1]);  
    } else {
        return "";  
    }     	
}

//刷新页面
function refreshPage(){
	// fix 不能刷新形如 http://vip.xunlei.com/help/help-1.html#1 的页面
	top.location.href = getnocacheurl(top.location.href.replace(/#\d+/, ''));
}

function getnocacheurl(urlstr){
	var returnurl = "http://vip.xunlei.com";
	var cachetime = new Date().getTime();
	 var index = urlstr.indexOf("cachetime=");
	 var param = urlstr.indexOf("?");
	 if(index == -1){
		 if(param == -1){
			 returnurl = urlstr + "?cachetime=" + cachetime;
		 }else{
			 returnurl = urlstr + "&cachetime=" + cachetime;
		 }
	 }else{
		 if(param == -1){
			 returnurl = urlstr.substring(0,index) + "?cachetime=" + cachetime;
		 }else{
			 returnurl = urlstr.substring(0,index) + "&cachetime=" + cachetime;
		 }
	 }
	 return returnurl.replace('&&','&').replace('?&','?');
}

function openpage(page){
	window.open(getnocacheurl(page));
}
function redirectpage(page){
	top.location.href = getnocacheurl(page);
}
/**
 * 判断是否为中文
 */
function chkChinese(s){
	for(var i = 0; i < s.length; i++){
		if(s.charCodeAt(i)>255)
		  return true;
	}
	return false;
};

/**
 * 定义验证各种格式类型的正则表达式对象
 */
var Regexs = {
  email:   (/^[0-9a-z][0-9a-z\-\_\.]+@([0-9a-z][0-9a-z\-]*\.)+[a-z]{2,}$/i),
  phone:   (/^0[0-9]{2,3}[2-9][0-9]{6,7}$/),
  ydphpne: (/^((13[4-9])|(15[012789])|147|187|188)[0-9]{8}$/),
  allphpne: (/^((13[0-9])|(15[0-9])|(18[0-9]))[0-9]{8}$/),
  ltphpne: (/^((13[0-2])|(15[56])|(186))[0-9]{8}$/),
  dxphpne: (/^((133)|(153)|(189))[0-9]{8}$/),
  url:     (/^http:\/\/([0-9a-z][0-9a-z\-]*\.)+[a-z]{2,}(:\d+)?\/[0-9a-z%\-_\/\.]+/i),
  num:    (/[^0-9]/),
  cnum:	  (/[^0-9a-zA-Z_.]/),
  photo:   (/\.jpg$|\.jpeg$|\.gif$/i),
  row:     (/\n/ig) 
};

/**
 * @return 若符合对应的格式，返回true，否则返回false
 */
function chkFormat(str,ftype){	
	var nReg  = Regexs[ftype];	
	if(str == null||str == "") return false;	//输入为空，认为是验证通过
	if(ftype == 'num'){
		if(!nReg.test(str)&&!chkChinese(str)){//10.23 tenfy 必须为数字且不能有中文
			 return true;
		}else{
			return false;
		}
	}
	if(!nReg.test(str)){
		return true;
	} else{
		return false;
	}
};
// 显示层
function showLayer(ob){ob.style.display = "";}
// 隐藏层
function hideLayer(ob){ob.style.display = "none";}
/********************************* javascript事件模型框架-eventutil.js *********************************/
// 检测浏览器对象
var sUserAgent = navigator.userAgent.toLowerCase();
var isOpera = sUserAgent.indexOf("opera")>-1;
var isIE = sUserAgent.indexOf("compatible")>-1 && sUserAgent.indexOf("msie")>-1 && !isOpera;
var isWin= (navigator.platform == "Win32" || navigator.platform == "Windows");

var EventUtil = new Object;
//格式化事件，因为IE和其他浏览器下获取事件的方式不同并且事件的属性也不尽相同，通过此方法提供一个一致的事件
EventUtil.formatEvent = function (oEvent) {
     //isIE和isWin引用到一个js文件，判断浏览器和操作系统类型
     if (isIE && isWin) {
         oEvent.charCode = (oEvent.type == "keypress") ? oEvent.keyCode : 0;
         //IE只支持冒泡，不支持捕获
         oEvent.eventPhase = 2;
         oEvent.isChar = (oEvent.charCode > 0);
         oEvent.pageX = oEvent.clientX + document.body.scrollLeft;
         oEvent.pageY = oEvent.clientY + document.body.scrollTop;
         //阻止事件的默认行为
         oEvent.preventDefault = function () {
             this.returnValue = false;
         };

          //将toElement,fromElement转化为标准的relatedTarget
         if (oEvent.type == "mouseout") {
             oEvent.relatedTarget = oEvent.toElement;
         } else if (oEvent.type == "mouseover") {
             oEvent.relatedTarget = oEvent.fromElement;
         }
         //取消冒泡     
         oEvent.stopPropagation = function () {
             this.cancelBubble = true;
         };

         oEvent.target = oEvent.srcElement;
         //添加事件发生时间属性，IE没有
         oEvent.time = (new Date).getTime();
     }
     return oEvent;
};

EventUtil.getEvent = function() {
     if (window.event) {
         //格式化IE的事件
         return this.formatEvent(window.event);
     } else {
         return EventUtil.getEvent.caller.arguments[0];
     }
};
/********************************* javascript事件模型框架-eventutil.js *********************************/

// 判断字符集
function validChars(o, e){
	var e = EventUtil.formatEvent(e);
	if(e.charCode==0)	return true;
	var c = String.fromCharCode(e.charCode);
	var bIs = bIsNot = true;

	s = o.getAttribute("validchars");
	if(s && s.length>0)		bIs = s.indexOf(c) > -1;
	s = o.getAttribute("invalidchars");
	if(s && s.length>0)		bIsNot = s.indexOf(c) == -1;

	return e.ctrlKey || (bIs && bIsNot);
}/*  |xGv00|af1182a2798e84e4af1033957163a153 */
//页面跳转  
function go_new(index){
	   window.top.location=g_static_urls['domain']+g_static_urls[index]+"?cachetime="+new Date().getTime();
}
function go_new1(index){
	   window.top.location=g_dynamic_urls['domain']+g_dynamic_urls[index]+"?cachetime="+new Date().getTime();
}
function go_new_np(index){
	   window.open(g_static_urls['domain']+g_static_urls[index]+"?cachetime="+new Date().getTime());
}

function go_new1_np(index){
	   window.open(g_dynamic_urls['domain']+g_dynamic_urls[index]+"?cachetime="+new Date().getTime());
}
//统计开通来源 add 2009.07.06
// 支持指定开通方式、开通月数
function go_pay_referFrom(index, payway, month){
  index = index || "";
  var pway = '';
  if(payway && payway != "") {
	  pway = "payway/" + payway;
  }
  if(month && month != "") {
	  pway += "/month/" + month;
  }
  window.open(g_dynamic_urls['domain']+g_dynamic_urls['kaitong']+ pway +"?cachetime="+new Date().getTime() + "&referfrom=VIP_" + index);
}
var _referFromNum = 0;     //hidden
var _headReferFromNum = 0; //头部文字链 num
var _ktframeFromNum = 0;  // 登录框下开通模块
function setRerferNum4Lbox(num, headNum, ktframe){
	_referFromNum = num;
	if(headNum) _headReferFromNum = headNum;
	if(ktframe != undefined) _ktframeFromNum = ktframe;
	if(_referFromNum != 0)
	  setCookie("vip_referfrom_b","VIP_" +　_referFromNum);
}
/**
 * 跳转到支付页
 * @param location  区别跳转的位置是页头按钮， 还是登录区按钮
 * @param payway
 * @param month
 * @return
 */
function go_pay_loginBox(location, payway, month){
	var refNum = _referFromNum;
	if(location == 'head') {
		refNum = _headReferFromNum;
	} else if(location == 'ktframe' && _ktframeFromNum > 0) {
		refNum = _ktframeFromNum;
	}
	var pway = '';
	if(payway && payway != "") {
		pway = "payway/" + payway;
	}
	if(month && month != "") {
		pway += "/month/" + month;
	}	
	
	if(refNum != 0)
	  window.open(g_dynamic_urls['domain']+g_dynamic_urls['kaitong']+pway+"?cachetime="+new Date().getTime() + "&referfrom=VIP_" + refNum);
	else
	  window.open(g_dynamic_urls['domain']+g_dynamic_urls['kaitong']+pway+"?cachetime="+new Date().getTime());
}

//静态链接
var g_static_urls={
	 domain:	("http://vip.xunlei.com/"),
	 index :("index.html"),
	 my_freedom_index:("my_freedom/level.html"),
	 freedom_set:("freedom/index.html"),
	 score_improve:("freedom/score_improve.html"),
	 exclusive_skin:("freedom/exclusive_skin.html"),
	 freedom_skinad:("freedom/freedom_skinad.html"),
	 nickname:("freedom/nickname.html"),
	 gamegift:("freedom/game_present.html"),
	 bluestone:("freedom/blue_stone.html"),
	 help:("help/index.html"),
	 yuanxun:("team/yuanxun.html"),
	 discount:("freedom/vip_discount.html"),
	 forums:("freedom/vip_forums.html"),
	 server:("freedom/exclusive_server.html"),
	 safesrv:("freedom/safety_service.html"),
	 mygrown:("my_freedom/mygrown.html"),
	 yxrank:("yuanxun/rank.html"),
	 yxintro:("yuanxun/introduce.html"),
	 sjtuiding:("help/tuiding.html"),
	 vipchannel:("freedom/exclusive_channel.html"),
	 account_retention:("freedom/account_retention.html")
};
//动态请求
var g_dynamic_urls={
		 domain:	("http://dynamic.vip.xunlei.com/"),
		 kaitong :("paycenter/index/"),
		 kaitong_zfb :("paycenter/index/payway/zfb"),
		 sendvip :("paycenter/send"),
		 my_mycenter_index :("my/my_mycenter_index"),
		 my_mycenter_myfun:("my/my_mycenter_myfun"),
		 my_mycenter_mylevel:("my/my_mycenter_mylevel"),
		 xufei :("paycenter/index"),
		 payinfo:("paycenter/orderlist"),
		 tuiding:("my/my_mycenter_tuiding"),
		 game_act:("game/act"),
		 vipmovie:("movie/"),
		 qyuanxun:("yuanxun/yuanxun/query")
		 //kaitong :("my/my_mycenter_myfun")
};
//使用iframe发送请求并回调js方法
function g_sendUrlAndCallBack(u,callback){
	var ifr=document.createElement('iframe');
	document.body.appendChild(ifr);
	ifr.id="result_frm";
	ifr.style.visibility="hidden";
	ifr.width="0";
	ifr.height="0";
	ifr.src=u;
	if(ifr.attachEvent) {
    	ifr.attachEvent('onload',function (){
    									   callback();
    									   document.body.removeChild(ifr);
    									   });		    
	} else {
	    ifr.addEventListener('onload',function (){
    									   callback();
    									   document.body.removeChild(ifr);
    									   }, false);
	}	
}
//利用js发送http请求包
function sendHttpPack(scripturl){
	var ifr=document.createElement("script");
	ifr.src=scripturl;
	
	if(ifr.attachEvent) {
	    ifr.attachEvent('onload',function (){});
	} else {
	    ifr.addEventListener('onload',function (){}, false);
	}			
}
//异步的获取信息接口 
//url:请求url params：参数 onread_func:回调函数 err_func:错误处理函数 method:若没有设置该参数，则默认为GET方法
function loadTextAsync(url, params,onread_func,err_func, method){
 var req =null,newUrl="";
 try{req =creXRequest();}catch(e){alert("你的浏览器无法创建XMLHttpRequest");return false;}
 req.onreadystatechange=function(){
  if(req.readyState==4){
   if(req.status==200){if(isFunction(onread_func)==true){onread_func(req.responseText);}}
   else if(err_func!=null&&isFunction(err_func)==true){err_func();}
  }
 }
 if(params!=null&&params!=""&&params!='') newUrl=url+"?"+params;else newUrl=url;
 switch(method){// Send a XMLHttpRequest
  case "GET":req.open("GET",newUrl,true);req.send(null);break;
  case "POST":req.open("POST",url,true);req.setRequestHeader("Content-Type","application/x-www-form-urlencoded");req.send(params);break;
  case "HEAD":req.open("HEAD",newUrl,true);req.send(null);break;
  default:req.open("GET",newUrl,true);req.send(null);break;
 }//< switch
};
//定义了各种环境常量的对象
var EnvXml={
 useActiveX: (typeof window.ActiveXObject != "undefined"),//ActiveX控件是否可用,for IE before v7
 useDom: (document.implementation && document.implementation.createDocument),//XMLDocument是否可以通过createDocument创建
 useXmlHttp: (typeof window.XMLHttpRequest != "undefined")//XMLHttpRequest是否可以通过new XMLHttpRequest方法创建
};
//定义了Microsoft的XmlDom的版本
EnvXml.MS_DOM_VERS=["MSXML2.DOMDocument.6.0","MSXML2.DOMDocument.5.0","MSXML2.DOMDocument.4.0","MSXML2.DOMDocument.3.0","MSXML2.DOMDocument","Microsoft.XmlDom"];
//定义了Microsoft的XMLHttpRequest对象版本
EnvXml.MS_XMLHTTP_VERS=["MSXML2.XMLHTTP.5.0","Msxml2.XMLHTTP.4.0","MSXML2.XMLHTTP.3.0","Msxml2.XMLHTTP","Microsoft.XMLHTTP"];
function creXRequest(){
 var xmlHttp = null;
 if(EnvXml.useXmlHttp){//<If IE7, Mozilla, Safari, and so on: Use native object
  xmlHttp = new XMLHttpRequest();if(xmlHttp.overrideMimeType){xmlHttp.overrideMimeType('text/xml');}return xmlHttp;
 }
 else if(EnvXml.useActiveX){ //<otherwise, use the ActiveX control for IE5.x and IE6
   if(!EnvXml.XMLHTTP_VER){
    for(var i=0;i<EnvXml.MS_XMLHTTP_VERS.length;i++){
     try{new ActiveXObject(EnvXml.MS_XMLHTTP_VERS[i]);EnvXml.XMLHTTP_VER = EnvXml.MS_XMLHTTP_VERS[i];break;}catch(e){;}
    }//end for
   }//end if
   if(EnvXml.XMLHTTP_VER){return new ActiveXObject(EnvXml.XMLHTTP_VER);}else{throw new Error("您的浏览器无法创建XMLHttpRequest.")}
 }
 else{throw new Error("您的浏览器不支持XMLHttpRequest.");}
};
function isFunction(wh){if(!wh){return false;}return(wh instanceof Function || typeof wh=="function");};
//md5
/*
 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
 * Digest Algorithm, as defined in RFC 1321.
 * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for more info.
 */

/*
 * Configurable variables. You may need to tweak these to be compatible with
 * the server-side, but the defaults work in most cases.
 */
var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */

/*
 * These are the functions you'll usually want to call
 * They take string arguments and return either hex or base-64 encoded strings
 */
function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }

/*
 * Perform a simple self-test to see if the VM is working
 */
function md5_vm_test()
{
  return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
}

/*
 * Calculate the MD5 of an array of little-endian words, and a bit length
 */
function core_md5(x, len)
{
  /* append padding */
  x[len >> 5] |= 0x80 << ((len) % 32);
  x[(((len + 64) >>> 9) << 4) + 14] = len;

  var a =  1732584193;
  var b = -271733879;
  var c = -1732584194;
  var d =  271733878;

  for(var i = 0; i < x.length; i += 16)
  {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;

    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
    d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
    c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
    b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
    a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
    d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
    c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
    b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
    a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
    d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
    c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
    b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
    a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
    d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
    c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
    b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);

    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
    d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
    c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
    b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
    a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
    d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
    c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
    b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
    a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
    d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
    c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
    b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
    a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
    d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
    c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
    b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
    d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
    c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
    b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
    a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
    d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
    c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
    b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
    a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
    d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
    c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
    b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
    a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
    d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
    c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
    b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
    d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
    c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
    b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
    a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
    d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
    c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
    b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
    a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
    d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
    c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
    b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
    a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
    d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
    c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
    b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
  }
  return Array(a, b, c, d);

}

/*
 * These functions implement the four basic operations the algorithm uses.
 */
function md5_cmn(q, a, b, x, s, t)
{
  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t)
{
  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
  return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}

/*
 * Calculate the HMAC-MD5, of a key and some data
 */
function core_hmac_md5(key, data)
{
  var bkey = str2binl(key);
  if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);

  var ipad = Array(16), opad = Array(16);
  for(var i = 0; i < 16; i++)
  {
    ipad[i] = bkey[i] ^ 0x36363636;
    opad[i] = bkey[i] ^ 0x5C5C5C5C;
  }

  var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
  return core_md5(opad.concat(hash), 512 + 128);
}

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
function safe_add(x, y)
{
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
}

/*
 * Bitwise rotate a 32-bit number to the left.
 */
function bit_rol(num, cnt)
{
  return (num << cnt) | (num >>> (32 - cnt));
}

/*
 * Convert a string to an array of little-endian words
 * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
 */
function str2binl(str)
{
  var bin = Array();
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < str.length * chrsz; i += chrsz)
    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
  return bin;
}

/*
 * Convert an array of little-endian words to a string
 */
function binl2str(bin)
{
  var str = "";
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < bin.length * 32; i += chrsz)
    str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
  return str;
}

/*
 * Convert an array of little-endian words to a hex string.
 */
function binl2hex(binarray)
{
  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i++)
  {
    str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
           hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
  }
  return str;
}

/*
 * Convert an array of little-endian words to a base-64 string
 */
function binl2b64(binarray)
{
  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i += 3)
  {
    var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
                | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
                |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
    for(var j = 0; j < 4; j++)
    {
      if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
      else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
    }
  }
  return str;
}