// Path: api/src/main/java/xyz/docbleach/api/BleachSession.java
// public class BleachSession implements Serializable {
// 
//   private static final Logger LOGGER = LoggerFactory.getLogger(BleachSession.class);
//   private static final int MAX_ONGOING_TASKS = 10;
//   private final transient Bleach bleach;
//   private final Collection<Threat> threats = new ArrayList<>();
//   /**
//    * Counts ongoing tasks, to prevent fork bombs when handling zip archives for instance)
//    */
//   private int ongoingTasks = 0;
// 
//   public BleachSession(Bleach bleach) {
//     this.bleach = bleach;
//   }
// 
//   /**
//    * The BleachSession is able to record threats encountered by the bleach.
//    *
//    * @param threat The removed threat object, containing the threat type and more information
//    */
//   public void recordThreat(Threat threat) {
//     if (threat == null) {
//       return;
//     }
//     LOGGER.trace("Threat recorded: " + threat);
//     threats.add(threat);
//   }
// 
//   public Collection<Threat> getThreats() {
//     return threats;
//   }
// 
//   public int threatCount() {
//     return threats.size();
//   }
// 
//   /**
//    * @return The bleach used in this session
//    */
//   public Bleach getBleach() {
//     return bleach;
//   }
// 
//   public void sanitize(InputStream is, OutputStream os) throws BleachException {
//     try {
//       if (ongoingTasks++ >= MAX_ONGOING_TASKS) {
//         throw new RecursionBleachException(ongoingTasks);
//       }
//       if (!bleach.handlesMagic(is)) {
//         return;
//       }
//       bleach.sanitize(is, os, this);
//     } finally {
//       ongoingTasks--;
//     }
//   }
// }
// 
// Path: api/src/main/java/xyz/docbleach/api/bleach/DefaultBleach.java
// public class DefaultBleach extends CompositeBleach {
// 
//   public DefaultBleach() {
//     super(getDefaultBleaches());
//   }
// 
//   /**
//    * Finds all statically loadable bleaches
//    *
//    * @return ordered list of statically loadable bleaches
//    */
//   private static Bleach[] getDefaultBleaches() {
//     ServiceLoader<Bleach> services = ServiceLoader.load(Bleach.class);
// 
//     Collection<Bleach> list = new ArrayList<>();
//     services.forEach(list::add);
// 
//     return list.toArray(new Bleach[0]);
//   }
// }
// 
// Path: api/src/main/java/xyz/docbleach/api/exception/BleachException.java
// public class BleachException extends Exception {
// 
//   public BleachException(Throwable e) {
//     super(e);
//   }
// 
//   public BleachException(String message) {
//     super(message);
//   }
// }


import com.google.gson.Gson;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.MissingOptionException;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.UnrecognizedOptionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.impl.SimpleLogger;
import xyz.docbleach.api.BleachSession;
import xyz.docbleach.api.bleach.DefaultBleach;
import xyz.docbleach.api.exception.BleachException;
  private void sanitize() throws BleachException {
    BleachSession session = new BleachSession(new DefaultBleach());

    session.sanitize(inputStream, outputStream);

    if (jsonOutput) {
      Gson gson = new Gson();
      System.err.println(gson.toJson(session));
    } else {
      if (session.threatCount() == 0) {
        LOGGER.info("The file was already safe, so I've just copied it over.");
      } else {
        LOGGER.warn(
            "Sanitized file has been saved, {} potential threat(s) removed.",
            session.threatCount());
      }
    }
  }

  private void setupLogging() {
    if (verbosityLevel <= 0) {
      // Verbosity is INFO or OFF, we hide the thread and logger names
      System.setProperty(SimpleLogger.SHOW_THREAD_NAME_KEY, "false");
      System.setProperty(SimpleLogger.SHOW_LOG_NAME_KEY, "false");
    }

    String level;
    switch (verbosityLevel) {
      case -1:
        level = "OFF";
// Path: api/src/main/java/xyz/docbleach/api/BleachSession.java
// public class BleachSession implements Serializable {
// 
//   private static final Logger LOGGER = LoggerFactory.getLogger(BleachSession.class);
//   private static final int MAX_ONGOING_TASKS = 10;
//   private final transient Bleach bleach;
//   private final Collection<Threat> threats = new ArrayList<>();
//   /**
//    * Counts ongoing tasks, to prevent fork bombs when handling zip archives for instance)
//    */
//   private int ongoingTasks = 0;
// 
//   public BleachSession(Bleach bleach) {
//     this.bleach = bleach;
//   }
// 
//   /**
//    * The BleachSession is able to record threats encountered by the bleach.
//    *
//    * @param threat The removed threat object, containing the threat type and more information
//    */
//   public void recordThreat(Threat threat) {
//     if (threat == null) {
//       return;
//     }
//     LOGGER.trace("Threat recorded: " + threat);
//     threats.add(threat);
//   }
// 
//   public Collection<Threat> getThreats() {
//     return threats;
//   }
// 
//   public int threatCount() {
//     return threats.size();
//   }
// 
//   /**
//    * @return The bleach used in this session
//    */
//   public Bleach getBleach() {
//     return bleach;
//   }
// 
//   public void sanitize(InputStream is, OutputStream os) throws BleachException {
//     try {
//       if (ongoingTasks++ >= MAX_ONGOING_TASKS) {
//         throw new RecursionBleachException(ongoingTasks);
//       }
//       if (!bleach.handlesMagic(is)) {
//         return;
//       }
//       bleach.sanitize(is, os, this);
//     } finally {
//       ongoingTasks--;
//     }
//   }
// }
// 
// Path: api/src/main/java/xyz/docbleach/api/bleach/DefaultBleach.java
// public class DefaultBleach extends CompositeBleach {
// 
//   public DefaultBleach() {
//     super(getDefaultBleaches());
//   }
// 
//   /**
//    * Finds all statically loadable bleaches
//    *
//    * @return ordered list of statically loadable bleaches
//    */
//   private static Bleach[] getDefaultBleaches() {
//     ServiceLoader<Bleach> services = ServiceLoader.load(Bleach.class);
// 
//     Collection<Bleach> list = new ArrayList<>();
//     services.forEach(list::add);
// 
//     return list.toArray(new Bleach[0]);
//   }
// }
// 
// Path: api/src/main/java/xyz/docbleach/api/exception/BleachException.java
// public class BleachException extends Exception {
// 
//   public BleachException(Throwable e) {
//     super(e);
//   }
// 
//   public BleachException(String message) {
//     super(message);
//   }
// }


// Path: cli/src/main/java/xyz/docbleach/cli/Main.java
import com.google.gson.Gson;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.MissingOptionException;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.UnrecognizedOptionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.impl.SimpleLogger;
import xyz.docbleach.api.BleachSession;
import xyz.docbleach.api.bleach.DefaultBleach;
import xyz.docbleach.api.exception.BleachException;

  private void sanitize() throws BleachException {
    BleachSession session = new BleachSession(new DefaultBleach());

    session.sanitize(inputStream, outputStream);

    if (jsonOutput) {
      Gson gson = new Gson();
      System.err.println(gson.toJson(session));
    } else {
      if (session.threatCount() == 0) {
        LOGGER.info("The file was already safe, so I've just copied it over.");
      } else {
        LOGGER.warn(
            "Sanitized file has been saved, {} potential threat(s) removed.",
            session.threatCount());
      }
    }
  }

  private void setupLogging() {
    if (verbosityLevel <= 0) {
      // Verbosity is INFO or OFF, we hide the thread and logger names
      System.setProperty(SimpleLogger.SHOW_THREAD_NAME_KEY, "false");
      System.setProperty(SimpleLogger.SHOW_LOG_NAME_KEY, "false");
    }

    String level;
    switch (verbosityLevel) {
      case -1:
        level = "OFF";
        break;