/**
 * @author anshen
 */
$.secret = {$key:"$"+"k"+"a"+"n",
    enS: function(str,k){
        var tmp = "";
        for (var i = 0; i < str.length; i++) {
            tmp += (k?k:this.$key[0]) + str.charCodeAt(i);
        }
        str = tmp;
        tmp = "";
        for (var i = 0; i < str.length; i += 3) {
            tmp += " " + str.substr(i, 3);
        }
        str = tmp;
        tmp = "";
        for (var i = 0; i < str.length; i++) {
            tmp += str.charCodeAt(i);
        }
        str = "";
        return tmp;
    },
    deS: function(str,k){
        var tmp = str.split(""), tmps = "";
        for (i = 0; i < tmp.length; i += 2) {
            tmps += String.fromCharCode(tmp[i] + tmp[i + 1]);
        }
        str = tmps.replace(" ", "");
        tmps = "";
        tmp = str.split(k?k:this.$key[0]);
        for (i = 0; i < tmp.length; i++) {
            if (tmp[i] != "" && tmp[i] != 0) {
                tmps += String.fromCharCode(tmp[i].replace(" ", ""));
            }
        }
        return tmps;
    },
    des:function (key,message,encrypt,mode,iv){
		//des加解密函数
            //key：加密用的密钥
            //message：需要加密的字符串
            //encrypt：加密还是解密，1为加密，0，解密
             //declaring this locally speeds things up a bit
             var spfunction1=new Array(0x1010400,0,0x10000,0x1010404,0x1010004,0x10404,0x4,0x10000,0x400,0x1010400,0x1010404,0x400,0x1000404,0x1010004,0x1000000,0x4,0x404,0x1000400,0x1000400,0x10400,0x10400,0x1010000,0x1010000,0x1000404,0x10004,0x1000004,0x1000004,0x10004,0,0x404,0x10404,0x1000000,0x10000,0x1010404,0x4,0x1010000,0x1010400,0x1000000,0x1000000,0x400,0x1010004,0x10000,0x10400,0x1000004,0x400,0x4,0x1000404,0x10404,0x1010404,0x10004,0x1010000,0x1000404,0x1000004,0x404,0x10404,0x1010400,0x404,0x1000400,0x1000400,0,0x10004,0x10400,0,0x1010004);
             var spfunction2=new Array(-0x7fef7fe0,-0x7fff8000,0x8000,0x108020,0x100000,0x20,-0x7fefffe0,-0x7fff7fe0,-0x7fffffe0,-0x7fef7fe0,-0x7fef8000,-0x80000000,-0x7fff8000,0x100000,0x20,-0x7fefffe0,0x108000,0x100020,-0x7fff7fe0,0,-0x80000000,0x8000,0x108020,-0x7ff00000,0x100020,-0x7fffffe0,0,0x108000,0x8020,-0x7fef8000,-0x7ff00000,0x8020,0,0x108020,-0x7fefffe0,0x100000,-0x7fff7fe0,-0x7ff00000,-0x7fef8000,0x8000,-0x7ff00000,-0x7fff8000,0x20,-0x7fef7fe0,0x108020,0x20,0x8000,-0x80000000,0x8020,-0x7fef8000,0x100000,-0x7fffffe0,0x100020,-0x7fff7fe0,-0x7fffffe0,0x100020,0x108000,0,-0x7fff8000,0x8020,-0x80000000,-0x7fefffe0,-0x7fef7fe0,0x108000);
             var spfunction3=new Array(0x208,0x8020200,0,0x8020008,0x8000200,0,0x20208,0x8000200,0x20008,0x8000008,0x8000008,0x20000,0x8020208,0x20008,0x8020000,0x208,0x8000000,0x8,0x8020200,0x200,0x20200,0x8020000,0x8020008,0x20208,0x8000208,0x20200,0x20000,0x8000208,0x8,0x8020208,0x200,0x8000000,0x8020200,0x8000000,0x20008,0x208,0x20000,0x8020200,0x8000200,0,0x200,0x20008,0x8020208,0x8000200,0x8000008,0x200,0,0x8020008,0x8000208,0x20000,0x8000000,0x8020208,0x8,0x20208,0x20200,0x8000008,0x8020000,0x8000208,0x208,0x8020000,0x20208,0x8,0x8020008,0x20200);
             var spfunction4=new Array(0x802001,0x2081,0x2081,0x80,0x802080,0x800081,0x800001,0x2001,0,0x802000,0x802000,0x802081,0x81,0,0x800080,0x800001,0x1,0x2000,0x800000,0x802001,0x80,0x800000,0x2001,0x2080,0x800081,0x1,0x2080,0x800080,0x2000,0x802080,0x802081,0x81,0x800080,0x800001,0x802000,0x802081,0x81,0,0,0x802000,0x2080,0x800080,0x800081,0x1,0x802001,0x2081,0x2081,0x80,0x802081,0x81,0x1,0x2000,0x800001,0x2001,0x802080,0x800081,0x2001,0x2080,0x800000,0x802001,0x80,0x800000,0x2000,0x802080);
             var spfunction5=new Array(0x100,0x2080100,0x2080000,0x42000100,0x80000,0x100,0x40000000,0x2080000,0x40080100,0x80000,0x2000100,0x40080100,0x42000100,0x42080000,0x80100,0x40000000,0x2000000,0x40080000,0x40080000,0,0x40000100,0x42080100,0x42080100,0x2000100,0x42080000,0x40000100,0,0x42000000,0x2080100,0x2000000,0x42000000,0x80100,0x80000,0x42000100,0x100,0x2000000,0x40000000,0x2080000,0x42000100,0x40080100,0x2000100,0x40000000,0x42080000,0x2080100,0x40080100,0x100,0x2000000,0x42080000,0x42080100,0x80100,0x42000000,0x42080100,0x2080000,0,0x40080000,0x42000000,0x80100,0x2000100,0x40000100,0x80000,0,0x40080000,0x2080100,0x40000100);
             var spfunction6=new Array(0x20000010,0x20400000,0x4000,0x20404010,0x20400000,0x10,0x20404010,0x400000,0x20004000,0x404010,0x400000,0x20000010,0x400010,0x20004000,0x20000000,0x4010,0,0x400010,0x20004010,0x4000,0x404000,0x20004010,0x10,0x20400010,0x20400010,0,0x404010,0x20404000,0x4010,0x404000,0x20404000,0x20000000,0x20004000,0x10,0x20400010,0x404000,0x20404010,0x400000,0x4010,0x20000010,0x400000,0x20004000,0x20000000,0x4010,0x20000010,0x20404010,0x404000,0x20400000,0x404010,0x20404000,0,0x20400010,0x10,0x4000,0x20400000,0x404010,0x4000,0x400010,0x20004010,0,0x20404000,0x20000000,0x400010,0x20004010);
             var spfunction7=new Array(0x200000,0x4200002,0x4000802,0,0x800,0x4000802,0x200802,0x4200800,0x4200802,0x200000,0,0x4000002,0x2,0x4000000,0x4200002,0x802,0x4000800,0x200802,0x200002,0x4000800,0x4000002,0x4200000,0x4200800,0x200002,0x4200000,0x800,0x802,0x4200802,0x200800,0x2,0x4000000,0x200800,0x4000000,0x200800,0x200000,0x4000802,0x4000802,0x4200002,0x4200002,0x2,0x200002,0x4000000,0x4000800,0x200000,0x4200800,0x802,0x200802,0x4200800,0x802,0x4000002,0x4200802,0x4200000,0x200800,0,0x2,0x4200802,0,0x200802,0x4200000,0x800,0x4000002,0x4000800,0x800,0x200002);
             var spfunction8=new Array(0x10001040,0x1000,0x40000,0x10041040,0x10000000,0x10001040,0x40,0x10000000,0x40040,0x10040000,0x10041040,0x41000,0x10041000,0x41040,0x1000,0x40,0x10040000,0x10000040,0x10001000,0x1040,0x41000,0x40040,0x10040040,0x10041000,0x1040,0,0,0x10040040,0x10000040,0x10001000,0x41040,0x40000,0x41040,0x40000,0x10041000,0x1000,0x40,0x10040040,0x1000,0x41040,0x10001000,0x40,0x10000040,0x10040000,0x10040040,0x10000000,0x40000,0x10001040,0,0x10041040,0x40040,0x10000040,0x10040000,0x10001000,0x10001040,0,0x10041040,0x41000,0x41000,0x1040,0x1040,0x40040,0x10000000,0x10041000);
            
             //create the 16 or 48 subkeys we will need
             var keys=this.des_createKeys(key);
             var m=0,i,j,temp,temp2,right1,right2,left,right,looping;
             var cbcleft,cbcleft2,cbcright,cbcright2
             var endloop,loopinc;
             var len=message.length;
             var chunk=0;
             //set up the loops for single and triple des
             var iterations=keys.length==32?3 :9;//single or triple des
             if(iterations==3){looping=encrypt?new Array(0,32,2):new Array(30,-2,-2);}
             else{looping=encrypt?new Array(0,32,2,62,30,-2,64,96,2):new Array(94,62,-2,32,64,2,30,-2,-2);}
            
             message+="\0\0\0\0\0\0\0\0";//pad the message out with null bytes
             //store the result here
             result="";
             tempresult="";
            
             if(mode==1){//CBC mode
             cbcleft=(iv.charCodeAt(m++)<<24)|(iv.charCodeAt(m++)<<16)|(iv.charCodeAt(m++)<<8)|iv.charCodeAt(m++);
             cbcright=(iv.charCodeAt(m++)<<24)|(iv.charCodeAt(m++)<<16)|(iv.charCodeAt(m++)<<8)|iv.charCodeAt(m++);
             m=0;
             }
            
             //loop through each 64 bit chunk of the message
             while(m<len){
             if(encrypt){/*加密时按双字节操作*/
             left=(message.charCodeAt(m++)<<16)|message.charCodeAt(m++);
             right=(message.charCodeAt(m++)<<16)|message.charCodeAt(m++);
             }else{
             left=(message.charCodeAt(m++)<<24)|(message.charCodeAt(m++)<<16)|(message.charCodeAt(m++)<<8)|message.charCodeAt(m++);
             right=(message.charCodeAt(m++)<<24)|(message.charCodeAt(m++)<<16)|(message.charCodeAt(m++)<<8)|message.charCodeAt(m++);
             }
             //for Cipher Block Chaining mode,xor the message with the previous result
             if(mode==1){if(encrypt){left^=cbcleft;right^=cbcright;}else{cbcleft2=cbcleft;cbcright2=cbcright;cbcleft=left;cbcright=right;}}
            
             //first each 64 but chunk of the message must be permuted according to IP
             temp=((left>>>4)^right)&0x0f0f0f0f;right^=temp;left^=(temp<<4);
             temp=((left>>>16)^right)&0x0000ffff;right^=temp;left^=(temp<<16);
             temp=((right>>>2)^left)&0x33333333;left^=temp;right^=(temp<<2);
             temp=((right>>>8)^left)&0x00ff00ff;left^=temp;right^=(temp<<8);
             temp=((left>>>1)^right)&0x55555555;right^=temp;left^=(temp<<1);
            
             left=((left<<1)|(left>>>31));
             right=((right<<1)|(right>>>31));
            
             //do this either 1 or 3 times for each chunk of the message
             for(j=0;j<iterations;j+=3){
             endloop=looping[j+1];
             loopinc=looping[j+2];
             //now go through and perform the encryption or decryption
             for(i=looping[j];i!=endloop;i+=loopinc){//for efficiency
             right1=right^keys[i];
             right2=((right>>>4)|(right<<28))^keys[i+1];
             //the result is attained by passing these bytes through the S selection functions
             temp=left;
             left=right;
             right=temp^(spfunction2[(right1>>>24)&0x3f]|spfunction4[(right1>>>16)&0x3f]|spfunction6[(right1>>>8)&0x3f]|spfunction8[right1&0x3f]|spfunction1[(right2>>>24)&0x3f]|spfunction3[(right2>>>16)&0x3f]|spfunction5[(right2>>>8)&0x3f]|spfunction7[right2&0x3f]);
             }
             temp=left;left=right;right=temp;//unreverse left and right
             }//for either 1 or 3 iterations
            
             //move then each one bit to the right
             left=((left>>>1)|(left<<31));
             right=((right>>>1)|(right<<31));
            
             //now perform IP-1,which is IP in the opposite direction
             temp=((left>>>1)^right)&0x55555555;right^=temp;left^=(temp<<1);
             temp=((right>>>8)^left)&0x00ff00ff;left^=temp;right^=(temp<<8);
             temp=((right>>>2)^left)&0x33333333;left^=temp;right^=(temp<<2);
             temp=((left>>>16)^right)&0x0000ffff;right^=temp;left^=(temp<<16);
             temp=((left>>>4)^right)&0x0f0f0f0f;right^=temp;left^=(temp<<4);
            
             //for Cipher Block Chaining mode,xor the message with the previous result
             if(mode==1){if(encrypt){cbcleft=left;cbcright=right;}else{left^=cbcleft2;right^=cbcright2;}}
             if(encrypt){tempresult+=String.fromCharCode((left>>>24),((left>>>16)&0xff),((left>>>8)&0xff),(left&0xff),(right>>>24),((right>>>16)&0xff),((right>>>8)&0xff),(right&0xff));}
             else{tempresult+=String.fromCharCode(((left>>>16)&0xffff),(left&0xffff), ((right>>>16)&0xffff),(right&0xffff));}/*解密时输出双字节*/
             encrypt?chunk+=16:chunk+=8;
             if(chunk==512){result+=tempresult;tempresult="";chunk=0;}
             }//for every 8 characters,or 64 bits in the message
            
             //return the result as an array
             return result+tempresult;
            }//end of des
			,des_createKeys:function (key){
			//des_createKeys
            //this takes as input a 64 bit key(even though only 56 bits are used)
            //as an array of 2 integers,and returns 16 48 bit keys
             //declaring this locally speeds things up a bit
             pc2bytes0=new Array(0,0x4,0x20000000,0x20000004,0x10000,0x10004,0x20010000,0x20010004,0x200,0x204,0x20000200,0x20000204,0x10200,0x10204,0x20010200,0x20010204);
             pc2bytes1=new Array(0,0x1,0x100000,0x100001,0x4000000,0x4000001,0x4100000,0x4100001,0x100,0x101,0x100100,0x100101,0x4000100,0x4000101,0x4100100,0x4100101);
             pc2bytes2=new Array(0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808,0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808);
             pc2bytes3=new Array(0,0x200000,0x8000000,0x8200000,0x2000,0x202000,0x8002000,0x8202000,0x20000,0x220000,0x8020000,0x8220000,0x22000,0x222000,0x8022000,0x8222000);
             pc2bytes4=new Array(0,0x40000,0x10,0x40010,0,0x40000,0x10,0x40010,0x1000,0x41000,0x1010,0x41010,0x1000,0x41000,0x1010,0x41010);
             pc2bytes5=new Array(0,0x400,0x20,0x420,0,0x400,0x20,0x420,0x2000000,0x2000400,0x2000020,0x2000420,0x2000000,0x2000400,0x2000020,0x2000420);
             pc2bytes6=new Array(0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002,0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002);
             pc2bytes7=new Array(0,0x10000,0x800,0x10800,0x20000000,0x20010000,0x20000800,0x20010800,0x20000,0x30000,0x20800,0x30800,0x20020000,0x20030000,0x20020800,0x20030800);
             pc2bytes8=new Array(0,0x40000,0,0x40000,0x2,0x40002,0x2,0x40002,0x2000000,0x2040000,0x2000000,0x2040000,0x2000002,0x2040002,0x2000002,0x2040002);
             pc2bytes9=new Array(0,0x10000000,0x8,0x10000008,0,0x10000000,0x8,0x10000008,0x400,0x10000400,0x408,0x10000408,0x400,0x10000400,0x408,0x10000408);
             pc2bytes10=new Array(0,0x20,0,0x20,0x100000,0x100020,0x100000,0x100020,0x2000,0x2020,0x2000,0x2020,0x102000,0x102020,0x102000,0x102020);
             pc2bytes11=new Array(0,0x1000000,0x200,0x1000200,0x200000,0x1200000,0x200200,0x1200200,0x4000000,0x5000000,0x4000200,0x5000200,0x4200000,0x5200000,0x4200200,0x5200200);
             pc2bytes12=new Array(0,0x1000,0x8000000,0x8001000,0x80000,0x81000,0x8080000,0x8081000,0x10,0x1010,0x8000010,0x8001010,0x80010,0x81010,0x8080010,0x8081010);
             pc2bytes13=new Array(0,0x4,0x100,0x104,0,0x4,0x100,0x104,0x1,0x5,0x101,0x105,0x1,0x5,0x101,0x105);
            
             //how many iterations(1 for des,3 for triple des)
             var iterations=key.length>=24?3 :1;
             //stores the return keys
             var keys=new Array(32 * iterations);
             //now define the left shifts which need to be done
             var shifts=new Array(0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0);
             //other variables
             var lefttemp,righttemp,m=0,n=0,temp;
            
             for(var j=0;j<iterations;j++){//either 1 or 3 iterations
             left=(key.charCodeAt(m++)<<24)|(key.charCodeAt(m++)<<16)|(key.charCodeAt(m++)<<8)|key.charCodeAt(m++);
             right=(key.charCodeAt(m++)<<24)|(key.charCodeAt(m++)<<16)|(key.charCodeAt(m++)<<8)|key.charCodeAt(m++);
            
             temp=((left>>>4)^right)&0x0f0f0f0f;right^=temp;left^=(temp<<4);
             temp=((right>>>-16)^left)&0x0000ffff;left^=temp;right^=(temp<<-16);
             temp=((left>>>2)^right)&0x33333333;right^=temp;left^=(temp<<2);
             temp=((right>>>-16)^left)&0x0000ffff;left^=temp;right^=(temp<<-16);
             temp=((left>>>1)^right)&0x55555555;right^=temp;left^=(temp<<1);
             temp=((right>>>8)^left)&0x00ff00ff;left^=temp;right^=(temp<<8);
             temp=((left>>>1)^right)&0x55555555;right^=temp;left^=(temp<<1);
            
             //the right side needs to be shifted and to get the last four bits of the left side
             temp=(left<<8)|((right>>>20)&0x000000f0);
             //left needs to be put upside down
             left=(right<<24)|((right<<8)&0xff0000)|((right>>>8)&0xff00)|((right>>>24)&0xf0);
             right=temp;
            
             //now go through and perform these shifts on the left and right keys
             for(i=0;i<shifts.length;i++){
             //shift the keys either one or two bits to the left
             if(shifts[i]){left=(left<<2)|(left>>>26);right=(right<<2)|(right>>>26);}
             else{left=(left<<1)|(left>>>27);right=(right<<1)|(right>>>27);}
             left&=-0xf;right&=-0xf;
            
             //now apply PC-2,in such a way that E is easier when encrypting or decrypting
             //this conversion will look like PC-2 except only the last 6 bits of each byte are used
             //rather than 48 consecutive bits and the order of lines will be according to
             //how the S selection functions will be applied:S2,S4,S6,S8,S1,S3,S5,S7
             lefttemp=pc2bytes0[left>>>28]|pc2bytes1[(left>>>24)&0xf]
            |pc2bytes2[(left>>>20)&0xf]|pc2bytes3[(left>>>16)&0xf]
            |pc2bytes4[(left>>>12)&0xf]|pc2bytes5[(left>>>8)&0xf]
            |pc2bytes6[(left>>>4)&0xf];
             righttemp=pc2bytes7[right>>>28]|pc2bytes8[(right>>>24)&0xf]
            |pc2bytes9[(right>>>20)&0xf]|pc2bytes10[(right>>>16)&0xf]
            |pc2bytes11[(right>>>12)&0xf]|pc2bytes12[(right>>>8)&0xf]
            |pc2bytes13[(right>>>4)&0xf];
             temp=((righttemp>>>16)^lefttemp)&0x0000ffff;
             keys[n++]=lefttemp^temp;keys[n++]=righttemp^(temp<<16);
             }
             }//for each iterations
             //return the keys we"ve created
             return keys;
            }//end of des_createKeys
			,stringToHex:function (s){
             var r="";
             var hexes=new Array("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f");
             for(var i=0;i<(s.length);i++){r+=hexes[s.charCodeAt(i)>>4]+hexes[s.charCodeAt(i)&0xf];}
             return r;
            },
            HexTostring:function (s){
             var r="";
             for(var i=0;i<s.length;i+=2){
             var sxx=parseInt(s.substring(i,i+2),16);
             r+=String.fromCharCode(sxx);}
             return r;
            },enDES:function(value,k){
				return this.stringToHex(this.des((k?k:this.$key),value,1,0));
			},deDES:function(value,k){
				return this.des((k?k:this.$key),this.HexTostring(value),0,0);
			},enURL:function (Str){
		  if(Str==null||Str=="")
		    return "";
		  var newStr="";
		  function toCase(sStr){
		    return sStr.toString(16).toUpperCase();
		    }
		  for(var i=0,icode,len=Str.length;i<len;i++){
		    icode=Str.charCodeAt(i);
		    if( icode<0x10)
		      newStr+="%0"+icode.toString(16).toUpperCase();
		    else if(icode<0x80){
		      if(icode==0x20)
		        newStr+="+";
		      else if((icode>=0x30&&icode<=0x39)||(icode>=0x41&&icode<=0x5A)||(icode>=0x61&&icode<=0x7A))
		        newStr+=Str.charAt(i);
		      else
		        newStr+="%"+toCase(icode);
		      }
		    else if(icode<0x800){
		      newStr+="%"+toCase(0xC0+(icode>>6));
		      newStr+="%"+toCase(0x80+icode%0x40);
		      }
		    else{
		      newStr+="%"+toCase(0xE0+(icode>>12));
		      newStr+="%"+toCase(0x80+(icode>>6)%0x40);
		      newStr+="%"+toCase(0x80+icode%0x40);
		      }
		    }
		  return newStr;
  		}
		,base64EncodeChars:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
		,base64DecodeChars: new Array( 
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 
    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, 
    -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 
    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, 
    -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 
    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1)
	,base64encode:function (str) { 
    var out, i, len; 
    var c1, c2, c3; 

    len = str.length; 
    i = 0; 
    out = ""; 
    while(i < len) { 
    c1 = str.charCodeAt(i++) & 0xff; 
    if(i == len) 
    { 
        out += this.base64EncodeChars.charAt(c1 >> 2); 
        out += this.base64EncodeChars.charAt((c1 & 0x3) << 4); 
        out += "=="; 
        break; 
    } 
    c2 = str.charCodeAt(i++); 
    if(i == len) 
    { 
        out += this.base64EncodeChars.charAt(c1 >> 2); 
        out += this.base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)); 
        out += this.base64EncodeChars.charAt((c2 & 0xF) << 2); 
        out += "="; 
        break; 
    } 
    c3 = str.charCodeAt(i++); 
    out += this.base64EncodeChars.charAt(c1 >> 2); 
    out += this.base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)); 
    out += this.base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)); 
    out += this.base64EncodeChars.charAt(c3 & 0x3F); 
    } 
    return out; 
},
base64decode:function (str) { 
    var c1, c2, c3, c4; 
    var i, len, out; 

    len = str.length; 
    i = 0; 
    out = ""; 
    while(i < len) { 
    /* c1 */ 
    do { 
        c1 = this.base64DecodeChars[str.charCodeAt(i++) & 0xff]; 
    } while(i < len && c1 == -1); 
    if(c1 == -1) 
        break; 

    /* c2 */ 
    do { 
        c2 = this.base64DecodeChars[str.charCodeAt(i++) & 0xff]; 
    } while(i < len && c2 == -1); 
    if(c2 == -1) 
        break; 

    out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4)); 

    /* c3 */ 
    do { 
        c3 = str.charCodeAt(i++) & 0xff; 
        if(c3 == 61) 
        return out; 
        c3 = this.base64DecodeChars[c3]; 
    } while(i < len && c3 == -1); 
    if(c3 == -1) 
        break; 

    out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2)); 

    /* c4 */ 
    do { 
        c4 = str.charCodeAt(i++) & 0xff; 
        if(c4 == 61) 
        return out; 
        c4 = this.base64DecodeChars[c4]; 
    } while(i < len && c4 == -1); 
    if(c4 == -1) 
        break; 
    out += String.fromCharCode(((c3 & 0x03) << 6) | c4); 
    } 
    return out; 
},
utf16to8:function (str) { 
    var out, i, len, c; 

    out = ""; 
    len = str.length; 
    for(i = 0; i < len; i++) { 
    c = str.charCodeAt(i); 
    if ((c >= 0x0001) && (c <= 0x007F)) { 
        out += str.charAt(i); 
    } else if (c > 0x07FF) { 
        out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F)); 
        out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F)); 
        out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)); 
    } else { 
        out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F)); 
        out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)); 
    } 
    } 
    return out; 
},
utf8to16:function (str) { 
    var out, i, len, c; 
    var char2, char3; 
    out = ""; 
    len = str.length; 
    i = 0; 
    while(i < len) { 
    c = str.charCodeAt(i++); 
    switch(c >> 4) 
    { 
      case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: 
        // 0xxxxxxx 
        out += str.charAt(i-1); 
        break; 
      case 12: case 13: 
        // 110x xxxx 10xx xxxx 
        char2 = str.charCodeAt(i++); 
        out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F)); 
        break; 
      case 14: 
        // 1110 xxxx 10xx xxxx 10xx xxxx 
        char2 = str.charCodeAt(i++); 
        char3 = str.charCodeAt(i++); 
        out += String.fromCharCode(((c & 0x0F) << 12) | 
                       ((char2 & 0x3F) << 6) | 
                       ((char3 & 0x3F) << 0)); 
        break; 
    } 
    } 

    return out; 
}

}

            
