http/js/api/string.js
function partiallyDiffText(a,b){
	if(b.length >= a.length){
		for(var i=0;i<a.length;++i){
			if(a[i] !== b[i]) break
		}
		var fi = i
		
		if(fi === a.length){
			return {type: 'add', index: fi, value: b.substr(fi)}
		}else{

			var ea = a.substr(fi)
			var eb = b.substr(fi)
		
			for(var i=0;i<ea.length;++i){
				if(ea[ea.length-i-1] !== eb[eb.length-i-1]){
					break
				}
			}

			var tailLength = i
			
			if(b.length-tailLength-fi > b.length-a.length){//if the changed region is larger than the difference in length	
				var manyToRemove = (b.length-tailLength-fi)-(b.length-a.length)
				return {type: 'remove', index: fi, many: manyToRemove}
			}else{
				return {type: 'add', index: fi, value: b.substring(fi,b.length-tailLength)}
			}
		}
	}else{
		var c = partiallyDiffText(b,a)
		if(c.type === 'remove'){
			return {type: 'add', index: c.index, value: b.substr(c.index,c.many)}
		}else{
			return {type: 'remove', index: c.index, many: c.value.length}
		}
	}
}
function partiallyDiffText(a,b){
	if(b.length >= a.length){
		for(var i=0;i<a.length;++i){
			if(a[i] !== b[i]) break
		}
		var fi = i
		
		if(fi === a.length){
			return {type: 'add', index: fi, value: b.substr(fi)}
		}else{

			var ea = a.substr(fi)
			var eb = b.substr(fi)
		
			for(var i=0;i<ea.length;++i){
				if(ea[ea.length-i-1] !== eb[eb.length-i-1]){
					break
				}
			}

			var tailLength = i
			
			if(b.length-tailLength-fi > b.length-a.length){//if the changed region is larger than the difference in length	
				var manyToRemove = (b.length-tailLength-fi)-(b.length-a.length)
				return {type: 'remove', index: fi, many: manyToRemove}
			}else{
				return {type: 'add', index: fi, value: b.substring(fi,b.length-tailLength)}
			}
		}
	}else{
		var c = partiallyDiffText(b,a)
		if(c.type === 'remove'){
			return {type: 'add', index: c.index, value: b.substr(c.index,c.many)}
		}else{
			return {type: 'remove', index: c.index, many: c.value.length}
		}
	}
}
produces a *partial* update - call and apply repeatedly until a===b to get all the changes