anchor.diff:      end,
       {noreply, S#state{nodes = gb_trees:update(Node, M0, S#state.nodes)}}.
   
  -handle_call(dbg_get_state, _, S) ->
  -    {reply, S, S};
  -
  -handle_call({new_job, JobName, JobCoord}, _, S) ->
  -    {reply, catch gen_server:call(scheduler,
  -        {new_job, JobName, JobCoord}), S};
  -
  -handle_call({new_task, Task}, _, S) ->
  -    NodeStats =
  -        [case gb_trees:lookup(Node, S#state.nodes) of
  -            none -> {false, Input};
  -            {value, N} -> {N#dnode.num_running, Input}
  -         end || {_Url, Node} = Input <- Task#task.input],
  -    case catch gen_server:call(scheduler, {new_task, Task, NodeStats}) of
  -        ok ->
  -            gen_server:cast(self(), schedule_next),
  -            {reply, ok, S};
  -        Error ->
  -            error_logger:warning_report({"Scheduling task failed",
  -                Task, Error}),
  -            {reply, failed, S}
  -    end;
  -
  -handle_call({get_active, all}, _From, #state{workers = Workers} = S) ->
  -    {reply, {ok, gb_trees:values(Workers)}, S};
  -
  -handle_call({get_active, JobName}, _From, #state{workers = Workers} = S) ->
  -    Active = [{Host, Task} || {Host, #task{jobname = N} = Task}
  -                                  <- gb_trees:values(Workers), N == JobName],
  -    {reply, {ok, Active}, S};
  -
  -handle_call({get_nodeinfo, all}, _From, #state{nodes = Nodes} = S) ->
  -    Info = [#nodeinfo{name = N#dnode.name,
  -                      slots = N#dnode.slots,
  -                      num_running = N#dnode.num_running,
  -                      stats_ok = N#dnode.stats_ok,
  -                      stats_failed = N#dnode.stats_failed,
  -                      stats_crashed = N#dnode.stats_crashed,
  -                      blacklisted = not (N#dnode.blacklisted == false)}
  -           || N <- gb_trees:values(Nodes)],
  -    {reply, {ok, Info}, S};
  -
  -handle_call(get_purged, _, #state{purged = Purged} = S) ->
  -    Now = now(),
  -    NPurged = gb_trees:from_orddict(
  -        [{Job, TStamp} || {Job, TStamp} <- gb_trees:to_list(Purged),
  -            timer:now_diff(Now, TStamp) < ?PURGE_TIMEOUT * 1000]),
  -    {reply, {ok, gb_trees:keys(NPurged)}, S#state{purged = NPurged}};
  -
  -handle_call(get_num_cores, _, #state{nodes = Nodes} = S) ->
  -    NumCores = lists:sum([N#dnode.slots || N <- gb_trees:values(Nodes)]),
  -    {reply, {ok, NumCores}, S};
  -
  -handle_call({kill_job, JobName}, _From, S) ->
  -    event_server:event(JobName, "WARN: Job killed", [], []),
  -    % Make sure that scheduler don't accept new tasks from this job
  -    gen_server:cast(scheduler, {job_done, JobName}),
  -    {reply, ok, S};
  -
  -handle_call({clean_job, JobName}, From, State) ->
  -    handle_call({kill_job, JobName}, From, State),
  -    gen_server:cast(event_server, {clean_job, JobName}),
  -    {reply, ok, State};
  -
  -handle_call({blacklist, Node, Token}, _From, #state{nodes = Nodes} = S) ->
  -    {reply, ok, S#state{nodes =
  -        toggle_blacklist(Node, Nodes, true, Token)}};
  -
  -handle_call({whitelist, Node, Token}, _From, #state{nodes = Nodes} = S) ->
  -    {reply, ok, S#state{nodes =
  -        toggle_blacklist(Node, Nodes, false, Token)}}.
  -
  -process_exit(Pid, Msg, Code, S) ->
  -    process_exit1(gb_trees:lookup(Pid, S#state.workers), Pid, Msg, Code, S).
  -
  -process_exit1(none, _, _, _, S) -> {noreply, S};
  -process_exit1({_, {Node, T}}, Pid, Msg, Code, S) ->
  -    P = io_lib:fwrite("WARN: [~s:~B] ", [T#task.mode, T#task.taskid]),
  -    event_server:event(Node, T#task.jobname, lists:flatten(P, Msg), [],
  -            {task_failed, T#task.mode}),
  -    gen_server:cast(self(), {exit_worker, Pid, {data_error, Code}}),
  -    {noreply, S}.
  -
  -handle_info({'EXIT', Pid, normal}, S) ->
  -    case gb_trees:lookup(Pid, S#state.workers) of
  -        none -> {noreply, S};
  -        _ -> error_logger:warning_report(
  -            {"Task failed to call exit_worker", Pid}),
  -             process_exit(Pid, "Died unexpectedly without a reason",
  -            "unexpected", S)
  -    end;
  -
  -handle_info({'EXIT', Pid, {worker_dies, {Msg, Args}}}, S) ->
  -    process_exit(Pid, io_lib:fwrite(Msg, Args), "worker_dies", S);
  -
  -handle_info({'EXIT', Pid, noconnection}, S) ->
  -    process_exit(Pid, "Connection lost to the node (network busy?)",
  -        "noconnection", S);
  -
  -handle_info({'EXIT', Pid, Reason}, S) when Pid == self() ->
  -    error_logger:warning_report(["Disco server dies on error!", Reason]),
  -    {stop, stop_requested, S};
  -
  -handle_info({'EXIT', Pid, Reason}, S) ->
  -    process_exit(Pid, io_lib:fwrite("Worked died unexpectedly: ~p",
  -        [Reason]), "unexpected", S).
  -
   toggle_blacklist(Node, Nodes, IsBlacklisted, Token) ->
       UpdatedNodes =
           case gb_trees:lookup(Node, Nodes) of
               % blacklist
               {value, M} when IsBlacklisted == true,
  -                    M#dnode.blacklisted =/= manual ->
  -                gb_trees:update(Node,
  -                    M#dnode{blacklisted = Token}, Nodes);
  +                            M#dnode.blacklisted =/= manual ->
  +                gb_trees:update(Node, M#dnode{blacklisted = Token}, Nodes);
               % whitelist if token is valid
               {value, M} when Token == any;
  -                    Token == M#dnode.blacklisted ->
  +                            Token == M#dnode.blacklisted ->
                   error_logger:info_report({"Whitelisted", Node}),
  -                gb_trees:update(Node,
  -                    M#dnode{blacklisted = false}, Nodes);
  +                gb_trees:update(Node, M#dnode{blacklisted = false}, Nodes);
               _ -> Nodes
           end,
       update_nodes(UpdatedNodes),
  
positive.code:     {ok, #state{workers = gb_trees:empty(),
                  nodes = gb_trees:empty(),
                  purged = gb_trees:empty()}}.
  
  update_nodes(Nodes) ->
      WhiteNodes = [{N#dnode.name, N#dnode.slots}
                    || #dnode{blacklisted = false} = N <- gb_trees:values(Nodes)],
      DDFSNodes = [{disco:node(N#dnode.name), not (N#dnode.blacklisted == false)}
                   || N <- gb_trees:values(Nodes)],
      gen_server:cast(ddfs_master, {update_nodes, DDFSNodes}),
      gen_server:cast(scheduler, {update_nodes, WhiteNodes}),
      gen_server:cast(self(), schedule_next).
  
  handle_cast({update_config_table, Config}, S) ->
      error_logger:info_report([{"Config table update"}]),
  
negative.code: 
  -export([start_link/0, stop/0]).
  -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
           terminate/2, code_change/3]).
  
  -include("disco.hrl").
  
  