From 5bfd91a5579a1dbb80eba00dbd32981d559d665e Mon Sep 17 00:00:00 2001
From: millosolomillo <marcomillo@gmail.com>
Date: Thu, 16 Apr 2020 05:33:02 +0200
Subject: [PATCH] Revert "Pulling updated benadida master branch (#6)" (#7)

This reverts commit 9b697dc698add751a7c29d17784483f29648338c.
---
 .travis.yml                                   |  41 +--
 CONTRIBUTORS.txt                              |   2 -
 Procfile                                      |   2 +-
 README.md                                     |   2 +-
 extract-passwords-for-email.py                |  12 +-
 helios/__init__.py                            |   6 +-
 helios/apps.py                                |   5 -
 helios/celery_app.py                          |  21 --
 helios/datatypes/__init__.py                  |  24 +-
 helios/datatypes/djangofield.py               |  24 +-
 helios/datatypes/legacy.py                    |   2 +-
 helios/datetimewidget.py                      |   2 -
 helios/election_url_names.py                  |  62 -----
 helios/election_urls.py                       | 120 ++++----
 helios/fixtures/users.json                    |  41 +--
 helios/forms.py                               |   4 +-
 .../commands/helios_trustee_decrypt.py        |   6 +-
 .../management/commands/load_voter_files.py   |  74 +++--
 .../management/commands/verify_cast_votes.py  |   6 +-
 helios/migrations/0001_initial.py             |  16 +-
 helios/models.py                              |  71 ++---
 helios/security.py                            |  24 +-
 helios/south_migrations/0001_initial.py       | 259 ++++++++++++++++++
 ...0002_v3_1_new_election_and_voter_fields.py | 196 +++++++++++++
 ...election_specific_voters_with_passwords.py | 178 ++++++++++++
 .../0004_v3_1_remove_voter_fields.py          | 153 +++++++++++
 .../0005_add_quarantine_fields.py             | 154 +++++++++++
 ..._unique_voter_voter_login_id_election__.py | 220 +++++++++++++++
 ..._file_content__chg_field_voterfile_vote.py | 149 ++++++++++
 ...auto__add_unique_trustee_election_email.py | 143 ++++++++++
 ...009_auto__add_field_election_help_email.py | 144 ++++++++++
 ...d_field_election_randomize_answer_order.py | 146 ++++++++++
 ...o__add_field_election_election_info_url.py | 147 ++++++++++
 ...__add_field_election_result_released_at.py | 148 ++++++++++
 helios/south_migrations/__init__.py           |   0
 helios/stats_url_names.py                     |   5 -
 helios/stats_urls.py                          |  20 +-
 helios/stats_views.py                         |  24 +-
 helios/tasks.py                               |  92 +++----
 helios/templates/_castconfirm_docast.html     |   2 +-
 helios/templates/_castconfirm_password.html   |   2 +-
 helios/templates/cast_done.html               |   4 +-
 helios/templates/castvote.html                |   2 +-
 helios/templates/combine_decryptions.html     |   2 +-
 .../templates/election_audited_ballots.html   |   4 +-
 helios/templates/election_bboard.html         |  10 +-
 helios/templates/election_build.html          |   2 +-
 helios/templates/election_cast_confirm.html   |   2 +-
 helios/templates/election_compute_tally.html  |   4 +-
 helios/templates/election_edit.html           |   2 +-
 helios/templates/election_extend.html         |   2 +-
 helios/templates/election_freeze.html         |   4 +-
 helios/templates/election_keygenerator.html   |   4 +-
 helios/templates/election_not_started.html    |   2 +-
 helios/templates/election_questions.html      |   2 +-
 helios/templates/election_register.html       |   2 +-
 helios/templates/election_tallied.html        |   2 +-
 helios/templates/election_view.html           |  38 +--
 helios/templates/elections_administered.html  |   2 +-
 helios/templates/elections_voted.html         |   2 +-
 helios/templates/list_trustees.html           |  12 +-
 helios/templates/new_trustee.html             |   2 +-
 helios/templates/release_result.html          |   2 +-
 helios/templates/stats.html                   |   8 +-
 helios/templates/stats_elections.html         |   4 +-
 helios/templates/stats_problem_elections.html |   2 +-
 helios/templates/stats_recent_votes.html      |   2 +-
 helios/templates/trustee_check_sk.html        |   2 +-
 .../templates/trustee_decrypt_and_prove.html  |   2 +-
 helios/templates/trustee_home.html            |   6 +-
 helios/templates/voters_eligibility.html      |   2 +-
 helios/templates/voters_email.html            |   4 +-
 helios/templates/voters_list.html             |  20 +-
 helios/templates/voters_manage.html           |   6 +-
 helios/templates/voters_search.html           |   4 +-
 helios/templates/voters_upload.html           |   2 +-
 helios/templates/voters_upload_confirm.html   |   6 +-
 helios/test.py                                |  25 +-
 helios/tests.py                               | 177 ++++++------
 helios/url_names.py                           |  27 --
 helios/urls.py                                |  45 +--
 helios/view_utils.py                          |  51 ++--
 helios/views.py                               |  91 +++---
 helios/widgets.py                             |  31 ++-
 helios/workflows/homomorphic.py               |   6 +-
 helios_auth/apps.py                           |   5 -
 helios_auth/auth_systems/cas.py               |  17 +-
 helios_auth/auth_systems/clever.py            |  11 +-
 .../djangofb/default_app/urls.py              |  10 +-
 helios_auth/auth_systems/google.py            |  10 +-
 helios_auth/auth_systems/linkedin.py          |   2 +-
 helios_auth/auth_systems/openid/util.py       |   2 +-
 helios_auth/auth_systems/password.py          |  18 +-
 helios_auth/auth_systems/twitter.py           |  13 +-
 helios_auth/auth_systems/yahoo.py             |   6 +-
 helios_auth/jsonfield.py                      |  28 +-
 helios_auth/models.py                         |   9 +-
 helios_auth/security/__init__.py              |  15 +-
 helios_auth/security/oauth.py                 |  29 +-
 helios_auth/south_migrations/0001_initial.py  |  49 ++++
 helios_auth/south_migrations/__init__.py      |   0
 helios_auth/templates/index.html              |   2 +-
 helios_auth/templates/login_box.html          |   4 +-
 helios_auth/templates/perms_why.html          |   2 +-
 helios_auth/tests.py                          |   4 +-
 helios_auth/url_names.py                      |   6 -
 helios_auth/urls.py                           |  22 +-
 helios_auth/view_utils.py                     |  48 ++--
 helios_auth/views.py                          |  44 +--
 requirements.txt                              |   9 +-
 reset.sh                                      |   2 +-
 server_ui/__init__.py                         |   2 +
 server_ui/glue.py                             |  51 ++--
 server_ui/templates/base.html                 |   8 +-
 server_ui/templates/confirm.html              |   2 +-
 server_ui/templates/done.html                 |   2 +-
 server_ui/templates/election_tallied.html     |   2 +-
 server_ui/templates/index.html                |  14 +-
 server_ui/urls.py                             |  16 +-
 server_ui/view_utils.py                       |  10 +-
 server_ui/views.py                            |  20 +-
 settings.py                                   |  84 +++---
 urls.py                                       |  26 +-
 123 files changed, 2930 insertions(+), 1054 deletions(-)
 delete mode 100644 helios/apps.py
 delete mode 100644 helios/celery_app.py
 delete mode 100644 helios/election_url_names.py
 create mode 100644 helios/south_migrations/0001_initial.py
 create mode 100644 helios/south_migrations/0002_v3_1_new_election_and_voter_fields.py
 create mode 100644 helios/south_migrations/0003_v3_1_election_specific_voters_with_passwords.py
 create mode 100644 helios/south_migrations/0004_v3_1_remove_voter_fields.py
 create mode 100644 helios/south_migrations/0005_add_quarantine_fields.py
 create mode 100644 helios/south_migrations/0006_auto__chg_field_voter_vote__add_unique_voter_voter_login_id_election__.py
 create mode 100644 helios/south_migrations/0007_auto__add_field_voterfile_voter_file_content__chg_field_voterfile_vote.py
 create mode 100644 helios/south_migrations/0008_auto__add_unique_trustee_election_email.py
 create mode 100644 helios/south_migrations/0009_auto__add_field_election_help_email.py
 create mode 100644 helios/south_migrations/0010_auto__add_field_election_randomize_answer_order.py
 create mode 100644 helios/south_migrations/0011_auto__add_field_election_election_info_url.py
 create mode 100644 helios/south_migrations/0012_auto__add_field_election_result_released_at.py
 create mode 100644 helios/south_migrations/__init__.py
 delete mode 100644 helios/stats_url_names.py
 delete mode 100644 helios/url_names.py
 delete mode 100644 helios_auth/apps.py
 create mode 100644 helios_auth/south_migrations/0001_initial.py
 create mode 100644 helios_auth/south_migrations/__init__.py
 delete mode 100644 helios_auth/url_names.py

diff --git a/.travis.yml b/.travis.yml
index 1505fcc..6b93e8a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,41 +2,16 @@ sudo: false
 language: python
 python:
   - "2.7"
-
-os: linux
-
-before_install:
-  - export BOTO_CONFIG=/dev/null
-
+# command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors
 install:
-  - pip install --upgrade pip
+  - pip install setuptools==24.3.1
   - pip install -r requirements.txt
-
+# command to run tests, e.g. python setup.py test
+script: "python manage.py test"
+addons:
+  postgresql: "9.3"
 before_script:
   - psql -c 'create database helios;' -U postgres
+before_install:
+  - export BOTO_CONFIG=/dev/null
 
-script: "python -Wall manage.py test"
-
-jobs:
-  include:
-  - dist: trusty
-    addons:
-      postgresql: "9.3"
-  - dist: trusty
-    addons:
-      postgresql: "9.4"
-  - dist: trusty
-    addons:
-      postgresql: "9.5"
-  - dist: trusty
-    addons:
-      postgresql: "9.6"
-  - dist: xenial
-    addons:
-      postgresql: "9.4"
-  - dist: xenial
-    addons:
-      postgresql: "9.5"
-  - dist: xenial
-    addons:
-      postgresql: "9.6"
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt
index e37f6e4..61ac196 100644
--- a/CONTRIBUTORS.txt
+++ b/CONTRIBUTORS.txt
@@ -7,5 +7,3 @@ Significant contributors:
 - Olivier de Marneffe
 - Emily Stark, Mike Hamburg, Tom Wu, and Dan Boneh for SJCL and integration of javascript crypto.
 - Nicholas Chang-Fong and Aleksander Essex for security reports and fixes.
-- Shirley Chaves
-- Marco Ciotola
diff --git a/Procfile b/Procfile
index 608417d..63d8d0c 100644
--- a/Procfile
+++ b/Procfile
@@ -1,2 +1,2 @@
 web: gunicorn wsgi:application -b 0.0.0.0:$PORT -w 8
-worker: celery worker --app helios --events --beat --concurrency 1 --logfile celeryw.log --pidfile celeryw.pid
\ No newline at end of file
+worker: python manage.py celeryd -E -B --beat --concurrency=1
\ No newline at end of file
diff --git a/README.md b/README.md
index 9a5519b..5c90a9c 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,6 @@
 
 Helios is an end-to-end verifiable voting system.
 
-[![Travis Build Status](https://travis-ci.org/benadida/helios-server.svg?branch=master)](https://travis-ci.org/benadida/helios-server)
+![Travis Build Status](https://travis-ci.org/benadida/helios-server.svg?branch=master)
 
 [![Stories in Ready](https://badge.waffle.io/benadida/helios-server.png?label=ready&title=Ready)](https://waffle.io/benadida/helios-server)
diff --git a/extract-passwords-for-email.py b/extract-passwords-for-email.py
index 7769d02..d727057 100644
--- a/extract-passwords-for-email.py
+++ b/extract-passwords-for-email.py
@@ -5,16 +5,12 @@
 # python extract-passwords-for-email.py <election_uuid> <email_address>
 #
 
-import sys
+from django.core.management import setup_environ
+import settings, sys, csv
 
-import csv
-import django
-import os
+setup_environ(settings)
 
-from helios.models import Election
-
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
-django.setup()
+from helios.models import *
 
 election_uuid = sys.argv[1]
 email = sys.argv[2]
diff --git a/helios/__init__.py b/helios/__init__.py
index 2f59829..3a516d7 100644
--- a/helios/__init__.py
+++ b/helios/__init__.py
@@ -1,9 +1,5 @@
 from django.conf import settings
-# This will make sure the app is always imported when
-# Django starts so that shared_task will use this app.
-from celery_app import app as celery_app
-
-__all__ = ('celery_app', 'TEMPLATE_BASE', 'ADMIN_ONLY', 'VOTERS_UPLOAD', 'VOTERS_EMAIL',)
+from django.core.urlresolvers import reverse
 
 TEMPLATE_BASE = settings.HELIOS_TEMPLATE_BASE or "helios/templates/base.html"
 
diff --git a/helios/apps.py b/helios/apps.py
deleted file mode 100644
index 9009743..0000000
--- a/helios/apps.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from django.apps import AppConfig
-
-class HeliosConfig(AppConfig):
-    name = 'helios'
-    verbose_name = "Helios"
diff --git a/helios/celery_app.py b/helios/celery_app.py
deleted file mode 100644
index 89f0ecb..0000000
--- a/helios/celery_app.py
+++ /dev/null
@@ -1,21 +0,0 @@
-import os
-
-# set the default Django settings module for the 'celery' program.
-from celery import Celery
-
-os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings')
-
-app = Celery()
-
-# Using a string here means the worker doesn't have to serialize
-# the configuration object to child processes.
-# - namespace='CELERY' means all celery-related configuration keys
-#   should have a `CELERY_` prefix.
-app.config_from_object('django.conf:settings', namespace='CELERY')
-
-# Load task modules from all registered Django app configs.
-app.autodiscover_tasks()
-
-@app.task(bind=True)
-def debug_task(self):
-    print('Request: {0!r}'.format(self.request))
diff --git a/helios/datatypes/__init__.py b/helios/datatypes/__init__.py
index 93bca24..b0ede25 100644
--- a/helios/datatypes/__init__.py
+++ b/helios/datatypes/__init__.py
@@ -33,7 +33,7 @@ from helios.crypto import utils as cryptoutils
 ## utility function
 ##
 def recursiveToDict(obj):
-    if obj is None:
+    if obj == None:
         return None
 
     if type(obj) == list:
@@ -53,7 +53,7 @@ def get_class(datatype):
     dynamic_module = __import__(".".join(parsed_datatype[:-1]), globals(), locals(), [], level=-1)
     
     if not dynamic_module:
-        raise Exception("no module for %s" % datatype)
+        raise Exception("no module for %s" % datatpye)
 
     # go down the attributes to get to the class
     try:
@@ -130,7 +130,7 @@ class LDObject(object):
             raise Exception("no datatype found")
 
         # nulls
-        if obj is None:
+        if obj == None:
             return None
 
         # the class
@@ -171,7 +171,7 @@ class LDObject(object):
                 self.structured_fields[f] = sub_ld_object
 
                 # set the field on the wrapped object too
-                if sub_ld_object is not None:
+                if sub_ld_object != None:
                     self._setattr_wrapped(f, sub_ld_object.wrapped_obj)
                 else:
                     self._setattr_wrapped(f, None)
@@ -190,7 +190,7 @@ class LDObject(object):
         fields = self.FIELDS
 
         if not self.structured_fields:
-            if self.wrapped_obj.alias is not None:
+            if self.wrapped_obj.alias != None:
                 fields = self.ALIASED_VOTER_FIELDS
 
         for f in (alternate_fields or fields):
@@ -214,7 +214,7 @@ class LDObject(object):
     @classmethod
     def fromDict(cls, d, type_hint=None):
         # null objects
-        if d is None:
+        if d == None:
             return None
 
         # the LD type is either in d or in type_hint
@@ -248,11 +248,11 @@ class LDObject(object):
         """
         process some fields on the way into the object
         """
-        if field_value is None:
+        if field_value == None:
             return None
       
         val = self._process_value_in(field_name, field_value)
-        if val is not None:
+        if val != None:
             return val
         else:
             return field_value
@@ -264,11 +264,11 @@ class LDObject(object):
         """
         process some fields on the way out of the object
         """
-        if field_value is None:
+        if field_value == None:
             return None
       
         val = self._process_value_out(field_name, field_value)
-        if val is not None:
+        if val != None:
             return val
         else:
             return field_value
@@ -278,9 +278,9 @@ class LDObject(object):
     
     def __eq__(self, other):
         if not hasattr(self, 'uuid'):
-            return super(LDObject, self) == other
+            return super(LDObject,self) == other
     
-        return other is not None and self.uuid == other.uuid
+        return other != None and self.uuid == other.uuid
   
 
 class BaseArrayOfObjects(LDObject):
diff --git a/helios/datatypes/djangofield.py b/helios/datatypes/djangofield.py
index 05f8cf3..e0eb1b4 100644
--- a/helios/datatypes/djangofield.py
+++ b/helios/datatypes/djangofield.py
@@ -6,12 +6,15 @@ http://www.djangosnippets.org/snippets/377/
 and adapted to LDObject
 """
 
+import datetime
 import json
 from django.db import models
+from django.db.models import signals
+from django.conf import settings
+from django.core.serializers.json import DjangoJSONEncoder
 
 from . import LDObject
 
-
 class LDObjectField(models.TextField):
     """
     LDObject is a generic textfield that neatly serializes/unserializes
@@ -20,6 +23,9 @@ class LDObjectField(models.TextField):
     deserialization_params added on 2011-01-09 to provide additional hints at deserialization time
     """
 
+    # Used so to_python() is called
+    __metaclass__ = models.SubfieldBase
+
     def __init__(self, type_hint=None, **kwargs):
         self.type_hint = type_hint
         super(LDObjectField, self).__init__(**kwargs)
@@ -31,11 +37,7 @@ class LDObjectField(models.TextField):
         if not isinstance(value, basestring):
             return value
 
-        return self.from_db_value(value)
-
-    # noinspection PyUnusedLocal
-    def from_db_value(self, value, *args, **kwargs):
-        if value is None:
+        if  value == None:
             return None
 
         # in some cases, we're loading an existing array or dict,
@@ -48,9 +50,9 @@ class LDObjectField(models.TextField):
         else:
             parsed_value = value
 
-        if parsed_value is not None:
-            # we give the wrapped object back because we're not dealing with serialization types
-            return_val = LDObject.fromDict(parsed_value, type_hint=self.type_hint).wrapped_obj
+        if parsed_value != None:
+            "we give the wrapped object back because we're not dealing with serialization types"            
+            return_val = LDObject.fromDict(parsed_value, type_hint = self.type_hint).wrapped_obj
             return return_val
         else:
             return None
@@ -60,7 +62,7 @@ class LDObjectField(models.TextField):
         if isinstance(value, basestring):
             return value
 
-        if value is None:
+        if value == None:
             return None
 
         # instantiate the proper LDObject to dump it appropriately
@@ -69,4 +71,4 @@ class LDObjectField(models.TextField):
 
     def value_to_string(self, obj):
         value = self._get_val_from_obj(obj)
-        return self.get_db_prep_value(value, None)
+        return self.get_db_prep_value(value)
diff --git a/helios/datatypes/legacy.py b/helios/datatypes/legacy.py
index d469b44..c0a24ff 100644
--- a/helios/datatypes/legacy.py
+++ b/helios/datatypes/legacy.py
@@ -77,7 +77,7 @@ class Voter(LegacyObject):
         """
         depending on whether the voter is aliased, use different fields
         """
-        if self.wrapped_obj.alias is not None:
+        if self.wrapped_obj.alias != None:
             return super(Voter, self).toDict(self.ALIASED_VOTER_FIELDS, complete = complete)
         else:
             return super(Voter,self).toDict(complete = complete)
diff --git a/helios/datetimewidget.py b/helios/datetimewidget.py
index 81d81e0..5a9e0d4 100644
--- a/helios/datetimewidget.py
+++ b/helios/datetimewidget.py
@@ -25,8 +25,6 @@ calbtn = u'''<img src="%smedia/admin/img/admin/icon_calendar.gif" alt="calendar"
 </script>'''
 
 class DateTimeWidget(forms.widgets.TextInput):
-    template_name = ''
-
     class Media:
         css = {
             'all': (
diff --git a/helios/election_url_names.py b/helios/election_url_names.py
deleted file mode 100644
index eff9a5e..0000000
--- a/helios/election_url_names.py
+++ /dev/null
@@ -1,62 +0,0 @@
-ELECTION_HOME="election@home"
-ELECTION_VIEW="election@view"
-ELECTION_META="election@meta"
-ELECTION_EDIT="election@edit"
-ELECTION_SCHEDULE="election@schedule"
-ELECTION_EXTEND="election@extend"
-ELECTION_ARCHIVE="election@archive"
-ELECTION_COPY="election@copy"
-ELECTION_BADGE="election@badge"
-
-ELECTION_TRUSTEES_HOME="election@trustees"
-ELECTION_TRUSTEES_VIEW="election@trustees@view"
-ELECTION_TRUSTEES_NEW="election@trustees@new"
-ELECTION_TRUSTEES_ADD_HELIOS="election@trustees@add-helios"
-ELECTION_TRUSTEES_DELETE="election@trustees@delete"
-
-ELECTION_TRUSTEE_HOME="election@trustee"
-ELECTION_TRUSTEE_SEND_URL="election@trustee@send-url"
-ELECTION_TRUSTEE_KEY_GENERATOR="election@trustee@key-generator"
-ELECTION_TRUSTEE_CHECK_SK="election@trustee@check-sk"
-ELECTION_TRUSTEE_UPLOAD_PK="election@trustee@upload-pk"
-ELECTION_TRUSTEE_DECRYPT_AND_PROVE="election@trustee@decrypt-and-prove"
-ELECTION_TRUSTEE_UPLOAD_DECRYPTION="election@trustee@upload-decryption"
-
-ELECTION_RESULT="election@result"
-ELECTION_RESULT_PROOF="election@result@proof"
-ELECTION_BBOARD="election@bboard"
-ELECTION_AUDITED_BALLOTS="election@audited-ballots"
-
-ELECTION_GET_RANDOMNESS="election@get-randomness"
-ELECTION_ENCRYPT_BALLOT="election@encrypt-ballot"
-ELECTION_QUESTIONS="election@questions"
-ELECTION_SET_REG="election@set-reg"
-ELECTION_SET_FEATURED="election@set-featured"
-ELECTION_SAVE_QUESTIONS="election@save-questions"
-ELECTION_REGISTER="election@register"
-ELECTION_FREEZE="election@freeze"
-
-ELECTION_COMPUTE_TALLY="election@compute-tally"
-ELECTION_COMBINE_DECRYPTIONS="election@combine-decryptions"
-ELECTION_RELEASE_RESULT="election@release-result"
-
-ELECTION_CAST="election@cast"
-ELECTION_CAST_CONFIRM="election@cast-confirm"
-ELECTION_PASSWORD_VOTER_LOGIN="election@password-voter-login"
-ELECTION_CAST_DONE="election@cast-done"
-
-ELECTION_POST_AUDITED_BALLOT="election@post-audited-ballot"
-
-ELECTION_VOTERS_HOME="election@voters"
-ELECTION_VOTERS_UPLOAD="election@voters@upload"
-ELECTION_VOTERS_UPLOAD_CANCEL="election@voters@upload-cancel"
-ELECTION_VOTERS_LIST="election@voters@list"
-ELECTION_VOTERS_LIST_PRETTY="election@voters@list-pretty"
-ELECTION_VOTERS_ELIGIBILITY="election@voters@eligibility"
-ELECTION_VOTERS_EMAIL="election@voters@email"
-ELECTION_VOTER="election@voter"
-ELECTION_VOTER_DELETE="election@voter@delete"
-
-ELECTION_BALLOTS_LIST="election@ballots@list"
-ELECTION_BALLOTS_VOTER="election@ballots@voter"
-ELECTION_BALLOTS_VOTER_LAST="election@ballots@voter@last"
diff --git a/helios/election_urls.py b/helios/election_urls.py
index 6fc07ef..6622c55 100644
--- a/helios/election_urls.py
+++ b/helios/election_urls.py
@@ -4,99 +4,91 @@ Helios URLs for Election related stuff
 Ben Adida (ben@adida.net)
 """
 
-from django.conf.urls import url
+from django.conf.urls import *
 
-from helios import views
-from helios import election_url_names as names
+from helios.views import *
 
-urlpatterns = [
+urlpatterns = patterns('',
     # election data that is cryptographically verified
-    url(r'^$', views.one_election, name=names.ELECTION_HOME),
+    (r'^$', one_election),
 
     # metadata that need not be verified
-    url(r'^/meta$', views.one_election_meta, name=names.ELECTION_META),
+    (r'^/meta$', one_election_meta),
     
     # edit election params
-    url(r'^/edit$', views.one_election_edit, name=names.ELECTION_EDIT),
-    url(r'^/schedule$', views.one_election_schedule, name=names.ELECTION_SCHEDULE),
-    url(r'^/extend$', views.one_election_extend, name=names.ELECTION_EXTEND),
-    url(r'^/archive$', views.one_election_archive, name=names.ELECTION_ARCHIVE),
-    url(r'^/copy$', views.one_election_copy, name=names.ELECTION_COPY),
+    (r'^/edit$', one_election_edit),
+    (r'^/schedule$', one_election_schedule),
+    (r'^/extend$', one_election_extend),
+    (r'^/archive$', one_election_archive),
+    (r'^/copy$', one_election_copy),
 
     # badge
-    url(r'^/badge$', views.election_badge, name=names.ELECTION_BADGE),
+    (r'^/badge$', election_badge),
 
     # adding trustees
-    url(r'^/trustees/$', views.list_trustees, name=names.ELECTION_TRUSTEES_HOME),
-    url(r'^/trustees/view$', views.list_trustees_view, name=names.ELECTION_TRUSTEES_VIEW),
-    url(r'^/trustees/new$', views.new_trustee, name=names.ELECTION_TRUSTEES_NEW),
-    url(r'^/trustees/add-helios$', views.new_trustee_helios, name=names.ELECTION_TRUSTEES_ADD_HELIOS),
-    url(r'^/trustees/delete$', views.delete_trustee, name=names.ELECTION_TRUSTEES_DELETE),
+    (r'^/trustees/$', list_trustees),
+    (r'^/trustees/view$', list_trustees_view),
+    (r'^/trustees/new$', new_trustee),
+    (r'^/trustees/add-helios$', new_trustee_helios),
+    (r'^/trustees/delete$', delete_trustee),
     
     # trustee pages
-    url(r'^/trustees/(?P<trustee_uuid>[^/]+)/home$',
-        views.trustee_home, name=names.ELECTION_TRUSTEE_HOME),
-    url(r'^/trustees/(?P<trustee_uuid>[^/]+)/sendurl$',
-        views.trustee_send_url, name=names.ELECTION_TRUSTEE_SEND_URL),
-    url(r'^/trustees/(?P<trustee_uuid>[^/]+)/keygenerator$',
-        views.trustee_keygenerator, name=names.ELECTION_TRUSTEE_KEY_GENERATOR),
-    url(r'^/trustees/(?P<trustee_uuid>[^/]+)/check-sk$',
-        views.trustee_check_sk, name=names.ELECTION_TRUSTEE_CHECK_SK),
-    url(r'^/trustees/(?P<trustee_uuid>[^/]+)/upoad-pk$',
-        views.trustee_upload_pk, name=names.ELECTION_TRUSTEE_UPLOAD_PK),
-    url(r'^/trustees/(?P<trustee_uuid>[^/]+)/decrypt-and-prove$',
-        views.trustee_decrypt_and_prove, name=names.ELECTION_TRUSTEE_DECRYPT_AND_PROVE),
-    url(r'^/trustees/(?P<trustee_uuid>[^/]+)/upload-decryption$',
-        views.trustee_upload_decryption, name=names.ELECTION_TRUSTEE_UPLOAD_DECRYPTION),
+    (r'^/trustees/(?P<trustee_uuid>[^/]+)/home$', trustee_home),
+    (r'^/trustees/(?P<trustee_uuid>[^/]+)/sendurl$', trustee_send_url),
+    (r'^/trustees/(?P<trustee_uuid>[^/]+)/keygenerator$', trustee_keygenerator),
+    (r'^/trustees/(?P<trustee_uuid>[^/]+)/check-sk$', trustee_check_sk),
+    (r'^/trustees/(?P<trustee_uuid>[^/]+)/upoad-pk$', trustee_upload_pk),
+    (r'^/trustees/(?P<trustee_uuid>[^/]+)/decrypt-and-prove$', trustee_decrypt_and_prove),
+    (r'^/trustees/(?P<trustee_uuid>[^/]+)/upload-decryption$', trustee_upload_decryption),
     
     # election voting-process actions
-    url(r'^/view$', views.one_election_view, name=names.ELECTION_VIEW),
-    url(r'^/result$', views.one_election_result, name=names.ELECTION_RESULT),
-    url(r'^/result_proof$', views.one_election_result_proof, name=names.ELECTION_RESULT_PROOF),
-    # url(r'^/bboard$', views.one_election_bboard, name=names.ELECTION_BBOARD),
-    url(r'^/audited-ballots/$', views.one_election_audited_ballots, name=names.ELECTION_AUDITED_BALLOTS),
+    (r'^/view$', one_election_view),
+    (r'^/result$', one_election_result),
+    (r'^/result_proof$', one_election_result_proof),
+    # (r'^/bboard$', one_election_bboard),
+    (r'^/audited-ballots/$', one_election_audited_ballots),
 
     # get randomness
-    url(r'^/get-randomness$', views.get_randomness, name=names.ELECTION_GET_RANDOMNESS),
+    (r'^/get-randomness$', get_randomness),
 
     # server-side encryption
-    url(r'^/encrypt-ballot$', views.encrypt_ballot, name=names.ELECTION_ENCRYPT_BALLOT),
+    (r'^/encrypt-ballot$', encrypt_ballot),
 
     # construct election
-    url(r'^/questions$', views.one_election_questions, name=names.ELECTION_QUESTIONS),
-    url(r'^/set_reg$', views.one_election_set_reg, name=names.ELECTION_SET_REG),
-    url(r'^/set_featured$', views.one_election_set_featured, name=names.ELECTION_SET_FEATURED),
-    url(r'^/save_questions$', views.one_election_save_questions, name=names.ELECTION_SAVE_QUESTIONS),
-    url(r'^/register$', views.one_election_register, name=names.ELECTION_REGISTER),
-    url(r'^/freeze$', views.one_election_freeze, name=names.ELECTION_FREEZE), # includes freeze_2 as POST target
+    (r'^/questions$', one_election_questions),
+    (r'^/set_reg$', one_election_set_reg),
+    (r'^/set_featured$', one_election_set_featured),
+    (r'^/save_questions$', one_election_save_questions),
+    (r'^/register$', one_election_register),
+    (r'^/freeze$', one_election_freeze), # includes freeze_2 as POST target
     
     # computing tally
-    url(r'^/compute_tally$', views.one_election_compute_tally, name=names.ELECTION_COMPUTE_TALLY),
-    url(r'^/combine_decryptions$', views.combine_decryptions, name=names.ELECTION_COMBINE_DECRYPTIONS),
-    url(r'^/release_result$', views.release_result, name=names.ELECTION_RELEASE_RESULT),
+    (r'^/compute_tally$', one_election_compute_tally),
+    (r'^/combine_decryptions$', combine_decryptions),
+    (r'^/release_result$', release_result),
     
     # casting a ballot before we know who the voter is
-    url(r'^/cast$', views.one_election_cast, name=names.ELECTION_CAST),
-    url(r'^/cast_confirm$', views.one_election_cast_confirm, name=names.ELECTION_CAST_CONFIRM),
-    url(r'^/password_voter_login$', views.password_voter_login, name=names.ELECTION_PASSWORD_VOTER_LOGIN),
-    url(r'^/cast_done$', views.one_election_cast_done, name=names.ELECTION_CAST_DONE),
+    (r'^/cast$', one_election_cast),
+    (r'^/cast_confirm$', one_election_cast_confirm),
+    (r'^/password_voter_login$', password_voter_login),
+    (r'^/cast_done$', one_election_cast_done),
     
     # post audited ballot
-    url(r'^/post-audited-ballot', views.post_audited_ballot, name=names.ELECTION_POST_AUDITED_BALLOT),
+    (r'^/post-audited-ballot', post_audited_ballot),
     
     # managing voters
-    url(r'^/voters/$', views.voter_list, name=names.ELECTION_VOTERS_LIST),
-    url(r'^/voters/upload$', views.voters_upload, name=names.ELECTION_VOTERS_UPLOAD),
-    url(r'^/voters/upload-cancel$', views.voters_upload_cancel, name=names.ELECTION_VOTERS_UPLOAD_CANCEL),
-    url(r'^/voters/list$', views.voters_list_pretty, name=names.ELECTION_VOTERS_LIST_PRETTY),
-    url(r'^/voters/eligibility$', views.voters_eligibility, name=names.ELECTION_VOTERS_ELIGIBILITY),
-    url(r'^/voters/email$', views.voters_email, name=names.ELECTION_VOTERS_EMAIL),
-    url(r'^/voters/(?P<voter_uuid>[^/]+)$', views.one_voter, name=names.ELECTION_VOTER),
-    url(r'^/voters/(?P<voter_uuid>[^/]+)/delete$', views.voter_delete, name=names.ELECTION_VOTER_DELETE),
+    (r'^/voters/$', voter_list),
+    (r'^/voters/upload$', voters_upload),
+    (r'^/voters/upload-cancel$', voters_upload_cancel),
+    (r'^/voters/list$', voters_list_pretty),
+    (r'^/voters/eligibility$', voters_eligibility),
+    (r'^/voters/email$', voters_email),
+    (r'^/voters/(?P<voter_uuid>[^/]+)$', one_voter),
+    (r'^/voters/(?P<voter_uuid>[^/]+)/delete$', voter_delete),
     
     # ballots
-    url(r'^/ballots/$', views.ballot_list, name=names.ELECTION_BALLOTS_LIST),
-    url(r'^/ballots/(?P<voter_uuid>[^/]+)/all$', views.voter_votes, name=names.ELECTION_BALLOTS_VOTER),
-    url(r'^/ballots/(?P<voter_uuid>[^/]+)/last$', views.voter_last_vote, name=names.ELECTION_BALLOTS_VOTER_LAST),
+    (r'^/ballots/$', ballot_list),
+    (r'^/ballots/(?P<voter_uuid>[^/]+)/all$', voter_votes),
+    (r'^/ballots/(?P<voter_uuid>[^/]+)/last$', voter_last_vote),
 
-]
+)
diff --git a/helios/fixtures/users.json b/helios/fixtures/users.json
index c6e18b5..c588ce4 100644
--- a/helios/fixtures/users.json
+++ b/helios/fixtures/users.json
@@ -1,40 +1 @@
-[
-  {
-    "pk": 1,
-    "model": "helios_auth.user",
-    "fields": {
-      "info": "{}",
-      "user_id": "ben@adida.net",
-      "name": "Ben Adida",
-      "user_type": "google",
-      "token": null,
-      "admin_p": false
-    }
-  },
-  {
-    "pk": 2,
-    "model": "helios_auth.user",
-    "fields": {
-      "info": "{}",
-      "user_id": "12345",
-      "name": "Ben Adida",
-      "user_type": "facebook",
-      "token": {
-        "access_token": "1234"
-      },
-      "admin_p": false
-    }
-  },
-  {
-    "pk": 3,
-    "model": "helios_auth.user",
-    "fields": {
-      "info": "{}",
-      "user_id": "mccio@github.com",
-      "name": "Marco Ciotola",
-      "user_type": "google",
-      "token": null,
-      "admin_p": true
-    }
-  }
-]
\ No newline at end of file
+[{"pk": 1, "model": "helios_auth.user", "fields": {"info": "{}", "user_id": "ben@adida.net", "name": "Ben Adida", "user_type": "google", "token": null, "admin_p": false}},{"pk": 2, "model": "helios_auth.user", "fields": {"info": "{}", "user_id": "12345", "name": "Ben Adida", "user_type": "facebook", "token": {"access_token":"1234"}, "admin_p": false}}]
\ No newline at end of file
diff --git a/helios/forms.py b/helios/forms.py
index 86fc18e..cb10cfa 100644
--- a/helios/forms.py
+++ b/helios/forms.py
@@ -4,8 +4,8 @@ Forms for Helios
 
 from django import forms
 from models import Election
-from widgets import SplitSelectDateTimeWidget
-from fields import SplitDateTimeField
+from widgets import *
+from fields import *
 from django.conf import settings
 
 
diff --git a/helios/management/commands/helios_trustee_decrypt.py b/helios/management/commands/helios_trustee_decrypt.py
index 4788330..3dc75a4 100644
--- a/helios/management/commands/helios_trustee_decrypt.py
+++ b/helios/management/commands/helios_trustee_decrypt.py
@@ -8,10 +8,12 @@ ben@adida.net
 2010-05-22
 """
 
-from django.core.management.base import BaseCommand
+from django.core.management.base import BaseCommand, CommandError
+import csv, datetime
 
-from helios.models import Trustee
+from helios import utils as helios_utils
 
+from helios.models import *
 
 class Command(BaseCommand):
     args = ''
diff --git a/helios/management/commands/load_voter_files.py b/helios/management/commands/load_voter_files.py
index c34e682..5b82285 100644
--- a/helios/management/commands/load_voter_files.py
+++ b/helios/management/commands/load_voter_files.py
@@ -8,15 +8,12 @@ ben@adida.net
 2010-05-22
 """
 
-import datetime
-
-import csv
-import uuid
-from django.core.management.base import BaseCommand
+from django.core.management.base import BaseCommand, CommandError
+import csv, datetime
 
 from helios import utils as helios_utils
-from helios.models import User, Voter, VoterFile
 
+from helios.models import *
 
 ##
 ## UTF8 craziness for CSV
@@ -30,45 +27,42 @@ def unicode_csv_reader(unicode_csv_data, dialect=csv.excel, **kwargs):
         # decode UTF-8 back to Unicode, cell by cell:
         yield [unicode(cell, 'utf-8') for cell in row]
 
-
 def utf_8_encoder(unicode_csv_data):
     for line in unicode_csv_data:
         yield line.encode('utf-8')
-
-
+  
 def process_csv_file(election, f):
     reader = unicode_csv_reader(f)
-
+    
     num_voters = 0
     for voter in reader:
-        # bad line
-        if len(voter) < 1:
-            continue
-
-        num_voters += 1
-        voter_id = voter[0]
-        name = voter_id
-        email = voter_id
-
-        if len(voter) > 1:
-            email = voter[1]
-
-        if len(voter) > 2:
-            name = voter[2]
-
-        # create the user
-        user = User.update_or_create(user_type='password', user_id=voter_id,
-                                     info={'password': helios_utils.random_string(10), 'email': email, 'name': name})
-        user.save()
-
-        # does voter for this user already exist
-        voter = Voter.get_by_election_and_user(election, user)
-
-        # create the voter
-        if not voter:
-            voter_uuid = str(uuid.uuid1())
-            voter = Voter(uuid=voter_uuid, voter_type='password', voter_id=voter_id, name=name, election=election)
-            voter.save()
+      # bad line
+      if len(voter) < 1:
+        continue
+    
+      num_voters += 1
+      voter_id = voter[0]
+      name = voter_id
+      email = voter_id
+    
+      if len(voter) > 1:
+        email = voter[1]
+    
+      if len(voter) > 2:
+        name = voter[2]
+    
+      # create the user
+      user = User.update_or_create(user_type='password', user_id=voter_id, info = {'password': helios_utils.random_string(10), 'email': email, 'name': name})
+      user.save()
+    
+      # does voter for this user already exist
+      voter = Voter.get_by_election_and_user(election, user)
+    
+      # create the voter
+      if not voter:
+        voter_uuid = str(uuid.uuid1())
+        voter = Voter(uuid= voter_uuid, voter_type = 'password', voter_id = voter_id, name = name, election = election)
+        voter.save()
 
     return num_voters
 
@@ -76,7 +70,7 @@ def process_csv_file(election, f):
 class Command(BaseCommand):
     args = ''
     help = 'load up voters from unprocessed voter files'
-
+    
     def handle(self, *args, **options):
         # load up the voter files in order of last uploaded
         files_to_process = VoterFile.objects.filter(processing_started_at=None).order_by('uploaded_at')
@@ -92,3 +86,5 @@ class Command(BaseCommand):
             file_to_process.processing_finished_at = datetime.datetime.utcnow()
             file_to_process.num_voters = num_voters
             file_to_process.save()
+            
+            
diff --git a/helios/management/commands/verify_cast_votes.py b/helios/management/commands/verify_cast_votes.py
index e2fab71..5b7f392 100644
--- a/helios/management/commands/verify_cast_votes.py
+++ b/helios/management/commands/verify_cast_votes.py
@@ -6,10 +6,12 @@ ben@adida.net
 2010-05-22
 """
 
-from django.core.management.base import BaseCommand
+from django.core.management.base import BaseCommand, CommandError
+import csv, datetime
 
-from helios.models import CastVote
+from helios import utils as helios_utils
 
+from helios.models import *
 
 def get_cast_vote_to_verify():
     # fixme: add "select for update" functionality here
diff --git a/helios/migrations/0001_initial.py b/helios/migrations/0001_initial.py
index 8ba6efb..cb2a41e 100644
--- a/helios/migrations/0001_initial.py
+++ b/helios/migrations/0001_initial.py
@@ -87,7 +87,7 @@ class Migration(migrations.Migration):
                 ('result_proof', helios_auth.jsonfield.JSONField(null=True)),
                 ('help_email', models.EmailField(max_length=75, null=True)),
                 ('election_info_url', models.CharField(max_length=300, null=True)),
-                ('admin', models.ForeignKey(to='helios_auth.User', on_delete=models.CASCADE)),
+                ('admin', models.ForeignKey(to='helios_auth.User')),
             ],
             options={
                 'abstract': False,
@@ -100,7 +100,7 @@ class Migration(migrations.Migration):
                 ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                 ('log', models.CharField(max_length=500)),
                 ('at', models.DateTimeField(auto_now_add=True)),
-                ('election', models.ForeignKey(to='helios.Election', on_delete=models.CASCADE)),
+                ('election', models.ForeignKey(to='helios.Election')),
             ],
             options={
             },
@@ -120,7 +120,7 @@ class Migration(migrations.Migration):
                 ('pok', helios.datatypes.djangofield.LDObjectField(null=True)),
                 ('decryption_factors', helios.datatypes.djangofield.LDObjectField(null=True)),
                 ('decryption_proofs', helios.datatypes.djangofield.LDObjectField(null=True)),
-                ('election', models.ForeignKey(to='helios.Election', on_delete=models.CASCADE)),
+                ('election', models.ForeignKey(to='helios.Election')),
             ],
             options={
             },
@@ -139,8 +139,8 @@ class Migration(migrations.Migration):
                 ('vote', helios.datatypes.djangofield.LDObjectField(null=True)),
                 ('vote_hash', models.CharField(max_length=100, null=True)),
                 ('cast_at', models.DateTimeField(null=True)),
-                ('election', models.ForeignKey(to='helios.Election', on_delete=models.CASCADE)),
-                ('user', models.ForeignKey(to='helios_auth.User', null=True, on_delete=models.CASCADE)),
+                ('election', models.ForeignKey(to='helios.Election')),
+                ('user', models.ForeignKey(to='helios_auth.User', null=True)),
             ],
             options={
             },
@@ -156,7 +156,7 @@ class Migration(migrations.Migration):
                 ('processing_started_at', models.DateTimeField(null=True)),
                 ('processing_finished_at', models.DateTimeField(null=True)),
                 ('num_voters', models.IntegerField(null=True)),
-                ('election', models.ForeignKey(to='helios.Election', on_delete=models.CASCADE)),
+                ('election', models.ForeignKey(to='helios.Election')),
             ],
             options={
             },
@@ -173,13 +173,13 @@ class Migration(migrations.Migration):
         migrations.AddField(
             model_name='castvote',
             name='voter',
-            field=models.ForeignKey(to='helios.Voter', on_delete=models.CASCADE),
+            field=models.ForeignKey(to='helios.Voter'),
             preserve_default=True,
         ),
         migrations.AddField(
             model_name='auditedballot',
             name='election',
-            field=models.ForeignKey(to='helios.Election', on_delete=models.CASCADE),
+            field=models.ForeignKey(to='helios.Election'),
             preserve_default=True,
         ),
     ]
diff --git a/helios/models.py b/helios/models.py
index 4252d16..96b6654 100644
--- a/helios/models.py
+++ b/helios/models.py
@@ -6,33 +6,35 @@ Ben Adida
 (ben@adida.net)
 """
 
-import datetime
+from django.db import models, transaction
+import json
+from django.conf import settings
+from django.core.mail import send_mail
 
+import datetime, logging, uuid, random, io
 import bleach
-import copy
-import csv
-import io
-import random
-import unicodecsv
-import uuid
-from django.conf import settings
-from django.db import models, transaction
 
-from crypto import algs, utils
-from helios import datatypes
+from crypto import electionalgs, algs, utils
 from helios import utils as heliosutils
-from helios.datatypes.djangofield import LDObjectField
+import helios.views
+
+from helios import datatypes
+
+
 # useful stuff in helios_auth
-from helios_auth.jsonfield import JSONField
 from helios_auth.models import User, AUTH_SYSTEMS
+from helios_auth.jsonfield import JSONField
+from helios.datatypes.djangofield import LDObjectField
 
+import csv, copy
+import unicodecsv
 
 class HeliosModel(models.Model, datatypes.LDObjectContainer):
   class Meta:
     abstract = True
 
 class Election(HeliosModel):
-  admin = models.ForeignKey(User, on_delete=models.CASCADE)
+  admin = models.ForeignKey(User)
   
   uuid = models.CharField(max_length=50, null=False)
 
@@ -143,9 +145,6 @@ class Election(HeliosModel):
   # downloadable election info
   election_info_url = models.CharField(max_length=300, null=True)
 
-  class Meta:
-    app_label = 'helios'
-
   # metadata for the election
   @property
   def metadata(self):
@@ -576,7 +575,6 @@ class Election(HeliosModel):
 
   @property
   def url(self):
-    import helios.views
     return helios.views.get_election_url(self)
 
   def init_tally(self):
@@ -651,8 +649,7 @@ class Election(HeliosModel):
       prettified_result.append({'question': q['short_name'], 'answers': pretty_question})
 
     return prettified_result
-
-
+    
 class ElectionLog(models.Model):
   """
   a log of events for an election
@@ -662,13 +659,10 @@ class ElectionLog(models.Model):
   VOTER_FILE_ADDED = "voter file added"
   DECRYPTIONS_COMBINED = "decryptions combined"
 
-  election = models.ForeignKey(Election, on_delete=models.CASCADE)
+  election = models.ForeignKey(Election)
   log = models.CharField(max_length=500)
   at = models.DateTimeField(auto_now_add=True)
 
-  class Meta:
-    app_label = 'helios'
-
 ##
 ## UTF8 craziness for CSV
 ##
@@ -697,7 +691,7 @@ class VoterFile(models.Model):
   # path where we store voter upload 
   PATH = settings.VOTER_UPLOAD_REL_PATH
 
-  election = models.ForeignKey(Election, on_delete=models.CASCADE)
+  election = models.ForeignKey(Election)
 
   # we move to storing the content in the DB
   voter_file = models.FileField(upload_to=PATH, max_length=250,null=True)
@@ -708,9 +702,6 @@ class VoterFile(models.Model):
   processing_finished_at = models.DateTimeField(auto_now_add=False, null=True)
   num_voters = models.IntegerField(null=True)
 
-  class Meta:
-    app_label = 'helios'
-
   def itervoters(self):
     if self.voter_file_content:
       if type(self.voter_file_content) == unicode:
@@ -788,9 +779,10 @@ class VoterFile(models.Model):
 
     return num_voters
 
+
     
 class Voter(HeliosModel):
-  election = models.ForeignKey(Election, on_delete=models.CASCADE)
+  election = models.ForeignKey(Election)
   
   # let's link directly to the user now
   # FIXME: delete this as soon as migrations are set up
@@ -802,7 +794,7 @@ class Voter(HeliosModel):
 
   # for users of type password, no user object is created
   # but a dynamic user object is created automatically
-  user = models.ForeignKey('helios_auth.User', null=True, on_delete=models.CASCADE)
+  user = models.ForeignKey('helios_auth.User', null=True)
 
   # if user is null, then you need a voter login ID and password
   voter_login_id = models.CharField(max_length = 100, null=True)
@@ -821,7 +813,6 @@ class Voter(HeliosModel):
 
   class Meta:
     unique_together = (('election', 'voter_login_id'))
-    app_label = 'helios'
 
   def __init__(self, *args, **kwargs):
     super(Voter, self).__init__(*args, **kwargs)
@@ -988,7 +979,7 @@ class Voter(HeliosModel):
   
 class CastVote(HeliosModel):
   # the reference to the voter provides the voter_uuid
-  voter = models.ForeignKey(Voter, on_delete=models.CASCADE)
+  voter = models.ForeignKey(Voter)
   
   # the actual encrypted vote
   vote = LDObjectField(type_hint = 'legacy/EncryptedVote')
@@ -1012,9 +1003,6 @@ class CastVote(HeliosModel):
   # auditing purposes, like too many votes from the same IP, if it isn't expected
   cast_ip = models.GenericIPAddressField(null=True)
 
-  class Meta:
-      app_label = 'helios'
-
   @property
   def datatype(self):
     return self.voter.datatype.replace('Voter', 'CastVote')
@@ -1098,14 +1086,11 @@ class AuditedBallot(models.Model):
   """
   ballots for auditing
   """
-  election = models.ForeignKey(Election, on_delete=models.CASCADE)
+  election = models.ForeignKey(Election)
   raw_vote = models.TextField()
   vote_hash = models.CharField(max_length=100)
   added_at = models.DateTimeField(auto_now_add=True)
 
-  class Meta:
-    app_label = 'helios'
-
   @classmethod
   def get(cls, election, vote_hash):
     return cls.objects.get(election = election, vote_hash = vote_hash)
@@ -1122,10 +1107,9 @@ class AuditedBallot(models.Model):
       query = query[:limit]
 
     return query
-
-
+    
 class Trustee(HeliosModel):
-  election = models.ForeignKey(Election, on_delete=models.CASCADE)
+  election = models.ForeignKey(Election)
   
   uuid = models.CharField(max_length=50)
   name = models.CharField(max_length=200)
@@ -1156,8 +1140,7 @@ class Trustee(HeliosModel):
 
   class Meta:
     unique_together = (('election', 'email'))
-    app_label = 'helios'
-
+    
   def save(self, *args, **kwargs):
     """
     override this just to get a hook
diff --git a/helios/security.py b/helios/security.py
index 88dc675..c022821 100644
--- a/helios/security.py
+++ b/helios/security.py
@@ -7,12 +7,12 @@ Ben Adida (ben@adida.net)
 # nicely update the wrapper function
 from functools import update_wrapper
 
-from django.urls import reverse
-from django.core.exceptions import PermissionDenied
-from django.http import Http404
+from django.core.urlresolvers import reverse
+from django.core.exceptions import *
+from django.http import *
 from django.conf import settings
 
-from models import Voter, Trustee, Election
+from models import *
 from helios_auth.security import get_user
 
 from django.http import HttpResponseRedirect
@@ -22,23 +22,11 @@ import helios
 
 
 class HSTSMiddleware:
-    def __init__(self, get_response):
-        self.get_response = get_response
-        # One-time configuration and initialization.
-
-    def __call__(self, request):
-        # Code to be executed for each request before
-        # the view (and later middleware) are called.
-
-        response = self.get_response(request)
-
-        # Code to be executed for each request/response after
-        # the view is called.
-
+    def process_response(self, request, response):
         if settings.STS:
           response['Strict-Transport-Security'] = "max-age=31536000; includeSubDomains; preload"
         return response
-
+        
 # current voter
 def get_voter(request, user, election):
   """
diff --git a/helios/south_migrations/0001_initial.py b/helios/south_migrations/0001_initial.py
new file mode 100644
index 0000000..4fa118c
--- /dev/null
+++ b/helios/south_migrations/0001_initial.py
@@ -0,0 +1,259 @@
+# encoding: utf-8
+import 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 'Election'
+        db.create_table('helios_election', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('admin', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['helios_auth.User'])),
+            ('uuid', self.gf('django.db.models.fields.CharField')(max_length=50)),
+            ('short_name', self.gf('django.db.models.fields.CharField')(max_length=100)),
+            ('name', self.gf('django.db.models.fields.CharField')(max_length=250)),
+            ('description', self.gf('django.db.models.fields.TextField')()),
+            ('public_key', self.gf('helios_auth.jsonfield.JSONField')(null=True)),
+            ('private_key', self.gf('helios_auth.jsonfield.JSONField')(null=True)),
+            ('questions', self.gf('helios_auth.jsonfield.JSONField')(null=True)),
+            ('eligibility', self.gf('helios_auth.jsonfield.JSONField')(null=True)),
+            ('openreg', self.gf('django.db.models.fields.BooleanField')(default=False)),
+            ('featured_p', self.gf('django.db.models.fields.BooleanField')(default=False)),
+            ('use_voter_aliases', self.gf('django.db.models.fields.BooleanField')(default=False)),
+            ('cast_url', self.gf('django.db.models.fields.CharField')(max_length=500)),
+            ('created_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+            ('modified_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+            ('frozen_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('archived_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('registration_starts_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('voting_starts_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('voting_ends_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('tallying_starts_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('voting_started_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('voting_extended_until', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('voting_ended_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('tallying_started_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('tallying_finished_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('tallies_combined_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True)),
+            ('voters_hash', self.gf('django.db.models.fields.CharField')(max_length=100, null=True)),
+            ('encrypted_tally', self.gf('helios_auth.jsonfield.JSONField')(null=True)),
+            ('result', self.gf('helios_auth.jsonfield.JSONField')(null=True)),
+            ('result_proof', self.gf('helios_auth.jsonfield.JSONField')(null=True)),
+        ))
+        db.send_create_signal('helios', ['Election'])
+
+        # Adding model 'ElectionLog'
+        db.create_table('helios_electionlog', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('election', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['helios.Election'])),
+            ('log', self.gf('django.db.models.fields.CharField')(max_length=500)),
+            ('at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+        ))
+        db.send_create_signal('helios', ['ElectionLog'])
+
+        # Adding model 'VoterFile'
+        db.create_table('helios_voterfile', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('election', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['helios.Election'])),
+            ('voter_file', self.gf('django.db.models.fields.files.FileField')(max_length=250)),
+            ('uploaded_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+            ('processing_started_at', self.gf('django.db.models.fields.DateTimeField')(null=True)),
+            ('processing_finished_at', self.gf('django.db.models.fields.DateTimeField')(null=True)),
+            ('num_voters', self.gf('django.db.models.fields.IntegerField')(null=True)),
+        ))
+        db.send_create_signal('helios', ['VoterFile'])
+
+        # Adding model 'Voter'
+        db.create_table('helios_voter', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('election', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['helios.Election'])),
+            ('name', self.gf('django.db.models.fields.CharField')(max_length=200, null=True)),
+            ('voter_type', self.gf('django.db.models.fields.CharField')(max_length=100)),
+            ('voter_id', self.gf('django.db.models.fields.CharField')(max_length=100)),
+            ('uuid', self.gf('django.db.models.fields.CharField')(max_length=50)),
+            ('alias', self.gf('django.db.models.fields.CharField')(max_length=100, null=True)),
+            ('vote', self.gf('helios_auth.jsonfield.JSONField')(null=True)),
+            ('vote_hash', self.gf('django.db.models.fields.CharField')(max_length=100, null=True)),
+            ('cast_at', self.gf('django.db.models.fields.DateTimeField')(null=True)),
+        ))
+        db.send_create_signal('helios', ['Voter'])
+
+        # Adding model 'CastVote'
+        db.create_table('helios_castvote', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('voter', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['helios.Voter'])),
+            ('vote', self.gf('helios_auth.jsonfield.JSONField')()),
+            ('vote_hash', self.gf('django.db.models.fields.CharField')(max_length=100)),
+            ('cast_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+            ('verified_at', self.gf('django.db.models.fields.DateTimeField')(null=True)),
+            ('invalidated_at', self.gf('django.db.models.fields.DateTimeField')(null=True)),
+        ))
+        db.send_create_signal('helios', ['CastVote'])
+
+        # Adding model 'AuditedBallot'
+        db.create_table('helios_auditedballot', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('election', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['helios.Election'])),
+            ('raw_vote', self.gf('django.db.models.fields.TextField')()),
+            ('vote_hash', self.gf('django.db.models.fields.CharField')(max_length=100)),
+            ('added_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+        ))
+        db.send_create_signal('helios', ['AuditedBallot'])
+
+        # Adding model 'Trustee'
+        db.create_table('helios_trustee', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('election', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['helios.Election'])),
+            ('uuid', self.gf('django.db.models.fields.CharField')(max_length=50)),
+            ('name', self.gf('django.db.models.fields.CharField')(max_length=200)),
+            ('email', self.gf('django.db.models.fields.EmailField')(max_length=75)),
+            ('secret', self.gf('django.db.models.fields.CharField')(max_length=100)),
+            ('public_key', self.gf('helios_auth.jsonfield.JSONField')(null=True)),
+            ('public_key_hash', self.gf('django.db.models.fields.CharField')(max_length=100)),
+            ('secret_key', self.gf('helios_auth.jsonfield.JSONField')(null=True)),
+            ('pok', self.gf('helios_auth.jsonfield.JSONField')(null=True)),
+            ('decryption_factors', self.gf('helios_auth.jsonfield.JSONField')(null=True)),
+            ('decryption_proofs', self.gf('helios_auth.jsonfield.JSONField')(null=True)),
+        ))
+        db.send_create_signal('helios', ['Trustee'])
+
+
+    def backwards(self, orm):
+        
+        # Deleting model 'Election'
+        db.delete_table('helios_election')
+
+        # Deleting model 'ElectionLog'
+        db.delete_table('helios_electionlog')
+
+        # Deleting model 'VoterFile'
+        db.delete_table('helios_voterfile')
+
+        # Deleting model 'Voter'
+        db.delete_table('helios_voter')
+
+        # Deleting model 'CastVote'
+        db.delete_table('helios_castvote')
+
+        # Deleting model 'AuditedBallot'
+        db.delete_table('helios_auditedballot')
+
+        # Deleting model 'Trustee'
+        db.delete_table('helios_trustee')
+
+
+    models = {
+        'helios_auth.user': {
+            'Meta': {'unique_together': "(('user_type', 'user_id'),)", 'object_name': 'User'},
+            'admin_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'info': ('helios_auth.jsonfield.JSONField', [], {}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'token': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'user_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'user_type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.auditedballot': {
+            'Meta': {'object_name': 'AuditedBallot'},
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'raw_vote': ('django.db.models.fields.TextField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'helios.castvote': {
+            'Meta': {'object_name': 'CastVote'},
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'invalidated_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'vote': ('helios_auth.jsonfield.JSONField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'voter': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Voter']"})
+        },
+        'helios.election': {
+            'Meta': {'object_name': 'Election'},
+            'admin': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']"}),
+            'archived_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'cast_url': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {}),
+            'eligibility': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'encrypted_tally': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'featured_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'frozen_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+            'openreg': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'private_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'public_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'questions': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'registration_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'result': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'result_proof': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'short_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'tallies_combined_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_finished_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'use_voter_aliases': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'voters_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voting_ended_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_extended_until': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'})
+        },
+        'helios.electionlog': {
+            'Meta': {'object_name': 'ElectionLog'},
+            'at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'log': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+        },
+        'helios.trustee': {
+            'Meta': {'object_name': 'Trustee'},
+            'decryption_factors': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'decryption_proofs': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'pok': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'public_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'public_key_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.voter': {
+            'Meta': {'object_name': 'Voter'},
+            'alias': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'vote': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'voter_type': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'helios.voterfile': {
+            'Meta': {'object_name': 'VoterFile'},
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'num_voters': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'processing_finished_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'processing_started_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'voter_file': ('django.db.models.fields.files.FileField', [], {'max_length': '250'})
+        }
+    }
+
+    complete_apps = ['helios']
diff --git a/helios/south_migrations/0002_v3_1_new_election_and_voter_fields.py b/helios/south_migrations/0002_v3_1_new_election_and_voter_fields.py
new file mode 100644
index 0000000..a5d4e1d
--- /dev/null
+++ b/helios/south_migrations/0002_v3_1_new_election_and_voter_fields.py
@@ -0,0 +1,196 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        
+        # Adding field 'Voter.user'
+        db.add_column('helios_voter', 'user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['helios_auth.User'], null=True), keep_default=False)
+
+        # Adding field 'Voter.voter_login_id'
+        db.add_column('helios_voter', 'voter_login_id', self.gf('django.db.models.fields.CharField')(max_length=100, null=True), keep_default=False)
+
+        # Adding field 'Voter.voter_password'
+        db.add_column('helios_voter', 'voter_password', self.gf('django.db.models.fields.CharField')(max_length=100, null=True), keep_default=False)
+
+        # Adding field 'Voter.voter_name'
+        db.add_column('helios_voter', 'voter_name', self.gf('django.db.models.fields.CharField')(max_length=200, null=True), keep_default=False)
+
+        # Adding field 'Voter.voter_email'
+        db.add_column('helios_voter', 'voter_email', self.gf('django.db.models.fields.CharField')(max_length=250, null=True), keep_default=False)
+
+        # Adding field 'Election.datatype'
+        db.add_column('helios_election', 'datatype', self.gf('django.db.models.fields.CharField')(default='legacy/Election', max_length=250), keep_default=False)
+
+        # Adding field 'Election.election_type'
+        db.add_column('helios_election', 'election_type', self.gf('django.db.models.fields.CharField')(default='election', max_length=250), keep_default=False)
+
+        # Adding field 'Election.private_p'
+        db.add_column('helios_election', 'private_p', self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False)
+
+        # Adding field 'Election.use_advanced_audit_features'
+        db.add_column('helios_election', 'use_advanced_audit_features', self.gf('django.db.models.fields.BooleanField')(default=True), keep_default=False)
+
+        # Adding field 'CastVote.vote_tinyhash'
+        db.add_column('helios_castvote', 'vote_tinyhash', self.gf('django.db.models.fields.CharField')(max_length=50, unique=True, null=True), keep_default=False)
+
+
+    def backwards(self, orm):
+        
+        # Deleting field 'Voter.user'
+        db.delete_column('helios_voter', 'user_id')
+
+        # Deleting field 'Voter.voter_login_id'
+        db.delete_column('helios_voter', 'voter_login_id')
+
+        # Deleting field 'Voter.voter_password'
+        db.delete_column('helios_voter', 'voter_password')
+
+        # Deleting field 'Voter.voter_name'
+        db.delete_column('helios_voter', 'voter_name')
+
+        # Deleting field 'Voter.voter_email'
+        db.delete_column('helios_voter', 'voter_email')
+
+        # Deleting field 'Election.datatype'
+        db.delete_column('helios_election', 'datatype')
+
+        # Deleting field 'Election.election_type'
+        db.delete_column('helios_election', 'election_type')
+
+        # Deleting field 'Election.private_p'
+        db.delete_column('helios_election', 'private_p')
+
+        # Deleting field 'Election.use_advanced_audit_features'
+        db.delete_column('helios_election', 'use_advanced_audit_features')
+
+        # Deleting field 'CastVote.vote_tinyhash'
+        db.delete_column('helios_castvote', 'vote_tinyhash')
+
+
+    models = {
+        'helios_auth.user': {
+            'Meta': {'unique_together': "(('user_type', 'user_id'),)", 'object_name': 'User'},
+            'admin_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'info': ('helios_auth.jsonfield.JSONField', [], {}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'token': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'user_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'user_type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.auditedballot': {
+            'Meta': {'object_name': 'AuditedBallot'},
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'raw_vote': ('django.db.models.fields.TextField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'helios.castvote': {
+            'Meta': {'object_name': 'CastVote'},
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'invalidated_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'vote': ('helios_auth.jsonfield.JSONField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'vote_tinyhash': ('django.db.models.fields.CharField', [], {'max_length': '50', 'unique': 'True', 'null': 'True'}),
+            'voter': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Voter']"})
+        },
+        'helios.election': {
+            'Meta': {'object_name': 'Election'},
+            'admin': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']"}),
+            'archived_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'cast_url': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'datatype': ('django.db.models.fields.CharField', [], {'default': "'legacy/Election'", 'max_length': '250'}),
+            'description': ('django.db.models.fields.TextField', [], {}),
+            'election_type': ('django.db.models.fields.CharField', [], {'default': "'election'", 'max_length': '250'}),
+            'eligibility': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'encrypted_tally': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'featured_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'frozen_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+            'openreg': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'private_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'private_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'public_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'questions': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'registration_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'result': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'result_proof': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'short_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'tallies_combined_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_finished_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'use_advanced_audit_features': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'use_voter_aliases': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'voters_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voting_ended_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_extended_until': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'})
+        },
+        'helios.electionlog': {
+            'Meta': {'object_name': 'ElectionLog'},
+            'at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'log': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+        },
+        'helios.trustee': {
+            'Meta': {'object_name': 'Trustee'},
+            'decryption_factors': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'decryption_proofs': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'pok': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'public_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'public_key_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.voter': {
+            'Meta': {'object_name': 'Voter'},
+            'alias': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']", 'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'vote': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_email': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'voter_login_id': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'voter_password': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_type': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'helios.voterfile': {
+            'Meta': {'object_name': 'VoterFile'},
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'num_voters': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'processing_finished_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'processing_started_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'voter_file': ('django.db.models.fields.files.FileField', [], {'max_length': '250'})
+        }
+    }
+
+    complete_apps = ['helios']
diff --git a/helios/south_migrations/0003_v3_1_election_specific_voters_with_passwords.py b/helios/south_migrations/0003_v3_1_election_specific_voters_with_passwords.py
new file mode 100644
index 0000000..573279f
--- /dev/null
+++ b/helios/south_migrations/0003_v3_1_election_specific_voters_with_passwords.py
@@ -0,0 +1,178 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+
+class Migration(DataMigration):
+
+    def forwards(self, orm):
+        """
+        update the voters data objects to point to users when it makes sense,
+        and otherwise to copy the data needed from the users table.
+        make all elections legacy, because before now they are.
+        """
+        for e in orm.Election.objects.all():
+            e.datatype = 'legacy/Election'
+            e.save()
+
+        # use the .iterator() call to reduce caching and make this more efficient
+        # so as not to trigger a memory error
+        for v in orm.Voter.objects.all().iterator():
+            user = orm['helios_auth.User'].objects.get(user_type = v.voter_type, user_id = v.voter_id)
+
+            if v.voter_type == 'password':
+                v.voter_login_id = v.voter_id
+                v.voter_name = v.name
+
+                v.voter_email = user.info['email']
+                v.voter_password = user.info['password']
+            else:
+                v.user = user
+
+            v.save()
+
+        # also, update tinyhash for all votes
+        for cv in orm.CastVote.objects.all().iterator():
+            safe_hash = cv.vote_hash
+            for c in ['/', '+']:
+                safe_hash = safe_hash.replace(c,'')
+    
+            length = 8
+            while True:
+                vote_tinyhash = safe_hash[:length]
+                if orm.CastVote.objects.filter(vote_tinyhash = vote_tinyhash).count() == 0:
+                    break
+                length += 1
+      
+            cv.vote_tinyhash = vote_tinyhash
+            cv.save()
+
+
+    def backwards(self, orm):
+        "Write your backwards methods here."
+        raise Exception("can't revert to system-wide user passwords, rather than election specific")
+
+
+    models = {
+        'helios_auth.user': {
+            'Meta': {'unique_together': "(('user_type', 'user_id'),)", 'object_name': 'User'},
+            'admin_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'info': ('helios_auth.jsonfield.JSONField', [], {}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'token': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'user_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'user_type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.auditedballot': {
+            'Meta': {'object_name': 'AuditedBallot'},
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'raw_vote': ('django.db.models.fields.TextField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'helios.castvote': {
+            'Meta': {'object_name': 'CastVote'},
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'invalidated_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'vote': ('helios_auth.jsonfield.JSONField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'vote_tinyhash': ('django.db.models.fields.CharField', [], {'max_length': '50', 'unique': 'True', 'null': 'True'}),
+            'voter': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Voter']"})
+        },
+        'helios.election': {
+            'Meta': {'object_name': 'Election'},
+            'admin': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']"}),
+            'archived_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'cast_url': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'datatype': ('django.db.models.fields.CharField', [], {'default': "'legacy/Election'", 'max_length': '250'}),
+            'description': ('django.db.models.fields.TextField', [], {}),
+            'election_type': ('django.db.models.fields.CharField', [], {'default': "'election'", 'max_length': '250'}),
+            'eligibility': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'encrypted_tally': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'featured_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'frozen_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+            'openreg': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'private_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'private_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'public_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'questions': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'registration_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'result': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'result_proof': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'short_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'tallies_combined_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_finished_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'use_advanced_audit_features': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'use_voter_aliases': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'voters_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voting_ended_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_extended_until': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'})
+        },
+        'helios.electionlog': {
+            'Meta': {'object_name': 'ElectionLog'},
+            'at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'log': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+        },
+        'helios.trustee': {
+            'Meta': {'object_name': 'Trustee'},
+            'decryption_factors': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'decryption_proofs': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'pok': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'public_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'public_key_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.voter': {
+            'Meta': {'object_name': 'Voter'},
+            'alias': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']", 'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'vote': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_email': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'voter_login_id': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'voter_password': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_type': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'helios.voterfile': {
+            'Meta': {'object_name': 'VoterFile'},
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'num_voters': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'processing_finished_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'processing_started_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'voter_file': ('django.db.models.fields.files.FileField', [], {'max_length': '250'})
+        }
+    }
+
+    complete_apps = ['helios']
diff --git a/helios/south_migrations/0004_v3_1_remove_voter_fields.py b/helios/south_migrations/0004_v3_1_remove_voter_fields.py
new file mode 100644
index 0000000..b934e94
--- /dev/null
+++ b/helios/south_migrations/0004_v3_1_remove_voter_fields.py
@@ -0,0 +1,153 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        
+        # Deleting field 'Voter.name'
+        db.delete_column('helios_voter', 'name')
+
+        # Deleting field 'Voter.voter_id'
+        db.delete_column('helios_voter', 'voter_id')
+
+        # Deleting field 'Voter.voter_type'
+        db.delete_column('helios_voter', 'voter_type')
+
+
+    def backwards(self, orm):
+        
+        # Adding field 'Voter.name'
+        db.add_column('helios_voter', 'name', self.gf('django.db.models.fields.CharField')(max_length=200, null=True), keep_default=False)
+
+        # We cannot add back in field 'Voter.voter_id'
+        raise RuntimeError(
+            "Cannot reverse this migration. 'Voter.voter_id' and its values cannot be restored.")
+
+        # We cannot add back in field 'Voter.voter_type'
+        raise RuntimeError(
+            "Cannot reverse this migration. 'Voter.voter_type' and its values cannot be restored.")
+
+
+    models = {
+        'helios_auth.user': {
+            'Meta': {'unique_together': "(('user_type', 'user_id'),)", 'object_name': 'User'},
+            'admin_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'info': ('helios_auth.jsonfield.JSONField', [], {}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'token': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'user_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'user_type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.auditedballot': {
+            'Meta': {'object_name': 'AuditedBallot'},
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'raw_vote': ('django.db.models.fields.TextField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'helios.castvote': {
+            'Meta': {'object_name': 'CastVote'},
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'invalidated_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'vote': ('helios_auth.jsonfield.JSONField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'vote_tinyhash': ('django.db.models.fields.CharField', [], {'max_length': '50', 'unique': 'True', 'null': 'True'}),
+            'voter': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Voter']"})
+        },
+        'helios.election': {
+            'Meta': {'object_name': 'Election'},
+            'admin': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']"}),
+            'archived_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'cast_url': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'datatype': ('django.db.models.fields.CharField', [], {'default': "'legacy/Election'", 'max_length': '250'}),
+            'description': ('django.db.models.fields.TextField', [], {}),
+            'election_type': ('django.db.models.fields.CharField', [], {'default': "'election'", 'max_length': '250'}),
+            'eligibility': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'encrypted_tally': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'featured_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'frozen_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+            'openreg': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'private_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'private_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'public_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'questions': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'registration_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'result': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'result_proof': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'short_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'tallies_combined_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_finished_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'use_advanced_audit_features': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'use_voter_aliases': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'voters_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voting_ended_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_extended_until': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'})
+        },
+        'helios.electionlog': {
+            'Meta': {'object_name': 'ElectionLog'},
+            'at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'log': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+        },
+        'helios.trustee': {
+            'Meta': {'object_name': 'Trustee'},
+            'decryption_factors': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'decryption_proofs': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'pok': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'public_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'public_key_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.voter': {
+            'Meta': {'object_name': 'Voter'},
+            'alias': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']", 'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'vote': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_email': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_login_id': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'voter_password': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
+        },
+        'helios.voterfile': {
+            'Meta': {'object_name': 'VoterFile'},
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'num_voters': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'processing_finished_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'processing_started_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'voter_file': ('django.db.models.fields.files.FileField', [], {'max_length': '250'})
+        }
+    }
+
+    complete_apps = ['helios']
diff --git a/helios/south_migrations/0005_add_quarantine_fields.py b/helios/south_migrations/0005_add_quarantine_fields.py
new file mode 100644
index 0000000..b0f9f1d
--- /dev/null
+++ b/helios/south_migrations/0005_add_quarantine_fields.py
@@ -0,0 +1,154 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        
+        # Adding field 'Election.complaint_period_ends_at'
+        db.add_column('helios_election', 'complaint_period_ends_at', self.gf('django.db.models.fields.DateTimeField')(default=None, null=True), keep_default=False)
+
+        # Adding field 'CastVote.quarantined_p'
+        db.add_column('helios_castvote', 'quarantined_p', self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False)
+
+        # Adding field 'CastVote.released_from_quarantine_at'
+        db.add_column('helios_castvote', 'released_from_quarantine_at', self.gf('django.db.models.fields.DateTimeField')(null=True), keep_default=False)
+
+
+    def backwards(self, orm):
+        
+        # Deleting field 'Election.complaint_period_ends_at'
+        db.delete_column('helios_election', 'complaint_period_ends_at')
+
+        # Deleting field 'CastVote.quarantined_p'
+        db.delete_column('helios_castvote', 'quarantined_p')
+
+        # Deleting field 'CastVote.released_from_quarantine_at'
+        db.delete_column('helios_castvote', 'released_from_quarantine_at')
+
+
+    models = {
+        'helios_auth.user': {
+            'Meta': {'unique_together': "(('user_type', 'user_id'),)", 'object_name': 'User'},
+            'admin_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'info': ('helios_auth.jsonfield.JSONField', [], {}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'token': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'user_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'user_type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.auditedballot': {
+            'Meta': {'object_name': 'AuditedBallot'},
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'raw_vote': ('django.db.models.fields.TextField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'helios.castvote': {
+            'Meta': {'object_name': 'CastVote'},
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'invalidated_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'quarantined_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'released_from_quarantine_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'vote': ('helios_auth.jsonfield.JSONField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'vote_tinyhash': ('django.db.models.fields.CharField', [], {'max_length': '50', 'unique': 'True', 'null': 'True'}),
+            'voter': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Voter']"})
+        },
+        'helios.election': {
+            'Meta': {'object_name': 'Election'},
+            'admin': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']"}),
+            'archived_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'cast_url': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+            'complaint_period_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'datatype': ('django.db.models.fields.CharField', [], {'default': "'legacy/Election'", 'max_length': '250'}),
+            'description': ('django.db.models.fields.TextField', [], {}),
+            'election_type': ('django.db.models.fields.CharField', [], {'default': "'election'", 'max_length': '250'}),
+            'eligibility': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'encrypted_tally': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'featured_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'frozen_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+            'openreg': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'private_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'private_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'public_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'questions': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'registration_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'result': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'result_proof': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'short_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'tallies_combined_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_finished_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'use_advanced_audit_features': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'use_voter_aliases': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'voters_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voting_ended_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_extended_until': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'})
+        },
+        'helios.electionlog': {
+            'Meta': {'object_name': 'ElectionLog'},
+            'at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'log': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+        },
+        'helios.trustee': {
+            'Meta': {'object_name': 'Trustee'},
+            'decryption_factors': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'decryption_proofs': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'pok': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'public_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'public_key_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret_key': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.voter': {
+            'Meta': {'object_name': 'Voter'},
+            'alias': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']", 'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'vote': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_email': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_login_id': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'voter_password': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
+        },
+        'helios.voterfile': {
+            'Meta': {'object_name': 'VoterFile'},
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'num_voters': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'processing_finished_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'processing_started_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'voter_file': ('django.db.models.fields.files.FileField', [], {'max_length': '250'})
+        }
+    }
+
+    complete_apps = ['helios']
diff --git a/helios/south_migrations/0006_auto__chg_field_voter_vote__add_unique_voter_voter_login_id_election__.py b/helios/south_migrations/0006_auto__chg_field_voter_vote__add_unique_voter_voter_login_id_election__.py
new file mode 100644
index 0000000..2791e49
--- /dev/null
+++ b/helios/south_migrations/0006_auto__chg_field_voter_vote__add_unique_voter_voter_login_id_election__.py
@@ -0,0 +1,220 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        
+        # Changing field 'Voter.vote'
+        db.alter_column('helios_voter', 'vote', self.gf('helios.datatypes.djangofield.LDObjectField')(null=True))
+
+        # Adding unique constraint on 'Voter', fields ['voter_login_id', 'election']
+        db.create_unique('helios_voter', ['voter_login_id', 'election_id'])
+
+        # Changing field 'Election.result'
+        db.alter_column('helios_election', 'result', self.gf('helios.datatypes.djangofield.LDObjectField')(null=True))
+
+        # Changing field 'Election.questions'
+        db.alter_column('helios_election', 'questions', self.gf('helios.datatypes.djangofield.LDObjectField')(null=True))
+
+        # Changing field 'Election.encrypted_tally'
+        db.alter_column('helios_election', 'encrypted_tally', self.gf('helios.datatypes.djangofield.LDObjectField')(null=True))
+
+        # Changing field 'Election.eligibility'
+        db.alter_column('helios_election', 'eligibility', self.gf('helios.datatypes.djangofield.LDObjectField')(null=True))
+
+        # Changing field 'Election.private_key'
+        db.alter_column('helios_election', 'private_key', self.gf('helios.datatypes.djangofield.LDObjectField')(null=True))
+
+        # Changing field 'Election.public_key'
+        db.alter_column('helios_election', 'public_key', self.gf('helios.datatypes.djangofield.LDObjectField')(null=True))
+
+        # Changing field 'Trustee.public_key'
+        db.alter_column('helios_trustee', 'public_key', self.gf('helios.datatypes.djangofield.LDObjectField')(null=True))
+
+        # Changing field 'Trustee.decryption_proofs'
+        db.alter_column('helios_trustee', 'decryption_proofs', self.gf('helios.datatypes.djangofield.LDObjectField')(null=True))
+
+        # Changing field 'Trustee.pok'
+        db.alter_column('helios_trustee', 'pok', self.gf('helios.datatypes.djangofield.LDObjectField')(null=True))
+
+        # Changing field 'Trustee.secret_key'
+        db.alter_column('helios_trustee', 'secret_key', self.gf('helios.datatypes.djangofield.LDObjectField')(null=True))
+
+        # Changing field 'Trustee.decryption_factors'
+        db.alter_column('helios_trustee', 'decryption_factors', self.gf('helios.datatypes.djangofield.LDObjectField')(null=True))
+
+        # Changing field 'CastVote.vote'
+        db.alter_column('helios_castvote', 'vote', self.gf('helios.datatypes.djangofield.LDObjectField')())
+
+
+    def backwards(self, orm):
+        
+        # Removing unique constraint on 'Voter', fields ['voter_login_id', 'election']
+        db.delete_unique('helios_voter', ['voter_login_id', 'election_id'])
+
+        # Changing field 'Voter.vote'
+        db.alter_column('helios_voter', 'vote', self.gf('helios_auth.jsonfield.JSONField')(null=True))
+
+        # Changing field 'Election.result'
+        db.alter_column('helios_election', 'result', self.gf('helios_auth.jsonfield.JSONField')(null=True))
+
+        # Changing field 'Election.questions'
+        db.alter_column('helios_election', 'questions', self.gf('helios_auth.jsonfield.JSONField')(null=True))
+
+        # Changing field 'Election.encrypted_tally'
+        db.alter_column('helios_election', 'encrypted_tally', self.gf('helios_auth.jsonfield.JSONField')(null=True))
+
+        # Changing field 'Election.eligibility'
+        db.alter_column('helios_election', 'eligibility', self.gf('helios_auth.jsonfield.JSONField')(null=True))
+
+        # Changing field 'Election.private_key'
+        db.alter_column('helios_election', 'private_key', self.gf('helios_auth.jsonfield.JSONField')(null=True))
+
+        # Changing field 'Election.public_key'
+        db.alter_column('helios_election', 'public_key', self.gf('helios_auth.jsonfield.JSONField')(null=True))
+
+        # Changing field 'Trustee.public_key'
+        db.alter_column('helios_trustee', 'public_key', self.gf('helios_auth.jsonfield.JSONField')(null=True))
+
+        # Changing field 'Trustee.decryption_proofs'
+        db.alter_column('helios_trustee', 'decryption_proofs', self.gf('helios_auth.jsonfield.JSONField')(null=True))
+
+        # Changing field 'Trustee.pok'
+        db.alter_column('helios_trustee', 'pok', self.gf('helios_auth.jsonfield.JSONField')(null=True))
+
+        # Changing field 'Trustee.secret_key'
+        db.alter_column('helios_trustee', 'secret_key', self.gf('helios_auth.jsonfield.JSONField')(null=True))
+
+        # Changing field 'Trustee.decryption_factors'
+        db.alter_column('helios_trustee', 'decryption_factors', self.gf('helios_auth.jsonfield.JSONField')(null=True))
+
+        # Changing field 'CastVote.vote'
+        db.alter_column('helios_castvote', 'vote', self.gf('helios_auth.jsonfield.JSONField')())
+
+
+    models = {
+        'helios_auth.user': {
+            'Meta': {'unique_together': "(('user_type', 'user_id'),)", 'object_name': 'User'},
+            'admin_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'info': ('helios_auth.jsonfield.JSONField', [], {}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'token': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'user_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'user_type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.auditedballot': {
+            'Meta': {'object_name': 'AuditedBallot'},
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'raw_vote': ('django.db.models.fields.TextField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'helios.castvote': {
+            'Meta': {'object_name': 'CastVote'},
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'invalidated_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'quarantined_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'released_from_quarantine_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'vote': ('helios.datatypes.djangofield.LDObjectField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'vote_tinyhash': ('django.db.models.fields.CharField', [], {'max_length': '50', 'unique': 'True', 'null': 'True'}),
+            'voter': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Voter']"})
+        },
+        'helios.election': {
+            'Meta': {'object_name': 'Election'},
+            'admin': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']"}),
+            'archived_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'cast_url': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+            'complaint_period_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'datatype': ('django.db.models.fields.CharField', [], {'default': "'legacy/Election'", 'max_length': '250'}),
+            'description': ('django.db.models.fields.TextField', [], {}),
+            'election_type': ('django.db.models.fields.CharField', [], {'default': "'election'", 'max_length': '250'}),
+            'eligibility': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'encrypted_tally': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'featured_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'frozen_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+            'openreg': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'private_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'private_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'public_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'questions': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'registration_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'result': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'result_proof': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'short_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'tallies_combined_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_finished_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'use_advanced_audit_features': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'use_voter_aliases': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'voters_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voting_ended_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_extended_until': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'})
+        },
+        'helios.electionlog': {
+            'Meta': {'object_name': 'ElectionLog'},
+            'at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'log': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+        },
+        'helios.trustee': {
+            'Meta': {'object_name': 'Trustee'},
+            'decryption_factors': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'decryption_proofs': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'pok': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'public_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'public_key_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.voter': {
+            'Meta': {'unique_together': "(('election', 'voter_login_id'),)", 'object_name': 'Voter'},
+            'alias': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']", 'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'vote': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_email': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_login_id': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'voter_password': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
+        },
+        'helios.voterfile': {
+            'Meta': {'object_name': 'VoterFile'},
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'num_voters': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'processing_finished_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'processing_started_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'voter_file': ('django.db.models.fields.files.FileField', [], {'max_length': '250'})
+        }
+    }
+
+    complete_apps = ['helios']
diff --git a/helios/south_migrations/0007_auto__add_field_voterfile_voter_file_content__chg_field_voterfile_vote.py b/helios/south_migrations/0007_auto__add_field_voterfile_voter_file_content__chg_field_voterfile_vote.py
new file mode 100644
index 0000000..04a7f00
--- /dev/null
+++ b/helios/south_migrations/0007_auto__add_field_voterfile_voter_file_content__chg_field_voterfile_vote.py
@@ -0,0 +1,149 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        
+        # Adding field 'VoterFile.voter_file_content'
+        db.add_column('helios_voterfile', 'voter_file_content', self.gf('django.db.models.fields.TextField')(null=True), keep_default=False)
+
+        # Changing field 'VoterFile.voter_file'
+        db.alter_column('helios_voterfile', 'voter_file', self.gf('django.db.models.fields.files.FileField')(max_length=250, null=True))
+
+
+    def backwards(self, orm):
+        
+        # Deleting field 'VoterFile.voter_file_content'
+        db.delete_column('helios_voterfile', 'voter_file_content')
+
+        # User chose to not deal with backwards NULL issues for 'VoterFile.voter_file'
+        raise RuntimeError("Cannot reverse this migration. 'VoterFile.voter_file' and its values cannot be restored.")
+
+
+    models = {
+        'helios_auth.user': {
+            'Meta': {'unique_together': "(('user_type', 'user_id'),)", 'object_name': 'User'},
+            'admin_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'info': ('helios_auth.jsonfield.JSONField', [], {}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'token': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'user_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'user_type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.auditedballot': {
+            'Meta': {'object_name': 'AuditedBallot'},
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'raw_vote': ('django.db.models.fields.TextField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'helios.castvote': {
+            'Meta': {'object_name': 'CastVote'},
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'invalidated_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'quarantined_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'released_from_quarantine_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'vote': ('helios.datatypes.djangofield.LDObjectField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'vote_tinyhash': ('django.db.models.fields.CharField', [], {'max_length': '50', 'unique': 'True', 'null': 'True'}),
+            'voter': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Voter']"})
+        },
+        'helios.election': {
+            'Meta': {'object_name': 'Election'},
+            'admin': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']"}),
+            'archived_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'cast_url': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+            'complaint_period_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'datatype': ('django.db.models.fields.CharField', [], {'default': "'legacy/Election'", 'max_length': '250'}),
+            'description': ('django.db.models.fields.TextField', [], {}),
+            'election_type': ('django.db.models.fields.CharField', [], {'default': "'election'", 'max_length': '250'}),
+            'eligibility': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'encrypted_tally': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'featured_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'frozen_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+            'openreg': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'private_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'private_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'public_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'questions': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'registration_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'result': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'result_proof': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'short_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'tallies_combined_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_finished_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'use_advanced_audit_features': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'use_voter_aliases': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'voters_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voting_ended_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_extended_until': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'})
+        },
+        'helios.electionlog': {
+            'Meta': {'object_name': 'ElectionLog'},
+            'at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'log': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+        },
+        'helios.trustee': {
+            'Meta': {'object_name': 'Trustee'},
+            'decryption_factors': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'decryption_proofs': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'pok': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'public_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'public_key_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.voter': {
+            'Meta': {'unique_together': "(('election', 'voter_login_id'),)", 'object_name': 'Voter'},
+            'alias': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']", 'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'vote': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_email': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_login_id': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'voter_password': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
+        },
+        'helios.voterfile': {
+            'Meta': {'object_name': 'VoterFile'},
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'num_voters': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'processing_finished_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'processing_started_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'voter_file': ('django.db.models.fields.files.FileField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_file_content': ('django.db.models.fields.TextField', [], {'null': 'True'})
+        }
+    }
+
+    complete_apps = ['helios']
diff --git a/helios/south_migrations/0008_auto__add_unique_trustee_election_email.py b/helios/south_migrations/0008_auto__add_unique_trustee_election_email.py
new file mode 100644
index 0000000..974dfd2
--- /dev/null
+++ b/helios/south_migrations/0008_auto__add_unique_trustee_election_email.py
@@ -0,0 +1,143 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        
+        # Adding unique constraint on 'Trustee', fields ['election', 'email']
+        db.create_unique('helios_trustee', ['election_id', 'email'])
+
+
+    def backwards(self, orm):
+        
+        # Removing unique constraint on 'Trustee', fields ['election', 'email']
+        db.delete_unique('helios_trustee', ['election_id', 'email'])
+
+
+    models = {
+        'helios.auditedballot': {
+            'Meta': {'object_name': 'AuditedBallot'},
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'raw_vote': ('django.db.models.fields.TextField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'helios.castvote': {
+            'Meta': {'object_name': 'CastVote'},
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'invalidated_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'quarantined_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'released_from_quarantine_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'vote': ('helios.datatypes.djangofield.LDObjectField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'vote_tinyhash': ('django.db.models.fields.CharField', [], {'max_length': '50', 'unique': 'True', 'null': 'True'}),
+            'voter': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Voter']"})
+        },
+        'helios.election': {
+            'Meta': {'object_name': 'Election'},
+            'admin': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']"}),
+            'archived_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'cast_url': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+            'complaint_period_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'datatype': ('django.db.models.fields.CharField', [], {'default': "'legacy/Election'", 'max_length': '250'}),
+            'description': ('django.db.models.fields.TextField', [], {}),
+            'election_type': ('django.db.models.fields.CharField', [], {'default': "'election'", 'max_length': '250'}),
+            'eligibility': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'encrypted_tally': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'featured_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'frozen_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+            'openreg': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'private_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'private_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'public_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'questions': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'registration_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'result': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'result_proof': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'short_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'tallies_combined_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_finished_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'use_advanced_audit_features': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'use_voter_aliases': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'voters_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voting_ended_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_extended_until': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'})
+        },
+        'helios.electionlog': {
+            'Meta': {'object_name': 'ElectionLog'},
+            'at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'log': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+        },
+        'helios.trustee': {
+            'Meta': {'unique_together': "(('election', 'email'),)", 'object_name': 'Trustee'},
+            'decryption_factors': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'decryption_proofs': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'pok': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'public_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'public_key_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.voter': {
+            'Meta': {'unique_together': "(('election', 'voter_login_id'),)", 'object_name': 'Voter'},
+            'alias': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']", 'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'vote': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_email': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_login_id': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'voter_password': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
+        },
+        'helios.voterfile': {
+            'Meta': {'object_name': 'VoterFile'},
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'num_voters': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'processing_finished_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'processing_started_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'voter_file': ('django.db.models.fields.files.FileField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_file_content': ('django.db.models.fields.TextField', [], {'null': 'True'})
+        },
+        'helios_auth.user': {
+            'Meta': {'unique_together': "(('user_type', 'user_id'),)", 'object_name': 'User'},
+            'admin_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'info': ('helios_auth.jsonfield.JSONField', [], {}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'token': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'user_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'user_type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        }
+    }
+
+    complete_apps = ['helios']
diff --git a/helios/south_migrations/0009_auto__add_field_election_help_email.py b/helios/south_migrations/0009_auto__add_field_election_help_email.py
new file mode 100644
index 0000000..1500f0e
--- /dev/null
+++ b/helios/south_migrations/0009_auto__add_field_election_help_email.py
@@ -0,0 +1,144 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        
+        # Adding field 'Election.help_email'
+        db.add_column('helios_election', 'help_email', self.gf('django.db.models.fields.EmailField')(max_length=75, null=True), keep_default=False)
+
+
+    def backwards(self, orm):
+        
+        # Deleting field 'Election.help_email'
+        db.delete_column('helios_election', 'help_email')
+
+
+    models = {
+        'helios.auditedballot': {
+            'Meta': {'object_name': 'AuditedBallot'},
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'raw_vote': ('django.db.models.fields.TextField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'helios.castvote': {
+            'Meta': {'object_name': 'CastVote'},
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'invalidated_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'quarantined_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'released_from_quarantine_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'vote': ('helios.datatypes.djangofield.LDObjectField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'vote_tinyhash': ('django.db.models.fields.CharField', [], {'max_length': '50', 'unique': 'True', 'null': 'True'}),
+            'voter': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Voter']"})
+        },
+        'helios.election': {
+            'Meta': {'object_name': 'Election'},
+            'admin': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']"}),
+            'archived_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'cast_url': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+            'complaint_period_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'datatype': ('django.db.models.fields.CharField', [], {'default': "'legacy/Election'", 'max_length': '250'}),
+            'description': ('django.db.models.fields.TextField', [], {}),
+            'election_type': ('django.db.models.fields.CharField', [], {'default': "'election'", 'max_length': '250'}),
+            'eligibility': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'encrypted_tally': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'featured_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'frozen_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'help_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+            'openreg': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'private_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'private_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'public_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'questions': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'registration_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'result': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'result_proof': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'short_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'tallies_combined_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_finished_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'use_advanced_audit_features': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'use_voter_aliases': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'voters_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voting_ended_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_extended_until': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'})
+        },
+        'helios.electionlog': {
+            'Meta': {'object_name': 'ElectionLog'},
+            'at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'log': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+        },
+        'helios.trustee': {
+            'Meta': {'unique_together': "(('election', 'email'),)", 'object_name': 'Trustee'},
+            'decryption_factors': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'decryption_proofs': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'pok': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'public_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'public_key_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.voter': {
+            'Meta': {'unique_together': "(('election', 'voter_login_id'),)", 'object_name': 'Voter'},
+            'alias': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']", 'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'vote': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_email': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_login_id': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'voter_password': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
+        },
+        'helios.voterfile': {
+            'Meta': {'object_name': 'VoterFile'},
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'num_voters': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'processing_finished_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'processing_started_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'voter_file': ('django.db.models.fields.files.FileField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_file_content': ('django.db.models.fields.TextField', [], {'null': 'True'})
+        },
+        'helios_auth.user': {
+            'Meta': {'unique_together': "(('user_type', 'user_id'),)", 'object_name': 'User'},
+            'admin_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'info': ('helios_auth.jsonfield.JSONField', [], {}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'token': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'user_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'user_type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        }
+    }
+
+    complete_apps = ['helios']
diff --git a/helios/south_migrations/0010_auto__add_field_election_randomize_answer_order.py b/helios/south_migrations/0010_auto__add_field_election_randomize_answer_order.py
new file mode 100644
index 0000000..96d1eb0
--- /dev/null
+++ b/helios/south_migrations/0010_auto__add_field_election_randomize_answer_order.py
@@ -0,0 +1,146 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        # Adding field 'Election.randomize_answer_order'
+        db.add_column('helios_election', 'randomize_answer_order',
+                      self.gf('django.db.models.fields.BooleanField')(default=False),
+                      keep_default=False)
+
+
+    def backwards(self, orm):
+        # Deleting field 'Election.randomize_answer_order'
+        db.delete_column('helios_election', 'randomize_answer_order')
+
+
+    models = {
+        'helios.auditedballot': {
+            'Meta': {'object_name': 'AuditedBallot'},
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'raw_vote': ('django.db.models.fields.TextField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'helios.castvote': {
+            'Meta': {'object_name': 'CastVote'},
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'invalidated_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'quarantined_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'released_from_quarantine_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'vote': ('helios.datatypes.djangofield.LDObjectField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'vote_tinyhash': ('django.db.models.fields.CharField', [], {'max_length': '50', 'unique': 'True', 'null': 'True'}),
+            'voter': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Voter']"})
+        },
+        'helios.election': {
+            'Meta': {'object_name': 'Election'},
+            'admin': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']"}),
+            'archived_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'cast_url': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+            'complaint_period_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'datatype': ('django.db.models.fields.CharField', [], {'default': "'legacy/Election'", 'max_length': '250'}),
+            'description': ('django.db.models.fields.TextField', [], {}),
+            'election_type': ('django.db.models.fields.CharField', [], {'default': "'election'", 'max_length': '250'}),
+            'eligibility': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'encrypted_tally': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'featured_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'frozen_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'help_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+            'openreg': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'private_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'private_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'public_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'questions': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'randomize_answer_order': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'registration_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'result': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'result_proof': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'short_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'tallies_combined_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_finished_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'use_advanced_audit_features': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'use_voter_aliases': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'voters_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voting_ended_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_extended_until': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'})
+        },
+        'helios.electionlog': {
+            'Meta': {'object_name': 'ElectionLog'},
+            'at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'log': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+        },
+        'helios.trustee': {
+            'Meta': {'unique_together': "(('election', 'email'),)", 'object_name': 'Trustee'},
+            'decryption_factors': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'decryption_proofs': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'pok': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'public_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'public_key_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.voter': {
+            'Meta': {'unique_together': "(('election', 'voter_login_id'),)", 'object_name': 'Voter'},
+            'alias': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']", 'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'vote': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_email': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_login_id': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'voter_password': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
+        },
+        'helios.voterfile': {
+            'Meta': {'object_name': 'VoterFile'},
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'num_voters': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'processing_finished_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'processing_started_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'voter_file': ('django.db.models.fields.files.FileField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_file_content': ('django.db.models.fields.TextField', [], {'null': 'True'})
+        },
+        'helios_auth.user': {
+            'Meta': {'unique_together': "(('user_type', 'user_id'),)", 'object_name': 'User'},
+            'admin_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'info': ('helios_auth.jsonfield.JSONField', [], {}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'token': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'user_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'user_type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        }
+    }
+
+    complete_apps = ['helios']
\ No newline at end of file
diff --git a/helios/south_migrations/0011_auto__add_field_election_election_info_url.py b/helios/south_migrations/0011_auto__add_field_election_election_info_url.py
new file mode 100644
index 0000000..48c98fb
--- /dev/null
+++ b/helios/south_migrations/0011_auto__add_field_election_election_info_url.py
@@ -0,0 +1,147 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        # Adding field 'Election.election_info_url'
+        db.add_column('helios_election', 'election_info_url',
+                      self.gf('django.db.models.fields.CharField')(max_length=300, null=True),
+                      keep_default=False)
+
+
+    def backwards(self, orm):
+        # Deleting field 'Election.election_info_url'
+        db.delete_column('helios_election', 'election_info_url')
+
+
+    models = {
+        'helios.auditedballot': {
+            'Meta': {'object_name': 'AuditedBallot'},
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'raw_vote': ('django.db.models.fields.TextField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'helios.castvote': {
+            'Meta': {'object_name': 'CastVote'},
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'invalidated_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'quarantined_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'released_from_quarantine_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'vote': ('helios.datatypes.djangofield.LDObjectField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'vote_tinyhash': ('django.db.models.fields.CharField', [], {'max_length': '50', 'unique': 'True', 'null': 'True'}),
+            'voter': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Voter']"})
+        },
+        'helios.election': {
+            'Meta': {'object_name': 'Election'},
+            'admin': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']"}),
+            'archived_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'cast_url': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+            'complaint_period_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'datatype': ('django.db.models.fields.CharField', [], {'default': "'legacy/Election'", 'max_length': '250'}),
+            'description': ('django.db.models.fields.TextField', [], {}),
+            'election_info_url': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}),
+            'election_type': ('django.db.models.fields.CharField', [], {'default': "'election'", 'max_length': '250'}),
+            'eligibility': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'encrypted_tally': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'featured_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'frozen_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'help_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+            'openreg': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'private_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'private_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'public_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'questions': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'randomize_answer_order': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'registration_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'result': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'result_proof': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'short_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'tallies_combined_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_finished_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'use_advanced_audit_features': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'use_voter_aliases': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'voters_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voting_ended_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_extended_until': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'})
+        },
+        'helios.electionlog': {
+            'Meta': {'object_name': 'ElectionLog'},
+            'at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'log': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+        },
+        'helios.trustee': {
+            'Meta': {'unique_together': "(('election', 'email'),)", 'object_name': 'Trustee'},
+            'decryption_factors': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'decryption_proofs': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'pok': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'public_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'public_key_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.voter': {
+            'Meta': {'unique_together': "(('election', 'voter_login_id'),)", 'object_name': 'Voter'},
+            'alias': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']", 'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'vote': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_email': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_login_id': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'voter_password': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
+        },
+        'helios.voterfile': {
+            'Meta': {'object_name': 'VoterFile'},
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'num_voters': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'processing_finished_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'processing_started_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'voter_file': ('django.db.models.fields.files.FileField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_file_content': ('django.db.models.fields.TextField', [], {'null': 'True'})
+        },
+        'helios_auth.user': {
+            'Meta': {'unique_together': "(('user_type', 'user_id'),)", 'object_name': 'User'},
+            'admin_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'info': ('helios_auth.jsonfield.JSONField', [], {}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'token': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'user_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'user_type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        }
+    }
+
+    complete_apps = ['helios']
\ No newline at end of file
diff --git a/helios/south_migrations/0012_auto__add_field_election_result_released_at.py b/helios/south_migrations/0012_auto__add_field_election_result_released_at.py
new file mode 100644
index 0000000..0cc6853
--- /dev/null
+++ b/helios/south_migrations/0012_auto__add_field_election_result_released_at.py
@@ -0,0 +1,148 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        # Adding field 'Election.result_released_at'
+        db.add_column('helios_election', 'result_released_at',
+                      self.gf('django.db.models.fields.DateTimeField')(default=None, null=True),
+                      keep_default=False)
+
+
+    def backwards(self, orm):
+        # Deleting field 'Election.result_released_at'
+        db.delete_column('helios_election', 'result_released_at')
+
+
+    models = {
+        'helios.auditedballot': {
+            'Meta': {'object_name': 'AuditedBallot'},
+            'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'raw_vote': ('django.db.models.fields.TextField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'helios.castvote': {
+            'Meta': {'object_name': 'CastVote'},
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'invalidated_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'quarantined_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'released_from_quarantine_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'vote': ('helios.datatypes.djangofield.LDObjectField', [], {}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'vote_tinyhash': ('django.db.models.fields.CharField', [], {'max_length': '50', 'unique': 'True', 'null': 'True'}),
+            'voter': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Voter']"})
+        },
+        'helios.election': {
+            'Meta': {'object_name': 'Election'},
+            'admin': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']"}),
+            'archived_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'cast_url': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+            'complaint_period_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'datatype': ('django.db.models.fields.CharField', [], {'default': "'legacy/Election'", 'max_length': '250'}),
+            'description': ('django.db.models.fields.TextField', [], {}),
+            'election_info_url': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'}),
+            'election_type': ('django.db.models.fields.CharField', [], {'default': "'election'", 'max_length': '250'}),
+            'eligibility': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'encrypted_tally': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'featured_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'frozen_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'help_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'modified_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+            'openreg': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'private_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'private_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'public_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'questions': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'randomize_answer_order': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'registration_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'result': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'result_proof': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'result_released_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'short_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'tallies_combined_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_finished_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'tallying_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'use_advanced_audit_features': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'use_voter_aliases': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'voters_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voting_ended_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_ends_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_extended_until': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_started_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+            'voting_starts_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'})
+        },
+        'helios.electionlog': {
+            'Meta': {'object_name': 'ElectionLog'},
+            'at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'log': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+        },
+        'helios.trustee': {
+            'Meta': {'unique_together': "(('election', 'email'),)", 'object_name': 'Trustee'},
+            'decryption_factors': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'decryption_proofs': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'pok': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'public_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'public_key_hash': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'secret_key': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'helios.voter': {
+            'Meta': {'unique_together': "(('election', 'voter_login_id'),)", 'object_name': 'Voter'},
+            'alias': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'cast_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios_auth.User']", 'null': 'True'}),
+            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+            'vote': ('helios.datatypes.djangofield.LDObjectField', [], {'null': 'True'}),
+            'vote_hash': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_email': ('django.db.models.fields.CharField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_login_id': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+            'voter_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'voter_password': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
+        },
+        'helios.voterfile': {
+            'Meta': {'object_name': 'VoterFile'},
+            'election': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['helios.Election']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'num_voters': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+            'processing_finished_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'processing_started_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+            'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+            'voter_file': ('django.db.models.fields.files.FileField', [], {'max_length': '250', 'null': 'True'}),
+            'voter_file_content': ('django.db.models.fields.TextField', [], {'null': 'True'})
+        },
+        'helios_auth.user': {
+            'Meta': {'unique_together': "(('user_type', 'user_id'),)", 'object_name': 'User'},
+            'admin_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'info': ('helios_auth.jsonfield.JSONField', [], {}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'token': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'user_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'user_type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        }
+    }
+
+    complete_apps = ['helios']
\ No newline at end of file
diff --git a/helios/south_migrations/__init__.py b/helios/south_migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/helios/stats_url_names.py b/helios/stats_url_names.py
deleted file mode 100644
index 2b8ffe2..0000000
--- a/helios/stats_url_names.py
+++ /dev/null
@@ -1,5 +0,0 @@
-STATS_HOME="stats@home"
-STATS_FORCE_QUEUE="stats@force-queue"
-STATS_ELECTIONS="stats@elections"
-STATS_ELECTIONS_PROBLEMS="stats@elections-problems"
-STATS_RECENT_VOTES="stats@recent-votes"
diff --git a/helios/stats_urls.py b/helios/stats_urls.py
index ac3b143..2d26d19 100644
--- a/helios/stats_urls.py
+++ b/helios/stats_urls.py
@@ -4,15 +4,15 @@ Helios URLs for Election related stuff
 Ben Adida (ben@adida.net)
 """
 
-from django.conf.urls import url
+from django.conf.urls import *
 
-from helios.stats_views import (home, force_queue, elections, recent_problem_elections, recent_votes)
-import helios.stats_url_names as names
+from helios.stats_views import *
 
-urlpatterns = [
-    url(r'^$', home, name=names.STATS_HOME),
-    url(r'^force-queue$', force_queue, name=names.STATS_FORCE_QUEUE),
-    url(r'^elections$', elections, name=names.STATS_ELECTIONS),
-    url(r'^problem-elections$', recent_problem_elections, name=names.STATS_ELECTIONS_PROBLEMS),
-    url(r'^recent-votes$', recent_votes, name=names.STATS_RECENT_VOTES),
-]
+urlpatterns = patterns(
+    '',
+    (r'^$', home),
+    (r'^force-queue$', force_queue),
+    (r'^elections$', elections),
+    (r'^problem-elections$', recent_problem_elections),
+    (r'^recent-votes$', recent_votes),
+)
diff --git a/helios/stats_views.py b/helios/stats_views.py
index 5e71a32..7d2a62e 100644
--- a/helios/stats_views.py
+++ b/helios/stats_views.py
@@ -2,19 +2,18 @@
 Helios stats views
 """
 
-import datetime
-
+from django.core.urlresolvers import reverse
+from django.core.mail import send_mail
 from django.core.paginator import Paginator
-from django.urls import reverse
-from django.db.models import Max, Count
-from django.http import HttpResponseRedirect
+from django.http import *
+from django.db import transaction
+from django.db.models import *
 
-from helios import tasks, url_names
-from helios.models import CastVote, Election
-from helios_auth.security import get_user
-from security import PermissionDenied
-from view_utils import render_template
+from security import *
+from helios_auth.security import get_user, save_in_session_across_logouts
+from view_utils import *
 
+from helios import tasks
 
 def require_admin(request):
   user = get_user(request)
@@ -34,7 +33,7 @@ def force_queue(request):
   for cv in votes_in_queue:
     tasks.cast_vote_verify_and_store.delay(cv.id)
 
-  return HttpResponseRedirect(reverse(url_names.stats.STATS_HOME))
+  return HttpResponseRedirect(reverse(home))
 
 def elections(request):
   user = require_admin(request)
@@ -43,7 +42,8 @@ def elections(request):
   limit = int(request.GET.get('limit', 25))
   q = request.GET.get('q','')
 
-  elections = Election.objects.filter(name__icontains = q).order_by('-created_at')
+  elections = Election.objects.filter(name__icontains = q)
+  elections.all().order_by('-created_at')
   elections_paginator = Paginator(elections, limit)
   elections_page = elections_paginator.page(page)
 
diff --git a/helios/tasks.py b/helios/tasks.py
index 8610097..5f7bba8 100644
--- a/helios/tasks.py
+++ b/helios/tasks.py
@@ -4,18 +4,20 @@ Celery queued tasks for Helios
 2010-08-01
 ben@adida.net
 """
-import copy
-from celery import shared_task
-from celery.utils.log import get_logger
 
-import signals
-from models import CastVote, Election, Voter, VoterFile
+from celery.decorators import task
+
+from models import *
 from view_utils import render_template_raw
+import signals
 
+import copy
 
-@shared_task
+from django.conf import settings
+
+@task()
 def cast_vote_verify_and_store(cast_vote_id, status_update_message=None, **kwargs):
-    cast_vote = CastVote.objects.get(id=cast_vote_id)
+    cast_vote = CastVote.objects.get(id = cast_vote_id)
     result = cast_vote.verify_and_store()
 
     voter = cast_vote.voter
@@ -25,22 +27,23 @@ def cast_vote_verify_and_store(cast_vote_id, status_update_message=None, **kwarg
     if result:
         # send the signal
         signals.vote_cast.send(sender=election, election=election, user=user, voter=voter, cast_vote=cast_vote)
-
+        
         if status_update_message and user.can_update_status():
+            from views import get_election_url
+
             user.update_status(status_update_message)
     else:
-        logger = get_logger(cast_vote_verify_and_store.__name__)
+        logger = cast_vote_verify_and_store.get_logger(**kwargs)
         logger.error("Failed to verify and store %d" % cast_vote_id)
-
-
-@shared_task
+    
+@task()
 def voters_email(election_id, subject_template, body_template, extra_vars={},
                  voter_constraints_include=None, voter_constraints_exclude=None):
     """
     voter_constraints_include are conditions on including voters
     voter_constraints_exclude are conditions on excluding voters
     """
-    election = Election.objects.get(id=election_id)
+    election = Election.objects.get(id = election_id)
 
     # select the right list of voters
     voters = election.voter_set.all()
@@ -50,66 +53,61 @@ def voters_email(election_id, subject_template, body_template, extra_vars={},
         voters = voters.exclude(**voter_constraints_exclude)
 
     for voter in voters:
-        single_voter_email.delay(voter.uuid, subject_template, body_template, extra_vars)
-
+        single_voter_email.delay(voter.uuid, subject_template, body_template, extra_vars)            
 
-@shared_task
+@task()
 def voters_notify(election_id, notification_template, extra_vars={}):
-    election = Election.objects.get(id=election_id)
+    election = Election.objects.get(id = election_id)
     for voter in election.voter_set.all():
         single_voter_notify.delay(voter.uuid, notification_template, extra_vars)
 
-
-@shared_task
+@task()
 def single_voter_email(voter_uuid, subject_template, body_template, extra_vars={}):
-    voter = Voter.objects.get(uuid=voter_uuid)
+    voter = Voter.objects.get(uuid = voter_uuid)
 
     the_vars = copy.copy(extra_vars)
-    the_vars.update({'voter': voter})
+    the_vars.update({'voter' : voter})
 
     subject = render_template_raw(None, subject_template, the_vars)
     body = render_template_raw(None, body_template, the_vars)
 
     voter.send_message(subject, body)
 
-
-@shared_task
+@task()
 def single_voter_notify(voter_uuid, notification_template, extra_vars={}):
-    voter = Voter.objects.get(uuid=voter_uuid)
+    voter = Voter.objects.get(uuid = voter_uuid)
 
     the_vars = copy.copy(extra_vars)
-    the_vars.update({'voter': voter})
+    the_vars.update({'voter' : voter})
 
     notification = render_template_raw(None, notification_template, the_vars)
 
     voter.send_notification(notification)
 
-
-@shared_task
+@task()
 def election_compute_tally(election_id):
-    election = Election.objects.get(id=election_id)
+    election = Election.objects.get(id = election_id)
     election.compute_tally()
 
-    election_notify_admin.delay(election_id=election_id,
-                                subject="encrypted tally computed",
-                                body="""
+    election_notify_admin.delay(election_id = election_id,
+                                subject = "encrypted tally computed",
+                                body = """
 The encrypted tally for election %s has been computed.
 
 --
 Helios
 """ % election.name)
-
+                                
     if election.has_helios_trustee():
-        tally_helios_decrypt.delay(election_id=election.id)
-
+        tally_helios_decrypt.delay(election_id = election.id)
 
-@shared_task
+@task()
 def tally_helios_decrypt(election_id):
-    election = Election.objects.get(id=election_id)
+    election = Election.objects.get(id = election_id)
     election.helios_trustee_decrypt()
-    election_notify_admin.delay(election_id=election_id,
-                                subject='Helios Decrypt',
-                                body="""
+    election_notify_admin.delay(election_id = election_id,
+                                subject = 'Helios Decrypt',
+                                body = """
 Helios has decrypted its portion of the tally
 for election %s.
 
@@ -117,14 +115,13 @@ for election %s.
 Helios
 """ % election.name)
 
-
-@shared_task
+@task()
 def voter_file_process(voter_file_id):
-    voter_file = VoterFile.objects.get(id=voter_file_id)
+    voter_file = VoterFile.objects.get(id = voter_file_id)
     voter_file.process()
-    election_notify_admin.delay(election_id=voter_file.election.id,
-                                subject='voter file processed',
-                                body="""
+    election_notify_admin.delay(election_id = voter_file.election.id, 
+                                subject = 'voter file processed',
+                                body = """
 Your voter file upload for election %s
 has been processed.
 
@@ -134,8 +131,7 @@ has been processed.
 Helios
 """ % (voter_file.election.name, voter_file.num_voters))
 
-
-@shared_task
+@task()
 def election_notify_admin(election_id, subject, body):
-    election = Election.objects.get(id=election_id)
+    election = Election.objects.get(id = election_id)
     election.admin.send_message(subject, body)
diff --git a/helios/templates/_castconfirm_docast.html b/helios/templates/_castconfirm_docast.html
index 1a91b21..fa6b3e7 100644
--- a/helios/templates/_castconfirm_docast.html
+++ b/helios/templates/_castconfirm_docast.html
@@ -23,7 +23,7 @@ You are logged in as <u>{{voter.display_html_big|safe}}</u><br /><br />
 </form>
 
 <p>
-    <button class="tiny" onclick="document.location='{% url "election@view" election.uuid %}';">cancel</button><br />
+    <button class="tiny" onclick="document.location='./view';">cancel</button><br />
     <span style="font-size:0.8em;">If you cancel now, your ballot will <em>NOT</em> be recorded.<br />
     You can start the voting process over again, of course.</span>
 </p>
diff --git a/helios/templates/_castconfirm_password.html b/helios/templates/_castconfirm_password.html
index 03e698a..25e31de 100644
--- a/helios/templates/_castconfirm_password.html
+++ b/helios/templates/_castconfirm_password.html
@@ -1,5 +1,5 @@
 Please provide the voter ID and password you received by email.<br /><br />
-<form method="post" action="{% url "election@password-voter-login" election.uuid %}" onsubmit="show_waiting()">
+<form method="post" action="{% url "helios.views.password_voter_login" election.uuid %}" onsubmit="show_waiting()">
 <input type="hidden" name="csrf_token" value="{{csrf_token}}" />
 <input type="hidden" name="return_url" value="{{return_url}}" />
 <input type="hidden" name="cast_ballot" value="{{cast_ballot}}" />
diff --git a/helios/templates/cast_done.html b/helios/templates/cast_done.html
index dc40805..75265ab 100644
--- a/helios/templates/cast_done.html
+++ b/helios/templates/cast_done.html
@@ -15,12 +15,12 @@
 
 {% if logout %}
 <p><b>For your safety, we have logged you out.</b></p>
-<iframe width="0" height="0" border="0" frameborder="0" src="{% url "auth@logout" %}">
+<iframe width="0" height="0" border="0" frameborder="0" src="/auth/logout">
 </iframe>
 {% endif %}
 
 <p style="font-size: 1.4em;">
-[ <a href="{% url "election@view" election.uuid %}">return to election info</a> ]
+[ <a href="{% url "helios.views.one_election_view" election.uuid %}">return to election info</a> ]
 </p>
 
 {% endblock %}
diff --git a/helios/templates/castvote.html b/helios/templates/castvote.html
index 21b5fa7..1c21d73 100644
--- a/helios/templates/castvote.html
+++ b/helios/templates/castvote.html
@@ -3,7 +3,7 @@
 {% block title %}{{cast_vote.vote_tinyhash}} &mdash; {{election.name}}{% endblock %}
 {% block content %}
 <h2 class="title">Cast Vote {{cast_vote.vote_tinyhash}}</h2>
-cast in <a href="{% url "election@view" election.uuid %}">{{election.name}}</a><br />
+cast in <a href="{% url "helios.views.one_election_view" election.uuid %}">{{election.name}}</a><br />
 Fingerprint: <tt>{{cast_vote.vote_hash}}</tt><br />
 by <b><u>
 {% if the_voter.alias %}
diff --git a/helios/templates/combine_decryptions.html b/helios/templates/combine_decryptions.html
index 89d60f1..3530867 100644
--- a/helios/templates/combine_decryptions.html
+++ b/helios/templates/combine_decryptions.html
@@ -2,7 +2,7 @@
 
 {% block title %}Compute Tally &mdash; {{election.name}}{% endblock %}
 {% block content %}
-  <h2 class="title">{{election.name}} &mdash; Compute Tally <span style="font-size:0.7em;">[<a href="{% url "election@view" election.uuid %}">cancel</a>]</span></h2>
+  <h2 class="title">{{election.name}} &mdash; Compute Tally <span style="font-size:0.7em;">[<a href="{% url "helios.views.one_election_view" election.uuid %}">cancel</a>]</span></h2>
 
   <p>
     You are about to compute the tally for this election. You only will then see the results.
diff --git a/helios/templates/election_audited_ballots.html b/helios/templates/election_audited_ballots.html
index 8225c1b..2e01f9b 100644
--- a/helios/templates/election_audited_ballots.html
+++ b/helios/templates/election_audited_ballots.html
@@ -3,7 +3,7 @@
 {% block title %}Audited Ballots for {{election.name}}{% endblock %}
 
 {% block content %}
-  <h2 class="title">{{election.name}} &mdash; Audited Ballots <span style="font-size:0.7em;">[<a href="{% url "election@view" election_uuid=election.uuid %}">back to election</a>]</span></h2>
+  <h2 class="title">{{election.name}} &mdash; Audited Ballots <span style="font-size:0.7em;">[<a href="{% url "helios.views.one_election_view" election_uuid=election.uuid %}">back to election</a>]</span></h2>
 
 <p>
 When you prepare a ballot with Helios, you immediately receive a smart ballot tracker. Before you choose to cast that ballot, you have the option to ask Helios to "break open" that encrypted ballot and verify that Helios encrypted your ballot correctly. Once that's done, you can post that opened ballot here, on the audited ballots' list, for everyone to verify (your identity is not included). Once you've done this, you have to re-encrypt your choices and obtain a different smart ballot tracker. This helps reduce the chance that someone might coerce you to vote differently from your true choice.
@@ -14,7 +14,7 @@ These ballots are <em>not cast</em>, and they will not be counted. They are just
 </p>
 
 <p>
-  To verify an audited ballot, copy its entire content and paste it in the <a target="_new" href="/booth/single-ballot-verify.html?election_url={% url "election@home" election.uuid %}">single ballot verifier</a>.
+  To verify an audited ballot, copy its entire content and paste it in the <a target="_new" href="/booth/single-ballot-verify.html?election_url={% url "helios.views.one_election" election.uuid %}">single ballot verifier</a>.
 </p>
 
 {% if audited_ballots %}
diff --git a/helios/templates/election_bboard.html b/helios/templates/election_bboard.html
index 2582193..a5fd7e7 100644
--- a/helios/templates/election_bboard.html
+++ b/helios/templates/election_bboard.html
@@ -3,7 +3,7 @@
 {% block title %}Ballot Tracking Center for {{election.name}}{% endblock %}
 
 {% block content %}
-  <h2 class="title">{{election.name}} &mdash; Ballot Tracking Center <span style="font-size:0.7em;">[<a href="{% url "election@view" election_uuid=election.uuid %}">back to election</a>]</span></h2>
+  <h2 class="title">{{election.name}} &mdash; Ballot Tracking Center <span style="font-size:0.7em;">[<a href="{% url "helios.views.one_election_view" election_uuid=election.uuid %}">back to election</a>]</span></h2>
 
 <p>
   This is the ballot tracking center, which displays the tracking numbers of all cast ballots in this election.
@@ -16,15 +16,15 @@
 Voters {{offset_plus_one}} - {{offset_plus_limit}} &nbsp;&nbsp;
 
 {% if next_after %}
-<a href="{% url "election@bboard" election.uuid %}?after={{next_after}}&offset={{offset_plus_limit}}">next {{limit}}</a> &nbsp;&nbsp;
+<a href="./bboard?after={{next_after}}&offset={{offset_plus_limit}}">next {{limit}}</a> &nbsp;&nbsp;
 {% endif %}
 
 {% ifequal offset 0 %}
 {% else %}
-<a href="{% url "election@bboard" election.uuid %}">back to start</a> &nbsp;&nbsp;
+<a href="./bboard">back to start</a> &nbsp;&nbsp;
 {% endifequal %}
 {% if more_p %}
-<a href="{% url "election@bboard" election.uuid %}?after={{next_after}}&offset={{next_offset}}">next {{limit}}</a>
+<a href="./bboard?after={{next_after}}&offset={{next_offset}}">next {{limit}}</a>
 {% endif %}
 <table class="pretty">
 <tr><th>
@@ -40,7 +40,7 @@ Name
 {{voter.alias}}
 {% else %}
 <img border="0" height="20" src="/static/auth/login-icons/{{voter.voter_type}}.png" alt="{{voter.voter_type}}" /> {% if voter.name %}{{voter.name}}{% else %}{{voter.voter_id}}{% endif %}
-{% endif %}</td><td><tt style="font-size: 1.4em;;">{% if voter.vote_hash %}{{voter.vote_hash}} <span style="font-size:0.8em;">[<a href="{% url "election@ballots@voter@last" election_uuid=election.uuid voter_uuid=voter.uuid %}">view</a>]</span>{% else %}&mdash;{% endif %}</tt></td></tr>
+{% endif %}</td><td><tt style="font-size: 1.4em;;">{% if voter.vote_hash %}{{voter.vote_hash}} <span style="font-size:0.8em;">[<a href="{% url "helios.views.voter_last_vote" election_uuid=election.uuid voter_uuid=voter.uuid %}">view</a>]</span>{% else %}&mdash;{% endif %}</tt></td></tr>
 {% endfor %}
 </table>
 
diff --git a/helios/templates/election_build.html b/helios/templates/election_build.html
index 8f56185..4526d6a 100644
--- a/helios/templates/election_build.html
+++ b/helios/templates/election_build.html
@@ -1,7 +1,7 @@
 {% extends "helios/templates/cryptobase.html" %}
 
 {% block content %}
-  <h2 class="title">{{election.name}} &mdash; Questions <span style="font-size:0.7em;">[<a href="{% url "election@view" election.uuid %}">back to election</a>]</span></h2>
+  <h2 class="title">{{election.name}} &mdash; Questions <span style="font-size:0.7em;">[<a href="{% url "helios.views.one_election_view" election.uuid %}">back to election</a>]</span></h2>
 
   <script language="javascript">
 {% if election.questions %}
diff --git a/helios/templates/election_cast_confirm.html b/helios/templates/election_cast_confirm.html
index 173d729..346284c 100644
--- a/helios/templates/election_cast_confirm.html
+++ b/helios/templates/election_cast_confirm.html
@@ -73,7 +73,7 @@ requires election-specific credentials.
   {% endif %}
   </b><br /></p>
 <p>
-    [<a href="{% url "election@view" election.uuid %}">return to the main election page</a>]
+    [<a href="{% url "helios.views.one_election_view" election.uuid %}">return to the main election page</a>]
 </p>
 {% else %}
 <p>
diff --git a/helios/templates/election_compute_tally.html b/helios/templates/election_compute_tally.html
index 2ad050a..fd98440 100644
--- a/helios/templates/election_compute_tally.html
+++ b/helios/templates/election_compute_tally.html
@@ -19,12 +19,12 @@
 <input type="hidden" name="csrf_token" value="{{csrf_token}}" />
     
 <input class="button" type="submit" value="compute encrypted tally!" />
-<button onclick="document.location='{% url "election@view" election.uuid %}'; return false;">never mind</button>
+<button onclick="document.location='./view'; return false;">never mind</button>
 </form>
 {% else %}
 <p>
 No votes have been cast in this election. At least one vote must be cast before you compute the tally.<br /><br />
-<a href="{% url "election@view" election.uuid %}">back to election</a>
+<a href="./view">back to election</a>
 </p>
 {% endif %}
 </div>
diff --git a/helios/templates/election_edit.html b/helios/templates/election_edit.html
index 025b258..2519fb7 100644
--- a/helios/templates/election_edit.html
+++ b/helios/templates/election_edit.html
@@ -2,7 +2,7 @@
 
 {% block content %}
 
-  <h2 class="title">{{election.name}} &mdash; Update <span style="font-size:0.7em;">[<a href="{% url "election@view" election.uuid %}">cancel</a>]</span></h2>
+  <h2 class="title">{{election.name}} &mdash; Update <span style="font-size:0.7em;">[<a href="{% url "helios.views.one_election_view" election.uuid %}">cancel</a>]</span></h2>
   
 {% if error %}
 <p style="color: red;">
diff --git a/helios/templates/election_extend.html b/helios/templates/election_extend.html
index 813afe7..0db2c44 100644
--- a/helios/templates/election_extend.html
+++ b/helios/templates/election_extend.html
@@ -2,7 +2,7 @@
 
 {% block content %}
 
-  <h2 class="title">{{election.name}} &mdash; Extend Voting <span style="font-size:0.7em;">[<a href="{% url "election@view" election.uuid %}">cancel</a>]</span></h2>
+  <h2 class="title">{{election.name}} &mdash; Extend Voting <span style="font-size:0.7em;">[<a href="{% url "helios.views.one_election_view" election.uuid %}">cancel</a>]</span></h2>
   
   <form class="prettyform" action="" method="POST" id="edit_election_form">
     <input type="hidden" name="csrf_token" value="{{csrf_token}}" />
diff --git a/helios/templates/election_freeze.html b/helios/templates/election_freeze.html
index f0229be..a0aad4d 100644
--- a/helios/templates/election_freeze.html
+++ b/helios/templates/election_freeze.html
@@ -29,14 +29,14 @@ You must freeze the ballot before you can contact voters.
         <li>{{issue.action}}</li>
         {% endfor %}
     </ul>
-    <a href="{% url "election@view" election.uuid %}">go back to the election</a>
+    <a href="{% url "helios.views.one_election_view" election.uuid %}">go back to the election</a>
 </p>
 {% else %}
 <form method="post" action="">
 <input type="hidden" name="csrf_token" value="{{csrf_token}}" />
     
 <input class="button" type="submit" value="Freeze the ballot" />
-<button onclick="document.location='{% url "election@view" election.uuid %}'; return false;">never mind</button>
+<button onclick="document.location='./view'; return false;">never mind</button>
 </form>
 {% endif %}
 
diff --git a/helios/templates/election_keygenerator.html b/helios/templates/election_keygenerator.html
index bce34b8..4521fc9 100644
--- a/helios/templates/election_keygenerator.html
+++ b/helios/templates/election_keygenerator.html
@@ -35,7 +35,7 @@ $(document).ready(function() {
     $('#generator').hide();
 
     // get some more server-side randomness for keygen
-    $.getJSON('{% url "election@get-randomness" election.uuid %}', function(result) {
+    $.getJSON('../../get-randomness', function(result) {
        sjcl.random.addEntropy(result.randomness);
        BigInt.setup(function() {
           ELGAMAL_PARAMS = ElGamal.Params.fromJSONObject({{eg_params_json|safe}});
@@ -159,7 +159,7 @@ Your key has been generated, but you may choose to<br /><a href="javascript:clea
 </p>
 </div>
 
-<form method="post" id="pk_form" action="{% url "election@trustee@upload-pk" election.uuid trustee.uuid %}">
+<form method="post" id="pk_form" action="{% url "helios.views.trustee_upload_pk" election.uuid trustee.uuid %}">
 <h3>Your Public Key</h3>
 <p>
     It's time to upload the public key to the server.
diff --git a/helios/templates/election_not_started.html b/helios/templates/election_not_started.html
index 5fba613..4ba944e 100644
--- a/helios/templates/election_not_started.html
+++ b/helios/templates/election_not_started.html
@@ -9,6 +9,6 @@
   </p>
   
   <p>
-      <a href="{% url "election@view" election.uuid %}">back to the election</a>
+      <a href="{% url "helios.views.one_election_view" election.uuid %}">back to the election</a>
   </p>
 {% endblock %}
diff --git a/helios/templates/election_questions.html b/helios/templates/election_questions.html
index 468c65e..d7b8f73 100644
--- a/helios/templates/election_questions.html
+++ b/helios/templates/election_questions.html
@@ -2,7 +2,7 @@
 
 {% block title %}Questions for {{election.name}}{% endblock %}
 {% block content %}
-  <h3 class="title">{{election.name}} &mdash; Questions <span style="font-size:0.7em;">[<a href="{% url "election@view" election.uuid %}">back to election</a>]</span></h3>
+  <h3 class="title">{{election.name}} &mdash; Questions <span style="font-size:0.7em;">[<a href="{% url "helios.views.one_election_view" election.uuid %}">back to election</a>]</span></h3>
 
   <script language="javascript">
 {% if election.questions %}
diff --git a/helios/templates/election_register.html b/helios/templates/election_register.html
index 96a6004..e1c731e 100644
--- a/helios/templates/election_register.html
+++ b/helios/templates/election_register.html
@@ -16,7 +16,7 @@
     You are <em>not</em> registered for this election.
 </p>
 
-<form method="post" action="{% url "election@register" election.uuid %}">
+<form method="post" action="{% url "helios.views.one_election_register" election.uuid %}">
 <input type="submit" value="register!" />
 </form>
 {% endif %}
diff --git a/helios/templates/election_tallied.html b/helios/templates/election_tallied.html
index b711682..9b00b63 100644
--- a/helios/templates/election_tallied.html
+++ b/helios/templates/election_tallied.html
@@ -9,6 +9,6 @@
   </p>
   
   <p>
-      <a href="{% url "election@view" election.uuid %}">view the election tally</a>
+      <a href="{% url "helios.views.one_election_view" election.uuid %}">view the election tally</a>
   </p>
 {% endblock %}
\ No newline at end of file
diff --git a/helios/templates/election_view.html b/helios/templates/election_view.html
index fcb7121..5973c20 100644
--- a/helios/templates/election_view.html
+++ b/helios/templates/election_view.html
@@ -5,7 +5,7 @@
   <h3 class="title">{{ election.name }}
 {% if admin_p %}
 {% if not election.frozen_at %}
-<small><a class="small button" href="{% url "election@edit" election.uuid %}">edit</a></small>
+<small><a class="small button" href="{% url "helios.views.one_election_edit" election.uuid %}">edit</a></small>
 {% endif %}
 {% endif %}</h3>
 <p style="padding-top:0px; margin-top:0px">
@@ -14,8 +14,8 @@
 [archived]
 {% endif %}
 {% if admin_p %}
-&nbsp;{% if election.is_archived %}<a class="small button" href="{% url "election@archive" election_uuid=election.uuid %}?archive_p=0">unarchive it</a>{% else %}<a class="small button" href="{% url "election@archive" election_uuid=election.uuid %}?archive_p=1">archive it</a>{% endif %}
-<a class="small button" onclick="return window.confirm('Are you sure you want to copy this election?');" href="{% url "election@copy" election_uuid=election.uuid %}">copy</a>
+&nbsp;{% if election.is_archived %}<a class="small button" href="{% url "helios.views.one_election_archive" election_uuid=election.uuid %}?archive_p=0">unarchive it</a>{% else %}<a class="small button" href="{% url "helios.views.one_election_archive" election_uuid=election.uuid %}?archive_p=1">archive it</a>{% endif %}
+<a class="small button" onclick="return window.confirm('Are you sure you want to copy this election?');" href="{% url "helios.views.one_election_copy" election_uuid=election.uuid %}">copy</a>
 {% endif %}
 <br />
 {% if admin_p %}
@@ -23,12 +23,12 @@
 {% if election.featured_p %}
 this {{election.election_type}} is featured on the front page.
 {% if can_feature_p %}
-[<a href="{% url "election@set-featured" election.uuid %}?featured_p=0">unfeature it</a>]
+[<a href="{% url "helios.views.one_election_set_featured" election.uuid %}?featured_p=0">unfeature it</a>]
 {% endif %}
 {% else %}
 this {{election.election_type}} is <u>not</u> featured on the front page.
 {% if can_feature_p %}
-[<a href="{% url "election@set-featured" election.uuid %}?featured_p=1">feature it</a>]
+[<a href="{% url "helios.views.one_election_set_featured" election.uuid %}?featured_p=1">feature it</a>]
 {% endif %}
 {% endif %}
 {% endif %}
@@ -51,11 +51,11 @@ this {{election.election_type}} is <u>not</u> featured on the front page.
 {% endif %}
 
 <p align="center" style="font-size: 1.5em;">
-<a href="{% url "election@questions" election.uuid %}">questions ({% if election.questions %}{{election.questions|length}}{% else %}0{% endif %})</a>
+<a href="{% url "helios.views.one_election_questions" election.uuid %}">questions ({% if election.questions %}{{election.questions|length}}{% else %}0{% endif %})</a>
 &nbsp;&nbsp;|&nbsp;&nbsp;
-<a href="{% url "election@voters@list-pretty" election.uuid %}">voters &amp; ballots</a>
+<a href="{% url "helios.views.voters_list_pretty" election.uuid %}">voters &amp; ballots</a>
 &nbsp;&nbsp;|&nbsp;&nbsp;
-<a href="{% url "election@trustees@view" election.uuid %}">trustees ({{trustees|length}})</a>
+<a href="{% url "helios.views.list_trustees_view" election.uuid %}">trustees ({{trustees|length}})</a>
 </p>
 
 {% if admin_p %}
@@ -87,7 +87,7 @@ this {{election.election_type}} is <u>not</u> featured on the front page.
 {{issue.action}}{% if forloop.last %}{% else %}, and{% endif %}<br />
 {% endfor %}
 {% else %}
-<a href="{% url "election@freeze" election.uuid %}">freeze ballot and open election.</a>
+<a href="{% url "helios.views.one_election_freeze" election.uuid %}">freeze ballot and open election.</a>
 <br />
 {% if election.voting_starts_at %}
 once you do this, the election will be ready for voting and will open automatically<br />
@@ -104,20 +104,20 @@ once you do this, the election will be immediately open for voting.
 Tally computation is under way.<br />
 Reload this page in a couple of minutes.
 {% else %}
-<a href="{% url "election@compute-tally" election.uuid %}">compute encrypted tally</a><br />
+<a href="{% url "helios.views.one_election_compute_tally" election.uuid %}">compute encrypted tally</a><br />
 The encrypted votes will be combined into an encrypted tally. Once this is done,<br />
 trustees will be asked to provide their share of the decryption.
 {% endif %}
 {% else %}
 
 {% if election.result %}
-<a href="{% url "election@release-result" election.uuid %}">release result</a><br />
+<a href="{% url "helios.views.release_result" election.uuid %}">release result</a><br />
 The result displayed below is visible only to you.<br />
 Once you release the result, it will be visible to everyone.
 {% else %}
 
 {% if election.ready_for_decryption_combination %}
-<a href="{% url "election@combine-decryptions" election.uuid %}">
+<a href="{% url "helios.views.combine_decryptions" election.uuid %}">
 {% if election.num_trustees == 1 %}
 compute results
 {% else %}
@@ -131,7 +131,7 @@ The decryption shares from the trustees will be combined and the tally computed.
 Once you do this, the tally will visible to you, the administrator, only.
 {% endif %}
 {% else %}
-<a href="{% url "election@trustees@view" election.uuid %}">trustees (for decryption)</a>
+<a href="{% url "helios.views.list_trustees_view" election.uuid %}">trustees (for decryption)</a>
 {% endif %}
 
 {% endif %}
@@ -236,7 +236,7 @@ You are <em>not eligible</em> to vote in this {{election.election_type}}.
 {% if election.openreg %}
 {% if election.eligibility %}
 This election is open to: {{election.pretty_eligibility|safe}}
-<a href="{{settings.SECURE_URL_HOST}}{% url "auth@index" %}?return_url={{CURRENT_URL}}">Log in</a> to check your eligibility.
+<a href="{{settings.SECURE_URL_HOST}}{% url "helios_auth.views.index" %}?return_url={{CURRENT_URL}}">Log in</a> to check your eligibility.
 {% else %}
 Anyone can vote in this election.
 {% endif %}
@@ -249,7 +249,7 @@ Anyone can vote in this election.
 {% endif %}
 
 {% if admin_p and election.voting_ends_at and not election.tallying_started_at %}
-<br /><a href="{% url "election@extend" election.uuid %}">extend voting</a><br />
+<br /><a href="{% url "helios.views.one_election_extend" election.uuid %}">extend voting</a><br />
 {% endif %}
 
 <div style="background: lightyellow; padding:5px; padding-left: 10px; margin-top: 15px; border: 1px solid #aaa; width: 720px;" class="round">
@@ -271,22 +271,22 @@ Anyone can vote in this election.
 {% endif %}
 
 <p style="font-size: 1.3em;">
-<a href="{% url "election@voters@list-pretty" election.uuid %}">Ballot Tracking Center</a> &nbsp;| &nbsp;
-<a href="{% url "election@audited-ballots" election.uuid %}">Audited Ballots</a>
+<a href="{% url "helios.views.voters_list_pretty" election.uuid %}">Ballot Tracking Center</a> &nbsp;| &nbsp;
+<a href="{% url "helios.views.one_election_audited_ballots" election.uuid %}">Audited Ballots</a>
 </p>
 
 {% endif %}
 
 {% if not election.voting_has_started %}
 <p style="font-size: 1.2em;">
-  <a href="{{SECURE_URL_HOST}}/booth/vote.html?election_url={% url "election@home" election.uuid %}">preview booth</a>
+  <a href="{{SECURE_URL_HOST}}/booth/vote.html?election_url={% url "helios.views.one_election" election.uuid %}">preview booth</a>
 </p>
 {% endif %}  
 
 {% if election.voting_has_stopped %}
 <p style="font-size: 1.2em;">
 {% if election.result %}
-verify <a target="_blank" href="/verifier/verify.html?election_url={% url "election@home" election.uuid %}">election tally</a>.
+verify <a target="_blank" href="/verifier/verify.html?election_url={% url "helios.views.one_election" election.uuid %}">election tally</a>.
 {% endif %}
 
 review the <a href="{{vote_url}}">voting booth</a>.
diff --git a/helios/templates/elections_administered.html b/helios/templates/elections_administered.html
index 563ecc9..03bc226 100644
--- a/helios/templates/elections_administered.html
+++ b/helios/templates/elections_administered.html
@@ -5,7 +5,7 @@
 
 <ul>
 {% for election in elections %}
-<li> <a href="{% url "election@view" election.uuid %}">{{election.name}}</a><em> - {{election.num_voters}} voters / {{election.num_cast_votes}} cast votes</em></li>
+<li> <a href="{% url "helios.views.one_election_view" election.uuid %}">{{election.name}}</a><em> - {{election.num_voters}} voters / {{election.num_cast_votes}} cast votes</em></li>
 {% endfor %}
 </ul>
 {% endblock %}
\ No newline at end of file
diff --git a/helios/templates/elections_voted.html b/helios/templates/elections_voted.html
index f013a98..7447eb0 100644
--- a/helios/templates/elections_voted.html
+++ b/helios/templates/elections_voted.html
@@ -5,7 +5,7 @@
 
 <ul>
 {% for election in elections %}
-<li> <a href="{% url "election@view" election.uuid %}">{{election.name}}</a></li>
+<li> <a href="{% url "helios.views.one_election_view" election.uuid %}">{{election.name}}</a></li>
 {% endfor %}
 </ul>
 {% endblock %}
diff --git a/helios/templates/list_trustees.html b/helios/templates/list_trustees.html
index 47032c4..39ddd55 100644
--- a/helios/templates/list_trustees.html
+++ b/helios/templates/list_trustees.html
@@ -3,7 +3,7 @@
 {% block title %}Trustees for {{election.name}}{% endblock %}
 
 {% block content %}
-  <h3 class="title">{{election.name}} &mdash; Trustees <span style="font-size:0.7em;">[<a href="{% url "election@view" election.uuid %}">back to election</a>]</span></h3>
+  <h3 class="title">{{election.name}} &mdash; Trustees <span style="font-size:0.7em;">[<a href="{% url "helios.views.one_election_view" election.uuid %}">back to election</a>]</span></h3>
 
 <p>
     Trustees are responsible for decrypting the election result.<br />
@@ -21,11 +21,11 @@
 
 {% if admin_p %}
 <p>
-    [ <a onclick="return(confirm('Adding your own trustee requires a good bit more work to tally the election.\nYou will need to have trustees generate keypairs and safeguard their secret key.\n\nIf you are not sure what that means, we strongly recommend\nclicking Cancel and letting Helios tally the election for you.'));" href="{% url "election@trustees@new" election.uuid %}">add a trustee</a> ]
+    [ <a onclick="return(confirm('Adding your own trustee requires a good bit more work to tally the election.\nYou will need to have trustees generate keypairs and safeguard their secret key.\n\nIf you are not sure what that means, we strongly recommend\nclicking Cancel and letting Helios tally the election for you.'));" href="{% url "helios.views.new_trustee" election.uuid %}">add a trustee</a> ]
 </p>
 {% if not election.has_helios_trustee %}
 <p>
-    <a href="{% url "election@trustees@add-helios" election.uuid %}">add Helios as a trustee</a>
+    <a href="{% url "helios.views.new_trustee_helios" election.uuid %}">add Helios as a trustee</a>
 </p>
 {% endif %}
 {% endif %}
@@ -39,11 +39,11 @@
 <h5> Trustee #{{forloop.counter}}: {{t.name}} 
 {% if admin_p %}
 {% if t.secret_key %}
-{% if not election.frozen_at %}[<a onclick="return confirm('Are you sure you want to remove Helios as a trustee?');" href="{% url "election@trustees@delete" election.uuid %}?uuid={{t.uuid}}">x</a>]{% endif %}
+{% if not election.frozen_at %}[<a onclick="return confirm('Are you sure you want to remove Helios as a trustee?');" href="{% url "helios.views.delete_trustee" election.uuid %}?uuid={{t.uuid}}">x</a>]{% endif %}
 {% else %}
 ({{t.email}})
-{% if not election.frozen_at %}[<a onclick="return confirm('Are you sure you want to remove this Trustee?');" href="{% url "election@trustees@delete" election.uuid %}?uuid={{t.uuid}}">x</a>]{% endif %}
-[<a onclick="return confirm('Are you sure you want to send this trustee his/her admin URL?');" href="{% url "election@trustee@send-url" election.uuid t.uuid %}">send login</a>]
+{% if not election.frozen_at %}[<a onclick="return confirm('Are you sure you want to remove this Trustee?');" href="{% url "helios.views.delete_trustee" election.uuid %}?uuid={{t.uuid}}">x</a>]{% endif %}
+[<a onclick="return confirm('Are you sure you want to send this trustee his/her admin URL?');" href="{% url "helios.views.trustee_send_url" election.uuid t.uuid %}">send login</a>]
 {% endif %}
 {% endif %}
 </h5>
diff --git a/helios/templates/new_trustee.html b/helios/templates/new_trustee.html
index 75af054..0df1a27 100644
--- a/helios/templates/new_trustee.html
+++ b/helios/templates/new_trustee.html
@@ -1,7 +1,7 @@
 {% extends "helios/templates/cryptobase.html" %}
 
 {% block content %}
-  <h2 class="title">{{election.name}} &mdash; New Trustee <span style="font-size:0.7em;">[<a href="{% url "election@trustees@view" election.uuid %}">cancel</a>]</span></h2>
+  <h2 class="title">{{election.name}} &mdash; New Trustee <span style="font-size:0.7em;">[<a href="{% url "helios.views.list_trustees_view" election.uuid %}">cancel</a>]</span></h2>
   
 <form method="post" action="">
 <input type="hidden" name="csrf_token" value="{{csrf_token}}" />
diff --git a/helios/templates/release_result.html b/helios/templates/release_result.html
index 5e467e4..cac6c64 100644
--- a/helios/templates/release_result.html
+++ b/helios/templates/release_result.html
@@ -2,7 +2,7 @@
 
 {% block title %}Release Result &mdash; {{election.name}}{% endblock %}
 {% block content %}
-  <h2 class="title">{{election.name}} &mdash; Release Result <span style="font-size:0.7em;">[<a href="{% url "election@view" election.uuid %}">cancel</a>]</span></h2>
+  <h2 class="title">{{election.name}} &mdash; Release Result <span style="font-size:0.7em;">[<a href="{% url "helios.views.one_election_view" election.uuid %}">cancel</a>]</span></h2>
 
   <p>
     You are about to release the result for this election.
diff --git a/helios/templates/stats.html b/helios/templates/stats.html
index 3f2bffe..37468b7 100644
--- a/helios/templates/stats.html
+++ b/helios/templates/stats.html
@@ -5,11 +5,11 @@
 <h1>Admin</h1>
 
 <ul>
-<li> <a href="{% url "stats@elections" %}">elections</a></li>
-<li> <a href="{% url "stats@recent-votes" %}">recent votes</a></li>
-<li> <a href="{% url "stats@elections-problems" %}">recent problem elections</a></li>
+<li> <a href="{% url "helios.stats_views.elections" %}">elections</a></li>
+<li> <a href="{% url "helios.stats_views.recent_votes" %}">recent votes</a></li>
+<li> <a href="{% url "helios.stats_views.recent_problem_elections" %}">recent problem elections</a></li>
 </ul>
 
-<p><b>{{num_votes_in_queue}}</b> votes in queue. {% if num_votes_in_queue %}[<a href="{% url "stats@force-queue" %}">force it</a>]{% endif %}</p>
+<p><b>{{num_votes_in_queue}}</b> votes in queue. {% if num_votes_in_queue %}[<a href="{% url "helios.stats_views.force_queue" %}">force it</a>]{% endif %}</p>
 
 {% endblock %}
diff --git a/helios/templates/stats_elections.html b/helios/templates/stats_elections.html
index e9a498e..7179698 100644
--- a/helios/templates/stats_elections.html
+++ b/helios/templates/stats_elections.html
@@ -5,7 +5,7 @@
 <h1>Elections</h1>
 
 <p>
-<form method="get" action="{% url "stats@elections" %}">
+<form method="get" action="{% url "helios.stats_views.elections" %}">
 <b>search</b>: <input type="text" name="q" value="{{q}}"/> 
 <input class="small button" type="submit" value="search" /> <a class="small button" href="?">clear search</a>
 </form>
@@ -26,7 +26,7 @@ Elections {{elections_page.start_index}} - {{elections_page.end_index}} (of {{to
 
 {% for election in elections %}
 <p>
-<b><a href="{% url "election@view" election.uuid %}">{{election.name}}</a></b> by <a href="mailto:{{election.admin.info.email}}">{{election.admin.pretty_name}}</a> -- {{election.num_voters}} voters / {{election.num_cast_votes}} cast votes
+<b><a href="{% url "helios.views.one_election_view" election.uuid %}">{{election.name}}</a></b> by <a href="mailto:{{election.admin.info.email}}">{{election.admin.pretty_name}}</a> -- {{election.num_voters}} voters / {{election.num_cast_votes}} cast votes
 </p>
 {% endfor %}
 
diff --git a/helios/templates/stats_problem_elections.html b/helios/templates/stats_problem_elections.html
index 2f82f74..9f8c1da 100644
--- a/helios/templates/stats_problem_elections.html
+++ b/helios/templates/stats_problem_elections.html
@@ -8,7 +8,7 @@ Unfrozen for more than a day.
 
 {% for election in elections %}
 <p>
-<b><a href="{% url "election@view" election.uuid %}">{{election.name}}</a></b> -- {{election.num_voters}} voters
+<b><a href="{% url "helios.views.one_election_view" election.uuid %}">{{election.name}}</a></b> -- {{election.num_voters}} voters
 </p>
 {% endfor %}
 
diff --git a/helios/templates/stats_recent_votes.html b/helios/templates/stats_recent_votes.html
index bf360a2..37c0741 100644
--- a/helios/templates/stats_recent_votes.html
+++ b/helios/templates/stats_recent_votes.html
@@ -8,7 +8,7 @@ Last 24 hours
 
 {% for election in elections %}
 <p>
-<b><a href="{% url "election@view" election.uuid %}">{{election.name}}</a></b> -- {{election.last_cast_vote}} {{election.num_recent_cast_votes}} recently cast votes
+<b><a href="{% url "helios.views.one_election_view" election.uuid %}">{{election.name}}</a></b> -- {{election.last_cast_vote}} {{election.num_recent_cast_votes}} recently cast votes
 </p>
 {% endfor %}
 
diff --git a/helios/templates/trustee_check_sk.html b/helios/templates/trustee_check_sk.html
index 99380d3..81afe42 100644
--- a/helios/templates/trustee_check_sk.html
+++ b/helios/templates/trustee_check_sk.html
@@ -43,7 +43,7 @@ function check_sk(sk_value) {
     }
 }
 </script>
-  <h2 class="title">{{election.name}} &mdash; Trustee {{trustee.name}} &mdash; Check Secret Key <span style="font-size:0.7em;">[<a href="{% url "election@trustee" election_uuid=election.uuid trustee_uuid=trustee.uuid %}">back to trustee home</a>]</span></h2>
+  <h2 class="title">{{election.name}} &mdash; Trustee {{trustee.name}} &mdash; Check Secret Key <span style="font-size:0.7em;">[<a href="./home">back to trustee home</a>]</span></h2>
 
 <p>
 Your public key fingerprint is: <b>{{trustee.public_key_hash}}</b>
diff --git a/helios/templates/trustee_decrypt_and_prove.html b/helios/templates/trustee_decrypt_and_prove.html
index cb4c2e6..05153b8 100644
--- a/helios/templates/trustee_decrypt_and_prove.html
+++ b/helios/templates/trustee_decrypt_and_prove.html
@@ -195,7 +195,7 @@ function reset() {
   </div>
   
   <div id="done_div">
-      Done! <a href="{% url "election@view" election.uuid %}">Back to election</a>
+      Done! <a href="{% url "helios.views.one_election_view" election.uuid %}">Back to election</a>
   </div>
   
   <div id="error_div">
diff --git a/helios/templates/trustee_home.html b/helios/templates/trustee_home.html
index 8d6dd11..5f6ee9c 100644
--- a/helios/templates/trustee_home.html
+++ b/helios/templates/trustee_home.html
@@ -7,9 +7,9 @@
 {% if trustee.public_key_hash %}
 You have successfully uploaded your public key.<br />
 Your public key fingerprint is: <b>{{trustee.public_key_hash}}</b>.<br />
-You can <a href="{% url "election@trustee@check-sk" election.uuid trustee.uuid %}">verify that you have the right secret key</a>.
+You can <a href="{% url "helios.views.trustee_check_sk" election.uuid trustee.uuid %}">verify that you have the right secret key</a>.
 {% else %}
-<a href="{% url "election@trustee@key-generator" election.uuid trustee.uuid %}">setup your key</a>
+<a href="{% url "helios.views.trustee_keygenerator" election.uuid trustee.uuid %}">setup your key</a>
 {% endif %}
 </p>
 
@@ -19,7 +19,7 @@ You can <a href="{% url "election@trustee@check-sk" election.uuid trustee.uuid %
 You have successfully uploaded your decryption.
 {% else %}
     The encrypted tally for this election is ready.<br />
-    <a href="{% url "election@trustee@decrypt-and-prove" election.uuid trustee.uuid %}">decrypt with your key</a>
+    <a href="{% url "helios.views.trustee_decrypt_and_prove" election.uuid trustee.uuid %}">decrypt with your key</a>
 {% endif %}
 {% else %}
 Once the tally is computed, come back here to provide your secret key for decryption purposes.<br />
diff --git a/helios/templates/voters_eligibility.html b/helios/templates/voters_eligibility.html
index 0baa6f7..51343be 100644
--- a/helios/templates/voters_eligibility.html
+++ b/helios/templates/voters_eligibility.html
@@ -2,7 +2,7 @@
 
 {% block title %}Voter Eligibility for {{election.name}}{% endblock %}
 {% block content %}
-  <h2 class="title">{{election.name}} &mdash; Voter Eligibility <span style="font-size:0.7em;">[<a href="{% url "election@voters@list-pretty" election.uuid %}">back to voters</a>]</span></h2>
+  <h2 class="title">{{election.name}} &mdash; Voter Eligibility <span style="font-size:0.7em;">[<a href="{% url "helios.views.voters_list_pretty" election.uuid %}">back to voters</a>]</span></h2>
 
 <p>
 <em>{{election.pretty_eligibility|safe}}</em>
diff --git a/helios/templates/voters_email.html b/helios/templates/voters_email.html
index 62a6c7d..535f753 100644
--- a/helios/templates/voters_email.html
+++ b/helios/templates/voters_email.html
@@ -9,7 +9,7 @@ voter_id = '{{voter.voter_id}}';
 {% endif %}
 </script>
 
-  <h2 class="title">{{election.name}} &mdash; Contact Voters <span style="font-size:0.7em;">[<a href="{% url "election@view" election.uuid %}">back to election</a>]</span></h2>
+  <h2 class="title">{{election.name}} &mdash; Contact Voters <span style="font-size:0.7em;">[<a href="{% url "helios.views.one_election_view" election.uuid %}">back to election</a>]</span></h2>
 
 {% if voter %}  
   <p>
@@ -55,7 +55,7 @@ You may tweak the subject and add a custom message using the form below.
   </div>
   
   <div id="done" style="display:none;">
-    Done, go <a href="{% url "election@view" election.uuid %}">back to election</a>.
+    Done, go <a href="{% url "helios.views.one_election_view" election.uuid %}">back to election</a>.
   </div>
 
   <div id="error" style="display:none;">
diff --git a/helios/templates/voters_list.html b/helios/templates/voters_list.html
index 3b345a0..fffe57f 100644
--- a/helios/templates/voters_list.html
+++ b/helios/templates/voters_list.html
@@ -2,7 +2,7 @@
 
 {% block title %}Voters &amp; Ballot Tracking Center for {{election.name}}{% endblock %}
 {% block content %}
-  <h3 class="title">{{election.name}} &mdash; Voters and Ballot Tracking Center <span style="font-size:0.7em;">[<a href="{% url "election@view" election.uuid %}">back to election</a>]</span></h3>
+  <h3 class="title">{{election.name}} &mdash; Voters and Ballot Tracking Center <span style="font-size:0.7em;">[<a href="{% url "helios.views.one_election_view" election.uuid %}">back to election</a>]</span></h3>
 
 <p>
 <b>Who can vote?</b>
@@ -18,7 +18,7 @@
 <em>Your election is marked private, which means you cannot open registration up more widely</em>.<br />
 {% else %}
 You can change this setting:
-<form method="post" action="{% url "election@voters@eligibility" election.uuid %}">
+<form method="post" action="{% url "helios.views.voters_eligibility" election.uuid %}">
 <input type="hidden" name="csrf_token" value="{{csrf_token}}" />
 <input type="radio" name="eligibility" value="openreg" {% if election.openreg and not election.eligibility %}CHECKED{% endif %} /> anyone can vote<br />
 <input type="radio" name="eligibility" value="closedreg" {% if not election.openreg %}CHECKED{% endif %} /> only voters listed explicitly below can vote<br />
@@ -37,7 +37,7 @@ You can change this setting:
 {% endif %}
 
 {% if email_voters and election.frozen_at and admin_p %}
-<p><a class="button" href="{% url "election@voters@email" election.uuid %}">email voters</a></p>
+<p><a class="button" href="{% url "helios.views.voters_email" election.uuid %}">email voters</a></p>
 {% endif %}
 
 {% if election.num_voters > 20 %}
@@ -45,7 +45,7 @@ You can change this setting:
 {% if q %}
 <p><em>searching for <u>{{q}}</u>.</em> [<a href="?">clear search</a>]</p>
 {% else %}
-<form method="get" action="{% url "election@voters@list-pretty" election.uuid %}"><b>search</b>: <input type="text" name="q" /> <input type="submit" value="search" /></form>
+<form method="get" action="{% url "helios.views.voters_list_pretty" election.uuid %}"><b>search</b>: <input type="text" name="q" /> <input type="submit" value="search" /></form>
 {% endif %}
 </p>
 {% endif %}
@@ -54,7 +54,7 @@ You can change this setting:
 <!-- Add a Voter: WORK HERE-->
 {% if upload_p and not election.openreg %}
 <p>
-<a class="button" href="{% url "election@voters@upload" election_uuid=election.uuid %}">bulk upload voters</a>
+<a class="button" href="{% url "helios.views.voters_upload" election_uuid=election.uuid %}">bulk upload voters</a>
 </p>
 
 {% if voter_files %}
@@ -99,14 +99,14 @@ no votes yet
 </p>
 
 {% if voters_page.has_previous %}
-<a href="{% url "election@voters@list-pretty" election.uuid %}?page={{voters_page.previous_page_number}}&limit={{limit}}&q={{q|urlencode}}">previous {{limit}}</a> &nbsp;&nbsp;
+<a href="./list?page={{voters_page.previous_page_number}}&limit={{limit}}&q={{q|urlencode}}">previous {{limit}}</a> &nbsp;&nbsp;
 {% endif %}
 
 
 Voters {{voters_page.start_index}} - {{voters_page.end_index}} (of {{total_voters}})&nbsp;&nbsp;
 
 {% if voters_page.has_next %}
-<a href="{% url "election@voters@list-pretty" election.uuid %}?page={{voters_page.next_page_number}}&limit={{limit}}&q={{q|urlencode}}">next {{limit}}</a> &nbsp;&nbsp;
+<a href="./list?page={{voters_page.next_page_number}}&limit={{limit}}&q={{q|urlencode}}">next {{limit}}</a> &nbsp;&nbsp;
 {% endif %}
 
 <table class="pretty">
@@ -131,9 +131,9 @@ Voters {{voters_page.start_index}} - {{voters_page.end_index}} (of {{total_voter
 {% if admin_p %}
 <td style="white-space: nowrap;">
 {% if election.frozen_at %}
-[<a href="{% url "election@voters@email" election.uuid %}?voter_id={{voter.voter_login_id}}">email</a>]
+[<a href="{% url "helios.views.voters_email" election.uuid %}?voter_id={{voter.voter_login_id}}">email</a>]
 {% endif %}
-[<a onclick="return confirm('are you sure you want to remove {{voter.name}} ?');" href="{% url "election@voter@delete" election.uuid voter.uuid %}">x</a>]
+[<a onclick="return confirm('are you sure you want to remove {{voter.name}} ?');" href="{% url "helios.views.voter_delete" election.uuid voter.uuid %}">x</a>]
 </td>
 <td>{{voter.voter_login_id}}</td>
 <td>{{voter.voter_email}}</td>
@@ -143,7 +143,7 @@ Voters {{voters_page.start_index}} - {{voters_page.end_index}} (of {{total_voter
 {% if election.use_voter_aliases %}
 <td>{{voter.alias}}</td>
 {% endif %}
-<td><tt style="font-size: 1.4em;">{% if voter.vote_hash %}{{voter.vote_hash}} <span style="font-size:0.8em;">[<a href="{% url "shortcut@vote" vote_tinyhash=voter.vote_tinyhash %}">view</a>]</span>{% else %}&mdash;{% endif %}</tt></td>
+<td><tt style="font-size: 1.4em;">{% if voter.vote_hash %}{{voter.vote_hash}} <span style="font-size:0.8em;">[<a href="{% url "helios.views.castvote_shortcut" vote_tinyhash=voter.vote_tinyhash %}">view</a>]</span>{% else %}&mdash;{% endif %}</tt></td>
 </tr>
 {% endfor %}
 </table>
diff --git a/helios/templates/voters_manage.html b/helios/templates/voters_manage.html
index f2a83c7..ccd5490 100644
--- a/helios/templates/voters_manage.html
+++ b/helios/templates/voters_manage.html
@@ -1,12 +1,12 @@
 {% extends TEMPLATE_BASE %}
 
 {% block content %}
-  <h2 class="title">{{election.name}} &mdash; Manage Voters <span style="font-size:0.7em;">[<a href="{% url "election@view" election.uuid %}">back to election</a>]</span></h2>
+  <h2 class="title">{{election.name}} &mdash; Manage Voters <span style="font-size:0.7em;">[<a href="{% url "helios.views.one_election_view" election.uuid %}">back to election</a>]</span></h2>
 
 <form method="get" action="{% url "helios.views.voters_search" election.uuid %}"><b>search</b>: <input type="text" name="q" /> <input type="submit" value="search" /></form>
 
 {% if upload_p %}
-<p><a href="{% url "election@voters@upload" election_uuid=election.uuid %}">bulk upload voters</a></p>
+<p><a href="{% url "helios.views.voters_upload" election_uuid=election.uuid %}">bulk upload voters</a></p>
 {% endif %}
 
 Voters {{offset_plus_one}} - {{offset_plus_limit}} &nbsp;&nbsp;
@@ -29,7 +29,7 @@ Voters {{offset_plus_one}} - {{offset_plus_limit}} &nbsp;&nbsp;
 <tr><td>{{voter.alias}}</td><td>{{voter.name}}</td><td>{{voter.voter_id}}
 {% if election.frozen_at %}
 {% else %}
-[<a onclick="return confirm('are you sure you want to remove {{voter.name}} ?');" href="{% url "election@voter@delete" election.uuid voter.uuid %}">x</a>]
+[<a onclick="return confirm('are you sure you want to remove {{voter.name}} ?');" href="{% url "helios.views.voter_delete" election.uuid voter.uuid %}">x</a>]
 {% endif %}
 </td></tr>
 {% endfor %}
diff --git a/helios/templates/voters_search.html b/helios/templates/voters_search.html
index 162051f..1adfb33 100644
--- a/helios/templates/voters_search.html
+++ b/helios/templates/voters_search.html
@@ -1,12 +1,12 @@
 {% extends TEMPLATE_BASE %}
 
 {% block content %}
-  <h2 class="title">{{election.name}} &mdash; Search Voters for '{{search_term}}' <span style="font-size:0.7em;">[<a href="{% url "election@view" election.uuid %}">back to election</a>]</span></h2>
+  <h2 class="title">{{election.name}} &mdash; Search Voters for '{{search_term}}' <span style="font-size:0.7em;">[<a href="{% url "helios.views.one_election_view" election.uuid %}">back to election</a>]</span></h2>
 
 {% if voter %}
 Voter Found: {{voter.name}} ({{voter.voter_id}})<br /><br />
 {% if election.frozen_at %}
-<a href="{% url "election@voters@email" election.uuid %}?voter_id={{voter.voter_id}}">email this voter</a>
+<a href="{% url "helios.views.voters_email" election.uuid %}?voter_id={{voter.voter_id}}">email this voter</a>
 {% else %}
 once this election is frozen, you'll be able to email this voter.
 {% endif %}
diff --git a/helios/templates/voters_upload.html b/helios/templates/voters_upload.html
index 908c147..a38956d 100644
--- a/helios/templates/voters_upload.html
+++ b/helios/templates/voters_upload.html
@@ -1,7 +1,7 @@
 {% extends TEMPLATE_BASE %}
 
 {% block content %}
-  <h2 class="title">{{election.name}} &mdash; Bulk Upload Voters <span style="font-size:0.7em;">[<a href="{% url "election@view" election.uuid %}">back to election</a>]</span></h2>
+  <h2 class="title">{{election.name}} &mdash; Bulk Upload Voters <span style="font-size:0.7em;">[<a href="{% url "helios.views.one_election_view" election.uuid %}">back to election</a>]</span></h2>
 
 <form method="post" action="" id="upload_form" enctype="multipart/form-data">
   <p>
diff --git a/helios/templates/voters_upload_confirm.html b/helios/templates/voters_upload_confirm.html
index 911cb25..c3d7c08 100644
--- a/helios/templates/voters_upload_confirm.html
+++ b/helios/templates/voters_upload_confirm.html
@@ -1,7 +1,7 @@
 {% extends TEMPLATE_BASE %}
 
 {% block content %}
-  <h2 class="title">{{election.name}} &mdash; Bulk Upload Voters &mdash; Confirm<span style="font-size:0.7em;">[<a href="{% url "election@view" election.uuid %}">back to election</a>]</span></h2>
+  <h2 class="title">{{election.name}} &mdash; Bulk Upload Voters &mdash; Confirm<span style="font-size:0.7em;">[<a href="{% url "helios.views.one_election_view" election.uuid %}">back to election</a>]</span></h2>
 
 <p>
 You have uploaded a file of voters. The first few rows of this file are:
@@ -23,7 +23,7 @@ HOLD ON:<br />
 </p>
 <br />
 
-<a href="{% url "election@voters@upload-cancel" election.uuid %}">never mind, upload a different file</a>
+<a href="{% url "helios.views.voters_upload_cancel" election.uuid %}">never mind, upload a different file</a>
 </p>
 
 {% else %}
@@ -34,7 +34,7 @@ HOLD ON:<br />
   <input type="submit" value="Yes, let's go" />
 </form>
 
-<a href="{% url "election@voters@upload-cancel" election.uuid %}">no, let me upload a different file</a>
+<a href="{% url "helios.views.voters_upload_cancel" election.uuid %}">no, let me upload a different file</a>
 
 {% endif %}
 
diff --git a/helios/test.py b/helios/test.py
index 11fde1c..086f117 100644
--- a/helios/test.py
+++ b/helios/test.py
@@ -2,21 +2,18 @@
 Testing Helios Features
 """
 
+from helios.models import *
+from helios_auth.models import *
 import uuid
 
-from helios.models import Voter
-from helios_auth.models import User
-
-
-def generate_voters(election, num_voters=1000, start_with=1):
-    # generate the user
-    for v_num in range(start_with, start_with + num_voters):
-        user = User(user_type='password', user_id='testuser%s' % v_num, name='Test User %s' % v_num)
-        user.save()
-        voter = Voter(uuid=str(uuid.uuid1()), election=election, voter_type=user.user_type, voter_id=user.user_id)
-        voter.save()
-
+def generate_voters(election, num_voters = 1000, start_with = 1):
+  # generate the user
+  for v_num in range(start_with, start_with + num_voters):
+    user = User(user_type='password', user_id='testuser%s' % v_num, name='Test User %s' % v_num)
+    user.put()
+    voter = Voter(uuid=str(uuid.uuid1()), election = election, voter_type=user.user_type, voter_id = user.user_id)
+    voter.put()
 
 def delete_voters(election):
-    for v in Voter.get_by_election(election):
-        v.delete()
+  for v in Voter.get_by_election(election):
+    v.delete()
\ No newline at end of file
diff --git a/helios/tests.py b/helios/tests.py
index 157ce28..3bd5731 100644
--- a/helios/tests.py
+++ b/helios/tests.py
@@ -2,28 +2,32 @@
 Unit Tests for Helios
 """
 
-import datetime
-import re
-import urllib
-
+import unittest, datetime, re, urllib
 import django_webtest
-import uuid
-from django.conf import settings
-from django.core import mail
-from django.core.files import File
+
+import models
+import datatypes
+
+from helios_auth import models as auth_models
+from views import ELGAMAL_PARAMS
+import views
+import utils
+
+from django.db import IntegrityError, transaction
+from django.test.client import Client
 from django.test import TestCase
 from django.utils.html import escape as html_escape
 
-import helios.datatypes as datatypes
-import helios.models as models
-import helios.utils as utils
-import helios.views as views
-from helios_auth import models as auth_models
+from django.core import mail
+from django.core.files import File
+from django.core.urlresolvers import reverse
+from django.conf import settings
+from django.core.exceptions import PermissionDenied
 
+import uuid
 
 class ElectionModelTests(TestCase):
     fixtures = ['users.json']
-    allow_database_queries = True
 
     def create_election(self):
         return models.Election.get_or_create(
@@ -37,7 +41,7 @@ class ElectionModelTests(TestCase):
         self.election.questions = QUESTIONS
 
     def setup_trustee(self):
-        self.election.generate_trustee(views.ELGAMAL_PARAMS)
+        self.election.generate_trustee(ELGAMAL_PARAMS)
 
     def setup_openreg(self):
         self.election.openreg=True
@@ -110,7 +114,7 @@ class ElectionModelTests(TestCase):
         self.assertEquals(len(issues), 0)
         
     def test_helios_trustee(self):
-        self.election.generate_trustee(views.ELGAMAL_PARAMS)
+        self.election.generate_trustee(ELGAMAL_PARAMS)
 
         self.assertTrue(self.election.has_helios_trustee())
 
@@ -194,15 +198,15 @@ class ElectionModelTests(TestCase):
     def test_voter_registration(self):
         # before adding a voter
         voters = models.Voter.get_by_election(self.election)
-        self.assertEquals(0, len(voters))
+        self.assertTrue(len(voters) == 0)
 
         # make sure no voter yet
         voter = models.Voter.get_by_election_and_user(self.election, self.user)
-        self.assertIsNone(voter)
+        self.assertTrue(voter == None)
 
         # make sure no voter at all across all elections
         voters = models.Voter.get_by_user(self.user)
-        self.assertEquals(0, len(voters))
+        self.assertTrue(len(voters) == 0)
 
         # register the voter
         voter = models.Voter.register_user_in_election(self.user, self.election)
@@ -210,13 +214,13 @@ class ElectionModelTests(TestCase):
         # make sure voter is there now
         voter_2 = models.Voter.get_by_election_and_user(self.election, self.user)
 
-        self.assertIsNotNone(voter)
-        self.assertIsNotNone(voter_2)
+        self.assertFalse(voter == None)
+        self.assertFalse(voter_2 == None)
         self.assertEquals(voter, voter_2)
 
         # make sure voter is there in this call too
         voters = models.Voter.get_by_user(self.user)
-        self.assertEquals(1, len(voters))
+        self.assertTrue(len(voters) == 1)
         self.assertEquals(voter, voters[0])
 
         voter_2 = models.Voter.get_by_election_and_uuid(self.election, voter.uuid)
@@ -228,7 +232,6 @@ class ElectionModelTests(TestCase):
 
 class VoterModelTests(TestCase):
     fixtures = ['users.json', 'election.json']
-    allow_database_queries = True
 
     def setUp(self):
         self.election = models.Election.objects.get(short_name='test')
@@ -252,7 +255,6 @@ class VoterModelTests(TestCase):
 
 class CastVoteModelTests(TestCase):
     fixtures = ['users.json', 'election.json']
-    allow_database_queries = True
 
     def setUp(self):
         self.election = models.Election.objects.get(short_name='test')
@@ -266,11 +268,10 @@ class CastVoteModelTests(TestCase):
 
 class DatatypeTests(TestCase):
     fixtures = ['users.json', 'election.json']
-    allow_database_queries = True
 
     def setUp(self):
         self.election = models.Election.objects.all()[0]
-        self.election.generate_trustee(views.ELGAMAL_PARAMS)
+        self.election.generate_trustee(ELGAMAL_PARAMS)
 
     def test_instantiate(self):
         ld_obj = datatypes.LDObject.instantiate(self.election.get_helios_trustee(), '2011/01/Trustee')
@@ -333,7 +334,6 @@ class DataFormatBlackboxTests(object):
 
 class LegacyElectionBlackboxTests(DataFormatBlackboxTests, TestCase):
     fixtures = ['legacy-data.json']
-    allow_database_queries = True
     EXPECTED_ELECTION_FILE = 'helios/fixtures/legacy-election-expected.json'
     EXPECTED_ELECTION_METADATA_FILE = 'helios/fixtures/legacy-election-metadata-expected.json'
     EXPECTED_VOTERS_FILE = 'helios/fixtures/legacy-election-voters-expected.json'
@@ -348,13 +348,6 @@ class LegacyElectionBlackboxTests(DataFormatBlackboxTests, TestCase):
 #    EXPECTED_BALLOTS_FILE = 'helios/fixtures/v3.1-ballots-expected.json'
 
 class WebTest(django_webtest.WebTest):
-    def assertStatusCode(self, response, status_code):
-        if hasattr(response, 'status_code'):
-            assert response.status_code == status_code, response.status_code
-        else:
-            assert response.status_int == status_code, response.status_int
-
-
     def assertRedirects(self, response, url):
         """
         reimplement this in case it's a WebOp response
@@ -362,23 +355,38 @@ class WebTest(django_webtest.WebTest):
         thus the localhost exception
         """
         if hasattr(response, 'location'):
-            assert url in response.location, response.location
+            assert url in response.location
         else:
-            assert url in response['location'], response['location']
-        self.assertStatusCode(response, 302)
+            assert url in response._headers['location'][1]
+
+        if hasattr(response, 'status_code'):
+            assert response.status_code == 302
+        else:
+            assert response.status_int == 302
+
+        #self.assertEqual(response.status_code, 302)
+
         #return super(django_webtest.WebTest, self).assertRedirects(response, url)
-        #assert url in response.location, "redirected to %s instead of %s" % (response.location, url)
+        #if hasattr(response, 'status_code') and hasattr(response, 'location'):
 
 
+        #assert url in response.location, "redirected to %s instead of %s" % (response.location, url)
+
     def assertContains(self, response, text):
-        self.assertStatusCode(response, 200)
+        if hasattr(response, 'status_code'):
+            assert response.status_code == 200
+#            return super(django_webtest.WebTest, self).assertContains(response, text)
+        else:
+            assert response.status_int == 200
 
+        
         if hasattr(response, "testbody"):
             assert text in response.testbody, "missing text %s" % text
-        elif hasattr(response, "body"):
-            assert text in response.body, "missing text %s" % text
         else:
-            assert text in response.content, "missing text %s" % text
+            if hasattr(response, "body"):
+                assert text in response.body, "missing text %s" % text        
+            else:
+                assert text in response.content, "missing text %s" % text
 
 
 ##
@@ -387,23 +395,31 @@ class WebTest(django_webtest.WebTest):
 
 class ElectionBlackboxTests(WebTest):
     fixtures = ['users.json', 'election.json']
-    allow_database_queries = True
 
     def setUp(self):
         self.election = models.Election.objects.all()[0]
         self.user = auth_models.User.objects.get(user_id='ben@adida.net', user_type='google')
 
-    def setup_login(self, from_scratch=False, **kwargs):
-        if from_scratch:
-            # a bogus call to set up the session
-            self.client.get("/")
+    def assertContains(self, response, text):
+        if hasattr(response, 'status_code'):
+            assert response.status_code == 200
+#            return super(django_webtest.WebTest, self).assertContains(response, text)
+        else:
+            assert response.status_int == 200
+
+        
+        if hasattr(response, "testbody"):
+            assert text in response.testbody, "missing text %s" % text
+        else:
+            if hasattr(response, "body"):
+                assert text in response.body, "missing text %s" % text        
+            else:
+                assert text in response.content, "missing text %s" % text
+
+    def setup_login(self):
         # set up the session
         session = self.client.session
-        if kwargs:
-            user = auth_models.User.objects.get(**kwargs)
-        else:
-            user = self.user
-        session['user'] = {'type': user.user_type, 'user_id': user.user_id}
+        session['user'] = {'type': self.user.user_type, 'user_id': self.user.user_id}
         session.save()
 
         # set up the app, too
@@ -422,11 +438,11 @@ class ElectionBlackboxTests(WebTest):
 
     def test_election_404(self):
         response = self.client.get("/helios/elections/foobar")
-        self.assertStatusCode(response, 404)
+        self.assertEquals(response.status_code, 404)
 
     def test_election_bad_trustee(self):
         response = self.client.get("/helios/t/%s/foobar@bar.com/badsecret" % self.election.short_name)
-        self.assertStatusCode(response, 404)
+        self.assertEquals(response.status_code, 404)
 
     def test_get_election_shortcut(self):
         response = self.client.get("/helios/e/%s" % self.election.short_name, follow=True)
@@ -475,7 +491,10 @@ class ElectionBlackboxTests(WebTest):
         self.assertRedirects(response, "/auth/?return_url=/helios/elections/new")
     
     def test_election_edit(self):
-        self.setup_login(from_scratch=True)
+        # a bogus call to set up the session
+        self.client.get("/")
+
+        self.setup_login()
         response = self.client.get("/helios/elections/%s/edit" % self.election.uuid)
         response = self.client.post("/helios/elections/%s/edit" % self.election.uuid, {
                 "short_name" : self.election.short_name + "-2",
@@ -491,31 +510,14 @@ class ElectionBlackboxTests(WebTest):
         new_election = models.Election.objects.get(uuid = self.election.uuid)
         self.assertEquals(new_election.short_name, self.election.short_name + "-2")
 
-    def test_get_election_stats(self):
-        self.setup_login(from_scratch=True, user_id='mccio@github.com', user_type='google')
-        response = self.client.get("/helios/stats/", follow=False)
-        self.assertStatusCode(response, 200)
-        response = self.client.get("/helios/stats/force-queue", follow=False)
-        self.assertRedirects(response, "/helios/stats/")
-        response = self.client.get("/helios/stats/elections", follow=False)
-        self.assertStatusCode(response, 200)
-        response = self.client.get("/helios/stats/problem-elections", follow=False)
-        self.assertStatusCode(response, 200)
-        response = self.client.get("/helios/stats/recent-votes", follow=False)
-        self.assertStatusCode(response, 200)
-        self.clear_login()
-        response = self.client.get("/helios/stats/", follow=False)
-        self.assertStatusCode(response, 403)
-        self.setup_login()
-        response = self.client.get("/helios/stats/", follow=False)
-        self.assertStatusCode(response, 403)
-        self.clear_login()
-
-    def _setup_complete_election(self, election_params=None):
+    def _setup_complete_election(self, election_params={}):
         "do the setup part of a whole election"
 
+        # a bogus call to set up the session
+        self.client.get("/")
+
         # REPLACE with params?
-        self.setup_login(from_scratch=True)
+        self.setup_login()
 
         # create the election
         full_election_params = {
@@ -530,14 +532,12 @@ class ElectionBlackboxTests(WebTest):
         }
 
         # override with the given
-        full_election_params.update(election_params or {})
+        full_election_params.update(election_params)
 
         response = self.client.post("/helios/elections/new", full_election_params)
 
         # we are redirected to the election, let's extract the ID out of the URL
-        election_id = re.search('/elections/([^/]+)/', str(response['Location']))
-        self.assertIsNotNone(election_id, "Election id not found in redirect: %s" % str(response['Location']))
-        election_id = election_id.group(1)
+        election_id = re.search('/elections/([^/]+)/', str(response['Location'])).group(1)
 
         # helios is automatically added as a trustee
 
@@ -577,7 +577,7 @@ class ElectionBlackboxTests(WebTest):
         self.assertContains(response, '"uuid": "%s"' % single_voter.uuid)
 
         response = self.client.get("/helios/elections/%s/voters/foobar" % election_id)
-        self.assertStatusCode(response, 404)
+        self.assertEquals(response.status_code, 404)
         
         # add questions
         response = self.client.post("/helios/elections/%s/save_questions" % election_id, {
@@ -670,7 +670,7 @@ class ElectionBlackboxTests(WebTest):
         # at this point an email should have gone out to the user
         # at position num_messages after, since that was the len() before we cast this ballot
         email_message = mail.outbox[len(mail.outbox) - 1]
-        url = re.search('https?://[^/]+(/[^ \n]*)', email_message.body).group(1)
+        url = re.search('http://[^/]+(/[^ \n]*)', email_message.body).group(1)
 
         # check that we can get at that URL
         if not need_login:
@@ -690,7 +690,7 @@ class ElectionBlackboxTests(WebTest):
                 login_form['password'] = '  ' + password + '      '
                 login_form.submit()
             
-        response = self.app.get(url, auto_follow=True)
+        response = self.app.get(url)
         self.assertContains(response, ballot.hash)
         self.assertContains(response, html_escape(encrypted_vote))
 
@@ -723,7 +723,7 @@ class ElectionBlackboxTests(WebTest):
 
         # check that we can't get the tally yet
         response = self.client.get("/helios/elections/%s/result" % election_id)
-        self.assertStatusCode(response, 403)
+        self.assertEquals(response.status_code, 403)
 
         # release
         response = self.client.post("/helios/elections/%s/release_result" % election_id, {
@@ -776,7 +776,8 @@ class ElectionBlackboxTests(WebTest):
 
     def test_election_voters_eligibility(self):
         # create the election
-        self.setup_login(from_scratch=True)
+        self.client.get("/")
+        self.setup_login()
         response = self.client.post("/helios/elections/new", {
                 "short_name" : "test-eligibility",
                 "name" : "Test Eligibility",
@@ -787,9 +788,7 @@ class ElectionBlackboxTests(WebTest):
                 "private_p" : "False",
                 'csrf_token': self.client.session['csrf_token']})
 
-        election_id = re.match("(.*)/elections/(.*)/view", str(response['Location']))
-        self.assertIsNotNone(election_id, "Election id not found in redirect: %s" % str(response['Location']))
-        election_id = election_id.group(2)
+        election_id = re.match("(.*)/elections/(.*)/view", response['Location']).group(2)
 
         # update eligiblity
         response = self.client.post("/helios/elections/%s/voters/eligibility" % election_id, {
diff --git a/helios/url_names.py b/helios/url_names.py
deleted file mode 100644
index 319a9be..0000000
--- a/helios/url_names.py
+++ /dev/null
@@ -1,27 +0,0 @@
-from helios import election_url_names as election, stats_url_names as stats
-
-__all__ = [
-    "election", "stats",
-    "COOKIE_TEST", "COOKIE_TEST_2", "COOKIE_NO",
-    "ELECTION_SHORTCUT", "ELECTION_SHORTCUT_VOTE", "CAST_VOTE_SHORTCUT",
-    "TRUSTEE_LOGIN",
-    "ELECTIONS_PARAMS", "ELECTIONS_VERIFIER", "ELECTIONS_VERIFIER_SINGLE_BALLOT",
-    "ELECTIONS_NEW", "ELECTIONS_ADMINISTERED", "ELECTIONS_VOTED",
-]
-
-COOKIE_TEST="cookie@test"
-COOKIE_TEST_2="cookie@test2"
-COOKIE_NO="cookie@no"
-
-ELECTION_SHORTCUT="shortcut@election"
-ELECTION_SHORTCUT_VOTE="shortcut@election@vote"
-CAST_VOTE_SHORTCUT="shortcut@vote"
-
-TRUSTEE_LOGIN="trustee@login"
-
-ELECTIONS_PARAMS="elections@params"
-ELECTIONS_VERIFIER="elections@verifier"
-ELECTIONS_VERIFIER_SINGLE_BALLOT="elections@verifier@single-ballot"
-ELECTIONS_NEW="elections@new"
-ELECTIONS_ADMINISTERED="elections@administered"
-ELECTIONS_VOTED="elections@voted"
diff --git a/helios/urls.py b/helios/urls.py
index 6d278a9..8effba1 100644
--- a/helios/urls.py
+++ b/helios/urls.py
@@ -1,34 +1,35 @@
 # -*- coding: utf-8 -*-
-from django.conf.urls import url, include
+from django.conf.urls import patterns, include
 
-import url_names as names
-import views
+from views import *
 
-urlpatterns = [
-  url(r'^autologin$', views.admin_autologin),
-  url(r'^testcookie$', views.test_cookie, name=names.COOKIE_TEST),
-  url(r'^testcookie_2$', views.test_cookie_2, name=names.COOKIE_TEST_2),
-  url(r'^nocookies$', views.nocookies, name=names.COOKIE_NO),
-  url(r'^stats/', include('helios.stats_urls')),
+urlpatterns = patterns('',
+  (r'^autologin$', admin_autologin),
+  (r'^testcookie$', test_cookie),
+  (r'^testcookie_2$', test_cookie_2),
+  (r'^nocookies$', nocookies),
+  (r'^stats/', include('helios.stats_urls')),
 
   # election shortcut by shortname
-  url(r'^e/(?P<election_short_name>[^/]+)$', views.election_shortcut, name=names.ELECTION_SHORTCUT),
-  url(r'^e/(?P<election_short_name>[^/]+)/vote$', views.election_vote_shortcut, name=names.ELECTION_SHORTCUT_VOTE),
+  (r'^e/(?P<election_short_name>[^/]+)$', election_shortcut),
+  (r'^e/(?P<election_short_name>[^/]+)/vote$', election_vote_shortcut),
 
   # vote shortcut
-  url(r'^v/(?P<vote_tinyhash>[^/]+)$', views.castvote_shortcut, name=names.CAST_VOTE_SHORTCUT),
+  (r'^v/(?P<vote_tinyhash>[^/]+)$', castvote_shortcut),
   
   # trustee login
-  url(r'^t/(?P<election_short_name>[^/]+)/(?P<trustee_email>[^/]+)/(?P<trustee_secret>[^/]+)$', views.trustee_login,
-      name=names.TRUSTEE_LOGIN),
+  (r'^t/(?P<election_short_name>[^/]+)/(?P<trustee_email>[^/]+)/(?P<trustee_secret>[^/]+)$', trustee_login),
   
   # election
-  url(r'^elections/params$', views.election_params, name=names.ELECTIONS_PARAMS),
-  url(r'^elections/verifier$', views.election_verifier, name=names.ELECTIONS_VERIFIER),
-  url(r'^elections/single_ballot_verifier$', views.election_single_ballot_verifier, name=names.ELECTIONS_VERIFIER_SINGLE_BALLOT),
-  url(r'^elections/new$', views.election_new, name=names.ELECTIONS_NEW),
-  url(r'^elections/administered$', views.elections_administered, name=names.ELECTIONS_ADMINISTERED),
-  url(r'^elections/voted$', views.elections_voted, name=names.ELECTIONS_VOTED),
+  (r'^elections/params$', election_params),
+  (r'^elections/verifier$', election_verifier),
+  (r'^elections/single_ballot_verifier$', election_single_ballot_verifier),
+  (r'^elections/new$', election_new),
+  (r'^elections/administered$', elections_administered),
+  (r'^elections/voted$', elections_voted),
   
-  url(r'^elections/(?P<election_uuid>[^/]+)', include('helios.election_urls')),
-]
+  (r'^elections/(?P<election_uuid>[^/]+)', include('helios.election_urls')),
+  
+)
+
+
diff --git a/helios/view_utils.py b/helios/view_utils.py
index 26da704..3e3fb5a 100644
--- a/helios/view_utils.py
+++ b/helios/view_utils.py
@@ -4,17 +4,23 @@ Utilities for all views
 Ben Adida (12-30-2008)
 """
 
-from django.conf import settings
-from django.http import HttpResponse
+from django.template import Context, Template, loader
+from django.http import HttpResponse, Http404
 from django.shortcuts import render_to_response
-from django.template import loader
+
+import utils
+
+from helios import datatypes
+
 # nicely update the wrapper function
 from functools import update_wrapper
 
-import helios
-import utils
 from helios_auth.security import get_user
 
+import helios
+
+from django.conf import settings
+
 ##
 ## BASICS
 ##
@@ -27,14 +33,14 @@ FAILURE = HttpResponse("FAILURE")
 ##
 ## template abstraction
 ##
-def prepare_vars(request, values):
-  vars_with_user = values.copy() if values is not None else {}
+def prepare_vars(request, vars):
+  vars_with_user = vars.copy()
   vars_with_user['user'] = get_user(request)
-
+  
   # csrf protection
   if request.session.has_key('csrf_token'):
     vars_with_user['csrf_token'] = request.session['csrf_token']
-
+    
   vars_with_user['utils'] = utils
   vars_with_user['settings'] = settings
   vars_with_user['HELIOS_STATIC'] = '/static/helios/helios'
@@ -44,32 +50,32 @@ def prepare_vars(request, values):
 
   return vars_with_user
 
-
-def render_template(request, template_name, values = None, include_user=True):
-  vars_with_user = prepare_vars(request, values)
-
+def render_template(request, template_name, vars = {}, include_user=True):
+  t = loader.get_template(template_name + '.html')
+  
+  vars_with_user = prepare_vars(request, vars)
+  
   if not include_user:
     del vars_with_user['user']
-
+  
   return render_to_response('helios/templates/%s.html' % template_name, vars_with_user)
-
-
-def render_template_raw(request, template_name, values=None):
+  
+def render_template_raw(request, template_name, vars={}):
   t = loader.get_template(template_name)
-
+  
   # if there's a request, prep the vars, otherwise can't do it.
   if request:
-    full_vars = prepare_vars(request, values)
+    full_vars = prepare_vars(request, vars)
   else:
-    full_vars = values or {}
+    full_vars = vars
 
-  return t.render(context=full_vars, request=request)
+  c = Context(full_vars)  
+  return t.render(c)
 
 
 def render_json(json_txt):
   return HttpResponse(json_txt, "application/json")
 
-
 # decorator
 def return_json(func):
     """
@@ -86,3 +92,4 @@ def return_json(func):
         raise e
 
     return update_wrapper(convert_to_json,func)
+    
diff --git a/helios/views.py b/helios/views.py
index b62f6ee..3337459 100644
--- a/helios/views.py
+++ b/helios/views.py
@@ -5,7 +5,7 @@ Helios Django Views
 Ben Adida (ben@adida.net)
 """
 
-from django.urls import reverse
+from django.core.urlresolvers import reverse
 from django.core.paginator import Paginator
 from django.core.exceptions import PermissionDenied
 from django.http import HttpResponse, Http404, HttpResponseRedirect, HttpResponseForbidden
@@ -18,13 +18,12 @@ import urllib, os, base64
 from crypto import algs, electionalgs, elgamal
 from crypto import utils as cryptoutils
 from workflows import homomorphic
-from helios import utils, VOTERS_EMAIL, VOTERS_UPLOAD, url_names
+from helios import utils, VOTERS_EMAIL, VOTERS_UPLOAD
 from view_utils import SUCCESS, FAILURE, return_json, render_template, render_template_raw
 
 from helios_auth.security import check_csrf, login_required, get_user, save_in_session_across_logouts
 from helios_auth.auth_systems import AUTH_SYSTEMS, can_list_categories
 from helios_auth.models import AuthenticationExpired
-import helios_auth.url_names as helios_auth_urls
 
 from helios_auth import views as auth_views
 
@@ -58,16 +57,16 @@ ELGAMAL_PARAMS_LD_OBJECT = datatypes.LDObject.instantiate(ELGAMAL_PARAMS, dataty
 from django.conf import settings
 
 def get_election_url(election):
-  return settings.URL_HOST + reverse(url_names.ELECTION_SHORTCUT, args=[election.short_name])
+  return settings.URL_HOST + reverse(election_shortcut, args=[election.short_name])  
 
 def get_election_badge_url(election):
-  return settings.URL_HOST + reverse(url_names.election.ELECTION_BADGE, args=[election.uuid])
+  return settings.URL_HOST + reverse(election_badge, args=[election.uuid])  
 
 def get_election_govote_url(election):
-  return settings.URL_HOST + reverse(url_names.ELECTION_SHORTCUT_VOTE, args=[election.short_name])
+  return settings.URL_HOST + reverse(election_vote_shortcut, args=[election.short_name])  
 
 def get_castvote_url(cast_vote):
-  return settings.URL_HOST + reverse(url_names.CAST_VOTE_SHORTCUT, args=[cast_vote.vote_tinyhash])
+  return settings.URL_HOST + reverse(castvote_shortcut, args=[cast_vote.vote_tinyhash])
 
 
 ##
@@ -77,7 +76,7 @@ def user_reauth(request, user):
   # FIXME: should we be wary of infinite redirects here, and
   # add a parameter to prevent it? Maybe.
   login_url = "%s%s?%s" % (settings.SECURE_URL_HOST,
-                           reverse(helios_auth_urls.AUTH_START, args=[user.user_type]),
+                           reverse(auth_views.start, args=[user.user_type]),
                            urllib.urlencode({'return_url':
                                                request.get_full_path()}))
   return HttpResponseRedirect(login_url)
@@ -117,16 +116,16 @@ def election_single_ballot_verifier(request):
 def election_shortcut(request, election_short_name):
   election = Election.get_by_short_name(election_short_name)
   if election:
-    return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW, args=[election.uuid]))
+    return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view, args=[election.uuid]))
   else:
     raise Http404
 
 # a hidden view behind the shortcut that performs the actual perm check
 @election_view()
 def _election_vote_shortcut(request, election):
-  vote_url = "%s/booth/vote.html?%s" % (settings.SECURE_URL_HOST, urllib.urlencode({'election_url' : reverse(url_names.election.ELECTION_HOME, args=[election.uuid])}))
+  vote_url = "%s/booth/vote.html?%s" % (settings.SECURE_URL_HOST, urllib.urlencode({'election_url' : reverse(one_election, args=[election.uuid])}))
   
-  test_cookie_url = "%s?%s" % (reverse(url_names.COOKIE_TEST), urllib.urlencode({'continue_url' : vote_url}))
+  test_cookie_url = "%s?%s" % (reverse(test_cookie), urllib.urlencode({'continue_url' : vote_url}))
 
   return HttpResponseRedirect(test_cookie_url)
   
@@ -209,7 +208,7 @@ def election_new(request):
         try:
           election = Election.objects.create(**election_params)
           election.generate_trustee(ELGAMAL_PARAMS)
-          return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW, args=[election.uuid]))
+          return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view, args=[election.uuid]))
         except IntegrityError:
           error = "An election with short name %s already exists" % election_params['short_name']
       else:
@@ -242,7 +241,7 @@ def one_election_edit(request, election):
         setattr(election, attr_name, clean_data[attr_name])
       try:
         election.save()
-        return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW, args=[election.uuid]))
+        return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view, args=[election.uuid]))
       except IntegrityError:
         error = "An election with short name %s already exists" % clean_data['short_name']
 
@@ -265,7 +264,7 @@ def one_election_extend(request, election):
       election.voting_extended_until = clean_data['voting_extended_until']
       election.save()
         
-      return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW, args=[election.uuid]))
+      return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view, args=[election.uuid]))
   
   return render_template(request, "election_extend", {'election_form' : election_form, 'election' : election})
 
@@ -304,9 +303,9 @@ def one_election_view(request, election):
   election_badge_url = get_election_badge_url(election)
   status_update_message = None
 
-  vote_url = "%s/booth/vote.html?%s" % (settings.SECURE_URL_HOST, urllib.urlencode({'election_url' : reverse(url_names.election.ELECTION_HOME, args=[election.uuid])}))
+  vote_url = "%s/booth/vote.html?%s" % (settings.SECURE_URL_HOST, urllib.urlencode({'election_url' : reverse(one_election, args=[election.uuid])}))
 
-  test_cookie_url = "%s?%s" % (reverse(url_names.COOKIE_TEST), urllib.urlencode({'continue_url' : vote_url}))
+  test_cookie_url = "%s?%s" % (reverse(test_cookie), urllib.urlencode({'continue_url' : vote_url}))
   
   if user:
     voter = Voter.get_by_election_and_user(election, user)
@@ -353,20 +352,20 @@ def one_election_view(request, election):
 def test_cookie(request):
   continue_url = request.GET['continue_url']
   request.session.set_test_cookie()
-  next_url = "%s?%s" % (reverse(url_names.COOKIE_TEST_2), urllib.urlencode({'continue_url': continue_url}))
+  next_url = "%s?%s" % (reverse(test_cookie_2), urllib.urlencode({'continue_url': continue_url}))
   return HttpResponseRedirect(settings.SECURE_URL_HOST + next_url)  
 
 def test_cookie_2(request):
   continue_url = request.GET['continue_url']
 
   if not request.session.test_cookie_worked():
-    return HttpResponseRedirect(settings.SECURE_URL_HOST + ("%s?%s" % (reverse(url_names.COOKIE_NO), urllib.urlencode({'continue_url': continue_url}))))
+    return HttpResponseRedirect(settings.SECURE_URL_HOST + ("%s?%s" % (reverse(nocookies), urllib.urlencode({'continue_url': continue_url}))))
 
   request.session.delete_test_cookie()
   return HttpResponseRedirect(continue_url)  
 
 def nocookies(request):
-  retest_url = "%s?%s" % (reverse(url_names.COOKIE_TEST), urllib.urlencode({'continue_url' : request.GET['continue_url']}))
+  retest_url = "%s?%s" % (reverse(test_cookie), urllib.urlencode({'continue_url' : request.GET['continue_url']}))
   return render_template(request, 'nocookies', {'retest_url': retest_url})
 
 ##
@@ -400,7 +399,7 @@ def new_trustee(request, election):
     
     trustee = Trustee(uuid = str(uuid.uuid1()), election = election, name=name, email=email)
     trustee.save()
-    return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_TRUSTEES_VIEW, args=[election.uuid]))
+    return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(list_trustees_view, args=[election.uuid]))
 
 @election_admin(frozen=False)
 def new_trustee_helios(request, election):
@@ -408,13 +407,13 @@ def new_trustee_helios(request, election):
   Make Helios a trustee of the election
   """
   election.generate_trustee(ELGAMAL_PARAMS)
-  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_TRUSTEES_VIEW, args=[election.uuid]))
+  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(list_trustees_view, args=[election.uuid]))
   
 @election_admin(frozen=False)
 def delete_trustee(request, election):
   trustee = Trustee.get_by_election_and_uuid(election, request.GET['uuid'])
   trustee.delete()
-  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_TRUSTEES_VIEW, args=[election.uuid]))
+  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(list_trustees_view, args=[election.uuid]))
   
 def trustee_login(request, election_short_name, trustee_email, trustee_secret):
   election = Election.get_by_short_name(election_short_name)
@@ -424,7 +423,7 @@ def trustee_login(request, election_short_name, trustee_email, trustee_secret):
     if trustee:
       if trustee.secret == trustee_secret:
         set_logged_in_trustee(request, trustee)
-        return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_TRUSTEE_HOME, args=[election.uuid, trustee.uuid]))
+        return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(trustee_home, args=[election.uuid, trustee.uuid]))
     # bad secret or no such trustee
     raise Http404("Trustee not recognized.")
   raise Http404("No election {} found.".format(election_short_name))
@@ -433,7 +432,7 @@ def trustee_login(request, election_short_name, trustee_email, trustee_secret):
 def trustee_send_url(request, election, trustee_uuid):
   trustee = Trustee.get_by_election_and_uuid(election, trustee_uuid)
   
-  url = settings.SECURE_URL_HOST + reverse(url_names.TRUSTEE_LOGIN, args=[election.short_name, trustee.email, trustee.secret])
+  url = settings.SECURE_URL_HOST + reverse(trustee_login, args=[election.short_name, trustee.email, trustee.secret])
   
   body = """
 
@@ -450,7 +449,7 @@ Helios
   utils.send_email(settings.SERVER_EMAIL, ["%s <%s>" % (trustee.name, trustee.email)], 'your trustee homepage for %s' % election.name, body)
 
   logging.info("URL %s " % url)
-  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_TRUSTEES_VIEW, args = [election.uuid]))
+  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(list_trustees_view, args = [election.uuid]))
 
 @trustee_check
 def trustee_home(request, election, trustee):
@@ -483,7 +482,7 @@ def trustee_upload_pk(request, election, trustee):
       # oh well, no message sent
       pass
     
-  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_TRUSTEE_HOME, args=[election.uuid, trustee.uuid]))
+  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(trustee_home, args=[election.uuid, trustee.uuid]))
 
 ##
 ## Ballot Management
@@ -531,14 +530,14 @@ def one_election_cast(request, election):
   on a GET, this is a cancellation, on a POST it's a cast
   """
   if request.method == "GET":
-    return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW, args = [election.uuid]))
+    return HttpResponseRedirect("%s%s" % (settings.SECURE_URL_HOST, reverse(one_election_view, args = [election.uuid])))
     
   user = get_user(request)
   encrypted_vote = request.POST['encrypted_vote']
 
   save_in_session_across_logouts(request, 'encrypted_vote', encrypted_vote)
 
-  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_cast_confirm, args=[election.uuid]))
+  return HttpResponseRedirect("%s%s" % (settings.SECURE_URL_HOST, reverse(one_election_cast_confirm, args=[election.uuid])))
 
 @election_view(allow_logins=True)
 def password_voter_login(request, election):
@@ -560,7 +559,7 @@ def password_voter_login(request, election):
     # if user logged in somehow in the interim, e.g. using the login link for administration,
     # then go!
     if user_can_see_election(request, election):
-      return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW, args = [election.uuid]))
+      return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view, args = [election.uuid]))
 
     password_login_form = forms.VoterPasswordForm()
     return render_template(request, 'password_voter_login',
@@ -575,7 +574,7 @@ def password_voter_login(request, election):
     # login depending on whether this is a private election
     # cause if it's private the login is happening on the front page
     if election.private_p:
-      login_url = reverse(url_names.election.ELECTION_PASSWORD_VOTER_LOGIN, args=[election.uuid])
+      login_url = reverse(password_voter_login, args=[election.uuid])
     else:
       login_url = reverse(one_election_cast_confirm, args=[election.uuid])
 
@@ -743,7 +742,7 @@ def one_election_cast_confirm(request, election):
     # remove the vote from the store
     del request.session['encrypted_vote']
     
-    return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_cast_done, args=[election.uuid]))
+    return HttpResponseRedirect("%s%s" % (settings.URL_HOST, reverse(one_election_cast_done, args=[election.uuid])))
   
 @election_view()
 def one_election_cast_done(request, election):
@@ -931,7 +930,7 @@ def one_election_set_featured(request, election):
   election.featured_p = featured_p
   election.save()
   
-  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW, args=[election.uuid]))
+  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view, args=[election.uuid]))
 
 @election_admin()
 def one_election_archive(request, election):
@@ -945,7 +944,7 @@ def one_election_archive(request, election):
     
   election.save()
 
-  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW, args=[election.uuid]))
+  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view, args=[election.uuid]))
   
 @election_admin()
 def one_election_copy(request, election):
@@ -979,7 +978,7 @@ def one_election_copy(request, election):
   
 
   new_election.generate_trustee(ELGAMAL_PARAMS)
-  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW, args=[new_election.uuid]))
+  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view, args=[new_election.uuid]))
 
 # changed from admin to view because 
 # anyone can see the questions, the administration aspect is now
@@ -1018,7 +1017,7 @@ def one_election_register(request, election):
   if not voter:
     voter = _register_voter(election, user)
     
-  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW, args=[election.uuid]))
+  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view, args=[election.uuid]))
 
 @election_admin(frozen=False)
 def one_election_save_questions(request, election):
@@ -1047,7 +1046,7 @@ def one_election_freeze(request, election):
     election.freeze()
 
     if get_user(request):
-      return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW, args=[election.uuid]))
+      return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view, args=[election.uuid]))
     else:
       return SUCCESS    
 
@@ -1063,7 +1062,7 @@ def one_election_compute_tally(request, election):
   tallying is done all at a time now
   """
   if not _check_election_tally_type(election):
-    return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW,args=[election.election_id]))
+    return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view,args=[election.election_id]))
 
   if request.method == "GET":
     return render_template(request, 'election_compute_tally', {'election': election})
@@ -1078,12 +1077,12 @@ def one_election_compute_tally(request, election):
 
   tasks.election_compute_tally.delay(election_id = election.id)
 
-  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW,args=[election.uuid]))
+  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view,args=[election.uuid]))
 
 @trustee_check
 def trustee_decrypt_and_prove(request, election, trustee):
   if not _check_election_tally_type(election) or election.encrypted_tally == None:
-    return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW,args=[election.uuid]))
+    return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view,args=[election.uuid]))
     
   return render_template(request, 'trustee_decrypt_and_prove', {'election': election, 'trustee': trustee})
   
@@ -1132,7 +1131,7 @@ def release_result(request, election):
     if request.POST.get('send_email', ''):
       return HttpResponseRedirect("%s?%s" % (settings.SECURE_URL_HOST + reverse(voters_email, args=[election.uuid]),urllib.urlencode({'template': 'result'})))
     else:
-      return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW, args=[election.uuid]))
+      return HttpResponseRedirect("%s" % (settings.SECURE_URL_HOST + reverse(one_election_view, args=[election.uuid])))
 
   # if just viewing the form or the form is not valid
   return render_template(request, 'release_result', {'election': election})
@@ -1151,7 +1150,7 @@ def combine_decryptions(request, election):
     election.combine_decryptions()
     election.save()
 
-    return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW, args=[election.uuid]))
+    return HttpResponseRedirect("%s" % (settings.SECURE_URL_HOST + reverse(one_election_view, args=[election.uuid])))
 
   # if just viewing the form or the form is not valid
   return render_template(request, 'combine_decryptions', {'election': election})
@@ -1159,7 +1158,7 @@ def combine_decryptions(request, election):
 @election_admin(frozen=True)
 def one_election_set_result_and_proof(request, election):
   if election.tally_type != "homomorphic" or election.encrypted_tally == None:
-    return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW, args=[election.election_id]))
+    return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view,args=[election.election_id]))
 
   # FIXME: check csrf
   
@@ -1168,7 +1167,7 @@ def one_election_set_result_and_proof(request, election):
   election.save()
 
   if get_user(request):
-    return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW, args=[election.uuid]))
+    return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view, args=[election.uuid]))
   else:
     return SUCCESS
   
@@ -1327,12 +1326,12 @@ def voters_upload_cancel(request, election):
     vf.delete()
   del request.session['voter_file_id']
 
-  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW, args=[election.uuid]))
+  return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view, args=[election.uuid]))
 
 @election_admin(frozen=True)
 def voters_email(request, election):
   if not VOTERS_EMAIL:
-    return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW, args=[election.uuid]))
+    return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view, args=[election.uuid]))
   TEMPLATES = [
     ('vote', 'Time to Vote'),
     ('simple', 'Simple'),
@@ -1409,7 +1408,7 @@ def voters_email(request, election):
         tasks.voters_email.delay(election_id = election.id, subject_template = subject_template, body_template = body_template, extra_vars = extra_vars, voter_constraints_include = voter_constraints_include, voter_constraints_exclude = voter_constraints_exclude)
 
       # this batch process is all async, so we can return a nice note
-      return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(url_names.election.ELECTION_VIEW, args=[election.uuid]))
+      return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view, args=[election.uuid]))
     
   return render_template(request, "voters_email", {
       'email_form': email_form, 'election': election,
diff --git a/helios/widgets.py b/helios/widgets.py
index 9eff2f4..7eff891 100644
--- a/helios/widgets.py
+++ b/helios/widgets.py
@@ -5,7 +5,8 @@ Widget for datetime split, with calendar for date, and drop-downs for times.
 from django import forms
 from django.db import models
 from django.template.loader import render_to_string
-from django.forms.widgets import Select, MultiWidget, DateInput, TextInput, Widget, SelectDateWidget
+from django.forms.widgets import Select, MultiWidget, DateInput, TextInput, Widget
+from django.forms.extras.widgets import SelectDateWidget
 from time import strftime
 
 import re
@@ -35,20 +36,19 @@ class SelectTimeWidget(Widget):
     
     Also allows user-defined increments for minutes/seconds
     """
-    template_name = ''
     hour_field = '%s_hour'
     minute_field = '%s_minute'
     meridiem_field = '%s_meridiem'
     twelve_hr = False # Default to 24hr.
-
+    
     def __init__(self, attrs=None, hour_step=None, minute_step=None, twelve_hr=False):
         """
         hour_step, minute_step, second_step are optional step values for
         for the range of values for the associated select element
         twelve_hr: If True, forces the output to be in 12-hr format (rather than 24-hr)
         """
-        super(SelectTimeWidget, self).__init__(attrs)
-
+        self.attrs = attrs or {}
+        
         if twelve_hr:
             self.twelve_hr = True # Do 12hr (rather than 24hr)
             self.meridiem_val = 'a.m.' # Default to Morning (A.M.)
@@ -67,7 +67,7 @@ class SelectTimeWidget(Widget):
         else:
             self.minutes = range(0,60)
 
-    def render(self, name, value, attrs=None, renderer=None):
+    def render(self, name, value, attrs=None):
         try: # try to get time values from a datetime.time object (value)
             hour_val, minute_val = value.hour, value.minute
             if self.twelve_hr:
@@ -80,7 +80,7 @@ class SelectTimeWidget(Widget):
             if isinstance(value, basestring):
                 match = RE_TIME.match(value)
                 if match:
-                    time_groups = match.groups()
+                    time_groups = match.groups();
                     hour_val = int(time_groups[HOURS]) % 24 # force to range(0-24)
                     minute_val = int(time_groups[MINUTES]) 
                     
@@ -117,7 +117,7 @@ class SelectTimeWidget(Widget):
         minute_val = u"%.2d" % minute_val
 
         hour_choices = [("%.2d"%i, "%.2d"%i) for i in self.hours]
-        local_attrs = self.build_attrs({'id': self.hour_field % id_})
+        local_attrs = self.build_attrs(id=self.hour_field % id_)
         select_html = Select(choices=hour_choices).render(self.hour_field % name, hour_val, local_attrs)
         output.append(select_html)
 
@@ -169,8 +169,6 @@ class SplitSelectDateTimeWidget(MultiWidget):
     This class combines SelectTimeWidget and SelectDateWidget so we have something 
     like SpliteDateTimeWidget (in django.forms.widgets), but with Select elements.
     """
-    template_name = ''
-
     def __init__(self, attrs=None, hour_step=None, minute_step=None, twelve_hr=None, years=None):
         """ pass all these parameters to their respective widget constructors..."""
         widgets = (SelectDateWidget(attrs=attrs, years=years), SelectTimeWidget(attrs=attrs, hour_step=hour_step, minute_step=minute_step, twelve_hr=twelve_hr))
@@ -187,6 +185,13 @@ class SplitSelectDateTimeWidget(MultiWidget):
             return [value.date(), value.time().replace(microsecond=0)]
         return [None, None]
 
-    def render(self, name, value, attrs=None, renderer=None):
-        rendered_widgets = list(widget.render(name, value, attrs=attrs, renderer=renderer) for widget in self.widgets)
-        return u'<br/>'.join(rendered_widgets)
+    def format_output(self, rendered_widgets):
+        """
+        Given a list of rendered widgets (as strings), it inserts an HTML
+        linebreak between them.
+        
+        Returns a Unicode string representing the HTML for the whole lot.
+        """
+        rendered_widgets.insert(-1, '<br/>')
+        return u''.join(rendered_widgets)
+
diff --git a/helios/workflows/homomorphic.py b/helios/workflows/homomorphic.py
index c3c98eb..63e2d0c 100644
--- a/helios/workflows/homomorphic.py
+++ b/helios/workflows/homomorphic.py
@@ -6,7 +6,11 @@ Ben Adida
 reworked 2011-01-09
 """
 
-from helios.crypto import algs
+from helios.crypto import algs, utils
+import logging
+import uuid
+import datetime
+from helios import models
 from . import WorkflowObject
 
 class EncryptedAnswer(WorkflowObject):
diff --git a/helios_auth/apps.py b/helios_auth/apps.py
deleted file mode 100644
index 7d1472a..0000000
--- a/helios_auth/apps.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from django.apps import AppConfig
-
-class HeliosAuthConfig(AppConfig):
-    name = 'helios_auth'
-    verbose_name = "Helios Authentication"
diff --git a/helios_auth/auth_systems/cas.py b/helios_auth/auth_systems/cas.py
index dd4216b..8202ad2 100644
--- a/helios_auth/auth_systems/cas.py
+++ b/helios_auth/auth_systems/cas.py
@@ -5,14 +5,11 @@ Some code borrowed from
 https://sp.princeton.edu/oit/sdp/CAS/Wiki%20Pages/Python.aspx
 """
 
-import datetime
-import re
-import urllib
-import urllib2
-import uuid
-from django.conf import settings
+from django.http import *
 from django.core.mail import send_mail
-from django.http import HttpResponseRedirect
+from django.conf import settings
+
+import sys, os, cgi, urllib, urllib2, re, uuid, datetime
 from xml.etree import ElementTree
 
 CAS_EMAIL_DOMAIN = "princeton.edu"
@@ -34,11 +31,11 @@ STATUS_UPDATES = False
 
 def _get_service_url():
   # FIXME current URL
-  from helios_auth import url_names
+  from helios_auth.views import after
   from django.conf import settings
-  from django.urls import reverse
+  from django.core.urlresolvers import reverse
   
-  return settings.SECURE_URL_HOST + reverse(url_names.AUTH_AFTER)
+  return settings.SECURE_URL_HOST + reverse(after)
   
 def get_auth_url(request, redirect_url):
   request.session['cas_redirect_url'] = redirect_url
diff --git a/helios_auth/auth_systems/clever.py b/helios_auth/auth_systems/clever.py
index 498951f..dcd52d0 100644
--- a/helios_auth/auth_systems/clever.py
+++ b/helios_auth/auth_systems/clever.py
@@ -3,11 +3,14 @@ Clever Authentication
 
 """
 
-import base64
-import httplib2
-import json
-import urllib
+from django.http import *
+from django.core.mail import send_mail
 from django.conf import settings
+
+import httplib2,json,base64
+
+import sys, os, cgi, urllib, urllib2, re
+
 from oauth2client.client import OAuth2WebServerFlow, OAuth2Credentials
 
 # some parameters to indicate that status updating is not possible
diff --git a/helios_auth/auth_systems/facebookclient/djangofb/default_app/urls.py b/helios_auth/auth_systems/facebookclient/djangofb/default_app/urls.py
index f75d8d2..5e793a6 100644
--- a/helios_auth/auth_systems/facebookclient/djangofb/default_app/urls.py
+++ b/helios_auth/auth_systems/facebookclient/djangofb/default_app/urls.py
@@ -1,7 +1,7 @@
-from django.conf.urls import url
+from django.conf.urls import *
 
-from views import canvas
+urlpatterns = patterns('{{ project }}.{{ app }}.views',
+    (r'^$', 'canvas'),
+    # Define other pages you want to create here
+)
 
-urlpatterns = [
-    url(r'^$', canvas),
-]
diff --git a/helios_auth/auth_systems/google.py b/helios_auth/auth_systems/google.py
index 0341991..7caa32f 100644
--- a/helios_auth/auth_systems/google.py
+++ b/helios_auth/auth_systems/google.py
@@ -3,10 +3,14 @@ Google Authentication
 
 """
 
-import httplib2
-import json
-from django.conf import settings
+from django.http import *
 from django.core.mail import send_mail
+from django.conf import settings
+
+import httplib2,json
+
+import sys, os, cgi, urllib, urllib2, re
+
 from oauth2client.client import OAuth2WebServerFlow
 
 # some parameters to indicate that status updating is not possible
diff --git a/helios_auth/auth_systems/linkedin.py b/helios_auth/auth_systems/linkedin.py
index 696eda9..32b0033 100644
--- a/helios_auth/auth_systems/linkedin.py
+++ b/helios_auth/auth_systems/linkedin.py
@@ -4,7 +4,7 @@ LinkedIn Authentication
 
 from oauthclient import client
 
-from django.urls import reverse
+from django.core.urlresolvers import reverse
 from django.http import HttpResponseRedirect
 
 from helios_auth import utils
diff --git a/helios_auth/auth_systems/openid/util.py b/helios_auth/auth_systems/openid/util.py
index 1ed33f3..277b92c 100644
--- a/helios_auth/auth_systems/openid/util.py
+++ b/helios_auth/auth_systems/openid/util.py
@@ -10,7 +10,7 @@ from django.template.context import RequestContext
 from django.template import loader
 from django import http
 from django.core.exceptions import ImproperlyConfigured
-from django.urls import reverse as reverseURL
+from django.core.urlresolvers import reverse as reverseURL
 
 from django.conf import settings
 
diff --git a/helios_auth/auth_systems/password.py b/helios_auth/auth_systems/password.py
index aadb03f..f78d9f6 100644
--- a/helios_auth/auth_systems/password.py
+++ b/helios_auth/auth_systems/password.py
@@ -2,21 +2,17 @@
 Username/Password Authentication
 """
 
-from django.urls import reverse
+from django.core.urlresolvers import reverse
 from django import forms
 from django.core.mail import send_mail
 from django.conf import settings
 from django.http import HttpResponseRedirect
-from django.conf.urls import url
-
-from helios_auth import url_names
 
 import logging
 
 # some parameters to indicate that status updating is possible
 STATUS_UPDATES = False
-PASSWORD_LOGIN_URL_NAME = "auth@password@login"
-PASSWORD_FORGOTTEN_URL_NAME = "auth@password@forgotten"
+
 
 def create_user(username, password, name = None):
   from helios_auth.models import User
@@ -62,7 +58,7 @@ def password_login_view(request):
         user = User.get_by_type_and_id('password', username)
         if password_check(user, password):
           request.session['password_user_id'] = user.user_id
-          return HttpResponseRedirect(reverse(url_names.AUTH_AFTER))
+          return HttpResponseRedirect(reverse(after))
       except User.DoesNotExist:
         pass
       error = 'Bad Username or Password'
@@ -105,7 +101,7 @@ Your password: %s
     return HttpResponseRedirect(return_url)
   
 def get_auth_url(request, redirect_url = None):
-  return reverse(PASSWORD_LOGIN_URL_NAME)
+  return reverse(password_login_view)
     
 def get_user_info_after_auth(request):
   from helios_auth.models import User
@@ -129,9 +125,3 @@ def send_message(user_id, user_name, user_info, subject, body):
 
 def can_create_election(user_id, user_info):
   return True
-
-
-urlpatterns = [
-  url(r'^password/login', password_login_view, name=PASSWORD_LOGIN_URL_NAME),
-  url(r'^password/forgot', password_forgotten_view, name=PASSWORD_FORGOTTEN_URL_NAME)
-]
diff --git a/helios_auth/auth_systems/twitter.py b/helios_auth/auth_systems/twitter.py
index 8739d60..9963f91 100644
--- a/helios_auth/auth_systems/twitter.py
+++ b/helios_auth/auth_systems/twitter.py
@@ -4,8 +4,7 @@ Twitter Authentication
 
 from oauthclient import client
 
-from django.conf.urls import url
-from django.urls import reverse
+from django.core.urlresolvers import reverse
 from django.http import HttpResponseRedirect
 
 from helios_auth import utils
@@ -22,7 +21,6 @@ DM_TOKEN = settings.TWITTER_DM_TOKEN
 # some parameters to indicate that status updating is possible
 STATUS_UPDATES = True
 STATUS_UPDATE_WORDING_TEMPLATE = "Tweet %s"
-FOLLOW_VIEW_URL_NAME = "auth@twitter@follow"
 
 OAUTH_PARAMS = {
   'root_url' : 'https://twitter.com',
@@ -72,7 +70,7 @@ def user_needs_intervention(user_id, user_info, token):
   if friendship:
     return None
 
-  return HttpResponseRedirect(reverse(FOLLOW_VIEW_URL_NAME))
+  return HttpResponseRedirect(reverse(follow_view))
 
 def _get_client_by_request(request):
   access_token = request.session['access_token']
@@ -116,8 +114,8 @@ def follow_view(request):
       twitter_client = _get_client_by_token(user.token)
       result = twitter_client.oauth_request('http://api.twitter.com/1/friendships/create.json', args={'screen_name': USER_TO_FOLLOW}, method='POST')
 
-    from helios_auth.url_names import AUTH_AFTER_INTERVENTION
-    return HttpResponseRedirect(reverse(AUTH_AFTER_INTERVENTION))
+    from helios_auth.views import after_intervention
+    return HttpResponseRedirect(reverse(after_intervention))
 
 
 
@@ -127,6 +125,3 @@ def follow_view(request):
 
 def can_create_election(user_id, user_info):
   return True
-
-
-urlpatterns = [url(r'^twitter/follow', follow_view, name=FOLLOW_VIEW_URL_NAME)]
\ No newline at end of file
diff --git a/helios_auth/auth_systems/yahoo.py b/helios_auth/auth_systems/yahoo.py
index 5131a19..16bc034 100644
--- a/helios_auth/auth_systems/yahoo.py
+++ b/helios_auth/auth_systems/yahoo.py
@@ -3,8 +3,12 @@ Yahoo Authentication
 
 """
 
-from django.conf import settings
+from django.http import *
 from django.core.mail import send_mail
+from django.conf import settings
+
+import sys, os, cgi, urllib, urllib2, re
+from xml.etree import ElementTree
 
 from openid import view_helpers
 
diff --git a/helios_auth/jsonfield.py b/helios_auth/jsonfield.py
index 34cecf7..0104ce4 100644
--- a/helios_auth/jsonfield.py
+++ b/helios_auth/jsonfield.py
@@ -4,11 +4,11 @@ taken from
 http://www.djangosnippets.org/snippets/377/
 """
 
-import json
-from django.core.exceptions import ValidationError
-from django.core.serializers.json import DjangoJSONEncoder
+import datetime, json
 from django.db import models
-
+from django.db.models import signals
+from django.conf import settings
+from django.core.serializers.json import DjangoJSONEncoder
 
 class JSONField(models.TextField):
     """
@@ -18,6 +18,9 @@ class JSONField(models.TextField):
     deserialization_params added on 2011-01-09 to provide additional hints at deserialization time
     """
 
+    # Used so to_python() is called
+    __metaclass__ = models.SubfieldBase
+
     def __init__(self, json_type=None, deserialization_params=None, **kwargs):
         self.json_type = json_type
         self.deserialization_params = deserialization_params
@@ -33,21 +36,17 @@ class JSONField(models.TextField):
         if isinstance(value, dict) or isinstance(value, list):
             return value
 
-        return self.from_db_value(value)
-
-    # noinspection PyUnusedLocal
-    def from_db_value(self, value, *args, **kwargs):
-        if value == "" or value is None:
+        if value == "" or value == None:
             return None
 
         try:
             parsed_value = json.loads(value)
-        except Exception as e:
-            raise ValidationError("Received value is not JSON", e)
+        except:
+            raise Exception("not JSON")
 
         if self.json_type and parsed_value:
             parsed_value = self.json_type.fromJSONDict(parsed_value, **self.deserialization_params)
-
+                
         return parsed_value
 
     # we should never look up by JSON field anyways.
@@ -58,7 +57,7 @@ class JSONField(models.TextField):
         if isinstance(value, basestring):
             return value
 
-        if value is None:
+        if value == None:
             return None
 
         if self.json_type and isinstance(value, self.json_type):
@@ -71,4 +70,5 @@ class JSONField(models.TextField):
 
     def value_to_string(self, obj):
         value = self._get_val_from_obj(obj)
-        return self.get_db_prep_value(value, None)
+        return self.get_db_prep_value(value)        
+
diff --git a/helios_auth/models.py b/helios_auth/models.py
index fb050d2..b917995 100644
--- a/helios_auth/models.py
+++ b/helios_auth/models.py
@@ -6,11 +6,13 @@ GAE
 Ben Adida
 (ben@adida.net)
 """
-from django.db import models
 
-from auth_systems import AUTH_SYSTEMS
+from django.db import models
 from jsonfield import JSONField
 
+import datetime, logging
+
+from auth_systems import AUTH_SYSTEMS, can_check_constraint, can_list_categories
 
 # an exception to catch when a user is no longer authenticated
 class AuthenticationExpired(Exception):
@@ -33,8 +35,7 @@ class User(models.Model):
 
   class Meta:
     unique_together = (('user_type', 'user_id'),)
-    app_label = 'helios_auth'
-
+    
   @classmethod
   def _get_type_and_id(cls, user_type, user_id):
     return "%s:%s" % (user_type, user_id)    
diff --git a/helios_auth/security/__init__.py b/helios_auth/security/__init__.py
index d3c5ac1..facc0c3 100644
--- a/helios_auth/security/__init__.py
+++ b/helios_auth/security/__init__.py
@@ -4,16 +4,19 @@ Generic Security -- for the auth system
 Ben Adida (ben@adida.net)
 """
 
-import uuid
-from django.conf import settings
-from django.core.exceptions import PermissionDenied
-from django.http import HttpResponseNotAllowed
-from django.http import HttpResponseRedirect
 # nicely update the wrapper function
 from functools import update_wrapper
 
+from django.http import HttpResponse, Http404, HttpResponseRedirect
+from django.core.exceptions import *
+from django.conf import settings
+from django.http import HttpResponseNotAllowed
+
 import oauth
-from helios_auth.models import User
+
+import uuid
+
+from helios_auth.models import *
 
 FIELDS_TO_SAVE = 'FIELDS_TO_SAVE'
 
diff --git a/helios_auth/security/oauth.py b/helios_auth/security/oauth.py
index 71676c8..4addf22 100644
--- a/helios_auth/security/oauth.py
+++ b/helios_auth/security/oauth.py
@@ -6,6 +6,7 @@ Hacked a bit by Ben Adida (ben@adida.net) so that:
 - access tokens are looked up with an extra param of consumer
 """
 
+import cgi
 import urllib
 import time
 import random
@@ -54,7 +55,7 @@ class OAuthConsumer(object):
         self.secret = secret
 
 # OAuthToken is a data type that represents an End User via either an access
-# or request token.
+# or request token.     
 class OAuthToken(object):
     # access tokens and request tokens
     key = None
@@ -73,9 +74,9 @@ class OAuthToken(object):
 
     # return a token from something like:
     # oauth_token_secret=digg&oauth_token=digg
-    @staticmethod
+    @staticmethod   
     def from_string(s):
-        params = urlparse.parse_qs(s, keep_blank_values=False)
+        params = cgi.parse_qs(s, keep_blank_values=False)
         key = params['oauth_token'][0]
         secret = params['oauth_token_secret'][0]
         return OAuthToken(key, secret)
@@ -87,11 +88,11 @@ class OAuthToken(object):
 class OAuthRequest(object):
     '''
     OAuth parameters:
-        - oauth_consumer_key
+        - oauth_consumer_key 
         - oauth_token
         - oauth_signature_method
-        - oauth_signature
-        - oauth_timestamp
+        - oauth_signature 
+        - oauth_timestamp 
         - oauth_nonce
         - oauth_version
         ... any additional parameters, as defined by the Service Provider.
@@ -100,7 +101,7 @@ class OAuthRequest(object):
     http_method = HTTP_METHOD
     http_url = None
     version = VERSION
-
+    
     # added by Ben to filter out extra params from header
     OAUTH_PARAMS = ['oauth_consumer_key', 'oauth_token', 'oauth_signature_method', 'oauth_signature', 'oauth_timestamp', 'oauth_nonce', 'oauth_version']
 
@@ -172,7 +173,7 @@ class OAuthRequest(object):
         parts = urlparse.urlparse(self.http_url)
         url_string = '%s://%s%s' % (parts[0], parts[1], parts[2]) # scheme, netloc, path
         return url_string
-
+        
     # set the signature parameter to the result of build_signature
     def sign_request(self, signature_method, consumer, token):
         # set the signature method
@@ -265,11 +266,11 @@ class OAuthRequest(object):
             # remove quotes and unescape the value
             params[param_parts[0]] = urllib.unquote(param_parts[1].strip('\"'))
         return params
-
+    
     # util function: turn url string into parameters, has to do some unescaping
     @staticmethod
     def _split_url_string(param_str):
-        parameters = urlparse.parse_qs(param_str, keep_blank_values=False)
+        parameters = cgi.parse_qs(param_str, keep_blank_values=False)
         for k, v in parameters.iteritems():
             parameters[k] = urllib.unquote(v[0])
         return parameters
@@ -286,7 +287,7 @@ class OAuthServer(object):
         self.signature_methods = signature_methods or {}
 
     def set_data_store(self, oauth_data_store):
-        self.data_store = oauth_data_store
+        self.data_store = data_store
 
     def get_data_store(self):
         return self.data_store
@@ -335,12 +336,12 @@ class OAuthServer(object):
     # authorize a request token
     def authorize_token(self, token, user):
         return self.data_store.authorize_request_token(token, user)
-
+    
     # get the callback url
     def get_callback(self, oauth_request):
         return oauth_request.get_parameter('oauth_callback')
 
-    # optional support for the authenticate header
+    # optional support for the authenticate header   
     def build_authenticate_header(self, realm=''):
         return {'WWW-Authenticate': 'OAuth realm="%s"' % realm}
 
@@ -494,7 +495,7 @@ class OAuthSignatureMethod_HMAC_SHA1(OAuthSignatureMethod):
 
     def get_name(self):
         return 'HMAC-SHA1'
-
+        
     def build_signature_base_string(self, oauth_request, consumer, token):
         sig = (
             escape(oauth_request.get_normalized_http_method()),
diff --git a/helios_auth/south_migrations/0001_initial.py b/helios_auth/south_migrations/0001_initial.py
new file mode 100644
index 0000000..4ba2a3a
--- /dev/null
+++ b/helios_auth/south_migrations/0001_initial.py
@@ -0,0 +1,49 @@
+# encoding: utf-8
+import 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 'User'
+        db.create_table('helios_auth_user', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('user_type', self.gf('django.db.models.fields.CharField')(max_length=50)),
+            ('user_id', self.gf('django.db.models.fields.CharField')(max_length=100)),
+            ('name', self.gf('django.db.models.fields.CharField')(max_length=200, null=True)),
+            ('info', self.gf('helios_auth.jsonfield.JSONField')()),
+            ('token', self.gf('helios_auth.jsonfield.JSONField')(null=True)),
+            ('admin_p', self.gf('django.db.models.fields.BooleanField')(default=False)),
+        ))
+        db.send_create_signal('helios_auth', ['User'])
+
+        # Adding unique constraint on 'User', fields ['user_type', 'user_id']
+        db.create_unique('helios_auth_user', ['user_type', 'user_id'])
+
+
+    def backwards(self, orm):
+        
+        # Removing unique constraint on 'User', fields ['user_type', 'user_id']
+        db.delete_unique('helios_auth_user', ['user_type', 'user_id'])
+
+        # Deleting model 'User'
+        db.delete_table('helios_auth_user')
+
+
+    models = {
+        'helios_auth.user': {
+            'Meta': {'unique_together': "(('user_type', 'user_id'),)", 'object_name': 'User'},
+            'admin_p': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'info': ('helios_auth.jsonfield.JSONField', [], {}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
+            'token': ('helios_auth.jsonfield.JSONField', [], {'null': 'True'}),
+            'user_id': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'user_type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        }
+    }
+
+    complete_apps = ['helios_auth']
diff --git a/helios_auth/south_migrations/__init__.py b/helios_auth/south_migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/helios_auth/templates/index.html b/helios_auth/templates/index.html
index 3c2e9f8..f16a7b8 100644
--- a/helios_auth/templates/index.html
+++ b/helios_auth/templates/index.html
@@ -8,7 +8,7 @@
     You are currently logged in as<br /><b>{{user.user_id}}</b> via <b>{{user.user_type}}</b>.
 </p>
 <p>
-    <a href="{% url "auth@logout" %}">logout</a>
+    <a href="{% url "helios_auth.views.logout" %}">logout</a>
 </p>
 
 {% else %}
diff --git a/helios_auth/templates/login_box.html b/helios_auth/templates/login_box.html
index 27ca7da..2e89e94 100644
--- a/helios_auth/templates/login_box.html
+++ b/helios_auth/templates/login_box.html
@@ -1,12 +1,12 @@
 {% if default_auth_system %}
 <p>
-<a class="small button" href="{% url "auth@start" system_name=default_auth_system %}?return_url={{return_url}}">Log in</a></p>
+<a class="small button" href="{% url "helios_auth.views.start" system_name=default_auth_system %}?return_url={{return_url}}">Log in</a></p>
 {% else %}
 {% for auth_system in enabled_auth_systems %}
 {% ifequal auth_system "password" %}
 {% else %}
 <p>
-    <a href="{{SECURE_URL_HOST}}{% url "auth@start" system_name=auth_system %}?return_url={{return_url}}" style="font-size: 1.4em;">
+    <a href="{{SECURE_URL_HOST}}{% url "helios_auth.views.start" system_name=auth_system %}?return_url={{return_url}}" style="font-size: 1.4em;">
 <img style="height: 35px; border: 0px;" src="/static/auth/login-icons/{{auth_system}}.png" alt="{{auth_system}}" /> {{auth_system}}
 {% endifequal %}
 </a>
diff --git a/helios_auth/templates/perms_why.html b/helios_auth/templates/perms_why.html
index 3f38fd1..179d103 100644
--- a/helios_auth/templates/perms_why.html
+++ b/helios_auth/templates/perms_why.html
@@ -13,7 +13,7 @@ this information, we unfortunately cannot help you vote.
 </p>
 
 <form method="POST" action="">
-<input type="hidden" name="csrf_token" value="{{csrf_token}}" />
+<input type="hidden" value="{{csrf_token}}" />
 <input type="submit" value="OK, I understand, let's do this login thing." /><br /><br />
 <a href="http://google.com">nope, get me out of here</a>.
 </form>
diff --git a/helios_auth/tests.py b/helios_auth/tests.py
index de21e3b..f07f309 100644
--- a/helios_auth/tests.py
+++ b/helios_auth/tests.py
@@ -91,7 +91,7 @@ class UserModelTests(unittest.TestCase):
 
 import views
 import auth_systems.password as password_views
-from django.urls import reverse
+from django.core.urlresolvers import reverse
 
 # FIXME: login CSRF should make these tests more complicated
 # and should be tested for
@@ -116,7 +116,7 @@ class UserBlackboxTests(TestCase):
         # self.assertContains(response, "Foobar User")
 
     def test_logout(self):
-        response = self.client.post(reverse("auth@logout"), follow=True)
+        response = self.client.post(reverse(views.logout), follow=True)
         
         self.assertContains(response, "not logged in")
         self.assertNotContains(response, "Foobar User")
diff --git a/helios_auth/url_names.py b/helios_auth/url_names.py
deleted file mode 100644
index 29f7b22..0000000
--- a/helios_auth/url_names.py
+++ /dev/null
@@ -1,6 +0,0 @@
-AUTH_INDEX="auth@index"
-AUTH_LOGOUT="auth@logout"
-AUTH_START="auth@start"
-AUTH_AFTER="auth@after"
-AUTH_WHY="auth@why"
-AUTH_AFTER_INTERVENTION="auth@after-intervention"
diff --git a/helios_auth/urls.py b/helios_auth/urls.py
index 5244e10..11d1013 100644
--- a/helios_auth/urls.py
+++ b/helios_auth/urls.py
@@ -7,27 +7,27 @@ Ben Adida (ben@adida.net)
 
 from django.conf.urls import url
 
-import url_names
 import views
 from settings import AUTH_ENABLED_AUTH_SYSTEMS
 
 urlpatterns = [
     # basic static stuff
-    url(r'^$', views.index, name=url_names.AUTH_INDEX),
-    url(r'^logout$', views.logout, name=url_names.AUTH_LOGOUT),
-    url(r'^start/(?P<system_name>.*)$', views.start, name=url_names.AUTH_START),
+    url(r'^$', views.index),
+    url(r'^logout$', views.logout),
+    url(r'^start/(?P<system_name>.*)$', views.start),
     # weird facebook constraint for trailing slash
-    url(r'^after/$', views.after, name=url_names.AUTH_AFTER),
-    url(r'^why$', views.perms_why, name=url_names.AUTH_WHY),
-    url(r'^after_intervention$', views.after_intervention, name=url_names.AUTH_AFTER_INTERVENTION),
+    url(r'^after/$', views.after),
+    url(r'^why$', views.perms_why),
+    url(r'^after_intervention$', views.after_intervention),
 ]
 
 # password auth
 if 'password' in AUTH_ENABLED_AUTH_SYSTEMS:
-    from auth_systems.password import urlpatterns as password_patterns
-    urlpatterns.extend(password_patterns)
+    from auth_systems.password import password_login_view, password_forgotten_view
+    urlpatterns.append(url(r'^password/login', password_login_view))
+    urlpatterns.append(url(r'^password/forgot', password_forgotten_view))
 
 # twitter
 if 'twitter' in AUTH_ENABLED_AUTH_SYSTEMS:
-    from auth_systems.twitter import urlpatterns as twitter_patterns
-    urlpatterns.extend(twitter_patterns)
+    from auth_systems.twitter import follow_view
+    urlpatterns.append(url(r'^twitter/follow', follow_view))
diff --git a/helios_auth/view_utils.py b/helios_auth/view_utils.py
index 6699ab2..1355ba4 100644
--- a/helios_auth/view_utils.py
+++ b/helios_auth/view_utils.py
@@ -4,14 +4,16 @@ Utilities for all views
 Ben Adida (12-30-2008)
 """
 
-from django.conf import settings
-from django.http import HttpResponse
+from django.template import Context, Template, loader
+from django.http import HttpResponse, Http404
 from django.shortcuts import render_to_response
-from django.template import loader
 
-import helios_auth
 from helios_auth.security import get_user
 
+import helios_auth
+
+from django.conf import settings
+
 ##
 ## BASICS
 ##
@@ -22,37 +24,37 @@ SUCCESS = HttpResponse("SUCCESS")
 ## template abstraction
 ##
 
-def prepare_vars(request, values):
-  vars_with_user = values.copy()
-
+def prepare_vars(request, vars):
+  vars_with_user = vars.copy()
+  
   if request:
     vars_with_user['user'] = get_user(request)
     vars_with_user['csrf_token'] = request.session['csrf_token']
     vars_with_user['SECURE_URL_HOST'] = settings.SECURE_URL_HOST
-
+    
   vars_with_user['STATIC'] = '/static/auth'
   vars_with_user['MEDIA_URL'] = '/static/auth/'
   vars_with_user['TEMPLATE_BASE'] = helios_auth.TEMPLATE_BASE
-
+  
   vars_with_user['settings'] = settings
-
+  
   return vars_with_user
-
-
-def render_template(request, template_name, values=None):
-  vars_with_user = prepare_vars(request, values or {})
-
+  
+def render_template(request, template_name, vars = {}):
+  t = loader.get_template(template_name + '.html')
+  
+  vars_with_user = prepare_vars(request, vars)
+  
   return render_to_response('helios_auth/templates/%s.html' % template_name, vars_with_user)
 
-
-def render_template_raw(request, template_name, values=None):
+def render_template_raw(request, template_name, vars={}):
   t = loader.get_template(template_name + '.html')
-  values = values or {}
-
-  vars_with_user = prepare_vars(request, values)
-
-  return t.render(context=vars_with_user, request=request)
-
+  
+  vars_with_user = prepare_vars(request, vars)
+  c = Context(vars_with_user)  
+  return t.render(c)
 
 def render_json(json_txt):
   return HttpResponse(json_txt)
+
+
diff --git a/helios_auth/views.py b/helios_auth/views.py
index f246daf..b85f82e 100644
--- a/helios_auth/views.py
+++ b/helios_auth/views.py
@@ -5,20 +5,22 @@ Ben Adida
 2009-07-05
 """
 
-import urllib
-from django.urls import reverse
-from django.http import HttpResponseRedirect, HttpResponse
+from django.http import *
+from django.core.urlresolvers import reverse
 
-import helios_auth
-import settings
+from view_utils import *
+from helios_auth.security import get_user
+
+import auth_systems
 from auth_systems import AUTH_SYSTEMS
 from auth_systems import password
-from helios_auth.security import get_user
-from helios_auth.url_names import AUTH_INDEX, AUTH_START, AUTH_AFTER, AUTH_WHY, AUTH_AFTER_INTERVENTION
+import helios_auth
+
+import copy, urllib
+
 from models import User
-from security import FIELDS_TO_SAVE
-from view_utils import render_template, render_template_raw
 
+from security import FIELDS_TO_SAVE
 
 def index(request):
   """
@@ -29,7 +31,7 @@ def index(request):
 
   # single auth system?
   if len(helios_auth.ENABLED_AUTH_SYSTEMS) == 1 and not user:
-    return HttpResponseRedirect(reverse(AUTH_START, args=[helios_auth.ENABLED_AUTH_SYSTEMS[0]])+ '?return_url=' + request.GET.get('return_url', ''))
+    return HttpResponseRedirect(reverse(start, args=[helios_auth.ENABLED_AUTH_SYSTEMS[0]])+ '?return_url=' + request.GET.get('return_url', ''))
 
   #if helios_auth.DEFAULT_AUTH_SYSTEM and not user:
   #  return HttpResponseRedirect(reverse(start, args=[helios_auth.DEFAULT_AUTH_SYSTEM])+ '?return_url=' + request.GET.get('return_url', ''))
@@ -40,10 +42,10 @@ def index(request):
 
   #form = password.LoginForm()
 
-  return render_template(request, 'index', {'return_url' : request.GET.get('return_url', '/'),
-                                            'enabled_auth_systems' : helios_auth.ENABLED_AUTH_SYSTEMS,
-                                            'default_auth_system': helios_auth.DEFAULT_AUTH_SYSTEM,
-                                            'default_auth_system_obj': default_auth_system_obj})
+  return render_template(request,'index', {'return_url' : request.GET.get('return_url', '/'),
+                                           'enabled_auth_systems' : helios_auth.ENABLED_AUTH_SYSTEMS,
+                                           'default_auth_system': helios_auth.DEFAULT_AUTH_SYSTEM,
+                                           'default_auth_system_obj': default_auth_system_obj})
 
 def login_box_raw(request, return_url='/', auth_systems = None):
   """
@@ -54,7 +56,7 @@ def login_box_raw(request, return_url='/', auth_systems = None):
     default_auth_system_obj = AUTH_SYSTEMS[helios_auth.DEFAULT_AUTH_SYSTEM]
 
   # make sure that auth_systems includes only available and enabled auth systems
-  if auth_systems is not None:
+  if auth_systems != None:
     enabled_auth_systems = set(auth_systems).intersection(set(helios_auth.ENABLED_AUTH_SYSTEMS)).intersection(set(AUTH_SYSTEMS.keys()))
   else:
     enabled_auth_systems = set(helios_auth.ENABLED_AUTH_SYSTEMS).intersection(set(AUTH_SYSTEMS.keys()))
@@ -85,7 +87,7 @@ def do_local_logout(request):
 
   # let's clean up the self-referential issue:
   field_names_to_save = set(field_names_to_save)
-  field_names_to_save = field_names_to_save - {FIELDS_TO_SAVE}
+  field_names_to_save = field_names_to_save - set([FIELDS_TO_SAVE])
   field_names_to_save = list(field_names_to_save)
 
   fields_to_save = dict([(name, request.session.get(name, None)) for name in field_names_to_save])
@@ -142,7 +144,7 @@ def _do_auth(request):
   system = AUTH_SYSTEMS[system_name]
   
   # where to send the user to?
-  redirect_url = settings.SECURE_URL_HOST + reverse(AUTH_AFTER)
+  redirect_url = "%s%s" % (settings.SECURE_URL_HOST,reverse(after))
   auth_url = system.get_auth_url(request, redirect_url=redirect_url)
   
   if auth_url:
@@ -152,7 +154,7 @@ def _do_auth(request):
   
 def start(request, system_name):
   if not (system_name in helios_auth.ENABLED_AUTH_SYSTEMS):
-    return HttpResponseRedirect(reverse(AUTH_INDEX))
+    return HttpResponseRedirect(reverse(index))
   
   # why is this here? Let's try without it
   # request.session.save()
@@ -188,7 +190,7 @@ def after(request):
     
     request.session['user'] = user
   else:
-    return HttpResponseRedirect("%s?%s" % (reverse(AUTH_WHY), urllib.urlencode({'system_name' : request.session['auth_system_name']})))
+    return HttpResponseRedirect("%s?%s" % (reverse(perms_why), urllib.urlencode({'system_name' : request.session['auth_system_name']})))
 
   # does the auth system want to present an additional view?
   # this is, for example, to prompt the user to follow @heliosvoting
@@ -199,12 +201,12 @@ def after(request):
       return intervention_response
 
   # go to the after intervention page. This is for modularity
-  return HttpResponseRedirect(reverse(AUTH_AFTER_INTERVENTION))
+  return HttpResponseRedirect(reverse(after_intervention))
 
 def after_intervention(request):
   return_url = "/"
   if request.session.has_key('auth_return_url'):
     return_url = request.session['auth_return_url']
     del request.session['auth_return_url']
-  return HttpResponseRedirect(settings.URL_HOST + return_url)
+  return HttpResponseRedirect("%s%s" % (settings.URL_HOST, return_url))
 
diff --git a/requirements.txt b/requirements.txt
index 8e69fb2..237e75c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,8 +1,9 @@
-Django==1.11.28
+Django==1.8.19
 anyjson==0.3.3
-celery==4.2.1
+celery==3.1.18
+django-celery==3.1.16
 django-picklefield==0.3.0
-kombu==4.2.0
+kombu==3.0.30
 html5lib==0.999
 psycopg2==2.7.3.2
 pyparsing==1.5.7
@@ -13,8 +14,10 @@ gunicorn==19.9
 requests==2.21.0
 unicodecsv==0.9.0
 dj_database_url==0.3.0
+django-sslify==0.2.7
 django_webtest>=1.9
 webtest==2.0.18
+django-secure==1.0.1
 bleach==1.4.1
 boto==2.27.0
 django-ses==0.6.0
diff --git a/reset.sh b/reset.sh
index 8192723..52141e1 100755
--- a/reset.sh
+++ b/reset.sh
@@ -2,6 +2,6 @@
 set -e  # Exit immediately if a command exits with a non-zero status.
 dropdb helios
 createdb helios
-python manage.py makemigrations
+python manage.py syncdb
 python manage.py migrate
 echo "from helios_auth.models import User; User.objects.create(user_type='google',user_id='ben@adida.net', info={'name':'Ben Adida'})" | python manage.py shell
\ No newline at end of file
diff --git a/server_ui/__init__.py b/server_ui/__init__.py
index 3f1966c..bb89b65 100644
--- a/server_ui/__init__.py
+++ b/server_ui/__init__.py
@@ -1,3 +1,5 @@
 """
 This django app is meant only to connect the pieces of Helios and Auth to present a clean UI
 """
+
+import glue
diff --git a/server_ui/glue.py b/server_ui/glue.py
index 12b64b1..9b3b5b3 100644
--- a/server_ui/glue.py
+++ b/server_ui/glue.py
@@ -2,35 +2,36 @@
 Glue some events together 
 """
 
-import helios.signals
-import helios.views
+from django.conf import settings
+from django.core.urlresolvers import reverse
+from django.conf import settings
 from helios.view_utils import render_template_raw
+import helios.views, helios.signals
 
+import views
 
 def vote_cast_send_message(user, voter, election, cast_vote, **kwargs):
-    ## FIXME: this doesn't work for voters that are not also users
-    # prepare the message
-    subject_template = 'email/cast_vote_subject.txt'
-    body_template = 'email/cast_vote_body.txt'
-
-    extra_vars = {
-        'election': election,
-        'voter': voter,
-        'cast_vote': cast_vote,
-        'cast_vote_url': helios.views.get_castvote_url(cast_vote),
-        'custom_subject': "%s - vote cast" % election.name
-    }
-    subject = render_template_raw(None, subject_template, extra_vars)
-    body = render_template_raw(None, body_template, extra_vars)
-
-    # send it via the notification system associated with the auth system
-    user.send_message(subject, body)
-
+  ## FIXME: this doesn't work for voters that are not also users
+  # prepare the message
+  subject_template = 'email/cast_vote_subject.txt'
+  body_template = 'email/cast_vote_body.txt'
+  
+  extra_vars = {
+    'election' : election,
+    'voter': voter,
+    'cast_vote': cast_vote,
+    'cast_vote_url': helios.views.get_castvote_url(cast_vote),
+    'custom_subject' : "%s - vote cast" % election.name
+  }
+  subject = render_template_raw(None, subject_template, extra_vars)
+  body = render_template_raw(None, body_template, extra_vars)
+  
+  # send it via the notification system associated with the auth system
+  user.send_message(subject, body)
+
+helios.signals.vote_cast.connect(vote_cast_send_message)
 
 def election_tallied(election, **kwargs):
-    pass
-
+  pass
 
-def glue():
-    helios.signals.vote_cast.connect(vote_cast_send_message)
-    helios.signals.election_tallied.connect(election_tallied)
+helios.signals.election_tallied.connect(election_tallied)
diff --git a/server_ui/templates/base.html b/server_ui/templates/base.html
index 8357be2..ac5f2d1 100644
--- a/server_ui/templates/base.html
+++ b/server_ui/templates/base.html
@@ -42,7 +42,7 @@
       <!-- Right Nav Section -->
       <ul class="right">
 	{% if user and user.admin_p %}
-	<li><a href="{% url "stats@home" %}">Admin</a></li>
+	<li><a href="{% url "helios.stats_views.home" %}">Admin</a></li>
 	<li class="divider"></li>
 	{% endif %}
 	{% if not settings.MASTER_HELIOS %}
@@ -88,13 +88,13 @@
     </span>-->
     {% if user %}
     logged in as <b>{{user.display_html_small|safe}}</b>&nbsp;&nbsp;
-    <a class="tiny button" href="{% url "auth@logout" %}?return_url={{CURRENT_URL}}">logout</a><br />
+    <a class="tiny button" href="{% url "helios_auth.views.logout" %}?return_url={{CURRENT_URL}}">logout</a><br />
     {% else %}
     {% if voter %}
-    You are signed in as voter <u>{% if voter.alias %}{{voter.alias}}{% else %}{{voter.name}}{% endif %}</u> in election <u>{{voter.election.name}}</u>. [<a href="{{settings.SECURE_URL_HOST}}{% url "auth@logout" %}?return_url={{CURRENT_URL}}">sign out</a>]
+    You are signed in as voter <u>{% if voter.alias %}{{voter.alias}}{% else %}{{voter.name}}{% endif %}</u> in election <u>{{voter.election.name}}</u>. [<a href="{{settings.SECURE_URL_HOST}}{% url "helios_auth.views.logout" %}?return_url={{CURRENT_URL}}">sign out</a>]
     {% else %}
 {% if settings.SHOW_LOGIN_OPTIONS %}
-    not logged in. <a class="tiny button" href="{{settings.SECURE_URL_HOST}}{% url "auth@index" %}?return_url={{CURRENT_URL}}">log in</a>
+    not logged in. <a class="tiny button" href="{{settings.SECURE_URL_HOST}}{% url "helios_auth.views.index" %}?return_url={{CURRENT_URL}}">log in</a>
 {% else %}
 powered by <a href="http://heliosvoting.org">Helios Voting</a>.
 {% endif %}
diff --git a/server_ui/templates/confirm.html b/server_ui/templates/confirm.html
index 2f24a80..d98f65f 100644
--- a/server_ui/templates/confirm.html
+++ b/server_ui/templates/confirm.html
@@ -38,7 +38,7 @@ function show_waiting() {
 </form>
 
 <p>
-    Forgot your password? <a href="{% url "auth@password@forgotten" %}?return_url={% url "election@cast-confirm" %}">Have it emailed to you</a>.<br />(don't worry, we won't forget your vote).
+    Forgot your password? <a href="{% url "helios_auth.auth_systems.password.password_forgotten_view" %}?return_url={% url "server_ui.views.cast_confirm" %}">Have it emailed to you</a>.<br />(don't worry, we won't forget your vote).
 </p>
 </div>
 
diff --git a/server_ui/templates/done.html b/server_ui/templates/done.html
index d428106..47ff73f 100644
--- a/server_ui/templates/done.html
+++ b/server_ui/templates/done.html
@@ -11,7 +11,7 @@
 </p>
 
 <p>
-    Visit the <a href="{% url "election@view" election.uuid %}">election homepage</a>.
+    Visit the <a href="{% url "helios.views.one_election_view" election.uuid %}">election homepage</a>.
 </p>
 
 {% endblock %}
diff --git a/server_ui/templates/election_tallied.html b/server_ui/templates/election_tallied.html
index 42d4441..747e083 100644
--- a/server_ui/templates/election_tallied.html
+++ b/server_ui/templates/election_tallied.html
@@ -9,6 +9,6 @@
   </p>
   
   <p>
-      <a href="{% url "election@view" election.uuid %}">view the election</a>
+      <a href="{% url "helios.views.one_election_view" election.uuid %}">view the election</a>
   </p>
 {% endblock %}
\ No newline at end of file
diff --git a/server_ui/templates/index.html b/server_ui/templates/index.html
index 4b1fcec..e31ac19 100644
--- a/server_ui/templates/index.html
+++ b/server_ui/templates/index.html
@@ -28,7 +28,7 @@ More than <b>2,000,000 votes</b> have been cast using Helios.
 </p>
 
 {% if create_p %}
-<a class="button" href="{% url "elections@new" %}">create an election</a>
+<a class="button" href="{% url "helios.views.election_new" %}">create an election</a>
 {% endif %}
 
   {% else %}
@@ -40,7 +40,7 @@ More than <b>2,000,000 votes</b> have been cast using Helios.
   <p>
     {% for election in elections %}
     <div class="panel">
-      <a style="font-size: 1.4em;" href="{% url "shortcut@election" election.short_name %}">{{election.name}}</a>{% if settings.SHOW_USER_INFO %}<br /> by {{election.admin.display_html_small|safe}}{% endif %}
+      <a style="font-size: 1.4em;" href="{% url "helios.views.election_shortcut" election.short_name %}">{{election.name}}</a>{% if settings.SHOW_USER_INFO %}<br /> by {{election.admin.display_html_small|safe}}{% endif %}
     </div>
     <br />
     {% endfor %}
@@ -58,19 +58,19 @@ More than <b>2,000,000 votes</b> have been cast using Helios.
 {% if user %}
 <!--<div class="row right">{{user.display_html_big|safe}}</div>-->
 {% if create_p %}
-<a class="small button" href="{% url "elections@new" %}">create election</a>
+<a class="small button" href="{% url "helios.views.election_new" %}">create election</a>
 <h5 class="subheader">Administration</h5>
 {% if elections_administered %}
 <ul>
 {% for election in elections_administered %}
-<li> <a href="{% url "election@view" election.uuid %}">{{election.name}}</a></li>
+<li> <a href="{% url "helios.views.one_election_view" election.uuid %}">{{election.name}}</a></li>
 {% endfor %}
 </ul>
 {% else %}
 <em>none yet</em>
 {% endif %}
 <div class="row right">
-<a class="tiny button" href="{% url "elections@administered" %}">see all</a>
+<a class="tiny button" href="{% url "helios.views.elections_administered" %}">see all</a>
 </div>
 <div class="row"></div>
 {% endif %}
@@ -79,13 +79,13 @@ More than <b>2,000,000 votes</b> have been cast using Helios.
 {% if elections_voted %}
 <ul>
 {% for election in elections_voted %}
-<li><a href="{% url "election@view" election.uuid %}">{{election.name}}</a></li>
+<li><a href="{% url "helios.views.one_election_view" election.uuid %}">{{election.name}}</a></li>
 {% endfor %}
 </ul>
 {% else %}
 <em>none yet</em>
 {% endif %}
-<div class="row right"><a class="tiny button" href="{% url "elections@voted" %}">see all</a></div>
+<div class="row right"><a class="tiny button" href="{% url "helios.views.elections_voted" %}">see all</a></div>
 <div class="row"></div>
 {% else %}
 {% if settings.SHOW_LOGIN_OPTIONS %}
diff --git a/server_ui/urls.py b/server_ui/urls.py
index e691c07..0711bd7 100644
--- a/server_ui/urls.py
+++ b/server_ui/urls.py
@@ -1,12 +1,12 @@
 # -*- coding: utf-8 -*-
-from django.conf.urls import url
+from django.conf.urls import patterns
 
 from views import home, about, docs, faq, privacy
 
-urlpatterns = [
-  url(r'^$', home),
-  url(r'^about$', about),
-  url(r'^docs$', docs),
-  url(r'^faq$', faq),
-  url(r'^privacy$', privacy),
-]
+urlpatterns = patterns('',
+  (r'^$', home),
+  (r'^about$', about),
+  (r'^docs$', docs),
+  (r'^faq$', faq),
+  (r'^privacy$', privacy),
+)
diff --git a/server_ui/view_utils.py b/server_ui/view_utils.py
index df94721..e22fcd5 100644
--- a/server_ui/view_utils.py
+++ b/server_ui/view_utils.py
@@ -4,17 +4,21 @@ Utilities for single election views
 Ben Adida (2009-07-18)
 """
 
-from django.conf import settings
+from django.template import Context, Template, loader
+from django.http import HttpResponse, Http404
 from django.shortcuts import render_to_response
 
 from helios_auth.security import get_user
 
+from django.conf import settings
 
 ##
 ## template abstraction
 ##
-def render_template(request, template_name, values = None):
-  vars_with_user = values.copy() if values is not None else {}
+def render_template(request, template_name, vars = {}):
+  t = loader.get_template(template_name + '.html')
+  
+  vars_with_user = vars.copy()
   vars_with_user['user'] = get_user(request)
   vars_with_user['settings'] = settings
   vars_with_user['CURRENT_URL'] = request.path
diff --git a/server_ui/views.py b/server_ui/views.py
index 190d902..a4fe095 100644
--- a/server_ui/views.py
+++ b/server_ui/views.py
@@ -2,19 +2,23 @@
 server_ui specific views
 """
 
-import copy
-from django.conf import settings
+from helios.models import *
+from helios_auth.security import *
+from view_utils import *
 
-import helios_auth.views as auth_views
-from helios.models import Election
+import helios.views
+import helios
+from helios.crypto import utils as cryptoutils
+from helios_auth.security import *
 from helios.security import can_create_election
-from helios_auth.security import get_user
-from view_utils import render_template
-import glue
 
+from django.core.urlresolvers import reverse
+from django.http import HttpResponse, HttpResponseRedirect, Http404, HttpResponseNotAllowed
 
-glue.glue()  # actually apply glue helios.view <-> helios.signals
+from django.conf import settings
 
+import copy
+import helios_auth.views as auth_views
 
 def get_election():
   return None
diff --git a/settings.py b/settings.py
index 1a4a08a..2cf2d8f 100644
--- a/settings.py
+++ b/settings.py
@@ -1,10 +1,8 @@
 
+import os, json
+
 # a massive hack to see if we're testing, in which case we use different settings
 import sys
-
-import json
-import os
-
 TESTING = 'test' in sys.argv
 
 # go through environment variables and override them
@@ -15,6 +13,7 @@ def get_from_env(var, default):
         return default
 
 DEBUG = (get_from_env('DEBUG', '1') == '1')
+TEMPLATE_DEBUG = DEBUG
 
 # add admins of the form: 
 #    ('Ben Adida', 'ben@adida.net'),
@@ -41,12 +40,14 @@ DATABASES = {
     }
 }
 
+SOUTH_DATABASE_ADAPTERS = {'default':'south.db.postgresql_psycopg2'}
+
 # override if we have an env variable
 if get_from_env('DATABASE_URL', None):
     import dj_database_url
     DATABASES['default'] =  dj_database_url.config()
     DATABASES['default']['ENGINE'] = 'django.db.backends.postgresql_psycopg2'
-    DATABASES['default']['CONN_MAX_AGE'] = '600'
+    DATABASES['default']['CONN_MAX_AGE'] = 600
 
     # require SSL
     DATABASES['default']['OPTIONS'] = {'sslmode': 'require'}
@@ -92,7 +93,7 @@ SECRET_KEY = get_from_env('SECRET_KEY', 'replaceme')
 ALLOWED_HOSTS = get_from_env('ALLOWED_HOSTS', 'localhost').split(",")
 
 # Secure Stuff
-if get_from_env('SSL', '0') == '1':
+if (get_from_env('SSL', '0') == '1'):
     SECURE_SSL_REDIRECT = True
     SESSION_COOKIE_SECURE = True
 
@@ -103,7 +104,7 @@ SESSION_COOKIE_HTTPONLY = True
 
 # let's go with one year because that's the way to do it now
 STS = False
-if get_from_env('HSTS', '0') == '1':
+if (get_from_env('HSTS', '0') == '1'):
     STS = True
     # we're using our own custom middleware now
     # SECURE_HSTS_SECONDS = 31536000
@@ -113,46 +114,45 @@ if get_from_env('HSTS', '0') == '1':
 SECURE_BROWSER_XSS_FILTER = True
 SECURE_CONTENT_TYPE_NOSNIFF = True
 
-SILENCED_SYSTEM_CHECKS = ['urls.W002']
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+    'django.template.loaders.filesystem.Loader',
+    'django.template.loaders.app_directories.Loader'
+)
+
+MIDDLEWARE_CLASSES = (
+    # make all things SSL
+    #'sslify.middleware.SSLifyMiddleware',
 
-MIDDLEWARE = [
     # secure a bunch of things
-    'django.middleware.security.SecurityMiddleware',
+    'djangosecure.middleware.SecurityMiddleware',
     'helios.security.HSTSMiddleware',
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
-    # 'django.middleware.csrf.CsrfViewMiddleware',
 
     'django.middleware.common.CommonMiddleware',
     'django.contrib.sessions.middleware.SessionMiddleware',
-    'django.contrib.auth.middleware.AuthenticationMiddleware',
-]
+    'django.contrib.auth.middleware.AuthenticationMiddleware'
+)
 
 ROOT_URLCONF = 'urls'
 
 ROOT_PATH = os.path.dirname(__file__)
-
-TEMPLATES = [
-    {
-        'BACKEND': 'django.template.backends.django.DjangoTemplates',
-        'APP_DIRS': True,
-        'DIRS': [
-            ROOT_PATH,
-            os.path.join(ROOT_PATH, 'templates'),
-            # os.path.join(ROOT_PATH, 'helios/templates'),  # covered by APP_DIRS:True
-            # os.path.join(ROOT_PATH, 'helios_auth/templates'),  # covered by APP_DIRS:True
-            # os.path.join(ROOT_PATH, 'server_ui/templates'),  # covered by APP_DIRS:True
-        ],
-        'OPTIONS': {
-            'debug': DEBUG
-        }
-    },
-]
+TEMPLATE_DIRS = (
+    ROOT_PATH,
+    os.path.join(ROOT_PATH, 'templates')
+)
 
 INSTALLED_APPS = (
-    'django.contrib.auth',
-    'django.contrib.contenttypes',
+#    'django.contrib.auth',
+#    'django.contrib.contenttypes',
+    'djangosecure',
     'django.contrib.sessions',
-    'django.contrib.sites',
+    #'django.contrib.sites',
+    ## needed for queues
+    'djcelery',
+    'kombu.transport.django',
+    ## in Django 1.7 we now use built-in migrations, no more south
+    ## 'south',
     ## HELIOS stuff
     'helios_auth',
     'helios',
@@ -267,17 +267,23 @@ logging.basicConfig(
 )
 
 
-# set up celery
-CELERY_BROKER_URL = get_from_env('CELERY_BROKER_URL', 'amqp://localhost')
-if TESTING:
-    CELERY_TASK_ALWAYS_EAGER = True
-#database_url = DATABASES['default']
+# set up django-celery
+# BROKER_BACKEND = "kombu.transport.DatabaseTransport"
+BROKER_URL = "django://"
+CELERY_RESULT_DBURI = DATABASES['default']
+import djcelery
+djcelery.setup_loader()
+
+
+# for testing
+TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner'
+# this effectively does CELERY_ALWAYS_EAGER = True
 
 # Rollbar Error Logging
 ROLLBAR_ACCESS_TOKEN = get_from_env('ROLLBAR_ACCESS_TOKEN', None)
 if ROLLBAR_ACCESS_TOKEN:
   print "setting up rollbar"
-  MIDDLEWARE += ['rollbar.contrib.django.middleware.RollbarNotifierMiddleware',]
+  MIDDLEWARE_CLASSES += ('rollbar.contrib.django.middleware.RollbarNotifierMiddleware',)
   ROLLBAR = {
     'access_token': ROLLBAR_ACCESS_TOKEN,
     'environment': 'development' if DEBUG else 'production',  
diff --git a/urls.py b/urls.py
index 8c29e83..d467499 100644
--- a/urls.py
+++ b/urls.py
@@ -1,19 +1,21 @@
 # -*- coding: utf-8 -*-
+from django.conf.urls import *
+from django.contrib import admin
 from django.conf import settings
-from django.conf.urls import url, include
-from django.views.static import serve
 
-urlpatterns = [
-    url(r'^auth/', include('helios_auth.urls')),
-    url(r'^helios/', include('helios.urls')),
+urlpatterns = patterns(
+    '',
+    (r'^auth/', include('helios_auth.urls')),
+    (r'^helios/', include('helios.urls')),
 
     # SHOULD BE REPLACED BY APACHE STATIC PATH
-    url(r'booth/(?P<path>.*)$', serve, {'document_root' : settings.ROOT_PATH + '/heliosbooth'}),
-    url(r'verifier/(?P<path>.*)$', serve, {'document_root' : settings.ROOT_PATH + '/heliosverifier'}),
+    (r'booth/(?P<path>.*)$', 'django.views.static.serve', {'document_root' : settings.ROOT_PATH + '/heliosbooth'}),
+    (r'verifier/(?P<path>.*)$', 'django.views.static.serve', {'document_root' : settings.ROOT_PATH + '/heliosverifier'}),
 
-    url(r'static/auth/(?P<path>.*)$', serve, {'document_root' : settings.ROOT_PATH + '/helios_auth/media'}),
-    url(r'static/helios/(?P<path>.*)$', serve, {'document_root' : settings.ROOT_PATH + '/helios/media'}),
-    url(r'static/(?P<path>.*)$', serve, {'document_root' : settings.ROOT_PATH + '/server_ui/media'}),
+    (r'static/auth/(?P<path>.*)$', 'django.views.static.serve', {'document_root' : settings.ROOT_PATH + '/helios_auth/media'}),
+    (r'static/helios/(?P<path>.*)$', 'django.views.static.serve', {'document_root' : settings.ROOT_PATH + '/helios/media'}),
+    (r'static/(?P<path>.*)$', 'django.views.static.serve', {'document_root' : settings.ROOT_PATH + '/server_ui/media'}),
 
-    url(r'^', include('server_ui.urls')),
-]
+    (r'^', include('server_ui.urls')),
+
+    )
-- 
GitLab