docs: @SuppressWarnings("OptionalGetWithoutIsPresent")
    @Override
    public void run() throws Exception {
      final Optional<File> inputMapFile = parameters.getOptionalExistingFile(INPUT_MAP_PARAM);
      final Optional<File> inputListFile = parameters.getOptionalExistingFile(INPUT_LIST_PARAM);
      final Optional<File> outputMapFile = parameters.getOptionalCreatableFile(OUTPUT_MAP_PARAM);
      final Optional<File> outputListFile = parameters.getOptionalCreatableFile(OUTPUT_LIST_PARAM);
      final Optional<File> outputDirectory =
          parameters.getOptionalCreatableDirectory(OUTPUT_DIR_PARAM);
      final boolean inPlace = parameters.getOptionalBoolean(IN_PLACE_PARAM).or(false);
      final Optional<File> basePath = parameters.getOptionalExistingDirectory(BASE_PATH_PARAM);
  
      if (inputListFile.isPresent() == inputMapFile.isPresent()) {
        log.error("Exactly one input parameter given. Expected exactly one of {} and {}",
            INPUT_LIST_PARAM, INPUT_MAP_PARAM);
        System.exit(1);
      }
  
      if (!outputListFile.isPresent() && !outputMapFile.isPresent() && !inPlace) {
        log.error("No output parameter given. Expected {} or {} or for {} to be true",
            OUTPUT_LIST_PARAM, OUTPUT_MAP_PARAM, IN_PLACE_PARAM);
        System.exit(1);
      }
  
      if (outputMapFile.isPresent() && !inputMapFile.isPresent()) {
        log.error("Cannot use {} without {}", OUTPUT_MAP_PARAM, INPUT_MAP_PARAM);
        System.exit(1);
      }
  
      if (!inPlace && !basePath.isPresent()) {
        log.error("Cannot determine whow to output. Either {} must be true or {} must be "
            + "specified", IN_PLACE_PARAM, BASE_PATH_PARAM);
      }
  
      final ImmutableMap<Symbol, File> inputFileMap;
      if (inputMapFile.isPresent()) {
        inputFileMap = FileUtils.loadSymbolToFileMap(inputMapFile.get());
      } else {
        // if a map wasn't supplied, we make a fake map using the file path as the key.
        // we know the key won't matter, because we know map output wasn't requested or
        // the checks above would have caught the missing input map
        // .get() is safe by checks above
        inputFileMap = Maps.uniqueIndex(FileUtils.loadFileList(inputListFile.get()),
            compose(symbolizeFunction(), toAbsolutePathFunction()));
      }
      log.info("Cleaning {} input files {}", inputFileMap.size(),
          inPlace ? "in-place" : ("to " + outputDirectory.get().getAbsolutePath()));
  
      int totalCharactersReplaced = 0;
      int numFilesWithReplacements = 0;
  
      final ImmutableList.Builder<File> outputFiles = ImmutableList.builder();
      final ImmutableMap.Builder<Symbol, File> outputMap = ImmutableMap.builder();
      for (final Map.Entry<Symbol, File> e : inputFileMap.entrySet()) {
        final File inputFileName = e.getValue();
        final File outFile;
        if (inPlace) {
          outFile = inputFileName;
        } else {
          // write the output to a file with the same position relative to the output directory
          // as the input had relative to the input directory
          // get safe by checks above
          //noinspection OptionalGetWithoutIsPresent
          outFile = outputDirectory.get().toPath().resolve(
              basePath.get().toPath().relativize(inputFileName.toPath())).toFile();
        }
        //noinspection ResultOfMethodCallIgnored
        outFile.getParentFile().mkdirs();
  
        final String originalText = Files.asCharSource(inputFileName, Charsets.UTF_8).read();
        final int numReplacementCharsInOriginal =
            CodepointMatcher.forCharacter(UNICODE_REPLACEMENT_CHARACTER).countIn(originalText);
        final String cleanedText = not(basicMultilingualPlane()).replaceAll(
            originalText, UNICODE_REPLACEMENT_CHARACTER);
        final int numReplacementCharsInCleaned =
            CodepointMatcher.forCharacter(UNICODE_REPLACEMENT_CHARACTER).countIn(cleanedText);
        Files.asCharSink(outFile, Charsets.UTF_8).write(cleanedText);
  
        outputFiles.add(outFile);
        outputMap.put(e.getKey(), outFile);
  
        final int numCharsReplaced = numReplacementCharsInCleaned - numReplacementCharsInOriginal;
  
        checkState(numCharsReplaced >= 0,
            "Number of replacement characters went down.  Either this program is buggy or you have"
                + " a very broken and bizarre document");
        if (numCharsReplaced > 0) {
          log.info("Replaced {} non-BMP code points with the Unicode replacement character for"
              + "input file {}", numCharsReplaced, inputFileName);
          totalCharactersReplaced += numCharsReplaced;
          ++numFilesWithReplacements;
        }
      }
  
      log.info("Replaced {} non-BMP characters in {} files",
          totalCharactersReplaced, numFilesWithReplacements);
      if (outputListFile.isPresent()) {
        log.info("Writing list of transformed files to {}", outputListFile.get());
        FileUtils.writeFileList(outputFiles.build(), Files.asCharSink(outputListFile.get(),
            Charsets.UTF_8));
      }
      if (outputMapFile.isPresent()) {
        log.info("Writing map of transformed files to {}", outputMapFile.get());
        FileUtils.writeSymbolToFileMap(outputMap.build(), Files.asCharSink(outputMapFile.get(),
            Charsets.UTF_8));
      }
    }