anchor.diff:  
   -spec reassemble(tcp_segment(), {Data::binary(), [offset_data()]}) ->
                           {Data::binary(), [offset_data()]}.
  -reassemble({0, TS, Data}, {<<>>, []}) ->
  -    {Data, [{TS, syn, 0, 0}]};
   reassemble({RSN, RTS, Data}, {Stream, Offsets})
     when is_integer(RSN), is_integer(RTS),
          is_binary(Data), is_binary(Stream),
  
positive.code:          ,reassemble/1
           ,finished/1
           ,relative_time/2
           ,analyze/2
          ]).
  
  -include("enet_types.hrl").
  
negative.code: 
  finished(#tcp_stream{state=S}) -> S =:= finished.
  
  acks(#tcp_stream{acks=Acks}) -> Acks.
  
  relative_time(TS, #tcp_stream{start_time=T0}) ->
      TS - T0.
  
  -spec analyze(Module::atom(), #tcp_stream{}, [{Ack::non_neg_integer(),
                                                 TS::non_neg_integer()}]) ->
                       {'error', 'broken_stream'} |
                       {[{Message::term(),
                          {StartIdx::non_neg_integer(),
                           StopIdx::non_neg_integer()},
                          {StartTS::non_neg_integer(),
                           Duration::non_neg_integer()}}],
                        Oddballs::[{Timestamp::non_neg_integer(),
                                    'retransmit' | 'missing_packet'}]}.
  analyze(_, #tcp_stream{state=error}, _Acks) ->
      {error, broken_stream};
  analyze(Module, #tcp_stream{} = S, Acks) ->
      Relacks = relative_acks(Acks, S),
      Stream = {_, Offsets} = reassemble(S),
      {analyze(Module, Stream, 0, Relacks),
       oddballs(Offsets)}.
  
  analyze(Module, {Stream, Offsets}, Idx, Relacks) when Idx < byte_size(Stream) ->
      <<_:Idx/binary, Buf/binary>> = Stream,
      case Module:decode(Buf) of
          {complete, Term, Rest} ->
              NewIdx = byte_size(Stream) - byte_size(Rest),
              IdxRange = {Idx, NewIdx - 1},
              [{Term, IdxRange, analyze_timing(IdxRange, Offsets, Relacks)}
               | analyze(Module, {Stream, Offsets}, NewIdx, Relacks)];
          {partial, _BytesNeeded} ->
              IdxRange = {Idx, byte_size(Stream)},
              [{partial, IdxRange, analyze_timing(IdxRange, Offsets, Relacks)}]
      end;
  analyze(_, _, _, _) -> [].
  
  oddballs(Offsets) ->
      [ {TS, Type} || {TS, Type, _, _} <- Offsets,
                      Type =/= normal, Type =/= syn ].
  
  analyze_timing({StartIdx, StopIdx}, Offsets, Relacks) ->
      StartTS = earliest_offset(StartIdx, Offsets),
      EndTS = latest_ack(StopIdx, Relacks),
      {StartTS, EndTS - StartTS}.
  
  earliest_offset(StartIdx, [{TS, _, I, J} | _])
    when I =< StartIdx,
         StartIdx =< J -> TS;
  earliest_offset(StartIdx, [_ | Rest]) ->
      earliest_offset(StartIdx, Rest).
  
  latest_ack(StopIdx, Relacks) ->
      MinAck = hd([ Ack || {Ack, _} <- Relacks,
                           Ack >= StopIdx ]),
      lists:max([ TS || {Ack, TS} <- Relacks,
                        Ack =:= MinAck]).
  
  %%====================================================================
  %% Internal functions
  %%====================================================================
  
  relative_acks(Acks, #tcp_stream{isn=ISN}) ->
      [{case AckNo > ISN of
            true -> AckNo - ISN;
            false -> AckNo + 16#ffffffff - ISN
        end, TS}
       || {AckNo, TS} <- Acks].
  