anchor.diff:  -module(pubsub).
   
   %% API
  --export([publish/0
  +-export([new/0
            ,add_subscriber/2
            ,remove_subscriber/2
            ,process_msg/2
  
positive.code: sync_unsubscribe(Publisher) ->
      gen_server:call(Publisher, {?MODULE, {unsub, self()}}).
  
  add_subscriber(Pid, P = #pubsub{subscribers=Subs}) ->
      case subscribed(Pid, P) of
          false ->
              P#pubsub{subscribers=[Pid | Subs]};
          true ->
              P
      end.
  
  remove_subscriber(Pid, P = #pubsub{subscribers=Subs}) ->
      P#pubsub{subscribers=lists:delete(Pid, Subs)}.
  
  process_msg({sub, Pid}, P = #pubsub{}) ->
      add_subscriber(Pid, P);
  
negative.code:     remove_subscriber(Pid, P).
  
  send(Message, #pubsub{subscribers=Subs}) ->
      [ Pid ! Message
        || #sub{pid=Pid, filter=Fn} <- Subs,
           Fn =:= ?FILTER_ALL orelse
           Fn(Message) ],
      ok.
  
  subscribed(Pid, #pubsub{subscribers=Subs}) when is_pid(Pid) ->
      lists:keymember(Pid, #sub.pid, Subs).
  
  %%====================================================================
  %% Internal functions
  %%====================================================================
  
  sub_test() ->
      P1 = new(),
      Pid = self(),
      P2 = process_msg({sub, Pid}, P1),
      ?assertMatch(true, subscribed(Pid, P2)),
  