diff --git a/svc_2019/q.rd b/svc_2019/q.rd
index cc4dcc7d1f876ff25b1f14a474fee4f4f0cd58c0..bd121d6ee04a6e8982fa30fe78ddfcc5e2dfd5a1 100644
--- a/svc_2019/q.rd
+++ b/svc_2019/q.rd
@@ -20,37 +20,60 @@
 
   <meta name="coverage.waveband">Radio</meta>
 
-  <table id="main" onDisk="True" mixin="//siap#pgs" adql="False">
-
-<!--    <mixin
-      calibLevel="2"
-      collectionName="'%a few letters identifying this data%'"
-      targetName="%column name of an object designation%"
-      expTime="%column name of an exposure time%"
-      targetClass="'%simbad taget class%'"
-    >//obscore#publishSIAP</mixin>-->
-
+  <STREAM id="localcolumns">
     <column name="beam_major"
-      unit="arcsec" ucd=""
+      unit="arcsec" ucd="phys.angsize;instr.beam"
       tablehead="Beam (maj)"
       description="Major axis of beam (perhaps half-sensitivity) size."
       verbLevel="15"/>
     <column name="beam_minor"
-      unit="arcsec" ucd=""
+      unit="arcsec" ucd="phys.angsize;instr.beam"
       tablehead="Beam (min)"
       description="Minor axis of beam (perhaps half-sensitivity) size."
       verbLevel="15"/>
     <column name="beam_pa"
-      unit="degree" ucd=""
+      unit="degree" ucd="pos.angsize;instr.beam"
       tablehead="Beam (PA)"
       description="Position agle of beam."
       verbLevel="15"/>
     <column name="object" type="text"
-      ucd=""
+      ucd="meta.id;src"
       tablehead="Object"
       description="Target object observed"
       verbLevel="10"/>
+    <column name="obsid" type="text"
+      ucd="meta.id;obs"
+      tablehead="Obs. Id"
+      description="APERTIF observation id; use datalink to discover other
+        data products from this observation."
+      verbLevel="5"/>
+    <column name="datalink" type="text"
+ 			tablehead="Datalink Access"
+			description="URL of a datalink document for the dataset (raw data,
+			  derived data"
+			displayHint="type=url">
+			<property name="targetType"
+				>application/x-votable+xml;content=datalink</property>
+			<property name="targetTitle">Datalink</property>
+		</column>
+  </STREAM>
+
+  <table id="main" onDisk="True" mixin="//siap#pgs" adql="False">
+    
+    <meta name="_associatedDatalinkService">
+      <meta name="serviceId">dl</meta>
+      <meta name="idColumn">accref</meta>
+    </meta>
+
+<!--    <mixin
+      calibLevel="2"
+      collectionName="'%a few letters identifying this data%'"
+      targetName="%column name of an object designation%"
+      expTime="%column name of an exposure time%"
+      targetClass="'%simbad taget class%'"
+    >//obscore#publishSIAP</mixin>-->
 
+    <FEED source="localcolumns"/>
   </table>
 
   <coverage>
@@ -72,12 +95,16 @@
           
           with open(self.sourceToken, "rb") as f:
             fitses = pickle.load(f)
-
+          
           for fitsdesc in fitses:
+            # relpath must be the path relative to the root URL given below.
+            relpath = fitsdesc["name"][2:]
+
             rawdict = dict(
                 (card.keyword.replace("-", "_"), card.value)
               for card in fitstools.parseCards(fitsdesc["header"]))
-            rawdict["accref"] = fitsdesc["name"]
+            rawdict["relpath"] = relpath
+            rawdict["accref"] = "svc_2019/"+relpath
             rawdict["fsize"] = fitsdesc["size"]
             yield rawdict
         </code>
@@ -87,10 +114,10 @@
         <bind key="accref">@accref</bind>
         <bind key="fsize">@fsize</bind>
         <bind key="path"
-          >"https://alta.astron.nl/webdav/SVC_2019_Imaging/"+accref</bind>
+          >"https://alta.astron.nl/webdav/SVC_2019_Imaging/"+@relpath</bind>
         <bind key="preview"
           >"https://alta.astron.nl/alta-static/media/"+(
-            accref[:-5]+".png")</bind>
+            @relpath[:-5]+".png")</bind>
         <bind key="preview_mime">"image/png"</bind>
       </rowfilter>
 
@@ -98,14 +125,12 @@
 
     <make table="main">
       <rowmaker>
-        <map key="beam_major">@BMAJ</map>
-        <map key="beam_minor">@BMIN</map>
-        <map key="beam_pa">@BPA</map>
+        <map key="beam_major" nullExcs="KeyError">@BMAJ</map>
+        <map key="beam_minor" nullExcs="KeyError">@BMIN</map>
+        <map key="beam_pa" nullExcs="KeyError">@BPA</map>
         <map key="object">@OBJECT</map>
-
-        <map key="bandpassRefval">LIGHT_C/@CRVAL3</map>
-        <map key="bandpassLo">LIGHT_C/(@CRVAL3+@CDELT3)</map>
-        <map key="bandpassHi">LIGHT_C/(@CRVAL3-@CDELT3)</map>
+        <map key="obsid">@relpath.split("/")[0]</map>
+        <map key="datalink">\dlMetaURI{dl}</map>
 
         <apply procDef="//siap#setMeta">
           <bind key="dateObs">@DATE_OBS</bind>
@@ -116,21 +141,85 @@
 
         <apply>
           <code>
-            if @NAXIS4==1:
-              @NAXIS -= 1
-              if @NAXIS3==1:
+            if "NAXIS4" in vars:
+              if @NAXIS4==1:
                 @NAXIS -= 1
+                if @NAXIS3==1:
+                  @NAXIS -= 1
           </code>
         </apply>
 
         <apply procDef="//siap#computePGS"/>
 
-        <!-- any custom columns need to be mapped here; do *not* use
-          idmaps="*" with SIAP -->
+        <apply name="computeBandpass">
+          <code>
+            # right now, the spectral axis is always 3, so let's try
+            # this.  If this ever becomes variable, we'll probably
+            # want to look at CTYPEn for FREQ-OBS
+            specAxis = getWCSAxis(vars, 3, True)
+            nSpecPix = vars.get("NAXIS3")
+            if not nSpecPix:
+              return
+            elif nSpecPix==1:
+              result["bandpassRefval"] = LIGHT_C/specAxis.pixToPhys(1)
+              result["bandpassLo"] = LIGHT_C/specAxis.pixToPhys(0.5)
+              result["bandpassHi"] = LIGHT_C/specAxis.pixToPhys(1.5)
+            elif nSpecPix>1:
+              result["bandpassRefval"] = LIGHT_C/specAxis.pixToPhys(nSpecPix/2)
+              result["bandpassHi"] = LIGHT_C/specAxis.pixToPhys(nSpecPix+0.5)
+              result["bandpassLo"] = LIGHT_C/specAxis.pixToPhys(0.5)
+          </code>
+        </apply>
+
       </rowmaker>
     </make>
   </data>
 
+  <service id="dl" allowed="dlmeta">
+    <meta name="description">
+      This datalink service gives all data products related to an observation.
+      Pass in accrefs of any product that's resulted from the observation.
+    </meta>
+
+    <datalinkCore>
+      <descriptorGenerator>
+        <code>
+          accref = pubDID.split("?")[-1]
+          desc = ProductDescriptor.fromAccref(pubDID, accref)
+          return desc
+        </code>
+      </descriptorGenerator>
+
+      <metaMaker>
+        <setup>
+          <par name="fnameToMeta"> {
+            "image_mf_V.fits": (
+              "#derivation",
+              "Continuum image generated by summing along the spectral axis"),
+          }</par>
+        </setup>
+        <code>
+          obsid = descriptor.pubDID.split("/")[1]
+          with base.getTableConn() as conn:
+            for row in conn.queryToDicts(
+                "SELECT * FROM \schema.main"
+                " WHERE obsid=%(obsid)s", locals()):
+              
+              sem, desc = fnameToMeta.get(
+                row["accref"].split("/")[-1],
+                ("#unknown", "Missing Description"))
+
+              yield descriptor.makeLink(
+                row["accref"],
+                semantics=sem,
+                description=desc,
+                contentType="image/fits",
+                contentLength=row["accsize"])
+        </code>
+      </metaMaker>
+    </datalinkCore>
+  </service>
+
   <!-- if you want to build an attractive form-based service from
     SIAP, you probably want to have a custom form service; for
     just basic functionality, this should do, however. -->