// Utility object:  Encode/Decode octet arrays to/from Base64 strings
Base64 = new function ()
{
	// Sextet to symbol
	this._symbols = new String("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=").split('');

	// Symbol to sextet
	this._symbolsInv = {};
	for (var i = 0; i < this._symbols.length; i++)
	{
		this._symbolsInv[this._symbols[i]] = i;
	}


	// Encoder
	this.Encode = function (a)
	{
		var rv = [];
		var lut = this._symbols;
		function EncodePhrase(c0, c1, c2)
		{
			var e0 = (c0 >> 2) & 0x3f;
			var e1 = ((c0 & 0x3) << 4) | ((c1 >> 4) & 0xf);
			var e2 = ((c1 & 0xf) << 2) | ((c2 >> 6) & 0x3);
			var e3 = c2 & 0x3f;

			rv.push(lut[e0]);
			rv.push(lut[e1]);
			rv.push(lut[e2]);
			rv.push(lut[e3]);
		}

		for (var i = 0; i < a.length-2; i += 3)
		{
			EncodePhrase(a[i], a[i+1], a[i+2]);
		}
		switch(a.length % 3)
		{
			case 1:
				EncodePhrase(a[a.length-1], 0, 0);
				rv[rv.length-2] = '=';
				rv[rv.length-1] = '=';
				break;
			case 2:
				EncodePhrase(a[a.length-2], a[a.length-1], 0);
				rv[rv.length-1] = '=';
				break;
		}
		return rv.join('');
	};

	// Decoder
	this.Decode = function (s)
	{
		s = s.replace(/[^A-Za-z0-9\+\/\=]/g, '').split('');

		var rv = new Array(3*(s.length/4));
		var pt = 0;

		var lut = this._symbolsInv;
		var e0, e1, e2, e3;

		for (var i = 0; i < s.length-3; i += 4)
		{
			e0 = lut[s[i]];
			e1 = lut[s[i+1]];
			e2 = lut[s[i+2]];
			e3 = lut[s[i+3]];

			rv[pt++] = ((e0 & 0x3f) << 2) | ((e1 >> 4) & 0x3);
			rv[pt++] = ((e1 & 0x0f) << 4) | ((e2 >> 2) & 0xf);
			rv[pt++] = ((e2 & 0x03) << 6) | (e3 & 0x3f);
		}
		if (s.length >= 2)
		{
			if (s[s.length-1] == '=')
			{
				rv.pop();
				if (s[s.length-2] == '=')
				{
					rv.pop();
				}
			}
		}
		return rv;
	};
}();