def calc_node_coords(tiling_edge_list, first_node_offset=0):
    """
    For a single tiling path (tiling_edge_list is a list
    of edges for a particular contig) calculates the
    genomic coordinate of every node in the path.
    In case there are cycles in the tiling path,
    the existing node's coordinate will be overwritten.
    `first_node_offset` refers to the length of the first node. If
    not specified, the contig length should not
    consider the length of the first node.
    """
    if not tiling_edge_list:
        return {}, 0
    coord_map = {}
    contig_len = 0
    edge0 = tiling_edge_list[0]
    coord_map[edge0.v] = first_node_offset
    for edge in tiling_edge_list:
        if edge.v not in coord_map:
            raise Exception(
                'Tiling path is not in sorted order. Node "{v!r}" does not yet have an assigned coordinate.'.format(v=edge.v))
        coord = coord_map[edge.v]
        coord += abs(int(edge.b) - int(edge.e))
        coord_map[edge.w] = coord
        contig_len = max(contig_len, coord)
    return coord_map, contig_len