anchor.diff:   when ?is_transport(Prot) ->
      {next_state, 'CLIENT', State};
   
  -'CLIENT'({Prot, _Sock, {terminated, Reason}}, Pipe, State)
  - when ?is_transport(Prot) ->
  -   pipe:a(Pipe, {ws, self(), {terminated, Reason}}),
  +'CLIENT'({Prot, _Sock, eof}, Pipe, State)
  + when ?is_transport(Prot) ->
  +   pipe:a(Pipe, {ws, self(), eof}),
  +   {stop, normal, State};
  +
  +'CLIENT'({Prot, _Sock, {error, _} = Error}, Pipe, State)
  + when ?is_transport(Prot) ->
  +   pipe:a(Pipe, {ws, self(), Error}),
      {stop, normal, State};
   
   %%
  
positive.code: 
        %% GET Request
        {{'GET', Url, Head}, _Recv} ->
           <<"Upgrade">>   = pair:lookup('Connection', Head),
           <<"websocket">> = pair:lookup('Upgrade',    Head),
           Key  = pair:lookup(<<"Sec-Websocket-Key">>, Head),
           Hash = base64:encode(crypto:hash(sha, <<Key/binary, ?WS_GUID>>)),
           {Msg, _} = htstream:encode(
              {101, [{'Upgrade', <<"websocket">>}, {'Connection', <<"Upgrade">>}, {<<"Sec-WebSocket-Accept">>, Hash}], <<>>},
              htstream:new()
           ),
           pipe:a(Pipe, Msg),
           pipe:b(Pipe, {ws, self(), {'GET', Url, Head, []}}), %% @todo env
           {upgrade, ws_new(server, Url, [])};
  
        %% ANY Request
  
negative.code:       {next_state, 'CLIENT', State#fsm{stream = Stream#stream{send = Send}}}
     catch _:Reason ->
        ?NOTICE("knet [ws]: failure ~p ~p", [Reason, erlang:get_stacktrace()]),
        pipe:b(Pipe, {ws, self(), {error, Reason}}),
        {stop, Reason, State}
     end.
  
  