This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
glasnost/servers/ElectionsServer/ElectionsServer.py

731 lines
31 KiB
Python
Executable File

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
# Glasnost
# By: Odile Bénassy <obenassy@entrouvert.com>
# Romain Chantereau <rchantereau@entrouvert.com>
# Nicolas Clapiès <nclapies@easter-eggs.org>
# Pierre-Antoine Dejace <padejace@entrouvert.be>
# Thierry Dulieu <tdulieu@easter-eggs.com>
# Florent Monnier <monnier@codelutin.com>
# Cédric Musso <cmusso@easter-eggs.org>
# Frédéric Péters <fpeters@entrouvert.be>
# Benjamin Poussin <poussin@codelutin.com>
# Emmanuel Raviart <eraviart@entrouvert.com>
# Sébastien Régnier <regnier@codelutin.com>
# Emmanuel Saracco <esaracco@easter-eggs.com>
#
# Copyright (C) 2000, 2001 Easter-eggs & Emmanuel Raviart
# Copyright (C) 2002 Odile Bénassy, Code Lutin, Thierry Dulieu, Easter-eggs,
# Entr'ouvert, Frédéric Péters, Benjamin Poussin, Emmanuel Raviart,
# Emmanuel Saracco & Théridion
# Copyright (C) 2003 Odile Bénassy, Romain Chantereau, Nicolas Clapiès,
# Code Lutin, Pierre-Antoine Dejace, Thierry Dulieu, Easter-eggs,
# Entr'ouvert, Florent Monnier, Cédric Musso, Ouvaton, Frédéric Péters,
# Benjamin Poussin, Rodolphe Quiédeville, Emmanuel Raviart, Sébastien
# Régnier, Emmanuel Saracco, Théridion & Vecam
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
__doc__ = """Glasnost Elections Server"""
__version__ = '$Revision$'[11:-2]
import sys
glasnostPythonDir = '/usr/local/lib/glasnost-devel' # changed on make install
sys.path.insert(0, glasnostPythonDir)
import glasnost
import glasnost.common.context as context
from glasnost.common.ElectionsCommon import *
import glasnost.common.faults as faults
import glasnost.common.tools_new as commonTools
import glasnost.common.xhtmlgenerator as X
from glasnost.server.ObjectsServer import register, ObjectServerMixin, \
AdminServerMixin, ObjectsServer
from glasnost.server.tools import *
from glasnost.proxy.AtomsProxy import Atom
from glasnost.proxy.BrevesProxy import BreveElectionCandidateAdded, \
BreveElectionRunning, BreveElectionClosed
from glasnost.proxy.CacheProxy import invalidateValue
from glasnost.proxy.DispatcherProxy import getApplicationId
from glasnost.proxy.GroupsProxy import getSetContainedIds
applicationName = 'ElectionsServer'
applicationRole = 'elections'
dispatcher = None
class AdminElections(AdminServerMixin, AdminElectionsCommon):
pass
register(AdminElections)
class ElectionMixin(ObjectServerMixin):
def importVoteFromXmlRpc(self, voteImport):
return commonTools.importThing(voteImport)
class AbstractElection(ElectionMixin, AbstractElectionCommon):
pass
register(AbstractElection)
class ElectionAverage(ElectionMixin, ElectionAverageCommon):
def compute(self):
virtualServerId = self.getServer().computeVirtualServerId(self.id)
self.candidateIds = getSetContainedIds(self.candidatesSet)
voterIds = self.getVoterIds(virtualServerId)
if not self.canCompute():
if self.ratings is not None:
del self.ratings
if self.winnerIds is not None:
del self.winnerIds
return
# Compute the ratings.
ratings = {}
for candidateId in self.candidateIds:
ratings[candidateId] = 0
count = 0
votes = getProxyForServerRole('ballots').getElectionVotes(
self.voteTokens, voterIds)
if self.weightingsGradeId is not None:
weightingsGrade = getProxyForServerRole('grades').getObject(
self.weightingsGradeId)
weightingsById = weightingsGrade.repairMarks(
weightingsGrade.marks, voterIds)
weightings = getProxyForServerRole('ballots'
).getElectionWeightings(self.voteTokens, weightingsById)
else:
weightings = None
for vote in votes:
if not vote.isAbstention() and not vote.isBlank(self.candidateIds):
if weightings is not None:
weighting = weightings[vote.voterToken]
else:
weighting = 1
count = count + weighting
marks = vote.repairMarks(vote.marks, self.candidateIds)
for candidateId, mark in marks.items():
ratings[candidateId] += weighting * mark
if count > 0:
count = float(count)
for candidateId in self.candidateIds:
ratings[candidateId] = ratings[candidateId] / count
self.ratings = ratings
# Compute the winners.
if self.winnersCount > 0:
winnerIds = self.candidateIds[:]
def winnersSorter(x, y, ratings = ratings):
return cmp(ratings[y], ratings[x])
winnerIds.sort(winnersSorter)
winnersCount = self.winnersCount
if len(winnerIds) > 0 and winnersCount < len(winnerIds):
lastRating = ratings[winnerIds[winnersCount - 1]]
for winnerId in winnerIds[winnersCount:]:
if ratings[winnerId] < lastRating:
break
winnersCount = winnersCount + 1
self.winnerIds = winnerIds[:winnersCount]
elif self.winnerIds is not None:
del self.winnerIds
# Update the winners' group, if it exists.
if self.winnerIds and self.winnersGroupId is not None:
group = getProxyForServerRole('groups').getObject(
self.winnersGroupId)
group.membersSet = self.winnerIds
group.nonMembersSet = []
getProxyForServerRole('groups').modifyObject(group)
# Update the winners' grade, if it exists.
if self.winnersGradeId is not None:
grade = getProxyForServerRole('grades').getObject(
self.winnersGradeId)
grade.membersSet = self.candidateIds
grade.marks = self.ratings
getProxyForServerRole('grades').modifyObject(grade)
register(ElectionAverage)
def _addToPotentialWinners(candidateId, newWinnerIds, winnerIds, ratings):
if candidateId in newWinnerIds:
return
if candidateId in winnerIds:
return
newWinnerIds.append(candidateId)
rating = ratings[candidateId]
for tieId in rating['ties']:
_addToPotentialWinners(tieId, newWinnerIds, winnerIds, ratings)
for lossId in rating['losses']:
_addToPotentialWinners(lossId, newWinnerIds, winnerIds, ratings)
class ElectionCondorcet(ElectionMixin, ElectionCondorcetCommon):
def compute(self):
virtualServerId = self.getServer().computeVirtualServerId(self.id)
self.candidateIds = getSetContainedIds(self.candidatesSet)
voterIds = self.getVoterIds(virtualServerId)
if not self.canCompute():
if self.pairwiseMatrix is not None:
del self.pairwiseMatrix
if self.ratings is not None:
del self.ratings
if self.winnerIds is not None:
del self.winnerIds
return
# Compute the pairwise matrix.
pairwiseMatrix = {}
for candidateId in self.candidateIds:
pairwiseMatrix[candidateId] = row = {}
for candidateId2 in self.candidateIds:
row[candidateId2] = 0
votes = getProxyForServerRole('ballots').getElectionVotes(
self.voteTokens, voterIds)
if self.weightingsGradeId is not None:
weightingsGrade = getProxyForServerRole('grades').getObject(
self.weightingsGradeId)
weightingsById = weightingsGrade.repairMarks(
weightingsGrade.marks, voterIds)
weightings = getProxyForServerRole('ballots'
).getElectionWeightings(self.voteTokens, weightingsById)
else:
weightings = None
for vote in votes:
if not vote.isAbstention() and not vote.isBlank(self.candidateIds):
if weightings is not None:
weighting = weightings[vote.voterToken]
else:
weighting = 1
marks = vote.repairMarks(vote.marks, self.candidateIds)
for candidateId, mark in marks.items():
for candidateId2, mark2 in marks.items():
if candidateId == candidateId2:
continue
if mark == mark2:
pairwiseMatrix[candidateId][candidateId2] += \
weighting / 2.0
elif mark < mark2:
pairwiseMatrix[candidateId][candidateId2] += \
weighting
self.pairwiseMatrix = pairwiseMatrix
# Compute the ratings.
ratings = {}
for candidateId in self.candidateIds:
rating = {
'wins': [],
'losses': [],
'ties': [],
'worstDefeat': 0,
}
for candidateId2 in self.candidateIds:
if candidateId == candidateId2:
continue
delta = pairwiseMatrix[candidateId][candidateId2] \
- pairwiseMatrix[candidateId2][candidateId]
if delta > 0:
rating['wins'].append(candidateId2)
elif delta < 0:
rating['losses'].append(candidateId2)
if delta < rating['worstDefeat']:
rating['worstDefeat'] = -delta
else:
rating['ties'].append(candidateId2)
ratings[candidateId] = rating
self.ratings = ratings
# Compute the winners.
if self.winnersCount >= len(self.candidateIds):
self.winnerIds = self.candidateIds[:]
elif self.winnersCount > 0:
winnerIds = []
remaining = self.candidateIds[:]
for k in range(self.winnersCount):
if len(winnerIds) >= self.winnersCount:
break
# If there is a candidate with no loss and no tie, then it is a
# winner.
for remainingId in remaining:
remainingRating = ratings[remainingId]
isWinner = 1
for lossId in remainingRating['losses']:
if lossId not in winnerIds:
isWinner = 0
break
if not isWinner:
continue
for tieId in remainingRating['ties']:
if tieId not in winnerIds:
isWinner = 0
break
if not isWinner:
continue
winnerIds.append(remainingId)
remaining.remove(remainingId)
break
else:
# If there is a group of candidates who lose only between
# them and if this group is smaller or equal to the
# remaining winners to find, add this group to the winners.
smallestGroup = remaining[:]
for remainingId in remaining:
newWinnerIds = []
_addToPotentialWinners(remainingId, newWinnerIds,
winnerIds, ratings)
if len(newWinnerIds) < len(smallestGroup):
smallestGroup = newWinnerIds[:]
if len(winnerIds) + len(newWinnerIds) \
<= self.winnersCount:
for winnerId in newWinnerIds:
winnerIds.append(winnerId)
remaining.remove(winnerId)
break
else:
# No candidate respects the Condorcet criterion.
# Choose the ones with the narrowest worst defeat.
narrowestWorstDefeat = None
newWinnerIds = None
for remainingId in smallestGroup:
remainingRating = ratings[remainingId]
if narrowestWorstDefeat is None \
or remainingRating['worstDefeat'] \
< narrowestWorstDefeat:
narrowestWorstDefeat = remainingRating[
'worstDefeat']
newWinnerIds = [remainingId]
elif remainingRating['worstDefeat'] \
== narrowestWorstDefeat:
newWinnerIds.append(remainingId)
## if len(winnerIds) + len(newWinnerIds) \
## <= self.winnersCount:
for winnerId in newWinnerIds:
winnerIds.append(winnerId)
remaining.remove(winnerId)
self.winnerIds = winnerIds
elif self.winnerIds is not None:
del self.winnerIds
# Update the winners' group, if it exists.
if self.winnerIds and self.winnersGroupId is not None:
group = getProxyForServerRole('groups').getObject(
self.winnersGroupId)
group.membersSet = self.winnerIds
group.nonMembersSet = []
getProxyForServerRole('groups').modifyObject(group)
register(ElectionCondorcet)
class ElectionsServer(ElectionsCommonMixin, ObjectsServer):
def abstainForVote(self, objectId, previousVoteToken):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
object = virtualServer.loadObjectCore(objectId)
if object.state != 'running':
raise faults.UserAccessDenied()
if object.voteTokens is None:
object.voteTokens = []
if previousVoteToken \
and object.voteTokens is not None \
and previousVoteToken in object.voteTokens:
del object.voteTokens[object.voteTokens.index(
previousVoteToken)]
if len(object.voteTokens) == 0:
del object.voteTokens
virtualServer.markObjectAsDirty(object)
def addObjectXmlRpc(self, objectImport):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
object = commonTools.importThing(objectImport)
# User must be an admin or (a writer and a writer of this object))
if not self.isAdmin() and not (
self.useAdminWritersSet
and getProxyForServerRole('authentication').setContainsUser(
self.getAdminCore().writersSet) and (
getProxyForServerRole('authentication').setContainsUser(
object.writersSet))) \
or object.state != 'draft':
if not object.canBeCreatedByClient():
raise faults.UserAccessDenied()
object.checkAddIsPossible()
object.setAutomaticalSlots()
virtualServer.objects[object.id] = object
object.saveNonCore()
object.releaseNonCore()
virtualServer.markObjectAsDirty(object)
virtualServer.markCoreAsDirty()
return object.id
def canDeleteObject(self, objectId):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
if not virtualServer.canLoadObjectCore(objectId):
return 0
object = virtualServer.loadObjectCore(objectId)
isAdmin = self.isAdmin()
if not isAdmin and not getProxyForServerRole('authentication'
).setContainsUser(object.writersSet):
return 0
if not isAdmin and object.state != 'draft':
return 0
return 1
def canModifyObject(self, objectId):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
if not virtualServer.canLoadObjectCore(objectId):
return 0
object = virtualServer.loadObjectCore(objectId)
if not object.canBeModified():
return 0
isAdmin = self.isAdmin()
if not isAdmin and not getProxyForServerRole('authentication'
).setContainsUser(object.writersSet):
return 0
if not isAdmin and object.state != 'draft':
return 0
return 1
def canVote(self, objectId):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
if not virtualServer.canLoadObjectCore(objectId):
return 0
object = virtualServer.loadObjectCore(objectId)
if object.state != 'running':
return 0
return 1
def computeObject(self, objectId):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
virtualServer.objects[objectId].compute()
invalidateValue(objectId)
def getBallotKind(self, objectId):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
object = virtualServer.loadObjectCore(objectId)
return object.ballotKind
def getLastObjectIds(
self, objectsCount, possibleAuthorsSet, possibleReadersSet,
possibleWritersSet, possibleStates):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
isAdmin = self.isAdmin()
try:
possibleAuthorIds = getSetContainedIds(
possibleAuthorsSet, ['people'])
except faults.UncountableGroup:
possibleAuthorIds = 'everybody'
try:
possibleReaderIds = getSetContainedIds(
possibleReadersSet, ['people'])
except faults.UncountableGroup:
possibleReaderIds = 'everybody'
try:
possibleWriterIds = getSetContainedIds(
possibleWritersSet, ['people'])
except faults.UncountableGroup:
possibleWriterIds = 'everybody'
objectIds = virtualServer.objects.keys()
def modificationTimeSorter(xId, yId,
virtualServer = virtualServer):
return cmp(virtualServer.loadObjectCore(yId).modificationTime,
virtualServer.loadObjectCore(xId).modificationTime)
objectIds.sort(modificationTimeSorter)
result = []
for objectId in objectIds:
object = virtualServer.loadObjectCore(objectId)
if possibleStates and not object.state in possibleStates:
continue
if not isAdmin and not getProxyForServerRole(
'authentication').setContainsUser(object.readersSet):
continue
if not self.getLastObjectIds_filter(
possibleAuthorIds, 1, object.authorsSet):
continue
if not self.getLastObjectIds_filter(
possibleReaderIds, 1, object.readersSet):
continue
if not self.getLastObjectIds_filter(
possibleWriterIds, 1, object.writersSet):
continue
result.append(objectId)
if objectsCount != -1 and len(result) >= objectsCount:
break
return result
def getLastObjectIdsWithVoter(self, objectsCount, voterId, possibleStates):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
objectIds = virtualServer.objects.keys()
def modificationTimeSorter(xId, yId,
virtualServer = virtualServer):
return cmp(virtualServer.loadObjectCore(yId).modificationTime,
virtualServer.loadObjectCore(xId).modificationTime)
objectIds.sort(modificationTimeSorter)
result = []
for objectId in objectIds:
object = virtualServer.loadObjectCore(objectId)
if not self.isAdmin() \
and not getProxyForServerRole('authentication'
).setContainsUser(object.readersSet):
continue
if possibleStates and not object.state in possibleStates:
continue
if not voterId in object.getVoterIds(virtualServerId):
continue
result.append(objectId)
if len(result) >= objectsCount:
break
return result
def getVoteXmlRpc(self, objectId, voteToken):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
object = virtualServer.loadObjectCore(objectId)
if object.votes is None or not object.votes.has_key(voteToken):
raise faults.UnknownVoteToken(voteToken)
vote = object.votes[voteToken]
result = vote.exportToXmlRpc()
return result
def modifyObjectXmlRpc(self,objectImport):
objectChanges = commonTools.importThing(objectImport)
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
object = virtualServer.loadObjectCore(objectChanges.id)
object.acquireNonCore()
try:
if not object.canBeModified():
raise faults.ReadOnlyObject()
previousState = object.state
newState = objectChanges.state
if not self.canModifyObject(object.id) or not (
self.isAdmin()
or not objectChanges.hasSlotName('writersSet')
or getProxyForServerRole('authentication'
).setContainsUser(
objectChanges.getSlot('writersSet').getValue())):
if not object.canBeModifiedByClient():
raise faults.UserAccessDenied()
if not self.isAdmin() and previousState != newState \
and (previousState != 'draft'
or newState != 'proposed'):
raise faults.UserAccessDenied()
object.checkModifyIsPossible(objectChanges)
object.modify(objectChanges)
object.compute()
object.saveNonCore()
finally:
object.releaseNonCore()
virtualServer.markObjectAsDirty(object)
brevesProxy = getProxyForServerRole('breves')
if brevesProxy:
if newState == 'running' and previousState != newState:
breve = BreveElectionRunning()
breve.language = object.getLanguage()
breve.electionId = object.id
breve.electionTitle = object.title
breve.electionSubject = object.subject
breve.readersSet = object.readersSet
if breve.readersSet is not None:
breve.readersSet = breve.readersSet[:]
breve.writersSet = object.writersSet
if breve.writersSet is not None:
breve.writersSet = breve.writersSet[:]
try:
brevesProxy.addObject(breve, serverId = virtualServerId)
except faults.UnknownServerId:
pass
elif newState == 'closed' and previousState != newState:
breve = BreveElectionClosed()
breve.language = object.getLanguage()
breve.electionId = object.id
breve.electionTitle = object.title
breve.electionSubject = object.subject
breve.readersSet = object.readersSet
if breve.readersSet is not None:
breve.readersSet = breve.readersSet[:]
breve.writersSet = object.writersSet
if breve.writersSet is not None:
breve.writersSet = breve.writersSet[:]
try:
brevesProxy.addObject(breve, serverId = virtualServerId)
except faults.UnknownServerId:
pass
invalidateValue(object.id)
return object.version
def pesterAbstentionnistsXmlRpc(self, objectId, httpHostName, httpPort,
httpScriptDirectoryPath):
httpHostName = iso8859_15(httpHostName)
httpPort = iso8859_15(httpPort)
httpScriptDirectoryPath = iso8859_15(httpScriptDirectoryPath)
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
if not virtualServer.canLoadObjectCore(objectId):
return 0
object = virtualServer.loadObjectCore(objectId)
if object.state != 'running':
return 0
if httpHostName:
context.setVar('httpHostName', httpHostName)
if httpPort:
context.setVar('httpPort', httpPort)
if httpScriptDirectoryPath:
context.setVar(
'httpScriptDirectoryPath', httpScriptDirectoryPath)
electionUrl = X.url(objectId).getAsAbsoluteUrl()
fromAddress = virtualServer.adminEmailAddress
abstentionnistsCount = 0
for voterId in object.getVoterIds(virtualServerId):
voter = getProxyForServerRole('people').getObject(voterId)
if voter.voteTokens is not None \
and voter.voteTokens.has_key(objectId):
continue
abstentionnistsCount += 1
toAddress = voter.email
message = """\
REMINDER
The election "%(label)s" is running.
You can vote at the URL:
%(url)s
Please, do it now!
""" % {
'label': object.getLabel(),
'url': electionUrl,
}
sendMail(
mailFrom = fromAddress,
mailTo = toAddress,
mailSubject = "[Glasnost] Election in Progress",
mailMessage = message,
mailPerson = voter,
)
return abstentionnistsCount
def registerPublicMethods(self):
ObjectsServer.registerPublicMethods(self)
self.registerPublicMethod('abstainForVote')
self.registerPublicMethod('canVote')
self.registerPublicMethod('computeObject')
self.registerPublicMethod('getBallotKind')
self.registerPublicMethod('getLastObjectIdsWithVoter')
self.registerPublicMethod('getVote', self.getVoteXmlRpc)
self.registerPublicMethod('pesterAbstentionnists',
self.pesterAbstentionnistsXmlRpc)
self.registerPublicMethod('vote')
def repairVirtualServer(self, virtualServer, version):
changed = 0
if version < 2006:
for object in virtualServer.objects.values():
if hasattr(object, 'isSecret'):
changed = 1
object.ballotKind = object.isSecret
del object.isSecret
if version < 3005:
for object in virtualServer.objects.values():
if object.readersSet is None and object.writersSet is None:
changed = 1
object.writersSet = object.authorsSet
if object.writersSet is not None:
object.writersSet = object.writersSet[:]
if object.state in ['refused', 'trashed']:
del object.state # => object.state = 'draft'
if object.state == 'draft':
object.readersSet = object.authorsSet
if object.readersSet is not None:
object.readersSet = object.readersSet[:]
if version < 4000:
changed = virtualServer.admin.repair(4000) or changed
for id, object in virtualServer.objects.items():
newId = repairId(id)
if newId:
changed = 1
del virtualServer.objects[id]
virtualServer.objects[newId] = object
changed = object.repair(4000) or changed
if not object.__dict__.has_key('language'):
changed = 1
object.language = 'fr'
if version < 5004:
changed = virtualServer.admin.repair(5004) or changed
for id, object in virtualServer.objects.items():
changed = object.repair(5004) or changed
if version <= 1013000:
admin = virtualServer.admin
if admin.id is None:
changed = 1
admin.id = '%s/__admin__' % virtualServer.virtualServerId
if version <= 1018000:
for object in virtualServer.objects.values():
if object.voteTokens is None:
continue
for i in range(len(object.voteTokens)):
voteToken = object.voteTokens[i]
if not voteToken.startswith('glasnost://'):
changed = 1
object.voteTokens[i] = '%s/votes/%s' % (
commonTools.extractDispatcherId(
virtualServer.virtualServerId),
voteToken)
if changed:
virtualServer.markAllAsDirtyFIXME()
def vote(self, objectId, voteToken, previousVoteToken):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
object = virtualServer.loadObjectCore(objectId)
if object.state != 'running':
raise faults.UserAccessDenied()
if object.voteTokens is None:
object.voteTokens = []
if previousVoteToken \
and previousVoteToken in object.voteTokens:
del object.voteTokens[object.voteTokens.index(
previousVoteToken)]
object.voteTokens.append(voteToken)
virtualServer.markObjectAsDirty(object)
electionsServer = ElectionsServer()
if __name__ == "__main__":
electionsServer.launch(applicationName, applicationRole)