You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cryptpad/www/debug/chainpad.dist.js

4199 lines
152 KiB
JavaScript

(function(){
var r=function(){var e="function"==typeof require&&require,r=function(i,o,u){o||(o=0);var n=r.resolve(i,o),t=r.m[o][n];if(!t&&e){if(t=e(n))return t}else if(t&&t.c&&(o=t.c,n=t.m,t=r.m[o][t.m],!t))throw new Error('failed to require "'+n+'" from '+o);if(!t)throw new Error('failed to require "'+i+'" from '+u);return t.exports||(t.exports={},t.call(t.exports,t,t.exports,r.relative(n,o))),t.exports};return r.resolve=function(e,n){var i=e,t=e+".js",o=e+"/index.js";return r.m[n][t]&&t?t:r.m[n][o]&&o?o:i},r.relative=function(e,t){return function(n){if("."!=n.charAt(0))return r(n,t,e);var o=e.split("/"),f=n.split("/");o.pop();for(var i=0;i<f.length;i++){var u=f[i];".."==u?o.pop():"."!=u&&o.push(u)}return r(o.join("/"),t,e)}},r}();r.m = [];
r.m[0] = {
"json.sortify": {"c":1,"m":"dist/JSON.sortify.js"},
"Diff.js": function(module, exports, require){
/*@flow*/
/*
* Copyright 2014 XWiki SAS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
"use strict";
var Operation = require('./Operation');
var Common = require('./Common');
/*::
import type { Operation_t } from './Operation';
*/
var DEFAULT_BLOCKSIZE = module.exports.DEFAULT_BLOCKSIZE = 8;
var hashScan = function (str, blockSize) {
var out = {};
for (var i = 0; i + blockSize <= str.length; i++) {
var slice = str.slice(i, i + blockSize);
(out[slice] = out[slice] || []).push(i);
}
return out;
};
// return true if two segments do not overlap, else false
var isCompatible = function (m1, m2) {
if (m1.oldIndex < m2.oldIndex) {
if (m1.oldIndex + m1.length > m2.oldIndex) { return false; }
if (m1.newIndex + m1.length > m2.newIndex) { return false; }
} else if (m2.oldIndex < m1.oldIndex) {
if (m2.oldIndex + m2.length > m1.oldIndex) { return false; }
if (m2.newIndex + m2.length > m1.newIndex) { return false; }
} else {
return false;
}
return true;
};
var scoreMatch = function (m) {
return (m.length * 2) - m.oldIndex - m.newIndex;
};
/* iterate backwards through and array, splicing out indices to remove
the indices to remove MUST be in ascending order
otherwise this could remove the wrong values
operates strictly via side-effects */
var removeAscendingIndices = function (A, toRemove) {
if (!toRemove.length) { return; }
for (var j = toRemove.length - 1; j > -1; j--) {
A.splice(toRemove[j], 1);
}
};
/* given a candidate match and the list of pending matches
evaluate whether the candidate conflicts with existing matches
if the candidate is determined to be a worse match than existing matches
return false
otherwise return the list of candidates which should be replaced
returns either:
false => the candidate is incompatible, and its conflicts are more valuable
empty array => truthy, but there is nothing to remove (no conflicts)
array => conflicting elements to replace with the candidate
*/
var listInferiorCandidates = function (current, pending) {
var score_m = scoreMatch(current);
var score_rest = 0;
var toRemove = [];
var l = pending.length;
for (var i = 0; i < l; i++) {
if (isCompatible(current, pending[i])) { continue; }
toRemove.push(i);
score_rest += scoreMatch(pending[i]);
if (score_rest > score_m) { return false; }
}
return toRemove;
};
/* called with all the matches, including the common start and common end, if they exist...
A: Common start (should not be replaced)
B: potential operations
B': satisfactory set of operations
C: Common end (should not be replaced)
this implementation does not do anything special to protect A and C
it is believed that the way matches are produced, they should not be removed.
*/
var reduceMatches = function (matches) {
// ascending sort
matches.sort(function (a, b) { return (a.oldIndex + a.newIndex) - (b.oldIndex + b.newIndex); });
var out = [];
var l_m = matches.length;
var toRemove;
for (var i = 0; i < l_m; i++) {
toRemove = listInferiorCandidates(matches[i], out);
if (toRemove) {
removeAscendingIndices(out, toRemove);
out.push(matches[i]);
}
}
return out;
};
var resolve = function (str, hash, blockSize) {
var matches = [];
var candidates = [];
// do the same thing as was done in hashscan, but for the new string
// look for commonalities between new and old data
for (var i = 0; i + blockSize <= str.length; i++) {
var slice = str.slice(i, i + blockSize);
var instances = (hash[slice] || []).slice(0);
for (var j = candidates.length - 1; j >= 0; j--) {
var c = candidates[j];
var ii = instances.indexOf(c.oldIndex + c.length - blockSize + 1);
if (ii > -1) {
c.length++;
instances.splice(ii, 1);
} else {
// We're pushing all of the candidates as "matches" and then we're going to sort them
// by length and pull out only ones which are non-intersecting because the result
// of this function needs to be a set of sequencial non-intersecting matches.
matches.push(candidates[j]);
//if (candidates.length === 1) { matches.push(candidates[j]); }
candidates.splice(j, 1);
}
}
for (var k = 0; k < instances.length; k++) {
candidates.push({
newIndex: i,
oldIndex: instances[k],
length: blockSize
});
}
//console.log(JSON.stringify(candidates));
}
// Normally we would only take one candidate, since they're equal value we just pick one and
// use it. However since we need all possible candidates which we will feed to our reduce
// function in order to get a list of sequencial non-intersecting matches.
// like concat, but destructive
Array.prototype.push.apply(matches, candidates);
//if (candidates[0]) { matches.push(candidates[0]); }
return matches;
};
var matchesToOps = function (oldS, newS, matches) {
// ascending sort
matches.sort(function (a, b) { return a.oldIndex - b.oldIndex; });
var oldI = 0;
var newI = 0;
var out = [];
for (var i = 0; i < matches.length; i++) {
var m = matches[i];
out.push(Operation.create(oldI, m.oldIndex - oldI, newS.slice(newI, m.newIndex)));
oldI = m.oldIndex + m.length;
newI = m.newIndex + m.length;
}
out.push(Operation.create(oldI, oldS.length - oldI, newS.slice(newI))); // does not check ops
if (Common.PARANOIA) {
out.forEach(function (op) {
if (!op.toRemove || !op.toInsert) { return; }
try { Operation.check(op); }
catch (e) {
console.log('\nINVALID OPERATION');
console.log(oldS);
console.log(newS);
//console.log(m);
console.log('\nMATCHES');
console.log(matches);
console.log('\nOPS');
console.log(out);
throw e;
}
});
}
return out.filter(function (x) { return x.toRemove || x.toInsert; });
};
var getCommonBeginning = function (oldS, newS) {
var commonStart = 0;
// This could be Math.min ?
var limit = oldS.length < newS.length ? oldS.length : newS.length;
while (oldS.charAt(commonStart) === newS.charAt(commonStart) && commonStart < limit) {
commonStart++;
}
return { newIndex: 0, oldIndex: 0, length: commonStart };
};
var getCommonEnd = function (oldS, newS, commonBeginning) {
var oldEnd = oldS.length - 1;
var newEnd = newS.length - 1;
var limit = Math.min(oldEnd, newEnd) - commonBeginning;
var commonEnd = 0;
while (oldS.charAt(oldEnd) === newS.charAt(newEnd) && limit >= 0) {
oldEnd--;
newEnd--;
commonEnd++;
limit--;
}
return { newIndex: newEnd + 1, oldIndex: oldEnd + 1, length: commonEnd };
};
module.exports.diff = function (
oldS /*:string*/,
newS /*:string*/,
blockSize /*:?number*/ ) /*:Array<Operation_t>*/
{
blockSize = blockSize || DEFAULT_BLOCKSIZE;
var cb = getCommonBeginning(oldS, newS);
if (cb.length === oldS.length && oldS.length === newS.length) { return []; }
var ce = getCommonEnd(oldS, newS, cb.length);
var oldST = oldS;
var newST = newS;
if (ce.length) {
oldST = oldST.slice(0, ce.oldIndex+1);
newST = newST.slice(0, ce.newIndex+1);
}
if (cb.length) {
oldST = oldST.slice(cb.length);
newST = newST.slice(cb.length);
}
var matches = resolve(newST, hashScan(oldST, blockSize), blockSize);
if (cb.length) {
for (var i = 0; i < matches.length; i++) {
matches[i].oldIndex += cb.length;
matches[i].newIndex += cb.length;
}
matches.push(cb);
}
if (ce.length) { matches.push(ce); }
var reduced = reduceMatches(matches);
var ops = matchesToOps(oldS, newS, reduced); // HERE produced operation with negative toRemove
if (Operation.applyMulti(ops, oldS) !== newS) {
// use 'self' instead of 'window' for node and webworkers
var x = (typeof(global) !== 'undefined'? global: self).ChainPad_Diff_DEBUG = {
oldS: oldS,
newS: newS,
matches: matches,
reduced: reduced,
ops: ops
};
console.log(x);
console.log("diff did not make a sane patch, check window.ChainPad_Diff_DEBUG");
ops = matchesToOps(oldS, newS, [cb, ce]);
if (Operation.applyMulti(ops, oldS) !== newS) {
throw new Error("diff is unrecoverable");
}
}
return ops;
};
},
"Patch.js": function(module, exports, require){
/*@flow*/
/*
* Copyright 2014 XWiki SAS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
"use strict";
var Common = require('./Common');
var Operation = require('./Operation');
var Sha = require('./sha256');
var Patch = module.exports;
/*::
import type {
Operation_t,
Operation_Packed_t,
Operation_Simplify_t,
Operation_Transform_t
} from './Operation';
import type { Sha256_t } from './sha256';
export type Patch_t = {
type: 'Patch',
operations: Array<Operation_t>,
parentHash: Sha256_t,
isCheckpoint: boolean,
mut: {
inverseOf: ?Patch_t,
}
};
export type Patch_Packed_t = Array<Operation_Packed_t|Sha256_t>;
export type Patch_Transform_t = (
toTransform:Array<Operation_t>,
transformBy:Array<Operation_t>,
state0:string
) => Array<Operation_t>;
*/
var create = Patch.create = function (parentHash /*:Sha256_t*/, isCheckpoint /*:?boolean*/) {
var out = Object.freeze({
type: 'Patch',
operations: [],
parentHash: parentHash,
isCheckpoint: !!isCheckpoint,
mut: {
inverseOf: undefined
}
});
if (isCheckpoint) {
out.mut.inverseOf = out;
}
return out;
};
var check = Patch.check = function (patch /*:any*/, docLength_opt /*:?number*/) /*:Patch_t*/ {
Common.assert(patch.type === 'Patch');
Common.assert(Array.isArray(patch.operations));
Common.assert(/^[0-9a-f]{64}$/.test(patch.parentHash));
for (var i = patch.operations.length - 1; i >= 0; i--) {
Operation.check(patch.operations[i], docLength_opt);
if (i > 0) {
Common.assert(!Operation.shouldMerge(patch.operations[i], patch.operations[i-1]));
}
if (typeof(docLength_opt) === 'number') {
docLength_opt += Operation.lengthChange(patch.operations[i]);
}
}
if (patch.isCheckpoint) {
Common.assert(patch.operations.length === 1);
Common.assert(patch.operations[0].offset === 0);
if (typeof(docLength_opt) === 'number') {
Common.assert(!docLength_opt || patch.operations[0].toRemove === docLength_opt);
}
}
return patch;
};
Patch.toObj = function (patch /*:Patch_t*/) {
if (Common.PARANOIA) { check(patch); }
var out /*:Array<Operation_Packed_t|Sha256_t>*/ = new Array(patch.operations.length+1);
var i;
for (i = 0; i < patch.operations.length; i++) {
out[i] = Operation.toObj(patch.operations[i]);
}
out[i] = patch.parentHash;
return out;
};
Patch.fromObj = function (obj /*:Patch_Packed_t*/, isCheckpoint /*:?boolean*/) {
Common.assert(Array.isArray(obj) && obj.length > 0);
var patch = create(Sha.check(obj[obj.length-1]), isCheckpoint);
var i;
for (i = 0; i < obj.length-1; i++) {
patch.operations[i] = Operation.fromObj(obj[i]);
}
if (Common.PARANOIA) { check(patch); }
return patch;
};
var hash = function (text) {
return Sha.hex_sha256(text);
};
var addOperation = Patch.addOperation = function (patch /*:Patch_t*/, op /*:Operation_t*/) {
if (Common.PARANOIA) {
check(patch);
Operation.check(op);
}
for (var i = 0; i < patch.operations.length; i++) {
if (Operation.shouldMerge(patch.operations[i], op)) {
var maybeOp = Operation.merge(patch.operations[i], op);
patch.operations.splice(i,1);
if (maybeOp === null) { return; }
op = maybeOp;
i--;
} else {
var out = Operation.rebase(patch.operations[i], op);
if (out === op) {
// op could not be rebased further, insert it here to keep the list ordered.
patch.operations.splice(i,0,op);
return;
} else {
op = out;
// op was rebased, try rebasing it against the next operation.
}
}
}
patch.operations.push(op);
if (Common.PARANOIA) { check(patch); }
};
Patch.createCheckpoint = function (
parentContent /*:string*/,
checkpointContent /*:string*/,
parentContentHash_opt /*:?string*/)
{
var op = Operation.create(0, parentContent.length, checkpointContent);
if (Common.PARANOIA && parentContentHash_opt) {
Common.assert(parentContentHash_opt === hash(parentContent));
}
parentContentHash_opt = parentContentHash_opt || hash(parentContent);
var out = create(parentContentHash_opt, true);
out.operations[0] = op;
return out;
};
var clone = Patch.clone = function (patch /*:Patch_t*/) {
if (Common.PARANOIA) { check(patch); }
var out = create(patch.parentHash, patch.isCheckpoint);
for (var i = 0; i < patch.operations.length; i++) {
out.operations[i] = patch.operations[i];
}
return out;
};
Patch.merge = function (oldPatch /*:Patch_t*/, newPatch /*:Patch_t*/) {
if (Common.PARANOIA) {
check(oldPatch);
check(newPatch);
}
if (oldPatch.isCheckpoint) {
Common.assert(newPatch.parentHash === oldPatch.parentHash);
if (newPatch.isCheckpoint) {
return create(oldPatch.parentHash);
}
return clone(newPatch);
} else if (newPatch.isCheckpoint) {
return clone(oldPatch);
}
oldPatch = clone(oldPatch);
for (var i = newPatch.operations.length-1; i >= 0; i--) {
addOperation(oldPatch, newPatch.operations[i]);
}
return oldPatch;
};
Patch.apply = function (patch /*:Patch_t*/, doc /*:string*/)
{
if (Common.PARANOIA) {
check(patch);
Common.assert(typeof(doc) === 'string');
Common.assert(Sha.hex_sha256(doc) === patch.parentHash);
}
var newDoc = doc;
for (var i = patch.operations.length-1; i >= 0; i--) {
newDoc = Operation.apply(patch.operations[i], newDoc);
}
return newDoc;
};
Patch.lengthChange = function (patch /*:Patch_t*/)
{
if (Common.PARANOIA) { check(patch); }
var out = 0;
for (var i = 0; i < patch.operations.length; i++) {
out += Operation.lengthChange(patch.operations[i]);
}
return out;
};
Patch.invert = function (patch /*:Patch_t*/, doc /*:string*/)
{
if (Common.PARANOIA) {
check(patch);
Common.assert(typeof(doc) === 'string');
Common.assert(Sha.hex_sha256(doc) === patch.parentHash);
}
var newDoc = doc;
var operations = new Array(patch.operations.length);
for (var i = patch.operations.length-1; i >= 0; i--) {
operations[i] = Operation.invert(patch.operations[i], newDoc);
newDoc = Operation.apply(patch.operations[i], newDoc);
}
var opOffsets = new Array(patch.operations.length);
(function () {
for (var i = operations.length-1; i >= 0; i--) {
opOffsets[i] = operations[i].offset;
for (var j = i - 1; j >= 0; j--) {
opOffsets[i] += operations[j].toRemove - operations[j].toInsert.length;
}
}
}());
var rpatch = create(Sha.hex_sha256(newDoc), patch.isCheckpoint);
rpatch.operations.splice(0, rpatch.operations.length);
for (var j = 0; j < operations.length; j++) {
rpatch.operations[j] =
Operation.create(opOffsets[j], operations[j].toRemove, operations[j].toInsert);
}
if (Common.PARANOIA) { check(rpatch); }
return rpatch;
};
Patch.simplify = function (
patch /*:Patch_t*/,
doc /*:string*/,
operationSimplify /*:Operation_Simplify_t*/ )
{
if (Common.PARANOIA) {
check(patch);
Common.assert(typeof(doc) === 'string');
Common.assert(Sha.hex_sha256(doc) === patch.parentHash);
}
var spatch = create(patch.parentHash);
var newDoc = doc;
var outOps = [];
var j = 0;
for (var i = patch.operations.length-1; i >= 0; i--) {
var outOp = operationSimplify(patch.operations[i], newDoc, Operation.simplify);
if (outOp) {
newDoc = Operation.apply(outOp, newDoc);
outOps[j++] = outOp;
}
}
Array.prototype.push.apply(spatch.operations, outOps.reverse());
if (!spatch.operations[0]) {
spatch.operations.shift();
}
if (Common.PARANOIA) {
check(spatch);
}
return spatch;
};
Patch.equals = function (patchA /*:Patch_t*/, patchB /*:Patch_t*/) {
if (patchA.operations.length !== patchB.operations.length) { return false; }
for (var i = 0; i < patchA.operations.length; i++) {
if (!Operation.equals(patchA.operations[i], patchB.operations[i])) { return false; }
}
return true;
};
var isCheckpointOp = function (op, text) {
return op.offset === 0 && op.toRemove === text.length && op.toInsert === text;
};
Patch.transform = function (
toTransform /*:Patch_t*/,
transformBy /*:Patch_t*/,
doc /*:string*/,
patchTransformer /*:Patch_Transform_t*/ )
{
if (Common.PARANOIA) {
check(toTransform, doc.length);
check(transformBy, doc.length);
if (Sha.hex_sha256(doc) !== toTransform.parentHash) { throw new Error("wrong hash"); }
}
if (toTransform.parentHash !== transformBy.parentHash) { throw new Error(); }
var afterTransformBy = Patch.apply(transformBy, doc);
var out = create(transformBy.mut.inverseOf
? transformBy.mut.inverseOf.parentHash
: Sha.hex_sha256(afterTransformBy),
toTransform.isCheckpoint
);
if (transformBy.operations.length === 0) { return clone(toTransform); }
if (toTransform.operations.length === 0) {
if (toTransform.isCheckpoint) { throw new Error(); }
return out;
}
if (toTransform.isCheckpoint ||
(toTransform.operations.length === 1 && isCheckpointOp(toTransform.operations[0], doc)))
{
throw new Error("Attempting to transform a checkpoint, this should not happen");
}
if (transformBy.operations.length === 1 && isCheckpointOp(transformBy.operations[0], doc)) {
if (!transformBy.isCheckpoint) { throw new Error(); }
return toTransform;
}
if (transformBy.isCheckpoint) { throw new Error(); }
var ops = patchTransformer(toTransform.operations, transformBy.operations, doc);
Array.prototype.push.apply(out.operations, ops);
if (Common.PARANOIA) {
check(out, afterTransformBy.length);
}
return out;
};
Patch.random = function (doc /*:string*/, opCount /*:?number*/) {
Common.assert(typeof(doc) === 'string');
opCount = opCount || (Math.floor(Math.random() * 30) + 1);
var patch = create(Sha.hex_sha256(doc));
var docLength = doc.length;
while (opCount-- > 0) {
var op = Operation.random(docLength);
docLength += Operation.lengthChange(op);
addOperation(patch, op);
}
check(patch);
return patch;
};
Object.freeze(module.exports);
},
"SHA256.js": function(module, exports, require){
/* A JavaScript implementation of the Secure Hash Algorithm, SHA-256
* Version 0.3 Copyright Angel Marin 2003-2004 - http://anmar.eu.org/
* Distributed under the BSD License
* Some bits taken from Paul Johnston's SHA-1 implementation
*/
(function () {
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
function safe_add (x, y) {
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
function S (X, n) {return ( X >>> n ) | (X << (32 - n));}
function R (X, n) {return ( X >>> n );}
function Ch(x, y, z) {return ((x & y) ^ ((~x) & z));}
function Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));}
function Sigma0256(x) {return (S(x, 2) ^ S(x, 13) ^ S(x, 22));}
function Sigma1256(x) {return (S(x, 6) ^ S(x, 11) ^ S(x, 25));}
function Gamma0256(x) {return (S(x, 7) ^ S(x, 18) ^ R(x, 3));}
function Gamma1256(x) {return (S(x, 17) ^ S(x, 19) ^ R(x, 10));}
function newArray (n) {
var a = [];
for (;n>0;n--) {
a.push(undefined);
}
return a;
}
function core_sha256 (m, l) {
var K = [0x428A2F98,0x71374491,0xB5C0FBCF,0xE9B5DBA5,0x3956C25B,0x59F111F1,0x923F82A4,0xAB1C5ED5,0xD807AA98,0x12835B01,0x243185BE,0x550C7DC3,0x72BE5D74,0x80DEB1FE,0x9BDC06A7,0xC19BF174,0xE49B69C1,0xEFBE4786,0xFC19DC6,0x240CA1CC,0x2DE92C6F,0x4A7484AA,0x5CB0A9DC,0x76F988DA,0x983E5152,0xA831C66D,0xB00327C8,0xBF597FC7,0xC6E00BF3,0xD5A79147,0x6CA6351,0x14292967,0x27B70A85,0x2E1B2138,0x4D2C6DFC,0x53380D13,0x650A7354,0x766A0ABB,0x81C2C92E,0x92722C85,0xA2BFE8A1,0xA81A664B,0xC24B8B70,0xC76C51A3,0xD192E819,0xD6990624,0xF40E3585,0x106AA070,0x19A4C116,0x1E376C08,0x2748774C,0x34B0BCB5,0x391C0CB3,0x4ED8AA4A,0x5B9CCA4F,0x682E6FF3,0x748F82EE,0x78A5636F,0x84C87814,0x8CC70208,0x90BEFFFA,0xA4506CEB,0xBEF9A3F7,0xC67178F2];
var HASH = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19];
var W = newArray(64);
var a, b, c, d, e, f, g, h, i, j;
var T1, T2;
/* append padding */
m[l >> 5] |= 0x80 << (24 - l % 32);
m[((l + 64 >> 9) << 4) + 15] = l;
for ( var i = 0; i<m.length; i+=16 ) {
a = HASH[0]; b = HASH[1]; c = HASH[2]; d = HASH[3];
e = HASH[4]; f = HASH[5]; g = HASH[6]; h = HASH[7];
for ( var j = 0; j<64; j++) {
if (j < 16) {
W[j] = m[j + i];
} else {
W[j] = safe_add(safe_add(safe_add(Gamma1256(
W[j - 2]), W[j - 7]), Gamma0256(W[j - 15])), W[j - 16]);
}
T1 = safe_add(safe_add(safe_add(
safe_add(h, Sigma1256(e)), Ch(e, f, g)), K[j]), W[j]);
T2 = safe_add(Sigma0256(a), Maj(a, b, c));
h = g; g = f; f = e; e = safe_add(d, T1);
d = c; c = b; b = a; a = safe_add(T1, T2);
}
HASH[0] = safe_add(a, HASH[0]); HASH[1] = safe_add(b, HASH[1]);
HASH[2] = safe_add(c, HASH[2]); HASH[3] = safe_add(d, HASH[3]);
HASH[4] = safe_add(e, HASH[4]); HASH[5] = safe_add(f, HASH[5]);
HASH[6] = safe_add(g, HASH[6]); HASH[7] = safe_add(h, HASH[7]);
}
return HASH;
}
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;
}
function binb2hex (binarray) {
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
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;
}
function hex_sha256(s){
return binb2hex(core_sha256(str2binb(s),s.length * chrsz));
}
module.exports.hex_sha256 = hex_sha256;
}());
},
"Common.js": function(module, exports, require){
/*@flow*/
/* globals localStorage, window */
/*
* Copyright 2014 XWiki SAS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
"use strict";
module.exports.global = (function () {
if (typeof(self) !== 'undefined') { return self; }
if (typeof(global) !== 'undefined') { return global; }
if (typeof(window) !== 'undefined') { return window; }
throw new Error("no self, nor global, nor window");
}());
var cfg = function (name) {
if (typeof(localStorage) !== 'undefined' && localStorage[name]) {
return localStorage[name];
}
// flow thinks global may be undefined
return module.exports.global[name];
};
var PARANOIA = module.exports.PARANOIA = cfg("ChainPad_PARANOIA");
/* Good testing but slooooooooooow */
module.exports.VALIDATE_ENTIRE_CHAIN_EACH_MSG = cfg("ChainPad_VALIDATE_ENTIRE_CHAIN_EACH_MSG");
/* throw errors over non-compliant messages which would otherwise be treated as invalid */
module.exports.TESTING = cfg("ChainPad_TESTING");
module.exports.assert = function (expr /*:any*/) {
if (!expr) { throw new Error("Failed assertion"); }
};
module.exports.isUint = function (integer /*:number*/) {
return (typeof(integer) === 'number') &&
(Math.floor(integer) === integer) &&
(integer >= 0);
};
module.exports.randomASCII = function (length /*:number*/) {
var content = [];
for (var i = 0; i < length; i++) {
content[i] = String.fromCharCode( Math.floor(Math.random()*256) % 57 + 65 );
}
return content.join('');
};
module.exports.strcmp = function (a /*:string*/, b /*:string*/) {
if (PARANOIA && typeof(a) !== 'string') { throw new Error(); }
if (PARANOIA && typeof(b) !== 'string') { throw new Error(); }
return ( (a === b) ? 0 : ( (a > b) ? 1 : -1 ) );
};
Object.freeze(module.exports);
},
"sha256.js": function(module, exports, require){
/*@flow*/
/*
* Copyright 2014 XWiki SAS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
var asm_sha256 = require('./sha256/exports.js');
var old = require('./SHA256.js');
var Common = require('./Common');
/*::
export type Sha256_t = string;
*/
var brokenTextEncode = function (str) {
var out = new Uint8Array(str.length);
for (var i = 0; i < str.length; i++) {
out[i] = str.charCodeAt(i) & 0xff;
}
return out;
};
module.exports.check = function (hex /*:any*/) /*:Sha256_t*/ {
if (typeof(hex) !== 'string') { throw new Error(); }
if (!/[a-f0-9]{64}/.test(hex)) { throw new Error(); }
return hex;
};
module.exports.hex_sha256 = function (d /*:string*/) /*:Sha256_t*/ {
d = d+'';
var ret = asm_sha256.hex(brokenTextEncode(d));
if (Common.PARANOIA) {
var oldHash = old.hex_sha256(d);
if (oldHash !== ret) {
try {
throw new Error();
} catch (e) {
console.log({
hashErr: e,
badHash: d,
asmHasher: asm_sha256.hex,
oldHasher: old.hex_sha256
});
}
return oldHash;
}
}
return ret;
};
Object.freeze(module.exports);
},
"Message.js": function(module, exports, require){
/*@flow*/
/*
* Copyright 2014 XWiki SAS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
"use strict";
var Common = require('./Common');
//var Operation = require('./Operation');
var Patch = require('./Patch');
var Sha = require('./sha256');
var Message = module.exports;
var PATCH = Message.PATCH = 2;
var CHECKPOINT = Message.CHECKPOINT = 4;
/*::
import type { Sha256_t } from './sha256'
import type { Patch_t } from './Patch'
export type Message_Type_t = 2 | 4;
export type Message_Status_t =
'accepted'|'initial_state'|'duplicate'|'failed_content_validation'|
'can_be_simplified'|'checkpoint_wrong_parentcount'|'parent_hash_invalid'|'unhandled';
export type Message_t = {
type: 'Message',
messageType: Message_Type_t,
content: Patch_t,
lastMsgHash: Sha256_t,
hashOf: Sha256_t,
mut: {
parentCount: ?number,
isInitialMessage: boolean,
parent: ?Message_t,
isFromMe: boolean,
recvOrder: number,
status: Message_Status_t
}
}
*/
var check = Message.check = function(msg /*:any*/) /*:Message_t*/ {
Common.assert(msg.type === 'Message');
Common.assert(msg.messageType === PATCH || msg.messageType === CHECKPOINT);
Patch.check(msg.content);
Common.assert(typeof(msg.lastMsgHash) === 'string');
return msg;
};
var DUMMY_HASH /*:Sha256_t*/ = "";
var create = Message.create = function (
type /*:Message_Type_t*/,
content /*:Patch_t*/,
lastMsgHash /*:Sha256_t*/) /*:Message_t*/
{
var msg = {
type: 'Message',
messageType: type,
content: content,
lastMsgHash: lastMsgHash,
hashOf: DUMMY_HASH,
mut: {
parentCount: undefined,
isInitialMessage: false,
isFromMe: false,
parent: undefined,
recvOrder: -1,
status: "unhandled"
}
};
msg.hashOf = hashOf(msg);
if (Common.PARANOIA) { check(msg); }
return Object.freeze(msg);
};
// $FlowFixMe doesn't like the toString()
var toString = Message.toStr = Message.toString = function (msg /*:Message_t*/) {
if (Common.PARANOIA) { check(msg); }
if (msg.messageType === PATCH || msg.messageType === CHECKPOINT) {
if (!msg.content) { throw new Error(); }
return JSON.stringify([msg.messageType, Patch.toObj(msg.content), msg.lastMsgHash]);
} else {
throw new Error();
}
};
Message.fromString = function (str /*:string*/) /*:Message_t*/ {
var m = JSON.parse(str);
if (m[0] !== CHECKPOINT && m[0] !== PATCH) { throw new Error("invalid message type " + m[0]); }
var msg = create(m[0], Patch.fromObj(m[1], (m[0] === CHECKPOINT)), m[2]);
return Object.freeze(msg);
};
var hashOf = Message.hashOf = function (msg /*:Message_t*/) {
if (Common.PARANOIA) { check(msg); }
var hash = Sha.hex_sha256(toString(msg));
return hash;
};
Object.freeze(module.exports);
},
"ChainPad.js": function(module, exports, require){
/*@flow*/
/*
* Copyright 2014 XWiki SAS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
"use strict";
var Common = module.exports.Common = require('./Common');
var Operation = module.exports.Operation = require('./Operation');
var Patch = module.exports.Patch = require('./Patch');
var Message = module.exports.Message = require('./Message');
var Sha = module.exports.Sha = require('./sha256');
var Diff = module.exports.Diff = require('./Diff');
var TextTransformer = module.exports.TextTransformer = require('./transform/TextTransformer');
module.exports.NaiveJSONTransformer = require('./transform/NaiveJSONTransformer');
module.exports.SmartJSONTransformer = require('./transform/SmartJSONTransformer');
// hex_sha256('')
var EMPTY_STR_HASH = module.exports.EMPTY_STR_HASH =
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855';
var ZERO = '0000000000000000000000000000000000000000000000000000000000000000';
// Default number of patches between checkpoints (patches older than this will be pruned)
// default for realtime.config.checkpointInterval
var DEFAULT_CHECKPOINT_INTERVAL = 50;
// Default number of milliseconds to wait before syncing to the server
var DEFAULT_AVERAGE_SYNC_MILLISECONDS = 300;
// By default, we allow checkpoints at any place but if this is set true, we will blow up on chains
// which have checkpoints not where we expect them to be.
var DEFAULT_STRICT_CHECKPOINT_VALIDATION = false;
var debug = function (realtime, msg) {
if (realtime.logLevel > 1) {
console.log("[" + realtime.userName + "] " + msg);
}
};
var warn = function (realtime, msg) {
if (realtime.logLevel > 0) {
console.error("[" + realtime.userName + "] " + msg);
}
};
var schedule = function (realtime, func, timeout) {
if (realtime.aborted) { return; }
if (!timeout) {
timeout = Math.floor(Math.random() * 2 * realtime.config.avgSyncMilliseconds);
}
var to = setTimeout(function () {
realtime.schedules.splice(realtime.schedules.indexOf(to), 1);
func();
}, timeout);
realtime.schedules.push(to);
return to;
};
var unschedule = function (realtime, schedule) {
var index = realtime.schedules.indexOf(schedule);
if (index > -1) {
realtime.schedules.splice(index, 1);
}
clearTimeout(schedule);
};
var onMessage = function (realtime, message, callback /*:(?string)=>void*/) {
if (!realtime.messageHandlers.length) {
callback("no onMessage() handler registered");
}
try {
realtime.messageHandlers.forEach(function (handler) {
handler(message, function () {
callback.apply(null, arguments);
callback = function () { };
});
});
} catch (e) {
callback(e.stack);
}
};
var sendMessage = function (realtime, msg, callback, timeSent) {
var strMsg = Message.toStr(msg);
onMessage(realtime, strMsg, function (err) {
if (err) {
debug(realtime, "Posting to server failed [" + err + "]");
realtime.pending = null;
} else {
var pending = realtime.pending;
realtime.pending = null;
if (!pending) { throw new Error(); }
Common.assert(pending.hash === msg.hashOf);
if (handleMessage(realtime, strMsg, true)) {
realtime.timeOfLastSuccess = +new Date();
realtime.lag = +new Date() - pending.timeSent;
} else {
debug(realtime, "Our message [" + msg.hashOf + "] failed validation");
}
pending.callback();
}
});
var timeout = schedule(realtime, function () {
debug(realtime, "Failed to send message [" + msg.hashOf + "] to server");
var pending = realtime.pending;
if (pending) {
//var timeSent = pending.timeSent;
realtime.pending = null;
realtime.syncSchedule = -1;
}
sync(realtime, 0);
if (!pending) {
throw new Error("INTERNAL ERROR: Message timed out but no realtime.pending");
}
}, 10000 + (Math.random() * 5000));
if (realtime.pending) { throw new Error("there is already a pending message"); }
if (realtime.timeOfLastSuccess === -1) { realtime.timeOfLastSuccess = +new Date(); }
realtime.pending = {
hash: msg.hashOf,
timeSent: timeSent || +new Date(),
callback: function () {
unschedule(realtime, timeout);
realtime.syncSchedule = schedule(realtime, function () { sync(realtime); }, 0);
callback();
}
};
if (Common.PARANOIA) { check(realtime); }
};
var settle = function (realtime) {
var onSettle = realtime.onSettle;
realtime.onSettle = [];
onSettle.forEach(function (handler) {
try {
handler();
} catch (e) {
warn(realtime, "Error in onSettle handler [" + e.stack + "]");
}
});
};
var inversePatch = function (patch) {
if (!patch.mut.inverseOf) { throw new Error(); }
return patch.mut.inverseOf;
};
var sync = function (realtime, timeSent) {
if (Common.PARANOIA) { check(realtime); }
if (realtime.syncSchedule && !realtime.pending) {
unschedule(realtime, realtime.syncSchedule);
realtime.syncSchedule = null;
} else {
//debug(realtime, "already syncing...");
// we're currently waiting on something from the server.
return;
}
realtime.uncommitted = Patch.simplify(
realtime.uncommitted, realtime.authDoc, realtime.config.operationSimplify);
if (realtime.uncommitted.operations.length === 0) {
//debug(realtime, "No data to sync to the server, sleeping");
settle(realtime);
realtime.timeOfLastSuccess = +new Date();
realtime.syncSchedule = schedule(realtime, function () { sync(realtime); });
return;
}
var pc = parentCount(realtime, realtime.best) + 1;
if ((pc % realtime.config.checkpointInterval) === 0) {
var best = realtime.best;
debug(realtime, "Sending checkpoint (interval [" + realtime.config.checkpointInterval +
"]) patch no [" + pc + "]");
debug(realtime, parentCount(realtime, realtime.best));
if (!best || !best.content || !inversePatch(best.content)) { throw new Error(); }
var cpp = Patch.createCheckpoint(realtime.authDoc,
realtime.authDoc,
inversePatch(best.content).parentHash);
var cp = Message.create(Message.CHECKPOINT, cpp, best.hashOf);
sendMessage(realtime, cp, function () {
debug(realtime, "Checkpoint sent and accepted");
}, timeSent);
return;
}
var msg;
if (realtime.setContentPatch) {
msg = realtime.setContentPatch;
} else {
msg = Message.create(Message.PATCH, realtime.uncommitted, realtime.best.hashOf);
}
sendMessage(realtime, msg, function () {
//debug(realtime, "patch sent");
if (realtime.setContentPatch) {
debug(realtime, "initial Ack received [" + msg.hashOf + "]");
realtime.setContentPatch = null;
}
}, timeSent);
};
var storeMessage = function (realtime, msg) {
Common.assert(msg.lastMsgHash);
Common.assert(msg.hashOf);
realtime.messages[msg.hashOf] = msg;
(realtime.messagesByParent[msg.lastMsgHash] =
realtime.messagesByParent[msg.lastMsgHash] || []).push(msg);
msg.mut.status = "accepted";
};
var forgetMessage = function (realtime, msg, reason) {
Common.assert(msg.lastMsgHash);
Common.assert(msg.hashOf);
if (reason) {
msg.mut.status = reason;
realtime.rejectedBlocks.push(msg);
}
delete realtime.messages[msg.hashOf];
var list = realtime.messagesByParent[msg.lastMsgHash];
Common.assert(list.indexOf(msg) > -1);
list.splice(list.indexOf(msg), 1);
if (list.length === 0) {
delete realtime.messagesByParent[msg.lastMsgHash];
}
var children = realtime.messagesByParent[msg.hashOf];
if (children) {
for (var i = 0; i < children.length; i++) {
delete children[i].mut.parent;
}
}
};
var create = function (config) {
var zeroPatch = Patch.create(EMPTY_STR_HASH);
mkInverse(zeroPatch, '');
var zeroMsg = Message.create(Message.PATCH, zeroPatch, ZERO);
zeroMsg.mut.parentCount = 0;
zeroMsg.mut.isInitialMessage = true;
var best = zeroMsg;
var initMsg;
if (config.initialState !== '') {
var initPatch = Patch.create(EMPTY_STR_HASH);
Patch.addOperation(initPatch, Operation.create(0, 0, config.initialState));
mkInverse(initPatch, '');
initMsg = Message.create(Message.PATCH, initPatch, zeroMsg.hashOf);
initMsg.mut.isInitialMessage = true;
best = initMsg;
}
var realtime = {
type: 'ChainPad',
authDoc: config.initialState,
config: config,
logLevel: config.logLevel,
/** A patch representing all uncommitted work. */
uncommitted: Patch.create(inversePatch(best.content).parentHash),
patchHandlers: [],
changeHandlers: [],
messageHandlers: [],
schedules: [],
aborted: false,
syncSchedule: -2,
// this is only used if PARANOIA is enabled.
userInterfaceContent: config.initialState,
// If we want to set the content to a particular thing, this patch will be sent across the
// wire. If the patch is not accepted we will not try to recover it. This is used for
// setting initial state.
setContentPatch: initMsg,
// hash and callback for previously send patch, currently in flight.
pending: undefined,
messages: {},
messagesByParent: {},
rootMessage: zeroMsg,
onSettle: [],
userName: config.userName,
best: best,
lag: 0,
timeOfLastSuccess: -1,
// Incremented every time a message comes in, valid or invalid, used to number messages.
recvCounter: 0,
// All of the messages which were discarded because they were faulty
rejectedBlocks: []
};
storeMessage(realtime, zeroMsg);
if (initMsg) {
storeMessage(realtime, initMsg);
}
return realtime;
};
var getParent = function (realtime, message) {
var parent = message.mut.parent = message.mut.parent || realtime.messages[message.lastMsgHash];
return parent;
};
var check = function(realtime) {
Common.assert(realtime.type === 'ChainPad');
Common.assert(typeof(realtime.authDoc) === 'string');
Patch.check(realtime.uncommitted, realtime.authDoc.length);
var uiDoc = Patch.apply(realtime.uncommitted, realtime.authDoc);
Common.assert(uiDoc.length === uncommittedDocLength(realtime));
if (realtime.userInterfaceContent !== '') {
Common.assert(uiDoc === realtime.userInterfaceContent);
}
if (!Common.VALIDATE_ENTIRE_CHAIN_EACH_MSG) { return; }
var doc = realtime.authDoc;
var patchMsg = realtime.best;
Common.assert(inversePatch(patchMsg.content).parentHash === realtime.uncommitted.parentHash);
var patches = [];
do {
patches.push(patchMsg);
doc = Patch.apply(inversePatch(patchMsg.content), doc);
} while ((patchMsg = getParent(realtime, patchMsg)));
if (realtime.rootMessage.content.isCheckpoint) {
if (doc !== realtime.rootMessage.content.operations[0].toInsert) { throw new Error(); }
} else if (doc !== '') { throw new Error(); }
while ((patchMsg = patches.pop())) {
doc = Patch.apply(patchMsg.content, doc);
}
Common.assert(doc === realtime.authDoc);
};
var uncommittedDocLength = function (realtime) {
return realtime.authDoc.length + Patch.lengthChange(realtime.uncommitted);
};
var doOperation = function (realtime, op) {
if (Common.PARANOIA) {
check(realtime);
realtime.userInterfaceContent = Operation.apply(op, realtime.userInterfaceContent);
}
Operation.check(op, uncommittedDocLength(realtime));
Patch.addOperation(realtime.uncommitted, op);
};
var doPatch = function (realtime, patch) {
if (Common.PARANOIA) {
check(realtime);
Common.assert(Patch.invert(realtime.uncommitted, realtime.authDoc).parentHash ===
patch.parentHash);
realtime.userInterfaceContent = Patch.apply(patch, realtime.userInterfaceContent);
}
Patch.check(patch, uncommittedDocLength(realtime));
realtime.uncommitted = Patch.merge(realtime.uncommitted, patch);
};
var isAncestorOf = function (realtime, ancestor, decendent) {
if (!ancestor) { return false; }
for (;;) {
if (!decendent) { return false; }
if (ancestor === decendent) { return true; }
decendent = getParent(realtime, decendent);
}
};
var parentCount = function (realtime, message) {
if (typeof(message.mut.parentCount) === 'number') { return message.mut.parentCount; }
var msgs = [];
for (; (typeof(message.mut.parentCount) !== 'number'); message = getParent(realtime, message)) {
if (!message) {
if (message === realtime.rootMessage) {
throw new Error("root message does not have parent count");
}
throw new Error("parentCount called on unlinked message");
}
msgs.unshift(message);
}
var pc = message.mut.parentCount;
for (var i = 0; i < msgs.length; i++) {
msgs[i].mut.parentCount = ++pc;
}
return pc;
};
var applyPatch = function (realtime, isFromMe, patch) {
Common.assert(patch);
var newAuthDoc;
if (isFromMe) {
// Case 1: We're applying a patch which we originally created (yay our work was accepted)
// We will merge the inverse of the patch with our uncommitted work in order that
// we do not try to commit that work over again.
// Case 2: We're reverting a patch which had originally come from us, a.k.a. we're applying
// the inverse of that patch.
//
// In either scenario, we want to apply the inverse of the patch we are applying, to the
// uncommitted work. Whatever we "add" to the authDoc we "remove" from the uncommittedWork.
//
Common.assert(patch.parentHash === realtime.uncommitted.parentHash);
realtime.uncommitted = Patch.merge(inversePatch(patch), realtime.uncommitted);
} else {
// It's someone else's patch which was received, we need to *transform* out uncommitted
// work over their patch in order to preserve intent as much as possible.
//debug(realtime, "Transforming patch " + JSON.stringify(realtime.uncommitted.operations));
realtime.uncommitted = Patch.transform(
realtime.uncommitted,
patch,
realtime.authDoc,
realtime.config.patchTransformer
);
//debug(realtime, "By " + JSON.stringify(patch.operations) +
// "\nResult " + JSON.stringify(realtime.uncommitted.operations));
if (realtime.config.validateContent) {
newAuthDoc = Patch.apply(patch, realtime.authDoc);
var userDoc = Patch.apply(realtime.uncommitted, newAuthDoc);
if (!realtime.config.validateContent(userDoc)) {
warn(realtime, "Transformed patch is not valid");
// big hammer
realtime.uncommitted = Patch.create(Sha.hex_sha256(realtime.authDoc));
}
}
}
Common.assert(realtime.uncommitted.parentHash === inversePatch(patch).parentHash);
realtime.authDoc = newAuthDoc || Patch.apply(patch, realtime.authDoc);
if (Common.PARANOIA) {
Common.assert(realtime.uncommitted.parentHash === inversePatch(patch).parentHash);
Common.assert(Sha.hex_sha256(realtime.authDoc) === realtime.uncommitted.parentHash);
realtime.userInterfaceContent = Patch.apply(realtime.uncommitted, realtime.authDoc);
}
};
var revertPatch = function (realtime, isFromMe, patch) {
applyPatch(realtime, isFromMe, inversePatch(patch));
};
var getBestChild = function (realtime, msg) {
var best = msg;
(realtime.messagesByParent[msg.hashOf] || []).forEach(function (child) {
Common.assert(child.lastMsgHash === msg.hashOf);
child = getBestChild(realtime, child);
if (parentCount(realtime, child) > parentCount(realtime, best)) { best = child; }
});
return best;
};
var pushUIPatch = function (realtime, patch) {
if (!patch.operations.length) { return; }
// push the uncommittedPatch out to the user interface.
realtime.patchHandlers.forEach(function (handler) { handler(patch); });
realtime.changeHandlers.forEach(function (handler) {
patch.operations.forEach(function (op) {
handler(op.offset, op.toRemove, op.toInsert);
});
});
};
var validContent = function (realtime, contentGetter) {
try {
return realtime.config.validateContent(contentGetter());
} catch (e) {
warn(realtime, "Error in content validator [" + e.stack + "]");
}
return false;
};
var forEachParent = function (realtime, patch, callback) {
for (var m = getParent(realtime, patch); m; m = getParent(realtime, m)) {
if (callback(m) === false) { return; }
}
};
var mkInverse = function (patch, content) {
if (patch.mut.inverseOf) { return; }
var inverse = patch.mut.inverseOf = Patch.invert(patch, content);
inverse.mut.inverseOf = patch;
};
var handleMessage = function (realtime, msgStr, isFromMe) {
if (Common.PARANOIA) { check(realtime); }
var msg = Message.fromString(msgStr);
msg.mut.recvOrder = realtime.recvCounter++;
debug(realtime, JSON.stringify([msg.hashOf, msg.content.operations]));
if (realtime.messages[msg.hashOf]) {
if (realtime.setContentPatch && realtime.setContentPatch.hashOf === msg.hashOf) {
// We got the initial state patch, channel already has a pad, no need to send it.
realtime.setContentPatch = null;
} else {
msg.mut.status = "duplicate";
realtime.rejectedBlocks.push(msg);
if (msg.content.isCheckpoint) {
debug(realtime, "[" +
(isFromMe ? "our" : "their") +
"] Checkpoint [" + msg.hashOf + "] is already known");
return true;
}
debug(realtime, "Patch [" + msg.hashOf + "] is already known");
}
if (Common.PARANOIA) { check(realtime); }
return;
}
if (msg.content.isCheckpoint &&
!validContent(realtime, function () { return msg.content.operations[0].toInsert; }))
{
// If it's not a checkpoint, we verify it later on...
debug(realtime, "Checkpoint [" + msg.hashOf + "] failed content validation");
msg.mut.status = "failed_content_validation";
realtime.rejectedBlocks.push(msg);
return;
}
storeMessage(realtime, msg);
if (!isAncestorOf(realtime, realtime.rootMessage, msg)) {
if (msg.content.isCheckpoint && realtime.best.mut.isInitialMessage) {
// We're starting with a trucated chain from a checkpoint, we will adopt this
// as the root message and go with it...
debug(realtime, 'applying checkpoint [' + msg.hashOf + ']');
var userDoc = Patch.apply(realtime.uncommitted, realtime.authDoc);
Common.assert(!Common.PARANOIA || realtime.userInterfaceContent === userDoc);
var fixUserDocPatch = Patch.invert(realtime.uncommitted, realtime.authDoc);
Patch.addOperation(fixUserDocPatch,
Operation.create(0, realtime.authDoc.length, msg.content.operations[0].toInsert));
fixUserDocPatch =
Patch.simplify(fixUserDocPatch, userDoc, realtime.config.operationSimplify);
msg.mut.parentCount = 0;
realtime.rootMessage = realtime.best = msg;
realtime.authDoc = msg.content.operations[0].toInsert;
realtime.uncommitted = Patch.create(Sha.hex_sha256(realtime.authDoc));
pushUIPatch(realtime, fixUserDocPatch);
if (Common.PARANOIA) { realtime.userInterfaceContent = realtime.authDoc; }
return true;
} else {
// we'll probably find the missing parent later.
debug(realtime, "Patch [" + msg.hashOf + "] not connected to root (parent: [" +
msg.lastMsgHash + "])");
if (Common.PARANOIA) { check(realtime); }
return;
}
}
// of this message fills in a hole in the chain which makes another patch better, swap to the
// best child of this patch since longest chain always wins.
msg = getBestChild(realtime, msg);
msg.mut.isFromMe = isFromMe;
var patch = msg.content;
// Find the ancestor of this patch which is in the main chain, reverting as necessary
var toRevert = [];
var commonAncestor = realtime.best;
if (!isAncestorOf(realtime, realtime.best, msg)) {
var pcBest = parentCount(realtime, realtime.best);
var pcMsg = parentCount(realtime, msg);
if (pcBest < pcMsg
|| (pcBest === pcMsg
&& Common.strcmp(realtime.best.hashOf, msg.hashOf) > 0))
{
// switch chains
while (commonAncestor && !isAncestorOf(realtime, commonAncestor, msg)) {
toRevert.push(commonAncestor);
commonAncestor = getParent(realtime, commonAncestor);
}
Common.assert(commonAncestor);
debug(realtime, "Patch [" + msg.hashOf + "] better than best chain, switching");
} else {
debug(realtime, "Patch [" + msg.hashOf + "] chain is [" + pcMsg + "] best chain is [" +
pcBest + "]");
if (Common.PARANOIA) { check(realtime); }
return true;
}
}
// Find the parents of this patch which are not in the main chain.
var toApply = [];
var current = msg;
do {
toApply.unshift(current);
current = getParent(realtime, current);
Common.assert(current);
} while (current !== commonAncestor);
var authDocAtTimeOfPatch = realtime.authDoc;
toRevert.forEach(function (tr) {
authDocAtTimeOfPatch = Patch.apply(inversePatch(tr.content), authDocAtTimeOfPatch);
});
toApply.forEach(function (ta, i) {
// toApply.length-1 because we do not want to apply the new patch.
if (i === toApply.length - 1) { return; }
mkInverse(ta.content, authDocAtTimeOfPatch);
authDocAtTimeOfPatch = Patch.apply(ta.content, authDocAtTimeOfPatch);
});
var headAtTimeOfPatch = realtime.best;
if (toApply.length > 1) {
headAtTimeOfPatch = toApply[toApply.length-2];
Common.assert(headAtTimeOfPatch);
} else if (toRevert.length) {
headAtTimeOfPatch = getParent(realtime, toRevert[toRevert.length-1]);
Common.assert(headAtTimeOfPatch);
}
Common.assert(inversePatch(headAtTimeOfPatch.content).parentHash);
Common.assert(!Common.PARANOIA ||
inversePatch(headAtTimeOfPatch.content).parentHash ===
Sha.hex_sha256(authDocAtTimeOfPatch));
if (inversePatch(headAtTimeOfPatch.content).parentHash !== patch.parentHash) {
debug(realtime, "patch [" + msg.hashOf + "] parentHash is not valid");
if (Common.PARANOIA) { check(realtime); }
if (Common.TESTING) { throw new Error(); }
forgetMessage(realtime, msg, "parent_hash_invalid");
return;
}
if (patch.isCheckpoint && realtime.config.noPrune) {
// do nothing, just fall through
} else if (patch.isCheckpoint) {
// Ok, we have a checkpoint patch.
// If the chain length is not equal to checkpointInterval then this patch is invalid.
var checkpointP;
forEachParent(realtime, msg, function (m) {
if (m.content.isCheckpoint) {
if (checkpointP) {
checkpointP = m;
return false;
}
checkpointP = m;
}
});
if (checkpointP && checkpointP !== realtime.rootMessage) {
var point = parentCount(realtime, checkpointP);
if (realtime.config.strictCheckpointValidation &&
(point % realtime.config.checkpointInterval) !== 0)
{
debug(realtime, "checkpoint [" + msg.hashOf + "] at invalid point [" + point + "]");
if (Common.PARANOIA) { check(realtime); }
if (Common.TESTING) { throw new Error(); }
forgetMessage(realtime, msg, "checkpoint_wrong_parentcount");
return;
}
// Time to prune some old messages from the chain
debug(realtime, "checkpoint [" + msg.hashOf + "]");
forEachParent(realtime, checkpointP, function (m) {
debug(realtime, "pruning [" + m.hashOf + "]");
forgetMessage(realtime, m);
});
realtime.rootMessage = checkpointP;
}
} else {
var simplePatch =
Patch.simplify(patch, authDocAtTimeOfPatch, realtime.config.operationSimplify);
if (!Patch.equals(simplePatch, patch)) {
debug(realtime, "patch [" + msg.hashOf + "] can be simplified");
if (Common.PARANOIA) { check(realtime); }
if (Common.TESTING) { throw new Error(); }
forgetMessage(realtime, msg, "can_be_simplified");
return;
}
if (!validContent(realtime,
function () { return Patch.apply(patch, authDocAtTimeOfPatch); }))
{
debug(realtime, "Patch [" + msg.hashOf + "] failed content validation");
return;
}
}
mkInverse(patch, authDocAtTimeOfPatch);
realtime.uncommitted = Patch.simplify(
realtime.uncommitted, realtime.authDoc, realtime.config.operationSimplify);
var oldUserInterfaceContent = Patch.apply(realtime.uncommitted, realtime.authDoc);
if (Common.PARANOIA) {
Common.assert(oldUserInterfaceContent === realtime.userInterfaceContent);
}
// Derive the patch for the user's uncommitted work
var uncommittedPatch = Patch.invert(realtime.uncommitted, realtime.authDoc);
toRevert.forEach(function (tr) {
debug(realtime, "reverting [" + tr.hashOf + "]");
if (tr.mut.isFromMe) {
debug(realtime, "reverting patch 'from me' [" + JSON.stringify(tr.content.operations) + "]");
}
uncommittedPatch = Patch.merge(uncommittedPatch, inversePatch(tr.content));
revertPatch(realtime, tr.mut.isFromMe, tr.content);
});
toApply.forEach(function (ta) {
debug(realtime, "applying [" + ta.hashOf + "]");
uncommittedPatch = Patch.merge(uncommittedPatch, ta.content);
applyPatch(realtime, ta.mut.isFromMe, ta.content);
});
uncommittedPatch = Patch.merge(uncommittedPatch, realtime.uncommitted);
uncommittedPatch = Patch.simplify(
uncommittedPatch, oldUserInterfaceContent, realtime.config.operationSimplify);
realtime.best = msg;
if (Common.PARANOIA) {
// apply the uncommittedPatch to the userInterface content.
var newUserInterfaceContent = Patch.apply(uncommittedPatch, oldUserInterfaceContent);
Common.assert(realtime.userInterfaceContent.length === uncommittedDocLength(realtime));
Common.assert(newUserInterfaceContent === realtime.userInterfaceContent);
}
pushUIPatch(realtime, uncommittedPatch);
if (!realtime.uncommitted.operations.length) {
settle(realtime);
}
if (Common.PARANOIA) { check(realtime); }
return true;
};
var getDepthOfState = function (content, minDepth, realtime) {
Common.assert(typeof(content) === 'string');
// minimum depth is an optional argument which defaults to zero
minDepth = minDepth || 0;
if (minDepth === 0 && realtime.authDoc === content) {
return 0;
}
var hash = Sha.hex_sha256(content);
var patchMsg = realtime.best;
var depth = 0;
do {
if (depth < minDepth) {
// you haven't exceeded the minimum depth
} else {
//console.log("Exceeded minimum depth");
// you *have* exceeded the minimum depth
if (patchMsg.content.parentHash === hash) {
// you found it!
return depth + 1;
}
}
depth++;
} while ((patchMsg = getParent(realtime, patchMsg)));
return -1;
};
var getContentAtState = function (realtime, msg) {
var patches = [ msg ];
while (patches[0] !== realtime.rootMessage) {
var parent = getParent(realtime, patches[0]);
if (!parent) {
return { error: 'not connected to root', doc: undefined };
}
patches.unshift(parent);
}
var doc = '';
if (realtime.rootMessage.content.operations.length) {
Common.assert(realtime.rootMessage.content.operations.length === 1);
doc = realtime.rootMessage.content.operations[0].toInsert;
}
for (var i = 1; i < patches.length; i++) {
doc = Patch.apply(patches[i].content, doc);
}
return { error: undefined, doc: doc };
};
/*::
import type { Message_Status_t } from './Message.js';
export type ChainPad_BlockContent_t = {
error: ?string,
doc: ?string
};
export type ChainPad_Block_t = {
type: 'Block',
hashOf: string,
lastMsgHash: string,
isCheckpoint: boolean,
status: Message_Status_t,
recvOrder: number,
parentCount: number,
getParent: ()=>?ChainPad_Block_t,
getChildren: ()=>Array<ChainPad_Block_t>,
getContent: ()=>{
error: ?string,
doc: ?string
},
getPatch: ()=>Patch_t,
getInversePatch: ()=>Patch_t,
equals: (?ChainPad_Block_t, ?any)=>boolean
};
*/
var wrapMessage = function (realtime, msg) /*:ChainPad_Block_t*/ {
var pc = -1;
try { pc = parentCount(realtime, msg); } catch (e) { }
return Object.freeze({
type: 'Block',
hashOf: msg.hashOf,
lastMsgHash: msg.lastMsgHash,
isCheckpoint: !!msg.content.isCheckpoint,
status: msg.mut.status,
recvOrder: msg.mut.recvOrder,
parentCount: pc,
getParent: function () {
var parentMsg = getParent(realtime, msg);
if (parentMsg) { return wrapMessage(realtime, parentMsg); }
},
getChildren: function () {
return (realtime.messagesByParent[msg.hashOf] || []).map(function (x) {
return wrapMessage(realtime, x);
});
},
getContent: function () { return getContentAtState(realtime, msg); },
getPatch: function () { return Patch.clone(msg.content); },
getInversePatch: function () { return Patch.clone(inversePatch(msg.content)); },
equals: function (block, msgOpt) {
if (msgOpt) { return msg === msgOpt; }
if (!block || typeof(block) !== 'object' || block.type !== 'Block') { return false; }
return block.equals(block, msg);
}
});
};
var mkConfig = function (config) {
config = config || {};
if (config.transformFunction) {
throw new Error("chainpad config transformFunction is nolonger used");
}
return Object.freeze({
initialState: config.initialState || '',
checkpointInterval: config.checkpointInterval || DEFAULT_CHECKPOINT_INTERVAL,
avgSyncMilliseconds: config.avgSyncMilliseconds || DEFAULT_AVERAGE_SYNC_MILLISECONDS,
strictCheckpointValidation: config.strictCheckpointValidation ||
DEFAULT_STRICT_CHECKPOINT_VALIDATION,
operationSimplify: config.operationSimplify || Operation.simplify,
logLevel: (typeof(config.logLevel) === 'number') ? config.logLevel : 2,
noPrune: config.noPrune,
patchTransformer: config.patchTransformer || TextTransformer,
userName: config.userName || 'anonymous',
validateContent: config.validateContent || function (x) { x = x; return true; },
diffFunction: config.diffFunction ||
function (strA, strB /*:string*/) {
return Diff.diff(strA, strB, config.diffBlockSize);
},
});
};
/*::
import type { Operation_Transform_t } from './Operation';
import type { Operation_Simplify_t } from './Operation';
import type { Operation_t } from './Operation';
import type { Patch_t } from './Patch';
import type { Patch_Transform_t } from './Patch';
export type ChainPad_Config_t = {
initialState?: string,
checkpointInterval?: number,
avgSyncMilliseconds?: number,
validateContent?: (string)=>boolean,
strictCheckpointValidation?: boolean,
patchTransformer?: Patch_Transform_t,
operationSimplify?: Operation_Simplify_t,
logLevel?: number,
userName?: string,
noPrune?: boolean,
diffFunction?: (string, string)=>Array<Operation_t>,
diffBlockSize?: number
};
*/
module.exports.create = function (conf /*:ChainPad_Config_t*/) {
var realtime = create(mkConfig(conf));
var out = {
onPatch: function (handler /*:(Patch_t)=>void*/) {
Common.assert(typeof(handler) === 'function');
realtime.patchHandlers.push(handler);
},
patch: function (patch /*:Patch_t|number*/, x /*:?number*/, y /*:?string*/) {
if (typeof(patch) === 'number') {
// Actually they meant to call realtime.change()
if (typeof(x) !== 'number' || typeof(y) !== 'string') { throw new Error(); }
out.change(patch, x, y);
return;
}
doPatch(realtime, patch);
},
onChange: function (handler /*:(number, number, string)=>void*/) {
Common.assert(typeof(handler) === 'function');
realtime.changeHandlers.push(handler);
},
change: function (offset /*:number*/, count /*:number*/, chars /*:string*/) {
if (count === 0 && chars === '') { return; }
doOperation(realtime, Operation.create(offset, count, chars));
},
contentUpdate: function (newContent /*:string*/) {
var ops = realtime.config.diffFunction(realtime.authDoc, newContent);
var uncommitted = Patch.create(realtime.uncommitted.parentHash);
Array.prototype.push.apply(uncommitted.operations, ops);
realtime.uncommitted = uncommitted;
},
onMessage: function (handler /*:(string, ()=>void)=>void*/) {
Common.assert(typeof(handler) === 'function');
realtime.messageHandlers.push(handler);
},
message: function (message /*:string*/) {
handleMessage(realtime, message, false);
},
/// Control functions
start: function () {
realtime.aborted = false;
if (realtime.syncSchedule) { unschedule(realtime, realtime.syncSchedule); }
realtime.pending = null;
realtime.syncSchedule = schedule(realtime, function () { sync(realtime); });
},
abort: function () {
realtime.aborted = true;
realtime.schedules.forEach(function (s) { clearTimeout(s); });
},
sync: function () {
sync(realtime);
},
getAuthDoc: function () { return realtime.authDoc; },
getUserDoc: function () { return Patch.apply(realtime.uncommitted, realtime.authDoc); },
getDepthOfState: function (content /*:string*/, minDepth /*:?number*/) {
return getDepthOfState(content, minDepth, realtime);
},
onSettle: function (handler /*:()=>void*/) {
Common.assert(typeof(handler) === 'function');
realtime.onSettle.push(handler);
},
getAuthBlock: function () {
return wrapMessage(realtime, realtime.best);
},
getBlockForHash: function (hash /*:string*/) {
Common.assert(typeof(hash) === 'string');
var msg = realtime.messages[hash];
if (msg) { return wrapMessage(realtime, msg); }
},
getBlockHashes: function () {
return Object.keys(realtime.messages);
},
getRootBlock: function () {
return wrapMessage(realtime, realtime.rootMessage);
},
getRejectedBlock: function (number /*:number*/) {
var msg = realtime.rejectedBlocks[number];
return msg ? wrapMessage(realtime, msg) : undefined;
},
getLag: function () {
var isPending = !!realtime.pending;
var lag = realtime.lag;
if (realtime.pending) { lag = +new Date() - realtime.timeOfLastSuccess; }
return {
pending: isPending,
lag: lag,
active: (!realtime.aborted && realtime.syncSchedule !== -2)
};
},
_: undefined
};
out._ = realtime;
return Object.freeze(out);
};
Object.freeze(module.exports);
},
"Operation.js": function(module, exports, require){
/*@flow*/
/*
* Copyright 2014 XWiki SAS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
"use strict";
var Common = require('./Common');
var Operation = module.exports;
/*::
export type Operation_t = {
type: 'Operation',
offset: number,
toRemove: number,
toInsert: string
};
export type Operation_Packed_t = [number, number, string];
export type Operation_Simplify_t = (Operation_t, string, typeof(Operation.simplify))=>?Operation_t;
export type Operation_Transform_t = (string, Operation_t, Operation_t)=>?Operation_t;
*/
var check = Operation.check = function (op /*:any*/, docLength_opt /*:?number*/) /*:Operation_t*/ {
Common.assert(op.type === 'Operation');
if (!Common.isUint(op.offset)) { throw new Error(); }
if (!Common.isUint(op.toRemove)) { throw new Error(); }
if (typeof(op.toInsert) !== 'string') { throw new Error(); }
if (op.toRemove < 1 && op.toInsert.length < 1) { throw new Error(); }
Common.assert(typeof(docLength_opt) !== 'number' || op.offset + op.toRemove <= docLength_opt);
return op;
};
var create = Operation.create = function (
offset /*:?number*/,
toRemove /*:?number*/,
toInsert /*:?string*/)
{
var out = {
type: 'Operation',
offset: offset || 0,
toRemove: toRemove || 0,
toInsert: toInsert || '',
};
if (Common.PARANOIA) { check(out); }
return Object.freeze(out);
};
Operation.toObj = function (op /*:Operation_t*/) {
if (Common.PARANOIA) { check(op); }
return [op.offset,op.toRemove,op.toInsert];
};
// Allow any as input because we assert its type internally..
Operation.fromObj = function (obj /*:any*/) {
Common.assert(Array.isArray(obj) && obj.length === 3);
return create(obj[0], obj[1], obj[2]);
};
/**
* @param op the operation to apply.
* @param doc the content to apply the operation on
*/
var apply = Operation.apply = function (op /*:Operation_t*/, doc /*:string*/)
{
if (Common.PARANOIA) {
Common.assert(typeof(doc) === 'string');
check(op, doc.length);
}
return doc.substring(0,op.offset) + op.toInsert + doc.substring(op.offset + op.toRemove);
};
Operation.applyMulti = function (ops /*:Array<Operation_t>*/, doc /*:string*/)
{
for (var i = ops.length - 1; i >= 0; i--) { doc = apply(ops[i], doc); }
return doc;
};
var invert = Operation.invert = function (op /*:Operation_t*/, doc /*:string*/) {
if (Common.PARANOIA) {
check(op);
Common.assert(typeof(doc) === 'string');
Common.assert(op.offset + op.toRemove <= doc.length);
}
return create(
op.offset,
op.toInsert.length,
doc.substring(op.offset, op.offset + op.toRemove)
);
};
// see http://unicode.org/faq/utf_bom.html#utf16-7
var surrogatePattern = /[\uD800-\uDBFF]|[\uDC00-\uDFFF]/;
var hasSurrogate = Operation.hasSurrogate = function(str /*:string*/) {
return surrogatePattern.test(str);
};
/**
* ATTENTION: This function is not just a neat way to make patches smaller, it's
* actually part of the ChainPad consensus rules, so if you have a clever
* idea to make it a bit faster, it is going to cause ChainPad to reject
* old patches, which means when you go to load the history of a pad, you're
* sunk.
* tl;dr can't touch this
*/
Operation.simplify = function (op /*:Operation_t*/, doc /*:string*/) {
if (Common.PARANOIA) {
check(op);
Common.assert(typeof(doc) === 'string');
Common.assert(op.offset + op.toRemove <= doc.length);
}
var rop = invert(op, doc);
var minLen = Math.min(op.toInsert.length, rop.toInsert.length);
var i = 0;
while (i < minLen && rop.toInsert[i] === op.toInsert[i]) {
if (hasSurrogate(rop.toInsert[i]) || hasSurrogate(op.toInsert[i])) {
if (op.toInsert[i + 1] === rop.toInsert[i + 1]) {
i++;
} else {
break;
}
}
i++;
}
var opOffset = op.offset + i;
var opToRemove = op.toRemove - i;
var opToInsert = op.toInsert.substring(i);
var ropToInsert = rop.toInsert.substring(i);
if (ropToInsert.length === opToInsert.length) {
for (i = ropToInsert.length-1; i >= 0 && ropToInsert[i] === opToInsert[i]; i--) ;
opToInsert = opToInsert.substring(0, i+1);
opToRemove = i+1;
}
if (opToRemove === 0 && opToInsert.length === 0) { return null; }
return create(opOffset, opToRemove, opToInsert);
};
Operation.equals = function (opA /*:Operation_t*/, opB /*:Operation_t*/) {
return (opA.toRemove === opB.toRemove
&& opA.toInsert === opB.toInsert
&& opA.offset === opB.offset);
};
Operation.lengthChange = function (op /*:Operation_t*/)
{
if (Common.PARANOIA) { check(op); }
return op.toInsert.length - op.toRemove;
};
/*
* @return the merged operation OR null if the result of the merger is a noop.
*/
Operation.merge = function (oldOpOrig /*:Operation_t*/, newOpOrig /*:Operation_t*/) {
if (Common.PARANOIA) {
check(newOpOrig);
check(oldOpOrig);
}
var oldOp_offset = oldOpOrig.offset;
var oldOp_toRemove = oldOpOrig.toRemove;
var oldOp_toInsert = oldOpOrig.toInsert;
var newOp_offset = newOpOrig.offset;
var newOp_toRemove = newOpOrig.toRemove;
var newOp_toInsert = newOpOrig.toInsert;
var offsetDiff = newOp_offset - oldOp_offset;
if (newOp_toRemove > 0) {
var origOldInsert = oldOp_toInsert;
oldOp_toInsert = (
oldOp_toInsert.substring(0,offsetDiff)
+ oldOp_toInsert.substring(offsetDiff + newOp_toRemove)
);
newOp_toRemove -= (origOldInsert.length - oldOp_toInsert.length);
if (newOp_toRemove < 0) { newOp_toRemove = 0; }
oldOp_toRemove += newOp_toRemove;
newOp_toRemove = 0;
}
if (offsetDiff < 0) {
oldOp_offset += offsetDiff;
oldOp_toInsert = newOp_toInsert + oldOp_toInsert;
} else if (oldOp_toInsert.length === offsetDiff) {
oldOp_toInsert = oldOp_toInsert + newOp_toInsert;
} else if (oldOp_toInsert.length > offsetDiff) {
oldOp_toInsert = (
oldOp_toInsert.substring(0,offsetDiff)
+ newOp_toInsert
+ oldOp_toInsert.substring(offsetDiff)
);
} else {
throw new Error("should never happen\n" +
JSON.stringify([oldOpOrig,newOpOrig], null, ' '));
}
if (oldOp_toInsert === '' && oldOp_toRemove === 0) { return null; }
return create(oldOp_offset, oldOp_toRemove, oldOp_toInsert);
};
/**
* If the new operation deletes what the old op inserted or inserts content in the middle of
* the old op's content or if they abbut one another, they should be merged.
*/
Operation.shouldMerge = function (oldOp /*:Operation_t*/, newOp /*:Operation_t*/)
{
if (Common.PARANOIA) {
check(oldOp);
check(newOp);
}
if (newOp.offset < oldOp.offset) {
return (oldOp.offset <= (newOp.offset + newOp.toRemove));
} else {
return (newOp.offset <= (oldOp.offset + oldOp.toInsert.length));
}
};
/**
* Rebase newOp against oldOp.
*
* @param oldOp the eariler operation to have happened.
* @param newOp the later operation to have happened (in time).
* @return either the untouched newOp if it need not be rebased,
* the rebased clone of newOp if it needs rebasing, or
* null if newOp and oldOp must be merged.
*/
Operation.rebase = function (oldOp /*:Operation_t*/, newOp /*:Operation_t*/) {
if (Common.PARANOIA) {
check(oldOp);
check(newOp);
}
if (newOp.offset < oldOp.offset) { return newOp; }
return create(
newOp.offset + oldOp.toRemove - oldOp.toInsert.length,
newOp.toRemove,
newOp.toInsert
);
};
/** Used for testing. */
Operation.random = function (docLength /*:number*/) {
Common.assert(Common.isUint(docLength));
var offset = Math.floor(Math.random() * 100000000 % docLength) || 0;
var toRemove = Math.floor(Math.random() * 100000000 % (docLength - offset)) || 0;
var toInsert = '';
do {
toInsert = Common.randomASCII(Math.floor(Math.random() * 20));
} while (toRemove === 0 && toInsert === '');
return create(offset, toRemove, toInsert);
};
Object.freeze(module.exports);
},
"sha256/hash.js": function(module, exports, require){
var Utils = require('./utils.js');
function hash_reset () {
this.result = null;
this.pos = 0;
this.len = 0;
this.asm.reset();
return this;
}
function hash_process ( data ) {
if ( this.result !== null )
throw new IllegalStateError("state must be reset before processing new data");
if ( Utils.is_string(data) )
data = Utils.string_to_bytes(data);
if ( Utils.is_buffer(data) )
data = new Uint8Array(data);
if ( !Utils.is_bytes(data) )
throw new TypeError("data isn't of expected type");
var asm = this.asm,
heap = this.heap,
hpos = this.pos,
hlen = this.len,
dpos = 0,
dlen = data.length,
wlen = 0;
while ( dlen > 0 ) {
wlen = Utils._heap_write( heap, hpos+hlen, data, dpos, dlen );
hlen += wlen;
dpos += wlen;
dlen -= wlen;
wlen = asm.process( hpos, hlen );
hpos += wlen;
hlen -= wlen;
if ( !hlen ) hpos = 0;
}
this.pos = hpos;
this.len = hlen;
return this;
}
function hash_finish () {
if ( this.result !== null )
throw new IllegalStateError("state must be reset before processing new data");
this.asm.finish( this.pos, this.len, 0 );
this.result = new Uint8Array(this.HASH_SIZE);
this.result.set( this.heap.subarray( 0, this.HASH_SIZE ) );
this.pos = 0;
this.len = 0;
return this;
}
module.exports.hash_reset = hash_reset;
module.exports.hash_process = hash_process;
module.exports.hash_finish = hash_finish;
},
"sha256/utils.js": function(module, exports, require){
//var FloatArray = global.Float64Array || global.Float32Array; // make PhantomJS happy
var string_to_bytes = module.exports.string_to_bytes = function( str, utf8 ) {
utf8 = !!utf8;
var len = str.length,
bytes = new Uint8Array( utf8 ? 4*len : len );
for ( var i = 0, j = 0; i < len; i++ ) {
var c = str.charCodeAt(i);
if ( utf8 && 0xd800 <= c && c <= 0xdbff ) {
if ( ++i >= len ) throw new Error( "Malformed string, low surrogate expected at position " + i );
c = ( (c ^ 0xd800) << 10 ) | 0x10000 | ( str.charCodeAt(i) ^ 0xdc00 );
}
else if ( !utf8 && c >>> 8 ) {
throw new Error("Wide characters are not allowed.");
}
if ( !utf8 || c <= 0x7f ) {
bytes[j++] = c;
}
else if ( c <= 0x7ff ) {
bytes[j++] = 0xc0 | (c >> 6);
bytes[j++] = 0x80 | (c & 0x3f);
}
else if ( c <= 0xffff ) {
bytes[j++] = 0xe0 | (c >> 12);
bytes[j++] = 0x80 | (c >> 6 & 0x3f);
bytes[j++] = 0x80 | (c & 0x3f);
}
else {
bytes[j++] = 0xf0 | (c >> 18);
bytes[j++] = 0x80 | (c >> 12 & 0x3f);
bytes[j++] = 0x80 | (c >> 6 & 0x3f);
bytes[j++] = 0x80 | (c & 0x3f);
}
}
return bytes.subarray(0, j);
};
var hex_to_bytes = module.exports.hex_to_bytes = function( str ) {
var len = str.length;
if ( len & 1 ) {
str = '0'+str;
len++;
}
var bytes = new Uint8Array(len>>1);
for ( var i = 0; i < len; i += 2 ) {
bytes[i>>1] = parseInt( str.substr( i, 2), 16 );
}
return bytes;
};
var base64_to_bytes = module.exports.base64_to_bytes = function( str ) {
return string_to_bytes( atob( str ) );
};
var bytes_to_string = module.exports.bytes_to_string = function( bytes, utf8 ) {
utf8 = !!utf8;
var len = bytes.length,
chars = new Array(len);
for ( var i = 0, j = 0; i < len; i++ ) {
var b = bytes[i];
if ( !utf8 || b < 128 ) {
chars[j++] = b;
}
else if ( b >= 192 && b < 224 && i+1 < len ) {
chars[j++] = ( (b & 0x1f) << 6 ) | (bytes[++i] & 0x3f);
}
else if ( b >= 224 && b < 240 && i+2 < len ) {
chars[j++] = ( (b & 0xf) << 12 ) | ( (bytes[++i] & 0x3f) << 6 ) | (bytes[++i] & 0x3f);
}
else if ( b >= 240 && b < 248 && i+3 < len ) {
var c = ( (b & 7) << 18 ) | ( (bytes[++i] & 0x3f) << 12 ) | ( (bytes[++i] & 0x3f) << 6 ) | (bytes[++i] & 0x3f);
if ( c <= 0xffff ) {
chars[j++] = c;
}
else {
c ^= 0x10000;
chars[j++] = 0xd800 | (c >> 10);
chars[j++] = 0xdc00 | (c & 0x3ff);
}
}
else {
throw new Error("Malformed UTF8 character at byte offset " + i);
}
}
var str = '',
bs = 16384;
for ( var _i = 0; _i < j; _i += bs ) {
str += String.fromCharCode.apply( String, chars.slice( _i, _i+bs <= j ? _i+bs : j ) );
}
return str;
};
var bytes_to_hex = module.exports.bytes_to_hex = function( arr ) {
var str = '';
for ( var i = 0; i < arr.length; i++ ) {
var h = ( arr[i] & 0xff ).toString(16);
if ( h.length < 2 ) str += '0';
str += h;
}
return str;
};
var bytes_to_base64 = module.exports.bytes_to_base64 = function( arr ) {
return btoa( bytes_to_string(arr) );
};
var pow2_ceil = module.exports.pow2_ceil = function( a ) {
a -= 1;
a |= a >>> 1;
a |= a >>> 2;
a |= a >>> 4;
a |= a >>> 8;
a |= a >>> 16;
a += 1;
return a;
};
var is_number = module.exports.is_number = function( a ) {
return ( typeof a === 'number' );
};
var is_string = module.exports.is_string = function( a ) {
return ( typeof a === 'string' );
};
var is_buffer = module.exports.is_buffer = function( a ) {
return ( a instanceof ArrayBuffer );
};
var is_bytes = module.exports.is_bytes = function( a ) {
return ( a instanceof Uint8Array );
};
var is_typed_array = module.exports.is_typed_array = function( a ) {
return ( a instanceof Int8Array ) || ( a instanceof Uint8Array )
|| ( a instanceof Int16Array ) || ( a instanceof Uint16Array )
|| ( a instanceof Int32Array ) || ( a instanceof Uint32Array )
|| ( a instanceof Float32Array )
|| ( a instanceof Float64Array );
};
var _heap_init = module.exports._heap_init = function( constructor, options ) {
var heap = options.heap,
size = heap ? heap.byteLength : options.heapSize || 65536;
if ( size & 0xfff || size <= 0 )
throw new Error("heap size must be a positive integer and a multiple of 4096");
heap = heap || new constructor( new ArrayBuffer(size) );
return heap;
};
var _heap_write = module.exports._heap_write = function( heap, hpos, data, dpos, dlen ) {
var hlen = heap.length - hpos,
wlen = ( hlen < dlen ) ? hlen : dlen;
heap.set( data.subarray( dpos, dpos+wlen ), hpos );
return wlen;
};
},
"sha256/sha256.js": function(module, exports, require){
var Utils = require('./utils.js');
var Hash = require('./hash.js');
var Asm = require('./sha256.asm.js');
var _sha256_block_size = 64,
_sha256_hash_size = 32;
function sha256_constructor ( options ) {
options = options || {};
this.heap = Utils._heap_init( Uint8Array, options );
this.asm = options.asm || Asm.sha256_asm( { Uint8Array: Uint8Array }, null, this.heap.buffer );
this.BLOCK_SIZE = _sha256_block_size;
this.HASH_SIZE = _sha256_hash_size;
this.reset();
}
sha256_constructor.BLOCK_SIZE = _sha256_block_size;
sha256_constructor.HASH_SIZE = _sha256_hash_size;
var sha256_prototype = sha256_constructor.prototype;
sha256_prototype.reset = Hash.hash_reset;
sha256_prototype.process = Hash.hash_process;
sha256_prototype.finish = Hash.hash_finish;
var sha256_instance = null;
function get_sha256_instance () {
if ( sha256_instance === null ) sha256_instance = new sha256_constructor( { heapSize: 0x100000 } );
return sha256_instance;
}
module.exports.get_sha256_instance = get_sha256_instance;
module.exports.sha256_constructor = sha256_constructor;
},
"sha256/exports.js": function(module, exports, require){
var Sha256 = require('./sha256.js');
var Utils = require('./utils.js');
/**
* SHA256 exports
*/
function sha256_bytes ( data ) {
if ( data === undefined ) throw new SyntaxError("data required");
return Sha256.get_sha256_instance().reset().process(data).finish().result;
}
function sha256_hex ( data ) {
var result = sha256_bytes(data);
return Utils.bytes_to_hex(result);
}
function sha256_base64 ( data ) {
var result = sha256_bytes(data);
return Utils.bytes_to_base64(result);
}
Sha256.sha256_constructor.bytes = sha256_bytes;
Sha256.sha256_constructor.hex = sha256_hex;
Sha256.sha256_constructor.base64 = sha256_base64;
//exports.SHA256 = sha256_constructor;
module.exports = Sha256.sha256_constructor;
},
"sha256/sha256.asm.js": function(module, exports, require){
module.exports.sha256_asm = function sha256_asm ( stdlib, foreign, buffer ) {
"use asm";
// SHA256 state
var H0 = 0, H1 = 0, H2 = 0, H3 = 0, H4 = 0, H5 = 0, H6 = 0, H7 = 0,
TOTAL0 = 0, TOTAL1 = 0;
// HMAC state
var I0 = 0, I1 = 0, I2 = 0, I3 = 0, I4 = 0, I5 = 0, I6 = 0, I7 = 0,
O0 = 0, O1 = 0, O2 = 0, O3 = 0, O4 = 0, O5 = 0, O6 = 0, O7 = 0;
// I/O buffer
var HEAP = new stdlib.Uint8Array(buffer);
function _core ( w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15 ) {
w0 = w0|0;
w1 = w1|0;
w2 = w2|0;
w3 = w3|0;
w4 = w4|0;
w5 = w5|0;
w6 = w6|0;
w7 = w7|0;
w8 = w8|0;
w9 = w9|0;
w10 = w10|0;
w11 = w11|0;
w12 = w12|0;
w13 = w13|0;
w14 = w14|0;
w15 = w15|0;
var a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0,
t = 0;
a = H0;
b = H1;
c = H2;
d = H3;
e = H4;
f = H5;
g = H6;
h = H7;
// 0
t = ( w0 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x428a2f98 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 1
t = ( w1 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x71374491 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 2
t = ( w2 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xb5c0fbcf )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 3
t = ( w3 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xe9b5dba5 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 4
t = ( w4 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x3956c25b )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 5
t = ( w5 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x59f111f1 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 6
t = ( w6 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x923f82a4 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 7
t = ( w7 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xab1c5ed5 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 8
t = ( w8 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xd807aa98 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 9
t = ( w9 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x12835b01 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 10
t = ( w10 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x243185be )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 11
t = ( w11 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x550c7dc3 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 12
t = ( w12 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x72be5d74 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 13
t = ( w13 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x80deb1fe )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 14
t = ( w14 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x9bdc06a7 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 15
t = ( w15 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xc19bf174 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 16
w0 = t = ( ( w1>>>7 ^ w1>>>18 ^ w1>>>3 ^ w1<<25 ^ w1<<14 ) + ( w14>>>17 ^ w14>>>19 ^ w14>>>10 ^ w14<<15 ^ w14<<13 ) + w0 + w9 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xe49b69c1 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 17
w1 = t = ( ( w2>>>7 ^ w2>>>18 ^ w2>>>3 ^ w2<<25 ^ w2<<14 ) + ( w15>>>17 ^ w15>>>19 ^ w15>>>10 ^ w15<<15 ^ w15<<13 ) + w1 + w10 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xefbe4786 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 18
w2 = t = ( ( w3>>>7 ^ w3>>>18 ^ w3>>>3 ^ w3<<25 ^ w3<<14 ) + ( w0>>>17 ^ w0>>>19 ^ w0>>>10 ^ w0<<15 ^ w0<<13 ) + w2 + w11 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x0fc19dc6 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 19
w3 = t = ( ( w4>>>7 ^ w4>>>18 ^ w4>>>3 ^ w4<<25 ^ w4<<14 ) + ( w1>>>17 ^ w1>>>19 ^ w1>>>10 ^ w1<<15 ^ w1<<13 ) + w3 + w12 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x240ca1cc )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 20
w4 = t = ( ( w5>>>7 ^ w5>>>18 ^ w5>>>3 ^ w5<<25 ^ w5<<14 ) + ( w2>>>17 ^ w2>>>19 ^ w2>>>10 ^ w2<<15 ^ w2<<13 ) + w4 + w13 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x2de92c6f )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 21
w5 = t = ( ( w6>>>7 ^ w6>>>18 ^ w6>>>3 ^ w6<<25 ^ w6<<14 ) + ( w3>>>17 ^ w3>>>19 ^ w3>>>10 ^ w3<<15 ^ w3<<13 ) + w5 + w14 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x4a7484aa )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 22
w6 = t = ( ( w7>>>7 ^ w7>>>18 ^ w7>>>3 ^ w7<<25 ^ w7<<14 ) + ( w4>>>17 ^ w4>>>19 ^ w4>>>10 ^ w4<<15 ^ w4<<13 ) + w6 + w15 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x5cb0a9dc )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 23
w7 = t = ( ( w8>>>7 ^ w8>>>18 ^ w8>>>3 ^ w8<<25 ^ w8<<14 ) + ( w5>>>17 ^ w5>>>19 ^ w5>>>10 ^ w5<<15 ^ w5<<13 ) + w7 + w0 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x76f988da )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 24
w8 = t = ( ( w9>>>7 ^ w9>>>18 ^ w9>>>3 ^ w9<<25 ^ w9<<14 ) + ( w6>>>17 ^ w6>>>19 ^ w6>>>10 ^ w6<<15 ^ w6<<13 ) + w8 + w1 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x983e5152 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 25
w9 = t = ( ( w10>>>7 ^ w10>>>18 ^ w10>>>3 ^ w10<<25 ^ w10<<14 ) + ( w7>>>17 ^ w7>>>19 ^ w7>>>10 ^ w7<<15 ^ w7<<13 ) + w9 + w2 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xa831c66d )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 26
w10 = t = ( ( w11>>>7 ^ w11>>>18 ^ w11>>>3 ^ w11<<25 ^ w11<<14 ) + ( w8>>>17 ^ w8>>>19 ^ w8>>>10 ^ w8<<15 ^ w8<<13 ) + w10 + w3 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xb00327c8 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 27
w11 = t = ( ( w12>>>7 ^ w12>>>18 ^ w12>>>3 ^ w12<<25 ^ w12<<14 ) + ( w9>>>17 ^ w9>>>19 ^ w9>>>10 ^ w9<<15 ^ w9<<13 ) + w11 + w4 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xbf597fc7 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 28
w12 = t = ( ( w13>>>7 ^ w13>>>18 ^ w13>>>3 ^ w13<<25 ^ w13<<14 ) + ( w10>>>17 ^ w10>>>19 ^ w10>>>10 ^ w10<<15 ^ w10<<13 ) + w12 + w5 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xc6e00bf3 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 29
w13 = t = ( ( w14>>>7 ^ w14>>>18 ^ w14>>>3 ^ w14<<25 ^ w14<<14 ) + ( w11>>>17 ^ w11>>>19 ^ w11>>>10 ^ w11<<15 ^ w11<<13 ) + w13 + w6 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xd5a79147 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 30
w14 = t = ( ( w15>>>7 ^ w15>>>18 ^ w15>>>3 ^ w15<<25 ^ w15<<14 ) + ( w12>>>17 ^ w12>>>19 ^ w12>>>10 ^ w12<<15 ^ w12<<13 ) + w14 + w7 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x06ca6351 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 31
w15 = t = ( ( w0>>>7 ^ w0>>>18 ^ w0>>>3 ^ w0<<25 ^ w0<<14 ) + ( w13>>>17 ^ w13>>>19 ^ w13>>>10 ^ w13<<15 ^ w13<<13 ) + w15 + w8 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x14292967 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 32
w0 = t = ( ( w1>>>7 ^ w1>>>18 ^ w1>>>3 ^ w1<<25 ^ w1<<14 ) + ( w14>>>17 ^ w14>>>19 ^ w14>>>10 ^ w14<<15 ^ w14<<13 ) + w0 + w9 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x27b70a85 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 33
w1 = t = ( ( w2>>>7 ^ w2>>>18 ^ w2>>>3 ^ w2<<25 ^ w2<<14 ) + ( w15>>>17 ^ w15>>>19 ^ w15>>>10 ^ w15<<15 ^ w15<<13 ) + w1 + w10 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x2e1b2138 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 34
w2 = t = ( ( w3>>>7 ^ w3>>>18 ^ w3>>>3 ^ w3<<25 ^ w3<<14 ) + ( w0>>>17 ^ w0>>>19 ^ w0>>>10 ^ w0<<15 ^ w0<<13 ) + w2 + w11 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x4d2c6dfc )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 35
w3 = t = ( ( w4>>>7 ^ w4>>>18 ^ w4>>>3 ^ w4<<25 ^ w4<<14 ) + ( w1>>>17 ^ w1>>>19 ^ w1>>>10 ^ w1<<15 ^ w1<<13 ) + w3 + w12 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x53380d13 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 36
w4 = t = ( ( w5>>>7 ^ w5>>>18 ^ w5>>>3 ^ w5<<25 ^ w5<<14 ) + ( w2>>>17 ^ w2>>>19 ^ w2>>>10 ^ w2<<15 ^ w2<<13 ) + w4 + w13 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x650a7354 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 37
w5 = t = ( ( w6>>>7 ^ w6>>>18 ^ w6>>>3 ^ w6<<25 ^ w6<<14 ) + ( w3>>>17 ^ w3>>>19 ^ w3>>>10 ^ w3<<15 ^ w3<<13 ) + w5 + w14 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x766a0abb )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 38
w6 = t = ( ( w7>>>7 ^ w7>>>18 ^ w7>>>3 ^ w7<<25 ^ w7<<14 ) + ( w4>>>17 ^ w4>>>19 ^ w4>>>10 ^ w4<<15 ^ w4<<13 ) + w6 + w15 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x81c2c92e )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 39
w7 = t = ( ( w8>>>7 ^ w8>>>18 ^ w8>>>3 ^ w8<<25 ^ w8<<14 ) + ( w5>>>17 ^ w5>>>19 ^ w5>>>10 ^ w5<<15 ^ w5<<13 ) + w7 + w0 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x92722c85 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 40
w8 = t = ( ( w9>>>7 ^ w9>>>18 ^ w9>>>3 ^ w9<<25 ^ w9<<14 ) + ( w6>>>17 ^ w6>>>19 ^ w6>>>10 ^ w6<<15 ^ w6<<13 ) + w8 + w1 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xa2bfe8a1 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 41
w9 = t = ( ( w10>>>7 ^ w10>>>18 ^ w10>>>3 ^ w10<<25 ^ w10<<14 ) + ( w7>>>17 ^ w7>>>19 ^ w7>>>10 ^ w7<<15 ^ w7<<13 ) + w9 + w2 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xa81a664b )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 42
w10 = t = ( ( w11>>>7 ^ w11>>>18 ^ w11>>>3 ^ w11<<25 ^ w11<<14 ) + ( w8>>>17 ^ w8>>>19 ^ w8>>>10 ^ w8<<15 ^ w8<<13 ) + w10 + w3 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xc24b8b70 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 43
w11 = t = ( ( w12>>>7 ^ w12>>>18 ^ w12>>>3 ^ w12<<25 ^ w12<<14 ) + ( w9>>>17 ^ w9>>>19 ^ w9>>>10 ^ w9<<15 ^ w9<<13 ) + w11 + w4 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xc76c51a3 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 44
w12 = t = ( ( w13>>>7 ^ w13>>>18 ^ w13>>>3 ^ w13<<25 ^ w13<<14 ) + ( w10>>>17 ^ w10>>>19 ^ w10>>>10 ^ w10<<15 ^ w10<<13 ) + w12 + w5 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xd192e819 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 45
w13 = t = ( ( w14>>>7 ^ w14>>>18 ^ w14>>>3 ^ w14<<25 ^ w14<<14 ) + ( w11>>>17 ^ w11>>>19 ^ w11>>>10 ^ w11<<15 ^ w11<<13 ) + w13 + w6 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xd6990624 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 46
w14 = t = ( ( w15>>>7 ^ w15>>>18 ^ w15>>>3 ^ w15<<25 ^ w15<<14 ) + ( w12>>>17 ^ w12>>>19 ^ w12>>>10 ^ w12<<15 ^ w12<<13 ) + w14 + w7 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xf40e3585 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 47
w15 = t = ( ( w0>>>7 ^ w0>>>18 ^ w0>>>3 ^ w0<<25 ^ w0<<14 ) + ( w13>>>17 ^ w13>>>19 ^ w13>>>10 ^ w13<<15 ^ w13<<13 ) + w15 + w8 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x106aa070 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 48
w0 = t = ( ( w1>>>7 ^ w1>>>18 ^ w1>>>3 ^ w1<<25 ^ w1<<14 ) + ( w14>>>17 ^ w14>>>19 ^ w14>>>10 ^ w14<<15 ^ w14<<13 ) + w0 + w9 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x19a4c116 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 49
w1 = t = ( ( w2>>>7 ^ w2>>>18 ^ w2>>>3 ^ w2<<25 ^ w2<<14 ) + ( w15>>>17 ^ w15>>>19 ^ w15>>>10 ^ w15<<15 ^ w15<<13 ) + w1 + w10 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x1e376c08 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 50
w2 = t = ( ( w3>>>7 ^ w3>>>18 ^ w3>>>3 ^ w3<<25 ^ w3<<14 ) + ( w0>>>17 ^ w0>>>19 ^ w0>>>10 ^ w0<<15 ^ w0<<13 ) + w2 + w11 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x2748774c )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 51
w3 = t = ( ( w4>>>7 ^ w4>>>18 ^ w4>>>3 ^ w4<<25 ^ w4<<14 ) + ( w1>>>17 ^ w1>>>19 ^ w1>>>10 ^ w1<<15 ^ w1<<13 ) + w3 + w12 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x34b0bcb5 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 52
w4 = t = ( ( w5>>>7 ^ w5>>>18 ^ w5>>>3 ^ w5<<25 ^ w5<<14 ) + ( w2>>>17 ^ w2>>>19 ^ w2>>>10 ^ w2<<15 ^ w2<<13 ) + w4 + w13 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x391c0cb3 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 53
w5 = t = ( ( w6>>>7 ^ w6>>>18 ^ w6>>>3 ^ w6<<25 ^ w6<<14 ) + ( w3>>>17 ^ w3>>>19 ^ w3>>>10 ^ w3<<15 ^ w3<<13 ) + w5 + w14 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x4ed8aa4a )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 54
w6 = t = ( ( w7>>>7 ^ w7>>>18 ^ w7>>>3 ^ w7<<25 ^ w7<<14 ) + ( w4>>>17 ^ w4>>>19 ^ w4>>>10 ^ w4<<15 ^ w4<<13 ) + w6 + w15 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x5b9cca4f )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 55
w7 = t = ( ( w8>>>7 ^ w8>>>18 ^ w8>>>3 ^ w8<<25 ^ w8<<14 ) + ( w5>>>17 ^ w5>>>19 ^ w5>>>10 ^ w5<<15 ^ w5<<13 ) + w7 + w0 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x682e6ff3 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 56
w8 = t = ( ( w9>>>7 ^ w9>>>18 ^ w9>>>3 ^ w9<<25 ^ w9<<14 ) + ( w6>>>17 ^ w6>>>19 ^ w6>>>10 ^ w6<<15 ^ w6<<13 ) + w8 + w1 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x748f82ee )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 57
w9 = t = ( ( w10>>>7 ^ w10>>>18 ^ w10>>>3 ^ w10<<25 ^ w10<<14 ) + ( w7>>>17 ^ w7>>>19 ^ w7>>>10 ^ w7<<15 ^ w7<<13 ) + w9 + w2 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x78a5636f )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 58
w10 = t = ( ( w11>>>7 ^ w11>>>18 ^ w11>>>3 ^ w11<<25 ^ w11<<14 ) + ( w8>>>17 ^ w8>>>19 ^ w8>>>10 ^ w8<<15 ^ w8<<13 ) + w10 + w3 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x84c87814 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 59
w11 = t = ( ( w12>>>7 ^ w12>>>18 ^ w12>>>3 ^ w12<<25 ^ w12<<14 ) + ( w9>>>17 ^ w9>>>19 ^ w9>>>10 ^ w9<<15 ^ w9<<13 ) + w11 + w4 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x8cc70208 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 60
w12 = t = ( ( w13>>>7 ^ w13>>>18 ^ w13>>>3 ^ w13<<25 ^ w13<<14 ) + ( w10>>>17 ^ w10>>>19 ^ w10>>>10 ^ w10<<15 ^ w10<<13 ) + w12 + w5 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x90befffa )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 61
w13 = t = ( ( w14>>>7 ^ w14>>>18 ^ w14>>>3 ^ w14<<25 ^ w14<<14 ) + ( w11>>>17 ^ w11>>>19 ^ w11>>>10 ^ w11<<15 ^ w11<<13 ) + w13 + w6 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xa4506ceb )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 62
w14 = t = ( ( w15>>>7 ^ w15>>>18 ^ w15>>>3 ^ w15<<25 ^ w15<<14 ) + ( w12>>>17 ^ w12>>>19 ^ w12>>>10 ^ w12<<15 ^ w12<<13 ) + w14 + w7 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xbef9a3f7 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 63
w15 = t = ( ( w0>>>7 ^ w0>>>18 ^ w0>>>3 ^ w0<<25 ^ w0<<14 ) + ( w13>>>17 ^ w13>>>19 ^ w13>>>10 ^ w13<<15 ^ w13<<13 ) + w15 + w8 )|0;
t = ( t + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xc67178f2 )|0;
h = g; g = f; f = e; e = ( d + t )|0; d = c; c = b; b = a;
a = ( t + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
H0 = ( H0 + a )|0;
H1 = ( H1 + b )|0;
H2 = ( H2 + c )|0;
H3 = ( H3 + d )|0;
H4 = ( H4 + e )|0;
H5 = ( H5 + f )|0;
H6 = ( H6 + g )|0;
H7 = ( H7 + h )|0;
}
function _core_heap ( offset ) {
offset = offset|0;
_core(
HEAP[offset|0]<<24 | HEAP[offset|1]<<16 | HEAP[offset|2]<<8 | HEAP[offset|3],
HEAP[offset|4]<<24 | HEAP[offset|5]<<16 | HEAP[offset|6]<<8 | HEAP[offset|7],
HEAP[offset|8]<<24 | HEAP[offset|9]<<16 | HEAP[offset|10]<<8 | HEAP[offset|11],
HEAP[offset|12]<<24 | HEAP[offset|13]<<16 | HEAP[offset|14]<<8 | HEAP[offset|15],
HEAP[offset|16]<<24 | HEAP[offset|17]<<16 | HEAP[offset|18]<<8 | HEAP[offset|19],
HEAP[offset|20]<<24 | HEAP[offset|21]<<16 | HEAP[offset|22]<<8 | HEAP[offset|23],
HEAP[offset|24]<<24 | HEAP[offset|25]<<16 | HEAP[offset|26]<<8 | HEAP[offset|27],
HEAP[offset|28]<<24 | HEAP[offset|29]<<16 | HEAP[offset|30]<<8 | HEAP[offset|31],
HEAP[offset|32]<<24 | HEAP[offset|33]<<16 | HEAP[offset|34]<<8 | HEAP[offset|35],
HEAP[offset|36]<<24 | HEAP[offset|37]<<16 | HEAP[offset|38]<<8 | HEAP[offset|39],
HEAP[offset|40]<<24 | HEAP[offset|41]<<16 | HEAP[offset|42]<<8 | HEAP[offset|43],
HEAP[offset|44]<<24 | HEAP[offset|45]<<16 | HEAP[offset|46]<<8 | HEAP[offset|47],
HEAP[offset|48]<<24 | HEAP[offset|49]<<16 | HEAP[offset|50]<<8 | HEAP[offset|51],
HEAP[offset|52]<<24 | HEAP[offset|53]<<16 | HEAP[offset|54]<<8 | HEAP[offset|55],
HEAP[offset|56]<<24 | HEAP[offset|57]<<16 | HEAP[offset|58]<<8 | HEAP[offset|59],
HEAP[offset|60]<<24 | HEAP[offset|61]<<16 | HEAP[offset|62]<<8 | HEAP[offset|63]
);
}
// offset — multiple of 32
function _state_to_heap ( output ) {
output = output|0;
HEAP[output|0] = H0>>>24;
HEAP[output|1] = H0>>>16&255;
HEAP[output|2] = H0>>>8&255;
HEAP[output|3] = H0&255;
HEAP[output|4] = H1>>>24;
HEAP[output|5] = H1>>>16&255;
HEAP[output|6] = H1>>>8&255;
HEAP[output|7] = H1&255;
HEAP[output|8] = H2>>>24;
HEAP[output|9] = H2>>>16&255;
HEAP[output|10] = H2>>>8&255;
HEAP[output|11] = H2&255;
HEAP[output|12] = H3>>>24;
HEAP[output|13] = H3>>>16&255;
HEAP[output|14] = H3>>>8&255;
HEAP[output|15] = H3&255;
HEAP[output|16] = H4>>>24;
HEAP[output|17] = H4>>>16&255;
HEAP[output|18] = H4>>>8&255;
HEAP[output|19] = H4&255;
HEAP[output|20] = H5>>>24;
HEAP[output|21] = H5>>>16&255;
HEAP[output|22] = H5>>>8&255;
HEAP[output|23] = H5&255;
HEAP[output|24] = H6>>>24;
HEAP[output|25] = H6>>>16&255;
HEAP[output|26] = H6>>>8&255;
HEAP[output|27] = H6&255;
HEAP[output|28] = H7>>>24;
HEAP[output|29] = H7>>>16&255;
HEAP[output|30] = H7>>>8&255;
HEAP[output|31] = H7&255;
}
function reset () {
H0 = 0x6a09e667;
H1 = 0xbb67ae85;
H2 = 0x3c6ef372;
H3 = 0xa54ff53a;
H4 = 0x510e527f;
H5 = 0x9b05688c;
H6 = 0x1f83d9ab;
H7 = 0x5be0cd19;
TOTAL0 = TOTAL1 = 0;
}
function init ( h0, h1, h2, h3, h4, h5, h6, h7, total0, total1 ) {
h0 = h0|0;
h1 = h1|0;
h2 = h2|0;
h3 = h3|0;
h4 = h4|0;
h5 = h5|0;
h6 = h6|0;
h7 = h7|0;
total0 = total0|0;
total1 = total1|0;
H0 = h0;
H1 = h1;
H2 = h2;
H3 = h3;
H4 = h4;
H5 = h5;
H6 = h6;
H7 = h7;
TOTAL0 = total0;
TOTAL1 = total1;
}
// offset — multiple of 64
function process ( offset, length ) {
offset = offset|0;
length = length|0;
var hashed = 0;
if ( offset & 63 )
return -1;
while ( (length|0) >= 64 ) {
_core_heap(offset);
offset = ( offset + 64 )|0;
length = ( length - 64 )|0;
hashed = ( hashed + 64 )|0;
}
TOTAL0 = ( TOTAL0 + hashed )|0;
if ( TOTAL0>>>0 < hashed>>>0 ) TOTAL1 = ( TOTAL1 + 1 )|0;
return hashed|0;
}
// offset — multiple of 64
// output — multiple of 32
function finish ( offset, length, output ) {
offset = offset|0;
length = length|0;
output = output|0;
var hashed = 0,
i = 0;
if ( offset & 63 )
return -1;
if ( ~output )
if ( output & 31 )
return -1;
if ( (length|0) >= 64 ) {
hashed = process( offset, length )|0;
if ( (hashed|0) == -1 )
return -1;
offset = ( offset + hashed )|0;
length = ( length - hashed )|0;
}
hashed = ( hashed + length )|0;
TOTAL0 = ( TOTAL0 + length )|0;
if ( TOTAL0>>>0 < length>>>0 ) TOTAL1 = ( TOTAL1 + 1 )|0;
HEAP[offset|length] = 0x80;
if ( (length|0) >= 56 ) {
for ( i = (length+1)|0; (i|0) < 64; i = (i+1)|0 )
HEAP[offset|i] = 0x00;
_core_heap(offset);
length = 0;
HEAP[offset|0] = 0;
}
for ( i = (length+1)|0; (i|0) < 59; i = (i+1)|0 )
HEAP[offset|i] = 0;
HEAP[offset|56] = TOTAL1>>>21&255;
HEAP[offset|57] = TOTAL1>>>13&255;
HEAP[offset|58] = TOTAL1>>>5&255;
HEAP[offset|59] = TOTAL1<<3&255 | TOTAL0>>>29;
HEAP[offset|60] = TOTAL0>>>21&255;
HEAP[offset|61] = TOTAL0>>>13&255;
HEAP[offset|62] = TOTAL0>>>5&255;
HEAP[offset|63] = TOTAL0<<3&255;
_core_heap(offset);
if ( ~output )
_state_to_heap(output);
return hashed|0;
}
function hmac_reset () {
H0 = I0;
H1 = I1;
H2 = I2;
H3 = I3;
H4 = I4;
H5 = I5;
H6 = I6;
H7 = I7;
TOTAL0 = 64;
TOTAL1 = 0;
}
function _hmac_opad () {
H0 = O0;
H1 = O1;
H2 = O2;
H3 = O3;
H4 = O4;
H5 = O5;
H6 = O6;
H7 = O7;
TOTAL0 = 64;
TOTAL1 = 0;
}
function hmac_init ( p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15 ) {
p0 = p0|0;
p1 = p1|0;
p2 = p2|0;
p3 = p3|0;
p4 = p4|0;
p5 = p5|0;
p6 = p6|0;
p7 = p7|0;
p8 = p8|0;
p9 = p9|0;
p10 = p10|0;
p11 = p11|0;
p12 = p12|0;
p13 = p13|0;
p14 = p14|0;
p15 = p15|0;
// opad
reset();
_core(
p0 ^ 0x5c5c5c5c,
p1 ^ 0x5c5c5c5c,
p2 ^ 0x5c5c5c5c,
p3 ^ 0x5c5c5c5c,
p4 ^ 0x5c5c5c5c,
p5 ^ 0x5c5c5c5c,
p6 ^ 0x5c5c5c5c,
p7 ^ 0x5c5c5c5c,
p8 ^ 0x5c5c5c5c,
p9 ^ 0x5c5c5c5c,
p10 ^ 0x5c5c5c5c,
p11 ^ 0x5c5c5c5c,
p12 ^ 0x5c5c5c5c,
p13 ^ 0x5c5c5c5c,
p14 ^ 0x5c5c5c5c,
p15 ^ 0x5c5c5c5c
);
O0 = H0;
O1 = H1;
O2 = H2;
O3 = H3;
O4 = H4;
O5 = H5;
O6 = H6;
O7 = H7;
// ipad
reset();
_core(
p0 ^ 0x36363636,
p1 ^ 0x36363636,
p2 ^ 0x36363636,
p3 ^ 0x36363636,
p4 ^ 0x36363636,
p5 ^ 0x36363636,
p6 ^ 0x36363636,
p7 ^ 0x36363636,
p8 ^ 0x36363636,
p9 ^ 0x36363636,
p10 ^ 0x36363636,
p11 ^ 0x36363636,
p12 ^ 0x36363636,
p13 ^ 0x36363636,
p14 ^ 0x36363636,
p15 ^ 0x36363636
);
I0 = H0;
I1 = H1;
I2 = H2;
I3 = H3;
I4 = H4;
I5 = H5;
I6 = H6;
I7 = H7;
TOTAL0 = 64;
TOTAL1 = 0;
}
// offset — multiple of 64
// output — multiple of 32
function hmac_finish ( offset, length, output ) {
offset = offset|0;
length = length|0;
output = output|0;
var t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0,
hashed = 0;
if ( offset & 63 )
return -1;
if ( ~output )
if ( output & 31 )
return -1;
hashed = finish( offset, length, -1 )|0;
t0 = H0, t1 = H1, t2 = H2, t3 = H3, t4 = H4, t5 = H5, t6 = H6, t7 = H7;
_hmac_opad();
_core( t0, t1, t2, t3, t4, t5, t6, t7, 0x80000000, 0, 0, 0, 0, 0, 0, 768 );
if ( ~output )
_state_to_heap(output);
return hashed|0;
}
// salt is assumed to be already processed
// offset — multiple of 64
// output — multiple of 32
function pbkdf2_generate_block ( offset, length, block, count, output ) {
offset = offset|0;
length = length|0;
block = block|0;
count = count|0;
output = output|0;
var h0 = 0, h1 = 0, h2 = 0, h3 = 0, h4 = 0, h5 = 0, h6 = 0, h7 = 0,
t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0;
if ( offset & 63 )
return -1;
if ( ~output )
if ( output & 31 )
return -1;
// pad block number into heap
// FIXME probable OOB write
HEAP[(offset+length)|0] = block>>>24;
HEAP[(offset+length+1)|0] = block>>>16&255;
HEAP[(offset+length+2)|0] = block>>>8&255;
HEAP[(offset+length+3)|0] = block&255;
// finish first iteration
hmac_finish( offset, (length+4)|0, -1 )|0;
h0 = t0 = H0, h1 = t1 = H1, h2 = t2 = H2, h3 = t3 = H3, h4 = t4 = H4, h5 = t5 = H5, h6 = t6 = H6, h7 = t7 = H7;
count = (count-1)|0;
// perform the rest iterations
while ( (count|0) > 0 ) {
hmac_reset();
_core( t0, t1, t2, t3, t4, t5, t6, t7, 0x80000000, 0, 0, 0, 0, 0, 0, 768 );
t0 = H0, t1 = H1, t2 = H2, t3 = H3, t4 = H4, t5 = H5, t6 = H6, t7 = H7;
_hmac_opad();
_core( t0, t1, t2, t3, t4, t5, t6, t7, 0x80000000, 0, 0, 0, 0, 0, 0, 768 );
t0 = H0, t1 = H1, t2 = H2, t3 = H3, t4 = H4, t5 = H5, t6 = H6, t7 = H7;
h0 = h0 ^ H0;
h1 = h1 ^ H1;
h2 = h2 ^ H2;
h3 = h3 ^ H3;
h4 = h4 ^ H4;
h5 = h5 ^ H5;
h6 = h6 ^ H6;
h7 = h7 ^ H7;
count = (count-1)|0;
}
H0 = h0;
H1 = h1;
H2 = h2;
H3 = h3;
H4 = h4;
H5 = h5;
H6 = h6;
H7 = h7;
if ( ~output )
_state_to_heap(output);
return 0;
}
return {
// SHA256
reset: reset,
init: init,
process: process,
finish: finish,
// HMAC-SHA256
hmac_reset: hmac_reset,
hmac_init: hmac_init,
hmac_finish: hmac_finish,
// PBKDF2-HMAC-SHA256
pbkdf2_generate_block: pbkdf2_generate_block
}
}
},
"transform/TextTransformer.js": function(module, exports, require){
/*@flow*/
/*
* Copyright 2014 XWiki SAS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
"use strict";
/*::
import type { Operation_t } from '../Operation'
*/
var Operation = require('../Operation');
var Common = require('../Common');
var transformOp0 = function (
toTransform /*:Operation_t*/,
transformBy /*:Operation_t*/)
{
if (toTransform.offset > transformBy.offset) {
if (toTransform.offset > transformBy.offset + transformBy.toRemove) {
// simple rebase
return Operation.create(
toTransform.offset - transformBy.toRemove + transformBy.toInsert.length,
toTransform.toRemove,
toTransform.toInsert
);
}
var newToRemove =
toTransform.toRemove - (transformBy.offset + transformBy.toRemove - toTransform.offset);
if (newToRemove < 0) { newToRemove = 0; }
if (newToRemove === 0 && toTransform.toInsert.length === 0) { return null; }
return Operation.create(
transformBy.offset + transformBy.toInsert.length,
newToRemove,
toTransform.toInsert
);
}
// they don't touch, yay
if (toTransform.offset + toTransform.toRemove < transformBy.offset) { return toTransform; }
// Truncate what will be deleted...
var _newToRemove = transformBy.offset - toTransform.offset;
if (_newToRemove === 0 && toTransform.toInsert.length === 0) { return null; }
return Operation.create(toTransform.offset, _newToRemove, toTransform.toInsert);
};
var transformOp = function (
toTransform /*:Operation_t*/,
transformBy /*:Operation_t*/)
{
if (Common.PARANOIA) {
Operation.check(toTransform);
Operation.check(transformBy);
}
var result = transformOp0(toTransform, transformBy);
if (Common.PARANOIA && result) { Operation.check(result); }
return result;
};
module.exports = function (
opsToTransform /*:Array<Operation_t>*/,
opsTransformBy /*:Array<Operation_t>*/,
doc /*:string*/ ) /*:Array<Operation_t>*/
{
var resultOfTransformBy = doc;
var i;
for (i = opsTransformBy.length - 1; i >= 0; i--) {
resultOfTransformBy = Operation.apply(opsTransformBy[i], resultOfTransformBy);
}
var out = [];
for (i = opsToTransform.length - 1; i >= 0; i--) {
var tti = opsToTransform[i];
for (var j = opsTransformBy.length - 1; j >= 0; j--) {
try {
tti = transformOp(tti, opsTransformBy[j]);
} catch (e) {
console.error("The pluggable transform function threw an error, " +
"failing operational transformation");
console.error(e.stack);
return [];
}
if (!tti) {
break;
}
}
if (tti) {
if (Common.PARANOIA) { Operation.check(tti, resultOfTransformBy.length); }
out.unshift(tti);
}
}
return out;
};
},
"transform/SmartJSONTransformer.js": function(module, exports, require){
/*@flow*/
/*
* Copyright 2014 XWiki SAS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
"use strict";
var Sortify = require('json.sortify');
var Diff = require('../Diff');
//var Patch = require('../Patch');
var Operation = require('../Operation');
var TextTransformer = require('./TextTransformer');
//var Sha = require('../sha256');
/*::
import type { Operation_t } from '../Operation';
*/
var isArray = function (obj) {
return Object.prototype.toString.call(obj)==='[object Array]';
};
/* Arrays and nulls both register as 'object' when using native typeof
we need to distinguish them as their own types, so use this instead. */
var type = function (dat) {
return dat === null? 'null': isArray(dat)?'array': typeof(dat);
};
var find = function (map, path) {
var l = path.length;
for (var i = 0; i < l; i++) {
if (typeof(map[path[i]]) === 'undefined') { return; }
map = map[path[i]];
}
return map;
};
var clone = function (val) {
return JSON.parse(JSON.stringify(val));
};
var deepEqual = function (A /*:any*/, B /*:any*/) {
var t_A = type(A);
var t_B = type(B);
if (t_A !== t_B) { return false; }
if (t_A === 'object') {
var k_A = Object.keys(A);
var k_B = Object.keys(B);
return k_A.length === k_B.length &&
!k_A.some(function (a) { return !deepEqual(A[a], B[a]); }) &&
!k_B.some(function (b) { return !(b in A); });
} else if (t_A === 'array') {
return A.length === B.length &&
!A.some(function (a, i) { return !deepEqual(a, B[i]); });
} else {
return A === B;
}
};
/*::
export type SmartJSONTransformer_Replace_t = {
type: 'replace',
path: Array<string|number>,
value: any,
prev: any
};
export type SmartJSONTransformer_Splice_t = {
type: 'splice',
path: Array<string|number>,
value: any,
offset: number,
removals: number
};
export type SmartJSONTransformer_Remove_t = {
type: 'remove',
path: Array<string|number>,
value: any
};
export type SmartJSONTransformer_Operation_t =
SmartJSONTransformer_Replace_t | SmartJSONTransformer_Splice_t | SmartJSONTransformer_Remove_t;
*/
var operation = function (type, path, value, prev, other) /*:SmartJSONTransformer_Operation_t*/ {
if (type === 'replace') {
return ({
type: 'replace',
path: path,
value: value,
prev: prev,
} /*:SmartJSONTransformer_Replace_t*/);
} else if (type === 'splice') {
if (typeof(prev) !== 'number') { throw new Error(); }
if (typeof(other) !== 'number') { throw new Error(); }
return ({
type: 'splice',
path: path,
value: value,
offset: prev,
removals: other
} /*:SmartJSONTransformer_Splice_t*/);
} else if (type !== 'remove') { throw new Error('expected a removal'); }
// if it's not a replace or splice, it's a 'remove'
return ({
type: 'remove',
path: path,
value: value,
} /*:SmartJSONTransformer_Remove_t*/);
};
var replace = function (ops, path, to, from) {
ops.push(operation('replace', path, to, from));
};
var remove = function (ops, path, val) {
ops.push(operation('remove', path, val));
};
// HERE
var splice = function (ops, path, value, offset, removals) {
ops.push(operation('splice', path, value, offset, removals));
};
/*
all of A's path is at the beginning of B
roughly: B.indexOf(A) === 0
*/
var pathOverlaps = function (A /*:Array<string|number>*/, B /*:Array<string|number>*/) {
return !A.some(function (a, i) {
return a !== B[i];
});
};
// OT Case #1 replace->replace ✔
// OT Case #2 replace->remove ✔
// OT Case #3 replace->splice ✔
// OT Case #4 remove->replace ✔
// OT Case #5 remove->remove ✔
// OT Case #6 remove->splice ✔
// OT Case #7 splice->replace ✔
// OT Case #8 splice->remove ✔
// OT Case #9 splice->splice ✔
var CASES = (function () {
var types = ['replace', 'remove', 'splice'];
var matrix = {};
var i = 1;
types.forEach(function (a) {
matrix[a] = {};
return types.forEach(function (b) { matrix[a][b] = i++; });
});
return matrix;
}());
// A and B are lists of operations which result from calling diff
var resolve = function (A /*:any*/, B /*:any*/, arbiter /*:?function*/) {
if (!(type(A) === 'array' && type(B) === 'array')) {
throw new Error("[resolve] expected two arrays");
}
/* OVERVIEW
* B
* 1. filter removals at identical paths
*
*/
B = B.filter(function (b) {
// if A removed part of the tree you were working on...
if (A.some(function (a) {
if (a.type === 'remove') {
if (pathOverlaps(a.path, b.path)) {
if (b.path.length - a.path.length > 1) { return true; }
}
}
})) {
// this is weird... FIXME
return false;
}
/* remove operations which would no longer make sense
for instance, if a replaces an array with a string,
that would invalidate a splice operation at that path */
if (b.type === 'splice' && A.some(function (a) {
if (a.type === 'splice' && pathOverlaps(a.path, b.path)) {
if (a.path.length - b.path.length < 0) {
if (!a.removals) { return; }
var start = a.offset;
var end = a.offset + a.removals;
for (;start < end; start++) {
if (start === b.path[a.path.length]) {
/*
if (typeof(arbiter) === 'function' &&
deepEqual(a.path, b.path) &&
a.value.length === 1 &&
b.value.length === 1 &&
typeof(a.value[0]) === 'string' &&
typeof(b.value[0]) === 'string') {
console.log('strings');
return arbiter(a, b, CASES.splice.splice);
}
*/
// b is a descendant of a removal
return true;
}
}
}
}
})) { return false; }
if (!A.some(function (a) {
return b.type === 'remove' && deepEqual(a.path, b.path);
})) { return true; }
})
.filter(function (b) {
// let A win conflicts over b if no arbiter is supplied here
// Arbiter is required here
return !A.some(function (a) {
if (b.type === 'replace' && a.type === 'replace') {
// remove any operations which return true
if (deepEqual(a.path, b.path)) {
if (typeof(a.value) === 'string' && typeof(b.value) === 'string') {
if (arbiter && a.prev === b.prev && a.value !== b.value) {
return arbiter(a, b, CASES.replace.replace);
}
return true;
}
return true;
}
}
});
})
.map(function (b) {
// if a splice in A modifies the path to b
// update b's path to reflect that
A.forEach(function (a) {
if (a.type === 'splice') {
// TODO
// what if a.path == b.path
// what if a removes elements (splice) and b also removes elements
// (generally we merge these two together but it is probably best to allow the api customer to decide via a "strategy")
// Note that A might be removing *and* inserting because a splice is roughly equivilent to a ChainPad Operation
// Consult Transform0 :)
// resolve insertion overlaps array.push conflicts
// iterate over A such that each overlapping splice
// adjusts the path/offset of b
if (deepEqual(a.path, b.path)) {
if (b.type === 'splice') {
// what if the splice is a removal?
b.offset += (a.value.length - a.removals);
// if both A and B are removing the same thing
// be careful
} else {
// adjust the path of b to account for the splice
// TODO
}
return;
}
if (pathOverlaps(a.path, b.path)) {
// TODO validate that this isn't an off-by-one error
var pos = a.path.length;
if (typeof(b.path[pos]) === 'number' && a.offset <= b.path[pos]) { // FIXME a.value is undefined
b.path[pos] += (a.value.length - a.removals);
}
}
}
});
return b;
});
return B;
};
// A, B, f, path, ops
var objects = function (A, B, path, ops) {
var Akeys = Object.keys(A);
var Bkeys = Object.keys(B);
Bkeys.forEach(function (b) {
var t_b = type(B[b]);
var old = A[b];
var nextPath = path.concat(b);
if (Akeys.indexOf(b) === -1) {
// there was an insertion
// mind the fallthrough behaviour
if (t_b === 'undefined') {
throw new Error("undefined type has key. this shouldn't happen?");
}
if (old) { throw new Error("no such key existed in b, so 'old' should be falsey"); }
replace(ops, nextPath, B[b], old);
return;
}
// else the key already existed
var t_a = type(old);
if (t_a !== t_b) {
// its type changed!
console.log("type changed from [%s] to [%s]", t_a, t_b);
// type changes always mean a change happened
if (t_b === 'undefined') {
throw new Error("first pass should never reveal undefined keys");
}
replace(ops, nextPath, B[b], old);
return;
}
if (t_a === 'object') {
// it's an object
objects(A[b], B[b], nextPath, ops);
} else if (t_a === 'array') {
// it's an array
arrays(A[b], B[b], nextPath, ops);
} else if (A[b] !== B[b]) {
// it's not an array or object, so we can do === comparison
replace(ops, nextPath, B[b], old);
}
});
Akeys.forEach(function (a) {
// the key was deleted
if (Bkeys.indexOf(a) === -1 || type(B[a]) === 'undefined') {
remove(ops, path.concat(a), A[a]);
}
});
};
var arrayShallowEquality = function (A, B) {
if (A.length !== B.length) { return false; }
for (var i = 0; i < A.length; i++) {
if (type(A[i]) !== type(B[i])) { return false; }
}
return true;
};
// When an element in an array (number, string, bool) is changed, instead of a replace we
// will do a splice(offset, [element], 1)
var arrays = function (A_orig, B, path, ops) {
var A = A_orig.slice(0); // shallow clone
if (A.length === 0) {
// A is zero length, this is going to be easy...
splice(ops, path, B, 0, 0);
} else if (arrayShallowEquality(A, B)) {
// This is a relatively simple case, the elements in A and B are all of the same type and if
// that type happens to be a primitive type, they are also equal.
// This means no change will be needed at the level of this array, only it's children.
A.forEach(function (a, i) {
var b = B[i];
if (b === a) { return; }
var old = a;
var nextPath = path.concat(i);
var t_a = type(a);
switch (t_a) {
case 'undefined':
throw new Error('existing key had type `undefined`. this should never happen');
case 'object':
objects(a, b, nextPath, ops);
break;
case 'array':
arrays(a, b, nextPath, ops);
break;
default:
//console.log('replace: ' + t_a);
//splice(ops, path, [b], i, 1);
replace(ops, nextPath, b, old);
}
});
} else {
// Something was changed in the length of the array or one of the primitives so we're going
// to make an actual change to this array, not only it's children.
var commonStart = 0;
var commonEnd = 0;
while (commonStart < A.length && deepEqual(A[commonStart], B[commonStart])) { commonStart++; }
while (deepEqual(A[A.length - 1 - commonEnd], B[B.length - 1 - commonEnd]) &&
commonEnd + commonStart < A.length && commonEnd + commonStart < B.length)
{
commonEnd++;
}
var toRemove = A.length - commonStart - commonEnd;
var toInsert = [];
if (B.length !== commonStart + commonEnd) {
toInsert = B.slice(commonStart, B.length - commonEnd);
}
splice(ops, path, toInsert, commonStart, toRemove);
}
};
var diff = function (A, B) {
var ops = [];
var t_A = type(A);
var t_B = type(B);
if (t_A !== t_B) {
throw new Error("Can't merge two objects of differing types");
}
if (t_B === 'array') {
arrays(A, B, [], ops);
} else if (t_B === 'object') {
objects(A, B, [], ops);
} else {
throw new Error("unsupported datatype" + t_B);
}
return ops;
};
var applyOp = function (O, op /*:SmartJSONTransformer_Operation_t*/) {
var path;
var key;
var result;
switch (op.type) {
case "replace":
key = op.path[op.path.length -1];
path = op.path.slice(0, op.path.length - 1);
var parent = find(O, path);
if (!parent) {
throw new Error("cannot apply change to non-existent element");
}
parent[key] = op.value;
break;
case "splice":
var found = find(O, op.path);
if (!found) {
console.error("[applyOp] expected path [%s] to exist in object", op.path.join(','));
throw new Error("Path did not exist");
}
if (type(found) !== 'array') {
throw new Error("Can't splice non-array");
}
Array.prototype.splice.apply(found, [op.offset, op.removals].concat(op.value));
break;
case "remove":
key = op.path[op.path.length -1];
path = op.path.slice(0, op.path.length - 1);
result = find(O, path);
if (typeof(result) !== 'undefined') { delete result[key]; }
break;
default:
throw new Error('unsupported operation type');
}
};
var patch = function (O, ops) {
ops.forEach(function (op) {
applyOp(O, op);
});
return O;
};
/////
// We mutate b in this function
// Our operation is p_b and the other person's operation is p_a.
// If we return true here, it means our operation will die off.
var arbiter = function (p_a, p_b, c) {
if (p_a.prev !== p_b.prev) { throw new Error("Parent values don't match!"); }
if (c === CASES.splice.splice) {
// We and the other person are both pushing strings to an array so
// we'll just accept both of them into the array.
console.log(p_a);
console.log(p_b);
console.log('\n\n\n\n\n\n\n\n\n');
// TODO: do we really want to kill off our operation in this case ?
return true;
}
var o = p_a.prev;
var ops_a = Diff.diff(o, p_a.value);
var ops_b = Diff.diff(o, p_b.value);
/* given the parent text, the op to transform, and the incoming op
return a transformed operation which takes the incoming
op into account */
var ops_x = TextTransformer(ops_b, ops_a, o);
/* Apply the incoming operation to the parent text
*/
var x2 = Operation.applyMulti(ops_a, o);
/* Apply the transformed operation to the result of the incoming op
*/
var x3 = Operation.applyMulti(ops_x, x2);
p_b.value = x3;
};
module.exports = function (
opsToTransform /*:Array<Operation_t>*/,
opsTransformBy /*:Array<Operation_t>*/,
s_orig /*:string*/ ) /*:Array<Operation_t>*/
{
var o_orig = JSON.parse(s_orig);
var s_transformBy = Operation.applyMulti(opsTransformBy, s_orig);
var o_transformBy = JSON.parse(s_transformBy);
// try whole patch at a time, see how it goes...
var s_toTransform = Operation.applyMulti(opsToTransform, s_orig);
var o_toTransform = JSON.parse(s_toTransform);
try {
var diffTTF = diff(o_orig, o_toTransform);
var diffTFB = diff(o_orig, o_transformBy);
var newDiffTTF = resolve(diffTFB, diffTTF, arbiter);
// mutates orig
patch(o_orig, diffTFB);
patch(o_orig, newDiffTTF);
var result = Sortify(o_orig);
var ret = Diff.diff(s_transformBy, result);
return ret;
} catch (err) {
console.error(err); // FIXME Path did not exist...
}
return [];
};
module.exports._ = {
clone: clone,
pathOverlaps: pathOverlaps,
deepEqual: deepEqual,
diff: diff,
resolve: resolve,
patch: patch,
};
},
"transform/NaiveJSONTransformer.js": function(module, exports, require){
/*@flow*/
/*
* Copyright 2014 XWiki SAS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
"use strict";
var TextTransformer = require('./TextTransformer');
//var ChainPad = require('../ChainPad');
var Operation = require('../Operation');
var Common = require('../Common');
/*::
import type { Operation_t } from '../Operation';
*/
module.exports = function (
opsToTransform /*:Array<Operation_t>*/,
opsTransformBy /*:Array<Operation_t>*/,
text /*:string*/ ) /*:Array<Operation_t>*/
{
var DEBUG = Common.global.REALTIME_DEBUG = Common.global.REALTIME_DEBUG || {};
var resultOps, text2, text3;
try {
// text = O (mutual common ancestor)
// toTransform = A (your own operation)
// transformBy = B (the incoming operation)
// threeway merge (0, A, B)
resultOps = TextTransformer(opsToTransform, opsTransformBy, text);
text2 = Operation.applyMulti(opsTransformBy, text);
text3 = Operation.applyMulti(resultOps, text2);
try {
JSON.parse(text3);
return resultOps;
} catch (e) {
console.error(e);
DEBUG.ot_parseError = {
type: 'resultParseError',
resultOps: resultOps,
toTransform: opsToTransform,
transformBy: opsTransformBy,
text1: text,
text2: text2,
text3: text3,
error: e
};
console.log('Debugging info available at `window.REALTIME_DEBUG.ot_parseError`');
}
} catch (x) {
console.error(x);
DEBUG.ot_applyError = {
type: 'resultParseError',
resultOps: resultOps,
toTransform: opsToTransform,
transformBy: opsTransformBy,
text1: text,
text2: text2,
text3: text3,
error: x
};
console.log('Debugging info available at `window.REALTIME_DEBUG.ot_applyError`');
}
// return an empty patch in case we can't do anything else
return [];
};
}
};
r.m[1] = {
"dist/JSON.sortify.js": function(module, exports, require){
"use strict";(function(factory){if(typeof module!=="undefined"&&module.exports)module.exports=factory();else if(typeof define=="function"&&typeof define.amd=="object")define("json.sortify",factory);else JSON.sortify=factory()})(function(){ /*!
* Copyright 2015-2017 Thomas Rosenau
*
* 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.
*/"use strict";var sortKeys=function sortKeys(o){if(Array.isArray(o)){return o.map(sortKeys)}else if(o instanceof Object){var _ret=function(){var numeric=[];var nonNumeric=[];Object.keys(o).forEach(function(key){if(/^(0|[1-9][0-9]*)$/.test(key)){numeric.push(+key)}else {nonNumeric.push(key)}});return {v:numeric.sort(function(a,b){return a-b}).concat(nonNumeric.sort()).reduce(function(result,key){result[key]=sortKeys(o[key]);return result},{})}}();if(typeof _ret==="object")return _ret.v}return o};var jsonStringify=JSON.stringify.bind(JSON);var sortify=function sortify(value,replacer,space){var nativeJson=jsonStringify(value,replacer,0);if(!nativeJson||nativeJson[0]!=="{"&&nativeJson[0]!=="["){return nativeJson}var cleanObj=JSON.parse(nativeJson);return jsonStringify(sortKeys(cleanObj),null,space)};return sortify});
}
};
function umd(n,f){"object"==typeof exports&&(module.exports=n),"function"==typeof define&&define.amd&&define(function(){return n});var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e[f]=n}umd(r("ChainPad.js"), "ChainPad");}());