docs: protected boolean checkTopicsForInvalidDuplicates(final ContentSpec contentSpec) {
          boolean valid = true;
  
          // Find all Topics that have two or more different revisions
          final List<ITopicNode> allTopicNodes = contentSpec.getAllTopicNodes();
          final Map<Integer, Map<Integer, Set<ITopicNode>>> invalidTopicNodes = new HashMap<Integer, Map<Integer, Set<ITopicNode>>>();
  
          for (final ITopicNode topicNode1 : allTopicNodes) {
              if (!topicNode1.isTopicAnExistingTopic()) continue;
  
              for (final ITopicNode topicNode2 : allTopicNodes) {
                  // If the Topic isn't an existing topic and doesn't match the first spec topic's id, then continue
                  if (topicNode1 == topicNode2 || !topicNode2.isTopicAnExistingTopic() || !topicNode1.getDBId().equals(topicNode2.getDBId()))
                      continue;
  
                  // Check if the revisions between the two topics are the same
                  if (topicNode1.getRevision() == null && topicNode2.getRevision() != null || topicNode1.getRevision() != null &&
                          topicNode2.getRevision() == null || topicNode1.getRevision() != null && !topicNode1.getRevision().equals(
                          topicNode2.getRevision())) {
                      if (!invalidTopicNodes.containsKey(topicNode1.getDBId())) {
                          invalidTopicNodes.put(topicNode1.getDBId(), new HashMap<Integer, Set<ITopicNode>>());
                      }
  
                      final Map<Integer, Set<ITopicNode>> revisionsToTopicNode = invalidTopicNodes.get(topicNode1.getDBId());
                      if (!revisionsToTopicNode.containsKey(topicNode1.getRevision())) {
                          revisionsToTopicNode.put(topicNode1.getRevision(), new HashSet<ITopicNode>());
                      }
  
                      revisionsToTopicNode.get(topicNode1.getRevision()).add(topicNode1);
  
                      valid = false;
                  }
              }
          }
  
          // Loop through and generate an error message for each invalid topic
          for (final Entry<Integer, Map<Integer, Set<ITopicNode>>> entry : invalidTopicNodes.entrySet()) {
              final Integer topicId = entry.getKey();
              final Map<Integer, Set<ITopicNode>> revisionsToTopicNode = entry.getValue();
  
              final List<String> revNumbers = new ArrayList<String>();
              final List<Integer> revisions = new ArrayList<Integer>(revisionsToTopicNode.keySet());
              Collections.sort(revisions, new NullNumberSort<Integer>());
  
              for (final Integer revision : revisions) {
                  final List<ITopicNode> topicNodes = new ArrayList<ITopicNode>(revisionsToTopicNode.get(revision));
  
                  // Build up the line numbers message
                  final StringBuilder lineNumbers = new StringBuilder();
                  if (topicNodes.size() > 1) {
                      // Sort the Topics by line numbers
                      Collections.sort(topicNodes, new TopicNodeLineNumberComparator());
  
                      for (int i = 0; i < topicNodes.size(); i++) {
                          if (i == topicNodes.size() - 1) {
                              lineNumbers.append(" and ");
                          } else if (lineNumbers.length() != 0) {
                              lineNumbers.append(", ");
                          }
  
                          lineNumbers.append(topicNodes.get(i).getLineNumber());
                      }
                  } else if (topicNodes.size() == 1) {
                      lineNumbers.append(topicNodes.get(0).getLineNumber());
                  }
  
                  // Build the revision message
                  revNumbers.add(
                          String.format(ProcessorConstants.ERROR_TOPIC_WITH_DIFFERENT_REVS_REV_MSG, (revision == null ? "Latest" : revision),
                                  lineNumbers));
              }
  
              final StringBuilder message = new StringBuilder(String.format(ProcessorConstants.ERROR_TOPIC_WITH_DIFFERENT_REVS_MSG, topicId));
              for (final String revNumber : revNumbers) {
                  message.append(String.format(ProcessorConstants.CSLINE_MSG, revNumber));
              }
  
              log.error(message.toString());
          }
  
          return valid;
      }