anchor.diff:  %%%_* Printing a B-tree (for debugging) ========================================
   
   print(IO, #btree{root = A}) ->
  -  print(IO, A, 1).
  -
  -print(_IO, ?NOPAGEID, _L) ->
  +  print_pageid(IO, A, 1).
  +
  +print_pageid(_IO, ?NOPAGEID, _L) ->
     ok;
  -print(IO, PageId, L) ->
  -  #page{p0 = P0, e = E} = page_read(IO, PageId),
  +print_pageid(IO, PageId, L) ->
  +  print_page(IO, page_read(IO, PageId), L).
  +
  +print_page(IO, #page{p0 = P0, e = E}, L) ->
     [io:format("     ") || _I <- lists:seq(1, L)],
     [io:format(" ~4w", [(element(I, E))#item.k]) || I <- lists:seq(1, size(E))],
     io:format("~n"),
  -  print(IO, P0, L + 1),
  -  [print(IO, (element(I, E))#item.p, L + 1) || I <- lists:seq(1, size(E))],
  +  print_pageid(IO, P0, L + 1),
  +  [print_pageid(IO, (element(I, E))#item.p, L + 1) || I <- lists:seq(1, size(E))],
     ok.
   
   %%%_* Emacs ====================================================================
  
positive.code: 
  -record(item,
          { k :: term()
          , p :: pageid_opt() % subtree with keys k' > k
          }).
  
  %% A page is an array of m keys and m+1 page references, constrained
  
negative.code: %%% Search and delete key X in B-tree A; if a page underflow is
  %%% necessary, balance with adjacent page if possible, otherwise merge;
  %%% return true if page A becomes undersize.
  delete(_Cache, _N, _X, ?NOPAGEID) ->
    ?dbg("delete(~p, ~p)~n", [_X, ?NOPAGEID]),
    false;
  delete(Cache1, N, X, APageId) ->
    {Cache2, A} = cache_read(Cache1, APageId),
    delete(Cache2, N, X, APageId, A).
  
  delete(Cache2, N, X, APageId, A = #page{p0 = AP0, e = AE}) ->
    ?dbg("delete(~p, ~p)~n", [X, A]),
    case binsearch(AE, X) of
      {found, K} ->
        %% found, now delete a^.e[k]
        R = K - 1,
        QPageId =
          if R =:= 0 -> AP0;
             true -> (element(R, AE))#item.p
          end,
        if QPageId =:= ?NOPAGEID ->
            %% a is a terminal page
            AE2 = erlang:delete_element(K, AE),
            Cache3 = cache_write(Cache2, A#page{e = AE2}),
            {Cache3, size(AE2) < N};
           true ->
            case del(Cache2, N, QPageId, APageId, K) of
              {Cache3, true} ->
                underflow(Cache3, N, APageId, QPageId, R);
              {Cache3, false} ->
                {Cache3, false}
            end
        end;
      {not_found, R} ->
        QPageId =
          if R =:= 0 -> AP0;
             true -> (element(R, AE))#item.p
          end,
        case delete(Cache2, N, X, QPageId) of
          {Cache3, true} ->
            underflow(Cache3, N, APageId, QPageId, R);
          {Cache3, false} ->
            {Cache3, false}
        end
    end.
  
  