public static void CreateGraph(string sourceAssembliesFolder, string skipAssemblyFile, string targetFilepath, string rootCsv = null)
        {
            var rootFilter     = rootCsv?.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            var skipAssemblies = GetSkipAssemblies(skipAssemblyFile, sourceAssembliesFolder, rootFilter);

            var allAssemblies = FindConflictsProgram.GetAllAssemblies(sourceAssembliesFolder, rootFilter)
                                .Where(x => !skipAssemblies.Contains(x.GetName().Name));
            var assemblies = allAssemblies
                             .Where(x => !ShouldSkip(x.GetName().Name, skipAssemblies))
                             .ToArray();

            var allAssemblyLinks = allAssemblies.SelectMany(a => a.GetReferencedAssemblies().Select(a2 => Tuple.Create(a, a2)));
            var assemblyLinks    = allAssemblyLinks
                                   .Where(x => !ShouldSkip(x.Item1.GetName().Name, skipAssemblies) && !ShouldSkip(x.Item2.Name, skipAssemblies));

            var builder = CreateBuilder();
            var graph   = builder.Build(assemblies, assemblyLinks);

            // write to file
            graph.WriteToFile(targetFilepath);
            Log.Info($"output written to '{targetFilepath}'");
        }
        private static string GetComplexityStats(string folder, HashSet <string> skipAssemblies, string[] rootFilter)
        {
            var allAssemblies    = FindConflictsProgram.GetAllAssemblies(folder, rootFilter);
            var allAssemblyLinks = allAssemblies.SelectMany(a => a.GetReferencedAssemblies().Select(a2 => Tuple.Create(a, a2)));

            var builder = CreateBuilder();
            var graph   = builder.Build(allAssemblies, allAssemblyLinks);

            var refData = new Dictionary <string, RefData>(StringComparer.OrdinalIgnoreCase);

            foreach (var link in graph.Links)
            {
                if (!refData.ContainsKey(link.Source))
                {
                    refData.Add(link.Source, new RefData());
                }
                if (!refData.ContainsKey(link.Target))
                {
                    refData.Add(link.Target, new RefData());
                }
                refData[link.Target].DirectRefNodes.Add(link.Source);
            }

            foreach (var node in refData)
            {
                node.Value.IndirectRefCount += node.Value.DirectRefNodes.Count;
                foreach (var refNode in node.Value.DirectRefNodes)
                {
                    node.Value.IndirectRefCount += refData[refNode].DirectRefNodes.Count;
                }
            }

            var getCategory = new Func <string, string>((string assemblyName) =>
            {
                var lowPriAssemblyTag = (ShouldSkip(assemblyName, skipAssemblies) ? "ExternalAssemblies | " : "");
                var assembly          = allAssemblies.SingleOrDefault(x => x.GetName().Name.Equals(assemblyName, StringComparison.OrdinalIgnoreCase));
                var framework         = (assembly != null ? assembly.GetTargetFramework() : "UnknownFramework");
                return(lowPriAssemblyTag + framework);
            });

            var groups = refData.GroupBy(x => getCategory(x.Key), StringComparer.OrdinalIgnoreCase)
                         .OrderBy(x => x.Key);

            // print analysis
            var output = new StringBuilder();

            var uniqueFrameworks = allAssemblies.Select(x => x.GetTargetFramework()).Distinct();

            output.AppendLine(Environment.NewLine + "===> Unique Frameworks");
            output.AppendLine(string.Join(Environment.NewLine, uniqueFrameworks));

            foreach (var group in groups)
            {
                output.AppendLine(Environment.NewLine + $"===> Complexity | {group.Key}");
                var groupItems = group
                                 .OrderByDescending(gi => gi.Value.IndirectRefCount)
                                 .Select(gi => $"{gi.Key}\t{gi.Value.DirectRefNodes.Count}\t{gi.Value.IndirectRefCount}");
                output.AppendLine(string.Join(Environment.NewLine, groupItems));
            }

            return(output.ToString());
        }