docs: def crawl(alphabet, initial, final, follow):
  	'''
  		Given the above conditions and instructions, crawl a new unknown FSM,
  		mapping its states, final states and transitions. Return the new FSM.
  		This is a pretty powerful procedure which could potentially go on
  		forever if you supply an evil version of follow().
  	'''
  
  	states = [initial]
  	finals = set()
  	map = {}
  
  	# iterate over a growing list
  	i = 0
  	while i < len(states):
  		state = states[i]
  
  		# add to finals
  		if final(state):
  			finals.add(i)
  
  		# compute map for this state
  		map[i] = {}
  		for symbol in sorted(alphabet, key=key):
  			try:
  				next = follow(state, symbol)
  
  				try:
  					j = states.index(next)
  				except ValueError:
  					j = len(states)
  					states.append(next)
  
  			except OblivionError:
  				# Reached an oblivion state. Don't list it.
  				continue
  
  			map[i][symbol] = j
  
  		i += 1
  
  	return fsm(
  		alphabet = alphabet,
  		states   = range(len(states)),
  		initial  = 0,
  		finals   = finals,
  		map      = map,
  	)