nodes: 0, module; 1, function_definition; 2, function_name:compare_baselines; 3, parameters; 4, block; 5, identifier:old_baseline_filename; 6, identifier:new_baseline_filename; 7, expression_statement; 8, if_statement; 9, expression_statement; 10, expression_statement; 11, expression_statement; 12, expression_statement; 13, comment:# We aggregate the secrets first, so that we can display a total count.; 14, expression_statement; 15, expression_statement; 16, expression_statement; 17, expression_statement; 18, for_statement; 19, comment:"""
      This function enables developers to more easily configure plugin
      settings, by comparing two generated baselines and highlighting
      their differences.
  
      For effective use, a few assumptions are made:
          1. Baselines are sorted by (filename, line_number, hash).
             This allows for a deterministic order, when doing a side-by-side
             comparison.
  
          2. Baselines are generated for the same codebase snapshot.
             This means that we won't have cases where secrets are moved around;
             only added or removed.
  
      NOTE: We don't want to do a version check, because we want to be able to
      use this functionality across versions (to see how the new version fares
      compared to the old one).
      """; 20, comparison_operator:old_baseline_filename == new_baseline_filename; 21, block; 22, assignment; 23, assignment; 24, call; 25, call; 26, assignment; 27, assignment; 28, assignment; 29, assignment; 30, pattern_list; 31, identifier:secret_iterator; 32, block; 33, identifier:old_baseline_filename; 34, identifier:new_baseline_filename; 35, raise_statement; 36, identifier:old_baseline; 37, call; 38, identifier:new_baseline; 39, call; 40, identifier:_remove_nonexistent_files_from_baseline; 41, argument_list; 42, identifier:_remove_nonexistent_files_from_baseline; 43, argument_list; 44, identifier:secrets_to_compare; 45, call; 46, identifier:total_reviews; 47, call; 48, identifier:current_index; 49, integer:0; 50, identifier:secret_iterator; 51, call; 52, identifier:filename; 53, identifier:secret; 54, identifier:is_removed; 55, expression_statement; 56, expression_statement; 57, expression_statement; 58, if_statement; 59, try_statement; 60, if_statement; 61, if_statement; 62, identifier:RedundantComparisonError; 63, identifier:_get_baseline_from_file; 64, argument_list; 65, identifier:_get_baseline_from_file; 66, argument_list; 67, identifier:old_baseline; 68, identifier:new_baseline; 69, identifier:_get_secrets_to_compare; 70, argument_list; 71, identifier:len; 72, argument_list; 73, identifier:BidirectionalIterator; 74, argument_list; 75, call; 76, augmented_assignment; 77, assignment; 78, identifier:is_removed; 79, block; 80, else_clause; 81, block; 82, except_clause; 83, comparison_operator:decision == 'q'; 84, block; 85, comparison_operator:decision == 'b'; 86, comment:# pragma: no cover; 87, block; 88, identifier:old_baseline_filename; 89, identifier:new_baseline_filename; 90, identifier:old_baseline; 91, identifier:new_baseline; 92, identifier:secrets_to_compare; 93, identifier:secrets_to_compare; 94, identifier:_clear_screen; 95, argument_list; 96, identifier:current_index; 97, integer:1; 98, identifier:header; 99, string; 100, expression_statement; 101, expression_statement; 102, block; 103, expression_statement; 104, expression_statement; 105, identifier:SecretNotFoundOnSpecifiedLineError; 106, block; 107, identifier:decision; 108, string; 109, expression_statement; 110, break_statement; 111, identifier:decision; 112, string; 113, expression_statement; 114, expression_statement; 115, string_content:{}      {}; 116, assignment; 117, assignment; 118, expression_statement; 119, expression_statement; 120, call; 121, assignment; 122, expression_statement; 123, string_content:q; 124, call; 125, string_content:b; 126, augmented_assignment; 127, call; 128, identifier:plugins_used; 129, subscript; 130, identifier:header; 131, call; 132, assignment; 133, assignment; 134, identifier:_print_context; 135, argument_list; 136, identifier:decision; 137, call; 138, assignment; 139, identifier:print; 140, argument_list; 141, identifier:current_index; 142, integer:2; 143, attribute; 144, argument_list; 145, identifier:old_baseline; 146, string; 147, attribute; 148, argument_list; 149, identifier:plugins_used; 150, subscript; 151, identifier:header; 152, call; 153, identifier:filename; 154, identifier:secret; 155, identifier:current_index; 156, identifier:total_reviews; 157, identifier:plugins_used; 158, keyword_argument; 159, keyword_argument; 160, identifier:_get_user_decision; 161, argument_list; 162, identifier:decision; 163, call; 164, string; 165, identifier:secret_iterator; 166, identifier:step_back_on_next_iteration; 167, string_content:plugins_used; 168, identifier:header; 169, identifier:format; 170, call; 171, call; 172, identifier:new_baseline; 173, string; 174, attribute; 175, argument_list; 176, identifier:additional_header_lines; 177, identifier:header; 178, identifier:force; 179, identifier:is_removed; 180, keyword_argument; 181, keyword_argument; 182, identifier:_get_user_decision; 183, argument_list; 184, string_content:Quitting...; 185, identifier:colorize; 186, argument_list; 187, attribute; 188, argument_list; 189, string_content:plugins_used; 190, identifier:header; 191, identifier:format; 192, call; 193, call; 194, identifier:can_step_back; 195, call; 196, identifier:prompt_secret_decision; 197, False; 198, keyword_argument; 199, string; 200, attribute; 201, string; 202, identifier:format; 203, call; 204, identifier:colorize; 205, argument_list; 206, attribute; 207, argument_list; 208, attribute; 209, argument_list; 210, identifier:prompt_secret_decision; 211, False; 212, string_content:Status:; 213, identifier:AnsiColor; 214, identifier:BOLD; 215, string_content:>> {} <<; 216, identifier:colorize; 217, argument_list; 218, string; 219, attribute; 220, string; 221, identifier:format; 222, call; 223, identifier:secret_iterator; 224, identifier:can_step_back; 225, string; 226, attribute; 227, string_content:Status:; 228, identifier:AnsiColor; 229, identifier:BOLD; 230, string_content:>> {} <<; 231, identifier:colorize; 232, argument_list; 233, string_content:REMOVED; 234, identifier:AnsiColor; 235, identifier:RED; 236, string; 237, attribute; 238, string_content:ADDED; 239, identifier:AnsiColor; 240, identifier:LIGHT_GREEN
code: def compare_baselines(old_baseline_filename, new_baseline_filename):
      """
      This function enables developers to more easily configure plugin
      settings, by comparing two generated baselines and highlighting
      their differences.
  
      For effective use, a few assumptions are made:
          1. Baselines are sorted by (filename, line_number, hash).
             This allows for a deterministic order, when doing a side-by-side
             comparison.
  
          2. Baselines are generated for the same codebase snapshot.
             This means that we won't have cases where secrets are moved around;
             only added or removed.
  
      NOTE: We don't want to do a version check, because we want to be able to
      use this functionality across versions (to see how the new version fares
      compared to the old one).
      """
      if old_baseline_filename == new_baseline_filename:
          raise RedundantComparisonError
  
      old_baseline = _get_baseline_from_file(old_baseline_filename)
      new_baseline = _get_baseline_from_file(new_baseline_filename)
  
      _remove_nonexistent_files_from_baseline(old_baseline)
      _remove_nonexistent_files_from_baseline(new_baseline)
  
      # We aggregate the secrets first, so that we can display a total count.
      secrets_to_compare = _get_secrets_to_compare(old_baseline, new_baseline)
      total_reviews = len(secrets_to_compare)
      current_index = 0
  
      secret_iterator = BidirectionalIterator(secrets_to_compare)
      for filename, secret, is_removed in secret_iterator:
          _clear_screen()
          current_index += 1
  
          header = '{}      {}'
          if is_removed:
              plugins_used = old_baseline['plugins_used']
              header = header.format(
                  colorize('Status:', AnsiColor.BOLD),
                  '>> {} <<'.format(
                      colorize('REMOVED', AnsiColor.RED),
                  ),
              )
          else:
              plugins_used = new_baseline['plugins_used']
              header = header.format(
                  colorize('Status:', AnsiColor.BOLD),
                  '>> {} <<'.format(
                      colorize('ADDED', AnsiColor.LIGHT_GREEN),
                  ),
              )
  
          try:
              _print_context(
                  filename,
                  secret,
                  current_index,
                  total_reviews,
                  plugins_used,
                  additional_header_lines=header,
                  force=is_removed,
              )
              decision = _get_user_decision(
                  can_step_back=secret_iterator.can_step_back(),
                  prompt_secret_decision=False,
              )
          except SecretNotFoundOnSpecifiedLineError:
              decision = _get_user_decision(prompt_secret_decision=False)
  
          if decision == 'q':
              print('Quitting...')
              break
  
          if decision == 'b':  # pragma: no cover
              current_index -= 2
              secret_iterator.step_back_on_next_iteration()