anchor.diff:  %
   % This is split into two phases: an 'upper half' to get the minimimal work done required to wire things up
   % and a 'lower half' that takes care of things that can wait
  -% 
  -init([Name, HeartbeatInterval, DeadIntervalCount]) ->
  +%
  +init([Name]) ->
  +    HeartbeatInterval = 1,
  +    DecayWindow = 5,
  +    UpThresh   = pushy_util:get_env(push, up_threshold, ?DEFAULT_UP_THRESHOLD, any), %% TODO constrain to float
  +    DownThresh = pushy_util:get_env(push, down_threshold, ?DEFAULT_DOWN_THRESHOLD, any), %% TODO constrain to float
   
       State = #state{name = Name,
  -                   dead_interval = HeartbeatInterval * DeadIntervalCount,
  -                   heartbeats = 0,
  +                   decay_window = DecayWindow,
  +                   heartbeat_interval = HeartbeatInterval,
                      current_status = down, % Fetch from db later
  -                   heartbeat_rate = pushy_ema:init(DeadIntervalCount, HeartbeatInterval)},
  +                   heartbeat_rate = pushy_ema:init(HeartbeatInterval, DecayWindow),
  +                   up_threshold = UpThresh,
  +                   down_threshold = DownThresh
  +                  },
       try
           %% The most important thing to have happen is this registration; we need to get this
           %% assigned before anyone else tries to start things up gproc:reg can only return
  
positive.code:     Observers = State#state.observers,
      State1 = State#state{observers=lists:delete(Object,Observers)},
      {next_state, CurState, State1};
  handle_info({heartbeat, NodeName, NodeStatus},
              CurState,
              #state{heartbeats=HeartBeats, logging=Level, current_status=CurStatus, heartbeat_rate=HRate}=State) ->
      nlog(Level, "Heartbeat recieved from ~p Currently ~p ~p", [NodeName, NodeStatus, HRate]),
  
      %% Note that we got a heartbeat
      State1 = State#state{heartbeat_rate=push_ema:inc(HRate,1), current_status=NodeStatus},
      %% Reset the timer
      State2 = reset_timer(State1),
  
      case HeartBeats of
          ?POC_HB_THRESHOLD - 1 -> % transitioning up
              update_status(?SAVE_MODE, NodeStatus, State2),
              {next_state, up, State2#state{heartbeats=HeartBeats + 1}};
          ?POC_HB_THRESHOLD -> % up, only do something if status changes
              case NodeStatus of
                  CurStatus -> ok;
                  _Else -> update_status(?SAVE_MODE, NodeStatus, State2)
              end,
              {next_state, up, State2};
          _ -> % we're down, don't save state changes
              {next_state, CurState, State2#state{heartbeats=HeartBeats +1}}
      end;
  handle_info(down, down, State) ->
      {next_state, down, State};
  handle_info(down, _CurState, State) ->
      {next_state, down, update_status(?SAVE_MODE, down, State#state{heartbeats=0})};
  handle_info({timeout, _Ref, update_avg}, CurState, #state{heartbeat_rate=HRate}=State) ->
      {next_state, CurState, State#state{heartbeat_rate=push_ema:tick(HRate)} };
  handle_info(no_heartbeats, _CurState, State) ->
      State1 = State#state{heartbeats=0, tref=undefined},
      update_status(?SAVE_MODE, down, State1),
      {next_state, down, State1};
  handle_info(Info, CurState, State) ->
      lager:error("Strange message ~p received in state ~p", [Info, CurState]),
      {next_state, CurState, State}.
  
negative.code: -include_lib("eunit/include/eunit.hrl").
  
  -type node_name() :: binary().
  -type fsm_states() :: 'up' | 'down'.
  -type logging_level() :: 'verbose' | 'normal'.
  -type status_atom() :: 'up' | 'down'.
  -type gproc_error() :: ok | {error, no_node}.
  
  -type eavg() :: any().
  
  -define(DEFAULT_UP_THRESHOLD, 0.8).
  -define(DEFAULT_DOWN_THRESHOLD, 0.2).
  
  -record(state, {name                  :: node_name(), %% TODO: Flesh this out 
                  heartbeat_interval    :: integer(),
                  decay_window          :: integer(),
                  logging = normal      :: logging_level(),
                  current_status = down :: status_atom(),
                  heartbeats_rcvd       :: integer(),
                  up_threshold          :: float(),
                  down_threshold        :: float(),
                  observers = []        :: [pid()],
                  tref,
                  heartbeat_rate   :: eavg()
                 }).
  
  
  %%%
  %%% External API
  %%%
  -spec start_link(node_name) -> 'ignore' | {'error',_} | {'ok',pid()}.
  start_link(Name) ->
      gen_fsm:start_link(?MODULE, [Name], []).
  
  -spec heartbeat(node_name()) -> 'ok'.
  heartbeat(NodeName) ->
      case catch gproc:send({n,l,NodeName}, %% FIXME: why not use sync_send_event?
              {heartbeat}) of
          {'EXIT', _} ->
              %% TODO this fails to take into account a failed initialize/gproc registration
              %% FIXME!!!!
              pushy_node_state_sup:new(NodeName),
              heartbeat(NodeName);
          _ -> ok
      end.
  
  