<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def read_graph(filename, directed=False, weighted=False, default_weight=None):
 """Read a graph from a text file :param filename: plain text file. All numbers are separated by space. Starts with a line containing n (#vertices) and m (#edges). Then m lines follow, for each edge. Vertices are numbered from 0 to n-1. Line for unweighted edge u,v contains two integers u, v. Line for weighted edge u,v contains three integers u, v, w[u,v]. :param directed: true for a directed graph, false for undirected :param weighted: true for an edge weighted graph :returns: graph in listlist format, possibly followed by weight matrix :complexity: O(n + m) for unweighted graph, :math:`O(n^2)` for weighted graph """

    with open(filename, 'r') as f:
        while True:
            line = f.readline()         # ignore leading comments
            if line[0] != '#':
                break
        nb_nodes, nb_edges = tuple(map(int, line.split()))
        graph = [[] for u in range(nb_nodes)]
        if weighted:
            weight = [[default_weight] * nb_nodes for v in range(nb_nodes)]
            for v in range(nb_nodes):
                weight[v][v] = 0
            for _ in range(nb_edges):
                u, v, w = readtab(f, int)
                graph[u].append(v)
                weight[u][v] = w
                if not directed:
                    graph[v].append(u)
                    weight[v][u] = w
            return graph, weight
        else:
            for _ in range(nb_edges):
                # si le fichier contient des poids, ils seront ignorés
                u, v = readtab(f, int)[:2]
                graph[u].append(v)
                if not directed:
                    graph[v].append(u)
            return graph