anchor.diff:  
   
   -record(state, {
  -    endgame  :: etorrent_endgame:originhandle(),
       receiver :: pid(),
       table :: ets:tid()}).
   
  
positive.code: start_link(TorrentID) ->
      gen_server:start_link(?MODULE, [TorrentID], []).
  
  
  %% @doc
  %% @end
  -spec peerhandle(torrent_id()) -> peerhandle().
  peerhandle(TorrentID) ->
      SrvPid = await_server(TorrentID),
      gen_server:call(SrvPid, {register_peer, self()}),
      {peer, SrvPid}.
  
  
  %% @doc
  %% @end
  -spec originhandle(torrent_id()) -> originhandle().
  originhandle(TorrentID) ->
      SrvPid = await_server(TorrentID),
      {origin, SrvPid}.
  
  
  %% @doc
  %% @end
  -spec start_endgame(originhandle()) -> ok.
  start_endgame({origin, SrvPid}) ->
      ok = gen_server:call(SrvPid, start_endgame),
      Ref = self() ! make_ref(),
      bounce_dropped(SrvPid, Ref).
  
  bounce_dropped(SrvPid, Ref) ->
      receive
          {dropped, Index, Offset, Length} ->
              mark_dropped_(SrvPid, Index, Offset, Length),
              bounce_dropped(SrvPid, Ref);
          Ref -> ok
      end.
  
  
  %% @doc
  %% @end
  -spec mark_sent(pieceindex(), chunkoffset(), chunklength(),
                  pid(), originhandle()) -> ok.
  mark_sent(Piece, Offset, Length, Pid, {origin, SrvPid}) ->
      gen_server:cast(SrvPid, {mark_sent, Pid, Piece, Offset, Length}).
  
  
  %% @doc
  %% @end
  -spec mark_dropped(pieceindex(), chunkoffset(), chunklength(), peerhandle()) -> ok.
  mark_dropped(Piece, Offset, Length, {peer, SrvPid}) ->
      mark_dropped_(SrvPid, Piece, Offset, Length).
  
  mark_dropped_(SrvPid, Piece, Offset, Length) ->
      gen_server:cast(SrvPid, {mark_dropped, self(), Piece, Offset, Length}).
  
  
  %% @doc
  %% @end
  -spec mark_stored(pieceindex(), chunkoffset, chunklength(), peerhandle()) -> ok.
  mark_stored(Piece, Offset, Length, {peer, SrvPid}) ->
      gen_server:cast(SrvPid, {mark_stored, self(), Piece, Offset, Length}).
  
  
  init([TorrentID]) ->
      true = register_server(TorrentID),
      Progress = etorrent_progress:await_server(TorrentID),
      Endgame = etorrent_endgame:originhandle(TorrentID),
      Table = ets:new(none, [private, set]),
      InitState = #state{
          receiver=Progress,
          endgame=Endgame,
          table=Table},
      {ok, InitState}.
  
  
  handle_call({register_peer, Pid}, _, State) ->
      #state{table=Table} = State,
      Ref = erlang:monitor(process, Pid),
      case ets:insert_new(Table, {Pid, Ref}) of
          true  -> ok;
          false -> erlang:demonitor(Ref)
      end,
      {reply, ok, State};
  
  handle_call(start_endgame, _, State) ->
      #state{endgame=Endgame, table=Table} = State,
      ReqTerm  = {'$1', '$2', '$3', '$4'},
      Requests = ets:select(Table, [{{ReqTerm}, [], [ReqTerm]}]),
      [etorrent_endgame:mark_sent(I, O, L, P, Endgame) || {I, O, L, P} <- Requests],
      NewState = State#state{receiver=Endgame},
      {reply, ok, NewState}.
  
  
  handle_cast({mark_sent, Pid, Index, Offset, Length}, State) ->
      #state{receiver=Receiver, table=Table} = State,
      case insert_request(Table, Pid, Index, Offset, Length) of
          false -> notify(Receiver, Index, Offset, Length);
          true  -> ok
      end,
      {noreply, State};
  
  handle_cast({mark_stored, Pid, Piece, Offset, Length}, State) ->
      #state{table=Table} = State,
      delete_request(Table, Pid, Piece, Offset, Length),
      {noreply, State};
  
  handle_cast({mark_dropped, Pid, Piece, Offset, Length}, State) ->
      #state{receiver=Receiver, table=Table} = State,
      notify(Receiver, Piece, Offset, Length),
      delete_request(Table, Pid, Piece, Offset, Length),
      {noreply, State}.
  
  
  handle_info({'DOWN', _, process, Pid, _}, State) ->
      #state{receiver=Receiver, table=Table} = State,
      Chunks = flush_requests(Table, Pid),
      ok = notify(Receiver, Chunks),
      true = ets:delete(Table, Pid),
      {noreply, State}.
  
  terminate(_, State) ->
  
negative.code: -module(etorrent_pending).
  -behaviour(gen_server).
  %% This module implements a server process tracking which open
  %% requests have been assigned to each peer process. The process
  %% assigning the requests to peers are responsible for keeping
  %% the request tracking process updated.
  %%
  %% #Peers
  %% Peer processes are responsible for notifying both the request
  %% tracking process and the process that assigned the request
  %% when a request is dropped, fetched or stored.
  %%
  %% When a peer exits the request tracking process must notify the
  %% process that is responsible for assigning requests that the
  %% request has been dropped.
  %%
  %% #Changing assigning process
  %% When endgame mode is activated the assigning process is replaced
  %% with the endgame process. The currently open requests are then sent
  %% to the endgame process. Any requests that have been sent to but
  %% not received by the assigning process is expected to be forwarded
  %% to the endgame process by the previous assigning process.
  
  %% exported functions
  -export([start_link/1,
           receiver/2]).
  
  %% gproc registry entries
  -export([register_server/1,
  