anchor.diff:  -export([start_link/0]).
   -export([login/0]).
   -export([get_token/0]).
  +-export([update_token/1]).
   
   
   %% gen_server callbacks
  
positive.code:     Reply = ok,
      {reply, Reply, State}.
  
  handle_cast(_Msg, State) ->
      {noreply, State}.
  
  handle_info(login,
              #state{credentials=Credentials, connection=Connection} = State) ->
      #{app_key := Appkey} = Credentials,
      lager:info("Logging in"),
      ReqBody = betfair_http:url_encode(maps:without([app_key], Credentials)),
      ReqHeaders = [{<<"Content-Type">>, "application/x-www-form-urlencoded"},
                    {<<"X-Application">>, Appkey}],
      _ = gun:post(Connection, "/api/certlogin", ReqHeaders, ReqBody),
      {noreply, State};
  handle_info({gun_data, _Connection, _StreamRef, nofin, Data}, State) ->
      lager:info("Received Data, ~p", [Data]),
      {noreply, State};
  handle_info({gun_data, _Connection, _StreamRef, fin, Data}, State) ->
      lager:info("Received Data, ~p", [Data]),
  
      case maybe_handle(Data) of
          {ok, Token} ->
              gproc_ps:publish(?SCOPE, session_token, Token),
              {noreply, State#state{token = Token}};
          {error, Reason} ->
              lager:error("Error login response: ~p", [Reason]),
              {noreply, State}
      end;
  handle_info({gun_up, Connection, _Transport}, State) ->
      lager:info("Connection established .."),
      self() ! login,
  
negative.code: %%% Internal functions
  %%%===================================================================
  
  %% TODO these look generic - maybe use elsewhere?
  
  receive_response(Self, Stream, Connection, Handler) ->
      receive
          {gun_response, Connection, Stream, fin, _Status, _Headers} ->
              no_data;
          {gun_response, Connection, Stream, nofin, _Status, _Headers} ->
              %% TODO only receive if 200 status?
              receive_data(Self, Connection, Stream, Handler);
          {'DOWN', _, process, Connection, Reason} ->
              error_logger:error_msg("Oops!"),
              exit(Reason)
      after 1000 ->
              exit(timeout)
      end.
  
  receive_data(Self, Connection, Stream, Handler) ->
      receive
          {gun_data, _Connection, _Stream, nofin, _Data} ->
              receive_data(Self, Connection, Stream, Handler);
          {gun_data, _Connection, Stream, fin, Data} ->
              lager:info("Received Data ~p", [Data]),
              Response = jsx:decode(Data, [return_maps, {labels, atom}]),
              Self ! Handler(Response);
          {'DOWN', _, process, _Connection, Reason} ->
              _ = lager:error("Oops!"),
              exit(Reason)
      after 1000 ->
              exit(timeout)
      end.
  
  
  login_handler(#{sessionToken := Token, loginStatus := _Reason}) ->
      {token, Token};
  login_handler(#{loginStatus := Reason}) ->
      exit(Reason).
  
  keep_alive_handler(#{token := Token, status := <<"SUCCESS">>}) ->
      {token, Token};
  keep_alive_handler(#{status := <<"SUCCESS">>, error := Reason}) ->
      exit(Reason).
  
  
  keep_alive(KeepAliveInterval) ->
      erlang:send_after(KeepAliveInterval, self(), keep_alive).
  