anchor.diff:  %%%  A topological sort of a partial order is a sequence of elements
   %%%  [X1, X2, X3 ...] such that if whenever {Xi, Xj} is in the partial
   %%%  order i &lt; j
  +%%%
  +%%%  This particular implementation guarantees that nodes closer to
  +%%%  the top level of the graph will be put as close as possible to
  +%%%  the beginning of the resulting list - this ensures that dependencies
  +%%%  are started as late as possible, and top-level apps are started
  +%%%  as early as possible.
   %%% @end
   %%%-------------------------------------------------------------------
   -module(rlx_topo).
   
  --export([sort/1,
  -         sort_apps/1,
  +-export([sort_apps/1,
            format_error/1]).
   
   -include("relx.hrl").
  -
  -%%====================================================================
  -%% Types
  -%%====================================================================
  --type pair() :: {DependentApp::atom(), PrimaryApp::atom()}.
  --type name() :: AppName::atom().
  --type element() :: name() | pair().
   
   %%====================================================================
   %% API
  
positive.code:                       end, Apps),
      App1.
  
  -spec apps_to_pairs([rlx_app_info:t()]) -> [pair()].
  apps_to_pairs(Apps) ->
      lists:flatten([app_to_pairs(App) || App <- Apps]).
  
  -spec app_to_pairs(rlx_app_info:t()) -> [pair()].
  app_to_pairs(App) ->
      [{DepApp, rlx_app_info:name(App)} ||
          DepApp <-
              rlx_app_info:active_deps(App) ++
              rlx_app_info:library_deps(App)].
  
  
  %% @doc Iterate over the system.  @private
  -spec iterate([pair()], [name()], [name()]) ->
      {ok, [name()]} | relx:error().
  iterate([], L, All) ->
      {ok, remove_duplicates(L ++ subtract(All, L))};
  iterate(Pairs, L, All) ->
      case subtract(lhs(Pairs), rhs(Pairs)) of
          []  ->
              ?RLX_ERROR({cycle, Pairs});
          Lhs ->
              iterate(remove_pairs(Lhs, Pairs), L ++ Lhs, All)
      end.
  
  -spec all([pair()]) -> [atom()].
  all(L) ->
      lhs(L) ++ rhs(L).
  
  -spec lhs([pair()]) -> [atom()].
  lhs(L) ->
      [X || {X, _} <- L].
  
  -spec rhs([pair()]) -> [atom()].
  rhs(L) ->
      [Y || {_, Y} <- L].
  
  %% @doc all the elements in L1 which are not in L2
  %% @private
  -spec subtract([element()], [element()]) -> [element()].
  subtract(L1, L2) ->
      [X || X <- L1, not lists:member(X, L2)].
  
  %% @doc remove dups from the list.  @private
  -spec remove_duplicates([element()]) -> [element()].
  remove_duplicates([H|T]) ->
    case lists:member(H, T) of
        true  ->
            remove_duplicates(T);
        false ->
            [H|remove_duplicates(T)]
    end;
  remove_duplicates([]) ->
      [].
  
  %% @doc
  %%   removes all pairs from L2 where the first element
  %%   of each pair is a member of L1
  %%
  %%   L2' L1 = [X] L2 = [{X,Y}].
  %% @private
  -spec remove_pairs([atom()], [pair()]) -> [pair()].
  remove_pairs(L1, L2) ->
      [All || All={X, _Y} <- L2, not lists:member(X, L1)].
  
  %%====================================================================
  %% Tests
  %%====================================================================
  -ifdef(TEST).
  -include_lib("eunit/include/eunit.hrl").
  
  topo_1_test() ->
      Pairs = [{one,two},{two,four},{four,six},
               {two,ten},{four,eight},
               {six,three},{one,three},
               {three,five},{five,eight},
               {seven,five},{seven,nine},
               {nine,four},{nine,ten}],
      ?assertMatch({ok, [one,seven,two,nine,four,six,three,five,eight,ten]},
                   sort(Pairs)).
  topo_2_test() ->
      Pairs = [{app2, app1}, {zapp1, app1}, {stdlib, app1},
               {app3, app2}, {kernel, app1}, {kernel, app3},
               {app2, zapp1}, {app3, zapp1}, {zapp2, zapp1}],
      ?assertMatch({ok, [stdlib, kernel, zapp2,
                         app3, app2, zapp1, app1]},
                   sort(Pairs)).
  
  topo_pairs_cycle_test() ->
      Pairs = [{app2, app1}, {app1, app2}, {stdlib, app1}],
      ?assertMatch({error, {_, {cycle, [{app2, app1}, {app1, app2}]}}},
                   sort(Pairs)).
  
  topo_apps_cycle_test() ->
      {ok, App1} = rlx_app_info:new(app1, "0.1", "/no-dir", [app2], [stdlib]),
      {ok, App2} = rlx_app_info:new(app2, "0.1", "/no-dir", [app1], []),
      Apps = [App1, App2],
      ?assertMatch({error, {_, {cycle, [{app2,app1},{app1,app2}]}}},
                   sort_apps(Apps)).
  
  topo_apps_good_test() ->
  
negative.code: %%%-------------------------------------------------------------------
  %%% @author Joe Armstrong
  %%% @author Eric Merritt
  %%% @author Konstantin Tcepliaev
  %%% @doc
  %%%  This is a pretty simple topological sort for erlang. It was
  %%%  originally written for ermake by Joe Armstrong back in '98. It
  %%%  has been pretty heavily modified by Eric Merritt since '06 and modified again for Relx.
  %%%  Konstantin Tcepliaev rewrote the algorithm in 2017.
  %%%
  %%%  A partial order on the set S is a set of pairs {Xi,Xj} such that
  %%%  some relation between Xi and Xj is obeyed.
  