anchor.diff:                                  {advanced, InitialState} ->
                                       InitialState
                               end,
  -            loop(CallbackMod, WSState, CallbackState, CallbackType)
  -    end.
  +            NState = State#state{wsstate=WSState,
  +                                 cbstate=CallbackState,
  +                                 cbtype=CallbackType},
  +            {noreply, NState}
  +    end;
  +handle_cast({send, {Type, Data}}, #state{wsstate=WSState}=State) ->
  +    do_send(WSState, {Type, Data}),
  +    {noreply, State};
  +handle_cast(_Msg, State) ->
  +    {noreply, State}.
  +
  +handle_info({tcp, Socket, FirstPacket}, #state{wsstate=#ws_state{sock=Socket}}=State) ->
  +    #state{cbmod=CallbackMod, wsstate=WSState,
  +           cbstate=CallbackState, cbtype=CallbackType} = State,
  +    FrameInfos = unframe_active_once(WSState, FirstPacket),
  +    {Results, NewCallbackState} =
  +        case CallbackType of
  +            basic ->
  +                {BasicMessages, NewCallbackState0} =
  +                    basic_messages(FrameInfos, CallbackState),
  +                CallbackResults = lists:map(
  +                                    fun(M) ->
  +                                            CallbackMod:handle_message(M)
  +                                    end,
  +                                    BasicMessages),
  +                {catch lists:foldl(handle_result_fun(WSState), ok, CallbackResults),
  +                 NewCallbackState0};
  +            {advanced,_} ->
  +                catch lists:foldl(do_callback_fun(WSState, CallbackMod),
  +                                  {ok, CallbackState},
  +                                  FrameInfos)
  +        end,
  +    case Results of
  +        {close, Reason} ->
  +            do_close(WSState, Reason),
  +            {stop, Reason, State#state{cbstate=NewCallbackState}};
  +        _ ->
  +            Last = lists:last(FrameInfos),
  +            NewWSState = Last#ws_frame_info.ws_state,
  +            {noreply, State#state{wsstate=NewWSState, cbstate=NewCallbackState}}
  +    end;
  +handle_info({tcp_closed, Socket}, #state{wsstate=#ws_state{sock=Socket}}=State) ->
  +    %% The only way we should get here is due to an abnormal close.
  +    %% Section 7.1.5 of RFC 6455 specifies 1006 as the connection
  +    %% close code for abnormal closure. It's also described in
  +    %% section 7.4.1.
  +    #state{cbmod=CallbackMod, wsstate=WSState,
  +           cbstate=CallbackState, cbtype=CallbackType} = State,
  +    CloseStatus = 1006,
  +    case CallbackType of
  +        basic ->
  +            CallbackMod:handle_message({close, CloseStatus, <<>>});
  +        {advanced, _} ->
  +            ClosePayload = <<CloseStatus:16/big>>,
  +            CloseWSState = WSState#ws_state{sock=undefined,
  +                                            frag_type=none},
  +            CloseFrameInfo = #ws_frame_info{fin=1,
  +                                            rsv=0,
  +                                            opcode=close,
  +                                            masked=0,
  +                                            masking_key=0,
  +                                            length=byte_size(ClosePayload),
  +                                            payload=ClosePayload,
  +                                            ws_state=CloseWSState},
  +            CallbackMod:handle_message(CloseFrameInfo, CallbackState)
  +    end,
  +    {stop, normal, State};
  +handle_info(_Info, State) ->
  +    {noreply, State}.
  +
  +terminate(_Reason, _State) ->
  +    ok.
  +
  +code_change(_OldVsn, Data, _Extra) ->
  +    {ok, Data}.
  +
  +%% internal functions
  +
  +do_send(#ws_state{sock=Socket, vsn=ProtoVsn}, {Type, Data}) ->
  +    DataFrame = frame(ProtoVsn, Type,  Data),
  +    case Socket of
  +        {sslsocket,_,_} ->
  +            ssl:send(Socket, DataFrame);
  +        _ ->
  +            gen_tcp:send(Socket, DataFrame)
  +    end.
  +
  +preprocess_opts(GivenOpts) ->
  +    Fun = fun({Key, Default}, Opts) ->
  +                  case lists:keyfind(Key, 1, Opts) of
  +                      false ->
  +                          [{Key, Default}|Opts];
  +                      _ -> Opts
  +                  end
  +          end,
  +    Defaults = [{origin, any},
  +                {callback, basic}],
  +    lists:foldl(Fun, GivenOpts, Defaults).
   
   origin_check(_Origin, {origin, any}) ->
       ok;
  
positive.code:                  _ when is_integer(Reason) -> Reason;
                   _ -> ?NORMAL_WS_STATUS
               end,
      send(WSState, {close, <<Status:16/big>>}),
      exit(Reason).
  
  basic_messages(FrameInfos, {FragType, FragAcc}) ->
      {Messages, NewFragType, NewFragAcc}
          = lists:foldl(fun handle_message/2, {[], FragType, FragAcc}, FrameInfos),
      {Messages, {NewFragType, NewFragAcc}}.
  
  %% start of a fragmented message
  
negative.code:      "Sec-WebSocket-Accept: ", AcceptHash , "\r\n",
       "\r\n"].
  
  handle_result_fun(WSState) ->
      fun(Result, Acc) ->
              case Result of
                  {reply, {Type, Data}} ->
                      do_send(WSState, {Type, Data}),
                      Acc;
                  noreply ->
                      Acc;
                  {close, Reason} ->
                      throw({close, Reason})
              end
      end.
  
  do_callback_fun(WSState, CallbackMod) ->
      fun(FrameInfo, {Results, CallbackState}) ->
              case CallbackMod:handle_message(FrameInfo, CallbackState) of
                  {reply, {Type, Data}, NewCallbackState} ->
                      do_send(WSState, {Type, Data}),
                      {Results, NewCallbackState};
                  {noreply, NewCallbackState} ->
                      {Results, NewCallbackState};
                  {close, Reason} ->
                      throw({{close, Reason}, CallbackState})
              end
      end.
  
  