anchor.diff:              let isEqOverlap = hasEqOverlap this appendMap
               if isEqOverlap then
                 let appC = appendMap.GetCursor();
  -              if appC.MoveAt(this.Last.Key, Lookup.GT) then
  +              if appC.MoveAt(this.LastUnsafe.Key, Lookup.GT) then
                   this.AddUnchecked(appC.CurrentKey, appC.CurrentValue) // TODO Add last when fixed flushing
                   let mutable c = 1
                   while appC.MoveNext() do
  
positive.code:       Interlocked.Increment(&this.version) |> ignore
        exitWriteLockIf &this.locker entered
        #if PRERELEASE
        if entered && this.version <> this.nextVersion then raise (ApplicationException("this.orderVersion <> this.nextVersion"))
        #else
        if entered && this.version <> this.nextVersion then Environment.FailFast("this.orderVersion <> this.nextVersion")
  
negative.code:       new SortedChunkedMapGenericCursor<_,_,_>(this)
      )
  
  //  member private this.GetCursorOld(outer:ICursor<'K,'TContainer>, isReset:bool,currentBatch:IReadOnlyOrderedMap<'K,'V>, isBatch:bool) : ICursor<'K,'V> =
  //    // TODO
  //    let nextBatch : Task<IReadOnlyOrderedMap<'K,'V>> ref = ref Unchecked.defaultof<Task<IReadOnlyOrderedMap<'K,'V>>>
  //    
  //    let outer = ref outer
  //    // Need to move, otherwise initial move is skipped in MoveAt, isReset knows that we haven't started in SCM even when outer is started
  //    let mutable inner = if outer.Value.MoveFirst() then try outer.Value.CurrentValue.GetCursor() with | _ -> Unchecked.defaultof<_> else Unchecked.defaultof<_>
  //    let isReset = ref isReset
  //    let mutable currentBatch : IReadOnlyOrderedMap<'K,'V> = currentBatch
  //    let isBatch = ref isBatch
  //
  //    let observerStarted = ref false
  //    let mutable semaphore : SemaphoreSlim = Unchecked.defaultof<_>
  //    let mutable are : AutoResetEvent =  Unchecked.defaultof<_>
  //    let onNextHandler : OnNextHandler<'K,'V> = 
  //      OnNextHandler(fun (kvp:KVP<'K,'V>) ->
  //          if semaphore.CurrentCount = 0 then semaphore.Release() |> ignore
  //      )
  //    let onCompletedHandler : OnCompletedHandler = 
  //      OnCompletedHandler(fun _ ->
  //          if semaphore.CurrentCount = 0 then semaphore.Release() |> ignore
  //      )
  //
  //    { new ICursor<'K,'V> with
  //        member c.Comparer: IComparer<'K> = comparer
  //        member c.Source with get() = this :> ISeries<_,_>
  //        member c.IsContinuous with get() = false
  //        member c.Clone() =
  //          let clone = this.GetCursorOld(outer.Value.Clone(), !isReset, currentBatch, !isBatch)
  //          if not !isReset then
  //            let moved = clone.MoveAt(c.CurrentKey, Lookup.EQ)
  //            if not moved then invalidOp "cannot correctly clone SCM cursor"
  //          clone
  //        
  //        member x.MoveNext(ct: CancellationToken): Task<bool> = 
  //          let rec completeTcs(tcs:AsyncTaskMethodBuilder<bool>, token: CancellationToken) : unit = // Task<bool> = 
  //            if x.MoveNext() then
  //              tcs.SetResult(true)
  //            else
  //              let semaphoreTask = semaphore.WaitAsync(-1, token)
  //              let awaiter = semaphoreTask.GetAwaiter()
  //              awaiter.UnsafeOnCompleted(fun _ ->
  //                match semaphoreTask.Status with
  //                | TaskStatus.RanToCompletion -> 
  //                  if x.MoveNext() then tcs.SetResult(true)
  //                  elif this.IsReadOnly then tcs.SetResult(false)
  //                  else completeTcs(tcs, token)
  //                | _ -> failwith "TODO process all task results"
  //                ()
  //              )
  //          match x.MoveNext() with
  //          | true -> trueTask            
  //          | false ->
  //            match this.IsReadOnly with
  //            | false ->
  //              let upd = this :> IObservableEvents<'K,'V>
  //              if not !observerStarted then
  //                semaphore <- new SemaphoreSlim(0,Int32.MaxValue)
  //                this.onNextEvent.Publish.AddHandler onNextHandler
  //                this.onCompletedEvent.Publish.AddHandler onCompletedHandler
  //                observerStarted := true
  //              let tcs = Runtime.CompilerServices.AsyncTaskMethodBuilder<bool>.Create()
  //              let returnTask = tcs.Task
  //              completeTcs(tcs, ct)
  //              returnTask
  //            | _ -> falseTask
  //
  //        member p.MovePrevious() = 
  //          let entered = enterLockIf this.SyncRoot this.IsSynchronized
  //          try
  //            if isReset.Value then p.MoveLast()
  //            else
  //              let res = inner.MovePrevious()
  //              if res then
  //                isBatch := false
  //                true
  //              else
  //                if outer.Value.MovePrevious() then // go to the previous bucket
  //                  inner <- outer.Value.CurrentValue.GetCursor()
  //                  let res = inner.MoveLast()
  //                  if res then
  //                    isBatch := false
  //                    true
  //                  else
  //                    raise (ApplicationException("Unexpected - empty bucket")) 
  //                else
  //                  false
  //          finally
  //            exitLockIf this.SyncRoot entered
  //
  //        // TODO (!) review the entire method for edge cases
  //        member p.MoveAt(key:'K, direction:Lookup) = 
  //          let entered = enterLockIf this.SyncRoot this.IsSynchronized
  //          try
  //            let res =
  //              if chunkUpperLimit = 0 then
  //                let hash = hasher.Hash(key)
  //                let c = 
  //                  if isReset.Value then 2 // <> 0 below
  //                  else comparer.Compare(hash, outer.Value.CurrentKey)
  //              
  //                if c <> 0 then // not in the current bucket, switch bucket
  //                  if outer.Value.MoveAt(hash, Lookup.EQ) then // Equal!
  //                    inner <- outer.Value.CurrentValue.GetCursor()
  //                    inner.MoveAt(key, direction)
  //                  else
  //                    false
  //                else
  //                  inner.MoveAt(key, direction)
  //              else
  //                if outer.Value.MoveAt(key, Lookup.LE) then // LE!
  //                  inner <- outer.Value.CurrentValue.GetCursor()
  //                  inner.MoveAt(key, direction)
  //                else
  //                  false
  //
  //            if res then
  //              isReset := false
  //              isBatch := false
  //              true
  //            else
  //                match direction with
  //                | Lookup.LT | Lookup.LE ->
  //                  // look into previous bucket
  //                  if outer.Value.MovePrevious() then
  //                    inner <- outer.Value.CurrentValue.GetCursor()
  //                    let res = inner.MoveAt(key, direction)
  //                    if res then
  //                      isBatch := false
  //                      isReset := false
  //                      true
  //                    else
  //                      p.Reset()
  //                      false
  //                  else
  //                    p.Reset()
  //                    false
  //                | Lookup.GT | Lookup.GE ->
  //                  // look into next bucket
  //                  let moved = outer.Value.MoveNext() 
  //                  if moved then
  //                    inner <- outer.Value.CurrentValue.GetCursor()
  //                    let res = inner.MoveAt(key, direction)
  //                    if res then
  //                      isBatch := false
  //                      isReset := false
  //                      true
  //                    else
  //                      p.Reset()
  //                      false 
  //                  else
  //                    p.Reset()
  //                    false 
  //                | _ -> false // LookupDirection.EQ
  //          finally
  //            exitLockIf this.SyncRoot entered
  //
  //        member p.MoveFirst() = 
  //          let entered = enterLockIf this.SyncRoot this.IsSynchronized
  //          try
  //            if this.IsEmpty then false
  //            else try p.MoveAt(this.First.Key, Lookup.EQ) with | _ -> false
  //          finally
  //            exitLockIf this.SyncRoot entered
  //
  //        member p.MoveLast() = 
  //          let entered = enterLockIf this.SyncRoot this.IsSynchronized
  //          try
  //            if this.IsEmpty then false
  //            else p.MoveAt(this.Last.Key, Lookup.EQ)
  //          finally
  //            exitLockIf this.SyncRoot entered
  //
  //        // TODO (v.0.2+) We now require that a false move keeps cursors on the same key before unsuccessfull move
  //        // Also, calling CurrentKey/Value must never throw, remove try/catch here to avoid muting error that should not happen
  //        //
  //        // (delete this) NB These are "undefined" when cursor is in invalid state, but they should not thow
  //        // Try/catch adds almost no overhead, even compared to null check, in the normal case. Calling these properties before move is 
  //        // an application error and should be logged or raise an assertion failure
  //        member c.CurrentKey with get() = try inner.CurrentKey with | _ -> Unchecked.defaultof<_>
  //        member c.CurrentValue with get() = try inner.CurrentValue with | _ -> Unchecked.defaultof<_>
  //        //member c.Current with get() : obj = box c.Current
  //        member c.TryGetValue(key: 'K, value: byref<'V>): bool = this.TryGetValue(key, &value)
  //
  //
  //
  //        member p.CurrentBatch = 
  //          if !isBatch then currentBatch
  //          else invalidOp "Current move is single, cannot return a batch"
  //
  //        member p.MoveNextBatch(ct) =
  //          Async.StartAsTask(async {
  //            let entered = enterLockIf this.SyncRoot this.IsSynchronized
  //            try
  //              if isReset.Value then 
  //                if outer.Value.MoveFirst() then
  //                  currentBatch <- outer.Value.CurrentValue :> IReadOnlyOrderedMap<'K,'V>
  //                  isBatch := true
  //                  isReset := false
  //                  return true
  //                else return false
  //              else
  //                if !isBatch then
  //                  let couldMove = outer.Value.MoveNext() // ct |> Async.AwaitTask // NB not async move next!
  //                  if couldMove then
  //                    currentBatch <- outer.Value.CurrentValue :> IReadOnlyOrderedMap<'K,'V>
  //                    isBatch := true
  //                    return true
  //                  else 
  //                    // no batch, but place cursor at the end of the last batch so that move next won't get null reference exception
  //                    inner <- outer.Value.CurrentValue.GetCursor()
  //                    if not outer.Value.CurrentValue.IsEmpty then inner.MoveLast() |> ignore
  //                    return false
  //                else
  //                  return false
  //            finally
  //              exitLockIf this.SyncRoot entered
  //          }, TaskCreationOptions.None, ct)
  //
  //      interface IEnumerator<KVP<'K,'V>> with
  //        member p.Reset() = 
  //          if not !isReset then
  //            outer.Value.Reset()
  //            outer.Value.MoveFirst() |> ignore
  //            //inner.Reset()
  //            inner <- Unchecked.defaultof<_>
  //            isReset := true
  //
  //        member p.Dispose() = 
  //            p.Reset()
  //            if !observerStarted then
  //              this.onNextEvent.Publish.RemoveHandler(onNextHandler)
  //              this.onCompletedEvent.Publish.RemoveHandler(onCompletedHandler)
  //        
  //        member p.MoveNext() = 
  //          let entered = enterLockIf this.SyncRoot this.IsSynchronized
  //          try
  //            if isReset.Value then (p :?> ICursor<'K,'V>).MoveFirst()
  //            else
  //              let res = inner.MoveNext() // could pass curent key by ref and save some single-dig %
  //              if res then
  //                if !isBatch then isBatch := false
  //                true
  //              else
  //                //let currentKey = inner.CurrentKey
  //                if outer.Value.MoveNext() then // go to the next bucket
  //                  inner <- outer.Value.CurrentValue.GetCursor()
  //                  let res = inner.MoveFirst()
  //                  if res then
  //                    isBatch := false
  //                    true
  //                  else
  //                    raise (ApplicationException("Unexpected - empty bucket")) 
  //                else
  //                  //p.MoveAt(currentKey, Lookup.GT)
  //                  false
  //          finally
  //            exitLockIf this.SyncRoot entered
  //
  //        member c.Current 
  //          with get() =
  //            if !isBatch then invalidOp "Current move is MoveNextBatxhAsync, cannot return a single valule"
  //            else inner.Current
  //        member this.Current with get(): obj = this.Current :> obj
  //    }
  //
  
    member private this.TryFindTuple(key:'K, direction:Lookup) = 
      let tupleResult =
  