Calculates and outputs comparison between all nodes on the network.

def do_compare_chains(args):
    """Calculates and outputs comparison between all nodes on the network."""
    urls = split_comma_append_args(args.urls)
    users = split_comma_append_args(args.users)
    clients = make_rest_apis(urls, users)

    broken = []

    chains, errors = get_chain_generators(clients, args.limit)
    broken.extend(errors)
    for node in errors:
        print("Error connecting to node %d: %s" % (node, urls[node]))
    if not chains:
        print("No nodes reporting")
        return

    tails, errors = get_tails(chains)
    broken.extend(errors)
    for node in errors:
        del chains[node]
    for node in errors:
        print("Failed to reach common height with node %d: %s" % (
            node, urls[node]))
    if not chains:
        print("Failed to get common height")
        return

    graph, errors = build_fork_graph(chains, tails)
    broken.extend(errors)
    for node in errors:
        print("Failed to reach common ancestor with node %d: %s" % (
            node, urls[node]))
    if not graph:
        print("Failed to build fork graph")
        return

    # Transform tails and errors into the format expected by the print
    # functions. Because errors can occur while building the graph, we need to
    # remove the tails for those clients.
    broken.sort()
    node_id_map = get_node_id_map(broken, len(clients))
    tails = list(map(
        lambda item: item[1],
        filter(
            lambda item: item[0] not in broken,
            sorted(tails.items()))))

    if args.table:
        print_table(graph, tails, node_id_map)

    elif args.tree:
        print_tree(graph, tails, node_id_map)

    else:
        print_summary(graph, tails, node_id_map)