func (dmp *DiffMatchPatch) DiffCleanupSemantic(diffs []Diff) []Diff {
	changes := false
	equalities := make([]int, 0, len(diffs))
	var lastequality string
	var pointer int  
	var lengthInsertions1, lengthDeletions1 int
	var lengthInsertions2, lengthDeletions2 int
	for pointer < len(diffs) {
		if diffs[pointer].Type == DiffEqual {
			equalities = append(equalities, pointer)
			lengthInsertions1 = lengthInsertions2
			lengthDeletions1 = lengthDeletions2
			lengthInsertions2 = 0
			lengthDeletions2 = 0
			lastequality = diffs[pointer].Text
		} else {
			if diffs[pointer].Type == DiffInsert {
				lengthInsertions2 += len(diffs[pointer].Text)
			} else {
				lengthDeletions2 += len(diffs[pointer].Text)
			}
			difference1 := int(math.Max(float64(lengthInsertions1), float64(lengthDeletions1)))
			difference2 := int(math.Max(float64(lengthInsertions2), float64(lengthDeletions2)))
			if len(lastequality) > 0 &&
				(len(lastequality) <= difference1) &&
				(len(lastequality) <= difference2) {
				insPoint := equalities[len(equalities)-1]
				diffs = splice(diffs, insPoint, 0, Diff{DiffDelete, lastequality})
				diffs[insPoint+1].Type = DiffInsert
				equalities = equalities[:len(equalities)-1]
				if len(equalities) > 0 {
					equalities = equalities[:len(equalities)-1]
				}
				pointer = -1
				if len(equalities) > 0 {
					pointer = equalities[len(equalities)-1]
				}
				lengthInsertions1 = 0  
				lengthDeletions1 = 0
				lengthInsertions2 = 0
				lengthDeletions2 = 0
				lastequality = ""
				changes = true
			}
		}
		pointer++
	}
	if changes {
		diffs = dmp.DiffCleanupMerge(diffs)
	}
	diffs = dmp.DiffCleanupSemanticLossless(diffs)
	pointer = 1
	for pointer < len(diffs) {
		if diffs[pointer-1].Type == DiffDelete &&
			diffs[pointer].Type == DiffInsert {
			deletion := diffs[pointer-1].Text
			insertion := diffs[pointer].Text
			overlapLength1 := dmp.DiffCommonOverlap(deletion, insertion)
			overlapLength2 := dmp.DiffCommonOverlap(insertion, deletion)
			if overlapLength1 >= overlapLength2 {
				if float64(overlapLength1) >= float64(len(deletion))/2 ||
					float64(overlapLength1) >= float64(len(insertion))/2 {
					diffs = splice(diffs, pointer, 0, Diff{DiffEqual, insertion[:overlapLength1]})
					diffs[pointer-1].Text =
						deletion[0 : len(deletion)-overlapLength1]
					diffs[pointer+1].Text = insertion[overlapLength1:]
					pointer++
				}
			} else {
				if float64(overlapLength2) >= float64(len(deletion))/2 ||
					float64(overlapLength2) >= float64(len(insertion))/2 {
					overlap := Diff{DiffEqual, deletion[:overlapLength2]}
					diffs = splice(diffs, pointer, 0, overlap)
					diffs[pointer-1].Type = DiffInsert
					diffs[pointer-1].Text = insertion[0 : len(insertion)-overlapLength2]
					diffs[pointer+1].Type = DiffDelete
					diffs[pointer+1].Text = deletion[overlapLength2:]
					pointer++
				}
			}
			pointer++
		}
		pointer++
	}
	return diffs
}
DiffCleanupSemantic reduces the number of edits by eliminating semantically trivial equalities.
package diffmatchpatch
import (
	"bytes"
	"errors"
	"fmt"
	"html"
	"math"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"
	"unicode/utf8"
)
type Operation int8
const (
	DiffDelete Operation = -1
	DiffInsert Operation = 1
	DiffEqual Operation = 0
)
type Diff struct {
	Type Operation
	Text string
}
func splice(slice []Diff, index int, amount int, elements ...Diff) []Diff {
	if len(elements) == amount {
		copy(slice[index:], elements)
		return slice
	}
	if len(elements) < amount {
		copy(slice[index:], elements)
		copy(slice[index+len(elements):], slice[index+amount:])
		end := len(slice) - amount + len(elements)
		tail := slice[end:]
		for i := range tail {
			tail[i] = Diff{}
		}
		return slice[:end]
	}
	need := len(slice) - amount + len(elements)
	for len(slice) < need {
		slice = append(slice, Diff{})
	}
	copy(slice[index+len(elements):], slice[index+amount:])
	copy(slice[index:], elements)
	return slice
}
func (dmp *DiffMatchPatch) DiffMain(text1, text2 string, checklines bool) []Diff {
	return dmp.DiffMainRunes([]rune(text1), []rune(text2), checklines)
}
func (dmp *DiffMatchPatch) DiffMainRunes(text1, text2 []rune, checklines bool) []Diff {
	var deadline time.Time
	if dmp.DiffTimeout > 0 {
		deadline = time.Now().Add(dmp.DiffTimeout)
	}
	return dmp.diffMainRunes(text1, text2, checklines, deadline)
}
func (dmp *DiffMatchPatch) diffMainRunes(text1, text2 []rune, checklines bool, deadline time.Time) []Diff {
	if runesEqual(text1, text2) {
		var diffs []Diff
		if len(text1) > 0 {
			diffs = append(diffs, Diff{DiffEqual, string(text1)})
		}
		return diffs
	}
	commonlength := commonPrefixLength(text1, text2)
	commonprefix := text1[:commonlength]
	text1 = text1[commonlength:]
	text2 = text2[commonlength:]
	commonlength = commonSuffixLength(text1, text2)
	commonsuffix := text1[len(text1)-commonlength:]
	text1 = text1[:len(text1)-commonlength]
	text2 = text2[:len(text2)-commonlength]
	diffs := dmp.diffCompute(text1, text2, checklines, deadline)
	if len(commonprefix) != 0 {
		diffs = append([]Diff{Diff{DiffEqual, string(commonprefix)}}, diffs...)
	}
	if len(commonsuffix) != 0 {
		diffs = append(diffs, Diff{DiffEqual, string(commonsuffix)})
	}
	return dmp.DiffCleanupMerge(diffs)
}
func (dmp *DiffMatchPatch) diffCompute(text1, text2 []rune, checklines bool, deadline time.Time) []Diff {
	diffs := []Diff{}
	if len(text1) == 0 {
		return append(diffs, Diff{DiffInsert, string(text2)})
	} else if len(text2) == 0 {
		return append(diffs, Diff{DiffDelete, string(text1)})
	}
	var longtext, shorttext []rune
	if len(text1) > len(text2) {
		longtext = text1
		shorttext = text2
	} else {
		longtext = text2
		shorttext = text1
	}
	if i := runesIndex(longtext, shorttext); i != -1 {
		op := DiffInsert
		if len(text1) > len(text2) {
			op = DiffDelete
		}
		return []Diff{
			Diff{op, string(longtext[:i])},
			Diff{DiffEqual, string(shorttext)},
			Diff{op, string(longtext[i+len(shorttext):])},
		}
	} else if len(shorttext) == 1 {
		return []Diff{
			Diff{DiffDelete, string(text1)},
			Diff{DiffInsert, string(text2)},
		}
	} else if hm := dmp.diffHalfMatch(text1, text2); hm != nil {
		text1A := hm[0]
		text1B := hm[1]
		text2A := hm[2]
		text2B := hm[3]
		midCommon := hm[4]
		diffsA := dmp.diffMainRunes(text1A, text2A, checklines, deadline)
		diffsB := dmp.diffMainRunes(text1B, text2B, checklines, deadline)
		diffs := diffsA
		diffs = append(diffs, Diff{DiffEqual, string(midCommon)})
		diffs = append(diffs, diffsB...)
		return diffs
	} else if checklines && len(text1) > 100 && len(text2) > 100 {
		return dmp.diffLineMode(text1, text2, deadline)
	}
	return dmp.diffBisect(text1, text2, deadline)
}
func (dmp *DiffMatchPatch) diffLineMode(text1, text2 []rune, deadline time.Time) []Diff {
	text1, text2, linearray := dmp.diffLinesToRunes(text1, text2)
	diffs := dmp.diffMainRunes(text1, text2, false, deadline)
	diffs = dmp.DiffCharsToLines(diffs, linearray)
	diffs = dmp.DiffCleanupSemantic(diffs)
	diffs = append(diffs, Diff{DiffEqual, ""})
	pointer := 0
	countDelete := 0
	countInsert := 0
	textDelete := ""
	textInsert := ""
	for pointer < len(diffs) {
		switch diffs[pointer].Type {
		case DiffInsert:
			countInsert++
			textInsert += diffs[pointer].Text
		case DiffDelete:
			countDelete++
			textDelete += diffs[pointer].Text
		case DiffEqual:
			if countDelete >= 1 && countInsert >= 1 {
				diffs = splice(diffs, pointer-countDelete-countInsert,
					countDelete+countInsert)
				pointer = pointer - countDelete - countInsert
				a := dmp.diffMainRunes([]rune(textDelete), []rune(textInsert), false, deadline)
				for j := len(a) - 1; j >= 0; j-- {
					diffs = splice(diffs, pointer, 0, a[j])
				}
				pointer = pointer + len(a)
			}
			countInsert = 0
			countDelete = 0
			textDelete = ""
			textInsert = ""
		}
		pointer++
	}
	return diffs[:len(diffs)-1]  
}
func (dmp *DiffMatchPatch) DiffBisect(text1, text2 string, deadline time.Time) []Diff {
	return dmp.diffBisect([]rune(text1), []rune(text2), deadline)
}
func (dmp *DiffMatchPatch) diffBisect(runes1, runes2 []rune, deadline time.Time) []Diff {
	runes1Len, runes2Len := len(runes1), len(runes2)
	maxD := (runes1Len + runes2Len + 1) / 2
	vOffset := maxD
	vLength := 2 * maxD
	v1 := make([]int, vLength)
	v2 := make([]int, vLength)
	for i := range v1 {
		v1[i] = -1
		v2[i] = -1
	}
	v1[vOffset+1] = 0
	v2[vOffset+1] = 0
	delta := runes1Len - runes2Len
	front := (delta%2 != 0)
	k1start := 0
	k1end := 0
	k2start := 0
	k2end := 0
	for d := 0; d < maxD; d++ {
		if !deadline.IsZero() && d%16 == 0 && time.Now().After(deadline) {
			break
		}
		for k1 := -d + k1start; k1 <= d-k1end; k1 += 2 {
			k1Offset := vOffset + k1
			var x1 int
			if k1 == -d || (k1 != d && v1[k1Offset-1] < v1[k1Offset+1]) {
				x1 = v1[k1Offset+1]
			} else {
				x1 = v1[k1Offset-1] + 1
			}
			y1 := x1 - k1
			for x1 < runes1Len && y1 < runes2Len {
				if runes1[x1] != runes2[y1] {
					break
				}
				x1++
				y1++
			}
			v1[k1Offset] = x1
			if x1 > runes1Len {
				k1end += 2
			} else if y1 > runes2Len {
				k1start += 2
			} else if front {
				k2Offset := vOffset + delta - k1
				if k2Offset >= 0 && k2Offset < vLength && v2[k2Offset] != -1 {
					x2 := runes1Len - v2[k2Offset]
					if x1 >= x2 {
						return dmp.diffBisectSplit(runes1, runes2, x1, y1, deadline)
					}
				}
			}
		}
		for k2 := -d + k2start; k2 <= d-k2end; k2 += 2 {
			k2Offset := vOffset + k2
			var x2 int
			if k2 == -d || (k2 != d && v2[k2Offset-1] < v2[k2Offset+1]) {
				x2 = v2[k2Offset+1]
			} else {
				x2 = v2[k2Offset-1] + 1
			}
			var y2 = x2 - k2
			for x2 < runes1Len && y2 < runes2Len {
				if runes1[runes1Len-x2-1] != runes2[runes2Len-y2-1] {
					break
				}
				x2++
				y2++
			}
			v2[k2Offset] = x2
			if x2 > runes1Len {
				k2end += 2
			} else if y2 > runes2Len {
				k2start += 2
			} else if !front {
				k1Offset := vOffset + delta - k2
				if k1Offset >= 0 && k1Offset < vLength && v1[k1Offset] != -1 {
					x1 := v1[k1Offset]
					y1 := vOffset + x1 - k1Offset
					x2 = runes1Len - x2
					if x1 >= x2 {
						return dmp.diffBisectSplit(runes1, runes2, x1, y1, deadline)
					}
				}
			}
		}
	}
	return []Diff{
		Diff{DiffDelete, string(runes1)},
		Diff{DiffInsert, string(runes2)},
	}
}
func (dmp *DiffMatchPatch) diffBisectSplit(runes1, runes2 []rune, x, y int,
	deadline time.Time) []Diff {
	runes1a := runes1[:x]
	runes2a := runes2[:y]
	runes1b := runes1[x:]
	runes2b := runes2[y:]
	diffs := dmp.diffMainRunes(runes1a, runes2a, false, deadline)
	diffsb := dmp.diffMainRunes(runes1b, runes2b, false, deadline)
	return append(diffs, diffsb...)
}
func (dmp *DiffMatchPatch) DiffLinesToChars(text1, text2 string) (string, string, []string) {
	chars1, chars2, lineArray := dmp.DiffLinesToRunes(text1, text2)
	return string(chars1), string(chars2), lineArray
}
func (dmp *DiffMatchPatch) DiffLinesToRunes(text1, text2 string) ([]rune, []rune, []string) {
	lineArray := []string{""}     
	lineHash := map[string]int{}  
	chars1 := dmp.diffLinesToRunesMunge(text1, &lineArray, lineHash)
	chars2 := dmp.diffLinesToRunesMunge(text2, &lineArray, lineHash)
	return chars1, chars2, lineArray
}
func (dmp *DiffMatchPatch) diffLinesToRunes(text1, text2 []rune) ([]rune, []rune, []string) {
	return dmp.DiffLinesToRunes(string(text1), string(text2))
}
func (dmp *DiffMatchPatch) diffLinesToRunesMunge(text string, lineArray *[]string, lineHash map[string]int) []rune {
	lineStart := 0
	lineEnd := -1
	runes := []rune{}
	for lineEnd < len(text)-1 {
		lineEnd = indexOf(text, "\n", lineStart)
		if lineEnd == -1 {
			lineEnd = len(text) - 1
		}
		line := text[lineStart : lineEnd+1]
		lineStart = lineEnd + 1
		lineValue, ok := lineHash[line]
		if ok {
			runes = append(runes, rune(lineValue))
		} else {
			*lineArray = append(*lineArray, line)
			lineHash[line] = len(*lineArray) - 1
			runes = append(runes, rune(len(*lineArray)-1))
		}
	}
	return runes
}
func (dmp *DiffMatchPatch) DiffCharsToLines(diffs []Diff, lineArray []string) []Diff {
	hydrated := make([]Diff, 0, len(diffs))
	for _, aDiff := range diffs {
		chars := aDiff.Text
		text := make([]string, len(chars))
		for i, r := range chars {
			text[i] = lineArray[r]
		}
		aDiff.Text = strings.Join(text, "")
		hydrated = append(hydrated, aDiff)
	}
	return hydrated
}
func (dmp *DiffMatchPatch) DiffCommonPrefix(text1, text2 string) int {
	return commonPrefixLength([]rune(text1), []rune(text2))
}
func (dmp *DiffMatchPatch) DiffCommonSuffix(text1, text2 string) int {
	return commonSuffixLength([]rune(text1), []rune(text2))
}
func commonPrefixLength(text1, text2 []rune) int {
	n := 0
	for ; n < len(text1) && n < len(text2); n++ {
		if text1[n] != text2[n] {
			return n
		}
	}
	return n
}
func commonSuffixLength(text1, text2 []rune) int {
	i1 := len(text1)
	i2 := len(text2)
	for n := 0; ; n++ {
		i1--
		i2--
		if i1 < 0 || i2 < 0 || text1[i1] != text2[i2] {
			return n
		}
	}
}
func (dmp *DiffMatchPatch) DiffCommonOverlap(text1 string, text2 string) int {
	text1Length := len(text1)
	text2Length := len(text2)
	if text1Length == 0 || text2Length == 0 {
		return 0
	}
	if text1Length > text2Length {
		text1 = text1[text1Length-text2Length:]
	} else if text1Length < text2Length {
		text2 = text2[0:text1Length]
	}
	textLength := int(math.Min(float64(text1Length), float64(text2Length)))
	if text1 == text2 {
		return textLength
	}
	best := 0
	length := 1
	for {
		pattern := text1[textLength-length:]
		found := strings.Index(text2, pattern)
		if found == -1 {
			break
		}
		length += found
		if found == 0 || text1[textLength-length:] == text2[0:length] {
			best = length
			length++
		}
	}
	return best
}
func (dmp *DiffMatchPatch) DiffHalfMatch(text1, text2 string) []string {
	runeSlices := dmp.diffHalfMatch([]rune(text1), []rune(text2))
	if runeSlices == nil {
		return nil
	}
	result := make([]string, len(runeSlices))
	for i, r := range runeSlices {
		result[i] = string(r)
	}
	return result
}
func (dmp *DiffMatchPatch) diffHalfMatch(text1, text2 []rune) [][]rune {
	if dmp.DiffTimeout <= 0 {
		return nil
	}
	var longtext, shorttext []rune
	if len(text1) > len(text2) {
		longtext = text1
		shorttext = text2
	} else {
		longtext = text2
		shorttext = text1
	}
	if len(longtext) < 4 || len(shorttext)*2 < len(longtext) {
		return nil  
	}
	hm1 := dmp.diffHalfMatchI(longtext, shorttext, int(float64(len(longtext)+3)/4))
	hm2 := dmp.diffHalfMatchI(longtext, shorttext, int(float64(len(longtext)+1)/2))
	hm := [][]rune{}
	if hm1 == nil && hm2 == nil {
		return nil
	} else if hm2 == nil {
		hm = hm1
	} else if hm1 == nil {
		hm = hm2
	} else {
		if len(hm1[4]) > len(hm2[4]) {
			hm = hm1
		} else {
			hm = hm2
		}
	}
	if len(text1) > len(text2) {
		return hm
	}
	return [][]rune{hm[2], hm[3], hm[0], hm[1], hm[4]}
}
func (dmp *DiffMatchPatch) diffHalfMatchI(l, s []rune, i int) [][]rune {
	var bestCommonA []rune
	var bestCommonB []rune
	var bestCommonLen int
	var bestLongtextA []rune
	var bestLongtextB []rune
	var bestShorttextA []rune
	var bestShorttextB []rune
	seed := l[i : i+len(l)/4]
	for j := runesIndexOf(s, seed, 0); j != -1; j = runesIndexOf(s, seed, j+1) {
		prefixLength := commonPrefixLength(l[i:], s[j:])
		suffixLength := commonSuffixLength(l[:i], s[:j])
		if bestCommonLen < suffixLength+prefixLength {
			bestCommonA = s[j-suffixLength : j]
			bestCommonB = s[j : j+prefixLength]
			bestCommonLen = len(bestCommonA) + len(bestCommonB)
			bestLongtextA = l[:i-suffixLength]
			bestLongtextB = l[i+prefixLength:]
			bestShorttextA = s[:j-suffixLength]
			bestShorttextB = s[j+prefixLength:]
		}
	}
	if bestCommonLen*2 < len(l) {
		return nil
	}
	return [][]rune{
		bestLongtextA,
		bestLongtextB,
		bestShorttextA,
		bestShorttextB,
		append(bestCommonA, bestCommonB...),
	}
}