diff --git a/gracedb/alert.py b/gracedb/alert.py
index 780833114a75161d1aa7f1a1072c9e050ef2b8ac..15e4f4b36f21713d4684a7f42866a4aa0c47ed5e 100644
--- a/gracedb/alert.py
+++ b/gracedb/alert.py
@@ -11,8 +11,8 @@ import logging
 
 log = logging.getLogger('gracedb.alert')
 
-def issueAlert(event, location, temp_data_loc, event_url):
-    issueXMPPAlert(event, location, temp_data_loc)
+def issueAlert(event, location, event_url, serialized_object=None):
+    issueXMPPAlert(event, location, serialized_object=serialized_object)
     issueEmailAlert(event, event_url)
 
 def indent(nindent, text):
@@ -23,14 +23,16 @@ def prepareSummary(event):
     return "GPS Time: %s" % event.gpstime
 
 
-def issueAlertForUpdate(event, description, doxmpp, filename=""):
+# The serialized object passed in here will normally be an EventLog or EMBB log entry
+def issueAlertForUpdate(event, description, doxmpp, filename="", serialized_object=None):
     if doxmpp:
-        issueXMPPAlert(event, filename, "", "update", description)
+        issueXMPPAlert(event, filename, "update", description, serialized_object)
     # XXX No emails for this.  Argh.
 
-def issueAlertForLabel(event, label, doxmpp):
+# The only kind of serialized object relevant for a Label is an event.
+def issueAlertForLabel(event, label, doxmpp, serialized_event=None):
     if doxmpp:
-        issueXMPPAlert(event, "", "", "label", label)
+        issueXMPPAlert(event, "", "label", label, serialized_event)
     # Email
     profileRecips = []
     pipeline = event.pipeline
@@ -109,7 +111,8 @@ Event Summary:
 
     #send_mail(subject, message, fromaddress, toaddresses)
 
-def issueXMPPAlert(event, location, temp_data_loc, alert_type="new", description=""):
+def issueXMPPAlert(event, location, alert_type="new", description="", serialized_object=None):
+    log.debug('issueXMPPAlert: inside')
     
     nodename = "%s_%s" % (event.group.name, event.pipeline.name)
     nodename = nodename.lower()
@@ -134,12 +137,13 @@ def issueXMPPAlert(event, location, temp_data_loc, alert_type="new", description
     lva_data = {
         'file': location,
         'uid': event.graceid(),
-        'data_loc': temp_data_loc,
         'alert_type': alert_type,
         # The following string cast is necessary because sometimes 
         # description is a label object!
         'description': str(description),
     }
+    if serialized_object:
+        lva_data['object'] = serialized_object
     msg = json.dumps(lva_data)
     log.debug("issueXMPPAlert: writing message %s" % msg)
 
@@ -148,6 +152,7 @@ def issueXMPPAlert(event, location, temp_data_loc, alert_type="new", description
         null = open('/dev/null','w')
         p = Popen(
             ["lvalert_send",
+#             "--server=jabber.phys.uwm.edu",
              "--username=gracedb",
              "--password=w4k3upal1ve",
              "--file=-",
diff --git a/gracedb/api.py b/gracedb/api.py
index dd843db4f6b4222c9b36dc3105a34e8a436a6b1f..7339b5349cba74457481b7eaee5f99f11d05b658 100644
--- a/gracedb/api.py
+++ b/gracedb/api.py
@@ -4,8 +4,6 @@ from django.http import HttpResponseForbidden, HttpResponseServerError
 from django.core.urlresolvers import reverse as django_reverse
 
 from django.conf import settings
-from django.utils.http import urlquote
-from django.utils import dateformat
 from django.utils.functional import wraps
 from django.db import IntegrityError
 
@@ -20,6 +18,9 @@ from view_logic import create_label, get_performance_info
 from view_logic import _createEventFromForm
 from view_logic import create_eel
 from view_utils import fix_old_creation_request
+from view_utils import eventToDict, eventLogToDict, labelToDict
+from view_utils import embbEventLogToDict
+from view_utils import reverse
 
 from translator import handle_uploaded_data
 from forms import CreateEventForm
@@ -33,7 +34,6 @@ import os
 import urllib
 import shutil
 import exceptions
-import pytz
 
 from utils.vfile import VersionedFile
 
@@ -62,9 +62,6 @@ MAX_FAILED_OPEN_ATTEMPTS = 5
 from forms import SimpleSearchForm
 
 
-from rest_framework.reverse import reverse as rest_framework_reverse
-from django.core.urlresolvers import resolve, get_script_prefix
-
 ##################################################################
 # Stuff for the LigoLwRenderer
 from glue.ligolw import ligolw
@@ -77,66 +74,6 @@ import StringIO
 
 use_in(LIGOLWContentHandler)
 
-# Note about reverse() in this file -- there are THREE versions of it here.
-#
-# SOURCE                               LOCAL NAME
-# django.core.urlresolvers.reverse ==> django_reverse
-# rest_framework.reverse.reverse   ==> rest_framework_reverse
-# reverse defined below            ==> reverse
-#
-# The Django reverse returns relative paths.
-#
-# The rest framework reverse is basically the same as the Django version
-# but will return full paths if the request is passed in using the request kw arg.
-#
-# The reverse defined below is basically the rest framework reverse, but
-# will attempt to deal with multiply-include()-ed url.py-type files with
-# different namespaces.  (see the comments in the function)
-
-def reverse(name, *args, **kw):
-    """Find a URL.  Respect where that URL was defined in urls.py
-
-    Allow for a set of URLs to have been include()-ed on multiple URL paths.
-
-    eg  urlpatterns = (
-        (r'^api1/', include('someapp.urls', app_name="api", namespace="x509")),
-        (r'^api2/', include('someapp.urls', app_name="api", namespace="shib")),
-        ...)
-
-    then reverse("api:root", request=self.request) will give the obviously
-    correct full URL for the URL named "root" in someapp/urls.py.  Django's
-    reverse will pick one URL path and use it no matter what path the
-    URL resolver flows through and it will do so whether you specify an app_name
-    or not.
-
-    This function solves that issue.  app_name and namespace are required.
-    The request must be the value at kw['request']
-
-    Assembled with hints from http://stackoverflow.com/a/13249060
-    """
-    # XXX rashly assuming app is "api:"  brutal.
-    if type(name) == str and not name.startswith("api:"):
-        name = "api:"+name
-
-    # Idea is to put 'current_app' into the kw args of reverse
-    # where current_app is the namespace of the urlpattern we got here from.
-    # Given that, reverse will find the right patterns in your urlpatterns.
-    # I do know know why Django does not do this by default.
-
-    # This probably only works if you give app_names which are the same
-    # and namespaces that are different.
-
-    if 'request' in kw and 'current_app' not in kw:
-        request = kw['request']
-        # For some reason, resolve() does not seem to like the script_prefix.
-        # So, remove it.
-        prefix = get_script_prefix()
-        path = request.path.replace(prefix, '/')
-        current_app = resolve(path).namespace
-        kw['current_app'] = current_app
-
-    return rest_framework_reverse(name, *args, **kw)
-
 # 
 # We do not want to handle authentication here because it has already
 # been taken care of by Apache/Shib or Apache/mod_ssl. Moreover the 
@@ -435,111 +372,6 @@ class TSVRenderer(BaseRenderer):
 #==================================================================
 # Events
 
-SERVER_TZ = pytz.timezone(settings.TIME_ZONE)
-def timeToUTC(dt):
-    if not dt.tzinfo:
-        dt = SERVER_TZ.localize(dt)
-    return dateformat.format(dt.astimezone(pytz.utc), settings.GRACE_DATETIME_FORMAT)
-
-def eventToDict(event, columns=None, request=None):
-    """Convert an Event to a dictionary so it can be serialized.  (ugh)"""
-
-    # XXX  Need to understand serializers.
-
-    rv = {}
-
-    graceid = event.graceid()
-    try:
-        rv['submitter'] = event.submitter.username
-    except:
-        rv['submitter'] = 'Unknown'
-
-    rv['created'] = timeToUTC(event.created)
-    rv['group'] = event.group.name
-    rv['graceid'] = graceid
-    rv['pipeline'] = event.pipeline.name
-    if event.search:
-        rv['search'] = event.search.name
-#    rv['analysisType'] = event.get_analysisType_display()
-    rv['gpstime'] = event.gpstime
-    rv['instruments'] = event.instruments
-    rv['nevents'] = event.nevents
-    rv['far'] = event.far
-    rv['likelihood'] = event.likelihood
-    rv['labels'] = dict([
-            (labelling.label.name,
-                reverse("labels",
-                    args=[graceid, labelling.label.name],
-                    request=request))
-            for labelling in event.labelling_set.all()])
-    # XXX Try to produce a dictionary of analysis specific attributes.  Duck typing.
-    rv['extra_attributes'] = {}
-    try:
-        # GrbEvent
-        rv['extra_attributes']['GRB'] = {
-                "ivorn" : event.ivorn,
-                "author_ivorn" : event.author_ivorn,
-                "author_shortname" : event.author_shortname,
-                "observatory_location_id" : event.observatory_location_id,
-                "coord_system" : event.coord_system,
-                "ra" : event.ra,
-                "dec" : event.dec,
-                "error_radius" : event.error_radius,
-                "how_description" : event.how_description,
-                "how_reference_url" : event.how_reference_url,
-                }
-    except:
-        pass
-    try:
-        # CoincInspiralEvent
-        rv['extra_attributes']['CoincInspiral'] = {
-                "ifos" : event.ifos,
-                "end_time" : event.end_time,
-                "end_time_ns" : event.end_time_ns,
-                "mass" : event.mass,
-                "mchirp" : event.mchirp,
-                "minimum_duration" : event.minimum_duration,
-                "snr" : event.snr,
-                "false_alarm_rate" : event.false_alarm_rate,
-                "combined_far" : event.combined_far,
-                }
-    except:
-        pass
-    try:
-        # MultiBurstEvent
-        rv['extra_attributes']['MultiBurst'] = {
-                "ifos" : event.ifos,
-                "start_time" : event.start_time,
-                "start_time_ns" : event.start_time_ns,
-                "duration" : event.duration,
-                "peak_time" : event.peak_time,
-                "peak_time_ns" : event.peak_time_ns,
-                "central_freq" : event.central_freq,
-                "bandwidth" : event.bandwidth,  
-                "amplitude" : event.amplitude,
-                "snr" : event.snr,
-                "confidence" : event.confidence,
-                "false_alarm_rate" : event.false_alarm_rate,
-                "ligo_axis_ra" : event.ligo_axis_ra,
-                "ligo_axis_dec" : event.ligo_axis_dec, 
-                "ligo_angle" : event.ligo_angle,    
-                "ligo_angle_sig" : event.ligo_angle_sig,
-                }
-    except:
-        pass
-    rv['links'] = {
-            "neighbors" : reverse("neighbors", args=[graceid], request=request),
-            "log"   : reverse("eventlog-list", args=[graceid], request=request),
-            "embb"   : reverse("embbeventlog-list", args=[graceid], request=request),
-            "files" : reverse("files", args=[graceid], request=request),
-            "filemeta" : reverse("filemeta", args=[graceid], request=request),
-            "labels" : reverse("labels", args=[graceid], request=request),
-            "self"  : reverse("event-detail", args=[graceid], request=request),
-            "tags"  : reverse("eventtag-list", args=[graceid], request=request),
-            }
-    return rv
-
-
 class EventList(APIView):
     """
     This resource represents the collection of  all candidate events in GraceDB.
@@ -660,6 +492,9 @@ class EventList(APIView):
 
     #@pipeline_auth_required
     def post(self, request, format=None):
+        import logging
+        logger = logging.getLogger(__name__)
+        logger.debug("Hello from inside the event creator.")
 
         # XXX Deal with POSTs coming in from the old client.
         # Eventually, we will want to get rid of this check and just let it fail.
@@ -922,16 +757,6 @@ class EventNeighbors(APIView):
 
 # XXX NOT FINISHED
 
-def labelToDict(label, request=None):
-    return { 
-            "name" : label.label.name,
-            "creator" : label.creator.username,
-            "created" : label.created,
-            "self" : reverse("labels",
-                args=[label.event.graceid(), label.label.name],
-                request=request),
-           }
-
 class EventLabel(APIView):
     """Event Label"""
     authentication_classes = (LigoAuthentication,)
@@ -975,36 +800,6 @@ class EventLabel(APIView):
 #==================================================================
 # EventLog
 
-# Janky serialization
-def eventLogToDict(log, request=None):
-    uri = None
-    taglist_uri = None
-    file_uri = None
-    if request:
-        uri = reverse("eventlog-detail",
-                args=[log.event.graceid(), log.N],
-                request=request)
-        taglist_uri = reverse("eventlogtag-list",
-                args=[log.event.graceid(), log.N],
-                request=request)
-        if log.filename:
-            actual_filename = log.filename
-            if log.file_version:
-                actual_filename += ',%d' % log.file_version
-            filename = urlquote(actual_filename)
-            file_uri = reverse("files",
-                args=[log.event.graceid(), filename],
-                request=request)
-
-    return {
-                "comment" : log.comment,
-                "created" : log.created,
-                "issuer"  : log.issuer.username,
-                "self"    : uri,
-                "tags"    : taglist_uri,
-                "file"    : file_uri,
-           }
-
 class EventLogList(APIView):
     """Event Log List Resource
 
@@ -1093,9 +888,12 @@ class EventLogList(APIView):
 
         # Issue alert.
         description = "LOG: "
+        fname = ""
         if uploadedFile:
             description = "UPLOAD: '%s' " % uploadedFile.name
-            issueAlertForUpdate(event, description+message, doxmpp=True, filename=uploadedFile.name)
+            fname = uploadedFile.name
+        issueAlertForUpdate(event, description+message, doxmpp=True, 
+            filename=fname, serialized_object=rv)
 
         return response
 
@@ -1112,42 +910,6 @@ class EventLogDetail(APIView):
 #==================================================================
 # EMBBEventLog (EEL)
 
-# EEL serializer.
-def embbEventLogToDict(eel, request=None):
-    uri = None
-    if request:
-        uri = reverse("embbeventlog-detail",
-                args=[eel.event.graceid(), eel.N],
-                request=request)
-    return {
-                "self"    : uri,
-                "created" : eel.created,
-                "submitter"  : eel.submitter.username,
-                "group" : eel.group.name,
-                "instrument" : eel.instrument,
-                "footprintID" : eel.footprintID,
-                "waveband" : eel.waveband,
-
-                "ra"       : eel.ra,
-                "dec"      : eel.dec,
-                "raWidth"  : eel.raWidth,
-                "decWidth" : eel.decWidth,
-                "gpstime"  : eel.gpstime,
-                "duration" : eel.duration,
-
-                "raList"       : json.loads('['+eel.raList+']'),
-                "decList"      : json.loads('['+eel.decList+']'),
-                "raWidthList"  : json.loads('['+eel.raWidthList+']'),
-                "decWidthList" : json.loads('['+eel.decWidthList+']'),
-                "gpstimeList"  : json.loads('['+eel.gpstimeList+']'),
-                "durationList" : json.loads('['+eel.durationList+']'),
-
-                "eel_status" : eel.get_eel_status_display(),
-                "obs_status" : eel.get_obs_status_display(),
-                "comment" : eel.comment,
-                "extra_info_dict" : eel.extra_info_dict,
-           }
-
 class EMBBEventLogList(APIView):
     """EMBB Event Log List Resource
 
@@ -1195,7 +957,8 @@ class EMBBEventLogList(APIView):
 
         # Issue alert.
         description = "New EMBB log entry."
-        issueAlertForUpdate(event, description, doxmpp=True)
+        issueAlertForUpdate(event, description, doxmpp=True,
+            filename="", serialized_object=rv)
 
         return response
 
@@ -1267,13 +1030,20 @@ class TagList(APIView):
 
     def get(self, request):
         # Return a list of links to all tag objects.
+        tag_dict = {}
+        for tag in Tag.objects.all():
+            tag_dict[tag.name] = { 
+                'displayName': tag.displayName,
+                'blessed': tag.name in settings.BLESSED_TAGS
+            }
         rv = {
 #                 'tags' : [ reverse("tag-detail", args=[tag.name],
 #                                    request=request)
 #                            for tag in Tag.objects.all() ]
 #                For now, we just output the tag names, since we don't know what 
 #                tag-detail should look like.
-                 'tags' : [ tag.name for tag in Tag.objects.all() ]
+#                 'tags' : [ tag.name for tag in Tag.objects.all() ]
+                  'tags' : tag_dict,
              }
         return Response(rv)
 
@@ -1893,7 +1663,8 @@ class Files(APIView):
 
         try:
             description = "UPLOAD: {0}".format(filename)
-            issueAlertForUpdate(event, description, doxmpp=True, filename=filename)
+            issueAlertForUpdate(event, description, doxmpp=True, 
+                filename=filename, serialized_object = eventLogToDict(logentry))
         except:
             # XXX something should be done here.
             pass
diff --git a/gracedb/management/commands/write_rate_info.py b/gracedb/management/commands/write_rate_info.py
new file mode 100644
index 0000000000000000000000000000000000000000..399d3a7b0098e5edc1cc6bb4bf294d2ab7e75bc0
--- /dev/null
+++ b/gracedb/management/commands/write_rate_info.py
@@ -0,0 +1,13 @@
+from django.conf import settings
+from django.core.management.base import NoArgsCommand
+from gracedb.reports import rate_data
+import json
+
+class Command(NoArgsCommand):
+    help = "I write down rate data in JSON to disk. That's about it."
+
+    def handle_noargs(self, **options):
+        outfile = open(settings.RATE_INFO_FILE, 'w')
+        json_data = json.dumps(rate_data())
+        outfile.write(json_data)
+        outfile.close()
diff --git a/gracedb/migrations/0035_add_mdc_search.py b/gracedb/migrations/0035_add_mdc_search.py
new file mode 100644
index 0000000000000000000000000000000000000000..efe6cb292c388fef2fb367710b3cc9f79d023fec
--- /dev/null
+++ b/gracedb/migrations/0035_add_mdc_search.py
@@ -0,0 +1,268 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+
+class Migration(DataMigration):
+
+    def forwards(self, orm):
+        orm.Search.objects.create(name='MDC')
+
+    def backwards(self, orm):
+        orm.Search.objects.get(name='MDC').delete()
+
+    models = {
+        u'auth.group': {
+            'Meta': {'object_name': 'Group'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+        },
+        u'auth.permission': {
+            'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        u'auth.user': {
+            'Meta': {'object_name': 'User'},
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        u'contenttypes.contenttype': {
+            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        u'gracedb.approval': {
+            'Meta': {'object_name': 'Approval'},
+            'approvedEvent': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}),
+            'approver': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+            'approvingCollaboration': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+        },
+        u'gracedb.coincinspiralevent': {
+            'Meta': {'ordering': "['-id']", 'object_name': 'CoincInspiralEvent', '_ormbases': [u'gracedb.Event']},
+            'combined_far': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'end_time': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+            'end_time_ns': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+            u'event_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['gracedb.Event']", 'unique': 'True', 'primary_key': 'True'}),
+            'false_alarm_rate': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'ifos': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20'}),
+            'mass': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'mchirp': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'minimum_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'snr': ('django.db.models.fields.FloatField', [], {'null': 'True'})
+        },
+        u'gracedb.embbeventlog': {
+            'Meta': {'ordering': "['-created', '-N']", 'unique_together': "(('event', 'N'),)", 'object_name': 'EMBBEventLog'},
+            'N': ('django.db.models.fields.IntegerField', [], {}),
+            'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'dec': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'decList': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'decWidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'decWidthList': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'duration': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+            'durationList': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'eel_status': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
+            'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}),
+            'extra_info_dict': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'footprintID': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'gpstime': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+            'gpstimeList': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.EMGroup']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'instrument': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
+            'obs_status': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
+            'ra': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'raList': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'raWidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'raWidthList': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'submitter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+            'waveband': ('django.db.models.fields.CharField', [], {'max_length': '25'})
+        },
+        u'gracedb.emgroup': {
+            'Meta': {'object_name': 'EMGroup'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'})
+        },
+        u'gracedb.event': {
+            'Meta': {'ordering': "['-id']", 'object_name': 'Event'},
+            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'far': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'gpstime': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+            'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Group']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'instruments': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20'}),
+            'labels': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['gracedb.Label']", 'through': u"orm['gracedb.Labelling']", 'symmetrical': 'False'}),
+            'likelihood': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'nevents': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+            'perms': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+            'pipeline': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Pipeline']"}),
+            'search': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Search']", 'null': 'True'}),
+            'submitter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
+        },
+        u'gracedb.eventlog': {
+            'Meta': {'ordering': "['-created', '-N']", 'unique_together': "(('event', 'N'),)", 'object_name': 'EventLog'},
+            'N': ('django.db.models.fields.IntegerField', [], {}),
+            'comment': ('django.db.models.fields.TextField', [], {}),
+            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}),
+            'file_version': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'filename': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'issuer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
+        },
+        u'gracedb.grbevent': {
+            'Meta': {'ordering': "['-id']", 'object_name': 'GrbEvent', '_ormbases': [u'gracedb.Event']},
+            'author_ivorn': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'author_shortname': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'coord_system': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'dec': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'error_radius': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            u'event_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['gracedb.Event']", 'unique': 'True', 'primary_key': 'True'}),
+            'how_description': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'how_reference_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+            'ivorn': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'observatory_location_id': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'ra': ('django.db.models.fields.FloatField', [], {'null': 'True'})
+        },
+        u'gracedb.group': {
+            'Meta': {'object_name': 'Group'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '20'})
+        },
+        u'gracedb.label': {
+            'Meta': {'object_name': 'Label'},
+            'defaultColor': ('django.db.models.fields.CharField', [], {'default': "'black'", 'max_length': '20'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'})
+        },
+        u'gracedb.labelling': {
+            'Meta': {'object_name': 'Labelling'},
+            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+            'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'label': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Label']"})
+        },
+        u'gracedb.multiburstevent': {
+            'Meta': {'ordering': "['-id']", 'object_name': 'MultiBurstEvent', '_ormbases': [u'gracedb.Event']},
+            'amplitude': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'bandwidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'central_freq': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'confidence': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            u'event_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['gracedb.Event']", 'unique': 'True', 'primary_key': 'True'}),
+            'false_alarm_rate': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'ifos': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20'}),
+            'ligo_angle': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'ligo_angle_sig': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'ligo_axis_dec': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'ligo_axis_ra': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'peak_time': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+            'peak_time_ns': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+            'snr': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'start_time': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+            'start_time_ns': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'})
+        },
+        u'gracedb.pipeline': {
+            'Meta': {'object_name': 'Pipeline'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        u'gracedb.search': {
+            'Meta': {'object_name': 'Search'},
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        u'gracedb.singleinspiral': {
+            'Gamma0': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Gamma1': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Gamma2': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Gamma3': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Gamma4': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Gamma5': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Gamma6': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Gamma7': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Gamma8': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Gamma9': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Meta': {'object_name': 'SingleInspiral'},
+            'alpha': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'alpha1': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'alpha2': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'alpha3': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'alpha4': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'alpha5': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'alpha6': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'amplitude': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'bank_chisq': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'bank_chisq_dof': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'beta': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'channel': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
+            'chi': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'chisq': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'chisq_dof': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'coa_phase': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'cont_chisq': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'cont_chisq_dof': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'eff_distance': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'end_time': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'end_time_gmst': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'end_time_ns': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'eta': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}),
+            'event_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'f_final': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'ifo': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True'}),
+            'impulse_time': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'impulse_time_ns': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'kappa': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'mass1': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'mass2': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'mchirp': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'mtotal': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'psi0': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'psi3': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'rsqveto_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'search': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True'}),
+            'sigmasq': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'snr': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'tau0': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'tau2': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'tau3': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'tau4': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'tau5': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'template_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'ttotal': ('django.db.models.fields.FloatField', [], {'null': 'True'})
+        },
+        u'gracedb.tag': {
+            'Meta': {'object_name': 'Tag'},
+            'displayName': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'eventlogs': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['gracedb.EventLog']", 'symmetrical': 'False'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        }
+    }
+
+    complete_apps = ['gracedb']
+    symmetrical = True
diff --git a/gracedb/migrations/0036_auto__add_field_singleinspiral_spin1x__add_field_singleinspiral_spin1y.py b/gracedb/migrations/0036_auto__add_field_singleinspiral_spin1x__add_field_singleinspiral_spin1y.py
new file mode 100644
index 0000000000000000000000000000000000000000..162a177c1edec9f40b14ab4b3d78dbb8bf500f6b
--- /dev/null
+++ b/gracedb/migrations/0036_auto__add_field_singleinspiral_spin1x__add_field_singleinspiral_spin1y.py
@@ -0,0 +1,320 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        # Adding field 'SingleInspiral.spin1x'
+        db.add_column(u'gracedb_singleinspiral', 'spin1x',
+                      self.gf('django.db.models.fields.FloatField')(null=True),
+                      keep_default=False)
+
+        # Adding field 'SingleInspiral.spin1y'
+        db.add_column(u'gracedb_singleinspiral', 'spin1y',
+                      self.gf('django.db.models.fields.FloatField')(null=True),
+                      keep_default=False)
+
+        # Adding field 'SingleInspiral.spin1z'
+        db.add_column(u'gracedb_singleinspiral', 'spin1z',
+                      self.gf('django.db.models.fields.FloatField')(null=True),
+                      keep_default=False)
+
+        # Adding field 'SingleInspiral.spin2x'
+        db.add_column(u'gracedb_singleinspiral', 'spin2x',
+                      self.gf('django.db.models.fields.FloatField')(null=True),
+                      keep_default=False)
+
+        # Adding field 'SingleInspiral.spin2y'
+        db.add_column(u'gracedb_singleinspiral', 'spin2y',
+                      self.gf('django.db.models.fields.FloatField')(null=True),
+                      keep_default=False)
+
+        # Adding field 'SingleInspiral.spin2z'
+        db.add_column(u'gracedb_singleinspiral', 'spin2z',
+                      self.gf('django.db.models.fields.FloatField')(null=True),
+                      keep_default=False)
+
+
+    def backwards(self, orm):
+        # Deleting field 'SingleInspiral.spin1x'
+        db.delete_column(u'gracedb_singleinspiral', 'spin1x')
+
+        # Deleting field 'SingleInspiral.spin1y'
+        db.delete_column(u'gracedb_singleinspiral', 'spin1y')
+
+        # Deleting field 'SingleInspiral.spin1z'
+        db.delete_column(u'gracedb_singleinspiral', 'spin1z')
+
+        # Deleting field 'SingleInspiral.spin2x'
+        db.delete_column(u'gracedb_singleinspiral', 'spin2x')
+
+        # Deleting field 'SingleInspiral.spin2y'
+        db.delete_column(u'gracedb_singleinspiral', 'spin2y')
+
+        # Deleting field 'SingleInspiral.spin2z'
+        db.delete_column(u'gracedb_singleinspiral', 'spin2z')
+
+
+    models = {
+        u'auth.group': {
+            'Meta': {'object_name': 'Group'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+        },
+        u'auth.permission': {
+            'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        u'auth.user': {
+            'Meta': {'object_name': 'User'},
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        u'contenttypes.contenttype': {
+            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        u'gracedb.approval': {
+            'Meta': {'object_name': 'Approval'},
+            'approvedEvent': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}),
+            'approver': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+            'approvingCollaboration': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+        },
+        u'gracedb.coincinspiralevent': {
+            'Meta': {'ordering': "['-id']", 'object_name': 'CoincInspiralEvent', '_ormbases': [u'gracedb.Event']},
+            'combined_far': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'end_time': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+            'end_time_ns': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+            u'event_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['gracedb.Event']", 'unique': 'True', 'primary_key': 'True'}),
+            'false_alarm_rate': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'ifos': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20'}),
+            'mass': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'mchirp': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'minimum_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'snr': ('django.db.models.fields.FloatField', [], {'null': 'True'})
+        },
+        u'gracedb.embbeventlog': {
+            'Meta': {'ordering': "['-created', '-N']", 'unique_together': "(('event', 'N'),)", 'object_name': 'EMBBEventLog'},
+            'N': ('django.db.models.fields.IntegerField', [], {}),
+            'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'dec': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'decList': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'decWidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'decWidthList': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'duration': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+            'durationList': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'eel_status': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
+            'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}),
+            'extra_info_dict': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'footprintID': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'gpstime': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+            'gpstimeList': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.EMGroup']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'instrument': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
+            'obs_status': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
+            'ra': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'raList': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'raWidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'raWidthList': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            'submitter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+            'waveband': ('django.db.models.fields.CharField', [], {'max_length': '25'})
+        },
+        u'gracedb.emgroup': {
+            'Meta': {'object_name': 'EMGroup'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'})
+        },
+        u'gracedb.event': {
+            'Meta': {'ordering': "['-id']", 'object_name': 'Event'},
+            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'far': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'gpstime': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+            'group': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Group']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'instruments': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20'}),
+            'labels': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['gracedb.Label']", 'through': u"orm['gracedb.Labelling']", 'symmetrical': 'False'}),
+            'likelihood': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'nevents': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+            'perms': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+            'pipeline': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Pipeline']"}),
+            'search': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Search']", 'null': 'True'}),
+            'submitter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
+        },
+        u'gracedb.eventlog': {
+            'Meta': {'ordering': "['-created', '-N']", 'unique_together': "(('event', 'N'),)", 'object_name': 'EventLog'},
+            'N': ('django.db.models.fields.IntegerField', [], {}),
+            'comment': ('django.db.models.fields.TextField', [], {}),
+            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}),
+            'file_version': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'filename': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'issuer': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
+        },
+        u'gracedb.grbevent': {
+            'Meta': {'ordering': "['-id']", 'object_name': 'GrbEvent', '_ormbases': [u'gracedb.Event']},
+            'author_ivorn': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'author_shortname': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'coord_system': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'dec': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'error_radius': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            u'event_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['gracedb.Event']", 'unique': 'True', 'primary_key': 'True'}),
+            'how_description': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'how_reference_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+            'ivorn': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'observatory_location_id': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'ra': ('django.db.models.fields.FloatField', [], {'null': 'True'})
+        },
+        u'gracedb.group': {
+            'Meta': {'object_name': 'Group'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '20'})
+        },
+        u'gracedb.label': {
+            'Meta': {'object_name': 'Label'},
+            'defaultColor': ('django.db.models.fields.CharField', [], {'default': "'black'", 'max_length': '20'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'})
+        },
+        u'gracedb.labelling': {
+            'Meta': {'object_name': 'Labelling'},
+            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+            'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'label': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Label']"})
+        },
+        u'gracedb.multiburstevent': {
+            'Meta': {'ordering': "['-id']", 'object_name': 'MultiBurstEvent', '_ormbases': [u'gracedb.Event']},
+            'amplitude': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'bandwidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'central_freq': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'confidence': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            u'event_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['gracedb.Event']", 'unique': 'True', 'primary_key': 'True'}),
+            'false_alarm_rate': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'ifos': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20'}),
+            'ligo_angle': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'ligo_angle_sig': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'ligo_axis_dec': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'ligo_axis_ra': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'peak_time': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+            'peak_time_ns': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+            'snr': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'start_time': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+            'start_time_ns': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'})
+        },
+        u'gracedb.pipeline': {
+            'Meta': {'object_name': 'Pipeline'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        u'gracedb.search': {
+            'Meta': {'object_name': 'Search'},
+            'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        u'gracedb.singleinspiral': {
+            'Gamma0': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Gamma1': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Gamma2': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Gamma3': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Gamma4': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Gamma5': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Gamma6': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Gamma7': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Gamma8': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Gamma9': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'Meta': {'object_name': 'SingleInspiral'},
+            'alpha': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'alpha1': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'alpha2': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'alpha3': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'alpha4': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'alpha5': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'alpha6': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'amplitude': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'bank_chisq': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'bank_chisq_dof': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'beta': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'channel': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
+            'chi': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'chisq': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'chisq_dof': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'coa_phase': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'cont_chisq': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'cont_chisq_dof': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'eff_distance': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'end_time': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'end_time_gmst': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'end_time_ns': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'eta': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'event': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['gracedb.Event']"}),
+            'event_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'f_final': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'ifo': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True'}),
+            'impulse_time': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'impulse_time_ns': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'kappa': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'mass1': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'mass2': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'mchirp': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'mtotal': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'psi0': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'psi3': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'rsqveto_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'search': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True'}),
+            'sigmasq': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'snr': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'spin1x': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'spin1y': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'spin1z': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'spin2x': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'spin2y': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'spin2z': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'tau0': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'tau2': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'tau3': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'tau4': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'tau5': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'template_duration': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'ttotal': ('django.db.models.fields.FloatField', [], {'null': 'True'})
+        },
+        u'gracedb.tag': {
+            'Meta': {'object_name': 'Tag'},
+            'displayName': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'eventlogs': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['gracedb.EventLog']", 'symmetrical': 'False'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        }
+    }
+
+    complete_apps = ['gracedb']
\ No newline at end of file
diff --git a/gracedb/models.py b/gracedb/models.py
index 60a0f804fa416465d950d6a4fb55651b7cf396c7..338e84a666ff77dce0cab61cea10d14fe6977bd9 100644
--- a/gracedb/models.py
+++ b/gracedb/models.py
@@ -137,6 +137,8 @@ class Event(models.Model):
     def graceid(self):
         if self.group.name == "Test":
             return "T%04d" % self.id
+        elif str(self.search) == str("MDC"):
+            return "M%04d" % self.id
         elif self.pipeline == "HardwareInjection":
             return "H%04d" % self.id
         elif self.group.name == "External":
@@ -210,6 +212,8 @@ class Event(models.Model):
             return e
         if (id[0] == "E") and (e.group.name == "External"):
             return e
+        if (id[0] == "M") and (e.search.name == "MDC"):
+            return e
         if (id[0] == "G"):
             return e
         raise cls.DoesNotExist("Event matching query does not exist")
@@ -721,6 +725,12 @@ class SingleInspiral(models.Model):
     Gamma7            = models.FloatField(null=True)
     Gamma8            = models.FloatField(null=True)
     Gamma9            = models.FloatField(null=True)
+    spin1x            = models.FloatField(null=True)
+    spin1y            = models.FloatField(null=True)
+    spin1z            = models.FloatField(null=True)
+    spin2x            = models.FloatField(null=True)
+    spin2y            = models.FloatField(null=True)
+    spin2z            = models.FloatField(null=True)
 
     def end_time_full(self):
         return LIGOTimeGPS(self.end_time, self.end_time_ns)
diff --git a/gracedb/query.py b/gracedb/query.py
index b846d1ec82411350bf1923a7cbefffb80119e0dd..db0a2666fe7d66e10ca29e0376d94f67b5ebc91d 100644
--- a/gracedb/query.py
+++ b/gracedb/query.py
@@ -138,6 +138,12 @@ eidRange = eid + Suppress("..") + eid
 eidQ = Optional(Suppress(Keyword("eid:"))) + (eid^eidRange)
 eidQ = eidQ.setParseAction(maybeRange("eid", dbname="id"))
 
+# MDC event id
+mid = Suppress("M")+Word("0123456789")
+midRange = mid + Suppress("..") + mid
+midQ = Optional(Suppress(Keyword("mid:"))) + (mid^midRange)
+midQ = midQ.setParseAction(maybeRange("mid", dbname="id"))
+
 # Submitter
 submitter = QuotedString('"').setParseAction(lambda toks: Q(submitter__username=toks[0]))
 submitterQ = Optional(Suppress(Keyword("submitter:"))) + submitter
@@ -258,7 +264,7 @@ ifoQ = ifoListQ | nifoQ
 ###########################
 
 #q = (ifoQ | hasfarQ | gidQ | hidQ | tidQ | eidQ | labelQ | atypeQ | groupQ | gpsQ | createdQ | submitterQ | runQ | attributeQ).setName("query term")
-q = (ifoQ | hasfarQ | gidQ | hidQ | tidQ | eidQ | labelQ | searchQ | pipelineQ | groupQ | gpsQ | createdQ | submitterQ | runQ | attributeQ).setName("query term")
+q = (ifoQ | hasfarQ | gidQ | hidQ | tidQ | eidQ | midQ | labelQ | searchQ | pipelineQ | groupQ | gpsQ | createdQ | submitterQ | runQ | attributeQ).setName("query term")
 
 #andTheseTags = ["attr"]
 andTheseTags = ["nevents"]
@@ -286,6 +292,8 @@ def parseQuery(s):
         d["hid"] = d["hid"] & Q(pipeline__name="HardwareInjection")
     if "eid" in d:
         d["eid"] = d["eid"] & Q(group__name="External")
+    if "mid" in d:
+        d["mid"] = d["mid"] & Q(search__name="MDC")
     if "id" in d:
         d["id"] = d["id"] & ~Q(pipeline__name="HardwareInjection") & ~Q(group__name="External")
     if "id" in d and "hid" in d:
diff --git a/gracedb/reports.py b/gracedb/reports.py
index 29e11ebdbd07dfd8c60042cae36085b7bc740474..7949c33ceaa49a4adefc2242e037f0c750aa8737 100644
--- a/gracedb/reports.py
+++ b/gracedb/reports.py
@@ -57,17 +57,25 @@ def histo(request):
         uptime = None
 
 
+    # Rate information
+    try:
+        rate_info = open(settings.RATE_INFO_FILE).read()
+    except IOError:
+        rate_info = None
+
     return render_to_response(
             'gracedb/histogram.html',
             {'table': table,
              'ifar' : ifar,
              'uptime' : uptime,
-             'rate' : json.dumps(rate_data(request)),
+             #'rate' : json.dumps(rate_data(request)),
+             'rate' : rate_info,
              'url_prefix' : settings.REPORT_INFO_URL_PREFIX,
             },
             context_instance=RequestContext(request))
 
-def rate_data(request):
+#def rate_data(request):
+def rate_data():
     # XXX there is a better way -- should be using group_by or something.
     # WAAY too many queries (~300) going on here.
     now = datetime.now()
@@ -76,7 +84,7 @@ def rate_data(request):
     ts_min = now - 60 * day
     ts_max = now
     ts_step = day
-    window_size = day
+#    window_size = day
 
     types = [
         ("total",   Q()),
diff --git a/gracedb/translator.py b/gracedb/translator.py
index 2650765856673751d4d835ee445ccf7c2bad0583..1a596cba49b3077c13955374e11939dff95fd803 100644
--- a/gracedb/translator.py
+++ b/gracedb/translator.py
@@ -55,6 +55,9 @@ def handle_uploaded_data(event, datafilename,
                    comment="Original Data")
     log.save()
 
+    # XXX If you can manage to get rid of the MBTA .gwf parsing and
+    # the Omega event parsing, you can deprecate temp_data_loc. It 
+    # has already been removed from the alerts.
     temp_data_loc = ""
     warnings = []
 
diff --git a/gracedb/urls.py b/gracedb/urls.py
index 397699b595c888908bbe033d6f589985f36223ca..76dcd7fd72fe148e2672307caee652365a3f3574 100644
--- a/gracedb/urls.py
+++ b/gracedb/urls.py
@@ -11,17 +11,17 @@ urlpatterns = patterns('gracedb.views',
     url (r'^$', 'index', name="home-events"),
     url (r'^create/$', 'create', name="create"),
     url (r'^search/(?P<format>(json|flex))?$', 'search', name="search"),
-    url (r'^view/(?P<graceid>[GEHT]\d+)', 'view', name="view"),
-    url (r'^voevent/(?P<graceid>[GEHT]\d+)', 'voevent', name="voevent"),
-#    url (r'^skyalert/(?P<graceid>[GEHT]\d+)', 'skyalert', name="skyalert"),
-    url (r'^neighbors/(?P<graceid>[GEHT]\d+)/\(?(?P<delta1>[-+]?\d+)(,(?P<delta2>[-+]?\d+)\)?)?', 'neighbors', name="neighbors"),
-    url (r'^(?P<graceid>[GEHT]\d+)$', 'view', name="view2"),
-    url (r'^(?P<graceid>[GEHT]\d+)/perms/$', 'modify_permissions', name="modify_permissions"),
-    url (r'^(?P<graceid>[GEHT]\d+)/files/$', 'file_list', name="file_list"),
-    url (r'^(?P<graceid>[GEHT]\d+)/files/(?P<filename>.*)$', download, name="file"),
-    url (r'^(?P<graceid>[GEHT]\d+)/log/(?P<num>([\d]*|preview))$', 'logentry', name="logentry"),
-    url (r'^(?P<graceid>[GEHT]\d+)/embblog/(?P<num>([\d]*|preview))$', 'embblogentry', name="embblogentry"),
-    url (r'^(?P<graceid>[GEHT]\d+)/log/(?P<num>\d+)/tag/(?P<tagname>\w+)$', 'taglogentry', name="taglogentry"),
+    url (r'^view/(?P<graceid>[GEHMT]\d+)', 'view', name="view"),
+    url (r'^voevent/(?P<graceid>[GEHMT]\d+)', 'voevent', name="voevent"),
+#    url (r'^skyalert/(?P<graceid>[GEHMT]\d+)', 'skyalert', name="skyalert"),
+    url (r'^neighbors/(?P<graceid>[GEHMT]\d+)/\(?(?P<delta1>[-+]?\d+)(,(?P<delta2>[-+]?\d+)\)?)?', 'neighbors', name="neighbors"),
+    url (r'^(?P<graceid>[GEHMT]\d+)$', 'view', name="view2"),
+    url (r'^(?P<graceid>[GEHMT]\d+)/perms/$', 'modify_permissions', name="modify_permissions"),
+    url (r'^(?P<graceid>[GEHMT]\d+)/files/$', 'file_list', name="file_list"),
+    url (r'^(?P<graceid>[GEHMT]\d+)/files/(?P<filename>.*)$', download, name="file"),
+    url (r'^(?P<graceid>[GEHMT]\d+)/log/(?P<num>([\d]*|preview))$', 'logentry', name="logentry"),
+    url (r'^(?P<graceid>[GEHMT]\d+)/embblog/(?P<num>([\d]*|preview))$', 'embblogentry', name="embblogentry"),
+    url (r'^(?P<graceid>[GEHMT]\d+)/log/(?P<num>\d+)/tag/(?P<tagname>\w+)$', 'taglogentry', name="taglogentry"),
 
 # RDW Aug 2014
 #(r'^admin/', include(admin.site.urls)),
diff --git a/gracedb/urls_rest.py b/gracedb/urls_rest.py
index db2d38a5e1f70728974a5b2b683134a50b71bf74..65b32c934d5488b0bae997b005b9fb11e9236ef8 100644
--- a/gracedb/urls_rest.py
+++ b/gracedb/urls_rest.py
@@ -28,23 +28,23 @@ urlpatterns = patterns('gracedb.api',
     # events/[{graceid}[/{version}]]
     url (r'events/$',
         EventList.as_view(), name='event-list'),
-    url (r'events/voevent/(?P<graceid>[GEHT]\d+)$',
+    url (r'events/voevent/(?P<graceid>[GEHMT]\d+)$',
         EventVODetail.as_view(), name='event-vo-detail'),
-    url (r'events/(?P<graceid>[GEHT]\d+)$',
+    url (r'events/(?P<graceid>[GEHMT]\d+)$',
         EventDetail.as_view(), name='event-detail'),
 
     # Event Log Resources
     # events/{graceid}/logs/[{logid}]
-    url (r'events/(?P<graceid>[GEHT]\d+)/log/$',
+    url (r'events/(?P<graceid>[GEHMT]\d+)/log/$',
         EventLogList.as_view(), name='eventlog-list'),
-    url (r'events/(?P<graceid>[GEHT]\d+)/log/(?P<n>\d+)$',
+    url (r'events/(?P<graceid>[GEHMT]\d+)/log/(?P<n>\d+)$',
         EventLogDetail.as_view(), name='eventlog-detail'),
 
     # EMBB Event Log Resources
     # events/{graceid}/logs/[{logid}]
-    url (r'events/(?P<graceid>[GEHT]\d+)/embb/$',
+    url (r'events/(?P<graceid>[GEHMT]\d+)/embb/$',
         EMBBEventLogList.as_view(), name='embbeventlog-list'),
-    url (r'events/(?P<graceid>[GEHT]\d+)/embb/(?P<n>\d+)$',
+    url (r'events/(?P<graceid>[GEHMT]\d+)/embb/(?P<n>\d+)$',
         EMBBEventLogDetail.as_view(), name='embbeventlog-detail'),
 
     # Tag Resources
@@ -53,21 +53,21 @@ urlpatterns = patterns('gracedb.api',
     # XXX unclear what the tag detail resource should be.
     #url (r'^tag/(?P<tagname>\w+)$', 
     #    TagDetail.as_view(), name='tag-detail'),
-    url (r'events/(?P<graceid>[GEHT]\d+)/tag/$',
+    url (r'events/(?P<graceid>[GEHMT]\d+)/tag/$',
         EventTagList.as_view(), name='eventtag-list'),
-    url (r'events/(?P<graceid>[GEHT]\d+)/tag/(?P<tagname>\w+)$',
+    url (r'events/(?P<graceid>[GEHMT]\d+)/tag/(?P<tagname>\w+)$',
         EventTagDetail.as_view(), name='eventtag-detail'),
-    url (r'events/(?P<graceid>[GEHT]\d+)/log/(?P<n>\d+)/tag/$',
+    url (r'events/(?P<graceid>[GEHMT]\d+)/log/(?P<n>\d+)/tag/$',
         EventLogTagList.as_view(), name='eventlogtag-list'),
-    url (r'events/(?P<graceid>[GEHT]\d+)/log/(?P<n>\d+)/tag/(?P<tagname>\w+)$',
+    url (r'events/(?P<graceid>[GEHMT]\d+)/log/(?P<n>\d+)/tag/(?P<tagname>\w+)$',
         EventLogTagDetail.as_view(), name='eventlogtag-detail'),
 
     # Permission Resources
-    url (r'events/(?P<graceid>[GEHT]\d+)/perms/$',
+    url (r'events/(?P<graceid>[GEHMT]\d+)/perms/$',
         EventPermissionList.as_view(), name='eventpermission-list'),
-    url (r'events/(?P<graceid>[GEHT]\d+)/perms/(?P<group_name>.+)/$', 
+    url (r'events/(?P<graceid>[GEHMT]\d+)/perms/(?P<group_name>.+)/$', 
         GroupEventPermissionList.as_view(), name='groupeventpermission-list'),
-    url (r'events/(?P<graceid>[GEHT]\d+)/perms/(?P<group_name>.+)/(?P<perm_shortname>\w+)$', 
+    url (r'events/(?P<graceid>[GEHMT]\d+)/perms/(?P<group_name>.+)/(?P<perm_shortname>\w+)$', 
         GroupEventPermissionDetail.as_view(), name='groupeventpermission-detail'),
 
     # Event File Resources
diff --git a/gracedb/view_logic.py b/gracedb/view_logic.py
index f79efe9dcc4cf415eaea096acda73fd99c7eed0a..b7a0c3697711761ae03ed6156f1f0fb3c1dba20c 100644
--- a/gracedb/view_logic.py
+++ b/gracedb/view_logic.py
@@ -12,6 +12,7 @@ from translator import handle_uploaded_data
 
 from utils.vfile import VersionedFile
 from view_utils import _saveUploadedFile
+from view_utils import eventToDict, eventLogToDict
 from permission_utils import assign_default_event_perms
 
 from django.contrib.contenttypes.models import ContentType
@@ -28,6 +29,8 @@ import json
 import datetime
 
 def _createEventFromForm(request, form):
+    import logging
+    logger = logging.getLogger(__name__)
     saved = False
     warnings = []
     try:
@@ -100,11 +103,12 @@ def _createEventFromForm(request, form):
                 # XXX This reverse will give the web-interface URL, not the REST URL.
                 # This could be a problem if anybody ever tries to use it.
                 # NOTE: The clusterurl method should be considered deprecated.
+                logger.debug("Bout to issue the alert.")
                 issueAlert(event,
                            #os.path.join(event.clusterurl(), "private", f.name),
                            request.build_absolute_uri(reverse("file", args=[event.graceid(),f.name])),
-                           temp_data_loc,
-                           request.build_absolute_uri(reverse("view", args=[event.graceid()])))
+                           request.build_absolute_uri(reverse("view", args=[event.graceid()])),
+                           eventToDict(event, request=request))
             except Exception, e:
                 warnings += ["Problem issuing an alert (%s)" % e]
         except Exception, e:
@@ -187,7 +191,9 @@ def _createLog(request, graceid, comment, uploadedFile=None):
             description = "LOG: "
             if uploadedFile:
                 description = "UPLOAD: '%s' " % uploadedFile.name
-            issueAlertForUpdate(event, description+comment, doxmpp=True, filename=uploadedFile.name)
+            issueAlertForUpdate(event, description+comment, doxmpp=True, 
+                filename=uploadedFile.name,
+                serialized_object=eventLogToDict(logEntry, request=request))
         except Exception, e:
             rdict['error'] = "Failed to save log message: %s" % str(e) 
 
diff --git a/gracedb/view_utils.py b/gracedb/view_utils.py
index 1deb144ad7768d57dac42104fc0ec60563e20a35..be5ec7006aaf0ce7b710dede07ca723a7d50ec57 100644
--- a/gracedb/view_utils.py
+++ b/gracedb/view_utils.py
@@ -1,7 +1,9 @@
 
 from django.http import HttpResponse
-from django.core.urlresolvers import reverse
+from django.core.urlresolvers import reverse as django_reverse
+from django.utils import dateformat
 from django.utils.html import escape, urlize
+from django.utils.http import urlquote
 from django.utils.safestring import mark_safe
 
 from utils.vfile import VersionedFile
@@ -17,6 +19,278 @@ MAX_QUERY_RESULTS = 1000
 GRACEDB_DATA_DIR = settings.GRACEDB_DATA_DIR
 
 import json
+import pytz
+
+SERVER_TZ = pytz.timezone(settings.TIME_ZONE)
+def timeToUTC(dt):
+    if not dt.tzinfo:
+        dt = SERVER_TZ.localize(dt)
+    return dateformat.format(dt.astimezone(pytz.utc), settings.GRACE_DATETIME_FORMAT)
+
+#---------------------------------------------------------------------------------------
+#---------------------------------------------------------------------------------------
+# Modified reverse for REST API and serializers below
+#---------------------------------------------------------------------------------------
+#---------------------------------------------------------------------------------------
+
+from rest_framework.reverse import reverse as rest_framework_reverse
+from django.core.urlresolvers import resolve, get_script_prefix
+
+# Note about reverse() in this file -- there are THREE versions of it here.
+  #
+  # SOURCE                               LOCAL NAME
+  # django.core.urlresolvers.reverse ==> django_reverse
+  # rest_framework.reverse.reverse   ==> rest_framework_reverse
+  # reverse defined below            ==> reverse
+  #
+  # The Django reverse returns relative paths.
+  #
+  # The rest framework reverse is basically the same as the Django version
+  # but will return full paths if the request is passed in using the request kw arg.
+  #
+  # The reverse defined below is basically the rest framework reverse, but
+  # will attempt to deal with multiply-include()-ed url.py-type files with
+  # different namespaces.  (see the comments in the function)
+def reverse(name, *args, **kw):
+      """Find a URL.  Respect where that URL was defined in urls.py
+  
+      Allow for a set of URLs to have been include()-ed on multiple URL paths.
+  
+      eg  urlpatterns = (
+          (r'^api1/', include('someapp.urls', app_name="api", namespace="x509")),
+          (r'^api2/', include('someapp.urls', app_name="api", namespace="shib")),
+          ...)
+  
+      then reverse("api:root", request=self.request) will give the obviously
+      correct full URL for the URL named "root" in someapp/urls.py.  Django's
+      reverse will pick one URL path and use it no matter what path the
+      URL resolver flows through and it will do so whether you specify an app_name
+      or not.
+  
+      This function solves that issue.  app_name and namespace are required.
+      The request must be the value at kw['request']
+  
+      Assembled with hints from http://stackoverflow.com/a/13249060
+      """
+      # XXX rashly assuming app is "api:"  brutal.
+      if type(name) == str and not name.startswith("api:"):
+          name = "api:"+name
+  
+      # Idea is to put 'current_app' into the kw args of reverse
+      # where current_app is the namespace of the urlpattern we got here from.
+      # Given that, reverse will find the right patterns in your urlpatterns.
+      # I do know know why Django does not do this by default.
+  
+      # This probably only works if you give app_names which are the same
+      # and namespaces that are different.
+  
+      if 'request' in kw and 'current_app' not in kw:
+          request = kw['request']
+          # For some reason, resolve() does not seem to like the script_prefix.
+          # So, remove it.
+          prefix = get_script_prefix()
+          path = request.path.replace(prefix, '/')
+          current_app = resolve(path).namespace
+          kw['current_app'] = current_app
+  
+      return rest_framework_reverse(name, *args, **kw)
+
+
+#---------------------------------------------------------------------------------------
+#---------------------------------------------------------------------------------------
+# Custom serializers 
+#---------------------------------------------------------------------------------------
+#---------------------------------------------------------------------------------------
+
+def eventToDict(event, columns=None, request=None):
+    """Convert an Event to a dictionary."""
+    rv = {}
+    graceid = event.graceid()
+    try:
+      rv['submitter'] = event.submitter.username
+    except:
+      rv['submitter'] = 'Unknown'
+
+    rv['created'] = timeToUTC(event.created)
+    rv['group'] = event.group.name
+    rv['graceid'] = graceid
+    rv['pipeline'] = event.pipeline.name
+    if event.search:
+        rv['search'] = event.search.name
+    rv['gpstime'] = event.gpstime
+    rv['instruments'] = event.instruments
+    rv['nevents'] = event.nevents
+    rv['far'] = event.far
+    rv['likelihood'] = event.likelihood
+    rv['labels'] = dict([
+          (labelling.label.name,
+              reverse("labels",
+                  args=[graceid, labelling.label.name],
+                  request=request))
+          for labelling in event.labelling_set.all()])
+    # XXX Try to produce a dictionary of analysis specific attributes.  Duck typing.
+    rv['extra_attributes'] = {}
+    try:
+        # GrbEvent
+        rv['extra_attributes']['GRB'] = {
+              "ivorn" : event.ivorn,
+              "author_ivorn" : event.author_ivorn,
+              "author_shortname" : event.author_shortname,
+              "observatory_location_id" : event.observatory_location_id,
+              "coord_system" : event.coord_system,
+              "ra" : event.ra,
+              "dec" : event.dec,
+              "error_radius" : event.error_radius,
+              "how_description" : event.how_description,
+              "how_reference_url" : event.how_reference_url,
+              }
+    except:
+        pass
+    try:
+        # CoincInspiralEvent
+        rv['extra_attributes']['CoincInspiral'] = {
+              "ifos" : event.ifos,
+              "end_time" : event.end_time,
+              "end_time_ns" : event.end_time_ns,
+              "mass" : event.mass,
+              "mchirp" : event.mchirp,
+              "minimum_duration" : event.minimum_duration,
+              "snr" : event.snr,
+              "false_alarm_rate" : event.false_alarm_rate,
+              "combined_far" : event.combined_far,
+              }
+    except:
+        pass
+    try:
+        # MultiBurstEvent
+        rv['extra_attributes']['MultiBurst'] = {
+              "ifos" : event.ifos,
+              "start_time" : event.start_time,
+              "start_time_ns" : event.start_time_ns,
+              "duration" : event.duration,
+              "peak_time" : event.peak_time,
+              "peak_time_ns" : event.peak_time_ns,
+              "central_freq" : event.central_freq,
+              "bandwidth" : event.bandwidth,
+              "amplitude" : event.amplitude,
+              "snr" : event.snr,
+              "confidence" : event.confidence,
+              "false_alarm_rate" : event.false_alarm_rate,
+              "ligo_axis_ra" : event.ligo_axis_ra,
+              "ligo_axis_dec" : event.ligo_axis_dec,
+              "ligo_angle" : event.ligo_angle,
+              "ligo_angle_sig" : event.ligo_angle_sig,
+              }
+    except:
+        pass
+    rv['links'] = {
+          "neighbors" : reverse("neighbors", args=[graceid], request=request),
+          "log"   : reverse("eventlog-list", args=[graceid], request=request),
+          "embb"   : reverse("embbeventlog-list", args=[graceid], request=request),
+          "files" : reverse("files", args=[graceid], request=request),
+          "filemeta" : reverse("filemeta", args=[graceid], request=request),
+          "labels" : reverse("labels", args=[graceid], request=request),
+          "self"  : reverse("event-detail", args=[graceid], request=request),
+          "tags"  : reverse("eventtag-list", args=[graceid], request=request),
+          }
+    return rv
+
+def eventLogToDict(log, request=None):
+    uri = None
+    taglist_uri = None
+    file_uri = None
+    if request:
+        uri = reverse("eventlog-detail",
+                args=[log.event.graceid(), log.N],
+                request=request)
+        taglist_uri = reverse("eventlogtag-list",
+                args=[log.event.graceid(), log.N],
+                request=request)
+        if log.filename:
+            actual_filename = log.filename
+            if log.file_version:
+                actual_filename += ',%d' % log.file_version
+            filename = urlquote(actual_filename)
+            file_uri = reverse("files",
+                args=[log.event.graceid(), filename],
+                request=request)
+
+        # This is purely for convenience in working with the web interface.
+        tag_names = [tag.name for tag in log.tag_set.all() ];
+
+    issuer_info = {
+        "username": log.issuer.username,
+        "display_name": "%s %s" % (log.issuer.first_name, log.issuer.last_name),
+    }
+
+    return {
+                "N"            : log.N,
+                "comment"      : log.comment,
+                "created"      : log.created.isoformat(),
+                "issuer"       : issuer_info,
+                "filename"     : log.filename,
+                "file_version" : log.file_version,
+                "tag_names"    : tag_names,
+                "self"         : uri,
+                "tags"         : taglist_uri,
+                "file"         : file_uri,
+           }
+
+
+def labelToDict(label, request=None):
+    return { 
+            "name" : label.label.name,
+            "creator" : label.creator.username,
+            "created" : label.created.isoformat(),
+            "self" : reverse("labels",
+                args=[label.event.graceid(), label.label.name],
+                request=request),
+           }
+
+# EEL serializer.
+def embbEventLogToDict(eel, request=None):
+      uri = None
+      if request:
+          uri = reverse("embbeventlog-detail",
+                  args=[eel.event.graceid(), eel.N],
+                  request=request)
+      return {
+                  "N"       : eel.N,
+                  "self"    : uri,
+                  "created" : eel.created.isoformat(),
+                  "submitter"  : eel.submitter.username,
+                  "group" : eel.group.name,
+                  "instrument" : eel.instrument,
+                  "footprintID" : eel.footprintID,
+                  "waveband" : eel.waveband,
+  
+                  "ra"       : eel.ra,
+                  "dec"      : eel.dec,
+                  "raWidth"  : eel.raWidth,
+                  "decWidth" : eel.decWidth,
+                  "gpstime"  : eel.gpstime,
+                  "duration" : eel.duration,
+  
+                  "raList"       : json.loads('['+eel.raList+']'),
+                  "decList"      : json.loads('['+eel.decList+']'),
+                  "raWidthList"  : json.loads('['+eel.raWidthList+']'),
+                  "decWidthList" : json.loads('['+eel.decWidthList+']'),
+                  "gpstimeList"  : json.loads('['+eel.gpstimeList+']'),
+                  "durationList" : json.loads('['+eel.durationList+']'),
+  
+                  "eel_status" : eel.get_eel_status_display(),
+                  "obs_status" : eel.get_obs_status_display(),
+                  "comment" : eel.comment,
+                  "extra_info_dict" : eel.extra_info_dict,
+             }
+  
+
+
+#---------------------------------------------------------------------------------------
+#---------------------------------------------------------------------------------------
+# Miscellany
+#---------------------------------------------------------------------------------------
+#---------------------------------------------------------------------------------------
 
 def assembleLigoLw(objects):
     from glue.ligolw import ligolw
@@ -115,14 +389,14 @@ def flexigridResponse(request, objects):
         rows.append(
             { 'id' : object.id,
               'cell': [ '<a href="%s">%s</a>' %
-                            (reverse("view", args=[object.graceid()]), object.graceid()),
+                            (django_reverse("view", args=[object.graceid()]), object.graceid()),
                          #Labels
                         " ".join(["""<span onmouseover="tooltip.show(tooltiptext('%s', '%s', '%s'));" onmouseout="tooltip.hide();"  style="color: %s"> %s </span>""" % (label.label.name, label.creator.username, label.created, label.label.defaultColor, label.label.name)
                                 for label in object.labelling_set.all()]),
                         # Links to neighbors
                         ', '.join([
                             '<a href="%s">%s</a>' %
-                            (reverse("view", args=[n.graceid()]), n.graceid())
+                            (django_reverse("view", args=[n.graceid()]), n.graceid())
                             for n in object.neighbors()
                         ]),
                         object.group.name,
diff --git a/gracedb/views.py b/gracedb/views.py
index e27efad687c118d100a6c349a3a64de8e3b3cecb..4f50ec708b8f52dcfeabe6c459d0f0c6e8491707 100644
--- a/gracedb/views.py
+++ b/gracedb/views.py
@@ -284,6 +284,7 @@ def view(request, event):
     context['single_inspiral_events'] = list(event.singleinspiral_set.all())
     context['neighbor_delta'] = "[%+d,%+d]" % (-5,5)
     context['SKYMAP_VIEWER_SERVICE_URL'] = settings.SKYMAP_VIEWER_SERVICE_URL
+    context['BOWER_URL'] = settings.BOWER_URL
 
     # XXX This is something of a hack. In the future, we will want to show the
     # executive user a list of groups and a two column list of radio buttons, showing
@@ -761,14 +762,12 @@ def modify_permissions(request, event):
     # Finished. Redirect back to the event.
     return HttpResponseRedirect(reverse("view", args=[event.graceid()]))
 
-from hashlib import md5
-
 # A view to create embb log entries
 @event_and_auth_required
 def embblogentry(request, event, num=None):
     if request.method == "POST":
         try:
-            eel = create_eel(request.POST, event, request.user)
+            create_eel(request.POST, event, request.user)
         except ValueError, e:
             return HttpResponseBadRequest(str(e))
         except Exception, e:
diff --git a/settings/branson.py b/settings/branson.py
index 046d67d5aa5df4e980ece03ae8a66ae9cbd4fe19..6f0a22638aaf630e24398f865594d10f3eb84a8b 100644
--- a/settings/branson.py
+++ b/settings/branson.py
@@ -19,6 +19,9 @@ DATABASES = {
 STATIC_URL = "/branson-static/"
 STATIC_ROOT = "/home/branson/gracedbdev/static/"
 
+BOWER_URL = "/bower-static/"
+BOWER_ROOT = "/home/branson/bower_components/"
+
 GRACEDB_DATA_DIR = "/home/branson/fake_data"
 
 ALERT_EMAIL_FROM = "Dev Alert <root@moe.phys.uwm.edu>"
@@ -46,12 +49,14 @@ XMPP_ALERT_CHANNELS = [
                       ]
  
 # Latency histograms.  Where they go and max latency to bin.
-LATENCY_REPORT_DEST_DIR = "/home/branson/data/latency"
+LATENCY_REPORT_DEST_DIR = "/home/branson/fake_data/latency"
 LATENCY_REPORT_WEB_PAGE_FILE_PATH = LATENCY_REPORT_DEST_DIR + "/latency.inc"
 
 # Uptime reporting
-UPTIME_REPORT_DIR = "/homebransonbmoe/data/uptime"
+UPTIME_REPORT_DIR = "/home/branson/fake_data/uptime"
 
+# Rate file location
+RATE_INFO_FILE = "/home/branson/fake_data/rate_info.json"
 
 #SITE_ID = 1
 
diff --git a/settings/default.py b/settings/default.py
index 65c17f434b3dd9dc14cf6d6cf5b4cf046f289302..331fc974b5b7bd072cb60a50cd4c61e1cdd10378 100644
--- a/settings/default.py
+++ b/settings/default.py
@@ -105,6 +105,9 @@ LATENCY_REPORT_WEB_PAGE_FILE_PATH = LATENCY_REPORT_DEST_DIR + "/latency.inc"
 # Uptime reporting
 UPTIME_REPORT_DIR = "/home/gracedb/data/uptime"
 
+# Rate file location
+RATE_INFO_FILE = "/home/gracedb/data/rate_info.json"
+
 # URL prefix for serving report information (usually plots and tables)
 REPORT_INFO_URL_PREFIX = "/report_info/"
 
@@ -285,6 +288,9 @@ REST_FRAMEWORK = {
 STATIC_URL = "/gracedb-static/"
 STATIC_ROOT = "/home/gracedb/graceproj/static/"
 
+BOWER_URL = "/bower-static/"
+BOWER_ROOT = "/home/gracedb/bower_components/"
+
 STATICFILES_FINDERS = (
     'django.contrib.staticfiles.finders.FileSystemFinder',
     'django.contrib.staticfiles.finders.AppDirectoriesFinder',
@@ -294,10 +300,10 @@ STATICFILES_FINDERS = (
 STATICFILES_DIRS = ()
 
 # Added in order to perform data migrations on the auth app
-#SOUTH_MIGRATION_MODULES = {
-#    'auth' : 'migrations.auth',
-#    'guardian' : 'migrations.guardian',
-#}
+SOUTH_MIGRATION_MODULES = {
+    'auth' : 'migrations.auth',
+    'guardian' : 'migrations.guardian',
+}
 
 SOUTH_TESTS_MIGRATE = False
 
diff --git a/static/css/labeltips.css b/static/css/labeltips.css
index d20daba96e9ef694119b7e63e71bbef3342569af..0f798b71020adaa17e17cdb2d331526d3190e33c 100644
--- a/static/css/labeltips.css
+++ b/static/css/labeltips.css
@@ -1,13 +1,13 @@
 #tt {
  position:absolute;
  display:block;
- background:url(images/tt_left.gif) top left no-repeat;
+ /* background:url(images/tt_left.gif) top left no-repeat; */
  }
  #tttop {
  display:block;
  height:5px;
  margin-left:5px;
- background:url(images/tt_top.gif) top right no-repeat;
+ /* background:url(images/tt_top.gif) top right no-repeat; */
  overflow:hidden;
  }
  #ttcont {
@@ -21,6 +21,6 @@
 display:block;
 height:5px;
 margin-left:5px;
-background:url(images/tt_bottom.gif) top right no-repeat;
+/* background:url(images/tt_bottom.gif) top right no-repeat; */
 overflow:hidden;
 }
diff --git a/static/css/style.css b/static/css/style.css
index 5984822ad059b37dedf3cc372c28757fce48050a..c3994835bab3346defc09a90ae44374b46876ec9 100644
--- a/static/css/style.css
+++ b/static/css/style.css
@@ -30,29 +30,31 @@ table.gstlalcbc th {padding:3px;border:none;vertical-align:bottom;}
 table.figures tr.figrow  {text-align:center;} 
 table.figures {width:300px;height:270px;border:1px solid gray;}
 
+/*  This was trying to style the title pane buttons. Doesn't work anymore.
 .tundra.eventDetail .pmTitlePaneClass .dijitOpen .dijitArrowNode {
     background-repeat: no-repeat;
     height: 14px;
     width: 14px;
 }
 
-.tundra.eventDetail .pmTitlePaneClass .dijitClosed .dijitArrowNode {
+.dijitClosed .dijitArrowNode {
     background-repeat: no-repeat;
     height: 14px;
     width: 14px;
 }
 
-.tundra.eventDetail .pmTitlePaneClass .dijitClosed .dijitArrowNode {
+.dijitClosed .dijitArrowNode {
     background-image: url('../images/plusButton.gif');
     background-position: 0px 0px;
 }
 
-.tundra.eventDetail .pmTitlePaneClass .dijitOpen .dijitArrowNode {
+.dijitOpen .dijitArrowNode {
     background-image: url('../images/minusButton.gif');
     background-position: 0px 0px;
 }
+*/ 
 
-.tundra.eventDetail .modButtonClass .dijitButtonNode {
+.modButtonClass {
     border: none;
     border-bottom: none;
     background-image: none;
@@ -60,18 +62,21 @@ table.figures {width:300px;height:270px;border:1px solid gray;}
     background-color: rgb(200, 200, 200);
     cursor: pointer;
     min-width: 20px;
+    /* min-height: 20px; */
+    height: 20px;
 }
 
-.tundra.eventDetail .modButtonClass.left.dijitButton {
-    padding: 0px 0px 0px 0px;
+.modButtonClass.left {   
+    padding: 2px 0px 2px 0px;
     margin: 2px 0px 2px 2px;
 }
-.tundra.eventDetail .modButtonClass.right.dijitButton {
-    padding: 2px 0px 2px 0px;
+
+.modButtonClass.right {
+    padding: 2px 2px 2px 0px;
     margin: 2px 2px 2px 0px;
 }
 
-.tundra.eventDetail .dijitDisabled .dijitButtonText {
+.dijitDisabled .dijitButtonText {
     color: #000000;
 }
 
@@ -85,7 +90,7 @@ table.figures {width:300px;height:270px;border:1px solid gray;}
     float: right;
 }
 
-.tundra.eventDetail .permButtonClass {
+.permButtonClass {
     font: x-small "Lucida Grande", "Lucida Sans Unicode", geneva, verdana, sans-serif;
     font-size: 150%;
     background-color : #ff6666;
@@ -370,3 +375,79 @@ table thead th.sorted a { padding-right:13px; }
 table thead th.ascending a { background:url('../images/arrow-down.gif') right .4em no-repeat; }
 table thead th.descending a { background:url('../images/arrow-up.gif') right .4em no-repeat; }
 
+
+/* Stuff added for dgrid */
+/* XXX FIXME. Note how this assumes the bower stuff will be in your home directory. Not cool. */
+@import "~/bower_components/dgrid/css/dgrid.css";
+
+.collapsed .expando {
+    display: none;
+}
+
+div.dgrid-row.collapsed:hover {
+    /* background-color: rgb(240,248,255); */
+    /* background-color: #ff6666; */
+    background-color: #d8bfd8;
+    cursor: pointer;
+}
+
+.supergrid-row.dgrid-row-odd {background-color:#edf3fe;}
+.supergrid-row.dgrid-row-even {background-color:#fff;}
+
+.dgrid.dgrid-grid.ui-widget.dgird-subgrid { 
+    height: auto;
+    border: none;
+}
+
+.tundra.eventDetail .dgrid-cell {
+    border: none;
+}
+
+.dgrid-cell.supergrid-cell {
+    border-top-style: solid;
+}
+
+.dgrid-cell.subgrid-cell {
+    border: none;
+}
+
+.dgrid-cell.field-N {
+    width: 5%;
+}
+
+.dgrid-cell.field-comment { 
+    width: 50%;
+}
+
+.dgrid-cell.field-image {
+    width: 10%;
+}
+
+th.dgrid-cell {
+    vertical-align: bottom;
+}
+
+/* Stuff added for new event detail */
+
+td.title {
+    cursor: pointer;
+}
+
+div.expandGlyph {
+    background-image: url('/bower-static/dijit/themes/tundra/images/spriteArrows.png');
+    background-repeat: no-repeat;
+    background-position: 0px 0px; 
+    vertical-align: middle;
+    height: 7px;
+    width: 7px;
+    padding: 0 0 0 0;
+}
+
+div.expandGlyph.closed {
+    background-position: -14px 0px;
+}
+
+.expandFormButton {
+    color: blue;
+    text-decoration: underline;
+}
diff --git a/templates/base.html b/templates/base.html
index 8b6a188fe5b8ccbc53b8cf5983378a88515c63fb..5d918ff4c2d6558670e0e536f4a987e49fc25b10 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -2,12 +2,13 @@
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
+{% block headcontents %}
     <link rel="stylesheet" href="{{STATIC_URL}}css/style.css" />
     <title>GraceDb | {% block title %}{% endblock %}</title>
 <!-- START TESTING -->
 <script type="text/javascript">
 function changeTime(obj, label) {
-    var timetype= obj[obj.selectedIndex].value;
+    var timetype = obj.get("value");
     if (timetype=="") { return; }
     var times = document.getElementsByName("time-"+label);
     for (i=0; i<times.length; i++) {
@@ -16,6 +17,7 @@ function changeTime(obj, label) {
     }
 }
 </script>
+{% endblock %}
 <!-- END TESTING -->
 {% block jscript %}{% endblock %}
 </head>
diff --git a/templates/gracedb/eel_form_frag.html b/templates/gracedb/eel_form_frag.html
new file mode 100644
index 0000000000000000000000000000000000000000..ed32a853509c77e03b096c4d4944fad411546b9e
--- /dev/null
+++ b/templates/gracedb/eel_form_frag.html
@@ -0,0 +1,180 @@
+<div data-dojo-type="dijit/form/Form" id="eelFormContainer"
+data-dojo-id="eelFormContainer" encType="multipart/form-data" action=""
+method="">
+<script>
+ require(["dojo/parser", "dijit/form/Form", "dijit/form/Button", "dijit/form/ValidationTextBox", "dijit/form/DateTextBox"]);
+ </script>
+		 
+<script type="dojo/on" data-dojo-event="reset">
+return confirm('Press OK to reset widget values');
+</script>
+<script type="dojo/on" data-dojo-event="submit">
+if(this.validate()){
+return confirm('Form is valid, press OK to submit');
+}else{
+alert('Form contains invalid data.  Please correct first');
+return false;
+}
+return true;
+</script>
+
+<form method="POST" action="{% url "embblogentry" object.graceid "" %}">
+<table>
+
+<tr><td><a href=# onclick="alert('Define here what subclass of report this is:\n FOOTPRINT: There is or could be image data taken of the sky, with a specific instrument, at a specific time, in a specific waveband, as followup of a specific LVC alert.\n SOURCE: There is a candidate source at the given location, that could be associated with the given LVC alert.\n COMMENT: The primary purpose of this report is a human-written comment concerning the given LVC alert.'); return false;">
+What type of report is this?</a></td>       <td><select name="eel_status">
+<option value="FO">FOOTPRINT</option>
+<option value="SO">SOURCE</option>
+<option value="CO">COMMENT</option>
+</select></td></tr>
+
+<tr><td><a href=# onclick="alert('There is also Observation Status which is:\n OBSERVATION: has been done.\n PREDICTION: this report represents intent or future observation.\n TEST: This EEL is part of a test and has no astrophysical significance.\n NOT APPLICABLE: It is neither observation nor prediction.'); return false;">
+Observation Status</a></td>       <td><select name="obs_status">
+<option value="OB">OBSERVATION</option>
+<option value="PR">PREDICTION</option>
+<option value="TE">TEST</option>
+<option value="NA">NOT APPLICABLE</option>
+</select></td></tr>
+
+<tr><td><a href=# onclick="alert('Group with which the LSC has signed a trust agreement, hereby providing data 
+under its trust (required).'); return false;">
+Which MOU Group provides this report?</a></td>       <td><select name="group">
+{% for g in groups %}
+<option value="{{ g }}">{{ g }}</option>
+{% endfor %} </select> </td> </tr>
+
+<tr><td><a href=# onclick="alert('An ID from the data owner to identify this footprint (optional).');return false;">
+Your reference</a></td>   <td><input type="text" name="footprintID"/></td></tr>
+
+<tr><td><a href=# onclick="alert('A natural language report.');return false;">
+Report as text</a></td>         <td colspan=2><textarea name="comment" rows="8" cols="50"></textarea></td></tr>
+
+<tr><td><a href=# onclick="alert('The name of the photon detector whose observational metadata is being recorded here (optional).');return false;">
+Instrument</a></td>       <td><input type="text" name="instrument"> </td> </tr>
+
+<tr><td><a href=# onclick="alert('Specify waveband of the observation. Vocabulary is taken from the UCD vocabulary, a Virtual Observatory standard. Waveband can be either wide (eg Radio) or narrow (eg Radio 200-400 MHz).');return false;">
+Waveband</a></td>       <td colspan=2><select name="waveband">
+<option value="em.gamma">Gamma rays part of the spectrum</option>
+<option value="em.gamma.soft">Soft gamma ray (120 - 500 keV)</option>
+<option value="em.gamma.hard">Hard gamma ray (&gt;500 keV)</option>
+<option value="em.X-ray">X-ray part of the spectrum</option>
+<option value="em.X-ray.soft">Soft X-ray (0.12 - 2 keV)</option>
+<option value="em.X-ray.medium">Medium X-ray (2 - 12 keV)</option>
+<option value="em.X-ray.hard">Hard X-ray (12 - 120 keV)</option>
+<option value="em.UV">Ultraviolet part of the spectrum</option>
+<option value="em.UV.10-50nm">Ultraviolet between 10 and 50 nm</option>
+<option value="em.UV.50-100nm">Ultraviolet between 50 and 100 nm</option>
+<option value="em.UV.100-200nm">Ultraviolet between 100 and 200 nm</option>
+<option value="em.UV.200-300nm">Ultraviolet between 200 and 300 nm</option>
+<option value="em.UV.FUV">Far-Infrared, 30-100 microns</option>
+<option value="em.opt">Optical part of the spectrum</option>
+<option value="em.opt.U">Optical band between 300 and 400 nm</option>
+<option value="em.opt.B">Optical band between 400 and 500 nm</option>
+<option value="em.opt.V">Optical band between 500 and 600 nm</option>
+<option value="em.opt.R">Optical band between 600 and 750 nm</option>
+<option value="em.opt.I">Optical band between 750 and 1000 nm</option>
+<option value="em.IR">Infrared part of the spectrum</option>
+<option value="em.IR.NIR">Near-Infrared, 1-5 microns</option>
+<option value="em.IR.J">Infrared between 1.0 and 1.5 micron</option>
+<option value="em.IR.H">Infrared between 1.5 and 2 micron</option>
+<option value="em.IR.K">Infrared between 2 and 3 micron</option>
+<option value="em.IR.MIR">Medium-Infrared, 5-30 microns</option>
+<option value="em.IR.3-4um">Infrared between 3 and 4 micron</option>
+<option value="em.IR.4-8um">Infrared between 4 and 8 micron</option>
+<option value="em.IR.8-15um">Infrared between 8 and 15 micron</option>
+<option value="em.IR.15-30um">Infrared between 15 and 30 micron</option>
+<option value="em.IR.30-60um">Infrared between 30 and 60 micron</option>
+<option value="em.IR.60-100um">Infrared between 60 and 100 micron</option>
+<option value="em.IR.FIR">Far-Infrared, 30-100 microns</option>
+<option value="em.mm">Millimetric part of the spectrum</option>
+<option value="em.mm.1500-3000GHz">Millimetric between 1500 and 3000 GHz</option>
+<option value="em.mm.750-1500GHz">Millimetric between 750 and 1500 GHz</option>
+<option value="em.mm.400-750GHz">Millimetric between 400 and 750 GHz</option>
+<option value="em.mm.200-400GHz">Millimetric between 200 and 400 GHz</option>
+<option value="em.mm.100-200GHz">Millimetric between 100 and 200 GHz</option>
+<option value="em.mm.50-100GHz">Millimetric between 50 and 100 GHz</option>
+<option value="em.mm.30-50GHz">Millimetric between 30 and 50 GHz</option>
+<option value="em.radio">Radio part of the spectrum</option>
+<option value="em.radio.12-30GHz">Radio between 12 and 30 GHz</option>
+<option value="em.radio.6-12GHz">Radio between 6 and 12 GHz</option>
+<option value="em.radio.3-6GHz">Radio between 3 and 6 GHz</option>
+<option value="em.radio.1500-3000MHz">Radio between 1500 and 3000 MHz</option>
+<option value="em.radio.750-1500MHz">Radio between 750 and 1500 MHz</option>
+<option value="em.radio.400-750MHz">Radio between 400 and 750 MHz</option>
+<option value="em.radio.200-400MHz">Radio between 200 and 400 MHz</option>
+<option value="em.radio.100-200MHz">Radio between 100 and 200 MHz</option>
+<option value="em.radio.20-100MHz">Radio between 20 and 100 MHz</option>
+                                </select></td></tr>
+</table>
+<hr/>
+<script>
+function showRectanglesCheckbox(){
+    var s = document.getElementById('showRectangles');
+    showRectangles = s.checked;
+    if(showRectangles){ document.getElementById('rectanglesForm').style.display = "block"
+    } else {            document.getElementById('rectanglesForm').style.display = "none"
+    }
+    redrawAll();
+    return false;
+}
+</script>
+<input id="showRectangles" type="checkbox" onclick="showRectanglesCheckbox()" />add Sky Footprints<br/>
+<div id=rectanglesForm style="display: none;">
+<table>
+<tr><td><a href=# onclick="alert('RA and Dec specify a center point of a rectangle that is aligned equatorially. Or list of centers. They must be in decimal degrees 0<=RA<=360 -90<=Dec<=90, in the J2000 frame.');return false;">
+RA (decimal degrees)</a></td>             <td><input type="text" name="raList" value="" size=80/></td></tr>
+
+<tr><td><a href=# onclick="alert('RA and Dec specify a center point of a rectangle that is aligned equatorially. Or list of centers. They must be in decimal degrees 0<=RA<=360 -90<=Dec<=90, in the J2000 frame.');return false;">
+Dec (decimal degrees)</a></td>            <td><input type="text" name="decList" value="" size=80/></td></tr>
+
+<!--
+<script language="javascript" type="text/javascript" src="https://losc.ligo.org/s/js/gpstimeutil.js"></script>
+<script language="javascript" type="text/javascript" src="https://losc.ligo.org/s/js/sexg.js"></script>
+-->
+
+<tr><td><a href=# onclick="alert('The time at the center of a time interval during which the observation was taken. Or list of times.');return false;">
+GPStime</a></td>
+<td><input type="text" name="gpstimeList" value="" size=80/></td>
+<!--
+<td><input onKeyUp="return TIMEcopy(2,1);" id="TIMEgps1" name="gpstimeList" maxlength="12" size="20" value="1000000000"/></td>
+<td><input onKeyUp="return TIMEcopy(1,1);" id="TIMEiso1" name="TIMEiso1" maxlength="25" size="25" value="2011-09-14T01:46:25"/></td>
+<td><span id="TIMEerr1" STYLE="font: 12px Arial; color:red">OK</span><br/></td>
+-->
+</tr>
+
+<tr><td><a href=# onclick="alert('RAWidth and DecWidth specify the size of a a rectangle that is aligned equatorially. Thus the edge of the box is distant from the center by half of the width.');return false;">
+RAwidth (decimal degrees)</a></td>        <td><input type="text" name="raWidthList" value=""/></td></tr>
+
+<tr><td><a href=# onclick="alert('RAWidth and DecWidth specify the size of a a rectangle that is aligned equatorially. Thus the edge of the box is distant from the center by half of the width.');return false;">
+Decwidth (decimal degrees)</a></td>       <td><input type="text" name="decWidthList" value=""/></td></tr>
+
+<tr><td><a href=# onclick="alert('Duration is the number of seconds in the time interval during which the observation was taken.');return false;">
+Duration (seconds)</a></td>       <td><input type="text" name="durationList" value=""/></td></tr>
+
+</table>
+</div>
+<hr/>
+<script>
+function showJsonCheckbox(){
+    var s = document.getElementById('showJson');
+    showJson = s.checked;
+    if(showJson){ document.getElementById('jsonForm').style.display = "block"
+    } else {      document.getElementById('jsonForm').style.display = "none"
+    }
+    redrawAll();
+    return false;
+}
+</script>
+<input id="showJson" type="checkbox" onclick="showJsonCheckbox()" />add JSON data<br/>
+<div id=jsonForm style="display: none;">
+<table>
+<tr><td><a href=# onclick="alert('This section allows for machine-readable data to be included in a flexible way. any key can be any value in a JSON dictionary. There is a useful validator at http://jsonlint.com.');return false;">
+JSON data</a></td>       <td colspan=2><textarea name="extra_info_dict" rows="20" cols="50"></textarea></td></tr>
+</table>
+</div>
+<hr/>
+<input type="submit" value="Submit EMBB Report"/>
+</form>
+
+</div>
+
diff --git a/templates/gracedb/event_detail.html b/templates/gracedb/event_detail.html
index 8881fb24f8d5209db62ee689c158acd0eb337fa7..a1d45cfc72b458b83c8580a1a71d8889e69d4ff7 100644
--- a/templates/gracedb/event_detail.html
+++ b/templates/gracedb/event_detail.html
@@ -3,578 +3,44 @@
 {% load scientific %}
 {% load sanitize_html %}
 {% load logtags %}
-{% block title %}View {{ object.graceid }}{% endblock %}
 {% block heading %}{% endblock %}
 {% block bodyattrs %}class="tundra eventDetail"{% endblock %}
 
 {% block jscript %}
-    {# XXX http/https depending on this pages' protocol #}
-    <script type="text/javascript"
-      src="https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
-    </script>
-    <script src="http{% if request.is_secure %}s{% endif %}://ajax.googleapis.com/ajax/libs/dojo/1.8.1/dojo/dojo.js" type="text/javascript"></script>
-    <script src="{{STATIC_URL}}js/labeltips.js" type="text/javascript"></script>
-    <link rel="stylesheet" href="{{STATIC_URL}}css/labeltips.css">
-    <style>
-        .emptyIcon{
-            background-image: none;
-            background-position: center center;
-            background-repeat: no-repeat;
-            height: 10px;
-            width: 10px;
-        }
-    </style>
-    <script type="text/javascript">
-        //------------------------------------------------------------------------------------------------------------------------
-        //------------------------------------------------------------------------------------------------------------------------
-        // Generate an array, the elements of which contain the inner html for each thematic digest
-        //------------------------------------------------------------------------------------------------------------------------
-        //------------------------------------------------------------------------------------------------------------------------
-  
-        function divFunction() {
-        }
-
-        function getDigests() {
-            var digests = new Array();
-{% for tag in object.getAvailableTags %}
-    {% if tag.name in blessed_tags %}
-                digest = new Object();
-                digest.title = "{{tag|tagUnicode}}";
-                digest.contents = "";
-                digest.hasfigs = false;
-                digest.figure_container_id = "";
-
-                // A section for the images 
-                var dc = "";
-        {% if object|logsForTagHaveImage:tag.name %}        
-                    digest.hasfigs = true;
-                    digest.figure_container_id = "{{tag.name}}_figure_container";
-                    dc += ' <div id="{{tag.name}}_figure_container"> \n';
-                    dc += '     <table class="figure_container"> \n';
-                    dc += '         <tr> \n';
-            {% for log in object|getLogsForTag:tag.name %} 
-                {% if log.hasImage %}
-                    dc += '         <td> \n';
-                    dc += '             <table class="figures"> \n';
-                    dc += '                 <tr class="figrow"> \n';
-                    dc += '                     <td>  <a href="{{ log.fileurl }}" dojoType="dojox.image.LightboxNano"><img height="180" src="{{ log.fileurl }}"></a> \n';
-                    dc += '                     </td> \n';
-                    dc += '                 </tr> \n';
-                    dc += '                 <tr> \n';
-                    dc += '                     <td> {{log.comment|sanitize|escapejs}} \n';
-                    {% if log.fileurl %} 
-                    dc += '                         <a href="{{log.fileurl}}">{{log.filename}}.</a> \n';
-                    {% endif %} 
-                    dc += '                         Submitted by {{log.issuer}} on {{log.created}} \n';
-                    dc += '                     </td> \n';
-                    dc += '                 </tr> \n';
-                    dc += '             </table> \n';
-                    dc += '         </td> \n';
-                {% endif %}
-            {% endfor %}
-                    dc += '         </tr> \n';
-                    dc += '     </table> \n';
-                    dc += ' </div> \n';
-                    digest.contents += dc;
-        {% endif %}
-          
-            // A section for the text-only captions 
-        {% if object|logsForTagHaveText:tag.name %}
-                    var dc = '';
-                    dc += ' <table class="event"> \n';
-                    dc += '     <tr> \n';
-                    dc += '         <th>No.</th> \n';
-                    dc += '         <th>{{ "logtime"|timeselect:"utc"|escapejs }} Log Entry Created</th> \n';
-                    dc += '         <th>Submitter</th> \n';
-                    dc += '         <th>Comment</th> \n';
-                    dc += '     </tr> \n';
-            {% for log in object|getLogsForTag:tag.name %} 
-                {% if not log.hasImage %}
-                    dc += '     <tr class="{% cycle 'odd' 'even'%}"> \n';
-                    dc += '         <td>{{log.N}}</td> \n';
-                    dc += '         <td>{{log.created|multiTime:"logtime"|escapejs}}</td> \n';
-                    dc += '         <td>{{log.issuer.first_name}} {{log.issuer.last_name}}</td> \n';
-                    dc += '         <td>{{log.comment|sanitize|escapejs}} \n';
-                               {% if log.fileurl %}
-                    dc += '             <a href="{{log.fileurl}}">{{log.filename}}</a> \n';
-                                    // If this is a skymap.json file, we want a button.
-                                    {% if log.filename == "skymap.json" %}
-                    dc += '             <button type="button" data-dojo-type="dijit/form/Button" id="sV_button" class="modButtonClass">View in skymapViewer!</button> \n';                                   
-                                    {% endif %}
-                               {% endif %}
-                    dc += '         </td> \n';
-                    dc += '    </tr> \n';
-                {% endif %}
-            {% endfor %}
-                    dc += '</table>';
-                    digest.contents += dc;
-        {% endif %}
-                digests.push(digest);
-    {% endif %} 
-{% endfor %}
-            return digests;
-        }
-
-        //------------------------------------------------------------------------------------------------------------------------
-        //------------------------------------------------------------------------------------------------------------------------
-        // Generate the html table for the full audit log
-        //------------------------------------------------------------------------------------------------------------------------
-        //------------------------------------------------------------------------------------------------------------------------
-        function getAuditLogContents() {
-            logs = new Array();
-            tags = new Array();
-            var ret = "";
-            ret += '    <table class="event"> \n';
-            ret += '    <tr> \n';
-            ret += '        <th>No.</th> \n';
-            ret += '        <th>{{ "logtime"|timeselect:"utc"|escapejs }} Log Entry Created</th> \n';
-            ret += '        <th>Submitter</th> \n';
-            ret += '        <th>Comment</th> \n';
-            ret += '        <th>&nbsp;</th> \n';
-            ret += '    </tr>\n';
-{% for log in object.eventlog_set.iterator %}
-            log = new Object();
-            log.n = {{log.N}};
-            log.button_id = "addtag_{{log.N}}";
-            logs.push(log);
-            ret += '    <tr class="{% cycle 'odd' 'even'%}"> \n';
-            ret += '        <td>{{log.N}} \n';
-            ret += '        <td>{{log.created|multiTime:"logtime"}}</td> \n';
-            ret += '        <td>{{log.issuer.first_name}} {{ log.issuer.last_name}}</td> \n';
-            ret += '        <td> \n';
-            ret += '        <div class="tagButtonContainerClass"> \n'
-    {% if object.getAvailableTags %}
-        {%for tag in log.tag_set.all %} 
-            tag = new Object();
-            tag.name = "{{tag.name}}";
-            tag.button_id = "del_button_{{log.N}}_{{tag.name}}";
-            tag.n = "{{log.N}}";
-            tags.push(tag);
-            ret += '            <div class="tagDelButtonDivClass"> \n';
-            ret += '            <button type="button" data-dojo-type="dijit/form/Button" id="' + tag.button_id + '" class="modButtonClass left"> \n';
-            ret += '                &times; \n';
-            ret += '            </button><button type="button" data-dojo-type="dijit/form/Button" class="modButtonClass right" disabled> \n';
-            ret += '                ' + tag.name + ' \n';
-            ret += '            </button> \n';
-            ret += '            </div> \n';
-        {% endfor %} 
-    {% endif %}
-            ret += '        <button type="button" data-dojo-type="dijit/form/Button" id="addtag_{{log.N}}" class="modButtonClass">&#43;</button> \n';
-            ret += '        </div> \n';
-
-            ret += '        {{log.comment|sanitize|escapejs}} \n';
-    {% if log.fileurl %}
-            ret += '            <a href="{{log.fileurl}}">{{log.filename}}</a> \n';
-    {% endif %}
-            ret += '        </td> \n';
-            ret += '        <td> \n';
-    {% if log.hasImage %}
-            ret += '            <a href="{{ log.fileurl }}" dojoType="dojox.image.LightboxNano"><img height="60" src="{{ log.fileurl }}"></a> \n';
-    {% endif %}
-            ret += '        </td> \n';
-            ret += '    </tr> \n';
-{% endfor %}
-            ret += '    </table>';
-            return {'logContents':ret, 'logs':logs, 'tags':tags};
-        }
-
-        //------------------------------------------------------------------------------------------------------------------------
-        //------------------------------------------------------------------------------------------------------------------------
-        // The main Dojo action happens here.
-        //------------------------------------------------------------------------------------------------------------------------
-        //------------------------------------------------------------------------------------------------------------------------
-        require(["dojo/dom",
-                 "dojo/dom-style",
-                 "dojo/parser",
-                 "dojo/on",
-                 "dojo/mouse",
-                 "dojo/request",
-                 "dojo/dom-form",
-                 "dojo/dom-construct",
-                 "dijit/Editor",
-                 "dojox/editor/plugins/Save",
-                 "dojox/editor/plugins/Preview",
-                 "dijit/form/Button",
-                 "dijit/form/TextBox",
-                 "dijit/form/Form",
-                 "dijit/TitlePane",
-                 "dijit/Tooltip",
-                 "dojox/layout/ScrollPane",
-                 "dojo/store/Memory",
-                 "dijit/form/ComboBox",
-                 "dijit/Dialog",
-                 "dojox/image/LightboxNano",
-                 "dijit/_editor/plugins/TextColor",
-                 "dijit/_editor/plugins/LinkDialog",
-                 "dijit/_editor/plugins/ViewSource",
-                 "dijit/_editor/plugins/NewPage",
-                 "dijit/_editor/plugins/FullScreen",
-                 "dojo/domReady!"], function (dom, domStyle, parser, on, mouse, request, domForm, domConstruct, Editor, Save, Preview, 
-                                              Button, TextBox, Form, TitlePane, Tooltip, ScrollPane, Memory, ComboBox, Dialog) {
-
-            parser.parse();
-
-            //--------------------------------------------------------------------------------------------------------------------
-            // Remember the blessed tags, if we have them.
-            //--------------------------------------------------------------------------------------------------------------------
-{% if blessed_tags %}
-            var blessedTagStore = new Memory({
-                data: [
-    {% for bt in blessed_tags %}
-                        {name:"{{bt}}"},
-    {% endfor %}
-                ]
-            });
-{% endif %}
-
-            //--------------------------------------------------------------------------------------------------------------------
-            // a utility function to get the callbacks for when the tag delete button is clicked.
-            //--------------------------------------------------------------------------------------------------------------------
-            function getTagDelCallback(tag) {
-                return function() {
-                    var tagUrl = "{% url "taglogentry" object.graceid "000" "temp" %}" 
-                    tagUrl = tagUrl.replace("000",tag.n); 
-                    tagUrl = tagUrl.replace("temp",tag.name); 
-                    var tagResultDialog = new Dialog({ style: "width: 300px" }); 
-                    var actionBar = domConstruct.create("div", { "class": "dijitDialogPaneActionBar" }); 
-                    var tbnode = domConstruct.create("div", { 
-                            style: "margin: 0px auto 0px auto; text-align: center;" 
-                    }, actionBar); 
-                    var tagButton = new Button({ 
-                        label: "Ok", 
-                        onClick: function(){ 
-                        tagResultDialog.hide(); 
-                    }}).placeAt(tbnode); 
-                    request.del(tagUrl).then( 
-                        function(text){ 
-                            tagResultDialog.set("content", text); 
-                            domConstruct.place(actionBar, tagResultDialog.containerNode); 
-                            tagResultDialog.show(); 
-                            location.reload(true); 
-                        }, 
-                        function(error){ 
-                            tagResultDialog.set("content", "Error: " + error); 
-                            domConstruct.place(actionBar, tagResultDialog.containerNode); 
-                            tagResultDialog.show();  
-                        });
-                    } 
-                }
-
-            //--------------------------------------------------------------------------------------------------------------------
-            // a utility function to get the callbacks for when the tag add button is clicked.
-            //--------------------------------------------------------------------------------------------------------------------
-            function getTagAddCallback(log) {
-                return function() {
-                    // Create the tag result dialog.
-                    var tagResultDialog = new Dialog({ style: "width: 300px" }); 
-                    var actionBar = domConstruct.create("div", { "class": "dijitDialogPaneActionBar" }); 
-                    var tbnode = domConstruct.create("div", { 
-                            style: "margin: 0px auto 0px auto; text-align: center;" 
-                    }, actionBar); 
-                    var tagButton = new Button({ 
-                        label: "Ok", 
-                        onClick: function(){ 
-                        tagResultDialog.hide();
-                        }
-                    }).placeAt(tbnode); 
-
-                    // Create the form
-                    addTagForm = new Form();
-                    var msg = "<p> Choose a tag \
-                        name from the dropdown menu or enter a new one.  If you are \
-                        creating a new tag, please also provide a display name. </p>";
-                    domConstruct.create("div", {innerHTML: msg} , addTagForm.containerNode);
-
-                    // Form for tagging existing log messages.
-                    new ComboBox({
-                        name: "existingTagSelect",
-                        value: "",
-    {% if blessed_tags %}                
-                        store: blessedTagStore,
-                        searchAttr: "name"
-    {% endif %}
-                    }).placeAt(addTagForm.containerNode);
-
-                    new TextBox({
-                        name: "tagDispName",
-                    }).placeAt(addTagForm.containerNode);
-
-                    new Button({
-                        type: "submit",
-                        label: "OK",
-                    }).placeAt(addTagForm.containerNode);
-
-                    // Create the dialoge
-                    addTagDialog = new Dialog({
-                        title: "Add Tag",
-                        content: addTagForm,
-                        style: "width: 300px"
-                        });
-
-                    // Define the form on submit handler
-                    on(addTagForm, "submit", function(evt) {
-                        evt.stopPropagation();
-                        evt.preventDefault();
-                        formData = addTagForm.getValues();
-                        var tagName = formData.existingTagSelect;
-                        var tagDispName = formData.tagDispName;
-                        var tagUrl = "{% url "taglogentry" object.graceid "000" "temp" %}"
-                        tagUrl = tagUrl.replace("000",log.n);
-                        tagUrl = tagUrl.replace("temp",tagName);
-
-                        request.post(tagUrl, {
-                            data: {displayName: tagDispName}
-                        }).then(
-                            function(text){
-                                tagResultDialog.set("content", text);
-                                domConstruct.place(actionBar, tagResultDialog.containerNode);
-                                tagResultDialog.show();
-                                location.reload(true);
-                            },
-                            function(error){
-                                tagResultDialog.set("content", "Error: " + error);
-                                domConstruct.place(actionBar, tagResultDialog.containerNode);
-                                tagResultDialog.show(); 
-                            }
-                       );
-                       addTagDialog.hide();
-                    });
-
-                    // show the dialog
-                    addTagDialog.show();
-                }
-            }
-
-            //--------------------------------------------------------------------------------------------------------------------
-            // Main processing begins here
-            //--------------------------------------------------------------------------------------------------------------------
-           
-            // If we have blessed tags *and* some log messages have been tagged,
-            // we will want some TitlePanes.
-{% if blessed_tags and object.getAvailableTags %}
-            var doingPanes = true;
-{% else %}
-            var doingPanes = false;
-{% endif %}
-            
-            var ret = getAuditLogContents();
-            var auditLogContents = ret.logContents;
-            var tags = ret.tags;
-
-            annotationsDiv = dom.byId("annotations");
-
-            //-------------------------------------------------------------------
-            // Set up the annotations section, depending on whether we're doing 
-            // title panes with annotation digests.
-            //-------------------------------------------------------------------
-            if (doingPanes) {
-                // Go and get me an array of objects.  
-                var digests = getDigests();
-                for (var i = 0; i<digests.length; i++) {
-                    tp = new dijit.TitlePane({title:digests[i].title,
-                                             content:digests[i].contents,
-                                             open:true});
-                    annotationsDiv.appendChild(tp.domNode);
-                };
-
-
-                // Handle event log seperately.  It will be closed by default.
-                tp = new dijit.TitlePane({title:"Full Event Log",
-                                         content:auditLogContents,
-                                         open:false});
-                annotationsDiv.appendChild(tp.domNode);
-
-
-                // Deal with the figure containers.
-                var figure_scrollpanes = new Array();
-                for (var i = 0; i<digests.length; i++) {
-                    if (digests[i].hasfigs) {
-                        figure_scrollpanes.push(new dojox.layout.ScrollPane({
-                                    orientation:"horizontal",
-                                    style:"overflow:hidden;"},
-                                    digests[i].figure_container_id));
-                    }
-                }
-            } else {
-{% if object.eventlog_set.count %}
-                annotationsDiv.innerHTML += auditLogContents;
-{% endif %}
-            }
-
-            //-------------------------------------------------------------------
-            // Now that the annotations section has been added to the dom, we
-            // can work on its functionality.
-            //-------------------------------------------------------------------
-            var logtitle = dom.byId("logmessagetitle");
-            var logtext = dom.byId("newlogtext");
-
-            var editor_div = dom.byId("editor");
-            var preview_div = dom.byId("previewer");
-
-            // A pane holder for the form that will tag new log messages.
-            // I need it up here because we're going to integrate it with the
-            // editor components.
-            dojo.style(preview_div, { 'display':'none'});
-            dojo.style(editor_div, { 'display':'none'});
-
-            var button_element = dojo.create('button');
-            dojo.place(button_element, logtitle, "right");
-            var button = new Button({
-                label: "Add Log Entry",
-                state: "add",
-                onClick: function(){
-                    if (this.state == 'add') {
-                        dojo.style(editor_div, {'display':'block'});
-                        button.set('label', "Cancel Log Entry");
-                        button.set('state', 'cancel');
-                        editor.focus();
-                    }
-                    else {
-                        dojo.style(editor_div, {'display':'none'});
-                        dojo.style(preview_div, {'display':'none'});
-                        button.set('label', "Add Log Entry");
-                        button.set('state', 'add');
-                        editor.set('value','');
-                    }
-                },
-            }, button_element);
-
-            var savebutton = new Save({
-                    url: "{% url "logentry" object.graceid "" %}",
-                    onSuccess: function (resp, ioargs) {
-                        //this.inherited(resp, ioargs);
-                        this.button.set("disabled", false);
-                        location.reload(true);
-                    },
-                    onError: function (error, ioargs) {
-                        //this.inherited(error, ioargs);
-                        this.button.set("disabled", false);
-                        alert("o hai " + error);
-                    },
-                    save: function(postdata) {
-                    var newTagName = "analyst_comments";
-                    var postArgs = {
-                                url: this.url,
-                                content: { comment: postdata, tagname: newTagName },
-                                handleAs: "json"
-                        };
-                        this.button.set("disabled", true);
-                        var deferred = dojo.xhrPost(postArgs);
-                        deferred.addCallback(dojo.hitch(this, this.onSuccess));
-                        deferred.addErrback(dojo.hitch(this, this.onError));
-                        // Call whatever function is necessary to attach the tag
-                        // or add to the postdata and handle in the django view?
-                    }
-            });
-
-            var previewbutton = new Preview({
-                _preview: function(){
-                        var content = this.editor.get("value");
-                        preview_div.innerHTML = editor.get('value');
-                        dojo.style(preview_div, {
-                            'display':'block',
-                            'border': ".2em solid #900",
-                            'padding': '10px'
-                        });
-                        MathJax.Hub.Queue(["Typeset",MathJax.Hub, preview_div]);
-                    }
-            });
-
-            var editor = new Editor({
-                 extraPlugins : ['foreColor','hiliteColor','|','createLink',
-                                 'insertImage','fullscreen','viewsource','newpage', '|', previewbutton, savebutton]
-            }, editor_div);
-
-            // Connect up the tag addition buttons and add helptext.
-            for (var i = 0; i<logs.length; i++) {
-                log = logs[i];
-                on(dom.byId(log.button_id), "click", getTagAddCallback(log));
-                new Tooltip({ connectId: log.button_id, label: "tag this log message"});
-            }
-
-            // Connect up the tag deletion buttons and add helptext.
-            for (var i = 0; i<tags.length; i++) {
-                tag = tags[i];
-                on(dom.byId(tag.button_id), "click", getTagDelCallback(tag));
-                new Tooltip({ connectId: tag.button_id, label: "delete this tag"});
-            }
-
-
-            // Handle the post to skymapViewer button.
-            var sV_button = dom.byId("sV_button");
-            if (sV_button) {
-                on(sV_button, "click", function() {
-                    var embblog_json_url = "{% url "api:embbeventlog-list" object.graceid %}";
-                    var embblog_json;
-                    dojo.xhrGet({
-                        url: embblog_json_url + "?format=json",
-                        async: true,
-                        load: function(embblog_json) {
-
-
-                        // construct skymap.json url.
-                        var skymap_json_url = "{% url "file" object.graceid "skymap.json" %}"
-                        // fetch JSON content.
-                        dojo.xhrGet({
-                            url: skymap_json_url,
-                            load: function(result) { 
-                                // Find the form and set its value to the appropriate JSON        
-                                sV_form = dom.byId("sV_form");
-                                // Shove the skymap.json contents into the value for the second form field.
-                                sV_form.elements[1].value = result; 
-                                sV_form.elements[2].value = embblog_json; 
-                                // Submit the form, which takes the user to the skymapViewer server.
-                                sV_form.submit();
-                            }
-                        });    // end of inside ajax
-                        }
-                    });        // end of outside ajax
-                });
-            }
-
-        });
+<!-- <script charset="utf-8" src="{{STATIC_URL}}js/labeltips.js" type=text/javascript"></script> -->
+<link rel="stylesheet" href="{{STATIC_URL}}css/labeltips.css">
+<script src="{{BOWER_URL}}moment/moment.js"></script>
+<script src="{{BOWER_URL}}moment-timezone/moment-timezone-with-data-2010-2020.min.js"></script>
+<script src="{{BOWER_URL}}dojo/dojo.js" data-dojo-config="async: true"></script>
+<!-- Styles for dgrid -->
+<!-- <link rel="stylesheet" href="{{BOWER_URL}}dgrid/css/dgrid.css" /> -->
+<!-- Styles for the editor components -->
+<link rel="stylesheet" href="{{BOWER_URL}}dojox/editor/plugins/resources/css/PageBreak.css" />
+<link rel="stylesheet" href="{{BOWER_URL}}dojox/editor/plugins/resources/css/ShowBlockNodes.css" />
+<link rel="stylesheet" href="{{BOWER_URL}}dojox/editor/plugins/resources/css/Preview.css" />
+<link rel="stylesheet" href="{{BOWER_URL}}dojox/editor/plugins/resources/css/Save.css" />
+<link rel="stylesheet" href="{{BOWER_URL}}dojox/editor/plugins/resources/css/Breadcrumb.css" />
+<link rel="stylesheet" href="{{BOWER_URL}}dojox/editor/plugins/resources/css/FindReplace.css" />
+<link rel="stylesheet" href="{{BOWER_URL}}dojox/editor/plugins/resources/css/PasteFromWord.css" />
+<link rel="stylesheet" href="{{BOWER_URL}}dojox/editor/plugins/resources/css/InsertAnchor.css" />
+<link rel="stylesheet" href="{{BOWER_URL}}dojox/editor/plugins/resources/css/CollapsibleToolbar.css" />
+<link rel="stylesheet" href="{{BOWER_URL}}dojox/editor/plugins/resources/css/Blockquote.css" />
+<link rel="stylesheet" href="{{BOWER_URL}}dojox/editor/plugins/resources/css/Smiley.css" />
+<!-- Styles for the lightboxes. --> 
+<link rel="stylesheet" href="{{BOWER_URL}}dojox/image/resources/LightboxNano.css" />
+<!-- Local style declarations -->
+<link rel="stylesheet" href="{{BOWER_URL}}dijit/themes/tundra/tundra.css" />
+
+<!-- the main JavaScript block is pulled in with an include -->
+<script>
+{% include "gracedb/event_detail_script.js" %}
+</script>
 
-    </script>
-        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojox/editor/plugins/resources/css/PageBreak.css" />
-        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojox/editor/plugins/resources/css/ShowBlockNodes.css" />
-        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojox/editor/plugins/resources/css/Preview.css" />
-        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojox/editor/plugins/resources/css/Save.css" />
-        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojox/editor/plugins/resources/css/Breadcrumb.css" />
-        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojox/editor/plugins/resources/css/FindReplace.css" />
-        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojox/editor/plugins/resources/css/PasteFromWord.css" />
-        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojox/editor/plugins/resources/css/InsertAnchor.css" />
-        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojox/editor/plugins/resources/css/CollapsibleToolbar.css" />
-        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojox/editor/plugins/resources/css/Blockquote.css" />
-        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojox/editor/plugins/resources/css/Smiley.css" />
-<style>
-        @import "https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dijit/themes/tundra/tundra.css";
-        a:hover .dojoxEnlarge {
-            display: block !important;
-        }
-        .dojoxEnlarge {
-            /* background: url(images/enlarge.png) no-repeat 0 0;*/
-            top: -5px;
-            left: -5px;
-            margin: 0 !important;
-            width: 16px;
-            height: 16px;
-        }
-        .dojoxLoading {
-            /* background: #333 url(images/loading-dark.gif) no-repeat center center;*/
-            border-radius: 5px;
-            -moz-border-radius: 5px;
-            -webkit-border-radius: 5px;
-            border: 2px solid #000;
-            height: 24px;
-            opacity: 0.8;
-            filter: alpha(opacity=80);
-            padding: 6px;
-            width: 24px;
-        }
-    </style>
 {% endblock %}
 
 {% block content %}
+<div id='event_detail_content'>
+
 <p>{{ message }}</p>
 
 <!-- XXX This next bit is super hacky. -->
@@ -598,15 +64,9 @@
 
 <div class="content-area">
 {% block basic_info %}
-<h3> Basic Info </h3>
+<h2> Basic Info </h2>
 
 <table class="event">
-    {# {% if skyalert_authorized  %}  #}
-    <!--    <tr><td colspan="4">
-           <a href="{# {% url "skyalert" object.graceid %} #}"><button type="button">Submit to Skyalert</button></a>
-        </td></tr> -->
-    {# {% endif %} #}
-
     <tr>
             <th valign="top">UID</th>
             <th>Labels</th>
@@ -615,18 +75,16 @@
             <th>Search</th>
             <th>Instruments</th>
             <th>
-                {{ "gps"|timeselect:"gps" }}
-                Event Time
+                <div id="basic_info_event_ts"></div>
+                <div> Event Time </div>
             </th>
             <th>FAR (Hz)</th>
             <th>Links</th>
             <th>
-                {{"created"|timeselect:"utc" }}
-                Submitted
+                <div id="basic_info_created_ts"></div>
+                <div> Submitted </div>
             </th>
     </tr>
-
-
     <tr>
         <td>{{ object.graceid }}</td>
         <td>
@@ -646,7 +104,6 @@
         <td><a href="{{ object.weburl }}">Data</a></td>
         <td>{{ object.created|multiTime:"created" }}</td>
     </tr>
-
 </table>
 {% endblock %}
 </div>
@@ -658,22 +115,7 @@
 {% endblock %}
 </div>
 
-{# Enable post to skymap viewer #}
-<div id="sV_form_div" style="display: none">
-
-<form action="{{ SKYMAP_VIEWER_SERVICE_URL }}" id="sV_form"  method="post">
-    <input type="hidden" name="skymapid" value="{{ object.graceid }}">
-    <!-- <input type="hidden" name="json" value="{{ skymap_json }}"> -->
-    <!-- <input type="hidden" name="json" value="blaargh"> -->
-
-    <input type="hidden" name="json" />
-    <input type="hidden" name="embb" />
-
-    <input type="submit" value="View in skymapViewer!">
-</form>
-</div>
-
-<!-- Neighbors Support refresh_neighbors() function -->
+{# Neighbors #}
 <script type="text/javascript">
     var refresh_neighbors= function() { alert("NOT SET YET"); };
     require(["dojo/dom", "dojo/html", "dojo/request", "dojo/domReady!"],
@@ -699,284 +141,12 @@
         // refresh_neighbors("5");
     });
     require(["dijit/InlineEditBox", "dijit/form/NumberSpinner", "dijit/form/TextBox"]);
-
-  </script>
-  
-  {% include "gracedb/neighbors_frag.html" %}
-</p>
-
-			<!-- Single Inspiral Data -->
-
-
-			<div id="bulletin_board" data-dojo-type="dijit/TitlePane"
-				data-dojo-props="title: 'EM Follow-up Bulletin Board', open: false">
-
-				<div data-dojo-type="dijit/form/Form" id="myForm"
-					data-dojo-id="myForm" encType="multipart/form-data" action=""
-					method="">
-				<script>
-				 require(["dojo/parser", "dijit/form/Form", "dijit/form/Button", "dijit/form/ValidationTextBox", "dijit/form/DateTextBox"]);
-				 </script>
-				 
-				<script type="dojo/on" data-dojo-event="reset">
-        			return confirm('Press OK to reset widget values');
-    			</script>
-
-				<script type="dojo/on" data-dojo-event="submit">
-        		if(this.validate()){
-            		return confirm('Form is valid, press OK to submit');
-        			}else{
-            			alert('Form contains invalid data.  Please correct first');
-            			return false;
-        			}
-       			 return true;
-    			</script>
-
-					<h2>Make a report here</h2>
-
-<form method="POST" action="{% url "embblogentry" object.graceid "" %}">
-<table>
-
-<tr><td><a href=# onclick="alert('Define here what subclass of report this is:\n FOOTPRINT: There is or could be image data taken of the sky, with a specific instrument, at a specific time, in a specific waveband, as followup of a specific LVC alert.\n SOURCE: There is a candidate source at the given location, that could be associated with the given LVC alert.\n COMMENT: The primary purpose of this report is a human-written comment concerning the given LVC alert.'); return false;">
-What type of report is this?</a></td>       <td><select name="eel_status">
-<option value="FO">FOOTPRINT</option>
-<option value="SO">SOURCE</option>
-<option value="CO">COMMENT</option>
-</select></td></tr>
-
-<tr><td><a href=# onclick="alert('There is also Observation Status which is:\n OBSERVATION: has been done.\n PREDICTION: this report represents intent or future observation.\n TEST: This EEL is part of a test and has no astrophysical significance.\n NOT APPLICABLE: It is neither observation nor prediction.'); return false;">
-Observation Status</a></td>       <td><select name="obs_status">
-<option value="OB">OBSERVATION</option>
-<option value="PR">PREDICTION</option>
-<option value="TE">TEST</option>
-<option value="NA">NOT APPLICABLE</option>
-</select></td></tr>
-
-<tr><td><a href=# onclick="alert('Group with which the LSC has signed a trust agreement, hereby providing data 
-under its trust (required).'); return false;">
-Which MOU Group provides this report?</a></td>       <td><select name="group">
-{% for g in groups %}
-<option value="{{ g }}">{{ g }}</option>
-{% endfor %} </select> </td> </tr>
-
-
-
-<tr><td><a href=# onclick="alert('An ID from the data owner to identify this footprint (optional).');return false;">
-Your reference</a></td>   <td><input type="text" name="footprintID"/></td></tr>
-
-<tr><td><a href=# onclick="alert('A natural language report.');return false;">
-Report as text</a></td>         <td colspan=2><textarea name="comment" rows="8" cols="50"></textarea></td></tr>
-
-<tr><td><a href=# onclick="alert('The name of the photon detector whose observational metadata is being recorded here (optional).');return false;">
-Instrument</a></td>       <td><input type="text" name="instrument"> </td> </tr>
-
-<tr><td><a href=# onclick="alert('Specify waveband of the observation. Vocabulary is taken from the UCD vocabulary, a Virtual Observatory standard. Waveband can be either wide (eg Radio) or narrow (eg Radio 200-400 MHz).');return false;">
-Waveband</a></td>       <td colspan=2><select name="waveband">
-<option value="em.gamma">Gamma rays part of the spectrum</option>
-<option value="em.gamma.soft">Soft gamma ray (120 - 500 keV)</option>
-<option value="em.gamma.hard">Hard gamma ray (&gt;500 keV)</option>
-<option value="em.X-ray">X-ray part of the spectrum</option>
-<option value="em.X-ray.soft">Soft X-ray (0.12 - 2 keV)</option>
-<option value="em.X-ray.medium">Medium X-ray (2 - 12 keV)</option>
-<option value="em.X-ray.hard">Hard X-ray (12 - 120 keV)</option>
-<option value="em.UV">Ultraviolet part of the spectrum</option>
-<option value="em.UV.10-50nm">Ultraviolet between 10 and 50 nm</option>
-<option value="em.UV.50-100nm">Ultraviolet between 50 and 100 nm</option>
-<option value="em.UV.100-200nm">Ultraviolet between 100 and 200 nm</option>
-<option value="em.UV.200-300nm">Ultraviolet between 200 and 300 nm</option>
-<option value="em.UV.FUV">Far-Infrared, 30-100 microns</option>
-<option value="em.opt">Optical part of the spectrum</option>
-<option value="em.opt.U">Optical band between 300 and 400 nm</option>
-<option value="em.opt.B">Optical band between 400 and 500 nm</option>
-<option value="em.opt.V">Optical band between 500 and 600 nm</option>
-<option value="em.opt.R">Optical band between 600 and 750 nm</option>
-<option value="em.opt.I">Optical band between 750 and 1000 nm</option>
-<option value="em.IR">Infrared part of the spectrum</option>
-<option value="em.IR.NIR">Near-Infrared, 1-5 microns</option>
-<option value="em.IR.J">Infrared between 1.0 and 1.5 micron</option>
-<option value="em.IR.H">Infrared between 1.5 and 2 micron</option>
-<option value="em.IR.K">Infrared between 2 and 3 micron</option>
-<option value="em.IR.MIR">Medium-Infrared, 5-30 microns</option>
-<option value="em.IR.3-4um">Infrared between 3 and 4 micron</option>
-<option value="em.IR.4-8um">Infrared between 4 and 8 micron</option>
-<option value="em.IR.8-15um">Infrared between 8 and 15 micron</option>
-<option value="em.IR.15-30um">Infrared between 15 and 30 micron</option>
-<option value="em.IR.30-60um">Infrared between 30 and 60 micron</option>
-<option value="em.IR.60-100um">Infrared between 60 and 100 micron</option>
-<option value="em.IR.FIR">Far-Infrared, 30-100 microns</option>
-<option value="em.mm">Millimetric part of the spectrum</option>
-<option value="em.mm.1500-3000GHz">Millimetric between 1500 and 3000 GHz</option>
-<option value="em.mm.750-1500GHz">Millimetric between 750 and 1500 GHz</option>
-<option value="em.mm.400-750GHz">Millimetric between 400 and 750 GHz</option>
-<option value="em.mm.200-400GHz">Millimetric between 200 and 400 GHz</option>
-<option value="em.mm.100-200GHz">Millimetric between 100 and 200 GHz</option>
-<option value="em.mm.50-100GHz">Millimetric between 50 and 100 GHz</option>
-<option value="em.mm.30-50GHz">Millimetric between 30 and 50 GHz</option>
-<option value="em.radio">Radio part of the spectrum</option>
-<option value="em.radio.12-30GHz">Radio between 12 and 30 GHz</option>
-<option value="em.radio.6-12GHz">Radio between 6 and 12 GHz</option>
-<option value="em.radio.3-6GHz">Radio between 3 and 6 GHz</option>
-<option value="em.radio.1500-3000MHz">Radio between 1500 and 3000 MHz</option>
-<option value="em.radio.750-1500MHz">Radio between 750 and 1500 MHz</option>
-<option value="em.radio.400-750MHz">Radio between 400 and 750 MHz</option>
-<option value="em.radio.200-400MHz">Radio between 200 and 400 MHz</option>
-<option value="em.radio.100-200MHz">Radio between 100 and 200 MHz</option>
-<option value="em.radio.20-100MHz">Radio between 20 and 100 MHz</option>
-                                </select></td></tr>
-</table>
-<hr/>
-<script>
-function showRectanglesCheckbox(){
-    var s = document.getElementById('showRectangles');
-    showRectangles = s.checked;
-    if(showRectangles){ document.getElementById('rectanglesForm').style.display = "block"
-    } else {            document.getElementById('rectanglesForm').style.display = "none"
-    }
-    redrawAll();
-    return false;
-}
 </script>
-<input id="showRectangles" type="checkbox" onclick="showRectanglesCheckbox()" />add Sky Footprints<br/>
-<div id=rectanglesForm style="display: none;">
-<table>
-<tr><td><a href=# onclick="alert('RA and Dec specify a center point of a rectangle that is aligned equatorially. Or list of centers. They must be in decimal degrees 0<=RA<=360 -90<=Dec<=90, in the J2000 frame.');return false;">
-RA (decimal degrees)</a></td>             <td><input type="text" name="raList" value="" size=80/></td></tr>
-
-<tr><td><a href=# onclick="alert('RA and Dec specify a center point of a rectangle that is aligned equatorially. Or list of centers. They must be in decimal degrees 0<=RA<=360 -90<=Dec<=90, in the J2000 frame.');return false;">
-Dec (decimal degrees)</a></td>            <td><input type="text" name="decList" value="" size=80/></td></tr>
-
-<!--
-<script language="javascript" type="text/javascript" src="https://losc.ligo.org/s/js/gpstimeutil.js"></script>
-<script language="javascript" type="text/javascript" src="https://losc.ligo.org/s/js/sexg.js"></script>
--->
-
-
-<tr><td><a href=# onclick="alert('The time at the center of a time interval during which the observation was taken. Or list of times.');return false;">
-GPStime</a></td>
-<td><input type="text" name="gpstimeList" value="" size=80/></td>
-<!--
-<td><input onKeyUp="return TIMEcopy(2,1);" id="TIMEgps1" name="gpstimeList" maxlength="12" size="20" value="1000000000"/></td>
-<td><input onKeyUp="return TIMEcopy(1,1);" id="TIMEiso1" name="TIMEiso1" maxlength="25" size="25" value="2011-09-14T01:46:25"/></td>
-<td><span id="TIMEerr1" STYLE="font: 12px Arial; color:red">OK</span><br/></td>
--->
-</tr>
-
-<tr><td><a href=# onclick="alert('RAWidth and DecWidth specify the size of a a rectangle that is aligned equatorially. Thus the edge of the box is distant from the center by half of the width.');return false;">
-RAwidth (decimal degrees)</a></td>        <td><input type="text" name="raWidthList" value=""/></td></tr>
-
-<tr><td><a href=# onclick="alert('RAWidth and DecWidth specify the size of a a rectangle that is aligned equatorially. Thus the edge of the box is distant from the center by half of the width.');return false;">
-Decwidth (decimal degrees)</a></td>       <td><input type="text" name="decWidthList" value=""/></td></tr>
-
-<tr><td><a href=# onclick="alert('Duration is the number of seconds in the time interval during which the observation was taken.');return false;">
-Duration (seconds)</a></td>       <td><input type="text" name="durationList" value=""/></td></tr>
-
-</table>
-</div>
-<hr/>
-<script>
-function showJsonCheckbox(){
-    var s = document.getElementById('showJson');
-    showJson = s.checked;
-    if(showJson){ document.getElementById('jsonForm').style.display = "block"
-    } else {      document.getElementById('jsonForm').style.display = "none"
-    }
-    redrawAll();
-    return false;
-}
-</script>
-<input id="showJson" type="checkbox" onclick="showJsonCheckbox()" />add JSON data<br/>
-<div id=jsonForm style="display: none;">
-<table>
-<tr><td><a href=# onclick="alert('This section allows for machine-readable data to be included in a flexible way. any key can be any value in a JSON dictionary. There is a useful validator at http://jsonlint.com.');return false;">
-JSON data</a></td>       <td colspan=2><textarea name="extra_info_dict" rows="20" cols="50"></textarea></td></tr>
-</table>
-</div>
-<hr/>
-<input type="submit" value="Submit EMBB Report"/>
-</form>
-
-
-				</div>
-
-				<!-- Bulletin Board Log -->
-				<div data-dojo-type="dijit/TitlePane"
-                {% if object.embbeventlog_set.count > 0 %}
-					data-dojo-props="title: 'Bulletin Board Log', open: true">
-                {% else %} 
-					data-dojo-props="title: 'Bulletin Board Log', open: false">
-                {% endif %}
-This data in <a href="{% url "api:embbeventlog-list" object.graceid %}">JSON</a><br/>
-<table id="bb_2" class="event" border="1" 
-style="table-layout:fixed; width:100%;word-wrap:break-word;">
-						<thead>
-							<tr>
-								<th>Date</th>
-								<th>Submitter</th>
-								<th>MOU Group</th>
-								<th>Instrument</th>
-								<th>Footprint ID</th>
-								<th>Waveband</th>
-								<th>RA</th>
-								<th>DEC</th>
-								<th>RAwidth</th>
-								<th>Decwidth</th>
-								<th>GPS Time</th>
-								<th>Duration</th>
-								<th>EEL Type</th>
-								<th>Obs status</th>
-								<th>Comment</th>
-								<th>JSON Data</th>
-							</tr>
-						</thead>
-						
-						  <tbody id="bb_log" >
-							{% for eel in object.embbeventlog_set.iterator %}
-<tr>
-<td>{{ eel.created }}</td> 
-<td>{{ eel.submitter }}</td> 
-<td>{{ eel.group }}</td> 
-<td>{{ eel.instrument }}</td>
-<td>{{ eel.footprintID }}</td> 
-<td>{{ eel.waveband }}</td> 
-<td>{{ eel.ra }}</td> 
-<td>{{ eel.dec }}</td> 
-<td>{{ eel.raWidth }}</td> 
-<td>{{ eel.decWidth }}</td> 
-<td>{{ eel.gpstime }}</td> 
-<td>{{ eel.duration }}</td> 
-<td>{{ eel.eel_status }}</td> 
-<td>{{ eel.obs_status }}</td> 
-<td>{{ eel.comment|truncatechars:40 }}</td> 
-<td>{{ eel.extra_info_dict|truncatechars:40 }}</td> 
-</tr>
-							{% endfor %}
-  						</tbody>
-						
-						</table>
-				</div>
-</div>
-
-
-<p>&nbsp; </p>
-<div id="annotations" class="content-area">
 
-    <div id="new_log_entry_form">
-    <noscript>
-        <h3>Create a new log entry</h3>
-        <form id="newlog" action="{% url "logentry" object.graceid "" %}" method="POST">
-            <p>
-              <textarea id="newlogtext" name="comment" style="width:300px;display:block"></textarea>
-              <input type="submit" value="Submit"/>
-            </p>
-        </form>
-    </noscript>
-  </div>
+{% include "gracedb/neighbors_frag.html" %}
 
-    <h3 id="logmessagetitle">Event Log Messages</h3>
-    <div id="previewer"></div>
-    <div id="editor"></div>
+{% include "gracedb/eel_form_frag.html" %}
 
-</div> 
+</div> <!-- end event_detail_content div -->
 {% endblock %}
 
-<!-- Single Inspiral Data -->
diff --git a/templates/gracedb/event_detail_CWB.html b/templates/gracedb/event_detail_CWB.html
index de184254918e290919a0d69ea6fdde66fff6ed64..fc2f6782b7476c7fa32118462fc5ca32ed4bcacd 100644
--- a/templates/gracedb/event_detail_CWB.html
+++ b/templates/gracedb/event_detail_CWB.html
@@ -4,7 +4,7 @@
 
 {# Analysis-specific attributes for a cWB event#}
 {% block analysis_specific %}
-<h3>Analysis-Specific Attributes</h3>
+<h2>Analysis-Specific Attributes</h2>
 
 <table class="analysis_specific"> <tbody>
     <tr>
diff --git a/templates/gracedb/event_detail_GRB.html b/templates/gracedb/event_detail_GRB.html
index 142035ac19af04c4e689b55c9412bdd0fb19a2ad..d2a69cb3df042b0224b19882a7131a7d14e321b4 100644
--- a/templates/gracedb/event_detail_GRB.html
+++ b/templates/gracedb/event_detail_GRB.html
@@ -2,7 +2,7 @@
 {% load timeutil %}
 
 {% block basic_info %}
-<h3> Basic Info </h3>
+<h2> Basic Info </h2>
 
 <table class="event">
     {% if skyalert_authorized  %}
@@ -19,13 +19,13 @@
             <th>Search</th>
             <th>Instruments</th>
             <th>
-                {{ "gps"|timeselect:"gps" }}
-                Event Time
+                <div id="basic_info_event_ts"></div>
+                <div> Event Time </div>
             </th>
             <th>Links</th>
             <th>
-                {{"created"|timeselect:"utc" }}
-                Submitted
+                <div id="basic_info_created_ts"></div>
+                <div> Submitted </div>
             </th>
     </tr>
 
diff --git a/templates/gracedb/event_detail_coinc.html b/templates/gracedb/event_detail_coinc.html
index 11d81da57d377ee221b5bce8d74f3db29af900cb..ed8bddbfb7b1c531bb4e83e43b763660e59ad5c7 100644
--- a/templates/gracedb/event_detail_coinc.html
+++ b/templates/gracedb/event_detail_coinc.html
@@ -12,10 +12,10 @@
 <div style="display:table-row;width:100%">
 
 <div style="display:table-cell;float:left;width:35%;">
-<h3>Coinc Tables</h3>
+<h2>Coinc Tables</h2>
 <!-- <table class="analysis_specific"> <tbody> -->
 <!-- 5 rows here -->
-<table style="height:320px"> 
+<table style="height:364px"> 
     <!-- <tr> <th> ifos </th> <td> {{object.ifos}} </td> </tr>  -->
     <tr> <th> End Time </th> <td> {{object|end_time:4}} </td> </tr>
     <!--<tr> <th> end_time_ns </th> <td> {{object.end_time_ns}} </td> </tr> -->
@@ -33,7 +33,7 @@
 <!-- Single Inspiral Data -->
 <!-- 13 rows here. -->
 <div style="display:table-cell;float:right;width:65%">
-<h3>Single Inspiral Tables</h3>
+<h2>Single Inspiral Tables</h2>
 
 <!--<div id="single_inspiral_tables"> -->
 <!-- <div id="single_inspiral_tables"
@@ -359,6 +359,18 @@
 		<td>{{ e.gamma9 }}</td>
 		{% endfor %}
     </tr> -->
+	<tr>
+		<th>spin1z</th>
+		{% for e in single_inspiral_events %}
+		<td>{{ e.spin1z }}</td>
+		{% endfor %}
+    </tr> 
+	<tr>
+		<th>spin2z</th>
+		{% for e in single_inspiral_events %}
+		<td>{{ e.spin2z }}</td>
+		{% endfor %}
+    </tr> 
 </table>
 </div> 
 
diff --git a/templates/gracedb/event_detail_script.js b/templates/gracedb/event_detail_script.js
new file mode 100644
index 0000000000000000000000000000000000000000..159c51d477c00e05534e1f292cf0330434d8773d
--- /dev/null
+++ b/templates/gracedb/event_detail_script.js
@@ -0,0 +1,1001 @@
+// Ugh. Why do I have to pull the stuff in here?
+// Tooltip pop-ups for labels.
+var label_descriptions = {
+    cWB_s: "cWB_s",
+    cWB_r: "cWB_r",
+    EM_READY: "Has been processed by GDB Processor.<br/>Skymaps have been produced.",
+    SWIFT_NO: "Do not send notification to SWIFT telescope.",
+    SWIFT_GO: "Send notification to SWIFT telescope.",
+    LUMIN_NO: "LUMIN No",
+    LUMIN_GO: "LUMIN Go",
+    DQV: "Data quality veto.",
+    INJ: "Injection occured near this time."
+}
+function tooltiptext(name, creator, time) {
+    return ( creator + " " + time + "<br/>" + label_descriptions[name] );
+};
+var tooltip=function(){
+ var id = 'tt';
+ var top = 3;
+ var left = 3;
+ var maxw = 300;
+ var speed = 10;
+ var timer = 20;
+ var endalpha = 95;
+ var alpha = 0;
+ var tt,t,c,b,h;
+ var ie = document.all ? true : false;
+ return{
+  show:function(v,w){
+   if(tt == null){
+    tt = document.createElement('div');
+    tt.setAttribute('id',id);
+    t = document.createElement('div');
+    t.setAttribute('id',id + 'top');
+    c = document.createElement('div');
+    c.setAttribute('id',id + 'cont');
+    b = document.createElement('div');
+    b.setAttribute('id',id + 'bot');
+    tt.appendChild(t);
+    tt.appendChild(c);
+    tt.appendChild(b);
+    document.body.appendChild(tt);
+    tt.style.opacity = 0;
+    tt.style.filter = 'alpha(opacity=0)';
+    document.onmousemove = this.pos;
+   }
+   tt.style.display = 'block';
+   c.innerHTML = v;
+   tt.style.width = w ? w + 'px' : 'auto';
+   if(!w && ie){
+    t.style.display = 'none';
+    b.style.display = 'none';
+    tt.style.width = tt.offsetWidth;
+    t.style.display = 'block';
+    b.style.display = 'block';
+   }
+  if(tt.offsetWidth > maxw){tt.style.width = maxw + 'px'}
+  h = parseInt(tt.offsetHeight) + top;
+  clearInterval(tt.timer);
+  tt.timer = setInterval(function(){tooltip.fade(1)},timer);
+  },
+  pos:function(e){
+   var u = ie ? event.clientY + document.documentElement.scrollTop : e.pageY;
+   var l = ie ? event.clientX + document.documentElement.scrollLeft : e.pageX;
+   tt.style.top = (u - h) + 'px';
+   tt.style.left = (l + left) + 'px';
+  },
+  fade:function(d){
+   var a = alpha;
+   if((a != endalpha && d == 1) || (a != 0 && d == -1)){
+    var i = speed;
+   if(endalpha - a < speed && d == 1){
+    i = endalpha - a;
+   }else if(alpha < speed && d == -1){
+     i = a;
+   }
+   alpha = a + (i * d);
+   tt.style.opacity = alpha * .01;
+   tt.style.filter = 'alpha(opacity=' + alpha + ')';
+  }else{
+    clearInterval(tt.timer);
+     if(d == -1){tt.style.display = 'none'}
+  }
+ },
+ hide:function(){
+  clearInterval(tt.timer);
+   tt.timer = setInterval(function(){tooltip.fade(-1)},timer);
+  }
+ };
+}();
+
+
+
+
+
+// A utility
+var getKeys = function(obj){
+   var keys = [];
+   for(var key in obj){
+      keys.push(key);
+   }
+   return keys;
+}
+
+var image_extensions = ['png', 'gif', 'jpg'];
+
+// A utility function to determine whether a log message has an image.
+// This would not be necessary if we were using django template language
+var hasImage = function(object) {
+    if (!object.filename) return false;
+    var file_extension = object.filename.slice(object.filename.length - 3);
+    return image_extensions.indexOf(file_extension) >= 0; 
+}
+
+// some URLs. Usage of Django template syntax should be limited to here
+var tagListUrl          = '{% url "api:tag-list" %}';
+var tagUrlPattern       = '{% url "taglogentry" object.graceid "000" "temp" %}';
+var eventLogListUrl     = '{% url "api:eventlog-list" object.graceid %}';
+var eventLogSaveUrl     = '{% url "logentry" object.graceid "" %}';
+var embbEventLogListUrl = '{% url "api:embbeventlog-list" object.graceid %}';
+var skymapJsonUrl       = '{% url "file" object.graceid "skymap.json" %}';
+var skymapViewerUrl     = '{{ SKYMAP_VIEWER_SERVICE_URL }}';
+
+// This little list determines the priority ordering of the digest sections.
+var blessed_tag_priority_order = [
+    'analyst_comments',
+    'psd',
+    'data_quality',
+    'sky_loc',
+    'background',
+    'ext_coinc',
+    'strain',
+    'tfplots',
+    'sig_info',
+    'audio',    
+];
+
+require([
+    'dojo/_base/declare',
+    'dojo/query',
+    'dojo/on',
+    'dojo/parser',
+    'dojo/dom',
+    'dojo/dom-construct',
+    'dojo/dom-style',
+    'dojo/request',
+    'dojo/store/Memory',
+    'dojo/data/ObjectStore',
+    'dstore/Rest',
+    'dstore/RequestMemory',
+    'dgrid/Grid',
+    'dgrid/extensions/DijitRegistry',
+    'put-selector/put',
+    'dijit/TitlePane',
+    'dijit/form/Form',        
+    'dijit/form/Button',
+    'dijit/form/TextBox',
+    'dijit/form/ComboBox',
+    'dijit/form/Select',
+    'dijit/Tooltip',
+    'dijit/Dialog',
+    'dijit/Editor',
+    'dojox/editor/plugins/Save',
+    'dojox/editor/plugins/Preview',
+    'dojox/layout/ScrollPane',
+    'dojox/image/LightboxNano',
+    'dijit/_editor/plugins/TextColor',
+    'dijit/_editor/plugins/LinkDialog',
+    'dijit/_editor/plugins/ViewSource',
+    'dijit/_editor/plugins/NewPage',
+    'dijit/_editor/plugins/FullScreen',
+    'dojo/domReady!',
+], function(declare, query, on, parser, dom, domConstruct, domStyle, request, Memory, ObjectStore,
+    Rest, RequestMemory, Grid, DijitRegistry, 
+    put, 
+    TitlePane, Form, Button, TextBox, ComboBox, Select, Tooltip, Dialog, Editor, 
+    Save, Preview, ScrollPane) {
+
+    parser.parse();
+    //----------------------------------------------------------------------------------------
+    // Some utility functions
+    //----------------------------------------------------------------------------------------
+    var createExpandingSection = function (titleNode, contentNode, formNode, titleText, initiallyOpen) {
+
+        // Instead let's make a table. 
+        var titleTableRow = put(titleNode, "table tr");
+        var expandGlyphNode = put(titleTableRow, "td.title div.expandGlyph"); 
+        var titleTextNode = put(titleTableRow, "td.title h2", titleText);
+        var addButtonNode = put(titleTableRow, "td.title div.expandFormButton", '(add)');
+
+        if (!(initiallyOpen && initiallyOpen==true)) { 
+            put(expandGlyphNode, '.closed');
+            domStyle.set(contentNode, 'display', 'none');
+            domStyle.set(addButtonNode, 'display', 'none');
+        }
+        // This one is always closed initially
+        domStyle.set(formNode, 'display', 'none');
+       
+        on(expandGlyphNode, "click", function() {
+            if (domStyle.get(contentNode, 'display') == 'none') {
+                domStyle.set(contentNode, 'display', 'block');
+                domStyle.set(addButtonNode, 'display', 'block');
+                put(expandGlyphNode, '!closed');
+            } else {
+                domStyle.set(contentNode, 'display', 'none');
+                domStyle.set(addButtonNode, 'display', 'none');
+                put(expandGlyphNode, '.closed');
+            }
+        });
+        
+        on(titleTextNode, "click", function() {
+            if (domStyle.get(contentNode, 'display') == 'none') {
+                domStyle.set(contentNode, 'display', 'block');
+                domStyle.set(addButtonNode, 'display', 'block');
+                put(expandGlyphNode, '!closed');
+            } else {
+                domStyle.set(contentNode, 'display', 'none');
+                domStyle.set(addButtonNode, 'display', 'none');
+                put(expandGlyphNode, '.closed');
+            }
+        });
+
+        on(addButtonNode, "click", function() {
+            if (domStyle.get(formNode, 'display') == 'none') {
+                domStyle.set(formNode, 'display', 'block');
+                addButtonNode.innerHTML = '(cancel)';
+            } else {
+                domStyle.set(formNode, 'display', 'none');
+                addButtonNode.innerHTML = '(add)';
+            }
+        });
+    }
+
+    var timeChoicesData = [ 
+        {"id": "llo",   "label": "LLO Local"},
+        {"id": "lho",   "label": "LHO Local"},
+        {"id": "virgo", "label": "Virgo Local"},
+        {"id": "utc",   "label": "UTC"},
+    ];
+    // XXX Fixme. So. Bad.
+    var timeChoicesDataWithGps = [ 
+        {"id": "gps",   "label": "GPS Time"},
+        {"id": "llo",   "label": "LLO Local"},
+        {"id": "lho",   "label": "LHO Local"},
+        {"id": "virgo", "label": "Virgo Local"},
+        {"id": "utc",   "label": "UTC"},
+    ];
+
+    var timeChoices = new Memory ({ data: timeChoicesData });
+    var timeChoicesStore = new ObjectStore({ objectStore: timeChoices});
+    var timeChoicesWithGps = new Memory ({ data: timeChoicesDataWithGps });
+    var timeChoicesWithGpsStore = new ObjectStore({ objectStore: timeChoicesWithGps});
+
+    var createTimeSelect = function(node, label, defaultName, useGps) {
+        var myStore = (useGps) ? timeChoicesWithGpsStore : timeChoicesStore;
+        var s = new Select({ store: myStore }, node);
+        s.attr("value", defaultName);
+        s.on("change", function () { changeTime(this, label); });
+        return s;
+    }
+
+    //----------------------------------------------------------------------------------------
+    // Take care of stray time selects
+    //----------------------------------------------------------------------------------------
+    createTimeSelect(dom.byId('basic_info_event_ts'), 'gps', 'gps', true);
+    createTimeSelect(dom.byId('basic_info_created_ts'), 'created', 'utc', true);
+    createTimeSelect(dom.byId('neighbors_event_ts'), 'ngps', 'gps', true);
+    createTimeSelect(dom.byId('neighbors_created_ts'), 'ncreated', 'utc', true);
+
+    //----------------------------------------------------------------------------------------
+    // Section for EMBB 
+    //----------------------------------------------------------------------------------------
+    var eventDetailContainer = dom.byId('event_detail_content');
+    var embbDiv = put(eventDetailContainer, 'div.content-area#embb_container');
+    var embbTitleDiv = put(embbDiv, 'div#embb_title_expander');
+    var embbContentDiv = put(embbDiv, 'div#embb_content'); 
+
+    // Put the EEL form into the content div
+    var oldEelFormDiv = dom.byId('eelFormContainer');
+    var eelFormContents = oldEelFormDiv.innerHTML;
+    domConstruct.destroy('eelFormContainer');
+    var embbAddDiv = put(embbContentDiv, 'div#add_eel_container');
+    var embbAddFormDiv = put(embbAddDiv, 'div#add_eel_form_container');
+    embbAddFormDiv.innerHTML = eelFormContents;
+
+    createExpandingSection(embbTitleDiv, embbContentDiv, embbAddDiv, 'Electromagnetic Bulletin Board');
+
+    // Append the div that will hold our dgrid
+    put(embbContentDiv, 'div#eel-grid');
+        
+    embbStore = new declare([Rest, RequestMemory])({target: embbEventLogListUrl});
+    embbStore.get('').then(function(content) {
+        // Pull the EELs out of the rest content and create a new simple store from them.
+        var eels = content.embblog;
+
+        if (eels.length == 0) {
+            eelDiv = dom.byId('eel-grid');
+            eelDiv.innerHTML = '<p> (No EMBB log entries.) </p>';
+        } else {
+
+            var columns  = [
+                { field: 'created', label: 'Time Created (UTC)' },
+                { field: 'submitter', label: 'Submitter' },
+                { field: 'group', label: 'MOU Group' },
+                { field: 'gpstime', label: 'GPS time of observation' },
+                { field: 'duration', label: 'Exposure time (s)' },
+                { field: 'radec',
+                  label: 'Covering (ra, dec)',
+                    get: function(object){
+                        var rastring = object.ra + " \xB1 " + object.raWidth/2.0;
+                        var decstring = object.dec + " \xB1 " + object.decWidth/2.0;
+                        return "(" + rastring + ','  + decstring + ")";
+                    },
+                }
+            ]; 
+
+            var subRowColumns  = [ 
+                    { field: 'instrument', label: 'Instrument' },
+                    { field: 'eel_status', label: 'Entry type' },
+                    { field: 'footprintID', label: 'Observation ID' },
+                    { field: 'waveband', label: 'Waveband' },
+                    { field: 'obs_status', label: 'Observation status' },
+                    { field: 'extra_info_dict', label: 'JSON info' },
+            ]; 
+
+            // Add extra class names to our grid cells so we can style them separately
+            for (i = 0; i < columns.length; i++) {
+                columns[i].className = 'supergrid-cell';
+            }
+            for (i = 0; i < subRowColumns.length; i++) {
+                subRowColumns[i].className = 'subgrid-cell';
+            }
+
+            var grid = new Grid({ 
+                columns: columns,
+                className: 'dgrid-autoheight',
+
+                renderRow: function (object, options) {
+                    // Add the supergrid-row class to the row so we can style it separately from the subrows.
+                    var div = put('div.collapsed.supergrid-row', Grid.prototype.renderRow.call(this, object, options));
+
+                    // Add the subdiv table which will expand and contract.
+                    var t = put(div, 'div.expando table');
+                    // I'm finding that the table needs to be 100% of the available width, otherwise
+                    // Firefox doesn't like it. Hence the extra empty column.
+                    var subGridNode = put(t, 'tr td[style="width: 5%"]+td div');
+                    var sg = new Grid({
+                        columns: subRowColumns,
+                        className: 'dgird-subgrid',
+                    }, subGridNode);
+                    sg.renderArray([object]);
+                    // Add the text comment
+                    put(t, 'tr td[style="width: 5%"]+td div.subrid-text', object.comment); 
+
+                    return div;
+                }
+            }, 'eel-grid'); 
+            grid.renderArray(eels);
+            grid.set("sort", 'N', descending=true);
+
+            var expandedNode = null;
+
+            // listen for clicks to trigger expand/collapse in table view mode
+            var expandoListener = on(grid.domNode, '.dgrid-row:click', function (event) {
+                var node = grid.row(event).element;
+                var collapsed = node.className.indexOf('collapsed') >= 0;
+
+                // toggle state of node which was clicked
+                put(node, (collapsed ? '!' : '.') + 'collapsed');
+
+                // if clicked row wasn't expanded, collapse any previously-expanded row
+                collapsed && expandedNode && put(expandedNode, '.collapsed');
+
+                // if the row clicked was previously expanded, nothing is expanded now
+                expandedNode = collapsed ? node : null;
+            });
+        } // endif on whether we have any eels or not.
+    });
+
+
+    //----------------------------------------------------------------------------------------
+    // Section for log entries
+    //----------------------------------------------------------------------------------------
+    var annotationsDiv = put(eventDetailContainer, 'div.content-area');
+    var logTitleDiv = put(annotationsDiv, 'div#log_title_expander');
+    var logContentDiv = put(annotationsDiv, 'div#log_content');
+
+    // Create the form for adding a new log entry.
+    var logAddDiv = put(logContentDiv, 'div#new_log_entry_form');
+    put(logAddDiv, 'div#previewer');
+    put(logAddDiv, 'div#editor');
+    createExpandingSection(logTitleDiv, logContentDiv, logAddDiv, 'Event Log Messages', true);
+
+    //----------------------------------------------------------------------------------------
+    //----------------------------------------------------------------------------------------
+    // Get the tag properties. Sorta hate it that this is so complicated.
+    tagStore = new declare([Rest, RequestMemory])({target: tagListUrl});
+    tagStore.get('').then(function(content) { 
+        var tags = content.tags;
+
+        var tag_display_names = new Object();
+        var blessed_tags = new Array();
+        for (var tag_name in tags) {
+            var tag = tags[tag_name];
+            tag_display_names[tag_name] = tag.displayName;
+            if (tag.blessed) blessed_tags.push({ name: tag_name }); 
+        }
+        // Reorder the blessed tags according to the priority order above.
+        var new_blessed_tags = new Array();
+        for (var i=0; i<blessed_tag_priority_order.length; i++) {
+            var tag_name = blessed_tag_priority_order[i];
+            for (var j=0; j<blessed_tags.length; j++) {
+                if (blessed_tags[j].name == tag_name) {
+                    new_blessed_tags.push(blessed_tags[j]);
+                    break;
+                }
+            }
+        }
+        // Add the rest of them.
+        for (var i=0; i<blessed_tags.length; i++) {
+            if (new_blessed_tags.indexOf(blessed_tags[i]) < 0) {
+                new_blessed_tags.push(blessed_tags[i]);
+            }
+
+        }
+        blessed_tags = new_blessed_tags;
+        var blessed_tag_names = blessed_tags.map(function (obj) { return obj.name; });
+        var blessedTagStore = new Memory({ data: blessed_tags });
+
+        // Create the tag callback generators. These don't depend on the log message contents
+        // so we should be able to define them here.
+        function getTagDelCallback(tag_name, N) {
+            return function() {
+                tagUrl = tagUrlPattern.replace("000", N).replace("temp",tag_name); 
+                var tagResultDialog = new Dialog({ style: "width: 300px" }); 
+                var actionBar = domConstruct.create("div", { "class": "dijitDialogPaneActionBar" }); 
+                var tbnode = domConstruct.create("div", { 
+                        style: "margin: 0px auto 0px auto; text-align: center;" 
+                }, actionBar); 
+                var tagButton = new Button({ 
+                    label: "Ok", 
+                    onClick: function(){ 
+                    tagResultDialog.hide(); 
+                }}).placeAt(tbnode); 
+                request.del(tagUrl).then( 
+                    function(text){ 
+                        tagResultDialog.set("content", text); 
+                        domConstruct.place(actionBar, tagResultDialog.containerNode); 
+                        tagResultDialog.show(); 
+                        location.reload(true); 
+                    }, 
+                    function(error){ 
+                        tagResultDialog.set("content", "Error: " + error); 
+                        domConstruct.place(actionBar, tagResultDialog.containerNode); 
+                        tagResultDialog.show();  
+                    });
+                } 
+        }
+        
+        function getTagAddCallback(N) {
+            return function() {
+                // Create the tag result dialog.
+                var tagResultDialog = new Dialog({ style: "width: 300px" }); 
+                var actionBar = domConstruct.create("div", { "class": "dijitDialogPaneActionBar" }); 
+                var tbnode = domConstruct.create("div", { 
+                        style: "margin: 0px auto 0px auto; text-align: center;" 
+                }, actionBar); 
+                var tagButton = new Button({ 
+                    label: "Ok", 
+                    onClick: function(){ 
+                    tagResultDialog.hide();
+                    }
+                }).placeAt(tbnode); 
+
+                // Create the form
+                addTagForm = new Form();
+                var msg = "<p> Choose a tag \
+                    name from the dropdown menu or enter a new one.  If you are \
+                    creating a new tag, please also provide a display name. </p>";
+                domConstruct.create("div", {innerHTML: msg} , addTagForm.containerNode);
+
+                // Form for tagging existing log messages.
+                new ComboBox({
+                    name: "existingTagSelect",
+                    value: "",
+                    store: blessedTagStore,
+                    searchAttr: "name"
+                }).placeAt(addTagForm.containerNode);
+
+                new TextBox({
+                    name: "tagDispName",
+                }).placeAt(addTagForm.containerNode);
+
+                new Button({
+                    type: "submit",
+                    label: "OK",
+                }).placeAt(addTagForm.containerNode);
+
+                // Create the dialoge
+                addTagDialog = new Dialog({
+                    title: "Add Tag",
+                    content: addTagForm,
+                    style: "width: 300px"
+                    });
+
+                // Define the form on submit handler
+                on(addTagForm, "submit", function(evt) {
+                    evt.stopPropagation();
+                    evt.preventDefault();
+                    formData = addTagForm.getValues();
+                    var tagName = formData.existingTagSelect;
+                    var tagDispName = formData.tagDispName;
+                    var tagUrl = tagUrlPattern.replace("000", N).replace("temp",tagName);
+
+                    request.post(tagUrl, {
+                        data: {displayName: tagDispName}
+                    }).then(
+                        function(text){
+                            tagResultDialog.set("content", text);
+                            domConstruct.place(actionBar, tagResultDialog.containerNode);
+                            tagResultDialog.show();
+                            location.reload(true);
+                        },
+                        function(error){
+                            tagResultDialog.set("content", "Error: " + error);
+                            domConstruct.place(actionBar, tagResultDialog.containerNode);
+                            tagResultDialog.show(); 
+                        }
+                   );
+                   addTagDialog.hide();
+                });
+
+                // show the dialog
+                addTagDialog.show();
+            }
+        }
+
+        //----------------------------------------------------------------------------------------
+        //----------------------------------------------------------------------------------------
+        // Now that we've got the tag info, let's get the event log objects.
+        logStore = new declare([Rest, RequestMemory])({target: eventLogListUrl});
+        logStore.get('').then(function(content) {
+
+            // Pull the logs out of the JSON returned by the server.
+            var logs = content.log;
+            var Nlogs = logs.length;
+
+            // Convert the 'created' times to UTC.
+            logs = logs.map( function(obj) {
+                var server_t = moment.tz(obj.created, 'America/Chicago');
+                obj.created = server_t.clone().tz('UTC').format('LLL');
+                return obj;
+            });
+            
+            // Total up the tags present. This list will have duplicates.
+            var total_tags = new Array();
+            logs.forEach( function(log) { 
+                log.tag_names.forEach( function (tag_name) {
+                    total_tags.push(tag_name);
+                });
+            });
+            
+            // Figure out what blessed tags are present. 
+            var our_blessed_tags = blessed_tag_names.filter( function(value) {
+                return total_tags.indexOf(value) >= 0;
+            });
+
+            // If there are any blessed tags here, we'll do TitlePanes
+            if (our_blessed_tags.length > 0) {
+                // define our columns for the topical digest panes
+                var columns = [
+                    { 
+                        field: 'created', 
+                        renderHeaderCell: function(node) {
+                            timeHeaderContainer = put(node, 'div');
+                            createTimeSelect(timeHeaderContainer, 'log', 'llo');
+                            put(timeHeaderContainer, 'div', 'Log Entry Created');
+                            return timeHeaderContainer;
+                        },
+                        renderCell: function(object, value, node, options) {
+                            var server_t = moment.tz(object.created, 'America/Chicago');
+                            var t = put(node, 'time[name="time-log"]', server_t.format('LLL'));
+                            put(t, '[utc="$"]', server_t.clone().tz('UTC').format('LLL'));
+                            put(t, '[llo="$"]', server_t.format('LLL'));
+                            put(t, '[lho="$"]', server_t.clone().tz('America/Los_Angeles').format('LLL'));
+                            put(t, '[virgo="$"]', server_t.clone().tz('Europe/Rome').format('LLL'));
+                            return t;                                                       
+                        }
+                    }, 
+                    { field: 'issuer', label: 'Submitter', get: function(obj) { return obj.issuer.display_name; } },
+                    // Sometimes the comment contains HTML, so we just want to return whatever it has.
+                    // This is where the link with the filename goes. Also the view in skymapViewer button
+                    { 
+                        field: 'comment', 
+                        label: 'Comment', 
+                        renderCell: function(object, value, node, options) {
+                            var commentDiv = put(node, 'div');
+                            // Putting this in the innerHTML allows users to create comments in HTML.
+                            // Whereas, inserting the comment with the put selector escapes it.
+                            commentDiv.innerHTML += value + ' ';
+                            if (object.filename) put(commentDiv, 'a[href=$]', object.file, object.filename);
+                            if (object.filename == 'skymap.json') {
+                                var svButton = put(commentDiv, 'button.modButtonClass#sV_button', 'View in SkymapViewer!');
+                                put(svButton, '[type="button"][data-dojo-type="dijit/form/Button"]');
+                                put(svButton, '[style="float: right"]');
+                            }
+                            return commentDiv;
+                        }
+                    },
+
+                ]; 
+
+                // Create the topical digest title panes
+                for (i=0; i<our_blessed_tags.length; i++) {
+                    var tag_name = our_blessed_tags[i];
+                    // First filter the log messages based on whether they have this blessed tag.
+                    var tagLogs = logs.filter( function(obj) { 
+                        // XXX Not sure why this simpler filter didn't work.
+                        // return obj.tag_names.indexOf(tag_name) > 0;
+                        for (var k=0; k<obj.tag_names.length; k++) {
+                            if (obj.tag_names[k]==tag_name) return true;
+                        }
+                        return false;  
+                    });
+
+                    // Next filter the remaining log messages based on whether or not images are present.
+                    var imgLogs = tagLogs.filter( function(obj) { return hasImage(obj); });
+                    var noImgLogs = tagLogs.filter ( function(obj) { return !hasImage(obj); }); 
+
+                    // Create the title pane with a placeholder div
+                    var pane_contents_id = tag_name + '_pane';
+                    var tp = new TitlePane({ 
+                        title: tag_display_names[tag_name],
+                        content: '<div id="' + pane_contents_id + '"></div>',
+                        open: true
+                    });
+                    logContentDiv.appendChild(tp.domNode);
+                    paneContentsNode = dom.byId(pane_contents_id);
+
+                    // Handle the log messages with images by putting them in little box.
+                    if (imgLogs.length) {
+                        var figContainerId = tag_name + '_figure_container';
+                        var figDiv = put(paneContentsNode, 'div#' + figContainerId);
+                        var figRow = put(figDiv, 'table.figure_container tr');
+                        for (j=0; j<imgLogs.length; j++) {
+                            var log = imgLogs[j];
+                            var figTabInner = put(figRow, 'td table.figures'); 
+                            var figA = put(figTabInner, 'tr.figrow img[height="180"][src=$]', log.file); 
+                            new dojox.image.LightboxNano({href: log.file}, figA); 
+                            var figComment = put(figTabInner, 'tr td');
+                            figComment.innerHTML = log.comment;
+                            figComment.innerHTML += ' <a href="' + log.file + '">' + log.filename + '.</a> ';
+                            figComment.innerHTML += 'Submitted by ' + log.issuer.display_name + ' on ' + log.created;
+                        }
+                        // Put the figures in a scrolling pane in case there are too many to display horizontally
+                        var sp = new dojox.layout.ScrollPane({ orientation: "horizontal", style: "overflow: hidden;" },
+                            figContainerId);
+
+                    }
+
+                    // Handle the log messages without images by putting them in a grid.
+                    if (noImgLogs.length) {
+                        var gridNode = put(paneContentsNode, 'div#' + pane_contents_id + '-grid')
+                        var grid = new declare([Grid, DijitRegistry])({
+                            columns: columns,
+                            className: 'dgrid-autoheight',
+                            // Overriding renderRow here to add an extra class to the row. This is for styling.
+                            renderRow: function(object,options) {
+                                return put('div.supergrid-row', Grid.prototype.renderRow.call(this,object,options));
+                            }
+                        }, gridNode);
+                        grid.renderArray(noImgLogs);
+                        grid.set("sort", 'N', descending=true);
+                    }
+
+                }
+
+                // Create the full event-log title pane
+                var columns = [
+                    { field: 'N', label: 'No.' },
+                    { 
+                        field: 'created', 
+                        renderHeaderCell: function(node) {
+                            timeHeaderContainer = put(node, 'div');
+                            var ts = createTimeSelect(timeHeaderContainer, 'audit-log', 'llo');
+                            put(timeHeaderContainer, 'div', 'Log Entry Created');
+                            // XXX Not sure how to get this to do the right thing.
+                            return timeHeaderContainer; 
+                            //return ts;
+                        },
+                        renderCell: function(object, value, node, options) {
+                            var server_t = moment.tz(object.created, 'America/Chicago');
+                            var t = put(node, 'time[name="time-audit-log"]', server_t.format('LLL'));
+                            put(t, '[utc="$"]', server_t.clone().tz('UTC').format('LLL'));
+                            put(t, '[llo="$"]', server_t.format('LLL'));
+                            put(t, '[lho="$"]', server_t.clone().tz('America/Los_Angeles').format('LLL'));
+                            put(t, '[virgo="$"]', server_t.clone().tz('Europe/Rome').format('LLL'));
+                            return t;                                                       
+                        }
+                    }, 
+{ field: 'issuer', label: 'Submitter', get: function(obj) { return obj.issuer.display_name; } },
+                    // Sometimes the comment contains HTML, so we just want to return whatever it has.
+                    // This is where the link with the filename goes. Also the view in skymapViewer button
+                    { 
+                        field: 'comment', 
+                        label: 'Comment', 
+                        renderCell: function(object, value, node, options) {
+                            commentDiv = put(node, 'div');
+                            // Putting this in the innerHTML allows users to create comments in HTML.
+                            // Whereas, inserting the comment with the put selector escapes it.
+                            commentDiv.innerHTML += value + ' ';
+                            if (object.filename) put(commentDiv, 'a[href=$]', object.file, object.filename);
+                            // Create tag-related features
+                            var tagButtonContainer = put(commentDiv, 'div.tagButtonContainerClass');
+                            // For each existing tag on a log message, we will make a little widget
+                            // to delete it.
+                            object.tag_names.forEach( function(tag_name) {
+                                var delDiv = put(tagButtonContainer, 'div.tagDelButtonDivClass');
+                                var del_button_id = "del_button_" + object.N + '_' + tag_name;
+                                var delButton = put(delDiv, 'button.modButtonClass.left#' + del_button_id);
+                                put(delButton, '[data-dojo-type="dijit/form/Button"]');
+                                // It looks like an 'x', so people will know that this means 'delete'
+                                delButton.innerHTML = '&times;';
+                                var labButton = put(delDiv, 'button.modButtonClass.right', tag_name); 
+                            }); 
+                            // Create a button for adding a new tag.
+                            var add_button_id = 'addtag_' + object.N;
+                            var addButton = put(tagButtonContainer, 'button.modButtonClass#' + add_button_id);
+                            put(addButton, '[data-dojo-type="dijit/form/Button"]');
+                            // Put a plus sign in there.
+                            addButton.innerHTML = '&#43;';
+
+                            // The div is finally ready. Return it.
+                            return commentDiv;
+                        }
+                    },
+                    {
+                        field: 'image',
+                        label: ' ',
+                        renderCell: function(object, value, node, options) {
+                            if (value) {
+                                imgNode = put(node, 'img[height="60"][src="$"]', value);
+                                return new dojox.image.LightboxNano({ href: value }, imgNode); 
+                            }
+                        },
+                        get: function(object) { 
+                            if (hasImage(object)) {
+                                return object.file;
+                            } else {
+                                return null;
+                            }
+                        },
+                    }
+                ]; 
+
+                var pane_contents_id = 'full_log_pane_div';
+                
+                // Create the title pane with a placeholder div
+                var tp = new TitlePane({ 
+                    title: 'Full Event Log',
+                    content: '<div id="' + pane_contents_id + '"></div>',
+                    open: false
+                });
+                logContentDiv.appendChild(tp.domNode);
+
+                var grid = new declare([Grid, DijitRegistry])({
+                    minRowsPerPage: Nlogs,
+                    columns: columns,
+                    className: 'dgrid-autoheight',
+                    renderRow: function(object,options) {
+                        return put('div.supergrid-row', Grid.prototype.renderRow.call(this,object,options));
+                    }
+                }, pane_contents_id);
+                grid.renderArray(logs);
+                grid.set("sort", 'N', descending=true);
+
+            } else {
+                // Not doing title panes, just put up the usual log message section.
+                // Will have the full eventlog section. Same as above, except that it 
+                // won't be in a title pane. What is the best way to do this.
+
+                var columns = [
+                    { field: 'N', label: 'No.' },
+                    { field: 'created', label: 'Log Entry Created (UTC)' }, 
+                    { field: 'issuer', label: 'Submitter', get: function(obj) { return obj.issuer.display_name; } },
+                    // Sometimes the comment contains HTML, so we just want to return whatever it has.
+                    // This is where the link with the filename goes. Also the view in skymapViewer button
+                    { 
+                        field: 'comment', 
+                        label: 'Comment', 
+                        renderCell: function(object, value, node, options) {
+                            commentDiv = put(node, 'div');
+                            // Putting this in the innerHTML allows users to create comments in HTML.
+                            // Whereas, inserting the comment with the put selector escapes it.
+                            commentDiv.innerHTML += value + ' ';
+                            if (object.filename) put(commentDiv, 'a[href=$]', object.file, object.filename);
+                            // Create tag-related features
+                            var tagButtonContainer = put(commentDiv, 'div.tagButtonContainerClass');
+                            // For each existing tag on a log message, we will make a little widget
+                            // to delete it.
+                            object.tag_names.forEach( function(tag_name) {
+                                var delDiv = put(tagButtonContainer, 'div.tagDelButtonDivClass');
+                                var del_button_id = "del_button_" + object.N + '_' + tag_name;
+                                var delButton = put(delDiv, 'button.modButtonClass.left#' + del_button_id);
+                                put(delButton, '[data-dojo-type="dijit/form/Button"]');
+                                // It looks like an 'x', so people will know that this means 'delete'
+                                delButton.innerHTML = '&times;';
+                                var labButton = put(delDiv, 'button.modButtonClass.right', tag_name); 
+                            }); 
+                            // Create a button for adding a new tag.
+                            var add_button_id = 'addtag_' + object.N;
+                            var addButton = put(tagButtonContainer, 'button.modButtonClass#' + add_button_id);
+                            put(addButton, '[data-dojo-type="dijit/form/Button"]');
+                            // Put a plus sign in there.
+                            addButton.innerHTML = '&#43;';
+
+                            // The div is finally ready. Return it.
+                            return commentDiv;
+                        }
+                    },
+                    {
+                        field: 'image',
+                        label: ' ',
+                        renderCell: function(object, value, node, options) {
+                            if (value) {
+                                imgNode = put(node, 'a[href="$"]', value);
+                                put(imgNode, '[dojoType="dojox.image.LightboxNano"]');
+                                put(imgNode, 'img[height="60"][src="$"]', value);
+                                return imgNode;
+                            }
+                        },
+                        get: function(object) { 
+                            if (hasImage(object)) {
+                                return object.file;
+                            } else {
+                                return null;
+                            }
+                        },
+                    }
+                ]; 
+
+                var grid = new declare([Grid, DijitRegistry])({
+                    minRowsPerPage: Nlogs,
+                    columns: columns,
+                    className: 'dgrid-autoheight',
+                    renderRow: function(object,options) {
+                        return put('div.supergrid-row', Grid.prototype.renderRow.call(this,object,options));
+                    }
+                }, logContentDiv);
+                grid.renderArray(logs);
+                grid.set("sort", 'N', descending=true);
+
+            }
+
+            //-------------------------------------------------------------------
+            // Now that the annotations section has been added to the dom, we
+            // can work on its functionality.
+            //-------------------------------------------------------------------
+            var logtitle = dom.byId("logmessagetitle");
+            var logtext = dom.byId("newlogtext");
+
+            var editor_div = dom.byId("editor");
+            var preview_div = dom.byId("previewer");
+
+            // A pane holder for the form that will tag new log messages.
+            // I need it up here because we're going to integrate it with the
+            // editor components.
+            /* 
+            dojo.style(preview_div, { 'display':'none'});
+            dojo.style(editor_div, { 'display':'none'});
+
+            var button_element = dojo.create('button');
+            dojo.place(button_element, logtitle, "right");
+            var button = new Button({
+                label: "Add Log Entry",
+                state: "add",
+                onClick: function(){
+                    if (this.state == 'add') {
+                        dojo.style(editor_div, {'display':'block'});
+                        button.set('label', "Cancel Log Entry");
+                        button.set('state', 'cancel');
+                        editor.focus();
+                    }
+                    else {
+                        dojo.style(editor_div, {'display':'none'});
+                        dojo.style(preview_div, {'display':'none'});
+                        button.set('label', "Add Log Entry");
+                        button.set('state', 'add');
+                        editor.set('value','');
+                    }
+                },
+            }, button_element); */
+
+            var savebutton = new Save({
+                    url: eventLogSaveUrl,
+                    onSuccess: function (resp, ioargs) {
+                        //this.inherited(resp, ioargs);
+                        this.button.set("disabled", false);
+                        location.reload(true);
+                    },
+                    onError: function (error, ioargs) {
+                        //this.inherited(error, ioargs);
+                        this.button.set("disabled", false);
+                        alert("o hai " + error);
+                    },
+                    save: function(postdata) {
+                    var newTagName = "analyst_comments";
+                    var postArgs = {
+                                url: this.url,
+                                content: { comment: postdata, tagname: newTagName },
+                                handleAs: "json"
+                        };
+                        this.button.set("disabled", true);
+                        var deferred = dojo.xhrPost(postArgs);
+                        deferred.addCallback(dojo.hitch(this, this.onSuccess));
+                        deferred.addErrback(dojo.hitch(this, this.onError));
+                        // Call whatever function is necessary to attach the tag
+                        // or add to the postdata and handle in the django view?
+                    }
+            });
+
+            var previewbutton = new Preview({
+                _preview: function(){
+                        var content = this.editor.get("value");
+                        preview_div.innerHTML = editor.get('value');
+                        dojo.style(preview_div, {
+                            'display':'block',
+                            'border': ".2em solid #900",
+                            'padding': '10px'
+                        });
+                        MathJax.Hub.Queue(["Typeset",MathJax.Hub, preview_div]);
+                    }
+            });
+
+            var editor = new Editor({
+                 extraPlugins : ['hiliteColor','|','createLink',
+                                 'insertImage','fullscreen','viewsource','newpage', '|', previewbutton, savebutton] 
+            }, editor_div);
+            editor.startup();
+
+            // For each log, attach callbacks for the tag delete and add buttons.
+            logs.forEach( function(log) {
+                // Attach a delete callback for each tag.
+                log.tag_names.forEach( function(tag_name) {
+                    var del_button_id = "del_button_" + log.N + '_' + tag_name;
+                    on(dom.byId(del_button_id), "click", getTagDelCallback(tag_name, log.N));
+                    new Tooltip({ connectId: del_button_id, label: "delete this tag" });
+                });
+
+                // Attach an add tag callback for each log.
+                var add_button_id = 'addtag_' + log.N;
+                on(dom.byId(add_button_id), "click", getTagAddCallback(log.N));
+                new Tooltip({ connectId: add_button_id, label: "tag this log message" });
+
+            });                 
+
+            // Handle the post to skymapViewer button.
+            // Tacking on an invisible div with a form inside.
+            sVdiv = put(annotationsDiv, 'div#sV_form_div[style="display: none"]');
+            sVform = put(sVdiv, 'form#sV_form[method="post"][action="$"]', 
+                encodeURI(skymapViewerUrl));
+            put(sVform, 'input[type="hidden"][name="json"]');
+            put(sVform, 'input[type="hidden"][name="embb"]');
+            put(sVform, 'input[type="submit"][value="View in skymapViewer!"]');
+            
+            var sV_button = dom.byId("sV_button");
+            if (sV_button) {
+                on(sV_button, "click", function() {
+                    console.log("You clicked the button!");
+                    var embblog_json_url = embbEventLogListUrl;
+                    var embblog_json;
+                    dojo.xhrGet({
+                        url: embblog_json_url + "?format=json",
+                        async: true,
+                        load: function(embblog_json) {
+
+                        // fetch JSON content.
+                        dojo.xhrGet({
+                            url: skymapJsonUrl,
+                            load: function(result) { 
+                                // Find the form and set its value to the appropriate JSON        
+                                sV_form = dom.byId("sV_form");
+                                // Shove the skymap.json contents into the value for the second form field.
+                                sV_form.elements[1].value = result; 
+                                sV_form.elements[2].value = embblog_json; 
+                                // Submit the form, which takes the user to the skymapViewer server.
+                                sV_form.submit();
+                            }
+                        });    // end of inside ajax
+                        }
+                    });        // end of outside ajax
+                });
+            }
+
+
+        });
+    });
+
+
+});
+
diff --git a/templates/gracedb/neighbors_frag.html b/templates/gracedb/neighbors_frag.html
index d27c77080c187b7e3ac37323a8ec4582b985bd9f..7b2df91b3706aab404958d9d29c927998fc79992 100644
--- a/templates/gracedb/neighbors_frag.html
+++ b/templates/gracedb/neighbors_frag.html
@@ -1,11 +1,11 @@
 {% load timeutil %}
 {% load scientific %}
 <div id="neighbors" class="content-area">
-<h3>Neighbors &nbsp;
+<h2>Neighbors &nbsp;
     <span data-dojo-type="dijit/InlineEditBox"
         data-dojo-props="editor:'dijit/form/TextBox', editorParams:{constraints:{places:0} }" width="100px" 
         title="window"
-        onchange="refresh_neighbors(this.value)">{{neighbor_delta}}</span></h3>
+        onchange="refresh_neighbors(this.value)">{{neighbor_delta}}</span></h2>
 
 {% if nearby %}
 
@@ -18,15 +18,15 @@
             <th>Search</th>
             <th>Instruments</th>
             <th>
-                {{ "ngps"|timeselect:"gps" }}
-                Event Time
+                <div id="neighbors_event_ts"></div>
+                <div> Event Time </div>
             </th>
             <th>&Delta;gpstime</th>
             <th>FAR (Hz)</th>
             <th>Links</th>
             <th>
-                {{"ncreated"|timeselect:"utc" }}
-                Submitted
+                <div id="neighbors_created_ts"></div>
+                <div> Submitted </div>
             </th>
     </tr>
     {% for delta, object in nearby %}