text: var b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var b64padchar="=";
  
  function hex2b64(h) {
    var i;
    var c;
    var ret = "";
    for(i = 0; i+3 <= h.length; i+=3) {
      c = parseInt(h.substring(i,i+3),16);
      ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
    }
    if(i+1 == h.length) {
      c = parseInt(h.substring(i,i+1),16);
      ret += b64map.charAt(c << 2);
    }
    else if(i+2 == h.length) {
      c = parseInt(h.substring(i,i+2),16);
      ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
    }
    while((ret.length & 3) > 0) ret += b64padchar;
    return ret;
  }
  
  // convert a base64 string to hex
  function b64tohex(s) {
    var ret = "";
    var i;
    var k = 0; // b64 state, 0-3
    var slop;
    var v;
    for(i = 0; i < s.length; ++i) {
      if(s.charAt(i) == b64padchar) break;
      v = b64map.indexOf(s.charAt(i));
      if(v < 0) continue;
      if(k == 0) {
        ret += BigInteger.utils.int2char(v >> 2);
        slop = v & 3;
        k = 1;
      }
      else if(k == 1) {
        ret += BigInteger.utils.int2char((slop << 2) | (v >> 4));
        slop = v & 0xf;
        k = 2;
      }
      else if(k == 2) {
        ret += BigInteger.utils.int2char(slop);
        ret += BigInteger.utils.int2char(v >> 2);
        slop = v & 3;
        k = 3;
      }
      else {
        ret += BigInteger.utils.int2char((slop << 2) | (v >> 4));
        ret += BigInteger.utils.int2char(v & 0xf);
        k = 0;
      }
    }
    if(k == 1)
      ret += BigInteger.utils.int2char(slop << 2);
    return ret;
  }
  
  // convert a base64 string to a byte/number array
  function b64toBA(s) {
    //piggyback on b64tohex for now, optimize later
    var h = b64tohex(s);
    var i;
    var a = new Array();
    for(i = 0; 2*i < h.length; ++i) {
      a[i] = parseInt(h.substring(2*i,2*i+2),16);
    }
    return a;
  }
  