anchor.diff:  %% @doc Converts the (external) representation of the routing table to a list
   %%      in the order of the fingers, i.e. first=succ, second=shortest finger,
   %%      third=next longer finger,...
  -%% XXX Filters the source node
  -%% TODO the order is not the same as described in the documentation
  --spec to_list(dht_node_state:state()) -> nodelist:snodelist().
  -to_list(State) -> lists:sort(
  -        fun(A, B) -> entry_nodeid(A) =< entry_nodeid(B) end
  -        , [X || X <- gb_trees:values(State), not is_source(X)]).
  +to_list(#rt_t{} = RT) ->
  +    SourceNode = get_source_node(RT),
  +    % sort
  +    Sorted = lists:sort(fun(A, B) -> entry_nodeid(A) =< entry_nodeid(B) end,
  +        [X || X <- gb_trees:values(get_rt_tree(RT))]),
  +    % rearrange elements: all until the source node must be attached at the end
  +    {Front, Tail} = lists:splitwith(fun(N) ->
  +                entry_nodeid(N) =:= SourceNode end, Sorted),
  +    TailNoSourceNode = case Tail of
  +        [SourceNode] -> [];
  +        [SourceNode|T] -> T
  +    end,
  +    % TODO inefficient -> reimplement with foldl
  +    TailNoSourceNode ++ Front
  +    ;
  +to_list(State) -> % match external RT
  +    RT = dht_node_state:get(State, rt),
  +    to_list(RT)
  +    .
   %% userdevguide-end rt_frtchord:to_list
   
   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   % FRT specific algorithms and functions
   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  -add_sticky_entry(Entry, RT) ->
  -    Sticky = #rt_entry{
  +
  +% @doc Filter one element from a set of nodes. Do it in a way that filters such a node
  +% that the resulting routing table is the best one under all _possible_ routing tables.
  +entry_filtering(RT, AllowedNodes) ->
  +    Spacings = [
  +        begin
  +            PredNode = predecessor_node(RT,Node),
  +            {Node, spacing(Node) + spacing(PredNode)}
  +        end || Node <- AllowedNodes],
  +    % remove the element with the smallest canonical spacing range between its predecessor
  +    % and its successor. TODO beware of numerical errors!
  +    {FilterEntry, _Spacing} = hd(lists:sort(
  +            fun ({_,SpacingA}, {_, SpacingB})
  +                        -> SpacingA =< SpacingB
  +            end, Spacings)
  +      ),
  +    entry_delete(entry_nodeid(FilterEntry), RT)
  +    .
  +
  +% @doc Delete an entry from the routing table
  +entry_delete(EntryKey, RT) ->
  +    Tree = gb_trees:delete(EntryKey, get_rt_tree(RT)),
  +    RT#rt_t{nodes=Tree}.
  +
  +% @doc Add a new entry to the routing table. A source node is only allowed to be added
  +% once.
  +entry_learn(#rt_entry{type=source} = Entry, #rt_t{source=undefined} = RT) -> 
  +    entry_learn(Entry, RT#rt_t{source=entry_nodeid(Entry)})
  +    ;
  +entry_learn(Entry, RT) -> 
  +    Nodes = gb_trees:enter(entry_nodeid(Entry), Entry, get_rt_tree(RT)),
  +    rt_set_nodes(RT, Nodes)
  +    .
  +
  +% @doc Combines entry learning and entry filtering.
  +entry_learning_and_filtering(Entry, RT) ->
  +    IntermediateRT = entry_learn(Entry, RT),
  +    SizeOfRT = get_size(IntermediateRT),
  +    MaxEntries = maximum_entries(),
  +    if SizeOfRT >= MaxEntries ->
  +            AllowedNodes = [N || N <- to_list(RT),
  +                not is_sticky(N) and not is_source(N)],
  +            entry_filtering(IntermediateRT, AllowedNodes);
  +        true -> IntermediateRT
  +    end.
  +
  +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  +% RT and RT entry record accessors
  +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  +% @private
  +
  +% @doc Get the source node of a routing table
  +% XXX using any() as return as dialyzer complains when using rt_entry()
  +get_source_node(#rt_t{source=undefined}) ->
  +    exit("routing table source unknown");
  +get_source_node(#rt_t{source=Node} = RT) -> gb_trees:get(Node, RT#rt_t.nodes).
  +
  +% @doc Get the gb_tree of the routing table containing its nodes
  +get_rt_tree(#rt_t{nodes=Nodes}) -> Nodes.
  +
  +% @doc Check if a node exists in the routing table
  +entry_exists(EntryKey, #rt_t{nodes=Nodes}) ->
  +    case gb_trees:lookup(EntryKey, Nodes) of
  +        none -> false;
  +        _Else -> true
  +    end.
  +
  +-spec add_entry(Entry :: rt_entry() | node:node_type(),
  +    entry_type(),
  +    RT :: rt()) -> rt().
  +add_entry(#rt_entry{node=Entry}, Type, RT) ->
  +    add_entry(Entry, Type, RT);
  +add_entry(Entry, Type, RT) ->
  +    NewNode = #rt_entry{
           node = Entry,
  -        type = sticky
  +        id   = node:id(Entry),
  +        type = Type
       },
  -    entry_learn(Sticky, RT)
  -    .
  -
  -add_source_entry(Entry, RT) ->
  -    Source = #rt_entry{
  -        node = Entry,
  -        type = source
  -    },
  -    entry_learn(Source, RT)
  -    .
  +    entry_learning_and_filtering(NewNode, RT)
  +    .
  +
  +% @doc Add a sticky entry to the routing table
  +% TODO add adjacent fingers if possible
  +add_sticky_entry(Entry, RT) -> add_entry(Entry, sticky, RT).
  +
  +% @doc Add the source entry to the routing table
  +% TODO unit test that only one source entry is allowed
  +% TODO add adjacent fingers if possible
  +add_source_entry(Entry, RT) -> add_entry(Entry, source, RT).
  +
  +% @doc Add a normal entry to the routing table
  +% TODO add adjacent fingers if possible
  +add_normal_entry(Entry, RT) -> add_entry(Entry, normal, RT).
  +
  +rt_entry_node(#rt_entry{node=N}) -> N.
  +
  +rt_set_nodes(RT, Nodes) ->
  +    RT#rt_t{nodes=Nodes}.
   
   %% is the given node the source entry?
   entry_is_of_type(#rt_entry{type=Type}, Type) -> true;
  
positive.code: %%      Begin==End, the whole key range is split in halves.
  %%      Beware: SplitFactor must be in [0, 1]; the final key will be rounded
  %%      down and may thus be Begin.
  -spec get_split_key(Begin::key(), End::key() | ?PLUS_INFINITY_TYPE, SplitFraction::{Num::0..100, Denom::0..100}) -> key().
  get_split_key(Begin, _End, {Num, _Denom}) when Num == 0 -> Begin;
  get_split_key(_Begin, End, {Num, Denom}) when Num == Denom -> End;
  get_split_key(Begin, End, {Num, Denom}) ->
  
negative.code: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  %% userdevguide-begin rt_frtchord:empty_ext
  empty_ext(Neighbors) -> empty(Neighbors).
  %% userdevguide-end rt_frtchord:empty_ext
  
  %% userdevguide-begin rt_frtchord:next_hop
  %% @doc Returns the next hop to contact for a lookup.
  %% TODO Next hop contains type errors
  next_hop(State, Id) ->
      Neighbors = dht_node_state:get(State, neighbors),
      case intervals:in(Id, nodelist:succ_range(Neighbors)) of
          true -> node:pidX(nodelist:succ(Neighbors));
          _ ->
              % check routing table:
              RT = dht_node_state:get(State, rt),
              RTSize = get_size(RT),
              NodeRT = case util:gb_trees_largest_smaller_than(Id, RT) of
                           {value, _Key, N} ->
                               N;
                           nil when RTSize =:= 0 ->
                               nodelist:succ(Neighbors);
                           nil -> % forward to largest finger
                               {_Key, N} = gb_trees:largest(get_rt_tree(RT)),
                               N
                       end,
              FinalNode =
                  case RTSize < config:read(rt_size_use_neighbors) of
                      false -> NodeRT;
                      _     ->
                          % check neighborhood:
                          nodelist:largest_smaller_than(Neighbors, Id, NodeRT)
                  end,
              node:pidX(FinalNode)
      end.
  %% userdevguide-end rt_frtchord:next_hop
  
  %% userdevguide-begin rt_frtchord:export_rt_to_dht_node
  %% @doc Converts the internal RT to the external RT used by the dht_node.
  %% TODO
  export_rt_to_dht_node(RT, _Neighbors) -> RT.
  %% userdevguide-end rt_frtchord:export_rt_to_dht_node
  
  