diff --git a/gstlal-burst/bin/Makefile.am b/gstlal-burst/bin/Makefile.am
index b880b819405e330f5c9bbb79939508a0c1014828..58cd60b32564f00991fff38ae84a03a65e411109 100644
--- a/gstlal-burst/bin/Makefile.am
+++ b/gstlal-burst/bin/Makefile.am
@@ -1,3 +1,8 @@
 dist_bin_SCRIPTS = \
 	gstlal_excesspower \
-	gstlal_excesspower_trigvis
+	gstlal_excesspower_trigvis \
+	gstlal_feature_extractor \
+	gstlal_feature_extractor_pipe \
+	gstlal_feature_extractor_pipe_online \
+	gstlal_feature_extractor_whitener_check \
+	gstlal_feature_extractor_template_overlap
diff --git a/gstlal-ugly/bin/gstlal_feature_extractor b/gstlal-burst/bin/gstlal_feature_extractor
similarity index 93%
rename from gstlal-ugly/bin/gstlal_feature_extractor
rename to gstlal-burst/bin/gstlal_feature_extractor
index b506d89b47dc385c2fa4fd95a3ff7a7bb967428f..b5b290530604479fa17dbdc8a39689782de354ab 100755
--- a/gstlal-ugly/bin/gstlal_feature_extractor
+++ b/gstlal-burst/bin/gstlal_feature_extractor
@@ -164,17 +164,18 @@ from glue.ligolw.utils import process as ligolw_process
 from glue.ligolw.utils import segments as ligolw_segments
 
 from gstlal import aggregator
-from gstlal import auxcache
 from gstlal import bottle
 from gstlal import datasource
 from gstlal import httpinterface
-from gstlal import idq_multirate_datasource
-from gstlal import idq_utils
-from gstlal import multichannel_datasource
 from gstlal import pipeio
 from gstlal import pipeparts
 from gstlal import simplehandler
-from gstlal import sngltriggertable
+
+from gstlal.fxtools import auxcache
+from gstlal.fxtools import multichannel_datasource
+from gstlal.fxtools import multirate_datasource
+from gstlal.fxtools import sngltriggertable
+from gstlal.fxtools import utils
 
 #
 # Make sure we have sufficient resources
@@ -244,7 +245,7 @@ class MultiChannelHandler(simplehandler.Handler):
 		self.feature_start_time = options.feature_start_time
 		self.feature_end_time = options.feature_end_time
 		self.columns = ['start_time', 'stop_time', 'trigger_time', 'frequency', 'q', 'snr', 'phase', 'sigmasq', 'chisq']
-		self.feature_queue = idq_utils.FeatureQueue(self.keys, self.columns, self.sample_rate)
+		self.feature_queue = utils.FeatureQueue(self.keys, self.columns, self.sample_rate)
 
 		# set whether data source is live
 		self.is_live = data_source_info.data_source in data_source_info.live_sources
@@ -257,7 +258,7 @@ class MultiChannelHandler(simplehandler.Handler):
 
 		# feature saving properties
 		if options.save_format == 'hdf5':
-			self.fdata = idq_utils.HDF5FeatureData(self.columns, keys = self.keys, cadence = self.cadence)
+			self.fdata = utils.HDF5FeatureData(self.columns, keys = self.keys, cadence = self.cadence)
 
 		elif options.save_format == 'ascii':
 			self.header = "# %18s\t%20s\t%20s\t%10s\t%8s\t%8s\t%8s\t%10s\t%s\n" % ("start_time", "stop_time", "trigger_time", "frequency", "phase", "q", "chisq", "snr", "channel")
@@ -330,12 +331,12 @@ class MultiChannelHandler(simplehandler.Handler):
 					self.last_save_time = self.timestamp
 					self.last_persist_time = self.timestamp
 					if options.save_format =='hdf5':
-						duration = idq_utils.floor_div(self.timestamp + self.persist_cadence, self.persist_cadence) - self.timestamp
+						duration = utils.floor_div(self.timestamp + self.persist_cadence, self.persist_cadence) - self.timestamp
 						self.set_hdf_file_properties(self.timestamp, duration)
 
 				# Save triggers once per cadence if saving to disk
 				if options.save_format == 'hdf5' or options.save_format == 'ascii':
-					if self.timestamp and idq_utils.in_new_epoch(self.timestamp, self.last_save_time, self.cadence) or (self.timestamp == self.feature_end_time):
+					if self.timestamp and utils.in_new_epoch(self.timestamp, self.last_save_time, self.cadence) or (self.timestamp == self.feature_end_time):
 						logger.info("saving features to disk at timestamp = %d" % self.timestamp)
 						if options.save_format == 'hdf5':
 							self.to_hdf_file()
@@ -347,7 +348,7 @@ class MultiChannelHandler(simplehandler.Handler):
 
 				# persist triggers once per persist cadence if using hdf5 format
 				if options.save_format == 'hdf5':
-					if self.timestamp and idq_utils.in_new_epoch(self.timestamp, self.last_persist_time, self.persist_cadence):
+					if self.timestamp and utils.in_new_epoch(self.timestamp, self.last_persist_time, self.persist_cadence):
 						logger.info("persisting features to disk at timestamp = %d" % self.timestamp)
 						self.finish_hdf_file()
 						self.last_persist_time = self.timestamp
@@ -438,7 +439,7 @@ class MultiChannelHandler(simplehandler.Handler):
 		# Only write triggers to disk where the associated data structure has more
 		# than the header stored within.
 		if len(self.fdata) > 1 :
-			fname = '%s-%d-%d.%s' % (self.tag, idq_utils.floor_div(self.last_save_time, self.cadence), self.cadence, "trg")
+			fname = '%s-%d-%d.%s' % (self.tag, utils.floor_div(self.last_save_time, self.cadence), self.cadence, "trg")
 			path = os.path.join(self.out_path, self.tag, self.tag+"-"+str(fname.split("-")[2])[:5])
 			fpath = os.path.join(path, fname)
 			tmpfile = fpath+"~"
@@ -459,7 +460,7 @@ class MultiChannelHandler(simplehandler.Handler):
 		Uses the T050017 filenaming convention.
 		NOTE: This method should only be called by an instance that is locked.
 		"""
-		self.fdata.dump(self.tmp_path, self.fname, idq_utils.floor_div(self.last_save_time, self.cadence), tmp = True)
+		self.fdata.dump(self.tmp_path, self.fname, utils.floor_div(self.last_save_time, self.cadence), tmp = True)
 
 	def finish_hdf_file(self):
 		"""
@@ -494,9 +495,9 @@ class MultiChannelHandler(simplehandler.Handler):
 		Also takes care of creating new directories as needed and removing any leftover temporary files.
 		"""
 		# set/update file names and directories with new gps time and duration
-		self.fname = os.path.splitext(idq_utils.to_trigger_filename(self.basename, start_time, duration, 'h5'))[0]
-		self.fpath = idq_utils.to_trigger_path(os.path.abspath(self.out_path), self.basename, start_time, self.job_id, self.subset_id)
-		self.tmp_path = idq_utils.to_trigger_path(self.tmp_dir, self.basename, start_time, self.job_id, self.subset_id)
+		self.fname = os.path.splitext(utils.to_trigger_filename(self.basename, start_time, duration, 'h5'))[0]
+		self.fpath = utils.to_trigger_path(os.path.abspath(self.out_path), self.basename, start_time, self.job_id, self.subset_id)
+		self.tmp_path = utils.to_trigger_path(self.tmp_dir, self.basename, start_time, self.job_id, self.subset_id)
 
 		# create temp and output directories if they don't exist
 		aggregator.makedir(self.fpath)
@@ -735,7 +736,7 @@ duration = options.feature_end_time - options.feature_start_time
 logdir = os.path.join(options.out_path, 'logs', options.job_id)
 aggregator.makedir(logdir)
 
-logger = idq_utils.get_logger('gstlal-feature-extractor_%d-%d' % (options.feature_start_time, duration), rootdir=logdir, verbose=options.verbose)
+logger = utils.get_logger('gstlal-feature-extractor_%d-%d' % (options.feature_start_time, duration), rootdir=logdir, verbose=options.verbose)
 logger.info("writing log to %s" % logdir)
 
 #
@@ -782,8 +783,8 @@ for subset_id, channel_subset in enumerate(data_source_info.channel_subsets, 1):
 		try:
 			# get path where triggers are located
 			duration = options.feature_end_time - options.feature_start_time
-			fname = idq_utils.to_trigger_filename(basename, options.feature_start_time, duration, 'h5')
-			fpath = idq_utils.to_trigger_path(os.path.abspath(options.out_path), basename, options.feature_start_time, options.job_id, str(subset_id).zfill(4))
+			fname = utils.to_trigger_filename(basename, options.feature_start_time, duration, 'h5')
+			fpath = utils.to_trigger_path(os.path.abspath(options.out_path), basename, options.feature_start_time, options.job_id, str(subset_id).zfill(4))
 			trg_file = os.path.join(fpath, fname)
 
 			# visit groups within a given hdf5 file
@@ -879,19 +880,19 @@ for subset_id, channel_subset in enumerate(data_source_info.channel_subsets, 1):
 
 		# generate templates
 		if options.waveform == 'half_sine_gaussian':
-			waveforms[channel] = idq_utils.HalfSineGaussianGenerator((flow, fhigh), (qlow, qhigh), rates, mismatch=options.mismatch, downsample_factor=downsample_factor)
+			waveforms[channel] = utils.HalfSineGaussianGenerator((flow, fhigh), (qlow, qhigh), rates, mismatch=options.mismatch, downsample_factor=downsample_factor)
 		elif options.waveform == 'sine_gaussian':
-			waveforms[channel] = idq_utils.SineGaussianGenerator((flow, fhigh), (qlow, qhigh), rates, mismatch=options.mismatch, downsample_factor=downsample_factor)
+			waveforms[channel] = utils.SineGaussianGenerator((flow, fhigh), (qlow, qhigh), rates, mismatch=options.mismatch, downsample_factor=downsample_factor)
 		else:
 			raise NotImplementedError
 
 		if options.latency_output:
-			head[channel] = pipeparts.mklatency(pipeline, head[channel], name=idq_utils.latency_name('beforewhitening', 2, channel))
+			head[channel] = pipeparts.mklatency(pipeline, head[channel], name=utils.latency_name('beforewhitening', 2, channel))
 
 		# whiten auxiliary channel data
-		for rate, thishead in idq_multirate_datasource.mkwhitened_multirate_src(pipeline, head[channel], rates, samp_rate, instrument, channel_name = channel, width=32, nxydump_segment=options.nxydump_segment).items():
+		for rate, thishead in multirate_datasource.mkwhitened_multirate_src(pipeline, head[channel], rates, samp_rate, instrument, channel_name = channel, width=32, nxydump_segment=options.nxydump_segment).items():
 			if options.latency_output:
-				thishead = pipeparts.mklatency(pipeline, thishead, name=idq_utils.latency_name('afterwhitening', 3, channel, rate))
+				thishead = pipeparts.mklatency(pipeline, thishead, name=utils.latency_name('afterwhitening', 3, channel, rate))
 
 			# determine whether to do time-domain or frequency-domain convolution
 			time_domain = (waveforms[channel].sample_pts[rate]*rate) < (5*waveforms[channel].sample_pts[rate]*numpy.log2(rate))
@@ -903,7 +904,7 @@ for subset_id, channel_subset in enumerate(data_source_info.channel_subsets, 1):
 
 			# add queues, change stream format, add tags
 			if options.latency_output:
-				thishead = pipeparts.mklatency(pipeline, thishead, name=idq_utils.latency_name('afterFIRbank', 4, channel, rate))
+				thishead = pipeparts.mklatency(pipeline, thishead, name=utils.latency_name('afterFIRbank', 4, channel, rate))
 			thishead = pipeparts.mkqueue(pipeline, thishead, max_size_buffers = 1, max_size_bytes = 0, max_size_time = 0)
 			thishead = pipeparts.mktogglecomplex(pipeline, thishead)
 			thishead = pipeparts.mkcapsfilter(pipeline, thishead, caps = "audio/x-raw, format=Z64LE, rate=%i" % rate)
@@ -918,7 +919,7 @@ for subset_id, channel_subset in enumerate(data_source_info.channel_subsets, 1):
 			thishead = pipeparts.mktrigger(pipeline, tee, rate, max_snr = True)
 
 			if options.latency_output:
-				thishead = pipeparts.mklatency(pipeline, thishead, name=idq_utils.latency_name('aftertrigger', 5, channel, rate))
+				thishead = pipeparts.mklatency(pipeline, thishead, name=utils.latency_name('aftertrigger', 5, channel, rate))
 
 			# link to src for processing by appsync
 			src[(channel, rate)] = thishead
diff --git a/gstlal-ugly/bin/gstlal_feature_extractor_pipe b/gstlal-burst/bin/gstlal_feature_extractor_pipe
similarity index 95%
rename from gstlal-ugly/bin/gstlal_feature_extractor_pipe
rename to gstlal-burst/bin/gstlal_feature_extractor_pipe
index fb75a5d866a7c300f415ee1100cd18084e33f967..eba36ea6b5e68c29a02168147348f2b1105a5bf9 100755
--- a/gstlal-ugly/bin/gstlal_feature_extractor_pipe
+++ b/gstlal-burst/bin/gstlal_feature_extractor_pipe
@@ -45,9 +45,10 @@ import glue.ligolw.utils.segments as ligolw_segments
 from gstlal import inspiral, inspiral_pipe
 from gstlal import dagparts as gstlaldagparts
 from gstlal import datasource
-from gstlal import multichannel_datasource
-from gstlal import idq_multirate_datasource
-from gstlal import idq_utils
+
+from gstlal.fxtools import multichannel_datasource
+from gstlal.fxtools import multirate_datasource
+from gstlal.fxtools import utils
 
 class LIGOLWContentHandler(ligolw.LIGOLWContentHandler):
 	pass
@@ -71,7 +72,7 @@ def breakupseg(seg, maxextent, overlap):
 	while abs(seg):
 		if (seg[0] + maxextent + overlap) < end:
 			# Round down segment gps end time to integer multiple of cadence.
-			seglist.append(segments.segment(seg[0], idq_utils.floor_div(int(seg[0]) + maxextent + overlap, options.cadence)))
+			seglist.append(segments.segment(seg[0], utils.floor_div(int(seg[0]) + maxextent + overlap, options.cadence)))
 			seg = segments.segment(seglist[-1][1] - overlap, seg[1])
 		else:
 			seglist.append(segments.segment(seg[0], end))
@@ -88,7 +89,7 @@ def breakupsegs(seglist, maxextent, overlap):
 def analysis_segments(ifo, allsegs, boundary_seg, segment_length, max_template_length = 30):
 	segsdict = segments.segmentlistdict()
 	# 512 seconds for the whitener to settle + the maximum template_length
-	start_pad = idq_multirate_datasource.PSD_DROP_TIME + max_template_length
+	start_pad = multirate_datasource.PSD_DROP_TIME + max_template_length
 
 	segsdict[ifo] = segments.segmentlist([boundary_seg])
 	segsdict[ifo] = segsdict[ifo].protract(start_pad)
@@ -132,7 +133,7 @@ def feature_extractor_node_gen(gstlalFeatureExtractorJob, dag, parent_nodes, seg
 			channels[0] = channels[0].split('=')[1]
 
 			outpath = os.path.join(options.out_path, "gstlal_feature_extractor")
-			trig_start = int(seg[0]) + idq_multirate_datasource.PSD_DROP_TIME + max_template_length
+			trig_start = int(seg[0]) + multirate_datasource.PSD_DROP_TIME + max_template_length
 
 			feature_extractor_nodes[(ii, seg)] = \
 				inspiral_pipe.generic_node(gstlalFeatureExtractorJob, dag, parent_nodes = dep_nodes,
@@ -207,7 +208,7 @@ def parse_command_line():
 
 	# sanity check to enforce a minimum segment length
 	# Minimum segment length chosen so that the overlap is a ~33% hit in run time
-	min_segment_length = int(4 * idq_multirate_datasource.PSD_DROP_TIME)
+	min_segment_length = int(4 * multirate_datasource.PSD_DROP_TIME)
 	assert options.segment_length >= min_segment_length
 
 
diff --git a/gstlal-ugly/bin/gstlal_feature_extractor_pipe_online b/gstlal-burst/bin/gstlal_feature_extractor_pipe_online
similarity index 97%
rename from gstlal-ugly/bin/gstlal_feature_extractor_pipe_online
rename to gstlal-burst/bin/gstlal_feature_extractor_pipe_online
index 2e88d93e53ec21f2cfc89b4fec3e21198a444b6f..ab94880f08ec43e9b45ffb54a50ce23bc9fb7bf4 100755
--- a/gstlal-ugly/bin/gstlal_feature_extractor_pipe_online
+++ b/gstlal-burst/bin/gstlal_feature_extractor_pipe_online
@@ -17,7 +17,7 @@
 # 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 """
-This program makes a dag to run gstlal_feature_extractor offline
+This program makes a dag to run gstlal_feature_extractor online
 """
 
 __author__ = 'Duncan Meacher <duncan.meacher@ligo.org>, Patrick Godwin <patrick.godwin@ligo.org>'
@@ -45,9 +45,10 @@ import glue.ligolw.utils.segments as ligolw_segments
 from gstlal import inspiral, inspiral_pipe
 from gstlal import dagparts as gstlaldagparts
 from gstlal import datasource
-from gstlal import multichannel_datasource
-from gstlal import idq_multirate_datasource
-from gstlal import idq_utils
+
+from gstlal.fxtools import multichannel_datasource
+from gstlal.fxtools import multirate_datasource
+from gstlal.fxtools import utils
 
 class LIGOLWContentHandler(ligolw.LIGOLWContentHandler):
 	pass
diff --git a/gstlal-ugly/bin/gstlal_feature_extractor_template_overlap b/gstlal-burst/bin/gstlal_feature_extractor_template_overlap
similarity index 97%
rename from gstlal-ugly/bin/gstlal_feature_extractor_template_overlap
rename to gstlal-burst/bin/gstlal_feature_extractor_template_overlap
index 2ae23886b1b62ed6aa7b57498537ccdc5ca0d774..220ab60c50cbbd0e54210d0f54590fe7b6259d26 100755
--- a/gstlal-ugly/bin/gstlal_feature_extractor_template_overlap
+++ b/gstlal-burst/bin/gstlal_feature_extractor_template_overlap
@@ -37,9 +37,9 @@ import numpy
 import lal
 from glue import markup
 
-from gstlal import idq_utils
 from gstlal import plotutil
 from gstlal import aggregator
+from gstlal.fxtools import utils
 
 import matplotlib
 matplotlib.use('Agg')
@@ -249,9 +249,9 @@ if __name__ == '__main__':
 	flow = min_samp_rate / 4.
 
 	if options.waveform == 'sine_gaussian':
-		waveforms = idq_utils.SineGaussianGenerator((flow, fhigh), (qlow, qhigh), rates, mismatch = options.mismatch, downsample_factor=downsample_factor)
+		waveforms = utils.SineGaussianGenerator((flow, fhigh), (qlow, qhigh), rates, mismatch = options.mismatch, downsample_factor=downsample_factor)
 	elif options.waveform == 'half_sine_gaussian':
-		waveforms = idq_utils.HalfSineGaussianGenerator((flow, fhigh), (qlow, qhigh), rates, mismatch = options.mismatch, downsample_factor=downsample_factor)
+		waveforms = utils.HalfSineGaussianGenerator((flow, fhigh), (qlow, qhigh), rates, mismatch = options.mismatch, downsample_factor=downsample_factor)
 	else:
 		raise NotImplementedError
 	basis_params = waveforms.parameter_grid
diff --git a/gstlal-ugly/bin/gstlal_feature_extractor_whitener_check b/gstlal-burst/bin/gstlal_feature_extractor_whitener_check
similarity index 99%
rename from gstlal-ugly/bin/gstlal_feature_extractor_whitener_check
rename to gstlal-burst/bin/gstlal_feature_extractor_whitener_check
index 18693586fe5c50c387d7ebd8a4509a19954fe57c..b732fbb945614e484aa3cc00463de24bea656574 100755
--- a/gstlal-ugly/bin/gstlal_feature_extractor_whitener_check
+++ b/gstlal-burst/bin/gstlal_feature_extractor_whitener_check
@@ -42,11 +42,12 @@ import lal
 from gstlal import aggregator
 from gstlal import pipeio
 from gstlal import datasource
-from gstlal import multichannel_datasource
 from gstlal import reference_psd
 from gstlal import pipeparts
 from gstlal import simplehandler
 
+from gstlal.fxtools import multichannel_datasource
+
 # global settings for whitening properties
 PSD_FFT_LENGTH = 32
 PSD_DROP_TIME = 16 * PSD_FFT_LENGTH
diff --git a/gstlal-burst/configure.ac b/gstlal-burst/configure.ac
index 6981690490912c8d1fdd61662458482b51fbbb70..decd6ed8d321570b788eaf1d2db01fd65ae9aee4 100644
--- a/gstlal-burst/configure.ac
+++ b/gstlal-burst/configure.ac
@@ -23,7 +23,8 @@ AC_CONFIG_FILES([ \
 	debian/control \
 	debian/Makefile \
 	python/Makefile \
-	python/excesspower/Makefile
+	python/excesspower/Makefile \
+	python/fxtools/Makefile
 ])
 
 
@@ -183,6 +184,25 @@ PKG_CHECK_MODULES([gstreamer_audio], [gstreamer-audio-${GSTREAMER_AUDIO_RELEASE}
 AC_SUBST([gstreamer_audio_CFLAGS])
 AC_SUBST([gstreamer_audio_LIBS])
 
+#
+# Check for GObject Introspection
+#
+
+
+AC_SUBST([MIN_GOBJECT_INTROSPECTION_VERSION], [1.30.0])
+GOBJECT_INTROSPECTION_CHECK([${MIN_GOBJECT_INTROSPECTION_VERSION}])
+AC_SUBST([GIR_VERSION], [${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}])
+AC_SUBST([GIR_VERSION_], [${GIR_VERSION/./_}])
+AS_IF([test "x$found_introspection" = "xyes"], [
+    AC_SUBST([girdir], ["\${datadir}/gir-1.0"])
+    AC_SUBST([typelibdir], ["\${libdir}/girepository-1.0"])
+    AC_MSG_NOTICE([If you have chosen to install the software in a location not included in your gobject introspection typelib search path, you might need to add the directory
+
+    $typelibdir
+
+to your GI_TYPELIB_PATH environment variable.])
+])
+
 
 #
 # Check for PyGObject
@@ -240,7 +260,7 @@ AX_PYTHON_PYLAL()
 #
 
 
-AC_SUBST([MIN_GSTLAL_VERSION], [0.8.0])
+AC_SUBST([MIN_GSTLAL_VERSION], [1.3.0])
 PKG_CHECK_MODULES([GSTLAL], [gstlal >= ${MIN_GSTLAL_VERSION}])
 AC_SUBST([GSTLAL_VERSION], [`$PKG_CONFIG --modversion gstlal`])
 AX_GSTLAL_SPLIT_VERSION([GSTLAL_VERSION])
@@ -255,12 +275,20 @@ AC_SUBST([GSTLAL_LIBS])
 #
 
 
-AC_SUBST([MIN_GSTLAL_UGLY_VERSION], [0.7.0])
+AC_SUBST([MIN_GSTLAL_UGLY_VERSION], [1.4.0])
 AX_GSTLAL_SPLIT_VERSION([GSTLAL_UGLY_VERSION])
 AC_SUBST([GSTLAL_UGLY_VERSION_MAJOR])
 AC_SUBST([GSTLAL_UGLY_VERSION_MINOR])
 AC_SUBST([GSTLAL_UGLY_VERSION_POINT])
 
+# 
+# Check for GSL 
+# 
+ 
+ 
+PKG_CHECK_MODULES([GSL], [gsl]) 
+AC_SUBST([GSL_CFLAGS])
+AC_SUBST([GSL_LIBS])
 
 #
 # Output configure information
diff --git a/gstlal-burst/gst/lal/Makefile.am b/gstlal-burst/gst/lal/Makefile.am
index 95a9ea74582a2d5c67608ee6df3c8c943a088e79..6b0cacaf2d2d4134cb3298de5f0eaaa22e1e047d 100644
--- a/gstlal-burst/gst/lal/Makefile.am
+++ b/gstlal-burst/gst/lal/Makefile.am
@@ -4,8 +4,10 @@ plugin_LTLIBRARIES = lib@GSTPLUGINPREFIX@gstlalburst.la
 
 lib@GSTPLUGINPREFIX@gstlalburst_la_SOURCES = \
 	gstlalburst.c \
+	gstlal_trigger.h gstlal_trigger.c \
 	gstlal_string_triggergen.c gstlal_string_triggergen.h
-lib@GSTPLUGINPREFIX@gstlalburst_la_CFLAGS = $(AM_CFLAGS) $(LAL_CFLAGS) $(GSTLAL_CFLAGS) $(gstreamer_CFLAGS)
+
+lib@GSTPLUGINPREFIX@gstlalburst_la_CFLAGS = $(AM_CFLAGS) $(GSL_CFLAGS) $(LAL_CFLAGS) $(GSTLAL_CFLAGS) $(gstreamer_CFLAGS)
 lib@GSTPLUGINPREFIX@gstlalburst_la_LIBADD = $(top_builddir)/lib/libgstlalburst.la
-lib@GSTPLUGINPREFIX@gstlalburst_la_LDFLAGS = $(AM_LDFLAGS) $(LAL_LIBS) $(GSTLAL_LIBS) $(gstreamer_LIBS) $(GSTLAL_PLUGIN_LDFLAGS)
+lib@GSTPLUGINPREFIX@gstlalburst_la_LDFLAGS = $(AM_LDFLAGS) $(GSL_LIBS) $(LAL_LIBS) $(GSTLAL_LIBS) $(gstreamer_LIBS) $(GSTLAL_PLUGIN_LDFLAGS)
 
diff --git a/gstlal-ugly/gst/lal/gstlal_trigger.c b/gstlal-burst/gst/lal/gstlal_trigger.c
similarity index 100%
rename from gstlal-ugly/gst/lal/gstlal_trigger.c
rename to gstlal-burst/gst/lal/gstlal_trigger.c
diff --git a/gstlal-ugly/gst/lal/gstlal_trigger.h b/gstlal-burst/gst/lal/gstlal_trigger.h
similarity index 100%
rename from gstlal-ugly/gst/lal/gstlal_trigger.h
rename to gstlal-burst/gst/lal/gstlal_trigger.h
diff --git a/gstlal-burst/gst/lal/gstlalburst.c b/gstlal-burst/gst/lal/gstlalburst.c
index c8e67325d2ad2d078d2d0cf53035eb7878f0423f..f6c59043bb83f8698b7b9ed1ea73b87714781c2e 100644
--- a/gstlal-burst/gst/lal/gstlalburst.c
+++ b/gstlal-burst/gst/lal/gstlalburst.c
@@ -51,6 +51,7 @@
 
 #include <gstlal/gstlal_tags.h>
 #include <gstlal_string_triggergen.h>
+#include <gstlal_trigger.h>
 
 
 /*
@@ -69,6 +70,7 @@ static gboolean plugin_init(GstPlugin *plugin)
 		GType type;
 	} *element, elements[] = {
 		{"lal_string_triggergen", GSTLAL_STRING_TRIGGERGEN_TYPE},
+		{"lal_trigger", GSTLAL_TRIGGER_TYPE},
 		{NULL, 0},
 	};
 
diff --git a/gstlal-burst/gstlal-burst.spec.in b/gstlal-burst/gstlal-burst.spec.in
index e7063edb174d6eb802bc52be4ca348b25a519f2b..07fb5127d33c8d40e24a67701b796ce5a8ff4aa2 100644
--- a/gstlal-burst/gstlal-burst.spec.in
+++ b/gstlal-burst/gstlal-burst.spec.in
@@ -17,20 +17,27 @@ Requires: python-%{gstreamername}
 Requires: %{gstreamername} >= @MIN_GSTREAMER_VERSION@
 Requires: %{gstreamername}-plugins-base >= @MIN_GSTREAMER_VERSION@
 Requires: %{gstreamername}-plugins-good >= @MIN_GSTREAMER_VERSION@
+Requires: h5py
 Requires: numpy
 Requires: scipy
 Requires: lal >= @MIN_LAL_VERSION@
 Requires: lalmetaio >= @MIN_LALMETAIO_VERSION@
 Requires: lalburst >= @MIN_LALBURST_VERSION@
+Requires: gsl
 
+BuildRequires: doxygen >= @MIN_DOXYGEN_VERSION@
+BuildRequires: gobject-introspection-devel >= @MIN_GOBJECT_INTROSPECTION_VERSION@
 BuildRequires: gstlal-devel >= @MIN_GSTLAL_VERSION@
 BuildRequires: python-devel >= @MIN_PYTHON_VERSION@
 BuildRequires: fftw-devel >= 3
 BuildRequires: %{gstreamername}-devel >= @MIN_GSTREAMER_VERSION@
 BuildRequires: %{gstreamername}-plugins-base-devel >= @MIN_GSTREAMER_VERSION@
 BuildRequires: lal-devel >= @MIN_LAL_VERSION@
+BuildRequires: lal-python >= @MIN_LAL_VERSION@
 BuildRequires: lalburst-devel >= @MIN_LALBURST_VERSION@
 BuildRequires: lalmetaio-devel >= @MIN_LALMETAIO_VERSION@
+BuildRequires: gsl-devel
+BuildRequires: graphviz
 
 Conflicts: gstlal-ugly < 0.6.0
 Source: @PACKAGE_NAME@-%{version}.tar.gz
diff --git a/gstlal-burst/lib/Makefile.am b/gstlal-burst/lib/Makefile.am
index 13c39244826297bd303cb2df6ee13886e3629678..16af354cfc5011697b51a9d9f8c5127f30080be5 100644
--- a/gstlal-burst/lib/Makefile.am
+++ b/gstlal-burst/lib/Makefile.am
@@ -1,7 +1,7 @@
-pkginclude_HEADERS = gstlal_snglburst.h
+pkginclude_HEADERS = gstlal_snglburst.h gstlal_sngltrigger.h sngltriggerrowtype.h
 pkgconfig_DATA = gstlal-burst.pc
 lib_LTLIBRARIES = libgstlalburst.la
 
-libgstlalburst_la_SOURCES =
+libgstlalburst_la_SOURCES = gstlal_sngltrigger.h gstlal_sngltrigger.c sngltriggerrowtype.h sngltriggerrowtype.c
 libgstlalburst_la_CFLAGS = $(AM_CFLAGS) $(LAL_CFLAGS) $(GSTLAL_CFLAGS) $(gstreamer_CFLAGS)
 libgstlalburst_la_LDFLAGS = -version-info $(LIBVERSION) $(AM_LDFLAGS) $(LAL_LIBS) $(GSTLAL_LIBS) $(gstreamer_LIBS)
diff --git a/gstlal-ugly/lib/gstlal_sngltrigger.c b/gstlal-burst/lib/gstlal_sngltrigger.c
similarity index 100%
rename from gstlal-ugly/lib/gstlal_sngltrigger.c
rename to gstlal-burst/lib/gstlal_sngltrigger.c
diff --git a/gstlal-ugly/lib/gstlal_sngltrigger.h b/gstlal-burst/lib/gstlal_sngltrigger.h
similarity index 100%
rename from gstlal-ugly/lib/gstlal_sngltrigger.h
rename to gstlal-burst/lib/gstlal_sngltrigger.h
diff --git a/gstlal-ugly/lib/sngltriggerrowtype.c b/gstlal-burst/lib/sngltriggerrowtype.c
similarity index 100%
rename from gstlal-ugly/lib/sngltriggerrowtype.c
rename to gstlal-burst/lib/sngltriggerrowtype.c
diff --git a/gstlal-ugly/lib/sngltriggerrowtype.h b/gstlal-burst/lib/sngltriggerrowtype.h
similarity index 100%
rename from gstlal-ugly/lib/sngltriggerrowtype.h
rename to gstlal-burst/lib/sngltriggerrowtype.h
diff --git a/gstlal-burst/python/Makefile.am b/gstlal-burst/python/Makefile.am
index 4d431e79dae215f6cfd9c726a22a24a552f5e3a2..7f0e920b99c4c8f6a1c562ab7da466311638b48d 100644
--- a/gstlal-burst/python/Makefile.am
+++ b/gstlal-burst/python/Makefile.am
@@ -1 +1 @@
-SUBDIRS = excesspower
+SUBDIRS = excesspower fxtools
diff --git a/gstlal-burst/python/fxtools/Makefile.am b/gstlal-burst/python/fxtools/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..a33cbe40b11e3149ae2cf907b241a662d835ba6a
--- /dev/null
+++ b/gstlal-burst/python/fxtools/Makefile.am
@@ -0,0 +1,24 @@
+AM_CPPFLAGS = -I$(top_srcdir)/lib
+
+# This is a trick taken from the gst-python automake setup.
+# All of the Python scripts will be installed under the exec dir,
+# which prevents the module from getting spread across lib and lib64
+# on e.g. CentOS.
+pkgpythondir = $(pkgpyexecdir)
+fxtoolsdir = $(pkgpythondir)/fxtools
+
+fxtools_PYTHON = \
+	__init__.py \
+	auxcache.py \
+	utils.py \
+	multirate_datasource.py \
+	multichannel_datasource.py \
+	sngltriggertable.py
+
+pkgpyexec_LTLIBRARIES = _sngltriggertable.la
+
+_sngltriggertable_la_SOURCES = sngltriggertable.c
+_sngltriggertable_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_CPPFLAGS) -DMODULE_NAME="\"gstlal._sngltriggertable\""
+_sngltriggertable_la_CFLAGS = $(AM_CFLAGS) $(GSTLAL_CFLAGS) $(LAL_CFLAGS) $(GSL_CFLAGS) $(gstreamer_CFLAGS) -fno-strict-aliasing -DMODULE_NAME="\"gstlal._sngltriggertable\""
+_sngltriggertable_la_LIBADD = $(top_builddir)/lib/libgstlalburst.la
+_sngltriggertable_la_LDFLAGS = $(AM_LDFLAGS) $(LAL_LIBS) $(GSL_LIBS) $(PYTHON_LIBS) -module -avoid-version
diff --git a/gstlal-burst/python/fxtools/__init__.py b/gstlal-burst/python/fxtools/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..faca20512de3c70ff5aacfc870707d90c782826d
--- /dev/null
+++ b/gstlal-burst/python/fxtools/__init__.py
@@ -0,0 +1,15 @@
+# Copyright (C) 2018  Patrick Godwin
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
diff --git a/gstlal-ugly/python/auxcache.py b/gstlal-burst/python/fxtools/auxcache.py
similarity index 100%
rename from gstlal-ugly/python/auxcache.py
rename to gstlal-burst/python/fxtools/auxcache.py
diff --git a/gstlal-ugly/python/multichannel_datasource.py b/gstlal-burst/python/fxtools/multichannel_datasource.py
similarity index 100%
rename from gstlal-ugly/python/multichannel_datasource.py
rename to gstlal-burst/python/fxtools/multichannel_datasource.py
diff --git a/gstlal-ugly/python/idq_multirate_datasource.py b/gstlal-burst/python/fxtools/multirate_datasource.py
similarity index 100%
rename from gstlal-ugly/python/idq_multirate_datasource.py
rename to gstlal-burst/python/fxtools/multirate_datasource.py
diff --git a/gstlal-ugly/python/sngltriggertable.c b/gstlal-burst/python/fxtools/sngltriggertable.c
similarity index 100%
rename from gstlal-ugly/python/sngltriggertable.c
rename to gstlal-burst/python/fxtools/sngltriggertable.c
diff --git a/gstlal-ugly/python/sngltriggertable.py b/gstlal-burst/python/fxtools/sngltriggertable.py
similarity index 97%
rename from gstlal-ugly/python/sngltriggertable.py
rename to gstlal-burst/python/fxtools/sngltriggertable.py
index e04f7c0c9a1e306ee1cfaeb5692cba8c6eeafc2e..545103b2f4ee21158e97ce3a910bab6bdaa602a0 100644
--- a/gstlal-ugly/python/sngltriggertable.py
+++ b/gstlal-burst/python/fxtools/sngltriggertable.py
@@ -1,7 +1,7 @@
 from glue.ligolw import ilwd
 from glue.ligolw import lsctables
 import lal
-from . import _sngltriggertable
+from gstlal import _sngltriggertable
 
 
 __all__ = ["GSTLALSnglTrigger"]
diff --git a/gstlal-ugly/python/idq_utils.py b/gstlal-burst/python/fxtools/utils.py
similarity index 100%
rename from gstlal-ugly/python/idq_utils.py
rename to gstlal-burst/python/fxtools/utils.py
diff --git a/gstlal-ugly/share/feature_extractor/Makefile.gstlal_feature_extractor_offline b/gstlal-burst/share/feature_extractor/Makefile.gstlal_feature_extractor_offline
similarity index 100%
rename from gstlal-ugly/share/feature_extractor/Makefile.gstlal_feature_extractor_offline
rename to gstlal-burst/share/feature_extractor/Makefile.gstlal_feature_extractor_offline
diff --git a/gstlal-ugly/share/feature_extractor/Makefile.gstlal_idq_icc b/gstlal-burst/share/feature_extractor/Makefile.gstlal_idq_icc
similarity index 100%
rename from gstlal-ugly/share/feature_extractor/Makefile.gstlal_idq_icc
rename to gstlal-burst/share/feature_extractor/Makefile.gstlal_idq_icc
diff --git a/gstlal-ugly/share/feature_extractor/O1/H1_O1_deep_channel_list.txt b/gstlal-burst/share/feature_extractor/O1/H1_O1_deep_channel_list.txt
similarity index 100%
rename from gstlal-ugly/share/feature_extractor/O1/H1_O1_deep_channel_list.txt
rename to gstlal-burst/share/feature_extractor/O1/H1_O1_deep_channel_list.txt
diff --git a/gstlal-ugly/share/feature_extractor/O1/H1_O1_standard_channel_list.txt b/gstlal-burst/share/feature_extractor/O1/H1_O1_standard_channel_list.txt
similarity index 100%
rename from gstlal-ugly/share/feature_extractor/O1/H1_O1_standard_channel_list.txt
rename to gstlal-burst/share/feature_extractor/O1/H1_O1_standard_channel_list.txt
diff --git a/gstlal-ugly/share/feature_extractor/O1/L1_O1_deep_channel_list.txt b/gstlal-burst/share/feature_extractor/O1/L1_O1_deep_channel_list.txt
similarity index 100%
rename from gstlal-ugly/share/feature_extractor/O1/L1_O1_deep_channel_list.txt
rename to gstlal-burst/share/feature_extractor/O1/L1_O1_deep_channel_list.txt
diff --git a/gstlal-ugly/share/feature_extractor/O1/L1_O1_standard_channel_list.txt b/gstlal-burst/share/feature_extractor/O1/L1_O1_standard_channel_list.txt
similarity index 100%
rename from gstlal-ugly/share/feature_extractor/O1/L1_O1_standard_channel_list.txt
rename to gstlal-burst/share/feature_extractor/O1/L1_O1_standard_channel_list.txt
diff --git a/gstlal-ugly/share/feature_extractor/O2/H1_O2_deep_channel_list.txt b/gstlal-burst/share/feature_extractor/O2/H1_O2_deep_channel_list.txt
similarity index 100%
rename from gstlal-ugly/share/feature_extractor/O2/H1_O2_deep_channel_list.txt
rename to gstlal-burst/share/feature_extractor/O2/H1_O2_deep_channel_list.txt
diff --git a/gstlal-ugly/share/feature_extractor/O2/H1_O2_full_channel_list.txt b/gstlal-burst/share/feature_extractor/O2/H1_O2_full_channel_list.txt
similarity index 100%
rename from gstlal-ugly/share/feature_extractor/O2/H1_O2_full_channel_list.txt
rename to gstlal-burst/share/feature_extractor/O2/H1_O2_full_channel_list.txt
diff --git a/gstlal-ugly/share/feature_extractor/O2/H1_O2_standard_channel_list.txt b/gstlal-burst/share/feature_extractor/O2/H1_O2_standard_channel_list.txt
similarity index 100%
rename from gstlal-ugly/share/feature_extractor/O2/H1_O2_standard_channel_list.txt
rename to gstlal-burst/share/feature_extractor/O2/H1_O2_standard_channel_list.txt
diff --git a/gstlal-ugly/share/feature_extractor/O2/L1_O2_deep_channel_list.txt b/gstlal-burst/share/feature_extractor/O2/L1_O2_deep_channel_list.txt
similarity index 100%
rename from gstlal-ugly/share/feature_extractor/O2/L1_O2_deep_channel_list.txt
rename to gstlal-burst/share/feature_extractor/O2/L1_O2_deep_channel_list.txt
diff --git a/gstlal-ugly/share/feature_extractor/O2/L1_O2_full_channel_list.txt b/gstlal-burst/share/feature_extractor/O2/L1_O2_full_channel_list.txt
similarity index 100%
rename from gstlal-ugly/share/feature_extractor/O2/L1_O2_full_channel_list.txt
rename to gstlal-burst/share/feature_extractor/O2/L1_O2_full_channel_list.txt
diff --git a/gstlal-ugly/share/feature_extractor/O2/L1_O2_standard_channel_list.txt b/gstlal-burst/share/feature_extractor/O2/L1_O2_standard_channel_list.txt
similarity index 100%
rename from gstlal-ugly/share/feature_extractor/O2/L1_O2_standard_channel_list.txt
rename to gstlal-burst/share/feature_extractor/O2/L1_O2_standard_channel_list.txt
diff --git a/gstlal-ugly/tests/trigger_test_01.py b/gstlal-burst/tests/trigger_test_01.py
similarity index 100%
rename from gstlal-ugly/tests/trigger_test_01.py
rename to gstlal-burst/tests/trigger_test_01.py
diff --git a/gstlal-ugly/bin/Makefile.am b/gstlal-ugly/bin/Makefile.am
index 4bb13849efbc292cccf74f7013a43825f2b57f04..8efc13536547c95cee428026f4df3458feab828c 100644
--- a/gstlal-ugly/bin/Makefile.am
+++ b/gstlal-ugly/bin/Makefile.am
@@ -33,9 +33,4 @@ dist_bin_SCRIPTS = \
 	gstlal_ll_dq \
 	gstlal_ll_inspiral_state \
 	gstlal_condor_top \
-	gstlal_feature_extractor \
-	gstlal_feature_extractor_pipe \
-	gstlal_feature_extractor_pipe_online \
-	gstlal_feature_extractor_whitener_check \
-	gstlal_feature_extractor_template_overlap \
 	gstlal_injsplitter
diff --git a/gstlal-ugly/gst/lal/Makefile.am b/gstlal-ugly/gst/lal/Makefile.am
index af3a0cbb9173ae616ac12e4b5123a47f89e9e020..ad0d824ccaf3dc39e96f780eec6145aceddbb9b7 100644
--- a/gstlal-ugly/gst/lal/Makefile.am
+++ b/gstlal-ugly/gst/lal/Makefile.am
@@ -10,7 +10,6 @@ lib@GSTPLUGINPREFIX@gstlalugly_la_SOURCES = \
 	gstlal_iirbank.h gstlal_iirbank.c \
 	gstlal_interpolator.h gstlal_interpolator.c \
 	gstlal_tdwhiten.h gstlal_tdwhiten.c \
-	gstlal_trigger.h gstlal_trigger.c \
 	gstlal_latency.h gstlal_latency.c \
 	#gstlal_specgram.h gstlal_specgram.c \
 	#gstlal_mean.h gstlal_mean.c \
diff --git a/gstlal-ugly/gst/lal/gstlalugly.c b/gstlal-ugly/gst/lal/gstlalugly.c
index e99a84625815a0778ced0c18d1e3ae7c616f7b00..225a73a33faedacd280e1d0558c13849ba99f92e 100644
--- a/gstlal-ugly/gst/lal/gstlalugly.c
+++ b/gstlal-ugly/gst/lal/gstlalugly.c
@@ -58,7 +58,6 @@
 #include <gstlal_trim.h>*/
 #include <gstlal_bitvectorgen.h>
 #include <audioratefaker.h>
-#include <gstlal_trigger.h>
 #include <gstlal_latency.h>
 #include <gstlaldeglitchfilter.h>
 
@@ -86,7 +85,6 @@ static gboolean plugin_init(GstPlugin *plugin)
 		{"lal_trim", GST_TYPE_LALTRIM},*/
 		{"lal_bitvectorgen", GSTLAL_BITVECTORGEN_TYPE},
 		{"audioratefaker", GST_TYPE_AUDIO_RATE_FAKER},
-		{"lal_trigger", GSTLAL_TRIGGER_TYPE},
 		{"lal_latency", GSTLAL_LATENCY_TYPE},
 		{"lal_deglitcher", GST_TYPE_LALDEGLITCHFILTER},
 		{NULL, 0},
diff --git a/gstlal-ugly/lib/Makefile.am b/gstlal-ugly/lib/Makefile.am
index c5bfdbb980e6c1b30fd7ba451a2f2f5854c1e5ce..c61c48f95f6c84da76ac44887b5dc947ef0ce42e 100644
--- a/gstlal-ugly/lib/Makefile.am
+++ b/gstlal-ugly/lib/Makefile.am
@@ -1,7 +1,7 @@
-pkginclude_HEADERS = gstlal_sngltrigger.h sngltriggerrowtype.h
+pkginclude_HEADERS =
 pkgconfig_DATA = gstlal-ugly.pc
 lib_LTLIBRARIES = libgstlalugly.la
 
-libgstlalugly_la_SOURCES = gstlal_sngltrigger.h gstlal_sngltrigger.c sngltriggerrowtype.h sngltriggerrowtype.c
+libgstlalugly_la_SOURCES =
 libgstlalugly_la_CFLAGS = $(AM_CFLAGS) $(LAL_CFLAGS) $(GSTLAL_CFLAGS) $(gstreamer_CFLAGS)
 libgstlalugly_la_LDFLAGS = -version-info $(LIBVERSION) $(AM_LDFLAGS) $(LAL_LIBS) $(GSTLAL_LIBS) $(gstreamer_LIBS)
diff --git a/gstlal-ugly/python/Makefile.am b/gstlal-ugly/python/Makefile.am
index 06a86d9efec7f0870d479864298a605036225579..97dfa37b797955a08278ef749282f614fccae94f 100644
--- a/gstlal-ugly/python/Makefile.am
+++ b/gstlal-ugly/python/Makefile.am
@@ -10,22 +10,11 @@ pkgpythondir = $(pkgpyexecdir)
 
 pkgpython_PYTHON = \
 	aggregator.py \
-	auxcache.py \
 	coherent_inspiral_metric_detector_details.py \
 	coherent_inspiral_metric_plots.py \
 	coherent_inspiral_metric.py \
 	gviz_api.py \
-	idq_utils.py \
-	idq_multirate_datasource.py \
 	metric.py \
-	multichannel_datasource.py \
-	sngltriggertable.py \
 	tree.py
 
-pkgpyexec_LTLIBRARIES = _sngltriggertable.la
-
-_sngltriggertable_la_SOURCES = sngltriggertable.c
-_sngltriggertable_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_CPPFLAGS) -DMODULE_NAME="\"gstlal._sngltriggertable\""
-_sngltriggertable_la_CFLAGS = $(AM_CFLAGS) $(GSTLAL_CFLAGS) $(LAL_CFLAGS) $(GSL_CFLAGS) $(gstreamer_CFLAGS) -fno-strict-aliasing -DMODULE_NAME="\"gstlal._sngltriggertable\""
-_sngltriggertable_la_LIBADD = $(top_builddir)/lib/libgstlalugly.la
-_sngltriggertable_la_LDFLAGS = $(AM_LDFLAGS) $(LAL_LIBS) $(GSL_LIBS) $(PYTHON_LIBS) -module -avoid-version
+pkgpyexec_LTLIBRARIES =