# File ../../auditor/lib/kasp_auditor/auditor.rb, line 1164
      def check_nsec3_types_and_opt_out(unknown_nsecs)
        # First of all we will have to sort the types file.
        system("#{Commands.sort} -t' ' #{@working}#{File::SEPARATOR}audit.types.#{Process.pid} > #{@working}#{File::SEPARATOR}audit.types.sorted.#{Process.pid}")

        # Go through each name in the files and check them
        # We want to check two things :
        # a) types covered
        # b) no hashes in between non-opt-out names

        # This checks the types covered for each domain name
        if (!File.exists?(@working +
                "#{File::SEPARATOR}audit.optout.#{Process.pid}"))
          File.new(@working +
              "#{File::SEPARATOR}audit.optout.#{Process.pid}", "w")
        end
        if (!File.exists?(@working +
                "#{File::SEPARATOR}audit.nsec3.#{Process.pid}"))
          File.new(@working +
              "#{File::SEPARATOR}audit.nsec3.#{Process.pid}", "w")
        end
        File.open(@working + 
            "#{File::SEPARATOR}audit.types.sorted.#{Process.pid}") {|ftypes|
          File.open(@working + 
              "#{File::SEPARATOR}audit.nsec3.#{Process.pid}") {|fnsec3|
            File.open(@working + 
                "#{File::SEPARATOR}audit.optout.#{Process.pid}") {|foptout|
              dont_load_next_types = false
              while (!ftypes.eof? && !fnsec3.eof? && !foptout.eof?)
                if (!dont_load_next_types)
                  types_name, types_name_unhashed, types_types = get_name_and_types(ftypes, true)
                else
                  dont_load_next_types = false
                end
                nsec3_name, nsec3_types = get_name_and_types(fnsec3)
                owner, next_hashed = get_next_non_optout(foptout)
                owner, next_hashed = check_optout(types_name_unhashed, owner, next_hashed, types_name, foptout)
                
                while ((nsec3_name < types_name) && (!fnsec3.eof?))
                  if (types_name < owner) # Don't forget about the optout list! If optout on empty nonterminal, then types_name == owner
                    log(LOG_ERROR, "Found NSEC3 record for hashed domain which couldn't be found in the zone (#{nsec3_name})")
                  end
                  nsec3_name, nsec3_types = get_name_and_types(fnsec3)
                end
                while ((types_name < nsec3_name) && (!ftypes.eof?))
                  if (!unknown_nsecs[types_name_unhashed+"."])
                    if (types_types.length > 0)
                      log(LOG_ERR, "Found RRs for #{types_name_unhashed} (#{types_name}) which was not covered by an NSEC3 record")
                    else
                      log(LOG_ERR, "Can't find NSEC3 for empty nonterminal #{types_name_unhashed} (should be #{types_name})")
                    end
                  end
                  types_name, types_name_unhashed, types_types = get_name_and_types(ftypes, true)

                  # Check the optout names as we load in more types
                  owner, next_hashed = check_optout(types_name_unhashed, owner, next_hashed, types_name, foptout)
                end
                # If there is only an NS record, and we are opt-out, then there should be no NSEC3 record here
                if (@parent.config.denial.nsec3.optout && (nsec3_types.include?Types::NS) && nsec3_types.include?(Types::RRSIG) && (nsec3_types.length == 2))
                  log(LOG_WARNING, "NSEC3 record found for #{types_name_unhashed} (#{nsec3_name}). Only an NS record is present, and opt out is being used, so no NSEC3 is expected")
                end
                # Now check the NSEC3 types_covered against the types ACTUALLY at the name
                if (types_types != nsec3_types)
                  # Let's just check that we haven't misidentified an empty nonterminal...
                  old_types_name = types_name
                  old_types_name_unhashed = types_name_unhashed
                  old_types_types = types_types
                  while (old_types_name == types_name)
                    types_name, types_name_unhashed, types_types = get_name_and_types(ftypes, true)
                    if (types_name == old_types_name)
                      dont_load_next_types = false
                      old_types_name = types_name
                      old_types_name_unhashed = types_name_unhashed
                      old_types_types = types_types
                    else
                      dont_load_next_types = true
                    end
                  end
                  if (old_types_types != nsec3_types)
                    log(LOG_ERR, "ERROR : expected #{@parent.get_types_string(nsec3_types)}" +
                        " at #{old_types_name_unhashed} (#{nsec3_name}) but found " +
                        "#{@parent.get_types_string(old_types_types)}")
                  end
                end
              end
            }
          }
        }

        # Now delete any intermediary files, if we're using NSEC3
        delete_nsec3_files()
      end