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}
		}
	}
}
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
produces a * partial * update - call and apply repeatedly until a === b to get all the changes