anchor.diff:  patch(Pid, Uri, Headers, Body, Options) ->
       request(Pid, patch, Uri, Headers, Body, Options).
   
  +%% @doc Performs a chunked <strong>PUT</strong> request to <code>Uri</code>
  +%% using %% <code>Headers</code> as the content data.
  +-spec put(connection(), uri(), headers(), options()) -> result().
  +put(Pid, Uri, Headers0, Options) ->
  +    request(Pid, put, Uri, Headers0, body_chunked, Options).
  +
   %% @doc Performs a <strong>PUT</strong> request to <code>Uri</code> using
   %% <code>Headers</code> and <code>Body</code> as the content data.
  --spec put(pid(), iodata(), headers(), iodata(), options()) -> result().
  +-spec put(connection(), uri(), headers(), body(), options()) -> result().
   put(Pid, Uri, Headers0, Body, Options) ->
       request(Pid, put, Uri, Headers0, Body, Options).
   
  
positive.code: 
  -behaviour(gen_fsm).
  
  -export([
           start/0,
           stop/0,
           start_link/4,
           open/2,
           open/3,
           open/4,
           close/1,
           %% get
           get/2,
           get/3,
           get/4,
           %% post
           post/5,
           %% delete
           delete/4,
           %% head
           head/4,
           %% options
           options/4,
           %% patch
           patch/5,
           %% put
           put/5,
           %% generic request
           request/6,
           %% events
           events/1
          ]).
  
  -export([
           init/1,
           handle_event/3,
           handle_sync_event/4,
           handle_info/3,
           terminate/3,
           code_change/4
          ]).
  
  -export([
           at_rest/2,
           wait_response/2,
           receive_data/2,
           receive_chunk/2,
           parse_event/1
          ]).
  
  %Work request handlers
  -export([
           at_rest/3,
           wait_response/3,
           receive_data/3,
           receive_chunk/3
          ]).
  
  -type response() ::
          #{
             status_code => integer(),
             header => map(),
             body => binary()
           }.
  -type result() :: {ok, reference() | response()} | {error, term()}.
  -type headers() :: #{}.
  -type options() ::
          #{
             async => boolean(),
             async_mode => binary | sse,
             handle_event => fun((fin | nofin, reference(), binary()) -> any()),
             basic_auth => {string(), string()},
             timeout => pos_integer() | infinity %% Default 5000 ms
           }.
  -type http_verb() :: get | post | head | delete | patch | put | options.
  
  -type connection_type() :: http | https.
  
  -type open_opts() ::
          #{
             %% transport_opts are passed to Ranch's TCP transport, which is
             %% -itself- a thin layer over gen_tcp.
             transport_opts => [],
             %% timeout is passed to gun:await_up. Default if not specified
             %% is 5000 ms.
             timeout => pos_integer() | infinity
           }.
  
  -type event() ::
          #{
             id    => binary(),
             event => binary(),
             data  => binary()
           }.
  
  -export_type([event/0]).
  
  %% @doc Starts the application and all the ones it depends on.
  -spec start() -> {ok, [atom()]}.
  
negative.code:               #{from := From, stream := StreamRef, async := Async} = State) ->
      StateName =
        case lists:keyfind(<<"transfer-encoding">>, 1, Headers) of
            {<<"transfer-encoding">>, <<"chunked">>} when Async == true->
                Result = {ok, StreamRef},
                gen_fsm:reply(From, Result),
                receive_chunk;
            _ ->
                receive_data
        end,
      { next_state
      , StateName
      , State#{status_code := StatusCode, headers := Headers}
      };
  wait_response({gun_error, _Pid, _StreamRef, Error},
                #{from := From} = State) ->
      gen_fsm:reply(From, {error, Error}),
      {next_state, at_rest, State, 0};
  wait_response(body_chunked,
                #{stream := StreamRef, from := From} = State) ->
      gen_fsm:reply(From, {ok, StreamRef}),
      {next_state, wait_response, State};
  wait_response({data, Data, FinNoFin},
                #{stream := StreamRef, pid := Pid} = State) ->
      ok = gun:data(Pid, StreamRef, FinNoFin, Data),
      {next_state, wait_response, State};
  wait_response(Event, State) ->
      {stop, {unexpected, Event}, State}.
  
  