/**
  * Check the logged out players for if any data can be removed.<br>
  * Currently only "dumb" full removal is performed. Later it is thinkable to remove "as much as
  * reasonable".
  */
 public void checkExpiration() {
   if (durExpireData <= 0) return;
   final long now = System.currentTimeMillis();
   final Set<CheckDataFactory> factories = new LinkedHashSet<CheckDataFactory>();
   final Set<Entry<String, Long>> entries = lastLogout.entrySet();
   final Iterator<Entry<String, Long>> iterator = entries.iterator();
   while (iterator.hasNext()) {
     final Entry<String, Long> entry = iterator.next();
     final long ts = entry.getValue();
     if (now - ts <= durExpireData) break;
     final String playerName = entry.getKey();
     if (deleteData) {
       factories.clear();
       for (final CheckType type : CheckType.values()) {
         final CheckDataFactory factory = type.getDataFactory();
         if (factory != null) factories.add(factory);
       }
       for (final CheckDataFactory factory : factories) {
         factory.removeData(playerName);
       }
       clearComponentData(CheckType.ALL, playerName);
     }
     if (deleteData || deleteHistory) removeExecutionHistory(CheckType.ALL, playerName);
     if (deleteHistory) ViolationHistory.removeHistory(playerName);
     iterator.remove();
   }
 }
 /**
  * Handle the '/nocheatplus info' command.
  *
  * @param sender the sender
  * @param playerName the player name
  * @return true, if successful
  */
 private void handleInfoCommand(final CommandSender sender, final String playerName) {
   final Player player = Bukkit.getPlayer(playerName);
   if (player != null) {
     final DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
     final TreeMap<Long, ViolationLevel> violations =
         ViolationHistory.getHistory(player).getViolationLevels();
     if (violations.size() > 0) {
       sender.sendMessage(TAG + "Displaying " + playerName + "'s violations...");
       for (final long time : violations.descendingKeySet()) {
         final ViolationLevel violationLevel = violations.get(time);
         final String[] parts = violationLevel.check.split("\\.");
         final String check = parts[parts.length - 1];
         final String parent = parts[parts.length - 2];
         final double VL = Math.round(violationLevel.VL);
         sender.sendMessage(
             TAG
                 + "["
                 + dateFormat.format(new Date(time))
                 + "] ("
                 + parent
                 + ".)"
                 + check
                 + " VL "
                 + VL);
       }
     } else
       sender.sendMessage(
           TAG + "Displaying " + playerName + "'s violations... nothing to display.");
   } else {
     sender.sendMessage(TAG + "404 Not Found");
     sender.sendMessage(TAG + "The requested player was not found on this server.");
   }
 }
 /**
  * Remove data and history of all players for the given check type and sub checks.
  *
  * @param checkType
  */
 public static void clearData(final CheckType checkType) {
   final Set<CheckDataFactory> factories = new HashSet<CheckDataFactory>();
   for (final CheckType type : APIUtils.getWithChildren(checkType)) {
     final Map<String, ExecutionHistory> map = instance.executionHistories.get(type);
     if (map != null) map.clear();
     final CheckDataFactory factory = type.getDataFactory();
     if (factory != null) factories.add(factory);
   }
   for (final CheckDataFactory factory : factories) {
     factory.removeAllData();
   }
   for (final IRemoveData rmd : instance.iRemoveData) {
     if (rmd instanceof IHaveCheckType) {
       final CheckType refType = ((IHaveCheckType) rmd).getCheckType();
       if (refType == checkType || APIUtils.isParent(checkType, refType)) rmd.removeAllData();
     }
   }
   ViolationHistory.clear(checkType);
 }