// JavaScript Base64 functions
// Anthony J. Mills, April 2004
// These functions may be freely used as long as credit is given.

function Base64Encode(s) {
  if (s.length < 1) return "";

  var aChars =
    [ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,  // 'A'..'P'
      81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99,100,101,102,  // 'Q'..'Z', 'a'..'f'
     103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,  // 'g'..'v'
     119,120,121,122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47]; // 'w'..'z', '0'..'9', '+', '/'
  var aResult = [];
  var iCharsLeft = s.length % 3;
  var n, i, iTriples;

  for (iTriples = Math.floor(s.length / 3), i = 0; iTriples; iTriples--, i += 3) {
    n = s.charCodeAt(i) << 16 | s.charCodeAt(i+1) << 8 | s.charCodeAt(i+2);
    aResult.push(String.fromCharCode(aChars[(n >> 18) & 63], aChars[(n >> 12) & 63], aChars[(n >> 6) & 63], aChars[n & 63]));
  }
  
  if (iCharsLeft == 1) {
    n = s.charCodeAt(i) << 4;
    aResult.push(String.fromCharCode(aChars[(n >> 6) & 63], aChars[n & 63], 61, 61));  // chr(61) == "="
  } else if (iCharsLeft == 2) {
    n = s.charCodeAt(i) << 10 | s.charCodeAt(i+1) << 2;
    aResult.push(String.fromCharCode(aChars[(n >> 12) & 63], aChars[(n >> 6) & 63], aChars[n & 63], 61));  // chr(61) == "="
  }

  return aResult.join("");
}

function Base64Decode(s) {
  if (s.length < 1) return "";

  var sChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var aResult = [];
  var iLength = s.length;
  if (s.substr(iLength-1, 1) == "=") iLength--;
  if (s.substr(iLength-1, 1) == "=") iLength--;
  var iCharsLeft = iLength % 4;
  var n, i, iQuads;

  for (iQuads = iLength >> 2, i = 0; iQuads; iQuads--, i += 4) {
    n = sChars.indexOf(s.substr(i, 1)) << 18 | sChars.indexOf(s.substr(i+1, 1)) << 12 |
        sChars.indexOf(s.substr(i+2, 1)) << 6 | sChars.indexOf(s.substr(i+3, 1));
    aResult.push(String.fromCharCode((n >> 16) & 255, (n >> 8) & 255, n & 255));
  }
  
  if (iCharsLeft == 2) {
    n = sChars.indexOf(s.substr(i, 1)) << 6 | sChars.indexOf(s.substr(i+1, 1));
    aResult.push(String.fromCharCode((n >> 4) & 255));
  } else if (iCharsLeft == 3) {
    n = sChars.indexOf(s.substr(i, 1)) << 12 | sChars.indexOf(s.substr(i+1, 1)) << 6 | sChars.indexOf(s.substr(i+2, 1));
    aResult.push(String.fromCharCode((n >> 10) & 255, (n >> 2) & 255));
  }
  
  return aResult.join("");
}
