/* pyRCV2: Preferential vote counting Copyright © 2020 Lee Yingtong Li (RunasSudo) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ importScripts('vendor/BigInt_BigRat-a5f89e2.min.js', 'vendor/big-6.0.0.min.js', 'vendor/sjcl-1.0.8.min.js', 'bundle.js'); let result, counter, ppDP, tiesPrompt; onmessage = function(evt) { if (evt.data.type === 'init') { // Set settings if (evt.data.data.numbers === 'native') { py.pyRCV2.numbers.set_numclass(py.pyRCV2.numbers.Native); } if (evt.data.data.numbers === 'rational') { py.pyRCV2.numbers.set_numclass(py.pyRCV2.numbers.Rational); } if (evt.data.data.numbers === 'fixed') { py.pyRCV2.numbers.set_numclass(py.pyRCV2.numbers.Fixed); py.pyRCV2.numbers.set_dps(evt.data.data.fixedDPs); } ppDP = evt.data.data.fixedDPs > 2 ? 2 : evt.data.data.fixedDPs; let election = py.pyRCV2.blt.readBLT(evt.data.data.data); postMessage({'type': 'init', 'election': { 'candidates': election.candidates.map(c => c.py_name) }}); // Create counter if (evt.data.data.transfers === 'uig') { counter = py.pyRCV2.method.base_stv.UIGSTVCounter(election, evt.data.data.options); } else if (evt.data.data.transfers === 'eg') { counter = py.pyRCV2.method.base_stv.EGSTVCounter(election, evt.data.data.options); } else if (evt.data.data.transfers === 'wright') { counter = py.pyRCV2.method.wright.WrightSTVCounter(election, evt.data.data.options); } else { counter = py.pyRCV2.method.base_stv.WIGSTVCounter(election, evt.data.data.options); } if (evt.data.data.options['ties'] === 'backwards_random') { counter.options['ties'] = [py.pyRCV2.ties.TiesBackwards(counter), py.pyRCV2.ties.TiesRandom(evt.data.data.seed)]; } else if (evt.data.data.options['ties'] === 'random') { counter.options['ties'] = [py.pyRCV2.ties.TiesRandom(evt.data.data.seed)]; } else if (evt.data.data.options['ties'] === 'prompt') { tiesPrompt = py.pyRCV2.ties.TiesPrompt(); counter.options['ties'] = [tiesPrompt]; } // Reset result = counter.reset(); postMessage({'type': 'result', 'result': { 'comment': result.comment, 'candidates': result.candidates.py_items().map(([c, cc]) => [c.py_name, { 'transfers': cc.transfers.pp(ppDP), 'votes': cc.votes.pp(ppDP), 'state': cc.state }]), 'exhausted': { 'transfers': result.exhausted.transfers.pp(ppDP), 'votes': result.exhausted.votes.pp(ppDP) }, 'loss_fraction': { 'transfers': result.loss_fraction.transfers.pp(ppDP), 'votes': result.loss_fraction.votes.pp(ppDP) }, 'total': result.total.pp(ppDP), 'quota': result.quota.pp(ppDP) }}); stepElection(); } else if (evt.data.type === 'require_input') { // Data received from the user tiesPrompt.buffer = evt.data.input; stepElection(); } } function stepElection() { while (true) { try { result = counter.step(); } catch (ex) { if (py.isinstance(ex, py.pyRCV2.ties.RequireInput)) { // Signals we require input to break a tie postMessage({'type': 'require_input', 'message': ex.message}); break; } else { console.error(ex); throw ex; } } if (py.isinstance(result, py.pyRCV2.model.CountCompleted)) { postMessage({'type': 'done'}); break; } else { postMessage({'type': 'result', 'result': { 'comment': result.comment, 'candidates': result.candidates.py_items().map(([c, cc]) => [c.py_name, { 'transfers': cc.transfers.pp(ppDP), 'votes': cc.votes.pp(ppDP), 'state': cc.state }]), 'exhausted': { 'transfers': result.exhausted.transfers.pp(ppDP), 'votes': result.exhausted.votes.pp(ppDP) }, 'loss_fraction': { 'transfers': result.loss_fraction.transfers.pp(ppDP), 'votes': result.loss_fraction.votes.pp(ppDP) }, 'total': result.total.pp(ppDP), 'quota': result.quota.pp(ppDP) }}); } } }