nodes: 0, module; 1, function_definition; 2, function_name:crack; 3, parameters; 4, block; 5, identifier:ciphertext; 6, list_splat_pattern; 7, default_parameter; 8, default_parameter; 9, default_parameter; 10, expression_statement; 11, if_statement; 12, expression_statement; 13, for_statement; 14, return_statement; 15, identifier:fitness_functions; 16, identifier:min_key; 17, integer:0; 18, identifier:max_key; 19, integer:26; 20, identifier:shift_function; 21, identifier:shift_case_english; 22, comment:"""Break ``ciphertext`` by enumerating keys between ``min_key`` and ``max_key``.
  
      Example:
          >>> decryptions = crack("KHOOR", fitness.english.quadgrams)
          >>> print(''.join(decryptions[0].plaintext))
          HELLO
  
      Args:
          ciphertext (iterable): The symbols to decrypt
          *fitness_functions (variable length argument list): Functions to score decryption with
  
      Keyword Args:
          min_key (int): Key to start with
          max_key (int): Key to stop at (exclusive)
          shift_function (function(shift, symbol)): Shift function to use
  
      Returns:
          Sorted list of decryptions
  
      Raises:
          ValueError: If min_key exceeds max_key
          ValueError: If no fitness_functions are given
      """; 23, comparison_operator:min_key >= max_key; 24, block; 25, assignment; 26, identifier:key; 27, call; 28, block; 29, call; 30, identifier:min_key; 31, identifier:max_key; 32, raise_statement; 33, identifier:decryptions; 34, list; 35, identifier:range; 36, argument_list; 37, expression_statement; 38, expression_statement; 39, identifier:sorted; 40, argument_list; 41, call; 42, identifier:min_key; 43, identifier:max_key; 44, assignment; 45, call; 46, identifier:decryptions; 47, keyword_argument; 48, identifier:ValueError; 49, argument_list; 50, identifier:plaintext; 51, call; 52, attribute; 53, argument_list; 54, identifier:reverse; 55, True; 56, string:"min_key cannot exceed max_key"; 57, identifier:decrypt; 58, argument_list; 59, identifier:decryptions; 60, identifier:append; 61, call; 62, identifier:key; 63, identifier:ciphertext; 64, keyword_argument; 65, identifier:Decryption; 66, argument_list; 67, identifier:shift_function; 68, identifier:shift_function; 69, identifier:plaintext; 70, identifier:key; 71, call; 72, identifier:score; 73, argument_list; 74, identifier:plaintext; 75, list_splat; 76, identifier:fitness_functions
code: def crack(ciphertext, *fitness_functions, min_key=0, max_key=26, shift_function=shift_case_english):
      """Break ``ciphertext`` by enumerating keys between ``min_key`` and ``max_key``.
  
      Example:
          >>> decryptions = crack("KHOOR", fitness.english.quadgrams)
          >>> print(''.join(decryptions[0].plaintext))
          HELLO
  
      Args:
          ciphertext (iterable): The symbols to decrypt
          *fitness_functions (variable length argument list): Functions to score decryption with
  
      Keyword Args:
          min_key (int): Key to start with
          max_key (int): Key to stop at (exclusive)
          shift_function (function(shift, symbol)): Shift function to use
  
      Returns:
          Sorted list of decryptions
  
      Raises:
          ValueError: If min_key exceeds max_key
          ValueError: If no fitness_functions are given
      """
      if min_key >= max_key:
          raise ValueError("min_key cannot exceed max_key")
  
      decryptions = []
      for key in range(min_key, max_key):
          plaintext = decrypt(key, ciphertext, shift_function=shift_function)
          decryptions.append(Decryption(plaintext, key, score(plaintext, *fitness_functions)))
  
      return sorted(decryptions, reverse=True)