anchor.diff:  
   -module(ex_fcgi).
   -author('Anthony Ramine <nox@dev.extend.eu>').
  --behaviour(gen_server).
   
   
   -type short() :: 0..65535.
  +-type uint32() :: 0..(1 bsl 32 - 1).
   
   -type address() :: string() | atom() | inet:ip_address().
   -type port_number() :: short().
  
positive.code:   Bin.
  
  
  -spec do_abort(reference(), #state{}) -> ok.
  do_abort(Ref, State) ->
    case delete(Ref, State) of
      {deleted, ReqId} -> send({fcgi_abort_request, ReqId}, State);
      not_found -> ok end.
  
  
  -spec initial_state(address(), port_number()) -> #state{}.
  initial_state(Address, Port) ->
    #state{address = Address, port = Port, table = ets:new(?MODULE, [private])}.
  
  -spec next_req_id(#state{}) -> {req_id(), #state{}}.
  next_req_id(State = #state{next_id = ReqId}) ->
    {ReqId, State#state{next_id = ReqId + 1 rem 65535}}.
  
  -spec send_packets([ex_fcgi_protocol:packet()], #state{}) ->
                      {ok, #state{socket :: inet:socket()}} |
                      {error, file:posix()}.
  send_packets(Packets, State = #state{socket = undefined}) ->
    case open_socket(State) of
      {ok, NewState} -> send_packets(Packets, NewState);
      Error -> Error end;
  send_packets(Packets, State = #state{socket = Socket}) ->
    case gen_tcp:send(Socket, [ ex_fcgi_protocol:encode(P) || P <- Packets ]) of
      ok -> {ok, State};
      Error -> Error end.
  
  -spec send(ex_fcgi_protocol:packet(), #state{}) ->
              {ok, #state{socket :: inet:socket()}} | {error, file:posix()}.
  send(Packet, State = #state{socket = undefined}) ->
    case open_socket(State) of
      {ok, NewState} -> send(Packet, NewState);
      Error -> Error end;
  send(Packet, State = #state{socket = Socket}) ->
    case gen_tcp:send(Socket, ex_fcgi_protocol:encode(Packet)) of
      ok -> {ok, State};
      Error -> Error end.
  
  -spec open_socket(#state{socket :: undefined}) ->
                     {ok, #state{socket :: inet:socket()}} |
                     {error, file:posix()}.
  open_socket(State = #state{socket = undefined,
                             address = Address,
                             port = Port}) ->
    case gen_tcp:connect(Address, Port, [binary, {packet, fcgi}]) of
      {ok, Socket} -> {ok, State#state{socket = Socket}};
      Error -> Error end.
  
  -spec insert({req_id(), reference(), pid()}, #state{}) -> true.
  insert(Req = {ReqId, Ref, _Pid}, #state{table = Tid}) ->
    true = ets:insert_new(Tid, [Req, {Ref, ReqId}]).
  
  -spec delete(reference(), #state{}) -> {deleted, req_id()} | not_found.
  delete(Ref, State = #state{table = Tid}) ->
    case lookup(Ref, State) of
      [{Ref, ReqId}] ->
        ets:delete(Tid, Ref),
        ets:delete(Tid, ReqId),
        {deleted, ReqId};
      [] -> not_found end.
  
  -spec lookup(reference(), #state{}) -> [{reference(), req_id()}];
              (req_id(), #state{}) -> [{req_id(), reference(), pid()}].
  lookup(Key, #state{table = Tid}) ->
    ets:lookup(Tid, Key).
  
negative.code: 
  -export([connect/3,
           disconnect/1,
           begin_request/4,
           send/3,
           abort_request/2,
           end_request/2]).
  
  -export([start_link/3,
           init/3]).
  
  -record(state, {socket :: undefined | inet:socket(),
                  address :: address(),
                  port :: port_number(),
                  requests :: ets:tid(),
                  monitors :: ets:tid(),
                  next_id = 1 :: req_id()}).
  
  
  