anchor.diff:      gen_server:cast(Notifier, {'detach', Event, Observer}).
   
   %% @doc Return all observers for a particular event
  -get_observers(Msg, #context{notifier=Notifier}) when is_tuple(Msg) ->
  -    gen_server:call(Notifier, {'get_observers', element(1, Msg)});
  -get_observers(Event, #context{notifier=Notifier}) ->
  -    gen_server:call(Notifier, {'get_observers', Event}).
  +get_observers(Msg, Context) when is_tuple(Msg) ->
  +    get_observers(element(1, Msg), Context);
  +get_observers(Event, #context{host=Host}) ->
  +    Table = observer_table_name(Host),
  +    case ets:lookup(Table, Event) of
  +        [] -> [];
  +        [{Event, Observers}] -> Observers
  +    end.
   
   
   %%====================================================================
  
positive.code: %%                                      {noreply, State, Timeout} |
  %%                                      {stop, Reason, Reply, State} |
  %%                                      {stop, Reason, State}
  %% @doc Return the list of observers for an event. The event must be an atom.
  handle_call({'get_observers', Event}, _From, State) ->
      case dict:find(Event, State#state.observers) of
          {ok, Observers} ->
              {reply, Observers, State};
          error ->
              {reply, [], State}
      end;
  
  %% @doc Trap unknown calls
  handle_call(Message, _From, State) ->
      {stop, {unknown_call, Message}, State}.
  
negative.code: start_link(SiteProps) when is_list(SiteProps) ->
      {host, Host} = proplists:lookup(host, SiteProps),
      Name = z_utils:name_for_host(?MODULE, Host),
  
      %% If the notifier crashes the supervisor gets ownership
      %% of the observer table. When it restarts the notifier
      %% it will give ownership back to the notifier.
      ObserverTable = ensure_observer_table(Host),
  
      case gen_server:start_link({local, Name}, ?MODULE, SiteProps, []) of
          {ok, P} ->
              ets:give_away(ObserverTable, P, observer_table),
              {ok, P};
          {already_started, P} ->
              ets:give_away(ObserverTable, P, observer_table),
              {already_started, P};
          R -> R
      end.
  
  % Make sure the observer table exists.
  %
  ensure_observer_table(Name) ->
      Table = observer_table_name(Name),
      case ets:info(Table) of
          undefined -> ets:new(Table, [named_table, set, {keypos, 1}, protected, {heir, self(), []}]);
          _ -> Table
      end.
  
  % Return the name of the observer table
  %
  observer_table_name(Context) when is_record(Context, context) ->
      observer_table_name(Context#context.host);
  observer_table_name(Name) when is_atom(Name) ->
      z_utils:name_for_host(observers, Name).
  
  %% @doc Start a notifier server for unit testing
  start_tests() ->
      io:format("Starting notifier server.~n"),
      start_link([{host, test}]).
  
  
  %%====================================================================
  