 
     product_vertex: (v1, v2) ->
       key = @vkey(v1, v2)
-      @product_vertices[key]
-
-    product_next: (v1, v2) ->
-      unless (result = @product_vertex(v1, v2))
-        result = @intersection.create_vertex()
-        @add_unvisited(v1, v2, result)
-      result
+      unless (vertex = @product_vertices[key])
+        # Implement sink/final checking for FSMs by
+        # overriding this method and messing with the
+        # vertex we create.
+        vertex = @intersection.create_vertex()
+        @add_unvisited(v1, v2, vertex)
+      vertex
 
     add_unvisited: (v1, v2, product_vertex) ->
       key = @vkey(v1, v2)

    find_arc: (val) ->
      for arc in @_arcs
        return arc if arc.test(val)

    intersect: (other) ->
      # warning: Cartesian product
      arc for arc in @arcs() when other.find_arc(arc.value)

  class @Arc
    constructor: (@vertex, @id, @value, @next_vertex) ->

    while (next_vertices = helper.get_next_vertices())
      [this_vertex, other_vertex, product_vertex] = next_vertices

      # for the two current vertices, iterate over the arcs with same values.
      # TODO: check the arc intersection algorithm for stupids.
      helper.intersecting_arcs this_vertex, other_vertex, (this_arc, other_arc) ->
        this_next = this_arc.next_vertex
        other_next = other_arc.next_vertex

        # if the new graph does not already have the intersection state,
        # create an intersection state and index it
        product_next = helper.product_vertex(this_next, other_next)
        product.add_arc(product_vertex, product_next, this_arc.value)
    product


  traverse: (callback) ->
    _traverse = @stepper()
    next = _traverse([@source], callback)
    while next.length > 0
      next = _traverse(next, callback)

  stepper: ->
    visited_arcs = {}
