diff --git a/gracedb/admin.py b/gracedb/admin.py
index d75cf54b3fffaf155b72b9197271261eef4595a5..4dbf01499602dbfa0b1c8f1ecea8ebf41b52b5c6 100644
--- a/gracedb/admin.py
+++ b/gracedb/admin.py
@@ -1,5 +1,5 @@
 
-from models import Event, EventLog, Group
+from models import Event, EventLog, EMBBEventLog, EMGroup, Group
 from models import Label, Labelling, Tag
 from django.contrib import admin
 
@@ -18,6 +18,11 @@ class EventLogAdmin(admin.ModelAdmin):
     list_display = [ 'event', 'issuer', 'filename', 'comment' ]
     search_fields = [ 'event__id', 'issuer__name', 'filename', 'comment']
 
+#class EMBBEventLogAdmin(admin.ModelAdmin):
+#    list_display = [ 'event' ]
+#    search_fields = [ 'event__id']
+#
+
 class LabellingAdmin(admin.ModelAdmin):
     list_display = [ 'event', 'label', 'creator' ]
     search_fields = [ 'event__id', 'label__name', 'creator__name' ]
@@ -28,6 +33,8 @@ class TagAdmin(admin.ModelAdmin):
 
 admin.site.register(Event, EventAdmin)
 admin.site.register(EventLog, EventLogAdmin)
+admin.site.register(EMBBEventLog)
+admin.site.register(EMGroup)
 admin.site.register(Group)
 admin.site.register(Label, LabelAdmin)
 admin.site.register(Labelling, LabellingAdmin)
diff --git a/gracedb/api.py b/gracedb/api.py
index ce613ea18991f77fa279c69cd4ee8f5a2a468c44..8e1d5612e944712bcadb5e3014e7f6250ac7ff56 100644
--- a/gracedb/api.py
+++ b/gracedb/api.py
@@ -7,6 +7,7 @@ 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
 
 import json
 
@@ -14,9 +15,12 @@ from django.contrib.auth.models import User, Permission
 from django.contrib.auth.models import Group as AuthGroup
 from django.contrib.contenttypes.models import ContentType
 from gracedb.models import Event, Group, Search, Pipeline, EventLog, Tag
+from gracedb.models import EMGroup, EMBBEventLog, EMSPECTRUM
 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 translator import handle_uploaded_data
 from forms import CreateEventForm
 from permission_utils import user_has_perm, filter_events_for_user
@@ -522,6 +526,7 @@ def eventToDict(event, columns=None, request=None):
     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),
@@ -1082,6 +1087,118 @@ class EventLogDetail(APIView):
     def get(self, request, event, eventlog):
         return Response(eventLogToDict(eventlog, request=request))
 
+
+#==================================================================
+# 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,
+                "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
+
+    POST param 'message'
+    """
+    authentication_classes = (LigoAuthentication,)
+    permission_classes = (IsAuthenticated,)
+
+    def get(self, request, graceid):
+        try:
+            event = Event.getByGraceid(graceid)
+        except Event.DoesNotExist:
+            # XXX Real error message.
+            return Response("Event does not exist.",
+                    status=status.HTTP_404_NOT_FOUND)
+
+        eel_set = event.embbeventlog_set.order_by("created","N")
+        count = eel_set.count()
+
+        eel = [ embbEventLogToDict(eel, request)
+                for eel in eel_set.iterator() ]
+
+        rv = {
+                'start': 0,
+                'numRows' : count,
+                'links' : {
+                    'self' : request.build_absolute_uri(),
+                    'first' : request.build_absolute_uri(),
+                    'last' : request.build_absolute_uri(),
+                    },
+                'embblog' : eel,
+             }
+        return Response(rv)
+
+    def post(self, request, graceid):
+        try:
+            event = Event.getByGraceid(graceid)
+        except Event.DoesNotExist:
+            return Response("Event Not Found",
+                    status=status.HTTP_404_NOT_FOUND)
+
+        # Now create the EEL
+        try:
+            eel = create_eel(request.DATA, event, request.user)
+        except ValueError, e:
+            return Response("str(e)", status=status.HTTP_400_BAD_REQUEST)
+        except IntegrityError, e:
+            return Response("Failed to save EMBB entry: %s" % str(e),
+                    status=status.HTTP_503_SERVICE_UNAVAILABLE)
+        except Exception, e:
+            return Response("Problem creating EEL: %s" % str(e), 
+                status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+        rv = embbEventLogToDict(eel, request=request)
+        response = Response(rv, status=status.HTTP_201_CREATED)
+        response['Location'] = rv['self']
+
+        # Issue alert.
+        description = "New EMBB log entry."
+        issueAlertForUpdate(event, description, doxmpp=True)
+
+        return response
+
+class EMBBEventLogDetail(APIView):
+    authentication_classes = (LigoAuthentication,)
+    permission_classes = (IsAuthenticated,)
+
+    def get(self, request, graceid, n):
+        try:
+            event = Event.getByGraceid(graceid)
+        except Event.DoesNotExist:
+            return Response("Event Not Found",
+                    status=status.HTTP_404_NOT_FOUND)
+        try:
+            rv = event.embbeventlog_set.filter(N=n)[0]
+        except:
+            return Response("Log Message Not Found",
+                    status=status.HTTP_404_NOT_FOUND)
+
+        return Response(embbEventLogToDict(rv, request=request))
+
 #==================================================================
 # Tags
 
@@ -1467,6 +1584,8 @@ class GracedbRoot(APIView):
         vo_detail = vo_detail.replace("G1200", "{graceid}")
         log = reverse("eventlog-list", args=["G1200"], request=request)
         log = log.replace("G1200", "{graceid}")
+        embb = reverse("embbeventlog-list", args=["G1200"], request=request)
+        embb = embb.replace("G1200", "{graceid}")
 
         files = reverse("files", args=["G1200", "filename"], request=request)
         files = files.replace("G1200", "{graceid}")
@@ -1495,6 +1614,7 @@ class GracedbRoot(APIView):
                 "event-detail-template" : detail,
                 "event-vo-detail-template" : vo_detail,
                 "event-log-template" : log,
+                "embb-event-log-template" : embb,
                 "event-label-template" : labels,
                 "files-template" : files,
                 "filemeta-template" : filemeta,
@@ -1528,6 +1648,10 @@ class GracedbRoot(APIView):
                         ("HWINJ", "HardwareInjection"),
                     ) 
                 ),
+            "em-groups"  : [g.name for g in EMGroup.objects.all()],
+            "wavebands"      : dict(EMSPECTRUM),
+            "eel-statuses"   : dict(EMBBEventLog.EEL_STATUS_CHOICES),
+            "obs-statuses"   : dict(EMBBEventLog.OBS_STATUS_CHOICES),
            })
 
 ##################################################################
diff --git a/gracedb/fixtures/initial_emgroups.json b/gracedb/fixtures/initial_emgroups.json
new file mode 100644
index 0000000000000000000000000000000000000000..5854b1d36f7a1da766045e85a52f870c82ab7fd5
--- /dev/null
+++ b/gracedb/fixtures/initial_emgroups.json
@@ -0,0 +1,163 @@
+[
+    {
+        "pk": 1, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "Apertif-EVN"
+        }
+    }, 
+    {
+        "pk": 2, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "ARI LJMU"
+        }
+    }, 
+    {
+        "pk": 3, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "ATLAS"
+        }
+    }, 
+    {
+        "pk": 4, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "CRTS"
+        }
+    }, 
+    {
+        "pk": 5, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "FIGARO"
+        }
+    }, 
+    {
+        "pk": 6, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "FRBSG"
+        }
+    }, 
+    {
+        "pk": 7, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "GOTO"
+        }
+    }, 
+    {
+        "pk": 8, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "GWU LSC Group"
+        }
+    }, 
+    {
+        "pk": 9, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "H.E.S.S."
+        }
+    }, 
+    {
+        "pk": 10, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "HXMT"
+        }
+    }, 
+    {
+        "pk": 11, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "INAF"
+        }
+    }, 
+    {
+        "pk": 12, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "IUCAA"
+        }
+    }, 
+    {
+        "pk": 13, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "LCOGT"
+        }
+    }, 
+    {
+        "pk": 14, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "LV-EM Followup"
+        }
+    }, 
+    {
+        "pk": 15, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "MAGIC"
+        }
+    }, 
+    {
+        "pk": 16, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "Pan-STARRS"
+        }
+    }, 
+    {
+        "pk": 17, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "PIRATE"
+        }
+    }, 
+    {
+        "pk": 18, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "RoboPol"
+        }
+    }, 
+    {
+        "pk": 19, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "Swift"
+        }
+    }, 
+    {
+        "pk": 20, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "TOROS"
+        }
+    }, 
+    {
+        "pk": 21, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "VERITAS"
+        }
+    }, 
+    {
+        "pk": 22, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "ZTF"
+        }
+    }, 
+    {
+        "pk": 23, 
+        "model": "gracedb.emgroup", 
+        "fields": {
+            "name": "Test"
+        }
+    }
+]
\ No newline at end of file
diff --git a/gracedb/management/commands/ingest_email.py b/gracedb/management/commands/ingest_email.py
new file mode 100644
index 0000000000000000000000000000000000000000..ab3f449ed1ca513e3fd38963ce5273dddc8f5274
--- /dev/null
+++ b/gracedb/management/commands/ingest_email.py
@@ -0,0 +1,303 @@
+from django.core.management.base import BaseCommand
+from gracedb.models import Event, EMBBEventLog
+from gracedb.models import EMGroup
+from ligoauth.models import AlternateEmail
+from django.conf import settings
+from django.contrib.auth.models import User
+import json
+import re
+import smtplib
+from email.mime.text import MIMEText
+from email import message_from_string
+from binascii import a2b_qp, a2b_base64
+wierdchars = re.compile(u'[\U00010000-\U0010ffff]')
+
+USER_NOT_FOUND_MESSAGE = """
+
+
+No GraceDB user was found matching email: %s
+
+To proceed, the following actions are recommended:
+
+For LVC users: Please re-send your EEL using your @LIGO.org mail 
+    forwarding address or a LIGO alternate mail address (i.e., an 
+    address from which you can send message to LIGO mailing lists).
+    
+For non-LVC users: If you have not already done so, please log in 
+    to the GraceDB web interface at 
+
+    https://gracedb.ligo.org
+
+    This will have the effect of caching your email address, and
+    then you can try re-sending your EEL message. We apologize for 
+    the inconvenience. 
+
+    Also, please use the email address with which you registered
+    at gw-astronomy.org. If you need to use an alternate email 
+    address, we can add it to the system manually. Just send a 
+    message to uwm-help@ligo.org.
+
+
+"""
+
+def sendResponse(to, subject, message):
+    print message
+    msg = MIMEText(message)
+    # Allow the 'to' argument to contain either a list (for multiple recipients)
+    # or a string (for a single recipient)
+    if isinstance(to, list):
+        msg['To'] = ','.join(to)
+        to_list = to
+    else:
+        msg['To'] = to
+        to_list = [to]
+    # Remove any addresses to ignore
+    to_list = list(set(to_list) - set(settings.EMBB_IGNORE_ADDRESSES))
+    if not len(to_list):
+        return None
+    from_address = settings.EMBB_MAIL_ADDRESS 
+    msg['From'] = from_address
+    msg['Subject'] = subject
+    s = smtplib.SMTP(settings.EMBB_SMTP_SERVER)
+    s.sendmail(from_address, to_list, msg.as_string())
+    s.quit()
+    return None
+
+# 
+# Given a string and an encoding, return a unicode string with the
+# 6, 9, 66, and 99 characters replaced.
+#
+def get_unicode_and_fix_quotes(s, encoding):
+    rv = u''
+    for char in s:
+        if encoding:
+            uchar = unicode(char, encoding)
+        else:
+            uchar = unicode(char)
+        if ord(uchar) > 127:
+            # Fix 6 and 9
+            if uchar == u'\u2018' or uchar == u'\u2019':
+                uchar = u"'"
+
+            # Fix 66 and 99
+            if uchar == u'\u201c' or uchar == u'\u201d':
+                uchar = u'"'
+        rv += uchar
+    return rv
+
+class Command(BaseCommand):
+    help = "I am the email ingester!"
+
+    def handle(self, *args, **options):
+        self.transcript = 'Started email ingester\n'
+
+        # The file is understood to contain the raw contents of the email.
+        filename = args[0]
+        try:
+            f = open(filename, 'r')
+            data = f.read()
+            f.close()
+            self.transcript += 'Got email with %d characters incl headers\n' % len(data)
+        except Exception, e:
+            self.transcript += 'Could not fetch email file\n' +  str(e)
+            return sendResponse(settings.EMBB_MAIL_ADMINS, 'embb submission', self.transcript)
+
+        # Try to convert to email object.
+        email_obj = message_from_string(data)
+
+        # Parse the email and find out who it's from.
+        from_string = email_obj['from']
+        try:
+            # XXX Hacky way to get the stuff between the '<' and the '>'
+            from_address = from_string.split('<')[1].split('>')[0]
+        except:
+            try:
+                from_address = email_obj._unixfrom.split()[1]
+            except Exception, e:
+                self.transcript += 'Problem parsing out sender address\n' + str(e)
+                return sendResponse(settings.EMBB_MAIL_ADMINS, 'embb submission failure', self.transcript)
+
+        # find the submitter
+        # Look up the sender's address.
+        user = None
+        try:
+            user = User.objects.get(email=from_address)
+        except:
+            pass
+
+        try: 
+            alt_email = AlternateEmail.objects.get(email=from_address)
+            user = alt_email.user
+            self.transcript += 'Found submitter %s\n' % user.username
+        except:
+            pass
+
+        if not user:
+            self.transcript += USER_NOT_FOUND_MESSAGE % from_address
+            return sendResponse(from_address, 'gracedb user not found', self.transcript)
+
+        # Get the subject of the email. Use it in the reply
+        subject = email_obj.get('Subject', '')
+        reply_subject = 'Re: ' + subject
+    
+        # Now we want to get the contents of the email.
+        # Get the payload and encoding.
+        encoding = None
+        if email_obj.is_multipart():
+            # Let's look for a plain text part.  If not, throw an error.
+            msg = None
+            for part in email_obj.get_payload():
+                if part.get_content_type() == 'text/plain':
+                    content_transfer_encoding = part.get('Content-Transfer-Encoding', None)
+                    msg = part.get_payload()
+                    try:
+                        encoding = part.get_content_charset()  
+                    except:
+                        pass
+            if not msg:
+                self.transcript += 'We cannot parse your email because it is not plain text.\n'
+                self.transcript += 'Please send plain text emails instead of just HTML.\n'
+                return sendResponse(from_address, reply_subject, self.transcript)
+        else:
+            # not multipart. 
+            msg = email_obj.get_payload()
+            content_transfer_encoding = email_obj.get('Content-Transfer-Encoding', None)
+            try:
+                encoding = email_obj.get_content_charset()
+            except:
+                pass
+
+        if content_transfer_encoding:
+            if content_transfer_encoding == 'quoted-printable':
+                msg = a2b_qp(msg)
+            elif content_transfer_encoding == 'base64':
+                msg = a2b_base64(msg)
+            else:
+                self.transcript += 'Your message uses an unsupported content transfer encoding.\n'
+                self.transcript += 'Please use quoted-printable or base64.\n'
+                return sendResponse(from_address, reply_subject, self.transcript)
+
+        # Get a unicode string and fix any quotation marks.
+        msg = get_unicode_and_fix_quotes(msg, encoding)
+
+        # Get the body of the message and convert to lines.
+        lines = msg.split('\n')
+
+        comment = ''
+        dict = {}
+        p = re.compile('[A-Za-z-]+:')
+        inkey = 0
+        key = ''
+    
+        for line in lines:
+            if len(line) > 0:
+                if inkey and line[0].isspace():   # initial space implies continuation
+                    dict[key] += line
+                    continue
+            m = p.match(line)
+            if m:
+                key = line[m.start():m.end()-1]
+                val = line[m.end():].strip()
+                if dict.has_key(key):            # same key again just makes a new line in val
+                    dict[key] += '\n' + val
+                else:
+                    dict[key] = val
+                inkey = 1
+            else:
+                comment += line
+                inkey = 0
+
+        self.transcript += 'Found %d keys in email\n' % len(dict.keys())
+        
+#        if not dict.has_key('JSON'):
+#            self.transcript += 'Error: no JSON key'
+#            return sendResponse(from_address, dict['SUBJECT'], self.transcript)
+        
+        def getpop(dict, key, default):
+            if dict.has_key(key):
+                return dict.pop(key)
+            else:
+                return default
+            
+        
+# look for the JSON field at the end of the mail
+        extra_dict = {}
+        if dict.has_key('JSON'):
+            try:
+                extra_dict = json.loads(dict['JSON'])
+                self.transcript += 'Found %d keys in JSON\n' % len(extra_dict.keys())
+            except Exception, e:
+                self.transcript += 'Error: Cannot parse JSON: %s\n' % dict['JSON']
+                self.transcript += str(e)
+                return sendResponse(from_address, reply_subject, self.transcript)
+
+# look for PARAM fields of the form
+# PARAM:  apple=34.2
+        if dict.has_key('PARAM'):
+            lines = dict['PARAM'].split('\n')
+            for line in lines:
+                tok = line.split('=')
+                if len(tok) == 2:
+                    key = tok[0].strip()
+                    val = tok[1].strip()
+                    extra_dict[key] = val
+
+# gotta get the Graceid!
+        graceid = getpop(extra_dict, 'graceid', None)   # try to get the graceid from the extra_dict
+        if not graceid and dict.has_key('SUBJECT'):
+            tok = dict['SUBJECT'].split(':')    # look for a second colon in the SUBJECT line
+            graceid = tok[0].strip()
+
+        if not graceid:
+            self.transcript += 'Cannot locate GraceID in SUBJECT, JSON, or PARAM data'
+            return sendResponse(from_address, reply_subject, self.transcript)
+
+        try:
+            event = Event.getByGraceid(graceid)
+            self.transcript += 'Found Graceid %s\n' % graceid
+        except Exception, e:
+            self.transcript += 'Error: Cannot find Graceid %s\n' % graceid
+            self.transcript += str(e)
+            return sendResponse(from_address, reply_subject, self.transcript)
+
+        # create a log entry
+        eel = EMBBEventLog(event=event)
+        eel.event = event
+        eel.submitter = user
+
+        # Assign a group name
+        group_name = getpop(extra_dict, 'group', None)
+        try:
+            group = EMGroup.objects.get(name=group_name)
+            eel.group = group
+            self.transcript += 'Found EMGroup %s\n' % group_name
+        except Exception, e:
+            self.transcript += 'Error: Cannot find EMGroup =%s=\n' % group_name
+            self.transcript += str(e)
+            return sendResponse(from_address, reply_subject, self.transcript)
+
+        eel.eel_status = getpop(extra_dict, 'eel_status', 'FO')
+        eel.obs_status = getpop(extra_dict, 'obs_status', 'TE')
+        eel.footprintID = getpop(extra_dict, 'footprintID', '')
+        eel.waveband = getpop(extra_dict, 'waveband', 'em.opt')
+        eel.ra = getpop(extra_dict, 'ra', 0.0)
+        eel.dec = getpop(extra_dict, 'dec', 0.0)
+        eel.raWidth = getpop(extra_dict, 'raWidth', 0.0)
+        eel.decWidth = getpop(extra_dict, 'decWidth', 0.0)
+        eel.gpstime = getpop(extra_dict, 'gpstime', 0)
+        eel.duration = getpop(extra_dict, 'duration', 0)
+        eel.extra_info_dict = json.dumps(extra_dict)
+        self.transcript += 'Extra_info_dict is %s\n' % eel.extra_info_dict
+    
+#        eel.comment = 'hello'    #   wierdchars.sub(u'', comment)
+        eel.comment = comment
+
+        try:
+            eel.save()
+        except Exception as e:
+            self.transcript += 'Error: Could not save EEL\n'
+            self.transcript += str(e)
+            return sendResponse(from_address, reply_subject, self.transcript)
+
+        self.transcript += 'EEL is successfully saved!'
+        return sendResponse(from_address, reply_subject, self.transcript)
diff --git a/gracedb/migrations/0019_auto__add_emgroup__add_embbeventlog__add_unique_embbeventlog_event_N.py b/gracedb/migrations/0019_auto__add_emgroup__add_embbeventlog__add_unique_embbeventlog_event_N.py
new file mode 100644
index 0000000000000000000000000000000000000000..5670de6d9b98dba6f21918a690dd34fc0948a63e
--- /dev/null
+++ b/gracedb/migrations/0019_auto__add_emgroup__add_embbeventlog__add_unique_embbeventlog_event_N.py
@@ -0,0 +1,291 @@
+# -*- 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 model 'EMGroup'
+        db.create_table(u'gracedb_emgroup', (
+            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=20)),
+        ))
+        db.send_create_signal(u'gracedb', ['EMGroup'])
+
+        # Adding model 'EMBBEventLog'
+        db.create_table(u'gracedb_embbeventlog', (
+            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('N', self.gf('django.db.models.fields.IntegerField')()),
+            ('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+            ('event', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['gracedb.Event'])),
+            ('submitter', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+            ('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['gracedb.EMGroup'])),
+            ('instrument', self.gf('django.db.models.fields.CharField')(max_length=200, blank=True)),
+            ('footprintID', self.gf('django.db.models.fields.CharField')(max_length=200, blank=True)),
+            ('waveband', self.gf('django.db.models.fields.CharField')(max_length=25)),
+            ('ra', self.gf('django.db.models.fields.FloatField')(null=True)),
+            ('dec', self.gf('django.db.models.fields.FloatField')(null=True)),
+            ('raWidth', self.gf('django.db.models.fields.FloatField')(null=True)),
+            ('decWidth', self.gf('django.db.models.fields.FloatField')(null=True)),
+            ('gpstime', self.gf('django.db.models.fields.PositiveIntegerField')(null=True)),
+            ('duration', self.gf('django.db.models.fields.PositiveIntegerField')(null=True)),
+            ('eel_status', self.gf('django.db.models.fields.CharField')(max_length=2)),
+            ('obs_status', self.gf('django.db.models.fields.CharField')(max_length=2)),
+            ('comment', self.gf('django.db.models.fields.TextField')(blank=True)),
+            ('extra_info_dict', self.gf('django.db.models.fields.TextField')(blank=True)),
+        ))
+        db.send_create_signal(u'gracedb', ['EMBBEventLog'])
+
+        # Adding unique constraint on 'EMBBEventLog', fields ['event', 'N']
+        db.create_unique(u'gracedb_embbeventlog', ['event_id', 'N'])
+
+
+    def backwards(self, orm):
+        # Removing unique constraint on 'EMBBEventLog', fields ['event', 'N']
+        db.delete_unique(u'gracedb_embbeventlog', ['event_id', 'N'])
+
+        # Deleting model 'EMGroup'
+        db.delete_table(u'gracedb_emgroup')
+
+        # Deleting model 'EMBBEventLog'
+        db.delete_table(u'gracedb_embbeventlog')
+
+
+    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'}),
+            'decWidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'duration': ('django.db.models.fields.PositiveIntegerField', [], {'null': '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.CharField', [], {'max_length': '200', 'blank': 'True'}),
+            'gpstime': ('django.db.models.fields.PositiveIntegerField', [], {'null': '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'}),
+            'raWidth': ('django.db.models.fields.FloatField', [], {'null': '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'},
+            'analysisType': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
+            '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'}),
+            'submitter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+            'uid': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20'})
+        },
+        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.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']
\ No newline at end of file
diff --git a/gracedb/migrations/0020_populate_emgroups.py b/gracedb/migrations/0020_populate_emgroups.py
new file mode 100644
index 0000000000000000000000000000000000000000..32638e9e03072f401df437acc2172fcb77a42224
--- /dev/null
+++ b/gracedb/migrations/0020_populate_emgroups.py
@@ -0,0 +1,252 @@
+# -*- 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
+from django.core.management import call_command
+
+class Migration(DataMigration):
+
+    def forwards(self, orm):
+        call_command("loaddata", "initial_emgroups.json")
+
+    def backwards(self, orm):
+        for emgroup in orm.EMGroup.objects.all():
+            emgroup.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'}),
+            'decWidth': ('django.db.models.fields.FloatField', [], {'null': 'True'}),
+            'duration': ('django.db.models.fields.PositiveIntegerField', [], {'null': '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.CharField', [], {'max_length': '200', 'blank': 'True'}),
+            'gpstime': ('django.db.models.fields.PositiveIntegerField', [], {'null': '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'}),
+            'raWidth': ('django.db.models.fields.FloatField', [], {'null': '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'},
+            'analysisType': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
+            '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'}),
+            'submitter': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+            'uid': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20'})
+        },
+        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.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/models.py b/gracedb/models.py
index 3ed021891b35fd9b621517fc24ce5ecb654d0220..14c1d225fa3965500301796fa796f7a66220d4ab 100644
--- a/gracedb/models.py
+++ b/gracedb/models.py
@@ -4,13 +4,12 @@ from django.core.urlresolvers import reverse
 from model_utils.managers import InheritanceManager
 
 from django.contrib.auth.models import User as DjangoUser
-from django.contrib.auth.models import Group, Permission
+from django.contrib.auth.models import Group
 from django.contrib.contenttypes.models import ContentType
 from guardian.models import GroupObjectPermission
 
 
 import os
-import logging
 
 import glue
 import glue.ligolw
@@ -21,8 +20,6 @@ from glue.lal import LIGOTimeGPS
 
 import json
 
-log = logging.getLogger('gracedb.models')
-
 # XXX ER2.utils.  utils is in project directory.  ugh.
 from utils import posixToGpsTime
 
@@ -50,7 +47,6 @@ schema_version = "1.1"
     #def __unicode__(self):
         #return self.name
 
-
 class Group(models.Model):
     name = models.CharField(max_length=20)
     def __unicode__(self):
@@ -147,8 +143,6 @@ class Event(models.Model):
 
     def weburl(self):
         # XXX Not good.  But then, it never was.
-        #return "https://ldas-jobs.phys.uwm.edu/gracedb/data/%s" % self.graceid()
-        #return "https://gracedb.ligo.org/gracedb-files/%s" % self.graceid()
         return reverse('file_list', args=[self.graceid()])
 
     # XXX This should be considered deprecated. (Branson, July 22, 2014.)
@@ -327,6 +321,164 @@ class EventLog(models.Model):
             # in the views that use it and give an informative error message.
             raise Exception("Too many attempts to save log message. Something is wrong.")
 
+class EMGroup(models.Model):
+    name = models.CharField(max_length=20, unique=True)
+
+    # XXX what else? Possibly the liasons. These can be populated 
+    # automatically from the gw-astronomy COManage-provisioned LDAP.
+    # Let's leave this out for now. The submitter will be stored in 
+    # the EMBB log record, and that should be enough for audit/blame
+    # purposes.
+    #liasons = models.ManyToManyField(DjangoUser)
+
+    # XXX Characteristics needed to produce pointings?
+
+    def __unicode__(self):
+        return self.name
+
+EMSPECTRUM = (
+('em.gamma',            'Gamma rays part of the spectrum'),
+('em.gamma.soft',       'Soft gamma ray (120 - 500 keV)'),
+('em.gamma.hard',       'Hard gamma ray (>500 keV)'),
+('em.X-ray',            'X-ray part of the spectrum'),
+('em.X-ray.soft',       'Soft X-ray (0.12 - 2 keV)'),
+('em.X-ray.medium',     'Medium X-ray (2 - 12 keV)'),
+('em.X-ray.hard',       'Hard X-ray (12 - 120 keV)'),
+('em.UV',               'Ultraviolet part of the spectrum'),
+('em.UV.10-50nm',       'Ultraviolet between 10 and 50 nm'),
+('em.UV.50-100nm',      'Ultraviolet between 50 and 100 nm'),
+('em.UV.100-200nm',     'Ultraviolet between 100 and 200 nm'),
+('em.UV.200-300nm',     'Ultraviolet between 200 and 300 nm'),
+('em.UV.FUV',           'Far-Infrared, 30-100 microns'),
+('em.opt',              'Optical part of the spectrum'),
+('em.opt.U',            'Optical band between 300 and 400 nm'),
+('em.opt.B',            'Optical band between 400 and 500 nm'),
+('em.opt.V',            'Optical band between 500 and 600 nm'),
+('em.opt.R',            'Optical band between 600 and 750 nm'),
+('em.opt.I',            'Optical band between 750 and 1000 nm'),
+('em.IR',               'Infrared part of the spectrum'),
+('em.IR.NIR',           'Near-Infrared, 1-5 microns'),
+('em.IR.J',             'Infrared between 1.0 and 1.5 micron'),
+('em.IR.H',             'Infrared between 1.5 and 2 micron'),
+('em.IR.K',             'Infrared between 2 and 3 micron'),
+('em.IR.MIR',           'Medium-Infrared, 5-30 microns'),
+('em.IR.3-4um',         'Infrared between 3 and 4 micron'),
+('em.IR.4-8um',         'Infrared between 4 and 8 micron'),
+('em.IR.8-15um',        'Infrared between 8 and 15 micron'),
+('em.IR.15-30um',       'Infrared between 15 and 30 micron'),
+('em.IR.30-60um',       'Infrared between 30 and 60 micron'),
+('em.IR.60-100um',      'Infrared between 60 and 100 micron'),
+('em.IR.FIR',           'Far-Infrared, 30-100 microns'),
+('em.mm',               'Millimetric part of the spectrum'),
+('em.mm.1500-3000GHz',  'Millimetric between 1500 and 3000 GHz'),
+('em.mm.750-1500GHz',   'Millimetric between 750 and 1500 GHz'),
+('em.mm.400-750GHz',    'Millimetric between 400 and 750 GHz'),
+('em.mm.200-400GHz',    'Millimetric between 200 and 400 GHz'),
+('em.mm.100-200GHz',    'Millimetric between 100 and 200 GHz'),
+('em.mm.50-100GHz',     'Millimetric between 50 and 100 GHz'),
+('em.mm.30-50GHz',      'Millimetric between 30 and 50 GHz'),
+('em.radio',            'Radio part of the spectrum'),
+('em.radio.12-30GHz',   'Radio between 12 and 30 GHz'),
+('em.radio.6-12GHz',    'Radio between 6 and 12 GHz'),
+('em.radio.3-6GHz',     'Radio between 3 and 6 GHz'),
+('em.radio.1500-3000MHz','Radio between 1500 and 3000 MHz'),
+('em.radio.750-1500MHz','Radio between 750 and 1500 MHz'),
+('em.radio.400-750MHz', 'Radio between 400 and 750 MHz'),
+('em.radio.200-400MHz', 'Radio between 200 and 400 MHz'),
+('em.radio.100-200MHz', 'Radio between 100 and 200 MHz'),
+('em.radio.20-100MHz',  'Radio between 20 and 100 MHz'),
+)
+
+class EMBBEventLog(models.Model):
+    """EMBB EventLog:  A multi-purpose annotation for EM followup.
+     
+    A rectangle on the sky, equatorially aligned,
+    that has or will be imaged that is related to an event"""
+
+    class Meta:
+        ordering = ['-created', '-N']
+        unique_together = ("event","N")
+
+    # A counter for Eels associated with a given event. This is 
+    # important for addressibility.
+    N = models.IntegerField(null=False)
+    
+    # The time at which this Eel was created. Important for event auditing.
+    created = models.DateTimeField(auto_now_add=True)
+
+    # The gracedb event that this Eel relates to
+    event = models.ForeignKey(Event)
+
+    # The responsible author of this communication
+    submitter  = models.ForeignKey(DjangoUser)  # from a table of people
+
+    # The MOU group responsible 
+    group = models.ForeignKey(EMGroup)       # from a table of facilities
+
+    # The instrument used or intended for the imaging implied by this footprint
+    instrument = models.CharField(max_length=200, blank=True)
+
+    # Facility-local identifier for this footprint
+    footprintID= models.CharField(max_length=200, blank=True)
+    # Now the global ID is a concatenation: facilityName#footprintID
+
+    # the EM waveband used for the imaging as below
+    waveband   = models.CharField(max_length=25, choices=EMSPECTRUM)
+
+    # The center of the rectangular foorprint, right ascension and declination
+    # in J2000 in decimal degrees
+    ra         = models.FloatField(null=True)
+    dec        = models.FloatField(null=True)
+
+    # The width and height (RA range and Dec range) in decimal degrees
+    raWidth    = models.FloatField(null=True)
+    decWidth   = models.FloatField(null=True)
+
+    # The GPS time of the middle of of the imaging time
+    gpstime    = models.PositiveIntegerField(null=True)
+
+    # The duration of the imaging in seconds
+    duration   = models.PositiveIntegerField(null=True)
+
+    # Event Log status
+    EEL_STATUS_CHOICES = (('FO','FOOTPRINT'), ('SO','SOURCE'), ('CO','COMMENT'), ('CI','CIRCULAR'))
+    eel_status     = models.CharField(max_length=2, choices=EEL_STATUS_CHOICES)
+
+    # Observation status. If OBSERVATION, then there is a good chance of good image
+    OBS_STATUS_CHOICES = (('NA', 'NOT APPLICABLE'), ('OB','OBSERVATION'), ('TE','TEST'), ('PR','PREDICTION'))
+    obs_status     = models.CharField(max_length=2, choices=OBS_STATUS_CHOICES)
+
+    # This field is natural language for human
+    comment = models.TextField(blank=True)
+
+    # This field is formal struct by a syntax TBD
+    # for example  {"phot.mag.limit": 22.3}
+    extra_info_dict = models.TextField(blank=True)
+
+    # We overload the 'save' method to avoid race conditions, since the Eels are numbered. 
+    def save(self, *args, **kwargs):
+        success = False
+        attempts = 0
+        while (not success and attempts < 5):
+            attempts = attempts + 1
+            if self.event.embbeventlog_set.count():
+                self.N = int(self.event.embbeventlog_set.aggregate(models.Max('N'))['N__max']) + 1
+            else:
+                self.N = 1
+            try:
+                super(EMBBEventLog, self).save(*args, **kwargs)
+                success = True
+            except IntegrityError:
+                # IntegrityError means an attempt to insert a duplicate
+                # key or to violate a foreignkey constraint.
+                # We are under race conditions.  Let's try again.
+                pass
+
+        if not success:
+            # XXX Should this be a custom exception?  That way we could catch it
+            # in the views that use it and give an informative error message.
+            raise Exception("Too many attempts to save EMBB entry. Something is wrong.")
+
 class Labelling(models.Model):
     event = models.ForeignKey(Event)
     label = models.ForeignKey(Label)
@@ -458,14 +610,14 @@ class SingleInspiral(models.Model):
         field_names = cls.field_names()
         created_events = []
 
-        log.debug("Single/create from table/fields: " + str(field_names))
+        #log.debug("Single/create from table/fields: " + str(field_names))
 
         for row in table:
             e = cls(event=event)
-            log.debug("Single/creating event")
+            #log.debug("Single/creating event")
             for column in field_names:
                 value = getattr(row, column)
-                log.debug("Setting column '%s' with value '%s'" % (column, value))
+                #log.debug("Setting column '%s' with value '%s'" % (column, value))
                 setattr(e, column, value)
             e.save()
             created_events.append(e)
diff --git a/gracedb/urls.py b/gracedb/urls.py
index 7a883f37f311756cd9a9f663fe65022d64537d5f..397699b595c888908bbe033d6f589985f36223ca 100644
--- a/gracedb/urls.py
+++ b/gracedb/urls.py
@@ -20,8 +20,11 @@ urlpatterns = patterns('gracedb.views',
     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"),
 
+# RDW Aug 2014
+#(r'^admin/', include(admin.site.urls)),
 
 #   (r'^view/(?P<uid>[\w\d]+)', 'view'),
 #   (r'^edit/(?P<uid>[\w\d]+)', 'edit'),
diff --git a/gracedb/urls_rest.py b/gracedb/urls_rest.py
index 9a25d66b24079a7376eda9dd18b2b56f74ef928d..db2d38a5e1f70728974a5b2b683134a50b71bf74 100644
--- a/gracedb/urls_rest.py
+++ b/gracedb/urls_rest.py
@@ -7,6 +7,7 @@ from django.conf.urls import patterns, url
 from gracedb.api import GracedbRoot
 from gracedb.api import EventList, EventDetail, EventVODetail
 from gracedb.api import EventLogList, EventLogDetail
+from gracedb.api import EMBBEventLogList, EMBBEventLogDetail
 from gracedb.api import TagList
 # from gracedb.api import TagDetail
 from gracedb.api import EventTagList, EventTagDetail
@@ -39,6 +40,13 @@ urlpatterns = patterns('gracedb.api',
     url (r'events/(?P<graceid>[GEHT]\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/$',
+        EMBBEventLogList.as_view(), name='embbeventlog-list'),
+    url (r'events/(?P<graceid>[GEHT]\d+)/embb/(?P<n>\d+)$',
+        EMBBEventLogDetail.as_view(), name='embbeventlog-detail'),
+
     # Tag Resources
     url (r'^tag/$', 
         TagList.as_view(), name='tag-list'),
diff --git a/gracedb/view_logic.py b/gracedb/view_logic.py
index b7657b84a1ba3a07d522a9598a2674c90584c110..5e6c1ff236ccdb6d490d657a1d351c676efb94b1 100644
--- a/gracedb/view_logic.py
+++ b/gracedb/view_logic.py
@@ -6,6 +6,7 @@ from models import Pipeline, Search
 from models import CoincInspiralEvent
 from models import MultiBurstEvent
 from models import GrbEvent
+from models import EMBBEventLog, EMGroup
 from alert import issueAlert, issueAlertForLabel, issueAlertForUpdate
 from translator import handle_uploaded_data
 
@@ -315,3 +316,55 @@ def get_lvem_perm_status(request, event):
         return (True, False)
     else:
         return (False, False)
+
+#
+# Create an EMBB event log message
+#
+def create_eel(d, event, user):    
+    # create a log entry
+    eel = EMBBEventLog(event=event)
+    eel.event = event
+    eel.submitter = user
+    # Assign a group name
+    try:
+        eel.group = EMGroup.objects.get(name=d.get('group'))
+    except:
+        raise ValueError('Please specify an EM followup MOU group')
+
+    # Assign an instrument name
+    eel.instrument = d.get('instrument', '')
+
+    # Assign a group-specific footprint ID (if provided)
+    eel.footprintID = d.get('footprintID', '')
+
+    # Assign the EM spectrum string
+    try:
+        eel.waveband = d.get('waveband')
+    except:
+        raise ValueError('Please specify a waveband')
+
+    # Assign RA and Dec, plus widths
+    eel.ra = d.get('ra', None)
+    eel.dec = d.get('dec', None)
+    eel.raWidth = d.get('raWidth', None)
+    eel.decWidth = d.get('decWidth', None)
+
+    # Assign gpstime and duration.
+    eel.gpstime = d.get('gpstime', None)
+    eel.duration = d.get('duration', None)
+
+    # Assign EEL status and observation status.
+    try:
+        eel.eel_status = d.get('eel_status')
+    except:
+        raise ValueError('Please specify an EEL status.')
+    try:
+        eel.obs_status = d.get('obs_status')
+    except:
+        raise ValueError('Please specify an observation status.')
+
+    eel.extra_info_dict = d.get('extra_info_dict', '')
+    eel.comment = d.get('comment', '')
+    eel.save()
+    return eel
+
diff --git a/gracedb/views.py b/gracedb/views.py
index 78d016b373cb14f2b9b31755b75d79511ea88013..f7130228d48c6cb421159b2a9dd961c2e6c1bd6d 100644
--- a/gracedb/views.py
+++ b/gracedb/views.py
@@ -11,6 +11,7 @@ from django.shortcuts import render_to_response
 from django.views.generic.list import ListView
 
 from models import Event, Group, EventLog, Label, Tag, Pipeline, Search
+from models import EMGroup
 from forms import CreateEventForm, EventSearchForm, SimpleSearchForm
 
 from django.contrib.auth.models import User, Permission
@@ -22,6 +23,7 @@ from guardian.models import GroupObjectPermission
 from view_logic import _createEventFromForm
 from view_logic import get_performance_info
 from view_logic import get_lvem_perm_status
+from view_logic import create_eel
 from view_utils import assembleLigoLw, get_file
 from view_utils import flexigridResponse, jqgridResponse
 
@@ -277,9 +279,11 @@ def view(request, event):
     context['nearby'] = [(e.gpstime - event.gpstime, e)
                             for e in event.neighbors()]
 #    context['skyalert_authorized'] = skyalert_authorized(request)
+    context['groups'] = [g.name for g in EMGroup.objects.all()]
     context['blessed_tags'] = settings.BLESSED_TAGS
     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
 
     # 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
@@ -763,6 +767,35 @@ def modify_permissions(request, event):
     # Finished. Redirect back to the event.
     return HttpResponseRedirect(reverse("view", args=[event.graceid()]))
 
+# A view to create embb log entries
+def embblogentry(request, graceid, num=None):
+    try:
+        event = Event.getByGraceid(graceid)
+    except Event.DoesNotExist:
+        raise Http404
+    if request.method == "POST":
+        try:
+            eel = create_eel(request.POST, event, request.user)
+        except ValueError, e:
+            return HttpResponseBadRequest(str(e))
+        except Exception, e:
+            return HttpResponseServerError(str(e))
+    else:
+        try:
+            eel = event.eventlog_set.filter(N=num)[0]
+        except Exception:
+            raise Http404
+
+    if not request.is_ajax():
+        return HttpResponseRedirect(reverse(view, args=[graceid]))
+
+    rv = {}
+    rv['comment'] = eel.comment
+    rv['submitter'] = eel.issuer.username
+    rv['created'] = eel.created.isoformat()
+
+    return HttpResponse(json.dumps(rv), content_type="application/json")
+
 #------------------------------------------------------------------------------------------
 # Old Stuff
 #------------------------------------------------------------------------------------------
@@ -918,3 +951,4 @@ def modify_permissions(request, event):
 #    return HttpResponseRedirect(reverse(view, args=[graceid]))
 #
 
+
diff --git a/ligoauth/management/commands/refresh_users_from_ldap.py b/ligoauth/management/commands/refresh_users_from_ldap.py
index 7d30d33ba4d51f7c335183099ce321a6f0268308..3fb0226c7688151d610b523a0760a9a810195f40 100644
--- a/ligoauth/management/commands/refresh_users_from_ldap.py
+++ b/ligoauth/management/commands/refresh_users_from_ldap.py
@@ -1,7 +1,7 @@
 
 from django.core.management.base import NoArgsCommand
 
-from ligoauth.models import LigoLdapUser, X509Cert
+from ligoauth.models import LigoLdapUser, X509Cert, AlternateEmail
 
 from django.contrib.auth.models import User, Group
 
@@ -15,7 +15,9 @@ retrieveAttributes = ["krbPrincipalName",
                       "givenName",
                       "sn",
                       "mail",
-                      "isMemberOf"]
+                      "isMemberOf", 
+                      "mailAlternateAddress",
+                      "mailForwardingAddress"]
 
 class Command(NoArgsCommand):
     help = "Update ligoauth.models.LigoUser and django.contrib.auth.models.User from LIGO LDAP"
@@ -39,6 +41,12 @@ class Command(NoArgsCommand):
                         memberships = ldap_result.get('isMemberOf',[])
                         is_active = "Communities:LSCVirgoLIGOGroupMembers" in memberships
                         principal = ldap_result['krbPrincipalName'][0]
+                        #mailForwardingAddress = ldap_result.get('mailForwardingAddress', None)
+                        try:
+                            mailForwardingAddress = unicode(ldap_result['mailForwardingAddress'][0])
+                        except:
+                            mailForwardingAddress = None
+                        mailAlternateAddresses = ldap_result.get('mailAlternateAddress', [])
 
                         # Update/Create LigoLdapUser entry
                         # This is breaking. XXX Do we need to pass in default values for the underlying User object?
@@ -93,3 +101,19 @@ class Command(NoArgsCommand):
                                 u = User.objects.get(username = user.username)
                                 print "Adding %s to %s" % (user.username,g.name)
                                 g.user_set.add(u)
+
+                        # Finally, deail with alternate emails.
+                        if mailForwardingAddress:
+                            try:
+                                AlternateEmail.objects.get_or_create(user=user, 
+                                    email=mailForwardingAddress)
+                            except:
+                                pass
+
+                        if len(mailAlternateAddresses) > 0:
+                            for email in mailAlternateAddresses:
+                                try:
+                                    AlternateEmail.objects.get_or_create(user=user,
+                                        email=email)
+                                except:
+                                    pass
diff --git a/ligoauth/middleware/auth.py b/ligoauth/middleware/auth.py
index b0f3963a64b32759131e826571c6feab982801a6..f30c74ccb0ceae7f921b84db6acd2533cfa4a541 100644
--- a/ligoauth/middleware/auth.py
+++ b/ligoauth/middleware/auth.py
@@ -73,6 +73,7 @@ class LigoAuthMiddleware:
         # An authenticated LIGO user will have one of these set.
 
         remote_user = request.META.get('REMOTE_USER')
+        message = remote_user
         dn = cert_dn_from_request(request)
 
         # Apache should be configured so that the *only* thing that can
@@ -90,7 +91,7 @@ class LigoAuthMiddleware:
                     return HttpResponseForbidden("{ 'error': '%s'  }" % str(e)) 
 
             if not (user and user.is_authenticated()):
-                # XXX THIS SHOULD NEVER HAPPEN
+                message += "THIS SHOULD NEVER HAPPEN"
                 pass
             
             # Add shib user to groups. This operation is idempotent, but may
@@ -135,7 +136,7 @@ class LigoAuthMiddleware:
                 return HttpResponseForbidden("{ 'error': '%s'  }" % message)
             return render_to_response(
                     'forbidden.html',
-                    {},
+                    {'error': message},
                     context_instance=RequestContext(request))
 
 class RemoteUserBackend(DefaultRemoteUserBackend):
diff --git a/ligoauth/migrations/0012_auto__add_alternateemail.py b/ligoauth/migrations/0012_auto__add_alternateemail.py
new file mode 100644
index 0000000000000000000000000000000000000000..d42a7cbd1bf3fb84e8a9121c16aee7bb3897b611
--- /dev/null
+++ b/ligoauth/migrations/0012_auto__add_alternateemail.py
@@ -0,0 +1,85 @@
+# -*- 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 model 'AlternateEmail'
+        db.create_table(u'ligoauth_alternateemail', (
+            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+            ('email', self.gf('django.db.models.fields.EmailField')(max_length=254)),
+        ))
+        db.send_create_signal(u'ligoauth', ['AlternateEmail'])
+
+
+    def backwards(self, orm):
+        # Deleting model 'AlternateEmail'
+        db.delete_table(u'ligoauth_alternateemail')
+
+
+    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'ligoauth.alternateemail': {
+            'Meta': {'object_name': 'AlternateEmail'},
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '254'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
+        },
+        u'ligoauth.ligoldapuser': {
+            'Meta': {'object_name': 'LigoLdapUser', '_ormbases': [u'auth.User']},
+            'ldap_dn': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
+            u'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True', 'primary_key': 'True'})
+        },
+        u'ligoauth.localuser': {
+            'Meta': {'object_name': 'LocalUser', '_ormbases': [u'auth.User']},
+            u'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True', 'primary_key': 'True'})
+        },
+        u'ligoauth.x509cert': {
+            'Meta': {'object_name': 'X509Cert'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'subject': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.User']", 'symmetrical': 'False'})
+        }
+    }
+
+    complete_apps = ['ligoauth']
\ No newline at end of file
diff --git a/ligoauth/models.py b/ligoauth/models.py
index eb8efc716f4322b376457194716f308b40a7a6b0..b64d6dc9f7c4cb991f90cc7e7a1286ea36139f5f 100644
--- a/ligoauth/models.py
+++ b/ligoauth/models.py
@@ -65,6 +65,9 @@ class X509Cert(models.Model):
     subject = models.CharField(max_length=200)
     users = models.ManyToManyField(User)
 
+class AlternateEmail(models.Model):
+    user = models.ForeignKey(User)
+    email = models.EmailField(max_length=254)
 
 def shibid_to_user(shibid):
     try:
diff --git a/manage.py b/manage.py
index 6124f342fe5b699d4d3b418fb426564cd0a455a7..c632a8a38923012b836655195baeadd5c2ffd930 100755
--- a/manage.py
+++ b/manage.py
@@ -7,4 +7,3 @@ if __name__ == "__main__":
     from django.core.management import execute_from_command_line
 
     execute_from_command_line(sys.argv)
-
diff --git a/settings/__init__.py b/settings/__init__.py
index 2c418284b3e0406651300b8c7ccef3d4b196409e..327421861d827656acbba8b37530cb0c54a7f144 100644
--- a/settings/__init__.py
+++ b/settings/__init__.py
@@ -32,6 +32,9 @@ configs = {
     '/home/fzhang/gracedb/gracedb': 'fan',
     '/home/fzhang/gracedb/gracedb/gracedb': 'fan',
 
+    '/home/roywilliams/gracedbdev': 'roy',
+    '/home/roywilliams/gracedbdev/gracedb': 'roy',
+
     "/home/gracedb/gracestage" : "stage",
 
 }
diff --git a/settings/branson.py b/settings/branson.py
index 167583f5aad8aab3950a386f18833e3db5b48375..7ef2d84c0ae44b45d0ad437ad5178a4e68e8400d 100644
--- a/settings/branson.py
+++ b/settings/branson.py
@@ -32,6 +32,11 @@ ALERT_TEST_EMAIL_TO = [
     "Branson Stephens <branson@gravity.phys.uwm.edu>",
     ]
 
+EMBB_MAIL_ADDRESS = 'branson@moe.phys.uwm.edu'
+EMBB_SMTP_SERVER = 'localhost'
+EMBB_MAIL_ADMINS = ['branson@gravity.phys.uwm.edu',]
+EMBB_IGNORE_ADDRESSES = ['Mailer-Daemon@moe.phys.uwm.edu',]
+
 # Don't sent out non-test XMPP alerts on dev box!
 XMPP_ALERT_CHANNELS = [
                         'test_omega',
diff --git a/settings/default.py b/settings/default.py
index 77bdbac0b9b94eff0c5c1c7042862fc3e9ebaab0..26eabc87d8a48ab76d29be320725a07d92dec45e 100644
--- a/settings/default.py
+++ b/settings/default.py
@@ -25,6 +25,11 @@ ALERT_TEST_EMAIL_FROM = "GraCEDb TEST <gracedb@archie.phys.uwm.edu>"
 ALERT_TEST_EMAIL_TO = [
                       ]
 
+EMBB_MAIL_ADDRESS = 'embb@gracedb.ligo.org'
+EMBB_SMTP_SERVER = 'localhost'
+EMBB_MAIL_ADMINS = ['branson@gravity.phys.uwm.edu','roy.williams@ligo.org',]
+MBB_IGNORE_ADDRESSES = ['Mailer-Daemon@gracedb.phys.uwm.edu',]
+
 XMPP_ALERT_CHANNELS = [
                         'burst_omega',
                         'test_omega',
@@ -40,6 +45,8 @@ XMPP_ALERT_CHANNELS = [
                         'external_grb',
                       ]
 
+SKYMAP_VIEWER_SERVICE_URL = "https://embb-dev.ligo.caltech.edu/cgi-bin/skymapViewer"
+
 BLESSED_TAGS = [
                  'analyst_comments',
                  'psd',
diff --git a/settings/roy.py b/settings/roy.py
new file mode 100644
index 0000000000000000000000000000000000000000..dc7120dfb7e682a257da25d3dce29b1fae8815ae
--- /dev/null
+++ b/settings/roy.py
@@ -0,0 +1,189 @@
+# XXX I know import * is ugly, but I want the stuff from logSettings to be
+# in this namespace.
+# from logSettings import *
+
+CONFIG_NAME = "EMBB development"
+
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+# LOG_ROOT = '/home/jkanner/logs'
+# LOGGING={}
+
+DATABASES = {
+    'default' : {
+        'NAME'     : 'gracedb',
+        'ENGINE'   : 'django.db.backends.mysql',
+        'USER'     : 'jkanner',
+        'PASSWORD' : 'batman',
+	'OPTIONS'  : {
+		'init_command' : 'SET storage_engine=MyISAM',
+		}
+    }
+}
+
+ROOT_URLCONF = 'urls'
+
+#MEDIA_URL = "/gracedb-static/"
+
+SKYMAP_VIEWER_MEDIA_URL = "/skymap-viewer/"
+
+GRACEDB_DATA_DIR = "/home/roywilliams/gracedbData"
+MPLCONFIGDIR = "/home/jkanner/mplconfig"
+
+ALERT_EMAIL_FROM = "Dev Alert <root@embb-dev.ligo.caltech.edu>"
+ALERT_EMAIL_TO = [
+    "Roy Williams <roy@caltech.edu>",
+    ]
+ALERT_EMAIL_BCC = ["roy@caltech.edu"]
+
+ALERT_TEST_EMAIL_FROM = "Dev Test Alert <root@embb-dev.ligo.caltech.edu>"
+ALERT_TEST_EMAIL_TO = [
+    "Roy Williams <roy@caltech.edu>",
+    ]
+
+
+EMBB_MAIL_ADDRESS = 'embb@embb-dev.ligo.caltech.edu'
+EMBB_SMTP_SERVER = 'acrux.ligo.caltech.edu'
+EMBB_MAIL_ADMINS = ['roy.williams@ligo.org',]
+
+BLESSED_TAGS = [
+                 'analyst_comments',
+                 'psd',
+                 'data_quality',
+                 'sky_loc',
+                 'background',
+                 'ext_coinc',
+                 'strain',
+                 'tfplots',
+                 'sig_info',
+                 'audio',
+               ]
+
+
+# Don't sent out non-test XMPP alerts on dev box!
+XMPP_ALERT_CHANNELS = [
+                        'test_omega',
+                        'test_mbtaonline',
+                        'test_cwb',
+                        'test_lowmass',
+                      ]
+ 
+# SkyAlert
+SKYALERT_IVORN_PATTERN = "ivo://ligo.org/gracedb#%s-dev"
+
+# Latency histograms.  Where they go and max latency to bin.
+LATENCY_REPORT_DEST_DIR = "/home/jkanner/data/latency"
+LATENCY_REPORT_WEB_PAGE_FILE_PATH = LATENCY_REPORT_DEST_DIR + "/latency.inc"
+
+# Uptime reporting
+UPTIME_REPORT_DIR = "/home/jkanner/data/uptime"
+
+
+SITE_ID = 4
+
+TEMPLATE_DIRS = (
+    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
+    # Always use forward slashes, even on Windows.
+    # Don't forget to use absolute paths, not relative paths.
+    "/home/roywilliams/gracedbdev/templates",
+)
+
+MIDDLEWARE_CLASSES = [
+    'middleware.accept.AcceptMiddleware',
+    'middleware.cli.CliExceptionMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+#    'django.contrib.auth.middleware.AuthenticationMiddleware',
+#    'ligodjangoauth.LigoShibbolethMiddleware',
+    'ligoauth.middleware.auth.LigoAuthMiddleware',
+    'maintenancemode.middleware.MaintenanceModeMiddleware',
+#    'debug_toolbar.middleware.DebugToolbarMiddleware',
+]
+
+AUTHENTICATION_BACKENDS = (
+#   'gracedb.middleware.auth.LigoAuthBackend',
+    'ligoauth.middleware.auth.LigoX509Backend',
+    'ligoauth.middleware.auth.LigoShibBackend',
+#   'ligoauth.middleware.auth.RemoteUserBackend',
+#   'ligodjangoauth.LigoShibbolethAuthBackend',
+#   'django.contrib.auth.backends.ModelBackend',
+)
+
+
+TEMPLATE_CONTEXT_PROCESSORS = (
+    #"django.core.context_processors.auth",
+    # replaced by...
+    "django.contrib.auth.context_processors.auth",
+    "django.core.context_processors.debug",
+    "django.core.context_processors.i18n",
+    "django.core.context_processors.media",
+    "django.core.context_processors.static",
+    "django.core.context_processors.request",
+    "gracedb.middleware.auth.LigoAuthContext",
+    'middleware.debug.LigoDebugContext',
+)
+
+
+INSTALLED_APPS = (
+    'django.contrib.auth',
+    'django.contrib.admin',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.sites',
+    'django.contrib.staticfiles',
+    'gracedb',
+    'userprofile',
+    'ligoauth',
+    'rest_framework',
+    'south',
+#    'debug_toolbar',
+)
+
+INTERNAL_IPS = (
+    '129.89.61.55',
+)
+
+
+LOGGING = {}
+x = """     HACH HACK HACK
+LOG_ROOT = '/home/jkanner/logs'
+LOG_FILE_SIZE = 1024*1024 # 1 MB
+LOG_FILE_BAK_CT = 3
+
+LOGGING = {
+    'version': 1,
+    'disable_existing_loggers' : True,
+    'formatters': {
+        'simple': {
+            'format': '%(asctime)s: %(message)s',
+            'datefmt': '%Y-%m-%dT%H:%M:%S',
+        },
+    },
+    'handlers': {
+        'null': {
+            'level':'DEBUG',
+            'class':'django.utils.log.NullHandler',
+        },
+        'performance_file': {
+            'class': 'logging.handlers.RotatingFileHandler',
+            'formatter': 'simple',
+            'filename': '%s/gracedb_performance.log' % LOG_ROOT,
+            'maxBytes': LOG_FILE_SIZE,
+            'backupCount': LOG_FILE_BAK_CT,
+        },
+    },
+    'loggers': {
+        'django': {
+            'handlers': ['null'],
+            'propagate': True,
+            'level': 'INFO',
+        },
+        'middleware': {
+            'handlers': ['performance_file'],
+            'propagate': True,
+            'level': 'INFO',
+        },
+   },
+}
+"""
diff --git a/templates/forbidden.html b/templates/forbidden.html
index e383758b9eccf0009b85c5f6af6520062175d58b..64e1485fcff1967531049642c60eac2a8fa038d0 100644
--- a/templates/forbidden.html
+++ b/templates/forbidden.html
@@ -6,6 +6,6 @@
 {% block heading %}Forbidden{{ object.graceid }}{% endblock %}
 
 {% block content %}
-    <p>The item you requested is not for you.</p> {{ message|safe }}
+    <p>You are {{ error }} and the item you requested is not for you.</p> {{ message|safe }}
 {% endblock %}
 
diff --git a/templates/gracedb/event_detail.html b/templates/gracedb/event_detail.html
index 06f51c5c3f1312705b08084debc26af32cd2ee3e..9b71370d82b66e732d5ffca6b4a164d28a3f36e2 100644
--- a/templates/gracedb/event_detail.html
+++ b/templates/gracedb/event_detail.html
@@ -30,6 +30,10 @@
         // 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 %}
@@ -93,6 +97,10 @@
                     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';
@@ -491,6 +499,28 @@
                 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() {
+                    // 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; 
+                            // Submit the form, which takes the user to the skymapViewer server.
+                            sV_form.submit();
+                        }
+                    });
+                });
+            }
+
         });
 
     </script>
@@ -505,7 +535,7 @@
         <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>
+<style>
         @import "https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dijit/themes/tundra/tundra.css";
         a:hover .dojoxEnlarge {
             display: block !important;
@@ -617,6 +647,17 @@
 {% 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="submit" value="View in skymapViewer!">
+</form>
+</div>
+
 <!-- Neighbors Support refresh_neighbors() function -->
 <script type="text/javascript">
     var refresh_neighbors= function() { alert("NOT SET YET"); };
@@ -644,21 +685,237 @@
     });
     require(["dijit/InlineEditBox", "dijit/form/NumberSpinner", "dijit/form/TextBox"]);
 
-</script>
+  </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>
+<tr><td><a href=# onclick="alert('RA and Dec specify a center point of a rectangle that is aligned equatorially. 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="ra" value="0.0"/></td></tr>
+
+<tr><td><a href=# onclick="alert('RA and Dec specify a center point of a rectangle that is aligned equatorially. 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="dec" value="0.0"/></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="raWidth" value="0.0"/></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="decWidth" value="0.0"/></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. Change either the GPS time or the UTC time and the other will change to match.');return false;">
+GPStime or UTC</a></td>
+<td><input onKeyUp="return TIMEcopy(2,1);" id="TIMEgps1" name="gpstime" 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('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="duration" value="10"/></td></tr>
+
+<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"  cols="50">{"phot.mag.limit": 22.3}</textarea></td></tr>
+</table>
+<input type="submit" value="Submit"/>
+</form>
+
+
+				</div>
 
-{% include "gracedb/neighbors_frag.html" %}
+				<!-- 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 %}
+						<table id="bb_2" class="event" border="1">
+						<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 }}</td> 
+<td>{{ eel.extra_info_dict }}</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">
-            <textarea id="newlogtext" name="comment" style="width:300px;display:block"></textarea>
-            <input type="submit" value="Submit"/>
+            <p>
+              <textarea id="newlogtext" name="comment" style="width:300px;display:block"></textarea>
+              <input type="submit" value="Submit"/>
+            </p>
         </form>
     </noscript>
-    </div>
+  </div>
 
     <h3 id="logmessagetitle">Event Log Messages</h3>
     <div id="previewer"></div>
@@ -666,3 +923,5 @@
 
 </div> 
 {% endblock %}
+
+<!-- Single Inspiral Data -->
diff --git a/wsgi/roy.wsgi b/wsgi/roy.wsgi
new file mode 100644
index 0000000000000000000000000000000000000000..bfd45820e40be8b24bc1734642173d6128093762
--- /dev/null
+++ b/wsgi/roy.wsgi
@@ -0,0 +1,27 @@
+import os
+import sys
+
+os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
+os.environ['MPLCONFIGDIR']='/tmp/'
+
+# Sandbox libs here, if required.
+#
+sys.path.append('/home/jkanner/djangoenv/lib/python2.7/site-packages')
+sys.path.append('/home/jkanner/djangoenv/lib/python2.7')
+sys.path.append('/home/roywilliams/gracedbdev')
+sys.path.append('/home/roywilliams')
+
+# Scott's Shib app uses loggers.
+import logging
+logging.basicConfig()
+
+os.environ['MPLCONFIGDIR']='/tmp/'
+
+#logging.basicConfig(level=logging.DEBUG,
+#                    format='%(asctime)s %(levelname)s %(message)s',
+#                    filename='/tmp/myapp.log',
+#                    filemode='w')
+
+import django.core.handlers.wsgi
+application = django.core.handlers.wsgi.WSGIHandler()
+