// used as a starting point (and then heavily modified)...
// http://www.answers.com/topic/base64?cat=technology

function myBase64Encode( stringToConvert )
{
  var b64table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-/';
  var workingArea = 0;
  var bitShiftArea = 0;
  var sixBits = 0;
  var base64 = '';

  if ( !stringToConvert )
    stringToConvert = '';

  var strLength = stringToConvert.length;
  var padding = 0;

  // what to do with zero length strings?
  if ( strLength == 0 )
  {
    return '====';
  }

  // figure out how much padding is required
  var m = strLength;
  while( (m%3) != 0 )
  {
    padding++;
    m++;
  }

  // copy the bytes into a padded array for final working
  //... in javascript, is this necessary???

  for( i = 0; i < strLength; i+=3 )
  {
    var char1 = stringToConvert.charCodeAt(i);
    var char2 = stringToConvert.charCodeAt(i+1);
    var char3 = stringToConvert.charCodeAt(i+2);

    var index1 = (char1 & 0xfc) >> 2;
    var index2 = ((char1 & 0x03) << 4) | ((char2 & 0xf0) >> 4);
    var index3 = ((char2 & 0x0f) << 2) | ((char3 & 0xc0) >> 6);
    var index4 = (char3 & 0x3f);

    base64 += b64table.charAt( index1 ) +
              b64table.charAt( index2 ) +
              b64table.charAt( index3 ) +
              b64table.charAt( index4 );
  }

  for( i = 0; i < padding; i++ )
  {
    base64 += '=';
  }

  return base64;
}

/*
function len( str )
{
  var l = 0;
  while ( str.charAt(0) != '' )
  {
    str = str.substr(1);
    l++;
  }
  return l;
}
*/

function len( str )
{
  for( var i = 0; i < 100000; i+=100 )
  {
    if ( str.charAt(i) == '' )
    {
      i -= 100;
      for( ; i < 100000; i++)
      {
        if ( str.charAt(i) == '' )
          return i;
      }
    }
  }

  return 0;
}

/*
UHJvZ3JhbXMgSG9tZSBQYWdlCgpUaGlzIGlzIHRoZSBwcm9ncmFtcyBhcmVhLgoKV2hhdCBjaGFu
Z2VzIGFyZSBtYWRlPwoKVGhpcyBjaGFuZ2UhCgpUaGlzIHdhcyBjaGFuZ2VkIHRocm91Z2ggYW4g
WE1MIHN1Ym1pc3Npb24u
 */
/*
function myBase64Decode_x( base64string )
{
  var base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

  // replace any incoming padding with a zero pad (the 'A' character is zero)
  var strlen = len(base64string);
  var padCount = strlen - base64string.indexOf("=");

  base64string = base64string.substr(0, base64string.indexOf("="));
  for( var i = 0; i < padCount; i++)
  {
    base64string += "A";
  }
  // remove/ignore any characters not in the base64 characters list -- particularly newlines
  base64string = base64string.replace(new RegExp('[^'+base64chars+']', 'g'), "");

  var resultString = "";

  // increment over the length of this encrypted string, four characters at a time
  for (var c = 0; c < strlen; c += 4) 
  {
    var index1 = base64chars.indexOf(base64string.charAt(c));
    var index2 = base64chars.indexOf(base64string.charAt(c+1));
    var index3 = base64chars.indexOf(base64string.charAt(c+2));
    var index4 = base64chars.indexOf(base64string.charAt(c+3));

    var char1 = String.fromCharCode( index1 << 2 | (index2 & 30) >> 4 );
    var char2 = String.fromCharCode( (index2 & 0x0f) << 4 | (index3 & 0x0f) );

    var char1 = stringToConvert.charCodeAt(i);
    var char2 = stringToConvert.charCodeAt(i+1);
    var char3 = stringToConvert.charCodeAt(i+2);

    var index1 = (char1 & 0xfc) >> 2;
    var index2 = ((char1 & 0x03) << 4) | ((char2 & 0xf0) >> 4);
    var index3 = ((char2 & 0x0f) << 2) | ((char3 & 0xc0) >> 6);
    var index4 = (char3 & 0x3f);

    base64 += b64table.charAt( index1 ) +
              b64table.charAt( index2 ) +
              b64table.charAt( index3 ) +
              b64table.charAt( index4 );
  }
  // remove any zero pad that was added to make this a multiple of 24 bits
  while ( resultString.charAt( len( resultString )-1 ) == "\0" )
  {
    resultString = resultString.substr( 0, len( resultString )-1 );
  }
  //resultString = resultString.replace(new RegExp('[\0]', 'g'), "");

  return resultString;
}
*/
function myBase64Decode (base64string)
{
  var base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-/';

  base64string = base64string.trim();

  // replace any incoming padding with a zero pad (the 'A' character is zero)
  var strlen = len(base64string);
  var padPosition = base64string.indexOf("=");

  if ( padPosition > -1 )
  {
    var padCount = strlen - padPosition;
    base64string = base64string.substr(0, padPosition);
    for( var i = 0; i < padCount; i++)
    {
      base64string += "A";
    }
  }
  // remove/ignore any characters not in the base64 characters list -- particularly newlines
  //base64string = base64string.replace(new RegExp('[^'+base64chars+']', 'g'), "");

  var resultString = "";

  // increment over the length of this encrypted string, four characters at a time
  for (var c = 0; c < strlen; c += 4) {

    // each of these four characters represents a 6-bit index in the base64 characters list
    //  which, when concatenated, will give the 24-bit number for the original 3 characters
    var n = (base64chars.indexOf(base64string.charAt(c)) << 18) | 
            (base64chars.indexOf(base64string.charAt(c+1)) << 12) | 
            (base64chars.indexOf(base64string.charAt(c+2)) << 6) |
             base64chars.indexOf(base64string.charAt(c+3));

    // split the 24-bit number into the original three 8-bit (ASCII) characters
    resultString += String.fromCharCode((n >>> 16) & 255, (n >>> 8) & 255, n & 255);

  } 
  // remove any zero pad that was added to make this a multiple of 24 bits
  while ( resultString.charAt( len( resultString )-1 ) == "\0" )
  {
    resultString = resultString.substr( 0, len( resultString )-1 );
  }
  //resultString = resultString.replace(new RegExp('[\0]', 'g'), "");

  return resultString;
}

/*
 * base64.js - Base64 encoding and decoding functions
 *
 * See: http://developer.mozilla.org/en/docs/DOM:window.btoa
 *      http://developer.mozilla.org/en/docs/DOM:window.atob
 *
 * Copyright (c) 2007, David Lindquist <david.lindquist@gmail.com>
 * Released under the MIT license
 */

/*
if (typeof btoa == 'undefined') {
    function btoa(str) {
        var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
        var encoded = [];
        var c = 0;
        while (c < str.length) {
            var b0 = str.charCodeAt(c++);
            var b1 = str.charCodeAt(c++);
            var b2 = str.charCodeAt(c++);
            var buf = (b0 << 16) + ((b1 || 0) << 8) + (b2 || 0);
            var i0 = (buf & (63 << 18)) >> 18;
            var i1 = (buf & (63 << 12)) >> 12;
            var i2 = isNaN(b1) ? 64 : (buf & (63 << 6)) >> 6;
            var i3 = isNaN(b2) ? 64 : (buf & 63);
            encoded[encoded.length] = chars.charAt(i0);
            encoded[encoded.length] = chars.charAt(i1);
            encoded[encoded.length] = chars.charAt(i2);
            encoded[encoded.length] = chars.charAt(i3);
        }
        return encoded.join('');
    }
}

function Base64Encode_a (stringToConvert)
{
  var b64table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
  var workingArea = 0;
  var bitShiftArea = 0;
  var sixBits = 0;
  var base64 = '';

  var strLength = stringToConvert.length;
  var padding = 0;

  // what to do with zero length strings?
  if ( strLength == 0 )
  {
    return '====';
  }

  // figure out how much padding is required
  var m = strLength;
  while( (m%3) != 0 )
  {
    padding++;
    m++;
  }

  // copy the bytes into a padded array for final working
  //... in javascript, is this necessary???

  for( i = 0; i < strLength; i+=3 )
  {
    workingArea = 0;
    for( j = 0; j < 3 && i+j < strLength; j++ )
    {
      bitShiftArea = stringToConvert.charCodeAt(i+j);
      bitShiftArea = bitShiftArea << (8 * (2-j));
      workingArea += bitShiftArea;
    }
    for( k = 0; k < 4 && (i+k*6/8) < strLength; k++ )
    {
      bitShiftArea = (0x3f << (6 * (3-k)));
      sixBits = ((workingArea & bitShiftArea) >> (6 * (3-k)));
      base64 += b64table.charAt(sixBits);
    }

  }

  for( i = 0; i < padding; i++ )
  {
    base64 += '=';
  }

  return base64;
}

if (typeof atob == 'undefined') {
    function atob(str) {
        var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
        var invalid = {
            strlen: (str.length % 4 != 0),
            chars:  new RegExp('[^' + chars + ']').test(str),
            equals: (/=/.test(str) && (/=[^=]/.test(str) || /={3}/.test(str)))
        };
        if (invalid.strlen || invalid.chars || invalid.equals)
            throw new Error('Invalid base64 data');
        var decoded = [];
        var c = 0;
        while (c < str.length) {
            var i0 = chars.indexOf(str.charAt(c++));
            var i1 = chars.indexOf(str.charAt(c++));
            var i2 = chars.indexOf(str.charAt(c++));
            var i3 = chars.indexOf(str.charAt(c++));
            var buf = (i0 << 18) + (i1 << 12) + ((i2 & 63) << 6) + (i3 & 63);
            var b0 = (buf & (255 << 16)) >> 16;
            var b1 = (i2 == 64) ? -1 : (buf & (255 << 8)) >> 8;
            var b2 = (i3 == 64) ? -1 : (buf & 255);
            decoded[decoded.length] = String.fromCharCode(b0);
            if (b1 >= 0) decoded[decoded.length] = String.fromCharCode(b1);
            if (b2 >= 0) decoded[decoded.length] = String.fromCharCode(b2);
        }
        return decoded.join('');
    }
}

// http://www.answers.com/topic/base64?cat=technology
function base64_encode (s)
{
  var base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

  // the result/encrypted string, the padding string, and the pad count
  var r = ""; var p = ""; var c = s.length % 3;

  // add a right zero pad to make this string a multiple of 3 characters
  if (c > 0) { for (; c < 3; c++) { p += '='; s += "\0"; } }

  // increment over the length of the string, three characters at a time
  for (c = 0; c < s.length; c += 3) {

    // we add newlines after every 76 output characters, according to the MIME specs
    if (c > 0 && (c / 3 * 4) % 76 == 0) { r += "\r\n"; }

    // these three 8-bit (ASCII) characters become one 24-bit number
    var n = (s.charCodeAt(c) << 16) + (s.charCodeAt(c+1) << 8) + s.charCodeAt(c+2);

    // this 24-bit number gets separated into four 6-bit numbers
    n = [(n >>> 18) & 63, (n >>> 12) & 63, (n >>> 6) & 63, n & 63];

    // those four 6-bit numbers are used as indices into the base64 character list
    r += base64chars[n[0]] + base64chars[n[1]] + base64chars[n[2]] + base64chars[n[3]];

    // add the actual padding string, after removing the zero pad
  } return r.substring(0, r.length - p.length) + p;
}

function base64_decode (s)
{
  var base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  var base64inv = {}; for (var i = 0; i < base64chars.length; i++) { base64inv[base64chars[i]] = i; };

  // replace any incoming padding with a zero pad (the 'A' character is zero)
  var p = (s.charAt(s.length-1) == '=' ? (s.charAt(s.length-2) == '='
   ? 'AA' : 'A') : ""); var r = ""; s = s.substr(0, s.length - p.length) + p;

  // remove/ignore any characters not in the base64 characters list -- particularly newlines
  s = s.replace(new RegExp('[^'+base64chars+']', 'g'), "");

  // increment over the length of this encrypted string, four characters at a time
  for (var c = 0; c < s.length; c += 4) {

    // each of these four characters represents a 6-bit index in the base64 characters list
    //  which, when concatenated, will give the 24-bit number for the original 3 characters
    var n = (base64inv[s.charAt(c)] << 18) + base64inv[s.charAt(c+3)] +
     (base64inv[s.charAt(c+1)] << 12) + (base64inv[s.charAt(c+2)] << 6);

    // split the 24-bit number into the original three 8-bit (ASCII) characters
    r += String.fromCharCode((n >>> 16) & 255, (n >>> 8) & 255, n & 255);

    // remove any zero pad that was added to make this a multiple of 24 bits
  } return r.substring(0, r.length - p.length);
}
*/
// this works every time?

///////////////////////////////////////////////////
//   Utility Scripts
///////////////////////////////////////////////////

// enhance the String object with trim capability
String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g,"");
}
String.prototype.ltrim = function() {
	return this.replace(/^\s+/,"");
}
String.prototype.rtrim = function() {
	return this.replace(/\s+$/,"");
}


