b64 decode

JavaScript performance comparison

Revision 3 of this test case created

Info

Benchmark the performance of various Base64-decoding functions.

Preparation code

<script type="text/javascript">

/*
CryptoJS v3.1.2
code.google.com/p/crypto-js
(c) 2009-2013 by Jeff Mott. All rights reserved.
code.google.com/p/crypto-js/wiki/License
*/

var CryptoJS=CryptoJS||function(u,p){var d={},l=d.lib={},s=function(){},t=l.Base={extend:function(a){s.prototype=this;var c=new s;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},
r=l.WordArray=t.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=p?c:4*a.length},toString:function(a){return(a||v).stringify(this)},concat:function(a){var c=this.words,e=a.words,j=this.sigBytes;a=a.sigBytes;this.clamp();if(j%4)for(var k=0;k<a;k++)c[j+k>>>2]|=(e[k>>>2]>>>24-8*(k%4)&255)<<24-8*((j+k)%4);else if(65535<e.length)for(k=0;k<a;k+=4)c[j+k>>>2]=e[k>>>2];else c.push.apply(c,e);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<
32-8*(c%4);a.length=u.ceil(c/4)},clone:function(){var a=t.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],e=0;e<a;e+=4)c.push(4294967296*u.random()|0);return new r.init(c,a)}}),w=d.enc={},v=w.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++){var k=c[j>>>2]>>>24-8*(j%4)&255;e.push((k>>>4).toString(16));e.push((k&15).toString(16))}return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j+=2)e[j>>>3]|=parseInt(a.substr(j,
2),16)<<24-4*(j%8);return new r.init(e,c/2)}},b=w.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++)e.push(String.fromCharCode(c[j>>>2]>>>24-8*(j%4)&255));return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j++)e[j>>>2]|=(a.charCodeAt(j)&255)<<24-8*(j%4);return new r.init(e,c)}},x=w.Utf8={stringify:function(a){try{return decodeURIComponent(escape(b.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return b.parse(unescape(encodeURIComponent(a)))}},
q=l.BufferedBlockAlgorithm=t.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=x.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,e=c.words,j=c.sigBytes,k=this.blockSize,b=j/(4*k),b=a?u.ceil(b):u.max((b|0)-this._minBufferSize,0);a=b*k;j=u.min(4*a,j);if(a){for(var q=0;q<a;q+=k)this._doProcessBlock(e,q);q=e.splice(0,a);c.sigBytes-=j}return new r.init(q,j)},clone:function(){var a=t.clone.call(this);
a._data=this._data.clone();return a},_minBufferSize:0});l.Hasher=q.extend({cfg:t.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){q.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(b,e){return(new a.init(e)).finalize(b)}},_createHmacHelper:function(a){return function(b,e){return(new n.HMAC.init(a,
e)).finalize(b)}}});var n=d.algo={};return d}(Math);
(function(){var u=CryptoJS,p=u.lib.WordArray;u.enc.Base64={stringify:function(d){var l=d.words,p=d.sigBytes,t=this._map;d.clamp();d=[];for(var r=0;r<p;r+=3)for(var w=(l[r>>>2]>>>24-8*(r%4)&255)<<16|(l[r+1>>>2]>>>24-8*((r+1)%4)&255)<<8|l[r+2>>>2]>>>24-8*((r+2)%4)&255,v=0;4>v&&r+0.75*v<p;v++)d.push(t.charAt(w>>>6*(3-v)&63));if(l=t.charAt(64))for(;d.length%4;)d.push(l);return d.join("")},parse:function(d){var l=d.length,s=this._map,t=s.charAt(64);t&&(t=d.indexOf(t),-1!=t&&(l=t));for(var t=[],r=0,w=0;w<
l;w++)if(w%4){var v=s.indexOf(d.charAt(w-1))<<2*(w%4),b=s.indexOf(d.charAt(w))>>>6-2*(w%4);t[r>>>2]|=(v|b)<<24-8*(r%4);r++}return p.create(t,r)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})();
(function(u){function p(b,n,a,c,e,j,k){b=b+(n&a|~n&c)+e+k;return(b<<j|b>>>32-j)+n}function d(b,n,a,c,e,j,k){b=b+(n&c|a&~c)+e+k;return(b<<j|b>>>32-j)+n}function l(b,n,a,c,e,j,k){b=b+(n^a^c)+e+k;return(b<<j|b>>>32-j)+n}function s(b,n,a,c,e,j,k){b=b+(a^(n|~c))+e+k;return(b<<j|b>>>32-j)+n}for(var t=CryptoJS,r=t.lib,w=r.WordArray,v=r.Hasher,r=t.algo,b=[],x=0;64>x;x++)b[x]=4294967296*u.abs(u.sin(x+1))|0;r=r.MD5=v.extend({_doReset:function(){this._hash=new w.init([1732584193,4023233417,2562383102,271733878])},
_doProcessBlock:function(q,n){for(var a=0;16>a;a++){var c=n+a,e=q[c];q[c]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360}var a=this._hash.words,c=q[n+0],e=q[n+1],j=q[n+2],k=q[n+3],z=q[n+4],r=q[n+5],t=q[n+6],w=q[n+7],v=q[n+8],A=q[n+9],B=q[n+10],C=q[n+11],u=q[n+12],D=q[n+13],E=q[n+14],x=q[n+15],f=a[0],m=a[1],g=a[2],h=a[3],f=p(f,m,g,h,c,7,b[0]),h=p(h,f,m,g,e,12,b[1]),g=p(g,h,f,m,j,17,b[2]),m=p(m,g,h,f,k,22,b[3]),f=p(f,m,g,h,z,7,b[4]),h=p(h,f,m,g,r,12,b[5]),g=p(g,h,f,m,t,17,b[6]),m=p(m,g,h,f,w,22,b[7]),
f=p(f,m,g,h,v,7,b[8]),h=p(h,f,m,g,A,12,b[9]),g=p(g,h,f,m,B,17,b[10]),m=p(m,g,h,f,C,22,b[11]),f=p(f,m,g,h,u,7,b[12]),h=p(h,f,m,g,D,12,b[13]),g=p(g,h,f,m,E,17,b[14]),m=p(m,g,h,f,x,22,b[15]),f=d(f,m,g,h,e,5,b[16]),h=d(h,f,m,g,t,9,b[17]),g=d(g,h,f,m,C,14,b[18]),m=d(m,g,h,f,c,20,b[19]),f=d(f,m,g,h,r,5,b[20]),h=d(h,f,m,g,B,9,b[21]),g=d(g,h,f,m,x,14,b[22]),m=d(m,g,h,f,z,20,b[23]),f=d(f,m,g,h,A,5,b[24]),h=d(h,f,m,g,E,9,b[25]),g=d(g,h,f,m,k,14,b[26]),m=d(m,g,h,f,v,20,b[27]),f=d(f,m,g,h,D,5,b[28]),h=d(h,f,
m,g,j,9,b[29]),g=d(g,h,f,m,w,14,b[30]),m=d(m,g,h,f,u,20,b[31]),f=l(f,m,g,h,r,4,b[32]),h=l(h,f,m,g,v,11,b[33]),g=l(g,h,f,m,C,16,b[34]),m=l(m,g,h,f,E,23,b[35]),f=l(f,m,g,h,e,4,b[36]),h=l(h,f,m,g,z,11,b[37]),g=l(g,h,f,m,w,16,b[38]),m=l(m,g,h,f,B,23,b[39]),f=l(f,m,g,h,D,4,b[40]),h=l(h,f,m,g,c,11,b[41]),g=l(g,h,f,m,k,16,b[42]),m=l(m,g,h,f,t,23,b[43]),f=l(f,m,g,h,A,4,b[44]),h=l(h,f,m,g,u,11,b[45]),g=l(g,h,f,m,x,16,b[46]),m=l(m,g,h,f,j,23,b[47]),f=s(f,m,g,h,c,6,b[48]),h=s(h,f,m,g,w,10,b[49]),g=s(g,h,f,m,
E,15,b[50]),m=s(m,g,h,f,r,21,b[51]),f=s(f,m,g,h,u,6,b[52]),h=s(h,f,m,g,k,10,b[53]),g=s(g,h,f,m,B,15,b[54]),m=s(m,g,h,f,e,21,b[55]),f=s(f,m,g,h,v,6,b[56]),h=s(h,f,m,g,x,10,b[57]),g=s(g,h,f,m,t,15,b[58]),m=s(m,g,h,f,D,21,b[59]),f=s(f,m,g,h,z,6,b[60]),h=s(h,f,m,g,C,10,b[61]),g=s(g,h,f,m,j,15,b[62]),m=s(m,g,h,f,A,21,b[63]);a[0]=a[0]+f|0;a[1]=a[1]+m|0;a[2]=a[2]+g|0;a[3]=a[3]+h|0},_doFinalize:function(){var b=this._data,n=b.words,a=8*this._nDataBytes,c=8*b.sigBytes;n[c>>>5]|=128<<24-c%32;var e=u.floor(a/
4294967296);n[(c+64>>>9<<4)+15]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360;n[(c+64>>>9<<4)+14]=(a<<8|a>>>24)&16711935|(a<<24|a>>>8)&4278255360;b.sigBytes=4*(n.length+1);this._process();b=this._hash;n=b.words;for(a=0;4>a;a++)c=n[a],n[a]=(c<<8|c>>>24)&16711935|(c<<24|c>>>8)&4278255360;return b},clone:function(){var b=v.clone.call(this);b._hash=this._hash.clone();return b}});t.MD5=v._createHelper(r);t.HmacMD5=v._createHmacHelper(r)})(Math);
(function(){var u=CryptoJS,p=u.lib,d=p.Base,l=p.WordArray,p=u.algo,s=p.EvpKDF=d.extend({cfg:d.extend({keySize:4,hasher:p.MD5,iterations:1}),init:function(d){this.cfg=this.cfg.extend(d)},compute:function(d,r){for(var p=this.cfg,s=p.hasher.create(),b=l.create(),u=b.words,q=p.keySize,p=p.iterations;u.length<q;){n&&s.update(n);var n=s.update(d).finalize(r);s.reset();for(var a=1;a<p;a++)n=s.finalize(n),s.reset();b.concat(n)}b.sigBytes=4*q;return b}});u.EvpKDF=function(d,l,p){return s.create(p).compute(d,
l)}})();
CryptoJS.lib.Cipher||function(u){var p=CryptoJS,d=p.lib,l=d.Base,s=d.WordArray,t=d.BufferedBlockAlgorithm,r=p.enc.Base64,w=p.algo.EvpKDF,v=d.Cipher=t.extend({cfg:l.extend(),createEncryptor:function(e,a){return this.create(this._ENC_XFORM_MODE,e,a)},createDecryptor:function(e,a){return this.create(this._DEC_XFORM_MODE,e,a)},init:function(e,a,b){this.cfg=this.cfg.extend(b);this._xformMode=e;this._key=a;this.reset()},reset:function(){t.reset.call(this);this._doReset()},process:function(e){this._append(e);return this._process()},
finalize:function(e){e&&this._append(e);return this._doFinalize()},keySize:4,ivSize:4,_ENC_XFORM_MODE:1,_DEC_XFORM_MODE:2,_createHelper:function(e){return{encrypt:function(b,k,d){return("string"==typeof k?c:a).encrypt(e,b,k,d)},decrypt:function(b,k,d){return("string"==typeof k?c:a).decrypt(e,b,k,d)}}}});d.StreamCipher=v.extend({_doFinalize:function(){return this._process(!0)},blockSize:1});var b=p.mode={},x=function(e,a,b){var c=this._iv;c?this._iv=u:c=this._prevBlock;for(var d=0;d<b;d++)e[a+d]^=
c[d]},q=(d.BlockCipherMode=l.extend({createEncryptor:function(e,a){return this.Encryptor.create(e,a)},createDecryptor:function(e,a){return this.Decryptor.create(e,a)},init:function(e,a){this._cipher=e;this._iv=a}})).extend();q.Encryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize;x.call(this,e,a,c);b.encryptBlock(e,a);this._prevBlock=e.slice(a,a+c)}});q.Decryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize,d=e.slice(a,a+c);b.decryptBlock(e,a);x.call(this,
e,a,c);this._prevBlock=d}});b=b.CBC=q;q=(p.pad={}).Pkcs7={pad:function(a,b){for(var c=4*b,c=c-a.sigBytes%c,d=c<<24|c<<16|c<<8|c,l=[],n=0;n<c;n+=4)l.push(d);c=s.create(l,c);a.concat(c)},unpad:function(a){a.sigBytes-=a.words[a.sigBytes-1>>>2]&255}};d.BlockCipher=v.extend({cfg:v.cfg.extend({mode:b,padding:q}),reset:function(){v.reset.call(this);var a=this.cfg,b=a.iv,a=a.mode;if(this._xformMode==this._ENC_XFORM_MODE)var c=a.createEncryptor;else c=a.createDecryptor,this._minBufferSize=1;this._mode=c.call(a,
this,b&&b.words)},_doProcessBlock:function(a,b){this._mode.processBlock(a,b)},_doFinalize:function(){var a=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){a.pad(this._data,this.blockSize);var b=this._process(!0)}else b=this._process(!0),a.unpad(b);return b},blockSize:4});var n=d.CipherParams=l.extend({init:function(a){this.mixIn(a)},toString:function(a){return(a||this.formatter).stringify(this)}}),b=(p.format={}).OpenSSL={stringify:function(a){var b=a.ciphertext;a=a.salt;return(a?s.create([1398893684,
1701076831]).concat(a).concat(b):b).toString(r)},parse:function(a){a=r.parse(a);var b=a.words;if(1398893684==b[0]&&1701076831==b[1]){var c=s.create(b.slice(2,4));b.splice(0,4);a.sigBytes-=16}return n.create({ciphertext:a,salt:c})}},a=d.SerializableCipher=l.extend({cfg:l.extend({format:b}),encrypt:function(a,b,c,d){d=this.cfg.extend(d);var l=a.createEncryptor(c,d);b=l.finalize(b);l=l.cfg;return n.create({ciphertext:b,key:c,iv:l.iv,algorithm:a,mode:l.mode,padding:l.padding,blockSize:a.blockSize,formatter:d.format})},
decrypt:function(a,b,c,d){d=this.cfg.extend(d);b=this._parse(b,d.format);return a.createDecryptor(c,d).finalize(b.ciphertext)},_parse:function(a,b){return"string"==typeof a?b.parse(a,this):a}}),p=(p.kdf={}).OpenSSL={execute:function(a,b,c,d){d||(d=s.random(8));a=w.create({keySize:b+c}).compute(a,d);c=s.create(a.words.slice(b),4*c);a.sigBytes=4*b;return n.create({key:a,iv:c,salt:d})}},c=d.PasswordBasedCipher=a.extend({cfg:a.cfg.extend({kdf:p}),encrypt:function(b,c,d,l){l=this.cfg.extend(l);d=l.kdf.execute(d,
b.keySize,b.ivSize);l.iv=d.iv;b=a.encrypt.call(this,b,c,d.key,l);b.mixIn(d);return b},decrypt:function(b,c,d,l){l=this.cfg.extend(l);c=this._parse(c,l.format);d=l.kdf.execute(d,b.keySize,b.ivSize,c.salt);l.iv=d.iv;return a.decrypt.call(this,b,c,d.key,l)}})}();
(function(){for(var u=CryptoJS,p=u.lib.BlockCipher,d=u.algo,l=[],s=[],t=[],r=[],w=[],v=[],b=[],x=[],q=[],n=[],a=[],c=0;256>c;c++)a[c]=128>c?c<<1:c<<1^283;for(var e=0,j=0,c=0;256>c;c++){var k=j^j<<1^j<<2^j<<3^j<<4,k=k>>>8^k&255^99;l[e]=k;s[k]=e;var z=a[e],F=a[z],G=a[F],y=257*a[k]^16843008*k;t[e]=y<<24|y>>>8;r[e]=y<<16|y>>>16;w[e]=y<<8|y>>>24;v[e]=y;y=16843009*G^65537*F^257*z^16843008*e;b[k]=y<<24|y>>>8;x[k]=y<<16|y>>>16;q[k]=y<<8|y>>>24;n[k]=y;e?(e=z^a[a[a[G^z]]],j^=a[a[j]]):e=j=1}var H=[0,1,2,4,8,
16,32,64,128,27,54],d=d.AES=p.extend({_doReset:function(){for(var a=this._key,c=a.words,d=a.sigBytes/4,a=4*((this._nRounds=d+6)+1),e=this._keySchedule=[],j=0;j<a;j++)if(j<d)e[j]=c[j];else{var k=e[j-1];j%d?6<d&&4==j%d&&(k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255]):(k=k<<8|k>>>24,k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255],k^=H[j/d|0]<<24);e[j]=e[j-d]^k}c=this._invKeySchedule=[];for(d=0;d<a;d++)j=a-d,k=d%4?e[j]:e[j-4],c[d]=4>d||4>=j?k:b[l[k>>>24]]^x[l[k>>>16&255]]^q[l[k>>>
8&255]]^n[l[k&255]]},encryptBlock:function(a,b){this._doCryptBlock(a,b,this._keySchedule,t,r,w,v,l)},decryptBlock:function(a,c){var d=a[c+1];a[c+1]=a[c+3];a[c+3]=d;this._doCryptBlock(a,c,this._invKeySchedule,b,x,q,n,s);d=a[c+1];a[c+1]=a[c+3];a[c+3]=d},_doCryptBlock:function(a,b,c,d,e,j,l,f){for(var m=this._nRounds,g=a[b]^c[0],h=a[b+1]^c[1],k=a[b+2]^c[2],n=a[b+3]^c[3],p=4,r=1;r<m;r++)var q=d[g>>>24]^e[h>>>16&255]^j[k>>>8&255]^l[n&255]^c[p++],s=d[h>>>24]^e[k>>>16&255]^j[n>>>8&255]^l[g&255]^c[p++],t=
d[k>>>24]^e[n>>>16&255]^j[g>>>8&255]^l[h&255]^c[p++],n=d[n>>>24]^e[g>>>16&255]^j[h>>>8&255]^l[k&255]^c[p++],g=q,h=s,k=t;q=(f[g>>>24]<<24|f[h>>>16&255]<<16|f[k>>>8&255]<<8|f[n&255])^c[p++];s=(f[h>>>24]<<24|f[k>>>16&255]<<16|f[n>>>8&255]<<8|f[g&255])^c[p++];t=(f[k>>>24]<<24|f[n>>>16&255]<<16|f[g>>>8&255]<<8|f[h&255])^c[p++];n=(f[n>>>24]<<24|f[g>>>16&255]<<16|f[h>>>8&255]<<8|f[k&255])^c[p++];a[b]=q;a[b+1]=s;a[b+2]=t;a[b+3]=n},keySize:8});u.AES=p._createHelper(d)})();


</script>




<!-- own code start -->





<script type="text/javascript">





function arrayIndexOf2(arr, searchElement, fromIndex) {
        if ( arr === undefined || arr === null ) {
                throw new TypeError( '"arr" is null or not defined' );
        }

        var length = arr.length >>> 0; // Hack to convert object.length to a UInt32

        fromIndex = +fromIndex || 0;

        if (Math.abs(fromIndex) === Infinity) {
                fromIndex = 0;
        }

        if (fromIndex < 0) {
                fromIndex += length;
                if (fromIndex < 0) {
                        fromIndex = 0;
                }
        }

        for (;fromIndex < length; fromIndex++) {
                if (arr[fromIndex] === searchElement) {
                        return fromIndex;
                }
        }

        return -1;
};

function arrayIndexOf(arr, a,b,c) {
        for (c = arr.length, b = (c + ~~b) % c; b < c && (!(b in arr) || arr[b] !== a); b++);
        return b ^ c ? b : -1;
}
 
 
 
var B64M1 = {
        // private property
        _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

        // public method for encoding
        encode: function (input) {
            var output = "";
            var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
            var i = 0;

            while (i < input.length) {

                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);

                enc1 = chr1 >> 2;
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                enc4 = chr3 & 63;

                if (isNaN(chr2)) {
                    enc3 = enc4 = 64;
                } else if (isNaN(chr3)) {
                    enc4 = 64;
                }

                output = output +
                B64M1._keyStr.charAt(enc1) + B64M1._keyStr.charAt(enc2) +
                B64M1._keyStr.charAt(enc3) + B64M1._keyStr.charAt(enc4);

            }

            return output;
        },
        encodeUTF8: function (input) {
            var output = "";
            var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
            var i = 0;

            input = B64M1._utf8_encode(input);

            while (i < input.length) {

                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);

                enc1 = chr1 >> 2;
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                enc4 = chr3 & 63;

                if (isNaN(chr2)) {
                    enc3 = enc4 = 64;
                } else if (isNaN(chr3)) {
                    enc4 = 64;
                }

                output = output +
                B64M1._keyStr.charAt(enc1) + B64M1._keyStr.charAt(enc2) +
                B64M1._keyStr.charAt(enc3) + B64M1._keyStr.charAt(enc4);

            }

            return output;
        },

        // public method for decoding
        decode: function (input) {
            var output = "";
            var chr1, chr2, chr3;
            var enc1, enc2, enc3, enc4;
            var i = 0;

            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

            while (i < input.length) {

                enc1 = B64M1._keyStr.indexOf(input.charAt(i++));
                enc2 = B64M1._keyStr.indexOf(input.charAt(i++));
                enc3 = B64M1._keyStr.indexOf(input.charAt(i++));
                enc4 = B64M1._keyStr.indexOf(input.charAt(i++));

                chr1 = (enc1 << 2) | (enc2 >> 4);
                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                chr3 = ((enc3 & 3) << 6) | enc4;

                output = output + String.fromCharCode(chr1);

                if (enc3 != 64) {
                    output = output + String.fromCharCode(chr2);
                }
                if (enc4 != 64) {
                    output = output + String.fromCharCode(chr3);
                }

            }

            return output;

        },
        decodeUTF8: function (input) {
            var output = "";
            var chr1, chr2, chr3;
            var enc1, enc2, enc3, enc4;
            var i = 0;

            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

            while (i < input.length) {

                enc1 = B64M1._keyStr.indexOf(input.charAt(i++));
                enc2 = B64M1._keyStr.indexOf(input.charAt(i++));
                enc3 = B64M1._keyStr.indexOf(input.charAt(i++));
                enc4 = B64M1._keyStr.indexOf(input.charAt(i++));

                chr1 = (enc1 << 2) | (enc2 >> 4);
                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                chr3 = ((enc3 & 3) << 6) | enc4;

                output = output + String.fromCharCode(chr1);

                if (enc3 != 64) {
                    output = output + String.fromCharCode(chr2);
                }
                if (enc4 != 64) {
                    output = output + String.fromCharCode(chr3);
                }

            }

            output = B64M1._utf8_decode(output);

            return output;

        },

        // private method for UTF-8 encoding
        _utf8_encode: function (string) {
            string = string.replace(/\r\n/g, "\n");
            var utftext = "";

            for (var n = 0; n < string.length; n++) {

                var c = string.charCodeAt(n);

                if (c < 128) {
                    utftext += String.fromCharCode(c);
                }
                else if ((c > 127) && (c < 2048)) {
                    utftext += String.fromCharCode((c >> 6) | 192);
                    utftext += String.fromCharCode((c & 63) | 128);
                }
                else {
                    utftext += String.fromCharCode((c >> 12) | 224);
                    utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                    utftext += String.fromCharCode((c & 63) | 128);
                }

            }

            return utftext;
        },

        // private method for UTF-8 decoding
        _utf8_decode: function (utftext) {
            var string = "";
            var i = 0;
            var c = 0, c1 = 0, c2 = 0;

            while (i < utftext.length) {

                c = utftext.charCodeAt(i);

                if (c < 128) {
                    string += String.fromCharCode(c);
                    i++;
                }
                else if ((c > 191) && (c < 224)) {
                    c1 = utftext.charCodeAt(i + 1);
                    string += String.fromCharCode(((c & 31) << 6) | (c1 & 63));
                    i += 2;
                }
                else {
                    c1 = utftext.charCodeAt(i + 1);
                    c2 = utftext.charCodeAt(i + 2);
                    string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63));
                    i += 3;
                }

            }
            return string;
        }
    };

       
var B64M2 = {
        encode : function(input) {
                return btoa(input);
        },
        decode : function(input) {
                return atob(input);
        }
};

var B64M3 = {
        encode : function(input) {
                var wordArray = CryptoJS.enc.Latin1.parse(input);
        return CryptoJS.enc.Base64.stringify(wordArray);
        },
        decode : function(input) {
                var wordArray = CryptoJS.enc.Base64.parse(input);
        return CryptoJS.enc.Latin1.stringify(wordArray);
        }
};

var B64M4 = {
        encode : function(data) {
  //  discuss at: http://phpjs.org/functions/base64_encode/
  // original by: Tyler Akins (http://rumkin.com)
  // improved by: Bayron Guevara
  // improved by: Thunder.m
  // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  // improved by: Rafał Kukawski (http://kukawski.pl)
  // bugfixed by: Pellentesque Malesuada
  //   example 1: base64_encode('Kevin van Zonneveld');
  //   returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='
  //   example 2: base64_encode('a');
  //   returns 2: 'YQ=='

  var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
  var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
    ac = 0,
    enc = '',
    tmp_arr = [];

  if (!data) {
    return data;
  }

  do { // pack three octets into four hexets
    o1 = data.charCodeAt(i++);
    o2 = data.charCodeAt(i++);
    o3 = data.charCodeAt(i++);

    bits = o1 << 16 | o2 << 8 | o3;

    h1 = bits >> 18 & 0x3f;
    h2 = bits >> 12 & 0x3f;
    h3 = bits >> 6 & 0x3f;
    h4 = bits & 0x3f;

    // use hexets to index into b64, and append result to encoded string
    tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
  } while (i < data.length);

  enc = tmp_arr.join('');

  var r = data.length % 3;

  return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
        },
        decode : function(data) {
          //  discuss at: http://phpjs.org/functions/base64_decode/
          // original by: Tyler Akins (http://rumkin.com)
          // improved by: Thunder.m
          // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
          // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
          //    input by: Aman Gupta
          //    input by: Brett Zamir (http://brett-zamir.me)
          // bugfixed by: Onno Marsman
          // bugfixed by: Pellentesque Malesuada
          // bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
          //   example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
          //   returns 1: 'Kevin van Zonneveld'
          //   example 2: base64_decode('YQ===');
          //   returns 2: 'a'
          //   example 3: base64_decode('4pyTIMOgIGxhIG1vZGU=');
          //   returns 3: '✓ à la mode'

          var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
          var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
                ac = 0,
                dec = '',
                tmp_arr = [];

          if (!data) {
                return data;
          }

          data += '';

          do {
                // unpack four hexets into three octets using index points in b64
                h1 = b64.indexOf(data.charAt(i++));
                h2 = b64.indexOf(data.charAt(i++));
                h3 = b64.indexOf(data.charAt(i++));
                h4 = b64.indexOf(data.charAt(i++));

                bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;

                o1 = bits >> 16 & 0xff;
                o2 = bits >> 8 & 0xff;
                o3 = bits & 0xff;

                if (h3 == 64) {
                  tmp_arr[ac++] = String.fromCharCode(o1);
                } else if (h4 == 64) {
                  tmp_arr[ac++] = String.fromCharCode(o1, o2);
                } else {
                  tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
                }
          } while (i < data.length);

          dec = tmp_arr.join('');

          return dec.replace(/\0+$/, '');

        }
};


var B64M5 = {};
B64M5.PADCHAR = '=';
B64M5.ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

B64M5.makeDOMException = function() {
    // sadly in FF,Safari,Chrome you can't make a DOMException
    var e, tmp;

    try {
        return new DOMException(DOMException.INVALID_CHARACTER_ERR);
    } catch (tmp) {
        // not available, just passback a duck-typed equiv
        // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Error
        // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Error/prototype
        var ex = new Error("DOM Exception 5");

        // ex.number and ex.description is IE-specific.
        ex.code = ex.number = 5;
        ex.name = ex.description = "INVALID_CHARACTER_ERR";

        // Safari/Chrome output format
        ex.toString = function() { return 'Error: ' + ex.name + ': ' + ex.message; };
        return ex;
    }
};

B64M5.getbyte64 = function(s,i) {
    // This is oddly fast, except on Chrome/V8.
    //  Minimal or no improvement in performance by using a
    //   object with properties mapping chars to value (eg. 'A': 0)
    var idx = B64M5.ALPHA.indexOf(s.charAt(i));
    if (idx === -1) {
        throw B64M5.makeDOMException();
    }
    return idx;
};

B64M5.decode = function(s) {
    // convert to string
    s = '' + s;
    var getbyte64 = B64M5.getbyte64;
    var pads, i, b10;
    var imax = s.length
    if (imax === 0) {
        return s;
    }

    if (imax % 4 !== 0) {
        throw B64M5.makeDOMException();
    }

    pads = 0
    if (s.charAt(imax - 1) === B64M5.PADCHAR) {
        pads = 1;
        if (s.charAt(imax - 2) === B64M5.PADCHAR) {
            pads = 2;
        }
        // either way, we want to ignore this last block
        imax -= 4;
    }

    var x = [];
    for (i = 0; i < imax; i += 4) {
        b10 = (getbyte64(s,i) << 18) | (getbyte64(s,i+1) << 12) |
            (getbyte64(s,i+2) << 6) | getbyte64(s,i+3);
        x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 0xff, b10 & 0xff));
    }

    switch (pads) {
    case 1:
        b10 = (getbyte64(s,i) << 18) | (getbyte64(s,i+1) << 12) | (getbyte64(s,i+2) << 6);
        x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 0xff));
        break;
    case 2:
        b10 = (getbyte64(s,i) << 18) | (getbyte64(s,i+1) << 12);
        x.push(String.fromCharCode(b10 >> 16));
        break;
    }
    return x.join('');
};

B64M5.getbyte = function(s,i) {
    var x = s.charCodeAt(i);
    if (x > 255) {
        throw B64M5.makeDOMException();
    }
    return x;
};

B64M5.encode = function(s) {
    if (arguments.length !== 1) {
        throw new SyntaxError("Not enough arguments");
    }
    var padchar = B64M5.PADCHAR;
    var alpha   = B64M5.ALPHA;
    var getbyte = B64M5.getbyte;

    var i, b10;
    var x = [];

    // convert to string
    s = '' + s;

    var imax = s.length - s.length % 3;

    if (s.length === 0) {
        return s;
    }
    for (i = 0; i < imax; i += 3) {
        b10 = (getbyte(s,i) << 16) | (getbyte(s,i+1) << 8) | getbyte(s,i+2);
        x.push(alpha.charAt(b10 >> 18));
        x.push(alpha.charAt((b10 >> 12) & 0x3F));
        x.push(alpha.charAt((b10 >> 6) & 0x3f));
        x.push(alpha.charAt(b10 & 0x3f));
    }
    switch (s.length - imax) {
    case 1:
        b10 = getbyte(s,i) << 16;
        x.push(alpha.charAt(b10 >> 18) + alpha.charAt((b10 >> 12) & 0x3F) +
               padchar + padchar);
        break;
    case 2:
        b10 = (getbyte(s,i) << 16) | (getbyte(s,i+1) << 8);
        x.push(alpha.charAt(b10 >> 18) + alpha.charAt((b10 >> 12) & 0x3F) +
               alpha.charAt((b10 >> 6) & 0x3f) + padchar);
        break;
    }
    return x.join('');
};


/*
Copyright Vassilis Petroulias [DRDigit]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

var B64M6 = {
    alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
    lookup: null,
    ie: /MSIE /.test(navigator.userAgent),
    ieo: /MSIE [67]/.test(navigator.userAgent),
    encode: function (s) {
        var buffer = B64M6.toUtf8(s),
            position = -1,
            len = buffer.length,
            nan0, nan1, nan2, enc = [, , , ];
        if (B64M6.ie) {
            var result = [];
            while (++position < len) {
                nan0 = buffer[position];
                nan1 = buffer[++position];
                enc[0] = nan0 >> 2;
                enc[1] = ((nan0 & 3) << 4) | (nan1 >> 4);
                if (isNaN(nan1))
                    enc[2] = enc[3] = 64;
                else {
                    nan2 = buffer[++position];
                    enc[2] = ((nan1 & 15) << 2) | (nan2 >> 6);
                    enc[3] = (isNaN(nan2)) ? 64 : nan2 & 63;
                }
                result.push(B64M6.alphabet.charAt(enc[0]), B64M6.alphabet.charAt(enc[1]), B64M6.alphabet.charAt(enc[2]), B64M6.alphabet.charAt(enc[3]));
            }
            return result.join('');
        } else {
            var result = '';
            while (++position < len) {
                nan0 = buffer[position];
                nan1 = buffer[++position];
                enc[0] = nan0 >> 2;
                enc[1] = ((nan0 & 3) << 4) | (nan1 >> 4);
                if (isNaN(nan1))
                    enc[2] = enc[3] = 64;
                else {
                    nan2 = buffer[++position];
                    enc[2] = ((nan1 & 15) << 2) | (nan2 >> 6);
                    enc[3] = (isNaN(nan2)) ? 64 : nan2 & 63;
                }
                result += B64M6.alphabet[enc[0]] + B64M6.alphabet[enc[1]] + B64M6.alphabet[enc[2]] + B64M6.alphabet[enc[3]];
            }
            return result;
        }
    },
    decode: function (s) {
        if (s.length % 4)
            throw new Error("InvalidCharacterError: 'B64M6.decode' failed: The string to be decoded is not correctly encoded.");
        var buffer = B64M6.fromUtf8(s),
            position = 0,
            len = buffer.length;
        if (B64M6.ieo && false) {
            var result = [];
            while (position < len) {
                        /*
                if (buffer[position] < 128)
                    result.push(String.fromCharCode(buffer[position++]));
                else if (buffer[position] > 191 && buffer[position] < 224)
                    result.push(String.fromCharCode(((buffer[position++] & 31) << 6) | (buffer[position++] & 63)));
                else
                    result.push(String.fromCharCode(((buffer[position++] & 15) << 12) | ((buffer[position++] & 63) << 6) | (buffer[position++] & 63)));
                                        */

                                        result.push(String.fromCharCode(buffer[position++]));
            }
            return result.join('');
        } else {
            var result = '';
            while (position < len) {
                        /*
                if (buffer[position] < 128)
                    result += String.fromCharCode(buffer[position++]);
                else if (buffer[position] > 191 && buffer[position] < 224)
                    result += String.fromCharCode(((buffer[position++] & 31) << 6) | (buffer[position++] & 63));
                else
                    result += String.fromCharCode(((buffer[position++] & 15) << 12) | ((buffer[position++] & 63) << 6) | (buffer[position++] & 63));
                                        */

                                result += String.fromCharCode(buffer[position++]);
            }
            return result;
        }
    },
    toUtf8: function (s) {
        var position = -1,
            len = s.length,
            chr, buffer = [];
        if (/^[\x00-\x7f]*$/.test(s)) while (++position < len)
            buffer.push(s.charCodeAt(position));
        else while (++position < len) {
            chr = s.charCodeAt(position);
                        buffer.push(chr);
                        /*
            if (chr < 128)
                buffer.push(chr);
            else if (chr < 2048)
                buffer.push((chr >> 6) | 192, (chr & 63) | 128);
            else
                buffer.push((chr >> 12) | 224, ((chr >> 6) & 63) | 128, (chr & 63) | 128);
                                */

        }
        return buffer;
    },
    fromUtf8: function (s) {
        var position = -1,
            len, buffer = [],
            enc = [, , , ];
        if (!B64M6.lookup) {
            len = B64M6.alphabet.length;
            B64M6.lookup = {};
            while (++position < len)
                B64M6.lookup[B64M6.alphabet.charAt(position)] = position;
            position = -1;
        }
        len = s.length;
        while (++position < len) {
            enc[0] = B64M6.lookup[s.charAt(position)];
            enc[1] = B64M6.lookup[s.charAt(++position)];
            buffer.push((enc[0] << 2) | (enc[1] >> 4));
            enc[2] = B64M6.lookup[s.charAt(++position)];
            if (enc[2] == 64)
                break;
            buffer.push(((enc[1] & 15) << 4) | (enc[2] >> 2));
            enc[3] = B64M6.lookup[s.charAt(++position)];
            if (enc[3] == 64)
                break;
            buffer.push(((enc[2] & 3) << 6) | enc[3]);
        }
        return buffer;
    }
};



B64M7 = {};
/**
 * @define {boolean}
 */

var B64M7_BTOA_STRICT = true;

/**
 * @const
 * @type {string}
 */

B64M7.Character =  'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

/**
 * @const
 * @type {string}
 */

B64M7.RangeError = "INVALID_CHARACTER_ERR";

/**
 * @param {string} str byte-string.
 * @return {string} base64 encoded string.
 */

B64M7.btoa = function(str) {
  /** @type {number} */
  var length = str.length;
  /** @type {number} */
  var outLength = (((length + 2) / 3) | 0) * 4;
  /** @type {string} */
  var out = '';
  /** @type {Array.<string>} */
  var table = B64M7.btoa.CharacterTable;
  /** @type {number} */
  var pos = 0;
  /** @type {number} */
  var v0;
  /** @type {number} */
  var v1;
  /** @type {number} */
  var v2;

  // main encode
  if (length > 1) {
    while (pos < length - 2) {
      // read 3 characters
      v0 = str.charCodeAt(pos);
      v1 = str.charCodeAt(pos + 1);
      v2 = str.charCodeAt(pos + 2);
      pos += 3;

      // check
      if (B64M7_BTOA_STRICT && (v0 > 0xff || v1 > 0xff || v2 > 0xff)) {
        throw new Error(B64M7.RangeError);
      }

      // output 4 character
      out +=
        table[ (v0 >> 2) & 0x3f] +
        table[((v1 >> 4) & 0x0f) | ((v0 << 4) & 0x3f)] +
        table[((v2 >> 6) & 0x03) | ((v1 << 2) & 0x3f)] +
        table[  v2       & 0x3f];
    }
  }

  // sub encode
  if (pos < length) {
    v0 = str.charCodeAt(pos++);
    if (B64M7_BTOA_STRICT && v0 > 0xff) {
      throw new Error(B64M7.RangeError);
    }
    out += table[(v0 >> 2) & 0x3f];
    if (pos < length) {
      v1 = str.charCodeAt(pos);
      if (B64M7_BTOA_STRICT && v1 > 0xff) {
        throw new Error(B64M7.RangeError);
      }
      out +=
        table[((v1 >> 4) & 0x0f) | ((v0 << 4) & 0x3f)] +
        table[ (v1 << 2) & 0x3f];
    } else {
      out += table[ (v0 << 4) & 0x3f];
    }
  }

  // Add padding
  v0 = outLength - out.length;
  if (v0 > 0) {
    out += v0 === 2 ? "==" : "=";
  }

  return out;
};

/**
 * @const
 * @type {Array.<string>}
 */

B64M7.btoa.CharacterTable = B64M7.Character.split('');

/**
 * @param {string} str base64 encoded string.
 * @return {string} decoded byte-string.
 */

B64M7.atob = function(str) {
  /** @type {number} */
  var buffer = 0;
  /** @type {number} */
  var pos = 0;
  /** @type {number} */
  var length = str.length;
  var out= '';
  /** @type {number} */
  var bitlen = 0;
  /** @type {Array.<string>} */
  var chars = B64M7.atob.StringFromCharCode;
  /** @type {Array.<number>|Int16Array} */
  var decode = B64M7.atob.DecodeTable;
  /** @type {number} */
  var decoded;
  /** @type {number} */
  var tmp;

  // remove padding
  while (str.charAt(length-1) === '=') {
    --length;
  }

  // check range
  if (length % 4 === 1 || (str.length > 0 && length === 0)) {
    throw new Error(B64M7.RangeError);
  }

  while (pos < length) {
    tmp = str.charCodeAt(pos++);
    decoded = tmp < 256 ? decode[tmp] : -1;

    // check character range
    if (decoded === -1) {
      throw new Error(B64M7.RangeError);
    }

    // add buffer (6bit)
    buffer = (buffer << 6) + decoded;
    bitlen += 6;

    // decode byte
    if (bitlen >= 8) {
      bitlen -= 8;

      // extract byte
      tmp = buffer >> bitlen;

      // decode character
      out += chars[tmp];

      // remove character bits
      buffer ^= tmp << bitlen;
    }
  }

  return out;
};

/**
 * @const
 * @type {Array.<string>}
 */

B64M7.atob.StringFromCharCode = (
/**
 * @return {Array.<string>}
 */

function() {
  /** @type {Array.<string>} */
  var table = new Array(256);
  /** @type {number} */
  var i;

  for (i = 0; i < 0xff; ++i) {
    table[i] = String.fromCharCode(i);
  }

  return table;
})();

/**
 * @const
 * @type {(Array.<number>|Int16Array)}
 */

B64M7.atob.DecodeTable = (
/**
 * @param {Array.<string>} chars character table.
 * @return {Int16Array|Array.<number>} decode table.
 */

function(chars) {
  /** @type {(Int16Array|Array.<number>)} */
  var table = new (typeof Int16Array !== 'undefined' ? Int16Array : Array)(256);
  /** @type {Array.<string>} */
  var stringFromCharCode = B64M7.atob.StringFromCharCode;
  /** @type {number} */
  var i;

  for (i = 0; i < 0xff; ++i) {
    table[i] = arrayIndexOf(chars,stringFromCharCode[i]);
  }

  return table;
})(B64M7.btoa.CharacterTable);

//-----------------------------------------------------------------------------

/**
 * @param {(Array.<number>|Uint8Array)} array byte-array.
 * @return {string} base64 encoded string.
 */

B64M7.btoaArray = function(array) {
  /** @type {number} */
  var length = array.length;
  /** @type {number} */
  var outLength = (((length + 2) / 3) | 0) * 4;
  /** @type {string} */
  var out = '';
  /** @type {(Uint8Array|Array.<number>)} */
  var table = B64M7.btoa.CharacterTable;
  /** @type {number} */
  var pos = 0;
  /** @type {number} */
  var v0;
  /** @type {number} */
  var v1;
  /** @type {number} */
  var v2;

  // main encode
  if (length > 1) {
    while (pos < length - 2) {
      // read 3 characters
      v0 = array[pos];
      v1 = array[pos + 1];
      v2 = array[pos + 2];
      pos += 3;

      // check
      if (B64M7_BTOA_STRICT && (v0 > 0xff || v1 > 0xff || v2 > 0xff)) {
        throw new Error(B64M7.RangeError);
      }

      // output 4 character
      out +=
        table[ (v0 >> 2) & 0x3f] +
        table[((v1 >> 4) & 0x0f) | ((v0 << 4) & 0x3f)] +
        table[((v2 >> 6) & 0x03) | ((v1 << 2) & 0x3f)] +
        table[  v2       & 0x3f];
    }
  }

  // sub encode
  if (pos < length) {
    v0 = array[pos++];
    if (B64M7_BTOA_STRICT && v0 > 0xff) {
      throw new Error(B64M7.RangeError);
    }
    out += table[(v0 >> 2) & 0x3f];
    if (pos < length) {
      v1 = array[pos];
      if (B64M7_BTOA_STRICT && v1 > 0xff) {
        throw new Error(B64M7.RangeError);
      }
      out +=
        table[((v1 >> 4) & 0x0f) | ((v0 << 4) & 0x3f)] +
        table[ (v1 << 2) & 0x3f];
    } else {
      out += table[ (v0 << 4) & 0x3f];
    }
  }

  // Add padding
  v0 = outLength - out.length;
  if (v0 > 0) {
    out += v0 === 2 ? "==" : "=";
  }

  return out;
};

/**
 * @const
 * @type {(Uint8Array|Array.<number>)}
 */

B64M7.btoaArray.CharacterTable = (
/**
 * @param {string} chars
 * @return {(Uint8Array|Array.<number>)}
 */

function(chars) {
  /** @type {(Uint8Array|Array.<number>)} */
  var array =
    new (typeof Uint8Array !== 'undefined' ? Uint8Array : Array)(chars.length);
  /** @type {number} */
  var i;
  /** @type {number} */
  var il;

  for (i = 0, il = array.length; i < il; ++i) {
    array[i] = chars.charCodeAt(i);
  }

  return array;
})(B64M7.Character);

/**
 * @param {string} str base64 encoded string.
 * @return {Array.<number>|Uint8Array} decoded byte-array.
 */

B64M7.atobArray = function(str) {
  /** @type {number} */
  var buffer = 0;
  /** @type {number} */
  var pos = 0;
  /** @type {number} */
  var length = str.length;
  /** @type {(Uint8Array|Array.<number>)} */
  var out;
  /** @type {number} */
  var outpos = 0;
  /** @type {number} */
  var bitlen = 0;
  /** @type {Array.<number>|Int16Array} */
  var decode = B64M7.atobArray.DecodeTable;
  /** @type {number} */
  var decoded;
  /** @type {number} */
  var tmp;
  /** @type {number} */
  var mod;

  // remove padding
  while (str.charAt(length-1) === '=') {
    --length;
  }
  mod = length % 4;

  // create output buffer
  out = new (typeof Uint8Array !== 'undefined' ? Uint8Array : Array)(
    ((length + 3) / 4 | 0) * 3 - [0, 0, 2, 1][mod]
  );

  // check range
  if (length % 4 === 1 || (str.length > 0 && length === 0)) {
    throw new Error(B64M7.RangeError);
  }

  while (pos < length) {
    tmp = str.charCodeAt(pos++);
    decoded = tmp < 256 ? decode[tmp] : -1;

    // check character range
    if (decoded === -1) {
      throw new Error(B64M7.RangeError);
    }

    // add buffer (6bit)
    buffer = (buffer << 6) + decoded;
    bitlen += 6;

    // decode byte
    if (bitlen >= 8) {
      bitlen -= 8;

      // extract byte
      tmp = buffer >> bitlen;

      // decode character
      out[outpos++] = tmp;

      // remove character bits
      buffer ^= tmp << bitlen;
    }
  }

  return out;
};

/**
 * @const
 * @type {(Array.<number>|Int16Array)}
 */

B64M7.atobArray.DecodeTable = (
/**
 * @param {Uint8Array|Array.<number>} encodeTable character table.
 * @return {Int16Array|Array.<number>} decode table.
 */

function(encodeTable) {
  /** @type {(Int16Array|Array.<number>)} */
  var table = new (typeof Int16Array !== 'undefined' ? Int16Array : Array)(256);
  /** @type {number} */
  var i;
  /** @type {Array.<number>} */
  var array = encodeTable instanceof Array ?
    encodeTable : Array.prototype.slice.call(encodeTable);

  for (i = 0; i < 0xff; ++i) {
    table[i] = arrayIndexOf(array,i);
  }

  return table;
})(B64M7.btoaArray.CharacterTable);

B64M7.encode = B64M7.btoa;
B64M7.decode = B64M7.atob;







</script>


<!-- test data -->


<script type="text/javascript">

var seed = 1;
function random() {
    var x = Math.sin(seed++) * 10000;
    return x - Math.floor(x);
}

var baseInput = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";


var input = "";
for (var i = 0; i < 30 * 1024; i++)
  input += baseInput[(baseInput.length * random())^0];

</script>

Preparation code output

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
Method 1
B64M1.decode(input);
pending…
Method 2
B64M2.decode(input);
pending…
Method 3
B64M3.decode(input);
pending…
Method 4
B64M4.decode(input);
pending…
Method 5
B64M5.decode(input);
pending…
Method 6
B64M6.decode(input);
pending…
Method 7
B64M7.decode(input);
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

0 comments

Add a comment