patch.js
function _compareMaps(a,b, options) {

    debug(a,b);

    let alength = a.size === undefined ? a.length : a.size;
    let blength = b.size === undefined ? b.length : b.size;

    if (alength === 0 && blength === 0) return ops.NOP;
    // ops.Map([...b]) and not just ops.Rpl(b) because if b is a map it's not good JSON.
    if (alength === 0 || blength === 0) return new ops.Map([...b]);

    let patch = [];

    if (!options.sorted) {
        a = Array.from(a).sort((a,b) => utils.compare(a,b,options));
        b = Array.from(b).sort((a,b) => utils.compare(a,b,options));
    }

    let ai = 1, bi = 1;
    let ao = a[0], bo = b[0]
    let element_options = options.getArrayElementOptions();

    do {
        let comparison = utils.compare(ao,bo,options);
        debug("comparing items", ao, bo, comparison);
        if (comparison < 0) {
            debug('skip');
            ao = a[ai++]; 
        } else if (comparison > 0) {
            debug('insert');
            patch.push([options.key(bo), new ops.Ins(options.value(bo))]);
            bo = b[bi++];
        } else {
            if (options.value(ao) !== options.value(bo)) {
                let element_patch = compare(options.value(ao), options.value(bo), element_options)
                if (element_patch != ops.NOP) patch.push([options.key(bo), element_patch]);
            }
            else debug('skip2');
            ao = a[ai++]; 
            bo = b[bi++];
        }
    } while (ai <= a.length && bi <= b.length);

    while (ai <= a.length) {
        patch.push([options.key(ao), ops.DEL]);
        ao=a[ai++]; 
    }

    while (bi <= b.length) {
        patch.push([options.key(bo), new ops.Ins(options.value(bo))]); 
        bo=b[bi++]; 
    }

    return new ops.Map(patch);
}
function _compareMaps(a,b, options) {

    debug(a,b);

    let alength = a.size === undefined ? a.length : a.size;
    let blength = b.size === undefined ? b.length : b.size;

    if (alength === 0 && blength === 0) return ops.NOP;
    // ops.Map([...b]) and not just ops.Rpl(b) because if b is a map it's not good JSON.
    if (alength === 0 || blength === 0) return new ops.Map([...b]);

    let patch = [];

    if (!options.sorted) {
        a = Array.from(a).sort((a,b) => utils.compare(a,b,options));
        b = Array.from(b).sort((a,b) => utils.compare(a,b,options));
    }

    let ai = 1, bi = 1;
    let ao = a[0], bo = b[0]
    let element_options = options.getArrayElementOptions();

    do {
        let comparison = utils.compare(ao,bo,options);
        debug("comparing items", ao, bo, comparison);
        if (comparison < 0) {
            debug('skip');
            ao = a[ai++]; 
        } else if (comparison > 0) {
            debug('insert');
            patch.push([options.key(bo), new ops.Ins(options.value(bo))]);
            bo = b[bi++];
        } else {
            if (options.value(ao) !== options.value(bo)) {
                let element_patch = compare(options.value(ao), options.value(bo), element_options)
                if (element_patch != ops.NOP) patch.push([options.key(bo), element_patch]);
            }
            else debug('skip2');
            ao = a[ai++]; 
            bo = b[bi++];
        }
    } while (ai <= a.length && bi <= b.length);

    while (ai <= a.length) {
        patch.push([options.key(ao), ops.DEL]);
        ao=a[ai++]; 
    }

    while (bi <= b.length) {
        patch.push([options.key(bo), new ops.Ins(options.value(bo))]); 
        bo=b[bi++]; 
    }

    return new ops.Map(patch);
}
Patch for objects

Functions that should allow us to compare two objects, compute a difference, send the difference over the wire, and apply a patch at the far end
to sync a remote object with the changes.

For 'patch' to work properly, the patched object (and child objects) should have a static 'fromJSON' method somewhere in its inheritance tree.
You may also implement a static 'getAttrProps(name)' object, which may return a variety of options that are applied to
child properties with the given name (see {@link DEFAULT_OPTIONS}).

Won't work with cyclic data structures.
 Compare two Map-like objects.