anchor.diff:  code_change(_, _, State) ->
       {ok, State}.
   
  -
  -is_disconnected(ID, IP, Port, Timeout, AccessTimes) ->
  -    LastActive = gb_trees:get({ID, IP, Port}, AccessTimes),
  -    (timer:now_diff(LastActive, now()) div 1000) > Timeout.
  -
  -disconnected(Nodes, Timeout, AccessTimes) ->
  -    [N || {ID, IP, Port}=N <- Nodes,
  -    is_disconnected(ID, IP, Port, Timeout, AccessTimes)].
  -
  -nodes_by_access(Nodes, AccessTimes) ->
  -    GetTime  = fun({_, _, _}=N) -> gb_trees:get(N, AccessTimes) end,
  -    WithTime = [{GetTime(N), ID, IP, Port} || {ID, IP, Port}=N <- Nodes],
  -    ByTime   = lists:sort(WithTime),
  -    [{ID, IP, Port} || {_, ID, IP, Port} <- ByTime].
  -
  -
  -reset_node_timer(ID, IP, Port, Timeout, Timers) ->
  -    init_node_timer(ID, IP, Port, Timeout,
  -        cancel_node_timer(ID, IP, Port, Timers)).
  -
  -init_node_timer(ID, IP, Port, Timeout, Timers) -> 
  -    Msg = {inactive_node, ID, IP, Port},
  -    Ref = erlang:send_after(Timeout, self(), Msg),
  -    gb_trees:insert({ID, IP, Port}, Ref, Timers).
  -
  -cancel_node_timer(ID, IP, Port, Timers) ->
  -    Ref = gb_trees:get({ID, IP, Port}, Timers),
  -    erlang:cancel_timer(Ref),
  -    gb_trees:delete({ID, IP, Port}, Timers).
  -
  -reset_node_access(ID, IP, Port, Access) ->
  -    init_node_access(ID, IP, Port,
  -        clear_node_access(ID, IP, Port, Access)).
  -
  -init_node_access(ID, IP, Port, Access) ->
  -    gb_trees:insert({ID, IP, Port}, now(), Access).
  -
  -clear_node_access(ID, IP, Port, Access) ->
  -    gb_trees:delete({ID, IP, Port}, Access).
  -
  --define(K, 8). 
  --define(in_range(IDExpr, MinExpr, MaxExpr),
  -    ((IDExpr >= MinExpr) and (IDExpr < MaxExpr))).
   
   %
   % Create a new bucket list
  
positive.code: 
      % If the new node replaced a new, remove all timer and access time
      % information from the state
      {TmpNTimers, TmpNAccess} = case Deleted of
          none ->
              {PrevNTimers, PrevNAccess};
          {DID, DIP, DPort} ->
              {cancel_node_timer(DID, DIP, DPort, PrevNTimers),
               clear_node_access(DID, DIP, DPort, PrevNAccess)}
      end,
  
  
  
      IsNewMember = b_is_member(ID, IP, Port, NewBuckets),
      {NewNTimers, NewNAccess} = case {IsPrevMember, IsNewMember} of
          {false, false} ->
              {TmpNTimers, TmpNAccess};
  
          {true, true} ->
              {TmpNTimers, TmpNAccess};
          
          {false, true} ->
              {init_node_timer(ID, IP, Port, NTimeout, TmpNTimers),
               init_node_access(ID, IP, Port, TmpNAccess)}
      end,
  
      NewBTimers = case {IsPrevMember, IsNewMember} of
          {false, false} ->
              % No changes, the old node timers are still valid
              PrevBTimers;
          {true, true} ->
              PrevBTimers;
  
          {false, true} ->
              % The bucket set may have changed, The least recently active
              % node in the affected buckets may also have changed.
              % Reset all bucket timers to be sure.
              TmpBTimers = lists:foldl(fun(Range, Acc) ->
                  cancel_bucket_timer(Range, Acc)
              end, PrevBTimers, b_ranges(PrevBuckets)),
              
              CaseBTimers = lists:foldl(fun(Range, Acc) ->
                  TmpBMembers = b_members(Range, NewBuckets),
                  LeastRecent = n_least_recent(TmpBMembers, NewNAccess),
                  init_bucket_timer(Range, LeastRecent, BTimeout, Acc)
              end, TmpBTimers, b_ranges(NewBuckets)),
              CaseBTimers
      end, 
      B0 = lists:sort(gb_trees:keys(NewBTimers)),
      B1 = lists:sort(b_ranges(NewBuckets)),
      true = (B0 == B1),
      NewState = State#state{
          buckets=NewBuckets,
          node_timers=NewNTimers,
          node_access=NewNAccess,
          buck_timers=NewBTimers},
      {reply, ok, NewState};
              
  
  
  
  handle_call({closest_to, InputNodeID, NumNodes}, From, State) ->
      NodeID = ensure_int_id(InputNodeID),
      #state{buckets=Buckets} = State,
      Nodes = b_node_list(Buckets),
  
negative.code: 
  handle_info({inactive_node, InputID, IP, Port}, State) ->
      ID = ensure_int_id(InputID),
      Now = now(),
      Node = {ID, IP, Port},
      #state{
          buckets=Buckets,
          node_timers=PrevNTimers,
          node_timeout=NTimeout} = State,
      
      IsMember = b_is_member(ID, IP, Port, Buckets),
      HasTimed = case IsMember of
          false -> false;
          true  -> has_timed_out(Node, NTimeout, PrevNTimers)
      end,
  
      NewState = case {IsMember, HasTimed} of
          {false, false} ->
              State;
          {true, false} ->
              State;
          {true, true} ->
              info_msg("Node at ~w:~w timed out", [IP, Port]),
              spawn_keepalive(ensure_bin_id(ID), IP, Port),
              {LActive,_} = get_timer(Node, PrevNTimers),
              TmpNTimers  = del_timer(Node, PrevNTimers),
              NewTimer    = node_timer_from(Now, NTimeout, Node),
              NewNTimers  = add_timer(Node, LActive, NewTimer, TmpNTimers),
              State#state{node_timers=NewNTimers}
      end,
      {noreply, NewState};
  
  handle_info({inactive_bucket, Range}, State) ->
      Now = now(),
      #state{
          buckets=Buckets,
          node_timers=NTimers,
          buck_timers=PrevBTimers,
          node_timeout=NTimeout,
          buck_timeout=BTimeout} = State,
  
      BucketExists = b_has_bucket(Range, Buckets),
      HasTimed = case BucketExists of
          false -> false;
          true  -> has_timed_out(Range, BTimeout, PrevBTimers)
      end,
  
      NewState = case {BucketExists, HasTimed} of
          {false, false} ->
              State;
          {true, false} ->
              State;
          {true, true} ->
              info_msg("Bucket timed out", []),
              TmpBTimers = del_timer(Range, PrevBTimers),
              BMembers   = b_members(Range, Buckets),
              LRecent    = least_recent(BMembers, NTimers),
              NewTimer   = bucket_timer_from(
                              Now, BTimeout, LRecent, NTimeout, Range),
              NewBTimers = add_timer(Range, Now, NewTimer, TmpBTimers),
              State#state{buck_timers=NewBTimers}
      end,
      {noreply, NewState}.
  