diff --git a/election-candidate-details.tpl.php b/election-candidate-details.tpl.php
deleted file mode 100644
index 0134efa5cce2c7be8fd5f0504babbc9af40bc9b8..0000000000000000000000000000000000000000
--- a/election-candidate-details.tpl.php
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-
-/**
- * @file
- * Default theme implementation to display an election candidate's full details.
- */
-
-?>
-<div id="election-<?php print $election->election_id; ?>-candidate-details-<?php print $candidate->candidate_id; ?>" class="<?php print $classes; ?> clearfix"<?php print $attributes; ?>>
-
-  <div class="content"<?php print $content_attributes; ?>>
-    <?php print render($content); ?>
-  </div>
-
-</div>
diff --git a/election-candidate.admin.inc b/election-candidate.admin.inc
deleted file mode 100644
index 2fa82a4c53dd925fa083acf0048ef42521971264..0000000000000000000000000000000000000000
--- a/election-candidate.admin.inc
+++ /dev/null
@@ -1,403 +0,0 @@
-<?php
-/**
- * @file
- * Administrative page callbacks for election candidates and nominations
- * (Election module).
- */
-
-/**
- * Form builder function for the main administrative election candidate list.
- *
- * @param array $form
- * @param array $form_state
- * @param stdClass $election
- *
- * @return array
- *   Render array.
- */
-function election_candidate_list_form($form, $form_state, $election) {
-
- // @todo this should not be necessary
-  drupal_set_title(t('Candidates'), PASS_THROUGH);
-  drupal_set_breadcrumb(
-    _election_build_breadcrumb($election)
-  );
-
-  $post_name = _election_get_posts_name($election->type);
-
-  // Build the sortable table header.
-  $header = array(
-    'created' => array('data' => t('Nominated'), 'field' => 'ec.created', 'sort' => 'desc'),
-    'post_title' => array('data' => drupal_ucfirst($post_name), 'field' => 'ep.title'),
-    'first_name' => array('data' => t('First name'), 'field' => 'ec.first_name'),
-    'last_name' => array('data' => t('Last name'), 'field' => 'ec.last_name'),
-    'username' => array('data' => t('Username'), 'field' => 'ec.username'),
-    'cstatus' => array('data' => t('Status'), 'field' => 'ec.cstatus'),
-    'operations' => array('data' => t('Operations')),
-  );
-
-  // Build the query, adding a pager and sorter.
-  $query = db_select('election_candidate', 'ec')
-    ->extend('PagerDefault')
-    ->extend('TableSort')
-    ->fields('ec', array('candidate_id'));
-  $query->leftJoin('election_post', 'ep', 'ec.post_id=ep.post_id');
-  $query->condition('ec.election_id', $election->election_id)
-    ->limit(50)
-    ->orderByHeader($header);
-  $result = $query->execute();
-
-  // Get array of candidates
-  $candidate_ids = $result->fetchCol();
-  $candidates = election_candidate_load_multiple($candidate_ids);
-
-  $destination = drupal_get_destination();
-
-  $default_post_title = '<em class="deleted-post">' . t('Deleted?') . '</em>';
-
-  $options = array();
-  foreach ($candidates as $id => $candidate) {
-
-    $post_title = $default_post_title;
-    if (!empty($candidate->post_id)) {
-      $post = election_post_load($candidate->post_id);
-      $post_title = check_plain($post->title);
-    }
-
-    $account = user_load($candidate->uid);
-
-    $options[$candidate->candidate_id] = array(
-      'created' => format_date($candidate->created, 'short'),
-      'post_title' => $post_title,
-      'first_name' => check_plain($candidate->first_name),
-      'last_name' => check_plain($candidate->last_name),
-      'username' => $account? theme('username', array('account' => $account)) : t('Anonymous'),
-      'cstatus' => _election_candidate_format_status($candidate),
-    );
-
-    $operations = array();
-    $candidate_uri_path = election_candidate_uri_path($candidate);
-
-    if (election_candidate_access('view', $candidate)) {
-      $operations['view'] = l(
-        t('view'),
-        $candidate_uri_path
-      );
-    }
-
-    if (election_candidate_access('view details', $candidate)) {
-      $operations['view_details'] = l(
-        t('details'),
-        $candidate_uri_path . '/details'
-      );
-    }
-
-    if (election_candidate_access('update', $candidate)) {
-      $operations['edit'] = l(
-        t('edit'),
-        $candidate_uri_path . '/edit',
-        array('query' => $destination)
-      );
-    }
-
-    if (count($operations)) {
-      // Render an unordered list of operations links.
-      $options[$candidate->candidate_id]['operations'] = array(
-        'data' => array(
-          '#theme' => 'item_list',
-          '#items' => $operations,
-          '#attributes' => array('class' => array('operations')),
-        ),
-      );
-    }
-
-  }
-
-  $form['election_candidates'] = array(
-    '#theme' => 'table',
-    '#header' => $header,
-    '#rows' => $options,
-    '#empty' => t('No candidates available.'),
-  );
-
-  $form['pager'] = array('#markup' => theme('pager'));
-
-  return $form;
-}
-
-/**
- * Display total numbers of candidates per post.
- */
-function election_candidate_totals_page(stdClass $election) {
-
-  drupal_set_title(t('Candidate totals'));
-
-  $result = db_query('SELECT COUNT(DISTINCT candidate_id) AS num_candidates, COUNT(DISTINCT IF (cstatus=0, candidate_id, NULL)) AS num_pending, COUNT(DISTINCT IF (cstatus=1, candidate_id, NULL)) AS num_approved, COUNT(DISTINCT IF (cstatus=-1, candidate_id, NULL)) AS num_withdrawn, COUNT(DISTINCT IF (cstatus=-2, candidate_id, NULL)) AS num_rejected FROM {election_candidate} WHERE election_id = :election_id', array(
-  ':election_id' => $election->election_id));
-  $totalAll = $result->fetch();
-
-  $output = array(
-    'total' => array(
-      '#markup' => '<p>' . t('Total number of candidates: !totalAll', array('!totalAll' => $totalAll->num_candidates)) . '</p>',
-    ),
-  );
-
-  if ($totalAll->num_candidates > 0) {
-    $result = db_query(
-      'SELECT ep.title, COUNT(DISTINCT ec.candidate_id) AS num_candidates, COUNT(DISTINCT IF (ec.cstatus=0, ec.candidate_id, NULL)) AS num_pending, COUNT(DISTINCT IF (ec.cstatus=1, ec.candidate_id, NULL)) AS num_approved, COUNT(DISTINCT IF (ec.cstatus=-1, ec.candidate_id, NULL)) AS num_withdrawn, COUNT(DISTINCT IF (ec.cstatus=-2, ec.candidate_id, NULL)) AS num_rejected FROM {election_post} ep LEFT JOIN {election_candidate} ec USING (post_id) WHERE ep.election_id = :election_id GROUP BY ep.post_id ORDER BY ep.title',
-      array(
-        ':election_id' => $election->election_id,
-      )
-    );
-    $totals = $result->fetchAll();
-    $header = array(t('Position'), t('Pending'), t('Approved'), t('Rejected'), t('Withdrawn'));
-    $rows = array();
-    $rows[] = array(t('TOTAL'), $totalAll->num_pending, $totalAll->num_approved, $totalAll->num_withdrawn, $totalAll->num_rejected);
-    foreach ($totals as $total) {
-      $rows[] = array(check_plain($total->title), $total->num_pending, $total->num_approved, $total->num_withdrawn, $total->num_rejected);
-    }
-    $output['by_position'] = array(
-      '#theme' => 'table',
-      '#header' => $header,
-      '#rows' => $rows,
-    );
-  }
-
-  return $output;
-}
-
-/**
- * Form builder function for the form at "election/%election/candidates/download".
- *
- * @param array $form
- * @param array $form_state
- * @param stdClass $election
- */
-function election_candidate_download_form($form, &$form_state, stdClass $election) {
-
-  drupal_set_title(t('Download candidate data'));
-
-  // @todo allow new candidate bundles.
-  $candidate_field_instances = field_info_instances('election_candidate', 'election_candidate');
-
-  $post_name = _election_get_posts_name($election->type);
-
-  $properties = array(
-    'election_id' => t('Election ID'),
-    'election_title' => array(
-      'label' => t('Election title'),
-      'default' => TRUE,
-    ),
-    'candidate_id' => t('Candidate ID'),
-    'first_name' => array(
-      'label' => t('First name'),
-      'default' => TRUE,
-    ),
-    'last_name' => array(
-      'label' => t('Last name'),
-      'default' => TRUE,
-    ),
-    'post_id' => t('@post_name ID', array('@post_name' => drupal_ucfirst($post_name))),
-    'post_title' => array(
-      'label' => t('@post_name title', array('@post_name' => drupal_ucfirst($post_name))),
-      'default' => TRUE,
-    ),
-    'cstatus' => array(
-      'label' => t('Candidate status'),
-      'default' => TRUE,
-    ),
-    'mail' => array(
-      'label' => t('Email address'),
-      'default' => TRUE,
-    ),
-    'phone' => array(
-      'label' => t('Phone number'),
-      'default' => TRUE,
-    ),
-    'uid' => t('User ID'),
-    'username' => array(
-      'label' => t('Username'),
-      'default' => TRUE,
-    ),
-    'created' => array(
-      'label' => t('Created date'),
-      'default' => TRUE,
-      'type' => 'timestamp',
-    ),
-    'changed' => array(
-      'label' => t('Last modified date'),
-      'default' => TRUE,
-      'type' => 'timestamp',
-    ),
-    'profile_link' => array(
-      'label' => t('Profile link'),
-      'default' => TRUE,
-    ),
-  );
-  foreach ($candidate_field_instances as $field_name => $cfi) {
-    $field = field_info_field($field_name);
-    $properties[$field_name] = array(
-      'label' => $cfi['label'],
-      'type' => $field['type'],
-      'default' => FALSE,
-    );
-  }
-
-  $property_options = array();
-  $default_properties = array();
-  foreach ($properties as $property_key => $property) {
-    $label = is_string($property)? $property : $property['label'];
-    $property_options[$property_key] = $label;
-    if (isset($property['default']) && $property['default'] === TRUE) {
-      $default_properties[] = $property_key;
-    }
-  }
-
-  $form_state['#election'] = $election;
-  $form_state['#properties'] = $properties;
-  $form_state['#property_options'] = $property_options;
-
-  $form['include_properties'] = array(
-    '#type' => 'checkboxes',
-    '#title' => t('Properties to include'),
-    '#options' => $property_options,
-    '#default_value' => $default_properties,
-  );
-
-  $form['buttons'] = array(
-    '#type' => 'actions',
-    '#weight' => 100,
-  );
-  $form['buttons']['download'] = array(
-    '#type' => 'submit',
-    '#value' => t('Download candidate spreadsheet'),
-  );
-
-  return $form;
-
-}
-
-/**
- * Submit callback for the form election_candidate_download_form.
- *
- * @param array $form
- * @param array $form_state
- */
-function election_candidate_download_form_submit($form, &$form_state) {
-
-  $election = $form_state['#election'];
-
-  $fileName = 'candidates_election' . $election->election_id . '_' . date('Y-m-d_His', REQUEST_TIME) . '.csv';
-
-  $include_properties = $form_state['values']['include_properties'];
-  foreach ($include_properties as $key => $value) {
-    if ($value === 0) {
-      unset($include_properties[$key]);
-    }
-  }
-
-  $properties = array_intersect_key($form_state['#properties'], $include_properties);
-
-  $separator = ',';
-  $enclosure = '"';
-  $empty = '';
-
-  $outstream = fopen('php://output', 'w');
-
-  $candidate_ids = db_select('election_candidate')
-    ->fields('election_candidate', array('candidate_id'))
-    ->condition('election_id', $election->election_id)
-    ->orderBy('created', 'DESC')
-    ->execute()
-    ->fetchCol();
-  $candidates = election_candidate_load_multiple($candidate_ids);
-
-  drupal_add_http_header('Content-Type', 'text/csv; charset=UTF-8');
-  drupal_add_http_header('Cache-Control', 'no-store, max-age=0, must-revalidate');
-  drupal_add_http_header('Pragma', FALSE);
-  drupal_add_http_header('Content-Description', 'File Transfer');
-  drupal_add_http_header('Content-Disposition', 'attachment; filename="' . $fileName . '"');
-
-  $property_headers = array();
-  foreach ($properties as $property) {
-    $property_headers[] = is_string($property)? $property : $property['label'];
-  }
-
-  fputcsv($outstream, $property_headers, $separator, $enclosure);
-
-  foreach ($candidates as $candidate) {
-
-    $row = array();
-    foreach ($properties as $property_key => $property) {
-      $value = _election_candidate_download_format_property($candidate, $property_key, $property);
-      $row[$property_key] = strlen($value)? $value : $empty;
-    }
-
-    fputcsv($outstream, $row, $separator, $enclosure);
-    fpassthru($outstream);
-  }
-
-  fpassthru($outstream);
-  fclose($outstream);
-
-  exit();
-
-}
-
-/**
- * Format a candidate property.
- *
- * @param stdClass $candidate
- */
-function _election_candidate_download_format_property(stdClass $candidate, $property_key, $property) {
-  $value = isset($candidate->{$property_key})? $candidate->{$property_key} : NULL;
-  switch ($property_key) {
-    case 'profile_link':
-      return url(election_candidate_uri_path($candidate), array('absolute' => TRUE));
-      return $election->title;
-      break;
-    case 'election_title':
-      $election = election_load($candidate->election_id);
-      return $election->title;
-      break;
-    case 'post_title':
-      if (empty($candidate->post_id)) {
-        return;
-      }
-      $post = election_post_load($candidate->post_id);
-      return $post->title;
-      break;
-    case 'cstatus':
-      return _election_candidate_format_status($candidate);
-      break;
-  }
-  $type = 'string';
-  if (is_array($property) && !empty($property['type'])) {
-    $type = $property['type'];
-  }
-  switch ($type) {
-    case 'timestamp':
-      return date('Y-m-d H:i:s', $value);
-      break;
-    case 'string':
-      if (is_string($value)) {
-        return check_plain($value);
-      }
-      break;
-    case 'file':
-    case 'image':
-      if (is_array($value) && isset($value['und'][0]['uri'])) {
-        return file_create_url($value['und'][0]['uri']);
-      }
-      break;
-    default:
-      if (is_array($value)) {
-        if (isset($value['und'][0]['safe_value'])) {
-          return $value['und'][0]['safe_value'];
-        }
-        else if (isset($value['und'][0]['value'])) {
-          return check_plain($value['und'][0]['value']);
-        }
-      }
-  }
-}
\ No newline at end of file
diff --git a/election-candidate.pages.inc b/election-candidate.pages.inc
deleted file mode 100644
index b42b7ce219013f1593d98a8959ef5afcc116369c..0000000000000000000000000000000000000000
--- a/election-candidate.pages.inc
+++ /dev/null
@@ -1,715 +0,0 @@
-<?php
-/**
- * @file
- * Page callbacks and form functions for election candidates and nominations
- * (Election module).
- */
-
-/**
- * Page callback for election/%election/candidate/%election_candidate
- *
- * @param stdClass $election
- * @param stdClass $candidate
- */
-function election_candidate_page_view(stdClass $election, stdClass $candidate, $view_mode = 'full') {
-
-  drupal_set_title(
-    t(
-      'Candidate: @first-name @last-name',
-      array(
-        '@first-name' => $candidate->first_name,
-        '@last-name' => $candidate->last_name,
-      )
-    ),
-    PASS_THROUGH
-  );
-
-  drupal_set_breadcrumb(
-    _election_build_breadcrumb($election, '_CANDIDATES_')
-  );
-
-  $uri = entity_uri('election_candidate', $candidate, $election);
-  // Set the candidate path as the canonical URL to prevent duplicate content.
-  drupal_add_html_head_link(array('rel' => 'canonical', 'href' => url($uri['path'], $uri['options'])), TRUE);
-  // Set the non-aliased path as a default shortlink.
-  drupal_add_html_head_link(array('rel' => 'shortlink', 'href' => url($uri['path'], array_merge($uri['options'], array('alias' => TRUE)))), TRUE);
-
-  return election_candidate_view($candidate, $election, $view_mode);
-
-}
-
-/**
- * Page callback for election/%election/candidate/%election_candidate/details
- *
- * @param stdClass $election
- * @param stdClass $candidate
- */
-function election_candidate_details_page_view(stdClass $election, stdClass $candidate) {
-
-  drupal_set_title(
-    t(
-      'Candidate: @first-name @last-name',
-      array(
-        '@first-name' => $candidate->first_name,
-        '@last-name' => $candidate->last_name,
-      )
-    ),
-    PASS_THROUGH
-  );
-
-  drupal_set_breadcrumb(
-    _election_build_breadcrumb($election, '_CANDIDATES_')
-  );
-
-  $post = election_post_load($candidate->post_id);
-
-  return array(
-    '#theme' => 'election_candidate_details',
-    '#candidate' => $candidate,
-    '#election' => $election,
-    '#post' => $post,
-  );
-
-}
-
-
-/**
- * Generate a table of a user's previous nominations in an election.
- *
- * @param stdClass $election
- * @param array $previous_nominations
- */
-function election_candidate_display_previous_nominations(stdClass $election, array $previous_nominations) {
-  if (empty($previous_nominations)) {
-    return;
-  }
-  $caption = t('Your previous nominations in this election');
-  $header = array(
-    t('Nomination date'),
-    drupal_ucfirst(_election_get_posts_name($election->type)),
-    t('Candidate name'),
-    t('Status'),
-  );
-  $rows = array();
-  foreach ($previous_nominations as $nomination) {
-    $post = election_post_load($nomination->post_id);
-    $post_title = empty($post)? '?' : check_plain($post->title);
-    $rows[] = array(
-      format_date($nomination->created, 'short'),
-      $post_title,
-      check_plain($nomination->first_name . ' ' . $nomination->last_name),
-      _election_candidate_format_status($nomination)
-    );
-  }
-  return array(
-    '#theme' => 'table',
-    '#header' => $header,
-    '#rows' => $rows,
-    '#caption' => $caption,
-  );
-}
-
-/**
- * Page callback for election/%election/nomination-form
- */
-function election_page_nomination_form(stdClass $election) {
-
-  // @todo this should not be necessary
-  drupal_set_title(t('Nomination form'), PASS_THROUGH);
-  drupal_set_breadcrumb(_election_build_breadcrumb($election));
-
-  if ($election->type == 'referendum') {
-    return MENU_NOT_FOUND;
-  }
-
-  $nopen = _election_is_open($election->nstatus, $election->nopen_time, $election->nclose_time);
-  if (!$nopen && !user_access('bypass nomination schedule')) {
-    return array(
-      '#markup' => t('Nominations are currently closed.'),
-    );
-  }
-
-  $previous_nominations = (array) election_candidate_get_user_nominations($election);
-
-  $available_post_ids = (array) election_candidate_get_available_posts($election, $previous_nominations);
-
-  // End with an error message if there are no available posts.
-  if (empty($available_post_ids)) {
-    $posts_name = _election_get_posts_name($election->type, TRUE);
-    return array(
-      election_candidate_display_previous_nominations($election, $previous_nominations),
-      array(
-        '#markup' => t(
-          'There are no more @posts-name available for nomination in this election.',
-          array('@posts-name' => $posts_name)
-        ),
-      ),
-    );
-  }
-  $available_posts = (array) election_post_load_multiple($available_post_ids);
-
-  return drupal_get_form('election_candidate_nomination_form', $election, $previous_nominations, $available_posts);
-
-}
-
-/*
- * Election nominations form function. This creates election_candidate entities.
- *
- * @param array $form
- * @param array $form_state
- * @param stdClass $election
- * @param array $previous_nominations
- * @param array $available_posts
- */
-function election_candidate_nomination_form($form, &$form_state, stdClass $election, array $previous_nominations, array $available_posts) {
-
-  global $user;
-
-  $candidate = entity_get_controller('election_candidate')->create();
-  $candidate->is_new = TRUE;
-
-  $form['#id'] = 'election-nomination-form';
-
-  if (!isset($form_state['seconder_count'])) {
-    $form_state['seconder_count'] = 1;
-  }
-
-  $form_state['candidate'] = $candidate;
-  $form_state['election'] = $election;
-
-  if (count($previous_nominations)) {
-    $form['previous_nominations'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Your previous nominations'),
-      '#collapsible' => TRUE,
-      '#collapsed' => TRUE,
-      '#weight' => -50,
-    );
-    $previous_nominations_display = election_candidate_display_previous_nominations($election, $previous_nominations);
-    unset($previous_nominations_display['#caption']);
-    $form['previous_nominations']['display'] = $previous_nominations_display;
-  }
-
-  $bypass = user_access('bypass nomination access control');
-  $post_options = array();
-  foreach ($available_posts as $post) {
-    if ($bypass || $post->nstatus_inheritance == ELECTION_POST_STATUS_INHERIT) {
-      // @todo make this alterable
-      $post_options[$post->post_id] = truncate_utf8($post->title, 100, TRUE, TRUE, 80);
-    }
-  }
-  drupal_alter('election_candidate_post_options', $post_options);
-  $post_name = _election_get_posts_name($election->type);
-  $form['post_id'] = array(
-    '#type' => 'select',
-    '#options' => $post_options,
-    '#title' => check_plain(drupal_ucfirst($post_name)),
-    '#empty_option' => t('- Select @post_name -', array('@post_name' => $post_name)),
-    '#required' => TRUE,
-  );
-
-  $form['first_name'] = array(
-    '#type' => 'textfield',
-    '#title' => t('First name(s)'),
-    '#max_length' => 100,
-    '#size' => 50,
-    '#required' => TRUE,
-  );
-
-  $form['last_name'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Last name(s)'),
-    '#max_length' => 100,
-    '#size' => 50,
-    '#required' => TRUE,
-  );
-
-  $form['mail'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Email address'),
-    '#size' => 30,
-    '#required' => TRUE,
-    '#default_value' => empty($user->mail)? NULL: $user->mail,
-  );
-
-  $form['phone'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Contact telephone number'),
-    '#size' => 12,
-    '#required' => TRUE, // @todo make this alterable
-  );
-
-  // Add custom fields from the Field system.
-  field_attach_form('election_candidate', $candidate, $form, $form_state);
-
-  $form['#validate'][] = 'election_candidate_form_validate';
-  $form['#validate'][] = 'election_candidate_nomination_form_validate';
-
-  $form['buttons'] = array(
-    '#type' => 'actions',
-    '#weight' => 100,
-  );
-  $form['buttons']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Submit nomination'),
-    '#submit' => array('election_candidate_nomination_form_submit'),
-  );
-
-  return $form;
-}
-
-
-/**
- * Validation function for both the candidate edit form and the nomination form.
- *
- * @param array $form
- * @param array $form_state
- */
-function election_candidate_form_validate($form, &$form_state) {
-
-  if (!empty($form_state['values']['mail']) && !filter_var($form_state['values']['mail'], FILTER_VALIDATE_EMAIL)) {
-    form_set_error('mail', t('Please enter a valid email address'));
-  }
-
-  if (!empty($form_state['values']['phone']) && !preg_match('/\b\+?([0-9]+[\s-\+]?)+\b/', $form_state['values']['phone'])) {
-    form_set_error('phone', t('Please enter a valid phone number.'));
-  }
-
-  field_attach_form_validate('election_candidate', $form_state['candidate'], $form, $form_state);
-
-}
-
-/**
- * Validation function for just the nomination form.
- *
- * @param array $form
- * @param array $form_state
- */
-function election_candidate_nomination_form_validate($form, &$form_state) {
-  // @todo validate post again
-}
-
-/**
- * Validation function for just the edit form.
- *
- * @param array $form
- * @param array $form_state
- */
-function election_candidate_edit_form_validate($form, &$form_state) {
-  if (!empty($form_state['values']['new_user'])) {
-    if (!$account = user_load_by_name($form_state['values']['new_user'])) {
-      form_set_error('new_user', t('The username %name does not exist', array('%name' => $form_state['values']['new_user'])));
-    }
-  }
-}
-
-
-/**
- * Submit callback for the nomination form.
- *
- * @param array $form
- * @param array $form_state
- */
-function election_candidate_nomination_form_submit($form, &$form_state) {
-
-  $candidate = &$form_state['candidate'];
-
-  $values = $form_state['values'];
-
-  // election object won't be changed, no need to pass by reference
-  $election = $form_state['election'];
-  $post = election_post_load($values['post_id']);
-
-  $candidate->election_id = $election->election_id;
-
-  $candidate->post_id = $values['post_id'];
-
-  $candidate->first_name = $values['first_name'];
-  $candidate->last_name = $values['last_name'];
-  $candidate->mail = $values['mail'];
-  $candidate->phone = $values['phone'];
-  $candidate->cstatus = ELECTION_CANDIDATE_PENDING;
-
-  // @todo set up manifesto, summary, photo fields
-
-  field_attach_submit('election_candidate', $candidate, $form, $form_state);
-
-  global $user;
-  if (!empty($user->uid)) {
-    $candidate->uid = $user->uid;
-    $candidate->username = $user->name;
-  }
-
-  // Save the nomination.
-  election_candidate_save($candidate);
-
-  // Trigger a Rules action.
-  if (function_exists('rules_invoke_event')) {
-    rules_invoke_event('election_candidate_nomination_submitted', $candidate, $post, $election);
-  }
-
-  // Notify the user that the nomination was saved.
-  drupal_set_message(t(
-    'The nomination for the @posts_name %title (name %first_name %last_name) was successfully submitted.',
-    array(
-      '@posts_name' => _election_get_posts_name($election->type),
-      '%title' => $post->title,
-      '%first_name' => $candidate->first_name,
-      '%last_name' => $candidate->last_name,
-    )
-  ));
-
-  if (empty($_GET['destination'])) {
-    $form_state['redirect'] = election_uri_path($election);
-  }
-
-}
-
-/**
- * Generate an array for rendering the given candidate.
- *
- * @param $candidate
- * @param $election
- * @param $view_mode
- *   View mode, e.g. 'full', 'teaser'...
- *
- * @return
- *   An array as expected by drupal_render().
- */
-function election_candidate_view($candidate, $election, $view_mode = 'full') {
-
-  // Remove previously built content, if it exists.
-  $candidate->content = array();
-
-  $title = t('Candidate: @first-name @last-name', array('@first-name' => $candidate->first_name, '@last-name' => $candidate->last_name));
-
-  if ($view_mode == 'teaser') {
-    $candidate->content['title'] = array(
-      '#markup' => $title,
-      '#weight' => -5,
-    );
-  }
-
-  // Build fields content.
-  // In case of a multiple view, node_view_multiple() already ran the
-  // 'prepare_view' step. An internal flag prevents the operation from running
-  // twice.
-  field_attach_prepare_view('election_candidate', array($candidate->candidate_id => $candidate), $view_mode);
-  entity_prepare_view('election_candidate', array($candidate->candidate_id => $candidate));
-  $candidate->content += field_attach_view('election_candidate', $candidate, $view_mode);
-
-  $build = $candidate->content;
-  // We don't need duplicate rendering info in election->content.
-  unset($candidate->content);
-
-  $post = election_post_load($candidate->post_id);
-
-  $build += array(
-    '#theme' => 'election_candidate',
-    '#candidate' => $candidate,
-    '#election' => $election,
-    '#post' => $post,
-    '#view_mode' => $view_mode,
-  );
-
-  // Add contextual links for this election, except when the election is already being
-  // displayed on its own page. Modules may alter this behavior (for example,
-  // to restrict contextual links to certain view modes) by implementing
-  // hook_election_candidate_view_alter().
-  if (!empty($candidate->candidate_id) && $view_mode != 'full') {
-    $build['#contextual_links']['election_candidate'] = array('election_candidate', array($candidate->candidate_id));
-  }
-
-  // Allow modules to modify the structured election.
-  $type = 'election_candidate'; // $type is passed by reference to drupal_alter() so it must be a variable.
-  drupal_alter(array('election_candidate_view', 'entity_view'), $build, $type);
-
-  return $build;
-
-}
-
-/*
- * Form builder function for editing a single candidate.
- *
- * @param array $form
- * @param array $form_state
- * @param stdClass $election
- * @param stdClass $candidate
- *
- * @return array
- *   Render array.
- */
-function election_candidate_edit_form($form, $form_state, stdClass $election, stdClass $candidate) {
-
- // @todo this should not be necessary
-  drupal_set_title(t('Edit candidate: %first-name %last-name', array('%first-name' => $candidate->first_name, '%last-name' => $candidate->last_name)), PASS_THROUGH);
-  drupal_set_breadcrumb(
-    _election_build_breadcrumb($election, '_CANDIDATES_')
-  );
-
-  $form['#id'] = 'election-candidate-edit-form';
-  $form['#candidate'] = $candidate;
-
-  $form_state['election'] = $election;
-  $form_state['candidate'] = $candidate;
-
-  $candidate_account = NULL;
-  if (!empty($candidate->uid)) {
-    $candidate_account = user_load($candidate->uid);
-  }
-
-  $form['cstatus'] = array(
-    '#type' => 'select',
-    '#options' => array(
-      ELECTION_CANDIDATE_PENDING => t('Pending approval'),
-      ELECTION_CANDIDATE_APPROVED => t('Approved'),
-      ELECTION_CANDIDATE_WITHDRAWN => t('Withdrawn'),
-      ELECTION_CANDIDATE_REJECTED => t('Rejected'),
-    ),
-    '#title' => t('Candidate status'),
-    '#required' => TRUE,
-    '#default_value' => $candidate->cstatus,
-    '#empty_option' => t('- Select status -'),
-    '#description' => t(
-      'If the status is set to !approved, the candidate will be visible to all those who have permission to view the election.',
-      array('!approved' => t('Approved'))
-    ),
-    '#weight' => 0,
-  );
-
-  $form['user_info']['current_user'] = array(
-    '#title' => t('Associated user account'),
-    '#type' => 'item',
-    '#default_value' => empty($candidate_account)? NULL : $candidate_account->name,
-    '#weight' => 1,
-  );
-  if (empty($account)) {
-    $form['user_info']['current_user']['#markup'] = t('No user account associated.');
-  }
-  else {
-    $form['user_info']['current_user']['#markup'] = theme(
-      'username',
-      array('account' => $candidate_account, 'link_options' => array('target' => '_blank'))
-    );
-    $form['user_info']['current_user']['#description'] = t('The account that submitted the nomination.');
-  }
-
-  $post_ids = election_candidate_get_available_posts($election, NULL, FALSE);
-  $available_posts = election_post_load_multiple($post_ids);
-  $post_options = array();
-  foreach ($available_posts as $post) {
-    $post_options[$post->post_id] = truncate_utf8($post->title, 100, TRUE, TRUE, 80);
-  }
-  $post_name = _election_get_posts_name($election->type);
-  $form['post'] = array(
-    '#type' => 'select',
-    '#options' => $post_options,
-    '#title' => check_plain(drupal_ucfirst($post_name)),
-    '#empty_option' => t('- Select @post_name -', array('@post_name' => $post_name)),
-    '#required' => TRUE,
-    '#default_value' => $candidate->post_id,
-  );
-
-  $form['first_name'] = array(
-    '#type' => 'textfield',
-    '#title' => t('First name(s)'),
-    '#max_length' => 100,
-    '#default_value' => $candidate->first_name,
-    '#size' => 50,
-    '#required' => TRUE,
-  );
-
-  $form['last_name'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Last name(s)'),
-    '#max_length' => 100,
-    '#default_value' => $candidate->last_name,
-    '#size' => 50,
-    '#required' => TRUE,
-  );
-
-  $form['mail'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Email address'),
-    '#size' => 30,
-    '#required' => FALSE,
-    '#default_value' => $candidate->mail,
-  );
-
-  $form['phone'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Contact telephone number'),
-    '#size' => 12,
-    '#required' => FALSE,
-    '#default_value' => $candidate->phone,
-  );
-
-  field_attach_form('election_candidate', $candidate, $form, $form_state);
-
-  foreach ($form as $key => &$field) {
-    if (strpos($key, 'field_') === 0 && isset($field['#required'])) {
-      $field['#required'] = FALSE;
-    }
-  }
-
-  $form['buttons'] = array(
-    '#type' => 'actions',
-    '#weight' => 100,
-  );
-  $form['buttons']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Save'),
-    '#submit' => array('election_candidate_edit_form_submit'),
-  );
-  $form['buttons']['delete'] = array(
-    '#type' => 'submit',
-    '#value' => t('Delete'),
-    '#submit' => array('election_candidate_edit_form_delete_submit'),
-    '#access' => entity_access('delete', 'election_candidate', $candidate),
-    '#limit_validation_errors' => array(), // No need to validate on deletion
-  );
-
-  $form['#validate'][] = 'election_candidate_form_validate';
-  $form['#validate'][] = 'election_candidate_edit_form_validate';
-
-  return $form;
-
-}
-
-/**
- * Form submit function for the Save button in the form election_candidate_edit_form().
- *
- * @param array $form
- * @param array &$form_state
- * @return void
- */
-function election_candidate_edit_form_submit($form, &$form_state) {
-
-  $candidate = &$form_state['candidate'];
-
-  foreach ($candidate as $property => $value) {
-    if (isset($form_state['values'][$property])) {
-      $candidate->$property = $form_state['values'][$property];
-    }
-  }
-
-  $candidate->post_id = $form_state['values']['post'];
-
-  if (!empty($form_state['values']['new_user'])) {
-    if ($account = user_load_by_name($form_state['values']['new_user'])) {
-      $candidate->uid = $account->uid;
-      $candidate->username = $account->username;
-    }
-  }
-
-  field_attach_submit('election_candidate', $candidate, $form, $form_state);
-
-  election_candidate_save($candidate);
-
-  drupal_set_message(
-    t(
-      'The candidate %first_name %last_name was saved.',
-      array(
-        '%first_name' => $candidate->first_name,
-        '%last_name' => $candidate->last_name,
-      )
-    )
-  );
-
-}
-
-/**
- * Form submit function for the Delete button in the form election_candidate_edit_form.
- *
- * @param array $form
- * @param array &$form_state
- * @return void
- */
-function election_candidate_edit_form_delete_submit($form, &$form_state) {
-  $destination = array();
-  if (isset($_GET['destination'])) {
-    $destination = drupal_get_destination();
-    unset($_GET['destination']);
-  }
-  $candidate = $form['#candidate'];
-  $form_state['redirect'] = array(
-    election_candidate_uri_path($candidate) . '/delete',
-    array('query' => $destination),
-  );
-}
-
-/**
- * Form builder function to confirm the delete action for a candidate.
- * See http://api.drupal.org/api/drupal/modules--system--system.module/function/confirm_form.
- *
- * @param array $form
- * @param array &$form_state
- * @param stdClass $election
- *
- * @return array
- *   Render array.
- */
-function election_candidate_edit_form_delete_confirm($form, &$form_state, $election, $candidate) {
-
-  drupal_set_breadcrumb(
-    _election_build_breadcrumb($election, '_CANDIDATES_')
-  );
-
-  $form['candidate_id'] = array(
-    '#type' => 'value',
-    '#value' => $candidate->candidate_id,
-  );
-
-  return confirm_form(
-    $form,
-    t('Are you sure you want to delete the candidate %title?', array('%title' => $candidate->first_name . ' ' . $candidate->last_name)),
-    election_candidate_uri_path($candidate),
-    t('Deleting a candidate also deletes ALL associated data, for example votes. This action cannot be undone.'),
-    t('Delete'),
-    t('Cancel')
-  );
-}
-
-/**
- * Form submit function for the Delete button in the form election_candidate_edit_form_delete_confirm.
- *
- * @param array $form
- * @param array &$form_state
- * @return void
- */
-function election_candidate_edit_form_delete_confirm_submit($form, &$form_state) {
-  if ($form_state['values']['confirm']) {
-
-    $candidate = election_candidate_load($form_state['values']['candidate_id']);
-    $election = election_load($candidate->election_id);
-
-    $info = array(
-      '%first_name' => $candidate->first_name,
-      '%last_name' => $candidate->last_name,
-      '%election_title' => !empty($election)? $election->title : t('unknown'),
-    );
-
-    // Delete the candidate
-    $delete = election_candidate_delete($form_state['values']['candidate_id']);
-    if ($delete) {
-      watchdog('election', 'Deleted candidate "%first_name %last_name".', $info);
-    }
-
-    if ($delete) {
-      drupal_set_message(
-        t('The candidate %first_name %last_name has been deleted from the election %election_title.', $info)
-      );
-    }
-    else {
-      drupal_set_message(
-        t('Failed to delete the candidate %first_name %last_name from the election %election_title.', $info)
-      );
-    }
-
-  }
-
-  if (empty($_GET['destination']) && $election) {
-    $form_state['redirect'] = election_uri_path($election) . '/candidates';
-  }
-
-}
diff --git a/election-candidate.tpl.php b/election-candidate.tpl.php
deleted file mode 100644
index 8e984a56001fd53d0a7f6c463b422ba728bc4a71..0000000000000000000000000000000000000000
--- a/election-candidate.tpl.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-
-/**
- * @file
- * Default theme implementation to display an election candidate.
- */
-
-?>
-<div id="election-<?php print $election->election_id; ?>-candidate-<?php print $candidate->candidate_id; ?>" class="<?php print $classes; ?> clearfix"<?php print $attributes; ?>>
-
-  <?php if (!$page): ?>
-    <h2<?php print $title_attributes; ?>><a href="<?php print $url; ?>"><?php print $full_name; ?></a></h2>
-  <?php endif; ?>
-
-  <div class="pseudo-field candidate-election">
-    <span class="label">Election: </span><span class="item"><?php print $election_link; ?></span>
-  </div>
-
-  <div class="pseudo-field candidate-post">
-    <span class="label">Standing for: </span><span class="item"><?php print $post_link; ?></span>
-  </div>
-
-  <div class="content"<?php print $content_attributes; ?>>
-    <?php print render($content); ?>
-  </div>
-
-</div>
diff --git a/election.info b/election.info
index ef49b5f00cd46e19165a3e77de8fa69a0817071a..b53f55d65df124d26e7c4558b5b29503b32f4f86 100644
--- a/election.info
+++ b/election.info
@@ -5,11 +5,9 @@ core = 7.x
 php = 5.3
 dependencies[] = entity
 dependencies[] = views
-dependencies[] = election_candidate
 files[] = includes/election-default.controller.inc
 files[] = includes/election.controller.inc
 files[] = includes/election-post.controller.inc
-files[] = includes/election-candidate.controller.inc
 files[] = views/handlers/views_handler_field_election.inc
 files[] = views/handlers/views_handler_field_election_link.inc
 files[] = views/handlers/views_handler_field_election_link_delete.inc
diff --git a/election.module b/election.module
index b11cdfb5d01e84e905ef8d8b5baa14f4e0605063..5c4f7dd7f26dd6570dbabbc68910a4d8311b5e03 100644
--- a/election.module
+++ b/election.module
@@ -1013,241 +1013,6 @@ function election_page_title($election) {
   return $election->title;
 }
 
-/**
- * Implements hook_token_info().
- * See http://api.drupal.org/api/drupal/modules--system--system.api.php/function/hook_token_info/7.
- */
-function election_token_info() {
-  $info = array();
-  $info['types'] = array(
-    'election' => array(
-      'name' => t('Elections'),
-      'description' => t('Tokens related to elections.'),
-      'needs-data' => 'election',
-    ),
-    'election_candidate' => array(
-      'name' => t('Candidates'),
-      'description' => t('Tokens related to election candidates.'),
-      'needs-data' => 'election_candidate',
-    ),
-  );
-  $info['tokens'] = array(
-    'election' => array(
-      'id' => array(
-        'name' => t('Election ID'),
-        'description' => t('The unique ID of the election.'),
-      ),
-      'type' => array(
-        'name' => t('Election type'),
-        'description' => t('The machine-readable name of the election type.'),
-      ),
-      'type_name' => array(
-        'name' => t('Election type name'),
-        'description' => t('The human-readable name of the election type.'),
-      ),
-      'title' => array(
-        'name' => t('Title'),
-        'description' => t('The title of the election.'),
-      ),
-      'created' => array(
-        'name' => t('Date created'),
-        'description' => t('The date the election was created.'),
-        'type' => 'date',
-      ),
-    ),
-    'election_candidate' => array(
-      'id' => array(
-        'name' => t('Election candidate ID'),
-        'description' => t('The unique ID of the candidate.'),
-      ),
-      'mail' => array(
-        'name' => t('Email address'),
-        'description' => t('The email address of the candidate.'),
-      ),
-    ),
-  );
-  return $info;
-}
-
-/**
- * Implements hook_tokens().
- */
-function election_tokens($type, array $tokens, array $data = array(), array $options = array()) {
-  $sanitize = !empty($options['sanitize']);
-  $replacements = array();
-  if ($type == 'election' && !empty($data['election'])) {
-    $election = $data['election'];
-    foreach ($tokens as $name => $original) {
-      switch ($name) {
-        case 'id':
-          $replacements[$original] = $election->election_id;
-          break;
-        case 'type':
-          $replacements[$original] = $sanitize ? check_plain($election->type) : $election->type;
-          break;
-        case 'type_name':
-          $type = _election_type_get_info($election->type);
-          $type_name = $type['name'];
-          $replacements[$original] = $sanitize ? check_plain($type_name) : $type_name;
-          break;
-        case 'title':
-          $replacements[$original] = $sanitize ? check_plain($election->title) : $election->title;
-          break;
-        case 'created':
-          $replacements[$original] = format_date($election->created, 'medium');
-          break;
-      }
-    }
-  }
-  else if ($type == 'election_candidate' && !empty($data['election_candidate'])) {
-    $candidate = $data['election_candidate'];
-    foreach ($tokens as $name => $original) {
-      switch ($name) {
-        case 'id':
-          $replacements[$original] = $candidate->candidate_id;
-          break;
-        case 'mail':
-          $replacements[$original] = $sanitize ? check_plain($candidate->mail) : $candidate->mail;
-          break;
-      }
-    }
-  }
-  return $replacements;
-}
-
-/**
- * Implements hook_pathauto(). See the Pathauto module.
- *
- * @param string $op
- * @return stdClass
- */
-function election_pathauto($op) {
-  switch ($op) {
-    case 'settings':
-      $settings = array();
-      $settings['module'] = 'election';
-      $settings['token_type'] = 'election';
-      $settings['groupheader'] = t('Election paths');
-      $settings['patterndescr'] = t('Default path pattern (applies to all election types with blank patterns below)');
-      $settings['patterndefault'] = 'election/[election:title]';
-      $settings['batch_update_callback'] = 'election_pathauto_bulk_update_batch_process';
-      $settings['batch_file'] = drupal_get_path('module', 'election') . '/election.module';
-      foreach (election_types() as $type_mn => $type) {
-        $settings['patternitems'][$type_mn] = t('Pattern for all %type paths', array('%type' => $type['name']));
-      }
-      return (object) $settings;
-    default:
-      break;
-  }
-}
-
-/**
- * Allow bulk updating of paths. See the Pathauto module.
- *
- * @see election_pathauto()
- * @param array &$context
- * @return void
- */
-function election_pathauto_bulk_update_batch_process(&$context) {
-  if (!isset($context['sandbox']['current'])) {
-    $context['sandbox']['count'] = 0;
-    $context['sandbox']['current'] = 0;
-  }
-  $query = db_select('election', 'e');
-  $query->leftJoin('url_alias', 'ua', "CONCAT('election/', e.election_id) = ua.source");
-  $query->addField('e', 'election_id');
-  $query->isNull('ua.source');
-  $query->condition('e.election_id', $context['sandbox']['current'], '>');
-  $query->orderBy('e.election_id');
-  $query->addTag('pathauto_bulk_update');
-  $query->addMetaData('entity', 'election');
-  // Get the total amount of items to process.
-  if (!isset($context['sandbox']['total'])) {
-    $context['sandbox']['total'] = $query->countQuery()->execute()->fetchField();
-    // If there are no elections to update, then stop immediately.
-    if (!$context['sandbox']['total']) {
-      $context['finished'] = 1;
-      return;
-    }
-  }
-  $query->range(0, 25);
-  $ids = $query->execute()->fetchCol();
-  pathauto_election_update_alias_multiple($ids, 'bulkupdate');
-  $context['sandbox']['count'] += count($ids);
-  $context['sandbox']['current'] = max($ids);
-  $context['message'] = t('Updated alias for election @id.', array('@id' => end($ids)));
-  if ($context['sandbox']['count'] != $context['sandbox']['total']) {
-    $context['finished'] = $context['sandbox']['count'] / $context['sandbox']['total'];
-  }
-}
-
-/**
- * Update the URL aliases for an individual election.
- *
- * @param $election
- *   A election object.
- * @param $op
- *   Operation being performed on the election ('insert', 'update' or 'bulkupdate').
- * @param $options
- *   An optional array of additional options.
- */
-function pathauto_election_update_alias(stdClass $election, $op, array $options = array()) {
-  // Skip processing if the user has disabled pathauto for the election.
-  if (isset($election->path['pathauto']) && empty($election->path['pathauto'])) {
-    return;
-  }
-  $options += array(
-    'language' => isset($election->language) ? $election->language : LANGUAGE_NONE,
-  );
-  // Skip processing if the election has no pattern.
-  if (!pathauto_pattern_load_by_entity('election', $election->type, $options['language'])) {
-    return;
-  }
-  module_load_include('inc', 'pathauto');
-  pathauto_create_alias(
-    'election',
-    $op,
-    election_uri_path($election),
-    array('election' => $election),
-    $election->type,
-    $options['language']
-  );
-}
-
-/**
- * Update the URL aliases for multiple elections.
- *
- * @param $election_ids
- *   An array of election IDs.
- * @param $op
- *   Operation being performed on the elections ('insert', 'update' or
- *   'bulkupdate').
- * @param $options
- *   An optional array of additional options.
- */
-function pathauto_election_update_alias_multiple(array $election_ids, $op, array $options = array()) {
-  $options += array('message' => FALSE);
-  $elections = election_load_multiple($election_ids);
-  foreach ($elections as $election) {
-    pathauto_election_update_alias($election, $op, $options);
-  }
-  if (!empty($options['message'])) {
-    drupal_set_message(format_plural(count($election_ids), 'Updated URL alias for 1 election.', 'Updated URL aliases for @count elections.'));
-  }
-}
-
-/**
- * Implements hook_path_alias_types(). See Pathauto module.
- *
- * Used primarily by the bulk delete form.
- */
-function election_path_alias_types() {
-  $objects = array(
-    'election/' => t('Elections')
-  );
-  return $objects;
-}
-
 /**
  * Implements hook_theme().
  */
@@ -1261,14 +1026,6 @@ function election_theme() {
       'render element' => 'elements',
       'template' => 'election-post',
     ),
-    'election_candidate' => array(
-      'render element' => 'elements',
-      'template' => 'election-candidate',
-    ),
-    'election_candidate_details' => array(
-      'render element' => 'elements',
-      'template' => 'election-candidate-details',
-    ),
   );
 }
 
@@ -1488,188 +1245,6 @@ function template_preprocess_election_post(&$variables) {
 
 }
 
-/**
- * Process variables for election-candidate.tpl.php
- *
- * The $variables array contains the following arguments:
- * - $candidate
- * - $election
- * - $view_mode
- * - $page
- *
- * @see election-candidate.tpl.php
- */
-function template_preprocess_election_candidate(&$variables) {
-  $variables['view_mode'] = $variables['elements']['#view_mode'];
-
-  // $teaser boolean
-  $variables['teaser'] = $variables['view_mode'] == 'teaser';
-  // $details boolean
-  $variables['details'] = $variables['view_mode'] == 'details';
-  // $page boolean
-  $variables['page'] = ($variables['view_mode'] == 'full' || $variables['view_mode'] == 'details');
-
-  $variables['election'] = $variables['elements']['#election'];
-  $variables['candidate'] = $variables['elements']['#candidate'];
-  $variables['post'] = $variables['elements']['#post'];
-
-  $election = $variables['election'];
-  $candidate = $variables['candidate'];
-  $post = $variables['post'];
-  $election_type = _election_type_get_info($election->type);
-
-  if (empty($post)) {
-    // Handle gracefully when the candidate's post is deleted prematurely.
-    $post = entity_get_controller('election_post')->create(array(
-      'type' => $election_type['post key'],
-    ));
-  }
-
-  $uri = entity_uri('election_candidate', $candidate, $election);
-  $variables['url'] = url($uri['path'], $uri['options']);
-
-  $election_uri = entity_uri('election', $election);
-  $variables['election_url'] = url($election_uri['path'], $election_uri['options']);
-  $variables['election_title'] = check_plain($election->title);
-  $variables['election_link'] = l($election->title, $election_uri['path'], $election_uri['options']);
-  $variables['election_type'] = check_plain($election_type['name']);
-
-  $post_uri = entity_uri('election_post', $post);
-  $variables['post_url'] = url($post_uri['path'], $post_uri['options']);
-  $variables['post_title'] = check_plain($post->title);
-  $variables['post_link'] = l($post->title, $post_uri['path'], $post_uri['options']);
-  $variables['post_name'] = check_plain($election_type['post name']);
-
-  $variables['full_name'] = t('@first_name @last_name', array('@first_name' => $candidate->first_name, '@last_name' => $candidate->last_name));
-
-  $variables += array('content' => array());
-  foreach (element_children($variables['elements']) as $key) {
-    $variables['content'][$key] = $variables['elements'][$key];
-  }
-
-  // Make the field variables available with the appropriate language.
-  field_attach_preprocess('election_candidate', $candidate, $variables['content'], $variables);
-
-  $variables['classes_array'][] = drupal_html_class('election-' . $election->type . '-candidate');
-
-  $variables['theme_hook_suggestions'][] = 'election_candidate__' . $candidate->candidate_id;
-  $variables['theme_hook_suggestions'][] = 'election__' . $election->type . '__candidate';
-  $variables['theme_hook_suggestions'][] = 'election__' . $election->election_id . '__candidate';
-
-}
-
-/**
- * Process variables for election-candidate-details.tpl.php
- *
- * The $variables array contains the following arguments:
- * - $candidate
- * - $election
- * - $page
- *
- * @see election-candidate.tpl.php
- */
-function template_preprocess_election_candidate_details(&$variables) {
-
-  $variables['election'] = $variables['elements']['#election'];
-  $variables['candidate'] = $variables['elements']['#candidate'];
-  $variables['post'] = $variables['elements']['#post'];
-
-  $election = $variables['election'];
-  $candidate = $variables['candidate'];
-  $post = $variables['post'];
-  $election_type = _election_type_get_info($election->type);
-
-  if (empty($post)) {
-    // Handle gracefully when the candidate's post is deleted prematurely.
-    $post = entity_get_controller('election_post')->create(array(
-      'type' => $election_type['post key'],
-    ));
-  }
-
-  $uri = entity_uri('election_candidate', $candidate, $election);
-  $variables['url'] = url($uri['path'], $uri['options']);
-
-  $election_uri = entity_uri('election', $election);
-  $variables['election_url'] = url($election_uri['path'], $election_uri['options']);
-  $variables['election_link'] = l($election->title, $election_uri['path'], $election_uri['options']);
-
-  $post_uri = entity_uri('election_post', $post);
-  $variables['post_url'] = url($post_uri['path'], $post_uri['options']);
-  $variables['post_link'] = l($post->title, $post_uri['path'], $post_uri['options']);
-
-  $variables['full_name'] = t('@first_name @last_name', array('@first_name' => $candidate->first_name, '@last_name' => $candidate->last_name));
-
-  $variables['content']['election'] = array(
-    '#theme' => 'container',
-    '#attributes' => array(
-      'class' => array('pseudo-field', 'candidate-election'),
-    ),
-    '#markup' => '<span class="label">' . t('Election:') . '</span>'
-               . ' <span class="item">' . $variables['election_link'] . '</span>',
-  );
-
-  $variables['content']['post'] = array(
-    '#theme' => 'container',
-    '#attributes' => array(
-      'class' => array('pseudo-field', 'candidate-post'),
-    ),
-    '#markup' => '<span class="label">' . drupal_ucfirst($election_type['post name'] . ':') . '</span>'
-               . ' <span class="item">' . $variables['post_link'] . '</span>',
-  );
-
-  $variables['content']['full-name'] = array(
-    '#theme' => 'container',
-    '#attributes' => array(
-      'class' => array('pseudo-field', 'candidate-full-name'),
-    ),
-    '#markup' => '<span class="label">' . t('Name:') . '</span>'
-               . ' <span class="item">' . $variables['full_name'] . '</span>',
-  );
-
-  $variables['username'] = theme('username', array('#account' => $candidate->uid? user_load($candidate->uid) : NULL));
-  $variables['phone'] = check_plain($candidate->phone);
-  $variables['mail'] = l($candidate->mail, 'mailto:' . $candidate->mail, array('absolute' => TRUE));
-
-  $variables['content']['mail'] = array(
-    '#theme' => 'container',
-    '#attributes' => array(
-      'class' => array('pseudo-field', 'candidate-email-address')
-    ),
-    '#markup' => '<span class="label">' . t('Email address:') . '</span>'
-               . ' <span class="item">' . $variables['mail'] . '</span>',
-  );
-
-  $variables['content']['phone'] = array(
-    '#theme' => 'container',
-    '#attributes' => array(
-      'class' => array('pseudo-field', 'candidate-phone'),
-    ),
-    '#markup' => '<span class="label">' . t('Phone number:') . '</span>'
-               . ' <span class="item">' . $variables['phone'] . '</span>',
-  );
-
-  $variables['content']['candidate-username'] = array(
-    '#theme' => 'container',
-    '#attributes' => array(
-      'class' => array('pseudo-field', 'candidate-username'),
-    ),
-    '#markup' => '<span class="label">' . t('Username:') . '</span>'
-               . ' <span class="item">' . $variables['username'] . '</span>',
-  );
-
-  $variables += array('content' => array());
-  foreach (element_children($variables['elements']) as $key) {
-    $variables['content'][$key] = $variables['elements'][$key];
-  }
-
-  $variables['classes_array'][] = drupal_html_class('election-' . $election->type . '-candidate', 'election-candidate-details');
-
-  $variables['theme_hook_suggestions'][] = 'election_candidate_details__' . $candidate->candidate_id;
-  $variables['theme_hook_suggestions'][] = 'election__' . $election->type . '__candidate_details';
-  $variables['theme_hook_suggestions'][] = 'election__' . $election->election_id . '__candidate_details';
-
-}
-
 /**
  * Internal function that determines whether voting/nominating in an election is 'open',
  * based on the status, opening time and closing time.
@@ -1763,33 +1338,6 @@ function _election_post_format_status(stdClass $election, stdClass $post, $statu
   return t('!status_formatted (overridden)', array('!status_formatted' => $status_formatted));
 }
 
-/**
- * Internal function to format the status field of an election candidate for display.
- *
- * @todo make this themeable
- *
- * @param stdClass $candidate
- *
- * @return string
- */
-function _election_candidate_format_status(stdClass $candidate) {
-  switch ($candidate->cstatus) {
-    case ELECTION_CANDIDATE_APPROVED:
-      return t('Approved');
-      break;
-    case ELECTION_CANDIDATE_REJECTED:
-      return t('Nomination rejected');
-      break;
-    case ELECTION_CANDIDATE_WITHDRAWN:
-      return t('Withdrawn');
-      break;
-    case ELECTION_CANDIDATE_PENDING:
-    default:
-      return t('Pending approval');
-      break;
-  }
-}
-
 /**
  * General function for creating breadcrumbs. Accepts any number of parameters,
  * each corresponding to the breadcrumb link. Output must be sanitized before
@@ -1933,3 +1481,58 @@ function election_menu_position_rule_plugins() {
     ),
   );
 }
+
+/**
+ * Update the URL aliases for an individual election.
+ *
+ * @param $election
+ *   A election object.
+ * @param $op
+ *   Operation being performed on the election ('insert', 'update' or 'bulkupdate').
+ * @param $options
+ *   An optional array of additional options.
+ */
+function pathauto_election_update_alias(stdClass $election, $op, array $options = array()) {
+  // Skip processing if the user has disabled pathauto for the election.
+  if (isset($election->path['pathauto']) && empty($election->path['pathauto'])) {
+    return;
+  }
+  $options += array(
+    'language' => isset($election->language) ? $election->language : LANGUAGE_NONE,
+  );
+  // Skip processing if the election has no pattern.
+  if (!pathauto_pattern_load_by_entity('election', $election->type, $options['language'])) {
+    return;
+  }
+  module_load_include('inc', 'pathauto');
+  pathauto_create_alias(
+    'election',
+    $op,
+    election_uri_path($election),
+    array('election' => $election),
+    $election->type,
+    $options['language']
+  );
+}
+
+/**
+ * Update the URL aliases for multiple elections.
+ *
+ * @param $election_ids
+ *   An array of election IDs.
+ * @param $op
+ *   Operation being performed on the elections ('insert', 'update' or
+ *   'bulkupdate').
+ * @param $options
+ *   An optional array of additional options.
+ */
+function pathauto_election_update_alias_multiple(array $election_ids, $op, array $options = array()) {
+  $options += array('message' => FALSE);
+  $elections = election_load_multiple($election_ids);
+  foreach ($elections as $election) {
+    pathauto_election_update_alias($election, $op, $options);
+  }
+  if (!empty($options['message'])) {
+    drupal_set_message(format_plural(count($election_ids), 'Updated URL alias for 1 election.', 'Updated URL aliases for @count elections.'));
+  }
+}
\ No newline at end of file
diff --git a/election.pathauto.inc b/election.pathauto.inc
new file mode 100644
index 0000000000000000000000000000000000000000..74e3d3e9f0a690338e86fcaaa3c787c0d269843a
--- /dev/null
+++ b/election.pathauto.inc
@@ -0,0 +1,83 @@
+<?php
+/**
+ * @file
+ * Pathauto hooks for the Election module.
+ */
+
+/**
+ * Implements hook_pathauto(). See the Pathauto module.
+ *
+ * @param string $op
+ * @return stdClass
+ */
+function election_pathauto($op) {
+  switch ($op) {
+    case 'settings':
+      $settings = array();
+      $settings['module'] = 'election';
+      $settings['token_type'] = 'election';
+      $settings['groupheader'] = t('Election paths');
+      $settings['patterndescr'] = t('Default path pattern (applies to all election types with blank patterns below)');
+      $settings['patterndefault'] = 'election/[election:title]';
+      $settings['batch_update_callback'] = 'election_pathauto_bulk_update_batch_process';
+      $settings['batch_file'] = drupal_get_path('module', 'election') . '/election.module';
+      foreach (election_types() as $type_mn => $type) {
+        $settings['patternitems'][$type_mn] = t('Pattern for all %type paths', array('%type' => $type['name']));
+      }
+      return (object) $settings;
+    default:
+      break;
+  }
+}
+
+/**
+ * Allow bulk updating of paths. See the Pathauto module.
+ *
+ * @see election_pathauto()
+ * @param array &$context
+ * @return void
+ */
+function election_pathauto_bulk_update_batch_process(&$context) {
+  if (!isset($context['sandbox']['current'])) {
+    $context['sandbox']['count'] = 0;
+    $context['sandbox']['current'] = 0;
+  }
+  $query = db_select('election', 'e');
+  $query->leftJoin('url_alias', 'ua', "CONCAT('election/', e.election_id) = ua.source");
+  $query->addField('e', 'election_id');
+  $query->isNull('ua.source');
+  $query->condition('e.election_id', $context['sandbox']['current'], '>');
+  $query->orderBy('e.election_id');
+  $query->addTag('pathauto_bulk_update');
+  $query->addMetaData('entity', 'election');
+  // Get the total amount of items to process.
+  if (!isset($context['sandbox']['total'])) {
+    $context['sandbox']['total'] = $query->countQuery()->execute()->fetchField();
+    // If there are no elections to update, then stop immediately.
+    if (!$context['sandbox']['total']) {
+      $context['finished'] = 1;
+      return;
+    }
+  }
+  $query->range(0, 25);
+  $ids = $query->execute()->fetchCol();
+  pathauto_election_update_alias_multiple($ids, 'bulkupdate');
+  $context['sandbox']['count'] += count($ids);
+  $context['sandbox']['current'] = max($ids);
+  $context['message'] = t('Updated alias for election @id.', array('@id' => end($ids)));
+  if ($context['sandbox']['count'] != $context['sandbox']['total']) {
+    $context['finished'] = $context['sandbox']['count'] / $context['sandbox']['total'];
+  }
+}
+
+/**
+ * Implements hook_path_alias_types(). See Pathauto module.
+ *
+ * Used primarily by the bulk delete form.
+ */
+function election_path_alias_types() {
+  $objects = array(
+    'election/' => t('Elections')
+  );
+  return $objects;
+}
\ No newline at end of file
diff --git a/election.tokens.inc b/election.tokens.inc
new file mode 100644
index 0000000000000000000000000000000000000000..6fad0985a1ae3bacc84b12633f282f135b6e6143
--- /dev/null
+++ b/election.tokens.inc
@@ -0,0 +1,79 @@
+<?php
+/**
+ * @file
+ * Token integration for the Election module.
+ */
+
+/**
+ * Implements hook_token_info().
+ * See http://api.drupal.org/api/drupal/modules--system--system.api.php/function/hook_token_info/7.
+ */
+function election_token_info() {
+  $info = array();
+  $info['types'] = array(
+    'election' => array(
+      'name' => t('Elections'),
+      'description' => t('Tokens related to elections.'),
+      'needs-data' => 'election',
+    ),
+  );
+  $info['tokens'] = array(
+    'election' => array(
+      'id' => array(
+        'name' => t('Election ID'),
+        'description' => t('The unique ID of the election.'),
+      ),
+      'type' => array(
+        'name' => t('Election type'),
+        'description' => t('The machine-readable name of the election type.'),
+      ),
+      'type_name' => array(
+        'name' => t('Election type name'),
+        'description' => t('The human-readable name of the election type.'),
+      ),
+      'title' => array(
+        'name' => t('Title'),
+        'description' => t('The title of the election.'),
+      ),
+      'created' => array(
+        'name' => t('Date created'),
+        'description' => t('The date the election was created.'),
+        'type' => 'date',
+      ),
+    ),
+  );
+  return $info;
+}
+
+/**
+ * Implements hook_tokens().
+ */
+function election_tokens($type, array $tokens, array $data = array(), array $options = array()) {
+  $sanitize = !empty($options['sanitize']);
+  $replacements = array();
+  if ($type == 'election' && !empty($data['election'])) {
+    $election = $data['election'];
+    foreach ($tokens as $name => $original) {
+      switch ($name) {
+        case 'id':
+          $replacements[$original] = $election->election_id;
+          break;
+        case 'type':
+          $replacements[$original] = $sanitize ? check_plain($election->type) : $election->type;
+          break;
+        case 'type_name':
+          $type = _election_type_get_info($election->type);
+          $type_name = $type['name'];
+          $replacements[$original] = $sanitize ? check_plain($type_name) : $type_name;
+          break;
+        case 'title':
+          $replacements[$original] = $sanitize ? check_plain($election->title) : $election->title;
+          break;
+        case 'created':
+          $replacements[$original] = format_date($election->created, 'medium');
+          break;
+      }
+    }
+  }
+  return $replacements;
+}
diff --git a/includes/election-candidate.controller.inc b/includes/election-candidate.controller.inc
deleted file mode 100644
index 42fad0f2a4ca43b9ccd80a5e9d7e7b6e18b92ba5..0000000000000000000000000000000000000000
--- a/includes/election-candidate.controller.inc
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-/**
- * @file
- * Entity controller for candidates (in the Election module).
- *
- * @class
- * ElectionCandidateController
- * @extends
- * ElectionDefaultController
- */
-class ElectionCandidateController extends ElectionDefaultController {
-
-  /**
-   * Overrides EntityAPIController::create(), allowing defaults to be defined.
-   */
-  public function create(array $values = array()) {
-    $default_values = array(
-      'candidate_id' => '',
-      'election_id' => '',
-      'post_id' => '',
-      'cstatus' => ELECTION_CANDIDATE_PENDING,
-      'uid' => '',
-      'username' => '',
-      'first_name' => '',
-      'last_name' => '',
-      'phone' => '',
-      'mail' => '',
-      'summary' => '',
-      'manifesto' => '',
-      'photo' => '',
-      'proposer' => new stdClass(),
-      'seconders' => array(),
-      'created' => 0,
-      'changed' => 0,
-    );
-    // Overwrite default values with supplied values.
-    $values = array_merge($default_values, $values);
-    return parent::create($values);
-  }
-
-}
diff --git a/includes/election.controller-old.inc b/includes/election.controller-old.inc
deleted file mode 100644
index c2c6037e826740daa1f80e5783372e937ff99805..0000000000000000000000000000000000000000
--- a/includes/election.controller-old.inc
+++ /dev/null
@@ -1,124 +0,0 @@
-<?php
-/**
- * @file
- * Entity controller for the Election module.
- *
- * @class
- * ElectionController
- * @extends
- * DrupalDefaultEntityController
- */
-class ElectionController extends DrupalDefaultEntityController {
-
-  public function create($type = 0) {
-
-    return (object) array(
-      'election_id' => '',
-      'type' => $type,
-      'title' => '',
-      'vstatus' => ELECTION_STATUS_CLOSED,
-      'vopen_time' => NULL,
-      'vclose_time' => NULL,
-      'nstatus' => ELECTION_STATUS_CLOSED,
-      'nopen_time' => NULL,
-      'nclose_time' => NULL,
-    );
-
-  }
-
-  public function save($election) {
-
-    $transaction = db_transaction();
-
-    try {
-
-      global $user;
-
-      // Determine whether the election is new.
-      $election->is_new = empty($election->election_id);
-
-      // Set timestamp fields.
-      if (empty($election->created)) {
-        $election->created = REQUEST_TIME;
-      }
-
-      $election->changed = REQUEST_TIME;
-      $update_election = TRUE;
-
-      field_attach_presave('election', $election);
-
-      if ($election->is_new) {
-        drupal_write_record('election', $election);
-        $op = 'insert';
-      }
-      else {
-        drupal_write_record('election', $election, 'election_id');
-        $op = 'update';
-      }
-
-      $function = 'field_attach_' . $op;
-      $function('election', $election);
-
-      module_invoke_all('entity_' . $op, $election, 'election');
-
-      if (function_exists('pathauto_election_update_alias')) {
-        pathauto_election_update_alias($election, $op);
-      }
-
-      unset($election->is_new);
-
-      // Skip the slave server for this user temporarily.
-      db_ignore_slave();
-
-      return $election;
-
-    }
-    catch (Exception $e) {
-
-      $transaction->rollback();
-      watchdog_exception('election', $e, NULL, WATCHDOG_ERROR);
-      return FALSE;
-
-    }
-
-  }
-
-  public function delete($ids) {
-
-    if (!empty($ids)) {
-      $elections = $this->load($ids, array());
-      $transaction = db_transaction();
-
-      try {
-        db_delete('election')
-          ->condition('election_id', $ids, 'IN')
-          ->execute();
-        foreach ($elections as $election_id => $election) {
-
-          field_attach_delete('election', $election);
-
-          module_invoke_all('entity_delete', $election, 'election');
-
-          if (function_exists('pathauto_entity_path_delete_all')) {
-            pathauto_entity_path_delete_all('election', $election);
-          }
-
-        }
-        db_ignore_slave();
-      }
-      catch (Exception $e) {
-        $transaction->rollback();
-        watchdog_exception('election', $e, NULL, WATCHDOG_ERROR);
-        return FALSE;
-      }
-
-      cache_clear_all();
-      $this->resetCache();
-
-    }
-
-    return TRUE;
-
-  }
-
-}
\ No newline at end of file
diff --git a/submodules/election_candidate/election_candidate.constants.inc b/submodules/election_candidate/election_candidate.constants.inc
deleted file mode 100644
index a7d610df424db8c35c81346969be027835a1b997..0000000000000000000000000000000000000000
--- a/submodules/election_candidate/election_candidate.constants.inc
+++ /dev/null
@@ -1,14 +0,0 @@
-<?php
-/**
- * @file
- * Constants for the Election Candidate module.
- */
-
-// Constants for the {election_candidate} table.
-define('ELECTION_CANDIDATE_APPROVED', 1);
-define('ELECTION_CANDIDATE_PENDING', 0);
-define('ELECTION_CANDIDATE_WITHDRAWN', -1);
-define('ELECTION_CANDIDATE_REJECTED', -2);
-
-// Cardinality of the nomination form's "seconder" field (instance of "endorser").
-define('ELECTION_CANDIDATE_MAX_SECONDERS', 10);
diff --git a/submodules/election_candidate/election_candidate.info b/submodules/election_candidate/election_candidate.info
deleted file mode 100644
index 60ca28554ab55ab278a973044c63ec35e6344d31..0000000000000000000000000000000000000000
--- a/submodules/election_candidate/election_candidate.info
+++ /dev/null
@@ -1,6 +0,0 @@
-name = Election Candidate
-description = "Allows elections to have candidates."
-package = Election
-core = 7.x
-php = 5.3
-dependencies[] = election
diff --git a/submodules/election_candidate/election_candidate.install b/submodules/election_candidate/election_candidate.install
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/submodules/election_candidate/election_candidate.module b/submodules/election_candidate/election_candidate.module
deleted file mode 100644
index ab803581736982da8fe25e837729652eedfb3d57..0000000000000000000000000000000000000000
--- a/submodules/election_candidate/election_candidate.module
+++ /dev/null
@@ -1,513 +0,0 @@
-<?php
-/**
- * @file
- * Election Candidate: primary module file.
- */
-
-// Required files.
-require_once 'election_candidate.constants.inc';
-
-
-/**
- * Implements hook_entity_info().
- */
-function election_candidate_entity_info() {
-
-  $entities = array();
-
-  $entities['election_candidate'] = array(
-    'label' => t('Election candidate'),
-    'access callback' => 'election_candidate_access',
-    'uri callback' => 'election_candidate_uri',
-    'controller class' => 'ElectionCandidateController',
-    'base table' => 'election_candidate',
-    'label callback' => 'election_candidate_label',
-    'entity keys' => array(
-      'id' => 'candidate_id',
-    ),
-    'static cache' => TRUE,
-    'fieldable' => TRUE,
-    'module' => 'election',
-    'bundles' => array(
-      // Single bundles are named after the entity type (see entity_extract_ids()).
-      'election_candidate' => array(
-        'label' => t('Election candidate'),
-        'admin' => array(
-          'path' => 'admin/election/candidate',
-          'access arguments' => array('administer elections'),
-        ),
-      ),
-    ),
-    'view modes' => array(
-      'teaser' => array(
-        'label' => t('Teaser'),
-        'custom settings' => TRUE,
-      ),
-    ),
-    'redirect' => FALSE, // for the Redirect module
-  );
-
-  return $entities;
-
-}
-
-/**
- * Implements hook_permission().
- */
-function election_candidate_permission() {
-  $permissions = array(
-    'bypass nomination schedule' => array(
-      'title' => t('Bypass nomination schedule'),
-      'description' => t('This allows the user to submit a nomination at any time, regardless of whether or not nominations are open.'),
-    ),
-    'bypass nomination exclusivity' => array(
-      'title' => t('Bypass nomination exclusivity'),
-      'description' => t('This allows the user to submit a nomination for more than one exclusive position.'),
-    ),
-    'allow duplicate nominations' => array(
-      'title' => t('Allow duplicate nominations'),
-      'description' => t('This allows the user to submit more than one nomination for the same position.'),
-    ),
-    'submit nominations' => array(
-      'title' => t('Submit nominations'),
-      'description' => t('This allows the user to submit a nomination, only when nominations are open.'),
-    ),
-    'edit own nominations' => array(
-      'title' => t('Edit own nominations'),
-      'description' => t('This allows the user to edit his/her own nominations.'),
-    ),
-  );
-  return $permissions;
-}
-
-/**
- * Determines whether the given user has access to a given election candidate.
- *
- * @param $op
- *   The operation being performed. One of 'view', 'update', 'create', 'delete'
- *   or just 'edit' (being the same as 'create' or 'update').
- * @param $candidate
- *   Optionally a candidate to check access for. If nothing is
- *   given, access for all candidates is determined.
- * @param $account
- *   The user to check for. Leave it to NULL to check for the global user.
- * @return boolean
- *   Whether access is allowed or not.
- */
-function election_candidate_access($op, $candidate = NULL, $account = NULL) {
-  if ($account === NULL) {
-    global $user;
-    $account = $user;
-  }
-  switch ($op) {
-    case 'view':
-      if (user_access('edit any election', $account)) {
-        return TRUE;
-      }
-      if ($candidate && $candidate->cstatus == ELECTION_CANDIDATE_APPROVED && user_access('view any election', $account)) {
-        return TRUE;
-      }
-      break;
-    case 'edit':
-    case 'update':
-    case 'delete':
-    case 'view details':
-      if (user_access('edit any election', $account)) {
-        return TRUE;
-      }
-      break;
-    case 'create':
-      // Creating must happen through the nomination form, not via entity_access.
-      return FALSE;
-      break;
-  }
-  if ($candidate === NULL || empty($candidate->uid) || $candidate->uid !== $account->uid) {
-    // This is not the account's nomination, and global checks have failed.
-    return FALSE;
-  }
-  // This is the $acccount's nomination.
-  switch ($op) {
-    case 'view':
-    case 'view details':
-      return TRUE;
-      break;
-    case 'edit':
-    case 'update':
-      return (bool) user_access('edit own nominations', $account);
-      break;
-    default:
-      return FALSE;
-      break;
-  }
-}
-
-/**
- * Implements hook_menu().
- */
-function election_candidate_menu() {
-  $items = array();
-
-  $items['admin/election/candidate'] = array(
-    'title' => 'Candidate settings',
-    'description' => 'Manage fields and display settings for election candidates (not applicable to referendums).',
-    'title callback' => 'check_plain',
-    'page callback' => 'system_admin_menu_block_page',
-    'file' => 'system.admin.inc',
-    'file path' => drupal_get_path('module', 'system'),
-    'access arguments' => array('administer elections'),
-  );
-
-  $items['admin/election/candidate/settings'] = array(
-    'title' => 'Settings',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-    'weight' => 0,
-  );
-
-  $items['election/%election/nomination-form'] = array(
-    'title' => 'Nomination form',
-    'page callback' => 'election_page_nomination_form',
-    'page arguments' => array(1),
-    'access callback' => 'election_access',
-    'access arguments' => array('nomination', 1),
-    'file' => 'election-candidate.pages.inc',
-    'type' => MENU_LOCAL_TASK,
-    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
-    'weight' => 2,
-  );
-
-  $items['election/%election/candidates'] = array(
-    'title' => 'Candidates',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('election_candidate_list_form', 1),
-    'access callback' => 'election_access',
-    'access arguments' => array('edit candidates', 1),
-    'file' => 'election-candidate.admin.inc',
-    'type' => MENU_LOCAL_TASK,
-    'weight' => 4,
-    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
-  );
-
-  $items['election/%election/candidates/list'] = array(
-    'title' => 'List candidates',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-    'weight' => 0,
-  );
-
-  $items['election/%election/candidates/totals'] = array(
-    'title' => 'View totals',
-    'page callback' => 'election_candidate_totals_page',
-    'page arguments' => array(1),
-    'access callback' => 'election_access',
-    'access arguments' => array('edit candidates', 1),
-    'file' => 'election-candidate.admin.inc',
-    'type' => MENU_LOCAL_TASK,
-    'weight' => 1,
-    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
-  );
-
-  $items['election/%election/candidates/download'] = array(
-    'title' => 'Download data',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('election_candidate_download_form', 1),
-    'access callback' => 'election_access',
-    'access arguments' => array('edit candidates', 1),
-    'file' => 'election-candidate.admin.inc',
-    'type' => MENU_LOCAL_TASK,
-    'weight' => 2,
-    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
-  );
-
-
-  $items['election/%election/candidate/%election_candidate'] = array(
-    'title callback' => 'election_candidate_page_title',
-    'title arguments' => array(1, 3),
-    'page callback' => 'election_candidate_page_view',
-    'page arguments' => array(1, 3),
-    'file' => 'election-candidate.pages.inc',
-    'access callback' => 'election_candidate_access',
-    'access arguments' => array('view', 3),
-    'type' => MENU_CALLBACK,
-  );
-
-  $items['election/%election/candidate/%election_candidate/view'] = array(
-    'title' => 'View',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-    'weight' => 0,
-  );
-
-  $items['election/%election/candidate/%election_candidate/details'] = array(
-    'title' => 'Details',
-    'page callback' => 'election_candidate_details_page_view',
-    'page arguments' => array(1, 3),
-    'file' => 'election-candidate.pages.inc',
-    'access callback' => 'election_candidate_access',
-    'access arguments' => array('view details', 3),
-    'type' => MENU_LOCAL_TASK,
-    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
-    'weight' => 1,
-  );
-
-  $items['election/%election/candidate/%election_candidate/edit'] = array(
-    'title' => 'Edit',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('election_candidate_edit_form', 1, 3),
-    'file' => 'election-candidate.pages.inc',
-    'access callback' => 'election_candidate_access',
-    'access arguments' => array('update', 3),
-    'type' => MENU_LOCAL_TASK,
-    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
-    'weight' => 2,
-  );
-
-  $items['election/%election/candidate/%election_candidate/delete'] = array(
-    'title' => 'Delete',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('election_candidate_edit_form_delete_confirm', 1, 3),
-    'access callback' => 'election_candidate_access',
-    'access arguments' => array('delete', 3),
-    'file' => 'election-candidate.pages.inc',
-    'weight' => 3,
-    'type' => MENU_LOCAL_TASK,
-    'context' => MENU_CONTEXT_INLINE,
-  );
-
-  return $items;
-}
-
-/**
- * Implements hook_menu_alter().
- */
-function election_candidate_menu_alter(&$items) {
-  unset($items['admin/election/candidate/settings']);
-  $items['admin/election/candidate/fields']['type'] = MENU_NORMAL_ITEM;
-  $items['admin/election/candidate/fields']['description'] = t('Manage fields for election candidates.');
-  $items['admin/election/candidate/display']['type'] = MENU_NORMAL_ITEM;
-  $items['admin/election/candidate/display']['description'] = t('Manage display for election candidates.');
-}
-
-/**
- * Implements hook_field_extra_fields().
- */
-function election_candidate_field_extra_fields() {
-  $extra = array();
-  $extra['election_candidate']['election_candidate'] = array(
-    'form' => array(
-      'post' => array(
-        'label' => t('Post'),
-        'description' => t('The post for this nomination.'),
-        'weight' => -1,
-      ),
-      'first_name' => array(
-        'label' => t('First name'),
-        'description' => t('The candidate\'s first name(s).'),
-        'weight' => 0,
-      ),
-      'last_name' => array(
-        'label' => t('Last name'),
-        'description' => t('The candidate\'s last name(s).'),
-        'weight' => 1,
-      ),
-      'mail' => array(
-        'label' => t('Email address'),
-        'description' => t('The candidate\'s email address.'),
-        'weight' => 2,
-      ),
-      'phone' => array(
-        'label' => t('Phone number'),
-        'description' => t('The candidate\'s phone number.'),
-        'weight' => 3,
-      ),
-    ),
-    'display' => array(
-      'election' => array(
-        'label' => t('Election'),
-        'description' => t('The election for this nomination.'),
-        'weight' => 0,
-      ),
-      'post' => array(
-        'label' => t('Post'),
-        'description' => t('The post/position for this nomination.'),
-        'weight' => 1,
-      ),
-      'full-name' => array(
-        'label' => t('Name'),
-        'description' => t('The candidate\'s name.'),
-        'weight' => 2,
-      ),
-    ),
-  );
-  return $extra;
-}
-
-
-/**
- * Title callback for election/%election_candidate/view (output should not be escaped here
- * as it is done later).
- *
- * @param stdClass $election
- * @param stdClass $candidate
- *
- * @return string
- */
-function election_candidate_page_title($election, $candidate) {
-  return $candidate->first_name . ' ' . $candidate->last_name;
-}
-
-/**
- * Wrapper function to allow saving an election candidate.
- *
- * @param stdClass $candidate
- *   Election candidate object.
- * @return bool
- */
-function election_candidate_save($candidate) {
-  return entity_get_controller('election_candidate')->save($candidate);
-}
-
-/**
- * Wrapper function to allow deleting multiple candidates.
- *
- * @param array $candidate_ids
- *   Array of candidate IDs.
- * @return bool
- */
-function election_candidate_delete_multiple(array $candidate_ids) {
-  return entity_get_controller('election_candidate')->delete($candidate_ids);
-}
-
-/**
- * Wrapper function to allow deleting an individual election.
- *
- * @see election_candidate_delete_multiple()
- *
- * @param mixed $candidate_id
- *   Single candidate ID.
- * @return bool
- */
-function election_candidate_delete($candidate_id) {
-  return election_candidate_delete_multiple(array($candidate_id));
-}
-
-
-/*
- * Find the nominations (election_candidate entities) for a specified election
- * and user.
- *
- * @param stdClass $election
- *   Election object.
- * @param stdClass $account
- *   Optional $user object.
- *
- * @return
- *   FALSE if the account is anonymous, or a SelectQuery object.
- */
-function election_candidate_get_user_nominations(stdClass $election, $account = NULL) {
-  if ($account === NULL) {
-    global $user;
-    $account = $user;
-  }
-  if ($account->uid == 0) {
-    return array();
-  }
-  $select = db_query(
-    'SELECT ec.*, ep.title AS post_title, ep.exclusive FROM {election_candidate} ec LEFT JOIN {election_post} ep USING (post_id) WHERE ec.uid = :uid AND ep.election_id = :eid',
-    array(
-      ':eid' => $election->election_id,
-      ':uid' => $account->uid,
-    )
-  );
-  return $select->fetchAll();
-}
-
-/*
- * Find the posts that a candidate may be nominated for.
- *
- * @param stdClass $election
- *   Election object.
- * @param array $nominations
- *   Array of the user's previous nominations (election_candidate objects).
- * @param stdClass $account
- *   User object.
- *
- * @return
- *   Array of post IDs.
- */
-function election_candidate_get_available_posts(stdClass $election, $nominations = NULL, $account = NULL) {
-  if ($nominations === NULL) {
-    if ($account === NULL) {
-      global $user;
-      $account = $user;
-    }
-    $nominations = election_candidate_get_user_nominations($election, $account);
-  }
-  $has_exclusive = FALSE;
-  $prev_post_ids = array();
-  foreach ($nominations as $nomination) {
-    if ($nomination->exclusive) {
-      $has_exclusive = TRUE;
-    }
-    $prev_post_ids[] = $nomination->post_id;
-  }
-  $select = db_select('election_post', 'ep')->fields('ep', array('post_id'));
-  $select->condition('election_id', $election->election_id, '=');
-  if ($prev_post_ids && !user_access('allow duplicate nominations')) {
-    $select->condition('post_id', $prev_post_ids, 'NOT IN');
-  }
-  if ($has_exclusive && !user_access('bypass nomination exclusivity')) {
-    $select->condition('exclusive', 0, '=');
-  }
-  $select->orderBy('title');
-  $result = $select->execute();
-  return $result->fetchCol();
-}
-
-/**
- * URI callback for a single election candidate.
- *
- * @return array
- */
-function election_candidate_uri($candidate) {
-  $path = 'election-candidate/' . $candidate->candidate_id;
-  if (!empty($candidate->election_id)) {
-    $election = election_load($candidate->election_id);
-    $path = election_uri_path($election) . '/candidate/' . $candidate->candidate_id;
-  }
-  return array(
-    'path' => $path,
-  );
-}
-
-/**
- * Return the path part of the election candidate URI callback as a string.
- *
- * @return string.
- */
-function election_candidate_uri_path($candidate) {
-  $uri = entity_uri('election_candidate', $candidate);
-  return $uri['path'];
-}
-
-/**
- * Label callback for an election_candidate, returning the candidate's name.
- *
- * @param stdClass $entity
- * @param string $entity_type
- *
- * @return string
- */
-function election_candidate_label(stdClass $entity, $entity_type) {
-  return $entity->first_name . ' ' . $entity->last_name;
-}
-
-/**
- * Load multiple candidates.
- *
- * @param mixed $candidate_ids
- *   An array of election candidate IDs.
- *
- * @return stdClass
- *   A stdClass election_candidate object.
- */
-function election_candidate_load_multiple(array $candidate_ids = array()) {
-  return entity_load('election_candidate', $candidate_ids);
-}