diff --git a/VendServer/DoorClient.py b/VendServer/DoorClient.py
index d46cebe98f9e7ca055cf0c58d9279480930b1b0a..121b563892457c9460274c4a99cfc09df423206d 100755
--- a/VendServer/DoorClient.py
+++ b/VendServer/DoorClient.py
@@ -1,6 +1,6 @@
 #!/usr/bin/python
 
-from LATClient import LATClient
+from .LATClient import LATClient
 from select import select
 import signal
 import sys
@@ -14,17 +14,17 @@ def check_door_service(service, test_string="got wombles?"):
 	rr, wr, er = select([rfh], [], [], 10.0)
 	if rfh not in rr: return "open"
 	recv = rfh.read(len(test_string))
-	if recv <> test_string: return "error"
+	if recv != test_string: return "error"
 	return "closed"
 
 if __name__ == '__main__':
 	result_codes = { 'open' : 0, 'closed' : 1, 'error' : 2, 'invalid args' : 3}
 	def return_result(result):
-		print result
+		print(result)
 		sys.exit(result_codes[result])
 	def timeout(signum, frame):
 		return_result("error")
-	if len(sys.argv) <> 2: return_result('invalid args')
+	if len(sys.argv) != 2: return_result('invalid args')
 	signal.signal(signal.SIGALRM, timeout)
 	signal.alarm(15)
 	return_result(check_door_service(sys.argv[1]))
diff --git a/VendServer/HorizScroll.py b/VendServer/HorizScroll.py
index d27f7dc8e8150b72df36f6915bd55873ffca6c14..23811f06e7ea0f6a1c60c227b04377450d17203f 100644
--- a/VendServer/HorizScroll.py
+++ b/VendServer/HorizScroll.py
@@ -11,7 +11,7 @@ class HorizScroll:
 
 	def expand(self, padding=None, paddingchar=" ", dir=None, wraparound=False):
 		if len(self.text) <= 10:
-			return [text]
+			return [self.text]
 
 		if padding == None:
 			padding = len(self.text) / 2 + 1
@@ -27,7 +27,7 @@ class HorizScroll:
 		expansion = []
 
 		for x in range(0,numiters):
-			  expansion.append("%-10.10s" % (padtext[x:] + padtext[:x]))
+			expansion.append("%-10.10s" % (padtext[x:] + padtext[:x]))
 		
 		if dir == -1:
 			expansion.reverse()
@@ -40,7 +40,7 @@ if __name__ == '__main__':
 	while 1:
 		for x in eh:
 			sys.stdout.write("\r")
-			print "%-10.10s" % x,
+			print("%-10.10s" % x, end=' ')
 			sys.stdout.flush()
 			time.sleep(0.1)
 
diff --git a/VendServer/Idler.py b/VendServer/Idler.py
index c2eedee233e8c2521dbe64f229e67d43cfa19afe..493f209124709cb71e9e91e97e56770269488ed5 100755
--- a/VendServer/Idler.py
+++ b/VendServer/Idler.py
@@ -3,307 +3,307 @@
 import string, time, os
 from subprocess import Popen, PIPE
 from random import random
-from MessageKeeper import MessageKeeper
+from .MessageKeeper import MessageKeeper
 
 orderings = None
 
 IDLER_TEXT_SPEED=1.8
 
 class Idler:
-	def __init__(self, v, affinity=None):
-		self.v = v
-		if affinity:
-			self._affinity = affinity
-		else:
-			self._affinity = 1
-
-	def next(self):
-		"""Displays next stage of the idler. Returns time to the next step"""
-		return 1
-
-	def reset(self):
-		"""Resets the idler to a known intial state"""
-		pass
-	
-	def finished(self):
-		"""Returns True if the idler is considered finished"""
-		return False
-
-	def affinity(self):
-		"""How much we want this idler to be the next one chosen"""
-		return self._affinity
+    def __init__(self, v, affinity=None):
+        self.v = v
+        if affinity:
+            self._affinity = affinity
+        else:
+            self._affinity = 1
+
+    def __next__(self):
+        """Displays next stage of the idler. Returns time to the next step"""
+        return 1
+
+    def reset(self):
+        """Resets the idler to a known intial state"""
+        pass
+    
+    def finished(self):
+        """Returns True if the idler is considered finished"""
+        return False
+
+    def affinity(self):
+        """How much we want this idler to be the next one chosen"""
+        return self._affinity
 
 class GreetingIdler(Idler):
-	def __init__(self, v, secs_to_greeting = None):
-		affinity = 0 
-		Idler.__init__(self, v, affinity = affinity)
-		self.secs_to_greeting = secs_to_greeting
-		self.message_displayed = False
+    def __init__(self, v, secs_to_greeting = None):
+        affinity = 0 
+        Idler.__init__(self, v, affinity = affinity)
+        self.secs_to_greeting = secs_to_greeting
+        self.message_displayed = False
 
-	def next(self):
-		if not self.secs_to_greeting is None:
-			x = self.secs_to_greeting
-			self.secs_to_greeting = None
-			return x
+    def __next__(self):
+        if not self.secs_to_greeting is None:
+            x = self.secs_to_greeting
+            self.secs_to_greeting = None
+            return x
 
-		self.v.display('UCC SNACKS')
-		self.message_displayed = True
-		return 5
+        self.v.display('UCC SNACKS')
+        self.message_displayed = True
+        return 5
 
-	def reset(self):
-		self.message_displayed = False
-		self.secs_to_greeting = None
+    def reset(self):
+        self.message_displayed = False
+        self.secs_to_greeting = None
 
-	def finished(self):
-		return self.message_displayed
+    def finished(self):
+        return self.message_displayed
 
 class TrainIdler(Idler):
-	def __init__(self, v):
-		Idler.__init__(self, v)
-		self.idle_state = 0
-
-	def put_shark(self, s, l):
-		if self.s[l] == ' ':
-			self.s[l] = s
-		elif self.s[l] == 'X':
-			self.s[l] = '*'
-		else:
-			self.s[l] = 'X'
-
-	def next(self):
-		# does the next stage of a dance
-		self.s = [' ']*10
-		shark1 = self.idle_state % 18
-		if shark1 < 9:
-			self.put_shark('^', shark1)
-		else:
-			self.put_shark('^', 18-shark1)
-
-		shark2 = ((self.idle_state+4) % 36)/2
-		if shark2 < 9:
-			self.put_shark('<', shark2)
-		else:
-			self.put_shark('<', 18-shark2)
-
-		shark3 = ((self.idle_state+7) % 54)/3
-		if shark3 < 9:
-			self.put_shark('>', 9-shark3)
-		else:
-			self.put_shark('>', 9-(18-shark3))
-
-		train1 = ((self.idle_state%(18*36)))
-		train1_start = 122
-		if train1 > train1_start and train1 < train1_start+(10*2):
-			for i in range(5):
-				ptr = i+train1-train1_start-5
-				if ptr >= 0 and ptr < 10: self.s[ptr] = '#'
-
-		train2 = ((self.idle_state%(18*36)))
-		train2_start = 400
-		if train2 > train2_start and train2 < train2_start+(10*2):
-			for i in range(5):
-				ptr = i+train2-train2_start-5
-				if ptr >= 0 and ptr < 10: self.s[9-ptr] = '#'
-
-		train3 = ((self.idle_state%(18*36)))
-		train3_start = 230
-		if train3 > train3_start and train3 < train3_start+(10*2):
-			for i in range(10):
-				ptr = i+train3-train3_start-10
-				if ptr >= 0 and ptr < 10: self.s[ptr] = '-'
-
-		self.v.display(string.join(self.s, ''))
-		self.idle_state += 1
-		self.idle_state %= 18*36*54
-
-	def reset(self):
-		self.idle_state = 0
+    def __init__(self, v):
+        Idler.__init__(self, v)
+        self.idle_state = 0
+
+    def put_shark(self, s, l):
+        if self.s[l] == ' ':
+            self.s[l] = s
+        elif self.s[l] == 'X':
+            self.s[l] = '*'
+        else:
+            self.s[l] = 'X'
+
+    def __next__(self):
+        # does the next stage of a dance
+        self.s = [' ']*10
+        shark1 = self.idle_state % 18
+        if shark1 < 9:
+            self.put_shark('^', shark1)
+        else:
+            self.put_shark('^', 18-shark1)
+
+        shark2 = ((self.idle_state+4) % 36)/2
+        if shark2 < 9:
+            self.put_shark('<', shark2)
+        else:
+            self.put_shark('<', 18-shark2)
+
+        shark3 = ((self.idle_state+7) % 54)/3
+        if shark3 < 9:
+            self.put_shark('>', 9-shark3)
+        else:
+            self.put_shark('>', 9-(18-shark3))
+
+        train1 = ((self.idle_state%(18*36)))
+        train1_start = 122
+        if train1 > train1_start and train1 < train1_start+(10*2):
+            for i in range(5):
+                ptr = i+train1-train1_start-5
+                if ptr >= 0 and ptr < 10: self.s[ptr] = '#'
+
+        train2 = ((self.idle_state%(18*36)))
+        train2_start = 400
+        if train2 > train2_start and train2 < train2_start+(10*2):
+            for i in range(5):
+                ptr = i+train2-train2_start-5
+                if ptr >= 0 and ptr < 10: self.s[9-ptr] = '#'
+
+        train3 = ((self.idle_state%(18*36)))
+        train3_start = 230
+        if train3 > train3_start and train3 < train3_start+(10*2):
+            for i in range(10):
+                ptr = i+train3-train3_start-10
+                if ptr >= 0 and ptr < 10: self.s[ptr] = '-'
+
+        self.v.display(string.join(self.s, ''))
+        self.idle_state += 1
+        self.idle_state %= 18*36*54
+
+    def reset(self):
+        self.idle_state = 0
 
 class OrderMaker:
-	def __init__(self, n=8):
-		self.n = n
-		self.make_factorials(n)
-	
-	def make_factorials(self, n):
-		self.factorial = []
-		a = 1
-		for i in range(1,n+1):
-			self.factorial.append(a)
-			a *= i
-
-	def order(self, index):
-		used = []
-		for i in range(0,self.n):
-			used.append(i)
-		i = self.n-1
-		j = 0
-		res = []
-		while i >= 0:
-			a = index/self.factorial[i]
-			index %= self.factorial[i]
-			res.append(a+1)
-			i -= 1
-			j += 1
-		for i in range(0,self.n):
-			tmp = used[res[i]-1]
-			for j in range(res[i],self.n):
-				used[j-1] = used[j]
-			res[i] = tmp
-		return res
-
-	def __getitem__(self, i):
-		return self.order(i)
+    def __init__(self, n=8):
+        self.n = n
+        self.make_factorials(n)
+    
+    def make_factorials(self, n):
+        self.factorial = []
+        a = 1
+        for i in range(1,n+1):
+            self.factorial.append(a)
+            a *= i
+
+    def order(self, index):
+        used = []
+        for i in range(0,self.n):
+            used.append(i)
+        i = self.n-1
+        j = 0
+        res = []
+        while i >= 0:
+            a = index/self.factorial[i]
+            index %= self.factorial[i]
+            res.append(a+1)
+            i -= 1
+            j += 1
+        for i in range(0,self.n):
+            tmp = used[res[i]-1]
+            for j in range(res[i],self.n):
+                used[j-1] = used[j]
+            res[i] = tmp
+        return res
+
+    def __getitem__(self, i):
+        return self.order(i)
 
 class GrayIdler(Idler):
-	def __init__(self, v, one=None, zero=None, reorder=0):
-		Idler.__init__(self, v)
-		self.bits = 8
-		self.size = 1 << self.bits
-		self.i = 0
-		self.grayCode = 0
-		self.one = one
-		self.zero = zero
-		self.reorder = reorder
-		global orderings
-		if not orderings:
-			orderings = OrderMaker()
-
-	def next(self):
-		output = self.do_next_state()
-		# does the next stage of a dance
-		if self.zero:
-			output = string.replace(output, "0", self.zero)
-		if self.one:
-			output = string.replace(output, "1", self.one)
-		if self.reorder:
-			global orderings
-			newoutput = ""
-			for i in range(0,8):
-				newoutput += output[orderings[self.reorder][i]]
-			output = newoutput
-		self.v.display(" %8.8s " % (output))
-		self.i = (self.i + 1) % self.size
-
-	def do_next_state(self):
-		self.grayCode = self.i ^ (self.i >> 1)
-		output = self.dec2bin(self.grayCode)
-
-		return "0"*(self.bits-len(output))+output
-
-
-	def dec2bin(self,num):
-	    """Convert long/integer number to binary string.
-
-	    E.g. dec2bin(12) ==> '1100'.
-	    
-	    from http://starship.python.net/~gherman/playground/decbingray/decbingray.py"""
-
-	    assert num >= 0, "Decimal number must be >= 0!"
-
-	    # Gracefully handle degenerate case.
-	    # (Not really needed, but anyway.)    
-	    if num == 0:
-		return '0'
-
-	    # Find highest value bit.
-	    val, j = 1L, 1L
-	    while val < num:
-		val, j = val*2L, j+1L
-
-	    # Convert.
-	    bin = '' 
-	    i = j - 1
-	    while i + 1L:
-		k = pow(2L, i)
-		if num >= k:
-		    bin = bin + '1'
-		    num = num - k
-		else:
-		    if len(bin) > 0:
-			bin = bin + '0'
-		i = i - 1L
-
-	    return bin
-
-	def reset(self):
-		self.i = 0
-		self.grayCode = 0
-		if self.reorder:
-			self.reorder = int(random()*40319)+1
+    def __init__(self, v, one=None, zero=None, reorder=0):
+        Idler.__init__(self, v)
+        self.bits = 8
+        self.size = 1 << self.bits
+        self.i = 0
+        self.grayCode = 0
+        self.one = one
+        self.zero = zero
+        self.reorder = reorder
+        global orderings
+        if not orderings:
+            orderings = OrderMaker()
+
+    def __next__(self):
+        output = self.do_next_state()
+        # does the next stage of a dance
+        if self.zero:
+            output = string.replace(output, "0", self.zero)
+        if self.one:
+            output = string.replace(output, "1", self.one)
+        if self.reorder:
+            global orderings
+            newoutput = ""
+            for i in range(0,8):
+                newoutput += output[orderings[self.reorder][i]]
+            output = newoutput
+        self.v.display(" %8.8s " % (output))
+        self.i = (self.i + 1) % self.size
+
+    def do_next_state(self):
+        self.grayCode = self.i ^ (self.i >> 1)
+        output = self.dec2bin(self.grayCode)
+
+        return "0"*(self.bits-len(output))+output
+
+
+    def dec2bin(self,num):
+        """Convert long/integer number to binary string.
+
+        E.g. dec2bin(12) ==> '1100'.
+        
+        from http://starship.python.net/~gherman/playground/decbingray/decbingray.py"""
+
+        assert num >= 0, "Decimal number must be >= 0!"
+
+        # Gracefully handle degenerate case.
+        # (Not really needed, but anyway.)    
+        if num == 0:
+            return '0'
+
+        # Find highest value bit.
+        val, j = 1, 1
+        while val < num:
+            val, j = val*2, j+1
+
+        # Convert.
+        bin = '' 
+        i = j - 1
+        while i + 1:
+            k = pow(2, i)
+            if num >= k:
+                bin = bin + '1'
+                num = num - k
+            else:
+                if len(bin) > 0:
+                    bin = bin + '0'
+            i = i - 1
+
+        return bin
+
+    def reset(self):
+        self.i = 0
+        self.grayCode = 0
+        if self.reorder:
+            self.reorder = int(random()*40319)+1
 
 
 class StringIdler(Idler):
-	def __init__(self, v, text="Hello Cruel World!  ",repeat=True, affinity=None):
-		Idler.__init__(self, v, affinity=affinity)
-		self.mk = MessageKeeper(v)
-		self.text = "         " + self.clean_text(text) + "          "
-		
-		msg = [("",False, None),(self.text, repeat, IDLER_TEXT_SPEED)]
-		self.mk.set_messages(msg)
-
-	def clean_text(self, text):
-		# nothing like a bit of good clean text :)
-		valid = string.digits \
-			+ string.letters \
-			+ string.punctuation \
-			+ " "
-		# uppercase it
-		text = string.upper(text)
-		clean = ""
-		for char in text:
-			if char in valid:
-				clean = clean + char
-			else:
-				clean = clean + " "
-		return clean
-
-	def next(self):
-		self.mk.update_display()
-
-	def finished(self):	
-		return self.mk.done()
+    def __init__(self, v, text="Hello Cruel World!  ",repeat=True, affinity=None):
+        Idler.__init__(self, v, affinity=affinity)
+        self.mk = MessageKeeper(v)
+        self.text = "         " + self.clean_text(text) + "          "
+        
+        msg = [("",False, None),(self.text, repeat, IDLER_TEXT_SPEED)]
+        self.mk.set_messages(msg)
+
+    def clean_text(self, text):
+        # nothing like a bit of good clean text :)
+        valid = string.digits \
+            + string.letters \
+            + string.punctuation \
+            + " "
+        # uppercase it
+        text = string.upper(text)
+        clean = ""
+        for char in text:
+            if char in valid:
+                clean = clean + char
+            else:
+                clean = clean + " "
+        return clean
+
+    def __next__(self):
+        self.mk.update_display()
+
+    def finished(self): 
+        return self.mk.done()
 
 class ClockIdler(Idler):
-	def __init__(self, v):
-		affinity = 3 
-		Idler.__init__(self, v, affinity = affinity)
-		self.last = None
-
-	def next(self):
-		colonchar = ':'
-		if int(time.time()*2) & 1: colonchar = ' '
-		output = time.strftime("%%H%c%%M%c%%S"%(colonchar,colonchar))
-		if output != self.last:
-			self.v.display(" %8.8s " % (output))
-			self.last = output
+    def __init__(self, v):
+        affinity = 3 
+        Idler.__init__(self, v, affinity = affinity)
+        self.last = None
+
+    def __next__(self):
+        colonchar = ':'
+        if int(time.time()*2) & 1: colonchar = ' '
+        output = time.strftime("%%H%c%%M%c%%S"%(colonchar,colonchar))
+        if output != self.last:
+            self.v.display(" %8.8s " % (output))
+            self.last = output
 
 class FortuneIdler(StringIdler):
-	def __init__(self, v, affinity = 30):
-		fortune = "/usr/games/fortune"
-		text = "I broke my wookie...."
-		if os.access(fortune,os.F_OK|os.X_OK):
-			(lines, unused) = Popen((fortune,), close_fds=True, stdout=PIPE).communicate()
-			text = lines.replace('\n', '  ').replace('\r', '')
-		StringIdler.__init__(self, v, text,repeat=False, affinity=affinity)
+    def __init__(self, v, affinity = 30):
+        fortune = "/usr/games/fortune"
+        text = "I broke my wookie...."
+        if os.access(fortune,os.F_OK|os.X_OK):
+            (lines, unused) = Popen((fortune,), close_fds=True, stdout=PIPE).communicate()
+            text = lines.replace('\n', '  ').replace('\r', '')
+        StringIdler.__init__(self, v, text,repeat=False, affinity=affinity)
 
-	def reset(self):
-		self.__init__(self.v, affinity=self._affinity)
+    def reset(self):
+        self.__init__(self.v, affinity=self._affinity)
 
 
 class PipeIdler(StringIdler):
-	def __init__(self, v, command, args, affinity = 5):
-		text = "I ate my cookie...."
-		if os.access(command,os.F_OK|os.X_OK):
-			(lines, unused) = Popen([command,] + args.split(), close_fds=True, stdout=PIPE).communicate()
-			text = lines.replace('\n', '  ').replace('\r', '')
-		StringIdler.__init__(self, v, text,repeat=False, affinity=affinity)
+    def __init__(self, v, command, args, affinity = 5):
+        text = "I ate my cookie...."
+        if os.access(command,os.F_OK|os.X_OK):
+            (lines, unused) = Popen([command,] + args.split(), close_fds=True, stdout=PIPE).communicate()
+            text = lines.replace('\n', '  ').replace('\r', '')
+        StringIdler.__init__(self, v, text,repeat=False, affinity=affinity)
 
 class FileIdler(StringIdler):
-	def __init__(self, v, thefile=None, repeat=False, affinity=8):
-		text = "I broke my wookie...."
-
-		if file and os.access(thefile,os.F_OK|os.R_OK):
-			f = file(thefile,'r')
-			text = string.join(f.readlines())
-			f.close()
-		StringIdler.__init__(self, v, text,repeat=False, affinity=affinity)
+    def __init__(self, v, thefile=None, repeat=False, affinity=8):
+        text = "I broke my wookie...."
+
+        if os.access(thefile,os.F_OK|os.R_OK):
+            f = open(thefile,'r')
+            text = string.join(f.readlines())
+            f.close()
+        StringIdler.__init__(self, v, text,repeat=False, affinity=affinity)
diff --git a/VendServer/LDAPConnector.py b/VendServer/LDAPConnector.py
index 8699fd2ba6f536d39efd434ca534c685bdad87e7..48050bfd7641db7d48f4d43c7ba167bfb2a7b791 100644
--- a/VendServer/LDAPConnector.py
+++ b/VendServer/LDAPConnector.py
@@ -32,7 +32,7 @@ def get_uid(card_id):
         ldapconn.unbind()
         
         if len(results) != 1:
-                raise ValueError, "no UID found for card ID"
+                raise ValueError("no UID found for card ID")
         
         return results[0][1]['uidNumber'][0]
 
@@ -48,15 +48,15 @@ def get_uname(uid):
         ldapconn.unbind()
         
         if len(results) != 1:
-                raise ValueError, "no username found for user id"
+                raise ValueError("no username found for user id")
         
         return results[0][1]['uid'][0]
 
 def set_card_id(uidNumber, card_id):
         ldapconn = get_ldap_connection()
         
-	# fix uidNumber for three/four digit uids
-	uidNumber = str(int(uidNumber))
+        # fix uidNumber for three/four digit uids
+        uidNumber = str(int(uidNumber))
         basedn = 'ou=People,dc=ucc,dc=gu,dc=uwa,dc=edu,dc=au'
         filter = ldap.filter.filter_format('(uidNumber=%s)', (uidNumber, ))
         attrs = ('objectClass', )
@@ -64,7 +64,7 @@ def set_card_id(uidNumber, card_id):
         results = ldapconn.search_st(basedn, ldap.SCOPE_SUBTREE, filter, attrs, timeout=LDAP_TIMEOUT)
         
         if len(results) != 1:
-                raise "ValueError", 'error in uidNumber'
+                raise ValueError('error in uidNumber')
         
         user_dn = results[0][0]
         
@@ -82,11 +82,11 @@ def set_card_id(uidNumber, card_id):
         try:
             try:
                 ldapconn.modify_s(user_dn, mod_attrs)
-            except ldap.TYPE_OR_VALUE_EXISTS, e:
+            except ldap.TYPE_OR_VALUE_EXISTS as e:
                 pass
         finally:
             ldapconn.unbind()
 
 if __name__ == '__main__':
         set_card_id('11126', '\x01\x02\x03\x04\x05\x06')
-        print get_uid('\x01\x02\x03\x04\x05\x06')
+        print(get_uid('\x01\x02\x03\x04\x05\x06'))
diff --git a/VendServer/MIFAREClient.py b/VendServer/MIFAREClient.py
index e0b6a6c83eed31f73bdbc6b1194b60adac73baee..96e19434f90264d921bece4d2f9e424ab55d5d01 100644
--- a/VendServer/MIFAREClient.py
+++ b/VendServer/MIFAREClient.py
@@ -1,44 +1,44 @@
-from MIFAREDriver import MIFAREReader, MIFAREException
-from serial import Serial
-from LDAPConnector import get_uid, set_card_id
-
-class MIFAREClient:
-    def __init__(self):
-        self.port = Serial('/dev/ttyS2', baudrate = 19200)
-        self.reader = MIFAREReader(self.port)
-        self.reader.set_led(red = False, green = True)
-        self.reader.beep(100)
-    
-    def get_card_id(self):
-        self.reader.set_led(red = True, green = False)
-        try:
-            card_id, capacity = self.reader.select_card()
-        except MIFAREException:
-            self.reader.set_led(red = False, green = True)
-            return None
-        else:
-            self.reader.set_led(red = False, green = True)
-            self.reader.beep(100)
-            return card_id
-    
-    def get_card_uid(self):
-		card_id = self.get_card_id()
-		if card_id == None:
-			return None
-		else:
-			return get_uid(card_id)
-    
-    def add_card(self, uid):
-        self.reader.set_led(red = True, green = False)
-        for attempt in range(5):
-            self.reader.beep(50)
-            try:
-                card_id, capacity = self.reader.select_card()
-            except MIFAREException:
-                pass
-            else:
-                set_card_id(uid, card_id)
-                self.reader.set_led(red = False, green = True)
-                return True
-        self.reader.set_led(red = False, green = True)
-        return False
+from .MIFAREDriver import MIFAREReader, MIFAREException
+from serial import Serial
+from .LDAPConnector import get_uid, set_card_id
+
+class MIFAREClient:
+    def __init__(self):
+        self.port = Serial('/dev/ttyS2', baudrate = 19200)
+        self.reader = MIFAREReader(self.port)
+        self.reader.set_led(red = False, green = True)
+        self.reader.beep(100)
+    
+    def get_card_id(self):
+        self.reader.set_led(red = True, green = False)
+        try:
+            card_id, capacity = self.reader.select_card()
+        except MIFAREException:
+            self.reader.set_led(red = False, green = True)
+            return None
+        else:
+            self.reader.set_led(red = False, green = True)
+            self.reader.beep(100)
+            return card_id
+    
+    def get_card_uid(self):
+        card_id = self.get_card_id()
+        if card_id == None:
+            return None
+        else:
+            return get_uid(card_id)
+    
+    def add_card(self, uid):
+        self.reader.set_led(red = True, green = False)
+        for attempt in range(5):
+            self.reader.beep(50)
+            try:
+                card_id, capacity = self.reader.select_card()
+            except MIFAREException:
+                pass
+            else:
+                set_card_id(uid, card_id)
+                self.reader.set_led(red = False, green = True)
+                return True
+        self.reader.set_led(red = False, green = True)
+        return False
diff --git a/VendServer/MIFAREDriver.py b/VendServer/MIFAREDriver.py
index a52a89115883b8d18f6574f805625ee3d8515995..5961383da7647bc7ce674f5d9a11affedba3d304 100644
--- a/VendServer/MIFAREDriver.py
+++ b/VendServer/MIFAREDriver.py
@@ -8,6 +8,7 @@ Licensed under an MIT-style license: see LICENSE file for details.
 '''
 
 import serial, logging
+from functools import reduce
 
 xor = lambda x, y: x ^ y
 def checksum(string):
@@ -70,7 +71,7 @@ class MIFAREReader:
                 # Strip off separator and address header
                 return data[3:]
             else:
-                raise MIFARECommunicationException, "Invalid response received"
+                raise MIFARECommunicationException("Invalid response received")
 
     def set_antenna(self, state = True):
         """Turn the card reader's antenna on or off (no return value)"""
@@ -79,7 +80,7 @@ class MIFAREReader:
         if response == '\x0c\x01\x00':
             return None
         else:
-            raise MIFAREException, 'command failed: set_antenna (%s)' % state
+            raise MIFAREException('command failed: set_antenna (%s)' % state)
 
     def select_card(self, include_halted = False):
         """Selects a card and returns a tuple of  (serial number, capacity).
@@ -97,7 +98,7 @@ class MIFAREReader:
         card_type_response = self.send_packet(command)
 
         if card_type_response == None or card_type_response[2] == '\x14':
-            raise MIFAREException, "select_card: no card available"
+            raise MIFAREException("select_card: no card available")
         card_type = card_type_response[3:5]
 
         if card_type == '\x44\x00': # MIFARE UltraLight
@@ -132,7 +133,7 @@ class MIFAREReader:
         sector = self.get_absolute_block((blockvect[0], 0))
 
         if len(key) != 6:
-            raise ValueError, 'key must be a six-byte string'
+            raise ValueError('key must be a six-byte string')
 
         keytype = 96 + keytype
 
@@ -140,7 +141,7 @@ class MIFAREReader:
 
         result = self.send_packet('\x07\x02' + data)
         if ord(result[2]) == 22:
-            raise MIFAREAuthenticationException, "incorrect key provided"
+            raise MIFAREAuthenticationException("incorrect key provided")
 
         return
 
@@ -155,7 +156,7 @@ class MIFAREReader:
         """Write the 16 bytes in data to the block at vector (sector, block)."""
         block = self.get_absolute_block(blockvect)
         if len(data) != 16:
-            raise ValueError, "invalid data length - must be 16 bytes"
+            raise ValueError("invalid data length - must be 16 bytes")
 
         result = self.send_packet('\x09\x02' + chr(block) + data)
         return
diff --git a/VendServer/MessageKeeper.py b/VendServer/MessageKeeper.py
index 60d2b9e2b331bee93bffe25f0edecedf3ddddb97..f14e05ac08f1c3cd51cba6a0c684ed80007c559a 100755
--- a/VendServer/MessageKeeper.py
+++ b/VendServer/MessageKeeper.py
@@ -2,7 +2,7 @@
 # vim:ts=4
 
 import sys, os, string, re, pwd, signal
-from HorizScroll import HorizScroll
+from .HorizScroll import HorizScroll
 from random import random, seed
 from time import time, sleep
 
diff --git a/VendServer/OpenDispense.py b/VendServer/OpenDispense.py
index 6b93058b19e0dac3bf1b9a921f8e5229ed736f05..63f85afa087f9ff49e54839748070f8b74f56021 100644
--- a/VendServer/OpenDispense.py
+++ b/VendServer/OpenDispense.py
@@ -7,7 +7,7 @@ This is so VendServer can easily operate regardless of the current accounting ba
 Documentation for this code can be found inder Dispence.DispenceInterface
 """
 
-from DispenseInterface import DispenseInterface
+from .DispenseInterface import DispenseInterface
 import os
 import logging
 import re
@@ -15,7 +15,7 @@ import pwd
 import base64
 import socket
 from subprocess import Popen, PIPE
-from LDAPConnector import get_uid,get_uname, set_card_id
+from .LDAPConnector import get_uid,get_uname, set_card_id
 
 DISPENSE_ENDPOINT = ("localhost", 11020)
 DISPSRV_MIFARE = True
@@ -88,11 +88,11 @@ class OpenDispense(DispenseInterface):
 		except OSError:
 			logging.info('getting pin for uid %d: .pin not found in home directory'%userId)
 			return False
-		if s.st_mode & 077:
+		if s.st_mode & 0o77:
 			logging.info('getting pin for uid %d: .pin has wrong permissions. Fixing.'%userId)
-			os.chmod(pinfile, 0600)
+			os.chmod(pinfile, 0o600)
 		try:
-			f = file(pinfile)
+			f = open(pinfile)
 		except IOError:
 			logging.info('getting pin for uid %d: I cannot read pin file'%userId)
 			return False
@@ -167,11 +167,11 @@ class OpenDispense(DispenseInterface):
 		self._disabled = False
 		return True
 
-        def logOut(self):
-            self._loggedIn = False
-            self._disabled = False
-            self._userId = None
-            self._username = None
+	def logOut(self):
+		self._loggedIn = False
+		self._disabled = False
+		self._userId = None
+		self._username = None
 
 	def addCard(self, cardId):
 		if not self.isLoggedIn():
@@ -239,7 +239,7 @@ class OpenDispense(DispenseInterface):
 		if not self.isLoggedIn() or self.getItemInfo(itemId)[0] == "dead":
 			return False
 		else:
-			print('dispense -u "%s" %s'%(self._username, itemId))
+			print(('dispense -u "%s" %s'%(self._username, itemId)))
 			#os.system('dispense -u "%s" %s'%(self._username, itemId))
 			return True
 
diff --git a/VendServer/SerialClient.py b/VendServer/SerialClient.py
index e0a9a7e965e95fcd0b86c2eb24917b8a8f49c1e8..3880cb0d41363e8292453ecc2826552c37266d95 100644
--- a/VendServer/SerialClient.py
+++ b/VendServer/SerialClient.py
@@ -36,6 +36,6 @@ if __name__ == '__main__':
 	(rfh, wfh) = s.get_fh()
 
 	wfh.write('B\n')
-	print rfh.read()
+	print(rfh.read())
 
 
diff --git a/VendServer/SnackConfig.py b/VendServer/SnackConfig.py
index 231407480171c5078e55d3aaedc1e361e9a24bb5..560f95f93aa83401e9e5ec2482b71335ee7002bf 100755
--- a/VendServer/SnackConfig.py
+++ b/VendServer/SnackConfig.py
@@ -22,25 +22,25 @@ def get_snack( slot ):
 		val = ( int(m.group(1))*100 + int(m.group(2)), m.group(3), m.group(3) )
 #		print 'Price: %i, Name: %s' % (val[0], val[1])
 	except BaseException as e:
-		print "BaseException"
-		print e
+		print("BaseException")
+		print(e)
 		val = (0, 'error', 'Error')
 	except:
-		print "Unknown exception"
+		print("Unknown exception")
 		val = (0, 'error', 'Error')
 	return val
 
 def get_price( slot ):
-		p, sn, n = get_snacks( slot )
+		p, sn, n = get_snack( slot )
 		return p
 
 def get_name( slot ):
-		p, sn, n = get_snacks( slot )
+		p, sn, n = get_snack( slot )
 		return n
 
 def get_short_name( slot ):
-		p, sn, n = get_snacks( slot )
+		p, sn, n = get_snack( slot )
 		return sn
 
 if __name__ == '__main__':
-	print "Don't run this"
+	print("Don't run this")
diff --git a/VendServer/VendServer.py b/VendServer/VendServer.py
index cf9c8bbdbb689476b1c8fe584a16049691175b2f..dda160bc3c7c59220ca697edb835dfbedbb92259 100755
--- a/VendServer/VendServer.py
+++ b/VendServer/VendServer.py
@@ -3,23 +3,23 @@
 
 USE_MIFARE = 1
 
-import ConfigParser
+import configparser
 import sys, os, string, re, pwd, signal, math, syslog
 import logging, logging.handlers
 from traceback import format_tb
 from time import time, sleep, mktime, localtime
 from subprocess import Popen, PIPE
-from LATClient import LATClient, LATClientException
-from SerialClient import SerialClient, SerialClientException
-from VendingMachine import VendingMachine, VendingException
-from MessageKeeper import MessageKeeper
-from HorizScroll import HorizScroll
+from .LATClient import LATClient, LATClientException
+from .SerialClient import SerialClient, SerialClientException
+from .VendingMachine import VendingMachine, VendingException
+from .MessageKeeper import MessageKeeper
+from .HorizScroll import HorizScroll
 from random import random, seed
-from Idler import GreetingIdler,TrainIdler,GrayIdler,StringIdler,ClockIdler,FortuneIdler,FileIdler,PipeIdler
-from SnackConfig import get_snack#, get_snacks
+from .Idler import GreetingIdler,TrainIdler,GrayIdler,StringIdler,ClockIdler,FortuneIdler,FileIdler,PipeIdler
+from .SnackConfig import get_snack#, get_snacks
 import socket
 from posix import geteuid
-from OpenDispense import OpenDispense as Dispense
+from .OpenDispense import OpenDispense as Dispense
 import TracebackPrinter
 
 CREDITS="""
@@ -59,7 +59,7 @@ STATE_GETTING_UID,
 STATE_GETTING_PIN,
 STATE_GET_SELECTION,
 STATE_GRANDFATHER_CLOCK,
-) = range(1,8)
+) = list(range(1,8))
 
 TEXT_SPEED = 0.8
 IDLE_SPEED = 0.05
@@ -82,7 +82,7 @@ config_options = {
 class VendConfigFile:
 	def __init__(self, config_file, options):
 		try:
-			cp = ConfigParser.ConfigParser()
+			cp = configparser.ConfigParser()
 			cp.read(config_file)
 
 			for option in options:
@@ -90,7 +90,7 @@ class VendConfigFile:
 				value = cp.get(section, name)
 				self.__dict__[option] = value
 		
-		except ConfigParser.Error, e:
+		except configparser.Error as e:
 			raise SystemExit("Error reading config file "+config_file+": " + str(e))
 
 """
@@ -176,7 +176,7 @@ class VendServer():
 		messages = ['  WASSUP! ', 'PINK FISH ', ' SECRETS ', '  ESKIMO  ', ' FORTUNES ', 'MORE MONEY']
 		choice = int(random()*len(messages))
 		msg = messages[choice]
-		left = range(len(msg))
+		left = list(range(len(msg)))
 		for i in range(len(msg)):
 			if msg[i] == ' ': left.remove(i)
 		reveal = 1
@@ -244,7 +244,7 @@ class VendServer():
 	"""
 	def reset_idler(self, t = None):
 		self.idler = GreetingIdler(self.v, t)
-		self.vstatus.time_of_next_idlestep = time()+self.idler.next()
+		self.vstatus.time_of_next_idlestep = time()+next(self.idler)
 		self.vstatus.time_of_next_idler = None
 		self.vstatus.time_to_autologout = None
 		self.vstatus.change_state(STATE_IDLE, 1)
@@ -287,7 +287,7 @@ class VendServer():
 		if self.idler.finished():
 			self.choose_idler()
 			self.vstatus.time_of_next_idler = time() + 30
-		nextidle = self.idler.next()
+		nextidle = next(self.idler)
 		if nextidle is None:
 			nextidle = IDLE_SPEED
 		self.vstatus.time_of_next_idlestep = time()+nextidle
@@ -307,7 +307,7 @@ class VendServer():
 	Don't do anything for this event.
 	"""
 	def do_nothing(self, event, params):
-		print "doing nothing (s,e,p)", state, " ", event, " ", params
+		print("doing nothing (s,e,p)", self.state, " ", event, " ", params)
 		pass
 
 	"""
@@ -451,7 +451,7 @@ class VendServer():
 					self.v.display('THANK YOU')
 					syslog.syslog(syslog.LOG_INFO | syslog.LOG_LOCAL4, "vended %s (slot %s) for %s" % (name, self.vstatus.cur_selection, self.vstatus.username))
 				else:
-					print "Vend Failed:", code, string
+					print("Vend Failed:", code, string)
 					syslog.syslog(syslog.LOG_WARNING | syslog.LOG_LOCAL4, "vending %s (slot %s) for %s FAILED %r %r" % (name, self.vstatus.cur_selection, self.vstatus.username, code, string))
 					self.v.display('VEND FAIL')
 			elif (exitcode == 5):	# RV_BALANCE
@@ -964,7 +964,7 @@ def parse_args():
 	op.add_option('-v', '--verbose', dest='verbose', action='store_true', default=False, help='spit out lots of debug output')
 	op.add_option('-q', '--quiet', dest='quiet', action='store_true', default=False, help='only report errors')
 	op.add_option('--pid-file', dest='pid_file', metavar='FILE', default='', help='store daemon\'s pid in the given file')
-        op.add_option('--traceback-file', dest='traceback_file', default='', help='destination to print tracebacks when receiving SIGUSR1')
+	op.add_option('--traceback-file', dest='traceback_file', default='', help='destination to print tracebacks when receiving SIGUSR1')
 	options, args = op.parse_args()
 
 	if len(args) != 0:
@@ -974,10 +974,10 @@ def parse_args():
 
 def create_pid_file(name):
 	try:
-		pid_file = file(name, 'w')
+		pid_file = open(name, 'w')
 		pid_file.write('%d\n'%os.getpid())
 		pid_file.close()
-	except IOError, e:
+	except IOError as e:
 		logging.warning('unable to write to pid file '+name+': '+str(e))
 
 def set_stuff_up():
@@ -1016,7 +1016,7 @@ def set_up_logging(options):
 			file_logger = logging.FileHandler(options.log_file)
 			file_logger.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s'))
 			logger.addHandler(file_logger)
-		except IOError, e:
+		except IOError as e:
 			logger.warning('unable to write to log file '+options.log_file+': '+str(e))
 
 	if options.syslog != None:
@@ -1032,7 +1032,7 @@ def set_up_logging(options):
 		logger.setLevel(logging.INFO)
 
 def become_daemon():
-	dev_null = file('/dev/null')
+	dev_null = open('/dev/null')
 	fd = dev_null.fileno()
 	os.dup2(fd, 0)
 	os.dup2(fd, 1)
@@ -1041,14 +1041,14 @@ def become_daemon():
 		if os.fork() != 0:
 			sys.exit(0)
 		os.setsid()
-	except OSError, e:
+	except OSError as e:
 		raise SystemExit('failed to fork: '+str(e))
 
 def do_vend_server(options, config_opts):
 	while True:
 		try:
 			rfh, wfh = connect_to_vend(options, config_opts)
-		except (SerialClientException, socket.error), e:
+		except (SerialClientException, socket.error) as e:
 			(exc_type, exc_value, exc_traceback) = sys.exc_info()
 			del exc_traceback
 			logging.error("Connection error: "+str(exc_type)+" "+str(e))
diff --git a/VendServer/VendingMachine.py b/VendServer/VendingMachine.py
index 72cec3dce2c63ba5be54f2a0f880a7507fa4f2c7..86a1342db1a3bf92b4b5ec4135e96d4fe9330911 100644
--- a/VendServer/VendingMachine.py
+++ b/VendServer/VendingMachine.py
@@ -1,10 +1,10 @@
 # vim:ts=4
 import re
-from CRC import do_crc
+from .CRC import do_crc
 from select import select
 import socket, logging
 from time import time, sleep
-from MIFAREClient import MIFAREClient
+from .MIFAREClient import MIFAREClient
 
 asynchronous_responses = [	'400', '401', # door open/closed
 				'610',        # switches changed
@@ -72,7 +72,7 @@ class VendingMachine:
 					self.challenge = int(prefix, 16)
 					return
 
-	def get_response(self, async = False):
+	def get_response(self, is_async = False):
 		self.wfh.flush()
 		while True:
 			s = ''
@@ -85,7 +85,7 @@ class VendingMachine:
 			text = s[4:]
 			if code in asynchronous_responses:
 				self.handle_event(code, text)
-				if async: return None
+				if is_async: return None
 			else:
 				self.await_prompt()
 				return (code, text)
@@ -116,13 +116,13 @@ class VendingMachine:
 			logging.warning('Unhandled event! (%s %s)\n'%(code,text))
 
 	def authed_message(self, message):
-		print 'self.challenge = %04x' % self.challenge
+		print('self.challenge = %04x' % self.challenge)
 		if self.challenge == None:
 			return message
 		crc = do_crc('%c%c'%(self.challenge >> 8, self.challenge & 0xff))
 		crc = do_crc(self.secret, crc)
 		crc = do_crc(message, crc)
-		print 'output = "%s|%04x"' % (message, crc)
+		print('output = "%s|%04x"' % (message, crc))
 		return message+'|'+('%04x'%crc)
 
 	def ping(self):
@@ -182,7 +182,7 @@ class VendingMachine:
 
 			(r, _, _) = select([self.rfh], [], [], this_timeout)
 			if r:
-				self.get_response(async = True)
+				self.get_response(is_async = True)
 				timeout = 0
 
 			if self.mifare: