r53858 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r53857‎ | r53858 | r53859 >
Date:06:05, 28 July 2009
Author:tstarling
Status:ok
Tags:
Comment:
Merging SecurePoll changes from trunk, r52089 to r52858. For Board election.
Modified paths:
  • /branches/wmf-deployment/extensions/SecurePoll (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/SecurePoll.alias.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/SecurePoll.css (deleted) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/SecurePoll.i18n.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/SecurePoll.js (deleted) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/SecurePoll.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/SecurePoll.sql (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/SecurePoll_body.php (deleted) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/auth-api.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/cli (added) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/Auth.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/Ballot.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/Base.php (added) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/Context.php (added) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/Crypt.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/DetailsPage.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/DumpPage.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/Election.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/ElectionTallier.php (added) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/Entity.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/ListPage.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/LoginPage.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/MessageDumpPage.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/Option.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/Page.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/Question.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/Random.php (added) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/Store.php (added) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/Tallier.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/TallyPage.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/TranslatePage.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/VotePage.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/includes/Voter.php (modified) (history)
  • /branches/wmf-deployment/extensions/SecurePoll/resources (added) (history)

Diff [purge]

Index: branches/wmf-deployment/extensions/SecurePoll/SecurePoll.js
@@ -1,111 +0,0 @@
2 -function securepoll_strike_popup(e, action, id) {
3 - var pop = document.getElementById('securepoll-popup');
4 -
5 - var e = window.event || e;
6 - if(!e) return;
7 - var target = e.target || e.srcElement;
8 - if(!target) return;
9 -
10 - if ( pop.parentNode.tagName.toLowerCase() != 'body' ) {
11 - pop = pop.parentNode.removeChild( pop );
12 - pop = document.body.appendChild( pop );
13 - }
14 -
15 - var left = 0;
16 - var top = 0;
17 - var containing = target;
18 - while ( containing ) {
19 - left += containing.offsetLeft;
20 - top += containing.offsetTop;
21 - containing = containing.offsetParent;
22 - }
23 - left += target.offsetWidth - 10;
24 - top += target.offsetHeight - 10;
25 -
26 - // Show the appropriate button
27 - var strikeButton = document.getElementById( 'securepoll-strike-button' );
28 - var unstrikeButton = document.getElementById( 'securepoll-unstrike-button' );
29 - if ( action == 'strike' ) {
30 - strikeButton.style.display = 'inline';
31 - strikeButton.disabled = false;
32 - unstrikeButton.style.display = 'none';
33 - unstrikeButton.disabled = true;
34 - } else {
35 - unstrikeButton.style.display = 'inline';
36 - unstrikeButton.disabled = false;
37 - strikeButton.style.display = 'none';
38 - strikeButton.disabled = true;
39 - }
40 - document.getElementById( 'securepoll-strike-result' ).innerHTML = '';
41 -
42 - // Set the hidden fields for submission
43 - document.getElementById( 'securepoll-action').value = action;
44 - document.getElementById( 'securepoll-vote-id' ).value = id;
45 -
46 - // Show the popup
47 - pop.style.left = left + 'px';
48 - pop.style.top = top + 'px';
49 - pop.style.display = 'block';
50 -
51 - // Focus on the reason box
52 - var reason = document.getElementById( 'securepoll-strike-reason' );
53 - reason.focus();
54 - reason.select();
55 -}
56 -
57 -function securepoll_strike(action) {
58 - var popup = document.getElementById('securepoll-popup');
59 - if(action == 'cancel') {
60 - popup.style.display = '';
61 - return;
62 - }
63 - if ( action == 'submit' ) {
64 - action = document.getElementById( 'securepoll-action' ).value;
65 - }
66 - var id = document.getElementById( 'securepoll-vote-id' ).value;
67 - var strikeButton = document.getElementById( 'securepoll-strike-button' );
68 - var unstrikeButton = document.getElementById( 'securepoll-unstrike-button' );
69 - var spinner = document.getElementById( 'securepoll-strike-spinner' );
70 - strikeButton.disabled = true;
71 - unstrikeButton.disabled = true;
72 - spinner.style.display = 'block';
73 - var reason = document.getElementById( 'securepoll-strike-reason' ).value;
74 -
75 - var processResult = function (xhr) {
76 - spinner.style.display = 'none';
77 - strikeButton.disabled = false;
78 - unstrikeButton.disabled = false;
79 -
80 - if ( xhr.status >= 300 || xhr.status < 200 ) {
81 - document.getElementById( 'securepoll-strike-result' ).innerHTML = xhr.responseText;
82 - return;
83 - }
84 -
85 - // Evaluate JSON result, with brackets to avoid interpretation as a code block
86 - result = eval( '(' + xhr.responseText + ')' );
87 - if ( result.status == 'good' ) {
88 - popup.style.display = 'none';
89 - } else {
90 - document.getElementById( 'securepoll-strike-result' ).innerHTML = result.message;
91 - }
92 -
93 - securepoll_modify_document( action, id );
94 - };
95 -
96 - sajax_do_call( 'wfSecurePollStrike', [ action, id, reason ], processResult );
97 -}
98 -
99 -function securepoll_modify_document( action, voteId ) {
100 - var popupButton = document.getElementById( 'securepoll-popup-' + voteId );
101 - var row = popupButton.parentNode.parentNode;
102 - if ( action == 'strike' ) {
103 - row.className += ' securepoll-struck-vote';
104 - popupButton.value = securepoll_unstrike_button;
105 - } else {
106 - row.className = row.className.replace( 'securepoll-struck-vote', '' );
107 - popupButton.value = securepoll_strike_button;
108 - }
109 - popupButton.onclick = function (event) {
110 - securepoll_strike_popup( event, action == 'strike' ? 'unstrike' : 'strike', voteId );
111 - }
112 -}
Index: branches/wmf-deployment/extensions/SecurePoll/SecurePoll_body.php
@@ -1,86 +0,0 @@
2 -<?php
3 -if ( !defined( 'MEDIAWIKI' ) ) {
4 - die( "Not a valid entry point\n" );
5 -}
6 -
7 -class SecurePollPage extends UnlistedSpecialPage {
8 - static $pages = array(
9 - 'details' => 'SecurePoll_DetailsPage',
10 - 'dump' => 'SecurePoll_DumpPage',
11 - 'entry' => 'SecurePoll_EntryPage',
12 - 'list' => 'SecurePoll_ListPage',
13 - 'login' => 'SecurePoll_LoginPage',
14 - 'msgdump' => 'SecurePoll_MessageDumpPage',
15 - 'tally' => 'SecurePoll_TallyPage',
16 - 'translate' => 'SecurePoll_TranslatePage',
17 - 'vote' => 'SecurePoll_VotePage',
18 - );
19 -
20 - /**
21 - * Constructor
22 - */
23 - public function __construct() {
24 - parent::__construct( 'SecurePoll' );
25 - }
26 -
27 - /**
28 - * Show the special page
29 - *
30 - * @param $paramString Mixed: parameter passed to the page or null
31 - */
32 - public function execute( $paramString ) {
33 - global $wgOut, $wgRequest, $wgScriptPath;
34 -
35 - wfLoadExtensionMessages( 'SecurePoll' );
36 -
37 - $this->setHeaders();
38 - $wgOut->addLink( array(
39 - 'rel' => 'stylesheet',
40 - 'href' => "$wgScriptPath/extensions/SecurePoll/SecurePoll.css",
41 - 'type' => 'text/css'
42 - ) );
43 - $wgOut->addScriptFile( "$wgScriptPath/extensions/SecurePoll/SecurePoll.js" );
44 -
45 - $this->request = $wgRequest;
46 -
47 - $paramString = strval( $paramString );
48 - if ( $paramString === '' ) {
49 - $paramString = 'entry';
50 - }
51 - $params = explode( '/', $paramString );
52 - $pageName = array_shift( $params );
53 - $page = $this->getSubpage( $pageName );
54 - if ( !$page ) {
55 - $wgOut->addWikiMsg( 'securepoll-invalid-page', $pageName );
56 - return;
57 - }
58 -
59 - $page->execute( $params );
60 - }
61 -
62 - function getSubpage( $name ) {
63 - if ( !isset( self::$pages[$name] ) ) {
64 - return false;
65 - }
66 - $className = self::$pages[$name];
67 - $page = new $className( $this );
68 - return $page;
69 - }
70 -
71 - function getElection( $id ) {
72 - $db = wfGetDB( DB_MASTER );
73 - $row = $db->selectRow( 'securepoll_elections', '*', array( 'el_entity' => $id ), __METHOD__ );
74 - if ( $row ) {
75 - return SecurePoll_Election::newFromRow( $row );
76 - } else {
77 - return false;
78 - }
79 - }
80 -
81 - function getEditToken() {
82 - if ( !isset( $_SESSION['spToken'] ) ) {
83 - $_SESSION['spToken'] = sha1( mt_rand() . mt_rand() . mt_rand() );
84 - }
85 - return $_SESSION['spToken'];
86 - }
87 -}
Index: branches/wmf-deployment/extensions/SecurePoll/SecurePoll.css
@@ -1,44 +0,0 @@
2 -.securepoll-old-vote {
3 - color: #666;
4 -}
5 -.securepoll-struck-vote td {
6 - text-decoration: line-through;
7 -}
8 -.securepoll-popup {
9 - padding: 0.5em 1em 0.5em 1em;
10 - border: outset;
11 - position: absolute;
12 - height: 7em;
13 - width: 38em;
14 - display: none;
15 - background-color: #ffffdd;
16 - overflow: auto;
17 - z-index: 3;
18 -}
19 -.securepoll-confirm-button {
20 - width: 16%;
21 - margin-left: 16%;
22 - margin-right: 16%;
23 -}
24 -#securepoll-strike-spinner {
25 - display: none;
26 - margin-left: auto;
27 - margin-right: auto;
28 - width: 30px;
29 -}
30 -.securepoll-detail-header {
31 - font-weight: bold;
32 - width: 20%;
33 -}
34 -.securepoll-trans-table {
35 - width: 100%;
36 -}
37 -.securepoll-error-box {
38 - font-size: larger;
39 - border: 2px solid;
40 - padding: .5em 1em;
41 - margin-bottom: 2em;
42 - color: #000;
43 - border-color: red;
44 - background-color: #fff2f2;
45 -}
Index: branches/wmf-deployment/extensions/SecurePoll/resources/SecurePoll.css
@@ -0,0 +1,67 @@
 2+.securepoll-old-vote {
 3+ color: #666;
 4+}
 5+.securepoll-struck-vote td {
 6+ text-decoration: line-through;
 7+}
 8+.securepoll-popup {
 9+ padding: 0.5em 1em 0.5em 1em;
 10+ border: outset;
 11+ position: absolute;
 12+ height: 7em;
 13+ width: 38em;
 14+ display: none;
 15+ background-color: #ffffdd;
 16+ overflow: auto;
 17+ z-index: 3;
 18+}
 19+.securepoll-confirm-button {
 20+ width: 16%;
 21+ margin-left: 16%;
 22+ margin-right: 16%;
 23+}
 24+#securepoll-strike-spinner {
 25+ display: none;
 26+ margin-left: auto;
 27+ margin-right: auto;
 28+ width: 30px;
 29+}
 30+.securepoll-detail-header {
 31+ font-weight: bold;
 32+ width: 20%;
 33+}
 34+.securepoll-trans-table {
 35+ width: 100%;
 36+}
 37+.securepoll-error-box {
 38+ font-size: larger;
 39+ border: 2px solid;
 40+ padding: .5em 1em;
 41+ margin-bottom: 2em;
 42+ color: #000;
 43+ border-color: red;
 44+ background-color: #fff2f2;
 45+}
 46+.securepoll-option-preferential {
 47+ margin-bottom: 0.5em;
 48+}
 49+.securepoll-results {
 50+ margin: 1em 1em 1em 0;
 51+ background: #f9f9f9;
 52+ border: 1px #aaa solid;
 53+ border-collapse: collapse;
 54+}
 55+.securepoll-results th, .securepoll-results td {
 56+ border: 1px #aaa solid;
 57+ padding: 0.4em;
 58+}
 59+.securepoll-results th {
 60+ background: #f2f2f2;
 61+ text-align: center;
 62+}
 63+.securepoll-results caption {
 64+ font-weight: bold;
 65+}
 66+.securepoll-results-row-heading {
 67+ background: #f2f2f2;
 68+}
Property changes on: branches/wmf-deployment/extensions/SecurePoll/resources/SecurePoll.css
___________________________________________________________________
Added: svn:mergeinfo
Added: svn:eol-style
169 + native
Index: branches/wmf-deployment/extensions/SecurePoll/resources/SecurePoll.js
@@ -0,0 +1,111 @@
 2+function securepoll_strike_popup(e, action, id) {
 3+ var pop = document.getElementById('securepoll-popup');
 4+
 5+ var e = window.event || e;
 6+ if(!e) return;
 7+ var target = e.target || e.srcElement;
 8+ if(!target) return;
 9+
 10+ if ( pop.parentNode.tagName.toLowerCase() != 'body' ) {
 11+ pop = pop.parentNode.removeChild( pop );
 12+ pop = document.body.appendChild( pop );
 13+ }
 14+
 15+ var left = 0;
 16+ var top = 0;
 17+ var containing = target;
 18+ while ( containing ) {
 19+ left += containing.offsetLeft;
 20+ top += containing.offsetTop;
 21+ containing = containing.offsetParent;
 22+ }
 23+ left += target.offsetWidth - 10;
 24+ top += target.offsetHeight - 10;
 25+
 26+ // Show the appropriate button
 27+ var strikeButton = document.getElementById( 'securepoll-strike-button' );
 28+ var unstrikeButton = document.getElementById( 'securepoll-unstrike-button' );
 29+ if ( action == 'strike' ) {
 30+ strikeButton.style.display = 'inline';
 31+ strikeButton.disabled = false;
 32+ unstrikeButton.style.display = 'none';
 33+ unstrikeButton.disabled = true;
 34+ } else {
 35+ unstrikeButton.style.display = 'inline';
 36+ unstrikeButton.disabled = false;
 37+ strikeButton.style.display = 'none';
 38+ strikeButton.disabled = true;
 39+ }
 40+ document.getElementById( 'securepoll-strike-result' ).innerHTML = '';
 41+
 42+ // Set the hidden fields for submission
 43+ document.getElementById( 'securepoll-action').value = action;
 44+ document.getElementById( 'securepoll-vote-id' ).value = id;
 45+
 46+ // Show the popup
 47+ pop.style.left = left + 'px';
 48+ pop.style.top = top + 'px';
 49+ pop.style.display = 'block';
 50+
 51+ // Focus on the reason box
 52+ var reason = document.getElementById( 'securepoll-strike-reason' );
 53+ reason.focus();
 54+ reason.select();
 55+}
 56+
 57+function securepoll_strike(action) {
 58+ var popup = document.getElementById('securepoll-popup');
 59+ if(action == 'cancel') {
 60+ popup.style.display = '';
 61+ return;
 62+ }
 63+ if ( action == 'submit' ) {
 64+ action = document.getElementById( 'securepoll-action' ).value;
 65+ }
 66+ var id = document.getElementById( 'securepoll-vote-id' ).value;
 67+ var strikeButton = document.getElementById( 'securepoll-strike-button' );
 68+ var unstrikeButton = document.getElementById( 'securepoll-unstrike-button' );
 69+ var spinner = document.getElementById( 'securepoll-strike-spinner' );
 70+ strikeButton.disabled = true;
 71+ unstrikeButton.disabled = true;
 72+ spinner.style.display = 'block';
 73+ var reason = document.getElementById( 'securepoll-strike-reason' ).value;
 74+
 75+ var processResult = function (xhr) {
 76+ spinner.style.display = 'none';
 77+ strikeButton.disabled = false;
 78+ unstrikeButton.disabled = false;
 79+
 80+ if ( xhr.status >= 300 || xhr.status < 200 ) {
 81+ document.getElementById( 'securepoll-strike-result' ).innerHTML = xhr.responseText;
 82+ return;
 83+ }
 84+
 85+ // Evaluate JSON result, with brackets to avoid interpretation as a code block
 86+ result = eval( '(' + xhr.responseText + ')' );
 87+ if ( result.status == 'good' ) {
 88+ popup.style.display = 'none';
 89+ } else {
 90+ document.getElementById( 'securepoll-strike-result' ).innerHTML = result.message;
 91+ }
 92+
 93+ securepoll_modify_document( action, id );
 94+ };
 95+
 96+ sajax_do_call( 'wfSecurePollStrike', [ action, id, reason ], processResult );
 97+}
 98+
 99+function securepoll_modify_document( action, voteId ) {
 100+ var popupButton = document.getElementById( 'securepoll-popup-' + voteId );
 101+ var row = popupButton.parentNode.parentNode;
 102+ if ( action == 'strike' ) {
 103+ row.className += ' securepoll-struck-vote';
 104+ popupButton.value = securepoll_unstrike_button;
 105+ } else {
 106+ row.className = row.className.replace( 'securepoll-struck-vote', '' );
 107+ popupButton.value = securepoll_strike_button;
 108+ }
 109+ popupButton.onclick = function (event) {
 110+ securepoll_strike_popup( event, action == 'strike' ? 'unstrike' : 'strike', voteId );
 111+ }
 112+}
Property changes on: branches/wmf-deployment/extensions/SecurePoll/resources/SecurePoll.js
___________________________________________________________________
Added: svn:mergeinfo
Added: svn:eol-style
1113 + native
Index: branches/wmf-deployment/extensions/SecurePoll/resources/critical-32.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: branches/wmf-deployment/extensions/SecurePoll/resources/critical-32.png
___________________________________________________________________
Added: svn:mime-type
2114 + image/png
Added: svn:executable
3115 + *
Index: branches/wmf-deployment/extensions/SecurePoll/SecurePoll.alias.php
@@ -68,6 +68,11 @@
6969 'SecurePoll' => array( 'Affshtemme' ),
7070 );
7171
 72+/** Luxembourgish (Lëtzebuergesch) */
 73+$aliases['lb'] = array(
 74+ 'SecurePoll' => array( 'Sécher Ofstëmmung' ),
 75+);
 76+
7277 /** Nedersaksisch (Nedersaksisch) */
7378 $aliases['nds-nl'] = array(
7479 'SecurePoll' => array( 'Beveilig_stemmen' ),
@@ -83,8 +88,18 @@
8489 'SecurePoll' => array( 'Sikker avstemning' ),
8590 );
8691
 92+/** Occitan (Occitan) */
 93+$aliases['oc'] = array(
 94+ 'SecurePoll' => array( 'Vòte securizat' ),
 95+);
 96+
8797 /** Polish (Polski) */
8898 $aliases['pl'] = array(
8999 'SecurePoll' => array( 'Bezpieczne głosowanie' ),
90100 );
91101
 102+/** Slovak (Slovenčina) */
 103+$aliases['sk'] = array(
 104+ 'SecurePoll' => array( 'BezpečnéHlasovanie' ),
 105+);
 106+
Index: branches/wmf-deployment/extensions/SecurePoll/SecurePoll.sql
@@ -1,106 +1,218 @@
22
 3+-- Generic entity ID allocation
34 CREATE TABLE /*_*/securepoll_entity (
 5+ -- ID
46 en_id int not null primary key auto_increment,
 7+
 8+ -- "election", "question" or "option"
59 en_type varbinary(32) not null
610 ) /*$wgDBTableOptions*/;
711
 12+
 13+-- i18n text associated with an entity
814 CREATE TABLE /*_*/securepoll_msgs (
 15+ -- securepoll_entity.en_id
916 msg_entity int not null,
 17+
 18+ -- Language code
1019 msg_lang varbinary(32) not null,
 20+
 21+ -- Message key
1122 msg_key varbinary(32) not null,
 23+
 24+ -- Message text, UTF-8 encoded
1225 msg_text mediumtext not null
1326 ) /*$wgDBTableOptions*/;
1427 CREATE UNIQUE INDEX /*i*/spmsg_entity ON /*_*/securepoll_msgs (msg_entity, msg_lang, msg_key);
1528
 29+
 30+-- key/value pairs (properties) associated with an entity
1631 CREATE TABLE /*_*/securepoll_properties (
 32+ -- securepoll_entity.en_id
1733 pr_entity int not null,
 34+
 35+ -- Property key
1836 pr_key varbinary(32) not null,
 37+
 38+ -- Property value
1939 pr_value mediumblob not null
2040 ) /*$wgDBTableOptions*/;
2141 CREATE UNIQUE INDEX /*i*/sppr_entity ON /*_*/securepoll_properties (pr_entity, pr_key);
2242
 43+
 44+-- List of elections (or polls, surveys, etc)
2345 CREATE TABLE /*_*/securepoll_elections (
 46+ -- securepoll_entity.en_id
2447 el_entity int not null primary key,
 48+
 49+ -- Election title
 50+ -- Only used for the election list on the entry page
2551 el_title varchar(255) not null,
 52+
 53+ -- Owner user.user_id
 54+ el_owner int not null,
 55+
 56+ -- Ballot type, see Ballot.php
2657 el_ballot varchar(32) not null,
 58+
 59+ -- Tally type, see Tally.php
2760 el_tally varchar(32) not null,
 61+
 62+ -- Primary (administrative) language
 63+ -- This is the primary source for translations
2864 el_primary_lang varbinary(32) not null,
 65+
 66+ -- Start date, in 14-char MW format
2967 el_start_date varbinary(14),
 68+
 69+ -- End date, in 14-char MW format
3070 el_end_date varbinary(14),
 71+
 72+ -- User authorisation type, see Auth.php
3173 el_auth_type varbinary(32) not null
3274 ) /*$wgDBTableOptions*/;
3375 CREATE UNIQUE INDEX /*i*/spel_title ON /*_*/securepoll_elections (el_title);
3476
 77+
 78+-- Questions, see Question.php
3579 CREATE TABLE /*_*/securepoll_questions (
 80+ -- securepoll_entity.en_id
3681 qu_entity int not null primary key,
 82+
 83+ -- securepoll_elections.el_entity
3784 qu_election int not null,
 85+
 86+ -- Index determining the order the questions are shown, if shuffle is off
3887 qu_index int not null
3988 ) /*$wgDBTableOptions*/;
4089 CREATE INDEX /*i*/spqu_election_index ON /*_*/securepoll_questions (qu_election, qu_index, qu_entity);
4190
 91+
 92+-- Options for answering a given question, see Option.php
 93+-- FIXME: needs op_election index for import.php
4294 CREATE TABLE /*_*/securepoll_options (
 95+ -- securepoll_entity.en_id
4396 op_entity int not null primary key,
 97+ -- securepoll_elections.el_entity
4498 op_election int not null,
 99+ -- securepoll_questions.qu_entity
45100 op_question int not null
46101 ) /*$wgDBTableOptions*/;
47102 CREATE INDEX /*i*/spop_question ON /*_*/securepoll_options (op_question, op_entity);
48103
 104+
 105+-- Voter list, independent for each election
 106+-- See Voter.php
49107 CREATE TABLE /*_*/securepoll_voters (
 108+ -- Primary key
50109 voter_id int not null primary key auto_increment,
 110+ -- securepoll_elections.el_id
51111 voter_election int not null,
 112+ -- The voter's name, as it appears on the remote site
52113 voter_name varchar(255) binary not null,
 114+ -- The auth type that created this voter
53115 voter_type varbinary(32) not null,
 116+ -- The voter's domain, should be fully-qualified
54117 voter_domain varbinary(255) not null,
 118+ -- A URL uniquely identifying the voter
55119 voter_url blob,
 120+ -- serialized properties blob
56121 voter_properties blob
57122 ) /*$wgDBTableOptions*/;
58123 CREATE INDEX /*i*/spvoter_elec_name_domain ON /*_*/securepoll_voters
59124 (voter_election, voter_name, voter_domain);
60125
 126+-- Votes that have been cast
 127+-- Contains a blob with answers to all questions
61128 CREATE TABLE /*_*/securepoll_votes (
62129 vote_id int not null primary key auto_increment,
 130+ -- securepoll_elections.el_id
63131 vote_election int not null,
 132+ -- securepoll_voters.voter_id
64133 vote_voter int not null,
65134
66135 -- Denormalised fields from the user table for efficient sorting
 136+
 137+ -- securepoll_voters.voter_name
67138 vote_voter_name varchar(255) binary not null,
 139+ -- securepoll_voters.voter_domain
68140 vote_voter_domain varbinary(32) not null,
69141
70142 -- Denormalised field from the strike table
71143 -- 1 if struck, 0 if not struck
72144 vote_struck tinyint not null,
73145
 146+ -- The voting record, produced and interpreted by the ballot type
 147+ -- May be encrypted
74148 vote_record blob not null,
 149+
 150+ -- The IP address, in hexadecimal form (IP::toHex())
75151 vote_ip varbinary(32) not null,
 152+
 153+ -- The X-Forwarded-For header
76154 vote_xff varbinary(255) not null,
 155+
 156+ -- The User-Agent header
77157 vote_ua varbinary(255) not null,
 158+
 159+ -- MW-format timestamp when the vote was cast
78160 vote_timestamp varbinary(14) not null,
 161+
 162+ -- 1 if the vote is current, 0 if old
 163+ -- Only one vote with a given voter will have vote_current=1
79164 vote_current tinyint not null,
 165+
 166+ -- 1 if the CSRF token matched (good), 0 for a potential hack
80167 vote_token_match tinyint not null,
 168+
 169+ -- 1 if the vote is flagged as being made by a potential sockpuppet
 170+ -- Details in securepoll_cookie_match
81171 vote_cookie_dup tinyint not null
82172 ) /*$wgDBTableOptions*/;
 173+-- For list subpage, sorted by timestamp
83174 CREATE INDEX /*i*/spvote_timestamp ON /*_*/securepoll_votes
84175 (vote_election, vote_timestamp);
 176+-- For list subpage, sorted by name
85177 CREATE INDEX /*i*/spvote_voter_name ON /*_*/securepoll_votes
86178 (vote_election, vote_voter_name, vote_timestamp);
 179+-- For list subpage, sorted by domain
87180 CREATE INDEX /*i*/spvote_voter_domain ON /*_*/securepoll_votes
88181 (vote_election, vote_voter_domain, vote_timestamp);
 182+-- For list subpage, sorted by IP
89183 CREATE INDEX /*i*/spvote_ip ON /*_*/securepoll_votes
90184 (vote_election, vote_ip, vote_timestamp);
91185
 186+-- Log of admin strike actions
92187 CREATE TABLE /*_*/securepoll_strike (
 188+ -- Primary key
93189 st_id int not null primary key auto_increment,
 190+
 191+ -- securepoll_votes.vote_id
94192 st_vote int not null,
 193+
 194+ -- Time at which the action occurred
95195 st_timestamp varbinary(14) not null,
 196+
 197+ -- "strike" or "unstrike"
96198 st_action varbinary(32) not null,
 199+
 200+ -- Explanatory reason
97201 st_reason varchar(255) not null,
 202+
 203+ -- user.user_id who did the action
98204 st_user int not null
99205 ) /*$wgDBTableOptions*/;
 206+-- For details subpage (strike log)
100207 CREATE INDEX /*i*/spstrike_vote ON /*_*/securepoll_strike
101208 (st_vote, st_timestamp);
102209
 210+
 211+-- Local voter qualification lists
 212+-- Currently manually populated, referenced by Auth.php
103213 CREATE TABLE /*_*/securepoll_lists (
 214+ -- List name
104215 li_name varbinary(255),
 216+ -- user.user_id
105217 li_member int not null
106218 ) /*$wgDBTableOptions*/;
107219 CREATE INDEX /*i*/splists_name ON /*_*/securepoll_lists
@@ -108,11 +220,17 @@
109221 CREATE INDEX /*i*/splists_member ON /*_*/securepoll_lists
110222 (li_member, li_name);
111223
 224+-- Suspicious cookie match logs
112225 CREATE TABLE /*_*/securepoll_cookie_match (
 226+ -- Primary key
113227 cm_id int not null primary key auto_increment,
 228+ -- securepoll_elections.el_id
114229 cm_election int not null,
 230+ -- securepoll_voters.voter_id
115231 cm_voter_1 int not null,
 232+ -- securepoll_voters.voter_id
116233 cm_voter_2 int not null,
 234+ -- Timestamp at which the match was logged
117235 cm_timestamp varbinary(14) not null
118236 ) /*$wgDBTableOptions*/;
119237 CREATE INDEX /*i*/spcookie_match_voter_1 ON /*_*/securepoll_cookie_match
Index: branches/wmf-deployment/extensions/SecurePoll/auth-api.php
@@ -37,6 +37,8 @@
3838 echo serialize( Status::newFatal( 'securepoll-api-token-mismatch' ) );
3939 exit;
4040 }
41 -$status = Status::newGood( SecurePoll_LocalAuth::getUserParams( $user ) );
 41+$context = new SecurePoll_Context;
 42+$auth = $context->newAuth( 'local' );
 43+$status = Status::newGood( $auth->getUserParams( $user ) );
4244 echo serialize( $status );
4345
Index: branches/wmf-deployment/extensions/SecurePoll/SecurePoll.i18n.php
@@ -57,10 +57,11 @@
5858 'securepoll-no-decryption-key' => 'No decryption key is configured.
5959 Cannot decrypt.',
6060 'securepoll-jump' => 'Go to the voting server',
61 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
62 - Your vote was invalid: $1
63 - </div>',
 61+ 'securepoll-bad-ballot-submission' => 'Your vote was invalid: $1',
6462 'securepoll-unanswered-questions' => 'You must answer all questions.',
 63+ 'securepoll-invalid-rank' => 'Invalid rank. You must give candidates a rank between 1 and 999.',
 64+ 'securepoll-unranked-options' => 'Some options were not ranked.
 65+You must give all options a rank between 1 and 999.',
6566
6667 # Authorisation related
6768 'securepoll-remote-auth-error' => 'Error fetching your account information from the server.',
@@ -75,6 +76,7 @@
7677 'securepoll-bot' => 'Sorry, accounts with the bot flag are not allowed to vote in this election.',
7778 'securepoll-not-in-group' => 'Only members of the "$1" group can vote in this election.',
7879 'securepoll-not-in-list' => 'Sorry, you are not in the predetermined list of users authorised to vote in this election.',
 80+ 'securepoll-custom-unqualified' => '$1',
7981
8082 # List page
8183 # Mostly for admins
@@ -94,6 +96,7 @@
9597 'securepoll-strike-reason' => 'Reason:',
9698 'securepoll-strike-cancel' => 'Cancel',
9799 'securepoll-strike-error' => 'Error performing strike/unstrike: $1',
 100+ 'securepoll-strike-token-mismatch' => 'Session data lost',
98101 'securepoll-details-link' => 'Details',
99102
100103 # Details page
@@ -116,6 +119,8 @@
117120 'securepoll-dump-not-finished' => 'Encrypted election records are only available after the finish date on $1 at $2',
118121 'securepoll-dump-no-urandom' => 'Cannot open /dev/urandom.
119122 To maintain voter privacy, encrypted election records are only publically available when they can be shuffled with a secure random number stream.',
 123+ 'securepoll-urandom-not-supported' => 'This server does not support cryptographic random number generation.
 124+To maintain voter privacy, encrypted election records are only publically available when they can be shuffled with a secure random number stream.',
120125
121126 # Translate page
122127 'securepoll-translate-title' => 'Translate: $1',
@@ -147,6 +152,11 @@
148153 'securepoll-tally-upload-submit' => 'Create tally',
149154 'securepoll-tally-error' => 'Error interpreting vote record, cannot produce a tally.',
150155 'securepoll-no-upload' => 'No file was uploaded, cannot tally results.',
 156+ 'securepoll-dump-corrupt' => 'The dump file is corrupt and cannot be processed.',
 157+ 'securepoll-tally-upload-error' => 'Error tallying dump file: $1',
 158+ 'securepoll-pairwise-victories' => 'Pairwise victory matrix',
 159+ 'securepoll-strength-matrix' => 'Path strength matrix',
 160+ 'securepoll-ranks' => 'Final ranking',
151161 );
152162
153163 /** Message documentation (Message documentation)
@@ -154,20 +164,27 @@
155165 * @author EugeneZelenko
156166 * @author Fryed-peach
157167 * @author IAlex
 168+ * @author Kiranmayee
158169 * @author Kwj2772
 170+ * @author Lloffiwr
159171 * @author Mormegil
160172 * @author Purodha
161173 * @author Raymond
 174+ * @author Saper
162175 * @author Siebrand
163176 */
164177 $messages['qqq'] = array(
165 - 'securepoll-desc' => 'A short description of this extension shown in [[Special:Version]].
166 -{{doc-important|Do not translate tag names.}}
167 -{{doc-important|Do not translate links.}}',
 178+ 'securepoll-desc' => '{{desc}}',
168179 'securepoll-not-started' => '* $2 is the date of it
169180 * $3 is its time.',
170181 'securepoll-return' => '{{Identical|Return to $1}}',
171 - 'securepoll-secret-gpg-error' => "<span style=\"color:red\">'''DO <u>NOT</u> translate LocalSettings.php and \$wgSecurePollShowErrorDetail=true;'''</span>",
 182+ 'securepoll-no-gpg-home' => 'GPG stands for [http://en.wikipedia.org/wiki/GNU_Privacy_Guard GNU Privacy Guard].',
 183+ 'securepoll-secret-gpg-error' => "<span style=\"color:red\">'''DO <u>NOT</u> translate LocalSettings.php and \$wgSecurePollShowErrorDetail=true;'''</span>
 184+
 185+GPG stands for [http://en.wikipedia.org/wiki/GNU_Privacy_Guard GNU Privacy Guard].",
 186+ 'securepoll-full-gpg-error' => 'GPG stands for [http://en.wikipedia.org/wiki/GNU_Privacy_Guard GNU Privacy Guard].',
 187+ 'securepoll-gpg-config-error' => 'GPG stands for [http://en.wikipedia.org/wiki/GNU_Privacy_Guard GNU Privacy Guard].',
 188+ 'securepoll-gpg-parse-error' => 'GPG stands for [http://en.wikipedia.org/wiki/GNU_Privacy_Guard GNU Privacy Guard].',
172189 'securepoll-header-timestamp' => '{{Identical|Time}}',
173190 'securepoll-header-voter-name' => '{{Identical|Name}}',
174191 'securepoll-header-ip' => '{{optional}}',
@@ -187,15 +204,22 @@
188205 'securepoll-invalid-vote' => 'The vote ID identifies a specific voting process.',
189206 'securepoll-header-id' => '{{optional}}',
190207 'securepoll-header-url' => '{{optional}}',
 208+ 'securepoll-header-action' => '{{Identical|Action}}',
191209 'securepoll-header-reason' => '{{Identical|Reason}}',
192210 'securepoll-cookie-dup-list' => 'Header of a list on [[Special:SecurePoll/details/1]]. The list shows duplicate voters detected by having a cookie from the first voting.',
193211 'securepoll-dump-not-finished' => '* $1 is the date
194212 * $2 is the time',
195 - 'securepoll-dump-no-urandom' => 'Do not translate "/dev/urandom".',
 213+ 'securepoll-dump-no-urandom' => 'Do not translate "/dev/urandom".
 214+
 215+Servers running Microsoft Windows will present [[MediaWiki:Securepoll-urandom-not-supported/en|Securepoll-urandom-not-supported]] instead.',
 216+ 'securepoll-urandom-not-supported' => "As to the meaning of ''cryptographic random number'', see [[:wikipedia:Cryptographically secure pseudorandom number generator]] for reference.
 217+
 218+The /dev/urandom cryptographic random number generation device is not supported on servers running Microsoft Windows. On other platforms the [[MediaWiki:Securepoll-dump-no-urandom/en|Securepoll-dump-no-urandom]] message is generated if opening of the /dev/urandom device fails.",
196219 'securepoll-translate-title' => '{{Identical|Translate}}',
197220 'securepoll-header-trans-id' => '{{optional}}',
198221 'securepoll-submit-select-lang' => '{{Identical|Translate}}',
199222 'securepoll-header-title' => '{{Identical|Name}}',
 223+ 'securepoll-subpage-vote' => 'వోటు',
200224 'securepoll-subpage-translate' => '{{Identical|Translate}}',
201225 );
202226
@@ -248,17 +272,18 @@
249273 'securepoll-no-decryption-key' => 'لا توجد مفاتيح فك شفرة مهيئة.
250274 لا يمكن فك الشفرة.',
251275 'securepoll-jump' => 'اذهب إلى خادم التصويت',
252 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
253 -تصويتك ليس صحيحا: $1
254 -</div>',
 276+ 'securepoll-bad-ballot-submission' => 'تصويتك ليس صحيحا: $1',
255277 'securepoll-unanswered-questions' => 'يجب أن تجيب على كل الأسئلة.',
 278+ 'securepoll-invalid-rank' => 'رتبة غير مقبولة. يجب أن تعطي المرشحين رتبة بين 1 و 999.',
 279+ 'securepoll-unranked-options' => 'لم يتم اعطاء رتبة لبعض الخيارات.
 280+يجب أن تعطي كل الخيارات رتبة ما بين 1 و 999.',
256281 'securepoll-remote-auth-error' => 'خطأ عند جلب معلومات حسابك من الخادوم.',
257282 'securepoll-remote-parse-error' => 'خطأ عند تفسير رد التصريح من الخادوم.',
258283 'securepoll-api-invalid-params' => 'محددات غير صحيحة.',
259284 'securepoll-api-no-user' => 'لم يوجد أي مستخدم بالهوية المعطاة.',
260285 'securepoll-api-token-mismatch' => 'نص الأمان لا يطابق، لا يمكن تسجيل الدخول.',
261286 'securepoll-not-logged-in' => 'يجب أن تدخل لتصوت في هذه الانتخابات',
262 - 'securepoll-too-few-edits' => 'عذرا، لا يمكنك التصويت. يجب أن تكون قد قمت ب$1 {{PLURAL:$1|تعديل|تعديل}} على الأقل لتصوت في هذه الانتخابات، أنت قمت ب$2.',
 287+ 'securepoll-too-few-edits' => 'عذرا لا يمكنك التصويت. يجب أن تقوم ب{{PLURAL:$1||تعديل واحد|تعديلين|$1 تعديلات|$1 تعديلًا|$1 تعديل}} على الأقل لتصوت في هذه الانتخابات، بينما قمت ب$2.',
263288 'securepoll-blocked' => 'عذرا، لا تستطيع التصويت في هذه الانتخابات إذا كنت ممنوعا حاليا من التعديل.',
264289 'securepoll-bot' => 'عذرا، الحسابات ذات أعلام البوت غير مسموح لها بالتصويت في هذه الانتخابات.',
265290 'securepoll-not-in-group' => 'فقط المستخدمين من المجموعة "$1" يمكنهم التصويت في هذه الانتخابات.',
@@ -276,6 +301,7 @@
277302 'securepoll-strike-reason' => 'السبب:',
278303 'securepoll-strike-cancel' => 'الغاء',
279304 'securepoll-strike-error' => 'خطأ اثناء القيام بالشطب/الغاء الشطب: $1',
 305+ 'securepoll-strike-token-mismatch' => 'فقدت بيانات الجلسة',
280306 'securepoll-details-link' => 'التفاصيل',
281307 'securepoll-details-title' => 'تفاصيل التصويت: #$1',
282308 'securepoll-invalid-vote' => '"$1" ليس رمز تعريف تصويت صحيح.',
@@ -291,6 +317,8 @@
292318 'securepoll-dump-not-finished' => 'سجلات الانتخابات المشفرة متاحة فقط بعد تاريخ الانتهاء في $1 ب $2',
293319 'securepoll-dump-no-urandom' => 'لا يمكن فتح /dev/urandom.
294320 للحفاظ على خصوصية المصوتين، سجلات الانتخابات المشفرة تتاح على الملأ عندما يمكن خلطهم عن طريق سيل ارقام عشوائية آمن.',
 321+ 'securepoll-urandom-not-supported' => 'هذا الخادم لا يدعم توليد أرقام عن طريق الترميز العشوائي.
 322+للحفاظ على خصوصية الناخبين ، سجلات الانتخابات المشفرة ليست متاحة علانية الا عندما يمكن خلطهم عن طريق دفق رقمي عشوائي آمن .',
295323 'securepoll-translate-title' => 'ترجم: $1',
296324 'securepoll-invalid-language' => 'كود لغة غير صحيح "$1"',
297325 'securepoll-submit-translate' => 'تحديث',
@@ -315,8 +343,19 @@
316344 'securepoll-tally-upload-submit' => 'أنشئ محصلة',
317345 'securepoll-tally-error' => 'خطأ في تفسير سجل التصويت، تعذّر توليد محصلة.',
318346 'securepoll-no-upload' => 'لم يرفع ملف، تعذّر تحصيل النتائج.',
 347+ 'securepoll-dump-corrupt' => 'ملف التفريغ تالف و لا يمكن معالجته.',
 348+ 'securepoll-tally-upload-error' => 'خطأ أثناء فرز ملف التفريغ: $1',
319349 );
320350
 351+/** Aramaic (ܐܪܡܝܐ)
 352+ * @author Basharh
 353+ */
 354+$messages['arc'] = array(
 355+ 'securepoll-strike-reason' => 'ܥܠܬܐ:',
 356+ 'securepoll-strike-cancel' => 'ܒܛܘܠ',
 357+ 'securepoll-header-reason' => 'ܥܠܬܐ',
 358+);
 359+
321360 /** Belarusian (Taraškievica orthography) (Беларуская (тарашкевіца))
322361 * @author EugeneZelenko
323362 * @author Jim-by
@@ -366,6 +405,9 @@
367406 'securepoll-jump' => 'Перайсьці на сэрвэр галасаваньня',
368407 'securepoll-bad-ballot-submission' => 'Ваш голас ня быў залічаны: $1',
369408 'securepoll-unanswered-questions' => 'Вам неабходна адказаць на ўсе пытаньні.',
 409+ 'securepoll-invalid-rank' => 'Няслушны ранг. Вам неабходна даць кандыдатам ранг паміж 1 і 999.',
 410+ 'securepoll-unranked-options' => 'Некаторыя пункты ня маюць рангу.
 411+Вам неабходна даць усім пунктам ранг паміж 1 і 999.',
370412 'securepoll-remote-auth-error' => 'Памылка атрыманьня інфармацыі пра Ваш рахунак з сэрвэра.',
371413 'securepoll-remote-parse-error' => 'Памылка інтэрпрэтацыі адказу аўтарызацыі з сэрвэра.',
372414 'securepoll-api-invalid-params' => 'Няслушныя парамэтры.',
@@ -390,6 +432,7 @@
391433 'securepoll-strike-reason' => 'Прычына:',
392434 'securepoll-strike-cancel' => 'Адмяніць',
393435 'securepoll-strike-error' => 'Памылка пад час закрэсьліваньня/адкрэсьліваньня: $1',
 436+ 'securepoll-strike-token-mismatch' => 'Зьвесткі сэсіі страчаныя',
394437 'securepoll-details-link' => 'Падрабязнасьці',
395438 'securepoll-details-title' => 'Падрабязнасьці галасаваньня: #$1',
396439 'securepoll-invalid-vote' => '«$1» не зьяўляецца слушным ідэнтыфікатарам голасу',
@@ -405,6 +448,8 @@
406449 'securepoll-dump-not-finished' => 'Зашыфраваныя выбарчыя запісы даступны толькі пасьля $1 у $2.',
407450 'securepoll-dump-no-urandom' => 'Не магчыма адкрыць /dev/urandom.
408451 Каб захаваць прыватнасьць галасоў, зашыфраваныя выбарчыя запісы будуць даступныя для грамадзкасьці, толькі калі іх парадак будуць будзе зьменены з дапамогай бясьпечнай крыніцы выпадковых лікаў.',
 452+ 'securepoll-urandom-not-supported' => 'Гэты сэрвэр не падтрымлівае генэрацыю крыптаграфічных выпадковых лікаў.
 453+У мэтах захаваньня прыватнасьці галасаваўшых, зашыфраваныя запісы выбараў будуць агульнадаступнымі толькі калі яны могуць быць зьмешаныя са струменем выпадковых лікаў.',
409454 'securepoll-translate-title' => 'Пераклад: $1',
410455 'securepoll-invalid-language' => 'Няслушны код мовы «$1»',
411456 'securepoll-submit-translate' => 'Абнавіць',
@@ -429,6 +474,8 @@
430475 'securepoll-tally-upload-submit' => 'Падлічыць',
431476 'securepoll-tally-error' => 'Памылка інтэрпрэтацыі запісу голасу, немагчыма падлічыць.',
432477 'securepoll-no-upload' => 'Файл не загружаны, немагчыма падлічыць.',
 478+ 'securepoll-dump-corrupt' => 'Вывадны файл пашкоджаны і ня можа быць апрацаваны.',
 479+ 'securepoll-tally-upload-error' => 'Памылка цэласнасьці вываднога файла: $1',
433480 );
434481
435482 /** Bulgarian (Български)
@@ -501,6 +548,9 @@
502549 'securepoll-jump' => 'Idi na server za glasanje',
503550 'securepoll-bad-ballot-submission' => 'Vaš glas nije valjan: $1',
504551 'securepoll-unanswered-questions' => 'Morate odgovoriti na sva pitanja.',
 552+ 'securepoll-invalid-rank' => 'Nevaljan rang. Morate dati kandidatima rang između 1 i 999.',
 553+ 'securepoll-unranked-options' => 'Neke opcije nisu rangirane.
 554+Morate dati svim opcijama rang između 1 i 999.',
505555 'securepoll-remote-auth-error' => 'Greška pri preuzimanju podataka o Vašem računu sa servera.',
506556 'securepoll-remote-parse-error' => 'Greška pri interpretaciji autentifikacijskog odgovora sa servera.',
507557 'securepoll-api-invalid-params' => 'Nevaljani parametri.',
@@ -525,6 +575,7 @@
526576 'securepoll-strike-reason' => 'Razlog:',
527577 'securepoll-strike-cancel' => 'Odustani',
528578 'securepoll-strike-error' => 'Greška izvšavanja precrtavanja/uklanjanja: $1',
 579+ 'securepoll-strike-token-mismatch' => 'Izgubljeni podaci sesije',
529580 'securepoll-details-link' => 'Detalji',
530581 'securepoll-details-title' => 'Detalji glasanja: #$1',
531582 'securepoll-invalid-vote' => '"$1" nije valjan glasački ID',
@@ -539,6 +590,8 @@
540591 'securepoll-dump-no-crypt' => 'Ne postoji dešifrirana varijanta ovog izbora, zato što izbor nije konfiguriran za korištenje šifriranja.',
541592 'securepoll-dump-not-finished' => 'Dešifrirani rezultati izbora su vidljivi tek poslije datuma završetka izbora $1 u $2 sati',
542593 'securepoll-dump-no-urandom' => 'Da bi se sačuvala privatnost glasača, dešifrirani rezultati glasanja su dostupni kada bude dostupna mogućnost prenosa slučajnim izborom brojki.',
 594+ 'securepoll-urandom-not-supported' => 'Ovaj server ne podržava generisanje kriptografskih nasumičnih brojeva.
 595+Da bi se zadržala privatnost glasača, šifrirani podaci o izborima su dostupni javno kada se mogu izmiješati putem sigurnog toka nasumičnih brojeva.',
543596 'securepoll-translate-title' => 'Prevedi: $1',
544597 'securepoll-invalid-language' => 'Pogrešan kod jezika "$1"',
545598 'securepoll-submit-translate' => 'Ažuriranje',
@@ -563,9 +616,13 @@
564617 'securepoll-tally-upload-submit' => 'Napravi prebrojavanje',
565618 'securepoll-tally-error' => 'Greška pri interpretaciji zapisa glasanja, ne može se izvršiti prebrojavanje.',
566619 'securepoll-no-upload' => 'Nijedna datoteka nije postavljena, ne mogu se prebrojati rezultati.',
 620+ 'securepoll-dump-corrupt' => 'Dump datoteka je pokvarena i ne može biti obrađena.',
 621+ 'securepoll-tally-upload-error' => 'Greška pri ažuriranju dump datoteke: $1',
567622 );
568623
569624 /** Catalan (Català)
 625+ * @author Cbrown1023
 626+ * @author Góngora
570627 * @author Jordi Roqué
571628 * @author SMP
572629 * @author Vriullop
@@ -599,34 +656,52 @@
600657 El vostre vot no ha estat enregistrat!
601658
602659 $1",
 660+ 'securepoll-no-gpg-home' => 'No es pot crear el directori de GPG.',
 661+ 'securepoll-secret-gpg-error' => 'Error en l\'execució de GPG.
 662+Useu $wgSecurePollShowErrorDetail=true; al LocalSettings.php per a mostrar més detalls.',
 663+ 'securepoll-full-gpg-error' => "Error en l'execució del GPG:
 664+
 665+Comanda: $1
 666+
 667+Error:
 668+<pre>$2</pre>",
 669+ 'securepoll-gpg-config-error' => 'Les claus GPG estan mal configurades.',
603670 'securepoll-gpg-parse-error' => 'Error en la interpretació de la sortida de GPG',
604671 'securepoll-no-decryption-key' => 'No està configurada la clau de desxifrat.
605672 No es pot desencriptar.',
606673 'securepoll-jump' => 'Tornar al servidor de votació',
607674 'securepoll-bad-ballot-submission' => 'El vostre vot no és vàlid: $1',
608675 'securepoll-unanswered-questions' => 'Heu de respondre totes les qüestions.',
 676+ 'securepoll-invalid-rank' => "Rang no vàlid.
 677+Heu d'introduir a cada candidat un valor entre 1 i 999.",
 678+ 'securepoll-unranked-options' => 'Algunes opcions no han estat qualificades.
 679+Heu de donar a totes les opcions, un rang entre 1 i 999.',
609680 'securepoll-remote-auth-error' => "S'ha produit un eror en recuperar del servidor la informació del vostre compte .",
610681 'securepoll-remote-parse-error' => "S'ha produit un error en la recepció de la resposta d'autorització des del servidor.",
611682 'securepoll-api-invalid-params' => 'Paràmetres invàlids.',
612683 'securepoll-api-no-user' => "No s'ha trobat cap usuari amb aquesta identificació.",
 684+ 'securepoll-api-token-mismatch' => "El token de seguretat no coincideix. No s'ha pogut accedir.",
613685 'securepoll-not-logged-in' => "Heu d'estar connectats en un compte per a votar en aquesta elecció",
614686 'securepoll-too-few-edits' => "Ho sentim, però no podeu votar.
615687 Per a votar en aquesta elecció cal haver fet un mínim {{PLURAL:$1|d'una edició|de $1 edicions}}, i n'heu fet $2.",
616688 'securepoll-blocked' => "Ho sentim però no podeu votar en aquesta elecció perquè el vostre compte està blocat a l'edició.",
617 - 'securepoll-bot' => 'Excuses, però els comptes de bot no poden votar en aquesta elecció.',
 689+ 'securepoll-bot' => 'Ho sentim, però els comptes de bot no poden votar en aquestes eleccions.',
618690 'securepoll-not-in-group' => 'Només els membres del grup «$1» poden votar en aquesta elecció.',
619691 'securepoll-not-in-list' => 'Ho sentim, però no esteu en la llista dels usuaris autoritzats a votar en aquesta elecció.',
620692 'securepoll-list-title' => 'Llista de vots: $1',
621693 'securepoll-header-timestamp' => 'Hora',
622694 'securepoll-header-voter-name' => 'Nom',
623695 'securepoll-header-voter-domain' => 'Domini',
 696+ 'securepoll-header-ua' => '<em>Useragent</em>',
 697+ 'securepoll-header-cookie-dup' => 'Duplicat',
624698 'securepoll-header-strike' => 'Anuŀlació',
625699 'securepoll-header-details' => 'Detalls',
626700 'securepoll-strike-button' => 'Anuŀla',
627701 'securepoll-unstrike-button' => "Desfés l'anuŀlació",
628702 'securepoll-strike-reason' => 'Motiu:',
629703 'securepoll-strike-cancel' => 'Canceŀla',
630 - 'securepoll-strike-error' => "Error en anul·lar o en desfer l'anul·lació: $1",
 704+ 'securepoll-strike-error' => "Error en anuŀlar o en desfer l'anuŀlació: $1",
 705+ 'securepoll-strike-token-mismatch' => 'Pèrdua de dades de la sessió',
631706 'securepoll-details-link' => 'Detalls',
632707 'securepoll-details-title' => 'Detalls de vot: #$1',
633708 'securepoll-invalid-vote' => '«$1» no és una ID de vot vàlida',
@@ -636,10 +711,14 @@
637712 'securepoll-header-action' => 'Acció',
638713 'securepoll-header-reason' => 'Motiu',
639714 'securepoll-header-admin' => 'Administrador',
 715+ 'securepoll-cookie-dup-list' => 'Usuaris amb galetes duplicades',
 716+ 'securepoll-dump-title' => 'Abocament: $1',
640717 'securepoll-dump-no-crypt' => 'No existeix cap registre encriptat en aquesta elecció perquè no està configurada per usar encriptació.',
641718 'securepoll-dump-not-finished' => "Els registres encriptats de l'elecció només estaran disponibles després de la seva conclusió, a $1 del $2",
642719 'securepoll-dump-no-urandom' => "No es pot obrir /dev/urandom.
643720 Per mantenir la privacitat dels votants, els registres encriptats de l'elecció es fan públics només quan poden ser barrejats amb un generador segur de nombres aleatoris.",
 721+ 'securepoll-urandom-not-supported' => "Aquest servidor no suporta la generació criptogràfica de nombres aleatoris.
 722+Per mantenir la privacitat del votant, els registres d'elecció encriptats només són públicament disponibles quan es poden emetre amb un flux segur de nombres aleatoris.",
644723 'securepoll-translate-title' => 'Traducció: $1',
645724 'securepoll-invalid-language' => "Codi d'idioma «$1» no vàlid",
646725 'securepoll-submit-translate' => 'Actualitza',
@@ -651,14 +730,21 @@
652731 'securepoll-subpage-vote' => 'Votació',
653732 'securepoll-subpage-translate' => 'Traducció',
654733 'securepoll-subpage-list' => 'Llista',
655 - 'securepoll-tally-not-finished' => 'Excuses, les dades de la votació no estaran disponibles fins que hagi finalitzat.',
 734+ 'securepoll-subpage-dump' => 'Abocament',
 735+ 'securepoll-subpage-tally' => 'Compte',
 736+ 'securepoll-tally-title' => 'Compte: $1',
 737+ 'securepoll-tally-not-finished' => 'Les dades de la votació no estaran disponibles fins que hagi finalitzat.',
656738 'securepoll-can-decrypt' => "El registre de l'elecció ha estat encriptat, però la clau de desxifratge està disponible.
657739 Podeu triar entre comptar els resultats presents a la base de dades, o de comptar-ne els encriptats a partir d'un fitxer carregat.",
658740 'securepoll-tally-no-key' => "No podeu comptar els vots d'aquesta elecció, perquè estan encriptats i la clau de desxifratge no està disponible.",
659741 'securepoll-tally-local-legend' => 'Comptar els resultats arxivats.',
660742 'securepoll-tally-local-submit' => 'Comptar els vots.',
 743+ 'securepoll-tally-upload-legend' => 'Carrega un abocament encriptat',
 744+ 'securepoll-tally-upload-submit' => 'Crea un compte',
661745 'securepoll-tally-error' => "Error en interpretar l'arxiu de votació, no es poden comptar els resultats.",
662746 'securepoll-no-upload' => "No s'ha carregat cap arxiu, no s'en poden comptar els resultats.",
 747+ 'securepoll-dump-corrupt' => 'El fitxer bolcat es troba danyat i no pot ser processat.',
 748+ 'securepoll-tally-upload-error' => 'Error al contar el fitxer bolcat: $1',
663749 );
664750
665751 /** Czech (Česky)
@@ -709,6 +795,9 @@
710796 'securepoll-jump' => 'Přejít na hlasovací server',
711797 'securepoll-bad-ballot-submission' => 'Váš hlas je neplatný: $1',
712798 'securepoll-unanswered-questions' => 'Musíte zodpovědět všechny otázky.',
 799+ 'securepoll-invalid-rank' => 'Neplatné pořadí. Kandidátům musíte přidělit pořadí mezi 1 a 999.',
 800+ 'securepoll-unranked-options' => 'Některé možnosti nebyly ohodnoceny.
 801+Musíte všem možnostem přidělit pořadí mezi 1 a 999.',
713802 'securepoll-remote-auth-error' => 'Při čtení informací o vašem uživatelském účtu ze serveru nastala chyba.',
714803 'securepoll-remote-parse-error' => 'Při zpracovávání autorizační odpovědi od serveru nastala chyba.',
715804 'securepoll-api-invalid-params' => 'Chybné parametry.',
@@ -733,6 +822,7 @@
734823 'securepoll-strike-reason' => 'Důvod:',
735824 'securepoll-strike-cancel' => 'Storno',
736825 'securepoll-strike-error' => 'Nepodařilo se provést přeškrtnutí či jeho zrušení: $1',
 826+ 'securepoll-strike-token-mismatch' => 'Data z relace byla ztracena',
737827 'securepoll-details-link' => 'Podrobnosti',
738828 'securepoll-details-title' => 'Podrobnosti hlasu #$1',
739829 'securepoll-invalid-vote' => '„$1“ není platný identifikátor hlasu',
@@ -748,6 +838,8 @@
749839 'securepoll-dump-not-finished' => 'Šifrovaný záznam hlasování bude k dispozici až po skončení voleb, $1, $2',
750840 'securepoll-dump-no-urandom' => 'Nelze otevřít <tt>/dev/urandom</tt>.
751841 Kvůli tajnosti hlasování je šifrovaný záznam hlasování veřejně dostupný pouze v případě, že hlasy mohou být zamíchány pomocí bezpečného zdroje náhodných čísel.',
 842+ 'securepoll-urandom-not-supported' => 'Tento server nepodporuje kryptografické generování náhodných čísel.
 843+Kvůli tajnosti hlasování je šifrovaný záznam hlasování veřejně dostupný pouze v případě, že hlasy mohou být zamíchány pomocí bezpečného zdroje náhodných čísel.',
752844 'securepoll-translate-title' => 'Překlad – $1',
753845 'securepoll-invalid-language' => 'Neplatný kód jazyka „$1“',
754846 'securepoll-submit-translate' => 'Uložit',
@@ -772,6 +864,8 @@
773865 'securepoll-tally-upload-submit' => 'Provést sčítání',
774866 'securepoll-tally-error' => 'Chyba při zpracovávání záznamu hlasování, hlasování nelze sečíst.',
775867 'securepoll-no-upload' => 'Nebyl načten žádný soubor, hlasování nelze sečíst.',
 868+ 'securepoll-dump-corrupt' => 'Soubor se záznamem je poškozený a nelze ho zpracovat.',
 869+ 'securepoll-tally-upload-error' => 'Chyba při sčítání záznamu: $1',
776870 );
777871
778872 /** Welsh (Cymraeg)
@@ -820,10 +914,11 @@
821915 'securepoll-no-decryption-key' => "Nid yw'r allwedd dadgryptio wedi ei ffurfweddu.
822916 Ni ellir dadgryptio.",
823917 'securepoll-jump' => 'Mynd i weinydd y pleidleisio',
824 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
825 -Nid oedd eich pleidlais yn ddilys: $1
826 -</div>',
 918+ 'securepoll-bad-ballot-submission' => 'Nid oedd eich pleidlais yn ddilys: $1',
827919 'securepoll-unanswered-questions' => 'Rhaid ateb pob cwestiwn.',
 920+ 'securepoll-invalid-rank' => "Gradd annilys yn y drefn restrol. Rhaid ichi roi gradd rhwng 1 a 999 i'r ymgeiswyr.",
 921+ 'securepoll-unranked-options' => 'Gadawyd rhai dewisiadau heb eu rhestru.
 922+Rhaid ichi roi gradd rhwng 1 a 999 i bob dewis.',
828923 'securepoll-remote-auth-error' => "Cafwyd gwall wrth nôl gwybodaeth eich cyfrif o'r gweinydd.",
829924 'securepoll-remote-parse-error' => "Cafwyd gwall wrth ddehongli ymateb y gweinydd i'r cais awdurdodi.",
830925 'securepoll-api-invalid-params' => 'Paramedrau annilys.',
@@ -848,6 +943,7 @@
849944 'securepoll-strike-reason' => 'Rheswm:',
850945 'securepoll-strike-cancel' => 'Canslo',
851946 'securepoll-strike-error' => 'Gwall wrth geisio annilysu/ail-ddilysu: $1',
 947+ 'securepoll-strike-token-mismatch' => "Collwyd data'r sesiwn",
852948 'securepoll-details-link' => 'Manylion',
853949 'securepoll-details-title' => 'Manylion y bleidlais: #$1',
854950 'securepoll-invalid-vote' => 'Nid yw "$1" yn ID dilys ar gyfer y bleidlais',
@@ -863,6 +959,8 @@
864960 'securepoll-dump-not-finished' => "Ni fydd y cofnodion amgryptiedig o'r etholiad ar gael hyd at ddiwedd yr etholiad am $2 ar $1",
865961 'securepoll-dump-no-urandom' => "Ni ellir agor /dev/urandom.
866962 Er mwyn diogelu cyfrinachedd pleidleiswyr, nid yw cofnodion yr etholiad ar gael i'r cyhoedd ond pan y gellir eu cymysgu trwy ddefnyddio llif haprifau diogel.",
 963+ 'securepoll-urandom-not-supported' => "Nid yw'r gweinydd hwn yn gallu cynhyrchu haprifau ar gyfer amgryptio.
 964+Er mwyn diogelu cyfrinachedd y pleidleiswyr, nid yw cofnodion amgryptiedig yr etholiad ar gael i'r cyhoedd ond pan fo modd eu cymysgu'n ddi-ôl trwy ddefnyddio ffrwd diogel o haprifau.",
867965 'securepoll-translate-title' => 'Cyfieithu: $1',
868966 'securepoll-invalid-language' => 'Côd iaith annilys, "$1"',
869967 'securepoll-submit-translate' => 'Diweddaru',
@@ -887,10 +985,13 @@
888986 'securepoll-tally-upload-submit' => 'Cadw cyfrif',
889987 'securepoll-tally-error' => "Cafwyd gwall wrth ddehongli'r cofnod pleidleisio, ni ellir cadw cyfrif.",
890988 'securepoll-no-upload' => 'Ni uwchlwythwyd unrhyw ffeil, ni ellir cyfrif y canlyniadau.',
 989+ 'securepoll-dump-corrupt' => 'Mae ffeil y dymp yn llygredig ac ni ellir weithredu arno.',
 990+ 'securepoll-tally-upload-error' => 'Cafwyd gwall wrth gyfrif y ffeil dymp: $1',
891991 );
892992
893993 /** Danish (Dansk)
894994 * @author Kaare
 995+ * @author Masz
895996 * @author Sir48
896997 */
897998 $messages['da'] = array(
@@ -902,7 +1003,8 @@
9031004 'securepoll-invalid-election' => '"$1" er ikke en gyldig valg-id.',
9041005 'securepoll-welcome' => '<strong>Velkommen $1!</strong>',
9051006 'securepoll-not-started' => 'Dette valg er endnu ikke begyndt.
906 -Det er planlagt til at begynde den $1.',
 1007+Det er planlagt til at begynde den $2 klokken $3.',
 1008+ 'securepoll-finished' => 'Dette valg er afsluttet, du kan ikke længere stemme.',
9071009 'securepoll-not-qualified' => 'Du er kvalificeret til at afgive din stemme ved dette valg: $1',
9081010 'securepoll-change-disallowed' => 'Du har allerede afgivet din stemme ved dette valg.
9091011 Desværre kan du ikke stemme igen.',
@@ -934,11 +1036,29 @@
9351037 'securepoll-gpg-parse-error' => 'Fejl ved fortolkning af uddata fra GPG.',
9361038 'securepoll-no-decryption-key' => 'Ingen dekrypteringsnøgle opsat.
9371039 Kan ikke dekryptere.',
 1040+ 'securepoll-jump' => 'Gå til stemmeserveren',
 1041+ 'securepoll-bad-ballot-submission' => 'Din stemme var ugyldig: $1',
 1042+ 'securepoll-unanswered-questions' => 'Du skal besvare alle spørgsmålene.',
 1043+ 'securepoll-invalid-rank' => 'Ugyldig rangorden. Du skal give kandidaterne en rangorden mellem 1 og 999.',
 1044+ 'securepoll-unranked-options' => 'Nogle muligheder blev ikke rangordnet.
 1045+Du skal give alle muligheder en rangordning mellem 1 og 999.',
 1046+ 'securepoll-remote-auth-error' => 'Der opstod en fejl under hentning af dine kontoinformationer fra serveren.',
 1047+ 'securepoll-remote-parse-error' => 'Der opstod en fejl under læsning af autorisationssvarene fra serveren.',
 1048+ 'securepoll-api-invalid-params' => 'Ugyldige parametere.',
 1049+ 'securepoll-api-no-user' => 'Ingen brugere med den angivne ID blev fundet.',
 1050+ 'securepoll-api-token-mismatch' => 'Sikkerhedskoden er forkert, du kan ikke logge ind.',
 1051+ 'securepoll-not-logged-in' => 'Du skal logge ind for at stemme i dette valg',
 1052+ 'securepoll-too-few-edits' => 'Beklager, men du kan ikke stemme. Du skal lave mindst $1 {{PLURAL:$1|redigering|redigeringer}}. Du har kun lavet $2.',
 1053+ 'securepoll-blocked' => 'Du kan ikke stemme, fordi du i øjeblikket er blokeret fra at redigere.',
 1054+ 'securepoll-bot' => 'Beklager, men konti med botflag kan ikke stemme i dette valg.',
 1055+ 'securepoll-not-in-group' => 'Kun brugere af gruppen "$1" kan stemme.',
 1056+ 'securepoll-not-in-list' => 'Du er desværre ikke på listen over brugere, som kan stemme i dette valg.',
9381057 'securepoll-list-title' => 'Vis stemmer: $1',
9391058 'securepoll-header-timestamp' => 'Tid',
9401059 'securepoll-header-voter-name' => 'Navn',
9411060 'securepoll-header-voter-domain' => 'Domæne',
9421061 'securepoll-header-ua' => 'Useragent',
 1062+ 'securepoll-header-cookie-dup' => 'Dublet',
9431063 'securepoll-header-strike' => 'Fjern',
9441064 'securepoll-header-details' => 'Oplysninger',
9451065 'securepoll-strike-button' => 'Fjern',
@@ -946,6 +1066,7 @@
9471067 'securepoll-strike-reason' => 'Årsag:',
9481068 'securepoll-strike-cancel' => 'Annuller',
9491069 'securepoll-strike-error' => 'Fejl ved fjernelse eller ophævelse af fjernelse: $1',
 1070+ 'securepoll-strike-token-mismatch' => 'Sessionsdata mistet',
9501071 'securepoll-details-link' => 'Oplysninger',
9511072 'securepoll-details-title' => 'Valgoplysninger: #$1',
9521073 'securepoll-invalid-vote' => '"$1" er ikke en gyldig valg-id',
@@ -955,21 +1076,46 @@
9561077 'securepoll-header-action' => 'Handling',
9571078 'securepoll-header-reason' => 'Årsag',
9581079 'securepoll-header-admin' => 'Admin',
 1080+ 'securepoll-cookie-dup-list' => 'Cooke-dubletbrugere',
9591081 'securepoll-dump-title' => 'Dump: $1',
9601082 'securepoll-dump-no-crypt' => 'Ingen krypterede valgregistreringer er tilgængelige til dette valg, fordi valget ikke er opsat til at anvende kryptering.',
961 - 'securepoll-dump-not-finished' => 'Krypterede valgregistreringer er kun tilgængelige efter den sidste valgdag: $1',
 1083+ 'securepoll-dump-not-finished' => 'Krypterede valgregistreringer er kun tilgængelige efter afstemningen den $1 klokken $2.',
9621084 'securepoll-dump-no-urandom' => 'Kan ikke åbne /dev/urandom.
9631085 For at sikre en hemmelig afstemning er de krypterede valgregistrering kun offentligt tilgængelige, når de kan blandes med en sikker strøm af tilfældige tal.',
 1086+ 'securepoll-urandom-not-supported' => 'Denne server understøtter ikke generering af tilfældige kryptografiske tal.
 1087+For at vedligeholde personlige oplysninger om vælgeren, er krypterede valgregistreringer kun offentligt tilgængelige, når de kan blandes med en strøm af sikre tilfældige tal.',
9641088 'securepoll-translate-title' => 'Oversæt: $1',
9651089 'securepoll-invalid-language' => 'Ugyldig sprogkode "$1"',
9661090 'securepoll-submit-translate' => 'Opdater',
9671091 'securepoll-language-label' => 'Vælg sprog:',
9681092 'securepoll-submit-select-lang' => 'Oversæt',
 1093+ 'securepoll-header-title' => 'Navn',
 1094+ 'securepoll-header-start-date' => 'Startsdato',
 1095+ 'securepoll-header-end-date' => 'Slutsdato',
 1096+ 'securepoll-subpage-vote' => 'Stem',
 1097+ 'securepoll-subpage-translate' => 'Oversæt',
 1098+ 'securepoll-subpage-list' => 'Liste',
 1099+ 'securepoll-subpage-dump' => 'Dump',
 1100+ 'securepoll-subpage-tally' => 'Optælling',
 1101+ 'securepoll-tally-title' => 'Optælling: $1',
 1102+ 'securepoll-tally-not-finished' => 'Du kan desværre ikke optælle valgresultatet før afstemningen er slut.',
 1103+ 'securepoll-can-decrypt' => 'Valgregisteret er blevet krypteret, men en dekrypteringsnøgle er tilgængelig.
 1104+Du kan enten optælle de nuværende stemmer i databasen, eller optælle krypterede resultater fra et oplagt fil.',
 1105+ 'securepoll-tally-no-key' => 'Du kan ikke tælle resultatet op, fordi stemmerne er krypterede, og dekrypteringsnøglen er utilgængelig.',
 1106+ 'securepoll-tally-local-legend' => 'Optællig af stemmerne',
 1107+ 'securepoll-tally-local-submit' => 'Opret en optælling',
 1108+ 'securepoll-tally-upload-legend' => 'Læg en krypteret dump op',
 1109+ 'securepoll-tally-upload-submit' => 'Opret optælling',
 1110+ 'securepoll-tally-error' => 'Fejl under læsning af stemmeregisteret, kan ikke oprette en optælling.',
 1111+ 'securepoll-no-upload' => 'Ingen fil blev lagt op; kan ikke tælle resultatet op.',
 1112+ 'securepoll-dump-corrupt' => 'Dumpfilen er korrupt og kan ikke behandles.',
 1113+ 'securepoll-tally-upload-error' => 'Fejl ved optælling af dumpfilen: $1',
9691114 );
9701115
9711116 /** German (Deutsch)
9721117 * @author ChrisiPK
9731118 * @author Metalhead64
 1119+ * @author Pill
9741120 * @author Umherirrender
9751121 */
9761122 $messages['de'] = array(
@@ -1017,6 +1163,9 @@
10181164 'securepoll-jump' => 'Gehe zum Abstimmungsserver',
10191165 'securepoll-bad-ballot-submission' => 'Deine Stimme war ungültig: $1',
10201166 'securepoll-unanswered-questions' => 'Du musst alle Fragen beantworten.',
 1167+ 'securepoll-invalid-rank' => 'Ungültige Rangfolge. Du musst den Kandidaten eine Rangnummer zwischen 1 und 999 geben.',
 1168+ 'securepoll-unranked-options' => 'Einige Optionen wurden nicht mit einer Rangnummer versehen.
 1169+Du musst allen Optionen eine Rangnummer zwischen 1 und 999 geben.',
10211170 'securepoll-remote-auth-error' => 'Fehler beim Abruf deiner Benutzerkonteninformationen vom Server.',
10221171 'securepoll-remote-parse-error' => 'Fehler beim Interpretieren der Berechtigungsantwort des Servers.',
10231172 'securepoll-api-invalid-params' => 'Ungültige Parameter.',
@@ -1041,6 +1190,7 @@
10421191 'securepoll-strike-reason' => 'Grund:',
10431192 'securepoll-strike-cancel' => 'Abbrechen',
10441193 'securepoll-strike-error' => 'Fehler bei der Streichung/Streichungsrücknahme: $1',
 1194+ 'securepoll-strike-token-mismatch' => 'Sitzungsdaten verloren',
10451195 'securepoll-details-link' => 'Details',
10461196 'securepoll-details-title' => 'Abstimmungsdetails: #$1',
10471197 'securepoll-invalid-vote' => '„$1“ ist keine gültige Abstimmungs-ID',
@@ -1056,6 +1206,8 @@
10571207 'securepoll-dump-not-finished' => 'Verschlüsselte Abstimmungsaufzeichnungen sind nur nach dem Endtermin am $1 um $2 Uhr verfügbar',
10581208 'securepoll-dump-no-urandom' => '/dev/urandom kann nicht geöffnet werden.
10591209 Um den Wählerdatenschutz zu wahren, sind verschlüsselte Abstimmungsaufzeichnungen nur öffentlich verfügbar, wenn sie mit einem sicheren Zufallszahlenstrom gemischt werden können.',
 1210+ 'securepoll-urandom-not-supported' => 'Dieser Server unterstützt keine kryptographische Zufallszahlenerzeugung.
 1211+Zur Sicherstellung des Wahlgeheimnisses sind verschlüsselte Wahlaufzeichnungen nur öffentlich verfügbar, sofern sie mit einer sicheren Zufallszahlenreihenfolge vermischt werden konnten.',
10601212 'securepoll-translate-title' => 'Übersetzen: $1',
10611213 'securepoll-invalid-language' => 'Ungültiger Sprachcode „$1“',
10621214 'securepoll-submit-translate' => 'Aktualisieren',
@@ -1080,6 +1232,10 @@
10811233 'securepoll-tally-upload-submit' => 'Zählung erstellen',
10821234 'securepoll-tally-error' => 'Fehler beim Interpretieren der Abstimmungsaufzeichnung, Auszählungserstellung nicht möglich.',
10831235 'securepoll-no-upload' => 'Es wurde keine Datei hochgeladen, Ergebniszählung nicht möglich.',
 1236+ 'securepoll-dump-corrupt' => 'Die Dump-Datei ist korrupt und kann nicht verarbeitet werden.',
 1237+ 'securepoll-tally-upload-error' => 'Fehler beim Zählen der Dump-Datei: $1',
 1238+ 'securepoll-pairwise-victories' => 'Paarweise Siegesmatrix',
 1239+ 'securepoll-ranks' => 'Schlussranking',
10841240 );
10851241
10861242 /** German (formal address) (Deutsch (Sie-Form))
@@ -1164,6 +1320,9 @@
11651321 'securepoll-jump' => 'K serweroju wótgłosowanja',
11661322 'securepoll-bad-ballot-submission' => 'Twój głos jo njepłaśiwy był: $1',
11671323 'securepoll-unanswered-questions' => 'Musyš na wše pšašanja wótegroniś.',
 1324+ 'securepoll-invalid-rank' => 'Njepłaśiwe pódaśe pozicije. Dejš kandidatam poziciju mjazy 1 a 999 daś.',
 1325+ 'securepoll-unranked-options' => 'Někotare opcije njamaju pódaśe pozicije.
 1326+Dejš wšyknym opcijam pódaśe pozicije mjazy 1 a 999 daś.',
11681327 'securepoll-remote-auth-error' => 'Zmólka pśi wótwołowanju twójich kontowych informacijow ze serwera.',
11691328 'securepoll-remote-parse-error' => 'Zmólka pśi interpretěrowanju awtorizěrowańskego wótegrona serwera.',
11701329 'securepoll-api-invalid-params' => 'Njepłaśiwe parametry.',
@@ -1188,6 +1347,7 @@
11891348 'securepoll-strike-reason' => 'Pśicyna:',
11901349 'securepoll-strike-cancel' => 'Pśetergnuś',
11911350 'securepoll-strike-error' => 'Zmólka pśi wušmarnjenju/anulěrowanju wušmarnjenja: $1',
 1351+ 'securepoll-strike-token-mismatch' => 'Daty pósejźenja su se zgubili',
11921352 'securepoll-details-link' => 'Drobnostki',
11931353 'securepoll-details-title' => 'Wótgłosowańske drobnostki: #$1',
11941354 'securepoll-invalid-vote' => '"$1" njejo płaśiwy wótgłosowański ID',
@@ -1230,11 +1390,14 @@
12311391 );
12321392
12331393 /** Greek (Ελληνικά)
 1394+ * @author Assassingr
 1395+ * @author Badseed
12341396 * @author Consta
12351397 * @author Crazymadlover
12361398 * @author Geraki
12371399 * @author Omnipaedista
12381400 * @author ZaDiak
 1401+ * @author Απεργός
12391402 */
12401403 $messages['el'] = array(
12411404 'securepoll' => 'SecurePoll',
@@ -1243,13 +1406,13 @@
12441407 'securepoll-need-admin' => 'Πρέπει να είστε διαχειριστής για να κάνετε αυτή την ενέργεια.',
12451408 'securepoll-too-few-params' => 'Μη αρκετές παράμετροι υποσελίδας (άκυρος σύνδεσμος).',
12461409 'securepoll-invalid-election' => '"$1" δεν είναι ένα αποδεκτό ID ψηφοφορίας.',
1247 - 'securepoll-welcome' => '<strong>Καλωσήρθες $1!</strong>',
 1410+ 'securepoll-welcome' => '<strong>Καλωσήρθατε $1!</strong>',
12481411 'securepoll-not-started' => 'Η ψηφοφορία δεν έχει ξεκινήσει ακόμη.
12491412 Είναι προγραμματισμένη να ξεκινήσει στις $2 στις $3.',
12501413 'securepoll-finished' => 'Αυτή η ψηφοφορία έχει τελειώσει, δεν μπορείτε πλέον να ψηφίσετε.',
12511414 'securepoll-not-qualified' => 'Δεν καλύπτετε τα κριτήρια για να ψηφίσετε σε αυτή την ψηφοφορία: $1',
12521415 'securepoll-change-disallowed' => 'Έχετε ψηφίσει προηγουμένως σε αυτή την ψηφοφορία.
1253 -Συγνώμη, δεν μπορείτε να ψηφίσετε ξανά.',
 1416+Λυπούμαστε, δεν μπορείτε να ψηφίσετε ξανά.',
12541417 'securepoll-change-allowed' => '<strong>Σημείωση: Έχετε ψηφίσει προηγουμένως σε αυτή την ψηφοφορία.</strong>
12551418 Μπορείτε να αλλάξετε την ψήφο σας αποστέλλοντας την φόρμα παρακάτω.
12561419 Λάβετε υπόψη ότι αν κάνετε αυτό, η αρχική ψήφος σας θα ακυρωθεί.',
@@ -1260,12 +1423,12 @@
12611424
12621425 <pre>$1</pre>',
12631426 'securepoll-thanks' => 'Ευχαριστούμε, η ψήφος σας καταγράφηκε.',
1264 - 'securepoll-return' => 'Επιστροφή στην $1',
1265 - 'securepoll-encrypt-error' => 'Αποτυχία κρυπτογράφησης της καταγραφής ψήφου σας.
 1427+ 'securepoll-return' => 'Επιστροφή στη σελίδα $1',
 1428+ 'securepoll-encrypt-error' => 'Αποτυχία κρυπτογράφησης της εγγραφής ψήφου σας.
12661429 Η ψήφος σας δεν έχει καταγραφεί!
12671430
12681431 $1',
1269 - 'securepoll-no-gpg-home' => 'Αποτυχία δημιουργίας οικείου καταλόγου GPG.',
 1432+ 'securepoll-no-gpg-home' => 'Αποτυχία δημιουργίας καταλόγου αρχείων του GPG.',
12701433 'securepoll-secret-gpg-error' => 'Σφάλμα εκτέλεσης GPG.
12711434 Χρησιμοποιήστε $wgSecurePollShowErrorDetail=true; στο LocalSettings.php για εμφάνιση περισσότερων λεπτομερειών.',
12721435 'securepoll-full-gpg-error' => 'Σφάλμα εκτέλεσης GPG:
@@ -1279,19 +1442,20 @@
12801443 'securepoll-no-decryption-key' => 'Δεν έχει ρυθμιστεί κλειδί αποκρυπτογράφησης.
12811444 Δεν είναι δυνατή η αποκρυπτογράφηση.',
12821445 'securepoll-jump' => 'Μετάβαση στον διακομιστή ψηφοφορίας',
1283 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
1284 -Η ψήφος σας ήταν άκυρη: $1
1285 -</div>',
1286 - 'securepoll-unanswered-questions' => 'Πρέπει να απαντήσεις σε όλες τις ερωτήσεις.',
 1446+ 'securepoll-bad-ballot-submission' => 'Η ψήφος σας ήταν άκυρη: $1',
 1447+ 'securepoll-unanswered-questions' => 'Πρέπει να απαντήσετε σε όλες τις ερωτήσεις.',
 1448+ 'securepoll-invalid-rank' => 'Εσφαλμένη κατάταξη. Πρέπει να δώσετε στους υποψηφίους μια κατάταξη μεταξύ 1 και 999.',
 1449+ 'securepoll-unranked-options' => 'Ορισμένες επιλογές δεν κατατάχθηκαν.
 1450+Πρέπει να δώσετε σε όλες τις επιλογές μια κατάταξη μεταξύ 1 και 999.',
12871451 'securepoll-remote-auth-error' => 'Σφάλμα κατά την ανάκτηση των πληροφοριών για τον λογαριασμό σας από τον διακομιστή.',
12881452 'securepoll-remote-parse-error' => 'Σφάλμα στην ερμηνεία της απάντησης για άδεια πρόβασης από τον διακομιστή.',
1289 - 'securepoll-api-invalid-params' => 'Άκυροι παράμετροι.',
1290 - 'securepoll-api-no-user' => 'Δεν βρέθηκε χρήστης με αυτό το ID.',
1291 - 'securepoll-api-token-mismatch' => 'Μη ταυτοποίηση κλειδιού ασφαλείας, δεν μπορείτε να συνδεθείτε.',
1292 - 'securepoll-not-logged-in' => 'Πρέπει να συνδεθείτε για να ψηφίσετε στις εκλογές',
1293 - 'securepoll-too-few-edits' => 'Συγνώμη, δεν μπορείτε να ψηφίσετε. Χρειάζεται να έχετε κάνει τουλάχιστον $1 {{PLURAL:$1|επεξεργασία|επεξεργασίες}} για να ψηφίσετε σε αυτή την ψηφοφορία, έχετε κάνει $2.',
1294 - 'securepoll-blocked' => 'Συγνώμη δεν μπορείτε να ψηφίσετε σε αυτή την ψηφοφορία αν είστε επί του παρόντος υπό φραγή από την επεξεργασία.',
1295 - 'securepoll-bot' => 'Συγνώμη, οι λογαριασμοί με σημαία μποτ δεν επιτρέπεται να ψηφίσουν σε αυτήν την ψηφοφορία.',
 1453+ 'securepoll-api-invalid-params' => 'Άκυρες παράμετροι.',
 1454+ 'securepoll-api-no-user' => 'Δεν βρέθηκε χρήστης με το συγκεκριμένο ID.',
 1455+ 'securepoll-api-token-mismatch' => 'Μη ταυτοποίηση κουπονιού ασφαλείας, δεν μπορείτε να συνδεθείτε.',
 1456+ 'securepoll-not-logged-in' => 'Πρέπει να συνδεθείτε για να ψηφίσετε σε αυτές τις εκλογές',
 1457+ 'securepoll-too-few-edits' => 'Λυπούμαστε, δεν μπορείτε να ψηφίσετε. Χρειάζεται να έχετε κάνει τουλάχιστον $1 {{PLURAL:$1|επεξεργασία|επεξεργασίες}} για να ψηφίσετε σε αυτή την ψηφοφορία, έχετε κάνει $2.',
 1458+ 'securepoll-blocked' => 'Λυπούμαστε, δεν μπορείτε να ψηφίσετε σε αυτή την ψηφοφορία αν είστε επί του παρόντος υπό φραγή από την επεξεργασία.',
 1459+ 'securepoll-bot' => 'Λυπούμαστε, οι λογαριασμοί με ιδιότητα bot δεν επιτρέπεται να ψηφίσουν σε αυτήν την ψηφοφορία.',
12961460 'securepoll-not-in-group' => "Μόνο τα μέλη της ομάδας $1 μπορούν να ψηφίσουν σ' αυτές τις εκλογές.",
12971461 'securepoll-not-in-list' => 'Λυπούμαστε, αλλά δεν βρίσκεστε στην προκαθορισμένη λίστα χρηστών που επιτρέπεται να ψηφίσουν στις εκλογές αυτές.',
12981462 'securepoll-list-title' => 'Λίστα ψήφων: $1',
@@ -1300,26 +1464,30 @@
13011465 'securepoll-header-voter-domain' => 'Περιοχή',
13021466 'securepoll-header-ua' => 'Αντιπρόσωπος χρήστη',
13031467 'securepoll-header-cookie-dup' => 'Διπλότυπες',
1304 - 'securepoll-header-strike' => 'Σβήσιμο',
 1468+ 'securepoll-header-strike' => 'Διαγραφή',
13051469 'securepoll-header-details' => 'Λεπτομέρειες',
1306 - 'securepoll-strike-button' => 'Σβήσιμο',
1307 - 'securepoll-unstrike-button' => 'Ακύρωση σβησίματος',
 1470+ 'securepoll-strike-button' => 'Διαγραφή',
 1471+ 'securepoll-unstrike-button' => 'Αναίρεση διαγραφής',
13081472 'securepoll-strike-reason' => 'Λόγος:',
13091473 'securepoll-strike-cancel' => 'Άκυρο',
1310 - 'securepoll-strike-error' => 'Σφάλμα κατά το σβήσιμο/την αναίρεση σβησίματος: $1',
 1474+ 'securepoll-strike-error' => 'Σφάλμα κατά τη διαγραφή/την αναίρεση διαγραφής: $1',
 1475+ 'securepoll-strike-token-mismatch' => 'Χάθηκαν τα δεδομένα συνεδρίας',
13111476 'securepoll-details-link' => 'Λεπτομέρειες',
1312 - 'securepoll-details-title' => 'Πληροφορίες ψήφου: #$1',
1313 - 'securepoll-invalid-vote' => 'Η "$1" δεν είναι μια έγκυρη ψήφος βάση ταυτότητας',
 1477+ 'securepoll-details-title' => 'Λεπτομέρειες ψήφου: #$1',
 1478+ 'securepoll-invalid-vote' => 'Το "$1" δεν είναι έγκυρο ID ψήφου',
13141479 'securepoll-header-voter-type' => 'Τύπος ψηφοφόρου',
13151480 'securepoll-voter-properties' => 'Ιδιότητες ψηφοφόρου',
1316 - 'securepoll-strike-log' => 'Ιστορικό σβησιμάτων',
 1481+ 'securepoll-strike-log' => 'Καταγραφές διαγραφών',
13171482 'securepoll-header-action' => 'Ενέργεια',
13181483 'securepoll-header-reason' => 'Λόγος',
13191484 'securepoll-header-admin' => 'Διαχειριστής',
13201485 'securepoll-cookie-dup-list' => 'Χρήστες που έχουν διπλότυπο cookie',
1321 - 'securepoll-dump-title' => 'Διπλότυπες: $1',
1322 - 'securepoll-dump-no-crypt' => 'Κανένα κρυπτογραφημένο εκλογικό αρχείο δεν είναι διαθέσιμο για αυτήν την εκλογή, επειδή αυτή δεν είναι διαμορφωμένη για χρήση κρυπτογράφησης.',
 1486+ 'securepoll-dump-title' => 'Αποτύπωση: $1',
 1487+ 'securepoll-dump-no-crypt' => 'Κανένα κρυπτογραφημένο εκλογικό αρχείο δεν είναι διαθέσιμο για αυτήν την εκλογή, επειδή αυτή δεν είναι ρυθμισμένη για χρήση κρυπτογράφησης.',
13231488 'securepoll-dump-not-finished' => 'Τα κρυπτογραφημένα αρχεία των εκλογών θα είναι μόνο διαθέσιμα μετά την τελευταία μέρα της ψηφοφορίας την $1 στις $2',
 1489+ 'securepoll-dump-no-urandom' => 'Αδύνατο το άνοιγμα του /dev/urandom.
 1490+Για να διατηρηθεί η ιδιωτικότητα των ψηφοφόρων, οι κρυπτογραφημένες εγγραφές της ψηφοφορίας γίνονται δημόσια διαθέσιμες μόνο όταν μπορούν να ανακατευτούν με μια ασφαλή ακολουθία τυχαίων αριθμών.',
 1491+ 'securepoll-urandom-not-supported' => 'Αυτός ο διακομιστής δεν υποστηρίζει την κρυπτογραφικά ασφαλή παραγωγή τυχαίων αριθμών. Για να διατηρηθεί η ιδιωτικότητα των ψηφοφόρων, οι κρυπτογραφημένες εγγραφές γίνονται δημόσια διαθέσιμες μόνο όταν μπορούν να ανακατευτούν με μία ασφαλή ακολουθία τυχαίων αριθμών.',
13241492 'securepoll-translate-title' => 'Μετάφραση: $1',
13251493 'securepoll-invalid-language' => 'Άκυρος κώδικας γλώσσας "$1"',
13261494 'securepoll-submit-translate' => 'Ενημέρωση',
@@ -1328,23 +1496,28 @@
13291497 'securepoll-header-title' => 'Όνομα',
13301498 'securepoll-header-start-date' => 'Ημερομηνία έναρξης',
13311499 'securepoll-header-end-date' => 'Ημερομηνία λήξης',
1332 - 'securepoll-subpage-vote' => 'Ψήφος',
 1500+ 'securepoll-subpage-vote' => 'Ψηφοφορία',
13331501 'securepoll-subpage-translate' => 'Μετάφραση',
13341502 'securepoll-subpage-list' => 'Λίστα',
1335 - 'securepoll-subpage-dump' => 'Διπλότυπες',
 1503+ 'securepoll-subpage-dump' => 'Αποτύπωση',
13361504 'securepoll-subpage-tally' => 'Καταμέτρηση',
13371505 'securepoll-tally-title' => 'Καταμέτρηση: $1',
1338 - 'securepoll-tally-not-finished' => 'Συγγνώμη, δεν είναι δυνατή η καταμέτρηση των ψήφων μέχρι να ολοκληρωθεί η ψηφοφορία.',
1339 - 'securepoll-tally-no-key' => 'Δεν μπορείτε να διεξάγετε ψηφομέτρηση σε αυτές τις εκλογές διότι οι ψήφοι είναι κρυπτογραφημένες και το κλειδί αποκρυπτογράφησης δεν είναι διαθέσιμο.',
1340 - 'securepoll-tally-local-legend' => 'Καταμέτρηση αποκατεστημένων αποτελεσμάτων',
 1506+ 'securepoll-tally-not-finished' => 'Λυπούμαστε, δεν είναι δυνατή η καταμέτρηση των ψήφων μέχρι να ολοκληρωθεί η ψηφοφορία.',
 1507+ 'securepoll-can-decrypt' => 'Η εγγραφή ψηφοφορίας έχει κρυποτογραφηθεί, αλλά το κλειδί αποκρυπτογράφησης είναι διαθέσιμο.
 1508+Μπορείτε να επιλέξετε είτε να καταμετρήσετε τα αποτελέσματα που υπάρχουν στη βάση δεδομένων ή να καταμετρήσετε κρυπτογραφημένα αποτελέσματα από ένα επιφορτωμένο αρχείο.',
 1509+ 'securepoll-tally-no-key' => 'Δεν μπορείτε να καταμετρήσετε τις ψήφους σε αυτές τις εκλογές διότι οι ψήφοι είναι κρυπτογραφημένες και το κλειδί αποκρυπτογράφησης δεν είναι διαθέσιμο.',
 1510+ 'securepoll-tally-local-legend' => 'Καταμέτρηση αποθηκευμένων αποτελεσμάτων',
13411511 'securepoll-tally-local-submit' => 'Δημιουργία καταμέτρησης',
1342 - 'securepoll-tally-upload-legend' => 'Επιφόρτωση κρυπτογραφημένης διπλότυπης',
 1512+ 'securepoll-tally-upload-legend' => 'Επιφόρτωση κρυπτογραφημένου αρχείου ψήφων',
13431513 'securepoll-tally-upload-submit' => 'Δημιουργία καταμέτρησης',
13441514 'securepoll-tally-error' => 'Σφάλμα κατά την ερμηνεία του αρχείου ψήφων· αδύνατη η καταμέτρηση.',
13451515 'securepoll-no-upload' => 'Κανένα αρχείο δεν επιφορτίστηκε· τα αποτελέσματα δεν μπορούν να καταμετρηθούν',
 1516+ 'securepoll-dump-corrupt' => 'Το αρχείο ψήφων είναι κατεστραμμένο και δεν μπορεί να υποστεί επεξεργασία.',
 1517+ 'securepoll-tally-upload-error' => 'Σφάλμα στην καταμέτρηση του αρχείου ψήφων: $1',
13461518 );
13471519
13481520 /** Esperanto (Esperanto)
 1521+ * @author ArnoLagrange
13491522 * @author Yekrats
13501523 */
13511524 $messages['eo'] = array(
@@ -1390,14 +1563,16 @@
13911564 'securepoll-no-decryption-key' => 'Neniu malĉifra ŝlosilo estas konfigurita.
13921565 Ne eblas malĉifri.',
13931566 'securepoll-jump' => 'Iri al la voĉdona servilo',
1394 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
1395 -Via voĉdono estis malvalida: $1
1396 -</div>',
 1567+ 'securepoll-bad-ballot-submission' => 'Via voĉdono estis malvalida: $1',
13971568 'securepoll-unanswered-questions' => 'Vi devas respondi al ĉiuj demandoj.',
 1569+ 'securepoll-invalid-rank' => 'Nevalida loko. Vi devas doni al kandidatoj lokon inter 1 kaj 999.',
 1570+ 'securepoll-unranked-options' => 'Kelkaj opcioj ne estis ordigitaj.
 1571+Vi devas doni al ĉiuj opcioj lokon inter 1 kaj 999.',
13981572 'securepoll-remote-auth-error' => 'Eraro akirante vian kontinformon de la servilo.',
13991573 'securepoll-remote-parse-error' => 'Eraro interpretante la aŭtoritadan respondon de la servilo.',
14001574 'securepoll-api-invalid-params' => 'Malvalidaj parametroj.',
14011575 'securepoll-api-no-user' => 'Neniu uzanto estis trovita kun tiu identigo.',
 1576+ 'securepoll-api-token-mismatch' => 'Nekongrua sekurecmarkilo. Neeblas ensaluti.',
14021577 'securepoll-not-logged-in' => 'Vi devas ensaluti por voĉdoni en ĉi tiu voĉdonado',
14031578 'securepoll-too-few-edits' => 'Bedaŭrinde, vi ne povas voĉdoni. Vi nepre havas almenaŭ $1 {{PLURAL:$1|redakto|redaktoj}} por voĉdoni en ĉi tiu voĉdonado; vi faris $2 redaktojn.',
14041579 'securepoll-blocked' => 'Bedaŭrinde, vi ne povas voĉdoni en ĉi tiu voĉdonado se vi nune estas forbarita de redaktado.',
@@ -1417,6 +1592,7 @@
14181593 'securepoll-strike-reason' => 'Kialo:',
14191594 'securepoll-strike-cancel' => 'Nuligi',
14201595 'securepoll-strike-error' => 'Eraro farante forstrekadon/malforstrekadon: $1',
 1596+ 'securepoll-strike-token-mismatch' => 'Sesiaj datenoj perditaj',
14211597 'securepoll-details-link' => 'Detaloj',
14221598 'securepoll-details-title' => 'Detaloj de voĉdono: #$1',
14231599 'securepoll-invalid-vote' => '"$1" ne estas valida voĉdona identigo',
@@ -1427,6 +1603,13 @@
14281604 'securepoll-header-reason' => 'Kialo',
14291605 'securepoll-header-admin' => 'Administranto',
14301606 'securepoll-cookie-dup-list' => 'Uzi seancan kuketon por duplikataj uzantoj',
 1607+ 'securepoll-dump-title' => 'Elŝuto: $1',
 1608+ 'securepoll-dump-no-crypt' => 'Neniu ĉifrita registraĵo havebla por tiu ĉi baloto, ĉar la baloto ne estas aranĝita por uzi ĉifradon.',
 1609+ 'securepoll-dump-not-finished' => 'Ĉifrita registraĵo estos havebla por tiu ĉi baloto nur post la findato $1 je $2',
 1610+ 'securepoll-dump-no-urandom' => 'Ne eblas malfermi /dev/urandom
 1611+Por garantii privatecon de balotinto, ĉifrita balotregistraĵo estas publike havebla nur kiam ĝi povas esti malnetigita per sekura hazarda nombrofluo.',
 1612+ 'securepoll-urandom-not-supported' => 'Ĉi tiu servilo ne eltenas generadon de ĉifrhazardnombroj.
 1613+Por garantii privatecon de balotinto, ĉifrita balotregistraĵo estas publike havebla nur kiam ĝi povas esti malnetigita per sekura hazarda nombrofluo.',
14311614 'securepoll-translate-title' => 'Traduki: $1',
14321615 'securepoll-invalid-language' => 'Malvalida lingva kodo "$1"',
14331616 'securepoll-submit-translate' => 'Ĝisdatigi',
@@ -1438,15 +1621,29 @@
14391622 'securepoll-subpage-vote' => 'Voĉdono',
14401623 'securepoll-subpage-translate' => 'Traduki',
14411624 'securepoll-subpage-list' => 'Listigi',
 1625+ 'securepoll-subpage-dump' => 'Elŝuto',
14421626 'securepoll-subpage-tally' => 'Kalkuli',
14431627 'securepoll-tally-title' => 'Kalkulo: $1',
14441628 'securepoll-tally-not-finished' => 'Bedaŭrinde vi ne povas kalkuli la voĉdonado ĝis post voĉdonado finas.',
 1629+ 'securepoll-can-decrypt' => 'La balotregistraĵo estis ĉifita, sed la malĉifra ŝlosilo haveblas.
 1630+Vi povas elekti nombri ĉu la rezultojn el la datumbazo, ĉu ĉifritajn rezultojn el elŝutita dosiero.',
 1631+ 'securepoll-tally-no-key' => 'Vi ne povas nombri la rezulton de ĉi tiu baloto, ĉar ĝi estas ĉifrita kaj la malĉifra ŝlosilo malhaveblas.',
 1632+ 'securepoll-tally-local-legend' => 'Konservitaj nombrorezultoj',
 1633+ 'securepoll-tally-local-submit' => 'Krei nombradon',
 1634+ 'securepoll-tally-upload-legend' => 'Elŝuti ĉifritan dosieron',
 1635+ 'securepoll-tally-upload-submit' => 'Krei nombradon',
 1636+ 'securepoll-tally-error' => 'Eraro dum interpretado de balotregistraĵo, ne eblas krei nombradon.',
 1637+ 'securepoll-no-upload' => 'Neniu dosiero estis elŝutita, ne eblas nombri rezulton.',
 1638+ 'securepoll-dump-corrupt' => 'La elŝutdosiero estas difektita kaj ne povas esti traktita.',
 1639+ 'securepoll-tally-upload-error' => 'Eraro dum nombrado de elŝutdosiero: $1',
14451640 );
14461641
14471642 /** Spanish (Español)
14481643 * @author Crazymadlover
14491644 * @author Dferg
14501645 * @author DoveBirkoff
 1646+ * @author Galio
 1647+ * @author Góngora
14511648 * @author Remember the dot
14521649 */
14531650 $messages['es'] = array(
@@ -1456,7 +1653,7 @@
14571654 'securepoll-need-admin' => 'Necesitas ser un administrador para realizar esta acción.',
14581655 'securepoll-too-few-params' => 'Parámetros de subpágina insuficientes (vínculo inválido).',
14591656 'securepoll-invalid-election' => '"$1" no es un identificador de elección valido.',
1460 - 'securepoll-welcome' => '<strong>Bienvenido $1!</strong>',
 1657+ 'securepoll-welcome' => '<strong>¡Bienvenido $1!</strong>',
14611658 'securepoll-not-started' => 'Esta elección aún no ha comenzado.
14621659 Está programada de comenzar en $2 de $3.',
14631660 'securepoll-finished' => 'Esta elección ha concluido, no puedes votar más.',
@@ -1478,6 +1675,7 @@
14791676 ¡Tu voto no ha sido registrado!
14801677
14811678 $1',
 1679+ 'securepoll-no-gpg-home' => 'Imposible crear un directorio hogar GPG.',
14821680 'securepoll-secret-gpg-error' => 'Error ejecutando GPG.
14831681 Usar $wgSecurePollShowErrorDetail=true; en LocalSettings.php para mostrar más detalle.',
14841682 'securepoll-full-gpg-error' => 'Error ejecutando GPG:
@@ -1488,14 +1686,23 @@
14891687 <pre>$2</pre>',
14901688 'securepoll-gpg-config-error' => 'Teclas GPG están configuradas incorrectamente.',
14911689 'securepoll-gpg-parse-error' => 'Error interpretando salida GPG.',
 1690+ 'securepoll-no-decryption-key' => 'No se ha especificado ninguna clave de desencriptación.
 1691+No se puede desencriptar.',
14921692 'securepoll-jump' => 'Ir al servidor de votación',
14931693 'securepoll-bad-ballot-submission' => 'Tu voto fue inválido: $1',
14941694 'securepoll-unanswered-questions' => 'Debes responder todas las preguntas.',
 1695+ 'securepoll-invalid-rank' => 'Rango inválido. Debes clasificar a los candidatos con un rango entre 1 y 999.',
 1696+ 'securepoll-unranked-options' => 'Algunas opciones no fueron clasificadas.
 1697+Debes clasificar a todas las opciones con un rango entre 1 y 999.',
 1698+ 'securepoll-remote-auth-error' => 'Se ha producido un error al obtener su información de cuenta del servidor.',
 1699+ 'securepoll-remote-parse-error' => 'Se ha producido un error al interpretar la respuesta de autorización del servidor.',
14951700 'securepoll-api-invalid-params' => 'Parámetros inválidos.',
14961701 'securepoll-api-no-user' => 'Ningún usuario fue encontrado con el ID dado.',
 1702+ 'securepoll-api-token-mismatch' => 'Clave de seguridad no coincidente, no se puede iniciar sesión.',
14971703 'securepoll-not-logged-in' => 'Debes iniciar sesión para votar en esta elección',
14981704 'securepoll-too-few-edits' => 'Perdón, no puedes votar. Necesitas haber hecho al menos $1 {{PLURAL:$1|edición|ediciones}} para votar en esta elección, has hecho $2.',
14991705 'securepoll-blocked' => 'Perdón, no puedes votar en esta elección si estás actualmente bloqueado para ediciones.',
 1706+ 'securepoll-bot' => 'Lo sentimos, las cuentas con flag de bot no están autorizadas a votar en esta elección.',
15001707 'securepoll-not-in-group' => 'Solamente mimbros del grupo $1 pueden votar en esta elección.',
15011708 'securepoll-not-in-list' => 'Perdón, no estás en el lista predetermindad de usuarios autorizados a votar en esta elección.',
15021709 'securepoll-list-title' => 'Lista votos: $1',
@@ -1507,18 +1714,28 @@
15081715 'securepoll-header-strike' => 'Tachar',
15091716 'securepoll-header-details' => 'Detalles',
15101717 'securepoll-strike-button' => 'Trachar',
 1718+ 'securepoll-unstrike-button' => 'Validar',
15111719 'securepoll-strike-reason' => 'Razón:',
15121720 'securepoll-strike-cancel' => 'Cancelar',
 1721+ 'securepoll-strike-error' => 'Se ha producido un error al invalidar/validar: $1',
 1722+ 'securepoll-strike-token-mismatch' => 'Pérdida de información de la sesión',
15131723 'securepoll-details-link' => 'Detalles',
15141724 'securepoll-details-title' => 'Detalles de voto: #$1',
 1725+ 'securepoll-invalid-vote' => '"$1" no es una identidad de voto válida',
15151726 'securepoll-header-voter-type' => 'Tipo de votante',
15161727 'securepoll-voter-properties' => 'Propiedades de votante',
 1728+ 'securepoll-strike-log' => 'Registro de votos invalidados',
15171729 'securepoll-header-action' => 'Acción',
15181730 'securepoll-header-reason' => 'Razón',
15191731 'securepoll-header-admin' => 'Administrador',
 1732+ 'securepoll-cookie-dup-list' => 'Usuarios con cookies duplicadas',
15201733 'securepoll-dump-title' => 'Volcado: $1',
15211734 'securepoll-dump-no-crypt' => 'No se dispone de un registro encriptado para esta votación dado que esta votación no ha sido configurada para usar encriptación.',
15221735 'securepoll-dump-not-finished' => 'Los registros encriptados de la votación están únicamente disponibles después de la fecha de finalización en $1 de $2',
 1736+ 'securepoll-dump-no-urandom' => 'Imposible abrir /dev/urandom.
 1737+Para preservar la privacidad de los votantes, sólo son publicados los resultados encriptados de la elección cuando pueden ser mezclados con un flujo de números aleatorio.',
 1738+ 'securepoll-urandom-not-supported' => 'Este servidor no posee capacidad de generación criptográfica de números aleatorios.
 1739+Para preservar la privacidad de los votantes, sólo son publicados los resultados encriptados de la elección cuando pueden ser mezclados con un flujo de números aleatorio.',
15231740 'securepoll-translate-title' => 'Traducir: $1',
15241741 'securepoll-invalid-language' => 'Código de lenguaje inválido "$1"',
15251742 'securepoll-submit-translate' => 'Actualizar',
@@ -1531,6 +1748,20 @@
15321749 'securepoll-subpage-translate' => 'Traducir',
15331750 'securepoll-subpage-list' => 'Lista',
15341751 'securepoll-subpage-dump' => 'Volcar',
 1752+ 'securepoll-subpage-tally' => 'Contador',
 1753+ 'securepoll-tally-title' => 'Contador: $1',
 1754+ 'securepoll-tally-not-finished' => 'Lo sentimos, no puede actualizar los contadores de la elección hasta que la votación no haya finalizado.',
 1755+ 'securepoll-can-decrypt' => 'El registro de elección ha sido encriptado pero la clave de desencriptación está disponible.
 1756+Puede escoger entre escrutar los resultados de la base de datos, o escrutar los resultados encriptados desde un fichero subido.',
 1757+ 'securepoll-tally-no-key' => 'No puede actualizar el contador de la elección, debido a que los votos están encriptados y la clave de desencriptación no está disponible.',
 1758+ 'securepoll-tally-local-legend' => 'Cuenta de resultados actualizada',
 1759+ 'securepoll-tally-local-submit' => 'Crear cuenta',
 1760+ 'securepoll-tally-upload-legend' => 'Subir dump encriptado',
 1761+ 'securepoll-tally-upload-submit' => 'Crear cuenta',
 1762+ 'securepoll-tally-error' => 'Se ha producido un error interpretando el registro de votos, no se puede crear un contador.',
 1763+ 'securepoll-no-upload' => 'No se ha subido ningún fichero, no se pueden contar los resultados.',
 1764+ 'securepoll-dump-corrupt' => 'El archivo volcado se encuentra dañado y no puede ser procesado.',
 1765+ 'securepoll-tally-upload-error' => 'Error al contar el archivo volcado: $1',
15351766 );
15361767
15371768 /** Estonian (Eesti)
@@ -1574,6 +1805,20 @@
15751806 'securepoll-submit-select-lang' => 'Tõlgi',
15761807 );
15771808
 1809+/** Basque (Euskara)
 1810+ * @author An13sa
 1811+ */
 1812+$messages['eu'] = array(
 1813+ 'securepoll-header-timestamp' => 'Ordua',
 1814+ 'securepoll-header-voter-name' => 'Izena',
 1815+ 'securepoll-header-reason' => 'Arrazoia',
 1816+ 'securepoll-language-label' => 'Hikuntza aukeratu:',
 1817+ 'securepoll-submit-select-lang' => 'Itzuli',
 1818+ 'securepoll-subpage-vote' => 'Bozkatu',
 1819+ 'securepoll-subpage-translate' => 'Itzuli',
 1820+ 'securepoll-subpage-list' => 'Zerrenda',
 1821+);
 1822+
15781823 /** Persian (فارسی)
15791824 * @author Mardetanha
15801825 * @author Meisam
@@ -1653,10 +1898,10 @@
16541899 'securepoll-no-decryption-key' => 'Salauksen purkuavainta ei ole asetettu.
16551900 Salausta ei voi purkaa.',
16561901 'securepoll-jump' => 'Siirry äänestyspalvelimelle.',
1657 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
1658 -Äänesi oli epäkelpo: $1
1659 -</div>',
 1902+ 'securepoll-bad-ballot-submission' => 'Äänesi oli epäkelpo: $1',
16601903 'securepoll-unanswered-questions' => 'Sinun täytyy vastata kaikkiin kysymyksiin.',
 1904+ 'securepoll-invalid-rank' => 'Virheellinen sijanumero. Ehdokkaille antamasi sijanumeron on sijaittava välillä 1 ja 999.',
 1905+ 'securepoll-unranked-options' => 'Joitain vaihtoehtoja ei asetettu paremmuusjärjestykseen. Jokaiselle vaihtoehdolle pitää tarjota sijoitus väliltä 1 ja 999.',
16611906 'securepoll-remote-auth-error' => 'Virhe hakiessa käyttäjätilisi tietoja palvelimelta.',
16621907 'securepoll-remote-parse-error' => 'Virhe tulkittaessa lupavastausta palvelimelta.',
16631908 'securepoll-api-invalid-params' => 'Virheellisiä parametrejä.',
@@ -1681,6 +1926,7 @@
16821927 'securepoll-strike-reason' => 'Syy',
16831928 'securepoll-strike-cancel' => 'Peruuta',
16841929 'securepoll-strike-error' => 'Tapahtui virhe poistossa/palautuksessa: $1',
 1930+ 'securepoll-strike-token-mismatch' => 'Istuntotiedot hävinneet',
16851931 'securepoll-details-link' => 'Tiedot',
16861932 'securepoll-details-title' => 'Äänestystiedot: #$1',
16871933 'securepoll-invalid-vote' => '"$1" ei ole kelvollinen tunniste.',
@@ -1696,6 +1942,7 @@
16971943 'securepoll-dump-not-finished' => 'Salauksin suojatut vaalitiedot ovat saatavilla vaalien päättymispäivän jälkeen $1 kello $2',
16981944 'securepoll-dump-no-urandom' => 'Toimintoa /dev/urandom ei voitu avata.
16991945 Äänestyssalaisuuden varmistamiseksi salatut tietueet ovat julkisesti saatavilla ainoastaan silloin, kun niiden järjestys voidaan sekoittaa turvallisella satunnaislukuvirralla.',
 1946+ 'securepoll-urandom-not-supported' => 'Tämä palvelin ei tue satunnaislukujen tuottoa salauksen alla. Jotta äänestäjien yksityisyys säilytetään, vaalien salauksenalaiset tiedostot ovat julkisesti saatavilla ainoastaan, kun niiden järjestys voidaan sekoittaa turvatusta satunnaislukulähteestä.',
17001947 'securepoll-translate-title' => 'Käännä: $1',
17011948 'securepoll-invalid-language' => 'Virheellinen kielikoodi ”$1”',
17021949 'securepoll-submit-translate' => 'Päivitä',
@@ -1720,12 +1967,15 @@
17211968 'securepoll-tally-upload-submit' => 'Luo laskenta',
17221969 'securepoll-tally-error' => 'Virhe äänestystiedoston tulkinnassa, joten ei voitu tuottaa laskentaa.',
17231970 'securepoll-no-upload' => 'Tiedostoa ei lähetettynä, joten laskenta ei onnistunut.',
 1971+ 'securepoll-dump-corrupt' => 'Vedostiedosto on vioittunut eikä sitä voida käsitellä.',
 1972+ 'securepoll-tally-upload-error' => 'Virhe vedostiedoston tarkistamisessa: $1',
17241973 );
17251974
17261975 /** French (Français)
17271976 * @author Crochet.david
17281977 * @author IAlex
17291978 * @author Louperivois
 1979+ * @author Omnipaedista
17301980 * @author PieRRoMaN
17311981 */
17321982 $messages['fr'] = array(
@@ -1773,6 +2023,9 @@
17742024 'securepoll-jump' => 'Aller au serveur de vote',
17752025 'securepoll-bad-ballot-submission' => 'Votre vote est invalide : $1',
17762026 'securepoll-unanswered-questions' => 'Vous devez répondre à toutes les questions.',
 2027+ 'securepoll-invalid-rank' => 'Rang invalide. Vous devez donner aux candidats un rang entre 1 et 999.',
 2028+ 'securepoll-unranked-options' => "Certaines options n'ont pas reçu de rang.
 2029+Vous devez donner un rang entre 1 et 999 à toutes les options.",
17772030 'securepoll-remote-auth-error' => 'Erreur lors de la récupération des informations de votre compte depuis le serveur.',
17782031 'securepoll-remote-parse-error' => 'Erreur lors de l’interprétation de la réponse d’autorisation du serveur.',
17792032 'securepoll-api-invalid-params' => 'Parmamètres invalides.',
@@ -1797,6 +2050,7 @@
17982051 'securepoll-strike-reason' => 'Raison :',
17992052 'securepoll-strike-cancel' => 'Annuler',
18002053 'securepoll-strike-error' => 'Erreur lors du (dé)biffage : $1',
 2054+ 'securepoll-strike-token-mismatch' => 'Perte des données de session',
18012055 'securepoll-details-link' => 'Détails',
18022056 'securepoll-details-title' => 'Détails du vote : #$1',
18032057 'securepoll-invalid-vote' => '« $1 » n’est pas un ID de vote valide',
@@ -1812,6 +2066,8 @@
18132067 'securepoll-dump-not-finished' => 'Les données cryptées ne sont disponibles qu’après la clôture de l’élection le $1 à $2',
18142068 'securepoll-dump-no-urandom' => 'Impossible d’ouvrir /dev/urandom.
18152069 Pour maintenir la confidentialité des votants, les données cryptées ne sont disponibles que si elles peuvent être brouillées avec un nombre de caractères aléatoires.',
 2070+ 'securepoll-urandom-not-supported' => 'Ce serveur ne supporte pas la génération cryptographique aléatoire de nombres.
 2071+Pour assurer la confidentialité des votants, les données cryptées ne sont publiés uniquement quand ils peuvent être brouillés avec un flux de nombres aléatoires.',
18162072 'securepoll-translate-title' => 'Traduire : $1',
18172073 'securepoll-invalid-language' => 'Code de langue « $1 » invalide.',
18182074 'securepoll-submit-translate' => 'Mettre à jour',
@@ -1836,6 +2092,8 @@
18372093 'securepoll-tally-upload-submit' => 'Créer une comptage',
18382094 'securepoll-tally-error' => 'Erreur lors de l’interprétation des enregistrements de vote, impossible de produire un résultat.',
18392095 'securepoll-no-upload' => 'Aucun fichier n’a été téléchargé, impossible de compter les résultats.',
 2096+ 'securepoll-dump-corrupt' => 'Le fichier de sauvegarde est corrompu et ne peut pas être utilisé.',
 2097+ 'securepoll-tally-upload-error' => 'Erreur lors du dépouillement du fichier de sauvegarde : $1',
18402098 );
18412099
18422100 /** Irish (Gaeilge)
@@ -1898,6 +2156,9 @@
18992157 'securepoll-jump' => 'Ir ao servidor de votos',
19002158 'securepoll-bad-ballot-submission' => 'O seu voto foi inválido: $1',
19012159 'securepoll-unanswered-questions' => 'Debe responder a todas as preguntas.',
 2160+ 'securepoll-invalid-rank' => 'Clasificación inválida. Debe darlles aos candidatos unha clasificación que estea entre 1 e 999.',
 2161+ 'securepoll-unranked-options' => 'Algunhas opcións non foron clasificadas.
 2162+Debe darlles a todas as opcións unha clasificación que estea entre 1 e 999.',
19022163 'securepoll-remote-auth-error' => 'Erro ao enviar a información da túa conta desde o servidor.',
19032164 'securepoll-remote-parse-error' => 'Erro ao interpretar a autorización de resposta desde o servidor.',
19042165 'securepoll-api-invalid-params' => 'Parámetros inválidos.',
@@ -1922,6 +2183,7 @@
19232184 'securepoll-strike-reason' => 'Motivo:',
19242185 'securepoll-strike-cancel' => 'Cancelar',
19252186 'securepoll-strike-error' => 'Erro ao levar a cabo o risco/a retirada do risco: $1',
 2187+ 'securepoll-strike-token-mismatch' => 'Perdéronse os datos da sesión',
19262188 'securepoll-details-link' => 'Detalles',
19272189 'securepoll-details-title' => 'Detalles do voto: #$1',
19282190 'securepoll-invalid-vote' => '"$1" non é un ID de voto válido',
@@ -1937,6 +2199,8 @@
19382200 'securepoll-dump-not-finished' => 'Os rexistros das eleccións encriptados só están dispoñibles despois da data de fin o $1 ás $2',
19392201 'securepoll-dump-no-urandom' => 'Non se pode abrir /dev/urandom.
19402202 Para manter a protección dos datos, os rexistros das eleccións encriptados só están dispoñibles publicamente cando poden ser baraxados cunha secuencia de números aleatorios.',
 2203+ 'securepoll-urandom-not-supported' => 'Este servidor non soporta a xeración criptográfica de números aleatorios.
 2204+Para manter a confidencialidade dos votantes, os rexistros cifrados das eleccións só están dispoñibles publicamente cando se poden barallar cun fluxo de números aleatorios.',
19412205 'securepoll-translate-title' => 'Traducir: $1',
19422206 'securepoll-invalid-language' => 'Código de lingua inválido "$1"',
19432207 'securepoll-submit-translate' => 'Actualizar',
@@ -1961,8 +2225,31 @@
19622226 'securepoll-tally-upload-submit' => 'Crear o escrutinio',
19632227 'securepoll-tally-error' => 'Erro de interpretación no rexistro da votación, non se pode producir un escrutinio.',
19642228 'securepoll-no-upload' => 'Non foi cargado ningún ficheiro, non se poden escrutar os resultados.',
 2229+ 'securepoll-dump-corrupt' => 'O ficheiro de descarga está danado e non pode ser procesado.',
 2230+ 'securepoll-tally-upload-error' => 'Erro ao enumerar o ficheiro de descarga: $1',
19652231 );
19662232
 2233+/** Ancient Greek (Ἀρχαία ἑλληνικὴ)
 2234+ * @author Crazymadlover
 2235+ * @author Omnipaedista
 2236+ */
 2237+$messages['grc'] = array(
 2238+ 'securepoll-header-timestamp' => 'Χρόνος',
 2239+ 'securepoll-header-voter-name' => 'Ὄνομα',
 2240+ 'securepoll-header-voter-domain' => 'Περιοχή',
 2241+ 'securepoll-strike-reason' => 'Αἰτία:',
 2242+ 'securepoll-strike-cancel' => 'Ἀκυροῦν',
 2243+ 'securepoll-details-link' => 'Λεπτομέρειαι',
 2244+ 'securepoll-header-action' => 'Δρᾶσις',
 2245+ 'securepoll-header-reason' => 'Αἰτία',
 2246+ 'securepoll-language-label' => 'Ἐπιλέγειν γλῶτταν:',
 2247+ 'securepoll-submit-select-lang' => 'Μεταγλωττίζειν',
 2248+ 'securepoll-header-title' => 'Ὄνομα',
 2249+ 'securepoll-subpage-vote' => 'Ψηφίζειν',
 2250+ 'securepoll-subpage-tally' => 'Ψηφομέτρησις',
 2251+ 'securepoll-tally-title' => 'Ψηφομέτρησις: $1',
 2252+);
 2253+
19672254 /** Swiss German (Alemannisch)
19682255 * @author Als-Holder
19692256 */
@@ -2011,6 +2298,9 @@
20122299 'securepoll-jump' => 'Gang zum Stimm-Server',
20132300 'securepoll-bad-ballot-submission' => 'Dyy Stimm isch nit giltig: $1',
20142301 'securepoll-unanswered-questions' => 'Du muesch uf alli Froge Antwort gee.',
 2302+ 'securepoll-invalid-rank' => 'Nit giltigi Rangfolg. Du muesch dr Kandidate e Rangnummere zwische 1 un 999 gee.',
 2303+ 'securepoll-unranked-options' => 'E Teil Optione hän kei Rangnummere.
 2304+Du muesch allene Optione e Rangnummere zwische 1 un 999 gee.',
20152305 'securepoll-remote-auth-error' => 'Fähler bim Abruefe vu Dyyne Benutzerkontoinformatione vum Server.',
20162306 'securepoll-remote-parse-error' => 'Fähler bim Dyte vu dr Autorisierigsantwort vum Server',
20172307 'securepoll-api-invalid-params' => 'Nit giltigi Parameter.',
@@ -2035,6 +2325,7 @@
20362326 'securepoll-strike-reason' => 'Grund:',
20372327 'securepoll-strike-cancel' => 'Abbräche',
20382328 'securepoll-strike-error' => 'Fähler bi dr Strychig/Strychigsrucknahm: $1',
 2329+ 'securepoll-strike-token-mismatch' => 'Sitzígsdate verlore',
20392330 'securepoll-details-link' => 'Detail',
20402331 'securepoll-details-title' => 'Abstimmigsdetail: #$1',
20412332 'securepoll-invalid-vote' => '„$1“ isch kei giltigi Abstimmigs-ID',
@@ -2050,6 +2341,8 @@
20512342 'securepoll-dump-not-finished' => 'Verschlissleti Abstimmigsufzeichnige sin nume noch em Ändtermin am $1 am $2 verfiegbar',
20522343 'securepoll-dump-no-urandom' => '/dev/urandom cha nit ufgmacht wäre.
20532344 Go dr Wehlerdateschutz wohre, sin verschlissleti Abstimmigsufzeichnige nume effentli verfiebar, wänn si mit eme sichere Zuefallszahlestrom chenne gmischt wäre.',
 2345+ 'securepoll-urandom-not-supported' => 'Dää Server unterstitzt kei kryptografischi Zuefallszahlegenerierig.
 2346+Ass es Wahlgheimnis sicher gstellt isch, sin verschlssleti Wahlufzeichnige nume effetlig verfiegbar, wänn si mit ere sichere Zuefallszahlereihefolg chenne vermischt wäre.',
20542347 'securepoll-translate-title' => 'Ibersetze: $1',
20552348 'securepoll-invalid-language' => 'Nit giltige Sprochcode „$1“',
20562349 'securepoll-submit-translate' => 'Aktualisiere',
@@ -2074,10 +2367,13 @@
20752368 'securepoll-tally-upload-submit' => 'Uuszellig aalege',
20762369 'securepoll-tally-error' => 'Fähler bim Interpretiere vu dr Abstimmigsufzeichnig, Uuszellig cha nit aagleit wäre.',
20772370 'securepoll-no-upload' => 'S isch kei Datei ufeglade wore, cha d Ergebnis nit uuszelle.',
 2371+ 'securepoll-dump-corrupt' => 'D Uusgabe-Datei isch fählerhaft un cha nit verarbeitet wäre.',
 2372+ 'securepoll-tally-upload-error' => 'Fähler in dr gwichtete Uusgabe-Datei: $1',
20782373 );
20792374
20802375 /** Hebrew (עברית)
20812376 * @author Rotem Liss
 2377+ * @author Rotemliss
20822378 * @author דניאל ב.
20832379 */
20842380 $messages['he'] = array(
@@ -2125,6 +2421,9 @@
21262422 'securepoll-jump' => 'מעבר לשרת ההצבעה',
21272423 'securepoll-bad-ballot-submission' => 'הצבעתכם הייתה בלתי תקינה: $1',
21282424 'securepoll-unanswered-questions' => 'עליכם לענות על כל השאלות.',
 2425+ 'securepoll-invalid-rank' => 'הדירוג אינו תקין. יש לתת למועמדים דירוג בין 1 ל־999.',
 2426+ 'securepoll-unranked-options' => 'כמה מהאפשרויות לא דורגו.
 2427+יש לקבוע לכל האפשרויות דירוג בין 1 ל־999.',
21292428 'securepoll-remote-auth-error' => 'שגיאה בקבלת פרטי החשבון שלכם מהשרת.',
21302429 'securepoll-remote-parse-error' => 'שגיאה בפענוח התגובה על מידע הכניסה מהשרת.',
21312430 'securepoll-api-invalid-params' => 'פרמטרים בלתי תקינים.',
@@ -2149,6 +2448,7 @@
21502449 'securepoll-strike-reason' => 'סיבה:',
21512450 'securepoll-strike-cancel' => 'ביטול',
21522451 'securepoll-strike-error' => 'שגיאה בביצוע הסתרה או בביטול הסתרה: $1',
 2452+ 'securepoll-strike-token-mismatch' => 'מידע הכניסה אבד',
21532453 'securepoll-details-link' => 'פרטים',
21542454 'securepoll-details-title' => 'פרטי ההצבעה: #$1',
21552455 'securepoll-invalid-vote' => '"$1" אינו מספר הצבעה תקין',
@@ -2165,6 +2465,8 @@
21662466 'securepoll-dump-not-finished' => 'רשומות ההצבעה המוצפנות זמינות רק לאחר תאריך הסיום ב־$2, $1',
21672467 'securepoll-dump-no-urandom' => 'לא ניתן לפתוח את /dev/urandom.
21682468 כדי לשמור על פרטיות המצביעים, רשומות ההצבעה המוצפנות זמינותת באופן ציבורי רק כאשר ניתן לערבב אותן באמצעות זרם המשתמש במספר אקראי מאובטח.',
 2469+ 'securepoll-urandom-not-supported' => 'שרת זה אינו תומך ביצירת מספרים אקראיים לצורך הצפנה.
 2470+כדי לשמור על פרטיות הבוחרים, רשומות ההצבעה המוצפנות תהיינה זמינות לציבור רק כאשר ניתן יהיה לערבלן באמצעות זרם מספרים אקראיים מאובטח.',
21692471 'securepoll-translate-title' => 'תרגום: $1',
21702472 'securepoll-invalid-language' => 'קוד שפה בלתי תקין "$1"',
21712473 'securepoll-header-trans-id' => 'מספר',
@@ -2192,6 +2494,120 @@
21932495 'securepoll-no-upload' => 'לא הועלה קובץ, לא ניתן לחשב את התוצאות.',
21942496 );
21952497
 2498+/** Croatian (Hrvatski)
 2499+ * @author SpeedyGonsales
 2500+ * @author Suradnik13
 2501+ */
 2502+$messages['hr'] = array(
 2503+ 'securepoll' => 'SigurnoGlasovanje',
 2504+ 'securepoll-desc' => 'Mediawiki ekstenzija za izbore i ankete',
 2505+ 'securepoll-invalid-page' => 'Nevaljana podstranica "<nowiki>$1</nowiki>"',
 2506+ 'securepoll-need-admin' => 'Morate biti administrator za izvršenje ove radnje.',
 2507+ 'securepoll-too-few-params' => 'Nema dovoljno parametara podstranice (neispravna poveznica).',
 2508+ 'securepoll-invalid-election' => '"$1" nije valjani izborni ID.',
 2509+ 'securepoll-welcome' => '<strong>Dobrodošli $1!</strong>',
 2510+ 'securepoll-not-started' => 'Izbori nisu još počeli.
 2511+Počinju dana $2 u $3 sati.',
 2512+ 'securepoll-finished' => 'Ovi izbori su okončani, ne možete više glasovati.',
 2513+ 'securepoll-not-qualified' => 'Niste kvalificirani za glasovanje na ovim izborima: $1',
 2514+ 'securepoll-change-disallowed' => 'Već ste glasovali na ovim izborima.
 2515+Žalimo, ne možete glasovati opet.',
 2516+ 'securepoll-change-allowed' => '<strong>Napomena: Vi ste već glasovali na ovim izborima.</strong>
 2517+Možete promijeniti svoj glas/svoje glasove ispunjavanjem donjeg obrasca.
 2518+No ako to učinite, vaše će prvo glasovanje biti poništeno.',
 2519+ 'securepoll-submit' => 'Pošalji (glasuj)',
 2520+ 'securepoll-gpg-receipt' => 'Hvala vam na glasovanju.
 2521+
 2522+Ako želite, možete zadržati (snimiti) slijedeći izraz kao dokaz vašeg glasovanja:
 2523+
 2524+<pre>$1</pre>',
 2525+ 'securepoll-thanks' => 'Hvala, Vaš glas je zaprimljen.',
 2526+ 'securepoll-return' => 'Vrati se na $1',
 2527+ 'securepoll-encrypt-error' => 'Neuspjela enkripcija vašeg glasa.
 2528+Vaš glas nije zabilježen!
 2529+
 2530+$1',
 2531+ 'securepoll-no-gpg-home' => "Nije moguće napraviti GPG ''home'' direktorij.",
 2532+ 'securepoll-secret-gpg-error' => 'Greška pri izvršavanju GPG-a.
 2533+Postavite $wgSecurePollShowErrorDetail=true; u LocalSettings.php datoteci da bi vidjeli više detalja.',
 2534+ 'securepoll-full-gpg-error' => 'Pogreška pri izvršavanju GPG-a:
 2535+
 2536+Naredba: $1
 2537+
 2538+Pogreška:
 2539+<pre>$2</pre>',
 2540+ 'securepoll-gpg-config-error' => 'GPG ključevi nisu pravilno konfigurirani.',
 2541+ 'securepoll-gpg-parse-error' => 'Pogreška pri prijevodu izlaza iz GPG-a.',
 2542+ 'securepoll-no-decryption-key' => 'Dekripcijski ključ nije konfiguriran.
 2543+Dekripcija nije moguća.',
 2544+ 'securepoll-jump' => 'Idi na poslužitelj za glasovanje',
 2545+ 'securepoll-bad-ballot-submission' => 'Vaš glas je bio nevažeći: $1',
 2546+ 'securepoll-unanswered-questions' => 'Morate odgovoriti na sva pitanja.',
 2547+ 'securepoll-remote-auth-error' => 'Pogreška pri dobavljanje informacije o Vašem računu s poslužitelja.',
 2548+ 'securepoll-remote-parse-error' => 'Pogreška pri tumačenju autorizacijskog odgovora s poslužitelja.',
 2549+ 'securepoll-api-invalid-params' => 'Nevažeći parametri.',
 2550+ 'securepoll-api-no-user' => 'Nema suradnika s tim ID brojem.',
 2551+ 'securepoll-api-token-mismatch' => 'Neslaganje sigurnosnog tokena, neuspjela prijava.',
 2552+ 'securepoll-not-logged-in' => 'Morate se prijaviti da bi mogli glasovati na ovim izborima',
 2553+ 'securepoll-too-few-edits' => 'Nažalost, ne možete glasovati. Morate imati najmanje $1 {{PLURAL:$1|uređivanje|uređivanja|uređivanja}} da bi mogli glasovati na ovim izborima, vi ih imate $2.',
 2554+ 'securepoll-blocked' => 'Nažalost, ne možete glasovati na ovim izborima ako ste trenutačno blokirani',
 2555+ 'securepoll-bot' => 'Nažalost, računi s bot statusom ne mogu glasovati na ovim izborima.',
 2556+ 'securepoll-not-in-group' => 'Samo članovi "$1" grupe mogu glasovati na ovim izborima.',
 2557+ 'securepoll-not-in-list' => 'Nažalost, niste na popisu ovlaštenih suradnika koji mogu glasovati na ovim izborima.',
 2558+ 'securepoll-list-title' => 'Popis glasova: $1',
 2559+ 'securepoll-header-timestamp' => 'Vrijeme',
 2560+ 'securepoll-header-voter-name' => 'Ime',
 2561+ 'securepoll-header-voter-domain' => 'Domena',
 2562+ 'securepoll-header-ua' => 'Suradnički posrednik',
 2563+ 'securepoll-header-cookie-dup' => 'Dupl',
 2564+ 'securepoll-header-strike' => 'Prekriži',
 2565+ 'securepoll-header-details' => 'Detalji',
 2566+ 'securepoll-strike-button' => 'Prekriži',
 2567+ 'securepoll-unstrike-button' => 'Ukloni prekriženo',
 2568+ 'securepoll-strike-reason' => 'Razlog:',
 2569+ 'securepoll-strike-cancel' => 'Odustani',
 2570+ 'securepoll-strike-error' => 'Pogreška tijekom izvođenja prekriži/ukloni prekriženo: $1',
 2571+ 'securepoll-details-link' => 'Detalji',
 2572+ 'securepoll-details-title' => 'Detalji glasovanja: #$1',
 2573+ 'securepoll-invalid-vote' => '"$1" nije valjan glasački ID',
 2574+ 'securepoll-header-voter-type' => 'Vrsta glasača',
 2575+ 'securepoll-voter-properties' => 'Svojstva glasača',
 2576+ 'securepoll-strike-log' => 'Evidencija križanja',
 2577+ 'securepoll-header-action' => 'Radnja',
 2578+ 'securepoll-header-reason' => 'Razlog',
 2579+ 'securepoll-header-admin' => 'Admin',
 2580+ 'securepoll-cookie-dup-list' => 'Suradnici s dvostrukim kolačićima',
 2581+ 'securepoll-dump-title' => 'Ispis: $1',
 2582+ 'securepoll-dump-no-crypt' => 'Enkriptirani zapis ovih izbora nije dostupan, jer enkripcija nije postavljena.',
 2583+ 'securepoll-dump-not-finished' => 'Enkriptirani zapisi izbora dostupni su samo poslije datuma okončanja - $1 u $2 sati',
 2584+ 'securepoll-dump-no-urandom' => 'Ne mogu otvoriti /dev/urandom.
 2585+Da biste zadržali privatnost glasača, enkriptirani zapisi izbora su javno dostupni samo kad ih se može izmiješati uporabom niza sigurnih slučajnih brojeva.',
 2586+ 'securepoll-translate-title' => 'Prevedi: $1',
 2587+ 'securepoll-invalid-language' => 'Neispravan jezični kôd "$1"',
 2588+ 'securepoll-submit-translate' => 'Ažuriraj',
 2589+ 'securepoll-language-label' => 'Odaberite jezik:',
 2590+ 'securepoll-submit-select-lang' => 'Prevedi',
 2591+ 'securepoll-header-title' => 'Ime',
 2592+ 'securepoll-header-start-date' => 'Početni datum',
 2593+ 'securepoll-header-end-date' => 'Krajnji datum',
 2594+ 'securepoll-subpage-vote' => 'Glasaj',
 2595+ 'securepoll-subpage-translate' => 'Prevedi',
 2596+ 'securepoll-subpage-list' => 'Popis',
 2597+ 'securepoll-subpage-dump' => 'Ispis',
 2598+ 'securepoll-subpage-tally' => 'Rezultat',
 2599+ 'securepoll-tally-title' => 'Rezultat: $1',
 2600+ 'securepoll-tally-not-finished' => 'Nažalost, ne možete vidjeti rezultate izbora za trajanja glasovanja.',
 2601+ 'securepoll-can-decrypt' => 'Izborni zapis je enkriptiran, ali dekripcijski ključ je dostupan.
 2602+Možete odabrati bilo prikaz rezultata iz baze podataka, ili prikaz enkriptiranih rezultata iz učitane datoteke.',
 2603+ 'securepoll-tally-no-key' => 'Ne možete prikazati rezultate ovih izbore, jer su glasovi enkriptirani a dekripcijski ključ nije dostupan.',
 2604+ 'securepoll-tally-local-legend' => 'Prikaži raspodjelu glasova pohranjenih izbora',
 2605+ 'securepoll-tally-local-submit' => 'Napravi prikaz rezultata',
 2606+ 'securepoll-tally-upload-legend' => 'Učitaj enkriptirani ispis',
 2607+ 'securepoll-tally-upload-submit' => 'Napravi prikaz rezultata (raspodjelu glasova)',
 2608+ 'securepoll-tally-error' => 'Pogreška pri prijevodu zapisa glasa, nije moguće prikazati raspodjelu glasova.',
 2609+ 'securepoll-no-upload' => 'Datoteka nije učitana, ne mogu prikazati raspodjelu rezultata.',
 2610+);
 2611+
21962612 /** Upper Sorbian (Hornjoserbsce)
21972613 * @author Michawiki
21982614 */
@@ -2240,6 +2656,9 @@
22412657 'securepoll-jump' => 'K serwerej wothłosowanja',
22422658 'securepoll-bad-ballot-submission' => 'Twój hłós bě njepłaćiwy: $1',
22432659 'securepoll-unanswered-questions' => 'Dyrbiš na wšě prašenja wotmołwić.',
 2660+ 'securepoll-invalid-rank' => 'Njepłaćiwy rjad. Dyrbiš kandidatam rjad mjez 1 a 999 dać.',
 2661+ 'securepoll-unranked-options' => 'Někotre opcije rjad nimaja.
 2662+Dyrbiš wšěm opcijam rjad mjez 1 a 999 dać.',
22442663 'securepoll-remote-auth-error' => 'Zmylk při wotwołowanju kontowych informacijow ze serwera.',
22452664 'securepoll-remote-parse-error' => 'Zmylk při interpretowanju awtorizaciskeje wotmołwy serwera.',
22462665 'securepoll-api-invalid-params' => 'Njepłaćiwe parametry.',
@@ -2264,6 +2683,7 @@
22652684 'securepoll-strike-reason' => 'Přičina:',
22662685 'securepoll-strike-cancel' => 'Přetorhnyć',
22672686 'securepoll-strike-error' => 'Zmylk při přewjedźenju šmórnjenja/cofnjenja šmórnjenja: $1',
 2687+ 'securepoll-strike-token-mismatch' => 'Daty posedźenja zhubjene',
22682688 'securepoll-details-link' => 'Podrobnosće',
22692689 'securepoll-details-title' => 'Podrobnosće hłosowanja: #$1',
22702690 'securepoll-invalid-vote' => '"$1" płaćiwy hłosowanski ID njeje.',
@@ -2279,6 +2699,8 @@
22802700 'securepoll-dump-not-finished' => 'Zaklučowane zapiski wólby jenož po kónčnym datumje $1 $2 k dispoziciji steja',
22812701 'securepoll-dump-no-urandom' => '/dev/urandom njeda so wočinić.
22822702 Zo by so škit datow wolerja wobchował, zaklučowane zapisy jenož zjawnje k dispoziciji steja, hdyž hodźa so z wěstotnym prudom připadnych ličbow měšeć.',
 2703+ 'securepoll-urandom-not-supported' => 'Tutón serwer kryptografiske płodźenje připadnych ličbow njepodpěruje.
 2704+Zo by so priwatnosć wolerja wobchowała, su zaklučowane wólbne zapiski jenož zjawnje k dispoziciji, hdyž dadźa so z wěstym prudom připadnych ličbow měšeć.',
22832705 'securepoll-translate-title' => 'Přełožić: $1',
22842706 'securepoll-invalid-language' => 'Njepłaćiwy rěčny kod "$1"',
22852707 'securepoll-submit-translate' => 'Aktualizować',
@@ -2303,10 +2725,14 @@
23042726 'securepoll-tally-upload-submit' => 'Ličenje wutworić',
23052727 'securepoll-tally-error' => 'Zmylk při interpretowanju zapisow wothłosowanja, ličenje njeda so wutworić.',
23062728 'securepoll-no-upload' => 'Njeje so žana dataja nahrała, wuslědki njehodźa so ličić.',
 2729+ 'securepoll-dump-corrupt' => 'Dataja składowakoweho wobsaha je poškodźeny a njeda so předźěłać.',
 2730+ 'securepoll-tally-upload-error' => 'Zmylk při wuličowanju dataje składowakeho wobsaha: $1',
23072731 );
23082732
23092733 /** Hungarian (Magyar)
23102734 * @author Bdamokos
 2735+ * @author Cassandro
 2736+ * @author Cbrown1023
23112737 * @author Dani
23122738 * @author Tgr
23132739 */
@@ -2353,10 +2779,11 @@
23542780 'securepoll-no-decryption-key' => 'Nincs visszafejtő kulcs beállítva.
23552781 Nem lehet visszafejteni.',
23562782 'securepoll-jump' => 'Irány a szavazás-szerverre',
2357 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
2358 -A szavazatod érvénytelen volt: $1
2359 -</div>',
 2783+ 'securepoll-bad-ballot-submission' => 'A szavazatod érvénytelen volt: $1',
23602784 'securepoll-unanswered-questions' => 'Minden kérdésre válaszolnod kell.',
 2785+ 'securepoll-invalid-rank' => 'Érvénytelen helyezés. A jelölteknek csak 1 és 999 közötti helyezést adhatsz.',
 2786+ 'securepoll-unranked-options' => 'Néhány javaslatra nem adtál helyezést.
 2787+Minden javaslathoz egy 1 és 999 közötti helyezést kell adnod.',
23612788 'securepoll-remote-auth-error' => 'Nem sikerült lekérdezni a felhasználói fiókod adatait a szerverről.',
23622789 'securepoll-remote-parse-error' => 'Nem sikerült értelmezni a szerver autorizációs válaszát.',
23632790 'securepoll-api-invalid-params' => 'Érvénytelen paraméterek.',
@@ -2372,6 +2799,8 @@
23732800 'securepoll-header-timestamp' => 'Idő',
23742801 'securepoll-header-voter-name' => 'Név',
23752802 'securepoll-header-voter-domain' => 'Domain',
 2803+ 'securepoll-header-ua' => 'Böngésző',
 2804+ 'securepoll-header-cookie-dup' => 'Duplikátum',
23762805 'securepoll-header-strike' => 'Törlés',
23772806 'securepoll-header-details' => 'Részletek',
23782807 'securepoll-strike-button' => 'Törlés',
@@ -2379,6 +2808,7 @@
23802809 'securepoll-strike-reason' => 'Ok:',
23812810 'securepoll-strike-cancel' => 'Mégse',
23822811 'securepoll-strike-error' => 'Hiba történt a törléskor vagy a törlés visszavonásakor: $1',
 2812+ 'securepoll-strike-token-mismatch' => 'A munkafázis adatai elvesztek.',
23832813 'securepoll-details-link' => 'Részletek',
23842814 'securepoll-details-title' => 'A szavazás részletei: #$1',
23852815 'securepoll-invalid-vote' => 'A(z) „$1” nem érvényes szavazatazonosító',
@@ -2388,16 +2818,40 @@
23892819 'securepoll-header-action' => 'Művelet',
23902820 'securepoll-header-reason' => 'Ok',
23912821 'securepoll-header-admin' => 'Adminisztrátor',
 2822+ 'securepoll-cookie-dup-list' => 'Többször szavazók (süti alapján)',
23922823 'securepoll-dump-title' => 'Dump: $1',
23932824 'securepoll-dump-no-crypt' => 'A szavazáshoz nem érhető el titkosított szavazatjegyzőkönyv, mert nem lett hozzá titkosítás beállítva.',
23942825 'securepoll-dump-not-finished' => 'A titkosított szavazatjegyzőkönyvek csak a befejezési dátum ($1 $2) után érhetőek el.',
23952826 'securepoll-dump-no-urandom' => 'Nem nyitható meg a /dev/urandom.
23962827 A szavazók névtelenségének megőrzése érdekében a titkosított szavazójegyzőkönyv csak akkor érhető el nyilvánosan, ha egy biztonságos véletlenszám-sorozattal lehet keverni.',
 2828+ 'securepoll-urandom-not-supported' => 'Ez a szerver nem képes titkosításra alkalmas véletlenszámokat generálni.
 2829+A szavazás titkosságának megőrzésére a titkosított szavazatok csak akkor válnak nyilvánossá, ha rendelkezésre áll olyan egy biztonságos véletlenszámforrás, amivel a sorrendjük megkeverhető.',
23972830 'securepoll-translate-title' => 'Fordítás: $1',
23982831 'securepoll-invalid-language' => 'Érvénytelen nyelvkód: „$1”',
23992832 'securepoll-submit-translate' => 'Frissítés',
24002833 'securepoll-language-label' => 'Nyelv kiválasztása:',
24012834 'securepoll-submit-select-lang' => 'Fordítás',
 2835+ 'securepoll-header-title' => 'Név',
 2836+ 'securepoll-header-start-date' => 'Kezdődátum',
 2837+ 'securepoll-header-end-date' => 'Záródátum',
 2838+ 'securepoll-subpage-vote' => 'Szavazás',
 2839+ 'securepoll-subpage-translate' => 'Fordítás',
 2840+ 'securepoll-subpage-list' => 'Listázás',
 2841+ 'securepoll-subpage-dump' => 'Dump',
 2842+ 'securepoll-subpage-tally' => 'Összesítés',
 2843+ 'securepoll-tally-title' => 'Összesítés: $1',
 2844+ 'securepoll-tally-not-finished' => 'Sajnos nem tudod összesíteni a választást amíg a szavazás le nem zárult.',
 2845+ 'securepoll-can-decrypt' => 'A szavazási jegyzőkönyvet titkosították, de a feloldókulcs elérhető.
 2846+Választhatod az adatbázisban szereplő eredmények összesítését vagy a titkosított eredmények összesítését egy feltöltött fájlból.',
 2847+ 'securepoll-tally-no-key' => 'Nem lehet a szavazást összesíteni, mert a szavazatokat titkosították és a feloldókulcs nem elérhető.',
 2848+ 'securepoll-tally-local-legend' => 'Tárolt eredmények összesítése',
 2849+ 'securepoll-tally-local-submit' => 'Összesítés készítése',
 2850+ 'securepoll-tally-upload-legend' => 'Titkosított dump feltöltése',
 2851+ 'securepoll-tally-upload-submit' => 'Összesítés készítése',
 2852+ 'securepoll-tally-error' => 'Hiba a szavazási jegyzőkönyv értelmezésében, nem lehetett összesítést készíteni.',
 2853+ 'securepoll-no-upload' => 'Semmilyen fájlt nem töltöttek fel, az eredményt így nem lehet összesíteni.',
 2854+ 'securepoll-dump-corrupt' => 'A dump fájl hibás, nem sikerült feldolgozni.',
 2855+ 'securepoll-tally-upload-error' => 'Hiba a dump fájl összesítésekor: $1',
24022856 );
24032857
24042858 /** Interlingua (Interlingua)
@@ -2448,6 +2902,9 @@
24492903 'securepoll-jump' => 'Ir al servitor de votation',
24502904 'securepoll-bad-ballot-submission' => 'Tu voto esseva invalide: $1',
24512905 'securepoll-unanswered-questions' => 'Tu debe responder a tote le questiones.',
 2906+ 'securepoll-invalid-rank' => 'Rango invalide. Tu debe dar al candidatos un rango inter 1 e 999.',
 2907+ 'securepoll-unranked-options' => 'Alcun optiones non ha un rango.
 2908+Tu debe dar a tote le optiones un rango inter 1 e 999.',
24522909 'securepoll-remote-auth-error' => 'Error durante le lectura del informationes de tu conto ab le servitor.',
24532910 'securepoll-remote-parse-error' => 'Error durante le interpretation del responsa de autorisation ab le servitor.',
24542911 'securepoll-api-invalid-params' => 'Parametros invalide.',
@@ -2472,6 +2929,7 @@
24732930 'securepoll-strike-reason' => 'Motivo:',
24742931 'securepoll-strike-cancel' => 'Annullar',
24752932 'securepoll-strike-error' => 'Error durante le cancellation/restauration: $1',
 2933+ 'securepoll-strike-token-mismatch' => 'Datos de session perdite',
24762934 'securepoll-details-link' => 'Detalios',
24772935 'securepoll-details-title' => 'Detalios del voto: #$1',
24782936 'securepoll-invalid-vote' => '"$1" non es un identificator valide de un voto',
@@ -2487,6 +2945,8 @@
24882946 'securepoll-dump-not-finished' => 'Le registro cryptate del election non essera disponibile usque le data final: le $1 a $2',
24892947 'securepoll-dump-no-urandom' => 'Impossibile aperir /dev/urandom.
24902948 Pro mantener le confidentialitate del votatores, le registro cryptate del election non essera disponibile al publico usque illo pote esser miscite con un fluxo secur de numeros aleatori.',
 2949+ 'securepoll-urandom-not-supported' => 'Iste servitor non supporta le generation de numeros aleatori cryptographic.
 2950+Pro assecurar le confidentialitate del votatores, le datos cryptate del election es solo publicamente disponibile si illos pote esser miscite con un fluxo de numeros aleatori secur.',
24912951 'securepoll-translate-title' => 'Traducer: $1',
24922952 'securepoll-invalid-language' => 'Le codice de lingua "$1" es invalide',
24932953 'securepoll-submit-translate' => 'Actualisar',
@@ -2511,9 +2971,12 @@
25122972 'securepoll-tally-upload-submit' => 'Contar resultatos',
25132973 'securepoll-tally-error' => 'Error durante le interpretation del registro de voto; non pote producer un conto.',
25142974 'securepoll-no-upload' => 'Nulle file ha essite cargate; non pote contar le resultatos.',
 2975+ 'securepoll-dump-corrupt' => 'Le file de dump es corrumpite e non pote esser processate.',
 2976+ 'securepoll-tally-upload-error' => 'Error de contar ex le file de dump: $1',
25152977 );
25162978
25172979 /** Indonesian (Bahasa Indonesia)
 2980+ * @author Bennylin
25182981 * @author Rex
25192982 */
25202983 $messages['id'] = array(
@@ -2558,10 +3021,11 @@
25593022 'securepoll-no-decryption-key' => 'Kunci dekripsi belum dikonfigurasikan.
25603023 Tidak dapat melakukan dekripsi.',
25613024 'securepoll-jump' => 'Pergi ke server pemungutan suara',
2562 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
2563 -Suara Anda tidak valid: $1
2564 -</div>',
 3025+ 'securepoll-bad-ballot-submission' => 'Suara Anda tidak valid: $1',
25653026 'securepoll-unanswered-questions' => 'Anda harus menjawab semua pertanyaan.',
 3027+ 'securepoll-invalid-rank' => 'Peringat tidak sah. Anda harus memberi peringkat kandidat antara 1 dan 99.',
 3028+ 'securepoll-unranked-options' => 'Beberapa pilihan tidak diberi peringkat.
 3029+Anda harus memberi peringkat antara 1 dan 99 untuk semua pilihan.',
25663030 'securepoll-remote-auth-error' => 'Terjadi kesalahan ketika menarik informasi akun Anda dari server.',
25673031 'securepoll-remote-parse-error' => 'Terjadi kesalahan interpretasi atas respons otorisasi dari server.',
25683032 'securepoll-api-invalid-params' => 'Parameter tidak valid.',
@@ -2582,10 +3046,11 @@
25833047 'securepoll-header-strike' => 'Coret',
25843048 'securepoll-header-details' => 'Rincian',
25853049 'securepoll-strike-button' => 'Coret',
2586 - 'securepoll-unstrike-button' => 'Batal coret',
 3050+ 'securepoll-unstrike-button' => 'Hapus coretan',
25873051 'securepoll-strike-reason' => 'Alasan:',
2588 - 'securepoll-strike-cancel' => 'Batal',
 3052+ 'securepoll-strike-cancel' => 'Batalkan',
25893053 'securepoll-strike-error' => 'Gagal mencoret/membatalkan pencoretan: $1',
 3054+ 'securepoll-strike-token-mismatch' => 'Data sesi terhilang',
25903055 'securepoll-details-link' => 'Rincian',
25913056 'securepoll-details-title' => 'Rincian suara: #$1',
25923057 'securepoll-invalid-vote' => 'ID suara tidak sah: "$1"',
@@ -2601,6 +3066,8 @@
26023067 'securepoll-dump-not-finished' => 'Catatan pemilihan terenkripsi hanya tersedia setelah selesainya pemungutan suara pada $2, $1.',
26033068 'securepoll-dump-no-urandom' => 'Tidak dapat membuka /dev/urandom.
26043069 Untuk memastikan privasi pemberi suara, catatan pemilihan terenkripsi hanya akan tersedia secara publik jika menggunakan sebuah rangkaian nomor keamanan acak.',
 3070+ 'securepoll-urandom-not-supported' => 'Peladen ini tidak mendukung kriptografi pembuatan angka acak.
 3071+Untuk menjaga kerahasiaan pemilih, catatan pemilihan ter-enkripsi hanya tersedia secara publik jika catatan tersebut dapat diacak dengan angka acak yang aman.',
26053072 'securepoll-translate-title' => 'Terjemahkan: $1',
26063073 'securepoll-invalid-language' => 'Kode bahasa tidak sah "$1"',
26073074 'securepoll-submit-translate' => 'Perbarui',
@@ -2625,11 +3092,22 @@
26263093 'securepoll-tally-upload-submit' => 'Membuat perhitungan',
26273094 'securepoll-tally-error' => 'Terjadi kesalahan dalam menginterpretasikan catatan pemungutan suara, tidak dapat melakukan penghitungan.',
26283095 'securepoll-no-upload' => 'Tidak ada berkas yang dimuatkan, tidak dapat melakukan penghitungan hasil.',
 3096+ 'securepoll-dump-corrupt' => 'Berkas dump terkorpusi dan tidak dapat diproses.',
 3097+ 'securepoll-tally-upload-error' => 'Kesalahan pada saat menjumlah berkas dump: $1',
26293098 );
26303099
 3100+/** Ido (Ido)
 3101+ * @author Wyvernoid
 3102+ */
 3103+$messages['io'] = array(
 3104+ 'securepoll' => 'SekuraVoto',
 3105+ 'securepoll-desc' => 'Extensilo por elekti e voti',
 3106+);
 3107+
26313108 /** Italian (Italiano)
26323109 * @author BrokenArrow
26333110 * @author Darth Kule
 3111+ * @author Massimiliano Lincetto
26343112 * @author Melos
26353113 * @author Nemo bis
26363114 * @author Pietrodn
@@ -2678,10 +3156,11 @@
26793157 'securepoll-no-decryption-key' => 'Nessuna chiave di decrittazione è configurata.
26803158 Impossibile decifrare.',
26813159 'securepoll-jump' => 'Vai al server della votazione',
2682 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
2683 -Il tuo voto non era valido: $1
2684 -</div>',
 3160+ 'securepoll-bad-ballot-submission' => 'Il tuo voto non era valido: $1',
26853161 'securepoll-unanswered-questions' => 'È necessario rispondere a tutte le domande.',
 3162+ 'securepoll-invalid-rank' => 'Voto non valido. Devi dare ai candidati un voto compreso tra 1 e 999.',
 3163+ 'securepoll-unranked-options' => 'Alcune voci sono prive di voto.
 3164+Devi assegnare a ciascuna voce un voto compreso tra 1 e 999.',
26863165 'securepoll-remote-auth-error' => 'Errore durante il recupero delle informazioni sul tuo account dal server.',
26873166 'securepoll-remote-parse-error' => "Errore nell'interpretare la risposta di autorizzazione dal server.",
26883167 'securepoll-api-invalid-params' => 'Parametri non validi.',
@@ -2698,6 +3177,7 @@
26993178 'securepoll-header-voter-name' => 'Nome',
27003179 'securepoll-header-voter-domain' => 'Dominio',
27013180 'securepoll-header-ua' => 'Agente utente',
 3181+ 'securepoll-header-cookie-dup' => 'Dup',
27023182 'securepoll-header-strike' => 'Annulla',
27033183 'securepoll-header-details' => 'Dettagli',
27043184 'securepoll-strike-button' => 'Annulla questo voto',
@@ -2705,6 +3185,7 @@
27063186 'securepoll-strike-reason' => 'Motivo:',
27073187 'securepoll-strike-cancel' => 'Annulla',
27083188 'securepoll-strike-error' => "Errore durante l'annullamento o ripristino del voto: $1",
 3189+ 'securepoll-strike-token-mismatch' => 'I dati della sessione sono andati perduti.',
27093190 'securepoll-details-link' => 'Dettagli',
27103191 'securepoll-details-title' => 'Dettagli del voto: #$1',
27113192 'securepoll-invalid-vote' => '"$1" non è l\'ID di un voto valido',
@@ -2715,10 +3196,13 @@
27163197 'securepoll-header-reason' => 'Motivo',
27173198 'securepoll-header-admin' => 'Amministratore',
27183199 'securepoll-cookie-dup-list' => 'Utenti doppi per cookie',
 3200+ 'securepoll-dump-title' => 'File di dump: $1',
27193201 'securepoll-dump-no-crypt' => "Per questa elezione non è disponibile nessuna registrazione criptata, perché l'elezione non è impostata per usare la crittazione.",
27203202 'securepoll-dump-not-finished' => "Le registrazioni criptate dell'elezione sono disponibili solo dopo la data di conclusione: $1 alle $2",
27213203 'securepoll-dump-no-urandom' => "Impossibile aprire /dev/urandom.
27223204 Per proteggere la riservatezza dei votanti, le registrazioni criptate dell'elezione sono disponibili pubblicamente solo quando potranno essere mescolate con un flusso sicuro di numeri casuali.",
 3205+ 'securepoll-urandom-not-supported' => 'Questo server non supporta la generazione di numeri casuali per la crittografia.
 3206+Al fine di garantire la privacy dei votanti, la procedura di votazione cifrata è pubblicamente utilizzabile quando è disponibile un generatore di numeri casuali per la crittografia del flusso di dati.',
27233207 'securepoll-translate-title' => 'Traduci: $1',
27243208 'securepoll-invalid-language' => 'Codice lingua non valido: "$1"',
27253209 'securepoll-submit-translate' => 'Aggiorna',
@@ -2730,6 +3214,21 @@
27313215 'securepoll-subpage-vote' => 'Vota',
27323216 'securepoll-subpage-translate' => 'Traduci',
27333217 'securepoll-subpage-list' => 'Elenca',
 3218+ 'securepoll-subpage-dump' => 'File di dump',
 3219+ 'securepoll-subpage-tally' => 'Conteggio',
 3220+ 'securepoll-tally-title' => 'Conteggio: $1',
 3221+ 'securepoll-tally-not-finished' => 'Non puoi effettuare il conteggio dei voti prima che la votazione sia terminata.',
 3222+ 'securepoll-can-decrypt' => "Le informazioni relative all'elezione sono state cifrate, ma è disponibile la chiave di decifratura.
 3223+Puoi scegliere di effettuare il conteggio dei risultati presenti nel database o di effettuare il conteggio dei risultati cifrati contenuti in un file caricato.",
 3224+ 'securepoll-tally-no-key' => 'Non puoi effettuare il conteggio dei risultati di questa elezione poiché i voti sono cifrati e la chiave di decifrazione non è disponibile.',
 3225+ 'securepoll-tally-local-legend' => 'Effettua il conteggio dei risultati memorizzati.',
 3226+ 'securepoll-tally-local-submit' => 'Crea conteggio',
 3227+ 'securepoll-tally-upload-legend' => 'Carica un file di dump cifrato',
 3228+ 'securepoll-tally-upload-submit' => 'Crea conteggio',
 3229+ 'securepoll-tally-error' => "Errore nell'elaborazione delle informazioni del voto, non è possibile effettuare il conteggio.",
 3230+ 'securepoll-no-upload' => 'Nessun file è stato caricato, non è possibile effettuare il conteggio.',
 3231+ 'securepoll-dump-corrupt' => 'Il file di dump è corrotto e non può essere elaborato.',
 3232+ 'securepoll-tally-upload-error' => "Errore nell'effettuare il conteggio sul file di dump: $1",
27343233 );
27353234
27363235 /** Japanese (日本語)
@@ -2775,13 +3274,15 @@
27763275 'securepoll-jump' => '投票サーバへ移動',
27773276 'securepoll-bad-ballot-submission' => 'あなたの投票は無効でした: $1',
27783277 'securepoll-unanswered-questions' => 'すべての質問に答えなくてはなりません。',
 3278+ 'securepoll-invalid-rank' => '順位が無効です。各候補に対しては1から999の間で順位を付けなければなりません。',
 3279+ 'securepoll-unranked-options' => '順位が付けられていない選択肢があります。すべての選択肢に1から999の間で順位を付けなければなりません。',
27793280 'securepoll-remote-auth-error' => 'エラー:サーバからあなたのアカウント情報を取得できませんでした',
27803281 'securepoll-remote-parse-error' => 'サーバーからの認証応答の解釈に失敗しました。',
27813282 'securepoll-api-invalid-params' => '不正なパラメータ。',
27823283 'securepoll-api-no-user' => '指定されたIDをもつ利用者が見つかりません。',
27833284 'securepoll-api-token-mismatch' => 'セキュリティ・トークンが一致しないのでログインできません。',
27843285 'securepoll-not-logged-in' => 'この投票に参加するためにはログインしていなければいけません',
2785 - 'securepoll-too-few-edits' => '申し訳ありませんが、あなたは投票できません。この投票に参加するためには少なくとも$1回の編集を行なっていなければなりません。現在の編集回数は$2です。',
 3286+ 'securepoll-too-few-edits' => '申し訳ありませんが、あなたは投票できません。この投票に参加するためには少なくとも$1{{PLURAL:$1|回}}の編集を行なっていなければなりません。現在の編集回数は$2です。',
27863287 'securepoll-blocked' => '申し訳ありませんが、あなたは投稿ブロックを受けているためこの投票に参加できません。',
27873288 'securepoll-bot' => '申し訳ありませんが、ボットフラグのあるアカウントはこの選挙で投票することが許可されていません。',
27883289 'securepoll-not-in-group' => '$1グループに属する利用者のみがこの投票に参加できます。',
@@ -2799,6 +3300,7 @@
28003301 'securepoll-strike-reason' => '理由:',
28013302 'securepoll-strike-cancel' => 'キャンセル',
28023303 'securepoll-strike-error' => '抹消あるいは抹消撤回の実行に失敗: $1',
 3304+ 'securepoll-strike-token-mismatch' => 'セッション情報消失',
28033305 'securepoll-details-link' => '詳細',
28043306 'securepoll-details-title' => '票の詳細: #$1',
28053307 'securepoll-invalid-vote' => '"$1"は有効な票IDではありません',
@@ -2813,6 +3315,7 @@
28143316 'securepoll-dump-no-crypt' => 'この選挙は暗号化を利用するように設定されていないため、暗号化された選挙記録は入手できません。',
28153317 'securepoll-dump-not-finished' => '暗号化された選挙記録は終了日の$1 $2以降にのみ入手できます',
28163318 'securepoll-dump-no-urandom' => '/dev/urandom を開けません。投票者のプライバシーを守るため、暗号化された選挙記録は暗号用乱数ストリームでシャッフルできる場合のみ公に入手できます。',
 3319+ 'securepoll-urandom-not-supported' => 'このサーバーは暗号学的乱数生成に対応していません。投票者のプライバシーを守るため、暗号化された選挙記録は暗号用乱数ストリームでシャッフルできる場合のみ公に入手できます。',
28173320 'securepoll-translate-title' => '翻訳: $1',
28183321 'securepoll-invalid-language' => '「$1」は無効な言語コードです',
28193322 'securepoll-submit-translate' => '更新',
@@ -2838,6 +3341,62 @@
28393342 'securepoll-no-upload' => 'ファイルがアップロードされておらず、結果を集計できません。',
28403343 );
28413344
 3345+/** Georgian (ქართული)
 3346+ * @author David1010
 3347+ * @author გიორგიმელა
 3348+ */
 3349+$messages['ka'] = array(
 3350+ 'securepoll' => 'უსაფრთხო კეჭისყრა',
 3351+ 'securepoll-invalid-election' => '"$1" არ წარმოადგენს არჩევნებისათვის დასაშვებ იდენტიფიკატორს.',
 3352+ 'securepoll-welcome' => '<strong>კეთილი იყოს თქვენი მობრძანება $1!</strong>',
 3353+ 'securepoll-submit' => 'ხმის მიცემა',
 3354+ 'securepoll-thanks' => 'გმადლობთ, თქვენი ხმა მიღებულია.',
 3355+ 'securepoll-return' => 'დაბრუნება $1–ზე',
 3356+ 'securepoll-full-gpg-error' => 'შეცდომა GPG შესრულებისას:
 3357+
 3358+ბრძანება: $1
 3359+
 3360+შეცდომა:
 3361+<pre>$2</pre>',
 3362+ 'securepoll-jump' => 'ხმის მიცემის სერვერზე გადასვლა',
 3363+ 'securepoll-bad-ballot-submission' => 'თქვენი ხმა ძალადაკარგულია: $1',
 3364+ 'securepoll-unanswered-questions' => 'თქვენ უნდა უპასუხოთ ყველა შეკითხვას.',
 3365+ 'securepoll-remote-auth-error' => 'შეცდომა ანგარიშზე ინფორმაციის მიღებისას სერვერიდან.',
 3366+ 'securepoll-api-invalid-params' => 'არასწორი პარამეტრები.',
 3367+ 'securepoll-api-no-user' => 'მომხმარებელი მითითებული იდენტიფიკატორით ვერ მოიძებნა.',
 3368+ 'securepoll-list-title' => 'ხმების სია: $1',
 3369+ 'securepoll-header-timestamp' => 'დრო',
 3370+ 'securepoll-header-voter-name' => 'სახელი',
 3371+ 'securepoll-header-voter-domain' => 'დომენი',
 3372+ 'securepoll-header-ua' => 'მომხმარებლის აგენტი',
 3373+ 'securepoll-header-details' => 'დეტალები',
 3374+ 'securepoll-strike-reason' => 'მიზეზი:',
 3375+ 'securepoll-strike-cancel' => 'გაუქმება',
 3376+ 'securepoll-strike-token-mismatch' => 'სესიის მონაცემების დაკარგვა',
 3377+ 'securepoll-details-link' => 'დეტალები',
 3378+ 'securepoll-details-title' => 'ხმის მიცემის დეტალები: #$1',
 3379+ 'securepoll-invalid-vote' => '"$1" არ წარმოადგენს ხმის მიცემისთვის დასაშვებ იდენტიფიკატორს',
 3380+ 'securepoll-header-voter-type' => 'ხმის მიმცემის ტიპი',
 3381+ 'securepoll-header-url' => 'URL',
 3382+ 'securepoll-header-action' => 'მოქმედება',
 3383+ 'securepoll-header-reason' => 'მიზეზი',
 3384+ 'securepoll-header-admin' => 'ადმინი',
 3385+ 'securepoll-translate-title' => 'თარგმნა: $1',
 3386+ 'securepoll-submit-translate' => 'განახლება',
 3387+ 'securepoll-language-label' => 'ენის არჩევა:',
 3388+ 'securepoll-submit-select-lang' => 'თარგმნა',
 3389+ 'securepoll-header-title' => 'სახელი',
 3390+ 'securepoll-header-start-date' => 'დაწყების თარიღი',
 3391+ 'securepoll-header-end-date' => 'დასრულების თარიღი',
 3392+ 'securepoll-subpage-vote' => 'ხმის მიცემა',
 3393+ 'securepoll-subpage-translate' => 'თარგმნა',
 3394+ 'securepoll-subpage-list' => 'სია',
 3395+ 'securepoll-subpage-tally' => 'დათვლა',
 3396+ 'securepoll-tally-title' => 'დათვლა: $1',
 3397+ 'securepoll-tally-local-submit' => 'დათვლის წარმოება',
 3398+ 'securepoll-tally-upload-submit' => 'დათვლის წარმოება',
 3399+);
 3400+
28423401 /** Korean (한국어)
28433402 * @author Kwj2772
28443403 * @author Mhha
@@ -2886,10 +3445,11 @@
28873446 'securepoll-no-decryption-key' => '암호 해독 키가 설정되지 않았습니다.
28883447 암호를 해독할 수 없습니다.',
28893448 'securepoll-jump' => '선거 서버로 이동하기',
2890 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
2891 -당신의 투표가 무효화되었습니다: $1
2892 -</div>',
 3449+ 'securepoll-bad-ballot-submission' => '당신의 투표가 무효화되었습니다: $1',
28933450 'securepoll-unanswered-questions' => '모든 질문에 답을 하셔야 합니다.',
 3451+ 'securepoll-invalid-rank' => '순위를 잘못 입력하였습니다. 당신은 후보자의 순위를 1부터 999까지 매겨야 합니다.',
 3452+ 'securepoll-unranked-options' => '어떤 선택 사항에 대한 순위가 매겨지지 않았습니다.
 3453+당신은 모든 선택 사항에 대해 1부터 999까지 순위를 매겨야 합니다.',
28943454 'securepoll-remote-auth-error' => '귀하의 계정 정보를 불러오는 중에 오류가 발생하였습니다.',
28953455 'securepoll-remote-parse-error' => '서버로부터 권한 응답에 따른 해석 오류가 발생',
28963456 'securepoll-api-invalid-params' => '명령 변수가 잘못되었습니다.',
@@ -2914,6 +3474,7 @@
29153475 'securepoll-strike-reason' => '이유:',
29163476 'securepoll-strike-cancel' => '취소',
29173477 'securepoll-strike-error' => '무효화/해제 과정에서 오류가 발생하였습니다: $1',
 3478+ 'securepoll-strike-token-mismatch' => '세션 데이터가 손실되었습니다.',
29183479 'securepoll-details-link' => '상세한 설명',
29193480 'securepoll-details-title' => '투표 설명: #$1',
29203481 'securepoll-invalid-vote' => '"$1"은 투표할 수 있는 ID가 아닙니다.',
@@ -2929,6 +3490,8 @@
29303491 'securepoll-dump-not-finished' => '암호화된 선거 기록은 오직 마지막 기한인 $1 $2가 지난 뒤에야 이용하실 수 있습니다.',
29313492 'securepoll-dump-no-urandom' => '/dev/urandom을 열 수 없습니다.
29323493 투표자의 사생활을 보호하기 위해서, 암호화된 선거 기록은 안전한 무작위 숫자 흐름으로 뒤섞일 수 있을 때 오직 공적으로 이용 가능합니다.',
 3494+ 'securepoll-urandom-not-supported' => '이 서버는 암호화 난수 생성을 지원하지 않습니다.
 3495+투표자의 개인 정보를 유지하기 위해, 선거 기록이 안전한 무작위 수열로 변환될 수 있을 경우에만 암호화된 선거 기록이 공개될 것입니다.',
29333496 'securepoll-translate-title' => '번역: $1',
29343497 'securepoll-invalid-language' => '"$1"은 인식되지 않는 언어 코드입니다.',
29353498 'securepoll-submit-translate' => '갱신',
@@ -2953,6 +3516,8 @@
29543517 'securepoll-tally-upload-submit' => '개표하기',
29553518 'securepoll-tally-error' => '투표 기록의 해석에 오류가 생겨서, 계정을 만들 수 없습니다.',
29563519 'securepoll-no-upload' => '파일이 올려지지 않아서, 결과를 집계할 수 없습니다.',
 3520+ 'securepoll-dump-corrupt' => '기록 파일에 문제가 있어서 처리할 수 없습니다.',
 3521+ 'securepoll-tally-upload-error' => '기록 파일을 개표하는 중 오류 발생: $1',
29573522 );
29583523
29593524 /** Ripoarisch (Ripoarisch)
@@ -3003,6 +3568,9 @@
30043569 'securepoll-jump' => 'Jangk op dä Server för de Afshtemmung',
30053570 'securepoll-bad-ballot-submission' => 'Ding Shtemm woh nit jöltesch: $1',
30063571 'securepoll-unanswered-questions' => 'Do moß op alle Froore en Antwoot jävve.',
 3572+ 'securepoll-invalid-rank' => 'Dat es ene verkeehte Rang. Do moß Dinge Kandidaate ene Rang zwesche 1 un 999 jävve.',
 3573+ 'securepoll-unranked-options' => 'Ene Deil vun dä Müjjeleschkeite hät keine Rang.
 3574+Do moß alle Müjjeleschkeite ene Rang zwesche 1 un 999 jevve.',
30073575 'securepoll-remote-auth-error' => 'Ene Fähler es opjetrodde, wi mer däm Server öm Ding Daate jefrooch hann.',
30083576 'securepoll-remote-parse-error' => 'Ene Fähler es opjetrodde. Mer kunnte met däm Server singem Zoshtemmungs_Kood nix aanfange.',
30093577 'securepoll-api-invalid-params' => 'Verkeehte Parrameeterre.',
@@ -3028,6 +3596,7 @@
30293597 'securepoll-strike-reason' => 'Aaanlaß o Jrund:',
30303598 'securepoll-strike-cancel' => 'Ophüre!',
30313599 'securepoll-strike-error' => 'Ene Fähler is opjetrodde beim Ußshtriishe odder widder zerök holle: $1',
 3600+ 'securepoll-strike-token-mismatch' => 'De Sezungsdaate sin fott',
30323601 'securepoll-details-link' => 'Einzelheite',
30333602 'securepoll-details-title' => 'Einzelheite vun dä Shtemm met dä Kennong: „$1“',
30343603 'securepoll-invalid-vote' => '„$1“ kein reschtijje Kännong för en Afshtemmung',
@@ -3045,6 +3614,8 @@
30463615 'securepoll-dump-no-urandom' => 'Mer künne <code>/dev/random</code> nit opmaache.
30473616 Öm dä Afshtemmer ze schötze, don mer verschlößelte Datesäz bloß dann ußjävve,
30483617 wann mer se met enem seschere, zohfällije Dateshtrom verwörfelle künne.',
 3618+ 'securepoll-urandom-not-supported' => 'Hee dä ßööver kann kein Zohfallszahle för et Verschößele maache.
 3619+Öm et Wahljeheimnis ze bewaahre, sin de verschößelte Opzeichnunge vun der Stemme bloß dann öffentlich ze han, wann mer se en ene seshere zofällije Reijefollsh zeije künne.',
30493620 'securepoll-translate-title' => 'Övveräze: $1',
30503621 'securepoll-invalid-language' => '„<code>$1</code>“ es enne onjöltijje Shprooche_Kood',
30513622 'securepoll-header-trans-id' => 'Kennong',
@@ -3070,6 +3641,8 @@
30713642 'securepoll-tally-upload-submit' => 'Lohß Jonn!',
30723643 'securepoll-tally-error' => 'Beim Ungersöke vun ene Shtemm es jet donevve jejange, dröm künne mer nix ußzälle.',
30733644 'securepoll-no-upload' => 'Nix huhjelaade, do künne mer kein Shtemme ußzälle.',
 3645+ 'securepoll-dump-corrupt' => 'De <i lang="en">dump</i>-Dattei es kappoott un kann nit verärbeidt wääde.',
 3646+ 'securepoll-tally-upload-error' => 'Ene Fähler es opjetrodde beim Ußzälle noh dä <i lang="en">dump</i>-Dattei: $1',
30743647 );
30753648
30763649 /** Luxembourgish (Lëtzebuergesch)
@@ -3104,19 +3677,30 @@
31053678 Är Stëmm gouf net gespäichert!
31063679
31073680 $1',
 3681+ 'securepoll-no-gpg-home' => 'De Basis-Repertoire GPG konnt net ugeluecht ginn.',
 3682+ 'securepoll-secret-gpg-error' => 'Feeler beim Ausféiere vun GPG.
 3683+Benotzt $wgSecurePollShowErrorDetail=true; op LocalSettings.php fir méi Detailer ze gesinn.',
 3684+ 'securepoll-full-gpg-error' => 'Feeler beim Ausféiere vun GPG:
 3685+
 3686+Kommando: $1
 3687+
 3688+Feeler:
 3689+<pre>$2</pre>',
31083690 'securepoll-gpg-config-error' => "D'GPG-Schlëssele sinn net korrekt konfiguréiert.",
31093691 'securepoll-gpg-parse-error' => 'Feeler beim Interpretéieren vum GPG-Ouput',
31103692 'securepoll-no-decryption-key' => 'Et ass keen Ëntschlësungsschlëssel agestallt.
31113693 Ëntschlësselung onméiglech.',
31123694 'securepoll-jump' => 'Op den Ofstëmmungs-Server goen',
3113 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
3114 -Är Stëmm ass net valabel: $1
3115 -</div>',
 3695+ 'securepoll-bad-ballot-submission' => 'Är Stëmm ass net valabel: $1',
31163696 'securepoll-unanswered-questions' => 'Dir musst all Froe beäntwerten',
 3697+ 'securepoll-invalid-rank' => 'Ongëltegt Classement. Dir musst de Kandidaten e Classement tëschent 1 an 999 ginn.',
 3698+ 'securepoll-unranked-options' => 'E puer Optioune krute kee Classement.
 3699+Dir musst allen optiounen e Classement tëschent 1 an 999 ginn.',
31173700 'securepoll-remote-auth-error' => 'Feeler beim Ofruf vun Äre Benotzerkontinformatioune vum Server.',
31183701 'securepoll-remote-parse-error' => 'Feeler beim Interpretéiere vun der Autorisatioun déi de Server geschéckt huet.',
31193702 'securepoll-api-invalid-params' => 'Parameter déi net valabel sinn.',
31203703 'securepoll-api-no-user' => 'Et gouf kee Benotzer mat der ID fonnt déi ugi war.',
 3704+ 'securepoll-api-token-mismatch' => 'Falsche Sécerheeets-Token, Aloggen ass net méiglech.',
31213705 'securepoll-not-logged-in' => 'Dir musst Iech aloggen fir bäi dëse Walen ofstëmmen ze kënnen',
31223706 'securepoll-too-few-edits' => 'Pardon, Dir däerft net ofstëmmen. Dir musst mindestens $1 {{PLURAL:$1|Ännerung|Ännerunge}} gemaacht hun, fir bäi dëse Walen ofstëmmen ze kënnen, Dir hutt der $2 gemaach.',
31233707 'securepoll-blocked' => 'Pardon, Dir kënnt net bäi dëse Walen ofstëmmen wann dir elo fir Ännerunge gespaart sidd.',
@@ -3136,6 +3720,7 @@
31373721 'securepoll-strike-reason' => 'Grond:',
31383722 'securepoll-strike-cancel' => 'Ofbriechen',
31393723 'securepoll-strike-error' => 'Feeler beim Sträiche respektiv Ophiewe vum Sträichen: $1',
 3724+ 'securepoll-strike-token-mismatch' => 'Verloscht vun den Donnéeë vun der Verbindung',
31403725 'securepoll-details-link' => 'Detailer',
31413726 'securepoll-details-title' => 'Detailer vun der Ofstëmmung: #$1',
31423727 'securepoll-invalid-vote' => '"$1" ass keng valabel Ofstëmmngs-ID',
@@ -3149,6 +3734,8 @@
31503735 'securepoll-dump-title' => 'Dump: $1',
31513736 'securepoll-dump-no-crypt' => "Fir dës Wale gëtt et keng verschlësselt Donnéeë vun der Ofstëmmung, well d'Walen net esou agestallt sinn fir d'Verschlësselung ze benotzen.",
31523737 'securepoll-dump-not-finished' => 'Verschlësselt Donnéeë vun de Wale sinn eréischt nom Enn vun de Walen den $1 ëm $2 disponibel',
 3738+ 'securepoll-dump-no-urandom' => "/dev/urandom kann net opgemaach ginn.
 3739+Fir d'Konfidentialitéit vun de Wieler z'assuréieren, si verschlësselt Opzeechnunge vun de Walen nëmmen disponibel wa se mat engem sécheren Zoufallszuelestroum kënne gemescht ginn.",
31533740 'securepoll-translate-title' => 'Iwwersetzen: $1',
31543741 'securepoll-invalid-language' => 'Net valabele Sproochecode "$1"',
31553742 'securepoll-submit-translate' => 'Aktualiséieren',
@@ -3171,6 +3758,8 @@
31723759 'securepoll-tally-upload-submit' => 'Auszielung uleeën',
31733760 'securepoll-tally-error' => "Feeler bäi der Interpretatioun vun de gespäicherten Donnéeë vun de Walen, d'Auszieleung kann net gemaach ginn.",
31743761 'securepoll-no-upload' => "Et gouf kee Fichier eropgelueden, d'Resultater kënnen net ausgezielt ginn.",
 3762+ 'securepoll-dump-corrupt' => 'Den Dump-Fichier ass futti a kann net verschafft ginn.',
 3763+ 'securepoll-tally-upload-error' => 'Feeler bei der Auswertung vum Dump-Fichier: $1',
31753764 );
31763765
31773766 /** Limburgish (Limburgs)
@@ -3220,9 +3809,7 @@
32213810 'securepoll-no-decryption-key' => "d'r Is geine decryptiesjleutel ingesjteld.
32223811 Decodere is neet meugelik.",
32233812 'securepoll-jump' => 'Gank nao de sjtömserver',
3224 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
3225 -Dien sjtöm is óngeldig: $1
3226 -</div>',
 3813+ 'securepoll-bad-ballot-submission' => 'Dien sjtöm is óngeldig: $1',
32273814 'securepoll-unanswered-questions' => 'Doe mós alle vraoge beantjwaorde.',
32283815 'securepoll-remote-auth-error' => "d'r Is 'n fout opgetraoje bie 't ophaole van dien gebroekersinformatie van de server.",
32293816 'securepoll-remote-parse-error' => "d'r Is 'n fout opgetraoje bie 't interpretere van 't antjwaord van de server.",
@@ -3285,18 +3872,113 @@
32863873 * @author Matasg
32873874 */
32883875 $messages['lt'] = array(
 3876+ 'securepoll' => 'Saugus balsavimas',
 3877+ 'securepoll-desc' => 'Priemonė rinkimams ir apklausoms',
 3878+ 'securepoll-invalid-page' => 'Netinkamas subpuslapis "<nowiki>$1</nowiki>"',
 3879+ 'securepoll-need-admin' => 'Jei norite atlikti šį veiksmą, Jums reikia administratoriumi.',
 3880+ 'securepoll-too-few-params' => 'Nepakanka subpuslapio parametrų (negalioja nuoroda).',
32893881 'securepoll-invalid-election' => '"$1" nėra tinkamas rinkimų ID.',
32903882 'securepoll-welcome' => '<strong>Sveiki $1!</strong>',
 3883+ 'securepoll-not-started' => 'Šie rinkimai dar nėra prasidėję.
 3884+Jie turėtų prasidėti $2 $3.',
 3885+ 'securepoll-finished' => 'Šie rinkimai baigėsi, jūs nebegalite balsuoti.',
 3886+ 'securepoll-not-qualified' => 'Jūs nesate kvalifikuotas balsuoti šiuose rinkimuose: $1',
 3887+ 'securepoll-change-disallowed' => 'Jūs balsavote šiuose rinkimuose anksčiau.
 3888+Atsiprašome, jūs negalite balsuoti dar kartą.',
 3889+ 'securepoll-change-allowed' => '<strong>Pastaba: Jūs balsavote anksčiau.</strong>
 3890+Galite pakeisti savo balsą, pasinaudodamas forma žemiau.
 3891+Jei tai padarysite, jūsų originalus balsavimas bus atmestas.',
32913892 'securepoll-submit' => 'Balsuoti',
 3893+ 'securepoll-gpg-receipt' => 'Dėkojame už balsą.
 3894+
 3895+Jei norite, galite nusikopijuoti išrašą, kaip įrodymą, kad balsavote:
 3896+
 3897+<pre>$1</pre>',
32923898 'securepoll-thanks' => 'Ačiū, jūsų balsas buvo įrašytas.',
32933899 'securepoll-return' => 'Grįžti į $1',
 3900+ 'securepoll-encrypt-error' => 'Nepavyko užšifruoti jūsų balsavimo įrašo.
 3901+Jūsų balsavimas nebuvo užregistruotas!
 3902+
 3903+$1',
 3904+ 'securepoll-no-gpg-home' => 'Nepavyko sukurti GPG katalogo.',
 3905+ 'securepoll-secret-gpg-error' => 'GPG vykdymo klaida.
 3906+Naudokite $wgSecurePollShowErrorDetail=true; skripte LocalSettings.php jei norite sužinoti daugiau informacijos.',
 3907+ 'securepoll-full-gpg-error' => 'GPG vykdymo klaida:
 3908+
 3909+Komanda: $1
 3910+
 3911+Klaida:
 3912+<pre>$2</pre>',
32943913 'securepoll-gpg-config-error' => 'GPG raktai sukonfigūruoti netinkamai.',
 3914+ 'securepoll-gpg-parse-error' => 'Klaida interpretuojant GPG išeigą.',
 3915+ 'securepoll-no-decryption-key' => 'Nėra sukonfigūruoto atkodavimo rakto.
 3916+Negalima iššifruoti.',
32953917 'securepoll-jump' => 'Eiti į balsavimo serverį',
3296 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
3297 -Jūsų balsas netinkamas: $1
3298 -</div>',
 3918+ 'securepoll-bad-ballot-submission' => 'Jūsų balsas netinkamas: $1',
 3919+ 'securepoll-unanswered-questions' => 'Turite atsakyti į visus klausimus.',
 3920+ 'securepoll-remote-auth-error' => 'Įvyko klaida pristatant jūsų sąskaitos informaciją iš serverio.',
 3921+ 'securepoll-remote-parse-error' => 'Klaida interpretuojant leidimo atsakymą iš serverio.',
32993922 'securepoll-api-invalid-params' => 'Netinkami parametrai',
33003923 'securepoll-api-no-user' => 'Nerastas naudotojas su duotu ID.',
 3924+ 'securepoll-api-token-mismatch' => 'Saugos žymės nesutampa, negalite prisijungti',
 3925+ 'securepoll-not-logged-in' => 'Jūs turite prisijungti, norėdami balsuoti šiuose rinkimuose',
 3926+ 'securepoll-too-few-edits' => 'Atsiprašome, Jūs negalite balsuoti. Jūs privalote atlikti bent $1 {{PLURAL:$1|redagavimą|redagavimų}}, norėdami balsuoti šiuose rinkimuose. Jūs atlikote $2.',
 3927+ 'securepoll-blocked' => 'Atsiprašome, Jūs negalite balsuoti šiuose rinkimuose jei dabar esate užblokuotas.',
 3928+ 'securepoll-bot' => 'Atsiprašome, sąskaitos su boto statusu negali balsuoti šiuose rinkimuose.',
 3929+ 'securepoll-not-in-group' => 'Tik nariai iš grupės "$1" gali balsuoti šiuose rinkimuose.',
 3930+ 'securepoll-not-in-list' => 'Atsiprašome, Jūs nesate vartotojų sąraše, kuriems leidžiama balsuoti šiuose rinkimuose.',
 3931+ 'securepoll-list-title' => 'Rodyti balsus: $1',
 3932+ 'securepoll-header-timestamp' => 'Laikas',
 3933+ 'securepoll-header-voter-name' => 'Vardas',
 3934+ 'securepoll-header-voter-domain' => 'Domenas',
 3935+ 'securepoll-header-ua' => 'Naudotojo agentas',
 3936+ 'securepoll-header-cookie-dup' => 'Nuor.',
 3937+ 'securepoll-header-strike' => 'Uždrausti',
 3938+ 'securepoll-header-details' => 'Detalės',
 3939+ 'securepoll-strike-button' => 'Uždrausti',
 3940+ 'securepoll-unstrike-button' => 'Nebedrausti',
 3941+ 'securepoll-strike-reason' => 'Priežastis:',
 3942+ 'securepoll-strike-cancel' => 'Atšaukti',
 3943+ 'securepoll-strike-error' => 'Klaida atliekant uždraudimą/nebedraudimą: $1',
 3944+ 'securepoll-details-link' => 'Detalės',
 3945+ 'securepoll-details-title' => 'Balsavimo detalės: #$1',
 3946+ 'securepoll-invalid-vote' => '"$1" nėra teisingas balsavimo ID',
 3947+ 'securepoll-header-voter-type' => 'Balsavusiojo tipas',
 3948+ 'securepoll-voter-properties' => 'Balsuotojo savybės',
 3949+ 'securepoll-strike-log' => 'Uždraudimo sąrašas',
 3950+ 'securepoll-header-action' => 'Veiksmas',
 3951+ 'securepoll-header-reason' => 'Priežastis',
 3952+ 'securepoll-header-admin' => 'Administratorius',
 3953+ 'securepoll-cookie-dup-list' => 'Cookie dublikuoti naudotojai',
 3954+ 'securepoll-dump-title' => 'Išmestas: $1',
 3955+ 'securepoll-dump-no-crypt' => 'Nėra prieinamas nė vienas šifruotas rinkimų įrašas, nes rinkimai nėra sukonfigūruoti naudoti kodavimą.',
 3956+ 'securepoll-dump-not-finished' => 'Šifruoti rinkimų įrašai prieinami tik po $1 $2',
 3957+ 'securepoll-dump-no-urandom' => 'Nepavyko atidaryti /dev/urandom.
 3958+Siekiant išlaikyti balsuotojų privatumą, šifruoti rinkimų įrašai viešai prieinami tik kai jie sumaišyti su saugiu atsitiktinių skaičių srautu.',
 3959+ 'securepoll-translate-title' => 'Išversti: $1',
 3960+ 'securepoll-invalid-language' => 'Neleistinas kalbos kodas "$1"',
 3961+ 'securepoll-submit-translate' => 'Atnaujinti',
 3962+ 'securepoll-language-label' => 'Pasirinkite kalbą:',
 3963+ 'securepoll-submit-select-lang' => 'Išversti',
 3964+ 'securepoll-header-title' => 'Pavadinimas',
 3965+ 'securepoll-header-start-date' => 'Pradžios data',
 3966+ 'securepoll-header-end-date' => 'Pabaigos data',
 3967+ 'securepoll-subpage-vote' => 'Balsavimas',
 3968+ 'securepoll-subpage-translate' => 'Vertimas',
 3969+ 'securepoll-subpage-list' => 'Sąrašas',
 3970+ 'securepoll-subpage-dump' => 'Perrašymas',
 3971+ 'securepoll-subpage-tally' => 'Rezultatas',
 3972+ 'securepoll-tally-title' => 'Rezultatas: $1',
 3973+ 'securepoll-tally-not-finished' => 'Atsiprašome, Jūs negalite paskelbti rinkimų rezultato iki balsavimo baigties.',
 3974+ 'securepoll-can-decrypt' => 'Rinkimų įrašas buvo šifruotas, tačiau iššifravimo raktas prieinamas.
 3975+Galite pasirinkti, ar sutampa rezultatai, esantys duomenų bazėje bei rezultatuoti šifruotus rezultatus iš įkelto failo.',
 3976+ 'securepoll-tally-no-key' => 'Jūs negalite paskelbti šių rinkimų rezultatų, nes balsai yra koduoti ir iššifravimo rakto nėra.',
 3977+ 'securepoll-tally-local-legend' => 'Paskelbti išsaugotus rezultatus',
 3978+ 'securepoll-tally-local-submit' => 'Sukurti rezultatus',
 3979+ 'securepoll-tally-upload-legend' => 'Įkelti šifruotą turinį',
 3980+ 'securepoll-tally-upload-submit' => 'Sukurti rezultatus',
 3981+ 'securepoll-tally-error' => 'Klaida interpretuojant balsavimo įrašą, negalima sukurti suvestinių.',
 3982+ 'securepoll-no-upload' => 'Failas nebuvo įkeltas, negalima skaičiuoti rezultatų.',
33013983 );
33023984
33033985 /** Macedonian (Македонски)
@@ -3356,9 +4038,7 @@
33574039 'securepoll-no-decryption-key' => 'Tiada kunci penyahsulitan dibentuk.
33584040 Tidak dapat menyahsulit.',
33594041 'securepoll-jump' => 'Pergi ke pelayan undian',
3360 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
3361 -Undi anda tak sah: $1
3362 -</div>',
 4042+ 'securepoll-bad-ballot-submission' => 'Undi anda tak sah: $1',
33634043 'securepoll-unanswered-questions' => 'Anda perlu jawab kesemua soalan.',
33644044 'securepoll-remote-auth-error' => 'Ralat dalam mengambil maklumat akaun anda dari pelayan.',
33654045 'securepoll-remote-parse-error' => 'Ralat menafsirkan jawapan kebenaran dari pelayan.',
@@ -3386,8 +4066,158 @@
33874067 'securepoll-strike-error' => 'Ralat membuang/kembalikan: $1',
33884068 'securepoll-details-link' => 'Lanjut',
33894069 'securepoll-details-title' => 'Maklumat undi: #$1',
 4070+ 'securepoll-invalid-vote' => '"$1" bukan ID undian yang sah',
 4071+ 'securepoll-header-voter-type' => 'Jenis pengundi',
 4072+ 'securepoll-voter-properties' => 'Sifat pengundi',
 4073+ 'securepoll-strike-log' => 'Log pemotongan',
 4074+ 'securepoll-header-action' => 'Tindakan',
 4075+ 'securepoll-header-reason' => 'Sebab',
 4076+ 'securepoll-header-admin' => 'Pentadbir',
 4077+ 'securepoll-cookie-dup-list' => 'Pengguna salinan cookie',
 4078+ 'securepoll-dump-title' => 'Longgokan: $1',
 4079+ 'securepoll-dump-no-crypt' => 'Tiada rekod sulit pemilihan yang ada untuk pemilihan ini, kerana pemilihan tidak disusun untuk menggunakan penyulitan.',
 4080+ 'securepoll-dump-not-finished' => 'Rekod sulit pemilihan hanya ada setelah tarikh tamat pada $1 pukul $2',
 4081+ 'securepoll-dump-no-urandom' => 'Gagal membuka /dev/urandom.
 4082+Untuk mengekalkan privasi pengundi, rekod sulit pemilihan hanya tersedia untuk awam apabila ia dirombak dengan aliran nombor rawak yang selamat.',
 4083+ 'securepoll-translate-title' => 'Terjemah: $1',
 4084+ 'securepoll-invalid-language' => 'Kod bahasa tidak sah "$1"',
 4085+ 'securepoll-submit-translate' => 'Kemas kini',
 4086+ 'securepoll-language-label' => 'Pilih bahasa:',
 4087+ 'securepoll-submit-select-lang' => 'Terjemah',
 4088+ 'securepoll-header-title' => 'Nama',
 4089+ 'securepoll-header-start-date' => 'Tarikh mula',
 4090+ 'securepoll-header-end-date' => 'Tarikh tamat',
 4091+ 'securepoll-subpage-vote' => 'Undi',
 4092+ 'securepoll-subpage-translate' => 'Terjemah',
 4093+ 'securepoll-subpage-list' => 'Senarai',
 4094+ 'securepoll-subpage-dump' => 'Longgokan',
 4095+ 'securepoll-subpage-tally' => 'Semak',
 4096+ 'securepoll-tally-title' => 'Semak: $1',
 4097+ 'securepoll-tally-not-finished' => 'Maaf, anda tidak dapat menyemak pemilihan sehingga selepas undian selesai.',
 4098+ 'securepoll-can-decrypt' => 'Rekod pemilihan telah disulitkan, tetapi kunci penyulitan dapat diperoleh.
 4099+Anda boleh memilih untuk menyemak keputusan yang ada dalam pangkalan data, atau menyemak keputusan yang disulitkan daripada fail yang dimuat naik.',
 4100+ 'securepoll-tally-no-key' => 'Anda tidak boleh menyemak pemilihan ini, kerana undian disulitkan, dan kunci penyulitan tidak dapat diperoleh.',
 4101+ 'securepoll-tally-local-legend' => 'Semak keputusan tersimpan',
 4102+ 'securepoll-tally-local-submit' => 'Cipta semakan',
 4103+ 'securepoll-tally-upload-legend' => 'Muat naik longgakan bersulit',
 4104+ 'securepoll-tally-upload-submit' => 'Cipta semakan',
 4105+ 'securepoll-tally-error' => 'Ralat mentafsir rekod undian, tidak dapat menghasilkan semakan.',
 4106+ 'securepoll-no-upload' => 'Tiada fail dimuat naik, tidak dapat menyemak keputusan.',
33904107 );
33914108
 4109+/** Maltese (Malti)
 4110+ * @author Chrisportelli
 4111+ */
 4112+$messages['mt'] = array(
 4113+ 'securepoll' => 'SecurePoll',
 4114+ 'securepoll-desc' => 'Estensjoni għall-elezzjonijiet u s-sondaġġi',
 4115+ 'securepoll-invalid-page' => 'Sottopaġna invalida "<nowiki>$1</nowiki>"',
 4116+ 'securepoll-need-admin' => 'Trid tkun amministratur biex tesegwixxi din l-azzjoni.',
 4117+ 'securepoll-too-few-params' => 'Parametri mhux biżżejjed tas-sottopaġna (ħolqa invalida)0.',
 4118+ 'securepoll-invalid-election' => '"$1" mhijiex ID valida għall-elezzjoni.',
 4119+ 'securepoll-welcome' => '<strong>Merħba $1!</strong>',
 4120+ 'securepoll-not-started' => 'Din l-elezzjoni għadha ma bdietx.
 4121+Hi skedata li tibda nhar $2 fil-$3.',
 4122+ 'securepoll-finished' => 'Din l-elezzjoni spiċċat, mhuwiex aktar possibbli li tivvota.',
 4123+ 'securepoll-not-qualified' => "Ma tikwalifikax biex tivvota f'din l-elezzjoni: $1",
 4124+ 'securepoll-change-disallowed' => "Diġà vvutajt f'din l-elezzjoni.
 4125+Mhuwiex possibbli li terġa' tivvota.",
 4126+ 'securepoll-change-allowed' => "<strong>Nota: Inti diġà vvutajt f'din l-elezzjoni.</strong>
 4127+Tista' tbiddel il-vot tiegħek billi tibgħat il-formola t'hawn taħt.
 4128+Kun af li jekk tagħmel dan, il-vot oriġinali tiegħek jiġi skartat.",
 4129+ 'securepoll-submit' => 'Ibgħat il-vot',
 4130+ 'securepoll-gpg-receipt' => "Grazzi talli tajt l-vot tiegħek.
 4131+
 4132+Jekk tixtieq tista' żżomm ir-riċevuta segwenti bħala evidenza tal-vot tiegħek:
 4133+
 4134+<pre>$1</pre>",
 4135+ 'securepoll-thanks' => 'Grazzi, il-vot tiegħek ġie reġistrat.',
 4136+ 'securepoll-return' => "Erġa' lura lejn $1.",
 4137+ 'securepoll-encrypt-error' => 'Impossibbli li l-voti tiegħek jiġi reġistrat.
 4138+Il-vot ma ġiex reġistrat!
 4139+
 4140+$1',
 4141+ 'securepoll-no-gpg-home' => "Impossibbli toħloq id-direttorju tad-destinazzjoni ta' GPG.",
 4142+ 'securepoll-secret-gpg-error' => "Żball waqt l-eżekuzzjoni ta' GPG.
 4143+Uża \$wgSecurePollShowErrorDetail=true; f'LocalSettings.php biex turi aktar dettalji.",
 4144+ 'securepoll-full-gpg-error' => "Żball waqt l-eżekuzzjoni ta' GPG:
 4145+
 4146+Kmanda: $1
 4147+
 4148+Żball:
 4149+<pre> $2 </pre>",
 4150+ 'securepoll-gpg-config-error' => 'Iċ-ċwievet GPG ma ġew konfigurati sewwa.',
 4151+ 'securepoll-gpg-parse-error' => "Żball fl-interpretazzjoni tar-riżultat ta' GPG.",
 4152+ 'securepoll-no-decryption-key' => "L-ebda ċavetta ta' dekritazzjoni ma ġiet konfigurata.
 4153+Impossibbli li tiġi deċifrata.",
 4154+ 'securepoll-jump' => 'Mur fis-server tal-votazzjoni',
 4155+ 'securepoll-bad-ballot-submission' => 'Il-vot tiegħek kien invalidu: $1',
 4156+ 'securepoll-unanswered-questions' => 'Trid tirrispondi kull mistoqsija.',
 4157+ 'securepoll-remote-auth-error' => 'Żball waqt ir-ripristinaġġ mis-server tal-informazzjoni fuq il-kont tiegħek.',
 4158+ 'securepoll-remote-parse-error' => "Żball fl-interpretazzjoni mis-server tar-risposta ta' awtorizzazzjoni.",
 4159+ 'securepoll-api-invalid-params' => 'Parametri invalidi.',
 4160+ 'securepoll-api-no-user' => 'L-ebda utent ma nstab bl-ID li ngħatat.',
 4161+ 'securepoll-api-token-mismatch' => "It-token ta' sigurtà ma jaqbilx, ma tistax tidħol.",
 4162+ 'securepoll-not-logged-in' => "Trid teffettwa l-login qabel ma tivvota f'din l-elezzjoni",
 4163+ 'securepoll-too-few-edits' => "Jiddispjaċina, ma tistax tivvota. Trid tal-anqas tkun għamilt $1 {{PLURAL:$1|modifika|modifika}} biex tivvota f'din l-elezzjoni, inti għamilt $2.",
 4164+ 'securepoll-blocked' => "Jiddispjaċina, ma tistax tivvota f'din l-elezzjoni jekk inti attwalment imblukkat milli timmodifika.",
 4165+ 'securepoll-bot' => "Jiddispjaċina, il-kontijiet li għandhom l-istatus ta' bot ma jistgħux jivvutaw f'din l-elezzjoni.",
 4166+ 'securepoll-not-in-group' => 'Il-membri biss tal-grupp "$1" jistgħu jivvutaw f\'din l-elezzjoni.',
 4167+ 'securepoll-not-in-list' => "Jiddispjaċina, mintix fil-lista predeterminata tal-utenti awtorizzati li jivvutaw f'din l-elezzjoni.",
 4168+ 'securepoll-list-title' => 'Lista tal-voti: $1',
 4169+ 'securepoll-header-timestamp' => 'Ħin',
 4170+ 'securepoll-header-voter-name' => 'Isem',
 4171+ 'securepoll-header-voter-domain' => 'Dominju',
 4172+ 'securepoll-header-ua' => 'Aġent tal-utent',
 4173+ 'securepoll-header-cookie-dup' => 'Dup',
 4174+ 'securepoll-header-strike' => 'Annulla',
 4175+ 'securepoll-header-details' => 'Dettalji',
 4176+ 'securepoll-strike-button' => 'Annulla dan il-vot',
 4177+ 'securepoll-unstrike-button' => 'Neħħi l-annulament',
 4178+ 'securepoll-strike-reason' => 'Raġuni:',
 4179+ 'securepoll-strike-cancel' => 'Annulla',
 4180+ 'securepoll-strike-error' => 'Żball waqt l-annulament jew ir-ripristinaġġ tal-vot: $1',
 4181+ 'securepoll-details-link' => 'Dettalji',
 4182+ 'securepoll-details-title' => 'Dettalji tal-vot: #$1',
 4183+ 'securepoll-invalid-vote' => '"$1" mhijiex ID ta\' vot validu',
 4184+ 'securepoll-header-voter-type' => "Tip ta' votant",
 4185+ 'securepoll-voter-properties' => 'Proprjetajiet tal-votant',
 4186+ 'securepoll-strike-log' => 'Reġistru tal-annulamenti',
 4187+ 'securepoll-header-action' => 'Azzjoni',
 4188+ 'securepoll-header-reason' => 'Raġuni',
 4189+ 'securepoll-header-admin' => 'Amministratur',
 4190+ 'securepoll-cookie-dup-list' => 'Utenti doppji skont il-cookie',
 4191+ 'securepoll-dump-title' => 'Dump: $1',
 4192+ 'securepoll-dump-no-crypt' => "Għal din l-elezzjoni mhi disponibbli l-ebda reġistrazzjoni kriptata, minħabba li l-elezzjoni mhix imposta li tuża' l-kritazzjoni.",
 4193+ 'securepoll-dump-not-finished' => "Ir-reġistrazzjonijiet kriptati tal-elezzjoni huma disponibbli biss wara d-data ta' konklużjoni: $1 fil-$2",
 4194+ 'securepoll-dump-no-urandom' => "Ma jistax jinfetaħ /dev/urandom.
 4195+Biex tinżamm il-privatezza tal-votant, ir-reġistrazzjonijieet kriptati tal-elezzjoni huma disponibbli pubblikament biss meta jistgħu jkunu mħawwda b'influss sigur ta' numru każwali.",
 4196+ 'securepoll-translate-title' => 'Ittraduċi: $1',
 4197+ 'securepoll-invalid-language' => 'Kodiċi tal-lingwa invalidu: "$1"',
 4198+ 'securepoll-submit-translate' => 'Aġġorna',
 4199+ 'securepoll-language-label' => 'Agħżel lingwa:',
 4200+ 'securepoll-submit-select-lang' => 'Ittraduċi',
 4201+ 'securepoll-header-title' => 'Isem',
 4202+ 'securepoll-header-start-date' => 'Data tal-bidu',
 4203+ 'securepoll-header-end-date' => 'Data tat-tmiem',
 4204+ 'securepoll-subpage-vote' => 'Ivvota',
 4205+ 'securepoll-subpage-translate' => 'Ittraduċi',
 4206+ 'securepoll-subpage-list' => 'Elenka',
 4207+ 'securepoll-subpage-dump' => 'Dump',
 4208+ 'securepoll-subpage-tally' => 'Talja',
 4209+ 'securepoll-tally-title' => 'Talja: $1',
 4210+ 'securepoll-tally-not-finished' => 'Jiddispjaċina, ma tisgtħux tgħoddu r-riżultati tal-elezzjoni qabel mal-votazzjoni tispiċċa.',
 4211+ 'securepoll-can-decrypt' => "Ir-reġistru tal-elezzjoni ġie kriptat, però ċ-ċavetta ta' dekritazzjoni hija disponibbli.
 4212+Inti tista' tagħżel jew li tgħodd ir-riżultati preżenti fid-databażi, jew li tgħodd ir-riżultati kriptati minn fajl imtella'.",
 4213+ 'securepoll-tally-no-key' => 'Ma tistax tgħodd ir-riżultati tal-elezzjoni, minħabba li l-voti huma kriptati, u ċ-ċavetta tad-dekritazzjoni mhix disponibbli.',
 4214+ 'securepoll-tally-local-legend' => 'L-għadd tar-riżultati salvati',
 4215+ 'securepoll-tally-local-submit' => 'Oħloq talja',
 4216+ 'securepoll-tally-upload-legend' => "Tella' riserva kriptata",
 4217+ 'securepoll-tally-upload-submit' => 'Oħloq talja',
 4218+ 'securepoll-tally-error' => 'Żball fl-interpretazzjoni tar-reġistrazzjoni tal-vot, ir-riżultati ma jistgħux jingħaddu.',
 4219+ 'securepoll-no-upload' => "L-ebda fajl ma ġie mtella', ir-riżultati ma jistgħux jingħaddu.",
 4220+);
 4221+
33924222 /** Low German (Plattdüütsch)
33934223 * @author Slomox
33944224 */
@@ -3434,9 +4264,7 @@
34354265 'securepoll-no-decryption-key' => 'Keen Opslötel-Slötel instellt.
34364266 Opslöteln geiht nich.',
34374267 'securepoll-jump' => 'Na’n Afstimmserver gahn',
3438 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
3439 -Dien Stimm weer ungüllig: $1
3440 -</div>',
 4268+ 'securepoll-bad-ballot-submission' => 'Dien Stimm weer ungüllig: $1',
34414269 'securepoll-unanswered-questions' => 'Du musst all Fragen antern.',
34424270 'securepoll-remote-auth-error' => 'Fehler bi’t Afropen vun dien Brukerkonteninfos vun’n Server.',
34434271 'securepoll-remote-parse-error' => 'Fehler bi’t Interpreteren vun de Antwoord vun’n Server to de Rechten.',
@@ -3562,6 +4390,10 @@
35634391 'securepoll-jump' => 'Naar de stemserver gaan',
35644392 'securepoll-bad-ballot-submission' => 'Uw stem is ongeldig: $1',
35654393 'securepoll-unanswered-questions' => 'U moet alle vragen beantwoorden.',
 4394+ 'securepoll-invalid-rank' => 'Ongeldige rang.
 4395+U moet de kandidaten een rang geven tussen 1 en 999.',
 4396+ 'securepoll-unranked-options' => 'Sommige stemmogelijkheden hebben geen rang.
 4397+U moet alle mogelijkheden een rang geven tussen 1 en 999.',
35664398 'securepoll-remote-auth-error' => 'Er is een fout opgetreden bij het ophalen van uw gebruikersinformatie van de server.',
35674399 'securepoll-remote-parse-error' => 'Er is een fout opgetreden bij het interpreteren van het antwoord van de server.',
35684400 'securepoll-api-invalid-params' => 'Ongeldige parameters.',
@@ -3588,6 +4420,7 @@
35894421 'securepoll-strike-reason' => 'Reden:',
35904422 'securepoll-strike-cancel' => 'Annuleren',
35914423 'securepoll-strike-error' => 'Er is een fout opgetreden bij het uitvoeren doorhalen/doorhalen ongedaan maken: $1',
 4424+ 'securepoll-strike-token-mismatch' => 'De sessiegegevens zijn verloren gegaan.',
35924425 'securepoll-details-link' => 'Details',
35934426 'securepoll-details-title' => 'Stemdetails: #$1',
35944427 'securepoll-invalid-vote' => '"$1" is geen geldig stemnummer',
@@ -3603,6 +4436,8 @@
36044437 'securepoll-dump-not-finished' => 'De versleutelde stemgegevens zijn pas beschikbaar na het eindigen van de stemming op $1 om $2',
36054438 'securepoll-dump-no-urandom' => 'Het was niet mogelijk om /dev/urandom te openen.
36064439 Om de privacy van de stemmers te beschermen, zijn de stemmingsgegevens pas beschikbaar als ze willekeurig gesorteerd kunnen worden met behulp van een willekeurige nummerreeks.',
 4440+ 'securepoll-urandom-not-supported' => 'Deze server biedt geen ondersteuning voor het versleuteld aanmaken van willekeurige getallen.
 4441+Om de anonimiteit van stemmers te handhaven, zijn de versleutelde stemresultaten pas beschikbaar als ze zijn herordend via een veilige reeks van willekeurige getallen.',
36074442 'securepoll-translate-title' => 'Vertalen: $1',
36084443 'securepoll-invalid-language' => 'Ongeldige taalcode "$1"',
36094444 'securepoll-submit-translate' => 'Bijwerken',
@@ -3637,6 +4472,7 @@
36384473 * @author Harald Khan
36394474 */
36404475 $messages['nn'] = array(
 4476+ 'securepoll' => 'TrygtVal',
36414477 'securepoll-desc' => 'Ei utviding for val og undersøkingar',
36424478 'securepoll-invalid-page' => 'Ugyldig underside «<nowiki>$1</nowiki>»',
36434479 'securepoll-need-admin' => 'Du må vera ein administrator for å kunna utføra denne handlinga.',
@@ -3676,25 +4512,44 @@
36774513 'securepoll-gpg-parse-error' => 'Feil ved tolking av utdata frå GPG.',
36784514 'securepoll-no-decryption-key' => 'Ingen dekrypteringsnøkkel er sett opp.
36794515 Kan ikkje dekryptera.',
 4516+ 'securepoll-jump' => 'Gå til stemmetenaren',
 4517+ 'securepoll-bad-ballot-submission' => 'Di stemme var ugyldig: $1',
36804518 'securepoll-unanswered-questions' => 'Du må svara på alle spørsmåla.',
36814519 'securepoll-remote-auth-error' => 'Feil oppstod ved henting av kontoinformasjonen din frå filtenaren.',
 4520+ 'securepoll-remote-parse-error' => 'Feil oppsto i samband med tolking av autorisasjonssvar frå tenaren',
 4521+ 'securepoll-api-invalid-params' => 'Ugyldige parametrar.',
36824522 'securepoll-api-no-user' => 'Ingen brukar var funnen med oppgjeven ID.',
36834523 'securepoll-not-logged-in' => 'Du må vera innlogga for å kunna røysta i dette valet',
 4524+ 'securepoll-too-few-edits' => 'Orsak, du kan ikkje røysta. Du lyt ha gjort minst {{PLURAL:$1|éi endring|$1 endringar}} for å kunna røysta ved dette valet. Du har gjort {{PLURAL:$2|éi|$2}}.',
36844525 'securepoll-blocked' => 'Du kan diverre ikkje røysta i dette valet om du for tida er blokkert frå å gjera endringar',
36854526 'securepoll-not-in-group' => 'Berre brukarar som er med i gruppa $1 kan røysta i denne avrøystinga.',
36864527 'securepoll-not-in-list' => 'Du er diverre ikkje på lista over brukarar som har løyve til å røysta i denne avrøystinga.',
 4528+ 'securepoll-list-title' => 'Vis stemmer: $1',
36874529 'securepoll-header-timestamp' => 'Tid',
36884530 'securepoll-header-voter-name' => 'Namn',
36894531 'securepoll-header-voter-domain' => 'Domene',
36904532 'securepoll-header-ua' => 'Brukaragent',
 4533+ 'securepoll-header-cookie-dup' => 'Dublett',
 4534+ 'securepoll-header-strike' => 'Stryk',
36914535 'securepoll-header-details' => 'Opplysingar',
 4536+ 'securepoll-strike-button' => 'Fjern',
 4537+ 'securepoll-unstrike-button' => 'Opphev strykinga',
36924538 'securepoll-strike-reason' => 'Grunngjeving:',
 4539+ 'securepoll-strike-cancel' => 'Avbryt',
 4540+ 'securepoll-strike-error' => 'Feil ved fjerning eller ved oppheving av fjerning: $1',
36934541 'securepoll-details-link' => 'Detaljar',
 4542+ 'securepoll-details-title' => 'Stemmedetaljar: #$1',
36944543 'securepoll-invalid-vote' => '«$1» er ikkje ein gyldig røyst-ID',
 4544+ 'securepoll-header-voter-type' => 'Stemmegjevartype',
 4545+ 'securepoll-voter-properties' => 'Eigenskapar for røystaren',
 4546+ 'securepoll-strike-log' => 'Strykingslogg',
36954547 'securepoll-header-action' => 'Handling',
36964548 'securepoll-header-reason' => 'Grunn',
36974549 'securepoll-header-admin' => 'Administrator',
 4550+ 'securepoll-cookie-dup-list' => 'Cookie duplikatbrukar',
 4551+ 'securepoll-dump-title' => 'Dump: $1',
36984552 'securepoll-dump-no-crypt' => 'Inga kryptert valregistrering er tilgjengeleg for dette valet, på grunn av at valet ikkje er sett opp til å nytta kryptering.',
 4553+ 'securepoll-dump-not-finished' => 'Krypterte valregister er berre tilgjengelege etter avsluttinga den $1 klokka $2',
36994554 'securepoll-translate-title' => 'Set om: $1',
37004555 'securepoll-invalid-language' => 'Ugyldig språkode "$1"',
37014556 'securepoll-submit-translate' => 'Oppdater',
@@ -3706,11 +4561,21 @@
37074562 'securepoll-subpage-vote' => 'Stem',
37084563 'securepoll-subpage-translate' => 'Set om',
37094564 'securepoll-subpage-list' => 'Utslisting',
 4565+ 'securepoll-subpage-dump' => 'Dump',
 4566+ 'securepoll-subpage-tally' => 'Oppteljing',
 4567+ 'securepoll-tally-title' => 'Oppteljing: $1',
 4568+ 'securepoll-tally-not-finished' => 'Diverre, du kan ikkje telja opp valresultatet før valet er fullført.',
 4569+ 'securepoll-can-decrypt' => 'Valregisteret har vorte kryptert, men dekrypteringsnøkkelen er tilgjengeleg.
 4570+Du kan velja å anten telja opp resultata tilgjengelege i databasen, eller å telja opp dei krypterte resultata frå ei opplasta fil.',
 4571+ 'securepoll-tally-no-key' => 'Du kan ikkje telja opp dette valet fordi stemmene er krypterte og dekrypteringsnøkkelen er utilgjengeleg.',
 4572+ 'securepoll-tally-upload-submit' => 'Opprett ei oppteljing',
 4573+ 'securepoll-no-upload' => 'Ingen fil vart lasta opp, kan ikkje summera resultata.',
37104574 );
37114575
37124576 /** Norwegian (bokmål)‬ (‪Norsk (bokmål)‬)
37134577 * @author Finnrind
37144578 * @author Guaca
 4579+ * @author Jon Harald Søby
37154580 * @author Laaknor
37164581 * @author Nghtwlkr
37174582 * @author Stigmj
@@ -3758,10 +4623,11 @@
37594624 'securepoll-no-decryption-key' => 'Ingen dekrypteringsnøkkel er konfigurert.
37604625 Kan ikke dekryptere.',
37614626 'securepoll-jump' => 'Gå til stemmetjeneren',
3762 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
3763 -Din stemme var ugyldig: $1
3764 -</div>',
 4627+ 'securepoll-bad-ballot-submission' => 'Din stemme var ugyldig: $1',
37654628 'securepoll-unanswered-questions' => 'Du må besvare alle spørsmålene.',
 4629+ 'securepoll-invalid-rank' => 'Ugyldig rangering. Du må gi kandidatene en rangering mellom 1 og 999.',
 4630+ 'securepoll-unranked-options' => 'Noen valg var urangerte.
 4631+Du må gi alle alternativene en rangering mellom 1 og 999.',
37664632 'securepoll-remote-auth-error' => 'Feil oppsto ved henting av din kontoinformasjon fra tjeneren.',
37674633 'securepoll-remote-parse-error' => 'Feil oppsto ved tolkning av autorisasjonssvar fra tjeneren.',
37684634 'securepoll-api-invalid-params' => 'Ugyldige parametere.',
@@ -3786,6 +4652,7 @@
37874653 'securepoll-strike-reason' => 'Årsak:',
37884654 'securepoll-strike-cancel' => 'Avbryt',
37894655 'securepoll-strike-error' => 'Feil ved fjerning eller ved opphevelse av fjerning: $1',
 4656+ 'securepoll-strike-token-mismatch' => 'Sesjonsdata tapt',
37904657 'securepoll-details-link' => 'Detaljer',
37914658 'securepoll-details-title' => 'Stemmedetaljer: #$1',
37924659 'securepoll-invalid-vote' => '«$1» er ikke en gyldig stemme-ID',
@@ -3801,6 +4668,8 @@
38024669 'securepoll-dump-not-finished' => 'Krypterte valgregistre er kun tilgjengelige etter avsluttningen den $1 klokken $2',
38034670 'securepoll-dump-no-urandom' => 'Kan ikke åpne /dev/urandom.
38044671 For å sikre en hemmelig avstemning er de krypterte valgregistrene kun offentlig tilgjengelig når de kan blandes med en sikker strøm av tilfeldige tall.',
 4672+ 'securepoll-urandom-not-supported' => 'Denne tjeneren støtter ikke kryptografisk generering av tilfeldige tall.
 4673+For å opprettholde velgernes anonymitet vil de enkelte stemmene kun offentliggjøres når de kan anonymiseres med en generator for tilfeldige tall.',
38054674 'securepoll-translate-title' => 'Oversett: $1',
38064675 'securepoll-invalid-language' => 'Ugyldig språkkode «$1»',
38074676 'securepoll-submit-translate' => 'Oppdater',
@@ -3825,6 +4694,8 @@
38264695 'securepoll-tally-upload-submit' => 'Opprett en opptelling',
38274696 'securepoll-tally-error' => 'Feil ved tolking av stemmeregisteret, kan ikke opprette en opptelling.',
38284697 'securepoll-no-upload' => 'Ingen fil ble lastet opp, kan ikke summere opp resultatene.',
 4698+ 'securepoll-dump-corrupt' => 'Dumpfila er ødelagt og kan ikke behandles.',
 4699+ 'securepoll-tally-upload-error' => 'Feil ved opptelling av dumpfila: $1',
38294700 );
38304701
38314702 /** Occitan (Occitan)
@@ -3875,6 +4746,9 @@
38764747 'securepoll-jump' => 'Anar al servidor de vòte',
38774748 'securepoll-bad-ballot-submission' => 'Vòstre vòte es invalid : $1',
38784749 'securepoll-unanswered-questions' => 'Vos cal respondre a totas las questions.',
 4750+ 'securepoll-invalid-rank' => 'Reng invalid. Vos cal balhar als candidats un reng entre 1 e 999.',
 4751+ 'securepoll-unranked-options' => "D'unas opcions an pas recebut de reng.
 4752+Vos cal balhar un reng entre 1 e 999 a totas las opcions.",
38794753 'securepoll-remote-auth-error' => 'Error al moment de la recuperacion de las informacions de vòstre compte dempuèi lo servidor.',
38804754 'securepoll-remote-parse-error' => 'Error al moment de l’interpretacion de la responsa d’autorizacion del servidor.',
38814755 'securepoll-api-invalid-params' => 'Paramètres invalids.',
@@ -3899,6 +4773,7 @@
39004774 'securepoll-strike-reason' => 'Rason :',
39014775 'securepoll-strike-cancel' => 'Anullar',
39024776 'securepoll-strike-error' => 'Error al moment del (des)raiatge : $1',
 4777+ 'securepoll-strike-token-mismatch' => 'Pèrta de donadas de sesilha',
39034778 'securepoll-details-link' => 'Detalhs',
39044779 'securepoll-details-title' => 'Detalhs del vòte : #$1',
39054780 'securepoll-invalid-vote' => '« $1 » es pas un ID de vòte valid',
@@ -3914,6 +4789,8 @@
39154790 'securepoll-dump-not-finished' => "Las donadas criptadas son disponiblas solament aprèp la clausura de l'eleccion lo $1 a $2",
39164791 'securepoll-dump-no-urandom' => 'Impossible de dobrir /dev/urandom.
39174792 Per manténer la confidencialitat dels votants, las donadas criptadas son disponiblas sonque se pòdon èsser reboladas amb un nombre de caractèrs aleatòris.',
 4793+ 'securepoll-urandom-not-supported' => 'Aqueste servidor supòrta pas la generacion criptografica aleatòri de nombres.
 4794+Per assegurar la confidencialitat dels votants, las donadas criptadas son publicadas unicament quand pòdon trebolar un flus aleatòri de nombres.',
39184795 'securepoll-translate-title' => 'Traduire : $1',
39194796 'securepoll-invalid-language' => 'Còde de lenga « $1 » invalid.',
39204797 'securepoll-submit-translate' => 'Metre a jorn',
@@ -3938,6 +4815,8 @@
39394816 'securepoll-tally-upload-submit' => 'Crear un comptatge',
39404817 'securepoll-tally-error' => "Error al moment de l'interpretacion dels enregistaments de vòte, impossible de produire un resultat.",
39414818 'securepoll-no-upload' => 'Cap de fichièr es pas estat telecargat, impossible de comptar los resultats.',
 4819+ 'securepoll-dump-corrupt' => 'Lo fichièr de salvament es corromput e pòt pas èsser utilizat.',
 4820+ 'securepoll-tally-upload-error' => 'Error al moment del decargament del fichièr de salvament : $1',
39424821 );
39434822
39444823 /** Papiamento (Papiamentu)
@@ -3986,9 +4865,7 @@
39874866 'securepoll-no-decryption-key' => 'No tin un klave deskriptivó konfigurá.
39884867 No por decrypt.',
39894868 'securepoll-jump' => 'Bai na e server di votashon',
3990 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
3991 -Bo voto no ta balido: $1
3992 -</div>',
 4869+ 'securepoll-bad-ballot-submission' => 'Bo voto no ta balido: $1',
39934870 'securepoll-unanswered-questions' => 'Bo mester kontestá tur e preguntanan.',
39944871 'securepoll-remote-auth-error' => 'Tabatin problema na ora di buska informashonnan tokante di bo kuenta riba e server.',
39954872 'securepoll-remote-parse-error' => 'Tabatin problema na ora di interpretá e derechinan for di riba e server.',
@@ -4059,11 +4936,20 @@
40604937 * @author Xqt
40614938 */
40624939 $messages['pdc'] = array(
 4940+ 'securepoll-welcome' => '<strong>Willkum $1!</strong>',
 4941+ 'securepoll-return' => 'Zerick zu $1',
40634942 'securepoll-header-timestamp' => 'Zeit',
40644943 'securepoll-header-voter-name' => 'Naame',
 4944+ 'securepoll-strike-reason' => 'Grund:',
 4945+ 'securepoll-header-reason' => 'Grund',
 4946+ 'securepoll-submit-select-lang' => 'Iwwersetze',
 4947+ 'securepoll-header-title' => 'Naame',
 4948+ 'securepoll-subpage-translate' => 'Iwwersetze',
 4949+ 'securepoll-subpage-list' => 'Lischt',
40654950 );
40664951
40674952 /** Polish (Polski)
 4953+ * @author Saper
40684954 * @author Sp5uhe
40694955 */
40704956 $messages['pl'] = array(
@@ -4109,15 +4995,13 @@
41104996 'securepoll-no-decryption-key' => 'Klucz odszyfrowujący nie został skonfigurowany.
41114997 Odszyfrowanie nie jest możliwe.',
41124998 'securepoll-jump' => 'Przejdź do serwera obsługującego głosowanie',
4113 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
4114 -Twój głos był nieważny – $1
4115 -</div>',
 4999+ 'securepoll-bad-ballot-submission' => 'Twój głos był nieważny – $1',
41165000 'securepoll-unanswered-questions' => 'Musisz odpowiedzieć na wszystkie pytania.',
41175001 'securepoll-remote-auth-error' => 'Wystąpił błąd podczas pobierania informacji z serwera o Twoim koncie.',
41185002 'securepoll-remote-parse-error' => 'Wystąpił błąd interpretacji odpowiedzi autoryzującej z serwera.',
41195003 'securepoll-api-invalid-params' => 'Nieprawidłowe parametry.',
41205004 'securepoll-api-no-user' => 'Nie znaleziono użytkownika o podanym ID.',
4121 - 'securepoll-api-token-mismatch' => 'Niepwawidłowy żeton bezpieczeństwa, nie można się zalogować.',
 5005+ 'securepoll-api-token-mismatch' => 'Nieprawidłowy żeton bezpieczeństwa, nie można się zalogować.',
41225006 'securepoll-not-logged-in' => 'Musisz się zalogować, aby głosować w tych wyborach',
41235007 'securepoll-too-few-edits' => 'Niestety, nie możesz głosować. Musisz mieć przynajmniej $1 {{PLURAL:$1|edycję|edycje|edycji}} aby głosować w tych wyborach, wykonane $2.',
41245008 'securepoll-blocked' => 'Niestety, nie możesz głosować w tych wyborach, ponieważ masz zablokowaną możliwość edytowania.',
@@ -4137,6 +5021,7 @@
41385022 'securepoll-strike-reason' => 'Powód',
41395023 'securepoll-strike-cancel' => 'Zrezygnuj',
41405024 'securepoll-strike-error' => 'Błąd podczas skreślania lub usuwania skreślenia – $1',
 5025+ 'securepoll-strike-token-mismatch' => 'Sesja użytkownika została utracona',
41415026 'securepoll-details-link' => 'Szczegóły',
41425027 'securepoll-details-title' => 'Szczegóły głosu nr $1',
41435028 'securepoll-invalid-vote' => '„$1” nie jest poprawnym identyfikatorem głosu',
@@ -4152,6 +5037,8 @@
41535038 'securepoll-dump-not-finished' => 'Zaszyfrowane rekordy głosów dostępne będą dopiero po zakończeniu wyborów $1 o $2',
41545039 'securepoll-dump-no-urandom' => 'Nie można otworzyć /dev/urandom.
41555040 Dla zapewnienia wyborcom poufności, zaszyfrowane rekordy głosów są publicznie dostępne wyłącznie wymieszane z danymi losowymi.',
 5041+ 'securepoll-urandom-not-supported' => 'System operacyjny na serwerze nie pozwala na korzystanie z urządzenia do tworzenia liczb losowych spełniających wymagania kryptografii.
 5042+Dla zapewnienia wyborcom poufności, zaszyfrowane rekordy głosów są publicznie dostępne wyłącznie wymieszane z danymi losowymi.',
41565043 'securepoll-translate-title' => 'Tłumaczenie $1',
41575044 'securepoll-invalid-language' => 'Nieprawidłowy kod języka „$1”',
41585045 'securepoll-submit-translate' => 'Uaktualnij',
@@ -4166,7 +5053,7 @@
41675054 'securepoll-subpage-dump' => 'Zrzut',
41685055 'securepoll-subpage-tally' => 'Rejestr',
41695056 'securepoll-tally-title' => 'Rejestr $1',
4170 - 'securepoll-tally-not-finished' => 'Nie można podliczyć głosów, przed zakończeniem wyborów.',
 5057+ 'securepoll-tally-not-finished' => 'Nie można podliczać głosów dopóki wybory trwają.',
41715058 'securepoll-can-decrypt' => 'Rekord głosu został zaszyfrowany, ale klucz odszyfrowujący jest dostępny.
41725059 Można podliczyć wyniki obecne w bazie danych lub podliczyć wyniki z przesłanego zaszyfrowanego pliku.',
41735060 'securepoll-tally-no-key' => 'Nie możesz podliczyć wyniku wyborów, ponieważ głosy są zaszyfrowane, a klucz odszyfrowujący jest niedostępny.',
@@ -4176,9 +5063,125 @@
41775064 'securepoll-tally-upload-submit' => 'Utwórz rejestr',
41785065 'securepoll-tally-error' => 'Błąd interpretacji rekordu głosu, nie można wykonać podliczenia.',
41795066 'securepoll-no-upload' => 'Żaden plik nie został przesłany, nie można podliczyć głosów.',
 5067+ 'securepoll-dump-corrupt' => 'Plik ze zrzutem danych jest uszkodzony i nie być przetworzony.',
 5068+ 'securepoll-tally-upload-error' => 'Podczas podliczania pliku ze zrzutem danych wystąpił błąd: $1',
41805069 );
41815070
 5071+/** Piedmontese (Piemontèis)
 5072+ * @author Dragonòt
 5073+ */
 5074+$messages['pms'] = array(
 5075+ 'securepoll' => 'SecurePoll',
 5076+ 'securepoll-desc' => 'Estension për elession e arserche',
 5077+ 'securepoll-invalid-page' => 'Sotpàgina nen vàlida "<nowiki>$1</nowiki>"',
 5078+ 'securepoll-need-admin' => "It deuve esse aministrador për fé st'assion-sì",
 5079+ 'securepoll-too-few-params' => 'Ij paràmetr ëd la sotpàgina a basto pa (anliura nen vàlida)',
 5080+ 'securepoll-invalid-election' => '"$1" a l\'é pa n\'ID vàlid për l\'elession',
 5081+ 'securepoll-welcome' => '<strong>Bin ëvnù $1!</strong>',
 5082+ 'securepoll-not-started' => "St'elession-sì a l'é ancó pa partìa.
 5083+A l'é programà për parte ël $2 a $3.",
 5084+ 'securepoll-finished' => "St'elession-sì a l'é finìa, it peule pa pì voté.",
 5085+ 'securepoll-not-qualified' => "It ses pa qualifià për voté an st'elession-sì: $1",
 5086+ 'securepoll-change-disallowed' => "It l'has già votà an st'elession-sì.
 5087+It peule pa torna voté.",
 5088+ 'securepoll-change-allowed' => "<strong>Nòta: it l'has già votà an st'elession-sì.</strong>
 5089+It peule cambié tò vot an compiland la form sota.
 5090+Nòta che s'it faras sòn-sì, tò vot original a sarà scartà.",
 5091+ 'securepoll-submit' => 'Spediss ël vot',
 5092+ 'securepoll-gpg-receipt' => "Mersì për avèj votà.
 5093+
 5094+S'it veule, it peule conservé l'arseivuda sota com evidensa ëd tò vot:
 5095+
 5096+<pre>$1</pre>",
 5097+ 'securepoll-thanks' => "Mersì, tò vot a l'é stàit registrà.",
 5098+ 'securepoll-return' => 'Torna a $1',
 5099+ 'securepoll-encrypt-error' => "Eror an cifrand le anformassion dël vot.
 5100+Tò vot a l'é pa stàit memorisà!
 5101+
 5102+$1",
 5103+ 'securepoll-no-gpg-home' => 'Ampossìbil creé la directory prinsipal ëd GPG.',
 5104+ 'securepoll-secret-gpg-error' => 'Eror fasend giré GPG.
 5105+Dòvra $wgSecurePollShowErrorDetail=true; an LocalSettings.php për mosté pì ëd detaj.',
 5106+ 'securepoll-full-gpg-error' => 'Eror fasend giré GPG:
 5107+
 5108+Comand: $1
 5109+
 5110+Eror:
 5111+<pre>$2</pre>',
 5112+ 'securepoll-gpg-config-error' => 'Le ciav GPG a son configurà nen giuste.',
 5113+ 'securepoll-gpg-parse-error' => "Eror an antërpretand l'output ëd GPG.",
 5114+ 'securepoll-no-decryption-key' => 'Pa gnun-e ciav ëd decifrassion a son configurà.
 5115+As peul pa decifré.',
 5116+ 'securepoll-jump' => 'Va al server ëd la votassion',
 5117+ 'securepoll-bad-ballot-submission' => "Tò vot a l'era pa vàlid: $1",
 5118+ 'securepoll-unanswered-questions' => 'It deuve arsponde a tute le custion.',
 5119+ 'securepoll-remote-auth-error' => 'Eror an lesend le anformassion ëd tò cont dal server.',
 5120+ 'securepoll-remote-parse-error' => "Eror an antërpretand l'arspòsta d'autorisassion dal server.",
 5121+ 'securepoll-api-invalid-params' => 'Paràmetr pa vàlid.',
 5122+ 'securepoll-api-no-user' => "Pa gnun utent trovà con l'ID fornì.",
 5123+ 'securepoll-api-token-mismatch' => 'Ij token ëd sicurëssa a corispondo pa, it peule pa intré.',
 5124+ 'securepoll-not-logged-in' => "It deuve intré për voté an st'elession-sì",
 5125+ 'securepoll-too-few-edits' => "Spiasent, it peule pa voté. It deuve avèj fàit almanch $1 {{PLURAL:$1|modìfica|modìfiche}} për voté an st'elession-sì, ti it l'has fane $2.",
 5126+ 'securepoll-blocked' => "Spiasent, it peule pa voté an st'elession-sì se it ses blocà.",
 5127+ 'securepoll-bot' => "Spiasent, ij cont lë stat ëd bot a peulo pa voté an st'elession-sì.",
 5128+ 'securepoll-not-in-group' => 'Mach ij mèmber dël grup "$1" a peulo voté an st\'elession-sì.',
 5129+ 'securepoll-not-in-list' => "Spiasent, it ses pa ant la lista predeterminà d'utent autorisà a voté an st'elession-sì.",
 5130+ 'securepoll-list-title' => 'Lista dij vot: $1',
 5131+ 'securepoll-header-timestamp' => 'Ora',
 5132+ 'securepoll-header-voter-name' => 'Nòm',
 5133+ 'securepoll-header-voter-domain' => 'Domini',
 5134+ 'securepoll-header-ua' => 'Agent utent',
 5135+ 'securepoll-header-cookie-dup' => 'Duplicà',
 5136+ 'securepoll-header-strike' => 'Anulà',
 5137+ 'securepoll-header-details' => 'Detaj',
 5138+ 'securepoll-strike-button' => 'Anulà',
 5139+ 'securepoll-unstrike-button' => 'Scansela anulament',
 5140+ 'securepoll-strike-reason' => 'Rason:',
 5141+ 'securepoll-strike-cancel' => 'Scancela',
 5142+ 'securepoll-strike-error' => 'Eror an fasend anula/scansela anulament: $1',
 5143+ 'securepoll-details-link' => 'Detaj',
 5144+ 'securepoll-details-title' => 'Detaj dël vot: #$1',
 5145+ 'securepoll-invalid-vote' => '"$1" a l\'é pa l\'ID d\'un vot vàlid',
 5146+ 'securepoll-header-voter-type' => 'Rasa ëd votant',
 5147+ 'securepoll-voter-properties' => 'Proprietà dël votant',
 5148+ 'securepoll-strike-log' => "Registr ëd j'anulament",
 5149+ 'securepoll-header-action' => 'Assion',
 5150+ 'securepoll-header-reason' => 'Rason',
 5151+ 'securepoll-header-admin' => 'Aministrador',
 5152+ 'securepoll-cookie-dup-list' => 'Utent dobi për cookie',
 5153+ 'securepoll-dump-title' => 'Dump: $1',
 5154+ 'securepoll-dump-no-crypt' => "Pa gnun-e registrassion cifrà dl'elession a-i son për st'elession-sì, përchè l'elession a l'é pa configurà për dovré la cifradura.",
 5155+ 'securepoll-dump-not-finished' => "Le registrassion cifrà dl'elession a son mach disponìbij d'apress la data ëd fin ël $1 a $2",
 5156+ 'securepoll-dump-no-urandom' => "As peul pa deurbe /dev/urandom.
 5157+Për manten-e la privacy dij votant, le registrassion cifrà dl'elession a saran disponibij publicament mach quand a saran cifrà con un fluss sicur ëd nùmer casuaj.",
 5158+ 'securepoll-translate-title' => 'Traduv: $1',
 5159+ 'securepoll-invalid-language' => 'Còdes lenga pa vàlid "$1"',
 5160+ 'securepoll-submit-translate' => 'Agiorna',
 5161+ 'securepoll-language-label' => 'Sern lenga:',
 5162+ 'securepoll-submit-select-lang' => 'Traduv',
 5163+ 'securepoll-header-title' => 'Nòm',
 5164+ 'securepoll-header-start-date' => 'Data inissi',
 5165+ 'securepoll-header-end-date' => 'Data fin',
 5166+ 'securepoll-subpage-vote' => 'Vòta',
 5167+ 'securepoll-subpage-translate' => 'Traduv',
 5168+ 'securepoll-subpage-list' => 'Lista',
 5169+ 'securepoll-subpage-dump' => 'Dump',
 5170+ 'securepoll-subpage-tally' => 'Puntegi',
 5171+ 'securepoll-tally-title' => 'Puntegi: $1',
 5172+ 'securepoll-tally-not-finished' => "Spiasent, it peule pa contegé l'elession fin a che ël vot a sia nen complet.",
 5173+ 'securepoll-can-decrypt' => "La registrassion ëd l'elession a l'é stàita cifrà, ma la ciav ëd decifrassion a l'é disponìbila.
 5174+It peule serne sia ëd conté j'arzultà present ant ël database, sia ëd conté j'arzultà cifrà da un file carià.",
 5175+ 'securepoll-tally-no-key' => "It peule pa conté st'elession-sì, përchè ij vot a son cifrà, e la ciav ëd decifrassion a l'é pa disponìbil.",
 5176+ 'securepoll-tally-local-legend' => "Conta j'arzultà memorisà",
 5177+ 'securepoll-tally-local-submit' => 'Crea ël contegi',
 5178+ 'securepoll-tally-upload-legend' => 'Caria ël dump cifrà',
 5179+ 'securepoll-tally-upload-submit' => 'Crea ël contegi',
 5180+ 'securepoll-tally-error' => 'Eror an antërpretand la registrassion dij vot, a peul pa prodove un contegi.',
 5181+ 'securepoll-no-upload' => "pa gnun file a l'é stàit carià, as peul pa conté j'arzultà.",
 5182+);
 5183+
41825184 /** Portuguese (Português)
 5185+ * @author Everton137
41835186 * @author Lijealso
41845187 * @author Malafaya
41855188 * @author Waldir
@@ -4226,10 +5229,11 @@
42275230 'securepoll-no-decryption-key' => 'Nenhuma chave de descodificação está configurada.
42285231 Não é possível descodificar.',
42295232 'securepoll-jump' => 'Ir para o servidor de votação',
4230 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
4231 -O seu voto foi inválido: $1
4232 -</div>',
 5233+ 'securepoll-bad-ballot-submission' => 'O seu voto foi inválido: $1',
42335234 'securepoll-unanswered-questions' => 'Você deve responder todas as perguntas.',
 5235+ 'securepoll-invalid-rank' => 'Ranque inválido. Você deve fornecer aos candidatos um ranque entre 1 e 999.',
 5236+ 'securepoll-unranked-options' => 'Algumas opções não foram ranqueadas.
 5237+Você deve fornecer para todas opções um ranque entre 1 e 999.',
42345238 'securepoll-remote-auth-error' => 'Erro ao buscar as informações da sua conta a partir do servidor.',
42355239 'securepoll-remote-parse-error' => 'Erro ao interpretar a resposta de autorização do servidor.',
42365240 'securepoll-api-invalid-params' => 'Parâmetros inválidos.',
@@ -4246,7 +5250,7 @@
42475251 'securepoll-header-voter-name' => 'Nome',
42485252 'securepoll-header-voter-domain' => 'Domínio',
42495253 'securepoll-header-ua' => 'Agente de utilizador',
4250 - 'securepoll-header-cookie-dup' => 'Dup',
 5254+ 'securepoll-header-cookie-dup' => 'Duplicado',
42515255 'securepoll-header-strike' => 'Riscar',
42525256 'securepoll-header-details' => 'Detalhes',
42535257 'securepoll-strike-button' => 'Riscar',
@@ -4254,6 +5258,7 @@
42555259 'securepoll-strike-reason' => 'Motivo:',
42565260 'securepoll-strike-cancel' => 'Cancelar',
42575261 'securepoll-strike-error' => 'Erro ao riscar/remover risco: $1',
 5262+ 'securepoll-strike-token-mismatch' => 'Dados da sessão perdidos.',
42585263 'securepoll-details-link' => 'Detalhes',
42595264 'securepoll-details-title' => 'Detalhes do voto: #$1',
42605265 'securepoll-invalid-vote' => '"$1" não é um ID de voto válido',
@@ -4293,10 +5298,12 @@
42945299 'securepoll-tally-upload-submit' => 'Criar apuramento',
42955300 'securepoll-tally-error' => 'Erro na interpretação de registo de voto, não é possível produzir apuramento.',
42965301 'securepoll-no-upload' => 'Nenhum ficheiro foi carregado, não é possível apurar resultados.',
 5302+ 'securepoll-dump-corrupt' => 'O arquivo dump está corrompido e não pode ser processado.',
42975303 );
42985304
42995305 /** Brazilian Portuguese (Português do Brasil)
43005306 * @author Eduardo.mps
 5307+ * @author Everton137
43015308 * @author GKnedo
43025309 * @author Heldergeovane
43035310 */
@@ -4343,9 +5350,7 @@
43445351 'securepoll-no-decryption-key' => 'Nenhuma chave de descriptografia está configurada.
43455352 Não foi possível descriptografar.',
43465353 'securepoll-jump' => 'Ir para o servidor de votação',
4347 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
4348 -Seu voto foi inválido: $1
4349 -</div>',
 5354+ 'securepoll-bad-ballot-submission' => 'Seu voto foi inválido: $1',
43505355 'securepoll-unanswered-questions' => 'Você deve responder todas as questões.',
43515356 'securepoll-remote-auth-error' => 'Erro ao tentar obter suas informações de conta do servidor.',
43525357 'securepoll-remote-parse-error' => 'Erro ao interpretar a resposta de autorização do servidor.',
@@ -4410,15 +5415,17 @@
44115416 'securepoll-tally-upload-submit' => 'Criar contagem de votos',
44125417 'securepoll-tally-error' => 'Erro ao interpretar registro de votos, não foi possível produzir uma contagem.',
44135418 'securepoll-no-upload' => 'Nenhum arquivo foi carregado, não foi possível contar os votos para o resultado.',
 5419+ 'securepoll-ranks' => 'Ranque final.',
44145420 );
44155421
44165422 /** Romanian (Română)
 5423+ * @author Firilacroco
44175424 * @author Mihai
44185425 */
44195426 $messages['ro'] = array(
44205427 'securepoll-submit' => 'Trimite votul',
44215428 'securepoll-unanswered-questions' => 'Trebuie să răspunzi la toate întrebările.',
4422 - 'securepoll-api-invalid-params' => 'Parametri invalizi.',
 5429+ 'securepoll-api-invalid-params' => 'Parametri incorecţi.',
44235430 'securepoll-api-no-user' => 'Niciun utilizator cu acest ID nu a fost găsit.',
44245431 'securepoll-list-title' => 'Listă voturi: $1',
44255432 'securepoll-header-voter-name' => 'Nume',
@@ -4503,6 +5510,9 @@
45045511 'securepoll-jump' => 'Перейти на сервер голосований',
45055512 'securepoll-bad-ballot-submission' => 'Ваш голос не действителен: $1',
45065513 'securepoll-unanswered-questions' => 'Вы должны ответить на все вопросы.',
 5514+ 'securepoll-invalid-rank' => 'Недействительный ранг. Вы должны указать для кандидата ранг от 1 до 999.',
 5515+ 'securepoll-unranked-options' => 'Некоторые записи не проранжированы.
 5516+Вам необходимо указать ранг от 1 до 999 для всех записей.',
45075517 'securepoll-remote-auth-error' => 'Ошибка получения информации об учётной записи с сервера.',
45085518 'securepoll-remote-parse-error' => 'Ошибка интерпретации ответа авторизации с сервера.',
45095519 'securepoll-api-invalid-params' => 'Ошибочные параметры.',
@@ -4527,6 +5537,7 @@
45285538 'securepoll-strike-reason' => 'Причина:',
45295539 'securepoll-strike-cancel' => 'Отмена',
45305540 'securepoll-strike-error' => 'Ошибка при вычёркивании или снятии вычёркивания: $1',
 5541+ 'securepoll-strike-token-mismatch' => 'Потеря данных сессии',
45315542 'securepoll-details-link' => 'Подробности',
45325543 'securepoll-details-title' => 'Подробности голосования: #$1',
45335544 'securepoll-invalid-vote' => '«$1» не является допустимым идентификатором голосования',
@@ -4542,6 +5553,8 @@
45435554 'securepoll-dump-not-finished' => 'Зашифрованные записи подачи голосов доступны только после окончания голосования $1 $2',
45445555 'securepoll-dump-no-urandom' => 'Не удаётся открыть /dev/urandom.
45455556 Для обеспечения конфиденциальности избирателей, зашифрованные записи подачи голосов можно делать общедоступными, когда порядок их следования изменён с использованием безопасного источника случайных чисел.',
 5557+ 'securepoll-urandom-not-supported' => 'Этот сервер не поддерживает криптографические генерирование случайных чисел.
 5558+Чтобы сохранить конфиденциальность голосующих, закодированные записи голосования станут общедоступными только после того, как они смогут быть перемешаны безопасным потоком случайных чисел.',
45465559 'securepoll-translate-title' => 'Перевод: $1',
45475560 'securepoll-invalid-language' => 'Ошибочный код языка «$1»',
45485561 'securepoll-submit-translate' => 'Обновить',
@@ -4566,6 +5579,8 @@
45675580 'securepoll-tally-upload-submit' => 'Произвести подсчёт',
45685581 'securepoll-tally-error' => 'Ошибка интерпретации записи голоса, невозможно произвести подсчёт.',
45695582 'securepoll-no-upload' => 'Файл не был загружен, невозможно подсчитать результаты.',
 5583+ 'securepoll-dump-corrupt' => 'Файл дампа повреждён и не может быть обработан.',
 5584+ 'securepoll-tally-upload-error' => 'Ошибка согласованности файла дампа: $1',
45705585 );
45715586
45725587 /** Yakut (Саха тыла)
@@ -4614,9 +5629,7 @@
46155630 'securepoll-no-decryption-key' => 'Расшифровка күлүүһэ настройкаламматах.
46165631 Расшифровкалыыр табыллыбат.',
46175632 'securepoll-jump' => 'Куоластааһын сиэрбэригэр көһүү',
4618 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
4619 -Эн куолаһыҥ ааҕыллыбат: $1
4620 -</div>',
 5633+ 'securepoll-bad-ballot-submission' => 'Эн куолаһыҥ ааҕыллыбат: $1',
46215634 'securepoll-unanswered-questions' => 'Бары ыйытыыларга хоруйдуохтааххын.',
46225635 'securepoll-remote-auth-error' => 'Аат-суол туһунан сибидиэнньэлэри сиэрбэртэн ылыыга алҕас таҕыста.',
46235636 'securepoll-remote-parse-error' => 'Сиэрбэртэн авторизацияны сыыһа көрүү буолбутун туһунан хоруй кэллэ.',
@@ -4739,6 +5752,9 @@
47405753 'securepoll-jump' => 'Prejsť na hlasovací server',
47415754 'securepoll-bad-ballot-submission' => 'Váš hlas bol neplatný: $1',
47425755 'securepoll-unanswered-questions' => 'Musíte zodpovedať všetky otázky.',
 5756+ 'securepoll-invalid-rank' => 'Neplatné hodnotenie. Musíte zadať kandidátov s hodnotením medzi 1 a 999.',
 5757+ 'securepoll-unranked-options' => 'Niektoré možnosti neboli ohodnotené.
 5758+Musíte dať každej možnosti hodnotenie medzi 1 a 999.',
47435759 'securepoll-remote-auth-error' => 'Pri zisťovaní vašich prihlasovacích informácií zo servera nastala chyba.',
47445760 'securepoll-remote-parse-error' => 'Pri interpretácii odpovede o autorizácii od servera nastala chyba.',
47455761 'securepoll-api-invalid-params' => 'Neplatné parametre.',
@@ -4763,6 +5779,7 @@
47645780 'securepoll-strike-reason' => 'Dôvod:',
47655781 'securepoll-strike-cancel' => 'Zrušiť',
47665782 'securepoll-strike-error' => 'Chyba operácie škrtnutie/zrušenie škrtnutia: $1',
 5783+ 'securepoll-strike-token-mismatch' => 'Údaje o relácii boli stratené',
47675784 'securepoll-details-link' => 'Podrobnosti',
47685785 'securepoll-details-title' => 'Podrobnosti hlasovania: #$1',
47695786 'securepoll-invalid-vote' => '„$1“ nie je platný ID hlasovania',
@@ -4778,6 +5795,8 @@
47795796 'securepoll-dump-not-finished' => 'Šifrované záznamy o voľbách sú dostupné len po dátume ich skončenia: $1 $2',
47805797 'securepoll-dump-no-urandom' => 'Nie je možné otvoriť /dev/urandom.
47815798 Aby bola zabezpečená anonymita hlasujúceho, šifrované záznamy o voľbách sú dostupné verejne len keď bôžu byť zamiešané náhodným tokom čísel.',
 5799+ 'securepoll-urandom-not-supported' => 'Tento server nepodporuje tvorbu kryptograficky náhodných čísiel.
 5800+Aby sa zachovalo súkromie hlasujúcich, šifrovaný záznam o voľbách je verejne dostupný iba keď ho možno kryptograficky zabezpečiť tokom náhodných čísiel.',
47825801 'securepoll-translate-title' => 'Preložiť: $1',
47835802 'securepoll-invalid-language' => 'Neplatný kód jazyka „$1“',
47845803 'securepoll-submit-translate' => 'Aktualizovať',
@@ -4802,6 +5821,11 @@
48035822 'securepoll-tally-upload-submit' => 'Vytvoriť vyhodnotenie',
48045823 'securepoll-tally-error' => 'Chyba pri interpretácii záznamu o hlasovaní, nemožno vyhodnotiť hlasovanie.',
48055824 'securepoll-no-upload' => 'Nebol nahraný súbor, nemožno vyhodnotiť hlasovanie.',
 5825+ 'securepoll-dump-corrupt' => 'Súbor s výpisom je poškodený a nemožno ho spracovať.',
 5826+ 'securepoll-tally-upload-error' => 'Chyba pri kontrole súboru výpisu: $1',
 5827+ 'securepoll-pairwise-victories' => 'Párová matica víťazstiev',
 5828+ 'securepoll-strength-matrix' => 'Párová matica sily',
 5829+ 'securepoll-ranks' => 'Finálne hodnotenie',
48065830 );
48075831
48085832 /** Serbian Cyrillic ekavian (ћирилица)
@@ -4812,10 +5836,12 @@
48135837 );
48145838
48155839 /** Swedish (Svenska)
 5840+ * @author Fluff
48165841 * @author Gabbe.g
48175842 * @author Micke
48185843 * @author Najami
48195844 * @author Poxnar
 5845+ * @author StefanB
48205846 */
48215847 $messages['sv'] = array(
48225848 'securepoll' => 'SäkerOmröstning',
@@ -4829,7 +5855,7 @@
48305856 Den planeras starta den $2 kl $3.',
48315857 'securepoll-finished' => 'Valet är avslutat, så du kan inte längre rösta.',
48325858 'securepoll-not-qualified' => 'Du är inte kvalificerad att rösta i den här omröstningen: $1',
4833 - 'securepoll-change-disallowed' => 'Du har redan röstat i den här omröstningen.
 5859+ 'securepoll-change-disallowed' => 'Du har redan deltagit i den här omröstningen.
48345860 Du kan tyvärr inte rösta igen.',
48355861 'securepoll-change-allowed' => '<strong>Observera att du redan har röstat i den här omröstningen.</strong>
48365862 Du kan ändra din röst genom att skicka in formuläret nedan.
@@ -4860,10 +5886,11 @@
48615887 'securepoll-no-decryption-key' => 'Ingen dekrypteringsnyckel är konfigurerad.
48625888 Kan inte dekryptera.',
48635889 'securepoll-jump' => 'Gå till röstnings-servern.',
4864 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
4865 -Din röst var ogiltig: $1
4866 -</div>',
 5890+ 'securepoll-bad-ballot-submission' => 'Din röst var ogiltig: $1',
48675891 'securepoll-unanswered-questions' => 'Du måste svara på alla frågor.',
 5892+ 'securepoll-invalid-rank' => 'Ogiltig rangordning. Du måste rangordna kandidater mellan 1 och 999.',
 5893+ 'securepoll-unranked-options' => 'Något eller några valmöjligheter rangordnades inte.
 5894+Du måste rangordna alla valmöjligheter mellan 1 och 999.',
48685895 'securepoll-remote-auth-error' => 'Fel uppstod vid hämtning av din kontoinformation från servern.',
48695896 'securepoll-remote-parse-error' => 'Fel uppstod vid tolkning av auktorisationssvar från servern.',
48705897 'securepoll-api-invalid-params' => 'Felaktig parameter.',
@@ -4888,13 +5915,14 @@
48895916 'securepoll-strike-reason' => 'Anledning:',
48905917 'securepoll-strike-cancel' => 'Avbryt',
48915918 'securepoll-strike-error' => 'Fel vid borttagning eller upphävning av borttagning: $1',
 5919+ 'securepoll-strike-token-mismatch' => 'Tappade sessionsdata',
48925920 'securepoll-details-link' => 'Detaljer',
48935921 'securepoll-details-title' => 'Röstningsdetaljer: #$1',
48945922 'securepoll-invalid-vote' => '"$1" är inte en giltig röst.',
48955923 'securepoll-header-voter-type' => 'Röstningstyp',
48965924 'securepoll-voter-properties' => 'Väljaregenskaper',
48975925 'securepoll-strike-log' => 'Borttagningslogg',
4898 - 'securepoll-header-action' => 'Handling',
 5926+ 'securepoll-header-action' => 'Åtgärd',
48995927 'securepoll-header-reason' => 'Anledning',
49005928 'securepoll-header-admin' => 'Administratör',
49015929 'securepoll-cookie-dup-list' => 'Cookie dubblettanvändare',
@@ -4903,6 +5931,8 @@
49045932 'securepoll-dump-not-finished' => 'Krypterade valregister finns endast tillgängliga efter avslutandet den $1 klockan $2',
49055933 'securepoll-dump-no-urandom' => 'Kan inte öppna /dev/urandom.
49065934 För att säkra en hemlig omröstning är de krypterade valregisterna endast tillgängliga offentligt när de kan blandas av en säker ström av tillfälliga tal.',
 5935+ 'securepoll-urandom-not-supported' => 'Den här servern har inte stöd för att generera slumpmässiga tal för kryptering.
 5936+För att säkerställa väljarnas integritet så kan krypterade valresultat enbart göras allmänt tillgängliga om de kan blandas med en säker slumptalsgenerator.',
49075937 'securepoll-translate-title' => 'Översätt: $1',
49085938 'securepoll-invalid-language' => 'Felaktig språkkod "$1"',
49095939 'securepoll-submit-translate' => 'Uppdatera',
@@ -4920,22 +5950,76 @@
49215951 'securepoll-tally-not-finished' => 'Beklagar, du kan inte räkna upp valresultatet innan omröstningen är slutförd.',
49225952 'securepoll-can-decrypt' => 'Valregistret har krypterats, men dekrypteringsnyckeln finns tillgänglig.
49235953 Du kan välja att antingen räkna upp resultaten som finns tillgängliga i databasen eller räkna upp de krypterade resultaten från en uppladdad fil.',
 5954+ 'securepoll-tally-no-key' => 'Du kan inte kontrollräkna det här valet eftersom rösterna är krypterade, och det finns ingen tillgänglig nyckel för att dekryptera dem.',
 5955+ 'securepoll-tally-local-legend' => 'Kontrollräkna lagrat resultat.',
 5956+ 'securepoll-tally-local-submit' => 'Skapa rösträkning',
 5957+ 'securepoll-tally-upload-legend' => 'Ladda upp krypterad dump.',
 5958+ 'securepoll-tally-upload-submit' => 'Skapa rösträkning',
 5959+ 'securepoll-tally-error' => 'Fel vid läsning av röstlängd, kan inte skapa rösträkning.',
 5960+ 'securepoll-no-upload' => 'Ingen fil laddades upp, kan inte räkna fram ett resultat.',
 5961+ 'securepoll-dump-corrupt' => 'Dumpningsfilen är korrupt och kan inte bearbetas.',
 5962+ 'securepoll-tally-upload-error' => 'Fel vid rösträkning av dumpfil: $1',
49245963 );
49255964
49265965 /** Telugu (తెలుగు)
 5966+ * @author Kiranmayee
49275967 * @author Veeven
49285968 */
49295969 $messages['te'] = array(
 5970+ 'securepoll' => 'సంరక్షితఎన్నిక',
 5971+ 'securepoll-desc' => 'ఎన్నికలకు, సర్వేలకు పొడగింపు',
 5972+ 'securepoll-need-admin' => 'ఈ పని పూర్తి చేయటకు మీరు అధికారి హోదా కలిగి వుండాలి.',
 5973+ 'securepoll-invalid-election' => '"$1" అన్నది సరైన ఎన్నిక గుర్తింపు కాదు.',
 5974+ 'securepoll-welcome' => '<strong>స్వాగతం $1!</strong>',
 5975+ 'securepoll-not-started' => 'ఈ ఎన్నిక ఇంకా మొదలు అవ్వలేదు.
 5976+$2 న, $3 లకు మోదలు అవుతుంది',
 5977+ 'securepoll-finished' => 'ఈ ఎన్నిక పూర్తి అయినది.
 5978+తమరు ఇంక వోటు వేయలేరు.',
 5979+ 'securepoll-not-qualified' => 'తమరికి ఈ ఎన్నికలలో వుతూ వినియోగించుకునే అర్హత లేదు: $1',
 5980+ 'securepoll-change-disallowed' => 'తమరు ఇదివరకే ఈ ఎన్నికలలో వోటు వేసారు.
 5981+క్షమించండి, తమరు మళ్లీ వోటు వేయలేరు.',
 5982+ 'securepoll-change-allowed' => '<strong>తమరు ఇదివరకే ఈ ఎన్నికలలో వోటు వేసారు.</strong>
 5983+తమ వోటుని మార్చుకోవడానికి క్రింది ఫాంను పూర్తి చేసి పంపండి.
 5984+గుర్తుంచుకోండి, కొత్త ఫాంను పంపిస్తే,తమ పాత వోటుకి విలువ వుండదు.',
 5985+ 'securepoll-submit' => 'వోటు వేయి',
 5986+ 'securepoll-gpg-receipt' => 'వోటు వేసినందుకు ధన్యవాదాలు. మీకు అవసరము అనుకుంటే, క్రింది రసీదుని మీ వోటుకి గుర్తుగా భద్రపరచుకోండి.
 5987+<pre>$1</pre>',
 5988+ 'securepoll-thanks' => 'ధన్యవాదాలు! మీ వోటుని భద్రపరచడమైనది.',
 5989+ 'securepoll-return' => 'తిరిగి $1కి',
 5990+ 'securepoll-jump' => 'వోటింగ్ సర్వరుకు వెళ్ళుము',
 5991+ 'securepoll-unanswered-questions' => 'మీరు అన్ని ప్రశ్నలకి సమాధానము ఇవ్వవలెను.',
 5992+ 'securepoll-not-logged-in' => 'ఈ ఎన్నికలో తమ వోటు హక్కును వినియోగించుకునేందుకు తమరు లోనికి ప్రవేశించి ఉండాలి',
 5993+ 'securepoll-too-few-edits' => 'క్షమించండి, తమరు వోటు వేయలేరు. ఈ ఎన్నికలో వోటు వేసేందుకు తమరు కనీసము $1 {{PLURAL:$1|మార్పు|మార్పులు}} చేసివుండాలి, కాని తమరు $2 చేసారు.',
49305994 'securepoll-header-timestamp' => 'సమయం',
49315995 'securepoll-header-voter-name' => 'పేరు',
 5996+ 'securepoll-header-ua' => 'వాడుకరి తరుపు ఏజంటు',
 5997+ 'securepoll-header-strike' => 'కొట్టివేయి',
49325998 'securepoll-header-details' => 'వివరాలు',
 5999+ 'securepoll-strike-button' => 'కొట్టివేయి',
 6000+ 'securepoll-unstrike-button' => 'కొట్టివేత తుడుపు',
49336001 'securepoll-strike-reason' => 'కారణం:',
 6002+ 'securepoll-strike-cancel' => 'రద్దు',
49346003 'securepoll-details-link' => 'వివరాలు',
 6004+ 'securepoll-details-title' => 'వోటు వివరాలు: #$1',
49356005 'securepoll-header-action' => 'చర్య',
49366006 'securepoll-header-reason' => 'కారణం',
 6007+ 'securepoll-header-admin' => 'నిర్వహణాధికారి',
 6008+ 'securepoll-translate-title' => 'అనువదించు: $1',
 6009+ 'securepoll-submit-translate' => 'అప్డేట్',
 6010+ 'securepoll-language-label' => 'భాషను ఎన్నుకో:',
 6011+ 'securepoll-submit-select-lang' => 'అనువదించు',
49376012 'securepoll-header-title' => 'పేరు',
49386013 'securepoll-header-start-date' => 'ఆరంభ తేదీ',
49396014 'securepoll-header-end-date' => 'ముగింపు తేదీ',
 6015+ 'securepoll-subpage-vote' => 'వోటు',
 6016+ 'securepoll-subpage-translate' => 'అనువదించు',
 6017+ 'securepoll-subpage-list' => 'జాబితా',
 6018+ 'securepoll-subpage-tally' => 'సరిచూడు',
 6019+ 'securepoll-tally-title' => 'సరిచూడు: $1',
 6020+ 'securepoll-tally-not-finished' => 'క్షమించండి, వోటింగు పూర్తి అయ్యే దాకా ఎన్నికను సరిచూడలేరు.',
 6021+ 'securepoll-tally-local-legend' => 'భద్రపరిచిన ఫలితాలను సరిచూడు',
 6022+ 'securepoll-tally-error' => 'వోటు రికార్డును అర్ధం చేసుకోవదములో తప్పు దొర్లినది, లెక్కలను సరిచూడలేము.',
 6023+ 'securepoll-no-upload' => 'ఫైల్ ఏమి అప్లోడ్ అవ్వబడలేదు, ఫలితాలను సరి చూడలేము.',
49406024 );
49416025
49426026 /** Thai (ไทย)
@@ -5010,9 +6094,7 @@
50116095 'securepoll-no-decryption-key' => 'Walang nakaayos na susing pangtanggal ng kodigo.
50126096 Hindi matanggal ang kodigo.',
50136097 'securepoll-jump' => 'Pumunta sa tagapaghain ng pagboto',
5014 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
5015 -Hindi tinanggap ang boto mo: $1
5016 -</div>',
 6098+ 'securepoll-bad-ballot-submission' => 'Hindi tinanggap ang boto mo: $1',
50176099 'securepoll-unanswered-questions' => 'Dapat mong sagutin ang lahat ng mga katanungan.',
50186100 'securepoll-remote-auth-error' => 'Kamalian sa pagpulot ng kabatiran ng akawnt mo mula sa tagapaghain.',
50196101 'securepoll-remote-parse-error' => 'Kamalian sa pagpapaliwanag ng tugon ng pagpapahintulot mula sa tagapaghain.',
@@ -5081,6 +6163,7 @@
50826164
50836165 /** Turkish (Türkçe)
50846166 * @author Joseph
 6167+ * @author Noumenon
50856168 */
50866169 $messages['tr'] = array(
50876170 'securepoll' => 'GüvenliAnket',
@@ -5106,7 +6189,7 @@
51076190
51086191 <pre>$1</pre>',
51096192 'securepoll-thanks' => 'Teşekkürler, oyunuz kaydedildi.',
5110 - 'securepoll-return' => "$1'e geri dön",
 6193+ 'securepoll-return' => '$1 sayfasına geri dön',
51116194 'securepoll-encrypt-error' => 'Oy kaydınızın şifrelenmesi başarısız oldu.
51126195 Oyunuz kaydedilmedi!
51136196
@@ -5127,6 +6210,9 @@
51286211 'securepoll-jump' => 'Oylama sunucusuna git',
51296212 'securepoll-bad-ballot-submission' => 'Oyunuz geçersiz: $1',
51306213 'securepoll-unanswered-questions' => 'Tüm sorulara cevap vermelisiniz.',
 6214+ 'securepoll-invalid-rank' => 'Geçersiz derece. Adaylara 1 ile 999 arasında bir derece vermelisiniz.',
 6215+ 'securepoll-unranked-options' => 'Bazı seçenekler derecelendirilmemiş.
 6216+Tüm seçeneklere 1 ile 999 arasında bir derece vermelisiniz.',
51316217 'securepoll-remote-auth-error' => 'Sunucudan hesap bilgileriniz alınırken hata.',
51326218 'securepoll-remote-parse-error' => 'Sunucunun yetkilendirme cevabı değerlendirilirken hata.',
51336219 'securepoll-api-invalid-params' => 'Geçersiz değişkenler.',
@@ -5151,6 +6237,7 @@
51526238 'securepoll-strike-reason' => 'Sebep:',
51536239 'securepoll-strike-cancel' => 'İptal',
51546240 'securepoll-strike-error' => 'Üsütünü çiz/çizme yerine getirilirken hata: $1',
 6241+ 'securepoll-strike-token-mismatch' => 'Oturum verileri kayıp',
51556242 'securepoll-details-link' => 'Ayrıntılar',
51566243 'securepoll-details-title' => 'Oy ayrıntıları: #$1',
51576244 'securepoll-invalid-vote' => '"$1" geçerli bir oy IDsi değil',
@@ -5166,6 +6253,8 @@
51676254 'securepoll-dump-not-finished' => "Şifreli seçim kayıtları sadece bitiş tarihi $1 saat $2'den sonra mevcut olur",
51686255 'securepoll-dump-no-urandom' => '/dev/urandom açılamıyor.
51696256 Seçmen gizliliğini idame etmek için, şifreli seçim kayıtları sadece güvenli bir rasgele sayı akıntısıyla karıştırılabilirse umumen mevcut olur.',
 6257+ 'securepoll-urandom-not-supported' => 'Bu sunucu kriptografik rastgele sayı üretimini desteklememektedir.
 6258+Oy veren gizliliğini sağlamak için, şifrelenmiş oylama kayıtları sadece güvenli bir rastgele sayı akışıyla karıştırılabilecekleri durumda alenen erişilebilirdirler.',
51706259 'securepoll-translate-title' => 'Çevir: $1',
51716260 'securepoll-invalid-language' => 'Geçersiz dil kodu "$1"',
51726261 'securepoll-submit-translate' => 'Güncelle',
@@ -5190,8 +6279,133 @@
51916280 'securepoll-tally-upload-submit' => 'Sayım oluştur',
51926281 'securepoll-tally-error' => 'Oy kaydı yorumlanırken hata, bir sayım üretilemiyor.',
51936282 'securepoll-no-upload' => 'Hiçbir dosya yüklenmedi, sonuçlar sayılamıyor.',
 6283+ 'securepoll-dump-corrupt' => 'Yığın dosyası bozuk ve işlenebilir değil.',
 6284+ 'securepoll-tally-upload-error' => 'Yığın dosyası sayımında hata: $1',
51946285 );
51956286
 6287+/** Ukrainian (Українська)
 6288+ * @author AS
 6289+ * @author Ahonc
 6290+ * @author Ilyaroz
 6291+ */
 6292+$messages['uk'] = array(
 6293+ 'securepoll' => 'Безпечне голосування',
 6294+ 'securepoll-desc' => 'Розширення для проведення виборів і опитувань',
 6295+ 'securepoll-invalid-page' => 'Помилкова підсторінка "<nowiki>$1</nowiki>"',
 6296+ 'securepoll-need-admin' => 'Вам потрібно бути адміністртором, щоб виконати цю дію.',
 6297+ 'securepoll-too-few-params' => 'Не вистачає параметрів підсторінки (помилкове посилання).',
 6298+ 'securepoll-invalid-election' => '«$1» не є допустимим виборчим ідентифікатором.',
 6299+ 'securepoll-welcome' => '<strong>Ласкаво просимо, $1!</strong>',
 6300+ 'securepoll-not-started' => 'Ці вибори ще не розпочалися.
 6301+Початок запланований на $2 $3.',
 6302+ 'securepoll-finished' => 'Ці вибори зкінчились, ви вже не можете проголосувати.',
 6303+ 'securepoll-not-qualified' => 'Ви не уповноважені голосувати на цих виборах: $1',
 6304+ 'securepoll-change-disallowed' => 'Ви вже голосували на цих виборах раніше.
 6305+Даруйте, ви не можете проголосувати ще раз.',
 6306+ 'securepoll-change-allowed' => '<strong>Примітка: ви вже проголосували на цих виборах.</strong>
 6307+Ви можете змінити свій голос, відправивши приведену нижче форму.
 6308+Якщо ви зробите це, то ваш попередній голос не буде врахований.',
 6309+ 'securepoll-submit' => 'Відправити голос',
 6310+ 'securepoll-gpg-receipt' => 'Дякуємо за участь в голосуванні.
 6311+
 6312+При бажання ви можете зберегти наступні рядки як підтвердження вашого голосу:
 6313+
 6314+<pre>$1</pre>',
 6315+ 'securepoll-thanks' => 'Спасибі, ваш голос записаний.',
 6316+ 'securepoll-return' => 'Повернутись до $1',
 6317+ 'securepoll-encrypt-error' => 'Не вдалося зашифрувати запис про ваш голос.
 6318+Ваш голос не був записаний!
 6319+
 6320+$1',
 6321+ 'securepoll-no-gpg-home' => 'Не в змозі створити домашню теку GPG.',
 6322+ 'securepoll-secret-gpg-error' => 'Помилка виконання GPG.
 6323+Задайте $wgSecurePollShowErrorDetail=true; в файлі LocalSettings.php щоб отримати докладніше повідомлення.',
 6324+ 'securepoll-full-gpg-error' => 'Помилка виконання GPG:
 6325+
 6326+Команда: $1
 6327+
 6328+Помилка:
 6329+<pre>$2</pre>',
 6330+ 'securepoll-gpg-config-error' => 'GPG-ключі налаштовані неправильно.',
 6331+ 'securepoll-gpg-parse-error' => 'Помилка при інтерпретації результату GPG.',
 6332+ 'securepoll-no-decryption-key' => 'Не налаштований ключ розшифрування.
 6333+Не в змозі розшифрувати.',
 6334+ 'securepoll-jump' => 'Перейти на сервер голосувань',
 6335+ 'securepoll-bad-ballot-submission' => 'Ваш голос не дійсний: $1',
 6336+ 'securepoll-unanswered-questions' => 'Ви повинні відповісти на всі запитання.',
 6337+ 'securepoll-invalid-rank' => 'Неправильне місце. Ви повинні вказати для кандидата місце від 1 до 999.',
 6338+ 'securepoll-unranked-options' => 'Для деяких записів не зазначені місця.
 6339+Вам слід вказати місця від 1 до 999 для кожного запису.',
 6340+ 'securepoll-remote-auth-error' => 'Помилка отримання інформації з сервера про ваш обліковий запис.',
 6341+ 'securepoll-remote-parse-error' => 'Помилка інтерпретації відповіді від авторизації з сервера.',
 6342+ 'securepoll-api-invalid-params' => 'Помилкові параметри.',
 6343+ 'securepoll-api-no-user' => 'Не знайдений користувач із заданим ідентифікатором.',
 6344+ 'securepoll-api-token-mismatch' => 'Невідповідність коду безпеки, не в змозі ввійти до системи.',
 6345+ 'securepoll-not-logged-in' => 'Ви маєте ввійти до системи, щоб взяти участь в голосуванні',
 6346+ 'securepoll-too-few-edits' => 'Вибачте, ви не можете проголосувати. Вам треба мати не менше $1 {{PLURAL:$1|редагування|редагувань|редагувань}} для участі в цьому голосуванні, у вас є $2.',
 6347+ 'securepoll-blocked' => 'Вибачте, ви не можете голосувати на виборах, оскільки вас заблоковано.',
 6348+ 'securepoll-bot' => 'Вибачте, облікові записи зі статусом бота не допускаються до участі в голосуванні.',
 6349+ 'securepoll-not-in-group' => 'Тільки члени групи "$1" можуть голосувати на цих виборах.',
 6350+ 'securepoll-not-in-list' => 'Вибачте, ви не входите в список користувачів, допущених до голосування на цих виборах.',
 6351+ 'securepoll-list-title' => 'Список голосів: $1',
 6352+ 'securepoll-header-timestamp' => 'Час',
 6353+ 'securepoll-header-voter-name' => "Ім'я",
 6354+ 'securepoll-header-voter-domain' => 'Домен',
 6355+ 'securepoll-header-ua' => 'Програма клієнта',
 6356+ 'securepoll-header-cookie-dup' => 'Дубл.',
 6357+ 'securepoll-header-strike' => 'Закреслення',
 6358+ 'securepoll-header-details' => 'Деталі',
 6359+ 'securepoll-strike-button' => 'Закреслити',
 6360+ 'securepoll-unstrike-button' => 'Зняти закреслення',
 6361+ 'securepoll-strike-reason' => 'Причина:',
 6362+ 'securepoll-strike-cancel' => 'Скасувати',
 6363+ 'securepoll-strike-error' => 'Помилка при викреслюванні/знятті викреслювання: $1',
 6364+ 'securepoll-strike-token-mismatch' => 'Дані сеансу втрачені',
 6365+ 'securepoll-details-link' => 'Докладніше',
 6366+ 'securepoll-details-title' => 'Деталі голосування: #$1',
 6367+ 'securepoll-invalid-vote' => '«$1» — неправильний ідентифікатор голосування',
 6368+ 'securepoll-header-voter-type' => 'Тип виборця',
 6369+ 'securepoll-voter-properties' => 'Властивості виборця',
 6370+ 'securepoll-strike-log' => 'Журнал викреслювань',
 6371+ 'securepoll-header-action' => 'Дія',
 6372+ 'securepoll-header-reason' => 'Причина',
 6373+ 'securepoll-header-admin' => 'Адміністратор',
 6374+ 'securepoll-cookie-dup-list' => 'Дублікати користувачів за куками',
 6375+ 'securepoll-dump-title' => 'Дамп: $1',
 6376+ 'securepoll-dump-no-crypt' => 'Незашифровані записи подачі голосу доступні на цих виборах, оскільки вибори не налаштовані на використання шифрування.',
 6377+ 'securepoll-dump-not-finished' => 'Зашифровані записи голосів доступні тільки після закінчення голосування $1 о $2',
 6378+ 'securepoll-dump-no-urandom' => 'Не вдається відкрити /dev/urandom.
 6379+Для забезпечення конфіденційності виборців, зашифровані записи подачі голосів можна робити загальнодоступними, тільки коли порядок їх слідування можна змінити з використанням безпечного джерела випадкових чисел.',
 6380+ 'securepoll-urandom-not-supported' => 'Цей сервер не підтримує криптографічні генерування випадкових чисел.
 6381+Щоб зберегти конфіденційність голосуючих, закодовані записи голосування стануть загальнодоступними тільки після того, як вони зможуть бути перемішані за допомогою безпечного потоку випадкових чисел.',
 6382+ 'securepoll-translate-title' => 'Переклад: $1',
 6383+ 'securepoll-invalid-language' => 'Неправильний код мови «$1»',
 6384+ 'securepoll-submit-translate' => 'Оновити',
 6385+ 'securepoll-language-label' => 'Вибір мови:',
 6386+ 'securepoll-submit-select-lang' => 'Перекласти',
 6387+ 'securepoll-header-title' => "Ім'я",
 6388+ 'securepoll-header-start-date' => 'Дата початку',
 6389+ 'securepoll-header-end-date' => 'Дата закінчення',
 6390+ 'securepoll-subpage-vote' => 'Голосування',
 6391+ 'securepoll-subpage-translate' => 'Переклад',
 6392+ 'securepoll-subpage-list' => 'Список',
 6393+ 'securepoll-subpage-dump' => 'Дамп',
 6394+ 'securepoll-subpage-tally' => 'Підрахунок',
 6395+ 'securepoll-tally-title' => 'Підрахунок: $1',
 6396+ 'securepoll-tally-not-finished' => 'Вибачте, ви можете проводити підрахунок підсумків тільки після завершення голосування.',
 6397+ 'securepoll-can-decrypt' => 'Запис голосування був зашифрований, але є ключ розшифровки.
 6398+Ви можете обрати або підрахунок поточних результатів в базі даних, або підрахунок зашифрованих результатів з завантаженого файлу.',
 6399+ 'securepoll-tally-no-key' => 'Ви можете не підраховувати голоси на цих виборах, так як вони були зашифровані, а ключ розшифровки відсутній.',
 6400+ 'securepoll-tally-local-legend' => 'Підрахунок збережених результатів',
 6401+ 'securepoll-tally-local-submit' => 'Зробити підрахунок',
 6402+ 'securepoll-tally-upload-legend' => 'Завантаження зашифрованого скиду (дампу)',
 6403+ 'securepoll-tally-upload-submit' => 'Зробити підрахунок',
 6404+ 'securepoll-tally-error' => 'Помилка інтерпретації запису голосу, неможливо провести підрахунок.',
 6405+ 'securepoll-no-upload' => 'Файл не був завантажений, неможливо підрахувати результати.',
 6406+ 'securepoll-dump-corrupt' => 'Файл скиду (дампу) пошкоджений і не може бути обробленим.',
 6407+ 'securepoll-tally-upload-error' => 'Помилка під час підрахунків у файлі скиду (дампу): $1',
 6408+);
 6409+
51966410 /** Urdu (اردو)
51976411 * @author محبوب عالم
51986412 */
@@ -5269,9 +6483,7 @@
52706484 'securepoll-no-decryption-key' => 'No xe stà configurà nissuna ciave de decritassion.
52716485 No se pole decritar.',
52726486 'securepoll-jump' => 'Và al server de ła votasion',
5273 - 'securepoll-bad-ballot-submission' => '<div class="securepoll-error-box">
5274 -El to voto no\'l xe mia vàłido: $1
5275 -</div>',
 6487+ 'securepoll-bad-ballot-submission' => "El to voto no'l xe mia vàłido: $1",
52766488 'securepoll-unanswered-questions' => 'Ti gà da rispóndar a tute le domande.',
52776489 'securepoll-remote-auth-error' => 'Eròr durante el recupero de le informassion su la to utensa dal server.',
52786490 'securepoll-remote-parse-error' => 'Se gà verificà un eròr interpretando la risposta de autorixassion dal server.',
@@ -5391,6 +6603,9 @@
53926604 'securepoll-jump' => 'Đi đến máy chủ bỏ phiếu',
53936605 'securepoll-bad-ballot-submission' => 'Phiếu bầu của bạn không hợp lệ: $1',
53946606 'securepoll-unanswered-questions' => 'Bạn phải trả lời tất cả các câu hỏi.',
 6607+ 'securepoll-invalid-rank' => 'Xếp hạng không hợp lệ. Bạn phải xếp hạng cho ứng viên trong khoảng từ 1 đến 999.',
 6608+ 'securepoll-unranked-options' => 'Một số ứng viên chưa được xếp hạng.
 6609+Bạn phải xếp hạng từ 1 đến 999 cho tất cả các ứng viên.',
53956610 'securepoll-remote-auth-error' => 'Lỗi khi truy xuất thông tin tài khoản của bạn từ máy chủ.',
53966611 'securepoll-remote-parse-error' => 'Lỗi khi thông dịch phản hồi ủy quyền từ máy chủ.',
53976612 'securepoll-api-invalid-params' => 'Thông số không hợp lệ.',
@@ -5415,6 +6630,7 @@
54166631 'securepoll-strike-reason' => 'Lý do:',
54176632 'securepoll-strike-cancel' => 'Hủy bỏ',
54186633 'securepoll-strike-error' => 'Lỗi khi gạch bỏ hay phục hồi: $1',
 6634+ 'securepoll-strike-token-mismatch' => 'Mất dữ liệu phiên',
54196635 'securepoll-details-link' => 'Chi tiết',
54206636 'securepoll-details-title' => 'Chi tiết lá phiếu: #$1',
54216637 'securepoll-invalid-vote' => '“$1” không phải là mã lá phiếu hợp lệ',
@@ -5430,6 +6646,8 @@
54316647 'securepoll-dump-not-finished' => 'Hồ sơ bầu cử đã mã hóa chỉ có sau khi kết thúc vào ngày $1 lúc $2',
54326648 'securepoll-dump-no-urandom' => 'Không thể mở /dev/urandom.
54336649 Để bảo đảm quyền riêng tư của cử tri, các bản ghi bầu cử đã mã hóa cần được xáo trộn bằng dòng số ngẫu nhiên mã hóa trước khi công khai.',
 6650+ 'securepoll-urandom-not-supported' => 'Máy chủ này không hỗ trợ tạo số ngẫu nhiên mã hóa.
 6651+Để duy trì bí mật danh tính cho người bỏ phiếu, các bản ghi bầu cử mã hóa chỉ hiển thị cho mọi người một khi chúng được xáo bằng một chuỗi số ngẫu nhiên an toàn.',
54346652 'securepoll-translate-title' => 'Biên dịch: $1',
54356653 'securepoll-invalid-language' => 'Mã ngôn ngữ “$1” không hợp lệ',
54366654 'securepoll-submit-translate' => 'Cập nhật',
@@ -5454,8 +6672,43 @@
54556673 'securepoll-tally-upload-submit' => 'Tạo cuộc kiểm phiếu',
54566674 'securepoll-tally-error' => 'Lỗi khi thông dịch bản ghi lá phiếu, không thể tạo cuộc kiểm phiếu.',
54576675 'securepoll-no-upload' => 'Không có tập tin nào được tải lên, không thể kiểm phiếu.',
 6676+ 'securepoll-dump-corrupt' => 'Tập tin kho bị hư và không thể được xử lý.',
 6677+ 'securepoll-tally-upload-error' => 'Có lỗi khi kiểm tập tin kho: $1',
 6678+ 'securepoll-pairwise-victories' => 'Ma trận chiến thắng theo cặp',
 6679+ 'securepoll-strength-matrix' => 'Ma trận độ mạnh đường đi',
 6680+ 'securepoll-ranks' => 'Xếp hạng sau cùng',
54586681 );
54596682
 6683+/** Yiddish (ייִדיש)
 6684+ * @author פוילישער
 6685+ */
 6686+$messages['yi'] = array(
 6687+ 'securepoll-invalid-page' => 'אומגילטיקער אונטערבלאט "<nowiki>$1</nowiki>"',
 6688+ 'securepoll-need-admin' => 'איר דארפט זיין א סיסאפ אדורכצופירן די פעולה.',
 6689+ 'securepoll-too-few-params' => 'נישט גענוג אונטערבלאט פאראמעטערס (אומגילטיקער לינק).',
 6690+ 'securepoll-invalid-election' => '"$1" איז נישט קיין גילטיקער אפשטימונג ID.',
 6691+ 'securepoll-welcome' => '<strong>ברוך הבא, $1!</strong>',
 6692+ 'securepoll-not-started' => 'די אפשטימונג האט נאך נישט אנגעהויבן.
 6693+זי איז באשטימט אנצוהייבן אום $2 אזייגער $3.',
 6694+ 'securepoll-finished' => 'די אפשטימונג האט שוין געקאנטשעט, איר קענט מער נישט אפשטימען.',
 6695+ 'securepoll-gpg-receipt' => 'א דאנק פארן שטימען.
 6696+
 6697+ווען איר ווילט, קענט איר היטן דעם פאלגנדן קוויט אלס ראיה פון אייער שטים.
 6698+
 6699+<pre>$1</pre>',
 6700+ 'securepoll-return' => 'צוריק צו $1',
 6701+ 'securepoll-bad-ballot-submission' => 'אייער שטים איז געווען אומגילטיג.',
 6702+ 'securepoll-unanswered-questions' => 'איר מוזט ענטפערן אלע שאלות.',
 6703+ 'securepoll-api-invalid-params' => 'אומגילטיגע פאראמעטערס',
 6704+ 'securepoll-header-timestamp' => 'צײַט',
 6705+ 'securepoll-header-voter-name' => 'נאָמען',
 6706+ 'securepoll-header-reason' => 'אורזאַך',
 6707+ 'securepoll-submit-translate' => 'דערהײַנטיקן',
 6708+ 'securepoll-submit-select-lang' => 'פארטייטשן',
 6709+ 'securepoll-header-title' => 'נאָמען',
 6710+ 'securepoll-subpage-list' => 'ליסטע',
 6711+);
 6712+
54606713 /** Yue (粵語)
54616714 * @author Shinjiman
54626715 */
@@ -5571,7 +6824,7 @@
55726825 'securepoll-no-upload' => '無檔案上載,整唔到記數結果。',
55736826 );
55746827
5575 -/** Zhuang (Sawcuengh)
 6828+/** Zhuang (Vahcuengh)
55766829 * @author Biŋhai
55776830 */
55786831 $messages['za'] = array(
@@ -5591,6 +6844,7 @@
55926845 * @author Bencmq
55936846 * @author Biŋhai
55946847 * @author FireJackey
 6848+ * @author PhiLiP
55956849 * @author Skjackey tse
55966850 */
55976851 $messages['zh-hans'] = array(
@@ -5635,6 +6889,8 @@
56366890 'securepoll-jump' => '进入投票服务器',
56376891 'securepoll-bad-ballot-submission' => '您的投票无效:$1',
56386892 'securepoll-unanswered-questions' => '您必须回答所有问题。',
 6893+ 'securepoll-invalid-rank' => '评级无效。给候选人的评级分数必须在1到999之间。',
 6894+ 'securepoll-unranked-options' => '部分选项尚未评级。所有选项均应评级,且分数应在1到999之间。',
56396895 'securepoll-remote-auth-error' => '从服务器提取您的用户信息时出错。',
56406896 'securepoll-remote-parse-error' => '服务器验证出错。',
56416897 'securepoll-api-invalid-params' => '参数无效。',
@@ -5659,6 +6915,7 @@
56606916 'securepoll-strike-reason' => '理由:',
56616917 'securepoll-strike-cancel' => '取消',
56626918 'securepoll-strike-error' => '进行删除选票/恢复被删除选票时出错:$1',
 6919+ 'securepoll-strike-token-mismatch' => '丢失会话数据',
56636920 'securepoll-details-link' => '细节',
56646921 'securepoll-details-title' => '投票细节:#$1',
56656922 'securepoll-invalid-vote' => '“$1”不是有效的投票ID',
@@ -5673,6 +6930,8 @@
56746931 'securepoll-dump-no-crypt' => '本次投票没有被加密的投票记录,因为它被配置为不须加密。',
56756932 'securepoll-dump-not-finished' => '加密的投票记录只有在截止日期$1 $2后方可获得',
56766933 'securepoll-dump-no-urandom' => '无法打开/dev/urandom。为了保证投票者的隐私,经过加密的投票记录只有在经随机数据串干涉后方可公开。',
 6934+ 'securepoll-urandom-not-supported' => '本服务器并不支持密文随机数生成。
 6935+为了保证投票者的隐私,经过加密的投票记录只有在经随机数据串干涉后方可公开。',
56776936 'securepoll-translate-title' => '翻译:$1',
56786937 'securepoll-invalid-language' => '无效的语言代码“$1”',
56796938 'securepoll-submit-translate' => '更新',
@@ -5696,11 +6955,15 @@
56976956 'securepoll-tally-upload-submit' => '创建点票数据',
56986957 'securepoll-tally-error' => '处理投票记录时出错,无法创建点票数据。',
56996958 'securepoll-no-upload' => '没有上传文件。',
 6959+ 'securepoll-dump-corrupt' => '无法处理损坏的转储文件。',
 6960+ 'securepoll-tally-upload-error' => '转储文件记录错误:$1',
57006961 );
57016962
57026963 /** Traditional Chinese (‪中文(繁體)‬)
57036964 * @author Alexsh
57046965 * @author Bencmq
 6966+ * @author FireJackey
 6967+ * @author PhiLiP
57056968 * @author Skjackey tse
57066969 * @author Wong128hk
57076970 */
@@ -5749,6 +7012,8 @@
57507013 'securepoll-jump' => '進入投票伺服器',
57517014 'securepoll-bad-ballot-submission' => '您的投票無效︰$1',
57527015 'securepoll-unanswered-questions' => '您必須回答所有問題。',
 7016+ 'securepoll-invalid-rank' => '評級無效。給候選人的評級分數必須在1到999之間。',
 7017+ 'securepoll-unranked-options' => '部分選項尚未評級。所有選項均應評級,且分數應在1到999之間。',
57537018 'securepoll-remote-auth-error' => '在投票伺服器提取您的用户信息時出錯',
57547019 'securepoll-remote-parse-error' => '伺服器驗證錯誤',
57557020 'securepoll-api-invalid-params' => '參數無效',
@@ -5773,6 +7038,7 @@
57747039 'securepoll-strike-reason' => '理由:',
57757040 'securepoll-strike-cancel' => '取消',
57767041 'securepoll-strike-error' => '進行刪除選票/恢復被刪除選票時出錯:$1',
 7042+ 'securepoll-strike-token-mismatch' => '丟失會話資料',
57777043 'securepoll-details-link' => '細節',
57787044 'securepoll-details-title' => '投票詳情︰#$1',
57797045 'securepoll-invalid-vote' => '「$1」不是有效的投票ID',
@@ -5788,6 +7054,8 @@
57897055 'securepoll-dump-not-finished' => '被加密的投票記錄只有在截止日期$1 $2後方可取得',
57907056 'securepoll-dump-no-urandom' => '無法打開/dev/urandom。
57917057 為了保證投票者的隱私,經過加密的投票記錄只有在經隨機數據串干擾後方可公開。',
 7058+ 'securepoll-urandom-not-supported' => '本伺服器並不支持密文隨機數生成。
 7059+為了保證投票者的隱私,經過加密的投票記錄只有在經隨機數據串干擾後方可公開。',
57927060 'securepoll-translate-title' => '翻譯:$1',
57937061 'securepoll-invalid-language' => '錯誤的語言代碼:「$1」',
57947062 'securepoll-submit-translate' => '更新',
@@ -5811,6 +7079,8 @@
58127080 'securepoll-tally-upload-submit' => '新增計票數據',
58137081 'securepoll-tally-error' => '投票記錄發生錯誤,無法新增計票數據。',
58147082 'securepoll-no-upload' => '沒有上傳文件。',
 7083+ 'securepoll-dump-corrupt' => '無法處理損壞的轉儲檔案。',
 7084+ 'securepoll-tally-upload-error' => '轉儲檔案記錄錯誤:$1',
58157085 );
58167086
58177087 /** Chinese (Hong Kong) (‪中文(香港)‬)
Index: branches/wmf-deployment/extensions/SecurePoll/SecurePoll.php
@@ -1,11 +1,8 @@
22 <?php
33 /**
4 - * Wikimedia Foundation Board of Trustees Election
5 - *
64 * @file
75 * @ingroup Extensions
86 * @author Tim Starling <tstarling@wikimedia.org>
9 - * @author Kwan Ting Chan
107 * @link http://www.mediawiki.org/wiki/Extension:SecurePoll Documentation
118 */
129
@@ -18,7 +15,7 @@
1916 $wgExtensionCredits['other'][] = array(
2017 'path' => __FILE__,
2118 'name' => 'SecurePoll',
22 - 'author' => array( 'Tim Starling', 'Kwan Ting Chan', 'others' ),
 19+ 'author' => array( 'Tim Starling', 'others' ),
2320 'url' => 'http://www.mediawiki.org/wiki/Extension:SecurePoll',
2421 'svn-date' => '$LastChangedDate$',
2522 'svn-revision' => '$LastChangedRevision$',
@@ -50,21 +47,23 @@
5148 $wgExtensionMessagesFiles['SecurePoll'] = "$dir/SecurePoll.i18n.php";
5249 $wgExtensionAliasesFiles['SecurePoll'] = "$dir/SecurePoll.alias.php";
5350
54 -$wgAutoloadClasses['SecurePollPage'] = "$dir/SecurePoll_body.php";
55 -$wgSpecialPages['SecurePoll'] = 'SecurePollPage';
 51+$wgSpecialPages['SecurePoll'] = 'SecurePoll_BasePage';
5652
5753 $wgAutoloadClasses = $wgAutoloadClasses + array(
5854 'SecurePoll_Auth' => "$dir/includes/Auth.php",
5955 'SecurePoll_LocalAuth' => "$dir/includes/Auth.php",
6056 'SecurePoll_RemoteMWAuth' => "$dir/includes/Auth.php",
6157 'SecurePoll_Ballot' => "$dir/includes/Ballot.php",
 58+ 'SecurePoll_BasePage' => "$dir/includes/Base.php",
6259 'SecurePoll_ChooseBallot' => "$dir/includes/Ballot.php",
6360 'SecurePoll_PreferentialBallot' => "$dir/includes/Ballot.php",
 61+ 'SecurePoll_Context' => "$dir/includes/Context.php",
6462 'SecurePoll_Crypt' => "$dir/includes/Crypt.php",
6563 'SecurePoll_GpgCrypt' => "$dir/includes/Crypt.php",
6664 'SecurePoll_DetailsPage' => "$dir/includes/DetailsPage.php",
6765 'SecurePoll_DumpPage' => "$dir/includes/DumpPage.php",
6866 'SecurePoll_Election' => "$dir/includes/Election.php",
 67+ 'SecurePoll_ElectionTallier' => "$dir/includes/ElectionTallier.php",
6968 'SecurePoll_Entity' => "$dir/includes/Entity.php",
7069 'SecurePoll_EntryPage' => "$dir/includes/EntryPage.php",
7170 'SecurePoll_ListPage' => "$dir/includes/ListPage.php",
@@ -73,8 +72,14 @@
7473 'SecurePoll_Option' => "$dir/includes/Option.php",
7574 'SecurePoll_Page' => "$dir/includes/Page.php",
7675 'SecurePoll_Question' => "$dir/includes/Question.php",
 76+ 'SecurePoll_Random' => "$dir/includes/Random.php",
 77+ 'SecurePoll_Store' => "$dir/includes/Store.php",
 78+ 'SecurePoll_DBStore' => "$dir/includes/Store.php",
 79+ 'SecurePoll_MemoryStore' => "$dir/includes/Store.php",
 80+ 'SecurePoll_XMLStore' => "$dir/includes/Store.php",
7781 'SecurePoll_Tallier' => "$dir/includes/Tallier.php",
7882 'SecurePoll_PluralityTallier' => "$dir/includes/Tallier.php",
 83+ 'SecurePoll_SchulzeTallier' => "$dir/includes/Tallier.php",
7984 'SecurePoll_TallyPage' => "$dir/includes/TallyPage.php",
8085 'SecurePoll_TranslatePage' => "$dir/includes/TranslatePage.php",
8186 'SecurePoll_Voter' => "$dir/includes/Voter.php",
@@ -82,8 +87,12 @@
8388 );
8489
8590 $wgAjaxExportList[] = 'wfSecurePollStrike';
 91+$wgHooks['UserLogout'][] = 'wfSecurePollLogout';
8692
8793 function wfSecurePollStrike( $action, $id, $reason ) {
8894 return SecurePoll_ListPage::ajaxStrike( $action, $id, $reason );
8995 }
90 -
 96+function wfSecurePollLogout( $user ) {
 97+ $_SESSION['securepoll_voter'] = null;
 98+ return true;
 99+}
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Auth.php
@@ -4,6 +4,8 @@
55 * Class for handling guest logins and sessions. Creates SecurePoll_Voter objects.
66 */
77 class SecurePoll_Auth {
 8+ var $context;
 9+
810 /**
911 * List of available authorisation modules (subclasses)
1012 */
@@ -16,14 +18,18 @@
1719 * Create an auth object of the given type
1820 * @param $type string
1921 */
20 - static function factory( $type ) {
 22+ static function factory( $context, $type ) {
2123 if ( !isset( self::$authTypes[$type] ) ) {
2224 throw new MWException( "Invalid authentication type: $type" );
2325 }
2426 $class = self::$authTypes[$type];
25 - return new $class;
 27+ return new $class( $context );
2628 }
2729
 30+ function __construct( $context ) {
 31+ $this->context = $context;
 32+ }
 33+
2834 /**
2935 * Create a voter transparently, without user interaction.
3036 * Sessions authorised against local accounts are created this way.
@@ -68,7 +74,7 @@
6975 }
7076
7177 # Sanity check election ID
72 - $voter = SecurePoll_Voter::newFromId( $voterId );
 78+ $voter = $this->context->getVoter( $voterId );
7379 if ( !$voter || $voter->getElectionId() != $election->getId() ) {
7480 return false;
7581 } else {
@@ -87,7 +93,7 @@
8894 * @return SecurePoll_Voter
8995 */
9096 function getVoter( $params ) {
91 - $dbw = wfGetDB( DB_MASTER );
 97+ $dbw = $this->context->getDB();
9298
9399 # This needs to be protected by FOR UPDATE
94100 # Otherwise a race condition could lead to duplicate users for a single remote user,
@@ -107,10 +113,10 @@
108114 if ( $row ) {
109115 # No need to hold the lock longer
110116 $dbw->commit();
111 - $user = SecurePoll_Voter::newFromRow( $row );
 117+ $user = $this->context->newVoterFromRow( $row );
112118 } else {
113119 # Lock needs to be held until the row is inserted
114 - $user = SecurePoll_Voter::createVoter( $params );
 120+ $user = $this->context->createVoter( $params );
115121 $dbw->commit();
116122 }
117123 return $user;
@@ -178,7 +184,7 @@
179185 if ( $wgUser->isAnon() ) {
180186 return Status::newFatal( 'securepoll-not-logged-in' );
181187 }
182 - $params = self::getUserParams( $wgUser );
 188+ $params = $this->getUserParams( $wgUser );
183189 $params['electionId'] = $election->getId();
184190 $qualStatus = $election->getQualifiedStatus( $params );
185191 if ( !$qualStatus->isOK() ) {
@@ -193,7 +199,7 @@
194200 * @param $user User
195201 * @return array
196202 */
197 - static function getUserParams( $user ) {
 203+ function getUserParams( $user ) {
198204 global $wgServer;
199205 if ( substr( $wgServer, 0, 5 ) == 'https' ) {
200206 global $site, $lang;
@@ -201,7 +207,7 @@
202208 } else {
203209 $server = preg_replace( '!.*/(.*)$!', '$1', $wgServer );
204210 }
205 - return array(
 211+ $params = array(
206212 'name' => $user->getName(),
207213 'type' => 'local',
208214 'domain' => $server,
@@ -213,9 +219,11 @@
214220 'bot' => $user->isBot(),
215221 'language' => $user->getOption( 'language' ),
216222 'groups' => $user->getGroups(),
217 - 'lists' => self::getLists( $user )
 223+ 'lists' => $this->getLists( $user )
218224 )
219225 );
 226+ wfRunHooks( 'SecurePoll_GetUserParams', array( $this, $user, &$params ) );
 227+ return $params;
220228 }
221229
222230 /**
@@ -223,8 +231,8 @@
224232 * @param $user User
225233 * @return array
226234 */
227 - static function getLists( $user ) {
228 - $dbr = wfGetDB( DB_SLAVE );
 235+ function getLists( $user ) {
 236+ $dbr = $this->context->getDB();
229237 $res = $dbr->select(
230238 'securepoll_lists',
231239 array( 'li_name' ),
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Crypt.php
@@ -29,9 +29,9 @@
3030 * Create an encryption object of the given type. Currently only "gpg" is
3131 * implemented.
3232 */
33 - static function factory( $type, $election ) {
 33+ static function factory( $context, $type, $election ) {
3434 if ( $type === 'gpg' ) {
35 - return new SecurePoll_GpgCrypt( $election );
 35+ return new SecurePoll_GpgCrypt( $context, $election );
3636 } else {
3737 return false;
3838 }
@@ -50,14 +50,15 @@
5151 * gpg-decrypt-key is for tallying.
5252 */
5353 class SecurePoll_GpgCrypt {
54 - var $election;
 54+ var $context, $election;
5555 var $recipient, $signer, $homeDir;
5656
5757 /**
5858 * Constructor.
5959 * @param $election SecurePoll_Election
6060 */
61 - function __construct( $election ) {
 61+ function __construct( $context, $election ) {
 62+ $this->context = $context;
6263 $this->election = $election;
6364 }
6465
Index: branches/wmf-deployment/extensions/SecurePoll/includes/DumpPage.php
@@ -4,6 +4,8 @@
55 * Special:SecurePoll subpage for exporting encrypted election records.
66 */
77 class SecurePoll_DumpPage extends SecurePoll_Page {
 8+ var $headersSent;
 9+
810 /**
911 * Execute the subpage.
1012 * @param $params array Array of subpage parameters.
@@ -17,7 +19,7 @@
1820 }
1921
2022 $electionId = intval( $params[0] );
21 - $this->election = $this->parent->getElection( $electionId );
 23+ $this->election = $this->context->getElection( $electionId );
2224 if ( !$this->election ) {
2325 $wgOut->addWikiMsg( 'securepoll-invalid-election', $electionId );
2426 return;
@@ -40,89 +42,36 @@
4143 return;
4244 }
4345
44 - if ( !$this->openRandom() ) {
45 - $wgOut->addWikiMsg( 'securepoll-dump-no-urandom' );
 46+ $this->headersSent = false;
 47+ $status = $this->election->dumpVotesToCallback( array( $this, 'dumpVote' ) );
 48+ if ( !$status->isOK() && !$this->headersSent ) {
 49+ $wgOut->addWikiText( $status->getWikiText() );
4650 return;
4751 }
48 -
49 - $wgOut->disable();
50 - header( 'Content-Type: text/plain' );
51 - $filename = urlencode( "SecurePoll-$electionId-" . wfTimestampNow() );
52 - header( "Content-Disposition: attachment; filename=$filename" );
53 - $db = wfGetDB( DB_SLAVE );
54 - $res = $db->select(
55 - 'securepoll_votes',
56 - array( 'vote_id', 'vote_record' ),
57 - array(
58 - 'vote_election' => $electionId,
59 - 'vote_current' => 1,
60 - 'vote_struck' => 0
61 - ),
62 - __METHOD__
63 - );
64 -
65 - $order = $this->shuffle( range( 0, $res->numRows() - 1 ) );
66 - foreach ( $order as $i ) {
67 - $res->seek( $i );
68 - echo $res->fetchObject()->vote_record . "\n\n";
 52+ if ( !$this->headersSent ) {
 53+ $this->sendHeaders();
6954 }
70 - $this->closeRandom();
 55+ echo "</election>\n</SecurePoll>\n";
7156 }
7257
73 - /**
74 - * Open the /dev/urandom device
75 - * @return bool success
76 - */
77 - function openRandom() {
78 - if ( wfIsWindows() ) {
79 - return false;
 58+ function dumpVote( $election, $row ) {
 59+ if ( !$this->headersSent ) {
 60+ $this->sendHeaders();
8061 }
81 - $this->urandom = fopen( '/dev/urandom', 'rb' );
82 - if ( !$this->urandom ) {
83 - return false;
84 - }
85 - return true;
 62+ echo "<vote>" . $row->vote_record . "</vote>\n";
8663 }
8764
88 - /**
89 - * Close the urandom device
90 - */
91 - function closeRandom() {
92 - fclose( $this->urandom );
93 - }
 65+ function sendHeaders() {
 66+ global $wgOut;
9467
95 - /**
96 - * Get a random integer between 0 and ($maxp1 - 1)
97 - */
98 - function random( $maxp1 ) {
99 - $numBytes = ceil( strlen( base_convert( $maxp1, 10, 16 ) ) / 2 );
100 - if ( $numBytes == 0 ) {
101 - return 0;
102 - }
103 - $data = fread( $this->urandom, $numBytes );
104 - if ( strlen( $data ) != $numBytes ) {
105 - throw new MWException( __METHOD__.': not enough bytes' );
106 - }
107 - $x = 0;
108 - for ( $i = 0; $i < $numBytes; $i++ ) {
109 - $x *= 256;
110 - $x += ord( substr( $data, $i, 1 ) );
111 - }
112 - return $x % $maxp1;
 68+ $this->headersSent = true;
 69+ $wgOut->disable();
 70+ header( 'Content-Type: application/vnd.mediawiki.securepoll' );
 71+ $electionId = $this->election->getId();
 72+ $filename = urlencode( "$electionId-" . wfTimestampNow() . '.securepoll' );
 73+ header( "Content-Disposition: attachment; filename=$filename" );
 74+ echo "<SecurePoll>\n<election>\n" .
 75+ $this->election->getConfXml();
 76+ $this->context->setLanguages( array( $this->election->getLanguage() ) );
11377 }
114 -
115 - /**
116 - * Works like shuffle() except more secure. Returns the new array instead
117 - * of modifying it. The algorithm is the Knuth/Durstenfeld kind.
118 - */
119 - function shuffle( $a ) {
120 - $a = array_values( $a );
121 - for ( $i = count( $a ) - 1; $i >= 0; $i-- ) {
122 - $target = $this->random( $i + 1 );
123 - $tmp = $a[$i];
124 - $a[$i] = $a[$target];
125 - $a[$target] = $tmp;
126 - }
127 - return $a;
128 - }
12978 }
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Election.php
@@ -56,34 +56,34 @@
5757 var $title, $ballotType, $tallyType, $primaryLang, $startDate, $endDate, $authType;
5858
5959 /**
60 - * Constructor.
 60+ * Constructor.
 61+ *
 62+ * Do not use this constructor directly, instead use SecurePoll_Context::getElection().
 63+ *
6164 * @param $id integer
6265 */
63 - function __construct( $id ) {
64 - parent::__construct( 'election', $id );
 66+ function __construct( $context, $info ) {
 67+ parent::__construct( $context, 'election', $info );
 68+ $this->title = $info['title'];
 69+ $this->ballotType = $info['ballot'];
 70+ $this->tallyType = $info['tally'];
 71+ $this->primaryLang = $info['primaryLang'];
 72+ $this->startDate = $info['startDate'];
 73+ $this->endDate = $info['endDate'];
 74+ $this->authType = $info['auth'];
6575 }
6676
6777 /**
68 - * Create an object based on a DB result row.
69 - * @param $row object
70 - */
71 - static function newFromRow( $row ) {
72 - $election = new self( $row->el_entity );
73 - $election->title = $row->el_title;
74 - $election->ballotType = $row->el_ballot;
75 - $election->tallyType = $row->el_tally;
76 - $election->primaryLang = $row->el_primary_lang;
77 - $election->startDate = $row->el_start_date;
78 - $election->endDate = $row->el_end_date;
79 - $election->authType = $row->el_auth_type;
80 - return $election;
81 - }
82 -
83 - /**
8478 * Get a list of localisable message names. See SecurePoll_Entity.
8579 */
8680 function getMessageNames() {
87 - return array( 'title', 'intro', 'jump-text', 'return-text' );
 81+ return array(
 82+ 'title',
 83+ 'intro',
 84+ 'jump-text',
 85+ 'return-text',
 86+ 'unqualified-error',
 87+ );
8888 }
8989
9090 /**
@@ -131,7 +131,7 @@
132132 */
133133 function getBallot() {
134134 if ( !$this->ballot ) {
135 - $this->ballot = SecurePoll_Ballot::factory( $this->ballotType, $this );
 135+ $this->ballot = $this->context->newBallot( $this->ballotType, $this );
136136 }
137137 return $this->ballot;
138138 }
@@ -180,6 +180,14 @@
181181 if ( $needList && !in_array( $needList, $lists ) ) {
182182 $status->fatal( 'securepoll-not-in-list' );
183183 }
 184+
 185+ # Get custom error message
 186+ if ( !$status->isOK() ) {
 187+ $errorMsg = $this->getMessage( 'unqualified-error' );
 188+ if ( $errorMsg !== '[unqualified-error]' && $errorMsg !== '' ) {
 189+ $status = Status::newFatal( 'securepoll-custom-unqualified', $errorMsg );
 190+ }
 191+ }
184192 return $status;
185193 }
186194
@@ -187,7 +195,7 @@
188196 * Returns true if the user is an admin of the current election.
189197 * @param $user User
190198 */
191 - function isAdmin( User $user ) {
 199+ function isAdmin( $user ) {
192200 $admins = array_map( 'trim', explode( '|', $this->getProperty( 'admins' ) ) );
193201 return in_array( $user->getName(), $admins );
194202 }
@@ -197,7 +205,7 @@
198206 * @param $voter SecurePoll_Voter
199207 */
200208 function hasVoted( $voter ) {
201 - $db = wfGetDB( DB_MASTER );
 209+ $db = $this->context->getDB();
202210 $row = $db->selectRow(
203211 'securepoll_votes',
204212 array( "1" ),
@@ -224,33 +232,11 @@
225233 */
226234 function getQuestions() {
227235 if ( $this->questions === null ) {
228 - $db = wfGetDB( DB_MASTER );
229 - $res = $db->select(
230 - array( 'securepoll_questions', 'securepoll_options' ),
231 - '*',
232 - array(
233 - 'qu_election' => $this->getId(),
234 - 'op_question=qu_entity'
235 - ),
236 - __METHOD__,
237 - array( 'ORDER BY' => 'qu_index, qu_entity' )
238 - );
239 -
 236+ $info = $this->context->getStore()->getQuestionInfo( $this->getId() );
240237 $this->questions = array();
241 - $options = array();
242 - $questionId = false;
243 - foreach ( $res as $row ) {
244 - if ( $questionId === false ) {
245 - } elseif ( $questionId !== $row->qu_entity ) {
246 - $this->questions[] = new SecurePoll_Question( $questionId, $options );
247 - $options = array();
248 - }
249 - $options[] = SecurePoll_Option::newFromRow( $row );
250 - $questionId = $row->qu_entity;
 238+ foreach ( $info as $questionInfo ) {
 239+ $this->questions[] = $this->context->newQuestion( $questionInfo );
251240 }
252 - if ( $questionId !== false ) {
253 - $this->questions[] = new SecurePoll_Question( $questionId, $options );
254 - }
255241 }
256242 return $this->questions;
257243 }
@@ -261,7 +247,7 @@
262248 */
263249 function getAuth() {
264250 if ( !$this->auth ) {
265 - $this->auth = SecurePoll_Auth::factory( $this->authType );
 251+ $this->auth = $this->context->newAuth( $this->authType );
266252 }
267253 return $this->auth;
268254 }
@@ -285,7 +271,7 @@
286272 if ( $type === false || $type === 'none' ) {
287273 return false;
288274 }
289 - $crypt = SecurePoll_Crypt::factory( $type, $this );
 275+ $crypt = $this->context->newCrypt( $type, $this );
290276 if ( !$crypt ) {
291277 throw new MWException( 'Invalid encryption type' );
292278 }
@@ -293,16 +279,112 @@
294280 }
295281
296282 /**
297 - * Get the tallier object
298 - * @return SecurePoll_Tallier
 283+ * Get the tally type
299284 */
300 - function getTallier() {
301 - $tallier = SecurePoll_Tallier::factory( $this->tallyType, $this );
302 - if ( !$tallier ) {
303 - throw new MWException( 'Invalid tally type' );
 285+ function getTallyType() {
 286+ return $this->tallyType;
 287+ }
 288+
 289+ /**
 290+ * Call a callback function for each valid vote record, in random order.
 291+ */
 292+ function dumpVotesToCallback( $callback ) {
 293+ if ( !$this->getCrypt() ) {
 294+ return Status::newFatal( 'securepoll-dump-no-crypt' );
304295 }
305 - return $tallier;
 296+
 297+ $random = $this->context->getRandom();
 298+ $status = $random->open();
 299+ if ( !$status->isOK() ) {
 300+ return $status;
 301+ }
 302+ $db = $this->context->getDB();
 303+ $res = $db->select(
 304+ 'securepoll_votes',
 305+ array( '*' ),
 306+ array(
 307+ 'vote_election' => $this->getId(),
 308+ 'vote_current' => 1,
 309+ 'vote_struck' => 0
 310+ ),
 311+ __METHOD__
 312+ );
 313+ if ( $res->numRows() ) {
 314+ $order = $random->shuffle( range( 0, $res->numRows() - 1 ) );
 315+ foreach ( $order as $i ) {
 316+ $res->seek( $i );
 317+ call_user_func( $callback, $this, $res->fetchObject() );
 318+ }
 319+ }
 320+ $random->close();
 321+ return Status::newGood();
306322 }
307323
 324+ /**
 325+ * Get an XML snippet describing the configuration of this object
 326+ */
 327+ function getConfXml( $options = array() ) {
 328+ $s = "<configuration>\n" .
 329+ Xml::element( 'title', array(), $this->title ) . "\n" .
 330+ Xml::element( 'ballot', array(), $this->ballotType ) . "\n" .
 331+ Xml::element( 'tally', array(), $this->tallyType ) . "\n" .
 332+ Xml::element( 'primaryLang', array(), $this->primaryLang ) . "\n" .
 333+ Xml::element( 'startDate', array(), wfTimestamp( TS_ISO_8601, $this->startDate ) ) . "\n" .
 334+ Xml::element( 'endDate', array(), wfTimestamp( TS_ISO_8601, $this->endDate ) ) . "\n" .
 335+ $this->getConfXmlEntityStuff( $options );
 336+
 337+ # If we're making a jump dump, we need to add some extra properties, and
 338+ # override the auth type
 339+ if ( !empty( $options['jump'] ) ) {
 340+ $s .=
 341+ Xml::element( 'auth', array(), 'local' ) . "\n" .
 342+ Xml::element( 'property',
 343+ array( 'name' => 'jump-url' ),
 344+ $this->context->getSpecialTitle()->getFullURL()
 345+ ) . "\n" .
 346+ Xml::element( 'property',
 347+ array( 'name' => 'jump-id' ),
 348+ $this->getId()
 349+ ) . "\n";
 350+ } else {
 351+ $s .= Xml::element( 'auth', array(), $this->authType ) . "\n";
 352+ }
 353+
 354+ foreach ( $this->getQuestions() as $question ) {
 355+ $s .= $question->getConfXml( $options );
 356+ }
 357+ $s .= "</configuration>\n";
 358+ return $s;
 359+ }
 360+
 361+ /**
 362+ * Get property names which aren't included in an XML dump
 363+ */
 364+ function getPropertyDumpBlacklist( $options = array() ) {
 365+ if ( !empty( $options['jump'] ) ) {
 366+ return array(
 367+ 'gpg-encrypt-key',
 368+ 'gpg-sign-key',
 369+ 'gpg-decrypt-key'
 370+ );
 371+ } else {
 372+ return array();
 373+ }
 374+ }
 375+
 376+ /**
 377+ * Tally the valid votes for this election.
 378+ * Returns a Status object. On success, the value property will contain a
 379+ * SecurePoll_ElectionTallier object.
 380+ */
 381+ function tally() {
 382+ $tallier = $this->context->newElectionTallier( $this );
 383+ $status = $tallier->execute();
 384+ if ( $status->isOK() ) {
 385+ return Status::newGood( $tallier );
 386+ } else {
 387+ return $status;
 388+ }
 389+ }
308390 }
309391
Index: branches/wmf-deployment/extensions/SecurePoll/includes/LoginPage.php
@@ -14,7 +14,7 @@
1515 }
1616
1717 $electionId = intval( $params[0] );
18 - $this->election = $this->parent->getElection( $electionId );
 18+ $this->election = $this->context->getElection( $electionId );
1919 if ( !$this->election ) {
2020 $wgOut->addWikiMsg( 'securepoll-invalid-election', $electionId );
2121 return;
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Question.php
@@ -9,12 +9,15 @@
1010
1111 /**
1212 * Constructor
13 - * @param $id integer
14 - * @param $options array Array of SecurePoll_Option children
 13+ * @param $context SecurePoll_Context
 14+ * @param $info Associative array of entity info
1515 */
16 - function __construct( $id, $options ) {
17 - parent::__construct( 'question', $id );
18 - $this->options = $options;
 16+ function __construct( $context, $info ) {
 17+ parent::__construct( $context, 'question', $info );
 18+ $this->options = array();
 19+ foreach ( $info['options'] as $optionInfo ) {
 20+ $this->options[] = new SecurePoll_Option( $context, $optionInfo );
 21+ }
1922 }
2023
2124 /**
@@ -31,5 +34,16 @@
3235 return $this->options;
3336 }
3437
35 - function getOptions() { return $this->options; }
 38+ function getOptions() {
 39+ return $this->options;
 40+ }
 41+
 42+ function getConfXml( $options = array() ) {
 43+ $s = "<question>\n" . $this->getConfXmlEntityStuff( $options );
 44+ foreach ( $this->getOptions() as $option ) {
 45+ $s .= $option->getConfXml( $options );
 46+ }
 47+ $s .= "</question>\n";
 48+ return $s;
 49+ }
3650 }
Index: branches/wmf-deployment/extensions/SecurePoll/includes/MessageDumpPage.php
@@ -10,7 +10,7 @@
1111 }
1212
1313 $electionId = intval( $params[0] );
14 - $this->election = $this->parent->getElection( $electionId );
 14+ $this->election = $this->context->getElection( $electionId );
1515 if ( !$this->election ) {
1616 $wgOut->addWikiMsg( 'securepoll-invalid-election', $electionId );
1717 return;
@@ -18,9 +18,9 @@
1919
2020 $wgOut->disable();
2121 header( 'Content-Type: application/x-sql; charset=utf-8' );
22 - $filename = urlencode( "sp-msgs-$electionId-" . wfTimestampNow() );
 22+ $filename = urlencode( "sp-msgs-$electionId-" . wfTimestampNow() . '.sql' );
2323 header( "Content-Disposition: attachment; filename=$filename" );
24 - $dbr = wfGetDB( DB_SLAVE );
 24+ $dbr = $this->context->getDB();
2525
2626 $entities = array_merge( array( $this->election ), $this->election->getDescendants() );
2727 $ids = array();
Index: branches/wmf-deployment/extensions/SecurePoll/includes/ListPage.php
@@ -20,7 +20,7 @@
2121 }
2222
2323 $electionId = intval( $params[0] );
24 - $this->election = $this->parent->getElection( $electionId );
 24+ $this->election = $this->context->getElection( $electionId );
2525 if ( !$this->election ) {
2626 $wgOut->addWikiMsg( 'securepoll-invalid-election', $electionId );
2727 return;
@@ -84,7 +84,7 @@
8585 */
8686 static function ajaxStrike( $action, $id, $reason ) {
8787 wfLoadExtensionMessages( 'SecurePoll' );
88 - $db = wfGetDB( DB_MASTER );
 88+ $db = $this->context->getDB();
8989 $table = $db->tableName( 'securepoll_elections' );
9090 $row = $db->selectRow(
9191 array( 'securepoll_votes', 'securepoll_elections' ),
@@ -98,9 +98,9 @@
9999 'message' => wfMsgHtml( 'securepoll-strike-nonexistent' )
100100 ) );
101101 }
102 - $page = new SecurePollPage;
 102+ $page = new SecurePoll_BasePage;
103103 $subpage = new self( $page );
104 - $subpage->election = SecurePoll_Election::newFromRow( $row );
 104+ $subpage->election = $subpage->context->newElectionFromRow( $row );
105105 $status = $subpage->strike( $action, $id, $reason );
106106 if ( $status->isGood() ) {
107107 return Xml::encodeJsVar( (object)array( 'status' => 'good' ) );
@@ -122,7 +122,7 @@
123123 */
124124 function strike( $action, $voteId, $reason ) {
125125 global $wgUser;
126 - $dbw = wfGetDB( DB_MASTER );
 126+ $dbw = $this->context->getDB();
127127 if ( !$this->election->isAdmin( $wgUser ) ) {
128128 return Status::newFatal( 'securepoll-need-admin' );
129129 }
@@ -220,7 +220,7 @@
221221 function formatValue( $name, $value ) {
222222 global $wgLang;
223223 $critical = Xml::element( 'img',
224 - array( 'src' => $GLOBALS['wgStylePath'] . '/common/images/critical-32.png' )
 224+ array( 'src' => $GLOBALS['wgScriptPath'] . '/extensions/SecurePoll/resources/critical-32.png' )
225225 );
226226
227227 switch ( $name ) {
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Option.php
@@ -6,22 +6,15 @@
77 */
88 class SecurePoll_Option extends SecurePoll_Entity {
99 /**
10 - * Create a new option from a DB row
11 - * @param $row object
 10+ * Constructor
 11+ * @param $context SecurePoll_Context
 12+ * @param $info Associative array of entity info
1213 */
13 - static function newFromRow( $row ) {
14 - return new self( $row->op_entity );
 14+ function __construct( $context, $info ) {
 15+ parent::__construct( $context, 'option', $info );
1516 }
1617
1718 /**
18 - * Constructor, from entity ID
19 - * @param $id integer
20 - */
21 - function __construct( $id ) {
22 - parent::__construct( 'option', $id );
23 - }
24 -
25 - /**
2619 * Get a list of localisable message names. This is used to provide the
2720 * translate subpage with a list of messages to localise.
2821 */
Index: branches/wmf-deployment/extensions/SecurePoll/includes/VotePage.php
@@ -19,7 +19,7 @@
2020 }
2121
2222 $electionId = intval( $params[0] );
23 - $this->election = $this->parent->getElection( $electionId );
 23+ $this->election = $this->context->getElection( $electionId );
2424 if ( !$this->election ) {
2525 $wgOut->addWikiMsg( 'securepoll-invalid-election', $electionId );
2626 return;
@@ -160,7 +160,7 @@
161161 $encrypted = $status->value;
162162 }
163163
164 - $dbw = wfGetDB( DB_MASTER );
 164+ $dbw = $this->context->getDB();
165165 $dbw->begin();
166166
167167 # Mark previous votes as old
@@ -236,6 +236,7 @@
237237 throw new MWException( 'Configuration error: no jump-id' );
238238 }
239239 $url .= "/login/$id";
 240+ wfRunHooks( 'SecurePoll_JumpUrl', array( $this, &$url ) );
240241 $wgOut->addWikiText( $this->election->getMessage( 'jump-text' ) );
241242 $wgOut->addHTML(
242243 Xml::openElement( 'form', array( 'action' => $url, 'method' => 'post' ) ) .
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Base.php
@@ -0,0 +1,105 @@
 2+<?php
 3+
 4+class SecurePoll_BasePage extends UnlistedSpecialPage {
 5+ static $pages = array(
 6+ 'details' => 'SecurePoll_DetailsPage',
 7+ 'dump' => 'SecurePoll_DumpPage',
 8+ 'entry' => 'SecurePoll_EntryPage',
 9+ 'list' => 'SecurePoll_ListPage',
 10+ 'login' => 'SecurePoll_LoginPage',
 11+ 'msgdump' => 'SecurePoll_MessageDumpPage',
 12+ 'tally' => 'SecurePoll_TallyPage',
 13+ 'translate' => 'SecurePoll_TranslatePage',
 14+ 'vote' => 'SecurePoll_VotePage',
 15+ );
 16+
 17+ var $sp_context;
 18+
 19+ /**
 20+ * Constructor
 21+ */
 22+ public function __construct() {
 23+ parent::__construct( 'SecurePoll' );
 24+ $this->sp_context = new SecurePoll_Context;
 25+ }
 26+
 27+ /**
 28+ * Show the special page
 29+ *
 30+ * @param $paramString Mixed: parameter passed to the page or null
 31+ */
 32+ public function execute( $paramString ) {
 33+ global $wgOut, $wgUser, $wgRequest, $wgScriptPath;
 34+
 35+ wfLoadExtensionMessages( 'SecurePoll' );
 36+
 37+ $this->setHeaders();
 38+ $wgOut->addLink( array(
 39+ 'rel' => 'stylesheet',
 40+ 'href' => "$wgScriptPath/extensions/SecurePoll/resources/SecurePoll.css",
 41+ 'type' => 'text/css'
 42+ ) );
 43+ $wgOut->addScriptFile( "$wgScriptPath/extensions/SecurePoll/resources/SecurePoll.js" );
 44+
 45+ $this->request = $wgRequest;
 46+
 47+ $paramString = strval( $paramString );
 48+ if ( $paramString === '' ) {
 49+ $paramString = 'entry';
 50+ }
 51+ $params = explode( '/', $paramString );
 52+ $pageName = array_shift( $params );
 53+ $page = $this->getSubpage( $pageName );
 54+ if ( !$page ) {
 55+ $wgOut->addWikiMsg( 'securepoll-invalid-page', $pageName );
 56+ return;
 57+ }
 58+
 59+ if ( !($page instanceof SecurePoll_EntryPage ) ) {
 60+ $this->setSubtitle();
 61+ }
 62+
 63+ $page->execute( $params );
 64+ }
 65+
 66+ /**
 67+ * Get a SecurePoll_Page subclass object for the given subpage name
 68+ */
 69+ function getSubpage( $name ) {
 70+ if ( !isset( self::$pages[$name] ) ) {
 71+ return false;
 72+ }
 73+ $className = self::$pages[$name];
 74+ $page = new $className( $this );
 75+ return $page;
 76+ }
 77+
 78+ /**
 79+ * Get a random token for CSRF protection
 80+ */
 81+ function getEditToken() {
 82+ if ( !isset( $_SESSION['spToken'] ) ) {
 83+ $_SESSION['spToken'] = sha1( mt_rand() . mt_rand() . mt_rand() );
 84+ }
 85+ return $_SESSION['spToken'];
 86+ }
 87+
 88+ /**
 89+ * Set a navigation subtitle.
 90+ * Each argument is a two-element array giving a Title object to be used as
 91+ * a link target, and the link text.
 92+ */
 93+ function setSubtitle( /*...*/ ) {
 94+ global $wgUser, $wgOut;
 95+ $skin = $wgUser->getSkin();
 96+ $title = $this->getTitle();
 97+ $subtitle = '&lt; ' . $skin->linkKnown( $title, htmlspecialchars( $title->getText() ) );
 98+ $pipe = wfMsg( 'pipe-separator' );
 99+ $links = func_get_args();
 100+ foreach ( $links as $link ) {
 101+ list( $title, $text ) = $link;
 102+ $subtitle .= $pipe . $skin->linkKnown( $title, htmlspecialchars( $text ) );
 103+ }
 104+ $wgOut->setSubtitle( $subtitle );
 105+ }
 106+}
Property changes on: branches/wmf-deployment/extensions/SecurePoll/includes/Base.php
___________________________________________________________________
Added: svn:mergeinfo
Added: svn:eol-style
1107 + native
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Entity.php
@@ -12,21 +12,21 @@
1313 */
1414 class SecurePoll_Entity {
1515 var $id;
 16+ var $context;
1617 var $messagesLoaded = array();
1718 var $properties;
1819
19 - static $languages = array();
20 - static $messageCache = array();
21 -
2220 /**
2321 * Create an entity of the given type. This is typically called from the
2422 * child constructor.
 23+ * @param $context SecurePoll_Context
2524 * @param $type string
26 - * @param $id integer
 25+ * @param $info Associative array of entity info
2726 */
28 - function __construct( $type, $id = false ) {
 27+ function __construct( $context, $type, $info ) {
 28+ $this->context = $context;
2929 $this->type = $type;
30 - $this->id = $id;
 30+ $this->id = isset( $info['id'] ) ? $info['id'] : false;
3131 }
3232
3333 /**
@@ -54,17 +54,6 @@
5555 }
5656
5757 /**
58 - * Set the global language fallback sequence.
59 - *
60 - * @param $languages array A list of language codes. When a message is
61 - * requested, the first code in the array will be tried first, followed
62 - * by the subsequent codes.
63 - */
64 - static function setLanguages( $languages ) {
65 - self::$languages = $languages;
66 - }
67 -
68 - /**
6958 * Get the child entity objects. When the messages of an object are loaded,
7059 * the messages of the children are loaded automatically, to reduce the
7160 * query count.
@@ -96,32 +85,13 @@
9786 */
9887 function loadMessages( $lang = false ) {
9988 if ( $lang === false ) {
100 - $lang = reset( self::$languages );
 89+ $lang = reset( $this->context->languages );
10190 }
10291 $ids = array( $this->getId() );
10392 foreach ( $this->getDescendants() as $child ) {
104 - $id = $child->getId();
105 - if ( !isset( self::$messageCache[$lang][$id] ) ) {
106 - $ids[] = $id;
107 - }
 93+ $ids[] = $child->getId();
10894 }
109 - if ( !count( $ids ) ) {
110 - return;
111 - }
112 -
113 - $db = wfGetDB( DB_MASTER );
114 - $res = $db->select(
115 - 'securepoll_msgs',
116 - '*',
117 - array(
118 - 'msg_entity' => $ids,
119 - 'msg_lang' => $lang
120 - ),
121 - __METHOD__
122 - );
123 - foreach ( $res as $row ) {
124 - self::$messageCache[$row->msg_lang][$row->msg_entity][$row->msg_key] = $row->msg_text;
125 - }
 95+ $this->context->getMessages( $lang, $ids );
12696 $this->messagesLoaded[$lang] = true;
12797 }
12898
@@ -131,15 +101,11 @@
132102 * automatically.
133103 */
134104 function loadProperties() {
135 - $db = wfGetDB( DB_MASTER );
136 - $res = $db->select(
137 - 'securepoll_properties',
138 - '*',
139 - array( 'pr_entity' => $this->getId() ),
140 - __METHOD__ );
141 - $this->properties = array();
142 - foreach ( $res as $row ) {
143 - $this->properties[$row->pr_key] = $row->pr_value;
 105+ $properties = $this->context->getStore()->getProperties( array( $this->getId() ) );
 106+ if ( count( $properties ) ) {
 107+ $this->properties = reset( $properties );
 108+ } else {
 109+ $this->properties = array();
144110 }
145111 }
146112
@@ -154,11 +120,7 @@
155121 if ( empty( $this->messagesLoaded[$language] ) ) {
156122 $this->loadMessages( $language );
157123 }
158 - if ( !isset( self::$messageCache[$language][$this->getId()][$name] ) ) {
159 - return false;
160 - } else {
161 - return self::$messageCache[$language][$this->getId()][$name];
162 - }
 124+ return $this->context->getMessage( $language, $this->getId(), $name );
163125 }
164126
165127 /**
@@ -170,18 +132,54 @@
171133 */
172134 function getMessage( $name ) {
173135 $id = $this->getId();
174 - foreach ( self::$languages as $language ) {
 136+ foreach ( $this->context->languages as $language ) {
175137 if ( empty( $this->messagesLoaded[$language] ) ) {
176138 $this->loadMessages( $language );
177139 }
178 - if ( isset( self::$messageCache[$language][$id][$name] ) ) {
179 - return self::$messageCache[$language][$id][$name];
 140+ $message = $this->getRawMessage( $name, $language );
 141+ if ( $message !== false ) {
 142+ return $message;
180143 }
181144 }
182145 return "[$name]";
183146 }
184147
185148 /**
 149+ * Get a message, and interpret it as wikitext, converting it to HTML.
 150+ */
 151+ function parseMessage( $name, $lineStart = true ) {
 152+ global $wgParser, $wgTitle;
 153+ $parserOptions = $this->context->getParserOptions();
 154+ if ( $wgTitle ) {
 155+ $title = $wgTitle;
 156+ } else {
 157+ $title = SpecialPage::getTitleFor( 'SecurePoll' );
 158+ }
 159+ $wikiText = $this->getMessage( $name );
 160+ $out = $wgParser->parse( $wikiText, $title, $parserOptions, $lineStart );
 161+ return $out->getText();
 162+ }
 163+
 164+ /**
 165+ * Get a message and convert it from wikitext to HTML, without <p> tags.
 166+ */
 167+ function parseMessageInline( $name ) {
 168+ return $this->parseMessage( $name, false );
 169+ }
 170+
 171+ /**
 172+ * Get a list of languages for which we have translations, for this entity
 173+ * and its descendants.
 174+ */
 175+ function getLangList() {
 176+ $ids = array( $this->getId() );
 177+ foreach ( $this->getDescendants() as $child ) {
 178+ $ids[] = $child->getId();
 179+ }
 180+ return $this->context->getStore()->getLangList( $ids );
 181+ }
 182+
 183+ /**
186184 * Get a property value. If it does not exist, the $default parameter
187185 * is passed back.
188186 * @param $name string
@@ -198,4 +196,62 @@
199197 }
200198 }
201199
 200+ /**
 201+ * Get all defined properties as an associative array
 202+ */
 203+ function getAllProperties() {
 204+ if ( $this->properties === null ) {
 205+ $this->loadProperties();
 206+ }
 207+ return $this->properties;
 208+ }
 209+
 210+ /**
 211+ * Get configuration XML. Overridden by most subclasses.
 212+ */
 213+ function getConfXml( $options = array() ) {
 214+ return "<{$this->type}>\n" .
 215+ $this->getConfXmlEntityStuff( $options ) .
 216+ "</{$this->type}>\n";
 217+ }
 218+
 219+ /**
 220+ * Get an XML snippet giving the messages and properties
 221+ */
 222+ function getConfXmlEntityStuff( $options = array() ) {
 223+ $s = Xml::element( 'id', array(), $this->getId() ) . "\n";
 224+ $blacklist = $this->getPropertyDumpBlacklist( $options );
 225+ foreach ( $this->getAllProperties() as $name => $value ) {
 226+ if ( !in_array( $name, $blacklist ) ) {
 227+ $s .= Xml::element( 'property', array( 'name' => $name ), $value ) . "\n";
 228+ }
 229+ }
 230+ if ( isset( $options['langs'] ) ) {
 231+ $langs = $options['langs'];
 232+ } else {
 233+ $langs = $this->context->languages;
 234+ }
 235+ foreach ( $this->getMessageNames() as $name ) {
 236+ foreach ( $langs as $lang ) {
 237+ $value = $this->getRawMessage( $name, $lang );
 238+ if ( $value !== false ) {
 239+ $s .= Xml::element(
 240+ 'message',
 241+ array( 'name' => $name, 'lang' => $lang ),
 242+ $value
 243+ ) . "\n";
 244+ }
 245+ }
 246+ }
 247+ return $s;
 248+ }
 249+
 250+ /**
 251+ * Get property names which aren't included in an XML dump.
 252+ * Overloaded by Election.
 253+ */
 254+ function getPropertyDumpBlacklist( $options = array() ) {
 255+ return array();
 256+ }
 257+
202258 }
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Page.php
@@ -5,6 +5,7 @@
66 */
77 abstract class SecurePoll_Page {
88 var $parent, $election, $auth, $user;
 9+ var $context;
910
1011 /**
1112 * Constructor.
@@ -12,6 +13,7 @@
1314 */
1415 function __construct( $parent ) {
1516 $this->parent = $parent;
 17+ $this->context = $parent->sp_context;
1618 }
1719
1820 /**
@@ -48,6 +50,6 @@
4951 if ( $fallback != 'en' ) {
5052 $languages[] = 'en';
5153 }
52 - SecurePoll_Entity::setLanguages( $languages );
 54+ $this->context->setLanguages( $languages );
5355 }
5456 }
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Ballot.php
@@ -4,7 +4,7 @@
55 * Parent class for ballot forms. This is the UI component of a voting method.
66 */
77 abstract class SecurePoll_Ballot {
8 - var $election;
 8+ var $election, $context;
99
1010 /**
1111 * Get a list of names of tallying methods, which may be used to produce a
@@ -14,11 +14,11 @@
1515 abstract function getTallyTypes();
1616
1717 /**
18 - * Get the HTML for this ballot. <form> tags should not be included,
19 - * they will be added by the VotePage.
 18+ * Get the HTML form segment for a single question
 19+ * @param $question SecurePoll_Question
2020 * @return string
2121 */
22 - abstract function getForm();
 22+ abstract function getQuestionForm( $question );
2323
2424 /**
2525 * Called when the form is submitted. This returns a Status object which,
@@ -35,17 +35,18 @@
3636
3737 /**
3838 * Create a ballot of the given type
 39+ * @param $context SecurePoll_Context
3940 * @param $type string
4041 * @param $election SecurePoll_Election
4142 */
42 - static function factory( $type, $election ) {
 43+ static function factory( $context, $type, $election ) {
4344 switch ( $type ) {
4445 case 'approval':
45 - return new SecurePoll_ApprovalBallot( $election );
 46+ return new SecurePoll_ApprovalBallot( $context, $election );
4647 case 'preferential':
47 - return new SecurePoll_PreferentialBallot( $election );
 48+ return new SecurePoll_PreferentialBallot( $context, $election );
4849 case 'choose':
49 - return new SecurePoll_ChooseBallot( $election );
 50+ return new SecurePoll_ChooseBallot( $context, $election );
5051 default:
5152 throw new MWException( "Invalid ballot type: $type" );
5253 }
@@ -53,11 +54,35 @@
5455
5556 /**
5657 * Constructor.
 58+ * @param $context SecurePoll_Context
5759 * @param $election SecurePoll_Election
5860 */
59 - function __construct( $election ) {
 61+ function __construct( $context, $election ) {
 62+ $this->context = $context;
6063 $this->election = $election;
6164 }
 65+
 66+ /**
 67+ * Get the HTML for this ballot. <form> tags should not be included,
 68+ * they will be added by the VotePage.
 69+ * @return string
 70+ */
 71+ function getForm() {
 72+ global $wgParser, $wgTitle;
 73+ $questions = $this->election->getQuestions();
 74+ if ( $this->election->getProperty( 'shuffle-questions' ) ) {
 75+ shuffle( $questions );
 76+ }
 77+
 78+ $s = '';
 79+ foreach ( $questions as $question ) {
 80+ $s .= "<hr/>\n" .
 81+ $question->parseMessage( 'text' ) .
 82+ $this->getQuestionForm( $question ) .
 83+ "\n";
 84+ }
 85+ return $s;
 86+ }
6287 }
6388
6489 /**
@@ -79,37 +104,27 @@
80105 }
81106
82107 /**
83 - * Get the HTML for this ballot.
 108+ * Get the HTML form segment for a single question
 109+ * @param $question SecurePoll_Question
84110 * @return string
85111 */
86 - function getForm() {
87 - global $wgParser, $wgTitle;
88 - $questions = $this->election->getQuestions();
89 - if ( $this->election->getProperty( 'shuffle-questions' ) ) {
90 - shuffle( $questions );
 112+ function getQuestionForm( $question ) {
 113+ $options = $question->getChildren();
 114+ if ( $this->election->getProperty( 'shuffle-options' ) ) {
 115+ shuffle( $options );
91116 }
92 -
 117+ $name = 'securepoll_q' . $question->getId();
93118 $s = '';
94 - $parserOpts = new ParserOptions;
95 -
96 - foreach ( $questions as $question ) {
97 - $s .= "<hr/>\n";
98 - $s .= $wgParser->parse( $question->getMessage( 'text' ), $wgTitle, $parserOpts )->getText();
99 - $options = $question->getChildren();
100 - if ( $this->election->getProperty( 'shuffle-options' ) ) {
101 - shuffle( $options );
102 - }
103 - $name = 'securepoll_q' . $question->getId();
104 - foreach ( $options as $option ) {
105 - $optionText = $option->getMessage( 'text' );
106 - $optionHTML = $wgParser->parse( $optionText, $wgTitle, $parserOpts, false )->getText();
107 - $optionId = $option->getId();
108 - $radioId = "{$name}_opt{$optionId}";
109 - $s .= Xml::radio( $name, $optionId, false, array( 'id' => $radioId ) ) .
110 - '&nbsp;' .
111 - Xml::tags( 'label', array( 'for' => $radioId ), $optionText ) .
112 - "<br/>\n";
113 - }
 119+ foreach ( $options as $option ) {
 120+ $optionHTML = $option->parseMessageInline( 'text' );
 121+ $optionId = $option->getId();
 122+ $radioId = "{$name}_opt{$optionId}";
 123+ $s .=
 124+ '<div class="securepoll-option-choose">' .
 125+ Xml::radio( $name, $optionId, false, array( 'id' => $radioId ) ) .
 126+ '&nbsp;' .
 127+ Xml::tags( 'label', array( 'for' => $radioId ), $optionHTML ) .
 128+ "</div>\n";
114129 }
115130 return $s;
116131 }
@@ -154,61 +169,100 @@
155170 }
156171
157172 /**
158 - * TODO: this is code copied directly from BoardVote, it needs to be ported.
 173+ * Ballot for preferential voting
 174+ * Properties:
 175+ * shuffle-questions
 176+ * shuffle-options
 177+ * must-rank-all
159178 */
160179 class SecurePoll_PreferentialBallot extends SecurePoll_Ballot {
161180 function getTallyTypes() {
162 - return array( 'plurality', 'condorcet' );
 181+ return array( 'schulze' );
163182 }
164183
165 - function getRecord() {
166 - global $wgBoardCandidates;
167 -
168 - $record = "I prefer: ";
169 - $num_candidates = count( $wgBoardCandidates );
170 - $cnt = 0;
171 - foreach ( $this->mVotedFor as $i => $rank ) {
172 - $cnt++;
173 -
174 - $record .= $wgBoardCandidates[ $i ] . "[";
175 - $record .= ( $rank == '' ) ? 100 : $rank;
176 - $record .= "]";
177 - $record .= ( $cnt != $num_candidates ) ? ", " : "";
 184+ function getQuestionForm( $question ) {
 185+ global $wgRequest;
 186+ $options = $question->getChildren();
 187+ if ( $this->election->getProperty( 'shuffle-options' ) ) {
 188+ shuffle( $options );
178189 }
179 - $record .= "\n";
 190+ $name = 'securepoll_q' . $question->getId();
 191+ $s = '';
 192+ foreach ( $options as $option ) {
 193+ $optionHTML = $option->parseMessageInline( 'text' );
 194+ $optionId = $option->getId();
 195+ $inputId = "{$name}_opt{$optionId}";
 196+ $oldValue = $wgRequest->getVal( $inputId, '' );
 197+ $s .=
 198+ '<div class="securepoll-option-preferential">' .
 199+ Xml::input( $inputId, '3', $oldValue, array(
 200+ 'id' => $inputId,
 201+ 'maxlength' => 3,
 202+ ) ) .
 203+ '&nbsp;' .
 204+ Xml::tags( 'label', array( 'for' => $inputId ), $optionHTML ) .
 205+ '&nbsp;' .
 206+ "</div>\n";
 207+ }
 208+ return $s;
 209+ }
180210
181 - // Pad it out with spaces to a constant length, so that the encrypted record is secure
182 - $padLength = array_sum( array_map( 'strlen', $wgBoardCandidates ) ) + $num_candidates * 8 + 20;
183 - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^
184 - // length of the candidate names added together room for rank & separators extra
 211+ function submitForm() {
 212+ global $wgRequest;
 213+ $questions = $this->election->getQuestions();
 214+ $record = '';
 215+ $status = Status::newGood();
185216
186 - $record = str_pad( $record, $padLength );
187 - return $record;
188 - }
 217+ foreach ( $questions as $question ) {
 218+ $options = $question->getOptions();
 219+ foreach ( $options as $option ) {
 220+ $id = 'securepoll_q' . $question->getId() . '_opt' . $option->getId();
 221+ $rank = $wgRequest->getVal( $id );
189222
190 - function validVote() {
191 - foreach ( $this->mVotedFor as $rank ) {
192 - if ( $rank != '' ) {
193 - if ( !preg_match( '/^[1-9]\d?$/', $rank ) ) {
194 - return false;
 223+ if ( is_numeric( $rank ) ) {
 224+ if ( $rank <= 0 || $rank >= 1000 ) {
 225+ $status->fatal( 'securepoll-invalid-rank', $id );
 226+ continue;
 227+ } else {
 228+ $rank = intval( $rank );
 229+ }
 230+ } elseif ( strval( $rank ) === '' ) {
 231+ if ( $this->election->getProperty( 'must-rank-all' ) ) {
 232+ $status->fatal( 'securepoll-unranked-options', $id );
 233+ continue;
 234+ } else {
 235+ $rank = 1000;
 236+ }
 237+ } else {
 238+ $status->fatal( 'securepoll-invalid-rank', $id );
 239+ continue;
195240 }
 241+ $record .= sprintf( 'Q%08X-A%08X-R%08X--',
 242+ $question->getId(), $option->getId(), $rank );
196243 }
197244 }
198 -
199 - return true;
 245+ if ( $status->isOK() ) {
 246+ $status->value = $record . "\n";
 247+ }
 248+ return $status;
200249 }
201250
202 - function voteEntry( $index, $candidate ) {
203 - return "
204 - <tr><td align=\"right\">
205 - <input type=\"text\" maxlength=\"2\" size=\"2\" name=\"candidate[{$index}]\" />
206 - </td><td align=\"left\">
207 - $candidate
208 - </td></tr>";
 251+ function unpackRecord( $record ) {
 252+ $ranks = array();
 253+ $itemLength = 3*8 + 7;
 254+ for ( $offset = 0; $offset < strlen( $record ); $offset += $itemLength ) {
 255+ if ( !preg_match( '/Q([0-9A-F]{8})-A([0-9A-F]{8})-R([0-9A-F]{8})--/A',
 256+ $record, $m, 0, $offset ) )
 257+ {
 258+ wfDebug( __METHOD__.": regex doesn't match\n" );
 259+ return false;
 260+ }
 261+ $qid = intval( base_convert( $m[1], 16, 10 ) );
 262+ $oid = intval( base_convert( $m[2], 16, 10 ) );
 263+ $rank = intval( base_convert( $m[3], 16, 10 ) );
 264+ $ranks[$qid][$oid] = $rank;
 265+ }
 266+ return $ranks;
209267 }
210 -
211 - function getForm() { }
212 - function submitForm() { }
213 - function unpackRecord( $record ) {}
214268 }
215269
Index: branches/wmf-deployment/extensions/SecurePoll/includes/ElectionTallier.php
@@ -0,0 +1,119 @@
 2+<?php
 3+
 4+/**
 5+ * A helper class for tallying a whole election (with multiple questions).
 6+ * Most of the functionality is contained in the SecurePoll_Tallier subclasses
 7+ * which operate on a single question at a time.
 8+ *
 9+ * A convenience function for accessing this class is
 10+ * SecurePoll_Election::tally().
 11+ */
 12+class SecurePoll_ElectionTallier {
 13+ /**
 14+ * Constructor.
 15+ * @param $context SecurePoll_Context
 16+ * @param $election SecurePoll_Election
 17+ */
 18+ function __construct( $context, $election ) {
 19+ $this->context = $context;
 20+ $this->election = $election;
 21+ }
 22+
 23+ /**
 24+ * Do the tally. Returns a Status object. On success, the value property
 25+ * of the status will be an array of SecurePoll_Tallier objects, which can
 26+ * be queried for results information.
 27+ */
 28+ function execute() {
 29+ $store = $this->context->getStore();
 30+ $this->crypt = $this->election->getCrypt();
 31+ $this->ballot = $this->election->getBallot();
 32+ $questions = $this->election->getQuestions();
 33+ $this->talliers = array();
 34+ $tallyType = $this->election->getTallyType();
 35+ foreach ( $questions as $question ) {
 36+ $tallier = $this->context->newTallier( $tallyType, $question );
 37+ if ( !$tallier ) {
 38+ throw new MWException( 'Invalid tally type' );
 39+ }
 40+ $this->talliers[$question->getId()] = $tallier;
 41+ }
 42+
 43+ $status = $store->callbackValidVotes( $this->election->getId(), array( $this, 'addRecord' ) );
 44+ if ( !$status->isOK() ) {
 45+ return $status;
 46+ }
 47+
 48+ foreach ( $this->talliers as $tallier ) {
 49+ $tallier->finishTally();
 50+ }
 51+ return Status::newGood( $this->talliers );
 52+ }
 53+
 54+ /**
 55+ * Add a record. This is the callback function for SecurePoll_Store::callbackValidVotes().
 56+ * On error, the Status object returned here will be passed through back to
 57+ * the caller of callbackValidVotes().
 58+ *
 59+ * @param $store SecurePoll_Store
 60+ * @param $record string Encrypted, packed record.
 61+ * @return Status
 62+ */
 63+ function addRecord( $store, $record ) {
 64+ # Decrypt and unpack
 65+ if ( $this->crypt ) {
 66+ $status = $this->crypt->decrypt( $record );
 67+ if ( !$status->isOK() ) {
 68+ return $status;
 69+ }
 70+ $record = $status->value;
 71+ }
 72+ $record = rtrim( $record );
 73+ $scores = $this->ballot->unpackRecord( $record );
 74+
 75+ # Add the record to the underlying question-specific tallier objects
 76+ foreach ( $this->election->getQuestions() as $question ) {
 77+ $qid = $question->getId();
 78+ if ( !isset( $scores[$qid] ) ) {
 79+ return Status::newFatal( 'securepoll-tally-error' );
 80+ }
 81+ if ( !$this->talliers[$qid]->addVote( $scores[$qid] ) ) {
 82+ return Status::newFatal( 'securepoll-tally-error' );
 83+ }
 84+ }
 85+ return Status::newGood();
 86+ }
 87+
 88+ /**
 89+ * Get HTML formatted results for this tally. Should only be called after
 90+ * execute().
 91+ */
 92+ function getHtmlResult() {
 93+ $s = '';
 94+ foreach ( $this->election->getQuestions() as $question ) {
 95+ if ( $s !== '' ) {
 96+ $s .= "<hr/>\n";
 97+ }
 98+ $tallier = $this->talliers[$question->getId()];
 99+ $s .= $tallier->getHtmlResult();
 100+ }
 101+ return $s;
 102+ }
 103+
 104+ /**
 105+ * Get text formatted results for this tally. Should only be called after
 106+ * execute().
 107+ */
 108+ function getTextResult() {
 109+ $s = '';
 110+ foreach ( $this->election->getQuestions() as $question ) {
 111+ if ( $s !== '' ) {
 112+ $s .= "\n";
 113+ }
 114+ $tallier = $this->talliers[$question->getId()];
 115+ $s .= $tallier->getTextResult();
 116+ }
 117+ return $s;
 118+ }
 119+}
 120+
Property changes on: branches/wmf-deployment/extensions/SecurePoll/includes/ElectionTallier.php
___________________________________________________________________
Added: svn:eol-style
1121 + native
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Random.php
@@ -0,0 +1,70 @@
 2+<?php
 3+
 4+class SecurePoll_Random {
 5+ var $urandom;
 6+
 7+ /**
 8+ * Open a /dev/urandom file handle
 9+ * Returns a Status object
 10+ */
 11+ function open() {
 12+ if ( $this->urandom ) {
 13+ return Status::newGood();
 14+ }
 15+
 16+ if ( wfIsWindows() ) {
 17+ return Status::newFatal( 'securepoll-urandom-not-supported' );
 18+ }
 19+ $this->urandom = fopen( '/dev/urandom', 'rb' );
 20+ if ( !$this->urandom ) {
 21+ return Status::newFatal( 'securepoll-dump-no-urandom' );
 22+ }
 23+ return Status::newGood();
 24+ }
 25+
 26+ /**
 27+ * Close any open file handles
 28+ */
 29+ function close() {
 30+ if ( $this->urandom ) {
 31+ fclose( $this->urandom );
 32+ $this->urandom = null;
 33+ }
 34+ }
 35+
 36+ /**
 37+ * Get a random integer between 0 and ($maxp1 - 1).
 38+ * Should only be called after open() succeeds.
 39+ */
 40+ function getInt( $maxp1 ) {
 41+ $numBytes = ceil( strlen( base_convert( $maxp1, 10, 16 ) ) / 2 );
 42+ if ( $numBytes == 0 ) {
 43+ return 0;
 44+ }
 45+ $data = fread( $this->urandom, $numBytes );
 46+ if ( strlen( $data ) != $numBytes ) {
 47+ throw new MWException( __METHOD__.': not enough bytes' );
 48+ }
 49+ $x = 0;
 50+ for ( $i = 0; $i < $numBytes; $i++ ) {
 51+ $x *= 256;
 52+ $x += ord( substr( $data, $i, 1 ) );
 53+ }
 54+ return $x % $maxp1;
 55+ }
 56+
 57+ /**
 58+ * Works like shuffle() except more secure. Returns the new array instead
 59+ * of modifying it. The algorithm is the Knuth/Durstenfeld kind.
 60+ */
 61+ function shuffle( $a ) {
 62+ $a = array_values( $a );
 63+ for ( $i = count( $a ) - 1; $i >= 0; $i-- ) {
 64+ $target = $this->getInt( $i + 1 );
 65+ $tmp = $a[$i];
 66+ $a[$i] = $a[$target];
 67+ $a[$target] = $tmp;
 68+ }
 69+ return $a;
 70+ }
 71+}
Property changes on: branches/wmf-deployment/extensions/SecurePoll/includes/Random.php
___________________________________________________________________
Added: svn:eol-style
172 + native
Index: branches/wmf-deployment/extensions/SecurePoll/includes/DetailsPage.php
@@ -17,7 +17,8 @@
1818 }
1919
2020 $this->voteId = intval( $params[0] );
21 - $db = wfGetDB( DB_MASTER );
 21+
 22+ $db = $this->context->getDB();
2223 $row = $db->selectRow(
2324 array( 'securepoll_votes', 'securepoll_elections', 'securepoll_voters' ),
2425 '*',
@@ -33,8 +34,13 @@
3435 return;
3536 }
3637
37 - $this->election = SecurePoll_Election::newFromRow( $row );
 38+ $this->election = $this->context->newElectionFromRow( $row );
3839 $this->initLanguage( $wgUser, $this->election );
 40+
 41+ $this->parent->setSubtitle( array(
 42+ $this->parent->getTitle( 'list/' . $this->election->getId() ),
 43+ wfMsg( 'securepoll-list-title', $this->election->getMessage( 'title' ) ) ) );
 44+
3945 if ( !$this->election->isAdmin( $wgUser ) ) {
4046 $wgOut->addWikiMsg( 'securepoll-need-admin' );
4147 return;
@@ -85,7 +91,7 @@
8692 $wgOut->addHTML( '<h2>' . wfMsgHTML( 'securepoll-cookie-dup-list' ) . '</h2>' );
8793 $wgOut->addHTML( '<table class="TablePager">' );
8894 foreach ( $res as $row ) {
89 - $voter = SecurePoll_Voter::newFromId( $row->voter );
 95+ $voter = $this->context->getVoter( $row->voter );
9096 $wgOut->addHTML(
9197 '<tr>' .
9298 '<td>' . htmlspecialchars( $wgLang->timeanddate( $row->cm_timestamp ) ) . '</td>' .
Index: branches/wmf-deployment/extensions/SecurePoll/includes/TallyPage.php
@@ -17,14 +17,13 @@
1818 }
1919
2020 $electionId = intval( $params[0] );
21 - $this->election = $this->parent->getElection( $electionId );
 21+ $this->election = $this->context->getElection( $electionId );
2222 if ( !$this->election ) {
2323 $wgOut->addWikiMsg( 'securepoll-invalid-election', $electionId );
2424 return;
2525 }
2626 $this->initLanguage( $wgUser, $this->election );
2727 $wgOut->setPageTitle( wfMsg( 'securepoll-tally-title', $this->election->getMessage( 'title' ) ) );
28 -
2928 if ( !$this->election->isAdmin( $wgUser ) ) {
3029 $wgOut->addWikiMsg( 'securepoll-need-admin' );
3130 return;
@@ -125,30 +124,13 @@
126125 */
127126 function submitLocal() {
128127 global $wgOut;
129 - $dbr = wfGetDB( DB_SLAVE );
130 - $res = $dbr->select(
131 - 'securepoll_votes',
132 - array( 'vote_record' ),
133 - array(
134 - 'vote_election' => $this->election->getId(),
135 - 'vote_current' => 1,
136 - 'vote_struck' => 0
137 - ), __METHOD__
138 - );
139 - $crypt = $this->election->getCrypt();
140 - $tallier = $this->election->getTallier();
141 - foreach ( $res as $row ) {
142 - $status = $crypt->decrypt( $row->vote_record );
143 - if ( !$status->isOK() ) {
144 - $wgOut->addWikiText( $status->getWikiText() );
145 - return;
146 - }
147 - if ( !$tallier->addRecord( $status->value ) ) {
148 - $wgOut->addWikiMsg( 'securepoll-tally-error' );
149 - return;
150 - }
 128+ $status = $this->election->tally();
 129+ if ( !$status->isOK() ) {
 130+ $wgOut->addWikiText( $status->getWikiText() );
 131+ return;
151132 }
152 - $wgOut->addHTML( $tallier->getResult() );
 133+ $tallier = $status->value;
 134+ $wgOut->addHTML( $tallier->getHtmlResult() );
153135 }
154136
155137 /**
@@ -156,8 +138,6 @@
157139 */
158140 function submitUpload() {
159141 global $wgOut;
160 - $crypt = $this->election->getCrypt();
161 - $tallier = $this->election->getTallier();
162142 if ( !isset( $_FILES['tally_file'] )
163143 || !is_uploaded_file( $_FILES['tally_file']['tmp_name'] )
164144 || !$_FILES['tally_file']['size'] )
@@ -165,24 +145,21 @@
166146 $wgOut->addWikiMsg( 'securepoll-no-upload' );
167147 return;
168148 }
169 -
170 - $fileString = file_get_contents( $_FILES['tally_file']['tmp_name'] );
171 - $records = StringUtils::explode( "\n\n\n", $fileString );
172 - foreach ( $records as $encrypted ) {
173 - if ( trim( $encrypted ) == '' ) {
174 - continue;
175 - }
176 - $status = $crypt->decrypt( $encrypted );
177 - if ( !$status->isOK() ) {
178 - $wgOut->addWikiText( $status->getWikiText() );
179 - return;
180 - }
181 - if ( !$tallier->addRecord( $status->value ) ) {
182 - $wgOut->addWikiMsg( 'securepoll-tally-error' );
183 - return;
184 - }
 149+ $context = SecurePoll_Context::newFromXmlFile( $_FILES['tally_file']['tmp_name'] );
 150+ if ( !$context ) {
 151+ $wgOut->addWikiMsg( 'securepoll-dump-corrupt' );
 152+ return;
185153 }
186 - $wgOut->addHTML( $tallier->getResult() );
 154+ $electionIds = $context->getStore()->getAllElectionIds();
 155+ $election = $context->getElection( reset( $electionIds ) );
 156+
 157+ $status = $election->tally();
 158+ if ( !$status->isOK() ) {
 159+ $wgOut->addWikiText( $status->getWikiText( 'securepoll-tally-upload-error' ) );
 160+ return;
 161+ }
 162+ $tallier = $status->value;
 163+ $wgOut->addHTML( $tallier->getHtmlResult() );
187164 }
188165
189166 function getTitle() {
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Context.php
@@ -0,0 +1,314 @@
 2+<?php
 3+
 4+/**
 5+ * This object contains caches and various items of processing context for
 6+ * SecurePoll. It manages instances of long-lived objects such as the
 7+ * SecurePoll_Store subclass.
 8+ *
 9+ * Long-lived data should be stored here, rather than in global variables or
 10+ * static member variables.
 11+ *
 12+ * A context object is passed to almost all SecurePoll constructors. This class
 13+ * provides factory functions for these objects, to simplify object creation
 14+ * and avoid having to use the SecurePoll_* prefixed class names.
 15+ *
 16+ * For debugging purposes, a var_dump() workalike which omits context objects
 17+ * is available as $context->varDump().
 18+ */
 19+class SecurePoll_Context {
 20+ /** Language fallback sequence */
 21+ public $languages = array( 'en' );
 22+
 23+ /** Message text cache */
 24+ var $messageCache = array();
 25+
 26+ /**
 27+ * Which messages are loaded. 2-d array: language and entity ID, value arbitrary.
 28+ */
 29+ var $messagesLoaded = array();
 30+
 31+ /** ParserOptions instance used for message parsing */
 32+ var $parserOptions;
 33+
 34+ /** The store class, for lazy loading */
 35+ var $storeClass = 'SecurePoll_DBStore';
 36+
 37+ /** The store object */
 38+ var $store;
 39+
 40+ /** The SecurePoll_Random instance */
 41+ var $random;
 42+
 43+ /** The Database instance */
 44+ var $db;
 45+
 46+ /**
 47+ * Create a new SecurePoll_Context with an XML file as the storage backend.
 48+ * Returns false if there was a problem with the file, like a parse error.
 49+ */
 50+ static function newFromXmlFile( $fileName ) {
 51+ $context = new self;
 52+ $store = new SecurePoll_XMLStore( $fileName );
 53+ $context->setStore( $store );
 54+ $success = $store->readFile();
 55+ if ( $success ) {
 56+ return $context;
 57+ } else {
 58+ return false;
 59+ }
 60+ }
 61+
 62+ /** Get the ParserOptions instance */
 63+ function getParserOptions() {
 64+ if ( !$this->parserOptions ) {
 65+ $this->parserOptions = new ParserOptions;
 66+ }
 67+ return $this->parserOptions;
 68+ }
 69+
 70+ /** Get the SecurePoll_Store instance */
 71+ function getStore() {
 72+ if ( !isset( $this->store ) ) {
 73+ $this->store = new $this->storeClass;
 74+ }
 75+ return $this->store;
 76+ }
 77+
 78+ /** Get a Title object for Special:SecurePoll */
 79+ function getSpecialTitle( $subpage = false ) {
 80+ return SpecialPage::getTitleFor( 'SecurePoll', $subpage );
 81+ }
 82+
 83+ /** Set the store class */
 84+ function setStoreClass( $class ) {
 85+ $this->store = null;
 86+ $this->storeClass = $class;
 87+ }
 88+
 89+ /** Set the store object. Overrides any previous store class. */
 90+ function setStore( $store ) {
 91+ $this->store = $store;
 92+ }
 93+
 94+ /**
 95+ * Get an election object from the store, with a given entity ID. Returns
 96+ * false if it does not exist.
 97+ */
 98+ function getElection( $id ) {
 99+ $info = $this->getStore()->getElectionInfo( array( $id ) );
 100+ if ( $info ) {
 101+ return $this->newElection( reset( $info ) );
 102+ } else {
 103+ return false;
 104+ }
 105+ }
 106+
 107+ /**
 108+ * Get an election object from the store, with a given name. Returns false
 109+ * if there is no such election.
 110+ */
 111+ function getElectionByTitle( $name ) {
 112+ $info = $this->getStore()->getElectionInfoByTitle( array( $name ) );
 113+ if ( $info ) {
 114+ return $this->newElection( reset( $info ) );
 115+ } else {
 116+ return false;
 117+ }
 118+ }
 119+
 120+ /**
 121+ * Get an election object from a securepoll_elections DB row. This will fail
 122+ * if the current store class does not support database operations.
 123+ */
 124+ function newElectionFromRow( $row ) {
 125+ $info = $this->getStore()->decodeElectionRow( $row );
 126+ return $this->newElection( $info );
 127+ }
 128+
 129+ /**
 130+ * Get a voter object from a securepoll_voters row
 131+ */
 132+ function newVoterFromRow( $row ) {
 133+ return SecurePoll_Voter::newFromRow( $this, $row );
 134+ }
 135+
 136+ /**
 137+ * Create a voter with the given parameters. Assumes the voter does not exist,
 138+ * and inserts it into the database.
 139+ *
 140+ * The row needs to be locked before this function is called, to avoid
 141+ * duplicate key errors.
 142+ */
 143+ function createVoter( $params ) {
 144+ return SecurePoll_Voter::createVoter( $this, $params );
 145+ }
 146+
 147+ /**
 148+ * Create a voter object from the database
 149+ * @return SecurePoll_Voter or false if the ID is not valid
 150+ */
 151+ function getVoter( $id ) {
 152+ return SecurePoll_Voter::newFromId( $this, $id );
 153+ }
 154+
 155+ /**
 156+ * Get a SecurePoll_Random instance. This provides cryptographic random
 157+ * number generation.
 158+ */
 159+ function getRandom() {
 160+ if ( !$this->random ) {
 161+ $this->random = new SecurePoll_Random;
 162+ }
 163+ return $this->random;
 164+ }
 165+ /**
 166+ * Set the global language fallback sequence.
 167+ *
 168+ * @param $languages array A list of language codes. When a message is
 169+ * requested, the first code in the array will be tried first, followed
 170+ * by the subsequent codes.
 171+ */
 172+ function setLanguages( $languages ) {
 173+ $this->languages = $languages;
 174+ }
 175+
 176+ /**
 177+ * Get some messages from the backend store or the cache.
 178+ * This is an internal interface for SecurePoll_Entity, generally you
 179+ * should use SecurePoll_Entity::getMessage() instead.
 180+ *
 181+ * @param $lang Language code
 182+ * @param $ids Entity IDs
 183+ */
 184+ function getMessages( $lang, $ids ) {
 185+ if ( isset( $this->messagesLoaded[$lang] ) ) {
 186+ $cacheRow = $this->messagesLoaded[$lang];
 187+ $uncachedIds = array_flip( $ids );
 188+ foreach ( $uncachedIds as $id => $unused ) {
 189+ if ( isset( $cacheRow[$id] ) ) {
 190+ unset( $uncachedIds[$id] );
 191+ }
 192+ }
 193+ if ( count( $uncachedIds ) ) {
 194+ $messages = $this->getStore()->getMessages( $lang, array_keys( $uncachedIds ) );
 195+ $this->messageCache[$lang] = $this->messageCache[$lang] + $messages;
 196+ $this->messagesLoaded[$lang] = $this->messagesLoaded[$lang] + $uncachedIds;
 197+ }
 198+ return array_intersect_key( $this->messageCache[$lang], array_flip( $ids ) );
 199+ } else {
 200+ $this->messagesLoaded[$lang] = $ids;
 201+ $this->messageCache[$lang] = $this->getStore()->getMessages( $lang, $ids );
 202+ return $this->messageCache[$lang];
 203+ }
 204+ }
 205+
 206+ /**
 207+ * Get a particular message.
 208+ * This is an internal interface for SecurePoll_Entity, generally you
 209+ * should use SecurePoll_Entity::getMessage() instead.
 210+ *
 211+ * @param $lang Language code
 212+ * @param $id Entity ID
 213+ * @param $key Message key
 214+ */
 215+ function getMessage( $lang, $id, $key ) {
 216+ if ( !isset( $this->messagesLoaded[$lang][$id] ) ) {
 217+ $this->getMessages( $lang, array( $id ) );
 218+ }
 219+ if ( isset( $this->messageCache[$lang][$id][$key] ) ) {
 220+ return $this->messageCache[$lang][$id][$key];
 221+ } else {
 222+ return false;
 223+ }
 224+ }
 225+
 226+ /**
 227+ * Get a database object, or throw an exception if the current store object
 228+ * does not support database operations.
 229+ */
 230+ function getDB() {
 231+ if ( !isset( $this->db ) ) {
 232+ $this->db = $this->getStore()->getDB();
 233+ }
 234+ return $this->db;
 235+ }
 236+
 237+ function newElection( $info ) {
 238+ return new SecurePoll_Election( $this, $info );
 239+ }
 240+
 241+ function newQuestion( $info ) {
 242+ return new SecurePoll_Question( $this, $info );
 243+ }
 244+
 245+ function newOption( $info ) {
 246+ return new SecurePoll_Option( $this, $info );
 247+ }
 248+
 249+ function newCrypt( $type, $election ) {
 250+ return SecurePoll_Crypt::factory( $this, $type, $election );
 251+ }
 252+
 253+ function newTallier( $type, $question ) {
 254+ return SecurePoll_Tallier::factory( $this, $type, $question );
 255+ }
 256+
 257+ function newBallot( $type, $election ) {
 258+ return SecurePoll_Ballot::factory( $this, $type, $election );
 259+ }
 260+
 261+ function newAuth( $type ) {
 262+ return SecurePoll_Auth::factory( $this, $type );
 263+ }
 264+
 265+ function newVoter( $params ) {
 266+ return new SecurePoll_Voter( $this, $params );
 267+ }
 268+
 269+ function newElectionTallier( $election ) {
 270+ return new SecurePoll_ElectionTallier( $this, $election );
 271+ }
 272+
 273+ /**
 274+ * Debugging function to output a representation of a mixed-type variable,
 275+ * but omitting the $obj->context member variables for brevity.
 276+ *
 277+ * @param $var mixed
 278+ * @param $return True to return the text instead of echoing
 279+ * @param $level Recursion level, leave this as zero when calling.
 280+ */
 281+ function varDump( $var, $return = false, $level = 0 ) {
 282+ $tab = ' ';
 283+ $indent = str_repeat( $tab, $level );
 284+ if ( is_array( $var ) ) {
 285+ $s = "array(\n";
 286+ foreach ( $var as $key => $value ) {
 287+ $s .= "$indent$tab" . $this->varDump( $key, true, $level + 1 ) . " => " .
 288+ $this->varDump( $value, true, $level + 1 ) . ",\n";
 289+ }
 290+ $s .= "{$indent})";
 291+ } elseif ( is_object( $var ) ) {
 292+ $props = (array)$var;
 293+ $s = get_class( $var ) . " {\n";
 294+ foreach ( $props as $key => $value ) {
 295+ $s .= "$indent$tab" . $this->varDump( $key, true, $level + 1 ) . " => ";
 296+ if ( $key === 'context' ) {
 297+ $s .= "[CONTEXT],\n";
 298+ } else {
 299+ $s .= $this->varDump( $value, true, $level + 1 ) . ",\n";
 300+ }
 301+ }
 302+ $s .= "{$indent}}";
 303+ } else {
 304+ $s = var_export( $var, true );
 305+ }
 306+ if ( $level == 0 ) {
 307+ $s .= "\n";
 308+ }
 309+ if ( $return ) {
 310+ return $s;
 311+ } else {
 312+ echo $s;
 313+ }
 314+ }
 315+}
Property changes on: branches/wmf-deployment/extensions/SecurePoll/includes/Context.php
___________________________________________________________________
Added: svn:eol-style
1316 + native
Index: branches/wmf-deployment/extensions/SecurePoll/includes/TranslatePage.php
@@ -17,7 +17,7 @@
1818 }
1919
2020 $electionId = intval( $params[0] );
21 - $this->election = $this->parent->getElection( $electionId );
 21+ $this->election = $this->context->getElection( $electionId );
2222 if ( !$this->election ) {
2323 $wgOut->addWikiMsg( 'securepoll-invalid-election', $electionId );
2424 return;
@@ -53,6 +53,11 @@
5454 return;
5555 }
5656
 57+ # Set a subtitle to return to the language selector
 58+ $this->parent->setSubtitle( array(
 59+ $this->getTitle(),
 60+ wfMsg( 'securepoll-translate-title', $this->election->getMessage( 'title' ) ) ) );
 61+
5762 # If the request was posted, do the submit
5863 if ( $wgRequest->wasPosted() && $wgRequest->getVal( 'action' ) == 'submit' ) {
5964 $this->doSubmit( $secondary );
@@ -102,7 +107,7 @@
103108 /**
104109 * @return Title
105110 */
106 - function getTitle( $lang ) {
 111+ function getTitle( $lang = false ) {
107112 $subpage = 'translate/' . $this->election->getId();
108113 if ( $lang !== false ) {
109114 $subpage .= '/' . $lang;
@@ -166,7 +171,7 @@
167172 }
168173 }
169174 if ( $replaceBatch ) {
170 - $dbw = wfGetDB( DB_MASTER );
 175+ $dbw = $this->context->getDB();
171176 $dbw->replace(
172177 'securepoll_msgs',
173178 array( array( 'msg_entity', 'msg_lang', 'msg_key' ) ),
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Store.php
@@ -0,0 +1,590 @@
 2+<?php
 3+
 4+/**
 5+ * This is an abstraction of the persistence layer, to allow XML dumps to be
 6+ * operated on and tallied, like elections in the local DB.
 7+ *
 8+ * Most of the UI layer has no need for this abstraction, and so we provide
 9+ * direct database access via getDB() to ease development of those components.
 10+ * The XML store will throw an exception if getDB() is called on it.
 11+ *
 12+ * Most of the functions here are internal interfaces for the use of
 13+ * the entity classes (election, question and option). The entity classes
 14+ * and SecurePoll_Context provide methods that are more appropriate for general
 15+ * users.
 16+ */
 17+interface SecurePoll_Store {
 18+ /**
 19+ * Get an array of messages with a given language, and entity IDs
 20+ * in a given array of IDs. The return format is a 2-d array mapping ID
 21+ * and message key to value.
 22+ */
 23+ function getMessages( $lang, $ids );
 24+
 25+ /**
 26+ * Get a list of languages that the given entity IDs have messages for.
 27+ * Returns an array of language codes.
 28+ */
 29+ function getLangList( $ids );
 30+
 31+ /**
 32+ * Get an array of properties for a given set of IDs. Returns a 2-d array
 33+ * mapping IDs and property keys to values.
 34+ */
 35+ function getProperties( $ids );
 36+
 37+ /**
 38+ * Get information about a set of elections, specifically the data that
 39+ * is stored in the securepoll_elections row in the DB. Returns a 2-d
 40+ * array mapping ID to associative array of properties.
 41+ */
 42+ function getElectionInfo( $ids );
 43+
 44+ /**
 45+ * Get election information for a given set of names.
 46+ */
 47+ function getElectionInfoByTitle( $names );
 48+
 49+ /**
 50+ * Convert a row from the securepoll_elections table into an associative
 51+ * array suitable for return by getElectionInfo().
 52+ */
 53+ function decodeElectionRow( $row );
 54+
 55+ /**
 56+ * Get a database connection object.
 57+ */
 58+ function getDB();
 59+
 60+ /**
 61+ * Get an associative array of information about all questions in a given
 62+ * election.
 63+ */
 64+ function getQuestionInfo( $electionId );
 65+
 66+ /**
 67+ * Call a callback function for all valid votes with a given election ID.
 68+ */
 69+ function callbackValidVotes( $electionId, $callback );
 70+}
 71+
 72+/**
 73+ * Storage class for a DB backend. This is the one that's most often used.
 74+ */
 75+class SecurePoll_DBStore implements SecurePoll_Store {
 76+ function getMessages( $lang, $ids ) {
 77+ $db = $this->getDB();
 78+ $res = $db->select(
 79+ 'securepoll_msgs',
 80+ '*',
 81+ array(
 82+ 'msg_entity' => $ids,
 83+ 'msg_lang' => $lang
 84+ ),
 85+ __METHOD__
 86+ );
 87+ $messages = array();
 88+ foreach ( $res as $row ) {
 89+ $messages[$row->msg_entity][$row->msg_key] = $row->msg_text;
 90+ }
 91+ return $messages;
 92+ }
 93+
 94+ function getLangList( $ids ) {
 95+ $db = $this->getDB();
 96+ $res = $db->select(
 97+ 'securepoll_msgs',
 98+ 'DISTINCT msg_lang',
 99+ array(
 100+ 'msg_entity' => $ids
 101+ ),
 102+ __METHOD__ );
 103+ $langs = array();
 104+ foreach ( $res as $row ) {
 105+ $langs[] = $row->msg_lang;
 106+ }
 107+ return $langs;
 108+ }
 109+
 110+ function getProperties( $ids ) {
 111+ $db = $this->getDB();
 112+ $res = $db->select(
 113+ 'securepoll_properties',
 114+ '*',
 115+ array( 'pr_entity' => $ids ),
 116+ __METHOD__ );
 117+ $properties = array();
 118+ foreach ( $res as $row ) {
 119+ $properties[$row->pr_entity][$row->pr_key] = $row->pr_value;
 120+ }
 121+ return $properties;
 122+ }
 123+
 124+ function getElectionInfo( $ids ) {
 125+ $ids = (array)$ids;
 126+ $db = $this->getDB();
 127+ $res = $db->select(
 128+ 'securepoll_elections',
 129+ '*',
 130+ array( 'el_entity' => $ids ),
 131+ __METHOD__ );
 132+ $infos = array();
 133+ foreach ( $res as $row ) {
 134+ $infos[$row->el_entity] = $this->decodeElectionRow( $row );
 135+ }
 136+ return $infos;
 137+ }
 138+
 139+ function getElectionInfoByTitle( $names ) {
 140+ $names = (array)$names;
 141+ $db = $this->getDB();
 142+ $res = $db->select(
 143+ 'securepoll_elections',
 144+ '*',
 145+ array( 'el_title' => $names ),
 146+ __METHOD__ );
 147+ $infos = array();
 148+ foreach ( $res as $row ) {
 149+ $infos[$row->el_title] = $this->decodeElectionRow( $row );
 150+ }
 151+ return $infos;
 152+ }
 153+
 154+ function decodeElectionRow( $row ) {
 155+ static $map = array(
 156+ 'id' => 'el_entity',
 157+ 'title' => 'el_title',
 158+ 'ballot' => 'el_ballot',
 159+ 'tally' => 'el_tally',
 160+ 'primaryLang' => 'el_primary_lang',
 161+ 'startDate' => 'el_start_date',
 162+ 'endDate' => 'el_end_date',
 163+ 'auth' => 'el_auth_type'
 164+ );
 165+
 166+ $info = array();
 167+ foreach ( $map as $key => $field ) {
 168+ if ( $key == 'startDate' || $key == 'endDate' ) {
 169+ $info[$key] = wfTimestamp( TS_MW, $row->$field );
 170+ } else {
 171+ $info[$key] = $row->$field;
 172+ }
 173+ }
 174+ return $info;
 175+ }
 176+
 177+ function getDB() {
 178+ return wfGetDB( DB_MASTER );
 179+ }
 180+
 181+ function getQuestionInfo( $electionId ) {
 182+ $db = $this->getDB();
 183+ $res = $db->select(
 184+ array( 'securepoll_questions', 'securepoll_options' ),
 185+ '*',
 186+ array(
 187+ 'qu_election' => $electionId,
 188+ 'op_question=qu_entity'
 189+ ),
 190+ __METHOD__,
 191+ array( 'ORDER BY' => 'qu_index, qu_entity' )
 192+ );
 193+
 194+ $questions = array();
 195+ $options = array();
 196+ $questionId = false;
 197+ foreach ( $res as $row ) {
 198+ if ( $questionId === false ) {
 199+ } elseif ( $questionId !== $row->qu_entity ) {
 200+ $questions[] = array( 'id' => $questionId, 'options' => $options );
 201+ $options = array();
 202+ }
 203+ $options[] = array( 'id' => $row->op_entity );
 204+ $questionId = $row->qu_entity;
 205+ }
 206+ if ( $questionId !== false ) {
 207+ $questions[] = array( 'id' => $questionId, 'options' => $options );
 208+ }
 209+ return $questions;
 210+ }
 211+
 212+ function callbackValidVotes( $electionId, $callback ) {
 213+ $dbr = $this->getDB();
 214+ $res = $dbr->select(
 215+ 'securepoll_votes',
 216+ array( 'vote_record' ),
 217+ array(
 218+ 'vote_election' => $electionId,
 219+ 'vote_current' => 1,
 220+ 'vote_struck' => 0
 221+ ), __METHOD__
 222+ );
 223+ foreach ( $res as $row ) {
 224+ $status = call_user_func( $callback, $this, $row->vote_record );
 225+ if ( $status && !$status->isOK() ) {
 226+ return $status;
 227+ }
 228+ }
 229+ return Status::newGood();
 230+ }
 231+}
 232+
 233+/**
 234+ * Storage class that stores all data in local memory. The memory must be
 235+ * initialised somehow, methods for this are not provided except in the
 236+ * subclass.
 237+ */
 238+class SecurePoll_MemoryStore implements SecurePoll_Store {
 239+ var $messages, $properties, $idsByName, $votes;
 240+ var $entityInfo;
 241+
 242+ /**
 243+ * Get an array containing all election IDs stored in this object
 244+ */
 245+ function getAllElectionIds() {
 246+ $electionIds = array();
 247+ foreach ( $this->entityInfo as $info ) {
 248+ if ( $info['type'] !== 'election' ) {
 249+ continue;
 250+ }
 251+ $electionIds[] = $info['id'];
 252+ }
 253+ return $electionIds;
 254+ }
 255+
 256+ function getMessages( $lang, $ids ) {
 257+ if ( !isset( $this->messages[$lang] ) ) {
 258+ return array();
 259+ }
 260+ return array_intersect_key( $this->messages[$lang], array_flip( $ids ) );
 261+ }
 262+
 263+ function getLangList( $ids ) {
 264+ $langs = array();
 265+ foreach ( $this->messages as $lang => $langMessages ) {
 266+ foreach ( $ids as $id ) {
 267+ if ( isset( $langMessages[$id] ) ) {
 268+ $langs[] = $lang;
 269+ break;
 270+ }
 271+ }
 272+ }
 273+ return $langs;
 274+ }
 275+
 276+ function getProperties( $ids ) {
 277+ $ids = (array)$ids;
 278+ return array_intersect_key( $this->properties, array_flip( $ids ) );
 279+ }
 280+
 281+ function getElectionInfo( $ids ) {
 282+ $ids = (array)$ids;
 283+ return array_intersect_key( $this->entityInfo, array_flip( $ids ) );
 284+ }
 285+
 286+ function getElectionInfoByTitle( $names ) {
 287+ $names = (array)$names;
 288+ $ids = array_intersect_key( $this->idsByName, array_flip( $names ) );
 289+ $info = array_intersect_key( $this->entityInfo, array_flip( $ids ) );
 290+ return $info;
 291+ }
 292+
 293+ function getQuestionInfo( $electionId ) {
 294+ return $this->entityInfo[$electionId]['questions'];
 295+ }
 296+
 297+ function decodeElectionRow( $row ) {
 298+ throw new MWException( 'Internal error: attempt to use decodeElectionRow() with ' .
 299+ 'a storage class that doesn\'t support it.' );
 300+ }
 301+
 302+ function getDB() {
 303+ throw new MWException( 'Internal error: attempt to use getDB() when the database ' .
 304+ 'is disabled.' );
 305+ }
 306+
 307+ function callbackValidVotes( $electionId, $callback ) {
 308+ if ( !isset( $this->votes[$electionId] ) ) {
 309+ return Status::newGood();
 310+ }
 311+ foreach ( $this->votes[$electionId] as $vote ) {
 312+ $status = call_user_func( $callback, $this, $vote );
 313+ if ( !$status->isOK() ) {
 314+ return $status;
 315+ }
 316+ }
 317+ return Status::newGood();
 318+ }
 319+}
 320+
 321+/**
 322+ * Storage class for an XML file store. Election configuration data is cached,
 323+ * and vote data can be loaded into a tallier on demand.
 324+ */
 325+class SecurePoll_XMLStore extends SecurePoll_MemoryStore {
 326+ var $xmlReader, $fileName;
 327+ var $voteCallback, $voteElectionId;
 328+
 329+ /** Valid entity info keys by entity type. */
 330+ static $entityInfoKeys = array(
 331+ 'election' => array(
 332+ 'id',
 333+ 'title',
 334+ 'ballot',
 335+ 'tally',
 336+ 'primaryLang',
 337+ 'startDate',
 338+ 'endDate',
 339+ 'auth'
 340+ ),
 341+ 'question' => array( 'id' ),
 342+ 'option' => array( 'id' ),
 343+ );
 344+
 345+ /** The type of each entity child and its corresponding (plural) info element */
 346+ static $childTypes = array(
 347+ 'election' => array( 'question' => 'questions' ),
 348+ 'question' => array( 'option' => 'options' ),
 349+ 'option' => array()
 350+ );
 351+
 352+ /** All entity types */
 353+ static $entityTypes = array( 'election', 'question', 'option' );
 354+
 355+ /**
 356+ * Constructor. Note that readFile() must be called before any information
 357+ * can be accessed. SecurePoll_Context::newFromXmlFile() is a shortcut
 358+ * method for this.
 359+ */
 360+ function __construct( $fileName ) {
 361+ $this->fileName = $fileName;
 362+ }
 363+
 364+ /**
 365+ * Read the file and return boolean success.
 366+ */
 367+ function readFile() {
 368+ $this->xmlReader = new XMLReader;
 369+ $xr = $this->xmlReader;
 370+ $fileName = realpath( $this->fileName );
 371+ $uri = 'file://' . str_replace( '%2F', '/', rawurlencode( $fileName ) );
 372+ $xr->open( $uri );
 373+ $xr->setParserProperty( XMLReader::SUBST_ENTITIES, true );
 374+ $success = $this->doTopLevel();
 375+ $xr->close();
 376+ $this->xmlReader = null;
 377+ return $success;
 378+ }
 379+
 380+ /**
 381+ * Do the top-level document element, and return success.
 382+ */
 383+ function doTopLevel() {
 384+ $xr = $this->xmlReader;
 385+
 386+ # Check document element
 387+ while ( $xr->read() && $xr->nodeType !== XMLReader::ELEMENT );
 388+ if ( $xr->name != 'SecurePoll' ) {
 389+ wfDebug( __METHOD__.": invalid document element\n" );
 390+ return false;
 391+ }
 392+
 393+ while ( $xr->read() ) {
 394+ if ( $xr->nodeType !== XMLReader::ELEMENT ) {
 395+ continue;
 396+ }
 397+ if ( $xr->name !== 'election' ) {
 398+ continue;
 399+ }
 400+ if ( !$this->doElection() ) {
 401+ return false;
 402+ }
 403+ }
 404+ return true;
 405+ }
 406+
 407+ /**
 408+ * Read an <election> element and position the cursor past the end of it.
 409+ * Return success.
 410+ */
 411+ function doElection() {
 412+ $xr = $this->xmlReader;
 413+ if ( $xr->isEmptyElement ) {
 414+ wfDebug( __METHOD__.": unexpected empty element\n" );
 415+ return false;
 416+ }
 417+ $xr->read();
 418+ $electionInfo = false;
 419+ while ( $xr->nodeType !== XMLReader::NONE ) {
 420+ if ( $xr->nodeType === XMLReader::END_ELEMENT ) {
 421+ # Finished
 422+ return true;
 423+ }
 424+ if ( $xr->nodeType !== XMLReader::ELEMENT ) {
 425+ # Skip comments, intervening text, etc.
 426+ $xr->read();
 427+ continue;
 428+ }
 429+ if ( $xr->name === 'configuration' ) {
 430+ # Load configuration
 431+ $electionInfo = $this->readEntity( 'election' );
 432+ if ( $electionInfo === false ) {
 433+ return false;
 434+ }
 435+ continue;
 436+ }
 437+
 438+ if ( $xr->name === 'vote' ) {
 439+ # Notify tallier of vote record if requested
 440+ if ( $this->voteCallback && $electionInfo
 441+ && $electionInfo['id'] == $this->voteElectionId )
 442+ {
 443+ $record = $this->readStringElement();
 444+ call_user_func( $this->voteCallback, $this, $record );
 445+ } else {
 446+ $xr->next();
 447+ }
 448+ continue;
 449+ }
 450+
 451+ wfDebug( __METHOD__.": ignoring unrecognised element <{$xr->name}>\n" );
 452+ $xr->next();
 453+ }
 454+ wfDebug( __METHOD__.": unexpected end of stream\n" );
 455+ return false;
 456+ }
 457+
 458+ /**
 459+ * Read an entity configuration element: <configuration>, <question> or
 460+ * <option>, and position the cursor past the end of it.
 461+ *
 462+ * This function operates recursively to read child elements. It returns
 463+ * the info array for the entity.
 464+ */
 465+ function readEntity( $entityType ) {
 466+ $xr = $this->xmlReader;
 467+ $info = array( 'type' => $entityType );
 468+ $messages = array();
 469+ $properties = array();
 470+ $children = array();
 471+ if ( $xr->isEmptyElement ) {
 472+ wfDebug( __METHOD__.": unexpected empty element\n" );
 473+ $xr->read();
 474+ return false;
 475+ }
 476+ $xr->read();
 477+
 478+ while ( true ) {
 479+ if ( $xr->nodeType === XMLReader::NONE ) {
 480+ wfDebug( __METHOD__.": unexpected end of stream\n" );
 481+ return false;
 482+ }
 483+ if ( $xr->nodeType === XMLReader::END_ELEMENT ) {
 484+ # End of entity
 485+ $xr->read();
 486+ break;
 487+ }
 488+ if ( $xr->nodeType !== XMLReader::ELEMENT ) {
 489+ # Intervening text, comments, etc.
 490+ $xr->read();
 491+ continue;
 492+ }
 493+ if ( $xr->name === 'message' ) {
 494+ $name = $xr->getAttribute( 'name' );
 495+ $lang = $xr->getAttribute( 'lang' );
 496+ $value = $this->readStringElement();
 497+ $messages[$lang][$name] = $value;
 498+ continue;
 499+ }
 500+ if ( $xr->name == 'property' ) {
 501+ $name = $xr->getAttribute( 'name' );
 502+ $value = $this->readStringElement();
 503+ $properties[$name] = $value;
 504+ continue;
 505+ }
 506+
 507+ # Info elements
 508+ if ( in_array( $xr->name, self::$entityInfoKeys[$entityType] ) ) {
 509+ $name = $xr->name;
 510+ $value = $this->readStringElement();
 511+ # Fix date format
 512+ if ( $name == 'startDate' || $name == 'endDate' ) {
 513+ $value = wfTimestamp( TS_MW, $value );
 514+ }
 515+ $info[$name] = $value;
 516+ continue;
 517+ }
 518+
 519+ # Child elements
 520+ if ( isset( self::$childTypes[$entityType][$xr->name] ) ) {
 521+ $infoKey = self::$childTypes[$entityType][$xr->name];
 522+ $childInfo = $this->readEntity( $xr->name );
 523+ if ( !$childInfo ) {
 524+ return false;
 525+ }
 526+ $info[$infoKey][] = $childInfo;
 527+ continue;
 528+ }
 529+
 530+ wfDebug( __METHOD__.": ignoring unrecognised element <{$xr->name}>\n" );
 531+ $xr->next();
 532+ }
 533+
 534+ if ( !isset( $info['id'] ) ) {
 535+ wfDebug( __METHOD__.": missing id element in <$entityType>\n" );
 536+ return false;
 537+ }
 538+ $id = $info['id'];
 539+ if ( isset( $info['title'] ) ) {
 540+ $this->idsByName[$info['title']] = $id;
 541+ }
 542+ $this->entityInfo[$id] = $info;
 543+ foreach ( $messages as $lang => $values ) {
 544+ $this->messages[$lang][$id] = $values;
 545+ }
 546+ $this->properties[$id] = $properties;
 547+ return $info;
 548+ }
 549+
 550+ /**
 551+ * When the cursor is positioned on an element node, this reads the entire
 552+ * element and returns the contents as a string. On return, the cursor is
 553+ * positioned past the end of the element.
 554+ */
 555+ function readStringElement() {
 556+ $xr = $this->xmlReader;
 557+ if ( $xr->isEmptyElement ) {
 558+ $xr->read();
 559+ return '';
 560+ }
 561+ $s = '';
 562+ $level = 1;
 563+ while ( $xr->read() && $level ) {
 564+ if ( $xr->nodeType == XMLReader::TEXT ) {
 565+ $s .= $xr->value;
 566+ continue;
 567+ }
 568+ if ( $xr->nodeType == XMLReader::ELEMENT && !$xr->isEmptyElement ) {
 569+ $level++;
 570+ continue;
 571+ }
 572+ if ( $xr->nodeType == XMLReader::END_ELEMENT ) {
 573+ $level--;
 574+ continue;
 575+ }
 576+ }
 577+ return $s;
 578+ }
 579+
 580+ function callbackValidVotes( $electionId, $callback ) {
 581+ $this->voteCallback = $callback;
 582+ $this->voteElectionId = $electionId;
 583+ $success = $this->readFile();
 584+ $this->voteCallback = $this->voteElectionId = null;
 585+ if ( $success ) {
 586+ return Status::newGood();
 587+ } else {
 588+ return Status::newFatal( 'securepoll-dump-file-corrupt' );
 589+ }
 590+ }
 591+}
Property changes on: branches/wmf-deployment/extensions/SecurePoll/includes/Store.php
___________________________________________________________________
Added: svn:eol-style
1592 + native
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Tallier.php
@@ -1,23 +1,78 @@
22 <?php
33
44 abstract class SecurePoll_Tallier {
5 - var $election;
 5+ var $context, $question, $optionsById;
66
7 - abstract function addRecord( $record );
8 - abstract function getResult();
 7+ abstract function addVote( $scores );
 8+ abstract function getHtmlResult();
 9+ abstract function getTextResult();
910
10 - static function factory( $type, $election ) {
 11+ abstract function finishTally();
 12+
 13+ static function factory( $context, $type, $question ) {
1114 switch ( $type ) {
1215 case 'plurality':
13 - return new SecurePoll_PluralityTallier( $election );
 16+ return new SecurePoll_PluralityTallier( $context, $question );
 17+ case 'schulze':
 18+ return new SecurePoll_SchulzeTallier( $context, $question );
1419 default:
1520 throw new MWException( "Invalid tallier type: $type" );
1621 }
1722 }
1823
19 - function __construct( $election ) {
20 - $this->election = $election;
 24+ function __construct( $context, $question ) {
 25+ $this->context = $context;
 26+ $this->question = $question;
 27+ foreach ( $this->question->getOptions() as $option ) {
 28+ $this->optionsById[$option->getId()] = $option;
 29+ }
2130 }
 31+
 32+ function convertRanksToHtml( $ranks ) {
 33+ $s = "<table class=\"securepoll-results\">";
 34+ $ids = array_keys( $ranks );
 35+ foreach ( $ids as $i => $oid ) {
 36+ $rank = $ranks[$oid];
 37+ $prevRank = isset( $ids[$i-1] ) ? $ranks[$ids[$i-1]] : false;
 38+ $nextRank = isset( $ids[$i+1] ) ? $ranks[$ids[$i+1]] : false;
 39+ if ( $rank === $prevRank || $rank === $nextRank ) {
 40+ $rank .= '*';
 41+ }
 42+
 43+ $option = $this->optionsById[$oid];
 44+ $s .= "<tr>" .
 45+ Xml::element( 'td', array(), $rank ) .
 46+ Xml::element( 'td', array(), $option->parseMessage( 'text' ) ) .
 47+ "</tr>\n";
 48+ }
 49+ $s .= "</table>";
 50+ return $s;
 51+ }
 52+
 53+ function convertRanksToText( $ranks ) {
 54+ $s = '';
 55+ $ids = array_keys( $ranks );
 56+ $colWidth = 6;
 57+ foreach ( $this->optionsById as $option ) {
 58+ $colWidth = max( $colWidth, $option->getMessage( 'text' ) );
 59+ }
 60+
 61+ foreach ( $ids as $i => $oid ) {
 62+ $rank = $ranks[$oid];
 63+ $prevRank = isset( $ids[$i-1] ) ? $ranks[$ids[$i-1]] : false;
 64+ $nextRank = isset( $ids[$i+1] ) ? $ranks[$ids[$i+1]] : false;
 65+ if ( $rank === $prevRank || $rank === $nextRank ) {
 66+ $rank .= '*';
 67+ }
 68+
 69+ $option = $this->optionsById[$oid];
 70+ $s .= str_pad( $rank, 6 ) . ' | ' .
 71+ $option->getMessage( 'text' ) . "\n";
 72+ }
 73+ return $s;
 74+ }
 75+
 76+
2277 }
2378
2479 /**
@@ -26,63 +81,510 @@
2782 class SecurePoll_PluralityTallier extends SecurePoll_Tallier {
2883 var $tally = array();
2984
30 - function __construct( $election ) {
31 - parent::__construct( $election );
32 - $questions = $this->election->getQuestions();
33 - foreach ( $questions as $question ) {
34 - foreach ( $question->getOptions() as $option ) {
35 - $this->tally[$question->getId()][$option->getId()] = 0;
 85+ function __construct( $context, $question ) {
 86+ parent::__construct( $context, $question );
 87+ foreach ( $question->getOptions() as $option ) {
 88+ $this->tally[$option->getId()] = 0;
 89+ }
 90+ }
 91+
 92+ function addVote( $scores ) {
 93+ foreach ( $scores as $oid => $score ) {
 94+ if ( !isset( $this->tally[$oid] ) ) {
 95+ wfDebug( __METHOD__.": unknown OID $oid\n" );
 96+ return false;
3697 }
 98+ $this->tally[$oid] += $score;
3799 }
 100+ return true;
38101 }
39102
40 - function addRecord( $record ) {
41 - $i = 0;
42 - $ballot = $this->election->getBallot();
43 - $scores = $ballot->unpackRecord( $record );
44 - if ( $scores === false ) {
45 - return false;
 103+ function finishTally() {
 104+ // Sort the scores
 105+ arsort( $this->tally );
 106+ }
 107+
 108+ function getHtmlResult() {
 109+ // Show the results
 110+ $s = "<table class=\"securepoll-results\">\n";
 111+
 112+ foreach ( $this->tally as $oid => $rank ) {
 113+ $option = $this->optionsById[$oid];
 114+ $s .= '<tr><td>' . $option->getMessage( 'text' ) . "</td>\n" .
 115+ '<td>' . $this->tally[$oid] . "</td>\n" .
 116+ "</tr>\n";
46117 }
47 - foreach ( $scores as $qid => $questionScores ) {
48 - if ( !isset( $this->tally[$qid] ) ) {
49 - wfDebug( __METHOD__.": unknown QID $qid\n" );
 118+ $s .= "</table>\n";
 119+ return $s;
 120+ }
 121+
 122+ function getTextResult() {
 123+ // Calculate column width
 124+ $width = 10;
 125+ foreach ( $this->tally as $oid => $rank ) {
 126+ $option = $this->optionsById[$oid];
 127+ $width = max( $width, strlen( $option->getMessage( 'text' ) ) );
 128+ }
 129+ if ( $width > 57 ) {
 130+ $width = 57;
 131+ }
 132+
 133+ // Show the results
 134+ $qtext = $this->question->getMessage( 'text' );
 135+ $s = '';
 136+ if ( $qtext !== '' ) {
 137+ $s .= wordwrap( $qtext ) . "\n";
 138+ }
 139+ foreach ( $this->tally as $oid => $rank ) {
 140+ $option = $this->optionsById[$oid];
 141+ $otext = $option->getMessage( 'text' );
 142+ if ( strlen( $otext ) > $width ) {
 143+ $otext = substr( $otext, 0, $width - 3 ) . '...';
 144+ } else {
 145+ $otext = str_pad( $otext, $width );
 146+ }
 147+ $s .= $otext . ' | ' .
 148+ $this->tally[$option->getId()] . "\n";
 149+ }
 150+ return $s;
 151+ }
 152+
 153+ function getRanks() {
 154+ $ranks = array();
 155+ $currentRank = 1;
 156+ $oids = array_keys( $this->tally );
 157+ $scores = array_values( $this->tally );
 158+ foreach ( $oids as $i => $oid ) {
 159+ if ( $i > 0 && $scores[$i-1] !== $scores[$i] ) {
 160+ $currentRank = $i + 1;
 161+ }
 162+ $ranks[$oid] = $currentRank;
 163+ }
 164+ return $ranks;
 165+ }
 166+}
 167+
 168+abstract class SecurePoll_PairwiseTallier extends SecurePoll_Tallier {
 169+ var $optionIds = array();
 170+ var $victories = array();
 171+ var $abbrevs;
 172+ var $rowLabels = array();
 173+
 174+ function __construct( $context, $question ) {
 175+ parent::__construct( $context, $question );
 176+ $this->optionIds = array();
 177+ foreach ( $question->getOptions() as $option ) {
 178+ $this->optionIds[] = $option->getId();
 179+ }
 180+
 181+ $this->victories = array();
 182+ foreach ( $this->optionIds as $i ) {
 183+ foreach ( $this->optionIds as $j ) {
 184+ $this->victories[$i][$j] = 0;
 185+ }
 186+ }
 187+ }
 188+
 189+ function addVote( $ranks ) {
 190+ foreach ( $this->optionIds as $oid1 ) {
 191+ if ( !isset( $ranks[$oid1] ) ) {
 192+ wfDebug( "Invalid vote record, missing option $oid1\n" );
50193 return false;
51194 }
52 - foreach ( $questionScores as $oid => $score ) {
53 - if ( !isset( $this->tally[$qid][$oid] ) ) {
54 - wfDebug( __METHOD__.": unknown OID $oid\n" );
55 - return false;
 195+ foreach ( $this->optionIds as $oid2 ) {
 196+ # Lower = better
 197+ if ( $ranks[$oid1] < $ranks[$oid2] ) {
 198+ $this->victories[$oid1][$oid2]++;
56199 }
57 - $this->tally[$qid][$oid] += $score;
58200 }
59201 }
60202 return true;
61203 }
62204
63 - function getResult() {
64 - global $wgOut;
65 - $questions = $this->election->getQuestions();
66 -
67 - // Sort the scores
68 - foreach ( $this->tally as &$scores ) {
69 - arsort( $scores );
 205+ function getOptionAbbreviations() {
 206+ if ( is_null( $this->abbrevs ) ) {
 207+ $abbrevs = array();
 208+ foreach ( $this->question->getOptions() as $option ) {
 209+ $text = $option->getMessage( 'text' );
 210+ $parts = explode( ' ', $text );
 211+ $initials = '';
 212+ foreach ( $parts as $part ) {
 213+ if ( $part === '' || ctype_punct( $part[0] ) ) {
 214+ continue;
 215+ }
 216+ $initials .= $part[0];
 217+ }
 218+ if ( isset( $abbrevs[$initials] ) ) {
 219+ $index = 2;
 220+ while ( isset( $abbrevs[$initials . $index] ) ) {
 221+ $index++;
 222+ }
 223+ $initials .= $index;
 224+ }
 225+ $abbrevs[$initials] = $option->getId();
 226+ }
 227+ $this->abbrevs = array_flip( $abbrevs );
70228 }
 229+ return $this->abbrevs;
 230+ }
71231
72 - // Show the results
73 - $s = '';
74 - foreach ( $questions as $question ) {
75 - if ( $s !== '' ) {
76 - $s .= "<hr/>\n";
 232+ function getRowLabels( $format = 'html' ) {
 233+ if ( !isset( $this->rowLabels[$format] ) ) {
 234+ $rowLabels = array();
 235+ $abbrevs = $this->getOptionAbbreviations();
 236+ foreach ( $this->question->getOptions() as $option ) {
 237+ if ( $format == 'html' ) {
 238+ $label = $option->parseMessage( 'text' );
 239+ } else {
 240+ $label = $option->getMessage( 'text' );
 241+ }
 242+ if ( $label !== $abbrevs[$option->getId()] ) {
 243+ $label .= ' (' . $abbrevs[$option->getId()] . ')';
 244+ }
 245+ $rowLabels[$option->getId()] = $label;
77246 }
78 - $s .= $wgOut->parse( $question->getMessage( 'text' ) ) .
79 - '<table class="securepoll-result-table" border="1">';
80 - foreach ( $question->getOptions() as $option ) {
81 - $s .= '<tr><td>' . $option->getMessage( 'text' ) . "</td>\n" .
82 - '<td>' . $this->tally[$question->getId()][$option->getId()] . "</td>\n" .
83 - "</tr>\n";
 247+ $this->rowLabels[$format] = $rowLabels;
 248+ }
 249+ return $this->rowLabels[$format];
 250+ }
 251+
 252+ function convertMatrixToHtml( $matrix, $rankedIds ) {
 253+ $abbrevs = $this->getOptionAbbreviations();
 254+ $rowLabels = $this->getRowLabels( 'html' );
 255+
 256+ $s = "<table class=\"securepoll-results\">";
 257+
 258+ # Corner box
 259+ $s .= "<tr>\n<th>&nbsp;</th>\n";
 260+
 261+ # Header row
 262+ foreach ( $rankedIds as $oid ) {
 263+ $s .= Xml::element( 'th', array(), $abbrevs[$oid] ) . "\n";
 264+ }
 265+ $s .= "</tr>\n";
 266+
 267+ foreach ( $rankedIds as $oid1 ) {
 268+ # Header column
 269+ $s .= "<tr>\n";
 270+ $s .= Xml::element( 'td', array( 'class' => 'securepoll-results-row-heading' ),
 271+ $rowLabels[$oid1] );
 272+ # Rest of the matrix
 273+ foreach ( $rankedIds as $oid2 ) {
 274+ if ( isset( $matrix[$oid1][$oid2] ) ) {
 275+ $value = $matrix[$oid1][$oid2];
 276+ } else {
 277+ $value = '';
 278+ }
 279+ if ( is_array( $value ) ) {
 280+ $value = '(' . implode( ', ', $value ) . ')';
 281+ }
 282+ $s .= Xml::element( 'td', array(), $value ) . "\n";
84283 }
85 - $s .= "</table>\n";
 284+ $s .= "</tr>\n";
86285 }
 286+ $s .= "</table>";
 287+ }
 288+
 289+ function convertMatrixToText( $matrix, $rankedIds ) {
 290+ $abbrevs = $this->getOptionAbbreviations();
 291+ $minWidth = 15;
 292+ $rowLabels = $this->getRowLabels( 'text' );
 293+
 294+ # Calculate column widths
 295+ $colWidths = array();
 296+ foreach ( $abbrevs as $id => $abbrev ) {
 297+ if ( strlen( $abbrev ) < $minWidth ) {
 298+ $colWidths[$id] = $minWidth;
 299+ } else {
 300+ $colWidths[$id] = strlen( $abbrev );
 301+ }
 302+ }
 303+ $headerColumnWidth = $minWidth;
 304+ foreach ( $rowLabels as $label ) {
 305+ $headerColumnWidth = max( $headerColumnWidth, strlen( $label ) );
 306+ }
 307+
 308+ # Corner box
 309+ $s = str_repeat( ' ', $headerColumnWidth ) . ' | ';
 310+
 311+ # Header row
 312+ foreach ( $rankedIds as $oid ) {
 313+ $s .= str_pad( $abbrevs[$oid], $colWidths[$oid] ) . ' | ';
 314+ }
 315+ $s .= "\n";
 316+
 317+ # Divider
 318+ $s .= str_repeat( '-', $headerColumnWidth ) . '-+-';
 319+ foreach ( $rankedIds as $oid ) {
 320+ $s .= str_repeat( '-', $colWidths[$oid] ) . '-+-';
 321+ }
 322+ $s .= "\n";
 323+
 324+ foreach ( $rankedIds as $oid1 ) {
 325+ # Header column
 326+ $s .= str_pad( $rowLabels[$oid1], $headerColumnWidth ) . ' | ';
 327+
 328+ # Rest of the matrix
 329+ foreach ( $rankedIds as $oid2 ) {
 330+ if ( isset( $matrix[$oid1][$oid2] ) ) {
 331+ $value = $matrix[$oid1][$oid2];
 332+ } else {
 333+ $value = '';
 334+ }
 335+ if ( is_array( $value ) ) {
 336+ $value = '(' . implode( ', ', $value ) . ')';
 337+ }
 338+ $s .= str_pad( $value, $colWidths[$oid2] ) . ' | ';
 339+ }
 340+ $s .= "\n";
 341+ }
87342 return $s;
88343 }
 344+
89345 }
 346+
 347+
 348+
 349+/**
 350+ * A tallier which gives a tie-breaking ranking of candidates (TBRC) by
 351+ * selecting random preferential votes
 352+ */
 353+abstract class SecurePoll_RandomPrefVoteTallier {
 354+ var $records, $random;
 355+
 356+ function addVote( $vote ) {
 357+ $this->records[] = $vote;
 358+ }
 359+
 360+ function getTBRCMatrix() {
 361+ $tbrc = array();
 362+ $marked = array();
 363+
 364+ $random = $this->context->getRandom();
 365+ $status = $random->open();
 366+ if ( !$status->isOK() ) {
 367+ throw new MWException( "Unable to open random device for TBRC ranking" );
 368+ }
 369+
 370+ # Random ballot round
 371+ $numCands = count( $this->optionIds );
 372+ $numPairsRanked = 0;
 373+ $numRecordsUsed = 0;
 374+ while ( $numRecordsUsed < count( $this->records )
 375+ && $numPairsRanked < $numCands * $numCands )
 376+ {
 377+ # Pick the record
 378+ $recordIndex = $random->getInt( $numCands - $numRecordsUsed );
 379+ $ranks = $this->records[$recordIndex];
 380+ $numRecordsUsed++;
 381+
 382+ # Swap it to the end
 383+ $destIndex = $numCands - $numRecordsUsed;
 384+ $this->records[$recordIndex] = $this->records[$destIndex];
 385+ $this->records[$destIndex] = $ranks;
 386+
 387+ # Apply its rankings
 388+ foreach ( $this->optionIds as $oid1 ) {
 389+ if ( !isset( $ranks[$oid1] ) ) {
 390+ throw new MWException( "Invalid vote record, missing option $oid1" );
 391+ }
 392+ foreach ( $this->optionIds as $oid2 ) {
 393+ if ( isset( $marked[$oid1][$oid2] ) ) {
 394+ // Already ranked
 395+ continue;
 396+ }
 397+
 398+ if ( $oid1 == $oid2 ) {
 399+ # Same candidate, no win
 400+ $tbrc[$oid1][$oid2] = false;
 401+ } elseif ( $ranks[$oid1] < $ranks[$oid2] ) {
 402+ # oid1 win
 403+ $tbrc[$oid1][$oid2] = true;
 404+ } elseif ( $ranks[$oid2] < $ranks[$oid1] ) {
 405+ # oid2 win
 406+ $tbrc[$oid1][$oid2] = false;
 407+ } else {
 408+ # Tie, don't mark
 409+ continue;
 410+ }
 411+ $marked[$oid1][$oid2] = true;
 412+ $numPairsRanked++;
 413+ }
 414+ }
 415+ }
 416+
 417+ # Random win round
 418+ if ( $numPairsRanked < $numCands * $numCands ) {
 419+ $randomRanks = $random->shuffle( $this->optionIds );
 420+ foreach ( $randomRanks as $oidWin ) {
 421+ if ( $numPairsRanked >= $numCands * $numCands ) {
 422+ # Done
 423+ break;
 424+ }
 425+ foreach ( $this->optionIds as $oidOther ) {
 426+ if ( !isset( $marked[$oidWin][$oidOther] ) ) {
 427+ $tbrc[$oidWin][$oidOther] = true;
 428+ $marked[$oidWin][$oidOther] = true;
 429+ $numPairsRanked++;
 430+ }
 431+ if ( !isset( $marked[$oidOther][$oidWin] ) ) {
 432+ $tbrc[$oidOther][$oidWin] = false;
 433+ $marked[$oidOther][$oidWin] = true;
 434+ $numPairsRanked++;
 435+ }
 436+ }
 437+ }
 438+ }
 439+
 440+ return $tbrc;
 441+ }
 442+}
 443+
 444+/**
 445+ * This is the basic Schulze method with no tie-breaking.
 446+ */
 447+class SecurePoll_SchulzeTallier extends SecurePoll_PairwiseTallier {
 448+ function getPathStrengths( $victories ) {
 449+ # This algorithm follows Markus Schulze, "A New Monotonic, Clone-Independent, Reversal
 450+ # Symmetric, and Condorcet-Consistent Single-Winner Election Method" and also
 451+ # http://en.wikipedia.org/w/index.php?title=User:MarkusSchulze/Statutory_Rules&oldid=303036893
 452+ #
 453+ # Path strengths in the Schulze method are given by pairs of integers notated (a, b)
 454+ # where a is the strength in one direction and b is the strength in the other. We make
 455+ # a matrix of path strength pairs "p", giving the path strength of the row index beating
 456+ # the column index.
 457+
 458+ # First the path strength matrix is populated with the "direct" victory count in each
 459+ # direction, i.e. the number of people who preferenced A over B, and B over A.
 460+ $strengths = array();
 461+ foreach ( $this->optionIds as $oid1 ) {
 462+ foreach ( $this->optionIds as $oid2 ) {
 463+ if ( $oid1 === $oid2 ) {
 464+ continue;
 465+ }
 466+ $v12 = $victories[$oid1][$oid2];
 467+ $v21 = $victories[$oid2][$oid1];
 468+ if ( $v12 > $v21 ) {
 469+ # Direct victory
 470+ $strengths[$oid1][$oid2] = array( $v12, $v21 );
 471+ } else {
 472+ # Direct loss
 473+ $strengths[$oid1][$oid2] = array( 0, 0 );
 474+ }
 475+ }
 476+ }
 477+
 478+ # Next (continuing the Floyd-Warshall algorithm) we calculate the strongest indirect
 479+ # paths. This part dominates the O(N^3) time order.
 480+ foreach ( $this->optionIds as $oid1 ) {
 481+ foreach ( $this->optionIds as $oid2 ) {
 482+ if ( $oid1 === $oid2 ) {
 483+ continue;
 484+ }
 485+ foreach ( $this->optionIds as $oid3 ) {
 486+ if ( $oid1 === $oid3 || $oid2 === $oid3 ) {
 487+ continue;
 488+ }
 489+ $s21 = $strengths[$oid2][$oid1];
 490+ $s13 = $strengths[$oid1][$oid3];
 491+ $s23 = $strengths[$oid2][$oid3];
 492+ if ( $this->isSchulzeWin( $s21, $s13 ) ) {
 493+ $temp = $s13;
 494+ } else {
 495+ $temp = $s21;
 496+ }
 497+ if ( $this->isSchulzeWin( $temp, $s23 ) ) {
 498+ $strengths[$oid2][$oid3] = $temp;
 499+ }
 500+ }
 501+ }
 502+ }
 503+
 504+ return $strengths;
 505+ }
 506+
 507+ function convertStrengthMatrixToRanks( $strengths ) {
 508+ $unusedIds = $this->optionIds;
 509+ $ranks = array();
 510+ $currentRank = 1;
 511+
 512+ while ( count( $unusedIds ) ) {
 513+ $winners = array_flip( $unusedIds );
 514+ foreach ( $unusedIds as $oid1 ) {
 515+ foreach ( $unusedIds as $oid2 ) {
 516+ if ( $oid1 == $oid2 ) {
 517+ continue;
 518+ }
 519+ $s12 = $strengths[$oid1][$oid2];
 520+ $s21 = $strengths[$oid2][$oid1];
 521+ if ( $this->isSchulzeWin( $s21, $s12 ) ) {
 522+ # oid1 is defeated by someone, not a winner
 523+ unset( $winners[$oid1] );
 524+ break;
 525+ }
 526+ }
 527+ }
 528+ if ( !count( $winners ) ) {
 529+ # No winners, everyone ties for this position
 530+ $winners = array_flip( $unusedIds );
 531+ }
 532+
 533+ # Now $winners is the list of candidates that tie for this position
 534+ foreach ( $winners as $oid => $unused ) {
 535+ $ranks[$oid] = $currentRank;
 536+ }
 537+ $currentRank += count( $winners );
 538+ $unusedIds = array_diff( $unusedIds, array_keys( $winners ) );
 539+ }
 540+ return $ranks;
 541+ }
 542+
 543+ /**
 544+ * Determine whether Schulze's win relation "s1 >win s2" for path strength
 545+ * pairs s1 and s2 is satisfied.
 546+ *
 547+ * When applied to final path strengths instead of intermediate results,
 548+ * the paper notates this relation >D (greater than subscript D).
 549+ *
 550+ * The inequality in the second part is reversed because the first part
 551+ * refers to wins, and the second part refers to losses.
 552+ */
 553+ function isSchulzeWin( $s1, $s2 ) {
 554+ return $s1[0] > $s2[0] || ( $s1[0] == $s2[0] && $s1[1] < $s2[1] );
 555+ }
 556+
 557+ function finishTally() {
 558+ $this->strengths = $this->getPathStrengths( $this->victories );
 559+ $this->ranks = $this->convertStrengthMatrixToRanks( $this->strengths );
 560+ }
 561+
 562+ function getRanks() {
 563+ return $this->ranks;
 564+ }
 565+
 566+ function getHtmlResult() {
 567+ global $wgOut;
 568+ $s = $wgOut->parse( '<h2>' . wfMsgNoTrans( 'securepoll-ranks' ) . "</h2>\n" );
 569+ $s .= $this->convertRanksToHtml( $this->ranks );
 570+
 571+ $s = $wgOut->parse( '<h2>' . wfMsgNoTrans( 'securepoll-pairwise-victories' ) . "</h2>\n" );
 572+ $rankedIds = array_keys( $this->ranks );
 573+ $s .= $this->convertMatrixToHtml( $this->victories, $rankedIds );
 574+
 575+ $s .= $wgOut->parse( '<h2>' . wfMsgNoTrans( 'securepoll-strength-matrix' ) . "</h2>\n" );
 576+ $s .= $this->convertMatrixToHtml( $this->strengths, $rankedIds );
 577+ return $s;
 578+ }
 579+
 580+ function getTextResult() {
 581+ $rankedIds = array_keys( $this->ranks );
 582+
 583+ return
 584+ wfMsg( 'securepoll-ranks' ) . "\n" .
 585+ $this->convertRanksToText( $this->ranks ) . "\n\n" .
 586+ wfMsg( 'securepoll-pairwise-victories' ). "\n" .
 587+ $this->convertMatrixToText( $this->victories, $rankedIds ) . "\n\n" .
 588+ wfMsg( 'securepoll-strength-matrix' ) . "\n" .
 589+ $this->convertMatrixToText( $this->strengths, $rankedIds );
 590+ }
 591+}
Index: branches/wmf-deployment/extensions/SecurePoll/includes/Voter.php
@@ -13,7 +13,8 @@
1414 /**
1515 * Create a voter from the given associative array of parameters
1616 */
17 - function __construct( $params ) {
 17+ function __construct( $context, $params ) {
 18+ $this->context = $context;
1819 foreach ( self::$paramNames as $name ) {
1920 if ( isset( $params[$name] ) ) {
2021 $this->$name = $params[$name];
@@ -25,20 +26,20 @@
2627 * Create a voter object from the database
2728 * @return SecurePoll_Voter or false if the ID is not valid
2829 */
29 - static function newFromId( $id ) {
30 - $db = wfGetDB( DB_MASTER );
 30+ static function newFromId( $context, $id ) {
 31+ $db = $context->getDB();
3132 $row = $db->selectRow( 'securepoll_voters', '*', array( 'voter_id' => $id ), __METHOD__ );
3233 if ( !$row ) {
3334 return false;
3435 }
35 - return self::newFromRow( $row );
 36+ return self::newFromRow( $context, $row );
3637 }
3738
3839 /**
3940 * Create a voter from a DB result row
4041 */
41 - static function newFromRow( $row ) {
42 - return new self( array(
 42+ static function newFromRow( $context, $row ) {
 43+ return new self( $context, array(
4344 'id' => $row->voter_id,
4445 'electionId' => $row->voter_election,
4546 'name' => $row->voter_name,
@@ -56,8 +57,8 @@
5758 * The row needs to be locked before this function is called, to avoid
5859 * duplicate key errors.
5960 */
60 - static function createVoter( $params ) {
61 - $db = wfGetDB( DB_MASTER );
 61+ static function createVoter( $context, $params ) {
 62+ $db = $context->getDB();
6263 $id = $db->nextSequenceValue( 'voters_voter_id' );
6364 $row = array(
6465 'voter_id' => $id,
@@ -70,7 +71,7 @@
7172 );
7273 $db->insert( 'securepoll_voters', $row, __METHOD__ );
7374 $params['id'] = $db->insertId();
74 - return new self( $params );
 75+ return new self( $context, $params );
7576 }
7677
7778 /** Get the voter ID */
@@ -152,13 +153,13 @@
153154 if ( isset( $_COOKIE[$cookieName] ) ) {
154155 $otherVoterId = intval( $_COOKIE[$cookieName] );
155156 if ( $otherVoterId != $this->getId() ) {
156 - $otherVoter = self::newFromId( $otherVoterId );
157 - if ( $otherVoter->getElectionId() == $this->getElectionId() ) {
 157+ $otherVoter = self::newFromId( $this->context, $otherVoterId );
 158+ if ( $otherVoter && $otherVoter->getElectionId() == $this->getElectionId() ) {
158159 $this->addCookieDup( $otherVoterId );
159160 }
160161 }
161162 } else {
162 - setcookie( $cookieName, $this->getId(), time() + 86400*3 );
 163+ setcookie( $cookieName, $this->getId(), time() + 86400*30 );
163164 }
164165 }
165166
@@ -166,7 +167,7 @@
167168 * Flag a duplicate voter
168169 */
169170 function addCookieDup( $voterId ) {
170 - $dbw = wfGetDB( DB_MASTER );
 171+ $dbw = $this->context->getDB();
171172 # Insert the log record
172173 $dbw->insert( 'securepoll_cookie_match',
173174 array(
Index: branches/wmf-deployment/extensions/SecurePoll/cli/cli.inc
@@ -0,0 +1,16 @@
 2+<?php
 3+
 4+$IP = getenv( 'MW_INSTALL_PATH' );
 5+if ( strval( $IP ) === '' ) {
 6+ $IP = dirname( __FILE__ ).'/../../..';
 7+}
 8+if ( !file_exists( "$IP/includes/WebStart.php" ) ) {
 9+ $IP .= '/phase3';
 10+}
 11+if ( !file_exists( "$IP/includes/WebStart.php" ) ) {
 12+ echo "Can't find your MediaWiki installation. Please set the MW_INSTALL_PATH environment variable.\n";
 13+ exit( 1 );
 14+}
 15+
 16+require( $IP . '/maintenance/commandLine.inc' );
 17+
Property changes on: branches/wmf-deployment/extensions/SecurePoll/cli/cli.inc
___________________________________________________________________
Added: svn:eol-style
118 + native
Index: branches/wmf-deployment/extensions/SecurePoll/cli/import.php
@@ -0,0 +1,257 @@
 2+<?php
 3+
 4+require( dirname( __FILE__ ) . '/cli.inc' );
 5+
 6+$usage = <<<EOT
 7+Import configuration files into the local SecurePoll database. Files can be
 8+generated with dump.php.
 9+
 10+Usage: import.php [options] <file>
 11+
 12+Options are:
 13+ --update-msgs Update the internationalised text for the elections, do
 14+ not update configuration.
 15+
 16+ --replace If an election with a conflicting title exists already,
 17+ replace it, updating its configuration. The default is
 18+ to exit with an error.
 19+
 20+Note that any vote records will NOT be imported.
 21+
 22+For the moment, the entity IDs are preserved, to allow easier implementation of
 23+the message update feature. This means conflicting entity IDs in the local
 24+database will generate an error. This restriction will be removed in the
 25+future.
 26+
 27+EOT;
 28+
 29+# Most of the code here will eventually be refactored into the update interfaces
 30+# of the entity and context classes, but that project can wait until we have a
 31+# setup UI.
 32+
 33+if ( !isset( $args[0] ) ) {
 34+ echo $usage;
 35+ exit( 1 );
 36+}
 37+if ( !file_exists( $args[0] ) ) {
 38+ echo "The specified file \"{$args[0]}\" does not exist\n";
 39+ exit( 1 );
 40+}
 41+
 42+foreach ( array( 'update-msgs', 'replace' ) as $optName ) {
 43+ if ( !isset( $options[$optName] ) ) {
 44+ $options[$optName] = false;
 45+ }
 46+}
 47+
 48+$success = spImportDump( $args[0], $options );
 49+exit( $success ? 0 : 1 );
 50+
 51+function spImportDump( $fileName, $options ) {
 52+ $store = new SecurePoll_XMLStore( $fileName );
 53+ $success = $store->readFile();
 54+ if ( !$success ) {
 55+ echo "Error reading XML dump, possibly corrupt\n";
 56+ return false;
 57+ }
 58+ $electionIds = $store->getAllElectionIds();
 59+ if ( !count( $electionIds ) ) {
 60+ echo "No elections found to import.\n";
 61+ return true;
 62+ }
 63+
 64+ $xc = new SecurePoll_Context;
 65+ $xc->setStore( $store );
 66+ $dbw = wfGetDB( DB_MASTER );
 67+
 68+ # Start the configuration transaction
 69+ $dbw->begin();
 70+ foreach ( $electionIds as $id ) {
 71+ $elections = $store->getElectionInfo( array( $id ) );
 72+ $electionInfo = reset( $elections );
 73+ $existingId = $dbw->selectField(
 74+ 'securepoll_elections',
 75+ 'el_entity',
 76+ array( 'el_title' => $electionInfo['title'] ),
 77+ __METHOD__,
 78+ array( 'FOR UPDATE' ) );
 79+ if ( $existingId !== false ) {
 80+ if ( $options['replace'] ) {
 81+ spDeleteElection( $existingId );
 82+ $success = spImportConfiguration( $store, $electionInfo );
 83+ } elseif ( $options['update-msgs'] ) {
 84+ # Do the message update and move on to the next election
 85+ $success = spUpdateMessages( $store, $electionInfo );
 86+ } else {
 87+ echo "Conflicting election title found \"{$electionInfo['title']}\"\n";
 88+ echo "Use --replace to replace the existing election.\n";
 89+ $success = false;
 90+ }
 91+ } elseif ( $options['update-msgs'] ) {
 92+ echo "Cannot update messages: election \"{$electionInfo['title']}\" not found.\n";
 93+ echo "Import the configuration first, without the --update-msgs switch.\n";
 94+ $success = false;
 95+ } else {
 96+ $success = spImportConfiguration( $store, $electionInfo );
 97+ }
 98+ if ( !$success ) {
 99+ $dbw->rollback();
 100+ return false;
 101+ }
 102+ }
 103+ $dbw->commit();
 104+ return true;
 105+}
 106+
 107+function spDeleteElection( $electionId ) {
 108+ $dbw = wfGetDB( DB_MASTER );
 109+
 110+ # Get a list of entity IDs and lock them
 111+ $questionIds = array();
 112+ $res = $dbw->select( 'securepoll_questions', array( 'qu_entity' ),
 113+ array( 'qu_election' => $electionId ),
 114+ __METHOD__, array( 'FOR UPDATE' ) );
 115+ foreach ( $res as $row ) {
 116+ $questionIds[] = $row->qu_entity;
 117+ }
 118+
 119+ $res = $dbw->select( 'securepoll_options', array( 'op_entity' ),
 120+ array( 'op_election' => $electionId ),
 121+ __METHOD__, array( 'FOR UPDATE' ) );
 122+ $optionIds = array();
 123+ foreach ( $res as $row ) {
 124+ $optionIds[] = $row->op_entity;
 125+ }
 126+
 127+ $entityIds = array_merge( $optionIds, $questionIds, array( $electionId ) );
 128+
 129+ # Delete the messages and properties
 130+ $dbw->delete( 'securepoll_msgs', array( 'msg_entity' => $entityIds ) );
 131+ $dbw->delete( 'securepoll_properties', array( 'pr_entity' => $entityIds ) );
 132+
 133+ # Delete the entities
 134+ $dbw->delete( 'securepoll_options', array( 'op_entity' => $optionIds ), __METHOD__ );
 135+ $dbw->delete( 'securepoll_questions', array( 'qu_entity' => $questionIds ), __METHOD__ );
 136+ $dbw->delete( 'securepoll_elections', array( 'el_entity' => $electionId ), __METHOD__ );
 137+ $dbw->delete( 'securepoll_entity', array( 'en_id' => $entityIds ), __METHOD__ );
 138+}
 139+
 140+function spInsertEntity( $type, $id ) {
 141+ $dbw = wfGetDB( DB_MASTER );
 142+ $dbw->insert( 'securepoll_entity',
 143+ array(
 144+ 'en_id' => $id,
 145+ 'en_type' => $type,
 146+ ),
 147+ __METHOD__
 148+ );
 149+}
 150+
 151+function spImportConfiguration( $store, $electionInfo ) {
 152+ $dbw = wfGetDB( DB_MASTER );
 153+ $sourceIds = array();
 154+
 155+ # Election
 156+ spInsertEntity( 'election', $electionInfo['id'] );
 157+ $dbw->insert( 'securepoll_elections',
 158+ array(
 159+ 'el_entity' => $electionInfo['id'],
 160+ 'el_title' => $electionInfo['title'],
 161+ 'el_ballot' => $electionInfo['ballot'],
 162+ 'el_tally' => $electionInfo['tally'],
 163+ 'el_primary_lang' => $electionInfo['primaryLang'],
 164+ 'el_start_date' => $dbw->timestamp( $electionInfo['startDate'] ),
 165+ 'el_end_date' => $dbw->timestamp( $electionInfo['endDate'] ),
 166+ 'el_auth_type' => $electionInfo['auth']
 167+ ),
 168+ __METHOD__ );
 169+ $sourceIds[] = $electionInfo['id'];
 170+
 171+
 172+ # Questions
 173+ $index = 1;
 174+ foreach ( $electionInfo['questions'] as $questionInfo ) {
 175+ spInsertEntity( 'question', $questionInfo['id'] );
 176+ $dbw->insert( 'securepoll_questions',
 177+ array(
 178+ 'qu_entity' => $questionInfo['id'],
 179+ 'qu_election' => $electionInfo['id'],
 180+ 'qu_index' => $index++,
 181+ ),
 182+ __METHOD__ );
 183+ $sourceIds[] = $questionInfo['id'];
 184+
 185+ # Options
 186+ $insertBatch = array();
 187+ foreach ( $questionInfo['options'] as $optionInfo ) {
 188+ spInsertEntity( 'option', $optionInfo['id'] );
 189+ $insertBatch[] = array(
 190+ 'op_entity' => $optionInfo['id'],
 191+ 'op_election' => $electionInfo['id'],
 192+ 'op_question' => $questionInfo['id']
 193+ );
 194+ $sourceIds[] = $optionInfo['id'];
 195+ }
 196+ $dbw->insert( 'securepoll_options', $insertBatch, __METHOD__ );
 197+ }
 198+
 199+ # Messages
 200+ spInsertMessages( $store, $sourceIds );
 201+
 202+ # Properties
 203+ $properties = $store->getProperties( $sourceIds );
 204+ $insertBatch = array();
 205+ foreach ( $properties as $id => $entityProps ) {
 206+ foreach ( $entityProps as $key => $value ) {
 207+ $insertBatch[] = array(
 208+ 'pr_entity' => $id,
 209+ 'pr_key' => $key,
 210+ 'pr_value' => $value
 211+ );
 212+ }
 213+ }
 214+ if ( $insertBatch ) {
 215+ $dbw->insert( 'securepoll_properties', $insertBatch, __METHOD__ );
 216+ }
 217+ return true;
 218+}
 219+
 220+function spInsertMessages( $store, $entityIds ) {
 221+ $langs = $store->getLangList( $entityIds );
 222+ $insertBatch = array();
 223+ foreach ( $langs as $lang ) {
 224+ $messages = $store->getMessages( $lang, $entityIds );
 225+ foreach ( $messages as $id => $entityMsgs ) {
 226+ foreach ( $entityMsgs as $key => $text ) {
 227+ $insertBatch[] = array(
 228+ 'msg_entity' => $id,
 229+ 'msg_lang' => $lang,
 230+ 'msg_key' => $key,
 231+ 'msg_text' => $text
 232+ );
 233+ }
 234+ }
 235+ }
 236+ if ( $insertBatch ) {
 237+ $dbw = wfGetDB( DB_MASTER );
 238+ $dbw->insert( 'securepoll_msgs', $insertBatch, __METHOD__ );
 239+ }
 240+}
 241+
 242+function spUpdateMessages( $store, $electionInfo ) {
 243+ $entityIds = array( $electionInfo['id'] );
 244+ foreach ( $electionInfo['questions'] as $questionInfo ) {
 245+ $entityIds[] = $questionInfo['id'];
 246+ foreach ( $questionInfo['options'] as $optionInfo ) {
 247+ $entityIds[] = $optionInfo['id'];
 248+ }
 249+ }
 250+
 251+ # Delete existing messages
 252+ $dbw = wfGetDB( DB_MASTER );
 253+ $dbw->delete( 'securepoll_msgs', array( 'msg_entity' => $entityIds ), __METHOD__ );
 254+
 255+ # Insert new messages
 256+ spInsertMessages( $store, $entityIds );
 257+}
 258+
Property changes on: branches/wmf-deployment/extensions/SecurePoll/cli/import.php
___________________________________________________________________
Added: svn:eol-style
1259 + native
Index: branches/wmf-deployment/extensions/SecurePoll/cli/testDebian.php
@@ -0,0 +1,175 @@
 2+<?php
 3+
 4+require( dirname(__FILE__).'/cli.inc' );
 5+$testDir = dirname(__FILE__).'/debtest';
 6+if ( !is_dir( $testDir ) ) {
 7+ mkdir( $testDir );
 8+}
 9+
 10+$spDebianVoteDir = '/home/tstarling/src/voting/debian-vote/debian-vote-0.8-fixed';
 11+
 12+if ( count( $args ) ) {
 13+ foreach ( $args as $arg ) {
 14+ if ( !file_exists( $arg ) ) {
 15+ echo "File not found: $arg\n";
 16+ exit( 1 );
 17+ }
 18+ $debResult = spRunDebianVote( $arg );
 19+ if ( spRunTest( $arg, $debResult ) ) {
 20+ echo "$arg OK\n";
 21+ }
 22+ }
 23+ exit( 0 );
 24+}
 25+
 26+for ( $i = 1; true; $i++ ) {
 27+ $fileName = "$testDir/$i.in";
 28+ spGenerateTest( $fileName );
 29+ $debResult = spRunDebianVote( $fileName );
 30+ if ( spRunTest( $fileName, $debResult ) ) {
 31+ unlink( $fileName );
 32+ }
 33+ if ( $i % 1000 == 0 ) {
 34+ echo "$i tests done\n";
 35+ }
 36+}
 37+
 38+function spRunTest( $fileName, $debResult ) {
 39+ $file = fopen( $fileName, 'r' );
 40+ if ( !$file ) {
 41+ echo "Unable to open file \"$fileName\" for input\n";
 42+ return;
 43+ }
 44+
 45+ $votes = array();
 46+ $numCands = 0;
 47+ while ( !feof( $file ) ) {
 48+ $line = fgets( $file );
 49+ if ( $line === false ) {
 50+ break;
 51+ }
 52+ $line = trim( $line );
 53+ if ( !preg_match( '/^V: ([0-9-]*)$/', $line, $m ) ) {
 54+ echo "Skipping unrecognised line $line\n";
 55+ continue;
 56+ }
 57+
 58+ $record = array();
 59+ for ( $i = 0; $i < strlen( $m[1] ); $i++ ) {
 60+ $pref = substr( $m[1], $i, 1 );
 61+ if ( $i == strlen( $m[1] ) - 1 ) {
 62+ $id = 'X';
 63+ } else {
 64+ $id = chr( ord( 'A' ) + $i );
 65+ }
 66+ if ( $pref === '-' ) {
 67+ $record[$id] = 1000;
 68+ } else {
 69+ $record[$id] = intval( $pref );
 70+ }
 71+ }
 72+ $votes[] = $record;
 73+ $numCands = max( $numCands, count( $record ) );
 74+ }
 75+
 76+ $options = array();
 77+ for ( $i = 0; $i < $numCands - 1; $i++ ) {
 78+ $id = chr( ord( 'A' ) + $i );
 79+ $options[$id] = $id;
 80+ }
 81+ $options['X'] = 'X';
 82+ $question = new SecurePoll_FakeQuestion( $options );
 83+ $tallier = new SecurePoll_SchulzeTallier( false, $question );
 84+ foreach ( $votes as $vote ) {
 85+ $tallier->addVote( $vote );
 86+ }
 87+ $tallier->finishTally();
 88+ $ranks = $tallier->getRanks();
 89+ $winners = array();
 90+ foreach ( $ranks as $oid => $rank ) {
 91+ if ( $rank === 1 ) {
 92+ $winners[] = $oid;
 93+ }
 94+ }
 95+ if ( count( $winners ) > 1 ) {
 96+ $expected = 'result: tie between options ' . implode( ', ', $winners );
 97+ } else {
 98+ $expected = 'result: option ' . reset( $winners ) . ' wins';
 99+ }
 100+ if ( $debResult === $expected ) {
 101+ return true;
 102+ }
 103+
 104+ echo "Mismatch in file $fileName\n";
 105+ echo "Debian got: $debResult\n";
 106+ echo "We got: $expected\n\n";
 107+ echo $tallier->getTextResult();
 108+ return false;
 109+}
 110+
 111+function spRunDebianVote( $fileName ) {
 112+ global $spDebianVoteDir;
 113+ $result = wfShellExec(
 114+ wfEscapeShellArg(
 115+ "$spDebianVoteDir/debian-vote",
 116+ $fileName
 117+ )
 118+ );
 119+ if ( !$result ) {
 120+ echo "Error running debian vote!\n";
 121+ exit( 1 );
 122+ }
 123+ $result = rtrim( $result );
 124+ $lastLineEnd = strrpos( $result, "\n" );
 125+ $lastLine = substr( $result, $lastLineEnd + 1 );
 126+ return $lastLine;
 127+}
 128+
 129+function spGetRandom( $min, $max ) {
 130+ return mt_rand( 0, mt_getrandmax() ) / mt_getrandmax() * ( $max - $min ) + $min;
 131+}
 132+
 133+function spGenerateTest( $fileName ) {
 134+ global $spDebianVoteDir;
 135+ wfShellExec(
 136+ wfEscapeShellArg( "$spDebianVoteDir/votegen" ) . ' > ' .
 137+ wfEscapeShellArg( $fileName )
 138+ );
 139+}
 140+
 141+class SecurePoll_FakeQuestion {
 142+ var $options;
 143+
 144+ function __construct( $options ) {
 145+ $this->options = array();
 146+ foreach ( $options as $i => $option ) {
 147+ $this->options[] = new SecurePoll_FakeOption( $i, $option );
 148+ }
 149+ }
 150+
 151+ function getOptions() {
 152+ return $this->options;
 153+ }
 154+}
 155+
 156+class SecurePoll_FakeOption {
 157+ var $id, $name;
 158+
 159+ function __construct( $id, $name ) {
 160+ $this->id = $id;
 161+ $this->name = $name;
 162+ }
 163+
 164+ function getMessage( $key ) {
 165+ return $this->name;
 166+ }
 167+
 168+ function parseMessage( $key ) {
 169+ return htmlspecialchars( $this->name );
 170+ }
 171+
 172+ function getId() {
 173+ return $this->id;
 174+ }
 175+}
 176+
Property changes on: branches/wmf-deployment/extensions/SecurePoll/cli/testDebian.php
___________________________________________________________________
Added: svn:mergeinfo
Added: svn:eol-style
1177 + native
Index: branches/wmf-deployment/extensions/SecurePoll/cli/dump.php
@@ -0,0 +1,85 @@
 2+<?php
 3+
 4+/**
 5+ * Generate an XML dump of an election, including configuration and votes.
 6+ */
 7+
 8+
 9+$optionsWithArgs = array( 'o' );
 10+require( dirname(__FILE__).'/cli.inc' );
 11+
 12+$usage = <<<EOT
 13+Usage: php dump.php [options...] <election name>
 14+Options:
 15+ -o <outfile> Output to the specified file
 16+ --votes Include vote records
 17+ --all-langs Include messages for all languages instead of just the primary
 18+ --jump Produce a configuration dump suitable for setting up a jump wiki
 19+EOT;
 20+
 21+if ( !isset( $args[0] ) ) {
 22+ spFatal( $usage );
 23+}
 24+
 25+$context = new SecurePoll_Context;
 26+$election = $context->getElectionByTitle( $args[0] );
 27+if ( !$election ) {
 28+ spFatal( "There is no election called \"$args[0]\"" );
 29+}
 30+
 31+if ( !isset( $options['o'] ) ) {
 32+ $fileName = '-';
 33+} else {
 34+ $fileName = $options['o'];
 35+}
 36+if ( $fileName === '-' ) {
 37+ $outFile = STDOUT;
 38+} else {
 39+ $outFile = fopen( $fileName, 'w' );
 40+}
 41+if ( !$outFile ) {
 42+ spFatal( "Unable to open $fileName for writing" );
 43+}
 44+
 45+if ( isset( $options['all-langs'] ) ) {
 46+ $langs = $election->getLangList();
 47+} else {
 48+ $langs = array( $election->getLanguage() );
 49+}
 50+$confXml = $election->getConfXml( array(
 51+ 'jump' => isset( $options['jump'] ),
 52+ 'langs' => $langs
 53+) );
 54+
 55+$cbdata = array(
 56+ 'header' => "<SecurePoll>\n<election>\n$confXml",
 57+ 'outFile' => $outFile
 58+);
 59+$election->cbdata = $cbdata;
 60+
 61+# Write vote records
 62+if ( isset( $options['votes'] ) ) {
 63+ $status = $election->dumpVotesToCallback( 'spDumpVote' );
 64+ if ( !$status->isOK() ) {
 65+ spFatal( $status->getWikiText() );
 66+ }
 67+}
 68+if ( $election->cbdata['header'] ) {
 69+ fwrite( $outFile, $election->cbdata['header'] );
 70+}
 71+
 72+fwrite( $outFile, "</election>\n</SecurePoll>\n" );
 73+
 74+function spFatal( $message ) {
 75+ fwrite( STDERR, rtrim( $message ) . "\n" );
 76+ exit( 1 );
 77+}
 78+
 79+function spDumpVote( $election, $row ) {
 80+ if ( $election->cbdata['header'] ) {
 81+ fwrite( $election->cbdata['outFile'], $election->cbdata['header'] );
 82+ $election->cbdata['header'] = false;
 83+ }
 84+ fwrite( $election->cbdata['outFile'], "<vote>" . $row->vote_record . "</vote>\n" );
 85+}
 86+
Property changes on: branches/wmf-deployment/extensions/SecurePoll/cli/dump.php
___________________________________________________________________
Added: svn:eol-style
187 + native
Index: branches/wmf-deployment/extensions/SecurePoll/cli/tally.php
@@ -0,0 +1,62 @@
 2+<?php
 3+
 4+/**
 5+ * Tally an election from a dump file or local database.
 6+ *
 7+ * Can be used to tally very large numbers of votes, when the web interface is
 8+ * not feasible.
 9+ */
 10+
 11+$optionsWithArgs = array( 'name' );
 12+require( dirname(__FILE__).'/cli.inc' );
 13+
 14+$usage = <<<EOT
 15+Usage:
 16+ php tally.php [--html] --name <election name>
 17+ php tally.php [--html] <dump file>
 18+EOT;
 19+
 20+if ( !isset( $options['name'] ) && !isset( $args[0] ) ) {
 21+ spFatal( $usage );
 22+}
 23+
 24+if ( !class_exists( 'SecurePoll_Context' ) ) {
 25+ if ( isset( $options['name'] ) ) {
 26+ spFatal( "Cannot load from database when SecurePoll is not installed" );
 27+ }
 28+ require( dirname( __FILE__ ) . '/../SecurePoll.php' );
 29+}
 30+
 31+$context = new SecurePoll_Context;
 32+if ( !isset( $options['name'] ) ) {
 33+ $context = SecurePoll_Context::newFromXmlFile( $args[0] );
 34+ if ( !$context ) {
 35+ spFatal( "Unable to parse XML file \"{$args[0]}\"" );
 36+ }
 37+ $electionIds = $context->getStore()->getAllElectionIds();
 38+ if ( !count( $electionIds ) ) {
 39+ spFatal( "No elections found in XML file \"{$args[0]}\"" );
 40+ }
 41+ $election = $context->getElection( reset( $electionIds ) );
 42+} else {
 43+ $election = $context->getElectionByTitle( $options['name'] );
 44+ if ( !$election ) {
 45+ spFatal( "The specified election does not exist." );
 46+ }
 47+}
 48+$status = $election->tally();
 49+if ( !$status->isOK() ) {
 50+ spFatal( "Tally error: " . $status->getWikiText() );
 51+}
 52+$tallier = $status->value;
 53+if ( isset( $options['html'] ) ) {
 54+ echo $tallier->getHtmlResult();
 55+} else {
 56+ echo $tallier->getTextResult();
 57+}
 58+
 59+
 60+function spFatal( $message ) {
 61+ fwrite( STDERR, rtrim( $message ) . "\n" );
 62+ exit( 1 );
 63+}
Property changes on: branches/wmf-deployment/extensions/SecurePoll/cli/tally.php
___________________________________________________________________
Added: svn:eol-style
164 + native
Property changes on: branches/wmf-deployment/extensions/SecurePoll
___________________________________________________________________
Added: svn:mergeinfo
265 Merged /trunk/phase3/extensions/SecurePoll:r52290,52402,52404,52718,52737,52759,52776,52791,52800,52808,52812-52813,52815-52819,52822,52846,52850,52852-52853,52855-52857,52859,52924,52986,53128-53129,53190,53197,53199,53203-53204,53210-53211,53247,53249,53252,53267,53369
366 Merged /trunk/phase3/SecurePoll:r52859,53272
467 Merged /branches/REL1_15/phase3/extensions/SecurePoll:r51646
568 Merged /trunk/extensions/SecurePoll:r52089-53857

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r52089Added support for PageCSS, PageNotice, PhpHighlight and PurgeCache extensionsialex07:20, 18 June 2009
r52858fi E_ERROR: Call to undefined method MessageCache::getExtensionMessagesFor() ...ialex20:40, 7 July 2009

Status & tagging log