code: def _traverse_graph(self):
      def traverse(node, seen, split_parents):
          if node.type in ("split", "foreach"):
              node.split_parents = split_parents
              split_parents = split_parents + [node.name]
          elif node.type == "join":
              # ignore joins without splits
              if split_parents:
                  self[split_parents[-1]].matching_join = node.name
                  node.split_parents = split_parents
                  split_parents = split_parents[:-1]
          else:
              node.split_parents = split_parents
  
          for n in node.out_funcs:
              # graph may contain loops - ignore them
              if n not in seen:
                  # graph may contain unknown transitions - ignore them
                  if n in self:
                      child = self[n]
                      child.in_funcs.add(node.name)
                      traverse(child, seen + [n], split_parents)
  
      if "start" in self:
          traverse(self["start"], [], [])
  
      # fix the order of in_funcs
      for node in self.nodes.values():
          node.in_funcs = sorted(node.in_funcs)
  
imports: import inspect
  import ast
  import re
label_desc: Use image node_id 4 for calling the FlowGraph obj's underlying member method code with example usage: obj._traverse_graph() without return types