(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, previousDoc) {
    var patches = [ msg ];
    var doc = previousDoc || '';
    if (!previousDoc) {
        while (patches[0] !== realtime.rootMessage) {
            var parent = getParent(realtime, patches[0]);
            if (!parent) {
                return { error: 'not connected to root', doc: undefined };
            }
            patches.unshift(parent);
        }
        if (realtime.rootMessage.content.operations.length) {
            Common.assert(realtime.rootMessage.content.operations.length === 1);
            doc = realtime.rootMessage.content.operations[0].toInsert;
        }
    }
    for (var i = previousDoc?0: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: (?string)=>{
        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 (previous) { return getContentAtState(realtime, msg, previous); },
        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");}());