diff --git a/build.gradle b/build.gradle
index 74c34eaf6d5920a65ce0de8bd5fb0c1d29f0d065..4b09cd3fa576ec7a942091539a1175956596d26a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -306,6 +306,7 @@ dependencies {
     compile "org.hibernate:hibernate-core:${vHibernate}"
     compile "org.hibernate:hibernate-ehcache:${vHibernate}"
     compile "org.hibernate:hibernate-validator:4.3.2.Final"
+    compile "org.hibernate:hibernate-envers:4.3.11.Final"
     compile "net.sf.ehcache:ehcache-core:${vEhcache}"
 
     compile "com.noelios.restlet:com.noelios.restlet:1.1.10"
@@ -361,6 +362,7 @@ dependencies {
     compile "log4j:log4j:${vLog4j}"
     compile "javax.servlet:jstl:1.2"
     compile "javax.mail:javax.mail-api:1.5.5"
+    compile 'com.google.code.gson:gson:2.6.2'
 
     runtime "org.apache.activemq:activemq-core:5.7.0"
     runtime "ant:ant:1.6.5"
diff --git a/src/main/java/org/nrg/dcm/id/ScriptedSessionAssignmentExtractor.java b/src/main/java/org/nrg/dcm/id/ScriptedSessionAssignmentExtractor.java
index 47188bf1ee4c5f86ee5ec6788da2e96be416cbae..b5684b3d91d4cd5ebbe43d9b34e1f8a6788584b8 100644
--- a/src/main/java/org/nrg/dcm/id/ScriptedSessionAssignmentExtractor.java
+++ b/src/main/java/org/nrg/dcm/id/ScriptedSessionAssignmentExtractor.java
@@ -3,6 +3,7 @@ package org.nrg.dcm.id;
 import org.apache.commons.lang3.StringUtils;
 import org.dcm4che2.data.DicomObject;
 import org.nrg.automation.entities.Script;
+import org.nrg.automation.entities.ScriptTrigger;
 import org.nrg.automation.services.ScriptRunnerService;
 import org.nrg.dcm.ChainExtractor;
 import org.nrg.dcm.Extractor;
@@ -136,7 +137,8 @@ public class ScriptedSessionAssignmentExtractor extends ChainExtractor implement
 
     private Script getScript(final String projectId) {
         final boolean hasEntity = StringUtils.isNotBlank(projectId);
-        final Script script = _service.getScript(hasEntity ? Scope.Project : Scope.Site, projectId, _event);
+        final Script script = _service.getScript(hasEntity ? Scope.Project : Scope.Site, projectId, ScriptTrigger.DEFAULT_CLASS, _event, ScriptTrigger.DEFAULT_FILTER);
+
         // If we didn't find a script for the indicated scope but we have an entity ID, then fail up to the site level.
         if (script == null && hasEntity) {
             return getScript(null);
diff --git a/src/main/java/org/nrg/xapi/model/event/EventClassInfo.java b/src/main/java/org/nrg/xapi/model/event/EventClassInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..bce9f8ff5ec19b2a80fb661ddbe950804dc9e3b8
--- /dev/null
+++ b/src/main/java/org/nrg/xapi/model/event/EventClassInfo.java
@@ -0,0 +1,143 @@
+package org.nrg.xapi.model.event;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.collect.Lists;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import org.nrg.xft.event.EventClass;
+import org.python.google.common.collect.Maps;
+import org.springframework.core.annotation.AnnotationUtils;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The Class EventClassInfo.
+ */
+@ApiModel(description = "Event class names and filterable fields.")
+public class EventClassInfo {
+	
+	/** The _class name. */
+	String _className;
+	
+	/** The _display name. */
+	String _displayName;
+	
+	/** The _filterable fields. */
+	final Map<String,List<String>> _filterableFields = Maps.newHashMap();
+	
+	/** The _event ids. */
+	final List<String> _eventIds = Lists.newArrayList();
+	
+	/** The _include event ids from database. */
+	boolean _includeEventIdsFromDatabase = true;
+
+	/**
+	 * Instantiates a new event class info.
+	 *
+	 * @param className the class name
+	 */
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	public EventClassInfo(final String className) {
+        this._className = className;
+        try {
+			Class clazz = Class.forName(className);
+			if (clazz.isAnnotationPresent(EventClass.class)) {
+				
+				Annotation anno = AnnotationUtils.findAnnotation(clazz, EventClass.class);
+				Object annoDisplayNameObj = AnnotationUtils.getValue(anno, "displayName");
+				_displayName = (annoDisplayNameObj != null && annoDisplayNameObj instanceof String) ? annoDisplayNameObj.toString() : _className;
+				
+				Object annoEventIdsObj = AnnotationUtils.getValue(anno, "defaultEventIds");
+				String[] annoEventIds = (annoEventIdsObj != null && annoEventIdsObj instanceof String[]) ? (String[])annoEventIdsObj : new String[] {};
+				_eventIds.addAll(Arrays.asList(annoEventIds));
+				
+				Object annoIncludeValuesFromDatabase = AnnotationUtils.getValue(anno, "includeValuesFromDatabase");
+				if (annoIncludeValuesFromDatabase != null && annoIncludeValuesFromDatabase instanceof Boolean) {
+					_includeEventIdsFromDatabase = (boolean)annoIncludeValuesFromDatabase;
+				}
+				
+			} else {
+				_displayName = _className;
+			}
+		} catch (ClassNotFoundException e) {
+			_displayName = _className;
+		}
+    }
+
+    /**
+     * Gets the class name.
+     *
+     * @return the class name
+     */
+    @ApiModelProperty(value = "Event class name (Should implement AutomationEventImplementerI")
+    @JsonProperty("class")
+    public String getClassName() {
+        return _className;
+    }
+    
+    /**
+     * Gets the display name.
+     *
+     * @return the display name
+     */
+    @ApiModelProperty(value = "Display Name")
+    @JsonProperty("displayName")
+    public String getDisplayName() {
+        return _displayName;
+    }
+
+    /**
+     * Sets the class name.
+     *
+     * @param className the new class name
+     */
+    public void setClassName(String className) {
+        _className = className;
+    }
+
+    /**
+     * Gets the filterable fields map.
+     *
+     * @return the filterable fields map
+     */
+    @ApiModelProperty(value = "Map of Filterable fields.")
+    @JsonProperty("filterableFields")
+    public Map<String,List<String>> getFilterableFieldsMap() {
+        return _filterableFields;
+    }
+    
+    /**
+     * Gets the event ids.
+     *
+     * @return the event ids
+     */
+    @ApiModelProperty(value = "List of event IDs.")
+    @JsonProperty("eventIds")
+    public List<String> getEventIds() {
+        return _eventIds;
+    }
+	
+    /**
+     * Gets the include event ids from database.
+     *
+     * @return the include event ids from database
+     */
+    public boolean getIncludeEventIdsFromDatabase() {
+		return _includeEventIdsFromDatabase;
+	}
+
+	/**
+	 * Sets the include event ids from database.
+	 *
+	 * @param _includeEventIdsFromDatabase the new include event ids from database
+	 */
+	public void setIncludeEventIdsFromDatabase(boolean _includeEventIdsFromDatabase) {
+		this._includeEventIdsFromDatabase = _includeEventIdsFromDatabase;
+	}
+    
+}
diff --git a/src/main/java/org/nrg/xapi/rest/event/EventHandlerApi.java b/src/main/java/org/nrg/xapi/rest/event/EventHandlerApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..fc39acce70e9b0f93aac6a4c80e9c02d6e039712
--- /dev/null
+++ b/src/main/java/org/nrg/xapi/rest/event/EventHandlerApi.java
@@ -0,0 +1,296 @@
+package org.nrg.xapi.rest.event;
+
+import io.swagger.annotations.*;
+import javassist.Modifier;
+
+import org.nrg.framework.utilities.Reflection;
+import org.nrg.xapi.model.event.EventClassInfo;
+import org.nrg.xdat.XDAT;
+import org.nrg.xdat.om.XnatProjectdata;
+import org.nrg.xdat.om.base.auto.AutoXnatProjectdata;
+import org.nrg.xdat.security.XDATUser;
+import org.nrg.xdat.security.helpers.Roles;
+import org.nrg.xdat.services.impl.hibernate.HibernateAutomationEventIdsService;
+import org.nrg.xdat.services.impl.hibernate.HibernateAutomationFiltersService;
+import org.nrg.xft.event.AutomationEventImplementerI;
+import org.nrg.xft.event.Filterable;
+import org.nrg.xft.event.entities.AutomationEventIds;
+import org.nrg.xft.event.entities.AutomationFilters;
+import org.nrg.xft.security.UserI;
+import org.nrg.xnat.event.conf.EventPackages;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.bind.annotation.*;
+
+import com.google.common.collect.Lists;
+
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * The Class EventHandlerApi.
+ */
+@Api(description = "The XNAT Event Handler API")
+@RestController
+public class EventHandlerApi {
+    
+    /** The Constant _log. */
+    private static final Logger _log = LoggerFactory.getLogger(EventHandlerApi.class);
+	
+	/** The event ids service. */
+	private HibernateAutomationEventIdsService eventIdsService;
+	
+	/** The filters service. */
+	private HibernateAutomationFiltersService filtersService;
+    
+    /** The event packages. */
+    private static EventPackages eventPackages;
+    
+    /**
+     * Inits the this.
+     */
+    @PostConstruct
+    private void initThis() {
+    	getEventIdsService();
+    	getFiltersService();
+    	getEventPackages();
+    }
+	
+    /**
+     * Automation event classes get.
+     *
+     * @param project_id the project_id
+     * @return the response entity
+     */
+    @ApiOperation(value = "Get list of event classes.", notes = "Returns a list of classes implementing AutomationEventI.", response = List.class)
+    @ApiResponses({@ApiResponse(code = 200, message = "An array of class names"), @ApiResponse(code = 500, message = "Unexpected error")})
+    @RequestMapping(value = {"/projects/{project_id}/eventHandlers/automationEventClasses"}, produces = {"application/json"}, method = RequestMethod.GET)
+    @ResponseBody
+    public ResponseEntity<List<EventClassInfo>> automationEventClassesGet(@PathVariable("project_id") String project_id) {
+        final HttpStatus status = isPermitted(project_id);
+    	if (status != null) {
+    		return new ResponseEntity<>(status);
+    	}
+        return new ResponseEntity<List<EventClassInfo>>(getEventInfoList(project_id), HttpStatus.OK);
+    }
+	
+    /**
+     * Automation event classes get.
+     *
+     * @return the response entity
+     */
+    @ApiOperation(value = "Get list of event classes.", notes = "Returns a list of classes implementing AutomationEventI.", response = List.class)
+    @ApiResponses({@ApiResponse(code = 200, message = "An array of class names"), @ApiResponse(code = 500, message = "Unexpected error")})
+    @RequestMapping(value = {"/eventHandlers/automationEventClasses"}, produces = {"application/json"}, method = RequestMethod.GET)
+    @ResponseBody
+    public ResponseEntity<List<EventClassInfo>> automationEventClassesGet() {
+        final HttpStatus status = isPermitted(null);
+    	if (status != null) {
+    		return new ResponseEntity<>(status);
+    	}
+        return new ResponseEntity<List<EventClassInfo>>(getEventInfoList(null), HttpStatus.OK);
+    }
+
+	/**
+	 * Gets the event info list.
+	 *
+	 * @param project_id the project_id
+	 * @return the event info list
+	 */
+	private List<EventClassInfo> getEventInfoList(String project_id) {
+		final List<EventClassInfo> eventInfoList = Lists.newArrayList();
+		final List<AutomationEventIds> eventIdsList = getEventIdsService().getEventIds(project_id, false);
+		final List<AutomationFilters> filtersList = getFiltersService().getAutomationFilters(project_id, false);
+		for (final String className : getEventClassList(eventIdsList)) {
+			final EventClassInfo eci = new EventClassInfo(className);
+			final List<String> eventIds = eci.getEventIds();
+			final Map<String, List<String>> filterableFields = eci.getFilterableFieldsMap();
+			if (eci.getIncludeEventIdsFromDatabase()) {
+				for (final AutomationEventIds autoIds : eventIdsList) {
+					if (autoIds.getSrcEventClass().equals(className)) {
+						for (String eId : autoIds.getEventIds()) {
+							if (!eventIds.contains(eId)) {
+								eventIds.add(eId);
+							}
+						}
+					}
+				}
+			}
+			Collections.sort(eventIds);
+			try {
+				for (final Method method : Arrays.asList(Class.forName(className).getMethods())) {
+					if (method.isAnnotationPresent(Filterable.class) && method.getName().substring(0,3).equalsIgnoreCase("get")) {
+						final char c[] = method.getName().substring(3).toCharArray();
+						c[0] = Character.toLowerCase(c[0]);
+						final String column = new String(c);
+						final Annotation anno = AnnotationUtils.findAnnotation(method, Filterable.class);
+						
+						final Object annoInitialValuesObj = AnnotationUtils.getValue(anno, "initialValues");
+						final String[] annoInitialValues = (annoInitialValuesObj != null && annoInitialValuesObj instanceof String[]) ? (String[])annoInitialValuesObj : new String[] {};
+						
+						final Object annoIncludeValuesFromDatabase = AnnotationUtils.getValue(anno, "includeValuesFromDatabase");
+						boolean includeValuesFromDatabase = (annoIncludeValuesFromDatabase != null && annoIncludeValuesFromDatabase instanceof Boolean) ?
+							(boolean)annoIncludeValuesFromDatabase : true;
+						if (!filterableFields.containsKey(column)) {
+							final List<String> newValueList = Lists.newArrayList();
+							filterableFields.put(column,newValueList);
+						}
+						final List<String> valueList = filterableFields.get(column);
+						valueList.addAll(Arrays.asList(annoInitialValues));
+						if (includeValuesFromDatabase) {
+							for (final AutomationFilters autoFilters : filtersList) {
+								if (autoFilters.getField().equals(column)) {
+									valueList.addAll(autoFilters.getValues());
+									break;
+								}
+							}
+						}
+						Collections.sort(valueList);
+					}
+				}
+			} catch (SecurityException | ClassNotFoundException e) {
+				for (final AutomationFilters autoFilters : filtersList) {
+					if (!filterableFields.containsKey(autoFilters.getField())) {
+						final List<String> valueList = Lists.newArrayList(autoFilters.getValues());
+						Collections.sort(valueList);
+						filterableFields.put(autoFilters.getField(), valueList);
+					} else {
+						for (String value : autoFilters.getValues()) {
+							final List<String> values = filterableFields.get(autoFilters.getField());
+							if (!values.contains(value)) {
+								values.add(value);
+							}
+							Collections.sort(values);
+						}
+					}
+				}
+			}
+			eventInfoList.add(eci);
+		}
+		return eventInfoList;
+	}
+
+	/**
+	 * Gets the event class list.
+	 *
+	 * @param eventIdsList the event ids list
+	 * @return the event class list
+	 */
+	private List<String> getEventClassList(List<AutomationEventIds> eventIdsList) {
+		final List<String> classList = Lists.newArrayList();
+		// ClassList should be pulled from available event classes rather than from events
+		final EventPackages eventPackages = getEventPackages();
+		if (eventPackages != null) {
+			for (final String pkg : eventPackages) {
+				try {
+					for (final Class<?> clazz : Reflection.getClassesForPackage(pkg)) {
+						if (AutomationEventImplementerI.class.isAssignableFrom(clazz) && !clazz.isInterface() && 
+								!Modifier.isAbstract(clazz.getModifiers())) {
+							if (!classList.contains(clazz.getName())) {
+								classList.add(clazz.getName());
+							}
+						}
+					}
+				} catch (ClassNotFoundException | IOException e) {
+					// Do nothing.  
+				}
+			}
+		}
+		// I think for now we'll not pull from the database if we've found event classes.  If the database
+		// contains any thing different, it should only be event classes that are no longer available.
+		if (classList.size()<1) {
+			for (final AutomationEventIds auto : eventIdsList) {
+				if (!classList.contains(auto.getSrcEventClass())) {
+					classList.add(auto.getSrcEventClass());
+				}
+			}
+		}
+        return classList;
+	}
+			
+	/**
+	 * Gets the event ids service.
+	 *
+	 * @return the event ids service
+	 */
+	private HibernateAutomationEventIdsService getEventIdsService() {
+		if (eventIdsService == null) {
+			eventIdsService = XDAT.getContextService().getBean(HibernateAutomationEventIdsService.class);
+		}
+		return eventIdsService;
+	}
+			
+	/**
+	 * Gets the filters service.
+	 *
+	 * @return the filters service
+	 */
+	private HibernateAutomationFiltersService getFiltersService() {
+		if (filtersService == null) {
+			filtersService = XDAT.getContextService().getBean(HibernateAutomationFiltersService.class);
+		}
+		return filtersService;
+	}
+    
+    /**
+     * Gets the event packages.
+     *
+     * @return the event packages
+     */
+    private static EventPackages getEventPackages() {
+		if (eventPackages == null) {
+			eventPackages = XDAT.getContextService().getBean("eventPackages",EventPackages.class);
+		}
+		return eventPackages;
+    }
+	
+    /**
+     * Gets the session user.
+     *
+     * @return the session user
+     */
+    private UserI getSessionUser() {
+        final Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+        if ((principal instanceof UserI)) {
+            return (UserI) principal;
+        }
+        return null;
+    }
+	
+    /**
+     * Checks if is permitted.
+     *
+     * @param project_id the project_id
+     * @return the http status
+     */
+    private HttpStatus isPermitted(String project_id) {
+        final UserI sessionUser = getSessionUser();
+        if ((sessionUser instanceof XDATUser)) {
+        	if (project_id != null) {
+        		final XnatProjectdata proj = AutoXnatProjectdata.getXnatProjectdatasById(project_id, sessionUser, false);
+        		try {
+        			return (proj.canEdit(sessionUser)) ? null : HttpStatus.FORBIDDEN;
+        		} catch (Exception e) {
+        			_log.error("Error checking read status for project",e);
+        			return HttpStatus.INTERNAL_SERVER_ERROR;
+        		}
+        	} else {
+        		return (Roles.isSiteAdmin(sessionUser)) ? null : HttpStatus.FORBIDDEN;
+        	}
+        }
+		_log.error("Error checking read status for project");
+		return HttpStatus.INTERNAL_SERVER_ERROR;
+    }
+	
+}
diff --git a/src/main/java/org/nrg/xnat/event/conf/EventPackages.java b/src/main/java/org/nrg/xnat/event/conf/EventPackages.java
new file mode 100644
index 0000000000000000000000000000000000000000..966d57c5d379c701de5ac898316a1e745a4bd59f
--- /dev/null
+++ b/src/main/java/org/nrg/xnat/event/conf/EventPackages.java
@@ -0,0 +1,33 @@
+package org.nrg.xnat.event.conf;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * The Class EventPackages.
+ */
+public class EventPackages extends HashSet<String> {
+    
+	/** The Constant serialVersionUID. */
+	private static final long serialVersionUID = 9166262514950558701L;
+
+	/**
+     * Instantiates a new event packages.
+     *
+     * @param packages the packages
+     */
+    public EventPackages(Set<String> packages) {
+    	super();
+        this.setPackages(packages);
+    }
+    
+    /**
+     * Sets the packages.
+     *
+     * @param packages the new packages
+     */
+    public void setPackages(Set<String> packages) {
+        clear();
+        addAll(packages);
+    }
+}
diff --git a/src/main/java/org/nrg/xnat/event/entities/ScriptLaunchRequestEvent.java b/src/main/java/org/nrg/xnat/event/entities/ScriptLaunchRequestEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..ecaae576417958a5692776c9d3059e3dc8efea1a
--- /dev/null
+++ b/src/main/java/org/nrg/xnat/event/entities/ScriptLaunchRequestEvent.java
@@ -0,0 +1,71 @@
+package org.nrg.xnat.event.entities;
+
+import java.util.Map;
+
+import javax.persistence.Entity;
+import javax.persistence.PrimaryKeyJoinColumn;
+import javax.persistence.Transient;
+
+import org.nrg.xft.event.AutomationEventImplementerI;
+import org.nrg.xft.event.EventClass;
+import org.nrg.xft.event.entities.AutomationCompletionEvent;
+import org.nrg.xft.event.entities.PersistentEvent;
+import org.nrg.xft.event.persist.PersistentEventImplementerI;
+
+/**
+ * The Class AutomationLaunchRequestEvent.
+ */
+@Entity
+@PrimaryKeyJoinColumn(name="ID", referencedColumnName="ID")
+@EventClass(displayName="Script Launch Request Event")
+public class ScriptLaunchRequestEvent extends PersistentEvent implements PersistentEventImplementerI, AutomationEventImplementerI {
+	
+	/** The Constant serialVersionUID. */
+	private static final long serialVersionUID = 7465778737330635218L;
+	
+	/** The automation completion event. */
+	private AutomationCompletionEvent automationCompletionEvent;
+	
+	private Map<String,Object> parameterMap;
+	
+	/**
+	 * Instantiates a new automation launch request event.
+	 */
+	public ScriptLaunchRequestEvent() {
+		super();
+	}
+
+	/* (non-Javadoc)
+	 * @see org.nrg.xft.event.AutomationEventImplementerI#getAutomationCompletionEvent()
+	 */
+	@Override
+	@Transient
+	public AutomationCompletionEvent getAutomationCompletionEvent() {
+		return automationCompletionEvent;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.nrg.xft.event.AutomationEventImplementerI#setAutomationCompletionEvent(org.nrg.xft.event.entities.AutomationCompletionEvent)
+	 */
+	@Override
+	public void setAutomationCompletionEvent(AutomationCompletionEvent automationCompletionEvent) {
+		this.automationCompletionEvent = automationCompletionEvent;
+	}
+
+	@Override
+	@Transient
+	public Map<String, Object> getParameterMap() {
+		return this.parameterMap;
+	}
+
+	@Override
+	public void setParameterMap(Map<String, Object> parameterMap) {
+		this.parameterMap = parameterMap;
+	}
+
+	@Override
+	public void addParameterToParameterMap(String parameter, Object value) {
+		this.parameterMap.put(parameter, value);
+	}
+
+}
diff --git a/src/main/java/org/nrg/xnat/event/entities/WorkflowStatusEvent.java b/src/main/java/org/nrg/xnat/event/entities/WorkflowStatusEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..8a56381ebdde492b84393ba62fc46b9a144536ee
--- /dev/null
+++ b/src/main/java/org/nrg/xnat/event/entities/WorkflowStatusEvent.java
@@ -0,0 +1,151 @@
+package org.nrg.xnat.event.entities;
+
+import java.util.Map;
+
+import org.nrg.xdat.om.WrkWorkflowdata;
+import org.nrg.xft.event.AutomationEventImplementerI;
+import org.nrg.xft.event.Filterable;
+import org.nrg.xft.event.StructuredEvent;
+import org.nrg.xft.event.EventClass;
+import org.nrg.xft.event.entities.AutomationCompletionEvent;
+import org.nrg.xft.event.persist.PersistentWorkflowI;
+import org.nrg.xft.security.UserI;
+import org.python.google.common.collect.Maps;
+
+/**
+ * The Class WorkflowStatusEvent.
+ */
+@EventClass(displayName = "Workflow Status Event")
+public class WorkflowStatusEvent extends StructuredEvent implements AutomationEventImplementerI {
+	
+	/** The Constant serialVersionUID. */
+	private static final long serialVersionUID = 7465778737330635218L;
+	
+	/** The workflow. */
+	PersistentWorkflowI workflow;
+	
+	/** The status. */
+	private String status;
+	
+	/** The justification. */
+	private String justification;
+
+	/** The automationCompletionEvent. */
+	private AutomationCompletionEvent automationCompletionEvent;
+
+	private Map<String,Object> parameterMap = Maps.newHashMap();
+	
+	/**
+	 * Instantiates a new workflow status event.
+	 */
+	public WorkflowStatusEvent() {
+		super();
+	}
+	
+	/**
+	 * Instantiates a new workflow status event.  u
+	 *
+	 * @param workflow the workflow
+	 */
+	public WorkflowStatusEvent(PersistentWorkflowI workflow) {
+		this();
+		this.workflow = workflow;
+		this.setEventId(workflow.getPipelineName());
+		this.setSrcEventClass(this.getClass().getName());
+		final String project = workflow.getExternalid();
+		this.setExternalId(project);
+		this.setEntityId(workflow.getId());
+		this.setEntityType(workflow.getDataType());
+		this.setStatus(workflow.getStatus());
+		this.setJustification(workflow.getJustification());
+		final Map<String,String> eventSpecificMap = Maps.newHashMap();
+		eventSpecificMap.put("status", status);
+		eventSpecificMap.put("justification", justification);
+		this.setEventSpecificFieldsAsMap(eventSpecificMap);
+		final WrkWorkflowdata wrkflow = (workflow instanceof WrkWorkflowdata) ? (WrkWorkflowdata)workflow : null;
+		if (wrkflow!=null) {
+			UserI user = (wrkflow.getUser()!=null) ? wrkflow.getUser() : wrkflow.getInsertUser();
+			this.setUserId(user.getID());
+		}
+	}
+	
+	/**
+	 * Gets the workflow.
+	 *
+	 * @return the workflow
+	 */
+	//@Transient
+	public PersistentWorkflowI getWorkflow() {
+		return workflow;
+	}
+	
+	/**
+	 * Sets the status.
+	 *
+	 * @param status the new status
+	 */
+	public void setStatus(String status) {
+		this.status = status;
+	}
+	
+	/**
+	 * Gets the status.
+	 *
+	 * @return the status
+	 */
+	@Filterable(initialValues = { "Complete", "Failed" }, includeValuesFromDatabase = false)
+	public String getStatus() {
+		return status;
+	}
+	
+	/**
+	 * Sets the justification.
+	 *
+	 * @param justification the new justification
+	 */
+	public void setJustification(String justification) {
+		this.justification = justification;
+	}
+	
+	/**
+	 * Gets the justification.
+	 *
+	 * @return the justification
+	 */
+	public String getJustification() {
+		return justification;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.nrg.xft.event.AutomationEventImplementerI#setAutomationCompletionEvent(org.nrg.xft.event.entities.AutomationCompletionEvent)
+	 */
+	@Override
+	public void setAutomationCompletionEvent(AutomationCompletionEvent automationCompletionEvent) {
+		this.automationCompletionEvent = automationCompletionEvent; 
+	}
+
+	/* (non-Javadoc)
+	 * @see org.nrg.xft.event.AutomationEventImplementerI#getAutomationCompletionEvent()
+	 */
+	@Override
+	//@Transient
+	public AutomationCompletionEvent getAutomationCompletionEvent() {
+		return automationCompletionEvent;
+	}
+
+	@Override
+	public Map<String, Object> getParameterMap() {
+		return this.parameterMap;
+	}
+
+	@Override
+	public void setParameterMap(Map<String, Object> parameterMap) {
+		this.parameterMap = parameterMap;
+	}
+
+	@Override
+	public void addParameterToParameterMap(String parameter, Object value) {
+		this.parameterMap.put(parameter, value);
+	}
+
+}
diff --git a/src/main/java/org/nrg/xnat/event/listeners/AutoRunEmailHandler.java b/src/main/java/org/nrg/xnat/event/listeners/AutoRunEmailHandler.java
index 91e823ce8ae242bcf12b57908861d65475399af6..ca4c48b92e8a6b192e2f2328e1576204dbd5f287 100644
--- a/src/main/java/org/nrg/xnat/event/listeners/AutoRunEmailHandler.java
+++ b/src/main/java/org/nrg/xnat/event/listeners/AutoRunEmailHandler.java
@@ -7,8 +7,8 @@ import reactor.bus.EventBus;
 import reactor.fn.Consumer;
 
 import org.nrg.xdat.om.WrkWorkflowdata;
-import org.nrg.xft.event.WorkflowStatusEvent;
 import org.nrg.xft.event.persist.PersistentWorkflowUtils;
+import org.nrg.xnat.event.entities.WorkflowStatusEvent;
 import org.springframework.stereotype.Service;
 
 import static reactor.bus.selector.Selectors.R;
diff --git a/src/main/java/org/nrg/xnat/event/listeners/AutomatedScriptHandler.java b/src/main/java/org/nrg/xnat/event/listeners/AutomatedScriptHandler.java
deleted file mode 100755
index 3102d310ef22beeafedc15bad95453788600ab02..0000000000000000000000000000000000000000
--- a/src/main/java/org/nrg/xnat/event/listeners/AutomatedScriptHandler.java
+++ /dev/null
@@ -1,137 +0,0 @@
-package org.nrg.xnat.event.listeners;
-
-import com.google.common.collect.Lists;
-
-import reactor.bus.Event;
-import reactor.bus.EventBus;
-import reactor.fn.Consumer;
-
-import org.apache.commons.lang3.StringUtils;
-import org.nrg.automation.entities.Script;
-import org.nrg.automation.services.ScriptRunnerService;
-import org.nrg.framework.constants.Scope;
-import org.nrg.xdat.XDAT;
-import org.nrg.xdat.om.WrkWorkflowdata;
-import org.nrg.xft.ItemI;
-import org.nrg.xft.XFTItem;
-import org.nrg.xft.collections.ItemCollection;
-import org.nrg.xft.event.EventUtils;
-import org.nrg.xft.event.WorkflowStatusEvent;
-import org.nrg.xft.event.persist.PersistentWorkflowI;
-import org.nrg.xft.event.persist.PersistentWorkflowUtils;
-import org.nrg.xft.exception.ElementNotFoundException;
-import org.nrg.xft.exception.FieldNotFoundException;
-import org.nrg.xft.exception.XFTInitException;
-import org.nrg.xft.security.UserI;
-import org.nrg.xnat.utils.WorkflowUtils;
-import org.nrg.xnat.services.messaging.automation.AutomatedScriptRequest;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Service;
-
-import static reactor.bus.selector.Selectors.$;
-
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Set;
-
-import javax.inject.Inject;
-
-/**
- * The Class AutomatedScriptHandler.
- */
-@Service
-@SuppressWarnings("unused")
-public class AutomatedScriptHandler extends WorkflowStatusEventHandlerAbst implements Consumer<Event<WorkflowStatusEvent>> {
-    
-    /** The Constant logger. */
-    private static final Logger logger = LoggerFactory.getLogger(AutomatedScriptHandler.class);
-	@Inject ScriptRunnerService _service;
-	
-	/**
-	 * Instantiates a new automated script handler.
-	 *
-	 * @param eventBus the event bus
-	 */
-	@Inject public AutomatedScriptHandler( EventBus eventBus ){
-	//public AutomatedScriptHandler( EventBus eventBus ){
-		eventBus.on($(WorkflowStatusEvent.class.getName() + "." + PersistentWorkflowUtils.COMPLETE), this);
-	}
-	
-	/* (non-Javadoc)
-	 * @see reactor.fn.Consumer#accept(java.lang.Object)
-	 */
-	@Override
-	public void accept(Event<WorkflowStatusEvent> event) {
-		
-		final WorkflowStatusEvent wfsEvent = event.getData();
-		if (wfsEvent.getWorkflow() instanceof WrkWorkflowdata) {
-			handleEvent(wfsEvent);
-		}
-		
-	}
-
-    /* (non-Javadoc)
-     * @see org.nrg.xnat.event.listeners.WorkflowStatusEventHandlerAbst#handleEvent(org.nrg.xft.event.WorkflowStatusEvent)
-     */
-    @Override
-    public void handleEvent(WorkflowStatusEvent wfsEvent) {
-    	PersistentWorkflowI wrk = wfsEvent.getWorkflow();
-    	if (!(wrk instanceof WrkWorkflowdata)) {
-    		return;
-    	}
-        final WrkWorkflowdata wrkflow = (WrkWorkflowdata)wrk;
-        final UserI user = (wrkflow.getUser()!=null) ? wrkflow.getUser() : wrkflow.getInsertUser();
-        final String pipelineName = wrkflow.getPipelineName().replaceAll("\\*OPEN\\*", "(").replaceAll("\\*CLOSE\\*", ")");
-				
-        if (StringUtils.equals(PersistentWorkflowUtils.COMPLETE, wrkflow.getStatus()) && !StringUtils.equals(wrkflow.getExternalid(), PersistentWorkflowUtils.ADMIN_EXTERNAL_ID)) {
-            //check to see if this has been handled before
-            for (Script script : getScripts(wrkflow.getExternalid(), pipelineName)) {
-                try {
-                    final String action = "Executed script " + script.getScriptId();
-                    final String justification = wrkflow.getJustification();
-                    final String comment = "Executed script " + script.getScriptId() + " triggered by event " + pipelineName;
-                    PersistentWorkflowI scriptWrk = PersistentWorkflowUtils.buildOpenWorkflow(user, wrkflow.getDataType(), wrkflow.getId(), wrkflow.getExternalid(), EventUtils.newEventInstance(EventUtils.CATEGORY.DATA, EventUtils.TYPE.PROCESS, action, StringUtils.isNotBlank(justification) ? justification : "Automated execution: " + comment, comment));
-                    assert scriptWrk != null;
-                    scriptWrk.setStatus(PersistentWorkflowUtils.QUEUED);
-                    WorkflowUtils.save(scriptWrk, scriptWrk.buildEvent());
-                    AutomatedScriptRequest request = new AutomatedScriptRequest(wrkflow.getWrkWorkflowdataId().toString(), user, script.getScriptId(), pipelineName, scriptWrk.getWorkflowId().toString(), wrk.getDataType(), wrk.getId(), wrk.getExternalid());
-                    XDAT.sendJmsRequest(request);
-                } catch (Exception e1) {
-                    logger.error("", e1);
-                }
-            }
-        }
-    }
-
-    /**
-     * Gets the scripts.
-     *
-     * @param projectId the project id
-     * @param event the event
-     * @return the scripts
-     */
-    private List<Script> getScripts(final String projectId, String event) {
-
-        final List<Script> scripts = Lists.newArrayList();
-
-        //project level scripts
-        if (StringUtils.isNotBlank(projectId)) {
-            Script script = _service.getScript(Scope.Project, projectId, event);
-            if (script != null) {
-                scripts.add(script);
-            }
-        }
-
-        //site level scripts
-        Script script = _service.getScript(Scope.Site, null, event);
-        if (script != null) {
-            scripts.add(script);
-        }
-
-        return scripts;
-    }
-
-}
diff --git a/src/main/java/org/nrg/xnat/event/listeners/AutomationCompletionEventListener.java b/src/main/java/org/nrg/xnat/event/listeners/AutomationCompletionEventListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..0741edfda1b01193948b2126e25d5be71cfb4be3
--- /dev/null
+++ b/src/main/java/org/nrg/xnat/event/listeners/AutomationCompletionEventListener.java
@@ -0,0 +1,105 @@
+package org.nrg.xnat.event.listeners;
+
+import com.google.common.collect.Lists;
+import reactor.bus.Event;
+import reactor.bus.EventBus;
+import reactor.fn.Consumer;
+import org.nrg.xdat.XDAT;
+import org.nrg.xft.event.entities.AutomationCompletionEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+import static reactor.bus.selector.Selectors.type;
+import java.util.Iterator;
+import java.util.List;
+import javax.inject.Inject;
+
+/**
+ * The Class AutomatedScriptHandler.
+ */
+@Service
+public class AutomationCompletionEventListener implements Consumer<Event<AutomationCompletionEvent>> {
+	
+    /** The Constant logger. */
+    private static final Logger logger = LoggerFactory.getLogger(AutomationCompletionEventListener.class);
+    /** The current instance */
+	private static AutomationCompletionEventListener _instance;
+	/** cache of completed events */
+	private List<AutomationCompletionEvent> completedCache = Lists.newArrayList(); 
+	/** HOW LONG WILL WE LET OBJECTS STAY IN CACHE? */
+	int CACHE_TIME_MILLIS = 60000;
+	
+	/**
+	 * Instantiates a new automation completion event listener.
+	 *
+	 * @throws Exception the exception
+	 */
+	public AutomationCompletionEventListener() throws Exception {
+		if (_instance != null) {
+			throw new Exception("The AutomationCompletionEventListener service is already initialized.  Try calling getService() instead.");
+		}
+		_instance = this;
+	}
+    
+	/**
+	 * Instantiates a new automated script handler.
+	 *
+	 * @param eventBus the event bus
+	 * @throws Exception 
+	 */
+	@Inject public AutomationCompletionEventListener( EventBus eventBus ) throws Exception{
+		this();
+		eventBus.on(type(AutomationCompletionEvent.class), this);
+	}
+	
+	public static AutomationCompletionEventListener getService() {
+	    if (_instance == null) {
+	    	_instance = XDAT.getContextService().getBean(AutomationCompletionEventListener.class);
+	    }
+	    return _instance;
+	}
+	
+	@Override
+	public void accept(Event<AutomationCompletionEvent> event) {
+		cleanUpCache();
+		if (logger.isDebugEnabled()) {
+			logger.debug("Receved event " + event.getId() + " - CURRENT TIME: " + System.currentTimeMillis());
+		}
+		if (event.getData().getEventCompletionTime()==null) {
+			if (logger.isDebugEnabled()) {
+				logger.debug("WARNING:  AutomationCompletionEvent - eventCompletionTime is null");
+			}		
+		}
+		completedCache.add(event.getData());
+	}
+	
+	private synchronized void cleanUpCache() {
+		final Iterator<AutomationCompletionEvent> i = completedCache.iterator();
+		final long currentTime = System.currentTimeMillis();
+		while (i.hasNext()) {
+			final AutomationCompletionEvent thisEvent = i.next();
+			if (thisEvent.getEventCompletionTime()==null || ((currentTime-thisEvent.getEventCompletionTime())>CACHE_TIME_MILLIS)) {
+				if (logger.isDebugEnabled()) {
+					logger.debug("cleanUpCache - removed item " + thisEvent.getId() + " - CURRENT TIME: " + currentTime);
+				}
+				i.remove();
+			}
+		}
+	}
+
+	public synchronized AutomationCompletionEvent getEvent(String id) {
+		final Iterator<AutomationCompletionEvent> i = completedCache.iterator();
+		while (i.hasNext()) {
+			final AutomationCompletionEvent thisEvent = i.next();
+			if (thisEvent.getId().equals(id)) {
+				i.remove();
+				return thisEvent;
+			}	
+		}
+		if (logger.isDebugEnabled()) {
+			logger.debug("getEvent - item not found " + id);
+		}
+		return null;
+	}
+
+}
diff --git a/src/main/java/org/nrg/xnat/event/listeners/AutomationEventScriptHandler.java b/src/main/java/org/nrg/xnat/event/listeners/AutomationEventScriptHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..2833b91059f5c495aa45489bb663b0a6a07c3d94
--- /dev/null
+++ b/src/main/java/org/nrg/xnat/event/listeners/AutomationEventScriptHandler.java
@@ -0,0 +1,420 @@
+package org.nrg.xnat.event.listeners;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import reactor.bus.Event;
+import reactor.bus.EventBus;
+import reactor.fn.Consumer;
+import org.apache.commons.lang3.StringUtils;
+import org.nrg.automation.entities.EventFilters;
+import org.nrg.automation.entities.Script;
+import org.nrg.automation.entities.ScriptOutput;
+import org.nrg.automation.entities.ScriptOutput.Status;
+import org.nrg.automation.entities.ScriptTrigger;
+import org.nrg.automation.services.ScriptRunnerService;
+import org.nrg.automation.services.ScriptTriggerService;
+import org.nrg.automation.services.impl.hibernate.HibernateScriptTriggerService;
+import org.nrg.framework.constants.Scope;
+import org.nrg.framework.exceptions.NrgServiceException;
+import org.nrg.xdat.XDAT;
+import org.nrg.xdat.security.helpers.Users;
+import org.nrg.xdat.security.user.exceptions.UserInitException;
+import org.nrg.xdat.security.user.exceptions.UserNotFoundException;
+import org.nrg.xdat.services.impl.hibernate.HibernateAutomationEventIdsService;
+import org.nrg.xdat.services.impl.hibernate.HibernateAutomationFiltersService;
+import org.nrg.xdat.services.impl.hibernate.HibernatePersistentEventService;
+import org.nrg.xdat.turbine.utils.AdminUtils;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.nrg.xft.event.AutomationEventImplementerI;
+import org.nrg.xft.event.EventUtils;
+import org.nrg.xft.event.Filterable;
+import org.nrg.xft.event.XftEventService;
+import org.nrg.xft.event.entities.AutomationCompletionEvent;
+import org.nrg.xft.event.entities.AutomationEventIds;
+import org.nrg.xft.event.entities.AutomationFilters;
+import org.nrg.xft.event.entities.PersistentEvent;
+import org.nrg.xft.event.persist.PersistentEventImplementerI;
+import org.nrg.xft.event.persist.PersistentWorkflowI;
+import org.nrg.xft.event.persist.PersistentWorkflowUtils;
+import org.nrg.xft.security.UserI;
+import org.nrg.xnat.utils.WorkflowUtils;
+import org.nrg.xnat.services.messaging.automation.AutomatedScriptRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+import static reactor.bus.selector.Selectors.type;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import javax.sql.DataSource;
+
+/**
+ * The Class AutomatedScriptHandler.
+ */
+@Service
+@SuppressWarnings("unused")
+public class AutomationEventScriptHandler implements Consumer<Event<AutomationEventImplementerI>> {
+	
+	private String EMAIL_SUBJECT = "Automation Results";
+    
+    /** The Constant logger. */
+    private static final Logger logger = LoggerFactory.getLogger(AutomationEventScriptHandler.class);
+	
+	/** The _service. */
+	@Inject ScriptRunnerService _service;
+	
+	/** The _script trigger service. */
+	@Inject ScriptTriggerService _scriptTriggerService;
+	
+	/** The _data source. */
+	@Inject DataSource _dataSource;
+	
+	/**
+	 * Instantiates a new automated script handler.
+	 *
+	 * @param eventBus the event bus
+	 */
+	@Inject public AutomationEventScriptHandler( EventBus eventBus ){
+		eventBus.on(type(AutomationEventImplementerI.class), this);
+	}
+	
+	/**
+	 *  init - update xhbm_script_trigger table for XNAT 1.7
+	 */
+	@PostConstruct
+	public void initUpdateTables() {
+        /** Update script trigger table for XNAT 1.7.  Drop constraints on any columns other than id and trigger_id */ 
+        if (_scriptTriggerService instanceof HibernateScriptTriggerService) {
+        	
+            List<String> cleanUpQuery = (new JdbcTemplate(_dataSource)).query(
+            			"SELECT DISTINCT 'ALTER TABLE '||tc.table_name||' DROP CONSTRAINT '||tc.constraint_name||';'" +
+                    	"  FROM information_schema.table_constraints tc " + 
+                    	"  LEFT JOIN information_schema.constraint_column_usage cu " +
+                    	"    ON cu.constraint_name = tc.constraint_name " + 
+                    	" WHERE (tc.table_name='xhbm_script_trigger' AND cu.column_name NOT IN ('id', 'trigger_id')) "           		
+            		, new RowMapper<String>() {
+            			public String mapRow(ResultSet rs, int rowNum) throws SQLException {
+            				return rs.getString(1);
+            			}
+            		});
+            if (!cleanUpQuery.isEmpty()) {
+            	logger.info("Cleaning up pre XNAT 1.7 constraints on the xhbm_script_trigger and xhbm_event tables");
+            	for (String query : cleanUpQuery) {
+            		if (query.contains("xhbm_script_trigger")) {
+            			logger.info("Execute clean-up query (" + query + ")");
+            			new JdbcTemplate(_dataSource).execute(query);
+            		}
+            	}
+            }
+            /** Update table rows for pre-XNAT 1.7 tables to fill in missing column values with defaults */
+        	((HibernateScriptTriggerService)_scriptTriggerService).updateOldStyleScriptTriggers();
+        }
+	}
+	
+	/* (non-Javadoc)
+	 * @see reactor.fn.Consumer#accept(java.lang.Object)
+	 */
+	@Override
+	public void accept(Event<AutomationEventImplementerI> event) {
+		
+		try {
+			handleAsPersistentEventIfMarkedPersistent(event);
+			updateAutomationTables(event);
+		} catch  (Throwable t) {
+			logger.error("Unexpected error persisting Persistent/Automation event information",t);
+		} finally {
+			handleEvent(event);
+		}
+		
+	}
+
+    /**
+     * Update automation tables.
+     *
+     * @param event the event
+     */
+    private void updateAutomationTables(Event<AutomationEventImplementerI> event) {
+		final HibernateAutomationEventIdsService idsService = XDAT.getContextService().getBean(HibernateAutomationEventIdsService.class);
+		final AutomationEventImplementerI eventData = event.getData();
+		if (eventData.getEventId()==null || eventData.getClass()==null) {
+			return;
+		}
+		List<AutomationEventIds> autoIds = idsService.getEventIds(eventData.getExternalId(), eventData.getSrcEventClass(), true);
+		if (autoIds.size()<1) {
+			final AutomationEventIds ids = new AutomationEventIds(eventData);
+			idsService.saveOrUpdate(ids);
+		} else {
+			for (final AutomationEventIds ids : autoIds) {
+				if (!ids.getEventIds().contains(eventData.getEventId())) {
+					ids.getEventIds().add(eventData.getEventId());
+					idsService.saveOrUpdate(ids);
+				}
+			}
+		}
+		final HibernateAutomationFiltersService filtersService = XDAT.getContextService().getBean(HibernateAutomationFiltersService.class);
+		final Class<? extends AutomationEventImplementerI> clazz = eventData.getClass();
+		for (final Method method : Arrays.asList(clazz.getMethods())) {
+			if (method.isAnnotationPresent(Filterable.class) && method.getName().substring(0,3).equalsIgnoreCase("get")) {
+				final char c[] = method.getName().substring(3).toCharArray();
+				c[0] = Character.toLowerCase(c[0]);
+				final String column = new String(c);
+				AutomationFilters filters = filtersService.getAutomationFilters(eventData.getExternalId(), eventData.getSrcEventClass(), column, true);
+				if (filters == null) {
+					filters = new AutomationFilters(eventData, column);
+					filtersService.saveOrUpdate(filters);
+				} else {
+					try {
+						final String value = method.invoke(eventData).toString();
+						final List<String> values = filters.getValues();
+						if (!values.contains(value)) {
+						values.add(value);
+							filters.setValues(values);
+							filtersService.saveOrUpdate(filters);
+						}
+					} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+						logger.error("Error invoking method on eventData",e);
+					}
+				}
+			}
+		}
+		
+	}
+
+	/**
+	 * Handle as persistent event if marked persistent.
+	 *
+	 * @param event the event
+	 */
+	private void handleAsPersistentEventIfMarkedPersistent(Event<AutomationEventImplementerI> event) {
+	    // Persist the event if this is a PersistentEventImplementerI
+		if (event.getData() instanceof PersistentEventImplementerI) {
+			try {
+				final HibernatePersistentEventService service = XDAT.getContextService().getBean(HibernatePersistentEventService.class);
+				service.create((PersistentEvent)event.getData());
+			} catch (SecurityException | IllegalArgumentException e) {
+				logger.error("Exception persisting event",e);
+			}
+		}
+	}
+
+	/**
+	 * Handle event.
+	 *
+	 * @param event the event
+	 */
+	/* (non-Javadoc)
+     * @see org.nrg.xnat.event.listeners.WorkflowStatusEventHandlerAbst#handleEvent(org.nrg.xft.event.WorkflowStatusEvent)
+     */
+    public void handleEvent(Event<AutomationEventImplementerI> event) {
+    	final AutomationEventImplementerI automationEvent = event.getData();
+    	if (automationEvent == null) {
+        	logger.debug("Automation script will not be launched because applicationEvent object is null");
+    		return;
+    	}
+    	final UserI user;
+    	try {
+			user = Users.getUser(automationEvent.getUserId());
+		} catch (UserNotFoundException | UserInitException e) {
+			// User is required to launch script
+        	logger.debug("Automation not launching because user object is null");
+			return;
+		}
+        final String eventClass = automationEvent.getSrcEventClass();
+        if (eventClass == null) {
+        	logger.debug("Automation not launching because eventClass is null");
+        	return;
+        }
+        final String eventID = automationEvent.getEventId();
+        if (eventID == null) {
+        	logger.debug("Automation not launching because eventID is null");
+        	return;
+        }
+        final Map<String,String> filterMap = Maps.newHashMap();
+		final Class<? extends AutomationEventImplementerI> clazz = automationEvent.getClass();
+		for (final Method method : Arrays.asList(clazz.getMethods())) {
+			if (method.isAnnotationPresent(Filterable.class) && method.getName().substring(0,3).equalsIgnoreCase("get")) {
+				final char c[] = method.getName().substring(3).toCharArray();
+				c[0] = Character.toLowerCase(c[0]);
+				final String column = new String(c);
+				String value;
+				try {
+					final Object rtValue = method.invoke(automationEvent);
+					if (rtValue != null) {
+						value = rtValue.toString(); 
+						filterMap.put(column, value);
+					}
+				} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+					logger.error("ERROR calling method on filterable field in event object", e);
+					// Let's let this pass for now.
+				}
+			}
+		}
+        if (eventID == null) {
+        	logger.debug("Automation not launching because eventID is null");
+        	return;
+        }
+        final String eventName = eventID.replaceAll("\\*OPEN\\*", "(").replaceAll("\\*CLOSE\\*", ")");
+        //check to see if this has been handled before
+        final AutomationCompletionEvent automationCompletionEvent = automationEvent.getAutomationCompletionEvent();
+        for (final Script script : getScripts(automationEvent.getExternalId(), eventClass, eventID, filterMap)) {
+            try {
+                final String action = "Executed script " + script.getScriptId();
+				Method justMethod = null;
+				try {
+					justMethod = automationEvent.getClass().getMethod("getJustification");
+				} catch (NoSuchMethodException | NullPointerException | SecurityException e) {
+					// Do nothing for now
+				}
+				final Object justObject = (justMethod!=null) ? justMethod.invoke(automationEvent) : null;
+				final String justification = (justObject!=null) ? justObject.toString() : "";
+                final String comment = "Executed script " + script.getScriptId() + " triggered by event " + eventID;
+                final PersistentWorkflowI scriptWrk = PersistentWorkflowUtils.buildOpenWorkflow(user, automationEvent.getEntityType(), automationEvent.getEntityId(), automationEvent.getExternalId(),
+                				EventUtils.newEventInstance(EventUtils.CATEGORY.DATA, EventUtils.TYPE.PROCESS, action,
+                						StringUtils.isNotBlank(justification) ? justification : "Automated execution: " + comment, comment));
+                assert scriptWrk != null;
+                scriptWrk.setStatus(PersistentWorkflowUtils.QUEUED);
+                WorkflowUtils.save(scriptWrk, scriptWrk.buildEvent());
+                
+                final AutomatedScriptRequest request = new AutomatedScriptRequest(automationEvent.getSrcStringifiedId(), automationEvent.getSrcEventClass(), user, script.getScriptId(), eventName,
+                			scriptWrk.getWorkflowId().toString(), automationEvent.getEntityType(), automationEvent.getSrcStringifiedId(), automationEvent.getExternalId(), automationEvent.getParameterMap());
+                
+                // We're running this here now, so we can return script output
+                //XDAT.sendJmsRequest(request);
+                final ScriptOutput scriptOut = executeScriptRequest(request);
+                if (automationCompletionEvent != null && scriptOut != null) {
+                	automationCompletionEvent.getScriptOutputs().add(scriptOut);
+                }
+            } catch (Exception e1) {
+                logger.error("Script launch exception", e1);
+            }
+        }
+        if (automationCompletionEvent!= null && automationCompletionEvent.getScriptOutputs().size()>0) {
+        	XftEventService eventService = XftEventService.getService();
+        	if (eventService != null) {
+        		automationCompletionEvent.setEventCompletionTime(System.currentTimeMillis());
+        		eventService.triggerEvent(automationCompletionEvent);
+        		List<String> notifyList = automationCompletionEvent.getNotificationList();
+        		if (notifyList != null && !notifyList.isEmpty()) {
+        			AdminUtils.sendUserHTMLEmail(EMAIL_SUBJECT, scriptOutputToHtmlString(automationCompletionEvent.getScriptOutputs()), false, notifyList.toArray(new String[0]));
+        		}
+        	}
+        }
+    }
+
+	private String scriptOutputToHtmlString(List<ScriptOutput> scriptOutputs) {
+		if (scriptOutputs == null) {
+			return "";
+		}
+		StringBuilder sb = new StringBuilder();
+		for (ScriptOutput scriptOut : scriptOutputs) {
+			sb.append("<br><b>SCRIPT EXECUTION RESULTS</b><br>");
+			sb.append("<br><b>FINAL STATUS:  " + scriptOut.getStatus() + "</b><br>");
+			if (scriptOut.getStatus().equals(Status.ERROR) && scriptOut.getResults()!=null && scriptOut.getResults().toString().length()>0) {
+				sb.append("<br><b>SCRIPT RESULTS</b><br>");
+				sb.append(scriptOut.getResults().toString().replace("\n", "<br>"));
+			}
+			if (scriptOut.getOutput()!=null && scriptOut.getOutput().length()>0) {
+				sb.append("<br><b>SCRIPT STDOUT</b><br>");
+				sb.append(scriptOut.getOutput().replace("\n", "<br>"));
+			}
+			if (scriptOut.getErrorOutput()!=null && scriptOut.getErrorOutput().length()>0) {
+				sb.append("<br><b>SCRIPT STDERR/EXCEPTION</b><br>");
+				sb.append(scriptOut.getErrorOutput().replace("\n", "<br>"));
+			}
+		}
+		return sb.toString();
+	}
+
+	/**
+     * Gets the scripts.
+     *
+     * @param projectId the project id
+     * @param eventClass the event class
+     * @param event the event
+     * @param filterMap the filter map
+     * @return the scripts
+     */
+    private List<Script> getScripts(final String projectId, String eventClass, String event, Map<String,String> filterMap) {
+
+        final List<Script> scripts = Lists.newArrayList();
+
+        //project level scripts
+        if (StringUtils.isNotBlank(projectId)) {
+            
+            final Script script = _service.getScript(Scope.Project, projectId, eventClass, event, filterMap);
+            if (script != null) {
+                scripts.add(script);
+            }
+        }
+
+        //site level scripts
+        final Script script = _service.getScript(Scope.Site, null, eventClass, event, filterMap);
+        if (script != null) {
+            scripts.add(script);
+        }
+
+        return scripts;
+    }
+    
+    /**
+     * Execute script request.
+     *
+     * @param request the request
+     * @return the script output
+     * @throws Exception the exception
+     */
+    private ScriptOutput executeScriptRequest(AutomatedScriptRequest request) throws Exception {
+    	
+        final PersistentWorkflowI workflow = WorkflowUtils.getUniqueWorkflow(request.getUser(), request.getScriptWorkflowId());
+        workflow.setStatus(PersistentWorkflowUtils.IN_PROGRESS);
+        WorkflowUtils.save(workflow, workflow.buildEvent());
+
+        final Map<String, Object> parameters = Maps.newHashMap();
+        parameters.put("user", request.getUser());
+        parameters.put("scriptId", request.getScriptId());
+        parameters.put("event", request.getEvent());
+        parameters.put("srcEventId", request.getSrcEventId());
+        parameters.put("srcEventClass", request.getSrcEventClass());
+        parameters.put("srcWorkflowId", request.getSrcEventId());
+        parameters.put("scriptWorkflowId", request.getScriptWorkflowId());
+        parameters.put("dataType", request.getDataType());
+        parameters.put("dataId", request.getDataId());
+        parameters.put("externalId", request.getExternalId());
+        parameters.put("workflow", workflow);
+        if (request.getArgumentMap()!=null && !request.getArgumentMap().isEmpty()) {
+        	parameters.putAll(request.getArgumentMap());
+        }
+
+        ScriptOutput scriptOut = null;
+        try {
+            scriptOut = _service.runScript(_service.getScript(request.getScriptId()), null, parameters, false);
+            if (PersistentWorkflowUtils.IN_PROGRESS.equals(workflow.getStatus())) {
+                WorkflowUtils.complete(workflow, workflow.buildEvent());
+            }
+        } catch (NrgServiceException e) {
+            final String message = String.format("Failed running the script %s by user %s for event %s on data type %s instance %s from project %s",
+                    request.getScriptId(),
+                    request.getUser().getLogin(),
+                    request.getEvent(),
+                    request.getDataType(),
+                    request.getDataId(),
+                    request.getExternalId());
+            AdminUtils.sendAdminEmail("Script execution failure", message);
+            logger.error(message, e);
+            if (PersistentWorkflowUtils.IN_PROGRESS.equals(workflow.getStatus())) {
+                WorkflowUtils.fail(workflow, workflow.buildEvent());
+            }
+        }
+        return scriptOut;
+	}
+    
+}
diff --git a/src/main/java/org/nrg/xnat/event/listeners/DicomToNiftiEmailHandler.java b/src/main/java/org/nrg/xnat/event/listeners/DicomToNiftiEmailHandler.java
index d316c329a06c72240e096935fc1756cece9d113f..a2c41276fe0f11e76d261694e9403ec1c0c4755f 100644
--- a/src/main/java/org/nrg/xnat/event/listeners/DicomToNiftiEmailHandler.java
+++ b/src/main/java/org/nrg/xnat/event/listeners/DicomToNiftiEmailHandler.java
@@ -8,8 +8,8 @@ import reactor.fn.Consumer;
 
 import org.apache.log4j.Logger;
 import org.nrg.xdat.om.WrkWorkflowdata;
-import org.nrg.xft.event.WorkflowStatusEvent;
 import org.nrg.xft.event.persist.PersistentWorkflowUtils;
+import org.nrg.xnat.event.entities.WorkflowStatusEvent;
 import org.springframework.stereotype.Service;
 
 import static reactor.bus.selector.Selectors.R;
diff --git a/src/main/java/org/nrg/xnat/event/listeners/PipelineEmailHandlerAbst.java b/src/main/java/org/nrg/xnat/event/listeners/PipelineEmailHandlerAbst.java
index 30690dbe06bfbd07dd4586d768681d359639e023..6468c88d7d4fd70327a7e7a6da281276d34bf5fc 100644
--- a/src/main/java/org/nrg/xnat/event/listeners/PipelineEmailHandlerAbst.java
+++ b/src/main/java/org/nrg/xnat/event/listeners/PipelineEmailHandlerAbst.java
@@ -18,7 +18,7 @@ import org.nrg.xdat.om.XnatSubjectassessordata;
 import org.nrg.xdat.schema.SchemaElement;
 import org.nrg.xdat.turbine.utils.TurbineUtils;
 import org.nrg.xft.db.PoolDBUtils;
-import org.nrg.xft.event.WorkflowStatusEvent;
+import org.nrg.xnat.event.entities.WorkflowStatusEvent;
 import org.nrg.xnat.notifications.NotifyProjectPipelineListeners;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
diff --git a/src/main/java/org/nrg/xnat/event/listeners/WorkflowStatusEventHandlerAbst.java b/src/main/java/org/nrg/xnat/event/listeners/WorkflowStatusEventHandlerAbst.java
index fddc98c029f19da14506166c064b260c0ce4f8e7..f74e60e0c8ae99d26dcb0bf84a0fe53458324b87 100644
--- a/src/main/java/org/nrg/xnat/event/listeners/WorkflowStatusEventHandlerAbst.java
+++ b/src/main/java/org/nrg/xnat/event/listeners/WorkflowStatusEventHandlerAbst.java
@@ -12,8 +12,8 @@ package org.nrg.xnat.event.listeners;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
-import org.nrg.xft.event.WorkflowStatusEvent;
 import org.nrg.xft.event.persist.PersistentWorkflowUtils;
+import org.nrg.xnat.event.entities.WorkflowStatusEvent;
 
 /**
  * @author Tim Olsen <tim@deck5consulting.com>
@@ -66,4 +66,4 @@ public abstract class WorkflowStatusEventHandlerAbst {
 		return StringUtils.equals(e.getWorkflow().getStatus(),PersistentWorkflowUtils.COMPLETE);
 	}
 	
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/nrg/xnat/initialization/RootConfig.java b/src/main/java/org/nrg/xnat/initialization/RootConfig.java
index 6ae818e422bad777c60226fdf8bef428a53179b9..d8d23ebb241e4426dc01385b351f2ceeb6bf16a2 100644
--- a/src/main/java/org/nrg/xnat/initialization/RootConfig.java
+++ b/src/main/java/org/nrg/xnat/initialization/RootConfig.java
@@ -7,6 +7,7 @@ import org.nrg.xdat.security.HistoricPasswordValidator;
 import org.nrg.xdat.security.PasswordValidatorChain;
 import org.nrg.xdat.security.RegExpValidator;
 import org.nrg.xnat.utils.XnatUserProvider;
+import org.nrg.xnat.event.conf.EventPackages;
 import org.nrg.xnat.restlet.XnatRestletExtensions;
 import org.nrg.xnat.restlet.actions.importer.ImporterHandlerPackages;
 import org.springframework.beans.factory.annotation.Value;
@@ -39,8 +40,8 @@ import java.util.List;
 @ImportResource({"WEB-INF/conf/xnat-security.xml", "WEB-INF/conf/mq-context.xml"})
 public class RootConfig {
 
-    private static final List<String> DEFAULT_ENTITY_PACKAGES = Arrays.asList("org.nrg.framework.datacache", "org.nrg.xft.entities", "org.nrg.xdat.entities",
-                                                                              "org.nrg.xnat.entities", "org.nrg.prefs.entities", "org.nrg.config.entities");
+    public static final List<String> DEFAULT_ENTITY_PACKAGES = Arrays.asList("org.nrg.framework.datacache", "org.nrg.xft.entities", "org.nrg.xft.event.entities", "org.nrg.xdat.entities",
+                                                                              "org.nrg.xnat.entities", "org.nrg.xnat.event.entities", "org.nrg.prefs.entities", "org.nrg.config.entities");
 
     @Bean
     public String siteId() {
@@ -94,6 +95,12 @@ public class RootConfig {
 		return new ImporterHandlerPackages(new HashSet<String>(Arrays.asList(new String[] {"org.nrg.xnat.restlet.actions","org.nrg.xnat.archive"})));
     }
 
+    @Bean
+    public EventPackages eventPackages() {
+    	// NOTE:  These should be treated as parent packages.  All sub-packages should be searched 
+		return new EventPackages(new HashSet<String>(Arrays.asList(new String[] {"org.nrg.xnat.event","org.nrg.xft.event","org.nrg.xdat.event"})));
+    }
+
     @Bean
     public SerializerRegistry serializerRegistry() {
         return new SerializerRegistry();
diff --git a/src/main/java/org/nrg/xnat/restlet/XNATApplication.java b/src/main/java/org/nrg/xnat/restlet/XNATApplication.java
index 3d3cda9a1476a6028808b6d04a45de0fb361b7a8..1bcbc4b25bf3fbaadf3d99377864e64df9f0e752 100755
--- a/src/main/java/org/nrg/xnat/restlet/XNATApplication.java
+++ b/src/main/java/org/nrg/xnat/restlet/XNATApplication.java
@@ -339,7 +339,6 @@ public class XNATApplication extends Application {
         attachURIs(router, ScriptRunnerResource.class, "/automation/runners", "/automation/runners/{LANGUAGE}", "/automation/runners/{LANGUAGE}/{VERSION}");
         attachURIs(router, ScriptResource.class, "/automation/scripts", "/automation/scripts/{SCRIPT_ID}", "/automation/scripts/{SCRIPT_ID}/{VERSION}");
         attachURIs(router, ScriptVersionsResource.class, "/automation/scriptVersions", "/automation/scriptVersions/{SCRIPT_ID}");
-        attachURIs(router, EventResource.class, "/automation/events", "/automation/events/{EVENT_ID}");
         attachURIs(router, WorkflowEventResource.class, "/automation/workflows", "/automation/workflows/{SPEC}");
         attachURIs(router, ScriptTriggerResource.class, "/automation/handlers",
                 "/automation/handlers/{EVENT_ID}",
diff --git a/src/main/java/org/nrg/xnat/restlet/actions/AutomationBasedImporter.java b/src/main/java/org/nrg/xnat/restlet/actions/AutomationBasedImporter.java
index 0cd57f8add0be061f25e7782780a419f84284954..ee9700a20a4efe9a82ef1c08cafac816ec8f8d89 100644
--- a/src/main/java/org/nrg/xnat/restlet/actions/AutomationBasedImporter.java
+++ b/src/main/java/org/nrg/xnat/restlet/actions/AutomationBasedImporter.java
@@ -12,57 +12,64 @@ package org.nrg.xnat.restlet.actions;
  */
 
 import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
 import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
 import java.net.URLDecoder;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.gson.Gson;
+import com.google.gson.JsonParseException;
+import com.google.gson.reflect.TypeToken;
 
 import java.util.concurrent.Callable;
 
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.log4j.Logger;
+import org.json.JSONObject;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONTokener;
+
 import org.nrg.action.ClientException;
 import org.nrg.action.ServerException;
-import org.nrg.automation.entities.Script;
 import org.nrg.automation.entities.ScriptOutput;
 import org.nrg.automation.entities.ScriptOutput.Status;
-import org.nrg.automation.services.ScriptRunnerService;
+import org.nrg.automation.entities.ScriptTrigger;
+import org.nrg.automation.services.ScriptTriggerService;
 import org.nrg.framework.constants.Scope;
-import org.nrg.framework.exceptions.NrgServiceException;
 import org.nrg.xdat.XDAT;
-import org.nrg.xdat.om.WrkWorkflowdata;
 import org.nrg.xdat.om.XnatExperimentdata;
 import org.nrg.xdat.om.XnatProjectdata;
 import org.nrg.xdat.om.XnatSubjectdata;
-import org.nrg.xdat.turbine.utils.AdminUtils;
+import org.nrg.xnat.event.entities.WorkflowStatusEvent;
+import org.nrg.xnat.event.listeners.AutomationCompletionEventListener;
 import org.nrg.xnat.restlet.actions.importer.ImporterHandler;
 import org.nrg.xnat.restlet.actions.importer.ImporterHandlerA;
 import org.nrg.xnat.restlet.files.utils.RestFileUtils;
 import org.nrg.xnat.restlet.util.FileWriterWrapperI;
-import org.nrg.xnat.services.messaging.automation.AutomatedScriptRequest;
 import org.nrg.xnat.turbine.utils.ArcSpecManager;
-import org.nrg.xnat.utils.WorkflowUtils;
-import org.json.JSONArray;
-import org.json.JSONException;
-//import net.sf.json.JSONObject;
-import org.json.JSONObject;
-import org.json.JSONTokener;
 
 import java.util.zip.ZipOutputStream;
 
+import org.nrg.xft.event.AutomationEventImplementerI;
 import org.nrg.xft.event.EventMetaI;
 import org.nrg.xft.event.EventUtils;
 import org.nrg.xft.event.EventUtils.CATEGORY;
 import org.nrg.xft.event.EventUtils.TYPE;
+import org.nrg.xft.event.XftEventService;
+import org.nrg.xft.event.Filterable;
+import org.nrg.xft.event.entities.AutomationCompletionEvent;
 import org.nrg.xft.event.persist.PersistentWorkflowI;
 import org.nrg.xft.event.persist.PersistentWorkflowUtils;
 import org.nrg.xft.event.persist.PersistentWorkflowUtils.EventRequirementAbsent;
@@ -71,50 +78,81 @@ import org.nrg.xft.utils.zip.TarUtils;
 import org.nrg.xft.utils.zip.ZipI;
 import org.nrg.xft.utils.zip.ZipUtils;
 
-
 /**
- * @author Mike Hodge <hodgem@mir.wustl.edu>
+ * The Class AutomationBasedImporter.
  *
+ * @author Mike Hodge <hodgem@mir.wustl.edu>
  */
 @ImporterHandler(handler = "automation", allowCallsWithoutFiles = true, callPartialUriWrap = false)
 public class AutomationBasedImporter extends ImporterHandlerA implements Callable<List<String>> {
- 	
-    private final ScriptRunnerService _service = XDAT.getContextService().getBean(ScriptRunnerService.class);
-
-	static final String[] ZIP_EXT={".zip",".jar",".rar",".ear",".gar",".xar"};
 
+	/** The Constant ZIP_EXT. */
+	static final String[] ZIP_EXT = { ".zip", ".jar", ".rar", ".ear", ".gar", ".xar" };
+	
 	private static final String STATUS_COMPLETE = "Complete";
+
+	/** The Constant CACHE_CONSTANT. */
 	private static final String CACHE_CONSTANT = "_CACHE_";
+
+	/** The Constant CONFIG_TOOL. */
 	private static final String CONFIG_TOOL = "resource_config";
+
+	/** The Constant CONFIG_SCRIPT_PATH. */
 	private static final String CONFIG_SCRIPT_PATH = "script";
-	private static final String EMAIL_SUBJECT = "AutomationBasedImporter results";
 
+	/** The Constant EMAIL_SUBJECT. */
+	// private static final String EMAIL_SUBJECT = "AutomationBasedImporter
+	// results";
+
+	/** The Constant TIMEOUT_SECONDS. */
+	private static final int TIMEOUT_SECONDS = 900;
+
+	/** The logger. */
 	static Logger logger = Logger.getLogger(AutomationBasedImporter.class);
-	
+
+	/** The fw. */
 	private final FileWriterWrapperI fw;
+
+	/** The user. */
 	private final UserI user;
-	final Map<String,Object> params;
+
+	/** The params. */
+	final Map<String, Object> params;
+
+	/** The return list. */
 	private final List<String> returnList = new ArrayList<String>();;
-	private String configuredResource; 
-	// Is this useful?  Do we want it to be configurable?
-	private boolean sendAdminEmail = false;
-	
+
+	/** The configured resource. */
+	private String configuredResource;
+
+	/** The send admin email. */
+	// Is this useful? Do we want it to be configurable?
+	// private boolean sendAdminEmail = false;
+
 	/**
-	 * 
+	 * Instantiates a new automation based importer.
+	 *
 	 * @param listenerControl
+	 *            the listener control
 	 * @param u
-	 * @param session
-	 * @param overwrite:   'append' means overwrite, but preserve un-modified content (don't delete anything)
-	 *                      'delete' means delete the pre-existing content.
-	 * @param additionalValues: should include project (subject and experiment are expected to be found in the archive)
+	 *            the u
+	 * @param fw
+	 *            the fw
+	 * @param params
+	 *            the params
 	 */
 	public AutomationBasedImporter(Object listenerControl, UserI u, FileWriterWrapperI fw, Map<String, Object> params) {
 		super(listenerControl, u, fw, params);
-		this.user=u;
-		this.fw=fw;
-		this.params=params;
+		this.user = u;
+		this.fw = fw;
+		this.params = params;
 	}
 
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.nrg.xnat.restlet.actions.importer.ImporterHandlerA#call()
+	 */
 	@SuppressWarnings("deprecation")
 	@Override
 	public List<String> call() throws ClientException, ServerException {
@@ -123,150 +161,317 @@ public class AutomationBasedImporter extends ImporterHandlerA implements Callabl
 			this.completed("Success");
 			return returnList;
 		} catch (ClientException e) {
-			logger.error("",e);
+			logger.error("", e);
 			this.failed(e.getMessage());
 			throw e;
 		} catch (ServerException e) {
-			logger.error("",e);
+			logger.error("", e);
 			this.failed(e.getMessage());
 			throw e;
 		} catch (Throwable e) {
-			logger.error("",e);
-			throw new ServerException(e.getMessage(),new Exception());
+			logger.error("", e);
+			throw new ServerException(e.getMessage(), new Exception());
 		}
 	}
 
-	/*
-	@SuppressWarnings("deprecation")
-	private void clientFailed(final String fmsg) throws ClientException {
-		this.failed(fmsg);
-		throw new ClientException(fmsg,new Exception());
-	}
-	*/
+	/**
+	 * Process upload.
+	 *
+	 * @throws ClientException
+	 *             the client exception
+	 * @throws ServerException
+	 *             the server exception
+	 */
+	private void processUpload() throws ClientException, ServerException {
 
-	private void processUpload() throws ClientException,ServerException {
-		
 		String cachePath = ArcSpecManager.GetInstance().getGlobalCachePath();
-		
+
 		final Object processParam = params.get("process");
 		final Object configuredResourceParam = params.get("configuredResource");
 		final Object buildPathParam = params.get("buildPath");
-		final Object sendemailParam = params.get("sendemail");
-		final boolean doProcess = processParam!=null && processParam.toString().equalsIgnoreCase("true");
-		configuredResource = (configuredResourceParam!=null) ? configuredResourceParam.toString() : CACHE_CONSTANT;
-		
-		// Uploads to configured resources are handled on the client side.  Only the workflow is generated by this resource
+		final Object eventHandlerParam = params.get("eventHandler");
+		// final Object sendemailParam = params.get("sendemail");
+		final boolean doProcess = processParam != null && processParam.toString().equalsIgnoreCase("true");
+		configuredResource = (configuredResourceParam != null) ? configuredResourceParam.toString() : CACHE_CONSTANT;
+
+		// Uploads to configured resources are handled on the client side. Only
+		// the workflow is generated by this resource
+		if (doProcess && !configuredResource.equalsIgnoreCase(CACHE_CONSTANT) && eventHandlerParam == null) {
+			createWorkflowEntry(configuredResourceParam.toString());
+			return;
+		}
 		if (doProcess && !configuredResource.equalsIgnoreCase(CACHE_CONSTANT)) {
 			doAutomation();
 			return;
 		}
-		
-		// Multiple uploads are allowed to same space (processing will take place when process parameter=true).  Use specified build path when
+
+		// Multiple uploads are allowed to same space (processing will take
+		// place when process parameter=true). Use specified build path when
 		// one is given, otherwise create new one
-		String specPath=null;
+		String specPath = null;
 		String buildPath = null;
-		if (buildPathParam!=null) {
+		if (buildPathParam != null) {
 			// If buildpath parameter is specified and valid, use it
-			specPath=buildPathParam.toString();
-			if (specPath.indexOf(cachePath)>=0 && specPath.indexOf("user_uploads")>=0 &&
-					specPath.indexOf(File.separator + user.getID() + File.separator)>=0 && new File(specPath).isDirectory()) {
-				buildPath=specPath;
+			specPath = buildPathParam.toString();
+			if (specPath.indexOf(cachePath) >= 0 && specPath.indexOf("user_uploads") >= 0
+					&& specPath.indexOf(File.separator + user.getID() + File.separator) >= 0
+					&& new File(specPath).isDirectory()) {
+				buildPath = specPath;
 			} else {
 				throw new ClientException("ERROR:  Specified build path is invalid or directory does not exist.");
 			}
-		} else  if (specPath==null && !(fw==null && doProcess)) {
+		} else if (specPath == null && !(fw == null && doProcess)) {
 			final Date d = Calendar.getInstance().getTime();
-			final java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat ("yyyyMMdd_HHmmss");
+			final java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat("yyyyMMdd_HHmmss");
 			final String uploadID = formatter.format(d);
 			// Save input files to cache space
 			buildPath = cachePath + "user_uploads/" + user.getID() + "/" + uploadID + "/";
-		} 
-		
+		}
+
 		File cacheLoc = null;
-		if (buildPath!=null) {
+		if (buildPath != null) {
 			cacheLoc = new File(buildPath);
 			cacheLoc.mkdirs();
 		}
-		
+
 		// If uploading a file, process it.
-		if (fw!=null && cacheLoc!=null) {
+		if (fw != null && cacheLoc != null) {
 			processFile(cacheLoc, specPath);
-		} 
-		
-		// Conditionally process cache location files, otherwise return cache location
+		}
+
+		// Conditionally process cache location files, otherwise return cache
+		// location
 		if (doProcess) {
 			doAutomation();
-			if (sendemailParam!=null && sendemailParam.toString().equalsIgnoreCase("true")) {
-				sendUserEmail(sendAdminEmail);
-			} else if (sendAdminEmail) {
-				sendAdminEmail();
-			}
-		} else if (buildPath!=null) {
+			/*
+			 * if (sendemailParam!=null &&
+			 * sendemailParam.toString().equalsIgnoreCase("true")) {
+			 * sendUserEmail(sendAdminEmail); } else if (sendAdminEmail) {
+			 * sendAdminEmail(); }
+			 */
+		} else if (buildPath != null) {
 			returnList.add(buildPath);
 		}
-		
+
 	}
-	
-	private String returnListToHtmlString() {
-		final StringBuilder sb = new StringBuilder("<br/>");
-		for (final String s : returnList) {
-			sb.append(s).append("<br/>\t");
+
+	/**
+	 * Return list to html string.
+	 *
+	 * @return the string
+	 */
+	/*
+	 * private String returnListToHtmlString() { final StringBuilder sb = new
+	 * StringBuilder("<br/>"); for (final String s : returnList) {
+	 * sb.append(s).append("<br/>\t"); } return sb.toString(); }
+	 */
+
+	/**
+	 * Send user email.
+	 *
+	 * @param ccAdmin
+	 *            the cc admin
+	 */
+	/*
+	 * private void sendUserEmail(boolean ccAdmin) {
+	 * AdminUtils.sendUserHTMLEmail(EMAIL_SUBJECT, returnListToHtmlString(),
+	 * ccAdmin, new String[] { user.getEmail() }); }
+	 */
+
+	/**
+	 * Send admin email.
+	 */
+	/*
+	 * private void sendAdminEmail() {
+	 * AdminUtils.sendAdminEmail(user,EMAIL_SUBJECT, returnListToHtmlString());
+	 * }
+	 */
+
+	private void createWorkflowEntry(String string) {
+		
+		final Map<String, Object> passMap = Maps.newHashMap();
+		final Object projectParam = params.get("project");
+		final Object subjectParam = params.get("subject");
+		final Object experimentParam = params.get("experiment");
+		final Object passedParametersParam = params.get("passedParameters");
+		String eventText = null; 
+
+		@SuppressWarnings("rawtypes")
+		Class clazz;
+		Object eventObj;
+		String eventClass = WorkflowStatusEvent.class.getName();
+		try {
+			clazz = WorkflowStatusEvent.class;
+			eventObj = clazz.newInstance();
+		} catch (InstantiationException | IllegalAccessException e) {
+			returnList.add("ERROR: Could not instantiate event (" + eventClass + "). <br>" + e.toString());
+			return;
 		}
-		return sb.toString();
-	}
-	
-	private void sendUserEmail(boolean ccAdmin) {
-			AdminUtils.sendUserHTMLEmail(EMAIL_SUBJECT, returnListToHtmlString(), ccAdmin, new String[] { user.getEmail() });
-	}
-	
-	private void sendAdminEmail() {
-			AdminUtils.sendAdminEmail(user,EMAIL_SUBJECT, returnListToHtmlString());
+		if (!(eventObj instanceof AutomationEventImplementerI)) {
+			returnList.add("ERROR: Event (" + eventClass + ") is not an AutomationEventImplementer.");
+		}
+		final AutomationEventImplementerI automationEvent = (AutomationEventImplementerI) eventObj;
+		final String entityId;
+		final String entityType;
+		if (experimentParam == null && subjectParam == null) {
+			entityId = projectParam.toString();
+			entityType = XnatProjectdata.SCHEMA_ELEMENT_NAME;
+		} else if (experimentParam == null && subjectParam != null) {
+			entityId = subjectParam.toString();
+			entityType = XnatSubjectdata.SCHEMA_ELEMENT_NAME;
+		} else if (experimentParam != null) {
+			entityId = experimentParam.toString();
+			final XnatExperimentdata experimentData = XnatExperimentdata.getXnatExperimentdatasById(experimentParam,
+					user, false);
+			entityType = experimentData.getXSIType();
+		} else {
+			entityId = null;
+			entityType = null;
+		}
+		if (entityId == null) {
+			returnList.add("ERROR: Entity type could not be determined");
+			return;
+		}
+		automationEvent.setEntityId(entityId);
+		automationEvent.setEntityType(entityType);
+		automationEvent.setExternalId(projectParam.toString());
+		automationEvent.setSrcEventClass(eventClass);
+		automationEvent.setUserId(user.getID());
+		automationEvent.setEventId(null);
+		// Create parameter map
+		XnatProjectdata proj = null;
+		XnatSubjectdata subj = null;
+		XnatExperimentdata exp = null;
+		if (projectParam != null && projectParam.toString().length() > 0) {
+			proj = XnatProjectdata.getXnatProjectdatasById(projectParam, user, false);
+			if (proj != null) {
+				passMap.put("project", proj.getId());
+			}
+		}
+		if (subjectParam != null && subjectParam.toString().length() > 0) {
+			subj = XnatSubjectdata.getXnatSubjectdatasById(subjectParam.toString(), user, false);
+			if (subj == null) {
+				subj = XnatSubjectdata.GetSubjectByProjectIdentifier(proj.getId(), subjectParam.toString(), user,
+						false);
+			}
+			if (subj != null) {
+				passMap.put("subject", subj.getId());
+			}
+		}
+		if (experimentParam != null && experimentParam.toString().length() > 0) {
+			exp = XnatExperimentdata.getXnatExperimentdatasById(experimentParam.toString(), user, false);
+			if (exp == null) {
+				exp = XnatExperimentdata.GetExptByProjectIdentifier(proj.getId(), experimentParam.toString(), user,
+						false);
+			}
+			if (exp != null) {
+				passMap.put("experiment", exp.getId());
+			}
+		}
+		if (passedParametersParam != null && passedParametersParam.toString().length() > 0) {
+			String passedParametersJsonStr = null;
+			try {
+				passedParametersJsonStr = URLDecoder.decode(passedParametersParam.toString(), "UTF-8");
+			} catch (UnsupportedEncodingException e1) {
+				returnList.add("WARNING: Could not parse passed parameters");
+			}
+			if (passedParametersJsonStr != null) {
+				try {
+					Type type = new TypeToken<Map<String, String>>() {
+					}.getType();
+					Map<String, String> gsonMap = new Gson().fromJson(passedParametersJsonStr, type);
+					passMap.putAll(gsonMap);
+				} catch (JsonParseException e) {
+					returnList.add("WARNING: Could not parse passed parameters");
+				}
+			}
+		}
+		if (!(configuredResource == null || configuredResource.equalsIgnoreCase(CACHE_CONSTANT))) {
+			eventText = getEventTextFromConfiguredResourceConfig(proj, subj, exp, configuredResource);
+			passMap.put("configuredResource", configuredResource);
+
+		}
+		if (eventText!=null) {
+			buildWorkflow(proj,subj,exp,passMap,eventText);
+		}
+		
 	}
 
-	private void processFile(final File cacheLoc,final  String specPath) throws ClientException {
+	/**
+	 * Process file.
+	 *
+	 * @param cacheLoc
+	 *            the cache loc
+	 * @param specPath
+	 *            the spec path
+	 * @throws ClientException
+	 *             the client exception
+	 */
+	private void processFile(final File cacheLoc, final String specPath) throws ClientException {
 		final String fileName;
 		try {
-			fileName = URLDecoder.decode(fw.getName(),"UTF-8");
+			fileName = URLDecoder.decode(fw.getName(), "UTF-8");
 		} catch (UnsupportedEncodingException e1) {
-			throw new ClientException("Could not decode file name.",e1);
+			throw new ClientException("Could not decode file name.", e1);
 		}
 		final Object extractParam = params.get("extract");
-		if (extractParam!=null && extractParam.toString().equalsIgnoreCase("true") && isZipFileName(fileName)) {
+		if (extractParam != null && extractParam.toString().equalsIgnoreCase("true") && isZipFileName(fileName)) {
 			final ZipI zipper = getZipper(fileName);
 			try {
-				zipper.extract(fw.getInputStream(),cacheLoc.getAbsolutePath());
+				zipper.extract(fw.getInputStream(), cacheLoc.getAbsolutePath());
 			} catch (Exception e) {
 				throw new ClientException("Archive file is corrupt or not a valid archive file type.");
 			}
 		} else {
-			final File cacheFile = new File(cacheLoc,fileName);
+			final File cacheFile = new File(cacheLoc, fileName);
 			try {
 				fw.write(cacheFile);
-				// Uploading directories via linux (and likely Mac) will not fail due to "Everything is a file".  In such cases we wind 
-				// up with a "file" generated.  Check for these "files".  Remove them, and thrown an exception.
-				// Windows uploads of directories should fail before hitting this class.
+				// Uploading directories via linux (and likely Mac) will not
+				// fail due to "Everything is a file". In such cases we wind
+				// up with a "file" generated. Check for these "files". Remove
+				// them, and thrown an exception.
+				// Windows uploads of directories should fail before hitting
+				// this class.
 				removeAndThrowExceptionIfDirectory(cacheFile);
 			} catch (ClientException e) {
 				throw e;
 			} catch (Exception e) {
-				throw new ClientException("Could not write uploaded file.",e);
+				throw new ClientException("Could not write uploaded file.", e);
 			}
 		}
 	}
-	
+
+	/**
+	 * Removes the and throw exception if directory.
+	 *
+	 * @param file
+	 *            the file
+	 * @throws ClientException
+	 *             the client exception
+	 */
 	private void removeAndThrowExceptionIfDirectory(File file) throws ClientException {
 		if (RestFileUtils.isFileRepresentationOfDirectory(file)) {
 			if (file.delete()) {
-				throw new ClientException("Upload of directories is not currently supported.  To upload a directory, please create a zip archive.");
-			};
+				throw new ClientException(
+						"Upload of directories is not currently supported.  To upload a directory, please create a zip archive.");
+			}
 		}
 	}
 
+	/**
+	 * Do automation.
+	 *
+	 * @throws ClientException
+	 *             the client exception
+	 * @throws ServerException
+	 *             the server exception
+	 */
+	@SuppressWarnings({ "rawtypes", "static-access" })
 	private void doAutomation() throws ClientException, ServerException {
-		
-		returnList.add("<b>BEGIN PROCESSING UPLOADED FILES</b><br>");
-		
-		final Map<String,Object> passMap = Maps.newHashMap();
+
+		returnList.add("<b>BEGIN PROCESSING UPLOADED FILES</b>");
+
+		final Map<String, Object> passMap = Maps.newHashMap();
 		final Object eventHandlerParam = params.get("eventHandler");
 		final Object projectParam = params.get("project");
 		final Object subjectParam = params.get("subject");
@@ -274,86 +479,236 @@ public class AutomationBasedImporter extends ImporterHandlerA implements Callabl
 		final Object buildPathParam = params.get("buildPath");
 		final Object passedParametersParam = params.get("passedParameters");
 		String eventText = null; 
+
+		final ScriptTriggerService scriptTriggerService = XDAT.getContextService().getBean(ScriptTriggerService.class);
+		if (scriptTriggerService == null) {
+			returnList.add("ERROR: Could not obtain event handler service.");
+			return;
+		}
+		final ScriptTrigger scriptTrigger = scriptTriggerService.getByTriggerId(eventHandlerParam.toString());
+		if (scriptTrigger == null) {
+			returnList.add("ERROR: Could not obtain event handler.");
+			return;
+		}
+		final String eventClass = scriptTrigger.getSrcEventClass();
+		final Map<String, List<String>> eventFilters = scriptTrigger.getEventFiltersAsMap();
+		Class clazz;
+		Object eventObj;
+		try {
+			clazz = Class.forName(eventClass);
+			eventObj = clazz.newInstance();
+		} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
+			returnList.add("ERROR: Could not instantiate event (" + eventClass + "). <br>" + e.toString());
+			return;
+		}
+		if (!(eventObj instanceof AutomationEventImplementerI)) {
+			returnList.add("ERROR: Event (" + eventClass + ") is not an AutomationEventImplementer.");
+		}
+		final AutomationEventImplementerI automationEvent = (AutomationEventImplementerI) eventObj;
+		final String entityId;
+		final String entityType;
+		if (experimentParam == null && subjectParam == null) {
+			entityId = projectParam.toString();
+			entityType = XnatProjectdata.SCHEMA_ELEMENT_NAME;
+		} else if (experimentParam == null && subjectParam != null) {
+			entityId = subjectParam.toString();
+			entityType = XnatSubjectdata.SCHEMA_ELEMENT_NAME;
+		} else if (experimentParam != null) {
+			entityId = experimentParam.toString();
+			final XnatExperimentdata experimentData = XnatExperimentdata.getXnatExperimentdatasById(experimentParam,
+					user, false);
+			entityType = experimentData.SCHEMA_ELEMENT_NAME;
+		} else {
+			entityId = null;
+			entityType = null;
+		}
+		if (entityId == null) {
+			returnList.add("ERROR: Entity type could not be determined");
+			return;
+		}
+		automationEvent.setEntityId(entityId);
+		automationEvent.setEntityType(entityType);
+		automationEvent.setExternalId(projectParam.toString());
+		automationEvent.setSrcEventClass(eventClass);
+		automationEvent.setUserId(user.getID());
+		automationEvent.setEventId(scriptTrigger.getEvent());
+		final List<Method> setters = Lists.newArrayList();
+		for (final Method method : Arrays.asList(automationEvent.getClass().getMethods())) {
+			if (method.isAnnotationPresent(Filterable.class)
+					&& method.getName().substring(0, 3).equalsIgnoreCase("get")) {
+				final char c[] = method.getName().substring(3).toCharArray();
+				c[0] = Character.toLowerCase(c[0]);
+				final String column = new String(c);
+				for (final String filterKey : eventFilters.keySet()) {
+					if (filterKey.equals(column)) {
+						Method setter;
+						try {
+							setter = automationEvent.getClass().getMethod(method.getName().replaceFirst("get", "set"),
+									String.class);
+						} catch (NoSuchMethodException | SecurityException e) {
+							continue;
+						}
+						if (setter.getName().substring(0, 3).equals("set")) {
+							List<String> filterList = eventFilters.get(filterKey);
+							setters.add(setter);
+							if (filterList != null && filterList.size() > 0) {
+								try {
+									setter.invoke(automationEvent, filterList.get(0));
+								} catch (IllegalAccessException | IllegalArgumentException
+										| InvocationTargetException e) {
+									returnList.add("ERROR: Could not set values for filters");
+									return;
+								}
+							}
+						}
+					}
+				}
+
+			}
+		}
+		if (!(setters.size() >= eventFilters.keySet().size())) {
+			returnList.add("ERROR: Could not set values for filters");
+			return;
+		}
+		// Create parameter map
 		XnatProjectdata proj = null;
 		XnatSubjectdata subj = null;
 		XnatExperimentdata exp = null;
-		if (projectParam!=null && projectParam.toString().length()>0) {
+		if (projectParam != null && projectParam.toString().length() > 0) {
 			proj = XnatProjectdata.getXnatProjectdatasById(projectParam, user, false);
 			if (proj != null) {
 				passMap.put("project", proj.getId());
 			}
 		}
-		if (subjectParam!=null && subjectParam.toString().length()>0) {
+		if (subjectParam != null && subjectParam.toString().length() > 0) {
 			subj = XnatSubjectdata.getXnatSubjectdatasById(subjectParam.toString(), user, false);
-			if (subj == null) {		
-				subj = XnatSubjectdata.GetSubjectByProjectIdentifier(proj.getId(), subjectParam.toString(), user, false);
+			if (subj == null) {
+				subj = XnatSubjectdata.GetSubjectByProjectIdentifier(proj.getId(), subjectParam.toString(), user,
+						false);
 			}
-			if (subj != null) {		
+			if (subj != null) {
 				passMap.put("subject", subj.getId());
 			}
 		}
-		if (experimentParam!=null && experimentParam.toString().length()>0) {
+		if (experimentParam != null && experimentParam.toString().length() > 0) {
 			exp = XnatExperimentdata.getXnatExperimentdatasById(experimentParam.toString(), user, false);
 			if (exp == null) {
-				exp = XnatExperimentdata.GetExptByProjectIdentifier(proj.getId(), experimentParam.toString(), user, false);
+				exp = XnatExperimentdata.GetExptByProjectIdentifier(proj.getId(), experimentParam.toString(), user,
+						false);
 			}
 			if (exp != null) {
 				passMap.put("experiment", exp.getId());
 			}
 		}
-		if (passedParametersParam!=null && passedParametersParam.toString().length()>0) {
+		if (passedParametersParam != null && passedParametersParam.toString().length() > 0) {
+			String passedParametersJsonStr = null;
 			try {
-				final String passedParametersJsonStr = URLDecoder.decode(passedParametersParam.toString(),"UTF-8");
-				final JSONObject json = new JSONObject(passedParametersJsonStr);
-				passMap.put("passedParameters", json);
-			} catch(UnsupportedEncodingException | JSONException e) {
-				// Do nothing for now.
+				passedParametersJsonStr = URLDecoder.decode(passedParametersParam.toString(), "UTF-8");
+			} catch (UnsupportedEncodingException e1) {
+				returnList.add("WARNING: Could not parse passed parameters");
+			}
+			if (passedParametersJsonStr != null) {
+				try {
+					Type type = new TypeToken<Map<String, String>>() {
+					}.getType();
+					Map<String, String> gsonMap = new Gson().fromJson(passedParametersJsonStr, type);
+					passMap.putAll(gsonMap);
+				} catch (JsonParseException e) {
+					returnList.add("WARNING: Could not parse passed parameters");
+				}
 			}
 		}
-		if (!(configuredResource==null || configuredResource.equalsIgnoreCase(CACHE_CONSTANT))) {
+		if (!(configuredResource == null || configuredResource.equalsIgnoreCase(CACHE_CONSTANT))) {
 			eventText = getEventTextFromConfiguredResourceConfig(proj, subj, exp, configuredResource);
 			passMap.put("configuredResource", configuredResource);
-			
+
+		}
+		if (eventText!=null) {
+			buildWorkflow(proj,subj,exp,passMap,eventText);
 		}
-		if (buildPathParam!=null) {
+		if (buildPathParam != null) {
 			passMap.put("BuildPath", buildPathParam);
 		}
-		if (eventHandlerParam!=null && eventHandlerParam.toString().length()>0) {
-			eventText = eventHandlerParam.toString();
-		}	
-		if (eventText!=null) {
-			PersistentWorkflowI wrk = buildWorkflow(proj,passMap,eventText);
-			// Launch automation script for workflow handler
-			if (wrk instanceof WrkWorkflowdata) {
-				ScriptOutput scriptOut = launchScript((WrkWorkflowdata)wrk);
-				if (scriptOut!=null) {
-					returnList.add("<br><b>SCRIPT EXECUTION RESULTS</b>");
-					returnList.add("<br><b>FINAL STATUS:  " + scriptOut.getStatus() + "</b>");
-					if (scriptOut.getStatus().equals(Status.ERROR) && scriptOut.getResults()!=null && scriptOut.getResults().toString().length()>0) {
-						returnList.add("<br><b>SCRIPT RESULTS</b>");
+		automationEvent.setParameterMap(passMap);
+		// Create automationCompletionEvent and launch automation
+		final String automationId = String.valueOf(System.currentTimeMillis()).concat("-")
+				.concat(String.valueOf(this.hashCode()));
+		final AutomationCompletionEvent automationCompletionEvent = new AutomationCompletionEvent(automationId);
+		final Object sendemailParam = params.get("sendemail");
+		if (sendemailParam != null && sendemailParam.toString().equalsIgnoreCase("true")) {
+			automationCompletionEvent.addNotificationEmailAddr(user.getEmail());
+		}
+		automationEvent.setAutomationCompletionEvent(automationCompletionEvent);
+		XftEventService eventService = XftEventService.getService();
+		if (eventService == null) {
+			returnList.add("ERROR: Could retrieve event service");
+			return;
+		}
+		eventService.triggerEvent(automationEvent);
+		final AutomationCompletionEventListener completionService = AutomationCompletionEventListener.getService();
+		List<ScriptOutput> scriptOutputs = null;
+		for (int i = 1; i < TIMEOUT_SECONDS; i++) {
+			try {
+				Thread.sleep(1000);
+				final AutomationCompletionEvent ace = completionService.getEvent(automationId);
+				if (ace != null) {
+					scriptOutputs = ace.getScriptOutputs();
+					break;
+				} else if (i == TIMEOUT_SECONDS) {
+					returnList.add("<br><b>TIMEOUT WAITING FOR SCRIPT TO RETURN.<b></br>");
+				}
+			} catch (InterruptedException e) {
+				// Do nothing for now.
+			}
+		}
+		if (scriptOutputs != null && scriptOutputs.size() > 0) {
+			for (ScriptOutput scriptOut : scriptOutputs) {
+				returnList.add("<br><b>SCRIPT EXECUTION RESULT</b>");
+				returnList.add("<br><b>FINAL STATUS:  " + scriptOut.getStatus() + "</b>");
+				StringWriter writer = new StringWriter();
+				if (scriptOut.getStatus().equals(Status.ERROR) && scriptOut.getResults() != null
+						&& scriptOut.getResults().toString().length() > 0) {
+					returnList.add("<br><b>SCRIPT RESULTS</b><br>");
+					try {
+						StringEscapeUtils.escapeHtml(writer, scriptOut.getResults().toString());
+						returnList.add(writer.toString().replace("\n", "<br>"));
+						writer.close();
+					} catch (IOException e) {
 						returnList.add(scriptOut.getResults().toString().replace("\n", "<br>"));
 					}
-					if (scriptOut.getOutput()!=null && scriptOut.getOutput().length()>0) {
-						returnList.add("<br><b>SCRIPT STDOUT</b>");
+				}
+				if (scriptOut.getOutput() != null && scriptOut.getOutput().length() > 0) {
+					returnList.add("<br><b>SCRIPT STDOUT</b><br>");
+					try {
+						StringEscapeUtils.escapeHtml(writer, scriptOut.getOutput());
+						returnList.add(writer.toString().replace("\n", "<br>"));
+						writer.close();
+					} catch (IOException e) {
 						returnList.add(scriptOut.getOutput().replace("\n", "<br>"));
 					}
-					if (scriptOut.getErrorOutput()!=null && scriptOut.getErrorOutput().length()>0) {
-						returnList.add("<br><b>SCRIPT STDERR/EXCEPTION</b>");
+				}
+				if (scriptOut.getErrorOutput() != null && scriptOut.getErrorOutput().length() > 0) {
+					returnList.add("<br><b>SCRIPT STDERR/EXCEPTION</b><br>");
+					try {
+						StringEscapeUtils.escapeHtml(writer, scriptOut.getErrorOutput());
+						returnList.add(writer.toString().replace("\n", "<br>"));
+						writer.close();
+					} catch (IOException e) {
 						returnList.add(scriptOut.getErrorOutput().replace("\n", "<br>"));
 					}
 				}
 			}
+			returnList.add("<br><b>FINISHED PROCESSING");
 		}
-		
-		returnList.add("<br><b>FINISHED PROCESSING");
-		
 	}
+	
 
- 	private PersistentWorkflowI buildWorkflow(XnatProjectdata proj,Map<String, Object> passMap,String eventText) {
+ 	private PersistentWorkflowI buildWorkflow(XnatProjectdata proj,XnatSubjectdata subj,XnatExperimentdata exp, Map<String, Object> passMap,String eventText) {
 		final PersistentWorkflowI wrk;
 		try {
 			returnList.add("Building workflow entry for configured resource / event handler - " + eventText);
-			wrk = PersistentWorkflowUtils.buildOpenWorkflow(user, params.get("xsiType").toString(), proj.getId(), proj.getId(),
+			wrk = PersistentWorkflowUtils.buildOpenWorkflow(user, params.get("xsiType").toString(),
+					(exp.getId()!=null) ? exp.getId() : (subj.getId()!=null) ? subj.getId() : proj.getId(), proj.getId(),
 			EventUtils.newEventInstance(CATEGORY.DATA, TYPE.WEB_SERVICE, eventText, "Automation-based upload", null));
 			wrk.setStatus(STATUS_COMPLETE);
 			//wrk.setDetails(JSONObject.fromObject(passMap).toString());
@@ -374,122 +729,54 @@ public class AutomationBasedImporter extends ImporterHandlerA implements Callabl
 		return null;
 	}
 
-    public ScriptOutput launchScript(WrkWorkflowdata wrk) {
-        if (StringUtils.equals(PersistentWorkflowUtils.COMPLETE, wrk.getStatus()) && !StringUtils.equals(wrk.getExternalid(), PersistentWorkflowUtils.ADMIN_EXTERNAL_ID)) {
-            //check to see if this has been handled before
-        	ScriptOutput scriptOut = null;
-            for (final Script script : getScripts(wrk.getExternalid(), wrk.getPipelineName())) {
-                try {
-                    //create a queued workflow to track this script
-                    final String action = "Executed script " + script.getScriptId();
-                    final String justification = wrk.getJustification();
-                    final String comment = "Executed script " + script.getScriptId() + " triggered by event " + wrk.getPipelineName();
-                    final PersistentWorkflowI scriptWrk = PersistentWorkflowUtils.buildOpenWorkflow(wrk.getUser(), wrk.getDataType(), wrk.getId(), wrk.getExternalid(),
-                    		EventUtils.newEventInstance(EventUtils.CATEGORY.DATA, EventUtils.TYPE.PROCESS, action, StringUtils.isNotBlank(justification) ? justification : "Automated execution: " + comment, comment));
-                    assert scriptWrk != null;
-                    scriptWrk.setStatus(PersistentWorkflowUtils.QUEUED);
-                    WorkflowUtils.save(scriptWrk, scriptWrk.buildEvent());
-                    final AutomatedScriptRequest request = new AutomatedScriptRequest(wrk.getWrkWorkflowdataId().toString(), wrk.getUser(), script.getScriptId(), 
-                    		wrk.getPipelineName(), scriptWrk.getWorkflowId().toString(), wrk.getDataType(), wrk.getId(), wrk.getExternalid());
-                    scriptOut = executeScriptRequest(request);
-                    return scriptOut;	
-                } catch (Exception e1) {
-                	if (scriptOut == null) {
-                		scriptOut = new ScriptOutput();
-                	}
-                	scriptOut.setErrorOutput((scriptOut.getErrorOutput()!=null) ? scriptOut.getErrorOutput() +
-                			ExceptionUtils.getStackTrace(e1) : ExceptionUtils.getStackTrace(e1));
-                	scriptOut.setOutput((scriptOut.getOutput()!=null) ? scriptOut.getOutput() : "");
-                    logger.error("", e1);
-                    return scriptOut;
-                }
-            }
-        }
-		return null;
-    }
-
-    private ScriptOutput executeScriptRequest(AutomatedScriptRequest request) throws Exception {
-    	
-        final PersistentWorkflowI workflow = WorkflowUtils.getUniqueWorkflow(request.getUser(), request.getScriptWorkflowId());
-        workflow.setStatus(PersistentWorkflowUtils.IN_PROGRESS);
-        WorkflowUtils.save(workflow, workflow.buildEvent());
-
-        final Map<String, Object> parameters = new HashMap<>();
-        parameters.put("user", request.getUser());
-        parameters.put("scriptId", request.getScriptId());
-        parameters.put("event", request.getEvent());
-        parameters.put("srcWorkflowId", request.getSrcWorkflowId());
-        parameters.put("scriptWorkflowId", request.getScriptWorkflowId());
-        parameters.put("dataType", request.getDataType());
-        parameters.put("dataId", request.getDataId());
-        parameters.put("externalId", request.getExternalId());
-        parameters.put("workflow", workflow);
-
-        ScriptOutput scriptOut = null;
-        try {
-            scriptOut = _service.runScript(_service.getScript(request.getScriptId()), null, parameters, false);
-            if (PersistentWorkflowUtils.IN_PROGRESS.equals(workflow.getStatus())) {
-                WorkflowUtils.complete(workflow, workflow.buildEvent());
-            }
-        } catch (NrgServiceException e) {
-            final String message = String.format("Failed running the script %s by user %s for event %s on data type %s instance %s from project %s",
-                    request.getScriptId(),
-                    request.getUser().getLogin(),
-                    request.getEvent(),
-                    request.getDataType(),
-                    request.getDataId(),
-                    request.getExternalId());
-            AdminUtils.sendAdminEmail("Script execution failure", message);
-            logger.error(message, e);
-            if (PersistentWorkflowUtils.IN_PROGRESS.equals(workflow.getStatus())) {
-                WorkflowUtils.fail(workflow, workflow.buildEvent());
-            }
-        }
-        return scriptOut;
-        
-	}
 
-	private List<Script> getScripts(final String projectId, final String event) {
-        final List<Script> scripts = Lists.newArrayList();
-
-        //project level scripts
-        if (StringUtils.isNotBlank(projectId)) {
-            final Script script = _service.getScript(Scope.Project, projectId, event);
-            if (script != null) {
-                scripts.add(script);
-            }
-        }
-
-        //site level scripts
-        final Script script = _service.getScript(Scope.Site, null, event);
-        if (script != null) {
-            scripts.add(script);
-        }
-
-        return scripts;
-    }
- 	
-
-	// TODO:  Configured Resource configuration should be updated to store EVENT, rather than using this "Uploaded {label}" event. 
-	private String getEventTextFromConfiguredResourceConfig(XnatProjectdata proj, XnatSubjectdata subj, XnatExperimentdata exp, String configuredResource) {
-		final Scope scope = (exp!=null) ? Scope.Experiment : (subj!=null) ? Scope.Subject : Scope.Project; 
-		final String crConfig = XDAT.getConfigService().getConfigContents(CONFIG_TOOL,CONFIG_SCRIPT_PATH,scope,proj.getId());
-		if (crConfig!=null && crConfig.length()>0) {
+
+	/**
+	 * Gets the event text from configured resource config.
+	 *
+	 * @param proj
+	 *            the proj
+	 * @param subj
+	 *            the subj
+	 * @param exp
+	 *            the exp
+	 * @param configuredResource
+	 *            the configured resource
+	 * @return the event text from configured resource config
+	 */
+	// TODO: Configured Resource configuration should be updated to store EVENT,
+	// rather than using this "Uploaded {label}" event.
+	private String getEventTextFromConfiguredResourceConfig(XnatProjectdata proj, XnatSubjectdata subj,
+			XnatExperimentdata exp, String configuredResource) {
+		// Do we need to handle scope differently?  I don't think site configured uploads will pass through this method.
+		// It's really only for configured resources, which should always be scoped at the project level, I think.
+		final Scope scope = (exp != null) ? Scope.Project : (subj != null) ? Scope.Project : (proj != null ) ? Scope.Project : Scope.Site;
+		final String crConfig = XDAT.getConfigService().getConfigContents(CONFIG_TOOL, CONFIG_SCRIPT_PATH, scope,
+				proj.getId());
+		if (crConfig != null && crConfig.length() > 0) {
 			try {
 				final JSONArray jsonArray = new JSONArray(new JSONTokener(crConfig));
-				for (int i=0;i<jsonArray.length();i++) {
+				for (int i = 0; i < jsonArray.length(); i++) {
 					final JSONObject jsonObj = jsonArray.getJSONObject(i);
 					if (jsonObj.getString("name").equals(configuredResource)) {
 						return "Uploaded " + jsonObj.getString("label");
 					}
 				}
 			} catch (JSONException e) {
-				logger.warn("WARNING:  Could not parse resource_config json results (PROJECT=" + proj.getId() + ",CONFIG_TOOL=" + CONFIG_TOOL + ",CONFIG_PATH=" + CONFIG_SCRIPT_PATH);
+				logger.warn("WARNING:  Could not parse resource_config json results (PROJECT=" + proj.getId()
+						+ ",CONFIG_TOOL=" + CONFIG_TOOL + ",CONFIG_PATH=" + CONFIG_SCRIPT_PATH);
 			}
 		}
 		return null;
 	}
 
+	/**
+	 * Checks if is zip file name.
+	 *
+	 * @param fileName
+	 *            the file name
+	 * @return true, if is zip file name
+	 */
 	private boolean isZipFileName(final String fileName) {
 		for (final String ext : ZIP_EXT) {
 			if (fileName.toLowerCase().endsWith(ext)) {
@@ -499,11 +786,18 @@ public class AutomationBasedImporter extends ImporterHandlerA implements Callabl
 		return false;
 	}
 
+	/**
+	 * Gets the zipper.
+	 *
+	 * @param fileName
+	 *            the file name
+	 * @return the zipper
+	 */
 	private ZipI getZipper(final String fileName) {
-		
+
 		// Assume file name represents correct compression method
 		String file_extension = null;
-		if (fileName!=null && fileName.indexOf(".")!=-1) {
+		if (fileName != null && fileName.indexOf(".") != -1) {
 			file_extension = fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
 			if (Arrays.asList(ZIP_EXT).contains(file_extension)) {
 				return new ZipUtils();
@@ -517,8 +811,7 @@ public class AutomationBasedImporter extends ImporterHandlerA implements Callabl
 		}
 		// Assume zip-compression for unnamed inbody files
 		return new ZipUtils();
-		
+
 	}
 
 }
-
diff --git a/src/main/java/org/nrg/xnat/restlet/resources/EventResource.java b/src/main/java/org/nrg/xnat/restlet/resources/EventResource.java
deleted file mode 100644
index 3c1fa83987e032ca02f7b93c0efe706ee39c3c48..0000000000000000000000000000000000000000
--- a/src/main/java/org/nrg/xnat/restlet/resources/EventResource.java
+++ /dev/null
@@ -1,296 +0,0 @@
-package org.nrg.xnat.restlet.resources;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.utils.URLEncodedUtils;
-import org.hibernate.HibernateException;
-import org.nrg.action.ClientException;
-import org.nrg.action.ServerException;
-import org.nrg.automation.entities.Event;
-import org.nrg.automation.entities.ScriptTrigger;
-import org.nrg.automation.services.EventService;
-import org.nrg.automation.services.ScriptTriggerService;
-import org.nrg.xdat.security.helpers.Roles;
-import org.nrg.xdat.XDAT;
-import org.nrg.xft.XFTTable;
-import org.nrg.xft.exception.DBPoolException;
-import org.restlet.Context;
-import org.restlet.data.*;
-import org.restlet.resource.Representation;
-import org.restlet.resource.ResourceException;
-import org.restlet.resource.StringRepresentation;
-import org.restlet.resource.Variant;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.nio.charset.Charset;
-import java.sql.SQLException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-public class EventResource extends AutomationResource {
-
-    private static final String PROPERTY_EVENT_ID    = "event_id";
-    private static final String PROPERTY_EVENT_LABEL = "event_label";
-
-    public EventResource(Context context, Request request, Response response) throws ResourceException {
-        super(context, request, response);
-
-        getVariants().add(new Variant(MediaType.APPLICATION_JSON));
-        getVariants().add(new Variant(MediaType.TEXT_HTML));
-        getVariants().add(new Variant(MediaType.TEXT_XML));
-        getVariants().add(new Variant(MediaType.TEXT_PLAIN));
-
-        _service = XDAT.getContextService().getBean(EventService.class);
-        _scriptTriggerService = XDAT.getContextService().getBean(ScriptTriggerService.class);
-        _cascade = isQueryVariableTrue("cascade");
-
-        final String eventId;
-        try {
-            if (getRequest().getAttributes().containsKey(EVENT_ID)) {
-                eventId = URLDecoder.decode((String) getRequest().getAttributes().get(EVENT_ID), "UTF-8");
-            } else {
-                eventId = null;
-            }
-        } catch (UnsupportedEncodingException exception) {
-            // This is the stupidest exception ever. From the docs:
-            //
-            // The supplied encoding is used to determine what characters are represented by any consecutive sequences
-            // of the form "%xy". Note: The World Wide Web Consortium Recommendation states that UTF-8 should be used.
-            // Not doing so may introduce incompatibilities.
-            //
-            // So in other words you have to specify an encoding then handle the exception if you specify an unsupported
-            // encoding, except that the only encoding you should use is "UTF-8" and you should specify that every time.
-            throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "Something stupid happened. Sorry about that.", exception);
-        }
-
-        getParameters();
-
-        if (!_properties.containsKey(PROPERTY_EVENT_ID) && StringUtils.isNotBlank(eventId)) {
-            _properties.setProperty(PROPERTY_EVENT_ID, eventId);
-        }
-
-        final Method method = request.getMethod();
-        if (method.equals(Method.PUT) || method.equals(Method.DELETE)) {
-            if (!Roles.isSiteAdmin(user)) {
-                getResponse().setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Only site administrators can create, update, or delete an event.");
-            }
-            if (!_properties.containsKey(PROPERTY_EVENT_ID)) {
-                getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "You must specify the event ID parameter on the REST URI when creating, updating, or deleting an event.");
-            }
-            if (method == Method.PUT && !_properties.containsKey(PROPERTY_EVENT_LABEL)) {
-                getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "Unable to find event label: no data sent?");
-            }
-            if (StringUtils.isNotBlank(eventId) && !StringUtils.equals(_properties.getProperty(PROPERTY_EVENT_ID), eventId)) {
-                getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "The event ID found in the form data or querystring parameters doesn't match the REST URI. Event IDs are immutable and can not be changed.");
-            }
-        }
-
-        final Status status = getResponse().getStatus();
-        if (status.getCode() < Status.CLIENT_ERROR_BAD_REQUEST.getCode()) {
-            _log.info("Got status " + status + ", won't process further: " + status.getDescription());
-        } else if (_log.isDebugEnabled()) {
-            if (StringUtils.isNotBlank(getResourceId())) {
-                _log.debug("Servicing event request for event ID " + getResourceId() + " for user " + user.getLogin());
-            } else {
-                _log.debug("Retrieving available events for user " + user.getLogin());
-            }
-        }
-    }
-
-    @Override
-    public boolean allowPut() {
-        return true;
-    }
-
-    @Override
-    public boolean allowDelete() {
-        return true;
-    }
-
-    @Override
-    protected String getResourceType() {
-        return "Event";
-    }
-
-    @Override
-    protected String getResourceId() {
-        if (_properties.containsKey(PROPERTY_EVENT_ID)) {
-            return _properties.getProperty(PROPERTY_EVENT_ID);
-        }
-        return null;
-    }
-
-    @Override
-    public Representation represent(Variant variant) throws ResourceException {
-        final MediaType mediaType = overrideVariant(variant);
-
-        try {
-            if (StringUtils.isNotBlank(getResourceId())) {
-                // They're requesting a specific event, so return that to them.
-                final XFTTable table = getEventsTable();
-                final Map<Object, Object> eventMap = table.convertToHashtable(PROPERTY_EVENT_ID, PROPERTY_EVENT_LABEL);
-                if (!eventMap.containsKey(getResourceId())) {
-                    throw new ResourceException(Status.CLIENT_ERROR_NOT_FOUND, "No event of ID " + getResourceId() + " was found.");
-                } else {
-                    final String label = (String) eventMap.get(getResourceId());
-                    final Map<String, String> event = new HashMap<>();
-                    event.put(PROPERTY_EVENT_ID, getResourceId());
-                    event.put(PROPERTY_EVENT_LABEL, label);
-                    return new StringRepresentation(getSerializer().toJson(event), mediaType);
-                }
-            } else {
-                // They're asking for list of existing script events, so give them that.
-                final XFTTable table = getEventsTable();
-                return representTable(table, mediaType, null);
-            }
-        } catch (IOException e) {
-            throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "An error occurred marshalling the event data to JSON", e);
-        } catch (SQLException | DBPoolException e) {
-            throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "An error occurred accessing the database.", e);
-        }
-    }
-
-    @Override
-    public void handlePut() {
-        try {
-            if (_log.isDebugEnabled()) {
-                _log.debug("Preparing to PUT event: " + getResourceId());
-            }
-            putEvent();
-        } catch (ClientException e) {
-            _log.error("Client error occurred trying to store an event: " + getResourceId(), e);
-            getResponse().setStatus(e.getStatus(), e.getMessage());
-        } catch (ServerException e) {
-            _log.error("Server error occurred trying to store an event: " + getResourceId(), e);
-            getResponse().setStatus(e.getStatus(), e.getMessage());
-        }
-    }
-
-    @Override
-    public void handleDelete() {
-        try {
-            if (_log.isDebugEnabled()) {
-                _log.debug("Preparing to DELETE event: " + getResourceId());
-            }
-            deleteEvent();
-        } catch (ClientException e) {
-            _log.error("Client error occurred trying to delete an event: " + getResourceId(), e);
-            getResponse().setStatus(e.getStatus(), e.getMessage());
-        } catch (ServerException e) {
-            _log.error("Server error occurred trying to delete an event: " + getResourceId(), e);
-            getResponse().setStatus(e.getStatus(), e.getMessage());
-        }
-    }
-
-    private void getParameters() throws ResourceException {
-        final Map<String, String> queryParameters = getQueryVariableMap();
-        if (queryParameters.size() > 0) {
-            _properties.putAll(queryParameters);
-        }
-        final Method method = getRequest().getMethod();
-        if (method != Method.GET) {
-            final Representation entity = getRequest().getEntity();
-            if (entity.getSize() > 0) {
-                final MediaType mediaType = entity.getMediaType();
-                if (!mediaType.equals(MediaType.APPLICATION_WWW_FORM) && !mediaType.equals(MediaType.APPLICATION_JSON)) {
-                    throw new ResourceException(Status.CLIENT_ERROR_UNSUPPORTED_MEDIA_TYPE, "This function currently only supports " + MediaType.APPLICATION_WWW_FORM + " and " + MediaType.APPLICATION_JSON);
-                }
-                if (mediaType.equals(MediaType.APPLICATION_WWW_FORM)) {
-                    try {
-                        final List<NameValuePair> formMap = URLEncodedUtils.parse(entity.getText(), DEFAULT_CHARSET);
-                        for (final NameValuePair entry : formMap) {
-                            _properties.setProperty(entry.getName(), entry.getValue());
-                        }
-                    } catch (IOException e) {
-                        throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "An error occurred trying to read the submitted form body.", e);
-                    }
-                } else {
-                    try {
-                        final String text = entity.getText();
-                        _properties.putAll(getSerializer().deserializeJson(text, Properties.class));
-                    } catch (IOException e) {
-                        throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "An error occurred processing the script properties", e);
-                    }
-                }
-            }
-        }
-    }
-
-    private void putEvent() throws ClientException, ServerException {
-        final String eventId = _properties.getProperty(PROPERTY_EVENT_ID);
-        final String eventLabel = _properties.getProperty(PROPERTY_EVENT_LABEL);
-
-        final Event event;
-        final boolean created;
-        if (_service.hasEvent(eventId)) {
-            event = _service.getByEventId(eventId);
-            boolean isDirty = false;
-            if (!StringUtils.equals(eventLabel, event.getEventLabel())) {
-                isDirty = true;
-                event.setEventLabel(eventLabel);
-            }
-            if (isDirty) {
-                _service.update(event);
-            }
-            created = false;
-        } else {
-            event = _service.create(getResourceId(), eventLabel);
-            created = true;
-        }
-
-        recordAutomationEvent(event.getEventId(), SITE_SCOPE, created ? "Create" : "Update", Event.class);
-    }
-
-    private void deleteEvent() throws ClientException, ServerException {
-        final String eventId = getResourceId();
-        if (!_service.hasEvent(eventId)) {
-            throw new ClientException(Status.CLIENT_ERROR_NOT_FOUND, "Couldn't find an event with the event ID " + eventId);
-        }
-
-        final List<ScriptTrigger> triggers = _scriptTriggerService.getByEvent(eventId);
-        if (triggers != null && triggers.size() > 0) {
-            if (!_cascade) {
-                throw new ClientException(Status.CLIENT_ERROR_FORBIDDEN, "There are " + triggers.size() + " event handlers that reference the indicated event ID " + eventId + ". Please delete these triggers directly or call this method with the \"cascade=true\" query parameter: " + getRequest().getResourceRef().toString() + "?cascade=true");
-            }
-            for (final ScriptTrigger trigger : triggers) {
-                _log.info("Deleting script trigger: " + trigger.getTriggerId());
-                _scriptTriggerService.delete(trigger);
-            }
-        }
-        try {
-            _service.delete(_service.getByEventId(eventId));
-            recordAutomationEvent(eventId, SITE_SCOPE, "Delete", Event.class);
-        } catch (HibernateException e) {
-            throw new ServerException(Status.SERVER_ERROR_INTERNAL, "An error occurred trying to delete the event " + eventId);
-        }
-    }
-
-    private XFTTable getEventsTable() throws SQLException, DBPoolException {
-        final EventService eventService = XDAT.getContextService().getBean(EventService.class);
-        final List<Event> events = eventService.getAll();
-        final XFTTable table = new XFTTable();
-        table.initTable(new String[] { PROPERTY_EVENT_LABEL, PROPERTY_EVENT_ID });
-
-        for (final Event event : events) {
-            table.insertRow(new String[] { event.getEventLabel(), event.getEventId() });
-        }
-
-        table.sort(PROPERTY_EVENT_LABEL, "ASC");
-        return table;
-    }
-
-    private static final Logger _log = LoggerFactory.getLogger(EventResource.class);
-    private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
-    private static final String EVENT_ID = "EVENT_ID";
-
-    private final EventService _service;
-    private final ScriptTriggerService _scriptTriggerService;
-    private final Properties _properties = new Properties();
-    private final boolean _cascade;
-}
diff --git a/src/main/java/org/nrg/xnat/restlet/resources/ScriptTriggerResource.java b/src/main/java/org/nrg/xnat/restlet/resources/ScriptTriggerResource.java
index efb570006e92de8cb8b34b3377472683f9ab721c..0b8330d3595a63e3263031b99cb4169f928293e4 100644
--- a/src/main/java/org/nrg/xnat/restlet/resources/ScriptTriggerResource.java
+++ b/src/main/java/org/nrg/xnat/restlet/resources/ScriptTriggerResource.java
@@ -3,13 +3,14 @@ package org.nrg.xnat.restlet.resources;
 import org.apache.commons.lang3.StringUtils;
 import org.nrg.action.ClientException;
 import org.nrg.action.ServerException;
+import org.nrg.automation.entities.EventFilters;
 import org.nrg.automation.entities.ScriptTrigger;
-import org.nrg.automation.services.EventService;
 import org.nrg.automation.services.ScriptTriggerService;
 import org.nrg.framework.constants.Scope;
 import org.nrg.xdat.XDAT;
 import org.nrg.xdat.security.helpers.Roles;
 import org.nrg.xft.XFTTable;
+import org.python.google.common.collect.Sets;
 import org.restlet.Context;
 import org.restlet.data.*;
 import org.restlet.resource.Representation;
@@ -19,6 +20,9 @@ import org.restlet.resource.Variant;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
 import java.io.IOException;
 import java.util.*;
 
@@ -32,22 +36,23 @@ public class ScriptTriggerResource extends AutomationResource {
         getVariants().add(new Variant(MediaType.TEXT_XML));
         getVariants().add(new Variant(MediaType.TEXT_PLAIN));
 
-        _eventService = XDAT.getContextService().getBean(EventService.class);
         _scriptTriggerService = XDAT.getContextService().getBean(ScriptTriggerService.class);
 
         _eventId = (String) getRequest().getAttributes().get(EVENT_ID);
         final String triggerId = (String) getRequest().getAttributes().get(TRIGGER_ID);
+        final String Id = (String) getRequest().getAttributes().get(ID);
 
         final boolean hasEvent = StringUtils.isNotBlank(_eventId);
         final boolean hasTriggerId = StringUtils.isNotBlank(triggerId);
+        final boolean hasId = StringUtils.isNotBlank(Id);
 
         final String projectId;
-        if (!hasTriggerId && !hasEvent) {
+        if (!hasTriggerId && !hasEvent && !hasId) {
             projectId = getProjectId();
             _trigger = null;
         } else {
-            if (hasTriggerId) {
-                _trigger = _scriptTriggerService.getByTriggerId(triggerId);
+            if (hasId || hasTriggerId) {
+            	_trigger = (hasId) ? _scriptTriggerService.getById(Id) : _scriptTriggerService.getByTriggerId(triggerId);
                 if (_trigger == null) {
                     throw new ResourceException(Status.CLIENT_ERROR_NOT_FOUND, "Can't find script trigger with ID: " + triggerId);
                 }
@@ -59,10 +64,14 @@ public class ScriptTriggerResource extends AutomationResource {
                 }
             } else if (hasProjectId()) {
                 projectId = getProjectId();
-                _trigger = _scriptTriggerService.getByAssociationAndEvent(Scope.encode(Scope.Project, projectId), _eventId);
+                _trigger = null;
+                // TODO: For these to make sense now, we need to pass at minimum an event class, but really we would need filters    
+                //_trigger = _scriptTriggerService.getByAssociationAndEvent(Scope.encode(Scope.Project, projectId), _eventId);
             } else {
                 projectId = null;
-                _trigger = _scriptTriggerService.getByAssociationAndEvent(Scope.Site.code(), _eventId);
+                _trigger = null;
+                // TODO: For these to make sense now, we need to pass at minimum an event class, but really we would need filters    
+                //_trigger = _scriptTriggerService.getByAssociationAndEvent(Scope.Site.code(), _eventId);
             }
         }
 
@@ -101,7 +110,7 @@ public class ScriptTriggerResource extends AutomationResource {
 
     @Override
     protected String getResourceId() {
-        return _trigger == null ? null : _trigger.getEvent().getEventId();
+        return _trigger == null ? null : _trigger.getEvent();
     }
 
     @Override
@@ -158,10 +167,11 @@ public class ScriptTriggerResource extends AutomationResource {
         final Map<String, String> association = Scope.decode(trigger.getAssociation());
 
         final Map<String, String> properties = new HashMap<>();
+        properties.put("id", String.valueOf(trigger.getId()));
         properties.put("triggerId", trigger.getTriggerId());
         properties.put("scope", association.get("scope"));
         properties.put("entityId", association.get("entityId"));
-        properties.put("event", trigger.getEvent().getEventId());
+        properties.put("event", trigger.getEvent());
         properties.put("scriptId", trigger.getScriptId());
         properties.put("description", trigger.getDescription());
 
@@ -192,10 +202,13 @@ public class ScriptTriggerResource extends AutomationResource {
         }
 
         ArrayList<String> columns = new ArrayList<>();
+        columns.add("id");
         columns.add("triggerId");
         columns.add("scope");
         columns.add("entityId");
+        columns.add("srcEventClass");
         columns.add("event");
+        columns.add("eventFilters");
         columns.add("scriptId");
         columns.add("description");
 
@@ -215,10 +228,14 @@ public class ScriptTriggerResource extends AutomationResource {
             final Map<String, String> atoms = Scope.decode(trigger.getAssociation());
             final String scope = atoms.get("scope");
             final String entityId = scope.equals(Scope.Site.code()) ? "" : atoms.get("entityId");
-            table.insertRowItems(trigger.getTriggerId(),
+            table.insertRowItems(
+            		String.valueOf(trigger.getId()),
+            		trigger.getTriggerId(),
                     scope,
                     entityId,
-                    trigger.getEvent().getEventId(),
+                    trigger.getSrcEventClass(),
+                    trigger.getEvent(),
+            		trigger.getEventFiltersAsMap(),
                     trigger.getScriptId(),
                     trigger.getDescription());
         }
@@ -238,62 +255,90 @@ public class ScriptTriggerResource extends AutomationResource {
         }
 
         MediaType mediaType = entity.getMediaType();
-        if (!mediaType.equals(MediaType.APPLICATION_WWW_FORM) && !mediaType.equals(MediaType.APPLICATION_JSON)) {
-            throw new ClientException(Status.CLIENT_ERROR_UNSUPPORTED_MEDIA_TYPE, "This function currently only supports " + MediaType.APPLICATION_WWW_FORM + " and " + MediaType.APPLICATION_JSON);
+        if (!mediaType.equals(MediaType.APPLICATION_JSON)) {
+            throw new ClientException(Status.CLIENT_ERROR_UNSUPPORTED_MEDIA_TYPE, "This function currently only supports " + MediaType.APPLICATION_JSON);
+        }
+                
+        //final Properties properties;
+        JsonResults jsonResults;
+        try {
+            final String text = entity.getText();
+            final String jsonString = text;
+            final GsonBuilder builder = new GsonBuilder(); 
+            final Gson gson = builder.create();
+            jsonResults = gson.fromJson(jsonString,JsonResults.class);
+        } catch (IOException e) {
+            throw new ServerException(Status.SERVER_ERROR_INTERNAL, "An error occurred processing the script properties", e);
         }
-
-        final Properties properties = decodeProperties(entity, mediaType);
 
         // TODO: These remove definitions of scope, entity ID, and script ID that may be passed in on the API call.
         // TODO: We may consider throwing an exception if something in the body parameters contradicts the URI
         // TODO: parameters. For example, if the URL indicates site scope, but the body parameters specify project and
         // TODO: ID, it may be worth throwing an exception and indicating that you should only specify that stuff in the
         // TODO: URL. For now, though, we'll just ignore the payload parameters for simplicity.
+        /*
+        final String scope;
+        final String entityId;
         if (getScope() == Scope.Project) {
-            properties.setProperty("scope", Scope.Project.code());
-            properties.setProperty("entityId", getProjectId());
+            scope = Scope.Project.code();
+            entityId = getProjectId();
         } else {
-            properties.setProperty("scope", Scope.Site.code());
-            properties.remove("entityId");
+            scope = Scope.Site.code();
+            entityId = null;
         }
+        */
 
         if (_trigger == null) {
-            if (!properties.containsKey("event")) {
+        	if (jsonResults.getEvent() == null || jsonResults.getEvent().length()<1) {
                 throw new ClientException(Status.CLIENT_ERROR_BAD_REQUEST, "You must specify the event for your new script trigger.");
             }
-            if (!properties.containsKey("scriptId")) {
+        	if (jsonResults.getScriptId() == null || jsonResults.getScriptId().length()<1) {
                 throw new ClientException(Status.CLIENT_ERROR_BAD_REQUEST, "You must specify the script ID for your new script trigger.");
             }
             if (_log.isDebugEnabled()) {
                 _log.debug("Creating new script trigger");
             }
-            final String scriptId = properties.getProperty("scriptId");
-            final String event = properties.getProperty("event");
-            final String triggerId = properties.getProperty("triggerId", _scriptTriggerService.getDefaultTriggerName(scriptId, getScope(), getProjectId(), event));
-            final String description = properties.getProperty("description", null);
-            final ScriptTrigger trigger = _scriptTriggerService.newEntity(triggerId, description, scriptId, getAssociation(), event);
+            final String scriptId = jsonResults.getScriptId();
+            final String event = jsonResults.getEvent();
+            final String description = jsonResults.getDescription();
+            final String eventClass = jsonResults.getEventClass();
+            final Map<String,List<String>> eventFilters = jsonResults.getFilters();
+            final String triggerId = _scriptTriggerService.getDefaultTriggerName(scriptId, getScope(), getProjectId(), eventClass, event, eventFilters);
+            final ScriptTrigger trigger = _scriptTriggerService.newEntity(triggerId, description, scriptId, getAssociation(), eventClass, event, eventFilters);
             if (_log.isInfoEnabled()) {
                 _log.info("Created a new trigger: " + trigger.toString());
             }
             recordAutomationEvent(triggerId, getAssociation(), "Create", ScriptTrigger.class);
+            // Return thie trigger ID in the response test.  The upload UI needs it
+            this.getResponse().setEntity(new StringRepresentation(triggerId));
         } else {
-            final String scriptId = properties.getProperty("scriptId");
-            final String event = properties.getProperty("event");
-            final String triggerId = properties.getProperty("triggerId");
-            final String description = properties.getProperty("description", null);
+            final String scriptId = jsonResults.getScriptId();
+            final String event = jsonResults.getEvent();
+            final String description = jsonResults.getDescription();
+            final String eventClass = jsonResults.getEventClass();
+            final Map<String,List<String>> eventFilters = jsonResults.getFilters();
+            final String triggerId = _scriptTriggerService.getDefaultTriggerName(scriptId, getScope(), getProjectId(), eventClass, event, eventFilters);
             boolean isDirty = false;
             if (StringUtils.isNotBlank(scriptId) && !scriptId.equals(_trigger.getScriptId())) {
                 _trigger.setScriptId(scriptId);
                 isDirty = true;
             }
-            if (StringUtils.isNotBlank(event) && !event.equals(_trigger.getEvent().getEventId())) {
-                _trigger.setEvent(_eventService.getByEventId(event));
+            if (StringUtils.isNotBlank(event) && !event.equals(_trigger.getEvent())) {
+                _trigger.setEvent(event);
                 isDirty = true;
             }
             if (StringUtils.isNotBlank(triggerId) && !triggerId.equals(_trigger.getTriggerId())) {
                 _trigger.setTriggerId(triggerId);
                 isDirty = true;
             }
+            if (StringUtils.isNotBlank(eventClass) && !eventClass.equals(_trigger.getSrcEventClass())) {
+                _trigger.setSrcEventClass(eventClass);
+                isDirty = true;
+            }
+            if (eventFilters != null && !eventFilters.equals(_trigger.getEventFiltersAsMap())) {
+                _trigger.setEventFiltersAsMap(eventFilters);
+                isDirty = true;
+            }
             // Description is a little different because you could specify an empty description.
             if (description != null && !description.equals(_trigger.getDescription())) {
                 _trigger.setDescription(description);
@@ -306,11 +351,23 @@ public class ScriptTriggerResource extends AutomationResource {
             if (isDirty) {
                 _scriptTriggerService.update(_trigger);
                 recordAutomationEvent(triggerId, getAssociation(), "Update", ScriptTrigger.class);
+                // Return thie trigger ID in the response test.  The upload UI needs it
+                this.getResponse().setEntity(new StringRepresentation(triggerId));
             }
         }
     }
 
-    private String formatScopeEntityIdAndEvent() {
+    @SuppressWarnings("unused")
+	private Set<EventFilters> getEventFilters(Map<String, List<String>> filters) {
+    	final Set<EventFilters> eventSet = Sets.newHashSet();
+    	for (final String filterKey : filters.keySet()) {
+    		EventFilters ef = new EventFilters(filterKey,filters.get(filterKey));
+    		eventSet.add(ef);
+    	}
+    	return eventSet;
+	}
+
+	private String formatScopeEntityIdAndEvent() {
         final StringBuilder buffer = new StringBuilder();
         if (_trigger != null) {
             final Map<String, String> atoms = Scope.decode(_trigger.getAssociation());
@@ -320,7 +377,7 @@ public class ScriptTriggerResource extends AutomationResource {
                 buffer.append("project ").append(atoms.get("entityId"));
             }
             if (_trigger.getEvent() != null) {
-                buffer.append(" and event ").append(_trigger.getEvent().getEventId());
+                buffer.append(" and event ").append(_trigger.getEvent());
             } else {
                 buffer.append(", no event");
             }
@@ -337,14 +394,64 @@ public class ScriptTriggerResource extends AutomationResource {
             }
         }
         return buffer.toString();
+    }
+    
+	@SuppressWarnings("unused")
+    private class JsonResults {
+    	private String event;
+		private String eventClass;
+		private String scriptId;
+		private String description;
+    	private Map<String,List<String>> filters;
+    	
+    	public String getEvent() {
+			return event;
+		}
+    	
+		public void setEvent(String event) {
+			this.event = event;
+		}
+		
+    	public String getEventClass() {
+			return eventClass;
+		}
+    	
+		public void setEventClass(String eventClass) {
+			this.eventClass = eventClass;
+		}
+		
+		public String getScriptId() {
+			return scriptId;
+		}
+		
+		public void setScriptId(String scriptId) {
+			this.scriptId = scriptId;
+		}
+		
+    	public String getDescription() {
+			return description;
+		}
+    	
+		public void setDescription(String description) {
+			this.description = description;
+		}
+		
+		public Map<String, List<String>> getFilters() {
+			return filters;
+		}
+		
+		public void setFilters(Map<String, List<String>> filters) {
+			this.filters = filters;
+		}
+    	
     }
 
     private static final Logger _log = LoggerFactory.getLogger(ScriptTriggerResource.class);
 
     private static final String EVENT_ID = "EVENT_ID";
     private static final String TRIGGER_ID = "TRIGGER_ID";
+    private static final String ID = "ID";
 
-    private final EventService _eventService;
     private final ScriptTriggerService _scriptTriggerService;
 
     private final String _eventId;
diff --git a/src/main/java/org/nrg/xnat/services/messaging/automation/AutomatedScriptRequest.java b/src/main/java/org/nrg/xnat/services/messaging/automation/AutomatedScriptRequest.java
index 14b13b054b5454b18249206c25826add10c05056..3937cfadfe8d3af9a7b2e68fcc1b8c2f8371ee41 100644
--- a/src/main/java/org/nrg/xnat/services/messaging/automation/AutomatedScriptRequest.java
+++ b/src/main/java/org/nrg/xnat/services/messaging/automation/AutomatedScriptRequest.java
@@ -1,13 +1,19 @@
 package org.nrg.xnat.services.messaging.automation;
 
+import org.json.JSONObject;
 import org.nrg.xft.security.UserI;
 
+import com.google.common.collect.Maps;
+
 import java.io.Serializable;
+import java.util.Map;
 
 public class AutomatedScriptRequest implements Serializable {
-	private static final long serialVersionUID = 6828367474920729056L;
 	
-	private final String _srcWorkflowId;
+	private static final long serialVersionUID = -5425712284737600869L;
+	
+	private final String _srcEventId;
+	private final String _srcEventClass;
 	private final UserI  _user;
 	private final String _scriptId;
 	private final String _event;
@@ -15,9 +21,11 @@ public class AutomatedScriptRequest implements Serializable {
 	private final String _externalId;
 	private final String _dataType;
 	private final String _dataId;
+	private final Map<String,Object> _argumentMap = Maps.newHashMap();
 	
-	public AutomatedScriptRequest(final String srcWorkflowId, final UserI user, final String scriptId, final String event, final String scriptWorkflow, final String dataType, final String dataId, final String externalId) {
-		_srcWorkflowId = srcWorkflowId;
+	public AutomatedScriptRequest(final String srcEventId, final String srcEventClass, final UserI user, final String scriptId, final String event, final String scriptWorkflow, final String dataType, final String dataId, final String externalId) {
+		_srcEventId = srcEventId;
+		_srcEventClass = srcEventClass;
 		_user = user;
 		_scriptId = scriptId;
 		_event = event;
@@ -26,9 +34,18 @@ public class AutomatedScriptRequest implements Serializable {
 		_dataId = dataId;
 		_externalId = externalId;
 	}
+	
+	public AutomatedScriptRequest(final String srcEventId, final String srcEventClass, final UserI user, final String scriptId, final String event, final String scriptWorkflow, final String dataType, final String dataId, final String externalId, Map<String,Object> argumentMap) {
+		this(srcEventId, srcEventClass, user, scriptId, event, scriptWorkflow, dataType, dataId, externalId);
+		_argumentMap.putAll(argumentMap);
+	}	
 
-	public String getSrcWorkflowId() {
-		return _srcWorkflowId;
+	public String getSrcEventId() {
+		return _srcEventId;
+	}
+	
+	public String getSrcEventClass() {
+		return _srcEventClass;
 	}
 
 	public UserI getUser() {
@@ -58,4 +75,12 @@ public class AutomatedScriptRequest implements Serializable {
 	public String getDataId() {
 		return _dataId;
 	}
+
+	public Map<String,Object> getArgumentMap() {
+		return _argumentMap;
+	}
+
+	public String getArgumentJson() {
+		return new JSONObject(_argumentMap).toString();
+	}
 }
diff --git a/src/main/java/org/nrg/xnat/services/messaging/automation/AutomatedScriptRequestListener.java b/src/main/java/org/nrg/xnat/services/messaging/automation/AutomatedScriptRequestListener.java
index 7b87c90eeaa20e506b116a3e616597185878b77a..6b93b22ffba2151b0fba3e3464dff36fd30952c5 100644
--- a/src/main/java/org/nrg/xnat/services/messaging/automation/AutomatedScriptRequestListener.java
+++ b/src/main/java/org/nrg/xnat/services/messaging/automation/AutomatedScriptRequestListener.java
@@ -1,6 +1,5 @@
 package org.nrg.xnat.services.messaging.automation;
 
-import org.nrg.automation.entities.ScriptOutput;
 import org.nrg.automation.services.ScriptRunnerService;
 import org.nrg.framework.exceptions.NrgServiceException;
 import org.nrg.xdat.turbine.utils.AdminUtils;
@@ -16,7 +15,6 @@ import java.util.Map;
 
 public class AutomatedScriptRequestListener {
 
-    @SuppressWarnings("unused")
     public void onRequest(final AutomatedScriptRequest request) throws Exception {
         final PersistentWorkflowI workflow = WorkflowUtils.getUniqueWorkflow(request.getUser(), request.getScriptWorkflowId());
         workflow.setStatus(PersistentWorkflowUtils.IN_PROGRESS);
@@ -26,16 +24,21 @@ public class AutomatedScriptRequestListener {
         parameters.put("user", request.getUser());
         parameters.put("scriptId", request.getScriptId());
         parameters.put("event", request.getEvent());
-        parameters.put("srcWorkflowId", request.getSrcWorkflowId());
+        parameters.put("srcEventId", request.getSrcEventId());
+        final String srcEventClass = request.getSrcEventClass();
+        parameters.put("srcEventClass", srcEventClass);
+        // For backwards compatibility
+        if (srcEventClass.contains("WorkflowStatusEvent") || srcEventClass.contains("WrkWorkflowdata")) {
+        	parameters.put("srcWorkflowId", request.getArgumentMap().get("wrkWorkflowId"));
+        }
         parameters.put("scriptWorkflowId", request.getScriptWorkflowId());
         parameters.put("dataType", request.getDataType());
         parameters.put("dataId", request.getDataId());
         parameters.put("externalId", request.getExternalId());
         parameters.put("workflow", workflow);
-
+        parameters.put("arguments", request.getArgumentJson());
         try {
             _service.runScript(_service.getScript(request.getScriptId()), parameters);
-
             if (PersistentWorkflowUtils.IN_PROGRESS.equals(workflow.getStatus())) {
                 WorkflowUtils.complete(workflow, workflow.buildEvent());
             }
diff --git a/src/main/webapp/scripts/project/projResourceMgmt.js b/src/main/webapp/scripts/project/projResourceMgmt.js
index 6eca65edc30d360c9f42413a3621180dc749c978..43ce30ea34766f46392c4986c686c9e16e28294e 100644
--- a/src/main/webapp/scripts/project/projResourceMgmt.js
+++ b/src/main/webapp/scripts/project/projResourceMgmt.js
@@ -155,6 +155,8 @@ XNAT.app.pResources={
 				if (scriptToRun == XNAT.app.pResources.scripts[i]["Script ID"]) {
 					var eventData = { event: ("Uploaded " + props.name),
 					      			scriptId: scriptToRun,
+					      			eventClass: "org.nrg.xnat.event.entities.WorkflowStatusEvent",
+					      			filters: { "status":["Complete"] },
 					      			description: "Run " + scriptToRun + " upon " + props.name + " upload." };
 					var eventHandlerAjax = $.ajax({
 						type : "PUT",
@@ -167,6 +169,7 @@ XNAT.app.pResources={
 					});
 					eventHandlerAjax.done( function( data, textStatus, jqXHR ) {
 						console.log("NOTE:  Event handler added for " + props.name + " upload");
+						props.triggerId = jqXHR.responseText;
 						// Configure uploader
 						var getUploadConfigAjax = $.ajax({
 							type : "GET",
@@ -195,10 +198,12 @@ XNAT.app.pResources={
 								}
 								var newHandlerObj = {
 									event:NEW_HANDLER,
+									eventTriggerId:props.triggerId,
 									eventScope:"prj",
 									launchFromResourceUploads:true,
 									launchFromCacheUploads:false,
 									launchWithoutUploads:false,
+									doNotUseUploader:false,
 									contexts:[props.type],
 									resourceConfigs:[props.name]
 								};
diff --git a/src/main/webapp/scripts/uploaders/AutomationBasedUploader.js b/src/main/webapp/scripts/uploaders/AutomationBasedUploader.js
index c52b43363fe5a0049a7de637cd894be19576ad7e..93c8bcd687d5ece04869ba344726f6fdaa4d9ce3 100644
--- a/src/main/webapp/scripts/uploaders/AutomationBasedUploader.js
+++ b/src/main/webapp/scripts/uploaders/AutomationBasedUploader.js
@@ -1,5 +1,8 @@
-//Copyright 2015 Washington University
-//Author: Mike Hodge <hodgem@mir.wustl.edu>
+/** 
+  * Copyright 2015 Washington University
+  * Automation Based Uploader
+  * Author: Mike Hodge <hodgem@mir.wustl.edu>
+  */
 
 /* 
  * resource dialog is used to upload resources at any level
@@ -270,6 +273,7 @@ XNAT.app.abu.eventHandlerChange = function(){
 	} else if ((XNAT.app.abu.usageSelect=='Launch') || (abu._fileUploader._uploadStarted && abu._fileUploader._filesInProgress<1)) {
 		$("#abu-process-button").removeClass("abu-button-disabled");
 	}
+	XNAT.app.abu.filesProcessed = false;
 }
 
 XNAT.app.abu.initUploaderConfig = function(){
@@ -285,6 +289,13 @@ XNAT.app.abu.initUploaderConfig = function(){
 	uploaderConfigAjax.done( function( data, textStatus, jqXHR ) {
 
 		if (typeof data !== 'undefined' && $.isArray(data)) {
+			// Configurations must have trigger IDs (remove old-style (pre XNAT 1.7) configurations)
+			for (var i = data.length -1; i >= 0 ; i--) {
+				var triggerId = data[i].eventTriggerId;
+				if (typeof triggerId == 'undefined' || triggerId.length<1) {
+					data.splice(i,1);
+				}
+			}
 			XNAT.app.abu.uploaderConfig = data;
 		} else {
 			XNAT.app.abu.uploaderConfig = [];
@@ -299,6 +310,13 @@ XNAT.app.abu.initUploaderConfig = function(){
 		 });
 		uploaderSiteConfigAjax.done( function( data, textStatus, jqXHR ) {
 			if (typeof data !== 'undefined' && $.isArray(data) && data.length>0) {
+				// Configurations must have trigger IDs (remove old-style (pre XNAT 1.7) configurations)
+				for (var i = data.length -1; i >= 0 ; i--) {
+					var triggerId = data[i].eventTriggerId;
+					if (typeof triggerId == 'undefined' || triggerId.length<1) {
+						data.splice(i,1);
+					}
+				}
 				Array.prototype.push.apply(XNAT.app.abu.uploaderConfig,data);
 			}
 		});
@@ -355,7 +373,7 @@ XNAT.app.abu.populateEventHandlerSelect = function(){
 			var currEvent = events[i];
 			for (var j=0; j<uploaderConfig.length; j++) {
 				var currConfig = uploaderConfig[j];
-				if (currEvent.event==currConfig.event && currEvent.scope==currConfig.eventScope) {
+				if (currEvent.triggerId==currConfig.eventTriggerId && currEvent.scope==currConfig.eventScope) {
 					var doAssign = true;
 					if (usageSelect == 'Upload' && resourceSelect==XNAT.app.abu.cacheConstant && !currConfig.launchFromCacheUploads) {
 						doAssign = false;
@@ -364,7 +382,8 @@ XNAT.app.abu.populateEventHandlerSelect = function(){
 					} else if (usageSelect == 'Upload' && resourceSelect != XNAT.app.abu.cacheConstant) {
 						if (!currConfig.launchFromResourceUploads) {
 							doAssign = false;
-						} else if (currConfig.resourceConfigs.length>0 && $.inArray(resourceSelect,currConfig.resourceConfigs)<0) {
+						} else if ((typeof currConfig.resourceConfigs === 'undefined') ||
+								 (currConfig.resourceConfigs.length>0 && $.inArray(resourceSelect,currConfig.resourceConfigs)<0)) {
 							doAssign = false;
 						}
 					}
@@ -372,14 +391,15 @@ XNAT.app.abu.populateEventHandlerSelect = function(){
 						doAssign = false;
 					}
 					if (doAssign) {
-						$('#eventHandlerSelect').append('<option value="' + currEvent.event + '" class="' + currEvent.scope + '">' +
+						$('#eventHandlerSelect').append('<option value="' + currEvent.triggerId + '" class="' + currEvent.scope + '">' +
 						 ((typeof(currEvent.description) !== 'undefined' && currEvent.description.length>0) ? currEvent.description : currEvent.scriptId) + '</option>');
 					}
 					continue outerLoop;
 				}
 			}
-			$('#eventHandlerSelect').append('<option value="' + currEvent.event + '" class="' + currEvent.scope + '">' +
-				 ((typeof(currEvent.description) !== 'undefined' && currEvent.description.length>0) ? currEvent.description : currEvent.scriptId) + '</option>');
+			// We now don't want to include event handlers with no upload configuration in the display.  The default for handlers is to not use the uploader.
+			//$('#eventHandlerSelect').append('<option value="' + currEvent.triggerId + '" class="' + currEvent.scope + '">' +
+			//	 ((typeof(currEvent.description) !== 'undefined' && currEvent.description.length>0) ? currEvent.description : currEvent.scriptId) + '</option>');
 		}
 		if ($('#eventHandlerSelect').find('option').length==1) {
 			$('#handlerDefaultOption').html('NONE DEFINED'); 
@@ -400,6 +420,8 @@ XNAT.app.abu.populateWhatToDoSelect = function(){
 	var uploaderConfig = XNAT.app.abu.uploaderConfig;
 	var usageSelect = $('#usageSelect').val();
 	var resourceSelect = $('#resourceSelect').val();
+	$('#whatToDoSelect').append('<option id="handlerDefaultOption" value="">' + 
+		((usageSelect=='Launch' || resourceSelect==XNAT.app.abu.cacheConstant) ?  'SELECT' : 'DEFAULT') + '</option>'); 
 	if (XNAT.app.abu.contextResourceConfigs!=undefined && XNAT.app.abu.contextResourceConfigs.length>0) {
 		for (var h=0; h<resourceConfigs.length; h++) {
 			var resourceMatch = false;
@@ -410,7 +432,7 @@ XNAT.app.abu.populateWhatToDoSelect = function(){
 					if (currEvent.event == ("Uploaded " + resourceConfigs[h].name)) {
 						for (var j=0; j<uploaderConfig.length; j++) {
 							var currConfig = uploaderConfig[j];
-							if (currEvent.event==currConfig.event && currEvent.scope==currConfig.eventScope) {
+							if (currEvent.triggerId==currConfig.eventTriggerId && currEvent.scope==currConfig.eventScope) {
 								var doAssign = true;
 								if ((usageSelect == 'Launch') ||
 								   (!(currConfig.launchFromResourceUploads)) ||
@@ -418,7 +440,7 @@ XNAT.app.abu.populateWhatToDoSelect = function(){
 									doAssign = false;
 								}
 								if (doAssign) {
-									$('#whatToDoSelect').append('<option value="resource- ' + resourceConfigs[h].name + ':launch-' + currEvent.event + '" class="' + currEvent.scope + '">' + 
+									$('#whatToDoSelect').append('<option value="resource- ' + resourceConfigs[h].name + ':launch-' + currEvent.triggerId + '" class="' + currEvent.scope + '">' + 
 				                                                ((typeof resourceConfigs[h].description !== 'undefined' && resourceConfigs[h].description.length>0) ? resourceConfigs[h].description : resourceConfigs[h].name) + " --> " + 
 									 ((typeof(currEvent.description) !== 'undefined' && currEvent.description.length>0) ? currEvent.description : currEvent.scriptId) + '</option>');
 									resourceMatch = true;
@@ -426,10 +448,11 @@ XNAT.app.abu.populateWhatToDoSelect = function(){
 								continue outerLoop;
 							}
 						}
-						$('#whatToDoSelect').append('<option value="resource-' + resourceConfigs[h].name + ':launch-' + currEvent.event + '" class="' + currEvent.scope + '">' + 
-				                                ((typeof resourceConfigs[h].description !== 'undefined' && resourceConfigs[h].description.length>0) ? resourceConfigs[h].description : resourceConfigs[h].name) + " --> " + 
-							 ((typeof(currEvent.description) !== 'undefined' && currEvent.description.length>0) ? currEvent.description : currEvent.scriptId) + '</option>');
-						resourceMatch = true;
+						// We now don't want to include event handlers with no upload configuration in the display.  The default for handlers is to not use the uploader.
+						//$('#whatToDoSelect').append('<option value="resource-' + resourceConfigs[h].name + ':launch-' + currEvent.triggerId + '" class="' + currEvent.scope + '">' + 
+				                //                ((typeof resourceConfigs[h].description !== 'undefined' && resourceConfigs[h].description.length>0) ? resourceConfigs[h].description : resourceConfigs[h].name) + " --> " + 
+						//	 ((typeof(currEvent.description) !== 'undefined' && currEvent.description.length>0) ? currEvent.description : currEvent.scriptId) + '</option>');
+						//resourceMatch = true;
 					}
 				}
 			} 
@@ -444,7 +467,7 @@ XNAT.app.abu.populateWhatToDoSelect = function(){
 			var currEvent = events[i];
 			for (var j=0; j<uploaderConfig.length; j++) {
 				var currConfig = uploaderConfig[j];
-				if (currEvent.event==currConfig.event && currEvent.scope==currConfig.eventScope) {
+				if (currEvent.triggerId==currConfig.eventTriggerId && currEvent.scope==currConfig.eventScope) {
 					var doAssign = true;
 					if ((usageSelect == 'Launch') ||
 					   (!(currConfig.launchFromCacheUploads)) ||
@@ -452,16 +475,22 @@ XNAT.app.abu.populateWhatToDoSelect = function(){
 						doAssign = false;
 					}
 					if (doAssign) {
-						$('#whatToDoSelect').append('<option value="resource-' + XNAT.app.abu.cacheConstant + ':launch-' + currEvent.event + '" class="' + currEvent.scope + '">' + "Upload --> " + 
+						$('#whatToDoSelect').append('<option value="resource-' + XNAT.app.abu.cacheConstant + ':launch-' + currEvent.triggerId + '" class="' + currEvent.scope + '">' + /*"Upload --> " +*/ 
 						 ((typeof(currEvent.description) !== 'undefined' && currEvent.description.length>0) ? currEvent.description : currEvent.scriptId) + '</option>');
 					}
 					continue outerLoop;
 				}
 			}
-			$('#whatToDoSelect').append('<option value="resource-' + XNAT.app.abu.cacheConstant + ':launch-' + currEvent.event + '" class="' + currEvent.scope + '">' + "Upload --> " + 
-				 ((typeof(currEvent.description) !== 'undefined' && currEvent.description.length>0) ? currEvent.description : currEvent.scriptId) + '</option>');
+			// We now don't want to include event handlers with no upload configuration in the display.  The default for handlers is to not use the uploader.
+			//$('#whatToDoSelect').append('<option value="resource-' + XNAT.app.abu.cacheConstant + ':launch-' + currEvent.triggerId + '" class="' + currEvent.scope + '">' + "Upload --> " + 
+			//	 ((typeof(currEvent.description) !== 'undefined' && currEvent.description.length>0) ? currEvent.description : currEvent.scriptId) + '</option>');
 		}
 	} 
+	if ($('#whatToDoSelect').find('option').length==1) {
+		$('#whatToDoOption').html('NONE DEFINED'); 
+	} else if ($('#whatToDoSelect').find('option').length==2) {
+		$('#whatToDoSelect').find('option').get(0).remove();
+	}
 	XNAT.app.abu.whatToDoChange();
 }
 
@@ -524,9 +553,17 @@ XNAT.app.abu.initializeAbuUploader = function(usageType){
 			debug:true,
 			doneFunction:function(){
 					// Since we're using the update-stats=false parameter for resource uploads, we need to call catalog refresh when we're finished uploading.
-					XNAT.app.abu.updateResourceStats();
-					XNAT.app.abu.sendWorkflowWhenDone();
+					if (abu._fileUploader.uploadsStarted>0 && abu._fileUploader.uploadsInProgress==0) {
+						XNAT.app.abu.updateResourceStats();
+						// Create workflow if we just uploaded files without any script processing (otherwise, workflow will have been generated there)
+						if (!XNAT.app.abu.filesProcessed) {
+							XNAT.app.abu.sendWorkflowWhenDone();
+						}
+					}
 					xModalCloseNew(XNAT.app.abu.abuConfigs.modalOpts.id);
+					//if (abu._fileUploader.uploadsStarted>0 && abu._fileUploader.uploadsInProgress==0) {
+					//	window.location.reload(true);
+					//}
 				},
 			uploadStartedFunction:function(){
 					if (abu._fileUploader._currentAction.indexOf("import-handler=" + XNAT.app.abu.importHandler)>=0 && (typeof(XNAT.app.abu.buildPath) == 'undefined' || XNAT.app.abu.buildPath == '')) {
@@ -538,7 +575,9 @@ XNAT.app.abu.initializeAbuUploader = function(usageType){
 						$("#abu-done-button").addClass("abu-button-disabled");
 					}
 					$("#resourceSelect").prop('disabled','disabled');
-					$("#whatToDoSelect").prop('disabled','disabled');
+					if ($("#whatToDoSelect").val() != "") {
+						$("#whatToDoSelect").prop('disabled','disabled');
+					}
 					$("#usageSelect").prop('disabled','disabled');
 				},
 			uploadCompletedFunction:function(){
@@ -554,6 +593,7 @@ XNAT.app.abu.initializeAbuUploader = function(usageType){
 					XNAT.app.abu.processFiles();
 				},
 			showEmailOption:true,
+			showCloseOption:true,
 			showExtractOption:(usageType !== 'launch'),
 			showVerboseOption:false,
 			showUpdateOption:false,
@@ -575,11 +615,20 @@ XNAT.app.abu.initializeAbuUploader = function(usageType){
 				$(".upload-area").css("display","none");
 				$(".whattodo-area").css("display","none");
 				$("#abu-upload-button").addClass("abu-button-disabled");
+				abu._fileUploader.DRAG_AND_DROP_ON = false;
 				$("#abu-upload-button").css("display","none");
 				$("#abu-process-button-text").html("Run script");
+				$("#abu-done-button-text").html("Cancel");
+				if ($('#eventHandlerSelect option').size()>1 && $('#eventHandlerSelect').val()=="") {
+					$("#abu-process-button").addClass("abu-button-disabled");
+				} 
 				$("#file-uploader-instructions-sel").css("display","none");
 			} else {
 				XNAT.app.abu.populateWhatToDoSelect();
+				if ($('#whatToDoSelect option').size()>1 && $('#whatToDoSelect').val()=="") {
+					$("#abu-upload-button").addClass("abu-button-disabled");
+					abu._fileUploader.DRAG_AND_DROP_ON = false;
+				} 
 				$("#abu-process-button").addClass("abu-button-disabled");
 				$(".upload-area").css("display","none");
 				$(".eventhandler-area").css("display","none");
@@ -604,6 +653,7 @@ XNAT.app.abu.usageSelectAction = function(){
 		XNAT.app.abu.populateEventHandlerSelect();
 		$("#abu-done-button").removeClass("abu-button-disabled");
 		$("#abu-upload-button").removeClass("abu-button-disabled");
+		abu._fileUploader.DRAG_AND_DROP_ON = true;
 		$("#abu-process-button").addClass("abu-button-disabled");
 		$("#script-select-text").html("Post-upload processing script:");
 		$("#abu-process-button-text").html("Process files");
@@ -613,6 +663,7 @@ XNAT.app.abu.usageSelectAction = function(){
 		XNAT.app.abu.populateEventHandlerSelect();
 		$("#abu-done-button").removeClass("abu-button-disabled");
 		$("#abu-upload-button").addClass("abu-button-disabled");
+		abu._fileUploader.DRAG_AND_DROP_ON = false;
 		var eventHandler = $('#eventHandlerSelect').val();
 		if (eventHandler != undefined && eventHandler != null && eventHandler.length>0) {
 			$("#abu-process-button").removeClass("abu-button-disabled");
@@ -636,7 +687,9 @@ XNAT.app.abu.updateModalAction = function(){
 			for (var i=0; i<resourceConfigs.length; i++) {
 				if (XNAT.app.abu.configuredResource==resourceConfigs[i].name) {
 					// NOTE:  Setting update-stats=false (no workflow entry for individual files).  The process step will create a workflow entry for the entire upload.
-					abu._fileUploader._currentAction = $(XNAT.app.abu.currentLink).attr("data-uri") + "/resources/" + resourceConfigs[i].label + "/files" + resourceConfigs[i].subdir + "?overwrite=" + resourceConfigs[i].overwrite + "&update-stats=false&XNAT_CSRF=" + window.csrfToken;
+					var subdir = resourceConfigs[i].subdir;
+					subdir = (typeof subdir !== 'undefined' && subdir.length > 0) ? "/" + subdir : subdir;
+					abu._fileUploader._currentAction = $(XNAT.app.abu.currentLink).attr("data-uri") + "/resources/" + resourceConfigs[i].label + "/files" + subdir + "/##FILENAME_REPLACE##?overwrite=" + resourceConfigs[i].overwrite + "&update-stats=false&XNAT_CSRF=" + window.csrfToken;
 					XNAT.app.abu.populateEventHandlerSelect();
 					return;
 				}
@@ -654,6 +707,17 @@ XNAT.app.abu.whatToDoChange = function(){
 	$('#resourceSelect').val(resourceSelect);
 	XNAT.app.abu.updateModalAction();
 	$('#eventHandlerSelect').val(launchSelect);
+	if (typeof abu !== 'undefined' && abu._fileUploader.uploadsStarted>0 && abu._fileUploader.uploadsInProgress==0) {
+		$("#abu-process-button").removeClass("abu-button-disabled");
+	}
+	if (XNAT.app.abu.usageSelect == 'Upload' && $('#whatToDoSelect option').size()>1 && $('#whatToDoSelect').val()=="") {
+		$("#abu-upload-button").addClass("abu-button-disabled");
+		abu._fileUploader.DRAG_AND_DROP_ON = false;
+	} else if (typeof abu == 'undefined' || abu._fileUploader.uploadsStarted==0) {
+		$("#abu-upload-button").removeClass("abu-button-disabled");
+		abu._fileUploader.DRAG_AND_DROP_ON = true;
+	} 
+	XNAT.app.abu.filesProcessed = false;
 }
 
 XNAT.app.abu.initializeBuildPath = function(){
@@ -710,8 +774,8 @@ XNAT.app.abu.updateResourceStats=function() {
 	if (XNAT.app.abu.usageSelect !== 'Launch') {
 		if (abu._fileUploader._currentAction.indexOf("import-handler=" + XNAT.app.abu.importHandler)<0) {
 			var updateStatsUrl = "/data/services/refresh/catalog?resource=" + 
-				abu._fileUploader._currentAction.replace(/\/files[?].*$/i,'').replace(/^\/data\//i,"/archive/").replace(/^\/REST\//i,"/archive/" +
-				"&options=populateStats");
+				abu._fileUploader._currentAction.replace(/\/files[\/?].*$/i,'').replace(/^\/data\//i,"/archive/").replace(/^\/REST\//i,"/archive/" +
+				"&options=populateStats") + "&XNAT_CSRF=" + window.csrfToken;
 			var updateStatsAjax = $.ajax({
 				type : "POST",
 				url:serverRoot+updateStatsUrl,
@@ -733,14 +797,51 @@ XNAT.app.abu.updateResourceStats=function() {
 XNAT.app.abu.sendWorkflowWhenDone=function() {
 	if (XNAT.app.abu.usageSelect !== 'Launch') {
 		if (abu._fileUploader._currentAction.indexOf("import-handler=" + XNAT.app.abu.importHandler)<0) {
-			// TO DO:  Implement this
+			var params = {};
+			params['project'] = XNAT.data.context.projectID;
+			params['process'] = 'true';
+			if (typeof(XNAT.app.abu.configuredResource)!=='undefined' && XNAT.app.abu.configuredResource!=null) {
+				params['configuredResource'] = XNAT.app.abu.configuredResource;
+			}
+			params['XNAT_CSRF'] = window.csrfToken;
+			if (XNAT.data.context.isSubject) {
+				params['subject'] = XNAT.data.context.subjectID;
+			}
+			if (XNAT.data.context.isExperiment || XNAT.data.context.isImageAssessor || XNAT.data.context.isImageSession || XNAT.data.context.isSubjectAssessor) {
+				params['experiment'] = XNAT.data.context.ID;
+			}
+			params['xsiType'] = XNAT.data.context.xsiType;
+			var queryParams = "?import-handler=" + XNAT.app.abu.importHandler + "&" + $.param(params);
+			var processAjax = $.ajax({
+				type : "POST",
+				url:serverRoot+"/REST/services/import" + queryParams,
+				cache: false,
+				async: true,
+				/*
+				data: JSON.stringify(this.paramData),
+				contentType: "application/json; charset=utf-8",
+				data: this.paramData,
+				contentType: "application/x-www-form-urlencoded",
+				encode: true,
+				*/
+				context: this,
+				dataType: 'text'
+			  });
+			processAjax.done( function( data, textStatus, jqXHR ) {
+				console.log(XNAT.app.abu.processReturnedText(data,true));
+			});
+			processAjax.fail( function( data, textStatus, jqXHR ) {
+				console.log(XNAT.app.abu.processReturnedText(data,true));
+			});
 		}
 	}
 }
 
 XNAT.app.abu.processFiles=function() {
 
-		$(".abu-files-processing").css("display","inline");
+		XNAT.app.abu.filesProcessed = true;
+
+		$(".abu-files-processing").css("display","block");
 
 		// Since we're using the update-stats=false parameter, we need to call catalog refresh when we're finished uploading.
 		XNAT.app.abu.updateResourceStats();
@@ -751,8 +852,9 @@ XNAT.app.abu.processFiles=function() {
 			var eventHandlerScope = eventHandlerElement.className;
 		}
 
+		this.paramsToPass = undefined;
 		for (var i=0;i<this.uploaderConfig.length;i++) {
-			if (this.uploaderConfig[i].event==eventHandler && this.uploaderConfig[i].eventScope==eventHandlerScope &&
+			if (this.uploaderConfig[i].eventTriggerId==eventHandler && this.uploaderConfig[i].eventScope==eventHandlerScope &&
 			 	(this.uploaderConfig[i].parameters!=undefined && this.uploaderConfig[i].parameters!=null && this.uploaderConfig[i].parameters.length>0)) {
 				this.paramsToPass = this.uploaderConfig[i].parameters;
 				break;
@@ -837,7 +939,9 @@ XNAT.app.abu.continueProcessing=function() {
 			type : "POST",
 			url:serverRoot+"/REST/services/import" + queryParams +
 					 (($("#extractRequestBox").length>0) ? (($("#extractRequestBox").is(':checked')) ? "&extract=true" : "&extract=false") : "") +
-					 (($("#emailBox").length>0) ? (($("#emailBox").is(':checked')) ? "&sendemail=true" : "&sendemail=false") : "") +
+					 (($("#closeBox").length>0) ? ($("#closeBox").is(':checked')) ? "&sendemail=true" : 
+					    (($("#emailBox").length>0) ? (($("#emailBox").is(':checked')) ? "&sendemail=true" : "&sendemail=false") : "") :
+					    (($("#emailBox").length>0) ? (($("#emailBox").is(':checked')) ? "&sendemail=true" : "&sendemail=false") : "")) +
 					 (($("#verboseBox").length>0) ? (($("#verboseBox").is(':checked')) ? "&verbose=true" : "&verbose=false") : "") +
 					 (($("#updateBox").length>0) ? (($("#updateBox").is(':checked')) ? "&update=true" : "&update=false") : "") 
 			,
@@ -894,7 +998,7 @@ XNAT.app.abu.continueProcessing=function() {
 		});
 		$("#abu-done-button").removeClass("abu-button-disabled");
 		setTimeout(function(){
-			if (document.getElementById("emailBox")!=null && document.getElementById("emailBox").checked) {
+			if (document.getElementById("closeBox")!=null && document.getElementById("closeBox").checked) {
 				xModalMessage('Notice',"You will be sent an e-mail upon completion");
 				xModalCloseNew(XNAT.app.abu.abuConfigs.modalOpts.id);
 			}
@@ -920,11 +1024,12 @@ XNAT.app.abu.removeUploaderConfiguration=function(configEvent,scope) {
 	}
 }
 
-XNAT.app.abu.saveUploaderConfiguration=function(configEvent,scope) {
-	var newConfigObj = { event: configEvent, eventScope: scope };
+XNAT.app.abu.saveUploaderConfiguration=function(configTriggerId, configEvent, scope) {
+	var newConfigObj = { eventTriggerId: configTriggerId, event: configEvent, eventScope: scope };
 	newConfigObj.launchFromCacheUploads = $('#ULC_RB_launchFromCacheUploads').is(':checked');
 	newConfigObj.launchFromResourceUploads = $('#ULC_RB_launchFromResourceUploads').is(':checked');
 	newConfigObj.launchWithoutUploads = $('#ULC_RB_launchWithoutUploads').is(':checked');
+	newConfigObj.doNotUseUploader = $('#ULC_RB_doNotUseUploader').is(':checked');
 	newConfigObj.parameters = undefined;
 	$(".ULC_parametersDiv").each(function() {
 		var parameterField = $(this).find(".ULC_parametersField").val();
@@ -1046,7 +1151,7 @@ XNAT.app.abu.validateUploaderConfiguration=function() {
 	return true;
 }
 
-XNAT.app.abu.configureUploaderForEventHandler=function(configEvent,scope) {
+XNAT.app.abu.configureUploaderForEventHandler=function(configTriggerId, configEvent, scope) {
 
 	var uploaderConfig = XNAT.app.abu.uploaderConfig;
 	if (typeof(uploaderConfig) === 'undefined' || uploaderConfig == null) {
@@ -1056,16 +1161,17 @@ XNAT.app.abu.configureUploaderForEventHandler=function(configEvent,scope) {
 	var configObj;
 	for (var i=0;i<uploaderConfig.length;i++) {
 		var objI = uploaderConfig[i];
-		if (objI.eventScope == scope && objI.event == configEvent) {
+		if (objI.eventScope == scope && objI.eventTriggerId == configTriggerId) {
 			// Clone the object because we may modify it (fill in context values).
 			configObj = jQuery.extend(true, {}, objI);
 		}
 	}
 	if (typeof(configObj) === 'undefined' || configObj == null) {
 		configObj = {};
-		configObj.launchFromCacheUploads = true;
-		configObj.launchFromResourceUploads = true;
-		configObj.launchWithoutUploads = true;
+		configObj.launchFromCacheUploads = false;
+		configObj.launchFromResourceUploads = false;
+		configObj.launchWithoutUploads = false;
+		configObj.doNotUseUploader = true;
 		// best to leave these undefined, I think
 		//configObj.parameters = [  ];
 		//configObj.contexts = [ 'xnat:projectData','xnat:subjectAssessorData','xnat:imageAssessorData','xnat:imageSessionData','xnat:imageScanData','xnat:subjectData' ];
@@ -1083,7 +1189,7 @@ XNAT.app.abu.configureUploaderForEventHandler=function(configEvent,scope) {
 				close: false,
 				action: function( obj ){
 					if (XNAT.app.abu.validateUploaderConfiguration()) {
-						XNAT.app.abu.saveUploaderConfiguration(configEvent,scope);
+						XNAT.app.abu.saveUploaderConfiguration(configTriggerId, configEvent, scope);
 						obj.close();
 					}
 				}
@@ -1107,6 +1213,8 @@ XNAT.app.abu.configureUploaderForEventHandler=function(configEvent,scope) {
 				 ((configObj.launchFromResourceUploads) ? ' checked' : '') + '> <b> Use for configured resource uploads </b> </div>';
 	configHtml+='<div style="margin-left:20px;width:100%"><input type="radio" id="ULC_RB_launchWithoutUploads" name="ULC_RB" value="launchWithoutUploads"' +
 				 ((configObj.launchWithoutUploads) ? ' checked' : '') + '> <b> Trigger without uploads </b> </div>';
+	configHtml+='<div style="margin-left:20px;width:100%"><input type="radio" id="ULC_RB_doNotUseUploader" name="ULC_RB" value="doNotUseUploader"' +
+				 ((configObj.doNotUseUploader) ? ' checked' : '') + '> <b> Do not use uploader </b> </div>';
 	configHtml+='</div></p>';
 	configHtml+='<p>';
 	configHtml+='<div style="margin-left:20px;width:100%"><p><b>User Supplied Parameters:</b><p><div id="ULC_parameters">';
diff --git a/src/main/webapp/scripts/uploaders/fileuploader.js b/src/main/webapp/scripts/uploaders/fileuploader.js
index e2a1868d1f01c2634081535648e6109586bc0f5e..cd32d43bd8ddbaa3916b31e0b0278b25c859232f 100644
--- a/src/main/webapp/scripts/uploaders/fileuploader.js
+++ b/src/main/webapp/scripts/uploaders/fileuploader.js
@@ -1,7 +1,9 @@
 
-//
-// Helper functions
-//
+/**
+ * Copyright 2015 Washington University
+ * File uploader
+ * Author:  Mike Hodge (hodgem@wustl.edu)
+ */
 
 var abu = abu || {};
 
@@ -16,6 +18,7 @@ abu.FileUploader = function(o){
 	// Leave this set to 1 if the uploader supports uploading directly to resources.
 	this.MAX_CONCURRENT_UPLOADS = 1;
 	this.ALLOW_DRAG_AND_DROP = true;
+	this.DRAG_AND_DROP_ON = true;
 	this.uploadsInProgress = 0;
 	this.uploadsStarted = 0;
 	$(this._options.element).html(""); 
@@ -23,7 +26,7 @@ abu.FileUploader = function(o){
 	this.buildUploaderDiv = function() {
 		$(this._options.element).append(
 			'<div class="abu-uploader">' +
-				'<div id="abu-files-processing" class="abu-files-processing">        Processing uploaded files..... </div>' +
+				'<div id="abu-files-processing" class="abu-files-processing">        Processing...... </div>' +
 				'<a id="file-uploader-instructions-sel" class="abu-uploader-instructions-sel" onclick="abu._fileUploader.uploaderHelp()">?</a>' +
 				'<div class="abu-upload-drop-area" style="display: none;"><span>Drop files here to upload</span></div>' +
 				'<div class="abu-xnat-interactivity-area">' +
@@ -46,12 +49,18 @@ abu.FileUploader = function(o){
 				'</div>' : 
 				'<div class="abu-extract-zip"><input id="extractRequestBox" type="hidden" value="1"/></div>'
 			) +
-			((this._options.showEmailOption) ?
+			((this._options.showCloseOption) ?
 				'<div class="abu-options-cb" title = "Close window upon submit and send e-mail upon completion">' +
-					'<input id="emailBox" type="checkbox" value="1">' +
+					'<input id="closeBox" type="checkbox" value="1">' +
 					'Close window upon submit' +
 				'</div>' : "" 
 			) +
+			((this._options.showEmailOption) ?
+				'<div class="abu-options-cb" title = "Send e-mail upon completion">' +
+					'<input id="emailBox" type="checkbox" value="1">' +
+					'Send e-mail upon completion' +
+				'</div>' : "" 
+			) +
 			((this._options.showUpdateOption) ?
 				'<div class="abu-options-cb" title = "Update existing records?">' +
 					'<input id="updateBox" type="checkbox" value="1">' +
@@ -77,13 +86,26 @@ abu.FileUploader = function(o){
 		$("#abu-process-button").click(this._options.processFunction);
 		$("#abu-process-button").mouseenter(function() { $(this).addClass("abu-process-button-hover"); });
 		$("#abu-process-button").mouseleave(function() { $(this).removeClass("abu-process-button-hover"); });
+		$('#closeBox').change(function(){ 
+			if ($('#closeBox').is(':checked')) { 
+				$('#emailBox').prop('checked', true);
+				$('#emailBox').attr('disabled', true);
+			} else {
+				$('#emailBox').attr('disabled', false);
+			}
+		 });
+
 		if (this.ALLOW_DRAG_AND_DROP) {
 			$(".abu-upload-drop-area").on('dragover',function(e) {
-					this.activateUploadArea(e);
+					if (this.DRAG_AND_DROP_ON) {
+						this.activateUploadArea(e);
+					}
 				}.bind(this)
 			);
 			$(".abu-upload-drop-area").on('dragenter',function(e) {
-					this.activateUploadArea(e);
+					if (this.DRAG_AND_DROP_ON) {
+						this.activateUploadArea(e);
+					}
 				}.bind(this)
 			);
 			$(".abu-upload-drop-area").on('drop',function(e) {
@@ -99,11 +121,15 @@ abu.FileUploader = function(o){
 				}.bind(this)
 			);
 			$(this._options.element).on('dragover',function(e) {
-					this.activateUploadArea(e);
+					if (this.DRAG_AND_DROP_ON) {
+						this.activateUploadArea(e);
+					}
 				}.bind(this)
 			).bind(this);
 			$(this._options.element).on('dragenter',function(e) {
-					this.activateUploadArea(e);
+					if (this.DRAG_AND_DROP_ON) {
+						this.activateUploadArea(e);
+					}
 				}.bind(this)
 			);
 		}	
@@ -132,7 +158,7 @@ abu.FileUploader = function(o){
 			var cFile = fileA[i];
 			var adj_i = i + start_i;
 			$(".abu-upload-list").append(
-				'<form id="file-upload-form-' + adj_i + '" action="' + this._currentAction +
+				'<form id="file-upload-form-' + adj_i + '" action="' + this._currentAction.replace("##FILENAME_REPLACE##",cFile.name) +
 					 (($("#extractRequestBox").length>0) ? (($("#extractRequestBox").is(':checked')) ? "&extract=true" : "&extract=false") : "") +
 					 (($("#emailBox").length>0) ? (($("#emailBox").is(':checked')) ? "&sendemail=true" : "&sendemail=false") : "") +
 					 (($("#verboseBox").length>0) ? (($("#verboseBox").is(':checked')) ? "&verbose=true" : "&verbose=false") : "") +
@@ -207,10 +233,24 @@ abu.FileUploader = function(o){
 					bar.width(percentVal)
 					percent.html(percentVal);
 					// Don't create results link if we're just returning the build path
-					if (typeof result.status !== 'undefined' || result.length > 150) {
-			 			status.html('<a href="javascript:abu._fileUploader.showReturnedText(\'' + $(status).attr('id') + '\')" class="underline abu-upload-complete abu-upload-complete-text">Upload complete</a>');
+					// check for duplicates
+					var isDuplicate = false;
+					try {
+						var resultObj = JSON.parse(result);
+						if (typeof resultObj.duplicates !== 'undefined' && resultObj.duplicates.length==1) {
+							isDuplicate = true;
+						} 
+					} catch(e) {
+						// Do nothing for now
+					} 
+					if (!isDuplicate) {
+						if (typeof result.status !== 'undefined' || result.length > 150) {
+				 			status.html('<a href="javascript:abu._fileUploader.showReturnedText(\'' + $(status).attr('id') + '\')" class="underline abu-upload-complete abu-upload-complete-text">Upload complete</a>');
+						} else {
+				 			status.html('<span class="abu-upload-complete abu-upload-complete-text">Upload complete</span>');
+						}
 					} else {
-			 			status.html('<span class="abu-upload-complete abu-upload-complete-text">Upload complete</span>');
+			 			status.html('<a href="javascript:abu._fileUploader.showReturnedText(\'' + $(status).attr('id') + '\')" class="underline abu-upload-fail">Duplicate file and overwrite=false.  Not uploaded.</a>');
 					}
 			 		status.css("display","inline-block");
 			 		$(infoSelector).find(".abu-progress").css("display","none");
diff --git a/src/main/webapp/scripts/xnat/app/automation.js b/src/main/webapp/scripts/xnat/app/automation.js
index fef6c53599b8de1df3178ff86af470f59647b619..8e5d42b879f2066827cb4d3f44b92713e66dde73 100644
--- a/src/main/webapp/scripts/xnat/app/automation.js
+++ b/src/main/webapp/scripts/xnat/app/automation.js
@@ -59,6 +59,7 @@ XNAT.app.automation = {};
         //return XNAT.url.restUrl('/scripts/xnat/app/automation-workflows.json');
     }
 
+    /*
     function eventsURL(part, params, cacheit){
         part = isDefined(part) ? part : '';
         // return events URL with CSRF and unique cache-busting paramater
@@ -69,6 +70,7 @@ XNAT.app.automation = {};
         automation.events = [];
         return xhr.getJSON(eventsURL(), callback)
     }
+    */
 
     function createEventRows(events){
         var rows = '';
@@ -111,6 +113,7 @@ XNAT.app.automation = {};
 
 
     // initialize the Events display
+    /*
     automation.initEvents = function(){
         // make sure things are hidden first
         $eventsTable.hide();
@@ -122,6 +125,7 @@ XNAT.app.automation = {};
         });
 
     };
+    */
 
     function getWorkflows(callback){
         //automation.workflows = {}; // reset workflows
@@ -208,6 +212,7 @@ XNAT.app.automation = {};
 
     }
 
+    /*
     automation.saveEvent = function(data){
         if (!data || !data.event_id){
             xmodal.loading.closeAll();
@@ -239,6 +244,7 @@ XNAT.app.automation = {};
             }
         });
     };
+    */
 
     function toggleDisabled($els, disabled){
 
@@ -342,6 +348,7 @@ XNAT.app.automation = {};
         })
     }
 
+    /*
     automation.deleteEvent = function(id, label){
         var _url =  eventsURL('', '?XNAT_CSRF=' + window.csrfToken + '&cascade=true', false);
         xmodal.confirm({
@@ -369,10 +376,11 @@ XNAT.app.automation = {};
             }
         });
     };
+    */
 
 
     // INITIALIZE
-    automation.initEvents();
+    //automation.initEvents();
 
 
     // click the "Define Event" button
diff --git a/src/main/webapp/scripts/xnat/app/eventsManager.js b/src/main/webapp/scripts/xnat/app/eventsManager.js
index 6bb1803c819331f62565cef3000e88125c0f137e..cf236a677d1c9707b9bb179f4dadfb103a6899e6 100644
--- a/src/main/webapp/scripts/xnat/app/eventsManager.js
+++ b/src/main/webapp/scripts/xnat/app/eventsManager.js
@@ -47,9 +47,22 @@ $(function(){
 
                 if(_handlers.length) {
                     handlersRendered = true;
+                    eventRows += 
+                    '<dl class="header">' + 
+                         '<dl>' +
+                              '<dd class="col1">Event</dd>' +
+                              '<dd class="col2">Script ID</dd>' +
+                              '<dd class="col3">Description</dd>' +
+                            ((doEdit) ?
+                              '<dd class="col4"></dd>' +
+                              '<dd class="col5"></dd>' 
+                            : '') +
+                         '</dl>' +
+                    '</dl>';
                     forEach(_handlers, function(eventHandler){
                         var _event_id = eventHandler['event'];
                         eventsManager.handlers.push(_event_id);
+                        /*
                         eventRows += '<tr class="highlight">' +
                             '<td class="event-id">' + _event_id + '</td>' +
                             '<td class="script-id">' + eventHandler.scriptId + '</td>' +
@@ -65,8 +78,31 @@ $(function(){
                                 '</td>' 
                             : '') +
                             '</tr>';
+                        */
+                        eventRows += '<dl class="item">' +
+                            '<dd class="col1">' + _event_id + '</dd>' +
+                            '<dd class="col2">' + eventHandler.scriptId + '</dd>' +
+                            '<dd class="col3">' + eventHandler.description + '</dd>' +
+                            ((doEdit) ?
+                                '<dd class="col4" style="text-align: center;">' +
+                                '<button href="javascript:" class="delete-handler event-handler-button" ' +
+                                'data-handler="' + eventHandler.triggerId + '" ' +
+                                'data-event="' + _event_id + '" ' +
+                                ' title="Delete handler for event ' + _event_id + '">delete</button>' +
+                                '</dd>' + 
+                                '<dd class="col5" style="text-align: center;">' +
+                                '<button href="javascript:" class="configure-uploader-handler event-handler-button" ' +
+                                'data-handler="' + eventHandler.triggerId + '" ' +
+                                'data-event="' + _event_id + '" ' +
+                                ' title="Configure uploader for event ' + _event_id + '">configure uploader</button>' +
+                                '</dd>' 
+                            : '') +
+                            '<dd class="colC">' + '<b>Event Class: </b> ' + getEventClassDisplayValueFromHandlers(_handlers, eventHandler) + '</dd>' +
+                            '<dd class="colC">' + '<b>Event Filters: </b> ' + eventHandler.eventFilters + '</dd>' +
+                            '</dl>';
                     });
-                    $((doEdit) ? events_manage_table : $events_table).find('tbody').html(eventRows);
+                    //$((doEdit) ? events_manage_table : $events_table).find('tbody').html(eventRows);
+                    $((doEdit) ? events_manage_table : $events_table).html(eventRows);
                     $((doEdit) ? events_manage_table : $events_table).show();
                 }
                 else {
@@ -90,7 +126,31 @@ $(function(){
 
     function initEventsMenu(){
         eventsManager.events = []; // reset array
-        return xhr.getJSON({
+
+        $("#select_event").prop('disabled','disabled');
+		if (typeof XNAT.app.eventsManager.eventClasses === 'undefined') {
+			var eventClassesAjax = $.ajax({
+				type : "GET",
+		  		url:serverRoot+"/xapi/projects/" + window.projectScope + '/eventHandlers/automationEventClasses?XNAT_CSRF=' + window.csrfToken,
+				cache: false,
+				async: true,
+				context: this,
+				dataType: 'json'
+			});
+			eventClassesAjax.done( function( data, textStatus, jqXHR ) {
+				if (typeof data !== 'undefined') {
+					XNAT.app.eventsManager.eventClasses = data;
+                    populateEventsMenu();
+				}
+			});
+			eventClassesAjax.fail( function( data, textStatus, jqXHR ) {
+                xmodal.message('Error', 'An error occurred retrieving system events: ' + textStatus);
+			});
+		} else {
+            populateEventsMenu();
+        }
+
+/*
             url: XNAT.url.restUrl('/data/automation/events'),
             success: function( response ){
 
@@ -140,6 +200,146 @@ $(function(){
                 }
             }
         });
+*/
+    }
+
+    function getEventClassDisplayValueFromHandlers(_handlers, eventHandler){
+        var classPart = eventHandler.srcEventClass.substring(eventHandler.srcEventClass.lastIndexOf('.')); 
+        var matches=0;
+        for (var i=0; i<_handlers.length; i++) {
+            var classVal = _handlers[i].srcEventClass;
+            if (typeof classVal !== 'undefined' && classVal.endsWith(classPart) && !(eventHandler.srcEventClass == _handlers[i].srcEventClass)) {
+                matches++;
+            }
+        }
+        return (matches<1) ? classPart.substring(1) : eventHandler.srcEventClass;
+    }
+
+    function getEventClassDisplayValue(ins){
+        var classPart = ins.substring(ins.lastIndexOf('.')); 
+        var displayName;
+        var matches=0;
+        for (var i=0; i<XNAT.app.eventsManager.eventClasses.length; i++) {
+            var classVal = XNAT.app.eventsManager.eventClasses[i].class;
+            if (typeof classVal !== 'undefined' && classVal.endsWith(classPart)) {
+                matches++;
+                displayName = XNAT.app.eventsManager.eventClasses[i].displayName;
+            }
+        }
+        return (typeof displayName !== 'undefined' && displayName !== ins) ? displayName : (matches<=1) ? classPart.substring(1) : ins;
+    }
+
+    function populateEventsMenu(){
+
+        $('#select_eventClass').empty().append('<option></option>');
+        for (var i=0; i<XNAT.app.eventsManager.eventClasses.length; i++) {
+            if (typeof XNAT.app.eventsManager.eventClasses[i].class !== 'undefined') {
+                $('#select_eventClass').append('<option value="' + XNAT.app.eventsManager.eventClasses[i].class + '">' + getEventClassDisplayValue(XNAT.app.eventsManager.eventClasses[i].class) + '</option>');
+            }
+        }
+        xmodal.open({
+            title: 'Add Event Handler',
+            template: $('#addEventHandler'),
+            width: 600,
+            height: 350,
+            overflow: 'auto',
+            beforeShow: function(obj){
+                //chosenInit(obj.$modal.find('select.event, select.scriptId'), null, 300);
+                //obj.$modal.find('select.event, select.scriptId').chosen({
+                //    width: '300px',
+                //    disable_search_threshold: 6
+                //});
+            },
+            buttons: {
+                save: {
+                    label: 'Save',
+                    isDefault: true,
+                    close: false,
+                    action: doAddEventHandler
+                },
+                close: {
+                    label: 'Cancel'
+                }
+            }
+        });
+        updateEventIdSelect();
+        $('#select_eventClass').change(function(){
+            updateEventIdSelect();
+        });
+
+    }
+
+    function updateEventIdSelect(){
+        $('#select_event').empty().append('<option></option>');
+        $('#filterRow').css('display','none');
+        $('#filterDiv').html(filterableHtml);
+        for (var i=0; i<XNAT.app.eventsManager.eventClasses.length; i++) {
+            if ($('#select_eventClass').val() == XNAT.app.eventsManager.eventClasses[i].class) {
+                var eventIds = XNAT.app.eventsManager.eventClasses[i].eventIds;
+                if (typeof eventIds !== 'undefined' && eventIds.length>0) {
+                    for (var j=0; j<eventIds.length; j++) {
+                        var eventId = eventIds[j];
+                        $('#select_event').append('<option value="' + eventId + '">' + eventId + '</option>');
+                    }
+                }
+                var filterableFields = XNAT.app.eventsManager.eventClasses[i].filterableFields;
+                var filterableHtml = ""
+                $('#filterRow').css('display','none');
+                if (typeof filterableFields !== 'undefined') {
+                    for (var filterable in filterableFields) {
+                        if (!filterableFields.hasOwnProperty(filterable)) continue;
+                        var filterableVals = filterableFields[filterable];
+                        if (typeof filterableVals !== 'undefined' && filterableVals.length>0) {
+                            filterableHtml = filterableHtml + '<div style="width:100%;margin-top:5px;margin-bottom:5px">' + filterable + ' &nbsp;<select id="filter_sel_' + filterable + '" name="' + filterable + '" class="filter">';
+                            filterableHtml = filterableHtml + '<option value="">&lt;NONE&gt;</option>';
+                            for (var i=0; i<filterableVals.length; i++) {
+                                filterableHtml = filterableHtml + '<option value="' + filterableVals[i] + '">' + filterableVals[i] + '</option>';
+                            }
+                            filterableHtml = filterableHtml + '</select> <input type="text" id="filter_input_' + filterable + '" name="' + filterable +
+                                  '" class="filter" style="display:none" size="15"/> <button class="customButton">Custom Value</button></div>';
+                        }
+                    }
+                }
+                if (filterableHtml.length>0) {
+                    $('#filterRow').css('display','table-row');
+                    $('#filterDiv').html(filterableHtml);
+                }
+                $("#select_event").prop('disabled',false);
+                break;
+            }
+        }
+/*
+        $(".customButton").click(function(event){
+            customInputToggle(event.target);
+        });
+*/
+        $(".customButton").each(function(){
+            var eventObject = $._data(this, 'events');
+            if (typeof eventObject == 'undefined' || typeof eventObject.click == 'undefined') {
+                $(this).click(function(event){
+                    customInputToggle(event.target);
+                });
+            }
+        });
+        $(".customButton").css('margin-left','5px');
+    }
+
+    function customInputToggle(ele){
+         $(ele).parent().find("input, select").each(function() {
+            if ($(this).css('display') == 'none') {
+                $(this).css('display','inline');
+            } else {
+                $(this).css('display','none');
+                //if ($(this).is("input")) {
+                    $(this).val("");
+                //}
+            }
+        });
+        if ($(ele).html() == "Selection Menu") {
+            $(ele).html("Custom Value");
+        } else {
+            $(ele).html("Selection Menu");
+        }
     }
 
     function initScriptsMenu(){
@@ -172,25 +372,70 @@ $(function(){
         });
     }
 
-    // initialize menus and table
-    initEventsMenu();
+    // initialize scripts menu and table
     initScriptsMenu();
+    if (!handlersRendered){
+        initEventsTable(false);
+    }
 
     function doAddEventHandler( xmodalObj ){
 
+	var filterVar = {};
+	var filterEle = $("select.filter, input.filter").filter(function() { return $(this).val() != "" });
+	for (var i=0; i<filterEle.length; i++) {
+		filterVar[filterEle[i].name]=[];
+		filterVar[filterEle[i].name].push($(filterEle[i]).val());
+	}
+
         var data = {
-            event: xmodalObj.__modal.find('select.event').val(),
+            eventClass: xmodalObj.__modal.find('select.eventClass').val(),
+            event: xmodalObj.__modal.find('select.event, input.event').filter(function() { return $(this).val() != "" }).val(),
             scriptId: xmodalObj.__modal.find('select.scriptId').val(),
-            description: xmodalObj.__modal.find('input.description').val()
+            description: xmodalObj.__modal.find('input.description').val(),
+            filters: filterVar
         };
 
         if (!data.event || data.event === '!' || !data.scriptId){
             xmodal.message('Missing Information','Please select an <b>Event</b> <i>and</i> <b>Script ID</b> to create an <br>Event Handler.');
             return false;
         }
+	XNAT.app.eventsManager.eventHandlerData = data;
+
+	var eventHandlerAjax = $.ajax({
+		type : "PUT",
+  		url:serverRoot+'/data/projects/' + window.projectScope + '/automation/handlers?XNAT_CSRF=' + window.csrfToken,
+		cache: false,
+		async: true,
+		data: JSON.stringify(data),
+		contentType: 'application/json'
+	});
+	eventHandlerAjax.done( function( data, textStatus, jqXHR ) {
+		if (typeof data !== 'undefined') {
+	                xmodal.message('Success', 'Your event handler was successfully added.', 'OK', { 
+	                        action: function(){
+	                            initEventsTable(false);
+	                            if ($("#events_manage_table").length>0) {
+	                                initEventsTable(true);
+	                            }
+	                            xmodal.closeAll($(xmodal.dialog.open),$('#xmodal-manage-events'));
+	                            // Trigger automation uploader to reload handlers
+	                            XNAT.app.abu.getAutomationHandlers();
+	                        }  
+	                    }
+	                );
+		}
+	});
+	eventHandlerAjax.fail( function( data, textStatus, jqXHR ) {
+                xmodal.message('Error', 'An error occurred: [' + data.statusText + '] ' + data.responseText, 'Close', {
+                    action: function(){
+                        xmodal.closeAll($(xmodal.dialog.open),$('#xmodal-manage-events'));
+                    }
+                });
+	});
 
+        /*
         xhr.put({
-            url: XNAT.url.restUrl('/data/projects/' + window.projectScope + '/automation/handlers?XNAT_CSRF=' + window.csrfToken, null, false),
+            url: '/data/projects/' + window.projectScope + '/automation/handlers?XNAT_CSRF=' + window.csrfToken,
             data: data,
             dataType: "json",
             success: function(){
@@ -215,6 +460,7 @@ $(function(){
                 });
             }
         });
+        */
     }
 
  
@@ -243,6 +489,18 @@ $(function(){
 			$('#manageModalDiv').html(
                '<p id="no_events_defined" style="display:none;padding:20px;">There are no events currently defined for this site.</p>' +
                 '<p id="no_event_handlers" style="display:none;padding:20px;">There are no event handlers currently configured for this project.</p>' +
+                '<div id="events_manage_table" class="xnat-table" style="display:table;width:100%">' +
+                    '<dl class="header">' + 
+                         '<dl>' +
+                              '<dd class="col1">Event</dd>' +
+                              '<dd class="col2">Script ID</dd>' +
+                              '<dd class="col3">Description</dd>' +
+                              '<dd class="col4"></dd>' +
+                              '<dd class="col5"></dd>' +
+                         '</dl>' +
+                    '</dl>' +
+                '</div>' 
+		/*
                 '<table id="events_manage_table" class="xnat-table" style="display:table;width:100%">' +
                     '<thead>' +
                     '<th>Event</th>' +
@@ -254,13 +512,14 @@ $(function(){
                     '<tbody>' +
                     '</tbody>' +
                 '</table>' 
+		*/
            ); 
            initEventsTable(true);
-           $("#events_manage_table").on('click', 'a.delete-handler', function(){
+           $("#events_manage_table").on('click', 'button.delete-handler', function(){
                deleteEventHandler($(this).data('handler'))
            });
-           $("#events_manage_table").on('click', 'a.configure-uploader-handler', function(){
-               XNAT.app.abu.configureUploaderForEventHandler($(this).data('handler'),'prj')
+           $("#events_manage_table").on('click', 'button.configure-uploader-handler', function(){
+               XNAT.app.abu.configureUploaderForEventHandler($(this).data('handler'), $(this).data('event'), 'prj')
            });
 
     }
@@ -268,9 +527,11 @@ $(function(){
 
     function addEventHandler(){
 
-        var getEvents = initEventsMenu();
+        initEventsMenu();
+/*
+        //var getEvents = initEventsMenu();
 
-        getEvents.done(function(){
+        //getEvents.done(function(){
             xmodal.open({
                 title: 'Add Event Handler',
                 template: $('#addEventHandler'),
@@ -278,7 +539,7 @@ $(function(){
                 height: 300,
                 overflow: true,
                 beforeShow: function(obj){
-                    chosenInit(obj.$modal.find('select.event, select.scriptId'), null, 300);
+                    //chosenInit(obj.$modal.find('select.event, select.scriptId'), null, 300);
                     //obj.$modal.find('select.event, select.scriptId').chosen({
                     //    width: '300px',
                     //    disable_search_threshold: 6
@@ -296,17 +557,34 @@ $(function(){
                     }
                 }
             });
-        });
+        //});
+*/
     }
 
-    function doDeleteTrigger( triggerId ){
-        var url = XNAT.url.restUrl('/data/automation/triggers/' + triggerId + "?XNAT_CSRF=" + window.csrfToken);
+    function doDeleteTrigger(triggerId){
+        var url = serverRoot+'/data/automation/triggers/' + triggerId + "?XNAT_CSRF=" + window.csrfToken;
         if (window.jsdebug) console.log(url);
         jQuery.ajax({
             type: 'DELETE',
             url: url,
             cache: false,
             success: function(){
+                var configScope;
+                if (typeof XNAT.app.abu.uploaderConfig !== 'undefined') {
+                    for (var i=0; i<XNAT.app.abu.uploaderConfig.length; i++) {
+                        var thisConfig = XNAT.app.abu.uploaderConfig[i];
+                        if (typeof thisConfig == 'undefined') {
+                            continue;
+                        }
+                        if (thisConfig.eventTriggerId == triggerId) {
+                            configScope = thisConfig.eventScope;
+                            XNAT.app.abu.uploaderConfig.splice(0,1);
+                        }
+                    }
+                }
+                if (typeof configScope !== 'undefined') {
+                    XNAT.app.abu.putUploaderConfiguration(configScope,false);
+                }
                 xmodal.message('Success', 'The event handler was successfully deleted.', 'OK', {
                     action: function(){
                         initEventsTable();
@@ -324,11 +602,11 @@ $(function(){
         });
     }
 
-    function deleteEventHandler( triggerId ){
+    function deleteEventHandler(triggerId){
         xmodal.confirm({
             title: 'Delete Event Handler?',
             content: 'Are you sure you want to delete the handler: <br><br><b>' + triggerId + '</b>?<br><br>Only the Event Handler will be deleted. The associated Script will still be available for use.',
-            width: 440,
+            width: 560,
             height: 240,
             okLabel: 'Delete',
             okClose: false, // don't close yet
@@ -351,3 +629,4 @@ $(function(){
     $manage_event_handlers.on('click', manageEventHandlers);
 
 });
+
diff --git a/src/main/webapp/scripts/xnat/app/siteEventsManager.js b/src/main/webapp/scripts/xnat/app/siteEventsManager.js
index 45ef98e089379a6b0ec97ca56b130889c3bd4b20..fbf982a8942792126a888a62168885abfecd386e 100644
--- a/src/main/webapp/scripts/xnat/app/siteEventsManager.js
+++ b/src/main/webapp/scripts/xnat/app/siteEventsManager.js
@@ -20,14 +20,14 @@ $(function(){
         $no_event_handlers = $('#no_event_handlers'),
         $add_event_handler = $('#add_event_handler'),
         $manage_event_handlers = $('#manage_event_handlers'),
-        //handlersRendered = false,
+        handlersRendered = false,
         hasEvents = false;
     
 
     function initHandlersTable(doEdit){
 
         if (doEdit) {
-            var events_manage_table = $('#events_manage_table');
+            var events_manage_table = $('#events_table');
         }
 
         // hide stuff
@@ -46,10 +46,23 @@ $(function(){
                 siteEventsManager.handlers = [];
 
                 if(_handlers.length) {
-                    //handlersRendered = true;
+                    handlersRendered = true;
+                    eventRows += 
+                    '<dl class="header">' + 
+                         '<dl>' +
+                              '<dd class="col1">Event</dd>' +
+                              '<dd class="col2">Script ID</dd>' +
+                              '<dd class="col3">Description</dd>' +
+                            //((doEdit) ?
+                              '<dd class="col4"></dd>' +
+                            //  '<dd class="col5"></dd>' + 
+			    // : '') +
+                         '</dl>' +
+                    '</dl>';
                     forEach(_handlers, function(eventHandler){
                         var _event_id = eventHandler['event'];
                         siteEventsManager.handlers.push(_event_id);
+			/*
                         eventRows += '<tr class="highlight">' +
                             '<td class="event-id">' + _event_id + '</td>' +
                             '<td class="script-id">' + eventHandler.scriptId + '</td>' +
@@ -67,9 +80,37 @@ $(function(){
                             '</td>' 
                              : '' ) +
                             '</tr>';
+			*/
+                        eventRows += '<dl class="item">' +
+                            '<dd class="col1">' + _event_id + '</dd>' +
+                            '<dd class="col2">' + eventHandler.scriptId + '</dd>' +
+                            '<dd class="col3">' + eventHandler.description + '</dd>' +
+                            //((doEdit) ?
+                                '<dd class="col4" style="text-align: center;">' +
+                                '<button href="javascript:" class="delete-handler event-handler-button" ' +
+                                'data-event="' + _event_id + '" ' +
+                                'data-handler="' + eventHandler.triggerId + '" title="Delete handler for event ' + _event_id + '">delete</button>' +
+                                '</dd>' + 
+                                '<dd class="col5" style="text-align: center;">' +
+                                '<button href="javascript:" class="configure-uploader-handler event-handler-button" ' +
+                                'data-event="' + _event_id + '" ' +
+                                'data-handler=' + eventHandler.triggerId + ' title="Configure uploader for event ' + _event_id + '">configure uploader</button>' +
+                                '</dd>' + 
+                            //: '') +
+                            '<dd class="colC">' + '<b>Event Class: </b> ' + getEventClassDisplayValueFromHandlers(_handlers, eventHandler) + '</dd>' +
+                            '<dd class="colC">' + '<b>Event Filters: </b> ' + eventHandler.eventFilters + '</dd>' +
+                            '</dl>';
+
                     });
-                    $((doEdit) ? events_manage_table : $events_table).find('tbody').html(eventRows);
+                    //$((doEdit) ? events_manage_table : $events_table).find('tbody').html(eventRows);
+                    $((doEdit) ? events_manage_table : $events_table).html(eventRows);
                     $((doEdit) ? events_manage_table : $events_table).show();
+                    $("#events_table").on('click', 'button.delete-handler', function(){
+                        deleteEventHandler($(this).data('handler'), $(this).data('event'))
+                    });
+                    $("#events_table").on('click', 'button.configure-uploader-handler', function(){
+                        XNAT.app.abu.configureUploaderForEventHandler($(this).data('handler'), $(this).data('event'), 'site')
+                    });
                 }
                 else {
                     $no_event_handlers.show();
@@ -111,6 +152,18 @@ $(function(){
 			$('#manageModalDiv').html(
                '<p id="no_events_defined" style="display:none;padding:20px;">There are no events currently defined for this site.</p>' +
                 '<p id="no_event_handlers" style="display:none;padding:20px;">There are no event handlers currently configured for this project.</p>' +
+                '<div id="events_manage_table" class="xnat-table" style="display:table;width:100%">' +
+                    '<dl class="header">' + 
+                         '<dl>' +
+                              '<dd class="col1">Event</dd>' +
+                              '<dd class="col2">Script ID</dd>' +
+                              '<dd class="col3">Description</dd>' +
+                              '<dd class="col4"></dd>' +
+                              '<dd class="col5"></dd>' +
+                         '</dl>' +
+                    '</dl>' +
+                '</div>' 
+                /*
                 '<table id="events_manage_table" class="xnat-table" style="display:table;width:100%">' +
                     '<thead>' +
                     '<th>Event</th>' +
@@ -122,19 +175,45 @@ $(function(){
                     '<tbody>' +
                     '</tbody>' +
                 '</table>' 
+                */
            ); 
            initHandlersTable(true);
-           $("#events_manage_table").on('click', 'a.delete-handler', function(){
+           $("#events_manage_table").on('click', 'button.delete-handler', function(){
                deleteEventHandler($(this).data('handler'), $(this).data('event'))
            });
-           $("#events_manage_table").on('click', 'a.configure-uploader-handler', function(){
-               XNAT.app.abu.configureUploaderForEventHandler($(this).data('handler'),'site')
+           $("#events_manage_table").on('click', 'button.configure-uploader-handler', function(){
+               XNAT.app.abu.configureUploaderForEventHandler($(this).data('handler'), $(this).data('event'), 'site')
            });
 
     }
 
     function initEventsMenu(){
         siteEventsManager.events = []; // reset array
+
+        $("#select_event").prop('disabled','disabled');
+		if (typeof XNAT.app.siteEventsManager.eventClasses === 'undefined') {
+			var eventClassesAjax = $.ajax({
+				type : "GET",
+		  		url: serverRoot+'/xapi/eventHandlers/automationEventClasses?XNAT_CSRF=' + window.csrfToken,
+				cache: false,
+				async: true,
+				context: this,
+				dataType: 'json'
+			});
+			eventClassesAjax.done( function( data, textStatus, jqXHR ) {
+				if (typeof data !== 'undefined') {
+					XNAT.app.siteEventsManager.eventClasses = data;
+                    populateEventsMenu();
+				}
+			});
+			eventClassesAjax.fail( function( data, textStatus, jqXHR ) {
+                xmodal.message('Error', 'An error occurred retrieving system events: ' + textStatus);
+			});
+		} else {
+            populateEventsMenu();
+        }
+
+    /*
         return xhr.getJSON({
             url: XNAT.url.restUrl('/data/automation/events'),
             success: function( response ){
@@ -185,6 +264,147 @@ $(function(){
                 //}
             }
         });
+    */
+    }
+
+
+    function getEventClassDisplayValueFromHandlers(_handlers, eventHandler){
+        var classPart = eventHandler.srcEventClass.substring(eventHandler.srcEventClass.lastIndexOf('.')); 
+        var matches=0;
+        for (var i=0; i<_handlers.length; i++) {
+            var classVal = _handlers[i].srcEventClass;
+            if (typeof classVal !== 'undefined' && classVal.endsWith(classPart) && !(eventHandler.srcEventClass == _handlers[i].srcEventClass)) {
+                matches++;
+            }
+        }
+        return (matches<1) ? classPart.substring(1) : eventHandler.srcEventClass;
+    }
+
+    function getEventClassDisplayValue(ins){
+        var classPart = ins.substring(ins.lastIndexOf('.')); 
+        var displayName;
+        var matches=0;
+        for (var i=0; i<XNAT.app.siteEventsManager.eventClasses.length; i++) {
+            var classVal = XNAT.app.siteEventsManager.eventClasses[i].class;
+            if (typeof classVal !== 'undefined' && classVal.endsWith(classPart)) {
+                matches++;
+                displayName = XNAT.app.siteEventsManager.eventClasses[i].displayName;
+            }
+        }
+        return (typeof displayName !== 'undefined' && displayName !== ins) ? displayName : (matches<=1) ? classPart.substring(1) : ins;
+    }
+
+    function populateEventsMenu(){
+
+        $('#select_eventClass').empty().append('<option></option>');
+        for (var i=0; i<XNAT.app.siteEventsManager.eventClasses.length; i++) {
+            if (typeof XNAT.app.siteEventsManager.eventClasses[i].class !== 'undefined') {
+                $('#select_eventClass').append('<option value="' + XNAT.app.siteEventsManager.eventClasses[i].class + '">' + getEventClassDisplayValue(XNAT.app.siteEventsManager.eventClasses[i].class) + '</option>');
+            }
+        }
+        xmodal.open({
+            title: 'Add Event Handler',
+            template: $('#addEventHandler'),
+            width: 600,
+            height: 350,
+            overflow: 'auto',
+            beforeShow: function(obj){
+                //chosenInit(obj.$modal.find('select.event, select.scriptId'), null, 300);
+                //obj.$modal.find('select.event, select.scriptId').chosen({
+                //    width: '300px',
+                //    disable_search_threshold: 6
+                //});
+            },
+            buttons: {
+                save: {
+                    label: 'Save',
+                    isDefault: true,
+                    close: false,
+                    action: doAddEventHandler
+                },
+                close: {
+                    label: 'Cancel'
+                }
+            }
+        });
+        updateEventIdSelect();
+        $('#select_eventClass').change(function(){
+            updateEventIdSelect();
+        });
+
+    }
+
+    function updateEventIdSelect(){
+        $('#select_event').empty().append('<option></option>');
+        $('#filterRow').css('display','none');
+        $('#filterDiv').html(filterableHtml);
+        for (var i=0; i<XNAT.app.siteEventsManager.eventClasses.length; i++) {
+            if ($('#select_eventClass').val() == XNAT.app.siteEventsManager.eventClasses[i].class) {
+                var eventIds = XNAT.app.siteEventsManager.eventClasses[i].eventIds;
+                if (typeof eventIds !== 'undefined' && eventIds.length>0) {
+                    for (var j=0; j<eventIds.length; j++) {
+                        var eventId = eventIds[j];
+                        $('#select_event').append('<option value="' + eventId + '">' + eventId + '</option>');
+                    }
+                }
+                var filterableFields = XNAT.app.siteEventsManager.eventClasses[i].filterableFields;
+                var filterableHtml = ""
+                $('#filterRow').css('display','none');
+                if (typeof filterableFields !== 'undefined') {
+                    for (var filterable in filterableFields) {
+                        if (!filterableFields.hasOwnProperty(filterable)) continue;
+                        var filterableVals = filterableFields[filterable];
+                        if (typeof filterableVals !== 'undefined' && filterableVals.length>0) {
+                            filterableHtml = filterableHtml + '<div style="width:100%;margin-top:5px;margin-bottom:5px">' + filterable + ' &nbsp;<select id="filter_sel_' + filterable + '" name="' + filterable + '" class="filter">';
+                            filterableHtml = filterableHtml + '<option value="">&lt;NONE&gt;</option>';
+                            for (var i=0; i<filterableVals.length; i++) {
+                                filterableHtml = filterableHtml + '<option value="' + filterableVals[i] + '">' + filterableVals[i] + '</option>';
+                            }
+                            filterableHtml = filterableHtml + '</select> <input type="text" id="filter_input_' + filterable + '" name="' + filterable +
+					 '" class="filter" style="display:none" size="15"/> <button class="customButton">Custom Value</button></div>';
+                        }
+                    }
+                }
+                if (filterableHtml.length>0) {
+                    $('#filterRow').css('display','table-row');
+                    $('#filterDiv').html(filterableHtml);
+                }
+                $("#select_event").prop('disabled',false);
+                break;
+            }
+        }
+/*
+        $(".customButton").click(function(event){
+            customInputToggle(event.target);
+        });
+*/
+        $(".customButton").each(function(){
+            var eventObject = $._data(this, 'events');
+            if (typeof eventObject == 'undefined' || typeof eventObject.click == 'undefined') {
+                $(this).click(function(event){
+                    customInputToggle(event.target);
+                });
+            }
+        });
+        $(".customButton").css('margin-left','5px');
+    }
+
+    function customInputToggle(ele){
+         $(ele).parent().find("input, select").each(function() {
+    		if ($(this).css('display') == 'none') {
+                $(this).css('display','inline');
+    		} else {
+                $(this).css('display','none');
+                //if ($(this).is("input")) {
+                    $(this).val("");
+                //}
+    		}
+    	});
+        if ($(ele).html() == "Selection Menu") {
+            $(ele).html("Custom Value");
+        } else {
+            $(ele).html("Selection Menu");
+        }
     }
 
     function initScriptsMenu(){
@@ -218,15 +438,26 @@ $(function(){
     }
 
     // initialize menus and table
-    initEventsMenu();
+    if (!handlersRendered) {
+        initHandlersTable(false);
+    }
     initScriptsMenu();
 
     function doAddEventHandler( xmodalObj ){
 
+	var filterVar = {};
+	var filterEle = $("select.filter, input.filter").filter(function() { return $(this).val() != "" });
+	for (var i=0; i<filterEle.length; i++) {
+		filterVar[filterEle[i].name]=[];
+		filterVar[filterEle[i].name].push($(filterEle[i]).val());
+	}
+
         var data = {
-            event: xmodalObj.__modal.find('select.event').val(),
+            eventClass: xmodalObj.__modal.find('select.eventClass').val(),
+            event: xmodalObj.__modal.find('select.event, input.event').filter(function() { return $(this).val() != "" }).val(),
             scriptId: xmodalObj.__modal.find('select.scriptId').val(),
-            description: xmodalObj.__modal.find('input.description').val()
+            description: xmodalObj.__modal.find('input.description').val(),
+            filters: filterVar
         };
 
         // TODO: Should we let them name the trigger? Is that worthwhile? (yes)
@@ -237,7 +468,41 @@ $(function(){
             xmodal.message('Missing Information','Please select an <b>Event</b> <i>and</i> <b>Script ID</b> to create an <br>Event Handler.');
             return false;
         }
+	XNAT.app.siteEventsManager.eventHandlerData = data;
+
+	var eventHandlerAjax = $.ajax({
+		type : "PUT",
+  		url:serverRoot+'/data/automation/handlers?XNAT_CSRF=' + window.csrfToken,
+		cache: false,
+		async: true,
+		data: JSON.stringify(data),
+		contentType: 'application/json'
+	});
+	eventHandlerAjax.done( function( data, textStatus, jqXHR ) {
+		if (typeof data !== 'undefined') {
+	                xmodal.message('Success', 'Your event handler was successfully added.', 'OK', { 
+	                        action: function(){
+	                            initHandlersTable(false);
+	                            if ($("#events_manage_table").length>0) {
+	                                initHandlersTable(true);
+	                            }
+	                            xmodal.closeAll($(xmodal.dialog.open),$('#xmodal-manage-events'));
+	                            // Trigger automation uploader to reload handlers
+	                            XNAT.app.abu.getAutomationHandlers();
+	                        }  
+	                    }
+	                );
+		}
+	});
+	eventHandlerAjax.fail( function( data, textStatus, jqXHR ) {
+                xmodal.message('Error', 'An error occurred: [' + data.statusText + '] ' + data.responseText, 'Close', {
+                    action: function(){
+                        xmodal.closeAll($(xmodal.dialog.open),$('#xmodal-manage-events'));
+                    }
+                });
+	});
 
+	/*
         xhr.put({
             url: XNAT.url.restUrl('/data/automation/handlers?XNAT_CSRF=' + window.csrfToken, null, false),
             data: data,
@@ -267,11 +532,51 @@ $(function(){
                 });
             }
         });
+	*/
     }
 
     function addEventHandler(){
+         initEventsMenu();
+/*
         xmodal.loading.open();
         initScriptsMenu().
+            //done(initEventsMenu().
+                done(function(){
+                    initEventsMenu();
+                    xmodal.loading.close();
+                    xmodal.open({
+                        title: 'Add Event Handler',
+                        template: $('#addEventHandler'),
+                        width: 500,
+                        height: 300,
+                        overflow: true,
+                        esc: false,
+                        enter: false,
+                        beforeShow: function(obj){
+                            var $menus = obj.$modal.find('select.event, select.scriptId');
+                            $menus.trigger('chosen:updated');
+                            //chosenInit($menus, null, 300);
+                            $menus.chosen({
+                                width: '300px',
+                                disable_search_threshold: 6
+                            });
+                        },
+                        buttons: {
+                            save: {
+                                label: 'Save',
+                                isDefault: true,
+                                close: false,
+                                action: doAddEventHandler
+                            },
+                            close: {
+                                label: 'Cancel'
+                            }
+                        }
+                    });
+                }
+            )
+*/
+	    /*	
             done(initEventsMenu().
                 done(function(){
                     xmodal.loading.close();
@@ -307,10 +612,11 @@ $(function(){
                 }
             )
         );
+	    */	
     }
 
     function doDeleteHandler( handlerId ){
-        var url = XNAT.url.restUrl('/data/automation/triggers/' + handlerId + "?XNAT_CSRF=" + window.csrfToken, null, false);
+        var url = serverRoot+'/data/automation/triggers/' + handlerId + "?XNAT_CSRF=" + window.csrfToken;
         if (window.jsdebug) console.log(url);
         xhr.delete({
             //type: 'DELETE',
@@ -337,9 +643,8 @@ $(function(){
     function deleteEventHandler( handlerId, event ){
         xmodal.confirm({
             title: 'Delete Event Handler?',
-            content: 'Are you sure you want to delete the handler for the <b>"' + event + '"</b> event? ' +
-            'Only the Event Handler will be deleted. The associated Script will still be available for use.',
-            width: 440,
+            content: 'Are you sure you want to delete the handler: <br><br><b>' + handlerId + '</b>?<br><br>Only the Event Handler will be deleted. The associated Script will still be available for use.',
+            width: 560,
             height: 220,
             okLabel: 'Delete',
             okClose: false, // don't close yet
@@ -354,7 +659,7 @@ $(function(){
     }
 
     // removed inline onclick attributes:
-    $events_table.on('click', 'a.delete-handler', function(){
+    $events_table.on('click', 'button.delete-handler', function(){
         deleteEventHandler($(this).data('handler'), $(this).data('event'));
     });
 
diff --git a/src/main/webapp/style/uploaders/fileuploader.css b/src/main/webapp/style/uploaders/fileuploader.css
index c33d6833aed5b82c9314c59d0b83778f54438466..6882f43dfcd1355987ee01fcee4e3360fec746bf 100644
--- a/src/main/webapp/style/uploaders/fileuploader.css
+++ b/src/main/webapp/style/uploaders/fileuploader.css
@@ -92,10 +92,10 @@ ad
 .abu-return-floatmessage {position:absolute;z-index:10001;width:auto;cursor:pointer;background-color:#FFFFCC; }
 .abu-return-message {width:auto;cursor:pointer;background-color:#FFFFCC; }
 
-.abu-options-div { position: relative; float: left; }
+.abu-options-div { position: relative; float: left; width: 430px; margin-left: 10px; }
 .abu-options-cb {
     display:block; /* or inline-block */
-    width: auto; padding: 7px 0; text-align:center; margin-left:10px; float:left;    
+    width: auto; padding: 7px 0; text-align:center; margin-left:10px; float:left; padding-top: 0px; padding-bottom: 0px;    
 }
 
 .abu-progress { position:relative; display:inline-block; width:250px; height:15px; border: 1px solid #ddd; padding: 0px; border-radius: 0px; margin-left: 10px; }
diff --git a/src/main/webapp/xnat-templates/screens/Scripts.vm b/src/main/webapp/xnat-templates/screens/Scripts.vm
index 82bb9c3229aca6f33af64b3cba13ebe1bffdc8e1..dacb9a5deeedb745d1820d45d68187dfd32e17a0 100644
--- a/src/main/webapp/xnat-templates/screens/Scripts.vm
+++ b/src/main/webapp/xnat-templates/screens/Scripts.vm
@@ -8,6 +8,112 @@
 #* @vtlvariable name="script" type="org.nrg.automation.entities.Script" *#
 #* @vtlvariable name="link" type="org.apache.turbine.services.pull.tools.TemplateLink" *#
 #* @vtlvariable name="error" type="java.lang.String" *#
+<style type="text/css">
+
+            #events_table .item, #events_table .header, #events_manage_table .item, #events_manage_table .header {
+                border-bottom: 1px solid #888;
+                font: 11px Arial, Helvetica, sans-serif;
+                margin-top: 0;
+                margin-bottom: 0;
+                padding: 4px;
+                overflow: auto;
+            }
+
+            dl.item, item.item {
+                display: block;
+            }
+
+            #events_table dl dl, #events_manage_table dl dl {
+                margin: 1px 0;
+            }
+
+            #events_table .header, #events_manage_table .header {
+                background-color: #ccc;
+                font-weight: bold;
+            }
+
+            #events_table dl dt, #events_table dl dd, #events_manage_table dl dt, #events_manage_table dl dd {
+                display: block;
+                float: left;
+                padding: 4px 0;
+            }
+
+            #events_table .item:hover {
+                background-color: #fff;
+            }
+
+            #events_manage_table .item:hover {
+                background-color: #fff;
+            }
+
+            #events_table dd, #events_manage_table dd {
+                margin-left: 20px;
+            }
+
+            #events_table dd.col1, #events_manage_table dd.col1 {
+                width: 140px;
+                margin-left: 10px
+            }
+
+            #events_table dd.col2, #events_manage_table dd.col2 {
+                width: 115px;
+            }
+
+            #events_table dd.col3, #events_manage_table dd.col3 {
+                width: 230px;
+            }
+
+            #events_table dd.col4, #events_manage_table dd.col4 {
+                width: 40px;
+            }
+
+            #events_table dd.col5, #events_manage_table dd.col5 {
+                width: 105px;
+            }
+
+            #events_table dd.col6, #events_manage_table dd.col6 {
+                width: 50px;
+            }
+
+            #events_table dd.col7, #events_manage_table dd.col7 {
+                width: 130px;
+            }
+
+            #events_table dd.colX, #events_manage_table dd.colX {
+                width: 90%;
+                padding-left: 70px;
+            }
+            #events_table dd.colC, #events_manage_table dd.colC {
+                width: 90%;
+                padding-left: 10px;
+                padding-top: 2px;
+                padding-bottom: 2px;
+            }
+
+            #events_table dd.colEx, #events_manage_table dd.colEx {
+                position: relative;
+            }
+
+            #events_table_title #events_manage_table_title {
+                font-weight: 700;
+            }
+            button.event-handler-button {
+                font: 11px Arial, Helvetica, sans-serif;
+                padding: 3px;
+                margin: -3px;
+            }
+
+            div.row3 {
+                float: right;
+                margin-top: 8px;
+            }
+
+            div.row4 {
+                clear: both;
+                margin-top: 8px;
+            }
+
+</style>
 
 
 <h3 style="margin:0 0 15px 0;">Automation</h3>
@@ -48,8 +154,16 @@
         <div id="addEventHandler" class="html-template">
             <table>
                 <tr>
-                    <td><label for="event" class="required"><strong>Event:</strong><i>*</i></label></td>
-                    <td><select id="select_event" name="event" class="event"></select></td>
+                    <td><label for="eventClass" class="required"><strong>Event Type:</strong><i>*</i></label></td>
+                    <td><select id="select_eventClass" name="eventClass" class="eventClass"></select></td>
+                </tr>
+                <tr>
+                    <td><label for="event" class="required"><strong>Event ID:</strong><i>*</i></label></td>
+                    <td><select id="select_event" name="event" class="event"></select> <input type="text" id="select_input" class="event" style="display:none" size="15"/> <button class="customButton">Custom Value</button></div></td>
+                </tr>
+                <tr id="filterRow">
+                    <td><label for="filters"><strong>Filters:</strong></label></td>
+                    <td><div id="filterDiv"></div></td>
                 </tr>
                 <tr>
                     <td><label for="scriptId" class="required"><strong>Script ID:</strong><i>*</i></label></td>
@@ -108,7 +222,7 @@
             <div class="yui-navset yui-navset-top bogus-tabs">
                 <ul class="yui-nav">
                     <li class="first selected"><a href="#automationEventHandlers"><em>Site Event Handlers</em></a></li>
-                    <li><a href="#automationEvents"><em>Events</em></a></li>
+                    ##<li><a href="#automationEvents"><em>Events</em></a></li>
                     <li><a href="#automationScripts"><em>Scripts</em></a></li>
                 </ul>
                 <div class="yui-content">
@@ -121,6 +235,7 @@
                         <div id="events_list">
 ##                            <p id="no_events_defined" style="display:none;padding:20px;">There are no events currently defined for this site.</p>
                             <p id="no_event_handlers" style="display:none;padding:20px;">There are no event handlers currently configured for this site.</p>
+                            <!--
                             <table id="events_table" class="xnat-table" style="display:none;width:100%;">
                                 <thead>
                                 <th>Event</th>
@@ -131,6 +246,9 @@
                                 ## content populated with XNAT.app.eventsManager.initEventsTable()
                                 </tbody>
                             </table>
+                            -->
+                            <div id="events_table" class="xnat-table" style="display:none;width:100%;">
+                            </div>
                             <br>
                             <b style="padding:0 8px;">Create a site-wide Event Handler: </b>
     <button type="button" id="add_event_handler" class="btn1" style="font-size:12px;" title="add an event handler">Add Event Handler</button>
@@ -139,39 +257,39 @@
 
                     </div>
 
-                    <!-- Events -->
-                    <div id="automationEvents" class="yui-hidden">
-
-                        <div id="events-container">
-
-                            <p id="no-events" style="display:none;">There are no Events defined for this site.</p>
-
-                            <table id="events-table" class="xnat-table" style="display:none;width:100%;">
-
-                                <thead>
-                                <th width="40%">Event ID</th>
-                                <th width="40%">Event Label</th>
+##                    <!-- Events -->
+##                    <div id="automationEvents" class="yui-hidden">
+##
+##                        <div id="events-container">
+##
+##                            <p id="no-events" style="display:none;">There are no Events defined for this site.</p>
+##
+##                            <table id="events-table" class="xnat-table" style="display:none;width:100%;">
+##
+##                                <thead>
+##                                <th width="40%">Event ID</th>
+##                                <th width="40%">Event Label</th>
 ##                                <th>Workflow</th>
-                                <th width="20%">&nbsp;</th>
-                                </thead>
-
-                                <tbody>
-
-                                ## events list inserted here via AJAX
-
-                                </tbody>
-
-                            </table>
-
-                            <br>
-
-                            <b style="padding:0 8px;">Define an Event from existing Workflows or create a new Event:</b>
-
-                            <button type="button" id="define-event-button" class="btn1" style="font-size:12px;" title="define an event">Define Event</button>
-
-                        </div>
-
-                    </div>
+##                                <th width="20%">&nbsp;</th>
+##                                </thead>
+##
+##                                <tbody>
+##
+##                                ## events list inserted here via AJAX
+##
+##                                </tbody>
+##
+##                            </table>
+##
+##                            <br>
+##
+##                            <b style="padding:0 8px;">Define an Event from existing Workflows or create a new Event:</b>
+##
+##                            <button type="button" id="define-event-button" class="btn1" style="font-size:12px;" title="define an event">Define Event</button>
+##
+##                        </div>
+##
+##                    </div>
 
                     <!-- Scripts -->
                     <div id="automationScripts" class="yui-hidden">
diff --git a/src/main/webapp/xnat-templates/screens/xnat_imageSessionData/upload/xnat_imageSessionData_scans.vm b/src/main/webapp/xnat-templates/screens/xnat_imageSessionData/upload/xnat_imageSessionData_scans.vm
index 02c587d218df468e13335ff64a75032c11c8a6d5..89df653c7cf6658897c1e8384b2675c8b8af8e9d 100644
--- a/src/main/webapp/xnat-templates/screens/xnat_imageSessionData/upload/xnat_imageSessionData_scans.vm
+++ b/src/main/webapp/xnat-templates/screens/xnat_imageSessionData/upload/xnat_imageSessionData_scans.vm
@@ -118,4 +118,4 @@ Other
 		</tr>
 	#end
 	</table>
-</div>
\ No newline at end of file
+</div>
diff --git a/src/main/webapp/xnat-templates/screens/xnat_imageSessionData/xnat_imageSessionData_scans.vm b/src/main/webapp/xnat-templates/screens/xnat_imageSessionData/xnat_imageSessionData_scans.vm
index ad392bdcf1d91ae438abb2a9a1f90c7e03ddfd52..b5de0812351fb963d717e848c0e53ed652866480 100644
--- a/src/main/webapp/xnat-templates/screens/xnat_imageSessionData/xnat_imageSessionData_scans.vm
+++ b/src/main/webapp/xnat-templates/screens/xnat_imageSessionData/xnat_imageSessionData_scans.vm
@@ -68,7 +68,7 @@
                 #else
                     #renderEmptyResourceCount()
                 #end
-                #if($user.canEdit($om))
+    		#if ($data.getSession().getAttribute("userHelper").canEdit($item))
                     <a class='uploadLink' style='display:none' href='' onclick='return false;' data-type='xnat:imageScanData' data-props='$!scan.getType()' data-uri='$content.getURI("/data/experiments/$om.getId()/scans/$scan.getId()")'>Upload</a>
                 #end
             </td>
diff --git a/src/main/webapp/xnat-templates/screens/xnat_projectData/report/manage_tab/ResourceManagement.vm b/src/main/webapp/xnat-templates/screens/xnat_projectData/report/manage_tab/ResourceManagement.vm
index f7aa07c98d8d9e028514429b5e0a5d6a73c94daf..efbe2adf96a142b8ca0fd7798eca2bfd33df348c 100644
--- a/src/main/webapp/xnat-templates/screens/xnat_projectData/report/manage_tab/ResourceManagement.vm
+++ b/src/main/webapp/xnat-templates/screens/xnat_projectData/report/manage_tab/ResourceManagement.vm
@@ -91,21 +91,26 @@
             }
 
             #pResource_exist dd.col1 {
-                width: 60px;
+                width: 40px;
                 padding: 0px;
                 margin-left: 10px
             }
 
+            dd.col1 button {
+                padding: 2px;
+                font-size: 11px;
+            }
+
             #pResource_exist dd.col2 {
                 width: 120px;
             }
 
             #pResource_exist dd.col3 {
-                width: 70px;
+                width: 85px;
             }
 
             #pResource_exist dd.col4 {
-                width: 70px;
+                width: 85px;
             }
 
             #pResource_exist dd.col5 {
@@ -113,7 +118,7 @@
             }
 
             #pResource_exist dd.col6 {
-                width: 50px;
+                width: 40px;
             }
 
             #pResource_exist dd.col7 {
diff --git a/src/main/webapp/xnat-templates/screens/xnat_projectData/xnat_projectData_summary_manage.vm b/src/main/webapp/xnat-templates/screens/xnat_projectData/xnat_projectData_summary_manage.vm
index 5b2a918ef80e104ed0b88485b16ab93e4922788b..8d2f168f1486998b9a27deb0d1a67cf0bdf18c3e 100644
--- a/src/main/webapp/xnat-templates/screens/xnat_projectData/xnat_projectData_summary_manage.vm
+++ b/src/main/webapp/xnat-templates/screens/xnat_projectData/xnat_projectData_summary_manage.vm
@@ -40,6 +40,110 @@
         border: 1px solid #d0d0d0;
     }
 
+
+            #events_table .item, #events_table .header, #events_manage_table .item, #events_manage_table .header {
+                border-bottom: 1px solid #888;
+                font: 11px Arial, Helvetica, sans-serif;
+                margin-top: 0;
+                margin-bottom: 0;
+                padding: 4px;
+                overflow: auto;
+            }
+
+            dl.item, item.item {
+                display: block;
+            }
+
+            #events_table dl dl, #events_manage_table dl dl {
+                margin: 1px 0;
+            }
+
+            #events_table .header, #events_manage_table .header {
+                background-color: #ccc;
+                font-weight: bold;
+            }
+
+            #events_table dl dt, #events_table dl dd, #events_manage_table dl dt, #events_manage_table dl dd {
+                display: block;
+                float: left;
+                padding: 4px 0;
+            }
+
+            #events_table .item:hover {
+                background-color: #fff;
+            }
+
+            #events_manage_table .item:hover {
+                background-color: #fff;
+            }
+
+            #events_table dd, #events_manage_table dd {
+                margin-left: 20px;
+            }
+
+            #events_table dd.col1, #events_manage_table dd.col1 {
+                width: 140px;
+                margin-left: 10px
+            }
+
+            #events_table dd.col2, #events_manage_table dd.col2 {
+                width: 115px;
+            }
+
+            #events_table dd.col3, #events_manage_table dd.col3 {
+                width: 230px;
+            }
+
+            #events_table dd.col4, #events_manage_table dd.col4 {
+                width: 40px;
+            }
+
+            #events_table dd.col5, #events_manage_table dd.col5 {
+                width: 105px;
+            }
+
+            #events_table dd.col6, #events_manage_table dd.col6 {
+                width: 50px;
+            }
+
+            #events_table dd.col7, #events_manage_table dd.col7 {
+                width: 130px;
+            }
+
+            #events_table dd.colX, #events_manage_table dd.colX {
+                width: 90%;
+                padding-left: 70px;
+            }
+            #events_table dd.colC, #events_manage_table dd.colC {
+                width: 90%;
+                padding-left: 10px;
+		padding-top: 2px;
+		padding-bottom: 2px;
+            }
+
+            #events_table dd.colEx, #events_manage_table dd.colEx {
+                position: relative;
+            }
+
+            #events_table_title #events_manage_table_title {
+                font-weight: 700;
+            }
+            button.event-handler-button {
+                font: 11px Arial, Helvetica, sans-serif;
+                padding: 3px;
+                margin: -3px;
+            }
+
+            div.row3 {
+                float: right;
+                margin-top: 8px;
+            }
+
+            div.row4 {
+                clear: both;
+                margin-top: 8px;
+            }
+
 </style>
 ##<script type="text/javascript">
 ##    writeScripts([
@@ -57,8 +161,16 @@
 <div id="addEventHandler" class="html-template">
     <table>
         <tr>
-            <td><label for="event" class="required"><strong>Event:</strong><i>*</i></label></td>
-            <td><select id="select_event" name="event" class="event"></select></td>
+            <td><label for="eventClass" class="required"><strong>Event Type:</strong><i>*</i></label></td>
+            <td><select id="select_eventClass" name="eventClass" class="eventClass"></select></td>
+        </tr>
+        <tr>
+            <td><label for="event" class="required"><strong>Event ID:</strong><i>*</i></label></td>
+            <td><select id="select_event" name="event" class="event"></select> <input type="text" id="select_input" class="event" style="display:none" size="15"/> <button class="customButton">Custom Value</button></div></td>
+        </tr>
+        <tr id="filterRow">
+            <td><label for="filters"><strong>Filters:</strong></label></td>
+            <td><div id="filterDiv"></div></td>
         </tr>
         <tr>
             <td><label for="scriptId" class="required"><strong>Script ID:</strong><i>*</i></label></td>
@@ -364,6 +476,7 @@
     <div id="events_list" style="min-height:120px;">
         <p id="no_events_defined" style="display:none;padding:20px;">There are no events currently defined for this site.</p>
         <p id="no_event_handlers" style="display:none;padding:20px;">There are no event handlers currently configured for this project.</p>
+        <!--
         <table id="events_table" class="xnat-table" style="display:none;width:100%;">
             <thead>
             <th>Event</th>
@@ -374,6 +487,9 @@
             ## content populated with XNAT.app.eventsManager.initEventsTable()
             </tbody>
         </table>
+        -->
+        <div id="events_table" class="xnat-table" style="display:none;width:100%;">
+        </div>
         <br>
         <button type="button" id="manage_event_handlers" class="btn1" style="font-size:12px;">Manage Event Handlers</button>
         <div class="alert" style="margin:15px 0;max-width:696px;min-width:400px;">