Inheritance: IPipeline, IPipelineBuilder
      public IEnumerable<ContributorCall> GenerateCallGraph(IEnumerable<IPipelineContributor> contributors)
    {
      contributors = contributors.ToList();

      var bootstrapper = contributors.OfType<KnownStages.IBegin>().Single();
      var nodes = new List<TopologicalNode<ContributorNotification>>();

      foreach (var contributor in contributors.Where(x => x != bootstrapper))
      {
        var builder = new PipelineBuilder(contributors);
        builder.ContributorRegistrations.Clear();

        contributor.Initialize(builder);

        nodes.AddRange(
          builder.ContributorRegistrations
              .DefaultIfEmpty(new Notification(
                  Middleware.IdentitySingleTap,
                  builder.Contributors))
              .Select(reg => new TopologicalNode<ContributorNotification>(
                  new ContributorNotification(contributor, reg))));
      }

      foreach (var notificationNode in nodes)
      {
        foreach (var afterType in notificationNode.Item.Notification.AfterTypes)
        {
          var parents = GetCompatibleNodes(nodes, notificationNode, afterType);
          notificationNode.Dependencies.AddRange(parents);
        }

        foreach (var beforeType in notificationNode.Item.Notification.BeforeTypes)
        {
          var children = GetCompatibleNodes(nodes, notificationNode, beforeType);
          foreach (var child in children)
          {
            child.Dependencies.Add(notificationNode);
          }
        }
      }

      var rootItem = new ContributorNotification(bootstrapper,
          new Notification(Middleware.IdentitySingleTap, contributors));

      return new TopologicalTree<ContributorNotification>(rootItem, nodes).Nodes
        .Select(
          n => new ContributorCall(n.Item.Contributor, n.Item.Notification.Target, n.Item.Notification.Description));
    }
    public IEnumerable<ContributorCall> GenerateCallGraph(IEnumerable<IPipelineContributor> contributors)
    {
      contributors = contributors.ToList();

      var bootstrapper = contributors.OfType<KnownStages.IBegin>().Single();
      var tree = new DependencyTree<ContributorNotification>(
        new ContributorNotification(bootstrapper, new Notification(Middleware.IdentitySingleTap, contributors)));

      foreach (var contrib in contributors.Where(x => x != bootstrapper))
      {
        var builder = new PipelineBuilder(contributors);

        builder.ContributorRegistrations.Clear();

        contrib.Initialize(builder);

        var contributorRegistrations =
          builder.ContributorRegistrations.DefaultIfEmpty(new Notification(Middleware.IdentitySingleTap, contributors)).ToList();
        foreach (var registration in contributorRegistrations)
        {
          tree.CreateNode(new ContributorNotification(contrib, registration));
        }
      }

      foreach (var notificationNode in tree.Nodes)
      {
        foreach (var parentNode in GetCompatibleTypes(tree,
          notificationNode,
          notificationNode.Value.Notification.AfterTypes))
          parentNode.ChildNodes.Add(notificationNode);
        foreach (var childNode in GetCompatibleTypes(tree,
          notificationNode,
          notificationNode.Value.Notification.BeforeTypes))
          childNode.ParentNodes.Add(notificationNode);
      }

      return
        tree.GetCallGraph()
          .Select(
            x => new ContributorCall(x.Value.Contributor, x.Value.Notification.Target, x.Value.Notification.Description));
    }