// Path: src/main/java/com/rmn/qa/AutomationContext.java
// public class AutomationContext {
// 
//     private static final Logger log = LoggerFactory.getLogger(AutomationContext.class);
//     private static final int DEFAULT_MAX_THREAD_COUNT = 150;
//     private static AutomationRunContext context = new AutomationRunContext();
// 
//     // Singleton to maintain a context object
// 
//     /**
//      * Returns the singleton {@link com.rmn.qa.AutomationRunContext context} instance
//      * @return
//      */
//     public static AutomationRunContext getContext() {
//         return AutomationContext.context;
//     }
// 
//     /**
//      * Clears out the previous context.  Used for unit testing
//      */
//     public static void refreshContext() {
//         AutomationContext.context = new AutomationRunContext();
//     }
// 
//     static {
//         String totalNodeCount = System.getProperty("totalNodeCount");
//         // Default to 150 if node count was not passed in
//         if(totalNodeCount == null) {
//             getContext().setTotalNodeCount(AutomationContext.DEFAULT_MAX_THREAD_COUNT);
//             log.warn("Defaulting node count to " + AutomationContext.DEFAULT_MAX_THREAD_COUNT);
//         } else {
//             getContext().setTotalNodeCount(Integer.parseInt(totalNodeCount));
//         }
//     }
// 
// }
// 
// Path: src/main/java/com/rmn/qa/AutomationUtils.java
// public final class AutomationUtils {
// 
//     /**
//      * Modifies the specified date
//      * @param dateToModify Date to modify
//      * @param unitsToModify Number of units to modify (e.g. 6 for 6 seconds)
//      * @param unitType Measurement type (e.g. Calendar.SECONDS)
//      * @return Modified date
//      */
//     public static Date modifyDate(Date dateToModify,int unitsToModify,int unitType) {
//         Calendar c = Calendar.getInstance();
//         c.setTime(dateToModify);
//         // Add 60 seconds so we're as close to the hour as we can be instead of adding 55 again
//         c.add(unitType,unitsToModify);
//         return c.getTime();
//     }
// 
//     /**
//      * Returns true if the current time is after the specified date, false otherwise
//      * @param dateToCheck Date to check against the current time
//      * @param unitsToCheckWith Number of units to add/subtract from dateToCheck
//      * @param unitType Unit type (e.g. Calendar.MINUTES)
//      * @return
//      */
//     public static boolean isCurrentTimeAfterDate(Date dateToCheck,int unitsToCheckWith,int unitType) {
//         Date targetDate = AutomationUtils.modifyDate(dateToCheck,unitsToCheckWith,unitType);
//         return new Date().after(targetDate);
//     }
// 
//     /**
//      * Returns true if the strings are lower case equal
//      * @param string1 First string to compare
//      * @param string2 Second string to compare
//      * @return
//      */
//     public static boolean lowerCaseMatch(String string1, String string2) {
//         string2 = string2.toLowerCase().replace(" ","");
//         return string2.equals(string1.toLowerCase().replace(" ", ""));
//     }
// 
// }
// 
// Path: src/main/java/com/rmn/qa/RegistryRetriever.java
// public interface RegistryRetriever {
// 
//     /**
//      * Retrieves a Selenium Registry
//      * @return
//      */
//     Registry retrieveRegistry();
// 
// }
// 
// Path: src/main/java/com/rmn/qa/aws/VmManager.java
// public interface VmManager {
// 
//     /**
//      * Launches the specified instances
//      * @param uuid UUID of the requesting test run
//      * @param os OS of the requesting test run
//      * @param browser Browser of the requesting test run
//      * @param hubHostName Hub host name for the nodes to register with
//      * @param nodeCount Number of nodes to be started
//      * @param maxSessions Number of max sessions per node
//      * @return
//      */
//     // TODO Refactor into AutomationRunRequest
//     List<Instance> launchNodes(String uuid, String os, String browser, String hubHostName, int nodeCount, int maxSessions) throws NodesCouldNotBeStartedException;
// 
//     /**
//      * Terminates the specified instance
//      * @param instanceId
//      */
//     // TODO Rename to be node or instance in the name
//     boolean terminateInstance(String instanceId);
// 
//     /**
//      * Returns a list of reservations as defined in the {@link com.amazonaws.services.ec2.model.DescribeInstancesRequest DescribeInstancesRequest}
//      * @param describeInstancesRequest
//      * @return
//      */
//     List<Reservation> describeInstances(DescribeInstancesRequest describeInstancesRequest);
// }


import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
import com.amazonaws.services.ec2.model.Filter;
import com.amazonaws.services.ec2.model.Instance;
import com.amazonaws.services.ec2.model.Reservation;
import com.google.common.annotations.VisibleForTesting;
import com.rmn.qa.AutomationContext;
import com.rmn.qa.AutomationUtils;
import com.rmn.qa.RegistryRetriever;
import com.rmn.qa.aws.VmManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
package com.rmn.qa.task;



public class AutomationReaperTask extends AbstractAutomationCleanupTask {

    private static final Logger log = LoggerFactory.getLogger(AutomationReaperTask.class);
    @VisibleForTesting static final String NAME = "VM Reaper Task";

    private VmManager ec2;

    /**
     * Constructs a registry task with the specified context retrieval mechanism
     * @param registryRetriever Represents the retrieval mechanism you wish to use
     */
// Path: src/main/java/com/rmn/qa/AutomationContext.java
// public class AutomationContext {
// 
//     private static final Logger log = LoggerFactory.getLogger(AutomationContext.class);
//     private static final int DEFAULT_MAX_THREAD_COUNT = 150;
//     private static AutomationRunContext context = new AutomationRunContext();
// 
//     // Singleton to maintain a context object
// 
//     /**
//      * Returns the singleton {@link com.rmn.qa.AutomationRunContext context} instance
//      * @return
//      */
//     public static AutomationRunContext getContext() {
//         return AutomationContext.context;
//     }
// 
//     /**
//      * Clears out the previous context.  Used for unit testing
//      */
//     public static void refreshContext() {
//         AutomationContext.context = new AutomationRunContext();
//     }
// 
//     static {
//         String totalNodeCount = System.getProperty("totalNodeCount");
//         // Default to 150 if node count was not passed in
//         if(totalNodeCount == null) {
//             getContext().setTotalNodeCount(AutomationContext.DEFAULT_MAX_THREAD_COUNT);
//             log.warn("Defaulting node count to " + AutomationContext.DEFAULT_MAX_THREAD_COUNT);
//         } else {
//             getContext().setTotalNodeCount(Integer.parseInt(totalNodeCount));
//         }
//     }
// 
// }
// 
// Path: src/main/java/com/rmn/qa/AutomationUtils.java
// public final class AutomationUtils {
// 
//     /**
//      * Modifies the specified date
//      * @param dateToModify Date to modify
//      * @param unitsToModify Number of units to modify (e.g. 6 for 6 seconds)
//      * @param unitType Measurement type (e.g. Calendar.SECONDS)
//      * @return Modified date
//      */
//     public static Date modifyDate(Date dateToModify,int unitsToModify,int unitType) {
//         Calendar c = Calendar.getInstance();
//         c.setTime(dateToModify);
//         // Add 60 seconds so we're as close to the hour as we can be instead of adding 55 again
//         c.add(unitType,unitsToModify);
//         return c.getTime();
//     }
// 
//     /**
//      * Returns true if the current time is after the specified date, false otherwise
//      * @param dateToCheck Date to check against the current time
//      * @param unitsToCheckWith Number of units to add/subtract from dateToCheck
//      * @param unitType Unit type (e.g. Calendar.MINUTES)
//      * @return
//      */
//     public static boolean isCurrentTimeAfterDate(Date dateToCheck,int unitsToCheckWith,int unitType) {
//         Date targetDate = AutomationUtils.modifyDate(dateToCheck,unitsToCheckWith,unitType);
//         return new Date().after(targetDate);
//     }
// 
//     /**
//      * Returns true if the strings are lower case equal
//      * @param string1 First string to compare
//      * @param string2 Second string to compare
//      * @return
//      */
//     public static boolean lowerCaseMatch(String string1, String string2) {
//         string2 = string2.toLowerCase().replace(" ","");
//         return string2.equals(string1.toLowerCase().replace(" ", ""));
//     }
// 
// }
// 
// Path: src/main/java/com/rmn/qa/RegistryRetriever.java
// public interface RegistryRetriever {
// 
//     /**
//      * Retrieves a Selenium Registry
//      * @return
//      */
//     Registry retrieveRegistry();
// 
// }
// 
// Path: src/main/java/com/rmn/qa/aws/VmManager.java
// public interface VmManager {
// 
//     /**
//      * Launches the specified instances
//      * @param uuid UUID of the requesting test run
//      * @param os OS of the requesting test run
//      * @param browser Browser of the requesting test run
//      * @param hubHostName Hub host name for the nodes to register with
//      * @param nodeCount Number of nodes to be started
//      * @param maxSessions Number of max sessions per node
//      * @return
//      */
//     // TODO Refactor into AutomationRunRequest
//     List<Instance> launchNodes(String uuid, String os, String browser, String hubHostName, int nodeCount, int maxSessions) throws NodesCouldNotBeStartedException;
// 
//     /**
//      * Terminates the specified instance
//      * @param instanceId
//      */
//     // TODO Rename to be node or instance in the name
//     boolean terminateInstance(String instanceId);
// 
//     /**
//      * Returns a list of reservations as defined in the {@link com.amazonaws.services.ec2.model.DescribeInstancesRequest DescribeInstancesRequest}
//      * @param describeInstancesRequest
//      * @return
//      */
//     List<Reservation> describeInstances(DescribeInstancesRequest describeInstancesRequest);
// }


// Path: src/main/java/com/rmn/qa/task/AutomationReaperTask.java
import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
import com.amazonaws.services.ec2.model.Filter;
import com.amazonaws.services.ec2.model.Instance;
import com.amazonaws.services.ec2.model.Reservation;
import com.google.common.annotations.VisibleForTesting;
import com.rmn.qa.AutomationContext;
import com.rmn.qa.AutomationUtils;
import com.rmn.qa.RegistryRetriever;
import com.rmn.qa.aws.VmManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

package com.rmn.qa.task;



public class AutomationReaperTask extends AbstractAutomationCleanupTask {

    private static final Logger log = LoggerFactory.getLogger(AutomationReaperTask.class);
    @VisibleForTesting static final String NAME = "VM Reaper Task";

    private VmManager ec2;

    /**
     * Constructs a registry task with the specified context retrieval mechanism
     * @param registryRetriever Represents the retrieval mechanism you wish to use
     */
    public AutomationReaperTask(RegistryRetriever registryRetriever,VmManager ec2) {