server/wraputil.js
function makeSyncOpGenericGetChangesBetween(handle, ws, rel, recurse, paramFuncs){

	//paramFuncs.forEach(function(pf){
	for(var i=0;i<paramFuncs.length;++i){
		var pf = paramFuncs[i]
		if(pf.isMacro){
			//_.errout('cannot apply this method if a param is a macro: ' + JSON.stringify(rel))
			return makeGenericGetChangesBetween(handle, ws, rel)
		}
	}
	//})
	//console.log(new Error().stack)
	function syncGenericGetChangesBetween(bindings, startEditId, endEditId, cb){
		_.assertLength(arguments, 4)
		
		if(startEditId === endEditId) _.errout('wasting time')
		
		var snaps = []
		
		var editIds = []
		var has = {}
		
		//console.log('getting ' + JSON.stringify(rel))
		
		var cdl = _.latch(paramFuncs.length, function(){
			if(editIds.length === 0){
				//console.log('no changes ' + startEditId + ' ' + endEditId)
				cb([])
				return
			}
			
			handle.getStateAt(bindings, startEditId, function(startState){
				handle.getStateAt(bindings, endEditId, function(state){
					if(startState === state){
						cb([])
					}else{
						var es = ws.diffFinder(startState, state)
						var changes = []
						es.forEach(function(e){
							e.editId = endEditId
							changes.push(e)
						})
						cb(changes)
					}
				})
			})
		})
		//console.log('here2')
		for(var i=0;i<paramFuncs.length;++i){
			paramFuncs[i].getChangesBetween(bindings, startEditId, endEditId, function(changes){
				changes.forEach(function(c){
					var editId = c.editId
					if(has[editId]) return
					has[editId] = true
					editIds.push(editId)
				})
						
				cdl()
			})
		}
	}
	return syncGenericGetChangesBetween
}
function makeSyncOpGenericGetChangesBetween(handle, ws, rel, recurse, paramFuncs){

	//paramFuncs.forEach(function(pf){
	for(var i=0;i<paramFuncs.length;++i){
		var pf = paramFuncs[i]
		if(pf.isMacro){
			//_.errout('cannot apply this method if a param is a macro: ' + JSON.stringify(rel))
			return makeGenericGetChangesBetween(handle, ws, rel)
		}
	}
	//})
	//console.log(new Error().stack)
	function syncGenericGetChangesBetween(bindings, startEditId, endEditId, cb){
		_.assertLength(arguments, 4)
		
		if(startEditId === endEditId) _.errout('wasting time')
		
		var snaps = []
		
		var editIds = []
		var has = {}
		
		//console.log('getting ' + JSON.stringify(rel))
		
		var cdl = _.latch(paramFuncs.length, function(){
			if(editIds.length === 0){
				//console.log('no changes ' + startEditId + ' ' + endEditId)
				cb([])
				return
			}
			
			handle.getStateAt(bindings, startEditId, function(startState){
				handle.getStateAt(bindings, endEditId, function(state){
					if(startState === state){
						cb([])
					}else{
						var es = ws.diffFinder(startState, state)
						var changes = []
						es.forEach(function(e){
							e.editId = endEditId
							changes.push(e)
						})
						cb(changes)
					}
				})
			})
		})
		//console.log('here2')
		for(var i=0;i<paramFuncs.length;++i){
			paramFuncs[i].getChangesBetween(bindings, startEditId, endEditId, function(changes){
				changes.forEach(function(c){
					var editId = c.editId
					if(has[editId]) return
					has[editId] = true
					editIds.push(editId)
				})
						
				cdl()
			})
		}
	}
	return syncGenericGetChangesBetween
}
function makeSyncOpGenericGetChangesBetween ( handle , ws , rel , recurse , paramFuncs ) { //paramFuncs.forEach(function(pf){ for ( var i = 0 ; i < paramFuncs . length ; ++ i ) { var pf = paramFuncs [ i ] if ( pf . isMacro ) { //_.errout('cannot apply this method if a param is a macro: ' + JSON.stringify(rel)) return makeGenericGetChangesBetween ( handle , ws , rel ) } } //}) //console.log(new Error().stack) function syncGenericGetChangesBetween ( bindings , startEditId , endEditId , cb ) { _ . assertLength ( arguments , 4 ) if ( startEditId === endEditId ) _ . errout ( 'wasting time' ) var snaps = [ ] var editIds = [ ] var has = { } //console.log('getting ' + JSON.stringify(rel)) var cdl = _ . latch ( paramFuncs . length , function ( ) { if ( editIds . length === 0 ) { //console.log('no changes ' + startEditId + ' ' + endEditId) cb ( [ ] ) return } handle . getStateAt ( bindings , startEditId , function ( startState ) { handle . getStateAt ( bindings , endEditId , function ( state ) { if ( startState === state ) { cb ( [ ] ) } else { var es = ws . diffFinder ( startState , state ) var changes = [ ] es . forEach ( function ( e ) { e . editId = endEditId changes . push ( e ) } ) cb ( changes ) } } ) } ) } ) //console.log('here2') for ( var i = 0 ; i < paramFuncs . length ; ++ i ) { paramFuncs [ i ] . getChangesBetween ( bindings , startEditId , endEditId , function ( changes ) { changes . forEach ( function ( c ) { var editId = c . editId if ( has [ editId ] ) return has [ editId ] = true editIds . push ( editId ) } ) cdl ( ) } ) } } return syncGenericGetChangesBetween }
function makeReallyGenericSyncOpGenericGetChangesBetween( find the union of the changed versions for the input parameters, use that to reduce the number of comparisons necessary
function makeReallyGenericSyncOpGenericGetChangesBetween ( find the union of the changed versions for the input parameters use that to reduce the number of comparisons necessary