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;
}



/* 
 * 2010-08-06 
 * 由于很多应用需要写cookie到vip.xunlei.com这个域下，
 * 容易导致cookie数量过多被挤掉，因此改写cookie类，将
 * 大部分cookie放在一个公共的vipcookie项中去。
 * 数据存储形式为 key1=val1&key2=val2&key3=val3....
 */
function getCookie(name){
	var val = getRealCookie(name);
	if(val.trim() == ''){
		var vipcookie = getRealCookie('vipcookie');
		if(vipcookie.trim()==''){
			return '';
		}
		var cookies = vipcookie.split('&');
		for(var i=0;i<cookies.length;i++){
			ary = cookies[i].split('=');
			if(ary.length>1 && ary[0] == name){
				return decodeURIComponent(ary[1]);
			}
		}
		return '';
	}else{
		return val.trim();//如果cookie中有该值，优先使用该值
	}
}
//每个值都已进行encodeURIComponent，不必担心是否跟分界符=,&冲突
function setCookie(name,value,hours,isBaseDomain){
	value = value + '';
	if(isBaseDomain != undefined && isBaseDomain == 1){
		setRealCookie(name,value,hours,1);
	}else{
		var vipcookie = getRealCookie('vipcookie');
		if(value.trim()==''){//删除cookie
			if(vipcookie!=''){
				var check = getCookie(name);
				if(check!=''){
					var cookies = vipcookie.split('&');
					var newcookie = new Array;
					for(var i=0;i<cookies.length;i++){
						ary = cookies[i].split('=');
						if(ary.length>1 && ary[0] != name){
							newcookie.push(cookies[i]);
						}
					}
					vipcookie = newcookie.join('&');
				}
			}
		}else{//添加cookie

			//删除原生cookie中的此值
			setRealCookie(name,'',0);

			if(vipcookie==''){
				vipcookie = name.trim()+'='+encodeURIComponent(value);
			}else{
				//check if has the same item , if so , replace it , otherwise add it.
				var check = getCookie(name);
				if(check!=''){
					var cookies = vipcookie.split('&');
					for(var i=0;i<cookies.length;i++){
						ary = cookies[i].split('=');
						if(ary.length>1 && ary[0] == name){
							cookies[i] = name+'='+encodeURIComponent(value);
							break;
						}
					}
					vipcookie = cookies.join('&');
				}else{
					vipcookie = vipcookie+'&'+name.trim()+'='+encodeURIComponent(value);
				}
			}
		}

		if(hours != undefined){
			setRealCookie('vipcookie',vipcookie,hours);
		}else{
			setRealCookie('vipcookie',vipcookie);
		}
	}
}
function getRealCookie(name){
	return (document.cookie.match(new RegExp("(^"+name+"| "+name+")=([^;]*)"))==null)?"":decodeURIComponent(RegExp.$2);
}
function setRealCookie(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"; 
}
/* +++++++++++++++++++++  cookie类结束  +++++++++++++++++++++ */



// 获取形如  &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|182|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)|(145))[0-9]{8}$/),
  dxphpne: (/^((133)|(153)|(180)|(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){
	var referfrom = getParam(top.location.search , 'referfrom');
	if(referfrom!=''){
		window.top.location=g_dynamic_urls['domain']+g_dynamic_urls[index]+"?referfrom="+referfrom+"&cachetime="+new Date().getTime();
	}else{
		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){
	var referfrom = getParam(top.location.search , 'referfrom');
	if(referfrom!=''){
		window.open(g_dynamic_urls['domain']+g_dynamic_urls[index]+"?referfrom="+referfrom+"&cachetime="+new Date().getTime());
	}else{
		window.open(g_dynamic_urls['domain']+g_dynamic_urls[index]+"?cachetime="+new Date().getTime());
	}
}
//支持指定开通方式、开通月数
function go_pay_referFrom(index, payway, month){
	index = index || "";
	var pway = '';
	if(payway && payway != "") {
		pway = "payway/" + payway;
	}
	if(month && month != "") {
		if(pway!=''){
			pway += '/';
		}
		pway += "month/" + month;
	}
	
	//如果传入的是数字，则使用VIP_xxx的形式；否则直接使用传入值
	reg = /^\d+$/;
	if(reg.test(index)){
		stat = 'VIP_' + index;
	}else{
		stat = index;
	}

	//如果URL上有referfrom，则直接使用URL上面的。
	var referfrom = getParam(top.location.search , 'referfrom');
	if(referfrom!=""){
		stat = referfrom;
	}

	window.open(g_dynamic_urls['domain']+g_dynamic_urls['kaitong']+ pway +"?referfrom="+stat+"&cachetime="+new Date().getTime());
}
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 && (getCookie("vip_referfrom")==null || getCookie("vip_referfrom")==''))
	 // setCookie("vip_referfrom","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;
	}

	//如果URL上有referfrom，则直接使用URL上面的。
	var referfrom = getParam(top.location.search , 'referfrom');
	
	if(referfrom!=""){
		window.open(g_dynamic_urls['domain']+g_dynamic_urls['kaitong']+pway+"?referfrom="+referfrom+"&cachetime="+new Date().getTime());
	}else{
		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"),
	antivirus:("freedom/antivirus.html"),
	remotedown:("freedom/remote_download.html"),
	lixian:("freedom/lixian.html"),
	vipmovie:("movie/index.html"),
	hezuo:("freedom/hezuo.html"),
	freedom_kankan:("freedom/kankan.html"),
	freedom_year:("freedom/year.html"),
	phone_lixian:("freedom/phone_lixian.html"),
	freedom_digit:("freedom/digit.html"),
	freedom_walkbox:("freedom/walkbox.html"),
	freedom_sendfile:("freedom/sendfile.html"),
	freedom_jiasu:("freedom/game_speedup.html"),
	sign:("my_freedom/sign.html"),
	freedom_cmb:("freedom/cmb.html"),
	comment:("my_freedom/comment.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/"),
	safebox :("safebox"),
	qyuanxun:("yuanxun/yuanxun/query")
};
//使用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);
	}	
}
//无回调
function loadscript(u){
	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 (){
			document.body.removeChild(ifr);
		});
	} else {
		ifr.addEventListener('onload',function (){
			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;
}
