function diff(oldArr, newArr, equals) { 
 | 
    if (!equals) { 
 | 
        equals = function (a, b) { 
 | 
            return a === b; 
 | 
        }; 
 | 
    } 
 | 
    oldArr = oldArr.slice(); 
 | 
    newArr = newArr.slice(); 
 | 
    var newLen = newArr.length; 
 | 
    var oldLen = oldArr.length; 
 | 
    var editLength = 1; 
 | 
    var maxEditLength = newLen + oldLen; 
 | 
    var bestPath = [{ newPos: -1, components: [] }]; 
 | 
    var oldPos = extractCommon(bestPath[0], newArr, oldArr, 0, equals); 
 | 
    if (!oldLen 
 | 
        || !newLen 
 | 
        || (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen)) { 
 | 
        var indices = []; 
 | 
        var allCleared = !newLen && oldLen > 0; 
 | 
        var allCreated = !oldLen && newLen > 0; 
 | 
        for (var i = 0; i < (allCleared ? oldArr : newArr).length; i++) { 
 | 
            indices.push(i); 
 | 
        } 
 | 
        return [{ 
 | 
                indices: indices, 
 | 
                count: indices.length, 
 | 
                added: allCreated, 
 | 
                removed: allCleared 
 | 
            }]; 
 | 
    } 
 | 
    function execEditLength() { 
 | 
        for (var diagonalPath = -1 * editLength; diagonalPath <= editLength; diagonalPath += 2) { 
 | 
            var basePath; 
 | 
            var addPath = bestPath[diagonalPath - 1]; 
 | 
            var removePath = bestPath[diagonalPath + 1]; 
 | 
            var oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; 
 | 
            if (addPath) { 
 | 
                bestPath[diagonalPath - 1] = undefined; 
 | 
            } 
 | 
            var canAdd = addPath && addPath.newPos + 1 < newLen; 
 | 
            var canRemove = removePath && 0 <= oldPos && oldPos < oldLen; 
 | 
            if (!canAdd && !canRemove) { 
 | 
                bestPath[diagonalPath] = undefined; 
 | 
                continue; 
 | 
            } 
 | 
            if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) { 
 | 
                basePath = clonePath(removePath); 
 | 
                pushComponent(basePath.components, false, true); 
 | 
            } 
 | 
            else { 
 | 
                basePath = addPath; 
 | 
                basePath.newPos++; 
 | 
                pushComponent(basePath.components, true, false); 
 | 
            } 
 | 
            oldPos = extractCommon(basePath, newArr, oldArr, diagonalPath, equals); 
 | 
            if (basePath.newPos + 1 >= newLen && oldPos + 1 >= oldLen) { 
 | 
                return buildValues(basePath.components); 
 | 
            } 
 | 
            else { 
 | 
                bestPath[diagonalPath] = basePath; 
 | 
            } 
 | 
        } 
 | 
        editLength++; 
 | 
    } 
 | 
    while (editLength <= maxEditLength) { 
 | 
        var ret = execEditLength(); 
 | 
        if (ret) { 
 | 
            return ret; 
 | 
        } 
 | 
    } 
 | 
} 
 | 
function extractCommon(basePath, newArr, oldArr, diagonalPath, equals) { 
 | 
    var newLen = newArr.length; 
 | 
    var oldLen = oldArr.length; 
 | 
    var newPos = basePath.newPos; 
 | 
    var oldPos = newPos - diagonalPath; 
 | 
    var commonCount = 0; 
 | 
    while (newPos + 1 < newLen && oldPos + 1 < oldLen && equals(newArr[newPos + 1], oldArr[oldPos + 1])) { 
 | 
        newPos++; 
 | 
        oldPos++; 
 | 
        commonCount++; 
 | 
    } 
 | 
    if (commonCount) { 
 | 
        basePath.components.push({ 
 | 
            count: commonCount, 
 | 
            added: false, 
 | 
            removed: false, 
 | 
            indices: [] 
 | 
        }); 
 | 
    } 
 | 
    basePath.newPos = newPos; 
 | 
    return oldPos; 
 | 
} 
 | 
function pushComponent(components, added, removed) { 
 | 
    var last = components[components.length - 1]; 
 | 
    if (last && last.added === added && last.removed === removed) { 
 | 
        components[components.length - 1] = { 
 | 
            count: last.count + 1, 
 | 
            added: added, 
 | 
            removed: removed, 
 | 
            indices: [] 
 | 
        }; 
 | 
    } 
 | 
    else { 
 | 
        components.push({ 
 | 
            count: 1, 
 | 
            added: added, 
 | 
            removed: removed, 
 | 
            indices: [] 
 | 
        }); 
 | 
    } 
 | 
} 
 | 
function buildValues(components) { 
 | 
    var componentPos = 0; 
 | 
    var componentLen = components.length; 
 | 
    var newPos = 0; 
 | 
    var oldPos = 0; 
 | 
    for (; componentPos < componentLen; componentPos++) { 
 | 
        var component = components[componentPos]; 
 | 
        if (!component.removed) { 
 | 
            var indices = []; 
 | 
            for (var i = newPos; i < newPos + component.count; i++) { 
 | 
                indices.push(i); 
 | 
            } 
 | 
            component.indices = indices; 
 | 
            newPos += component.count; 
 | 
            if (!component.added) { 
 | 
                oldPos += component.count; 
 | 
            } 
 | 
        } 
 | 
        else { 
 | 
            for (var i = oldPos; i < oldPos + component.count; i++) { 
 | 
                component.indices.push(i); 
 | 
            } 
 | 
            oldPos += component.count; 
 | 
        } 
 | 
    } 
 | 
    return components; 
 | 
} 
 | 
function clonePath(path) { 
 | 
    return { newPos: path.newPos, components: path.components.slice(0) }; 
 | 
} 
 | 
export default function arrayDiff(oldArr, newArr, equal) { 
 | 
    return diff(oldArr, newArr, equal); 
 | 
} 
 |