Skip to content

Instantly share code, notes, and snippets.

@alpicola
Created December 18, 2009 07:13
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alpicola/259339 to your computer and use it in GitHub Desktop.
Save alpicola/259339 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Atomos Entry Management
// @namespace http://5ivestar.org/
// @include http://localhost:9292/*
// @include http://localhost:9393/*
// ==/UserScript==
var username = 'admin';
var password = 'password';
var style = document.createElement('style');
style.type = 'text/css';
style.appendChild(document.createTextNode([
'#atomos-shader {',
'position: fixed;',
'top: 0;',
'left: 0;',
'width: 100%;',
'height: 100%;',
'background: #000;',
'opacity: 0.7;',
'z-index: 20;',
'}',
'#atomos-container {',
'position: fixed;',
'top: 10%;',
'left: 0;',
'width: 100%;',
'z-index: 30;',
'}',
'#atomos-container div {',
'margin: 0 auto;',
'padding: 1.5em;',
'width: 35em;',
'background-color: #fff;',
'-webkit-border-top-left-radius: 0.5em;',
'-webkit-border-top-right-radius: 0.5em;',
'-webkit-border-bottom-right-radius: 0.5em;',
'-webkit-border-bottom-left-radius: 0.5em;',
'-moz-border-radius-bottomleft: 0.5em;',
'-moz-border-radius-bottomright: 0.5em;',
'-moz-border-radius-topleft: 0.5em;',
'-moz-border-radius-topright: 0.5em;',
'}',
'#atomos-container h2 {',
'margin: 0 0 0.6em;',
'font-size: 180%;',
'}',
'#atomos-container h3 {',
'margin: 0.4em 0 0.1em;',
'font-size: 120%;',
'}',
'#atomos-container h3 .optional {',
'margin-left: 0.5em;',
'font-family: "Lucida Grande", sans-serif;',
'font-size: 60%;',
'color: #616263;',
'}',
'#atomos-container p {',
'margin: 0;',
'}',
'#atomos-container input, textarea {',
'padding: 0.2em;',
'font-family: "Lucida Grande", sans-serif;',
'font-size: 100%;',
'}',
'#atomos-container input[type="text"] {',
'border: 1px solid #d1d1d1;',
'width: 25em;',
'}',
'#atomos-container input[type="button"] {',
'border: 1px solid #d1d1d1;',
'-webkit-border-top-left-radius: 0.5em;',
'-webkit-border-top-right-radius: 0.5em;',
'-webkit-border-bottom-right-radius: 0.5em;',
'-webkit-border-bottom-left-radius: 0.5em;',
'-moz-border-radius-bottomleft: 0.5em;',
'-moz-border-radius-bottomright: 0.5em;',
'-moz-border-radius-topleft: 0.5em;',
'-moz-border-radius-topright: 0.5em;',
'margin-right: 0.8em;',
'padding: 0.6em 0.8em;',
'font-size: 80%;',
'background-color: #f4f5f5;',
'}',
'#atomos-container input[type="button"][value="Delete"] {',
'float: right;',
'margin-right: 0;',
'}',
'#atomos-container input[type="button"]:focus {',
'outline: none;',
'}',
'#atomos-container textarea {',
'width: 34.6em;',
'margin: 0 0 0.4em;',
'border: 1px solid #d1d1d1;',
'}',
'.action {',
'position: fixed;',
'top: 5px;',
'right: 15px;',
'color: #000;',
'font-size: 80%;',
'text-decoration: underline;',
'text-transform: uppercase;',
'letter-spacing: 0.1em;',
'cursor: pointer;',
'}',
'.action:hover {',
'color: #991100;',
'}'
].join('\n')));
var shader = document.createElement('div');
shader.id = 'atomos-shader';
shader.style.display = 'none'
var container = document.createElement('div');
container.id = 'atomos-container';
container.style.display = 'none'
document.getElementsByTagName('head')[0].appendChild(style);
document.body.appendChild(shader);
document.body.appendChild(container);
var span = document.createElement('span');
span.className = 'action';
if (document.body.id == 'home') {
span.appendChild(document.createTextNode('new'));
span.addEventListener('click', function(e) {
var draft = eval('('+getValue('draft')+')') || {};
container.innerHTML = [
'<div>',
'<h2>New Post</h2>',
'<h3>Slug<span class="optional">(optional)</span></h3>',
'<p><input type="text" value="' + (draft.slug || '') + '"/></p>',
'<h3>Tags<span class="optional">(optional)</span></h3>',
'<p><input type="text" value="' + (draft.tags || '') + '"/></p>',
'<h3>Title</h3>',
'<p><input type="text" value="' + escapeHTML(draft.title || '') + '"/></p>',
'<h3>Post</h3>',
'<textarea rows="12">' + escapeHTML(draft.content || '') + '</textarea>',
'<p><input type="button" value="Post"/><input type="button" value="Cancel"/></p>',
'</div>'
].join('');
shader.style.display = 'block';
container.style.display = 'block';
container.querySelector('input[type="button"][value="Post"]').addEventListener('click', function(e) {
draft.slug = container.querySelector('p:nth-child(3) input').value;
draft.tags = container.querySelector('p:nth-child(5) input').value;
draft.title = container.querySelector('p:nth-child(7) input').value;
draft.content = container.querySelector('textarea').value;
var req = new XMLHttpRequest();
req.open('POST', '/atom/', true);
if (draft.slug && draft.slug.length) req.setRequestHeader('Slug', draft.slug);
req.setRequestHeader('Content-Type', 'application/atom+xml;type=entry;charset="utf-8"');
req.setRequestHeader('X-WSSE', wsse(username, password));
req.onreadystatechange = function(e) {
if (req.readyState == 4) {
if (req.status == 201) {
deleteValue('draft');
location.href = req.getResponseHeader('Location');
} else {
var message = document.createElement('span');
message.className = 'message';
message.appendChild(document.createTextNode('error'));
container.querySelector('p:last-child').appendChild(message);
}
}
};
req.send([
'<entry xmlns="http://www.w3.org/2005/Atom">',
'<title>' + escapeHTML(draft.title) + '</title>',
'<content type="text/plain">' + escapeHTML(draft.content) + '</content>',
draft.tags.split(/\s+/).map(function(tag) {
return '<category term="' + escapeHTML(tag) + '"/>';
}),
'</entry>'
].join(''));
}, false);
container.querySelector('input[type="button"][value="Cancel"]').addEventListener('click', function(e) {
draft.slug = container.querySelector('p:nth-child(3) input').value;
draft.tags = container.querySelector('p:nth-child(5) input').value;
draft.title = container.querySelector('p:nth-child(7) input').value;
draft.content = container.querySelector('textarea').value;
setValue('draft', uneval(draft));
shader.style.display = 'none';
container.style.display = 'none';
}, false);
}, false);
document.body.appendChild(span);
} else if (document.body.id == "entry") {
var entry = document.querySelector('.entry');
var url = entry.querySelector('h2 a').href.replace(/^http:\/\/.+?\//, '/atom/');
span.appendChild(document.createTextNode('edit'));
span.addEventListener('click', function(e) {
var req = new XMLHttpRequest();
req.open('GET', url, false);
req.setRequestHeader('X-WSSE', wsse(username, password));
req.send(null);
if (!(req.status == 200)) return;
var title = req.responseXML.getElementsByTagName('title')[0].textContent;
var content = req.responseXML.getElementsByTagNameNS('http://daringfireball.net/projects/markdown/', 'markdown')[0].textContent;
var tags = Array.prototype.map.call(req.responseXML.getElementsByTagName('category'), function(tag) {
return tag.getAttribute('term');
}).join(' ');
container.innerHTML = [
'<div>',
'<h2>New Post</h2>',
'<h3>Tags<span class="optional">(optional)</span></h3>',
'<p><input type="text" value="' + escapeHTML(tags) + '"/></p>',
'<h3>Title</h3>',
'<p><input type="text" value="' + escapeHTML(title) + '"/></p>',
'<h3>Post</h3>',
'<textarea rows="12">' + escapeHTML(content) + '</textarea>',
'<p><input type="button" value="Post"/><input type="button" value="Cancel"/><input type="button" value="Delete"/></p>',
'</div>'
].join('');
shader.style.display = 'block';
container.style.display = 'block';
container.querySelector('input[type="button"][value="Post"]').addEventListener('click', function(e) {
tags = container.querySelector('p:nth-child(3) input').value.split(/\s+/);
title = container.querySelector('p:nth-child(5) input').value;
content = container.querySelector('textarea').value;
var req = new XMLHttpRequest();
req.open('PUT', url, true);
req.setRequestHeader('Content-Type', 'application/atom+xml;type=entry;charset="utf-8"');
req.setRequestHeader('X-WSSE', wsse(username, password));
req.onreadystatechange = function(e) {
if (req.readyState == 4) {
if (req.status == 200) {
content = req.responseXML.getElementsByTagName('content')[0].textContent;
entry.querySelector('h2').innerHTML = title;
entry.querySelector('div').innerHTML = content;
entry.querySelector('.meta').innerHTML = 'filed in ' + tags.map(function(tag) {
return '<a href="/tag/' + tag + '">' + tag + '</a>';
}).join(' ');
shader.style.display = 'none';
container.style.display = 'none';
} else {
var message = document.createElement('span');
message.className = 'message';
message.appendChild(document.createTextNode('error'));
container.querySelector('p:last-child').appendChild(message);
}
}
};
req.send([
'<entry xmlns="http://www.w3.org/2005/Atom">',
'<title>' + escapeHTML(title) + '</title>',
'<content type="text/plain">' + escapeHTML(content) + '</content>',
tags.map(function(tag) {
return '<category term="' + escapeHTML(tag) + '"/>';
}),
'</entry>'
].join(''));
}, false);
container.querySelector('input[type="button"][value="Cancel"]').addEventListener('click', function(e) {
shader.style.display = 'none';
container.style.display = 'none';
}, false);
container.querySelector('input[type="button"][value="Delete"]').addEventListener('click', function(e) {
var req = new XMLHttpRequest();
req.open('Delete', url, true);
req.setRequestHeader('X-WSSE', wsse(username, password));
req.onreadystatechange = function(e) {
if (req.readyState == 4) {
if (req.status == 200) {
location.href = document.querySelector('h1 a').href;
shader.style.display = 'none';
container.style.display = 'none';
} else {
var message = document.createElement('span');
message.className = 'message';
message.appendChild(document.createTextNode('error'));
container.querySelector('p:last-child').appendChild(message);
}
}
};
req.send(null);
}, false);
}, false);
document.body.appendChild(span);
}
function escapeHTML(s) {
return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}
function wsse(username, password) {
var nonce = Math.floor(Math.random() * 4026531840 + 268435456).toString(16);
var created = getW3CDate(new Date());
var digest = b64_sha1(nonce + created + password);
return [
'UsernameToken',
'Username="' + username + '"',
'PasswordDigest="' + digest + '"',
'Nonce="' + base64encode(nonce) + '"',
'Created="' + created + '"'
].join(' ');
}
function getW3CDate(date) {
var yyyy = date.getUTCFullYear();
var mm = date.getUTCMonth() + 1;
if (mm < 10) mm = '0' + mm;
var dd = date.getUTCDate();
if (dd < 10) dd = '0' + dd;
var hh = date.getUTCHours();
if (hh < 10) hh = '0' + hh;
var mn = date.getUTCMinutes();
if (mn < 10) mn = '0' + mn;
var ss = date.getUTCSeconds();
if (ss < 10) ss = '0' + ss;
return yyyy + '-' + mm + '-' + dd + 'T' + hh + ':' + mn + ':' + ss + 'Z';
}
function getValue(name) {
if (typeof GM_getValue === 'function' && !window.chrome) {
return GM_getValue(name);
} else {
return localStorage.getItem(name);
}
}
function setValue(name, value) {
if (typeof GM_setValue === 'function' && !window.chrome) {
GM_setValue(name, value);
} else {
localStorage.setItem(name, value);
}
}
function deleteValue(name) {
if (typeof GM_deleteValue === 'function' && !window.chrome) {
GM_deleteValue(name);
} else {
localStorage.removeItem(name);
}
}
/*
* $Id: uneval.js,v 0.3 2009/02/26 02:29:58 dankogai Exp dankogai $
*/
if (typeof(this['uneval']) !== 'function') {
var hasOwnProperty = Object.prototype.hasOwnProperty;
var protos = [];
var char2esc = {'\t':'t','\n':'n','\v':'v','\f':'f','\r':'\r',
'\'':'\'','\"':'\"','\\':'\\'};
var escapeChar = function(c){
if (c in char2esc) return '\\' + char2esc[c];
var ord = c.charCodeAt(0);
return ord < 0x20 ? '\\x0' + ord.toString(16)
: ord < 0x7F ? '\\' + c
: ord < 0x100 ? '\\x' + ord.toString(16)
: ord < 0x1000 ? '\\u0' + ord.toString(16)
: '\\u' + ord.toString(16)
};
var uneval_asis = function(o){ return o.toString() };
/* predefine objects where typeof(o) != 'object' */
var name2uneval = {
'boolean':uneval_asis,
'number': uneval_asis,
'string': function(o){
return '\''
+ o.toString()
.replace(/[\x00-\x1F\'\"\\\u007F-\uFFFF]/g, escapeChar)
+ '\''
},
'undefined': function(o){ return 'undefined' },
'function':uneval_asis
};
var uneval_default = function(o, np){
var src = []; // a-ha!
for (var p in o){
if (!hasOwnProperty.call(o, p)) continue;
src[src.length] = uneval(p) + ':' + uneval(o[p], 1);
};
// parens needed to make eval() happy
return np ? '{' + src.toString() + '}' : '({' + src.toString() + '})';
};
uneval_set = function(proto, name, func){
protos[protos.length] = [ proto, name ];
name2uneval[name] = func || uneval_default;
};
uneval_set(Array, 'array', function(o){
var src = [];
for (var i = 0, l = o.length; i < l; i++)
src[i] = uneval(o[i]);
return '[' + src.toString() + ']';
});
uneval_set(RegExp, 'regexp', uneval_asis);
uneval_set(Date, 'date', function(o){
return '(new Date(' + o.valueOf() + '))';
});
var typeName = function(o){
// if (o === null) return 'null';
var t = typeof o;
if (t != 'object') return t;
// we have to lenear-search. sigh.
for (var i = 0, l = protos.length; i < l; i++){
if (o instanceof protos[i][0]) return protos[i][1];
}
return 'object';
};
uneval = function(o, np){
// if (o.toSource) return o.toSource();
if (o === null) return 'null';
var func = name2uneval[typeName(o)] || uneval_default;
return func(o, np);
}
}
if (typeof(this['clone']) !== 'function') {
clone = function(o){
try{
return eval(uneval(o));
}catch(e){
throw(e);
}
};
}
/*
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
* in FIPS PUB 180-1
* Version 2.1 Copyright Paul Johnston 2000 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for details.
*/
/*
* Configurable variables. You may need to tweak these to be compatible with
* the server-side, but the defaults work in most cases.
*/
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
var b64pad = "="; /* base-64 pad character. "=" for strict RFC compliance */
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
/*
* These are the functions you'll usually want to call
* They take string arguments and return either hex or base-64 encoded strings
*/
function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));}
function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));}
function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));}
function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));}
function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}
function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}
/*
* Perform a simple self-test to see if the VM is working
*/
function sha1_vm_test()
{
return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";
}
/*
* Calculate the SHA-1 of an array of big-endian words, and a bit length
*/
function core_sha1(x, len)
{
/* append padding */
x[len >> 5] |= 0x80 << (24 - len % 32);
x[((len + 64 >> 9) << 4) + 15] = len;
var w = Array(80);
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
var e = -1009589776;
for(var i = 0; i < x.length; i += 16)
{
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
var olde = e;
for(var j = 0; j < 80; j++)
{
if(j < 16) w[j] = x[i + j];
else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
safe_add(safe_add(e, w[j]), sha1_kt(j)));
e = d;
d = c;
c = rol(b, 30);
b = a;
a = t;
}
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
e = safe_add(e, olde);
}
return Array(a, b, c, d, e);
}
/*
* Perform the appropriate triplet combination function for the current
* iteration
*/
function sha1_ft(t, b, c, d)
{
if(t < 20) return (b & c) | ((~b) & d);
if(t < 40) return b ^ c ^ d;
if(t < 60) return (b & c) | (b & d) | (c & d);
return b ^ c ^ d;
}
/*
* Determine the appropriate additive constant for the current iteration
*/
function sha1_kt(t)
{
return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
(t < 60) ? -1894007588 : -899497514;
}
/*
* Calculate the HMAC-SHA1 of a key and some data
*/
function core_hmac_sha1(key, data)
{
var bkey = str2binb(key);
if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz);
var ipad = Array(16), opad = Array(16);
for(var i = 0; i < 16; i++)
{
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5C5C5C5C;
}
var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
return core_sha1(opad.concat(hash), 512 + 160);
}
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
function safe_add(x, y)
{
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
function rol(num, cnt)
{
return (num << cnt) | (num >>> (32 - cnt));
}
/*
* Convert an 8-bit or 16-bit string to an array of big-endian words
* In 8-bit function, characters >255 have their hi-byte silently ignored.
*/
function str2binb(str)
{
var bin = Array();
var mask = (1 << chrsz) - 1;
for(var i = 0; i < str.length * chrsz; i += chrsz)
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i%32);
return bin;
}
/*
* Convert an array of big-endian words to a string
*/
function binb2str(bin)
{
var str = "";
var mask = (1 << chrsz) - 1;
for(var i = 0; i < bin.length * 32; i += chrsz)
str += String.fromCharCode((bin[i>>5] >>> (24 - i%32)) & mask);
return str;
}
/*
* Convert an array of big-endian words to a hex string.
*/
function binb2hex(binarray)
{
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for(var i = 0; i < binarray.length * 4; i++)
{
str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF);
}
return str;
}
/*
* Convert an array of big-endian words to a base-64 string
*/
function binb2b64(binarray)
{
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var str = "";
for(var i = 0; i < binarray.length * 4; i += 3)
{
var triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16)
| (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 )
| ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
for(var j = 0; j < 4; j++)
{
if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
}
}
return str;
}
/* Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
* Version: 1.0
* LastModified: Dec 25 1999
* This library is free. You can redistribute it and/or modify it.
*/
/*
* Interfaces:
* b64 = base64encode(data);
* data = base64decode(b64);
*/
var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var base64DecodeChars = new Array(
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1);
function base64encode(str) {
var out, i, len;
var c1, c2, c3;
len = str.length;
i = 0;
out = "";
while(i < len) {
c1 = str.charCodeAt(i++) & 0xff;
if(i == len)
{
out += base64EncodeChars.charAt(c1 >> 2);
out += base64EncodeChars.charAt((c1 & 0x3) << 4);
out += "==";
break;
}
c2 = str.charCodeAt(i++);
if(i == len)
{
out += base64EncodeChars.charAt(c1 >> 2);
out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
out += base64EncodeChars.charAt((c2 & 0xF) << 2);
out += "=";
break;
}
c3 = str.charCodeAt(i++);
out += base64EncodeChars.charAt(c1 >> 2);
out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6));
out += base64EncodeChars.charAt(c3 & 0x3F);
}
return out;
}
function base64decode(str) {
var c1, c2, c3, c4;
var i, len, out;
len = str.length;
i = 0;
out = "";
while(i < len) {
/* c1 */
do {
c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
} while(i < len && c1 == -1);
if(c1 == -1)
break;
/* c2 */
do {
c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
} while(i < len && c2 == -1);
if(c2 == -1)
break;
out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));
/* c3 */
do {
c3 = str.charCodeAt(i++) & 0xff;
if(c3 == 61)
return out;
c3 = base64DecodeChars[c3];
} while(i < len && c3 == -1);
if(c3 == -1)
break;
out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));
/* c4 */
do {
c4 = str.charCodeAt(i++) & 0xff;
if(c4 == 61)
return out;
c4 = base64DecodeChars[c4];
} while(i < len && c4 == -1);
if(c4 == -1)
break;
out += String.fromCharCode(((c3 & 0x03) << 6) | c4);
}
return out;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment