| 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); | 
| } |