anchor.diff:  %
   % Check if a node is a member of a bucket list
   %
  -b_is_member(ID, IP, Port, []) ->
  +b_is_member(_, _, _, []) ->
       false;
  -b_is_member(ID, IP, Port, [{Min, Max, Members}|T])
  +b_is_member(ID, IP, Port, [{Min, Max, Members}|_])
   when ?in_range(ID, Min, Max) ->
       lists:member({ID, IP, Port}, Members);
   b_is_member(ID, IP, Port, [_|T]) ->
  
positive.code:     {reply, OutputClose, State};
  
  
  handle_call({request_timeout, InputID, IP, Port}, From, State) ->
      ID = ensure_int_id(InputID),
      #state{
          buckets=Buckets,
          node_timeout=NTimeout,
          node_timers=PrevNTimers,
          node_access=NAccess} = State,
  
      NewState = case b_is_member(ID, IP, Port, Buckets) of
          false ->
              State;
          true ->
              NewNTimers = reset_node_timer(ID, IP, Port, NTimeout, PrevNTimers),
              State#state{node_timers=NewNTimers}
      end,
      {reply, ok, NewState};
  
  handle_call({request_success, InputID, IP, Port}, From, State) ->
      ID = ensure_int_id(InputID),
      #state{
          node_id=Self,
          buckets=Buckets,
          node_timeout=NTimeout,
          node_timers=PrevNTimers,
          node_access=PrevNAccess,
          buck_timers=PrevBTimers,
          buck_timeout=BTimeout} = State,
      NewState = case b_is_member(ID, IP, Port, Buckets) of
          false ->
              State;
          true ->
              NewNTimers  = reset_node_timer(ID, IP, Port, NTimeout, PrevNTimers),
              NewNAccess  = reset_node_access(ID, IP, Port, PrevNAccess),
              Bucket      = b_range(ID, Buckets),
              BMembers    = b_members(Bucket, Buckets),
              LeastRecent = n_least_recent(BMembers, NewNAccess),
              TmpBTimers  = cancel_bucket_timer(Bucket, PrevBTimers),
              NewBTimers  = init_bucket_timer(Bucket, LeastRecent, BTimeout, TmpBTimers),
              State#state{
                  node_timers=NewNTimers,
                  node_access=NewNAccess,
                  buck_timers=NewBTimers}
      end,
      {reply, ok, NewState};
  
  
  handle_call({request_from, ID, IP, Port}, From, State) ->
      {reply, ok, State};
  
  handle_call({dump_state}, _From, State) ->
      #state{
  
negative.code: %
  % Return the range of the bucket that a node falls within
  %
  b_range(ID, [{Min, Max, _}|_]) when ?in_range(ID, Min, Max) ->
      {Min, Max};
  b_range(ID, [_|T]) ->
      b_range(ID, T).
  
  
  
  inactive_nodes(Nodes, Timeout, Timers) ->
      [N || N <- Nodes, has_timed_out(N, Timeout, Timers)].
  
  timer_tree() ->
      gb_trees:empty().
  
  get_timer(Item, Timers) ->
      gb_trees:get(Item, Timers).
  
  add_timer(Item, ATime, TRef, Timers) ->
      TState = {ATime, TRef},
      gb_trees:insert(Item, TState, Timers).
  
  del_timer(Item, Timers) ->
      {_, TRef} = get_timer(Item, Timers),
      _ = erlang:cancel_timer(TRef),
      gb_trees:delete(Item, Timers).
  
  node_timer_from(Time, Timeout, {ID, IP, Port}) ->
      Msg = {inactive_node, ID, IP, Port},
      timer_from(Time, Timeout, Msg).
  
  bucket_timer_from(Time, BTimeout, LeastRecent, NTimeout, Range) ->
      % In the best case, the bucket should time out N seconds
      % after the first node in the bucket timed out. If that node
      % can't be replaced, a bucket refresh should be performed
      % at most every N seconds, based on when the bucket was last
      % marked as active, instead of _constantly_.
      Msg = {inactive_bucket, Range},
      if
          LeastRecent <  Time ->
              timer_from(Time, BTimeout, Msg);
          LeastRecent >= Time ->
              SumTimeout = NTimeout + NTimeout,
              timer_from(LeastRecent, SumTimeout, Msg)
      end.
      
  
  timer_from(Time, Timeout, Msg) ->
      Interval = ms_between(Time, Timeout),
      erlang:send_after(Interval, self(), Msg).
  
  ms_since(Time) ->
      timer:now_diff(Time, now()) div 1000.
  
  ms_between(Time, Timeout) ->
      MS = Timeout - ms_since(Time),
      if MS =< 0 -> Timeout;
         MS >= 0 -> MS
      end.
  
  has_timed_out(Item, Timeout, Times) ->
      {LastActive, _} = get_timer(Item, Times),
      ms_since(LastActive) > Timeout.
  
  least_recent([], _) ->
      now();
  least_recent(Items, Times) ->
      ATimes = [element(1, get_timer(I, Times)) || I <- Items],
      lists:min(ATimes).
  