Commit dbd5b718 authored by Brian Moe's avatar Brian Moe
Browse files

Added REST API support. Removed utils.py.

parent cd9d9c8a
../ligo/gracedb/__init__.py
\ No newline at end of file
../ligo/gracedb/cli.py
\ No newline at end of file
ligo-gracedb (1.5-1) unstable; urgency=low
* Added support for REST API
* Added unit tests and test data
-- Brian Moe <brian.moe@ligo.org> Wed, 12 Dec 2012 17:17:25 -0500
ligo-gracedb (1.4-1) unstable; urgency=low
* Fixed SSL renegotiation bug on large file upload.
......
This diff is collapsed.
This diff is collapsed.
# Copyright (C) 2012 LIGO Scientific Collaboration
#
# 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 3 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.
import httplib
import mimetypes
import urllib
import os
import sys
import json
DEFAULT_SERVICE_URL = "https://gracedb.ligo.org/api"
#-----------------------------------------------------------------
# Exception(s)
class HTTPError(Exception):
def __init__(self, status, reason, message):
self.status = status
self.reason = reason
self.message = message
Exception.__init__(self, (status, reason))
#-----------------------------------------------------------------
# Generic GSI REST
class GsiRest(object):
"""docstring for GracedbRest"""
def __init__(self, cred=None):
if not cred:
cred = findUserCredentials()
if isinstance(cred, (list, tuple)):
self.cert, self.key = cred
elif cred:
self.cert = self.key = cred
self.connection = None
def getConnection(self, url):
proto, rest = urllib.splittype(url)
host, path = urllib.splithost(rest)
host, port = urllib.splitport(host)
return httplib.HTTPSConnection(host, port,
key_file=self.key, cert_file=self.cert)
def request(self, method, url, body=None, headers=None, priming_url=None):
conn = self.getConnection(url)
if priming_url:
conn.request("GET", priming_url, headers={'connection' : 'keep-alive'})
response = conn.getresponse()
if response.status != 200:
response = self.adjustResponse(response)
else:
# Throw away the response and make sure to read the body.
response = response.read()
conn.request(method, url, body, headers or {})
response = conn.getresponse()
return self.adjustResponse(response)
def adjustResponse(self, response):
# XXX WRONG.
if response.status >= 400:
raise HTTPError(response.status, response.reason, response.read())
response.json = lambda: json.loads(response.read())
return response
def get(self, url, headers=None):
return self.request("GET", url, headers=headers)
def head(self, url, headers=None):
return self.request("HEAD", url, headers=headers)
def delete(self, url, headers=None):
return self.request("DELETE", url, headers=headers)
def options(self, url, headers=None):
return self.request("OPTIONS", url, headers=headers)
def post(self, *args, **kwargs):
return self.post_or_put("POST", *args, **kwargs)
def put(self, *args, **kwargs):
return self.post_or_put("PUT", *args, **kwargs)
def post_or_put(self, method, url, body=None, headers=None, files=None):
headers = headers or {}
if not files:
# Simple urlencoded body
if isinstance(body, dict):
# XXX What about the headers in the params?
if 'content-type' not in headers:
headers['content-type'] = "application/x-www-form-urlencoded"
body = urllib.urlencode(body)
else:
body = body or {}
if isinstance(body, dict):
body = body.items()
content_type, body = encode_multipart_formdata(body, files)
# XXX What about the headers in the params?
headers = {
'content-type': content_type,
'content-length': str(len(body)),
# 'connection': 'keep-alive',
}
return self.request(method, url, body, headers)
#------------------------------------------------------------------
# GraceDB
#
# Example Gracedb REST client.
class GraceDb(GsiRest):
"""docstring for GraceDb"""
def __init__(self, service_url=DEFAULT_SERVICE_URL, *args, **kwargs):
GsiRest.__init__(self, *args, **kwargs)
self.service_url = service_url
self._service_info = None
@property
def service_info(self):
if not self._service_info:
self._service_info = self.request("GET", self.service_url).json()
return self._service_info
@property
def links(self):
return self.service_info.get('links')
@property
def templates(self):
return self.service_info.get('templates')
@property
def analysis_types(self):
return self.service_info.get('analysis-types')
@property
def groups(self):
return self.service_info.get('groups')
def _analysisTypeCode(self, analysis_type):
"""Check if analysis_type is valid.
Return coded version of type if it is"""
# types is dict of { code : descriptive_name }
types = self.analysis_types
if analysis_type in types.keys():
# Already coded
return analysis_type
if not analysis_type in types.values():
# Not valid
return None
return [code
for code, name in types.items()
if name == analysis_type][0]
def createEvent(self, group, analysis_type, filename, filecontents=None):
errors = []
analysis_type_code = self._analysisTypeCode(analysis_type)
if group not in self.groups:
errors += ["bad group"]
if not analysis_type_code:
errors += ["bad type"]
if errors:
# XXX Terrible error messages / weak exception type
raise Exception(str(errors))
if filecontents is None:
filecontents = open(filename, 'rb').read() # XXX or 'rb' ?
fields = [
('group', group),
('type', analysis_type_code),
]
files = [('eventFile', filename, filecontents)]
# Python httplib bug? unicode link
uri = str(self.links['events'])
return self.post(uri, fields, files=files)
def replaceEvent(self, graceid, filename, filecontents=None):
if filecontents is None:
filecontents = open(filename, 'rb').read()
return self.put(
self.templates['event-detail-template'].format(graceid=graceid),
files=[('eventFile', filename, filecontents)])
def event(self, graceid):
return self.get(
self.templates['event-detail-template'].format(graceid=graceid))
def events(self, query=None, orderby=None, count=None):
uri = self.links['events']
qdict = {}
if query: qdict['query'] = query
if count: qdict['count'] = count
if orderby: qdict['orderby'] = orderby
if qdict:
uri += "?" + urllib.urlencode(qdict)
while uri:
response = self.get(uri).json()
events = response['events']
uri = response['links'].get('next')
for event in events:
yield event
def numEvents(self, query=None):
uri = self.links['events']
if query:
uri += "?" + urllib.urlencode({'query': query})
return self.get(uri).json()['numRows']
def files(self, graceid, filename=None, raw=False):
template = self.templates['files-template']
uri = template.format(graceid=graceid, filename=filename or "")
return self.get(uri)
def writeFile(self, graceid, filename, filecontents=None):
template = self.templates['files-template']
uri = template.format(graceid=graceid, filename=os.path.basename(filename))
if filecontents is None:
filecontents = open(filename, "rb").read()
elif isinstance(filecontents, file):
# XXX Does not scale well.
filecontents = filecontents.read()
files = [('upload', os.path.basename(filename), filecontents)]
return self.put(uri, files=files)
def logs(self, graceid):
template = self.templates['event-log-template']
uri = template.format(graceid=graceid)
return self.get(uri)
def writeLog(self, graceid, message):
template = self.templates['event-log-template']
uri = template.format(graceid=graceid)
return self.post(uri, body={'message' : message})
def labels(self, graceid, label=""):
template = self.templates['event-label-template']
uri = template.format(graceid=graceid, label=label)
return self.get(uri)
def writeLabel(self, graceid, label):
template = self.templates['event-label-template']
uri = template.format(graceid=graceid, label=label)
return self.put(uri)
def removeLabel(self, graceid, label):
template = self.templates['event-label-template']
uri = template.format(graceid=graceid, label=label)
return self.delete(uri)
#-----------------------------------------------------------------
# TBD
# Media Types
# Root
# Collection
# Event
# Log
# File
# Label
#-----------------------------------------------------------------
# HTTP upload encoding
# Taken from http://code.activestate.com/recipes/146306/
def encode_multipart_formdata(fields, files):
"""
fields is a sequence of (name, value) elements for regular form fields.
files is a sequence of (name, filename, value) elements for data to be uploaded as files
Return (content_type, body) ready for httplib.HTTP instance
"""
BOUNDARY = '----------ThIs_Is_tHe_bouNdaRY_$'
CRLF = '\r\n'
L = []
for (key, value) in fields:
L.append('--' + BOUNDARY)
L.append('Content-Disposition: form-data; name="%s"' % key)
L.append('')
L.append(value)
for (key, filename, value) in files:
L.append('--' + BOUNDARY)
L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
L.append('Content-Type: %s' % get_content_type(filename))
L.append('')
L.append(value)
L.append('--' + BOUNDARY + '--')
L.append('')
body = CRLF.join(L)
content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
return content_type, body
def get_content_type(filename):
return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
#-----------------------------------------------------------------
# X509 Credentials
def findUserCredentials(warnOnOldProxy=1):
proxyFile = os.environ.get('X509_USER_PROXY')
certFile = os.environ.get('X509_USER_CERT')
keyFile = os.environ.get('X509_USER_KEY')
if certFile and keyFile:
return certFile, keyFile
if proxyFile:
return proxyFile, proxyFile
# Try default proxy
proxyFile = os.path.join('/tmp', "x509up_u%d" % os.getuid())
if os.path.exists(proxyFile):
return proxyFile, proxyFile
# Try default cert/key
homeDir = os.environ.get('HOME')
certFile = os.path.join(homeDir, '.globus', 'usercert.pem')
keyFile = os.path.join(homeDir, '.globus', 'userkey.pem')
if os.path.exists(certFile) and os.path.exists(keyFile):
return certFile, keyFile
nevent: 2
ndim: 3
run: 1
rho: 675.260010
netCC: 0.975443
netED: 0.017502
penalty: 1.000000
gnet: 0.219568
anet: 0.008039
inet: 2.847070
likelihood: 2.853813e+06
far: 1.402366e+06
ecor: 1.606101e+06
ECOR: 1.402366e+06
factor: 0.000000
distance: 0.000000
mchirp: 0.000000
norm: 0.000000
usize: 0
ifo: 6 1 2
eventID: 2 0
type: 1 0
rate: 256 256 256
volume: 4392 4392 4392
size: 4096 4096 4096
lag: 0.000000 0.000000 0.000000
phi: 276.601074 0.000000 197.526505 276.601074
theta: 141.600006 0.000000 -51.599998 141.600006
psi: 0.000000 0.000000
iota: 0.000000 0.000000
bp: 0.5966 0.4321 -0.3823
inj_bp: 0.0000 0.0000 0.0000
bx: -0.0148 -0.1584 0.2818
inj_bx: 0.0000 0.0000 0.0000
Deff: 0.000000 0.000000 0.000000
mass: 0.000000 0.000000
snr: 2.854587e+05 1.364957e+06 1.243832e+06
xSNR: 2.798880e+05 1.345537e+06 1.230917e+06
sSNR: 2.859383e+05 1.331482e+06 1.238922e+06
null: -5.512349e+02 4.287211e+04 -1.886499e+03
strain: 7.991493e-21 0.000000e+00
hrss: 5.459924e-21 4.210231e-21 4.040685e-21
inj_hrss: 0.000000e+00 0.000000e+00 0.000000e+00
noise: 1.367987e-23 3.587663e-24 3.592267e-24
segment: 1012125540.0000 1012125616.0000
start: 1012125586.9414 1012125586.9414 1012125586.9414
time: 1012125588.9392 1012125588.9242 1012125588.9317
stop: 1012125590.9414 1012125590.9414 1012125590.9414
inj_time: 0.0000 0.0000 0.0000
left: 46.941406 46.941406 46.941406
right: 25.058594 25.058594 25.058594
duration: 4.000000 4.000000 4.000000
frequency: 782.836853 782.836853 782.836853
low: 128.000000 128.000000 128.000000
high: 1792.000000 1792.000000 1792.000000
bandwidth: 1664.000000 1664.000000 1664.000000
rSNR: 0.000000e+00 0.000000e+00 0.000000e+00
gSNR: 2.812548e+05 1.386890e+06 1.216279e+06
rCF: 0.000000e+00 0.000000e+00 0.000000e+00
gCF: 1.375586e+05 6.589778e+05 5.788578e+05
rSF: 0.000000e+00 0.000000e+00 0.000000e+00
gSF: 1.191858e+05 6.342397e+05 5.546464e+05
netcc: 0.975443 0.971975 0.784070 0.784451
neted: 28110.107422 39058.550781 17161.662109 48855.515625 102585.070312
ndm: 53330.550781 238870.953125 214243.906250 649608.312500 1152986.125000 547301.937500
erA: 0.000 0.400 0.400 0.566 0.566 0.693 0.693 0.800 0.980 1.131 0.000
sky_res: 0.400011
map_lenght: 15
#skyID theta DEC step phi R.A step probability cumulative
230079 141.6 -51.6 0.40 276.6 197.5 0.64 2.658248e-01 2.658248e-01
230635 142.0 -52.0 0.40 276.6 197.6 0.65 1.951620e-01 4.609868e-01
230080 141.6 -51.6 0.40 277.2 198.2 0.64 1.432831e-01 6.042698e-01
229520 141.2 -51.2 0.40 277.2 198.1 0.64 1.051949e-01 7.094647e-01
230634 142.0 -52.0 0.40 276.0 196.9 0.65 7.723147e-02 7.866962e-01
229519 141.2 -51.2 0.40 276.6 197.5 0.64 5.670144e-02 8.433976e-01
230078 141.6 -51.6 0.40 276.0 196.9 0.64 4.162879e-02 8.850264e-01
230636 142.0 -52.0 0.40 277.3 198.2 0.65 3.056283e-02 9.155893e-01
229518 141.2 -51.2 0.40 275.9 196.8 0.64 2.243847e-02 9.380277e-01
228956 140.8 -50.8 0.40 277.4 198.4 0.63 1.647377e-02 9.545015e-01
228955 140.8 -50.8 0.40 276.8 197.7 0.63 1.209463e-02 9.665961e-01
231185 142.4 -52.4 0.40 276.4 197.3 0.66 8.879580e-03 9.754757e-01
229521 141.2 -51.2 0.40 277.8 198.8 0.64 6.519167e-03 9.819949e-01
231184 142.4 -52.4 0.40 275.7 196.7 0.66 4.786211e-03 9.867811e-01
230081 141.6 -51.6 0.40 277.9 198.8 0.64 3.513917e-03 9.902950e-01
wat version = 5.3.9
online version = 1
search=r
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE LIGO_LW SYSTEM "http://ldas-sw.ligo.caltech.edu/doc/ligolwAPI/html/ligolw_dtd.txt">
<LIGO_LW>
<Table Name="sngl_inspiral:table">
<Column Type="real_4" Name="sngl_inspiral:cont_chisq"/>
<Column Type="real_4" Name="sngl_inspiral:bank_chisq"/>
<Column Type="int_4s" Name="sngl_inspiral:chisq_dof"/>
<Column Type="real_8" Name="sngl_inspiral:end_time_gmst"/>
<Column Type="real_8" Name="sngl_inspiral:event_duration"/>
<Column Type="real_4" Name="sngl_inspiral:chisq"/>
<Column Type="real_4" Name="sngl_inspiral:alpha"/>
<Column Type="real_4" Name="sngl_inspiral:coa_phase"/>
<Column Type="real_4" Name="sngl_inspiral:alpha2"/>
<Column Type="real_4" Name="sngl_inspiral:mchirp"/>
<Column Type="real_4" Name="sngl_inspiral:alpha1"/>
<Column Type="real_4" Name="sngl_inspiral:alpha6"/>
<Column Type="real_4" Name="sngl_inspiral:alpha4"/>
<Column Type="real_4" Name="sngl_inspiral:alpha5"/>
<Column Type="ilwd:char" Name="sngl_inspiral:event_id"/>
<Column Type="real_4" Name="sngl_inspiral:chi"/>
<Column Type="int_4s" Name="sngl_inspiral:cont_chisq_dof"/>
<Column Type="real_4" Name="sngl_inspiral:tau2"/>
<Column Type="real_4" Name="sngl_inspiral:tau3"/>
<Column Type="real_4" Name="sngl_inspiral:tau0"/>
<Column Type="real_4" Name="sngl_inspiral:tau4"/>
<Column Type="real_4" Name="sngl_inspiral:tau5"/>
<Column Type="real_8" Name="sngl_inspiral:template_duration"/>
<Column Type="int_4s" Name="sngl_inspiral:impulse_time"/>
<Column Type="int_4s" Name="sngl_inspiral:impulse_time_ns"/>
<Column Type="real_4" Name="sngl_inspiral:rsqveto_duration"/>
<Column Type="lstring" Name="sngl_inspiral:channel"/>
<Column Type="real_4" Name="sngl_inspiral:mtotal"/>
<Column Type="real_4" Name="sngl_inspiral:alpha3"/>
<Column Type="real_4" Name="sngl_inspiral:Gamma5"/>
<Column Type="real_4" Name="sngl_inspiral:f_final"/>
<Column Type="real_4" Name="sngl_inspiral:beta"/>
<Column Type="ilwd:char" Name="sngl_inspiral:process_id"/>
<Column Type="real_4" Name="sngl_inspiral:snr"/>
<Column Type="int_4s" Name="sngl_inspiral:bank_chisq_dof"/>
<Column Type="real_4" Name="sngl_inspiral:kappa"/>
<Column Type="real_4" Name="sngl_inspiral:eff_distance"/>
<Column Type="real_4" Name="sngl_inspiral:Gamma7"/>
<Column Type="real_4" Name="sngl_inspiral:Gamma6"/>
<Column Type="lstring" Name="sngl_inspiral:search"/>
<Column Type="real_4" Name="sngl_inspiral:Gamma4"/>
<Column Type="real_4" Name="sngl_inspiral:mass1"/>
<Column Type="real_4" Name="sngl_inspiral:Gamma2"/>
<Column Type="real_4" Name="sngl_inspiral:Gamma1"/>
<Column Type="real_4" Name="sngl_inspiral:mass2"/>
<Column Type="real_4" Name="sngl_inspiral:ttotal"/>
<Column Type="real_4" Name="sngl_inspiral:Gamma0"/>
<Column Type="real_4" Name="sngl_inspiral:Gamma9"/>
<Column Type="real_4" Name="sngl_inspiral:Gamma8"/>
<Column Type="real_4" Name="sngl_inspiral:Gamma3"/>
<Column Type="real_4" Name="sngl_inspiral:eta"/>
<Column Type="real_4" Name="sngl_inspiral:psi0"/>
<Column Type="int_4s" Name="sngl_inspiral:end_time"/>
<Column Type="real_4" Name="sngl_inspiral:amplitude"/>
<Column Type="real_4" Name="sngl_inspiral:psi3"/>
<Column Type="int_4s" Name="sngl_inspiral:end_time_ns"/>
<Column Type="lstring" Name="sngl_inspiral:ifo"/>
<Column Type="real_8" Name="sngl_inspiral:sigmasq"/>
<Stream Name="sngl_inspiral:table" Type="Local" Delimiter=",">
111117.7,46.05555,0,13.37498739211096,0.000244140625,0,0,-2.222122,0,1.161378,0,0,0,0,"sngl_inspiral:event_id:0",0,112837,1.459517,0.9047917,26.94421,0.04901026,0,27.54793872301135,971609248,861816406,0,"DMT-STRAIN",2.698323,0,426.13315,1629.595,0,"process:process_id:0",5.561541,15,0,57.40068,0,0,"FindChirpSPtwoPN",-212.24567,1.533016,7010.147,-2963.2476,1.165307,27.54794,174532.62,0,0,115.9822,0.2453574,0,971609248,0,0,861816406,"H1",101911.765625,
109975.2,32.12224,0,13.37498868415753,0.000244140625,0,0,-2.353283,0,1.15963,0,0,0,0,"sngl_inspiral:event_id:1",0,112935,1.504488,0.9970195,27.01193,0.05250296,0,27.57190592010491,971609248,866455078,0,"DMT-STRAIN",2.965915,0,386.59695,1482.569,0,"process:process_id:0",5.63967,15,0,49.10112,0,0,"FindChirpSPtwoPN",-201.89705,2.083082,6643.8418,-2951.074,0.8828334,27.57191,170850.05,0,0,115.80309,0.2090584,0,971609248,0,0,866455078,"L1",76681.4296875
</Stream>
</Table>
<Table Name="coinc_inspiral:table">
<Column Type="real_8" Name="coinc_inspiral:false_alarm_rate"/>
<Column Type="real_8" Name="coinc_inspiral:mchirp"/>
<Column Type="ilwd:char" Name="coinc_inspiral:coinc_event_id"/>
<Column Type="real_8" Name="coinc_inspiral:combined_far"/>
<Column Type="real_8" Name="coinc_inspiral:mass"/>
<Column Type="int_4s" Name="coinc_inspiral:end_time"/>
<Column Type="real_8" Name="coinc_inspiral:snr"/>
<Column Type="int_4s" Name="coinc_inspiral:end_time_ns"/>
<Column Type="lstring" Name="coinc_inspiral:ifos"/>
<Stream Name="coinc_inspiral:table" Type="Local" Delimiter=",">
2.075093374861122,1.160504,"coinc_event:coinc_event_id:0",2.075093374861122,2.8321192,971609248,7.121797825164989,861816406,"H1,L1"
</Stream>
</Table>
<Table Name="coinc_definer:table">
<Column Type="lstring" Name="coinc_definer:search"/>
<Column Type="lstring" Name="coinc_definer:description"/>
<Column Type="ilwd:char" Name="coinc_definer:coinc_def_id"/>
<Column Type="int_4u" Name="coinc_definer:search_coinc_type"/>
<Stream Name="coinc_definer:table" Type="Local" Delimiter=",">
"inspiral","sngl_inspiral&lt;--&gt;sngl_inspiral coincidences","coinc_definer:coinc_def_id:1",0
</Stream>
</Table>
<Table Name="coinc_event:table">
<Column Type="ilwd:char" Name="coinc_event:coinc_event_id"/>
<Column Type="lstring" Name="coinc_event:instruments"/>
<Column Type="int_4u" Name="coinc_event:nevents"/>
<Column Type="ilwd:char" Name="coinc_event:process_id"/>
<Column Type="ilwd:char" Name="coinc_event:coinc_def_id"/>
<Column Type="ilwd:char" Name="coinc_event:time_slide_id"/>
<Column Type="real_8" Name="coinc_event:likelihood"/>
<Stream Name="coinc_event:table" Type="Local" Delimiter=",">
"coinc_event:coinc_event_id:0","H1,L1",3,"process:process_id:2","coinc_definer:coinc_def_id:1",,,
</Stream>
</Table>
<Table Name="coinc_event_map:table">
<Column Type="ilwd:char" Name="coinc_event_map:event_id"/>
<Column Type="char_v" Name="coinc_event_map:table_name"/>
<Column Type="ilwd:char" Name="coinc_event_map:coinc_event_id"/>
<Stream Name="coinc_event_map:table" Type="Local" Delimiter=",">
"sngl_inspiral:event_id:0","sngl_inspiral","coinc_event:coinc_event_id:0",
"sngl_inspiral:event_id:1","sngl_inspiral","coinc_event:coinc_event_id:0"
</Stream>
</Table>
</LIGO_LW>
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE LIGO_LW SYSTEM "http://ldas-sw.ligo.caltech.edu/doc/ligolwAPI/html/ligolw_dtd.txt">
<LIGO_LW>
<Table Name="sngl_inspiral:table">
<Column Type="real_4" Name="sngl_inspiral:cont_chisq"/>
<Column Type="real_4" Name="sngl_inspiral:bank_chisq"/>
<Column Type="int_4s" Name="sngl_inspiral:chisq_dof"/>
<Column Type="real_8" Name="sngl_inspiral:end_time_gmst"/>
<Column Type="real_8" Name="sngl_inspiral:event_duration"/>
<Column Type="real_4" Name="sngl_inspiral:chisq"/>
<Column Type="real_4" Name="sngl_inspiral:alpha"/>
<Column Type="real_4" Name="sngl_inspiral:coa_phase"/>
<Column Type="real_4" Name="sngl_inspiral:alpha2"/>
<Column Type="real_4" Name="sngl_inspiral:mchirp"/>
<Column Type="real_4" Name="sngl_inspiral:alpha1"/>
<Column Type="real_4" Name="sngl_inspiral:alpha6"/>
<Column Type="real_4" Name="sngl_inspiral:alpha4"/>
<Column Type="real_4" Name="sngl_inspiral:alpha5"/>
<Column Type="ilwd:char" Name="sngl_inspiral:event_id"/>
<Column Type="real_4" Name="sngl_inspiral:chi"/>
<Column Type="int_4s" Name="sngl_inspiral:cont_chisq_dof"/>
<Column Type="real_4" Name="sngl_inspiral:tau2"/>
<Column Type="real_4" Name="sngl_inspiral:tau3"/>
<Column Type="real_4" Name="sngl_inspiral:tau0"/>
<Column Type="real_4" Name="sngl_inspiral:tau4"/>
<Column Type="real_4" Name="sngl_inspiral:tau5"/>
<Column Type="real_8" Name="sngl_inspiral:template_duration"/>
<Column Type="int_4s" Name="sngl_inspiral:impulse_time"/>
<Column Type="int_4s" Name="sngl_inspiral:impulse_time_ns"/>
<Column Type="real_4" Name="sngl_inspiral:rsqveto_duration"/>
<Column Type="lstring" Name="sngl_inspiral:channel"/>
<Column Type="real_4" Name="sngl_inspiral:mtotal"/>
<Column Type="real_4" Name="sngl_inspiral:alpha3"/>
<Column Type="real_4" Name="sngl_inspiral:Gamma5"/>
<Column Type="real_4" Name="sngl_inspiral:f_final"/>
<Column Type="real_4" Name="sngl_inspiral:beta"/>
<Column Type="ilwd:char" Name="sngl_inspiral:process_id"/>