anchor.diff:      digraph:add_edge(MG, From, To),
       MG.
   
  +   
  +edge_list_to_dot(Edges, OutFileName, GraphName, WithLabel) ->
  +    NodeList=ordsets:to_list(
  +	       ordsets:from_list(
  +		 lists:append(
  +		   [[V1, V2]||{V1, V2, _Label, _Weak, _Score} <- Edges]))),
  +    refac_io:format("\nEdges:\n~p\n", [Edges]),
  +    NodesToColor = ordsets:to_list(
  +		      ordsets:from_list(
  +			[V1||{V1, _V2, _Label, Weak, {_, Score}} <- Edges, Weak, Score>0.2])),
  +    refac_io:format("NodesToColor:\n~p\n", [NodesToColor]),
  +    Start = ["digraph ",GraphName ," {"],
  +    VertexList = [node_format(V, NodesToColor) ||V <- NodeList],
  +    End = ["graph [", GraphName, "=", GraphName, "]}"],
  +    EdgeList = [edge_format(X, Y, Label,WithLabel, Weak) || {X,Y, Label, Weak, _Score} <- Edges],
  +    String = [Start, VertexList, EdgeList, End],
  +    ok = file:write_file(OutFileName, list_to_binary(String)).
  +
  +
  +is_scc_node(V, Sccs) ->
  +    lists:member(V, Sccs).
  +
  +is_scc_edge({V1, V2}, Sccs) ->
  +    lists:member(V1, Sccs) andalso
  +	lists:member(V2, Sccs).
  +	
  +
  +node_format(V, NodesToColor) ->
  +    String = io_lib:format("~p", [V]),
  +    {Width, Heigth} = calc_dim(String),
  +    W = (Width div 7 + 1) * 0.55,
  +    H = Heigth * 0.4,
  +    SL = io_lib:format("~f", [W]),
  +    SH = io_lib:format("~f", [H]),
  +    case lists:member(V, NodesToColor) of 
  +	true ->
  +	    [String, " [width=", SL, " heigth=", SH, " color=red, style=filled", " ", "", "];\n"];
  +	false ->
  +	    [String, " [width=", SL, " heigth=", SH, " ", "", "];\n"]
  +    end.
  +
  +calc_dim(String) ->
  +  calc_dim(String, 1, 0, 0).
  +
  +calc_dim("\\n" ++ T, H, TmpW, MaxW) ->
  +  calc_dim(T, H+1, 0, erlang:max(TmpW, MaxW));
  +calc_dim([_|T], H, TmpW, MaxW) ->
  +  calc_dim(T, H, TmpW+1, MaxW);
  +calc_dim([], H, TmpW, MaxW) ->
  +  {erlang:max(TmpW, MaxW), H}.
  +
  +edge_format([],_,_,_,_) ->
  +    "";
  +edge_format(_,[],_,_, _) ->
  +    "";
  +edge_format(V1, V2, Label, WithLabel,WithColor) ->
  +    String = [io_lib:format("~p", [V1]), " -> ",
  +	      io_lib:format("~p", [V2])],
  +    case  WithColor of 
  +	true ->
  +	    case WithLabel of 
  +		true ->
  +		    [String, " [", "label=", "\"", format_label(Label),  "\"", " color=red", "];\n"];
  +		false ->
  +		    [String, " ["," color=red", "];\n"]
  +	    end;
  +	false ->
  +	    case WithLabel of 
  +		true ->
  +		    [String, " [", "label=", "\"", format_label(Label),  "\"", "];\n"];
  +		false ->
  +		    [String, " [", "];\n"]
  +	    end
  +    end.
  +  
  +
  +format_label([]) ->
  +    "";
  +format_label([{F,A}|T]) ->
  +    case T of 
  +	[] ->
  +	    io_lib:format("~p/~p.", [F, A]);
  +	[{F1, A1}|T1] ->
  +	    case T1 of 
  +		[] ->
  +		    io_lib:format("~p/~p,~p/~p,", [F, A, F1, A1])++format_label(T1);
  +		_ ->
  +		    io_lib:format("~p/~p,~p/~p,", [F, A, F1, A1])++"\\n"++format_label(T1)
  +		end
  +    end.
  +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  +%%                                                                        %%
  +%%                    Clustering API functions                            %%
  +%%                                                                        %%
  +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  +
  +
  +cluster(File, SearchPaths) ->
  +    Files = refac_util:expand_files(SearchPaths, ".erl"),
  +    refac_io:format("Files:\n~p\n", [Files]),
  +    #callgraph{callercallee = CallerCallees} =
  +	wrangler_callgraph_server:get_callgraph(Files),
  +    CG = digraph:new(),
  +    add_edges(CallerCallees, CG),
  +    Matrix = generate_fun_dist_matrix(File, CG),
  +    Funs = exported_funs(File),
  +    refac_io:format("Funs:\n~p\n", [Funs]),
  +    %%refac_io:format("Matrix:\n~p\n", [Matrix]),
  +    Cs =agglomerative_cluster(Matrix, CG),
  +    refac_io:format("Cs:\n~p\n", [Cs]),
  +    Cs1= lists:usort(lists:append(Cs)),
  +    Cs2 =[C||C<-Cs1, is_component(C, CG)],
  +    Cs3 = remove_sub_lists(Cs2),
  +    refac_io:format("Cs1:\n~p\n", [Cs1]),
  +    refac_io:format("Cs2:\n~p\n", [Cs2]),  
  +    refac_io:format("Cs3:\n~p\n", [Cs3]),  
  +    digraph:delete(CG).
  +
  +generate_fun_dist_matrix(File, CG) ->
  +    Funs = exported_funs(File),
  +    IntialMatrix = [{[F], [{[F1], undefined}||F1<-Funs]}||F<- Funs],
  +    update_dist(IntialMatrix, CG).
  +
  +agglomerative_cluster(Matrix, CG) ->
  +    agglomerative_cluster(Matrix, CG,[]).
  +
  +agglomerative_cluster(_Matric=[_], _CG,  Acc) ->
  +    lists:reverse(Acc);
  +agglomerative_cluster(Matrix, CG, Acc) ->
  +    %% refac_io:format("Matrix:\n~p\n", [Matrix]),
  +    {FG, Dist} = find_min_dist(Matrix),
  +    refac_io:format("FG:\n~p\n", [FG]),
  +    refac_io:format("Dist:\n~p\n", [Dist]),
  +    Matrix1=group_funs(Matrix, FG),
  +    Matrix2 = update_dist(Matrix1, CG),
  +    Cs = [F||{F, _}<- Matrix2],
  +    %% refac_io:format("Cs:\n~p\n", [Cs]),
  +    agglomerative_cluster(Matrix2, CG, [Cs|Acc]).
  +    
  +find_min_dist(Matrix) ->
  +    {FG, Dist}=
  +	lists:foldl(fun({RowKey, RowElems}, {Acc, Min})->
  +			    lists:foldl(fun({E, Dist}, {Acc0, Min0}) ->
  +						case Dist>=Min0 of
  +						    true -> {Acc0,Min0};
  +						    false ->
  +							{RowKey++E, Dist}
  +						end
  +					end, {Acc, Min}, RowElems)
  +		    end, {[],{1,1}}, Matrix),
  +    {lists:usort(FG), Dist}.
  +
  +group_funs(Matrix, FunsToGroup) ->
  +    Matrix1 =[{RowKey1, group_cols(RowElems1, FunsToGroup)}
  +	      || {RowKey, RowElems} <- Matrix, 
  +		 {RowKey1, RowElems1}<-
  +		     [case is_sub_list(RowKey, FunsToGroup) of 
  +			  true -> {FunsToGroup, [{Es, undefined}||
  +						    {Es, _Dist}<-RowElems]};
  +			  false -> {RowKey, RowElems}
  +		      end]],
  +    remove_duplicated_keys(Matrix1).
  +
  +						
  +group_cols(RowElems, FunsToGroup) ->
  +    NewRowElems =[{ColKey1, Dist1}||
  +		     {ColKey, Dist}<-RowElems,
  +		     {ColKey1, Dist1} <-[case is_sub_list(ColKey, FunsToGroup) of
  +					     true -> {FunsToGroup, undefined};
  +					     false -> {ColKey, Dist}
  +					 end]],
  +    remove_duplicated_keys(NewRowElems).
  +
  +remove_duplicated_keys(Tuples) ->
  +    remove_duplicated_keys(Tuples, [], []).
  +
  +remove_duplicated_keys([],_, Tuples1) -> 
  +    lists:reverse(Tuples1);
  +remove_duplicated_keys([{Key, V}|T], Keys, Tuples1) ->
  +    case lists:member(Key, Keys) of
  +	true ->
  +	    remove_duplicated_keys(T, Keys, Tuples1);
  +	false ->
  +	    remove_duplicated_keys(T, [Key|Keys],[{Key, V}|Tuples1])
  +    end.
  +
  +update_dist(Matrix, CG) ->
  +    [{RowKey, RowElems1} ||{RowKey, RowElems}<-Matrix,
  +			   RowElems1<-[[{ColKey, Dist1}
  +					||{ColKey, Dist}<-RowElems,
  +					  Dist1<-[update_dist(RowKey, ColKey, Dist, CG)]]]].
  +
  +update_dist(RowKey, ColKey, Dist, CG) ->
  +    case Dist of 
  +	undefined ->
  +	    calculate_dist(RowKey, ColKey, CG);
  +	_ -> Dist
  +    end.
  +
  +calculate_dist(FunGroup1=[{M, _F, _A}|_], FunGroup2, CG) ->
  +    case lists:usort(FunGroup1) == lists:usort(FunGroup2) of
  +      true -> {1,1};
  +      false ->
  +	    FunGroup1Reachable = digraph_utils:reachable(FunGroup1, CG),
  +	    FunGroup1ReachingMods =lists:usort([M1||{M1, _F1, _A1}<-digraph_utils:reaching(FunGroup1, CG), M1/=M]),
  +	    %%refac_io:format("ReachingMods1:\n~p\n", [FunGroup1ReachingMods]),
  +	    %% refac_io:format("FunGroup1:\n~p\n", [FunGroup1]),
  +	    %% refac_io:format("FunGroupReachable1:\n~p\n", [FunGroup1Reachable]),
  +	    FunGroup2Reachable = digraph_utils:reachable(FunGroup2, CG),
  +	    FunGroup2ReachingMods =lists:usort([M1||{M1, _F1, _A1}<-digraph_utils:reaching(FunGroup2, CG), M1/=M]),
  +	    %%refac_io:format("ReachingMods2:\n~p\n", [FunGroup2ReachingMods]),
  +	    CommonReachable = list_insection(FunGroup1Reachable, FunGroup2Reachable),
  +	    CommonReachableScore=1-2 * length(CommonReachable) / (length(FunGroup1Reachable) + length(FunGroup2Reachable)),
  +	    CommonReaching=list_insection(FunGroup1ReachingMods, FunGroup2ReachingMods),
  +	    CommonReachingScore=case FunGroup1ReachingMods==[] andalso FunGroup2ReachingMods==[] of 
  +				    true -> 0;
  +				    false ->
  +					1-2 * length(CommonReaching) / 
  +					    (length(FunGroup1ReachingMods) + length(FunGroup2ReachingMods))
  +				end,
  +	    refac_io:format("Es:\n~p\n", [{FunGroup1, FunGroup2}]),
  +	    refac_io:format("dist:\n~p\n", [{CommonReachableScore, CommonReachingScore}]),
  +	    {CommonReachableScore, CommonReachingScore}							  
  +    end.
  +
  +
  +is_component([], _CG) ->
  +    false;
  +is_component(Vs=[{M, _F, _A}|_T], CG) ->
  +    InEdges=lists:sort([{V1, V2}|| V<-Vs, E<-digraph:in_edges(CG,V), 
  +				   {_, V1, V2, _}<-[digraph:edge(CG, E)]]),
  +    InVs=element(1, lists:unzip(InEdges)),
  +    OutEdges=lists:sort([{V1, {M2, F2, A2}}|| V<-Vs, E<-digraph:out_edges(CG,V), 
  +					      {_, V1, {M2, F2,A2}, _}<-
  +						  [digraph:edge(CG, E)], M2==M]),
  +    OutVs=element(2, lists:unzip(OutEdges)),
  +    not (list_subtract(InVs, Vs)=/=[] andalso list_subtract(OutVs, Vs)=/=[]).
  +
  + 
  +%% wrangler_modularity_inspection:gen_module_graph("ibrowse_mg.dot", [],["c:/cygwin/home/hl/modularity_casestudy/apache-couchdb-0.11.0/src/ibrowse"], true).
  +%% wrangler_modularity_inspection:gen_module_graph("couchdb_mg.dot", [],["c:/cygwin/home/hl/modularity_casestudy/apache-couchdb-0.11.0/src/couchdb"], true). 
  +%% wrangler_modularity_inspection:gen_module_graph("wrangler_mg.dot", [], ["c:/cygwin/home/hl/modularity_casestudy/wrangler-0.8.7/src"], true).
  +
  +
  +%% wrangler_modularity_inspection:improper_inter_module_calls("ibrowse_improper_mc.dot", ["c:/cygwin/home/hl/modularity_casestudy/apache-couchdb-0.11.0/src/ibrowse"], []).
  +%% wrangler_modularity_inspection:improper_inter_module_calls("couchdb_improper__mc.dot", ["c:/cygwin/home/hl/modularity_casestudy/apache-couchdb-0.11.0/src/couchdb"], []). 
  +%% wrangler_modularity_inspection:improper_inter_module_calls("wrangler_improper__mc.dot", ["c:/cygwin/home/hl/modularity_casestudy/wrangler-0.8.7/src"], []).
  +
  +
  +%% wrangler_modularity_inspection:cyclic_dependent_modules("ibrowse_cycles.dot", ["c:/cygwin/home/hl/modularity_casestudy/apache-couchdb-0.11.0/src/ibrowse"],true).
  +%% wrangler_modularity_inspection:cyclic_dependent_modules("couchdb_cycles.dot", ["c:/cygwin/home/hl/modularity_casestudy/apache-couchdb-0.11.0/src/couchdb"],true).
  +%% wrangler_modularity_inspection:cyclic_dependent_modules("wrangler_cycles.dot", ["c:/cygwin/home/hl/modularity_casestudy/wrangler-0.8.7/src"],true).
  +
  +
  +%%wrangler_modularity_inspection:find_min_dist([{[a], [{[a], 1},{[b],0.1}, {[c], 0.9}]},{[b], [{[a],0.1}, {[b],1}, {[c], 0.9}]}, {[c], [{[a],0.9}, {[b], 0.9}, {[c],1}]}]).
  +
  +%% wrangler_modularity_inspection:cluster("c:/cygwin/home/hl/modularity_casestudy/apache-couchdb-0.11.0/src/ibrowse/ibrowse_lib.erl", ["c:/cygwin/home/hl/modularity_casestudy/%%apache-couchdb-0.11.0/src/ibrowse"]).
  
positive.code: 
  -export([gen_module_graph/4, gen_module_scc_graph/3, gen_function_callgraph/3]).
  
  -export([improper_inter_module_calls/3, mutual_recursive_modules/3, 
  	 partition_a_module/1, modules_with_big_fanin/4, modules_with_big_fanout/4]).
  
  -include("../include/wrangler.hrl").
  
  
negative.code:     refac_module_graph:module_graph_to_dot(OutFile, Res, false).
  
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %%                                                                     %%
  %%  Some utility functions.                                            %%
  %%                                                                     %%
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  
  
  
  list_insection(L1, L2) ->
      ordsets:to_list(ordsets:intersection(ordsets:from_list(L1), ordsets:from_list(L2))).
  
  list_subtract(L1, L2) ->
      ordsets:to_list(ordsets:subtract(ordsets:from_list(L1), ordsets:from_list(L2))).
  
  is_sub_list(L1, L2) ->
      ordsets:is_subset(ordsets:from_list(L1), ordsets:from_list(L2)).
  
  remove_sub_lists(ListOfLists) ->
      ListOfLists1 = lists:sort(fun(L1, L2)-> length(L1)>= length(L2) end, ListOfLists),
      remove_sub_lists(ListOfLists1,[]).
  
  remove_sub_lists([], Acc) ->
      lists:reverse(Acc);
  remove_sub_lists([L|T], Acc) ->
      case lists:any(fun(A)->
  			   is_sub_list(L, A) 
  		   end, Acc) of 
  	true ->
  	    remove_sub_lists(T, Acc);
  	false ->
  	    remove_sub_lists(T, [L|Acc])
      end.
  		  
  
  
  is_prop_sub_list(L1, L2) ->
      S1 = ordsets:from_list(L1),
      S2 = ordsets:from_list(L2),
      size(S1) < size(S2) andalso ordsets:is_subset(S1, S2).
  
  add_edges([], MG) ->
      MG;
  add_edges([{Caller, Callees}|Left], MG) ->
  