function applyHunk(hunkLines, toPos, maxErrors) {
        var hunkLinesI = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
        var lastContextLineMatched = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;
        var patchedLines = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : [];
        var patchedLinesLength = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : 0;
        var nConsecutiveOldContextLines = 0;
        var nextContextLineMustMatch = false;
        for (; hunkLinesI < hunkLines.length; hunkLinesI++) {
        var hunkLine = hunkLines[hunkLinesI],
            operation = hunkLine.length > 0 ? hunkLine[0] : ' ',
            content = hunkLine.length > 0 ? hunkLine.substr(1) : hunkLine;
        if (operation === '-') {
            if (compareLine(toPos + 1, lines[toPos], operation, content)) {
            toPos++;
            nConsecutiveOldContextLines = 0;
            } else {
            if (!maxErrors || lines[toPos] == null) {
                return null;
            }
            patchedLines[patchedLinesLength] = lines[toPos];
            return applyHunk(hunkLines, toPos + 1, maxErrors - 1, hunkLinesI, false, patchedLines, patchedLinesLength + 1);
            }
        }
        if (operation === '+') {
            if (!lastContextLineMatched) {
            return null;
            }
            patchedLines[patchedLinesLength] = content;
            patchedLinesLength++;
            nConsecutiveOldContextLines = 0;
            nextContextLineMustMatch = true;
        }
        if (operation === ' ') {
            nConsecutiveOldContextLines++;
            patchedLines[patchedLinesLength] = lines[toPos];
            if (compareLine(toPos + 1, lines[toPos], operation, content)) {
            patchedLinesLength++;
            lastContextLineMatched = true;
            nextContextLineMustMatch = false;
            toPos++;
            } else {
            if (nextContextLineMustMatch || !maxErrors) {
                return null;
            }

            // Consider 3 possibilities in sequence:
            // 1. lines contains a *substitution* not included in the patch context, or
            // 2. lines contains an *insertion* not included in the patch context, or
            // 3. lines contains a *deletion* not included in the patch context
            // The first two options are of course only possible if the line from lines is non-null -
            // i.e. only option 3 is possible if we've overrun the end of the old file.
            return lines[toPos] && (applyHunk(hunkLines, toPos + 1, maxErrors - 1, hunkLinesI + 1, false, patchedLines, patchedLinesLength + 1) || applyHunk(hunkLines, toPos + 1, maxErrors - 1, hunkLinesI, false, patchedLines, patchedLinesLength + 1)) || applyHunk(hunkLines, toPos, maxErrors - 1, hunkLinesI + 1, false, patchedLines, patchedLinesLength);
            }
        }
        }

        // Before returning, trim any unmodified context lines off the end of patchedLines and reduce
        // toPos (and thus oldLineLastI) accordingly. This allows later hunks to be applied to a region
        // that starts in this hunk's trailing context.
        patchedLinesLength -= nConsecutiveOldContextLines;
        toPos -= nConsecutiveOldContextLines;
        patchedLines.length = patchedLinesLength;
        return {
        patchedLines: patchedLines,
        oldLineLastI: toPos - 1
        };
    }
Checks if the hunk can be made to fit at the provided location with at most `maxErrors`
insertions, substitutions, or deletions, while ensuring also that:
- lines deleted in the hunk match exactly, and
- wherever an insertion operation or block of insertion operations appears in the hunk, the
  immediately preceding and following lines of context match exactly

`toPos` should be set such that lines[toPos] is meant to match hunkLines[0].

If the hunk can be applied, returns an object with properties `oldLineLastI` and
`replacementLines`. Otherwise, returns null.