diff --git a/html/blt/index.html b/html/blt/index.html
index 3d36fc7..f0c5a33 100644
--- a/html/blt/index.html
+++ b/html/blt/index.html
@@ -29,7 +29,7 @@
-
+
Information and instructions
diff --git a/html/blt/index.js b/html/blt/index.js
index 68d9493..1ad023a 100644
--- a/html/blt/index.js
+++ b/html/blt/index.js
@@ -145,7 +145,7 @@ async function changeInpFile() {
ballots = [];
for (let ballot of election.ballots) {
- let js_ballot = {'value': ballot.value.impl, 'preferences': []};
+ let js_ballot = {'value': ballot.value.__str__(), 'preferences': []};
for (let i = 0; i < candidates.length; i++) {
js_ballot['preferences'].push('');
}
@@ -183,8 +183,62 @@ function clickSaveJSON() {
'ballots': ballots,
};
+ // Download file
let url = URL.createObjectURL(new File([JSON.stringify(result)], 'ballots.json', {type: 'application/json'}));
+ let elA = document.createElement('a');
+ elA.href = url;
+ elA.download = '';
+ elA.click();
+}
+
+function clickExportBLT() {
+ let election = py.pyRCV2.model.Election();
+ let result = window.prompt('Enter the number of seats to elect:', '1');
+ if (result !== null) {
+ election.seats = parseInt(result);
+ } else {
+ return;
+ }
+
+ result = window.prompt('Enter the name of the election:');
+ if (result !== null) {
+ election.name = result;
+ } else {
+ return;
+ }
+
+ for (let candidate of candidates) {
+ let py_candidate = py.pyRCV2.model.Candidate(candidate);
+ election.candidates.push(py_candidate);
+ }
+
+ // Process ballots
+ for (let ballot of ballots) {
+ let py_ballot = py.pyRCV2.model.Ballot(py.pyRCV2.numbers.StringNum(ballot['value']), []);
+
+ for (let i = 1; i < candidates.length + 1; i++) {
+ let candidate = null;
+ for (let j = 0; j < candidates.length; j++) {
+ if (ballot.preferences[j].trim() === '' + i) {
+ candidate = j;
+ break;
+ }
+ }
+
+ if (candidate !== null) {
+ py_ballot.preferences.push(election.candidates[candidate]);
+ } else {
+ // No such preference
+ break;
+ }
+ }
+
+ election.ballots.push(py_ballot);
+ }
+
+ // Download file
+ let url = URL.createObjectURL(new File([py.pyRCV2.blt.writeBLT(election)], 'election.blt', {type: 'application/json'}));
let elA = document.createElement('a');
elA.href = url;
elA.download = '';
diff --git a/pyRCV2/blt.py b/pyRCV2/blt.py
index dcad81d..399c25c 100644
--- a/pyRCV2/blt.py
+++ b/pyRCV2/blt.py
@@ -68,3 +68,26 @@ def readBLT(data):
election.withdrawn = [election.candidates[x] for x in withdrawn]
return election
+
+def writeBLT(election, stringify=str):
+ lines = []
+
+ lines.append('{} {}'.format(len(election.candidates), election.seats))
+
+ if len(election.withdrawn) > 0:
+ lines.append(' '.join(['-{}'.format(election.candidates.index(candidate) + 1) for candidate in election.withdrawn]))
+
+ for ballot in election.ballots:
+ if ballot.preferences:
+ lines.append('{} {} 0'.format(stringify(ballot.value), ' '.join(str(election.candidates.index(x) + 1) for x in ballot.preferences)))
+ else:
+ lines.append('{} 0'.format(stringify(ballot.value)))
+
+ lines.append('0')
+
+ for candidate in election.candidates:
+ lines.append('"{}"'.format(candidate.name))
+
+ lines.append('"{}"'.format(election.name))
+
+ return '\n'.join(lines)
diff --git a/pyRCV2/numbers/string_js.py b/pyRCV2/numbers/string_js.py
index 7fd871d..1c3c756 100644
--- a/pyRCV2/numbers/string_js.py
+++ b/pyRCV2/numbers/string_js.py
@@ -26,3 +26,6 @@ class StringNum(BaseNum):
def _to_impl(cls, value):
"""Implements BaseNum._to_impl"""
return value
+
+ def __str__(self):
+ return self.impl