code: def cut_nodes(graph):
      
      recursionlimit = getrecursionlimit()
      setrecursionlimit(max(len(graph.nodes())*2,recursionlimit))
      
      # Dispatch if we have a hypergraph
      if 'hypergraph' == graph.__class__.__name__:
          return _cut_hypernodes(graph)
          
      pre = {}    # Pre-ordering
      low = {}    # Lowest pre[] reachable from this node going down the spanning tree + one backedge
      reply = {}
      spanning_tree = {}
      pre[None] = 0
      
      # Create spanning trees, calculate pre[], low[]
      for each in graph:
          if (each not in pre):
              spanning_tree[each] = None
              _cut_dfs(graph, spanning_tree, pre, low, [], each)
  
      # Find cuts
      for each in graph:
          # If node is not a root
          if (spanning_tree[each] is not None):
              for other in graph[each]:
                  # If there is no back-edge from descendent to a ancestral of each
                  if (low[other] >= pre[each] and spanning_tree[other] == each):
                      reply[each] = 1
          # If node is a root
          else:
              children = 0
              for other in graph:
                  if (spanning_tree[other] == each):
                      children = children + 1
              # root is cut-vertex iff it has two or more children
              if (children >= 2):
                  reply[each] = 1
  
      setrecursionlimit(recursionlimit)
      return list(reply.keys())
docs: Return the cut-nodes of the given graph.
      
      A cut node, or articulation point, is a node of a graph whose removal increases the number of
      connected components in the graph.
      
      @type  graph: graph, hypergraph
      @param graph: Graph.
          
      @rtype:  list
      @return: List of cut-nodes.