diff --git a/helios/election_urls.py b/helios/election_urls.py
index c7cd8fc00fbfa75c7572b875238121673efb82cb..6622c5568a2564d986fdf916b401de7651281796 100644
--- a/helios/election_urls.py
+++ b/helios/election_urls.py
@@ -20,6 +20,7 @@ urlpatterns = patterns('',
     (r'^/schedule$', one_election_schedule),
     (r'^/extend$', one_election_extend),
     (r'^/archive$', one_election_archive),
+    (r'^/copy$', one_election_copy),
 
     # badge
     (r'^/badge$', election_badge),
diff --git a/helios/forms.py b/helios/forms.py
index 2ef7c809f5b84d1e6e8ce7b88ed182d8c412d9b2..cb10cfab8b7179b315f866de6ff1705dcb0d83f5 100644
--- a/helios/forms.py
+++ b/helios/forms.py
@@ -10,7 +10,7 @@ from django.conf import settings
 
 
 class ElectionForm(forms.Form):
-  short_name = forms.SlugField(max_length=25, help_text='no spaces, will be part of the URL for your election, e.g. my-club-2010')
+  short_name = forms.SlugField(max_length=40, help_text='no spaces, will be part of the URL for your election, e.g. my-club-2010')
   name = forms.CharField(max_length=100, widget=forms.TextInput(attrs={'size':60}), help_text='the pretty name for your election, e.g. My Club 2010 Election')
   description = forms.CharField(max_length=4000, widget=forms.Textarea(attrs={'cols': 70, 'wrap': 'soft'}), required=False)
   election_type = forms.ChoiceField(label="type", choices = Election.ELECTION_TYPES)
diff --git a/helios/templates/election_view.html b/helios/templates/election_view.html
index 2cc8538a54311271972b85a7b52b4e9f7b699516..8d9d7af295e4a01e466c0ddcb96f176276a49186 100644
--- a/helios/templates/election_view.html
+++ b/helios/templates/election_view.html
@@ -15,6 +15,7 @@
 {% endif %}
 {% if admin_p %}
 &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" href="{% url "helios.views.one_election_copy" election_uuid=election.uuid %}">copy</a>
 {% endif %}
 <br />
 {% if admin_p %}
diff --git a/helios/views.py b/helios/views.py
index 2582851bd4b89fb37cbc52517d8653f22d02d386..b3a14b3e215cc4cf71f2be5cb23591d7bc5d7c23 100644
--- a/helios/views.py
+++ b/helios/views.py
@@ -920,6 +920,40 @@ def one_election_archive(request, election):
   election.save()
 
   return HttpResponseRedirect(settings.SECURE_URL_HOST + reverse(one_election_view, args=[election.uuid]))
+  
+@election_admin()
+def one_election_copy(request, election):
+  # FIXME: make this a POST and CSRF protect it
+  # check_csrf(request)
+  
+  # new short name by uuid, because it's easier and the user can change it.
+  new_uuid = uuid.uuid4()
+  new_short_name = new_uuid
+  
+  new_election = Election.objects.create(
+    admin = election.admin,
+    uuid = new_uuid,
+    datatype = election.datatype,
+    short_name = new_short_name,
+    name = "Copy of " + election.name,
+    election_type = election.election_type,
+    private_p = election.private_p,
+    description = election.description,
+    questions = election.questions,
+    eligibility = election.eligibility,
+    openreg = election.openreg,
+    use_voter_aliases = election.use_voter_aliases,
+    use_advanced_audit_features = election.use_advanced_audit_features,
+    randomize_answer_order = election.randomize_answer_order,
+    registration_starts_at = election.registration_starts_at,
+    voting_starts_at = election.voting_starts_at,
+    voting_ends_at = election.voting_ends_at,
+    cast_url = settings.SECURE_URL_HOST + reverse(one_election_cast, args=[new_uuid])
+  )
+  
+
+  new_election.generate_trustee(ELGAMAL_PARAMS)
+  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