Tried to fix borked permissions
authorjudge <[email protected]>
Sun, 19 May 2013 08:04:37 +0000 (16:04 +0800)
committerjudge <[email protected]>
Sun, 19 May 2013 08:04:37 +0000 (16:04 +0800)
30 files changed:
agents/bishop/bishop.py [changed mode: 0755->0644]
agents/bishop/data [deleted symlink]
agents/bishop/data/DejaVuSans.ttf [new file with mode: 0644]
agents/bishop/data/help.txt [new file with mode: 0644]
agents/bishop/qchess.py [changed from symlink to file mode: 0644]
agents/c++/agent++ [changed mode: 0755->0644]
agents/fortran/agent [changed mode: 0755->0644]
agents/java/cough [changed mode: 0755->0644]
agents/python/data [deleted symlink]
agents/python/data/DejaVuSans.ttf [new file with mode: 0644]
agents/python/data/help.txt [new file with mode: 0644]
agents/python/qchess.py [changed from symlink to file mode: 0644]
agents/python/sample.py [changed mode: 0755->0644]
agents/silverfish/silver [changed mode: 0755->0644]
clean.sh [changed mode: 0755->0644]
qchess/data/images/index.html [new file with mode: 0644]
qchess/qchess.py [changed mode: 0755->0644]
qchess/tools/images.py [changed from symlink to file mode: 0644]
qchess_login.sh [changed mode: 0755->0644]
run.sh [changed mode: 0755->0644]
web/images [new symlink]
web/logs/log [new file with mode: 0644]
web/logs/log_1 [new file with mode: 0644]
web/logs/log_2 [new file with mode: 0644]
web/logs/log_3 [new file with mode: 0644]
web/logs/log_4 [new file with mode: 0644]
web/poster [deleted symlink]
web/poster/original.pdf [new file with mode: 0644]
web/poster/outlines.svg [new file with mode: 0644]
web/poster/poster.svg [new file with mode: 0644]

old mode 100755 (executable)
new mode 100644 (file)
diff --git a/agents/bishop/data b/agents/bishop/data
deleted file mode 120000 (symlink)
index 75a080a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../../qchess/data/
\ No newline at end of file
diff --git a/agents/bishop/data/DejaVuSans.ttf b/agents/bishop/data/DejaVuSans.ttf
new file mode 100644 (file)
index 0000000..27cff47
Binary files /dev/null and b/agents/bishop/data/DejaVuSans.ttf differ
diff --git a/agents/bishop/data/help.txt b/agents/bishop/data/help.txt
new file mode 100644 (file)
index 0000000..8911f3b
--- /dev/null
@@ -0,0 +1,135 @@
+NAME
+       qchess.py - Play quantum chess
+
+SYNOPSIS
+       qchess.py [OPTIONS] [white] [black]
+
+DESCRIPTION
+       An implementation of Quantum Chess as originally described and implemented here:
+       http://research.cs.queensu.ca/Parallel/QuantumChess/QuantumChess.html
+
+       Reimplemented for UCC::Progcomp 2013
+       http://progcomp.ucc.asn.au
+
+       IMPORTANT:
+        - This version does not implement castling or en passen rules.
+        - If a piece currently in a pawn state moves into the opposing back row, that state always becomes a queen.
+           - (The other state of the piece is unaffected).
+
+
+ARGUMENTS
+
+       If no arguments are given, a window should appear asking you to pick each player.
+       Then the game will commence using default values.
+
+       white, black
+               Each of the two players in order. They need not be provided if graphics is enabled (default).
+               
+               Any arguments that do not begin with a hyphen (-) are treated as the player arguments in the order they appear.
+
+               Player arguments that begin with '@' are treated as special players:
+
+               @human
+                       A human player; if graphics are enabled, this players turns are made through the GUI
+
+               @network[:address]
+                       A player over a network connection. 
+
+                       For example, if black@host1 wants to play white@host2:
+
+                       black@host1:~$ ./qchess.py @network @human
+                       white@host2:~$ ./qchess.py @human @network:host1
+
+                       IMPORTANT: Only ONE of the games should give the other's address.
+
+               @internal:name
+                       An internal agent player
+
+                       These agents run within the qchess program (unless there is a timeout setting... never mind).
+                       
+                       Choices are:
+                       
+                       AgentRandom - Makes random moves only
+
+                       AgentBishop - Uses probability estimates and a min/max recursive (depth is only one) algorithm
+                                   - Will usually take a long time to run
+
+OPTIONS
+
+       --help
+               Print this page
+       
+       --graphics
+               Enable the GUI
+
+               If graphics are enabled (default), then the user will be prompted to choose any of the two players not supplied as arguments.
+
+       --no-graphics
+               Disable the GUI
+               
+               
+       --reveal
+               If graphics are enabled, the two states for pieces will always be shown, regardless of whether both states have been revealed.
+               Note that this switch only affects the GUI and does not provide any information to agent players.
+
+               If graphics are disabled, has no effect.
+
+       --file[=filename][:events]
+               Replay a game saved in file, or read from stdin if no filename given
+               If a number of events is supplied, the game will advance that many events before stopping.
+
+               If no players are given, the GUI will NOT ask for player selections.
+               The game will exit after the replay finishes. Events in the replay will be subject to the normal delay (see --delay).
+
+               If black and white players are supplied, the game will continue using those players.
+               In this case, there will be no delays between events in the replay (the game starts at the end of the replay)
+
+               (We hope that) this feature will be useful for comparing how different versions of an agent respond to the same situation.
+
+       --log[=filename]
+               Log moves to a file or stdout if no filename given
+
+               
+
+       --delay[=time]
+               The game pauses between moves so that it can be followed by a human observer.
+               This option can be used to change the delay. If no time is given, the delay is disabled.
+
+               If graphics are enabled (default), the delay is 0.5s by default.
+               If graphics are disabled, there is no delay unless this option is used.
+
+       --timeout[=time]
+               Set the maximum time in seconds to wait before declaring an AI program unresponsive.
+               If no time is given, the timeout is disabled.
+
+               By default the timeout is disabled.
+               
+       --blackout[=time]
+               Setting a blackout time will cause the display to become black if the mouse is not moved and no keys or buttons are pressed.
+               If no time is given, the blackout time is disabled.
+               
+               By default the blackout is disabled.
+               
+               This switch was introduced for entirely obscure purposes.
+
+       --classical
+               If this option is used, the game will treat pieces "classically", ie: as in standard chess.
+               Note that the game does not enforce rules related to check and checkmate.
+
+       --quantum
+               The game uses the quantum chess representation of pieces (default).
+
+       
+AUTHOR
+       Written for the UCC Programming Competition 2013 by Sam Moore.
+       UCC::Progcomp home page: http://progcomp.ucc.asn.au
+
+REPORTING BUGS
+       Report bugs to [email protected]
+       Join IRC channel #progcomp on irc://irc.ucc.asn.au
+
+COPYRIGHT
+       Copyright 2013 The University Computer Club, Inc.
+
+       Contact [email protected]
+
deleted file mode 120000 (symlink)
index 35c6d6e8a5edf5bdf5173254d57a1c5500b7b59b..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-../../qchess/qchess.py
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..8a3610bd9cfc1d3e4ba1af9565d070f9d645d6b8
--- /dev/null
+#!/usr/bin/python -u
+import random
+
+# I know using non-abreviated strings is inefficient, but this is python, who cares?
+# Oh, yeah, this stores the number of pieces of each type in a normal chess game
+piece_types = {"pawn" : 8, "bishop" : 2, "knight" : 2, "rook" : 2, "queen" : 1, "king" : 1, "unknown" : 0}
+
+# Class to represent a quantum chess piece
+class Piece():
+       def __init__(self, colour, x, y, types):
+               self.colour = colour # Colour (string) either "white" or "black"
+               self.x = x # x coordinate (0 - 8), none of this fancy 'a', 'b' shit here
+               self.y = y # y coordinate (0 - 8)
+               self.types = types # List of possible types the piece can be (should just be two)
+               self.current_type = "unknown" # Current type
+               self.choice = -1 # Index of the current type in self.types (-1 = unknown type)
+               
+               
+               self.last_state = None
+               
+               self.move_pattern = None
+               self.coverage = None
+               self.possible_moves = {}
+               
+
+       def init_from_copy(self, c):
+               self.colour = c.colour
+               self.x = c.x
+               self.y = c.y
+               self.types = c.types[:]
+               self.current_type = c.current_type
+               self.choice = c.choice
+               
+               self.last_state = None
+               self.move_pattern = None
+
+       
+
+       # Make a string for the piece (used for debug)
+       def __str__(self):
+               return str(self.colour) + " " + str(self.current_type) + " " + str(self.types) + " at " + str(self.x) + ","+str(self.y)  
+
+       # Draw the piece in a pygame surface
+       def draw(self, window, grid_sz = [80,80], style="quantum"):
+
+               # First draw the image corresponding to self.current_type
+               img = images[self.colour][self.current_type]
+               rect = img.get_rect()
+               if style == "classical":
+                       offset = [-rect.width/2, -rect.height/2]
+               else:
+                       offset = [-rect.width/2,-3*rect.height/4] 
+               window.blit(img, (self.x * grid_sz[0] + grid_sz[0]/2 + offset[0], self.y * grid_sz[1] + grid_sz[1]/2 + offset[1]))
+               
+               
+               if style == "classical":
+                       return
+
+               # Draw the two possible types underneath the current_type image
+               for i in range(len(self.types)):
+                       if always_reveal_states == True or self.types[i][0] != '?':
+                               if self.types[i][0] == '?':
+                                       img = small_images[self.colour][self.types[i][1:]]
+                               else:
+                                       img = small_images[self.colour][self.types[i]]
+                       else:
+                               img = small_images[self.colour]["unknown"] # If the type hasn't been revealed, show a placeholder
+
+                       
+                       rect = img.get_rect()
+                       offset = [-rect.width/2,-rect.height/2] 
+                       
+                       if i == 0:
+                               target = (self.x * grid_sz[0] + grid_sz[0]/5 + offset[0], self.y * grid_sz[1] + 3*grid_sz[1]/4 + offset[1])                             
+                       else:
+                               target = (self.x * grid_sz[0] + 4*grid_sz[0]/5 + offset[0], self.y * grid_sz[1] + 3*grid_sz[1]/4 + offset[1])                           
+                               
+                       window.blit(img, target) # Blit shit
+       
+       # Collapses the wave function!          
+       def select(self):
+               if self.current_type == "unknown" or not self.choice in [0,1]:
+                       self.choice = random.randint(0,1)
+                       if self.types[self.choice][0] == '?':
+                               self.types[self.choice] = self.types[self.choice][1:]
+                       self.current_type = self.types[self.choice]
+               return self.choice
+
+       # Uncollapses (?) the wave function!
+       def deselect(self):
+               #print "Deselect called"
+               if (self.x + self.y) % 2 != 0:
+                       if (self.types[0] != self.types[1]) or (self.types[0][0] == '?' or self.types[1][0] == '?'):
+                               self.current_type = "unknown"
+                               self.choice = -1
+                       else:
+                               self.choice = 0 # Both the two types are the same
+
+       # The sad moment when you realise that you do not understand anything about a subject you studied for 4 years...
+# --- piece.py --- #
+[w,h] = [8,8] # Width and height of board(s)
+
+always_reveal_states = False
+
+# Class to represent a quantum chess board
+class Board():
+       # Initialise; if master=True then the secondary piece types are assigned
+       #       Otherwise, they are left as unknown
+       #       So you can use this class in Agent programs, and fill in the types as they are revealed
+       def __init__(self, style="agent"):
+               self.style = style
+               self.pieces = {"white" : [], "black" : []}
+               self.grid = [[None] * w for _ in range(h)] # 2D List (you can get arrays in python, somehow, but they scare me)
+               self.unrevealed_types = {"white" : piece_types.copy(), "black" : piece_types.copy()}
+               self.king = {"white" : None, "black" : None} # We need to keep track of the king, because he is important
+               self.max_moves = None
+               self.moves = 0
+               self.move_stack = []
+               for c in ["black", "white"]:
+                       del self.unrevealed_types[c]["unknown"]
+
+               if style == "empty":
+                       return
+
+               # Add all the pieces with known primary types
+               for i in range(0, 2):
+                       
+                       s = ["black", "white"][i]
+                       c = self.pieces[s]
+                       y = [0, h-1][i]
+
+                       c.append(Piece(s, 0, y, ["rook"]))
+                       c.append(Piece(s, 1, y, ["knight"]))
+                       c.append(Piece(s, 2, y, ["bishop"]))
+                       k = Piece(s, 3, y, ["king", "king"]) # There can only be one ruler!
+                       k.current_type = "king"
+                       self.king[s] = k
+                       c.append(k)
+                       c.append(Piece(s, 4, y, ["queen"])) # Apparently he may have multiple wives though.
+                       c.append(Piece(s, 5, y, ["bishop"]))
+                       c.append(Piece(s, 6, y, ["knight"]))
+                       c.append(Piece(s, 7, y, ["rook"]))
+                       
+                       if y == 0: 
+                               y += 1 
+                       else: 
+                               y -= 1
+                       
+                       # Lots of pawn
+                       for x in range(0, w):
+                               c.append(Piece(s, x, y, ["pawn"]))
+
+                       types_left = {}
+                       types_left.update(piece_types)
+                       del types_left["king"] # We don't want one of these randomly appearing (although it might make things interesting...)
+                       del types_left["unknown"] # We certainly don't want these!
+                       for piece in c:
+                               # Add to grid
+                               self.grid[piece.x][piece.y] = piece 
+
+                               if len(piece.types) > 1:
+                                       continue                                
+                               if style == "agent": # Assign placeholder "unknown" secondary type
+                                       piece.types.append("unknown")
+                                       continue
+
+                               elif style == "quantum":
+                                       # The master allocates the secondary types
+                                       choice = types_left.keys()[random.randint(0, len(types_left.keys())-1)]
+                                       types_left[choice] -= 1
+                                       if types_left[choice] <= 0:
+                                               del types_left[choice]
+                                       piece.types.append('?' + choice)
+                               elif style == "classical":
+                                       piece.types.append(piece.types[0])
+                                       piece.current_type = piece.types[0]
+                                       piece.choice = 0
+
+       def clone(self):
+               newboard = Board(master = False)
+               newpieces = newboard.pieces["white"] + newboard.pieces["black"]
+               mypieces = self.pieces["white"] + self.pieces["black"]
+
+               for i in range(len(mypieces)):
+                       newpieces[i].init_from_copy(mypieces[i])
+       
+       # Reset the board from a string
+       def reset_board(self, s):
+               self.pieces = {"white" : [], "black" : []}
+               self.king = {"white" : None, "black" : None}
+               self.grid = [[None] * w for _ in range(h)]
+               for x in range(w):
+                       for y in range(h):
+                               self.grid[x][y] = None
+
+               for line in s.split("\n"):
+                       if line == "":
+                               continue
+                       if line[0] == "#":
+                               continue
+
+                       tokens = line.split(" ")
+                       [x, y] = map(int, tokens[len(tokens)-1].split(","))
+                       current_type = tokens[1]
+                       types = map(lambda e : e.strip(" '[],"), line.split('[')[1].split(']')[0].split(','))
+                       
+                       target = Piece(tokens[0], x, y, types)
+                       target.current_type = current_type
+                       
+                       try:
+                               target.choice = types.index(current_type)
+                       except:
+                               target.choice = -1
+
+                       self.pieces[tokens[0]].append(target)
+                       if target.current_type == "king":
+                               self.king[tokens[0]] = target
+
+                       self.grid[x][y] = target
+                       
+
+       def display_grid(self, window = None, grid_sz = [80,80]):
+               if window == None:
+                       return # I was considering implementing a text only display, then I thought "Fuck that"
+
+               # The indentation is getting seriously out of hand...
+               for x in range(0, w):
+                       for y in range(0, h):
+                               if (x + y) % 2 == 0:
+                                       c = pygame.Color(200,200,200)
+                               else:
+                                       c = pygame.Color(64,64,64)
+                               pygame.draw.rect(window, c, (x*grid_sz[0], y*grid_sz[1], (x+1)*grid_sz[0], (y+1)*grid_sz[1]))
+
+       def display_pieces(self, window = None, grid_sz = [80,80]):
+               if window == None:
+                       return
+               for p in self.pieces["white"] + self.pieces["black"]:
+                       p.draw(window, grid_sz, self.style)
+
+       # Draw the board in a pygame window
+       def display(self, window = None):
+               self.display_grid(window)
+               self.display_pieces(window)
+               
+
+               
+
+       def verify(self):
+               for x in range(w):
+                       for y in range(h):
+                               if self.grid[x][y] == None:
+                                       continue
+                               if (self.grid[x][y].x != x or self.grid[x][y].y != y):
+                                       raise Exception(sys.argv[0] + ": MISMATCH " + str(self.grid[x][y]) + " should be at " + str(x) + "," + str(y))
+
+       # Select a piece on the board (colour is the colour of whoever is doing the selecting)
+       def select(self, x,y, colour=None):
+               if not self.on_board(x, y): # Get on board everyone!
+                       raise Exception("BOUNDS " + str(x) + ","+str(y))
+
+               piece = self.grid[x][y]
+               if piece == None:
+                       raise Exception("EMPTY")
+
+               if colour != None and piece.colour != colour:
+                       raise Exception("COLOUR " + str(piece.colour) + " not " + str(colour))
+
+               # I'm not quite sure why I made this return a string, but screw logical design
+               return str(x) + " " + str(y) + " " + str(piece.select()) + " " + str(piece.current_type)
+
+
+       # Update the board when a piece has been selected
+       # "type" is apparently reserved, so I'll use "state"
+       def update_select(self, x, y, type_index, state, sanity=True, deselect=True):
+               #debug(str(self) + " update_select called")
+               piece = self.grid[x][y]
+               if piece.types[type_index] == "unknown":
+                       if not state in self.unrevealed_types[piece.colour].keys() and sanity == True:
+                               raise Exception("SANITY: Too many " + piece.colour + " " + state + "s")
+                       self.unrevealed_types[piece.colour][state] -= 1
+                       if self.unrevealed_types[piece.colour][state] <= 0:
+                               del self.unrevealed_types[piece.colour][state]
+
+               piece.types[type_index] = state
+               piece.current_type = state
+
+               if deselect == True and len(self.possible_moves(piece)) <= 0:
+                       piece.deselect() # Piece can't move; deselect it
+                       
+               # Piece needs to recalculate moves
+               piece.possible_moves = None
+               
+       # Update the board when a piece has been moved
+       def update_move(self, x, y, x2, y2, sanity=True):
+               #debug(str(self) + " update_move called \""+str(x)+ " " + str(y) + " -> " + str(x2) + " " + str(y2) + "\"")     
+               piece = self.grid[x][y]
+               #print "Moving " + str(x) + "," + str(y) + " to " + str(x2) + "," + str(y2) + "; possible_moves are " + str(self.possible_moves(piece))
+               
+               if not [x2,y2] in self.possible_moves(piece) and sanity == True:
+                       raise Exception("ILLEGAL move " + str(x2)+","+str(y2))
+               
+               self.grid[x][y] = None
+               taken = self.grid[x2][y2]
+               if taken != None:
+                       if taken.current_type == "king":
+                               self.king[taken.colour] = None
+                       self.pieces[taken.colour].remove(taken)
+               self.grid[x2][y2] = piece
+               piece.x = x2
+               piece.y = y2
+
+               # If the piece is a pawn, and it reaches the final row, it becomes a queen
+               # I know you are supposed to get a choice
+               # But that would be effort
+               if piece.current_type == "pawn" and ((piece.colour == "white" and piece.y == 0) or (piece.colour == "black" and piece.y == h-1)):
+                       if self.style == "classical":
+                               piece.types[0] = "queen"
+                               piece.types[1] = "queen"
+                       else:
+                               piece.types[piece.choice] = "queen"
+                       piece.current_type = "queen"
+
+               piece.deselect() # Uncollapse (?) the wavefunction!
+               self.moves += 1
+               
+               # All other pieces need to recalculate moves
+               for p in self.pieces["white"] + self.pieces["black"]:
+                       p.possible_moves = None
+               
+               #self.verify()  
+
+       # Update the board from a string
+       # Guesses what to do based on the format of the string
+       def update(self, result, sanity=True, deselect=True):
+               #debug(str(self) + " update called \""+str(result)+"\"")
+               # String always starts with 'x y'
+               try:
+                       s = result.split(" ")
+                       [x,y] = map(int, s[0:2])        
+               except:
+                       raise Exception("GIBBERISH \""+ str(result) + "\"") # Raise expectations
+
+               piece = self.grid[x][y]
+               if piece == None and sanity == True:
+                       raise Exception("EMPTY " + str(x) + " " + str(y))
+
+               # If a piece is being moved, the third token is '->'
+               # We could get away with just using four integers, but that wouldn't look as cool
+               if "->" in s:
+                       # Last two tokens are the destination
+                       try:
+                               [x2,y2] = map(int, s[3:])
+                       except:
+                               raise Exception("GIBBERISH \"" + str(result) + "\"") # Raise the alarm
+
+                       # Move the piece (take opponent if possible)
+                       self.update_move(x, y, x2, y2, sanity)
+                       
+               else:
+                       # Otherwise we will just assume a piece has been selected
+                       try:
+                               type_index = int(s[2]) # We need to know which of the two types the piece is in; that's the third token
+                               state = s[3] # The last token is a string identifying the type
+                       except:
+                               raise Exception("GIBBERISH \"" + result + "\"") # Throw a hissy fit
+
+
+                       # Select the piece
+                       self.update_select(x, y, type_index, state, sanity=sanity, deselect=deselect)
+
+               return result
+
+       # Gets each piece that could reach the given square and the probability that it could reach that square 
+       # Will include allied pieces that defend the attacker
+       def coverage(self, x, y, colour = None, reject_allied = True):
+               result = {}
+               
+               if colour == None:
+                       pieces = self.pieces["white"] + self.pieces["black"]
+               else:
+                       pieces = self.pieces[colour]
+
+               for p in pieces:
+                       prob = self.probability_grid(p, reject_allied)[x][y]
+                       if prob > 0:
+                               result.update({p : prob})
+               
+               #self.verify()
+               return result
+
+
+               
+
+
+       # Associates each square with a probability that the piece could move into it
+       # Look, I'm doing all the hard work for you here...
+       def probability_grid(self, p, reject_allied = True):
+               
+               result = [[0.0] * w for _ in range(h)]
+               if not isinstance(p, Piece):
+                       return result
+
+               if p.current_type != "unknown":
+                       #sys.stderr.write(sys.argv[0] + ": " + str(p) + " moves " + str(self.possible_moves(p, reject_allied)) + "\n")
+                       for point in self.possible_moves(p, reject_allied):
+                               result[point[0]][point[1]] = 1.0
+                       return result
+               
+               
+               for i in range(len(p.types)):
+                       t = p.types[i]
+                       prob = 1.0 / float(len(p.types))
+                       if t == "unknown" or p.types[i][0] == '?':
+                               total_types = 0
+                               for t2 in self.unrevealed_types[p.colour].keys():
+                                       total_types += self.unrevealed_types[p.colour][t2]
+                               
+                               for t2 in self.unrevealed_types[p.colour].keys():
+                                       prob2 = float(self.unrevealed_types[p.colour][t2]) / float(total_types)
+                                       #p.current_type = t2
+                                       for point in self.possible_moves(p, reject_allied, state=t2):
+                                               result[point[0]][point[1]] += prob2 * prob
+                               
+                       else:
+                               #p.current_type = t
+                               for point in self.possible_moves(p, reject_allied, state=t):
+                                               result[point[0]][point[1]] += prob
+               
+               #self.verify()
+               #p.current_type = "unknown"
+               return result
+
+       def prob_is_type(self, p, state):
+               prob = 0.5
+               result = 0
+               for i in range(len(p.types)):
+                       t = p.types[i]
+                       if t == state:
+                               result += prob
+                               continue        
+                       if t == "unknown" or p.types[i][0] == '?':
+                               total_prob = 0
+                               for t2 in self.unrevealed_types[p.colour].keys():
+                                       total_prob += self.unrevealed_types[p.colour][t2]
+                               for t2 in self.unrevealed_types[p.colour].keys():
+                                       if t2 == state:
+                                               result += prob * float(self.unrevealed_types[p.colour][t2]) / float(total_prob)
+                               
+
+
+       # Get all squares that the piece could move into
+       # This is probably inefficient, but I looked at some sample chess games and they seem to actually do things this way
+       # reject_allied indicates whether squares occupied by allied pieces will be removed
+       # (set to false to check for defense)
+       def possible_moves(self, p, reject_allied = True, state=None):
+               if p == None:
+                       raise Exception("SANITY: No piece")
+               
+               
+               
+               if state != None and state != p.current_type:
+                       old_type = p.current_type
+                       p.current_type = state
+                       result = self.possible_moves(p, reject_allied, state=None)
+                       p.current_type = old_type
+                       return result
+               
+               
+               
+               
+               result = []
+               
+
+               
+               if p.current_type == "unknown":
+                       raise Exception("SANITY: Unknown state for piece: "+str(p))
+                       # The below commented out code causes things to break badly
+                       #for t in p.types:
+                       #       if t == "unknown":
+                       #               continue
+                       #       p.current_type = t
+                       #       result += self.possible_moves(p)                                                
+                       #p.current_type = "unknown"
+                       #return result
+
+               if p.current_type == "king":
+                       result = [[p.x-1,p.y],[p.x+1,p.y],[p.x,p.y-1],[p.x,p.y+1], [p.x-1,p.y-1],[p.x-1,p.y+1],[p.x+1,p.y-1],[p.x+1,p.y+1]]
+               elif p.current_type == "queen":
+                       for d in [[-1,0],[1,0],[0,-1],[0,1],[-1,-1],[-1,1],[1,-1],[1,1]]:
+                               result += self.scan(p.x, p.y, d[0], d[1])
+               elif p.current_type == "bishop":
+                       for d in [[-1,-1],[-1,1],[1,-1],[1,1]]: # There's a reason why bishops move diagonally
+                               result += self.scan(p.x, p.y, d[0], d[1])
+               elif p.current_type == "rook":
+                       for d in [[-1,0],[1,0],[0,-1],[0,1]]:
+                               result += self.scan(p.x, p.y, d[0], d[1])
+               elif p.current_type == "knight":
+                       # I would use two lines, but I'm not sure how python likes that
+                       result = [[p.x-2, p.y-1], [p.x-2, p.y+1], [p.x+2, p.y-1], [p.x+2,p.y+1], [p.x-1,p.y-2], [p.x-1, p.y+2],[p.x+1,p.y-2],[p.x+1,p.y+2]]
+               elif p.current_type == "pawn":
+                       if p.colour == "white":
+                               
+                               # Pawn can't move forward into occupied square
+                               if self.on_board(p.x, p.y-1) and self.grid[p.x][p.y-1] == None:
+                                       result = [[p.x,p.y-1]]
+                               for f in [[p.x-1,p.y-1],[p.x+1,p.y-1]]:
+                                       if not self.on_board(f[0], f[1]):
+                                               continue
+                                       if self.grid[f[0]][f[1]] != None:  # Pawn can take diagonally
+                                               result.append(f)
+                               if p.y == h-2:
+                                       # Slightly embarrassing if the pawn jumps over someone on its first move...
+                                       if self.grid[p.x][p.y-1] == None and self.grid[p.x][p.y-2] == None:
+                                               result.append([p.x, p.y-2])
+                       else:
+                               # Vice versa for the black pawn
+                               if self.on_board(p.x, p.y+1) and self.grid[p.x][p.y+1] == None:
+                                       result = [[p.x,p.y+1]]
+
+                               for f in [[p.x-1,p.y+1],[p.x+1,p.y+1]]:
+                                       if not self.on_board(f[0], f[1]):
+                                               continue
+                                       if self.grid[f[0]][f[1]] != None:
+                                               #sys.stderr.write(sys.argv[0] + " : "+str(p) + " can take " + str(self.grid[f[0]][f[1]]) + "\n")
+                                               result.append(f)
+                               if p.y == 1:
+                                       if self.grid[p.x][p.y+1] == None and self.grid[p.x][p.y+2] == None:
+                                               result.append([p.x, p.y+2])
+
+                       #sys.stderr.write(sys.argv[0] + " : possible_moves for " + str(p) + " " + str(result) + "\n")
+
+               # Remove illegal moves
+               # Note: The result[:] creates a copy of result, so that the result.remove calls don't fuck things up
+               for point in result[:]: 
+
+                       if (point[0] < 0 or point[0] >= w) or (point[1] < 0 or point[1] >= h):
+                               result.remove(point) # Remove locations outside the board
+                               continue
+                       g = self.grid[point[0]][point[1]]
+                       
+                       if g != None and (g.colour == p.colour and reject_allied == True):
+                               result.remove(point) # Remove allied pieces
+               
+               #self.verify()
+               
+               p.possible_moves = result
+               return result
+
+
+       # Scans in a direction until it hits a piece, returns all squares in the line
+       # (includes the final square (which contains a piece), but not the original square)
+       def scan(self, x, y, vx, vy):
+               p = []
+                       
+               xx = x
+               yy = y
+               while True:
+                       xx += vx
+                       yy += vy
+                       if not self.on_board(xx, yy):
+                               break
+                       if not [xx,yy] in p:
+                               p.append([xx, yy])
+                       g = self.grid[xx][yy]
+                       if g != None:
+                               return p        
+                                       
+               return p
+
+       # Returns "white", "black" or "DRAW" if the game should end
+       def end_condition(self):
+               if self.king["white"] == None:
+                       if self.king["black"] == None:
+                               return "DRAW" # This shouldn't happen
+                       return "black"
+               elif self.king["black"] == None:
+                       return "white"
+               elif len(self.pieces["white"]) == 1 and len(self.pieces["black"]) == 1:
+                       return "DRAW"
+               elif self.max_moves != None and self.moves > self.max_moves:
+                       return "DRAW"
+               return None
+
+
+       # I typed the full statement about 30 times before writing this function...
+       def on_board(self, x, y):
+               return (x >= 0 and x < w) and (y >= 0 and y < h)
+       
+       # Pushes a move temporarily
+       def push_move(self, piece, x, y):
+               target = self.grid[x][y]
+               self.move_stack.append([piece, target, piece.x, piece.y, x, y])
+               [piece.x, piece.y] = [x, y]
+               self.grid[x][y] = piece
+               self.grid[piece.x][piece.y] = None
+               
+               for p in self.pieces["white"] + self.pieces["black"]:
+                       p.possible_moves = None
+               
+       # Restore move
+       def pop_move(self):
+               #print str(self.move_stack)
+               [piece, target, x1, y1, x2, y2] = self.move_stack[len(self.move_stack)-1]
+               self.move_stack = self.move_stack[:-1]
+               piece.x = x1
+               piece.y = y1
+               self.grid[x1][y1] = piece
+               if target != None:
+                       target.x = x2
+                       target.y = y2
+               self.grid[x2][y2] = target
+               
+               for p in self.pieces["white"] + self.pieces["black"]:
+                               p.possible_moves = None
+               
+# --- board.py --- #
+import subprocess
+import select
+import platform
+import re
+
+agent_timeout = -1.0 # Timeout in seconds for AI players to make moves
+                       # WARNING: Won't work for windows based operating systems
+
+if platform.system() == "Windows":
+       agent_timeout = -1 # Hence this
+
+# A player who can't play
+class Player():
+       def __init__(self, name, colour):
+               self.name = name
+               self.colour = colour
+
+       def update(self, result):
+               return result
+
+       def reset_board(self, s):
+               pass
+       
+       def __str__(self):
+               return self.name + "<"+str(self.colour)+">"
+
+       def base_player(self):
+               return self
+
+# Player that runs from another process
+class ExternalAgent(Player):
+
+
+       def __init__(self, name, colour):
+               Player.__init__(self, name, colour)
+               self.p = subprocess.Popen(name,bufsize=0,stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True,universal_newlines=True)
+               
+               self.send_message(colour)
+
+       def send_message(self, s):
+               if agent_timeout > 0.0:
+                       ready = select.select([], [self.p.stdin], [], agent_timeout)[1]
+               else:
+                       ready = [self.p.stdin]
+               if self.p.stdin in ready:
+                       #sys.stderr.write("Writing \'" + s + "\' to " + str(self.p) + "\n")
+                       try:
+                               self.p.stdin.write(s + "\n")
+                       except:
+                               raise Exception("UNRESPONSIVE")
+               else:
+                       raise Exception("TIMEOUT")
+
+       def get_response(self):
+               if agent_timeout > 0.0:
+                       ready = select.select([self.p.stdout], [], [], agent_timeout)[0]
+               else:
+                       ready = [self.p.stdout]
+               if self.p.stdout in ready:
+                       #sys.stderr.write("Reading from " + str(self.p) + " 's stdout...\n")
+                       try:
+                               result = self.p.stdout.readline().strip(" \t\r\n")
+                               #sys.stderr.write("Read \'" + result + "\' from " + str(self.p) + "\n")
+                               return result
+                       except: # Exception, e:
+                               raise Exception("UNRESPONSIVE")
+               else:
+                       raise Exception("TIMEOUT")
+
+       def select(self):
+
+               self.send_message("SELECTION?")
+               line = self.get_response()
+               
+               try:
+                       m = re.match("\s*(\d+)\s+(\d+)\s*", line)
+                       result = map(int, [m.group(1), m.group(2)])
+               except:
+                       raise Exception("GIBBERISH \"" + str(line) + "\"")
+               return result
+
+       def update(self, result):
+               #print "Update " + str(result) + " called for AgentPlayer"
+               self.send_message(result)
+               return result
+
+       def get_move(self):
+               
+               self.send_message("MOVE?")
+               line = self.get_response()
+               
+               try:
+                       m = re.match("\s*(\d+)\s+(\d+)\s*", line)
+                       result = map(int, [m.group(1), m.group(2)])
+
+               except:
+                       raise Exception("GIBBERISH \"" + str(line) + "\"")
+               return result
+
+       def reset_board(self, s):
+               self.send_message("BOARD")
+               for line in s.split("\n"):
+                       self.send_message(line.strip(" \r\n"))
+               self.send_message("END BOARD")
+
+       def quit(self, final_result):
+               try:
+                       self.send_message("QUIT " + final_result)
+               except:
+                       self.p.kill()
+
+# So you want to be a player here?
+class HumanPlayer(Player):
+       def __init__(self, name, colour):
+               Player.__init__(self, name, colour)
+               
+       # Select your preferred account
+       def select(self):
+               if isinstance(graphics, GraphicsThread):
+                       # Basically, we let the graphics thread do some shit and then return that information to the game thread
+                       graphics.cond.acquire()
+                       # We wait for the graphics thread to select a piece
+                       while graphics.stopped() == False and graphics.state["select"] == None:
+                               graphics.cond.wait() # The difference between humans and machines is that humans sleep
+                       select = graphics.state["select"]
+                       
+                       
+                       graphics.cond.release()
+                       if graphics.stopped():
+                               return [-1,-1]
+                       return [select.x, select.y]
+               else:
+                       # Since I don't display the board in this case, I'm not sure why I filled it in...
+                       while True:
+                               sys.stdout.write("SELECTION?\n")
+                               try:
+                                       p = map(int, sys.stdin.readline().strip("\r\n ").split(" "))
+                               except:
+                                       sys.stderr.write("ILLEGAL GIBBERISH\n")
+                                       continue
+       # It's your move captain
+       def get_move(self):
+               if isinstance(graphics, GraphicsThread):
+                       graphics.cond.acquire()
+                       while graphics.stopped() == False and graphics.state["dest"] == None:
+                               graphics.cond.wait()
+                       graphics.cond.release()
+                       
+                       return graphics.state["dest"]
+               else:
+
+                       while True:
+                               sys.stdout.write("MOVE?\n")
+                               try:
+                                       p = map(int, sys.stdin.readline().strip("\r\n ").split(" "))
+                               except:
+                                       sys.stderr.write("ILLEGAL GIBBERISH\n")
+                                       continue
+
+       # Are you sure you want to quit?
+       def quit(self, final_result):
+               if graphics == None:            
+                       sys.stdout.write("QUIT " + final_result + "\n")
+
+       # Completely useless function
+       def update(self, result):
+               if isinstance(graphics, GraphicsThread):
+                       pass
+               else:
+                       sys.stdout.write(result + "\n") 
+               return result
+
+
+# Default internal player (makes random moves)
+class InternalAgent(Player):
+       def __init__(self, name, colour):
+               Player.__init__(self, name, colour)
+               self.choice = None
+
+               self.board = Board(style = "agent")
+
+
+
+       def update(self, result):
+               
+               self.board.update(result)
+               #self.board.verify()
+               return result
+
+       def reset_board(self, s):
+               self.board.reset_board(s)
+
+       def quit(self, final_result):
+               pass
+
+class AgentRandom(InternalAgent):
+       def __init__(self, name, colour):
+               InternalAgent.__init__(self, name, colour)
+
+       def select(self):
+               while True:
+                       self.choice = self.board.pieces[self.colour][random.randint(0, len(self.board.pieces[self.colour])-1)]
+                       all_moves = []
+                       # Check that the piece has some possibility to move
+                       tmp = self.choice.current_type
+                       if tmp == "unknown": # For unknown pieces, try both types
+                               for t in self.choice.types:
+                                       if t == "unknown":
+                                               continue
+                                       self.choice.current_type = t
+                                       all_moves += self.board.possible_moves(self.choice)
+                       else:
+                               all_moves = self.board.possible_moves(self.choice)
+                       self.choice.current_type = tmp
+                       if len(all_moves) > 0:
+                               break
+               return [self.choice.x, self.choice.y]
+
+       def get_move(self):
+               moves = self.board.possible_moves(self.choice)
+               move = moves[random.randint(0, len(moves)-1)]
+               return move
+
+
+# Terrible, terrible hacks
+
+def run_agent(agent):
+       #sys.stderr.write(sys.argv[0] + " : Running agent " + str(agent) + "\n")
+       while True:
+               line = sys.stdin.readline().strip(" \r\n")
+               if line == "SELECTION?":
+                       #sys.stderr.write(sys.argv[0] + " : Make selection\n")
+                       [x,y] = agent.select() # Gets your agent's selection
+                       #sys.stderr.write(sys.argv[0] + " : Selection was " + str(agent.choice) + "\n")
+                       sys.stdout.write(str(x) + " " + str(y) + "\n")                          
+               elif line == "MOVE?":
+                       #sys.stderr.write(sys.argv[0] + " : Make move\n")
+                       [x,y] = agent.get_move() # Gets your agent's move
+                       sys.stdout.write(str(x) + " " + str(y) + "\n")
+               elif line.split(" ")[0] == "QUIT":
+                       #sys.stderr.write(sys.argv[0] + " : Quitting\n")
+                       agent.quit(" ".join(line.split(" ")[1:])) # Quits the game
+                       break
+               elif line.split(" ")[0] == "BOARD":
+                       s = ""
+                       line = sys.stdin.readline().strip(" \r\n")
+                       while line != "END BOARD":
+                               s += line + "\n"
+                               line = sys.stdin.readline().strip(" \r\n")
+                       agent.board.reset_board(s)
+                       
+               else:
+                       agent.update(line) # Updates agent.board
+       return 0
+
+
+# Sort of works?
+
+class ExternalWrapper(ExternalAgent):
+       def __init__(self, agent):
+               run = "python -u -c \"import sys;import os;from qchess import *;agent = " + agent.__class__.__name__ + "('" + agent.name + "','"+agent.colour+"');sys.stdin.readline();sys.exit(run_agent(agent))\""
+               # str(run)
+               ExternalAgent.__init__(self, run, agent.colour)
+
+       
+
+# --- player.py --- #
+# A sample agent
+
+
+class AgentBishop(AgentRandom): # Inherits from AgentRandom (in qchess)
+       def __init__(self, name, colour):
+               InternalAgent.__init__(self, name, colour)
+               self.value = {"pawn" : 1, "bishop" : 3, "knight" : 3, "rook" : 5, "queen" : 9, "king" : 100, "unknown" : 4}
+
+               self.aggression = 2.0 # Multiplier for scoring due to aggressive actions
+               self.defence = 1.0 # Multiplier for scoring due to defensive actions
+               
+               self.depth = 0 # Current depth
+               self.max_depth = 2 # Recurse this many times (for some reason, makes more mistakes when this is increased???)
+               self.recurse_for = -1 # Recurse for the best few moves each times (less than 0 = all moves)
+
+               for p in self.board.pieces["white"] + self.board.pieces["black"]:
+                       p.last_moves = None
+                       p.selected_moves = None
+
+               
+
+       def get_value(self, piece):
+               if piece == None:
+                       return 0.0
+               return float(self.value[piece.types[0]] + self.value[piece.types[1]]) / 2.0
+               
+       # Score possible moves for the piece
+       
+       def prioritise_moves(self, piece):
+
+               #sys.stderr.write(sys.argv[0] + " : " + str(self) + " prioritise called for " + str(piece) + "\n")
+
+               
+               
+               grid = self.board.probability_grid(piece)
+               #sys.stderr.write("\t Probability grid " + str(grid) + "\n")
+               moves = []
+               for x in range(w):
+                       for y in range(h):
+                               if grid[x][y] < 0.3: # Throw out moves with < 30% probability
+                                       #sys.stderr.write("\tReject " + str(x) + "," + str(y) + " (" + str(grid[x][y]) + ")\n")
+                                       continue
+
+                               target = self.board.grid[x][y]
+                       
+                               
+                               
+                               
+                               # Get total probability that the move is protected
+                               self.board.push_move(piece, x, y)
+                               
+
+                               
+                               defenders = self.board.coverage(x, y, piece.colour, reject_allied = False)
+                               d_prob = 0.0
+                               for d in defenders.keys():
+                                       d_prob += defenders[d]
+                               if len(defenders.keys()) > 0:
+                                       d_prob /= float(len(defenders.keys()))
+
+                               if (d_prob > 1.0):
+                                       d_prob = 1.0
+
+                               # Get total probability that the move is threatened
+                               attackers = self.board.coverage(x, y, opponent(piece.colour), reject_allied = False)
+                               a_prob = 0.0
+                               for a in attackers.keys():
+                                       a_prob += attackers[a]
+                               if len(attackers.keys()) > 0:
+                                       a_prob /= float(len(attackers.keys()))
+
+                               if (a_prob > 1.0):
+                                       a_prob = 1.0
+
+                               self.board.pop_move()
+                               
+
+                               
+                               # Score of the move
+                               value = self.aggression * (1.0 + d_prob) * self.get_value(target) - self.defence * (1.0 - d_prob) * a_prob * self.get_value(piece)
+
+                               # Adjust score based on movement of piece out of danger
+                               attackers = self.board.coverage(piece.x, piece.y, opponent(piece.colour))
+                               s_prob = 0.0
+                               for a in attackers.keys():
+                                       s_prob += attackers[a]
+                               if len(attackers.keys()) > 0:
+                                       s_prob /= float(len(attackers.keys()))
+
+                               if (s_prob > 1.0):
+                                       s_prob = 1.0
+                               value += self.defence * s_prob * self.get_value(piece)
+                               
+                               # Adjust score based on probability that the move is actually possible
+                               moves.append([[x, y], grid[x][y] * value])
+
+               moves.sort(key = lambda e : e[1], reverse = True)
+               #sys.stderr.write(sys.argv[0] + ": Moves for " + str(piece) + " are " + str(moves) + "\n")
+
+               piece.last_moves = moves
+               piece.selected_moves = None
+
+               
+
+               
+               return moves
+
+       def select_best(self, colour):
+
+               self.depth += 1
+               all_moves = {}
+               for p in self.board.pieces[colour]:
+                       self.choice = p # Temporarily pick that piece
+                       m = self.prioritise_moves(p)
+                       if len(m) > 0:
+                               all_moves.update({p : m[0]})
+
+               if len(all_moves.items()) <= 0:
+                       return None
+               
+               
+               opts = all_moves.items()
+               opts.sort(key = lambda e : e[1][1], reverse = True)
+
+               if self.depth >= self.max_depth:
+                       self.depth -= 1
+                       return list(opts[0])
+
+               if self.recurse_for >= 0:
+                       opts = opts[0:self.recurse_for]
+               #sys.stderr.write(sys.argv[0] + " : Before recurse, options are " + str(opts) + "\n")
+
+               # Take the best few moves, and recurse
+               for choice in opts[0:self.recurse_for]:
+                       [xx,yy] = [choice[0].x, choice[0].y] # Remember position
+                       [nx,ny] = choice[1][0] # Target
+                       [choice[0].x, choice[0].y] = [nx, ny] # Set position
+                       target = self.board.grid[nx][ny] # Remember piece in spot
+                       self.board.grid[xx][yy] = None # Remove piece
+                       self.board.grid[nx][ny] = choice[0] # Replace with moving piece
+                       
+                       # Recurse
+                       best_enemy_move = self.select_best(opponent(choice[0].colour))
+                       choice[1][1] -= best_enemy_move[1][1] / float(self.depth + 1.0)
+                       
+                       [choice[0].x, choice[0].y] = [xx, yy] # Restore position
+                       self.board.grid[nx][ny] = target # Restore taken piece
+                       self.board.grid[xx][yy] = choice[0] # Restore moved piece
+                       
+               
+
+               opts.sort(key = lambda e : e[1][1], reverse = True)
+               #sys.stderr.write(sys.argv[0] + " : After recurse, options are " + str(opts) + "\n")
+
+               self.depth -= 1
+               return list(opts[0])
+
+               
+
+       # Returns [x,y] of selected piece
+       def select(self):
+               #sys.stderr.write("Getting choice...")
+               self.choice = self.select_best(self.colour)[0]
+               
+               #sys.stderr.write(" Done " + str(self.choice)+"\n")
+               return [self.choice.x, self.choice.y]
+       
+       # Returns [x,y] of square to move selected piece into
+       def get_move(self):
+               #sys.stderr.write("Choice is " + str(self.choice) + "\n")
+               self.choice.selected_moves = self.choice.last_moves
+               moves = self.prioritise_moves(self.choice)
+               if len(moves) > 0:
+                       return moves[0][0]
+               else:
+                       return AgentRandom.get_move(self)
+
+# --- agent_bishop.py --- #
+import multiprocessing
+
+# Hacky alternative to using select for timing out players
+
+# WARNING: Do not wrap around HumanPlayer or things breakify
+# WARNING: Do not use in general or things breakify
+
+class Sleeper(multiprocessing.Process):
+       def __init__(self, timeout):
+               multiprocessing.Process.__init__(self)
+               self.timeout = timeout
+
+       def run(self):
+               time.sleep(self.timeout)
+
+
+class Worker(multiprocessing.Process):
+       def __init__(self, function, args, q):
+               multiprocessing.Process.__init__(self)
+               self.function = function
+               self.args = args
+               self.q = q
+
+       def run(self):
+               #print str(self) + " runs " + str(self.function) + " with args " + str(self.args) 
+               self.q.put(self.function(*self.args))
+               
+               
+
+def TimeoutFunction(function, args, timeout):
+       q = multiprocessing.Queue()
+       w = Worker(function, args, q)
+       s = Sleeper(timeout)
+       w.start()
+       s.start()
+       while True: # Busy loop of crappyness
+               if not w.is_alive():
+                       s.terminate()
+                       result = q.get()
+                       w.join()
+                       #print "TimeoutFunction gets " + str(result)
+                       return result
+               elif not s.is_alive():
+                       w.terminate()
+                       s.join()
+                       raise Exception("TIMEOUT")
+
+       
+               
+
+# A player that wraps another player and times out its moves
+# Uses threads
+# A (crappy) alternative to the use of select()
+class TimeoutPlayer(Player):
+       def __init__(self, base_player, timeout):
+               Player.__init__(self, base_player.name, base_player.colour)
+               self.base_player = base_player
+               self.timeout = timeout
+               
+       def select(self):
+               return TimeoutFunction(self.base_player.select, [], self.timeout)
+               
+       
+       def get_move(self):
+               return TimeoutFunction(self.base_player.get_move, [], self.timeout)
+
+       def update(self, result):
+               return TimeoutFunction(self.base_player.update, [result], self.timeout)
+
+       def quit(self, final_result):
+               return TimeoutFunction(self.base_player.quit, [final_result], self.timeout)
+# --- timeout_player.py --- #
+import socket
+import select
+
+network_timeout_start = -1.0 # Timeout in seconds to wait for the start of a message
+network_timeout_delay = 1.0 # Maximum time between two characters being received
+
+class NetworkPlayer(Player):
+       def __init__(self, colour, network, player):
+               Player.__init__(self, "@network:"+str(network.address), colour) 
+               self.player = player
+               self.network = network
+               
+       def __str__(self):
+               return "NetworkPlayer<"+str(self.colour)+","+str(self.player)+">"
+               
+       def select(self):
+               #debug(str(self) + " select called")
+               if self.player != None:
+                       s = self.player.select()
+                       self.send_message(str(s[0]) + " " + str(s[1]))
+               else:
+                       s = map(int, self.get_response().split(" "))
+                       for p in game.players:
+                               if p != self and isinstance(p, NetworkPlayer) and p.player == None:
+                                       p.network.send_message(str(s[0]) + " " + str(s[1]))
+               if s == [-1,-1]:
+                       game.final_result = "network terminate"
+                       game.stop()
+               return s
+       
+       def send_message(self, message):
+               #debug(str(self) + " send_message(\""+str(message)+"\") called")
+               self.network.send_message(message)
+               
+       def get_response(self):
+               #debug(str(self) + " get_response() called")
+               s = self.network.get_response()
+               #debug(str(self) + " get_response() returns \""+str(s)+"\"")
+               return s
+                       
+                       
+       def get_move(self):
+               #debug(str(self) + " get_move called")
+               if self.player != None:
+                       s = self.player.get_move()
+                       self.send_message(str(s[0]) + " " + str(s[1]))
+               else:
+                       s = map(int, self.get_response().split(" "))
+                       for p in game.players:
+                               if p != self and isinstance(p, NetworkPlayer) and p.player == None:
+                                       p.network.send_message(str(s[0]) + " " + str(s[1]))
+                                       
+               if s == [-1,-1]:
+                       game.final_result = "network terminate"
+                       game.stop()
+               return s
+       
+       def update(self, result):
+               #debug(str(self) + " update(\""+str(result)+"\") called")
+               if self.network.server == True:
+                       if self.player == None:
+                               self.send_message(result)
+               elif self.player != None:
+                       result = self.get_response()
+                       if result == "-1 -1":
+                               game.final_result = "network terminate"
+                               game.stop()
+                               return "-1 -1"
+                       self.board.update(result, deselect=False)
+               
+               
+               
+               if self.player != None:
+                       result = self.player.update(result)
+                       
+               return result
+               
+               
+       
+       def base_player(self):
+               if self.player == None:
+                       return self
+               else:
+                       return self.player.base_player()
+               
+       def quit(self, result):
+               try:
+                       self.send_message("-1 -1")
+               except:
+                       pass
+
+class Network():
+       def __init__(self, address = (None,4562)):
+               self.socket = socket.socket()
+               self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+               #self.socket.setblocking(0)
+               self.address = address
+               self.server = (address[0] == None)
+               
+               
+               self.connected = False
+                       
+       def connect(self):      
+               #debug(str(self) + "Tries to connect")
+               self.connected = True
+               if self.address[0] == None:
+                       self.host = "0.0.0.0" #socket.gethostname() # Breaks things???
+                       self.socket.bind((self.host, self.address[1]))
+                       self.socket.listen(5)   
+
+                       self.src, self.actual_address = self.socket.accept()
+                       
+                       self.src.send("ok\n")
+                       s = self.get_response()
+                       if s == "QUIT":
+                               self.src.close()
+                               return
+                       elif s != "ok":
+                               self.src.close()
+                               self.__init__(colour, (self.address[0], int(s)), baseplayer)
+                               return
+                       
+               else:
+                       time.sleep(0.3)
+                       self.socket.connect(self.address)
+                       self.src = self.socket
+                       self.src.send("ok\n")
+                       s = self.get_response()
+                       if s == "QUIT":
+                               self.src.close()
+                               return
+                       elif s != "ok":
+                               self.src.close()
+                               self.__init__(colour, (self.address[0], int(s)), baseplayer)
+                               return
+                       
+
+               
+       def __str__(self):
+               return "@network:"+str(self.address)
+
+       def get_response(self):
+               
+               # Timeout the start of the message (first character)
+               if network_timeout_start > 0.0:
+                       ready = select.select([self.src], [], [], network_timeout_start)[0]
+               else:
+                       ready = [self.src]
+               if self.src in ready:
+                       s = self.src.recv(1)
+               else:
+                       raise Exception("UNRESPONSIVE")
+
+
+               while s[len(s)-1] != '\n':
+                       # Timeout on each character in the message
+                       if network_timeout_delay > 0.0:
+                               ready = select.select([self.src], [], [], network_timeout_delay)[0]
+                       else:
+                               ready = [self.src]
+                       if self.src in ready:
+                               s += self.src.recv(1) 
+                       else:
+                               raise Exception("UNRESPONSIVE")
+
+               
+               return s.strip(" \r\n")
+
+       def send_message(self,s):
+               if network_timeout_start > 0.0:
+                       ready = select.select([], [self.src], [], network_timeout_start)[1]
+               else:
+                       ready = [self.src]
+
+               if self.src in ready:
+                       self.src.send(s + "\n")
+               else:
+                       raise Exception("UNRESPONSIVE")
+               
+               
+
+       def close(self):
+               self.src.shutdown()
+               self.src.close()
+# --- network.py --- #
+import threading
+
+# A thread that can be stopped!
+# Except it can only be stopped if it checks self.stopped() periodically
+# So it can sort of be stopped
+class StoppableThread(threading.Thread):
+       def __init__(self):
+               threading.Thread.__init__(self)
+               self._stop = threading.Event()
+
+       def stop(self):
+               self._stop.set()
+
+       def stopped(self):
+               return self._stop.isSet()
+# --- thread_util.py --- #
+log_files = []
+import datetime
+import urllib2
+
+class LogFile():
+       def __init__(self, log, name):  
+               self.name = name
+               self.log = log
+               self.logged = []
+               self.log.write("# Log starts " + str(datetime.datetime.now()) + "\n")
+
+       def write(self, s):
+               now = datetime.datetime.now()
+               self.log.write(str(now) + " : " + s + "\n")
+               self.logged.append((now, s))
+
+       def setup(self, board, players):
+               
+               for p in players:
+                       self.log.write("# " + str(p.colour) + " : " + str(p.name) + "\n")
+               
+               self.log.write("# Initial board\n")
+               for x in range(0, w):
+                       for y in range(0, h):
+                               if board.grid[x][y] != None:
+                                       self.log.write(str(board.grid[x][y]) + "\n")
+
+               self.log.write("# Start game\n")
+
+       def close(self):
+               self.log.write("# EOF\n")
+               if self.log != sys.stdout:
+                       self.log.close()
+
+class ShortLog(LogFile):
+       def __init__(self, file_name):
+               if file_name == "":
+                       self.log = sys.stdout
+               else:
+                       self.log = open(file_name, "w", 0)
+               LogFile.__init__(self, self.log, "@"+file_name)
+               self.file_name = file_name
+               self.phase = 0
+
+       def write(self, s):
+               now = datetime.datetime.now()
+               self.logged.append((now, s))
+               
+               if self.phase == 0:
+                       if self.log != sys.stdout:
+                               self.log.close()
+                               self.log = open(self.file_name, "w", 0)
+                       self.log.write("# Short log updated " + str(datetime.datetime.now()) + "\n")    
+                       LogFile.setup(self, game.board, game.players)
+
+               elif self.phase == 1:
+                       for message in self.logged[len(self.logged)-2:]:
+                               self.log.write(str(message[0]) + " : " + message[1] + "\n")
+
+               self.phase = (self.phase + 1) % 2               
+               
+       def close(self):
+               if self.phase == 1:
+                       ending = self.logged[len(self.logged)-1]
+                       self.log.write(str(ending[0]) + " : " + ending[1] + "\n")
+               self.log.write("# EOF\n")
+               if self.log != sys.stdout:
+                       self.log.close()
+               
+
+class HeadRequest(urllib2.Request):
+       def get_method(self):
+               return "HEAD"
+
+class HttpGetter(StoppableThread):
+       def __init__(self, address):
+               StoppableThread.__init__(self)
+               self.address = address
+               self.log = urllib2.urlopen(address)
+               self.lines = []
+               self.lock = threading.RLock() #lock for access of self.state
+               self.cond = threading.Condition() # conditional
+
+       def run(self):
+               while not self.stopped():
+                       line = self.log.readline()
+                       if line == "":
+                               date_mod = datetime.datetime.strptime(self.log.headers['last-modified'], "%a, %d %b %Y %H:%M:%S GMT")
+                               self.log.close()
+       
+                               next_log = urllib2.urlopen(HeadRequest(self.address))
+                               date_new = datetime.datetime.strptime(next_log.headers['last-modified'], "%a, %d %b %Y %H:%M:%S GMT")
+                               while date_new <= date_mod and not self.stopped():
+                                       next_log = urllib2.urlopen(HeadRequest(self.address))
+                                       date_new = datetime.datetime.strptime(next_log.headers['last-modified'], "%a, %d %b %Y %H:%M:%S GMT")
+                               if self.stopped():
+                                       break
+
+                               self.log = urllib2.urlopen(self.address)
+                               line = self.log.readline()
+
+                       self.cond.acquire()
+                       self.lines.append(line)
+                       self.cond.notifyAll()
+                       self.cond.release()
+
+                       #sys.stderr.write(" HttpGetter got \'" + str(line) + "\'\n")
+
+               self.log.close()
+                               
+                               
+       
+               
+               
+class HttpReplay():
+       def __init__(self, address):
+               self.getter = HttpGetter(address)
+               self.getter.start()
+               
+       def readline(self):
+               self.getter.cond.acquire()
+               while len(self.getter.lines) == 0:
+                       self.getter.cond.wait()
+                       
+               result = self.getter.lines[0]
+               self.getter.lines = self.getter.lines[1:]
+               self.getter.cond.release()
+
+               return result
+                       
+                       
+       def close(self):
+               self.getter.stop()
+
+class FileReplay():
+       def __init__(self, filename):
+               self.f = open(filename, "r", 0)
+               self.filename = filename
+               self.mod = os.path.getmtime(filename)
+               self.count = 0
+       
+       def readline(self):
+               line = self.f.readline()
+               
+               while line == "":
+                       mod2 = os.path.getmtime(self.filename)
+                       if mod2 > self.mod:
+                               #sys.stderr.write("File changed!\n")
+                               self.mod = mod2
+                               self.f.close()
+                               self.f = open(self.filename, "r", 0)
+                               
+                               new_line = self.f.readline()
+                               
+                               if " ".join(new_line.split(" ")[0:3]) != "# Short log":
+                                       for i in range(self.count):
+                                               new_line = self.f.readline()
+                                               #sys.stderr.write("Read back " + str(i) + ": " + str(new_line) + "\n")
+                                       new_line = self.f.readline()
+                               else:
+                                       self.count = 0
+                               
+                               line = new_line
+
+               self.count += 1
+               return line
+
+       def close(self):
+               self.f.close()
+               
+                                               
+def log(s):
+       for l in log_files:
+               l.write(s)
+               
+def debug(s):
+       sys.stderr.write("# DEBUG: " + s + "\n")
+               
+
+def log_init(board, players):
+       for l in log_files:
+               l.setup(board, players)
+
+# --- log.py --- #
+
+
+
+       
+
+# A thread that runs the game
+class GameThread(StoppableThread):
+       def __init__(self, board, players, server = True):
+               StoppableThread.__init__(self)
+               self.board = board
+               self.players = players
+               self.state = {"turn" : None} # The game state
+               self.error = 0 # Whether the thread exits with an error
+               self.lock = threading.RLock() #lock for access of self.state
+               self.cond = threading.Condition() # conditional for some reason, I forgot
+               self.final_result = ""
+               self.server = server
+               
+               
+                       
+               
+               
+
+       # Run the game (run in new thread with start(), run in current thread with run())
+       def run(self):
+               result = ""
+               while not self.stopped():
+                       
+                       for p in self.players:
+                               with self.lock:
+                                       self.state["turn"] = p.base_player()
+                               #try:
+                               if True:
+                                       [x,y] = p.select() # Player selects a square
+                                       if self.stopped():
+                                               #debug("Quitting in select")
+                                               break
+                                               
+                                       if isinstance(p, NetworkPlayer):
+                                               if p.network.server == True:
+                                                       result = self.board.select(x, y, colour = p.colour)
+                                               else:
+                                                       result = None
+                                                       
+                                       else:
+                                               result = self.board.select(x, y, colour = p.colour)
+                                       
+                                       result = p.update(result)
+                                       if self.stopped():
+                                               break
+                                       for p2 in self.players:
+                                               if p2 == p:
+                                                       continue
+                                               p2.update(result) # Inform players of what happened
+                                               if self.stopped():
+                                                       break
+                                       
+                                       if self.stopped():
+                                               break
+
+
+                                       log(result)
+
+                                       target = self.board.grid[x][y]
+                                       if isinstance(graphics, GraphicsThread):
+                                               with graphics.lock:
+                                                       graphics.state["moves"] = self.board.possible_moves(target)
+                                                       graphics.state["select"] = target
+
+                                       time.sleep(turn_delay)
+
+
+                                       if len(self.board.possible_moves(target)) == 0:
+                                               #print "Piece cannot move"
+                                               target.deselect()
+                                               if isinstance(graphics, GraphicsThread):
+                                                       with graphics.lock:
+                                                               graphics.state["moves"] = None
+                                                               graphics.state["select"] = None
+                                                               graphics.state["dest"] = None
+                                               continue
+
+                                       try:
+                                               [x2,y2] = p.get_move() # Player selects a destination
+                                       except:
+                                               self.stop()
+
+                                       if self.stopped():
+                                               #debug("Quitting in get_move")
+                                               break
+                                       
+                                       if isinstance(p, NetworkPlayer):
+                                               if p.network.server == True:
+                                                       result = str(x) + " " + str(y) + " -> " + str(x2) + " " + str(y2)
+                                                       self.board.update_move(x, y, x2, y2)
+                                               else:
+                                                       result = None
+                                                       
+                                       else:
+                                               result = str(x) + " " + str(y) + " -> " + str(x2) + " " + str(y2)
+                                               self.board.update_move(x, y, x2, y2)
+                                       
+                                       result = p.update(result)
+                                       if self.stopped():
+                                               break
+                                       for p2 in self.players:
+                                               if p2 == p:
+                                                       continue
+                                               p2.update(result) # Inform players of what happened
+                                               if self.stopped():
+                                                       break
+                                       
+                                       if self.stopped():
+                                               break
+                                       
+                                       
+                                                                                       
+                                       log(result)
+
+
+                                                                               
+
+                                       if isinstance(graphics, GraphicsThread):
+                                               with graphics.lock:
+                                                       graphics.state["moves"] = [[x2,y2]]
+
+                                       time.sleep(turn_delay)
+
+                                       if isinstance(graphics, GraphicsThread):
+                                               with graphics.lock:
+                                                       graphics.state["select"] = None
+                                                       graphics.state["dest"] = None
+                                                       graphics.state["moves"] = None
+
+                       # Commented out exception stuff for now, because it makes it impossible to tell if I made an IndentationError somewhere
+                       #       except Exception,e:
+                       #               result = e.message
+                       #               #sys.stderr.write(result + "\n")
+                       #               
+                       #               self.stop()
+                       #               with self.lock:
+                       #                       self.final_result = self.state["turn"].colour + " " + e.message
+
+                               end = self.board.end_condition()
+                               if end != None:         
+                                       with self.lock:
+                                               if end == "DRAW":
+                                                       self.final_result = self.state["turn"].colour + " " + end
+                                               else:
+                                                       self.final_result = end
+                                       self.stop()
+                               
+                               if self.stopped():
+                                       break
+
+
+               for p2 in self.players:
+                       p2.quit(self.final_result)
+
+               log(self.final_result)
+
+               if isinstance(graphics, GraphicsThread):
+                       graphics.stop()
+
+       
+# A thread that replays a log file
+class ReplayThread(GameThread):
+       def __init__(self, players, src, end=False,max_moves=None):
+               self.board = Board(style="empty")
+               self.board.max_moves = max_moves
+               GameThread.__init__(self, self.board, players)
+               self.src = src
+               self.end = end
+
+               self.reset_board(self.src.readline())
+
+       def reset_board(self, line):
+               agent_str = ""
+               self_str = ""
+               while line != "# Start game" and line != "# EOF":
+                       
+                       while line == "":
+                               line = self.src.readline().strip(" \r\n")
+                               continue
+
+                       if line[0] == '#':
+                               line = self.src.readline().strip(" \r\n")
+                               continue
+
+                       self_str += line + "\n"
+
+                       if self.players[0].name == "dummy" and self.players[1].name == "dummy":
+                               line = self.src.readline().strip(" \r\n")
+                               continue
+                       
+                       tokens = line.split(" ")
+                       types = map(lambda e : e.strip("[] ,'"), tokens[2:4])
+                       for i in range(len(types)):
+                               if types[i][0] == "?":
+                                       types[i] = "unknown"
+
+                       agent_str += tokens[0] + " " + tokens[1] + " " + str(types) + " ".join(tokens[4:]) + "\n"
+                       line = self.src.readline().strip(" \r\n")
+
+               for p in self.players:
+                       p.reset_board(agent_str)
+               
+               
+               self.board.reset_board(self_str)
+
+       
+       def run(self):
+               move_count = 0
+               last_line = ""
+               line = self.src.readline().strip(" \r\n")
+               while line != "# EOF":
+
+
+                       if self.stopped():
+                               break
+                       
+                       if len(line) <= 0:
+                               continue
+                                       
+
+                       if line[0] == '#':
+                               last_line = line
+                               line = self.src.readline().strip(" \r\n")
+                               continue
+
+                       tokens = line.split(" ")
+                       if tokens[0] == "white" or tokens[0] == "black":
+                               self.reset_board(line)
+                               last_line = line
+                               line = self.src.readline().strip(" \r\n")
+                               continue
+
+                       move = line.split(":")
+                       move = move[len(move)-1].strip(" \r\n")
+                       tokens = move.split(" ")
+                       
+                       
+                       try:
+                               [x,y] = map(int, tokens[0:2])
+                       except:
+                               last_line = line
+                               self.stop()
+                               break
+
+                       log(move)
+
+                       target = self.board.grid[x][y]
+                       with self.lock:
+                               if target.colour == "white":
+                                       self.state["turn"] = self.players[0]
+                               else:
+                                       self.state["turn"] = self.players[1]
+                       
+                       move_piece = (tokens[2] == "->")
+                       if move_piece:
+                               [x2,y2] = map(int, tokens[len(tokens)-2:])
+
+                       if isinstance(graphics, GraphicsThread):
+                               with graphics.lock:
+                                       graphics.state["select"] = target
+                                       
+                       if not move_piece:
+                               self.board.update_select(x, y, int(tokens[2]), tokens[len(tokens)-1])
+                               if isinstance(graphics, GraphicsThread):
+                                       with graphics.lock:
+                                               if target.current_type != "unknown":
+                                                       graphics.state["moves"] = self.board.possible_moves(target)
+                                               else:
+                                                       graphics.state["moves"] = None
+                                       time.sleep(turn_delay)
+                       else:
+                               self.board.update_move(x, y, x2, y2)
+                               if isinstance(graphics, GraphicsThread):
+                                       with graphics.lock:
+                                               graphics.state["moves"] = [[x2,y2]]
+                                       time.sleep(turn_delay)
+                                       with graphics.lock:
+                                               graphics.state["select"] = None
+                                               graphics.state["moves"] = None
+                                               graphics.state["dest"] = None
+                       
+
+                       
+                       
+                       
+                       for p in self.players:
+                               p.update(move)
+
+                       last_line = line
+                       line = self.src.readline().strip(" \r\n")
+                       
+                       
+                       end = self.board.end_condition()
+                       if end != None:
+                               self.final_result = end
+                               self.stop()
+                               break
+                                       
+                                               
+                                               
+
+                       
+                                       
+
+
+                       
+
+                               
+                       
+
+               
+
+               if self.end and isinstance(graphics, GraphicsThread):
+                       #graphics.stop()
+                       pass # Let the user stop the display
+               elif not self.end and self.board.end_condition() == None:
+                       global game
+                       # Work out the last move
+                                       
+                       t = last_line.split(" ")
+                       if t[len(t)-2] == "black":
+                               self.players.reverse()
+                       elif t[len(t)-2] == "white":
+                               pass
+                       elif self.state["turn"] != None and self.state["turn"].colour == "white":
+                               self.players.reverse()
+
+
+                       game = GameThread(self.board, self.players)
+                       game.run()
+               else:
+                       pass
+
+               
+
+def opponent(colour):
+       if colour == "white":
+               return "black"
+       else:
+               return "white"
+# --- game.py --- #
+try:
+       import pygame
+except:
+       pass
+import os
+
+# Dictionary that stores the unicode character representations of the different pieces
+# Chess was clearly the reason why unicode was invented
+# For some reason none of the pygame chess implementations I found used them!
+piece_char = {"white" : {"king" : u'\u2654',
+                        "queen" : u'\u2655',
+                        "rook" : u'\u2656',
+                        "bishop" : u'\u2657',
+                        "knight" : u'\u2658',
+                        "pawn" : u'\u2659',
+                        "unknown" : '?'},
+               "black" : {"king" : u'\u265A',
+                        "queen" : u'\u265B',
+                        "rook" : u'\u265C',
+                        "bishop" : u'\u265D',
+                        "knight" : u'\u265E',
+                        "pawn" : u'\u265F',
+                        "unknown" : '?'}}
+
+images = {"white" : {}, "black" : {}}
+small_images = {"white" : {}, "black" : {}}
+
+def create_images(grid_sz, font_name=os.path.join(os.path.curdir, "data", "DejaVuSans.ttf")):
+
+       # Get the font sizes
+       l_size = 5*(grid_sz[0] / 8)
+       s_size = 3*(grid_sz[0] / 8)
+
+       for c in piece_char.keys():
+               
+               if c == "black":
+                       for p in piece_char[c].keys():
+                               images[c].update({p : pygame.font.Font(font_name, l_size).render(piece_char[c][p], True,(0,0,0))})
+                               small_images[c].update({p : pygame.font.Font(font_name, s_size).render(piece_char[c][p],True,(0,0,0))})         
+               elif c == "white":
+                       for p in piece_char[c].keys():
+                               images[c].update({p : pygame.font.Font(font_name, l_size+1).render(piece_char["black"][p], True,(255,255,255))})
+                               images[c][p].blit(pygame.font.Font(font_name, l_size).render(piece_char[c][p], True,(0,0,0)),(0,0))
+                               small_images[c].update({p : pygame.font.Font(font_name, s_size+1).render(piece_char["black"][p],True,(255,255,255))})
+                               small_images[c][p].blit(pygame.font.Font(font_name, s_size).render(piece_char[c][p],True,(0,0,0)),(0,0))
+       
+
+def load_images(image_dir=os.path.join(os.path.curdir, "data", "images")):
+       if not os.path.exists(image_dir):
+               raise Exception("Couldn't load images from " + image_dir + " (path doesn't exist)")
+       for c in piece_char.keys():
+               for p in piece_char[c].keys():
+                       images[c].update({p : pygame.image.load(os.path.join(image_dir, c + "_" + p + ".png"))})
+                       small_images[c].update({p : pygame.image.load(os.path.join(image_dir, c + "_" + p + "_small.png"))})
+# --- images.py --- #
+graphics_enabled = True
+
+try:
+       import pygame
+       os.environ["SDL_VIDEO_ALLOW_SCREENSAVER"] = "1"
+except:
+       graphics_enabled = False
+       
+import time
+
+
+
+# A thread to make things pretty
+class GraphicsThread(StoppableThread):
+       def __init__(self, board, title = "UCC::Progcomp 2013 - QChess", grid_sz = [80,80]):
+               StoppableThread.__init__(self)
+               
+               self.board = board
+               pygame.init()
+               self.window = pygame.display.set_mode((grid_sz[0] * w, grid_sz[1] * h))
+               pygame.display.set_caption(title)
+
+               #print "Initialised properly"
+               
+               self.grid_sz = grid_sz[:]
+               self.state = {"select" : None, "dest" : None, "moves" : None, "overlay" : None, "coverage" : None}
+               self.error = 0
+               self.lock = threading.RLock()
+               self.cond = threading.Condition()
+               self.sleep_timeout = None
+               self.last_event = time.time()
+               self.blackout = False
+
+               #print "Test font"
+               pygame.font.Font(os.path.join(os.path.curdir, "data", "DejaVuSans.ttf"), 32).render("Hello", True,(0,0,0))
+
+               #load_images()
+               create_images(grid_sz)
+
+               """
+               for c in images.keys():
+                       for p in images[c].keys():
+                               images[c][p] = images[c][p].convert(self.window)
+                               small_images[c][p] = small_images[c][p].convert(self.window)
+               """
+
+               
+       
+
+
+       # On the run from the world
+       def run(self):
+               
+               while not self.stopped():
+                       
+                       if self.sleep_timeout == None or (time.time() - self.last_event) < self.sleep_timeout:
+                       
+                               #print "Display grid"
+                               self.board.display_grid(window = self.window, grid_sz = self.grid_sz) # Draw the board
+
+                               #print "Display overlay"
+                               self.overlay()
+
+                               #print "Display pieces"
+                               self.board.display_pieces(window = self.window, grid_sz = self.grid_sz) # Draw the board                
+                               self.blackout = False
+                               
+                       elif pygame.mouse.get_focused() and not self.blackout:
+                               os.system("xset dpms force off")
+                               self.blackout = True
+                               self.window.fill((0,0,0))
+
+                       pygame.display.flip()
+
+                       for event in pygame.event.get():
+                               self.last_event = time.time()
+                               if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_q):
+                                       if isinstance(game, GameThread):
+                                               with game.lock:
+                                                       game.final_result = ""
+                                                       if game.state["turn"] != None:
+                                                               game.final_result = game.state["turn"].colour + " "
+                                                       game.final_result += "terminated"
+                                               game.stop()
+                                       self.stop()
+                                       break
+                               elif event.type == pygame.MOUSEBUTTONDOWN:
+                                       self.mouse_down(event)
+                                       
+                               elif event.type == pygame.MOUSEBUTTONUP:
+                                       self.mouse_up(event)                    
+                               
+                               
+                                       
+  
+                               
+                                                               
+                                               
+                                               
+               self.message("Game ends, result \""+str(game.final_result) + "\"")
+               time.sleep(1)
+
+               # Wake up anyone who is sleeping
+               self.cond.acquire()
+               self.cond.notify()
+               self.cond.release()
+
+               pygame.quit() # Time to say goodbye
+
+       # Mouse release event handler
+       def mouse_up(self, event):
+               if event.button == 3:
+                       with self.lock:
+                               self.state["overlay"] = None
+               elif event.button == 2:
+                       with self.lock:
+                               self.state["coverage"] = None   
+
+       # Mouse click event handler
+       def mouse_down(self, event):
+               if event.button == 1:
+                       m = [event.pos[i] / self.grid_sz[i] for i in range(2)]
+                       if isinstance(game, GameThread):
+                               with game.lock:
+                                       p = game.state["turn"]
+                       else:
+                                       p = None
+                                       
+                                       
+                       if isinstance(p, HumanPlayer):
+                               with self.lock:
+                                       s = self.board.grid[m[0]][m[1]]
+                                       select = self.state["select"]
+                               if select == None:
+                                       if s != None and s.colour != p.colour:
+                                               self.message("Wrong colour") # Look at all this user friendliness!
+                                               time.sleep(1)
+                                               return
+                                       # Notify human player of move
+                                       self.cond.acquire()
+                                       with self.lock:
+                                               self.state["select"] = s
+                                               self.state["dest"] = None
+                                       self.cond.notify()
+                                       self.cond.release()
+                                       return
+
+                               if select == None:
+                                       return
+                                               
+                                       
+                               if self.state["moves"] == None:
+                                       return
+
+                               if not m in self.state["moves"]:
+                                       self.message("Illegal Move") # I still think last year's mouse interface was adequate
+                                       time.sleep(2)
+                                       return
+                                               
+                               with self.lock:
+                                       if self.state["dest"] == None:
+                                               self.cond.acquire()
+                                               self.state["dest"] = m
+                                               self.state["select"] = None
+                                               self.state["moves"] = None
+                                               self.cond.notify()
+                                               self.cond.release()
+               elif event.button == 3:
+                       m = [event.pos[i] / self.grid_sz[i] for i in range(len(event.pos))]
+                       if isinstance(game, GameThread):
+                               with game.lock:
+                                       p = game.state["turn"]
+                       else:
+                               p = None
+                                       
+                                       
+                       if isinstance(p, HumanPlayer):
+                               with self.lock:
+                                       self.state["overlay"] = self.board.probability_grid(self.board.grid[m[0]][m[1]])
+
+               elif event.button == 2:
+                       m = [event.pos[i] / self.grid_sz[i] for i in range(len(event.pos))]
+                       if isinstance(game, GameThread):
+                               with game.lock:
+                                       p = game.state["turn"]
+                       else:
+                               p = None
+                       
+                       
+                       if isinstance(p, HumanPlayer):
+                               with self.lock:
+                                       self.state["coverage"] = self.board.coverage(m[0], m[1], None, self.state["select"])
+                               
+       # Draw the overlay
+       def overlay(self):
+
+               square_img = pygame.Surface((self.grid_sz[0], self.grid_sz[1]),pygame.SRCALPHA) # A square image
+               # Draw square over the selected piece
+               with self.lock:
+                       select = self.state["select"]
+               if select != None:
+                       mp = [self.grid_sz[i] * [select.x, select.y][i] for i in range(len(self.grid_sz))]
+                       square_img.fill(pygame.Color(0,255,0,64))
+                       self.window.blit(square_img, mp)
+               # If a piece is selected, draw all reachable squares
+               # (This quality user interface has been patented)
+               with self.lock:
+                       m = self.state["moves"]
+               if m != None:
+                       square_img.fill(pygame.Color(255,0,0,128)) # Draw them in blood red
+                       for move in m:
+                               mp = [self.grid_sz[i] * move[i] for i in range(2)]
+                               self.window.blit(square_img, mp)
+               # If a piece is overlayed, show all squares that it has a probability to reach
+               with self.lock:
+                       m = self.state["overlay"]
+               if m != None:
+                       for x in range(w):
+                               for y in range(h):
+                                       if m[x][y] > 0.0:
+                                               mp = [self.grid_sz[i] * [x,y][i] for i in range(2)]
+                                               square_img.fill(pygame.Color(255,0,255,int(m[x][y] * 128))) # Draw in purple
+                                               self.window.blit(square_img, mp)
+                                               font = pygame.font.Font(os.path.join(os.path.curdir, "data", "DejaVuSans.ttf"), 14)
+                                               text = font.render("{0:.2f}".format(round(m[x][y],2)), 1, pygame.Color(0,0,0))
+                                               self.window.blit(text, mp)
+                               
+               # If a square is selected, highlight all pieces that have a probability to reach it
+               with self.lock:                         
+                       m = self.state["coverage"]
+               if m != None:
+                       for p in m:
+                               mp = [self.grid_sz[i] * [p.x,p.y][i] for i in range(2)]
+                               square_img.fill(pygame.Color(0,255,255, int(m[p] * 196))) # Draw in pale blue
+                               self.window.blit(square_img, mp)
+                               font = pygame.font.Font(os.path.join(os.path.curdir, "data", "DejaVuSans.ttf"), 14)
+                               text = font.render("{0:.2f}".format(round(m[p],2)), 1, pygame.Color(0,0,0))
+                               self.window.blit(text, mp)
+                       # Draw a square where the mouse is
+               # This also serves to indicate who's turn it is
+               
+               if isinstance(game, GameThread):
+                       with game.lock:
+                               turn = game.state["turn"]
+               else:
+                       turn = None
+
+               if isinstance(turn, HumanPlayer):
+                       mp = [self.grid_sz[i] * int(pygame.mouse.get_pos()[i] / self.grid_sz[i]) for i in range(2)]
+                       square_img.fill(pygame.Color(0,0,255,128))
+                       if turn.colour == "white":
+                               c = pygame.Color(255,255,255)
+                       else:
+                               c = pygame.Color(0,0,0)
+                       pygame.draw.rect(square_img, c, (0,0,self.grid_sz[0], self.grid_sz[1]), self.grid_sz[0]/10)
+                       self.window.blit(square_img, mp)
+
+       # Message in a bottle
+       def message(self, string, pos = None, colour = None, font_size = 20):
+               #print "Drawing message..."
+               font = pygame.font.Font(os.path.join(os.path.curdir, "data", "DejaVuSans.ttf"), font_size)
+               if colour == None:
+                       colour = pygame.Color(0,0,0)
+               
+               text = font.render(string, 1, colour)
+       
+
+               s = pygame.Surface((text.get_width(), text.get_height()), pygame.SRCALPHA)
+               s.fill(pygame.Color(128,128,128))
+
+               tmp = self.window.get_size()
+
+               if pos == None:
+                       pos = (tmp[0] / 2 - text.get_width() / 2, tmp[1] / 3 - text.get_height())
+               else:
+                       pos = (pos[0]*text.get_width() + tmp[0] / 2 - text.get_width() / 2, pos[1]*text.get_height() + tmp[1] / 3 - text.get_height())
+               
+
+               rect = (pos[0], pos[1], text.get_width(), text.get_height())
+       
+               pygame.draw.rect(self.window, pygame.Color(0,0,0), pygame.Rect(rect), 1)
+               self.window.blit(s, pos)
+               self.window.blit(text, pos)
+
+               pygame.display.flip()
+
+       def getstr(self, prompt = None):
+               s = pygame.Surface((self.window.get_width(), self.window.get_height()))
+               s.blit(self.window, (0,0))
+               result = ""
+
+               while True:
+                       #print "LOOP"
+                       if prompt != None:
+                               self.message(prompt)
+                               self.message(result, pos = (0, 1))
+       
+                       pygame.event.pump()
+                       for event in pygame.event.get():
+                               if event.type == pygame.QUIT:
+                                       return None
+                               if event.type == pygame.KEYDOWN:
+                                       if event.key == pygame.K_BACKSPACE:
+                                               result = result[0:len(result)-1]
+                                               self.window.blit(s, (0,0)) # Revert the display
+                                               continue
+                               
+                                               
+                                       try:
+                                               if event.unicode == '\r':
+                                                       return result
+                                       
+                                               result += str(event.unicode)
+                                       except:
+                                               continue
+
+
+       # Function to pick a button
+       def SelectButton(self, choices, prompt = None, font_size=20):
+
+               #print "Select button called!"
+               self.board.display_grid(self.window, self.grid_sz)
+               if prompt != None:
+                       self.message(prompt)
+               font = pygame.font.Font(os.path.join(os.path.curdir, "data", "DejaVuSans.ttf"), font_size)
+               targets = []
+               sz = self.window.get_size()
+
+               
+               for i in range(len(choices)):
+                       c = choices[i]
+                       
+                       text = font.render(c, 1, pygame.Color(0,0,0))
+                       p = (sz[0] / 2 - (1.5*text.get_width())/2, sz[1] / 2 +(i-1)*text.get_height()+(i*2))
+                       targets.append((p[0], p[1], p[0] + 1.5*text.get_width(), p[1] + text.get_height()))
+
+               while True:
+                       mp =pygame.mouse.get_pos()
+                       for i in range(len(choices)):
+                               c = choices[i]
+                               if mp[0] > targets[i][0] and mp[0] < targets[i][2] and mp[1] > targets[i][1] and mp[1] < targets[i][3]:
+                                       font_colour = pygame.Color(255,0,0)
+                                       box_colour = pygame.Color(0,0,255,128)
+                               else:
+                                       font_colour = pygame.Color(0,0,0)
+                                       box_colour = pygame.Color(128,128,128)
+                               
+                               text = font.render(c, 1, font_colour)
+                               s = pygame.Surface((text.get_width()*1.5, text.get_height()), pygame.SRCALPHA)
+                               s.fill(box_colour)
+                               pygame.draw.rect(s, (0,0,0), (0,0,1.5*text.get_width(), text.get_height()), self.grid_sz[0]/10)
+                               s.blit(text, ((text.get_width()*1.5)/2 - text.get_width()/2 ,0))
+                               self.window.blit(s, targets[i][0:2])
+                               
+       
+                       pygame.display.flip()
+
+                       for event in pygame.event.get():
+                               if event.type == pygame.QUIT:
+                                       return None
+                               elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
+                                       for i in range(len(targets)):
+                                               t = targets[i]
+                                               if event.pos[0] > t[0] and event.pos[0] < t[2]:
+                                                       if event.pos[1] > t[1] and event.pos[1] < t[3]:
+                                                               return i
+                                               #print "Reject " + str(i) + str(event.pos) + " vs " + str(t)
+               
+
+       # Function to choose between dedicated server or normal play
+       def SelectServer(self):
+       
+               choice = self.SelectButton(["Normal", "Join Eigenserver"],prompt="Game type?")
+               if choice == 0:
+                       return None
+               choice = self.SelectButton(["progcomp.ucc", "other"], prompt="Address?")
+               if choice == 0:
+                       return "progcomp.ucc.asn.au"
+               else:
+                       return self.getstr(prompt = "Enter address:")
+                       
+       # Function to pick players in a nice GUI way
+       def SelectPlayers(self, players = []):
+
+
+               #print "SelectPlayers called"
+               
+               missing = ["white", "black"]
+               for p in players:
+                       missing.remove(p.colour)
+
+               for colour in missing:
+                       
+                       
+                       choice = self.SelectButton(["human", "agent", "network"],prompt = "Choose " + str(colour) + " player")
+                       if choice == 0:
+                               players.append(HumanPlayer("human", colour))
+                       elif choice == 1:
+                               import inspect
+                               internal_agents = inspect.getmembers(sys.modules[__name__], inspect.isclass)
+                               internal_agents = [x for x in internal_agents if issubclass(x[1], InternalAgent)]
+                               internal_agents.remove(('InternalAgent', InternalAgent)) 
+                               if len(internal_agents) > 0:
+                                       choice2 = self.SelectButton(["internal", "external"], prompt="Type of agent")
+                               else:
+                                       choice2 = 1
+
+                               if choice2 == 0:
+                                       agent = internal_agents[self.SelectButton(map(lambda e : e[0], internal_agents), prompt="Choose internal agent")]
+                                       players.append(agent[1](agent[0], colour))                                      
+                               elif choice2 == 1:
+                                       try:
+                                               import Tkinter
+                                               from tkFileDialog import askopenfilename
+                                               root = Tkinter.Tk() # Need a root to make Tkinter behave
+                                               root.withdraw() # Some sort of magic incantation
+                                               path = askopenfilename(parent=root, initialdir="../agents",title=
+'Choose an agent.')
+                                               if path == "":
+                                                       return self.SelectPlayers()
+                                               players.append(make_player(path, colour))       
+                                       except:
+                                               
+                                               p = None
+                                               while p == None:
+                                                       self.board.display_grid(self.window, self.grid_sz)
+                                                       pygame.display.flip()
+                                                       path = self.getstr(prompt = "Enter path:")
+                                                       if path == None:
+                                                               return None
+       
+                                                       if path == "":
+                                                               return self.SelectPlayers()
+       
+                                                       try:
+                                                               p = make_player(path, colour)
+                                                       except:
+                                                               self.board.display_grid(self.window, self.grid_sz)
+                                                               pygame.display.flip()
+                                                               self.message("Invalid path!")
+                                                               time.sleep(1)
+                                                               p = None
+                                               players.append(p)
+                       elif choice == 1:
+                               address = ""
+                               while address == "":
+                                       self.board.display_grid(self.window, self.grid_sz)
+                                       
+                                       address = self.getstr(prompt = "Address? (leave blank for server)")
+                                       if address == None:
+                                               return None
+                                       if address == "":
+                                               address = None
+                                               continue
+                                       try:
+                                               map(int, address.split("."))
+                                       except:
+                                               self.board.display_grid(self.window, self.grid_sz)
+                                               self.message("Invalid IPv4 address!")
+                                               address = ""
+
+                               players.append(NetworkReceiver(colour, address))
+                       else:
+                               return None
+               #print str(self) + ".SelectPlayers returns " + str(players)
+               return players
+                       
+                               
+                       
+# --- graphics.py --- #
+def dedicated_server():
+       global log_files
+       
+       max_games = 5
+       games = []
+       gameID = 0
+       while True:
+               # Get players
+               gameID += 1
+               log("Getting clients...")
+               s = socket.socket()
+               s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+               s.bind(("0.0.0.0", 4562))
+               s.listen(2)
+               ss = s.accept()
+               
+               log("Got white player")
+               
+               args = ["python", "qchess.py", "--no-graphics", "@network::"+str(4600+2*len(games)), "@network::"+str(4600+2*len(games))]
+               if len(log_files) != 0:
+                       for l in log_files:
+                               if l.name == "":
+                                       args.append("--log")
+                               else:
+                                       args.append("--log="+str(l.name)+"_"+str(gameID))
+               
+               g = subprocess.Popen(args, stdout=subprocess.PIPE)
+               games.append(g)
+               
+               time.sleep(0.5)
+               ss[0].send("white " + str(4600 + 2*(len(games)-1)))
+               ss[0].shutdown(socket.SHUT_RD)
+               ss[0].close()
+               
+               time.sleep(0.5)
+               ss = s.accept()
+               
+               log("Got black player")
+               
+               time.sleep(0.5)
+               ss[0].send("black " + str(4600 + 2*(len(games)-1)))
+               ss[0].shutdown(socket.SHUT_RD)
+               ss[0].close()
+               
+               s.shutdown(socket.SHUT_RDWR)
+               s.close()
+               
+               
+               while len(games) > max_games:
+                       #log("Too many games; waiting for game to finish...")
+                       ready = select.select(map(lambda e : e.stdout, games),[], [])
+                       for r in ready[0]:
+                               s = r.readline().strip(" \r\n").split(" ")
+                               if s[0] == "white" or s[0] == "black":
+                                       for g in games[:]:
+                                               if g.stdout == r:
+                                                       log("Game " + str(g) + " has finished")
+                                                       games.remove(g)
+                                                       
+       return 0
+       
+def client(addr):
+       
+       
+       
+       s = socket.socket()
+       s.connect((addr, 4562))
+       
+       [colour,port] = s.recv(1024).strip(" \r\n").split(" ")
+       
+       #debug("Colour: " + colour + ", port: " + port)
+       
+       s.shutdown(socket.SHUT_RDWR)
+       s.close()
+       
+       if colour == "white":
+               p = subprocess.Popen(["python", "qchess.py", "@human", "@network:"+addr+":"+port])
+       else:
+               p = subprocess.Popen(["python", "qchess.py", "@network:"+addr+":"+port, "@human"])
+       p.wait()
+       return 0# --- server.py --- #
+#!/usr/bin/python -u
+
+# Do you know what the -u does? It unbuffers stdin and stdout
+# I can't remember why, but last year things broke without that
+
+"""
+       UCC::Progcomp 2013 Quantum Chess game
+       @author Sam Moore [SZM] "matches"
+       @copyright The University Computer Club, Incorporated
+               (ie: You can copy it for not for profit purposes)
+"""
+
+# system python modules or whatever they are called
+import sys
+import os
+import time
+
+turn_delay = 0.5
+sleep_timeout = None
+[game, graphics] = [None, None]
+
+def make_player(name, colour):
+       if name[0] == '@':
+               if name[1:] == "human":
+                       return HumanPlayer(name, colour)
+               s = name[1:].split(":")
+               if s[0] == "network":
+                       ip = None
+                       port = 4562
+                       #print str(s)
+                       if len(s) > 1:
+                               if s[1] != "":
+                                       ip = s[1]
+                       if len(s) > 2:
+                               port = int(s[2])
+                               
+                       if ip == None:
+                               if colour == "black":
+                                       port += 1
+                       elif colour == "white":
+                               port += 1
+                                               
+                       return NetworkPlayer(colour, Network((ip, port)), None)
+               if s[0] == "internal":
+
+                       import inspect
+                       internal_agents = inspect.getmembers(sys.modules[__name__], inspect.isclass)
+                       internal_agents = [x for x in internal_agents if issubclass(x[1], InternalAgent)]
+                       internal_agents.remove(('InternalAgent', InternalAgent)) 
+                       
+                       if len(s) != 2:
+                               sys.stderr.write(sys.argv[0] + " : '@internal' should be followed by ':' and an agent name\n")
+                               sys.stderr.write(sys.argv[0] + " : Choices are: " + str(map(lambda e : e[0], internal_agents)) + "\n")
+                               return None
+
+                       for a in internal_agents:
+                               if s[1] == a[0]:
+                                       return a[1](name, colour)
+                       
+                       sys.stderr.write(sys.argv[0] + " : Can't find an internal agent matching \"" + s[1] + "\"\n")
+                       sys.stderr.write(sys.argv[0] + " : Choices are: " + str(map(lambda e : e[0], internal_agents)) + "\n")
+                       return None
+                       
+
+       else:
+               return ExternalAgent(name, colour)
+                       
+
+
+# The main function! It does the main stuff!
+def main(argv):
+
+       # Apparently python will silently treat things as local unless you do this
+       # Anyone who says "You should never use a global variable" can die in a fire
+       global game
+       global graphics
+       
+       global turn_delay
+       global agent_timeout
+       global log_files
+       global src_file
+       global graphics_enabled
+       global always_reveal_states
+       global sleep_timeout
+
+
+       server_addr = None
+
+       max_moves = None
+       src_file = None
+       
+       style = "quantum"
+       colour = "white"
+
+       # Get the important warnings out of the way
+       if platform.system() == "Windows":
+               sys.stderr.write(sys.argv[0] + " : Warning - You are using " + platform.system() + "\n")
+               if platform.release() == "Vista":
+                       sys.stderr.write(sys.argv[0] + " : God help you.\n")
+       
+
+       players = []
+       i = 0
+       while i < len(argv)-1:
+               i += 1
+               arg = argv[i]
+               if arg[0] != '-':
+                       p = make_player(arg, colour)
+                       if not isinstance(p, Player):
+                               sys.stderr.write(sys.argv[0] + " : Fatal error creating " + colour + " player\n")
+                               return 100
+                       players.append(p)
+                       if colour == "white":
+                               colour = "black"
+                       elif colour == "black":
+                               pass
+                       else:
+                               sys.stderr.write(sys.argv[0] + " : Too many players (max 2)\n")
+                       continue
+
+               # Option parsing goes here
+               if arg[1] == '-' and arg[2:] == "classical":
+                       style = "classical"
+               elif arg[1] == '-' and arg[2:] == "quantum":
+                       style = "quantum"
+               elif arg[1] == '-' and arg[2:] == "reveal":
+                       always_reveal_states = True
+               elif (arg[1] == '-' and arg[2:] == "graphics"):
+                       graphics_enabled = True
+               elif (arg[1] == '-' and arg[2:] == "no-graphics"):
+                       graphics_enabled = False
+               elif (arg[1] == '-' and arg[2:].split("=")[0] == "file"):
+                       # Load game from file
+                       if len(arg[2:].split("=")) == 1:
+                               src_file = sys.stdin
+                       else:
+                               f = arg[2:].split("=")[1]
+                               if f[0:7] == "http://":
+                                       src_file = HttpReplay(f)
+                               else:
+                                       src_file = FileReplay(f.split(":")[0])
+
+                                       if len(f.split(":")) == 2:
+                                               max_moves = int(f.split(":")[1])
+                                               
+               elif (arg[1] == '-' and arg[2:].split("=")[0] == "server"):
+                       #debug("Server: " + str(arg[2:]))
+                       if len(arg[2:].split("=")) <= 1:
+                               server_addr = True
+                       else:
+                               server_addr = arg[2:].split("=")[1]
+                       
+               elif (arg[1] == '-' and arg[2:].split("=")[0] == "log"):
+                       # Log file
+                       if len(arg[2:].split("=")) == 1:
+                               log_files.append(LogFile(sys.stdout,""))
+                       else:
+                               f = arg[2:].split("=")[1]
+                               if f == "":
+                                       log_files.append(LogFile(sys.stdout, ""))
+                               elif f[0] == '@':
+                                       log_files.append(ShortLog(f[1:]))
+                               else:
+                                       log_files.append(LogFile(open(f, "w", 0), f))
+               elif (arg[1] == '-' and arg[2:].split("=")[0] == "delay"):
+                       # Delay
+                       if len(arg[2:].split("=")) == 1:
+                               turn_delay = 0
+                       else:
+                               turn_delay = float(arg[2:].split("=")[1])
+
+               elif (arg[1] == '-' and arg[2:].split("=")[0] == "timeout"):
+                       # Timeout
+                       if len(arg[2:].split("=")) == 1:
+                               agent_timeout = -1
+                       else:
+                               agent_timeout = float(arg[2:].split("=")[1])
+               elif (arg[1] == '-' and arg[2:].split("=")[0] == "blackout"):
+                       # Screen saver delay
+                       if len(arg[2:].split("=")) == 1:
+                               sleep_timeout = -1
+                       else:
+                               sleep_timeout = float(arg[2:].split("=")[1])
+                               
+               elif (arg[1] == '-' and arg[2:] == "help"):
+                       # Help
+                       os.system("less data/help.txt") # The best help function
+                       return 0
+               
+       # Dedicated server?
+       
+       #debug("server_addr = " + str(server_addr))
+       
+       if server_addr != None:
+               if server_addr == True:
+                       return dedicated_server()
+               else:
+                       return client(server_addr)
+               
+
+       # Create the board
+       
+       # Construct a GameThread! Make it global! Damn the consequences!
+                       
+       if src_file != None:
+               # Hack to stop ReplayThread from exiting
+               #if len(players) == 0:
+               #       players = [HumanPlayer("dummy", "white"), HumanPlayer("dummy", "black")]
+
+               # Normally the ReplayThread exits if there are no players
+               # TODO: Decide which behaviour to use, and fix it
+               end = (len(players) == 0)
+               if end:
+                       players = [Player("dummy", "white"), Player("dummy", "black")]
+               elif len(players) != 2:
+                       sys.stderr.write(sys.argv[0] + " : Usage " + sys.argv[0] + " white black\n")
+                       if graphics_enabled:
+                               sys.stderr.write(sys.argv[0] + " : (You won't get a GUI, because --file was used, and the author is lazy)\n")
+                       return 44
+               game = ReplayThread(players, src_file, end=end, max_moves=max_moves)
+       else:
+               board = Board(style)
+               board.max_moves = max_moves
+               game = GameThread(board, players) 
+
+
+
+
+       # Initialise GUI
+       if graphics_enabled == True:
+               try:
+                       graphics = GraphicsThread(game.board, grid_sz = [64,64]) # Construct a GraphicsThread!
+                       
+                       graphics.sleep_timeout = sleep_timeout
+
+               except Exception,e:
+                       graphics = None
+                       sys.stderr.write(sys.argv[0] + " : Got exception trying to initialise graphics\n"+str(e.message)+"\nDisabled graphics\n")
+                       graphics_enabled = False
+
+       # If there are no players listed, display a nice pretty menu
+       if len(players) != 2:
+               if graphics != None:
+                       
+                       server_addr = graphics.SelectServer()
+                       if server_addr != None:
+                               if server_addr == True:
+                                       return dedicated_server()
+                               else:
+                                       return client(server_addr)      
+                       
+                       players = graphics.SelectPlayers(players)
+               else:
+                       sys.stderr.write(sys.argv[0] + " : Usage " + sys.argv[0] + " white black\n")
+                       return 44
+
+       # If there are still no players, quit
+       if players == None or len(players) != 2:
+               sys.stderr.write(sys.argv[0] + " : Graphics window closed before players chosen\n")
+               return 45
+
+       old = players[:]
+       for p in old:
+               if isinstance(p, NetworkPlayer):
+                       for i in range(len(old)):
+                               if old[i] == p or isinstance(old[i], NetworkPlayer):
+                                       continue
+                               players[i] = NetworkPlayer(old[i].colour, p.network, old[i])
+               
+       for p in players:
+               #debug(str(p))
+               if isinstance(p, NetworkPlayer):
+                       p.board = game.board
+                       if not p.network.connected:
+                               if not p.network.server:
+                                       time.sleep(0.2)
+                               p.network.connect()
+                               
+       
+       # If using windows, select won't work; use horrible TimeoutPlayer hack
+       if agent_timeout > 0:
+               if platform.system() == "Windows":
+                       for i in range(len(players)):
+                               if isinstance(players[i], ExternalAgent) or isinstance(players[i], InternalAgent):
+                                       players[i] = TimeoutPlayer(players[i], agent_timeout)
+
+               else:
+                       warned = False
+                       # InternalAgents get wrapped to an ExternalAgent when there is a timeout
+                       # This is not confusing at all.
+                       for i in range(len(players)):
+                               if isinstance(players[i], InternalAgent):
+                                               players[i] = ExternalWrapper(players[i])
+
+
+               
+
+
+
+
+       log_init(game.board, players)
+       
+       
+       if graphics != None:
+               game.start() # This runs in a new thread
+               graphics.run()
+               if game.is_alive():
+                       game.join()
+       
+
+               error = game.error + graphics.error
+       else:
+               game.run()
+               error = game.error
+       
+
+       for l in log_files:
+               l.close()
+
+       if src_file != None and src_file != sys.stdin:
+               src_file.close()
+
+       sys.stdout.write(game.final_result + "\n")
+
+       return error
+               
+               
+       
+               
+       
+               
+               
+
+# This is how python does a main() function...
+if __name__ == "__main__":
+       retcode = 0
+       try:
+               retcode = main(sys.argv)
+       except KeyboardInterrupt:
+               sys.stderr.write(sys.argv[0] + " : Got KeyboardInterrupt. Stopping everything\n")
+               if isinstance(graphics, StoppableThread):
+                       graphics.stop()
+                       graphics.run() # Will clean up graphics because it is stopped, not run it (a bit dodgy)
+
+               if isinstance(game, StoppableThread):
+                       game.stop()
+                       if game.is_alive():
+                               game.join()
+               retcode = 102
+       #except Exception, e:
+       #       sys.stderr.write(sys.argv[0] + " : " + e.message + "\n")
+       #       retcode = 103   
+               
+       try:
+               sys.stdout.close()
+       except:
+               pass
+       try:
+               sys.stderr.close()
+       except:
+               pass
+       sys.exit(retcode)
+               
+
+# --- main.py --- #
+# EOF - created from make on Sat Apr 20 12:19:31 WST 2013
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/agents/python/data b/agents/python/data
deleted file mode 120000 (symlink)
index 75a080a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../../qchess/data/
\ No newline at end of file
diff --git a/agents/python/data/DejaVuSans.ttf b/agents/python/data/DejaVuSans.ttf
new file mode 100644 (file)
index 0000000..27cff47
Binary files /dev/null and b/agents/python/data/DejaVuSans.ttf differ
diff --git a/agents/python/data/help.txt b/agents/python/data/help.txt
new file mode 100644 (file)
index 0000000..8911f3b
--- /dev/null
@@ -0,0 +1,135 @@
+NAME
+       qchess.py - Play quantum chess
+
+SYNOPSIS
+       qchess.py [OPTIONS] [white] [black]
+
+DESCRIPTION
+       An implementation of Quantum Chess as originally described and implemented here:
+       http://research.cs.queensu.ca/Parallel/QuantumChess/QuantumChess.html
+
+       Reimplemented for UCC::Progcomp 2013
+       http://progcomp.ucc.asn.au
+
+       IMPORTANT:
+        - This version does not implement castling or en passen rules.
+        - If a piece currently in a pawn state moves into the opposing back row, that state always becomes a queen.
+           - (The other state of the piece is unaffected).
+
+
+ARGUMENTS
+
+       If no arguments are given, a window should appear asking you to pick each player.
+       Then the game will commence using default values.
+
+       white, black
+               Each of the two players in order. They need not be provided if graphics is enabled (default).
+               
+               Any arguments that do not begin with a hyphen (-) are treated as the player arguments in the order they appear.
+
+               Player arguments that begin with '@' are treated as special players:
+
+               @human
+                       A human player; if graphics are enabled, this players turns are made through the GUI
+
+               @network[:address]
+                       A player over a network connection. 
+
+                       For example, if black@host1 wants to play white@host2:
+
+                       black@host1:~$ ./qchess.py @network @human
+                       white@host2:~$ ./qchess.py @human @network:host1
+
+                       IMPORTANT: Only ONE of the games should give the other's address.
+
+               @internal:name
+                       An internal agent player
+
+                       These agents run within the qchess program (unless there is a timeout setting... never mind).
+                       
+                       Choices are:
+                       
+                       AgentRandom - Makes random moves only
+
+                       AgentBishop - Uses probability estimates and a min/max recursive (depth is only one) algorithm
+                                   - Will usually take a long time to run
+
+OPTIONS
+
+       --help
+               Print this page
+       
+       --graphics
+               Enable the GUI
+
+               If graphics are enabled (default), then the user will be prompted to choose any of the two players not supplied as arguments.
+
+       --no-graphics
+               Disable the GUI
+               
+               
+       --reveal
+               If graphics are enabled, the two states for pieces will always be shown, regardless of whether both states have been revealed.
+               Note that this switch only affects the GUI and does not provide any information to agent players.
+
+               If graphics are disabled, has no effect.
+
+       --file[=filename][:events]
+               Replay a game saved in file, or read from stdin if no filename given
+               If a number of events is supplied, the game will advance that many events before stopping.
+
+               If no players are given, the GUI will NOT ask for player selections.
+               The game will exit after the replay finishes. Events in the replay will be subject to the normal delay (see --delay).
+
+               If black and white players are supplied, the game will continue using those players.
+               In this case, there will be no delays between events in the replay (the game starts at the end of the replay)
+
+               (We hope that) this feature will be useful for comparing how different versions of an agent respond to the same situation.
+
+       --log[=filename]
+               Log moves to a file or stdout if no filename given
+
+               
+
+       --delay[=time]
+               The game pauses between moves so that it can be followed by a human observer.
+               This option can be used to change the delay. If no time is given, the delay is disabled.
+
+               If graphics are enabled (default), the delay is 0.5s by default.
+               If graphics are disabled, there is no delay unless this option is used.
+
+       --timeout[=time]
+               Set the maximum time in seconds to wait before declaring an AI program unresponsive.
+               If no time is given, the timeout is disabled.
+
+               By default the timeout is disabled.
+               
+       --blackout[=time]
+               Setting a blackout time will cause the display to become black if the mouse is not moved and no keys or buttons are pressed.
+               If no time is given, the blackout time is disabled.
+               
+               By default the blackout is disabled.
+               
+               This switch was introduced for entirely obscure purposes.
+
+       --classical
+               If this option is used, the game will treat pieces "classically", ie: as in standard chess.
+               Note that the game does not enforce rules related to check and checkmate.
+
+       --quantum
+               The game uses the quantum chess representation of pieces (default).
+
+       
+AUTHOR
+       Written for the UCC Programming Competition 2013 by Sam Moore.
+       UCC::Progcomp home page: http://progcomp.ucc.asn.au
+
+REPORTING BUGS
+       Report bugs to [email protected]
+       Join IRC channel #progcomp on irc://irc.ucc.asn.au
+
+COPYRIGHT
+       Copyright 2013 The University Computer Club, Inc.
+
+       Contact [email protected]
+
deleted file mode 120000 (symlink)
index 35c6d6e8a5edf5bdf5173254d57a1c5500b7b59b..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-../../qchess/qchess.py
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..8a3610bd9cfc1d3e4ba1af9565d070f9d645d6b8
--- /dev/null
+#!/usr/bin/python -u
+import random
+
+# I know using non-abreviated strings is inefficient, but this is python, who cares?
+# Oh, yeah, this stores the number of pieces of each type in a normal chess game
+piece_types = {"pawn" : 8, "bishop" : 2, "knight" : 2, "rook" : 2, "queen" : 1, "king" : 1, "unknown" : 0}
+
+# Class to represent a quantum chess piece
+class Piece():
+       def __init__(self, colour, x, y, types):
+               self.colour = colour # Colour (string) either "white" or "black"
+               self.x = x # x coordinate (0 - 8), none of this fancy 'a', 'b' shit here
+               self.y = y # y coordinate (0 - 8)
+               self.types = types # List of possible types the piece can be (should just be two)
+               self.current_type = "unknown" # Current type
+               self.choice = -1 # Index of the current type in self.types (-1 = unknown type)
+               
+               
+               self.last_state = None
+               
+               self.move_pattern = None
+               self.coverage = None
+               self.possible_moves = {}
+               
+
+       def init_from_copy(self, c):
+               self.colour = c.colour
+               self.x = c.x
+               self.y = c.y
+               self.types = c.types[:]
+               self.current_type = c.current_type
+               self.choice = c.choice
+               
+               self.last_state = None
+               self.move_pattern = None
+
+       
+
+       # Make a string for the piece (used for debug)
+       def __str__(self):
+               return str(self.colour) + " " + str(self.current_type) + " " + str(self.types) + " at " + str(self.x) + ","+str(self.y)  
+
+       # Draw the piece in a pygame surface
+       def draw(self, window, grid_sz = [80,80], style="quantum"):
+
+               # First draw the image corresponding to self.current_type
+               img = images[self.colour][self.current_type]
+               rect = img.get_rect()
+               if style == "classical":
+                       offset = [-rect.width/2, -rect.height/2]
+               else:
+                       offset = [-rect.width/2,-3*rect.height/4] 
+               window.blit(img, (self.x * grid_sz[0] + grid_sz[0]/2 + offset[0], self.y * grid_sz[1] + grid_sz[1]/2 + offset[1]))
+               
+               
+               if style == "classical":
+                       return
+
+               # Draw the two possible types underneath the current_type image
+               for i in range(len(self.types)):
+                       if always_reveal_states == True or self.types[i][0] != '?':
+                               if self.types[i][0] == '?':
+                                       img = small_images[self.colour][self.types[i][1:]]
+                               else:
+                                       img = small_images[self.colour][self.types[i]]
+                       else:
+                               img = small_images[self.colour]["unknown"] # If the type hasn't been revealed, show a placeholder
+
+                       
+                       rect = img.get_rect()
+                       offset = [-rect.width/2,-rect.height/2] 
+                       
+                       if i == 0:
+                               target = (self.x * grid_sz[0] + grid_sz[0]/5 + offset[0], self.y * grid_sz[1] + 3*grid_sz[1]/4 + offset[1])                             
+                       else:
+                               target = (self.x * grid_sz[0] + 4*grid_sz[0]/5 + offset[0], self.y * grid_sz[1] + 3*grid_sz[1]/4 + offset[1])                           
+                               
+                       window.blit(img, target) # Blit shit
+       
+       # Collapses the wave function!          
+       def select(self):
+               if self.current_type == "unknown" or not self.choice in [0,1]:
+                       self.choice = random.randint(0,1)
+                       if self.types[self.choice][0] == '?':
+                               self.types[self.choice] = self.types[self.choice][1:]
+                       self.current_type = self.types[self.choice]
+               return self.choice
+
+       # Uncollapses (?) the wave function!
+       def deselect(self):
+               #print "Deselect called"
+               if (self.x + self.y) % 2 != 0:
+                       if (self.types[0] != self.types[1]) or (self.types[0][0] == '?' or self.types[1][0] == '?'):
+                               self.current_type = "unknown"
+                               self.choice = -1
+                       else:
+                               self.choice = 0 # Both the two types are the same
+
+       # The sad moment when you realise that you do not understand anything about a subject you studied for 4 years...
+# --- piece.py --- #
+[w,h] = [8,8] # Width and height of board(s)
+
+always_reveal_states = False
+
+# Class to represent a quantum chess board
+class Board():
+       # Initialise; if master=True then the secondary piece types are assigned
+       #       Otherwise, they are left as unknown
+       #       So you can use this class in Agent programs, and fill in the types as they are revealed
+       def __init__(self, style="agent"):
+               self.style = style
+               self.pieces = {"white" : [], "black" : []}
+               self.grid = [[None] * w for _ in range(h)] # 2D List (you can get arrays in python, somehow, but they scare me)
+               self.unrevealed_types = {"white" : piece_types.copy(), "black" : piece_types.copy()}
+               self.king = {"white" : None, "black" : None} # We need to keep track of the king, because he is important
+               self.max_moves = None
+               self.moves = 0
+               self.move_stack = []
+               for c in ["black", "white"]:
+                       del self.unrevealed_types[c]["unknown"]
+
+               if style == "empty":
+                       return
+
+               # Add all the pieces with known primary types
+               for i in range(0, 2):
+                       
+                       s = ["black", "white"][i]
+                       c = self.pieces[s]
+                       y = [0, h-1][i]
+
+                       c.append(Piece(s, 0, y, ["rook"]))
+                       c.append(Piece(s, 1, y, ["knight"]))
+                       c.append(Piece(s, 2, y, ["bishop"]))
+                       k = Piece(s, 3, y, ["king", "king"]) # There can only be one ruler!
+                       k.current_type = "king"
+                       self.king[s] = k
+                       c.append(k)
+                       c.append(Piece(s, 4, y, ["queen"])) # Apparently he may have multiple wives though.
+                       c.append(Piece(s, 5, y, ["bishop"]))
+                       c.append(Piece(s, 6, y, ["knight"]))
+                       c.append(Piece(s, 7, y, ["rook"]))
+                       
+                       if y == 0: 
+                               y += 1 
+                       else: 
+                               y -= 1
+                       
+                       # Lots of pawn
+                       for x in range(0, w):
+                               c.append(Piece(s, x, y, ["pawn"]))
+
+                       types_left = {}
+                       types_left.update(piece_types)
+                       del types_left["king"] # We don't want one of these randomly appearing (although it might make things interesting...)
+                       del types_left["unknown"] # We certainly don't want these!
+                       for piece in c:
+                               # Add to grid
+                               self.grid[piece.x][piece.y] = piece 
+
+                               if len(piece.types) > 1:
+                                       continue                                
+                               if style == "agent": # Assign placeholder "unknown" secondary type
+                                       piece.types.append("unknown")
+                                       continue
+
+                               elif style == "quantum":
+                                       # The master allocates the secondary types
+                                       choice = types_left.keys()[random.randint(0, len(types_left.keys())-1)]
+                                       types_left[choice] -= 1
+                                       if types_left[choice] <= 0:
+                                               del types_left[choice]
+                                       piece.types.append('?' + choice)
+                               elif style == "classical":
+                                       piece.types.append(piece.types[0])
+                                       piece.current_type = piece.types[0]
+                                       piece.choice = 0
+
+       def clone(self):
+               newboard = Board(master = False)
+               newpieces = newboard.pieces["white"] + newboard.pieces["black"]
+               mypieces = self.pieces["white"] + self.pieces["black"]
+
+               for i in range(len(mypieces)):
+                       newpieces[i].init_from_copy(mypieces[i])
+       
+       # Reset the board from a string
+       def reset_board(self, s):
+               self.pieces = {"white" : [], "black" : []}
+               self.king = {"white" : None, "black" : None}
+               self.grid = [[None] * w for _ in range(h)]
+               for x in range(w):
+                       for y in range(h):
+                               self.grid[x][y] = None
+
+               for line in s.split("\n"):
+                       if line == "":
+                               continue
+                       if line[0] == "#":
+                               continue
+
+                       tokens = line.split(" ")
+                       [x, y] = map(int, tokens[len(tokens)-1].split(","))
+                       current_type = tokens[1]
+                       types = map(lambda e : e.strip(" '[],"), line.split('[')[1].split(']')[0].split(','))
+                       
+                       target = Piece(tokens[0], x, y, types)
+                       target.current_type = current_type
+                       
+                       try:
+                               target.choice = types.index(current_type)
+                       except:
+                               target.choice = -1
+
+                       self.pieces[tokens[0]].append(target)
+                       if target.current_type == "king":
+                               self.king[tokens[0]] = target
+
+                       self.grid[x][y] = target
+                       
+
+       def display_grid(self, window = None, grid_sz = [80,80]):
+               if window == None:
+                       return # I was considering implementing a text only display, then I thought "Fuck that"
+
+               # The indentation is getting seriously out of hand...
+               for x in range(0, w):
+                       for y in range(0, h):
+                               if (x + y) % 2 == 0:
+                                       c = pygame.Color(200,200,200)
+                               else:
+                                       c = pygame.Color(64,64,64)
+                               pygame.draw.rect(window, c, (x*grid_sz[0], y*grid_sz[1], (x+1)*grid_sz[0], (y+1)*grid_sz[1]))
+
+       def display_pieces(self, window = None, grid_sz = [80,80]):
+               if window == None:
+                       return
+               for p in self.pieces["white"] + self.pieces["black"]:
+                       p.draw(window, grid_sz, self.style)
+
+       # Draw the board in a pygame window
+       def display(self, window = None):
+               self.display_grid(window)
+               self.display_pieces(window)
+               
+
+               
+
+       def verify(self):
+               for x in range(w):
+                       for y in range(h):
+                               if self.grid[x][y] == None:
+                                       continue
+                               if (self.grid[x][y].x != x or self.grid[x][y].y != y):
+                                       raise Exception(sys.argv[0] + ": MISMATCH " + str(self.grid[x][y]) + " should be at " + str(x) + "," + str(y))
+
+       # Select a piece on the board (colour is the colour of whoever is doing the selecting)
+       def select(self, x,y, colour=None):
+               if not self.on_board(x, y): # Get on board everyone!
+                       raise Exception("BOUNDS " + str(x) + ","+str(y))
+
+               piece = self.grid[x][y]
+               if piece == None:
+                       raise Exception("EMPTY")
+
+               if colour != None and piece.colour != colour:
+                       raise Exception("COLOUR " + str(piece.colour) + " not " + str(colour))
+
+               # I'm not quite sure why I made this return a string, but screw logical design
+               return str(x) + " " + str(y) + " " + str(piece.select()) + " " + str(piece.current_type)
+
+
+       # Update the board when a piece has been selected
+       # "type" is apparently reserved, so I'll use "state"
+       def update_select(self, x, y, type_index, state, sanity=True, deselect=True):
+               #debug(str(self) + " update_select called")
+               piece = self.grid[x][y]
+               if piece.types[type_index] == "unknown":
+                       if not state in self.unrevealed_types[piece.colour].keys() and sanity == True:
+                               raise Exception("SANITY: Too many " + piece.colour + " " + state + "s")
+                       self.unrevealed_types[piece.colour][state] -= 1
+                       if self.unrevealed_types[piece.colour][state] <= 0:
+                               del self.unrevealed_types[piece.colour][state]
+
+               piece.types[type_index] = state
+               piece.current_type = state
+
+               if deselect == True and len(self.possible_moves(piece)) <= 0:
+                       piece.deselect() # Piece can't move; deselect it
+                       
+               # Piece needs to recalculate moves
+               piece.possible_moves = None
+               
+       # Update the board when a piece has been moved
+       def update_move(self, x, y, x2, y2, sanity=True):
+               #debug(str(self) + " update_move called \""+str(x)+ " " + str(y) + " -> " + str(x2) + " " + str(y2) + "\"")     
+               piece = self.grid[x][y]
+               #print "Moving " + str(x) + "," + str(y) + " to " + str(x2) + "," + str(y2) + "; possible_moves are " + str(self.possible_moves(piece))
+               
+               if not [x2,y2] in self.possible_moves(piece) and sanity == True:
+                       raise Exception("ILLEGAL move " + str(x2)+","+str(y2))
+               
+               self.grid[x][y] = None
+               taken = self.grid[x2][y2]
+               if taken != None:
+                       if taken.current_type == "king":
+                               self.king[taken.colour] = None
+                       self.pieces[taken.colour].remove(taken)
+               self.grid[x2][y2] = piece
+               piece.x = x2
+               piece.y = y2
+
+               # If the piece is a pawn, and it reaches the final row, it becomes a queen
+               # I know you are supposed to get a choice
+               # But that would be effort
+               if piece.current_type == "pawn" and ((piece.colour == "white" and piece.y == 0) or (piece.colour == "black" and piece.y == h-1)):
+                       if self.style == "classical":
+                               piece.types[0] = "queen"
+                               piece.types[1] = "queen"
+                       else:
+                               piece.types[piece.choice] = "queen"
+                       piece.current_type = "queen"
+
+               piece.deselect() # Uncollapse (?) the wavefunction!
+               self.moves += 1
+               
+               # All other pieces need to recalculate moves
+               for p in self.pieces["white"] + self.pieces["black"]:
+                       p.possible_moves = None
+               
+               #self.verify()  
+
+       # Update the board from a string
+       # Guesses what to do based on the format of the string
+       def update(self, result, sanity=True, deselect=True):
+               #debug(str(self) + " update called \""+str(result)+"\"")
+               # String always starts with 'x y'
+               try:
+                       s = result.split(" ")
+                       [x,y] = map(int, s[0:2])        
+               except:
+                       raise Exception("GIBBERISH \""+ str(result) + "\"") # Raise expectations
+
+               piece = self.grid[x][y]
+               if piece == None and sanity == True:
+                       raise Exception("EMPTY " + str(x) + " " + str(y))
+
+               # If a piece is being moved, the third token is '->'
+               # We could get away with just using four integers, but that wouldn't look as cool
+               if "->" in s:
+                       # Last two tokens are the destination
+                       try:
+                               [x2,y2] = map(int, s[3:])
+                       except:
+                               raise Exception("GIBBERISH \"" + str(result) + "\"") # Raise the alarm
+
+                       # Move the piece (take opponent if possible)
+                       self.update_move(x, y, x2, y2, sanity)
+                       
+               else:
+                       # Otherwise we will just assume a piece has been selected
+                       try:
+                               type_index = int(s[2]) # We need to know which of the two types the piece is in; that's the third token
+                               state = s[3] # The last token is a string identifying the type
+                       except:
+                               raise Exception("GIBBERISH \"" + result + "\"") # Throw a hissy fit
+
+
+                       # Select the piece
+                       self.update_select(x, y, type_index, state, sanity=sanity, deselect=deselect)
+
+               return result
+
+       # Gets each piece that could reach the given square and the probability that it could reach that square 
+       # Will include allied pieces that defend the attacker
+       def coverage(self, x, y, colour = None, reject_allied = True):
+               result = {}
+               
+               if colour == None:
+                       pieces = self.pieces["white"] + self.pieces["black"]
+               else:
+                       pieces = self.pieces[colour]
+
+               for p in pieces:
+                       prob = self.probability_grid(p, reject_allied)[x][y]
+                       if prob > 0:
+                               result.update({p : prob})
+               
+               #self.verify()
+               return result
+
+
+               
+
+
+       # Associates each square with a probability that the piece could move into it
+       # Look, I'm doing all the hard work for you here...
+       def probability_grid(self, p, reject_allied = True):
+               
+               result = [[0.0] * w for _ in range(h)]
+               if not isinstance(p, Piece):
+                       return result
+
+               if p.current_type != "unknown":
+                       #sys.stderr.write(sys.argv[0] + ": " + str(p) + " moves " + str(self.possible_moves(p, reject_allied)) + "\n")
+                       for point in self.possible_moves(p, reject_allied):
+                               result[point[0]][point[1]] = 1.0
+                       return result
+               
+               
+               for i in range(len(p.types)):
+                       t = p.types[i]
+                       prob = 1.0 / float(len(p.types))
+                       if t == "unknown" or p.types[i][0] == '?':
+                               total_types = 0
+                               for t2 in self.unrevealed_types[p.colour].keys():
+                                       total_types += self.unrevealed_types[p.colour][t2]
+                               
+                               for t2 in self.unrevealed_types[p.colour].keys():
+                                       prob2 = float(self.unrevealed_types[p.colour][t2]) / float(total_types)
+                                       #p.current_type = t2
+                                       for point in self.possible_moves(p, reject_allied, state=t2):
+                                               result[point[0]][point[1]] += prob2 * prob
+                               
+                       else:
+                               #p.current_type = t
+                               for point in self.possible_moves(p, reject_allied, state=t):
+                                               result[point[0]][point[1]] += prob
+               
+               #self.verify()
+               #p.current_type = "unknown"
+               return result
+
+       def prob_is_type(self, p, state):
+               prob = 0.5
+               result = 0
+               for i in range(len(p.types)):
+                       t = p.types[i]
+                       if t == state:
+                               result += prob
+                               continue        
+                       if t == "unknown" or p.types[i][0] == '?':
+                               total_prob = 0
+                               for t2 in self.unrevealed_types[p.colour].keys():
+                                       total_prob += self.unrevealed_types[p.colour][t2]
+                               for t2 in self.unrevealed_types[p.colour].keys():
+                                       if t2 == state:
+                                               result += prob * float(self.unrevealed_types[p.colour][t2]) / float(total_prob)
+                               
+
+
+       # Get all squares that the piece could move into
+       # This is probably inefficient, but I looked at some sample chess games and they seem to actually do things this way
+       # reject_allied indicates whether squares occupied by allied pieces will be removed
+       # (set to false to check for defense)
+       def possible_moves(self, p, reject_allied = True, state=None):
+               if p == None:
+                       raise Exception("SANITY: No piece")
+               
+               
+               
+               if state != None and state != p.current_type:
+                       old_type = p.current_type
+                       p.current_type = state
+                       result = self.possible_moves(p, reject_allied, state=None)
+                       p.current_type = old_type
+                       return result
+               
+               
+               
+               
+               result = []
+               
+
+               
+               if p.current_type == "unknown":
+                       raise Exception("SANITY: Unknown state for piece: "+str(p))
+                       # The below commented out code causes things to break badly
+                       #for t in p.types:
+                       #       if t == "unknown":
+                       #               continue
+                       #       p.current_type = t
+                       #       result += self.possible_moves(p)                                                
+                       #p.current_type = "unknown"
+                       #return result
+
+               if p.current_type == "king":
+                       result = [[p.x-1,p.y],[p.x+1,p.y],[p.x,p.y-1],[p.x,p.y+1], [p.x-1,p.y-1],[p.x-1,p.y+1],[p.x+1,p.y-1],[p.x+1,p.y+1]]
+               elif p.current_type == "queen":
+                       for d in [[-1,0],[1,0],[0,-1],[0,1],[-1,-1],[-1,1],[1,-1],[1,1]]:
+                               result += self.scan(p.x, p.y, d[0], d[1])
+               elif p.current_type == "bishop":
+                       for d in [[-1,-1],[-1,1],[1,-1],[1,1]]: # There's a reason why bishops move diagonally
+                               result += self.scan(p.x, p.y, d[0], d[1])
+               elif p.current_type == "rook":
+                       for d in [[-1,0],[1,0],[0,-1],[0,1]]:
+                               result += self.scan(p.x, p.y, d[0], d[1])
+               elif p.current_type == "knight":
+                       # I would use two lines, but I'm not sure how python likes that
+                       result = [[p.x-2, p.y-1], [p.x-2, p.y+1], [p.x+2, p.y-1], [p.x+2,p.y+1], [p.x-1,p.y-2], [p.x-1, p.y+2],[p.x+1,p.y-2],[p.x+1,p.y+2]]
+               elif p.current_type == "pawn":
+                       if p.colour == "white":
+                               
+                               # Pawn can't move forward into occupied square
+                               if self.on_board(p.x, p.y-1) and self.grid[p.x][p.y-1] == None:
+                                       result = [[p.x,p.y-1]]
+                               for f in [[p.x-1,p.y-1],[p.x+1,p.y-1]]:
+                                       if not self.on_board(f[0], f[1]):
+                                               continue
+                                       if self.grid[f[0]][f[1]] != None:  # Pawn can take diagonally
+                                               result.append(f)
+                               if p.y == h-2:
+                                       # Slightly embarrassing if the pawn jumps over someone on its first move...
+                                       if self.grid[p.x][p.y-1] == None and self.grid[p.x][p.y-2] == None:
+                                               result.append([p.x, p.y-2])
+                       else:
+                               # Vice versa for the black pawn
+                               if self.on_board(p.x, p.y+1) and self.grid[p.x][p.y+1] == None:
+                                       result = [[p.x,p.y+1]]
+
+                               for f in [[p.x-1,p.y+1],[p.x+1,p.y+1]]:
+                                       if not self.on_board(f[0], f[1]):
+                                               continue
+                                       if self.grid[f[0]][f[1]] != None:
+                                               #sys.stderr.write(sys.argv[0] + " : "+str(p) + " can take " + str(self.grid[f[0]][f[1]]) + "\n")
+                                               result.append(f)
+                               if p.y == 1:
+                                       if self.grid[p.x][p.y+1] == None and self.grid[p.x][p.y+2] == None:
+                                               result.append([p.x, p.y+2])
+
+                       #sys.stderr.write(sys.argv[0] + " : possible_moves for " + str(p) + " " + str(result) + "\n")
+
+               # Remove illegal moves
+               # Note: The result[:] creates a copy of result, so that the result.remove calls don't fuck things up
+               for point in result[:]: 
+
+                       if (point[0] < 0 or point[0] >= w) or (point[1] < 0 or point[1] >= h):
+                               result.remove(point) # Remove locations outside the board
+                               continue
+                       g = self.grid[point[0]][point[1]]
+                       
+                       if g != None and (g.colour == p.colour and reject_allied == True):
+                               result.remove(point) # Remove allied pieces
+               
+               #self.verify()
+               
+               p.possible_moves = result
+               return result
+
+
+       # Scans in a direction until it hits a piece, returns all squares in the line
+       # (includes the final square (which contains a piece), but not the original square)
+       def scan(self, x, y, vx, vy):
+               p = []
+                       
+               xx = x
+               yy = y
+               while True:
+                       xx += vx
+                       yy += vy
+                       if not self.on_board(xx, yy):
+                               break
+                       if not [xx,yy] in p:
+                               p.append([xx, yy])
+                       g = self.grid[xx][yy]
+                       if g != None:
+                               return p        
+                                       
+               return p
+
+       # Returns "white", "black" or "DRAW" if the game should end
+       def end_condition(self):
+               if self.king["white"] == None:
+                       if self.king["black"] == None:
+                               return "DRAW" # This shouldn't happen
+                       return "black"
+               elif self.king["black"] == None:
+                       return "white"
+               elif len(self.pieces["white"]) == 1 and len(self.pieces["black"]) == 1:
+                       return "DRAW"
+               elif self.max_moves != None and self.moves > self.max_moves:
+                       return "DRAW"
+               return None
+
+
+       # I typed the full statement about 30 times before writing this function...
+       def on_board(self, x, y):
+               return (x >= 0 and x < w) and (y >= 0 and y < h)
+       
+       # Pushes a move temporarily
+       def push_move(self, piece, x, y):
+               target = self.grid[x][y]
+               self.move_stack.append([piece, target, piece.x, piece.y, x, y])
+               [piece.x, piece.y] = [x, y]
+               self.grid[x][y] = piece
+               self.grid[piece.x][piece.y] = None
+               
+               for p in self.pieces["white"] + self.pieces["black"]:
+                       p.possible_moves = None
+               
+       # Restore move
+       def pop_move(self):
+               #print str(self.move_stack)
+               [piece, target, x1, y1, x2, y2] = self.move_stack[len(self.move_stack)-1]
+               self.move_stack = self.move_stack[:-1]
+               piece.x = x1
+               piece.y = y1
+               self.grid[x1][y1] = piece
+               if target != None:
+                       target.x = x2
+                       target.y = y2
+               self.grid[x2][y2] = target
+               
+               for p in self.pieces["white"] + self.pieces["black"]:
+                               p.possible_moves = None
+               
+# --- board.py --- #
+import subprocess
+import select
+import platform
+import re
+
+agent_timeout = -1.0 # Timeout in seconds for AI players to make moves
+                       # WARNING: Won't work for windows based operating systems
+
+if platform.system() == "Windows":
+       agent_timeout = -1 # Hence this
+
+# A player who can't play
+class Player():
+       def __init__(self, name, colour):
+               self.name = name
+               self.colour = colour
+
+       def update(self, result):
+               return result
+
+       def reset_board(self, s):
+               pass
+       
+       def __str__(self):
+               return self.name + "<"+str(self.colour)+">"
+
+       def base_player(self):
+               return self
+
+# Player that runs from another process
+class ExternalAgent(Player):
+
+
+       def __init__(self, name, colour):
+               Player.__init__(self, name, colour)
+               self.p = subprocess.Popen(name,bufsize=0,stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True,universal_newlines=True)
+               
+               self.send_message(colour)
+
+       def send_message(self, s):
+               if agent_timeout > 0.0:
+                       ready = select.select([], [self.p.stdin], [], agent_timeout)[1]
+               else:
+                       ready = [self.p.stdin]
+               if self.p.stdin in ready:
+                       #sys.stderr.write("Writing \'" + s + "\' to " + str(self.p) + "\n")
+                       try:
+                               self.p.stdin.write(s + "\n")
+                       except:
+                               raise Exception("UNRESPONSIVE")
+               else:
+                       raise Exception("TIMEOUT")
+
+       def get_response(self):
+               if agent_timeout > 0.0:
+                       ready = select.select([self.p.stdout], [], [], agent_timeout)[0]
+               else:
+                       ready = [self.p.stdout]
+               if self.p.stdout in ready:
+                       #sys.stderr.write("Reading from " + str(self.p) + " 's stdout...\n")
+                       try:
+                               result = self.p.stdout.readline().strip(" \t\r\n")
+                               #sys.stderr.write("Read \'" + result + "\' from " + str(self.p) + "\n")
+                               return result
+                       except: # Exception, e:
+                               raise Exception("UNRESPONSIVE")
+               else:
+                       raise Exception("TIMEOUT")
+
+       def select(self):
+
+               self.send_message("SELECTION?")
+               line = self.get_response()
+               
+               try:
+                       m = re.match("\s*(\d+)\s+(\d+)\s*", line)
+                       result = map(int, [m.group(1), m.group(2)])
+               except:
+                       raise Exception("GIBBERISH \"" + str(line) + "\"")
+               return result
+
+       def update(self, result):
+               #print "Update " + str(result) + " called for AgentPlayer"
+               self.send_message(result)
+               return result
+
+       def get_move(self):
+               
+               self.send_message("MOVE?")
+               line = self.get_response()
+               
+               try:
+                       m = re.match("\s*(\d+)\s+(\d+)\s*", line)
+                       result = map(int, [m.group(1), m.group(2)])
+
+               except:
+                       raise Exception("GIBBERISH \"" + str(line) + "\"")
+               return result
+
+       def reset_board(self, s):
+               self.send_message("BOARD")
+               for line in s.split("\n"):
+                       self.send_message(line.strip(" \r\n"))
+               self.send_message("END BOARD")
+
+       def quit(self, final_result):
+               try:
+                       self.send_message("QUIT " + final_result)
+               except:
+                       self.p.kill()
+
+# So you want to be a player here?
+class HumanPlayer(Player):
+       def __init__(self, name, colour):
+               Player.__init__(self, name, colour)
+               
+       # Select your preferred account
+       def select(self):
+               if isinstance(graphics, GraphicsThread):
+                       # Basically, we let the graphics thread do some shit and then return that information to the game thread
+                       graphics.cond.acquire()
+                       # We wait for the graphics thread to select a piece
+                       while graphics.stopped() == False and graphics.state["select"] == None:
+                               graphics.cond.wait() # The difference between humans and machines is that humans sleep
+                       select = graphics.state["select"]
+                       
+                       
+                       graphics.cond.release()
+                       if graphics.stopped():
+                               return [-1,-1]
+                       return [select.x, select.y]
+               else:
+                       # Since I don't display the board in this case, I'm not sure why I filled it in...
+                       while True:
+                               sys.stdout.write("SELECTION?\n")
+                               try:
+                                       p = map(int, sys.stdin.readline().strip("\r\n ").split(" "))
+                               except:
+                                       sys.stderr.write("ILLEGAL GIBBERISH\n")
+                                       continue
+       # It's your move captain
+       def get_move(self):
+               if isinstance(graphics, GraphicsThread):
+                       graphics.cond.acquire()
+                       while graphics.stopped() == False and graphics.state["dest"] == None:
+                               graphics.cond.wait()
+                       graphics.cond.release()
+                       
+                       return graphics.state["dest"]
+               else:
+
+                       while True:
+                               sys.stdout.write("MOVE?\n")
+                               try:
+                                       p = map(int, sys.stdin.readline().strip("\r\n ").split(" "))
+                               except:
+                                       sys.stderr.write("ILLEGAL GIBBERISH\n")
+                                       continue
+
+       # Are you sure you want to quit?
+       def quit(self, final_result):
+               if graphics == None:            
+                       sys.stdout.write("QUIT " + final_result + "\n")
+
+       # Completely useless function
+       def update(self, result):
+               if isinstance(graphics, GraphicsThread):
+                       pass
+               else:
+                       sys.stdout.write(result + "\n") 
+               return result
+
+
+# Default internal player (makes random moves)
+class InternalAgent(Player):
+       def __init__(self, name, colour):
+               Player.__init__(self, name, colour)
+               self.choice = None
+
+               self.board = Board(style = "agent")
+
+
+
+       def update(self, result):
+               
+               self.board.update(result)
+               #self.board.verify()
+               return result
+
+       def reset_board(self, s):
+               self.board.reset_board(s)
+
+       def quit(self, final_result):
+               pass
+
+class AgentRandom(InternalAgent):
+       def __init__(self, name, colour):
+               InternalAgent.__init__(self, name, colour)
+
+       def select(self):
+               while True:
+                       self.choice = self.board.pieces[self.colour][random.randint(0, len(self.board.pieces[self.colour])-1)]
+                       all_moves = []
+                       # Check that the piece has some possibility to move
+                       tmp = self.choice.current_type
+                       if tmp == "unknown": # For unknown pieces, try both types
+                               for t in self.choice.types:
+                                       if t == "unknown":
+                                               continue
+                                       self.choice.current_type = t
+                                       all_moves += self.board.possible_moves(self.choice)
+                       else:
+                               all_moves = self.board.possible_moves(self.choice)
+                       self.choice.current_type = tmp
+                       if len(all_moves) > 0:
+                               break
+               return [self.choice.x, self.choice.y]
+
+       def get_move(self):
+               moves = self.board.possible_moves(self.choice)
+               move = moves[random.randint(0, len(moves)-1)]
+               return move
+
+
+# Terrible, terrible hacks
+
+def run_agent(agent):
+       #sys.stderr.write(sys.argv[0] + " : Running agent " + str(agent) + "\n")
+       while True:
+               line = sys.stdin.readline().strip(" \r\n")
+               if line == "SELECTION?":
+                       #sys.stderr.write(sys.argv[0] + " : Make selection\n")
+                       [x,y] = agent.select() # Gets your agent's selection
+                       #sys.stderr.write(sys.argv[0] + " : Selection was " + str(agent.choice) + "\n")
+                       sys.stdout.write(str(x) + " " + str(y) + "\n")                          
+               elif line == "MOVE?":
+                       #sys.stderr.write(sys.argv[0] + " : Make move\n")
+                       [x,y] = agent.get_move() # Gets your agent's move
+                       sys.stdout.write(str(x) + " " + str(y) + "\n")
+               elif line.split(" ")[0] == "QUIT":
+                       #sys.stderr.write(sys.argv[0] + " : Quitting\n")
+                       agent.quit(" ".join(line.split(" ")[1:])) # Quits the game
+                       break
+               elif line.split(" ")[0] == "BOARD":
+                       s = ""
+                       line = sys.stdin.readline().strip(" \r\n")
+                       while line != "END BOARD":
+                               s += line + "\n"
+                               line = sys.stdin.readline().strip(" \r\n")
+                       agent.board.reset_board(s)
+                       
+               else:
+                       agent.update(line) # Updates agent.board
+       return 0
+
+
+# Sort of works?
+
+class ExternalWrapper(ExternalAgent):
+       def __init__(self, agent):
+               run = "python -u -c \"import sys;import os;from qchess import *;agent = " + agent.__class__.__name__ + "('" + agent.name + "','"+agent.colour+"');sys.stdin.readline();sys.exit(run_agent(agent))\""
+               # str(run)
+               ExternalAgent.__init__(self, run, agent.colour)
+
+       
+
+# --- player.py --- #
+# A sample agent
+
+
+class AgentBishop(AgentRandom): # Inherits from AgentRandom (in qchess)
+       def __init__(self, name, colour):
+               InternalAgent.__init__(self, name, colour)
+               self.value = {"pawn" : 1, "bishop" : 3, "knight" : 3, "rook" : 5, "queen" : 9, "king" : 100, "unknown" : 4}
+
+               self.aggression = 2.0 # Multiplier for scoring due to aggressive actions
+               self.defence = 1.0 # Multiplier for scoring due to defensive actions
+               
+               self.depth = 0 # Current depth
+               self.max_depth = 2 # Recurse this many times (for some reason, makes more mistakes when this is increased???)
+               self.recurse_for = -1 # Recurse for the best few moves each times (less than 0 = all moves)
+
+               for p in self.board.pieces["white"] + self.board.pieces["black"]:
+                       p.last_moves = None
+                       p.selected_moves = None
+
+               
+
+       def get_value(self, piece):
+               if piece == None:
+                       return 0.0
+               return float(self.value[piece.types[0]] + self.value[piece.types[1]]) / 2.0
+               
+       # Score possible moves for the piece
+       
+       def prioritise_moves(self, piece):
+
+               #sys.stderr.write(sys.argv[0] + " : " + str(self) + " prioritise called for " + str(piece) + "\n")
+
+               
+               
+               grid = self.board.probability_grid(piece)
+               #sys.stderr.write("\t Probability grid " + str(grid) + "\n")
+               moves = []
+               for x in range(w):
+                       for y in range(h):
+                               if grid[x][y] < 0.3: # Throw out moves with < 30% probability
+                                       #sys.stderr.write("\tReject " + str(x) + "," + str(y) + " (" + str(grid[x][y]) + ")\n")
+                                       continue
+
+                               target = self.board.grid[x][y]
+                       
+                               
+                               
+                               
+                               # Get total probability that the move is protected
+                               self.board.push_move(piece, x, y)
+                               
+
+                               
+                               defenders = self.board.coverage(x, y, piece.colour, reject_allied = False)
+                               d_prob = 0.0
+                               for d in defenders.keys():
+                                       d_prob += defenders[d]
+                               if len(defenders.keys()) > 0:
+                                       d_prob /= float(len(defenders.keys()))
+
+                               if (d_prob > 1.0):
+                                       d_prob = 1.0
+
+                               # Get total probability that the move is threatened
+                               attackers = self.board.coverage(x, y, opponent(piece.colour), reject_allied = False)
+                               a_prob = 0.0
+                               for a in attackers.keys():
+                                       a_prob += attackers[a]
+                               if len(attackers.keys()) > 0:
+                                       a_prob /= float(len(attackers.keys()))
+
+                               if (a_prob > 1.0):
+                                       a_prob = 1.0
+
+                               self.board.pop_move()
+                               
+
+                               
+                               # Score of the move
+                               value = self.aggression * (1.0 + d_prob) * self.get_value(target) - self.defence * (1.0 - d_prob) * a_prob * self.get_value(piece)
+
+                               # Adjust score based on movement of piece out of danger
+                               attackers = self.board.coverage(piece.x, piece.y, opponent(piece.colour))
+                               s_prob = 0.0
+                               for a in attackers.keys():
+                                       s_prob += attackers[a]
+                               if len(attackers.keys()) > 0:
+                                       s_prob /= float(len(attackers.keys()))
+
+                               if (s_prob > 1.0):
+                                       s_prob = 1.0
+                               value += self.defence * s_prob * self.get_value(piece)
+                               
+                               # Adjust score based on probability that the move is actually possible
+                               moves.append([[x, y], grid[x][y] * value])
+
+               moves.sort(key = lambda e : e[1], reverse = True)
+               #sys.stderr.write(sys.argv[0] + ": Moves for " + str(piece) + " are " + str(moves) + "\n")
+
+               piece.last_moves = moves
+               piece.selected_moves = None
+
+               
+
+               
+               return moves
+
+       def select_best(self, colour):
+
+               self.depth += 1
+               all_moves = {}
+               for p in self.board.pieces[colour]:
+                       self.choice = p # Temporarily pick that piece
+                       m = self.prioritise_moves(p)
+                       if len(m) > 0:
+                               all_moves.update({p : m[0]})
+
+               if len(all_moves.items()) <= 0:
+                       return None
+               
+               
+               opts = all_moves.items()
+               opts.sort(key = lambda e : e[1][1], reverse = True)
+
+               if self.depth >= self.max_depth:
+                       self.depth -= 1
+                       return list(opts[0])
+
+               if self.recurse_for >= 0:
+                       opts = opts[0:self.recurse_for]
+               #sys.stderr.write(sys.argv[0] + " : Before recurse, options are " + str(opts) + "\n")
+
+               # Take the best few moves, and recurse
+               for choice in opts[0:self.recurse_for]:
+                       [xx,yy] = [choice[0].x, choice[0].y] # Remember position
+                       [nx,ny] = choice[1][0] # Target
+                       [choice[0].x, choice[0].y] = [nx, ny] # Set position
+                       target = self.board.grid[nx][ny] # Remember piece in spot
+                       self.board.grid[xx][yy] = None # Remove piece
+                       self.board.grid[nx][ny] = choice[0] # Replace with moving piece
+                       
+                       # Recurse
+                       best_enemy_move = self.select_best(opponent(choice[0].colour))
+                       choice[1][1] -= best_enemy_move[1][1] / float(self.depth + 1.0)
+                       
+                       [choice[0].x, choice[0].y] = [xx, yy] # Restore position
+                       self.board.grid[nx][ny] = target # Restore taken piece
+                       self.board.grid[xx][yy] = choice[0] # Restore moved piece
+                       
+               
+
+               opts.sort(key = lambda e : e[1][1], reverse = True)
+               #sys.stderr.write(sys.argv[0] + " : After recurse, options are " + str(opts) + "\n")
+
+               self.depth -= 1
+               return list(opts[0])
+
+               
+
+       # Returns [x,y] of selected piece
+       def select(self):
+               #sys.stderr.write("Getting choice...")
+               self.choice = self.select_best(self.colour)[0]
+               
+               #sys.stderr.write(" Done " + str(self.choice)+"\n")
+               return [self.choice.x, self.choice.y]
+       
+       # Returns [x,y] of square to move selected piece into
+       def get_move(self):
+               #sys.stderr.write("Choice is " + str(self.choice) + "\n")
+               self.choice.selected_moves = self.choice.last_moves
+               moves = self.prioritise_moves(self.choice)
+               if len(moves) > 0:
+                       return moves[0][0]
+               else:
+                       return AgentRandom.get_move(self)
+
+# --- agent_bishop.py --- #
+import multiprocessing
+
+# Hacky alternative to using select for timing out players
+
+# WARNING: Do not wrap around HumanPlayer or things breakify
+# WARNING: Do not use in general or things breakify
+
+class Sleeper(multiprocessing.Process):
+       def __init__(self, timeout):
+               multiprocessing.Process.__init__(self)
+               self.timeout = timeout
+
+       def run(self):
+               time.sleep(self.timeout)
+
+
+class Worker(multiprocessing.Process):
+       def __init__(self, function, args, q):
+               multiprocessing.Process.__init__(self)
+               self.function = function
+               self.args = args
+               self.q = q
+
+       def run(self):
+               #print str(self) + " runs " + str(self.function) + " with args " + str(self.args) 
+               self.q.put(self.function(*self.args))
+               
+               
+
+def TimeoutFunction(function, args, timeout):
+       q = multiprocessing.Queue()
+       w = Worker(function, args, q)
+       s = Sleeper(timeout)
+       w.start()
+       s.start()
+       while True: # Busy loop of crappyness
+               if not w.is_alive():
+                       s.terminate()
+                       result = q.get()
+                       w.join()
+                       #print "TimeoutFunction gets " + str(result)
+                       return result
+               elif not s.is_alive():
+                       w.terminate()
+                       s.join()
+                       raise Exception("TIMEOUT")
+
+       
+               
+
+# A player that wraps another player and times out its moves
+# Uses threads
+# A (crappy) alternative to the use of select()
+class TimeoutPlayer(Player):
+       def __init__(self, base_player, timeout):
+               Player.__init__(self, base_player.name, base_player.colour)
+               self.base_player = base_player
+               self.timeout = timeout
+               
+       def select(self):
+               return TimeoutFunction(self.base_player.select, [], self.timeout)
+               
+       
+       def get_move(self):
+               return TimeoutFunction(self.base_player.get_move, [], self.timeout)
+
+       def update(self, result):
+               return TimeoutFunction(self.base_player.update, [result], self.timeout)
+
+       def quit(self, final_result):
+               return TimeoutFunction(self.base_player.quit, [final_result], self.timeout)
+# --- timeout_player.py --- #
+import socket
+import select
+
+network_timeout_start = -1.0 # Timeout in seconds to wait for the start of a message
+network_timeout_delay = 1.0 # Maximum time between two characters being received
+
+class NetworkPlayer(Player):
+       def __init__(self, colour, network, player):
+               Player.__init__(self, "@network:"+str(network.address), colour) 
+               self.player = player
+               self.network = network
+               
+       def __str__(self):
+               return "NetworkPlayer<"+str(self.colour)+","+str(self.player)+">"
+               
+       def select(self):
+               #debug(str(self) + " select called")
+               if self.player != None:
+                       s = self.player.select()
+                       self.send_message(str(s[0]) + " " + str(s[1]))
+               else:
+                       s = map(int, self.get_response().split(" "))
+                       for p in game.players:
+                               if p != self and isinstance(p, NetworkPlayer) and p.player == None:
+                                       p.network.send_message(str(s[0]) + " " + str(s[1]))
+               if s == [-1,-1]:
+                       game.final_result = "network terminate"
+                       game.stop()
+               return s
+       
+       def send_message(self, message):
+               #debug(str(self) + " send_message(\""+str(message)+"\") called")
+               self.network.send_message(message)
+               
+       def get_response(self):
+               #debug(str(self) + " get_response() called")
+               s = self.network.get_response()
+               #debug(str(self) + " get_response() returns \""+str(s)+"\"")
+               return s
+                       
+                       
+       def get_move(self):
+               #debug(str(self) + " get_move called")
+               if self.player != None:
+                       s = self.player.get_move()
+                       self.send_message(str(s[0]) + " " + str(s[1]))
+               else:
+                       s = map(int, self.get_response().split(" "))
+                       for p in game.players:
+                               if p != self and isinstance(p, NetworkPlayer) and p.player == None:
+                                       p.network.send_message(str(s[0]) + " " + str(s[1]))
+                                       
+               if s == [-1,-1]:
+                       game.final_result = "network terminate"
+                       game.stop()
+               return s
+       
+       def update(self, result):
+               #debug(str(self) + " update(\""+str(result)+"\") called")
+               if self.network.server == True:
+                       if self.player == None:
+                               self.send_message(result)
+               elif self.player != None:
+                       result = self.get_response()
+                       if result == "-1 -1":
+                               game.final_result = "network terminate"
+                               game.stop()
+                               return "-1 -1"
+                       self.board.update(result, deselect=False)
+               
+               
+               
+               if self.player != None:
+                       result = self.player.update(result)
+                       
+               return result
+               
+               
+       
+       def base_player(self):
+               if self.player == None:
+                       return self
+               else:
+                       return self.player.base_player()
+               
+       def quit(self, result):
+               try:
+                       self.send_message("-1 -1")
+               except:
+                       pass
+
+class Network():
+       def __init__(self, address = (None,4562)):
+               self.socket = socket.socket()
+               self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+               #self.socket.setblocking(0)
+               self.address = address
+               self.server = (address[0] == None)
+               
+               
+               self.connected = False
+                       
+       def connect(self):      
+               #debug(str(self) + "Tries to connect")
+               self.connected = True
+               if self.address[0] == None:
+                       self.host = "0.0.0.0" #socket.gethostname() # Breaks things???
+                       self.socket.bind((self.host, self.address[1]))
+                       self.socket.listen(5)   
+
+                       self.src, self.actual_address = self.socket.accept()
+                       
+                       self.src.send("ok\n")
+                       s = self.get_response()
+                       if s == "QUIT":
+                               self.src.close()
+                               return
+                       elif s != "ok":
+                               self.src.close()
+                               self.__init__(colour, (self.address[0], int(s)), baseplayer)
+                               return
+                       
+               else:
+                       time.sleep(0.3)
+                       self.socket.connect(self.address)
+                       self.src = self.socket
+                       self.src.send("ok\n")
+                       s = self.get_response()
+                       if s == "QUIT":
+                               self.src.close()
+                               return
+                       elif s != "ok":
+                               self.src.close()
+                               self.__init__(colour, (self.address[0], int(s)), baseplayer)
+                               return
+                       
+
+               
+       def __str__(self):
+               return "@network:"+str(self.address)
+
+       def get_response(self):
+               
+               # Timeout the start of the message (first character)
+               if network_timeout_start > 0.0:
+                       ready = select.select([self.src], [], [], network_timeout_start)[0]
+               else:
+                       ready = [self.src]
+               if self.src in ready:
+                       s = self.src.recv(1)
+               else:
+                       raise Exception("UNRESPONSIVE")
+
+
+               while s[len(s)-1] != '\n':
+                       # Timeout on each character in the message
+                       if network_timeout_delay > 0.0:
+                               ready = select.select([self.src], [], [], network_timeout_delay)[0]
+                       else:
+                               ready = [self.src]
+                       if self.src in ready:
+                               s += self.src.recv(1) 
+                       else:
+                               raise Exception("UNRESPONSIVE")
+
+               
+               return s.strip(" \r\n")
+
+       def send_message(self,s):
+               if network_timeout_start > 0.0:
+                       ready = select.select([], [self.src], [], network_timeout_start)[1]
+               else:
+                       ready = [self.src]
+
+               if self.src in ready:
+                       self.src.send(s + "\n")
+               else:
+                       raise Exception("UNRESPONSIVE")
+               
+               
+
+       def close(self):
+               self.src.shutdown()
+               self.src.close()
+# --- network.py --- #
+import threading
+
+# A thread that can be stopped!
+# Except it can only be stopped if it checks self.stopped() periodically
+# So it can sort of be stopped
+class StoppableThread(threading.Thread):
+       def __init__(self):
+               threading.Thread.__init__(self)
+               self._stop = threading.Event()
+
+       def stop(self):
+               self._stop.set()
+
+       def stopped(self):
+               return self._stop.isSet()
+# --- thread_util.py --- #
+log_files = []
+import datetime
+import urllib2
+
+class LogFile():
+       def __init__(self, log, name):  
+               self.name = name
+               self.log = log
+               self.logged = []
+               self.log.write("# Log starts " + str(datetime.datetime.now()) + "\n")
+
+       def write(self, s):
+               now = datetime.datetime.now()
+               self.log.write(str(now) + " : " + s + "\n")
+               self.logged.append((now, s))
+
+       def setup(self, board, players):
+               
+               for p in players:
+                       self.log.write("# " + str(p.colour) + " : " + str(p.name) + "\n")
+               
+               self.log.write("# Initial board\n")
+               for x in range(0, w):
+                       for y in range(0, h):
+                               if board.grid[x][y] != None:
+                                       self.log.write(str(board.grid[x][y]) + "\n")
+
+               self.log.write("# Start game\n")
+
+       def close(self):
+               self.log.write("# EOF\n")
+               if self.log != sys.stdout:
+                       self.log.close()
+
+class ShortLog(LogFile):
+       def __init__(self, file_name):
+               if file_name == "":
+                       self.log = sys.stdout
+               else:
+                       self.log = open(file_name, "w", 0)
+               LogFile.__init__(self, self.log, "@"+file_name)
+               self.file_name = file_name
+               self.phase = 0
+
+       def write(self, s):
+               now = datetime.datetime.now()
+               self.logged.append((now, s))
+               
+               if self.phase == 0:
+                       if self.log != sys.stdout:
+                               self.log.close()
+                               self.log = open(self.file_name, "w", 0)
+                       self.log.write("# Short log updated " + str(datetime.datetime.now()) + "\n")    
+                       LogFile.setup(self, game.board, game.players)
+
+               elif self.phase == 1:
+                       for message in self.logged[len(self.logged)-2:]:
+                               self.log.write(str(message[0]) + " : " + message[1] + "\n")
+
+               self.phase = (self.phase + 1) % 2               
+               
+       def close(self):
+               if self.phase == 1:
+                       ending = self.logged[len(self.logged)-1]
+                       self.log.write(str(ending[0]) + " : " + ending[1] + "\n")
+               self.log.write("# EOF\n")
+               if self.log != sys.stdout:
+                       self.log.close()
+               
+
+class HeadRequest(urllib2.Request):
+       def get_method(self):
+               return "HEAD"
+
+class HttpGetter(StoppableThread):
+       def __init__(self, address):
+               StoppableThread.__init__(self)
+               self.address = address
+               self.log = urllib2.urlopen(address)
+               self.lines = []
+               self.lock = threading.RLock() #lock for access of self.state
+               self.cond = threading.Condition() # conditional
+
+       def run(self):
+               while not self.stopped():
+                       line = self.log.readline()
+                       if line == "":
+                               date_mod = datetime.datetime.strptime(self.log.headers['last-modified'], "%a, %d %b %Y %H:%M:%S GMT")
+                               self.log.close()
+       
+                               next_log = urllib2.urlopen(HeadRequest(self.address))
+                               date_new = datetime.datetime.strptime(next_log.headers['last-modified'], "%a, %d %b %Y %H:%M:%S GMT")
+                               while date_new <= date_mod and not self.stopped():
+                                       next_log = urllib2.urlopen(HeadRequest(self.address))
+                                       date_new = datetime.datetime.strptime(next_log.headers['last-modified'], "%a, %d %b %Y %H:%M:%S GMT")
+                               if self.stopped():
+                                       break
+
+                               self.log = urllib2.urlopen(self.address)
+                               line = self.log.readline()
+
+                       self.cond.acquire()
+                       self.lines.append(line)
+                       self.cond.notifyAll()
+                       self.cond.release()
+
+                       #sys.stderr.write(" HttpGetter got \'" + str(line) + "\'\n")
+
+               self.log.close()
+                               
+                               
+       
+               
+               
+class HttpReplay():
+       def __init__(self, address):
+               self.getter = HttpGetter(address)
+               self.getter.start()
+               
+       def readline(self):
+               self.getter.cond.acquire()
+               while len(self.getter.lines) == 0:
+                       self.getter.cond.wait()
+                       
+               result = self.getter.lines[0]
+               self.getter.lines = self.getter.lines[1:]
+               self.getter.cond.release()
+
+               return result
+                       
+                       
+       def close(self):
+               self.getter.stop()
+
+class FileReplay():
+       def __init__(self, filename):
+               self.f = open(filename, "r", 0)
+               self.filename = filename
+               self.mod = os.path.getmtime(filename)
+               self.count = 0
+       
+       def readline(self):
+               line = self.f.readline()
+               
+               while line == "":
+                       mod2 = os.path.getmtime(self.filename)
+                       if mod2 > self.mod:
+                               #sys.stderr.write("File changed!\n")
+                               self.mod = mod2
+                               self.f.close()
+                               self.f = open(self.filename, "r", 0)
+                               
+                               new_line = self.f.readline()
+                               
+                               if " ".join(new_line.split(" ")[0:3]) != "# Short log":
+                                       for i in range(self.count):
+                                               new_line = self.f.readline()
+                                               #sys.stderr.write("Read back " + str(i) + ": " + str(new_line) + "\n")
+                                       new_line = self.f.readline()
+                               else:
+                                       self.count = 0
+                               
+                               line = new_line
+
+               self.count += 1
+               return line
+
+       def close(self):
+               self.f.close()
+               
+                                               
+def log(s):
+       for l in log_files:
+               l.write(s)
+               
+def debug(s):
+       sys.stderr.write("# DEBUG: " + s + "\n")
+               
+
+def log_init(board, players):
+       for l in log_files:
+               l.setup(board, players)
+
+# --- log.py --- #
+
+
+
+       
+
+# A thread that runs the game
+class GameThread(StoppableThread):
+       def __init__(self, board, players, server = True):
+               StoppableThread.__init__(self)
+               self.board = board
+               self.players = players
+               self.state = {"turn" : None} # The game state
+               self.error = 0 # Whether the thread exits with an error
+               self.lock = threading.RLock() #lock for access of self.state
+               self.cond = threading.Condition() # conditional for some reason, I forgot
+               self.final_result = ""
+               self.server = server
+               
+               
+                       
+               
+               
+
+       # Run the game (run in new thread with start(), run in current thread with run())
+       def run(self):
+               result = ""
+               while not self.stopped():
+                       
+                       for p in self.players:
+                               with self.lock:
+                                       self.state["turn"] = p.base_player()
+                               #try:
+                               if True:
+                                       [x,y] = p.select() # Player selects a square
+                                       if self.stopped():
+                                               #debug("Quitting in select")
+                                               break
+                                               
+                                       if isinstance(p, NetworkPlayer):
+                                               if p.network.server == True:
+                                                       result = self.board.select(x, y, colour = p.colour)
+                                               else:
+                                                       result = None
+                                                       
+                                       else:
+                                               result = self.board.select(x, y, colour = p.colour)
+                                       
+                                       result = p.update(result)
+                                       if self.stopped():
+                                               break
+                                       for p2 in self.players:
+                                               if p2 == p:
+                                                       continue
+                                               p2.update(result) # Inform players of what happened
+                                               if self.stopped():
+                                                       break
+                                       
+                                       if self.stopped():
+                                               break
+
+
+                                       log(result)
+
+                                       target = self.board.grid[x][y]
+                                       if isinstance(graphics, GraphicsThread):
+                                               with graphics.lock:
+                                                       graphics.state["moves"] = self.board.possible_moves(target)
+                                                       graphics.state["select"] = target
+
+                                       time.sleep(turn_delay)
+
+
+                                       if len(self.board.possible_moves(target)) == 0:
+                                               #print "Piece cannot move"
+                                               target.deselect()
+                                               if isinstance(graphics, GraphicsThread):
+                                                       with graphics.lock:
+                                                               graphics.state["moves"] = None
+                                                               graphics.state["select"] = None
+                                                               graphics.state["dest"] = None
+                                               continue
+
+                                       try:
+                                               [x2,y2] = p.get_move() # Player selects a destination
+                                       except:
+                                               self.stop()
+
+                                       if self.stopped():
+                                               #debug("Quitting in get_move")
+                                               break
+                                       
+                                       if isinstance(p, NetworkPlayer):
+                                               if p.network.server == True:
+                                                       result = str(x) + " " + str(y) + " -> " + str(x2) + " " + str(y2)
+                                                       self.board.update_move(x, y, x2, y2)
+                                               else:
+                                                       result = None
+                                                       
+                                       else:
+                                               result = str(x) + " " + str(y) + " -> " + str(x2) + " " + str(y2)
+                                               self.board.update_move(x, y, x2, y2)
+                                       
+                                       result = p.update(result)
+                                       if self.stopped():
+                                               break
+                                       for p2 in self.players:
+                                               if p2 == p:
+                                                       continue
+                                               p2.update(result) # Inform players of what happened
+                                               if self.stopped():
+                                                       break
+                                       
+                                       if self.stopped():
+                                               break
+                                       
+                                       
+                                                                                       
+                                       log(result)
+
+
+                                                                               
+
+                                       if isinstance(graphics, GraphicsThread):
+                                               with graphics.lock:
+                                                       graphics.state["moves"] = [[x2,y2]]
+
+                                       time.sleep(turn_delay)
+
+                                       if isinstance(graphics, GraphicsThread):
+                                               with graphics.lock:
+                                                       graphics.state["select"] = None
+                                                       graphics.state["dest"] = None
+                                                       graphics.state["moves"] = None
+
+                       # Commented out exception stuff for now, because it makes it impossible to tell if I made an IndentationError somewhere
+                       #       except Exception,e:
+                       #               result = e.message
+                       #               #sys.stderr.write(result + "\n")
+                       #               
+                       #               self.stop()
+                       #               with self.lock:
+                       #                       self.final_result = self.state["turn"].colour + " " + e.message
+
+                               end = self.board.end_condition()
+                               if end != None:         
+                                       with self.lock:
+                                               if end == "DRAW":
+                                                       self.final_result = self.state["turn"].colour + " " + end
+                                               else:
+                                                       self.final_result = end
+                                       self.stop()
+                               
+                               if self.stopped():
+                                       break
+
+
+               for p2 in self.players:
+                       p2.quit(self.final_result)
+
+               log(self.final_result)
+
+               if isinstance(graphics, GraphicsThread):
+                       graphics.stop()
+
+       
+# A thread that replays a log file
+class ReplayThread(GameThread):
+       def __init__(self, players, src, end=False,max_moves=None):
+               self.board = Board(style="empty")
+               self.board.max_moves = max_moves
+               GameThread.__init__(self, self.board, players)
+               self.src = src
+               self.end = end
+
+               self.reset_board(self.src.readline())
+
+       def reset_board(self, line):
+               agent_str = ""
+               self_str = ""
+               while line != "# Start game" and line != "# EOF":
+                       
+                       while line == "":
+                               line = self.src.readline().strip(" \r\n")
+                               continue
+
+                       if line[0] == '#':
+                               line = self.src.readline().strip(" \r\n")
+                               continue
+
+                       self_str += line + "\n"
+
+                       if self.players[0].name == "dummy" and self.players[1].name == "dummy":
+                               line = self.src.readline().strip(" \r\n")
+                               continue
+                       
+                       tokens = line.split(" ")
+                       types = map(lambda e : e.strip("[] ,'"), tokens[2:4])
+                       for i in range(len(types)):
+                               if types[i][0] == "?":
+                                       types[i] = "unknown"
+
+                       agent_str += tokens[0] + " " + tokens[1] + " " + str(types) + " ".join(tokens[4:]) + "\n"
+                       line = self.src.readline().strip(" \r\n")
+
+               for p in self.players:
+                       p.reset_board(agent_str)
+               
+               
+               self.board.reset_board(self_str)
+
+       
+       def run(self):
+               move_count = 0
+               last_line = ""
+               line = self.src.readline().strip(" \r\n")
+               while line != "# EOF":
+
+
+                       if self.stopped():
+                               break
+                       
+                       if len(line) <= 0:
+                               continue
+                                       
+
+                       if line[0] == '#':
+                               last_line = line
+                               line = self.src.readline().strip(" \r\n")
+                               continue
+
+                       tokens = line.split(" ")
+                       if tokens[0] == "white" or tokens[0] == "black":
+                               self.reset_board(line)
+                               last_line = line
+                               line = self.src.readline().strip(" \r\n")
+                               continue
+
+                       move = line.split(":")
+                       move = move[len(move)-1].strip(" \r\n")
+                       tokens = move.split(" ")
+                       
+                       
+                       try:
+                               [x,y] = map(int, tokens[0:2])
+                       except:
+                               last_line = line
+                               self.stop()
+                               break
+
+                       log(move)
+
+                       target = self.board.grid[x][y]
+                       with self.lock:
+                               if target.colour == "white":
+                                       self.state["turn"] = self.players[0]
+                               else:
+                                       self.state["turn"] = self.players[1]
+                       
+                       move_piece = (tokens[2] == "->")
+                       if move_piece:
+                               [x2,y2] = map(int, tokens[len(tokens)-2:])
+
+                       if isinstance(graphics, GraphicsThread):
+                               with graphics.lock:
+                                       graphics.state["select"] = target
+                                       
+                       if not move_piece:
+                               self.board.update_select(x, y, int(tokens[2]), tokens[len(tokens)-1])
+                               if isinstance(graphics, GraphicsThread):
+                                       with graphics.lock:
+                                               if target.current_type != "unknown":
+                                                       graphics.state["moves"] = self.board.possible_moves(target)
+                                               else:
+                                                       graphics.state["moves"] = None
+                                       time.sleep(turn_delay)
+                       else:
+                               self.board.update_move(x, y, x2, y2)
+                               if isinstance(graphics, GraphicsThread):
+                                       with graphics.lock:
+                                               graphics.state["moves"] = [[x2,y2]]
+                                       time.sleep(turn_delay)
+                                       with graphics.lock:
+                                               graphics.state["select"] = None
+                                               graphics.state["moves"] = None
+                                               graphics.state["dest"] = None
+                       
+
+                       
+                       
+                       
+                       for p in self.players:
+                               p.update(move)
+
+                       last_line = line
+                       line = self.src.readline().strip(" \r\n")
+                       
+                       
+                       end = self.board.end_condition()
+                       if end != None:
+                               self.final_result = end
+                               self.stop()
+                               break
+                                       
+                                               
+                                               
+
+                       
+                                       
+
+
+                       
+
+                               
+                       
+
+               
+
+               if self.end and isinstance(graphics, GraphicsThread):
+                       #graphics.stop()
+                       pass # Let the user stop the display
+               elif not self.end and self.board.end_condition() == None:
+                       global game
+                       # Work out the last move
+                                       
+                       t = last_line.split(" ")
+                       if t[len(t)-2] == "black":
+                               self.players.reverse()
+                       elif t[len(t)-2] == "white":
+                               pass
+                       elif self.state["turn"] != None and self.state["turn"].colour == "white":
+                               self.players.reverse()
+
+
+                       game = GameThread(self.board, self.players)
+                       game.run()
+               else:
+                       pass
+
+               
+
+def opponent(colour):
+       if colour == "white":
+               return "black"
+       else:
+               return "white"
+# --- game.py --- #
+try:
+       import pygame
+except:
+       pass
+import os
+
+# Dictionary that stores the unicode character representations of the different pieces
+# Chess was clearly the reason why unicode was invented
+# For some reason none of the pygame chess implementations I found used them!
+piece_char = {"white" : {"king" : u'\u2654',
+                        "queen" : u'\u2655',
+                        "rook" : u'\u2656',
+                        "bishop" : u'\u2657',
+                        "knight" : u'\u2658',
+                        "pawn" : u'\u2659',
+                        "unknown" : '?'},
+               "black" : {"king" : u'\u265A',
+                        "queen" : u'\u265B',
+                        "rook" : u'\u265C',
+                        "bishop" : u'\u265D',
+                        "knight" : u'\u265E',
+                        "pawn" : u'\u265F',
+                        "unknown" : '?'}}
+
+images = {"white" : {}, "black" : {}}
+small_images = {"white" : {}, "black" : {}}
+
+def create_images(grid_sz, font_name=os.path.join(os.path.curdir, "data", "DejaVuSans.ttf")):
+
+       # Get the font sizes
+       l_size = 5*(grid_sz[0] / 8)
+       s_size = 3*(grid_sz[0] / 8)
+
+       for c in piece_char.keys():
+               
+               if c == "black":
+                       for p in piece_char[c].keys():
+                               images[c].update({p : pygame.font.Font(font_name, l_size).render(piece_char[c][p], True,(0,0,0))})
+                               small_images[c].update({p : pygame.font.Font(font_name, s_size).render(piece_char[c][p],True,(0,0,0))})         
+               elif c == "white":
+                       for p in piece_char[c].keys():
+                               images[c].update({p : pygame.font.Font(font_name, l_size+1).render(piece_char["black"][p], True,(255,255,255))})
+                               images[c][p].blit(pygame.font.Font(font_name, l_size).render(piece_char[c][p], True,(0,0,0)),(0,0))
+                               small_images[c].update({p : pygame.font.Font(font_name, s_size+1).render(piece_char["black"][p],True,(255,255,255))})
+                               small_images[c][p].blit(pygame.font.Font(font_name, s_size).render(piece_char[c][p],True,(0,0,0)),(0,0))
+       
+
+def load_images(image_dir=os.path.join(os.path.curdir, "data", "images")):
+       if not os.path.exists(image_dir):
+               raise Exception("Couldn't load images from " + image_dir + " (path doesn't exist)")
+       for c in piece_char.keys():
+               for p in piece_char[c].keys():
+                       images[c].update({p : pygame.image.load(os.path.join(image_dir, c + "_" + p + ".png"))})
+                       small_images[c].update({p : pygame.image.load(os.path.join(image_dir, c + "_" + p + "_small.png"))})
+# --- images.py --- #
+graphics_enabled = True
+
+try:
+       import pygame
+       os.environ["SDL_VIDEO_ALLOW_SCREENSAVER"] = "1"
+except:
+       graphics_enabled = False
+       
+import time
+
+
+
+# A thread to make things pretty
+class GraphicsThread(StoppableThread):
+       def __init__(self, board, title = "UCC::Progcomp 2013 - QChess", grid_sz = [80,80]):
+               StoppableThread.__init__(self)
+               
+               self.board = board
+               pygame.init()
+               self.window = pygame.display.set_mode((grid_sz[0] * w, grid_sz[1] * h))
+               pygame.display.set_caption(title)
+
+               #print "Initialised properly"
+               
+               self.grid_sz = grid_sz[:]
+               self.state = {"select" : None, "dest" : None, "moves" : None, "overlay" : None, "coverage" : None}
+               self.error = 0
+               self.lock = threading.RLock()
+               self.cond = threading.Condition()
+               self.sleep_timeout = None
+               self.last_event = time.time()
+               self.blackout = False
+
+               #print "Test font"
+               pygame.font.Font(os.path.join(os.path.curdir, "data", "DejaVuSans.ttf"), 32).render("Hello", True,(0,0,0))
+
+               #load_images()
+               create_images(grid_sz)
+
+               """
+               for c in images.keys():
+                       for p in images[c].keys():
+                               images[c][p] = images[c][p].convert(self.window)
+                               small_images[c][p] = small_images[c][p].convert(self.window)
+               """
+
+               
+       
+
+
+       # On the run from the world
+       def run(self):
+               
+               while not self.stopped():
+                       
+                       if self.sleep_timeout == None or (time.time() - self.last_event) < self.sleep_timeout:
+                       
+                               #print "Display grid"
+                               self.board.display_grid(window = self.window, grid_sz = self.grid_sz) # Draw the board
+
+                               #print "Display overlay"
+                               self.overlay()
+
+                               #print "Display pieces"
+                               self.board.display_pieces(window = self.window, grid_sz = self.grid_sz) # Draw the board                
+                               self.blackout = False
+                               
+                       elif pygame.mouse.get_focused() and not self.blackout:
+                               os.system("xset dpms force off")
+                               self.blackout = True
+                               self.window.fill((0,0,0))
+
+                       pygame.display.flip()
+
+                       for event in pygame.event.get():
+                               self.last_event = time.time()
+                               if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_q):
+                                       if isinstance(game, GameThread):
+                                               with game.lock:
+                                                       game.final_result = ""
+                                                       if game.state["turn"] != None:
+                                                               game.final_result = game.state["turn"].colour + " "
+                                                       game.final_result += "terminated"
+                                               game.stop()
+                                       self.stop()
+                                       break
+                               elif event.type == pygame.MOUSEBUTTONDOWN:
+                                       self.mouse_down(event)
+                                       
+                               elif event.type == pygame.MOUSEBUTTONUP:
+                                       self.mouse_up(event)                    
+                               
+                               
+                                       
+  
+                               
+                                                               
+                                               
+                                               
+               self.message("Game ends, result \""+str(game.final_result) + "\"")
+               time.sleep(1)
+
+               # Wake up anyone who is sleeping
+               self.cond.acquire()
+               self.cond.notify()
+               self.cond.release()
+
+               pygame.quit() # Time to say goodbye
+
+       # Mouse release event handler
+       def mouse_up(self, event):
+               if event.button == 3:
+                       with self.lock:
+                               self.state["overlay"] = None
+               elif event.button == 2:
+                       with self.lock:
+                               self.state["coverage"] = None   
+
+       # Mouse click event handler
+       def mouse_down(self, event):
+               if event.button == 1:
+                       m = [event.pos[i] / self.grid_sz[i] for i in range(2)]
+                       if isinstance(game, GameThread):
+                               with game.lock:
+                                       p = game.state["turn"]
+                       else:
+                                       p = None
+                                       
+                                       
+                       if isinstance(p, HumanPlayer):
+                               with self.lock:
+                                       s = self.board.grid[m[0]][m[1]]
+                                       select = self.state["select"]
+                               if select == None:
+                                       if s != None and s.colour != p.colour:
+                                               self.message("Wrong colour") # Look at all this user friendliness!
+                                               time.sleep(1)
+                                               return
+                                       # Notify human player of move
+                                       self.cond.acquire()
+                                       with self.lock:
+                                               self.state["select"] = s
+                                               self.state["dest"] = None
+                                       self.cond.notify()
+                                       self.cond.release()
+                                       return
+
+                               if select == None:
+                                       return
+                                               
+                                       
+                               if self.state["moves"] == None:
+                                       return
+
+                               if not m in self.state["moves"]:
+                                       self.message("Illegal Move") # I still think last year's mouse interface was adequate
+                                       time.sleep(2)
+                                       return
+                                               
+                               with self.lock:
+                                       if self.state["dest"] == None:
+                                               self.cond.acquire()
+                                               self.state["dest"] = m
+                                               self.state["select"] = None
+                                               self.state["moves"] = None
+                                               self.cond.notify()
+                                               self.cond.release()
+               elif event.button == 3:
+                       m = [event.pos[i] / self.grid_sz[i] for i in range(len(event.pos))]
+                       if isinstance(game, GameThread):
+                               with game.lock:
+                                       p = game.state["turn"]
+                       else:
+                               p = None
+                                       
+                                       
+                       if isinstance(p, HumanPlayer):
+                               with self.lock:
+                                       self.state["overlay"] = self.board.probability_grid(self.board.grid[m[0]][m[1]])
+
+               elif event.button == 2:
+                       m = [event.pos[i] / self.grid_sz[i] for i in range(len(event.pos))]
+                       if isinstance(game, GameThread):
+                               with game.lock:
+                                       p = game.state["turn"]
+                       else:
+                               p = None
+                       
+                       
+                       if isinstance(p, HumanPlayer):
+                               with self.lock:
+                                       self.state["coverage"] = self.board.coverage(m[0], m[1], None, self.state["select"])
+                               
+       # Draw the overlay
+       def overlay(self):
+
+               square_img = pygame.Surface((self.grid_sz[0], self.grid_sz[1]),pygame.SRCALPHA) # A square image
+               # Draw square over the selected piece
+               with self.lock:
+                       select = self.state["select"]
+               if select != None:
+                       mp = [self.grid_sz[i] * [select.x, select.y][i] for i in range(len(self.grid_sz))]
+                       square_img.fill(pygame.Color(0,255,0,64))
+                       self.window.blit(square_img, mp)
+               # If a piece is selected, draw all reachable squares
+               # (This quality user interface has been patented)
+               with self.lock:
+                       m = self.state["moves"]
+               if m != None:
+                       square_img.fill(pygame.Color(255,0,0,128)) # Draw them in blood red
+                       for move in m:
+                               mp = [self.grid_sz[i] * move[i] for i in range(2)]
+                               self.window.blit(square_img, mp)
+               # If a piece is overlayed, show all squares that it has a probability to reach
+               with self.lock:
+                       m = self.state["overlay"]
+               if m != None:
+                       for x in range(w):
+                               for y in range(h):
+                                       if m[x][y] > 0.0:
+                                               mp = [self.grid_sz[i] * [x,y][i] for i in range(2)]
+                                               square_img.fill(pygame.Color(255,0,255,int(m[x][y] * 128))) # Draw in purple
+                                               self.window.blit(square_img, mp)
+                                               font = pygame.font.Font(os.path.join(os.path.curdir, "data", "DejaVuSans.ttf"), 14)
+                                               text = font.render("{0:.2f}".format(round(m[x][y],2)), 1, pygame.Color(0,0,0))
+                                               self.window.blit(text, mp)
+                               
+               # If a square is selected, highlight all pieces that have a probability to reach it
+               with self.lock:                         
+                       m = self.state["coverage"]
+               if m != None:
+                       for p in m:
+                               mp = [self.grid_sz[i] * [p.x,p.y][i] for i in range(2)]
+                               square_img.fill(pygame.Color(0,255,255, int(m[p] * 196))) # Draw in pale blue
+                               self.window.blit(square_img, mp)
+                               font = pygame.font.Font(os.path.join(os.path.curdir, "data", "DejaVuSans.ttf"), 14)
+                               text = font.render("{0:.2f}".format(round(m[p],2)), 1, pygame.Color(0,0,0))
+                               self.window.blit(text, mp)
+                       # Draw a square where the mouse is
+               # This also serves to indicate who's turn it is
+               
+               if isinstance(game, GameThread):
+                       with game.lock:
+                               turn = game.state["turn"]
+               else:
+                       turn = None
+
+               if isinstance(turn, HumanPlayer):
+                       mp = [self.grid_sz[i] * int(pygame.mouse.get_pos()[i] / self.grid_sz[i]) for i in range(2)]
+                       square_img.fill(pygame.Color(0,0,255,128))
+                       if turn.colour == "white":
+                               c = pygame.Color(255,255,255)
+                       else:
+                               c = pygame.Color(0,0,0)
+                       pygame.draw.rect(square_img, c, (0,0,self.grid_sz[0], self.grid_sz[1]), self.grid_sz[0]/10)
+                       self.window.blit(square_img, mp)
+
+       # Message in a bottle
+       def message(self, string, pos = None, colour = None, font_size = 20):
+               #print "Drawing message..."
+               font = pygame.font.Font(os.path.join(os.path.curdir, "data", "DejaVuSans.ttf"), font_size)
+               if colour == None:
+                       colour = pygame.Color(0,0,0)
+               
+               text = font.render(string, 1, colour)
+       
+
+               s = pygame.Surface((text.get_width(), text.get_height()), pygame.SRCALPHA)
+               s.fill(pygame.Color(128,128,128))
+
+               tmp = self.window.get_size()
+
+               if pos == None:
+                       pos = (tmp[0] / 2 - text.get_width() / 2, tmp[1] / 3 - text.get_height())
+               else:
+                       pos = (pos[0]*text.get_width() + tmp[0] / 2 - text.get_width() / 2, pos[1]*text.get_height() + tmp[1] / 3 - text.get_height())
+               
+
+               rect = (pos[0], pos[1], text.get_width(), text.get_height())
+       
+               pygame.draw.rect(self.window, pygame.Color(0,0,0), pygame.Rect(rect), 1)
+               self.window.blit(s, pos)
+               self.window.blit(text, pos)
+
+               pygame.display.flip()
+
+       def getstr(self, prompt = None):
+               s = pygame.Surface((self.window.get_width(), self.window.get_height()))
+               s.blit(self.window, (0,0))
+               result = ""
+
+               while True:
+                       #print "LOOP"
+                       if prompt != None:
+                               self.message(prompt)
+                               self.message(result, pos = (0, 1))
+       
+                       pygame.event.pump()
+                       for event in pygame.event.get():
+                               if event.type == pygame.QUIT:
+                                       return None
+                               if event.type == pygame.KEYDOWN:
+                                       if event.key == pygame.K_BACKSPACE:
+                                               result = result[0:len(result)-1]
+                                               self.window.blit(s, (0,0)) # Revert the display
+                                               continue
+                               
+                                               
+                                       try:
+                                               if event.unicode == '\r':
+                                                       return result
+                                       
+                                               result += str(event.unicode)
+                                       except:
+                                               continue
+
+
+       # Function to pick a button
+       def SelectButton(self, choices, prompt = None, font_size=20):
+
+               #print "Select button called!"
+               self.board.display_grid(self.window, self.grid_sz)
+               if prompt != None:
+                       self.message(prompt)
+               font = pygame.font.Font(os.path.join(os.path.curdir, "data", "DejaVuSans.ttf"), font_size)
+               targets = []
+               sz = self.window.get_size()
+
+               
+               for i in range(len(choices)):
+                       c = choices[i]
+                       
+                       text = font.render(c, 1, pygame.Color(0,0,0))
+                       p = (sz[0] / 2 - (1.5*text.get_width())/2, sz[1] / 2 +(i-1)*text.get_height()+(i*2))
+                       targets.append((p[0], p[1], p[0] + 1.5*text.get_width(), p[1] + text.get_height()))
+
+               while True:
+                       mp =pygame.mouse.get_pos()
+                       for i in range(len(choices)):
+                               c = choices[i]
+                               if mp[0] > targets[i][0] and mp[0] < targets[i][2] and mp[1] > targets[i][1] and mp[1] < targets[i][3]:
+                                       font_colour = pygame.Color(255,0,0)
+                                       box_colour = pygame.Color(0,0,255,128)
+                               else:
+                                       font_colour = pygame.Color(0,0,0)
+                                       box_colour = pygame.Color(128,128,128)
+                               
+                               text = font.render(c, 1, font_colour)
+                               s = pygame.Surface((text.get_width()*1.5, text.get_height()), pygame.SRCALPHA)
+                               s.fill(box_colour)
+                               pygame.draw.rect(s, (0,0,0), (0,0,1.5*text.get_width(), text.get_height()), self.grid_sz[0]/10)
+                               s.blit(text, ((text.get_width()*1.5)/2 - text.get_width()/2 ,0))
+                               self.window.blit(s, targets[i][0:2])
+                               
+       
+                       pygame.display.flip()
+
+                       for event in pygame.event.get():
+                               if event.type == pygame.QUIT:
+                                       return None
+                               elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
+                                       for i in range(len(targets)):
+                                               t = targets[i]
+                                               if event.pos[0] > t[0] and event.pos[0] < t[2]:
+                                                       if event.pos[1] > t[1] and event.pos[1] < t[3]:
+                                                               return i
+                                               #print "Reject " + str(i) + str(event.pos) + " vs " + str(t)
+               
+
+       # Function to choose between dedicated server or normal play
+       def SelectServer(self):
+       
+               choice = self.SelectButton(["Normal", "Join Eigenserver"],prompt="Game type?")
+               if choice == 0:
+                       return None
+               choice = self.SelectButton(["progcomp.ucc", "other"], prompt="Address?")
+               if choice == 0:
+                       return "progcomp.ucc.asn.au"
+               else:
+                       return self.getstr(prompt = "Enter address:")
+                       
+       # Function to pick players in a nice GUI way
+       def SelectPlayers(self, players = []):
+
+
+               #print "SelectPlayers called"
+               
+               missing = ["white", "black"]
+               for p in players:
+                       missing.remove(p.colour)
+
+               for colour in missing:
+                       
+                       
+                       choice = self.SelectButton(["human", "agent", "network"],prompt = "Choose " + str(colour) + " player")
+                       if choice == 0:
+                               players.append(HumanPlayer("human", colour))
+                       elif choice == 1:
+                               import inspect
+                               internal_agents = inspect.getmembers(sys.modules[__name__], inspect.isclass)
+                               internal_agents = [x for x in internal_agents if issubclass(x[1], InternalAgent)]
+                               internal_agents.remove(('InternalAgent', InternalAgent)) 
+                               if len(internal_agents) > 0:
+                                       choice2 = self.SelectButton(["internal", "external"], prompt="Type of agent")
+                               else:
+                                       choice2 = 1
+
+                               if choice2 == 0:
+                                       agent = internal_agents[self.SelectButton(map(lambda e : e[0], internal_agents), prompt="Choose internal agent")]
+                                       players.append(agent[1](agent[0], colour))                                      
+                               elif choice2 == 1:
+                                       try:
+                                               import Tkinter
+                                               from tkFileDialog import askopenfilename
+                                               root = Tkinter.Tk() # Need a root to make Tkinter behave
+                                               root.withdraw() # Some sort of magic incantation
+                                               path = askopenfilename(parent=root, initialdir="../agents",title=
+'Choose an agent.')
+                                               if path == "":
+                                                       return self.SelectPlayers()
+                                               players.append(make_player(path, colour))       
+                                       except:
+                                               
+                                               p = None
+                                               while p == None:
+                                                       self.board.display_grid(self.window, self.grid_sz)
+                                                       pygame.display.flip()
+                                                       path = self.getstr(prompt = "Enter path:")
+                                                       if path == None:
+                                                               return None
+       
+                                                       if path == "":
+                                                               return self.SelectPlayers()
+       
+                                                       try:
+                                                               p = make_player(path, colour)
+                                                       except:
+                                                               self.board.display_grid(self.window, self.grid_sz)
+                                                               pygame.display.flip()
+                                                               self.message("Invalid path!")
+                                                               time.sleep(1)
+                                                               p = None
+                                               players.append(p)
+                       elif choice == 1:
+                               address = ""
+                               while address == "":
+                                       self.board.display_grid(self.window, self.grid_sz)
+                                       
+                                       address = self.getstr(prompt = "Address? (leave blank for server)")
+                                       if address == None:
+                                               return None
+                                       if address == "":
+                                               address = None
+                                               continue
+                                       try:
+                                               map(int, address.split("."))
+                                       except:
+                                               self.board.display_grid(self.window, self.grid_sz)
+                                               self.message("Invalid IPv4 address!")
+                                               address = ""
+
+                               players.append(NetworkReceiver(colour, address))
+                       else:
+                               return None
+               #print str(self) + ".SelectPlayers returns " + str(players)
+               return players
+                       
+                               
+                       
+# --- graphics.py --- #
+def dedicated_server():
+       global log_files
+       
+       max_games = 5
+       games = []
+       gameID = 0
+       while True:
+               # Get players
+               gameID += 1
+               log("Getting clients...")
+               s = socket.socket()
+               s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+               s.bind(("0.0.0.0", 4562))
+               s.listen(2)
+               ss = s.accept()
+               
+               log("Got white player")
+               
+               args = ["python", "qchess.py", "--no-graphics", "@network::"+str(4600+2*len(games)), "@network::"+str(4600+2*len(games))]
+               if len(log_files) != 0:
+                       for l in log_files:
+                               if l.name == "":
+                                       args.append("--log")
+                               else:
+                                       args.append("--log="+str(l.name)+"_"+str(gameID))
+               
+               g = subprocess.Popen(args, stdout=subprocess.PIPE)
+               games.append(g)
+               
+               time.sleep(0.5)
+               ss[0].send("white " + str(4600 + 2*(len(games)-1)))
+               ss[0].shutdown(socket.SHUT_RD)
+               ss[0].close()
+               
+               time.sleep(0.5)
+               ss = s.accept()
+               
+               log("Got black player")
+               
+               time.sleep(0.5)
+               ss[0].send("black " + str(4600 + 2*(len(games)-1)))
+               ss[0].shutdown(socket.SHUT_RD)
+               ss[0].close()
+               
+               s.shutdown(socket.SHUT_RDWR)
+               s.close()
+               
+               
+               while len(games) > max_games:
+                       #log("Too many games; waiting for game to finish...")
+                       ready = select.select(map(lambda e : e.stdout, games),[], [])
+                       for r in ready[0]:
+                               s = r.readline().strip(" \r\n").split(" ")
+                               if s[0] == "white" or s[0] == "black":
+                                       for g in games[:]:
+                                               if g.stdout == r:
+                                                       log("Game " + str(g) + " has finished")
+                                                       games.remove(g)
+                                                       
+       return 0
+       
+def client(addr):
+       
+       
+       
+       s = socket.socket()
+       s.connect((addr, 4562))
+       
+       [colour,port] = s.recv(1024).strip(" \r\n").split(" ")
+       
+       #debug("Colour: " + colour + ", port: " + port)
+       
+       s.shutdown(socket.SHUT_RDWR)
+       s.close()
+       
+       if colour == "white":
+               p = subprocess.Popen(["python", "qchess.py", "@human", "@network:"+addr+":"+port])
+       else:
+               p = subprocess.Popen(["python", "qchess.py", "@network:"+addr+":"+port, "@human"])
+       p.wait()
+       return 0# --- server.py --- #
+#!/usr/bin/python -u
+
+# Do you know what the -u does? It unbuffers stdin and stdout
+# I can't remember why, but last year things broke without that
+
+"""
+       UCC::Progcomp 2013 Quantum Chess game
+       @author Sam Moore [SZM] "matches"
+       @copyright The University Computer Club, Incorporated
+               (ie: You can copy it for not for profit purposes)
+"""
+
+# system python modules or whatever they are called
+import sys
+import os
+import time
+
+turn_delay = 0.5
+sleep_timeout = None
+[game, graphics] = [None, None]
+
+def make_player(name, colour):
+       if name[0] == '@':
+               if name[1:] == "human":
+                       return HumanPlayer(name, colour)
+               s = name[1:].split(":")
+               if s[0] == "network":
+                       ip = None
+                       port = 4562
+                       #print str(s)
+                       if len(s) > 1:
+                               if s[1] != "":
+                                       ip = s[1]
+                       if len(s) > 2:
+                               port = int(s[2])
+                               
+                       if ip == None:
+                               if colour == "black":
+                                       port += 1
+                       elif colour == "white":
+                               port += 1
+                                               
+                       return NetworkPlayer(colour, Network((ip, port)), None)
+               if s[0] == "internal":
+
+                       import inspect
+                       internal_agents = inspect.getmembers(sys.modules[__name__], inspect.isclass)
+                       internal_agents = [x for x in internal_agents if issubclass(x[1], InternalAgent)]
+                       internal_agents.remove(('InternalAgent', InternalAgent)) 
+                       
+                       if len(s) != 2:
+                               sys.stderr.write(sys.argv[0] + " : '@internal' should be followed by ':' and an agent name\n")
+                               sys.stderr.write(sys.argv[0] + " : Choices are: " + str(map(lambda e : e[0], internal_agents)) + "\n")
+                               return None
+
+                       for a in internal_agents:
+                               if s[1] == a[0]:
+                                       return a[1](name, colour)
+                       
+                       sys.stderr.write(sys.argv[0] + " : Can't find an internal agent matching \"" + s[1] + "\"\n")
+                       sys.stderr.write(sys.argv[0] + " : Choices are: " + str(map(lambda e : e[0], internal_agents)) + "\n")
+                       return None
+                       
+
+       else:
+               return ExternalAgent(name, colour)
+                       
+
+
+# The main function! It does the main stuff!
+def main(argv):
+
+       # Apparently python will silently treat things as local unless you do this
+       # Anyone who says "You should never use a global variable" can die in a fire
+       global game
+       global graphics
+       
+       global turn_delay
+       global agent_timeout
+       global log_files
+       global src_file
+       global graphics_enabled
+       global always_reveal_states
+       global sleep_timeout
+
+
+       server_addr = None
+
+       max_moves = None
+       src_file = None
+       
+       style = "quantum"
+       colour = "white"
+
+       # Get the important warnings out of the way
+       if platform.system() == "Windows":
+               sys.stderr.write(sys.argv[0] + " : Warning - You are using " + platform.system() + "\n")
+               if platform.release() == "Vista":
+                       sys.stderr.write(sys.argv[0] + " : God help you.\n")
+       
+
+       players = []
+       i = 0
+       while i < len(argv)-1:
+               i += 1
+               arg = argv[i]
+               if arg[0] != '-':
+                       p = make_player(arg, colour)
+                       if not isinstance(p, Player):
+                               sys.stderr.write(sys.argv[0] + " : Fatal error creating " + colour + " player\n")
+                               return 100
+                       players.append(p)
+                       if colour == "white":
+                               colour = "black"
+                       elif colour == "black":
+                               pass
+                       else:
+                               sys.stderr.write(sys.argv[0] + " : Too many players (max 2)\n")
+                       continue
+
+               # Option parsing goes here
+               if arg[1] == '-' and arg[2:] == "classical":
+                       style = "classical"
+               elif arg[1] == '-' and arg[2:] == "quantum":
+                       style = "quantum"
+               elif arg[1] == '-' and arg[2:] == "reveal":
+                       always_reveal_states = True
+               elif (arg[1] == '-' and arg[2:] == "graphics"):
+                       graphics_enabled = True
+               elif (arg[1] == '-' and arg[2:] == "no-graphics"):
+                       graphics_enabled = False
+               elif (arg[1] == '-' and arg[2:].split("=")[0] == "file"):
+                       # Load game from file
+                       if len(arg[2:].split("=")) == 1:
+                               src_file = sys.stdin
+                       else:
+                               f = arg[2:].split("=")[1]
+                               if f[0:7] == "http://":
+                                       src_file = HttpReplay(f)
+                               else:
+                                       src_file = FileReplay(f.split(":")[0])
+
+                                       if len(f.split(":")) == 2:
+                                               max_moves = int(f.split(":")[1])
+                                               
+               elif (arg[1] == '-' and arg[2:].split("=")[0] == "server"):
+                       #debug("Server: " + str(arg[2:]))
+                       if len(arg[2:].split("=")) <= 1:
+                               server_addr = True
+                       else:
+                               server_addr = arg[2:].split("=")[1]
+                       
+               elif (arg[1] == '-' and arg[2:].split("=")[0] == "log"):
+                       # Log file
+                       if len(arg[2:].split("=")) == 1:
+                               log_files.append(LogFile(sys.stdout,""))
+                       else:
+                               f = arg[2:].split("=")[1]
+                               if f == "":
+                                       log_files.append(LogFile(sys.stdout, ""))
+                               elif f[0] == '@':
+                                       log_files.append(ShortLog(f[1:]))
+                               else:
+                                       log_files.append(LogFile(open(f, "w", 0), f))
+               elif (arg[1] == '-' and arg[2:].split("=")[0] == "delay"):
+                       # Delay
+                       if len(arg[2:].split("=")) == 1:
+                               turn_delay = 0
+                       else:
+                               turn_delay = float(arg[2:].split("=")[1])
+
+               elif (arg[1] == '-' and arg[2:].split("=")[0] == "timeout"):
+                       # Timeout
+                       if len(arg[2:].split("=")) == 1:
+                               agent_timeout = -1
+                       else:
+                               agent_timeout = float(arg[2:].split("=")[1])
+               elif (arg[1] == '-' and arg[2:].split("=")[0] == "blackout"):
+                       # Screen saver delay
+                       if len(arg[2:].split("=")) == 1:
+                               sleep_timeout = -1
+                       else:
+                               sleep_timeout = float(arg[2:].split("=")[1])
+                               
+               elif (arg[1] == '-' and arg[2:] == "help"):
+                       # Help
+                       os.system("less data/help.txt") # The best help function
+                       return 0
+               
+       # Dedicated server?
+       
+       #debug("server_addr = " + str(server_addr))
+       
+       if server_addr != None:
+               if server_addr == True:
+                       return dedicated_server()
+               else:
+                       return client(server_addr)
+               
+
+       # Create the board
+       
+       # Construct a GameThread! Make it global! Damn the consequences!
+                       
+       if src_file != None:
+               # Hack to stop ReplayThread from exiting
+               #if len(players) == 0:
+               #       players = [HumanPlayer("dummy", "white"), HumanPlayer("dummy", "black")]
+
+               # Normally the ReplayThread exits if there are no players
+               # TODO: Decide which behaviour to use, and fix it
+               end = (len(players) == 0)
+               if end:
+                       players = [Player("dummy", "white"), Player("dummy", "black")]
+               elif len(players) != 2:
+                       sys.stderr.write(sys.argv[0] + " : Usage " + sys.argv[0] + " white black\n")
+                       if graphics_enabled:
+                               sys.stderr.write(sys.argv[0] + " : (You won't get a GUI, because --file was used, and the author is lazy)\n")
+                       return 44
+               game = ReplayThread(players, src_file, end=end, max_moves=max_moves)
+       else:
+               board = Board(style)
+               board.max_moves = max_moves
+               game = GameThread(board, players) 
+
+
+
+
+       # Initialise GUI
+       if graphics_enabled == True:
+               try:
+                       graphics = GraphicsThread(game.board, grid_sz = [64,64]) # Construct a GraphicsThread!
+                       
+                       graphics.sleep_timeout = sleep_timeout
+
+               except Exception,e:
+                       graphics = None
+                       sys.stderr.write(sys.argv[0] + " : Got exception trying to initialise graphics\n"+str(e.message)+"\nDisabled graphics\n")
+                       graphics_enabled = False
+
+       # If there are no players listed, display a nice pretty menu
+       if len(players) != 2:
+               if graphics != None:
+                       
+                       server_addr = graphics.SelectServer()
+                       if server_addr != None:
+                               if server_addr == True:
+                                       return dedicated_server()
+                               else:
+                                       return client(server_addr)      
+                       
+                       players = graphics.SelectPlayers(players)
+               else:
+                       sys.stderr.write(sys.argv[0] + " : Usage " + sys.argv[0] + " white black\n")
+                       return 44
+
+       # If there are still no players, quit
+       if players == None or len(players) != 2:
+               sys.stderr.write(sys.argv[0] + " : Graphics window closed before players chosen\n")
+               return 45
+
+       old = players[:]
+       for p in old:
+               if isinstance(p, NetworkPlayer):
+                       for i in range(len(old)):
+                               if old[i] == p or isinstance(old[i], NetworkPlayer):
+                                       continue
+                               players[i] = NetworkPlayer(old[i].colour, p.network, old[i])
+               
+       for p in players:
+               #debug(str(p))
+               if isinstance(p, NetworkPlayer):
+                       p.board = game.board
+                       if not p.network.connected:
+                               if not p.network.server:
+                                       time.sleep(0.2)
+                               p.network.connect()
+                               
+       
+       # If using windows, select won't work; use horrible TimeoutPlayer hack
+       if agent_timeout > 0:
+               if platform.system() == "Windows":
+                       for i in range(len(players)):
+                               if isinstance(players[i], ExternalAgent) or isinstance(players[i], InternalAgent):
+                                       players[i] = TimeoutPlayer(players[i], agent_timeout)
+
+               else:
+                       warned = False
+                       # InternalAgents get wrapped to an ExternalAgent when there is a timeout
+                       # This is not confusing at all.
+                       for i in range(len(players)):
+                               if isinstance(players[i], InternalAgent):
+                                               players[i] = ExternalWrapper(players[i])
+
+
+               
+
+
+
+
+       log_init(game.board, players)
+       
+       
+       if graphics != None:
+               game.start() # This runs in a new thread
+               graphics.run()
+               if game.is_alive():
+                       game.join()
+       
+
+               error = game.error + graphics.error
+       else:
+               game.run()
+               error = game.error
+       
+
+       for l in log_files:
+               l.close()
+
+       if src_file != None and src_file != sys.stdin:
+               src_file.close()
+
+       sys.stdout.write(game.final_result + "\n")
+
+       return error
+               
+               
+       
+               
+       
+               
+               
+
+# This is how python does a main() function...
+if __name__ == "__main__":
+       retcode = 0
+       try:
+               retcode = main(sys.argv)
+       except KeyboardInterrupt:
+               sys.stderr.write(sys.argv[0] + " : Got KeyboardInterrupt. Stopping everything\n")
+               if isinstance(graphics, StoppableThread):
+                       graphics.stop()
+                       graphics.run() # Will clean up graphics because it is stopped, not run it (a bit dodgy)
+
+               if isinstance(game, StoppableThread):
+                       game.stop()
+                       if game.is_alive():
+                               game.join()
+               retcode = 102
+       #except Exception, e:
+       #       sys.stderr.write(sys.argv[0] + " : " + e.message + "\n")
+       #       retcode = 103   
+               
+       try:
+               sys.stdout.close()
+       except:
+               pass
+       try:
+               sys.stderr.close()
+       except:
+               pass
+       sys.exit(retcode)
+               
+
+# --- main.py --- #
+# EOF - created from make on Sat Apr 20 12:19:31 WST 2013
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/qchess/data/images/index.html b/qchess/data/images/index.html
new file mode 100644 (file)
index 0000000..9daeafb
--- /dev/null
@@ -0,0 +1 @@
+test
old mode 100755 (executable)
new mode 100644 (file)
deleted file mode 120000 (symlink)
index a1ec45aa605d80fd643857c0e37ae8ff18a8013b..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-../src/images.py
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..72848683a6db192d411098609b0811639e775741
--- /dev/null
@@ -0,0 +1,54 @@
+try:
+       import pygame
+except:
+       pass
+import os
+
+# Dictionary that stores the unicode character representations of the different pieces
+# Chess was clearly the reason why unicode was invented
+# For some reason none of the pygame chess implementations I found used them!
+piece_char = {"white" : {"king" : u'\u2654',
+                        "queen" : u'\u2655',
+                        "rook" : u'\u2656',
+                        "bishop" : u'\u2657',
+                        "knight" : u'\u2658',
+                        "pawn" : u'\u2659',
+                        "unknown" : '?'},
+               "black" : {"king" : u'\u265A',
+                        "queen" : u'\u265B',
+                        "rook" : u'\u265C',
+                        "bishop" : u'\u265D',
+                        "knight" : u'\u265E',
+                        "pawn" : u'\u265F',
+                        "unknown" : '?'}}
+
+images = {"white" : {}, "black" : {}}
+small_images = {"white" : {}, "black" : {}}
+
+def create_images(grid_sz, font_name=os.path.join(os.path.curdir, "data", "DejaVuSans.ttf")):
+
+       # Get the font sizes
+       l_size = 5*(grid_sz[0] / 8)
+       s_size = 3*(grid_sz[0] / 8)
+
+       for c in piece_char.keys():
+               
+               if c == "black":
+                       for p in piece_char[c].keys():
+                               images[c].update({p : pygame.font.Font(font_name, l_size).render(piece_char[c][p], True,(0,0,0))})
+                               small_images[c].update({p : pygame.font.Font(font_name, s_size).render(piece_char[c][p],True,(0,0,0))})         
+               elif c == "white":
+                       for p in piece_char[c].keys():
+                               images[c].update({p : pygame.font.Font(font_name, l_size+1).render(piece_char["black"][p], True,(255,255,255))})
+                               images[c][p].blit(pygame.font.Font(font_name, l_size).render(piece_char[c][p], True,(0,0,0)),(0,0))
+                               small_images[c].update({p : pygame.font.Font(font_name, s_size+1).render(piece_char["black"][p],True,(255,255,255))})
+                               small_images[c][p].blit(pygame.font.Font(font_name, s_size).render(piece_char[c][p],True,(0,0,0)),(0,0))
+       
+
+def load_images(image_dir=os.path.join(os.path.curdir, "data", "images")):
+       if not os.path.exists(image_dir):
+               raise Exception("Couldn't load images from " + image_dir + " (path doesn't exist)")
+       for c in piece_char.keys():
+               for p in piece_char[c].keys():
+                       images[c].update({p : pygame.image.load(os.path.join(image_dir, c + "_" + p + ".png"))})
+                       small_images[c].update({p : pygame.image.load(os.path.join(image_dir, c + "_" + p + "_small.png"))})
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/run.sh b/run.sh
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/web/images b/web/images
new file mode 120000 (symlink)
index 0000000..850630b
--- /dev/null
@@ -0,0 +1 @@
+../qchess/data/images/
\ No newline at end of file
diff --git a/web/logs/log b/web/logs/log
new file mode 100644 (file)
index 0000000..ac55277
--- /dev/null
@@ -0,0 +1,14 @@
+# Log starts 2013-05-02 12:40:48.956309
+2013-05-02 12:40:48.956389 : Getting clients...
+2013-05-10 09:50:45.266308 : Got white player
+2013-05-10 09:50:51.328055 : Got black player
+2013-05-10 09:50:51.828767 : Getting clients...
+2013-05-18 17:50:16.077574 : Got white player
+2013-05-18 17:50:41.904604 : Got black player
+2013-05-18 17:50:42.405349 : Getting clients...
+2013-05-18 18:25:12.576240 : Got white player
+2013-05-18 18:25:21.680798 : Got black player
+2013-05-18 18:25:22.181525 : Getting clients...
+2013-05-18 18:28:48.112894 : Got white player
+2013-05-18 18:28:49.116687 : Got black player
+2013-05-18 18:28:49.617370 : Getting clients...
diff --git a/web/logs/log_1 b/web/logs/log_1
new file mode 100644 (file)
index 0000000..50f55de
--- /dev/null
@@ -0,0 +1,53 @@
+# Log starts 2013-05-10 09:50:45.382246
+# white : @network:(None, 4600)
+# black : @network:(None, 4601)
+# Initial board
+black unknown ['rook', '?queen'] at 0,0
+black unknown ['pawn', '?pawn'] at 0,1
+white unknown ['pawn', '?knight'] at 0,6
+white unknown ['rook', '?pawn'] at 0,7
+black unknown ['knight', '?bishop'] at 1,0
+black unknown ['pawn', '?pawn'] at 1,1
+white unknown ['pawn', '?knight'] at 1,6
+white unknown ['knight', '?rook'] at 1,7
+black unknown ['bishop', '?bishop'] at 2,0
+black unknown ['pawn', '?pawn'] at 2,1
+white unknown ['pawn', '?pawn'] at 2,6
+white unknown ['bishop', '?pawn'] at 2,7
+black king ['king', 'king'] at 3,0
+black unknown ['pawn', '?pawn'] at 3,1
+white unknown ['pawn', '?pawn'] at 3,6
+white king ['king', 'king'] at 3,7
+black unknown ['queen', '?rook'] at 4,0
+black unknown ['pawn', '?knight'] at 4,1
+white unknown ['pawn', '?pawn'] at 4,6
+white unknown ['queen', '?queen'] at 4,7
+black unknown ['bishop', '?rook'] at 5,0
+black unknown ['pawn', '?pawn'] at 5,1
+white unknown ['pawn', '?pawn'] at 5,6
+white unknown ['bishop', '?rook'] at 5,7
+black unknown ['knight', '?knight'] at 6,0
+black unknown ['pawn', '?pawn'] at 6,1
+white unknown ['pawn', '?pawn'] at 6,6
+white unknown ['knight', '?bishop'] at 6,7
+black unknown ['rook', '?pawn'] at 7,0
+black unknown ['pawn', '?pawn'] at 7,1
+white unknown ['pawn', '?pawn'] at 7,6
+white unknown ['rook', '?bishop'] at 7,7
+# Start game
+2013-05-10 09:50:54.310819 : 4 6 1 pawn
+2013-05-10 09:50:55.481921 : 4 6 -> 4 4
+2013-05-10 09:50:57.309623 : 3 1 1 pawn
+2013-05-10 09:50:58.103761 : 3 1 -> 3 3
+2013-05-10 09:51:33.678172 : 5 6 0 pawn
+2013-05-10 09:51:34.228357 : 5 6 -> 5 5
+2013-05-10 09:51:37.401411 : 4 1 1 knight
+2013-05-10 09:51:38.490964 : 4 1 -> 5 3
+2013-05-10 09:51:40.679271 : 4 7 0 queen
+2013-05-10 09:51:41.963620 : 4 7 -> 7 4
+2013-05-10 09:51:44.292005 : 3 0 0 king
+2013-05-10 09:51:44.975591 : 3 0 -> 4 1
+2013-05-10 09:51:47.471950 : 7 4 0 queen
+2013-05-10 09:51:51.777611 : 7 4 -> 4 1
+2013-05-10 09:51:52.278222 : white
+# EOF
diff --git a/web/logs/log_2 b/web/logs/log_2
new file mode 100644 (file)
index 0000000..efcc3c3
--- /dev/null
@@ -0,0 +1,49 @@
+# Log starts 2013-05-18 17:50:16.195914
+# white : @network:(None, 4602)
+# black : @network:(None, 4603)
+# Initial board
+black unknown ['rook', '?queen'] at 0,0
+black unknown ['pawn', '?pawn'] at 0,1
+white unknown ['pawn', '?pawn'] at 0,6
+white unknown ['rook', '?rook'] at 0,7
+black unknown ['knight', '?pawn'] at 1,0
+black unknown ['pawn', '?knight'] at 1,1
+white unknown ['pawn', '?knight'] at 1,6
+white unknown ['knight', '?knight'] at 1,7
+black unknown ['bishop', '?rook'] at 2,0
+black unknown ['pawn', '?bishop'] at 2,1
+white unknown ['pawn', '?pawn'] at 2,6
+white unknown ['bishop', '?pawn'] at 2,7
+black king ['king', 'king'] at 3,0
+black unknown ['pawn', '?bishop'] at 3,1
+white unknown ['pawn', '?pawn'] at 3,6
+white king ['king', 'king'] at 3,7
+black unknown ['queen', '?pawn'] at 4,0
+black unknown ['pawn', '?pawn'] at 4,1
+white unknown ['pawn', '?pawn'] at 4,6
+white unknown ['queen', '?bishop'] at 4,7
+black unknown ['bishop', '?rook'] at 5,0
+black unknown ['pawn', '?pawn'] at 5,1
+white unknown ['pawn', '?pawn'] at 5,6
+white unknown ['bishop', '?queen'] at 5,7
+black unknown ['knight', '?pawn'] at 6,0
+black unknown ['pawn', '?pawn'] at 6,1
+white unknown ['pawn', '?bishop'] at 6,6
+white unknown ['knight', '?rook'] at 6,7
+black unknown ['rook', '?knight'] at 7,0
+black unknown ['pawn', '?pawn'] at 7,1
+white unknown ['pawn', '?pawn'] at 7,6
+white unknown ['rook', '?pawn'] at 7,7
+# Start game
+2013-05-18 17:50:43.367638 : 3 6 1 pawn
+2013-05-18 17:50:50.415485 : 3 6 -> 3 4
+2013-05-18 17:50:51.816167 : 3 1 0 pawn
+2013-05-18 17:50:52.371079 : 3 1 -> 3 3
+2013-05-18 17:50:55.174875 : 4 7 0 queen
+2013-05-18 17:50:57.503496 : 4 7 -> 0 3
+2013-05-18 17:50:58.565433 : 2 1 0 pawn
+2013-05-18 17:50:59.316660 : 2 1 -> 2 3
+2013-05-18 17:51:00.398013 : 0 3 0 queen
+2013-05-18 17:51:01.230841 : 0 3 -> 3 0
+2013-05-18 17:51:01.731467 : white
+# EOF
diff --git a/web/logs/log_3 b/web/logs/log_3
new file mode 100644 (file)
index 0000000..325ebb1
--- /dev/null
@@ -0,0 +1 @@
+# Log starts 2013-05-18 18:25:12.694368
diff --git a/web/logs/log_4 b/web/logs/log_4
new file mode 100644 (file)
index 0000000..2ba46ac
--- /dev/null
@@ -0,0 +1,47 @@
+# Log starts 2013-05-18 18:28:48.231038
+# white : @network:(None, 4606)
+# black : @network:(None, 4607)
+# Initial board
+black unknown ['rook', '?bishop'] at 0,0
+black unknown ['pawn', '?pawn'] at 0,1
+white unknown ['pawn', '?bishop'] at 0,6
+white unknown ['rook', '?rook'] at 0,7
+black unknown ['knight', '?knight'] at 1,0
+black unknown ['pawn', '?knight'] at 1,1
+white unknown ['pawn', '?pawn'] at 1,6
+white unknown ['knight', '?rook'] at 1,7
+black unknown ['bishop', '?queen'] at 2,0
+black unknown ['pawn', '?pawn'] at 2,1
+white unknown ['pawn', '?pawn'] at 2,6
+white unknown ['bishop', '?knight'] at 2,7
+black king ['king', 'king'] at 3,0
+black unknown ['pawn', '?pawn'] at 3,1
+white unknown ['pawn', '?pawn'] at 3,6
+white king ['king', 'king'] at 3,7
+black unknown ['queen', '?rook'] at 4,0
+black unknown ['pawn', '?pawn'] at 4,1
+white unknown ['pawn', '?pawn'] at 4,6
+white unknown ['queen', '?knight'] at 4,7
+black unknown ['bishop', '?rook'] at 5,0
+black unknown ['pawn', '?pawn'] at 5,1
+white unknown ['pawn', '?pawn'] at 5,6
+white unknown ['bishop', '?pawn'] at 5,7
+black unknown ['knight', '?pawn'] at 6,0
+black unknown ['pawn', '?pawn'] at 6,1
+white unknown ['pawn', '?pawn'] at 6,6
+white unknown ['knight', '?bishop'] at 6,7
+black unknown ['rook', '?bishop'] at 7,0
+black unknown ['pawn', '?pawn'] at 7,1
+white unknown ['pawn', '?pawn'] at 7,6
+white unknown ['rook', '?queen'] at 7,7
+# Start game
+2013-05-18 18:28:51.646758 : 5 6 1 pawn
+2013-05-18 18:28:52.548055 : 5 6 -> 5 4
+2013-05-18 18:28:56.728446 : 0 1 1 pawn
+2013-05-18 18:28:57.297094 : 0 1 -> 0 2
+2013-05-18 18:28:58.898872 : 5 4 0 pawn
+2013-05-18 18:28:59.420966 : 5 4 -> 5 3
+2013-05-18 18:29:03.940562 : 7 1 0 pawn
+2013-05-18 18:29:04.499325 : 7 1 -> 7 2
+2013-05-18 18:29:10.454964 : network terminate
+# EOF
diff --git a/web/poster b/web/poster
deleted file mode 120000 (symlink)
index e200c80..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../poster
\ No newline at end of file
diff --git a/web/poster/original.pdf b/web/poster/original.pdf
new file mode 100644 (file)
index 0000000..2f68aea
Binary files /dev/null and b/web/poster/original.pdf differ
diff --git a/web/poster/outlines.svg b/web/poster/outlines.svg
new file mode 100644 (file)
index 0000000..8f99274
--- /dev/null
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="744.09448819"
+   height="1052.3622047"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="New document 1">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.4"
+     inkscape:cx="181.83741"
+     inkscape:cy="458.16394"
+     inkscape:document-units="px"
+     inkscape:current-layer="g3014"
+     showgrid="false"
+     inkscape:window-width="1366"
+     inkscape:window-height="721"
+     inkscape:window-x="-2"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <g
+       transform="matrix(1.25,0,0,-1.25,-2.8571443,1030.0193)"
+       inkscape:label="original"
+       id="g3012">
+      <g
+         transform="matrix(576,0,0,823.68,-69.498491,69.498495)"
+         id="g3014">
+        <path
+           style="fill:#000000"
+           d="m 0.33468027,0.35396112 c -0.008514,-3.4267e-4 -0.0168728,-0.004036 -0.022092,-0.0108659 l -0.001302,-0.004097 -5.2083e-4,6.07e-5 c 1.75e-5,-1.5042e-4 1.7779e-4,-3.7746e-4 3.4722e-4,-6.6773e-4 l -1.7361e-4,-5.1598e-4 5.6424e-4,-1.2141e-4 c 0.002864,-0.004175 0.0135227,-0.0158256 0.0136719,-0.0207908 7.1951e-4,-0.0151608 -0.009796,-0.0270683 -0.0203559,-0.0364523 l 0.001215,-0.00346 c -1.449e-4,-0.008836 0.0106291,-0.00708 0.0164931,-0.007558 0.0137072,-0.002823 0.027305,0.00138 0.0410157,0.002337 0.005851,0.002878 0.0148131,-0.001851 0.0196181,0.003733 l -8.6805e-4,0.004462 -0.00434,0.007254 c -0.0117922,0.00694 -0.017316,0.0225367 -0.0222222,0.0348436 8.0069e-4,1.5002e-4 0.001607,5.7879e-4 0.002387,0.001366 0.002371,0.004766 0.00876,0.005654 0.009766,0.0114729 2.0681e-4,0.0134158 -0.0152826,0.015246 -0.0247396,0.018211 -0.00276,6.3758e-4 -0.005626,9.0337e-4 -0.008464,7.8914e-4 z m 0.001042,-0.001032 c 9.8536e-4,-1.055e-5 0.001924,-7.802e-5 0.002821,-1.8211e-4 0.002967,-3.45e-4 0.005822,-0.001734 0.009245,-0.001791 0.002081,-0.001118 0.0103853,-0.003813 0.0139323,-0.006343 0.003689,-0.00277 0.005565,-0.008887 0.001302,-0.0125048 -0.006838,0.001092 -0.018579,0.001082 -0.0246528,0.002125 l 0.002474,-0.003794 0.004253,-0.004462 c 0.002782,-3.174e-5 0.005735,-0.002978 0.008637,-0.003733 0.001314,-0.006892 0.0141962,-0.0268918 0.012283,-0.0263148 6.9296e-4,-0.001182 0.001706,-0.002758 0.002691,-0.003581 0.004096,-0.003428 0.009173,-0.005027 0.0114149,-0.0104713 l -8.681e-5,-0.007011 c -0.0101952,-9.21e-4 -0.0202864,-0.002402 -0.0304688,-0.003369 -0.0115662,-0.002382 -0.0229883,-0.001076 -0.0346355,-2.7317e-4 -0.005839,1.392e-4 -0.009691,0.007611 -0.005469,0.0119889 0.0114921,0.009289 0.0208471,0.0245858 0.0162761,0.0397909 -0.002973,0.004621 -0.006877,0.0110886 -0.0114583,0.0148116 l 0.001345,0.00428 c 0.00454,0.008441 0.0131979,0.0109093 0.0200955,0.0108355 z m 0.0141927,-0.007618 -0.004297,-1.8211e-4 5.6424e-4,-5.7668e-4 0.007769,-0.002944 0.004167,-7.2843e-4 -0.00816,0.004431 -4.34e-5,0 z m 9.5486e-4,-0.004219 -0.004123,-1.2141e-4 -0.001345,-0.001427 c 6.39e-4,-0.005577 0.008405,-0.001571 0.005469,0.001548 z m -0.00204,-0.001457 c 0.001106,-3.885e-5 4.733e-4,-0.003005 -0.001085,-5.4633e-4 4.4512e-4,4.05e-4 8.2991e-4,5.553e-4 0.001085,5.4633e-4 z m -0.006727,-0.006981 c 7.55e-4,-3.2759e-4 0.001479,-6.3623e-4 0.001953,-9.1054e-4 2.5669e-4,-1.4857e-4 2.8158e-4,5.7481e-4 6.5104e-4,-4.2493e-4 0.001094,-0.002962 -0.00349,-0.002174 -0.003212,6.6774e-4 l 6.0764e-4,6.6773e-4 z m 0.005512,-8.1949e-4 0.003602,-9.105e-5 0.0114583,9.105e-5 c -0.001782,-0.001354 -0.00449,-0.002314 -0.00842,-0.002519 -0.002066,-0.001255 -0.004247,0.002034 -0.005295,1.5176e-4 l -0.002344,0.001062 9.9827e-4,0.001305 z m -8.681e-5,-0.003794 c 0.001106,-3.885e-5 5.1671e-4,-0.003005 -0.001042,-5.4633e-4 4.4512e-4,4.0501e-4 7.8651e-4,5.553e-4 0.001042,5.4633e-4 z m 0.002995,-9.105e-5 0.003429,-4.8563e-4 c 0.007508,-0.001292 -0.00119,-0.005147 9.9826e-4,-0.0017 l -0.002821,-5.1597e-4 -0.002344,0.001062 7.3785e-4,0.001639 z m -0.009245,-0.0150544 0.001389,-0.002519 c 0.002247,-0.00615 0.0100991,-0.005737 0.0133681,-0.0104106 -0.00371,-0.005995 -0.0124039,-0.006967 -0.0178819,-0.003157 l 0.00178,0.001487 c 0.003184,0.006032 -0.002918,0.00878 -0.00599,0.012262 4.22e-4,-0.002927 0.00288,-0.005076 0.004557,-0.007284 0.003772,-0.004076 -0.005127,-0.00551 -2.6042e-4,-0.008802 0.006751,-0.00184 0.0170958,-0.002403 0.0190538,0.006677 -0.004572,0.003179 -0.0115223,0.003823 -0.0137153,0.009834 l -0.0023,0.001912 z"
+           id="path3027"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:#000000"
+           d="M 393.90625 416.6875 C 392.91602 416.79627 392.82734 417.46895 392.4375 419.375 C 392.32662 419.92142 391.65705 420.1824 390.65625 420.0625 C 389.76993 419.95659 388.85351 420.014 388.625 420.1875 C 388.39778 420.3615 388.43728 422.54991 388.71875 425.03125 C 389.19323 429.21319 389.3427 429.55732 390.9375 430.0625 C 392.63206 430.59892 392.64284 430.7034 392.4375 435.4375 C 392.18622 441.09874 391.95322 441.72721 390.0625 441.46875 C 388.93498 441.31534 388.35938 441.77347 387.3125 443.6875 C 386.9112 444.42409 385.54996 444.71019 384.375 444.90625 C 384.11767 444.85905 383.72805 444.83605 383.21875 444.84375 C 380.72121 444.88145 375.71682 445.58066 373.6875 446.3125 C 372.70902 446.66396 371.27083 447.18242 370.46875 447.46875 C 369.66667 447.75498 368.04428 448.57487 366.875 449.3125 C 365.1719 450.38946 364.82996 450.89521 365.1875 451.8125 C 365.4359 452.44159 366.07012 454.64925 366.59375 456.71875 C 367.11719 458.78835 368.59268 464.00017 369.875 468.28125 C 371.15732 472.56274 372.70277 478.69596 373.28125 481.90625 C 373.86013 485.11654 374.52373 487.9127 374.78125 488.125 C 375.04261 488.3371 375.54497 489.95299 375.875 491.71875 C 376.4654 494.88213 376.45642 494.9385 375.0625 495.78125 C 374.28739 496.25238 373.60749 496.88971 373.5625 497.21875 C 373.5176 497.54749 373.23047 497.89778 372.9375 497.96875 C 371.91582 498.21585 368.40578 502.91291 368.21875 504.28125 C 368.07259 505.34717 367.6543 505.64262 366.4375 505.5625 C 365.57278 505.5058 364.31989 505.45597 363.65625 505.4375 C 362.99025 505.4187 362.17966 505.3881 361.84375 505.375 C 361.11755 505.3472 360.10768 512.13327 360.71875 512.9375 C 360.9503 513.24226 364.3211 513.94012 368.1875 514.46875 C 372.05721 514.99743 375.4201 515.68991 375.65625 516 C 376.18401 516.69271 371.57476 550.35991 369.625 560.09375 C 367.7242 569.58553 365.79847 576.39298 364.84375 577 C 364.40671 577.27387 363.3303 580.39604 362.4375 583.96875 C 361.54254 587.53992 359.84209 592.6046 358.65625 595.21875 C 357.46753 597.8329 356.4468 600.41234 356.375 600.9375 C 356.303 601.46363 357.5037 603.53794 359.0625 605.53125 C 360.6213 607.52559 361.82806 609.61657 361.75 610.1875 C 361.55992 611.57643 359.22766 616.05862 358.53125 616.375 C 357.72528 616.74205 352.55877 623.83281 350.53125 627.34375 L 348.78125 630.34375 L 350.75 633.84375 C 351.83144 635.77013 353.26172 637.62087 353.9375 637.9375 C 354.56027 638.2294 355.18155 638.71112 355.40625 639.0625 C 355.03505 639.38182 354.66372 639.68047 354.5 639.6875 C 354.36577 639.6935 354.22766 639.7159 354.09375 639.75 C 353.55879 639.88664 352.10159 639.99338 350.84375 640 C 349.58519 640.007 348.39328 640.21914 348.1875 640.46875 C 347.98619 640.71791 348.1008 643.7751 348.46875 647.25 C 348.84175 650.7249 349.10365 653.99906 349.03125 654.53125 C 348.90075 655.48578 351.00279 657.34148 351.84375 657.34375 C 352.43797 657.68611 353.19419 658.02798 353.71875 658.21875 C 356.44208 659.21025 380.15576 662.38842 383.75 662.25 C 385.56217 662.1798 388.85325 662.05939 391.03125 661.96875 C 393.20925 661.87785 396.31923 661.8951 397.96875 662 C 401.07886 662.19768 405.18186 661.9182 417.21875 660.71875 C 423.25213 660.1169 424.37179 660.16808 424.84375 660.96875 C 425.30311 661.75099 425.56573 661.67138 426.53125 660.5625 C 427.44925 659.51025 427.83589 657.98368 428.34375 653.125 C 428.92315 647.56001 428.85448 646.88426 427.75 645.875 C 425.76784 644.05879 421.9346 639.47835 422 639 C 422.0331 638.75598 422.97098 637.38512 424.0625 635.9375 C 426.12224 633.19773 427.32838 632.34153 425.6875 629.21875 C 425.50318 629.02724 423.57316 624.66072 421.375 619.53125 L 417.375 610.21875 L 418.84375 607 C 419.14866 606.33045 419.3733 605.70161 419.5625 605.125 C 419.73001 605.42936 419.89117 605.62244 419.96875 605.46875 C 420.02075 605.36423 419.9637 604.76559 419.875 604.03125 C 419.97652 603.52928 419.99527 603.10606 419.90625 602.90625 C 419.82045 602.71332 419.74785 602.6173 419.65625 602.59375 C 419.38822 600.85279 419.03532 598.90599 418.8125 598.4375 C 418.4129 597.59014 417.76654 595.10342 417.375 592.90625 C 416.98548 590.70908 416.14825 586.7563 415.53125 584.09375 C 412.59221 571.46766 412.15581 569.26046 411.75 565.53125 C 411.50598 563.33202 411.09788 561.23855 410.875 560.875 C 410.64873 560.51052 410.25824 558.68019 410 556.8125 C 409.73936 554.94584 409.22359 551.47727 408.84375 549.09375 C 408.46445 546.71043 408.03108 541.89314 407.875 538.375 C 407.71656 534.85583 407.44276 531.2654 407.25 530.40625 C 406.4999 527.04955 406.60849 516.13291 407.40625 515.71875 C 408.36795 515.21738 418.38561 515.06863 419.90625 515.53125 L 421.75 516.09375 L 422.5 512.15625 C 422.90751 509.99718 423.13253 508.01444 423 507.71875 C 422.86608 507.42269 421.459 506.91496 419.875 506.59375 C 417.86692 506.18706 416.98125 505.72785 416.96875 505.09375 C 416.95875 504.59233 416.89285 503.75632 416.84375 503.25 C 416.79475 502.74346 417.10242 502.45612 417.5 502.59375 C 418.54849 502.95617 418.57986 501.36506 417.5625 500.25 C 417.08154 499.72696 415.41623 498.52914 413.84375 497.59375 C 412.38859 496.72815 410.80905 495.97704 410.125 495.78125 C 410.70495 493.24538 410.83418 487.53103 412.8125 483.03125 C 413.6441 481.14708 414.55501 479.3561 414.84375 479.0625 C 415.12887 478.76803 415.69395 477.49648 416.09375 476.21875 C 416.49335 474.94102 417.5784 472.34056 418.5 470.46875 C 419.42448 468.59591 421.05868 464.62217 422.125 461.625 C 424.36708 455.32129 424.4111 455.22877 425.9375 455.4375 C 427.72814 455.68152 427.41977 454.8892 424.90625 452.8125 C 423.31347 451.4977 420.80044 450.33684 416.875 449.125 C 413.73724 448.15675 410.96778 447.35082 410.6875 447.3125 C 410.4024 447.2734 409.97117 446.2589 409.75 445.0625 C 409.52824 443.8661 408.96504 442.84484 408.5 442.78125 C 408.35257 442.76105 408.23437 442.7436 408.125 442.75 C 407.96629 442.759 407.85899 442.8284 407.78125 442.90625 C 406.81333 442.87055 405.21585 442.95525 404 442.90625 L 401 442.78125 L 400.6875 440.5625 C 400.52123 439.34036 400.44349 437.99072 400.5 437.5625 C 400.5267 437.3606 400.4662 437.21895 400.375 437.125 C 400.369 437.119 400.381 437.09895 400.375 437.09375 C 400.53347 436.25888 400.9251 434.25375 401.09375 433.125 C 402.29466 433.91625 404.12966 434.82063 404.5 434.65625 C 404.96335 434.4493 405.7205 427.07668 405.4375 425.53125 C 405.3655 425.10475 404.49864 424.6678 403.5 424.53125 C 401.58076 424.2687 401.53923 424.20803 401.0625 420.09375 L 400.75 417.5 L 396.9375 416.96875 C 395.42904 416.76257 394.50039 416.62224 393.90625 416.6875 z M 395.34375 418.09375 C 395.8196 418.09443 396.39985 418.16625 397.09375 418.3125 C 399.61515 418.8448 399.69471 418.90661 400.09375 421.78125 C 400.36519 423.73337 400.83669 424.80017 401.5 424.9375 C 402.04432 425.05034 402.87359 425.2034 403.34375 425.3125 C 404.35417 425.54725 404.76781 429.18638 404.03125 431.3125 C 403.59493 432.58548 403.25653 432.70808 401.78125 432.28125 C 401.01196 432.05907 400.36043 431.97843 400.125 432.0625 C 400.122 432.06302 400.09505 432.0615 400.09375 432.0625 C 400.09075 432.0645 400.09675 432.09015 400.09375 432.09375 C 400.0928 432.09475 400.0634 432.09275 400.0625 432.09375 C 400.037 432.11075 400.03455 432.13175 400.03125 432.15625 C 400.02925 432.17165 400.02625 432.20045 400.03125 432.21875 C 399.81278 432.95048 399.52519 436.928 399.59375 437.625 C 399.38262 438.1551 399.1912 438.97703 399.125 439.875 L 398.9375 442.375 L 396.09375 442.09375 C 393.39484 441.82811 393.25913 441.73741 393.4375 440.21875 C 393.54069 439.3405 393.63346 437.51671 393.65625 436.1875 C 393.67905 434.85829 393.76666 432.84271 393.84375 431.6875 C 393.96111 429.87278 393.76215 429.51972 392.34375 429.15625 C 390.58191 428.70426 389.61616 426.44638 389.6875 422.9375 C 389.7185 421.27554 389.83866 421.15105 391.3125 421.53125 C 392.65472 421.8768 392.95934 421.71565 393.125 420.5625 C 393.37772 418.79429 393.91619 418.09172 395.34375 418.09375 z M 390.0625 442.4375 C 390.61553 442.3627 394.2743 442.79242 398.1875 443.40625 C 403.51993 444.24283 406.46673 444.21798 407.78125 443.78125 C 407.9242 444.2671 408.20459 444.90309 408.6875 445.875 C 409.87255 448.26264 411.25436 448.99615 418.625 451.15625 C 422.5094 452.29499 424.46135 453.8036 423.59375 455 C 423.21647 455.52921 422.39409 457.58773 421.75 459.5625 C 421.102 461.53696 418.12236 468.48881 415.125 475 C 409.28085 487.70547 406.9868 495.27064 407.75 495.375 C 407.8187 495.384 408.35359 495.92596 408.875 496.3125 C 408.88 496.3155 408.87 496.34045 408.875 496.34375 C 409.12471 496.98042 410.12583 497.98256 411.6875 499.03125 C 414.61106 500.99573 414.65008 501.09083 414.59375 504.21875 C 414.52535 508.01781 414.97607 508.81795 416.84375 508.125 C 417.60191 507.84416 418.89795 507.78398 419.71875 508 C 421.07536 508.35521 421.19142 508.68357 420.9375 511.28125 L 420.65625 514.125 L 418.53125 513.46875 C 417.20717 513.05459 415.58315 513.01336 414.21875 513.375 C 413.01275 513.6944 410.93655 513.98879 409.59375 514.03125 C 406.11453 514.13936 405.61799 515.21756 405.5 522.9375 C 405.4497 526.44123 405.5894 530.95382 405.8125 532.96875 C 406.03106 534.98471 406.22934 537.84259 406.25 539.34375 C 406.2925 542.59502 408.7144 558.50621 409.3125 559.5 C 409.54362 559.88301 410.26939 563.05156 410.9375 566.5625 C 411.60566 570.07344 412.30032 573.12197 412.46875 573.34375 C 412.63722 573.56614 412.69665 574.37241 412.59375 575.125 C 412.49079 575.87764 413.14018 579.67885 414.0625 583.5625 C 414.98482 587.44615 416.00333 592.01064 416.3125 593.71875 C 416.76142 596.20061 418.03638 600.97786 418.96875 603.625 C 418.94975 603.6762 418.92585 603.6949 418.90625 603.75 C 418.57217 604.70135 417.54588 606.5602 416.625 607.875 L 414.96875 610.28125 L 416.65625 613.03125 C 417.59009 614.54991 418.88724 617.24144 419.5625 619 C 420.7757 622.13585 422.29232 625.61106 424.25 629.84375 C 425.32784 632.1655 425.38195 631.96428 421.46875 637.09375 L 420.15625 638.84375 L 421.9375 641.71875 C 422.91886 643.31154 424.62853 645.34751 425.78125 646.21875 C 427.81624 647.758 427.8804 647.87953 427.34375 650.84375 C 427.04021 652.51891 426.60222 655.02865 426.375 656.40625 C 426.03012 658.50306 425.74431 658.9275 424.59375 659 C 423.83804 659.0474 420.17459 659.3403 416.46875 659.65625 C 405.78662 660.56691 400.81256 660.84327 397.25 660.75 C 395.42458 660.702 391.0653 660.6952 387.5625 660.75 C 380.68557 660.85708 356.33204 657.96523 353.375 656.6875 C 352.5671 656.33938 351.75395 656.19053 351.3125 656.28125 C 351.08541 656.0267 350.86805 655.75951 350.78125 655.53125 C 350.33197 654.35133 349.27303 643.23697 349.5 642.125 C 349.5662 641.80097 349.9348 641.53566 350.34375 641.5625 C 350.75415 641.5896 352.11356 641.55445 353.375 641.46875 C 354.87089 641.36698 356.1073 640.34743 356.5625 639.40625 C 356.89923 639.25838 357.19781 638.97544 357.25 638.59375 C 357.2919 638.2861 356.98488 637.99525 356.5625 637.9375 C 355.72082 637.82321 351.91183 632.79968 351.21875 630.90625 C 350.76947 629.67279 351.21675 628.78491 354.5625 624.03125 C 362.03617 613.43028 363.43238 611.24242 363.59375 610.0625 C 363.71831 609.15336 362.74324 607.5425 360.625 605.125 C 357.61684 601.69231 357.04055 600.17483 358.34375 599.09375 C 359.16383 598.41071 362.41033 591.12501 363.15625 588.28125 C 363.49897 586.99631 364.26465 584.6694 364.84375 583.125 C 368.9147 572.26993 370.48005 565.13749 373.78125 543.09375 C 377.42517 518.77686 377.61246 515.13041 375.1875 514.15625 C 374.43992 513.85645 371.04601 513.31845 367.65625 512.96875 L 361.5 512.34375 L 361.625 509.96875 C 361.7654 507.45172 363.20459 505.98034 364.71875 506.8125 C 365.14499 507.04477 366.47934 507.06818 367.6875 506.84375 C 369.57363 506.49575 369.85613 506.21148 369.71875 504.96875 C 369.44155 502.47712 374.21199 497.50284 376.59375 497.78125 C 377.41238 497.87805 377.54914 497.47424 377.4375 495.1875 C 377.3641 493.70282 377.02563 491.45906 376.6875 490.1875 C 375.9675 487.48108 376.33452 486.8148 378.375 487.09375 C 381.5677 487.5303 386.42578 483.42255 387.8125 479.125 C 388.78522 476.10209 388.43808 474.83636 386.25 473.40625 C 383.50039 471.60822 379.90978 471.31535 376.5625 472.625 C 374.98138 473.24114 373.56876 473.70972 373.40625 473.6875 C 373.13337 473.6502 367.96436 457.90928 366.875 453.8125 C 366.61211 452.82305 366.56913 451.60507 366.8125 451.09375 C 367.5109 449.62554 374.3404 446.90219 378.25 446.53125 C 379.89315 446.37538 382.27321 446.15245 383.125 445.9375 C 384.48408 446.2498 387.87407 445.44791 388.09375 444.46875 C 388.64815 442.00801 389.17402 442.55672 390.0625 442.4375 z M 381.53125 454.5625 C 380.05854 454.606 378.39442 454.96142 376.9375 455.625 C 373.99774 456.96245 372.60463 458.20325 373 459.09375 C 373.43848 460.08143 374.42546 460.03353 374.5625 459.03125 C 374.74099 457.72469 379.92844 455.82171 382.375 456.15625 C 384.38668 456.43218 386.19792 457.90595 386.03125 459.125 C 385.99025 459.4286 386.38456 459.71419 386.875 459.78125 C 387.36349 459.84805 387.75863 459.71545 387.78125 459.46875 C 387.84105 458.76759 386.22861 456.37442 385.03125 455.40625 C 384.28947 454.80744 383.00396 454.51902 381.53125 454.5625 z M 379.40625 461.40625 C 378.25446 461.40625 378.09893 461.75834 377.84375 463.625 C 377.61407 465.30531 377.83255 466.21169 378.65625 466.9375 C 379.65561 467.81681 379.98325 467.81135 381.53125 466.90625 C 383.54293 465.7253 384.03318 463.84121 382.6875 462.46875 C 382.17774 461.94776 380.95731 461.49097 379.96875 461.4375 C 379.76025 461.4262 379.57079 461.40625 379.40625 461.40625 z M 380.21875 462.8125 C 380.90516 462.61143 382.01606 464.37832 381.6875 465.3125 C 381.28214 466.47018 379.5803 466.1967 379.34375 464.9375 C 379.26155 464.4995 379.41835 464.22584 379.6875 464.3125 C 380.85157 464.68788 381.29906 464.43242 380.5625 463.8125 C 380.12313 463.44263 379.91811 463.00839 380.09375 462.875 C 380.13535 462.8432 380.17295 462.8259 380.21875 462.8125 z M 379.75 474.15625 C 382.39329 474.18045 385.16151 474.89037 385.5625 475.96875 C 386.52874 478.57364 385.6327 480.56828 382.5 482.75 C 376.82906 486.70469 374.62515 486.19016 374.75 480.90625 C 374.7843 479.37112 374.60335 477.93279 374.34375 477.71875 C 373.38399 476.92699 374.1617 475.57608 376.0625 474.75 C 376.7533 474.44987 377.65195 474.25555 378.625 474.1875 C 378.98989 474.162 379.37239 474.15275 379.75 474.15625 z M 388.75 534.78125 C 387.49679 535.10102 385.25742 543.55593 383.625 554.59375 C 383.13178 557.92874 381.07802 561.3906 380.4375 563.15625 C 379.84824 562.64449 374.80922 566.43444 373.90625 568.09375 C 373.29425 569.21293 373.46807 571.05315 373.78125 574.34375 C 374.15133 578.27888 374.44237 578.99556 376.28125 580.75 C 380.58865 584.86669 385.0542 584.63114 390.375 580 C 393.22675 577.51763 393.33232 577.35221 393.6875 573.71875 C 393.88881 571.66161 393.7674 568.99448 393.4375 567.8125 C 392.3921 564.06579 392.25567 560.43292 393.09375 558.53125 C 393.52575 557.5521 394.09659 555.26952 394.34375 553.46875 C 394.77719 550.35359 397.93945 540.3181 399.15625 538.21875 L 399.125 538.21875 C 399.43536 537.6824 399.49063 537.43786 399.21875 537.40625 C 399.12825 537.39575 399.00222 537.4003 398.84375 537.4375 C 397.28999 537.80229 394.52909 545.57792 392.28125 555.90625 C 389.89085 566.90546 389.87251 566.75564 391.46875 567.625 C 392.98759 568.45177 393.05711 568.99086 392.09375 574.34375 C 391.64807 576.86009 391.1059 577.963 389.6875 579.25 C 387.24879 581.46839 385.55319 581.94467 381.84375 581.4375 C 378.13431 580.92991 376.56201 579.67698 375.65625 576.46875 C 373.98225 570.53352 374.89384 567.42507 379 565.03125 C 379.60979 564.6758 380.00826 564.24435 380.25 563.875 C 380.2749 564.50533 382.20019 563.68286 382.34375 563.65625 C 382.96295 563.54145 385.6915 553.23794 387.4375 542.21875 C 387.87598 539.4481 388.5413 536.91436 388.90625 536.5625 C 389.27121 536.21141 389.40325 535.57191 389.21875 535.15625 C 389.08474 534.85402 388.92903 534.73557 388.75 534.78125 z M 416.3125 609.75 C 416.63943 609.7947 416.8572 610.11054 416.8125 610.4375 C 416.7678 610.76445 416.48319 610.98221 416.15625 610.9375 C 415.82931 610.8928 415.5803 610.60819 415.625 610.28125 C 415.6697 609.95428 415.98556 609.70531 416.3125 609.75 z "
+           transform="matrix(0.00138889,0,0,-9.7125097e-4,0.12462536,0.91603164)"
+           id="path3027-8" />
+        <path
+           style="fill:#000000"
+           d="M 81.65625 476.25 C 79.260806 476.25 77.62152 477.3301 77.25 479.1875 C 76.98288 480.52392 76.564361 481.0625 75.6875 481.0625 C 74.741418 481.0625 74.46875 480.66395 74.46875 479.28125 C 74.46875 475.96182 70.225732 475.32964 69.03125 478.46875 C 68.633169 479.51276 68.65327 480.24416 69.125 480.8125 C 69.67058 481.47081 69.541652 481.55628 68.5625 481.65625 C 67.89351 481.72455 66.621642 482.14283 65.875 482.40625 C 65.584898 481.83399 64.997642 481.06575 64.125 480.1875 L 64.125 480.15625 C 62.597158 478.61906 61.031172 477.94065 59.78125 478.03125 C 58.174208 478.14726 57.05674 479.56366 57.0625 482.0625 L 58.4375 483.5625 C 58.642412 483.80115 58.878938 484.05974 59.09375 484.3125 C 59.4898 484.77852 59.86551 485.22412 60.09375 485.5625 C 60.31623 485.88682 60.86149 487.19653 61.28125 488.5 C 62.064612 490.93089 65.214338 496.71255 66.0625 497.25 C 66.32314 497.41474 66.81929 499.02959 67.15625 500.84375 C 67.493217 502.65791 68.06166 504.95835 68.4375 505.9375 C 68.81406 506.91974 69.40584 510.41373 69.75 513.71875 C 70.094297 517.0248 70.52406 521.04148 70.6875 522.625 C 70.7672 523.39746 70.897265 523.98756 71.03125 524.4375 C 70.757549 525.20795 70.40245 526.60761 70.09375 526.8125 C 68.707748 527.73398 68.262192 528.46385 67.46875 531.15625 C 66.98059 532.80773 66.678814 532.98061 63.65625 533.28125 C 61.848328 533.46092 61.09535 533.66559 61.34375 533.90625 C 61.231041 534.14905 61.45559 536.25582 61.375 537.375 C 61.078353 541.4934 61.206368 541.58666 67.03125 541.78125 L 72.25 541.9375 L 72.4375 549.03125 C 72.538048 552.93446 72.24707 559.90592 71.8125 564.5 C 71.377922 569.09716 71.135875 573.45582 71.28125 574.21875 C 71.42597 574.97758 70.851388 578.42584 70 581.875 C 69.149678 585.31901 68.46947 588.70921 68.46875 589.40625 C 68.46803 592.91307 62.991832 611.58027 61.34375 613.71875 C 60.73751 614.50331 59.516362 616.75324 58.625 618.71875 C 57.734358 620.68426 56.343412 623.15311 55.53125 624.21875 C 54.996859 624.91798 54.59719 625.63121 54.34375 626.25 L 52.46875 628.4375 C 52.44066 628.4702 54.128348 626.86943 52.40625 628.5625 C 52.02807 631.64615 54.40556 632.47246 54.875 633.5 C 55.720282 635.34916 54.331801 636.57853 47.59375 643.8125 C 45.484866 646.08071 45.461628 646.08947 46.71875 646.96875 C 48.713874 648.36386 52.40382 653.71738 52.6875 656 C 56.406306 661.16138 56.305798 660.86981 57.375 663.09375 C 57.93228 664.2747 58.782 665.25 59.25 665.25 C 59.71872 665.25 61.380858 665.87845 62.9375 666.65625 C 64.952784 667.66402 67.311516 668.20348 71.15625 668.5 C 74.125534 668.73063 78.568126 669.30841 81.03125 669.8125 C 86.444938 670.92035 99.792996 671.13347 106.875 670.21875 C 113.92526 669.31166 119.66472 668.18129 120.34375 667.5625 C 120.65767 667.27708 121.41349 667.03125 122.03125 667.03125 C 122.64901 667.03125 124.35018 666.35657 125.8125 665.5 C 127.84794 664.30463 128.46875 663.57279 128.46875 662.40625 C 128.46875 660.68579 129.63527 656.26282 130.34375 655.3125 C 130.60168 654.96654 130.95984 653.46924 131.15625 652 C 131.23605 651.40439 131.30986 650.95924 131.34375 650.625 C 131.73745 650.14691 132.70323 646.97318 132.84375 646.125 C 132.97534 646.01566 133.10085 645.9131 133.28125 645.75 C 134.40949 644.72761 134.40229 644.56085 133.46875 643.53125 C 133.01574 643.03128 132.4634 642.63123 132.09375 642.5 C 131.55458 641.81121 129.53943 639.78596 128.40625 638.875 C 125.01145 636.14656 124.71413 634.9293 126.78125 632.71875 L 128.4375 630.9375 L 127 629.03125 C 126.21232 627.98724 124.83246 625.39569 123.9375 623.25 C 123.04182 621.10431 121.80958 618.62825 121.1875 617.75 C 120.56558 616.87793 120.06682 615.78751 120.0625 615.34375 C 120.0467 613.91878 118.26204 609.35421 117.375 608.46875 C 116.74379 607.28076 116.11284 605.77131 115.5 604.15625 C 113.37332 594.98763 107.74421 574.96526 106.53125 573.4375 C 105.40085 572.09284 102.71871 563.06767 102.09375 558.53125 C 101.79203 556.34232 101.4698 552.09848 101.375 549.125 L 101.1875 543.75 L 103.28125 543.03125 C 104.42749 542.63856 106.37263 542.29984 107.59375 542.28125 C 108.81487 542.26255 111.18948 541.95525 112.875 541.59375 C 115.89684 540.94613 115.92754 540.89603 115.5625 539.03125 C 115.35874 537.99444 114.88323 536.52014 114.5 535.75 C 114.32019 535.38708 114.13865 535.17496 114 535.03125 C 113.9716 534.99595 113.94495 534.94465 113.90625 534.90625 C 113.85445 534.86725 113.82225 534.84905 113.78125 534.84375 C 113.3107 534.43576 112.4428 533.9245 112 533.90625 C 111.87884 533.90125 110.79777 533.94325 110.15625 533.96875 C 110.09765 533.83403 109.98706 533.70406 109.84375 533.53125 C 109.47511 533.09161 108.99264 531.96958 108.75 531.0625 C 108.39144 529.7302 107.60955 529.16901 104.71875 528.125 C 103.52499 527.6944 102.43947 527.38956 101.71875 527.21875 C 101.57675 526.05118 100.875 523.29174 100.875 523.03125 C 100.875 522.79039 100.8372 521.00973 100.6875 520.0625 C 101.34706 517.85813 102.4456 511.64548 103 506.53125 C 103.21456 504.55133 103.78589 501.73365 104.28125 500.25 C 105.52037 496.52903 109.11828 488.9991 109.875 488.53125 C 110.21719 488.32147 110.32714 487.93281 110.15625 487.65625 C 109.98489 487.38238 110.44297 485.61461 111.15625 483.75 C 112.35217 480.62516 112.36729 480.30612 111.46875 479.40625 C 110.93307 478.86586 109.3523 478.22754 107.9375 478 C 106.76822 477.81138 105.96929 477.69333 105.40625 477.6875 C 105.28452 477.6865 104.24159 478.07691 103.34375 478.4375 C 102.99071 478.3476 102.5573 478.5297 102.3125 478.875 C 102.3035 478.879 102.22235 478.90355 102.21875 478.90625 C 102.10288 478.98145 102.1115 479.05356 102.1875 479.09375 C 102.1175 479.26936 102.0897 479.46374 102.125 479.6875 C 102.32444 480.95185 101.9705 481.625 101.09375 481.625 C 100.34351 481.625 100.17647 481.24098 100.4375 479.9375 C 100.72478 478.5043 100.55038 478.13326 99.1875 477.59375 C 97.847578 477.06302 97.00731 476.84746 96.46875 476.9375 C 96.145412 476.9915 95.917429 477.1675 95.75 477.4375 C 95.66649 477.57274 95.69185 477.68185 95.78125 477.78125 C 95.531532 478.55347 95.156832 479.88674 95.03125 480 C 93.282368 481.58455 92.46875 481.26332 92.46875 479.03125 C 92.46875 477.92958 92.335359 476.92848 92.1875 476.78125 C 92.05466 476.64798 91.686856 476.59095 91.1875 476.59375 C 89.783498 476.60075 86.80961 478.98253 86.65625 479.625 C 86.65325 479.6393 86.656812 479.64385 86.65625 479.65625 C 86.493458 479.81679 86.327464 480.00897 86.125 480.28125 C 85.011158 481.77829 83.21067 480.5587 82.96875 478.125 C 82.83195 476.74945 82.47567 476.25 81.65625 476.25 z M 81.0625 477.34375 C 81.62091 477.21405 81.99381 477.60216 82.03125 478.34375 C 82.17885 481.23384 82.334628 481.49883 84.0625 481.84375 C 86.390984 482.30397 87.65625 481.79425 87.65625 480.375 C 87.65625 480.11691 87.62795 479.91649 87.59375 479.75 C 88.163853 479.19879 89.08557 477.81656 89.53125 477.71875 C 91.333412 477.32234 91.56925 477.75765 91.28125 480.59375 C 91.17181 481.67071 91.305898 481.70542 94.125 481.8125 C 95.440442 481.8557 95.80027 481.58018 95.96875 480.40625 C 96.02265 480.02858 96.26743 478.60371 96.34375 478.03125 C 96.41455 478.03925 96.483019 478.03125 96.5625 478.03125 C 98.077382 478.03125 99.21875 479.46473 99.21875 481.34375 C 99.21875 482.62972 99.472288 482.84375 101.125 482.84375 C 103.49668 482.84375 104.26481 480.99681 103.90625 479.125 C 103.90425 479.1143 103.90825 479.10415 103.90625 479.09375 C 104.10122 479.06555 104.28307 479.0375 104.34375 479 C 104.86215 478.67568 110.25782 479.59435 110.9375 480.125 C 111.18806 480.32062 109.40826 484.81833 107.0625 489.9375 C 105.9537 492.36324 105.0625 494.57436 105.0625 494.875 C 105.0625 495.76046 104.53048 495.53278 102.15625 493.625 C 99.661446 491.62346 95.627302 489.4375 94.4375 489.4375 C 92.921898 489.4375 93.710386 490.38619 95.84375 491.15625 C 97.036792 491.58764 98.577088 492.4571 99.28125 493.0625 C 99.986132 493.66689 101.3513 494.83566 102.3125 495.65625 L 104.0625 497.125 L 102.71875 501.375 C 101.41483 505.51296 101.34017 505.625 99.40625 505.625 C 98.314728 505.625 96.488122 505.26567 95.375 504.8125 C 94.261878 504.35871 92.387022 503.8086 91.1875 503.59375 C 89.072856 503.21177 89.00372 503.25808 88.625 505.28125 C 87.670998 510.36541 92.303466 515.90813 98.6875 517.3125 C 100.1239 517.62962 100.33207 517.94178 100.09375 519.1875 C 99.99435 519.70494 100.01485 520.19269 100.09375 520.53125 C 99.869348 521.50835 99.65625 522.8243 99.65625 523.03125 C 99.65625 523.28381 100.66133 525.90184 101.28125 527.125 C 101.18285 527.1094 101.0627 527.0634 101 527.0625 C 100.9329 527.06156 100.89556 527.07655 100.875 527.09375 C 100.389 527.49735 102.81142 529.03125 103.9375 529.03125 C 105.96502 529.03125 106.86197 529.79589 108.03125 532.4375 C 108.72461 534.00352 109.49916 534.95041 109.875 534.71875 C 110.22267 534.73425 111.15962 534.58253 112.0625 534.71875 C 112.66633 534.80985 113.21359 535.06696 113.59375 535.21875 C 113.54385 535.66086 113.65615 536.45732 114.0625 537.4375 C 115.03306 539.77778 114.47156 540.4375 111.46875 540.4375 C 107.82267 540.4375 102.2975 542.01393 100.84375 543.46875 C 99.693908 544.61572 99.6243 545.17544 99.9375 550.8125 C 100.31839 557.66449 100.98931 561.72116 102.71875 567.4375 C 103.92406 572.83095 112.9202 600.08052 115.46875 606.96875 C 115.74595 608.1334 115.90794 608.80698 116.21875 610.125 C 116.69971 612.22024 116.77764 611.79909 117.25 612.34375 C 117.72232 612.89047 118.29941 614.12181 118.53125 615.09375 C 118.76309 616.05849 119.43149 617.56404 120.03125 618.40625 C 120.63101 619.24845 121.76834 621.48877 122.5625 623.375 C 123.35738 625.26123 124.61511 627.47646 125.34375 628.3125 C 126.07239 629.15471 126.65625 630.08568 126.65625 630.375 C 126.65625 630.66226 125.5712 631.86713 124.25 633.0625 C 122.9288 634.25787 122.17975 635.24897 122.59375 635.25 C 123.00703 635.257 123.85243 635.98426 124.46875 636.90625 C 125.32881 638.18786 130.24181 642.13772 131.75 642.71875 C 131.75089 642.72157 131.78031 642.71589 131.78125 642.71875 C 131.85272 642.93594 132.04121 643.25637 132.375 643.625 C 132.99087 644.30803 133.14324 644.84375 132.75 644.84375 C 132.40104 644.84375 132.13962 645.23539 132.09375 645.71875 C 131.6 646.94358 130.6514 650.39675 130.5 651.15625 C 130.03587 652.12054 129.42427 654.01128 129.03125 655.65625 C 128.59853 657.47761 128.02 659.21722 127.75 659.53125 C 127.48022 659.84837 127.25 660.81785 127.25 661.71875 C 127.25 662.92132 126.74345 663.67226 125.25 664.59375 C 124.13832 665.27754 122.6997 665.84375 122.0625 665.84375 C 121.42458 665.84375 120.65695 666.08325 120.34375 666.375 C 120.03077 666.66947 116.67034 667.36289 112.875 667.90625 C 109.07988 668.44576 104.24425 669.17089 102.15625 669.53125 C 98.130004 670.23005 86.640746 669.80608 82.8125 668.8125 C 81.627378 668.50981 77.31318 667.88846 73.21875 667.4375 C 68.355142 666.89696 64.655186 666.13649 62.59375 665.25 C 59.234944 663.80547 59.228504 663.7571 51.6875 650.96875 C 50.272698 648.56463 48.66068 646.35454 48.125 646.03125 C 47.240838 645.49969 47.268919 645.40031 48.25 644.8125 C 48.844 644.45317 50.865756 642.21286 52.75 639.84375 C 55.053284 636.94234 56.516028 635.58284 57.21875 635.71875 C 58.524112 635.97099 58.573121 635.04365 57.3125 634 C 56.790507 633.56757 55.877362 631.80656 54.5 630.5 C 54.104086 629.92412 54.182283 628.93179 54.34375 628 C 54.39045 628.0135 54.44195 628.03315 54.5 628.03125 C 55.184002 628.01275 59.209608 621.47585 60.40625 618.4375 C 60.98801 616.96208 61.63855 615.60327 61.84375 615.4375 C 62.981352 614.52167 68.47883 598.40515 68.46875 596 C 68.46575 595.30193 68.83141 592.98944 69.3125 590.84375 C 72.046344 578.6538 72.67211 574.89871 72.96875 568.65625 C 73.148829 564.86114 73.506438 559.84291 73.75 557.53125 C 73.993583 555.2198 73.975099 551.99214 73.71875 550.34375 C 73.461818 548.69536 73.42088 546.0114 73.625 544.40625 C 74.08364 540.77382 73.670144 540.44986 68.375 540.4375 C 63.440112 540.4231 62.46875 540.0763 62.46875 538.3125 C 62.46875 537.68004 62.50441 535.39734 62.375 534.28125 C 62.969173 534.40648 63.796438 534.52871 64.875 534.65625 C 67.993324 535.02382 69.24768 534.4873 69 532.875 C 68.71776 531.03922 69.609461 528.4375 70.53125 528.4375 C 71.457172 528.4375 72.21874 525.83478 72.0625 524.625 C 72.311519 523.55936 72.100001 521.37092 71.46875 519.15625 C 71.186935 518.16269 70.792772 514.95428 70.59375 512.03125 C 70.12863 505.19471 68.041044 497.59122 65.75 494.53125 C 65.008398 493.53873 63.148522 490.24026 61.625 487.1875 C 60.654438 485.24362 59.371202 483.88345 58.5 483.09375 L 57.96875 482.03125 C 58.45997 481.08815 58.731232 480.08534 58.5625 479.8125 C 58.393869 479.54144 58.5084 479.14479 58.84375 478.9375 C 59.179126 478.73027 59.46875 478.8376 59.46875 479.15625 C 59.46875 479.47488 59.971173 479.60044 60.59375 479.4375 C 61.379992 479.2357 62.245178 479.78291 63.4375 481.28125 C 64.382862 482.4622 65.37732 483.4375 65.625 483.4375 C 65.820638 483.4375 65.959653 483.3824 66.03125 483.28125 C 66.875812 483.24245 68.33183 483.03744 68.84375 482.84375 C 70.227592 482.31761 71.128392 480.03345 70.09375 479.6875 C 69.021668 479.33435 70.152479 477.4375 71.4375 477.4375 C 72.907742 477.4375 73.92523 479.19542 73.46875 480.9375 C 73.16131 482.11124 73.357707 482.25 75.59375 482.25 C 78.140394 482.25 78.13754 482.255 78.3125 479 C 78.3463 478.37082 78.755058 477.79906 79.25 477.71875 C 79.74536 477.63805 80.56786 477.46097 81.0625 477.34375 z M 94.75 493.125 C 93.986798 493.1904 93.41255 493.66114 92.84375 494.53125 C 91.224468 497.00126 91.569866 497.84375 94.21875 497.84375 C 95.511872 497.84375 96.978 497.66906 97.5 497.46875 C 98.928482 496.92203 98.695207 494.53698 97.125 493.78125 C 96.322198 493.39525 95.65535 493.15896 95.09375 493.125 C 94.976692 493.118 94.859037 493.116 94.75 493.125 z M 95.5 493.9375 C 95.891954 493.9663 96.94328 494.26831 97.25 494.75 C 97.59776 495.29692 97.19405 496.033 97.34375 496.09375 C 97.986906 496.357 95.926192 496.56029 94.71875 496.59375 C 93.810828 496.61695 93.0625 496.36122 93.0625 496.03125 C 93.1406 495.89563 93.186849 495.33957 93.59375 494.875 C 94.064925 494.33704 94.92832 493.89545 95.5 493.9375 z M 90.625 505.125 C 90.779583 505.1027 90.960635 505.116 91.15625 505.125 C 91.938892 505.1614 93.054098 505.44556 94.5625 506 C 95.882262 506.48664 97.912658 506.81455 99.0625 506.71875 C 101.38522 506.52417 101.88849 507.42771 101.15625 510.34375 C 100.76241 511.91286 100.74597 511.92419 99.84375 510.75 C 99.209284 509.92178 98.84993 509.76328 98.65625 510.28125 C 98.16665 511.58781 96.49311 511.18326 96.84375 509.84375 C 97.016348 509.18117 96.89285 508.625 96.59375 508.625 C 96.29464 508.625 96.0625 509.02445 96.0625 509.5 C 96.0625 512.07709 92.61461 511.13953 92.28125 508.46875 L 92.0625 506.53125 L 91.96875 508.53125 C 91.90825 509.78736 91.605559 510.43054 91.15625 510.28125 C 90.321768 510.00739 89.34248 506.88292 89.75 505.78125 C 89.88365 505.42069 90.16125 505.19177 90.625 505.125 z M 92.75 511.71875 C 92.8038 511.69835 92.8444 511.70875 92.90625 511.71875 C 94.488812 511.9637 95.46875 512.41566 95.46875 512.90625 C 95.46875 513.21836 96.146753 513.30003 96.96875 513.09375 C 98.686672 512.66235 99.713202 514.24213 98.5 515.4375 C 97.944153 515.98751 97.600912 515.88804 96.96875 515.03125 C 96.51875 514.41809 95.89183 514.06567 95.59375 514.25 C 94.950788 514.6464 92.46875 513.03213 92.46875 512.21875 C 92.46875 511.98526 92.588641 511.78 92.75 511.71875 z M 100.25 513.4375 C 100.58 513.4375 100.875 513.95324 100.875 514.59375 C 100.875 515.23508 100.58 515.95136 100.25 516.15625 C 99.909699 516.36527 99.65625 515.83958 99.65625 514.96875 C 99.65625 514.12556 99.920002 513.4375 100.25 513.4375 z M 82.59375 565.78125 C 82.477744 565.81055 82.360041 565.92118 82.1875 566.09375 C 81.736845 566.54677 81.726554 567.34563 82.15625 568.75 C 82.494204 569.85888 82.92412 571.73493 83.125 572.9375 C 83.3266 574.14728 83.994278 575.79478 84.625 576.59375 C 85.255722 577.39273 85.95998 578.84776 86.1875 579.8125 C 86.41502 580.77825 87.175588 582.84574 87.84375 584.4375 C 88.984232 587.14432 88.995034 587.45032 88.09375 589.34375 C 86.049666 593.62689 88.456338 597.84805 93.78125 599.28125 C 99.81198 600.90493 103.7443 598.06915 104.6875 591.4375 C 105.16414 588.08203 103.65562 585.3202 100.5625 583.84375 C 98.875538 583.03757 98.208752 582.17799 97.21875 579.5 C 94.582106 572.36178 92.21008 566.84375 91.75 566.84375 C 90.981038 566.84375 91.152959 567.66727 92.75 571.28125 C 93.575842 573.14689 94.25 575.20231 94.25 575.84375 C 94.25 576.49137 94.768558 578.18217 95.40625 579.59375 C 96.043452 581.00533 96.69039 582.57895 96.84375 583.09375 C 96.99639 583.61164 98.198238 584.35978 99.5 584.75 C 101.19704 585.26068 102.18539 586.01393 102.96875 587.46875 C 104.02787 589.43426 104.01707 589.61092 102.90625 593.03125 C 101.93497 596.01915 101.41333 596.70351 99.53125 597.625 C 93.8598 600.39771 87.205356 594.90256 89.5 589.34375 C 89.908701 588.3502 90.229354 587.41577 90.1875 587.25 C 90.145 587.08422 89.272402 584.65147 88.25 581.84375 C 86.728638 577.66769 84.843352 571.96166 83.09375 566.28125 C 83.00015 565.97798 82.864644 565.81427 82.71875 565.78125 C 82.68225 565.77325 82.63245 565.77125 82.59375 565.78125 z M 111.375 590.46875 C 111.4417 590.62247 111.94431 592.60185 112.75 595.8125 C 111.83598 592.64763 111.27929 590.24833 111.375 590.46875 z M 55.875 660.5625 C -37.437726 925.63729 9.2186374 793.09989 55.875 660.5625 z "
+           transform="matrix(0.00138889,0,0,-9.7125097e-4,0.12462536,0.91603164)"
+           id="path3027-3" />
+        <path
+           style="fill:#1a1a1a;fill-opacity:1;stroke:#000000;stroke-width:1.01015258;stroke-miterlimit:4;stroke-dasharray:none"
+           d="m 375.768,484.68313 c -0.58247,-0.58247 -0.90846,-2.05238 -0.91003,-4.10334 -8.2e-4,-1.06899 -0.16174,-2.22274 -0.38432,-2.75546 -0.49283,-1.17949 -0.30225,-1.72523 0.85828,-2.45784 1.89922,-1.19892 4.84337,-1.38306 8.03123,-0.50228 1.68739,0.46621 2.35401,1.27623 2.34839,2.85356 -0.006,1.56899 -0.79729,2.89384 -2.59446,4.34168 -3.04669,2.45446 -6.34189,3.63087 -7.34909,2.62368 z"
+           id="path3092"
+           inkscape:connector-curvature="0"
+           transform="matrix(0.00138889,0,0,-9.7125097e-4,0.12462536,0.91603164)" />
+        <path
+           style="fill:#1a1a1a;fill-opacity:1;stroke:#000000;stroke-width:1.01015258;stroke-miterlimit:4;stroke-dasharray:none"
+           d="m 379.79546,465.38839 c -0.5595,-0.61823 -0.34154,-0.99442 0.48465,-0.83649 0.73188,0.13991 0.8864,-0.42613 0.25856,-0.94719 -0.20834,-0.17291 -0.37881,-0.43392 -0.37881,-0.58002 0,-0.47248 1.21484,0.86004 1.37847,1.51201 0.30384,1.2106 -0.89007,1.79403 -1.74287,0.85169 z"
+           id="path3094"
+           inkscape:connector-curvature="0"
+           transform="matrix(0.00138889,0,0,-9.7125097e-4,0.12462536,0.91603164)" />
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/web/poster/poster.svg b/web/poster/poster.svg
new file mode 100644 (file)
index 0000000..b67cd69
--- /dev/null
@@ -0,0 +1,1505 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   sodipodi:docname="poster.svg"
+   inkscape:version="0.48.4 r9939"
+   version="1.1"
+   id="svg2"
+   height="1052.3622047"
+   width="744.09448819">
+  <defs
+     id="defs4">
+    <filter
+       id="filter4549"
+       y="0"
+       height="1"
+       inkscape:menu-tooltip="Edges are partly feathered out"
+       inkscape:menu="Blurs"
+       inkscape:label="Apparition"
+       color-interpolation-filters="sRGB"
+       x="0"
+       width="1">
+      <feGaussianBlur
+         id="feGaussianBlur4551"
+         stdDeviation="5"
+         result="result6" />
+      <feComposite
+         id="feComposite4553"
+         in2="result6"
+         result="result8"
+         in="SourceGraphic"
+         operator="atop" />
+      <feComposite
+         id="feComposite4555"
+         in2="SourceAlpha"
+         result="result9"
+         operator="over"
+         in="result8" />
+      <feColorMatrix
+         id="feColorMatrix4557"
+         values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
+         result="result10" />
+      <feBlend
+         id="feBlend4559"
+         in2="result6"
+         in="result10"
+         mode="normal"
+         result="fbSourceGraphic" />
+      <feColorMatrix
+         result="fbSourceGraphicAlpha"
+         in="fbSourceGraphic"
+         values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
+         id="feColorMatrix4597" />
+      <feMorphology
+         id="feMorphology4599"
+         radius="4"
+         in="fbSourceGraphic"
+         result="result0" />
+      <feGaussianBlur
+         id="feGaussianBlur4601"
+         in="result0"
+         stdDeviation="8"
+         result="result91" />
+      <feComposite
+         id="feComposite4603"
+         in2="result91"
+         operator="in"
+         in="fbSourceGraphic" />
+    </filter>
+    <filter
+       id="filter4561"
+       y="0"
+       height="1"
+       inkscape:menu-tooltip="Edges are partly feathered out"
+       inkscape:menu="Blurs"
+       inkscape:label="Apparition"
+       color-interpolation-filters="sRGB"
+       x="0"
+       width="1">
+      <feGaussianBlur
+         id="feGaussianBlur4563"
+         stdDeviation="5"
+         result="result6" />
+      <feComposite
+         id="feComposite4565"
+         in2="result6"
+         result="result8"
+         in="SourceGraphic"
+         operator="atop" />
+      <feComposite
+         id="feComposite4567"
+         in2="SourceAlpha"
+         result="result9"
+         operator="over"
+         in="result8" />
+      <feColorMatrix
+         id="feColorMatrix4569"
+         values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
+         result="result10" />
+      <feBlend
+         id="feBlend4571"
+         in2="result6"
+         in="result10"
+         mode="normal"
+         result="fbSourceGraphic" />
+      <feColorMatrix
+         result="fbSourceGraphicAlpha"
+         in="fbSourceGraphic"
+         values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
+         id="feColorMatrix4613" />
+      <feMorphology
+         id="feMorphology4615"
+         radius="4"
+         in="fbSourceGraphic"
+         result="result0" />
+      <feGaussianBlur
+         id="feGaussianBlur4617"
+         in="result0"
+         stdDeviation="8"
+         result="result91" />
+      <feComposite
+         id="feComposite4619"
+         in2="result91"
+         operator="in"
+         in="fbSourceGraphic" />
+    </filter>
+    <filter
+       id="filter4573"
+       y="0"
+       height="1"
+       inkscape:menu-tooltip="Edges are partly feathered out"
+       inkscape:menu="Blurs"
+       inkscape:label="Apparition"
+       color-interpolation-filters="sRGB"
+       x="0"
+       width="1">
+      <feGaussianBlur
+         id="feGaussianBlur4575"
+         stdDeviation="5"
+         result="result6" />
+      <feComposite
+         id="feComposite4577"
+         in2="result6"
+         result="result8"
+         in="SourceGraphic"
+         operator="atop" />
+      <feComposite
+         id="feComposite4579"
+         in2="SourceAlpha"
+         result="result9"
+         operator="over"
+         in="result8" />
+      <feColorMatrix
+         id="feColorMatrix4581"
+         values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
+         result="result10" />
+      <feBlend
+         id="feBlend4583"
+         in2="result6"
+         in="result10"
+         mode="normal"
+         result="fbSourceGraphic" />
+      <feColorMatrix
+         result="fbSourceGraphicAlpha"
+         in="fbSourceGraphic"
+         values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
+         id="feColorMatrix4621" />
+      <feMorphology
+         id="feMorphology4623"
+         radius="4"
+         in="fbSourceGraphic"
+         result="result0" />
+      <feGaussianBlur
+         id="feGaussianBlur4625"
+         in="result0"
+         stdDeviation="8"
+         result="result91" />
+      <feComposite
+         id="feComposite4627"
+         in2="result91"
+         operator="in"
+         in="fbSourceGraphic" />
+    </filter>
+    <filter
+       id="filter4585"
+       y="0"
+       height="1"
+       inkscape:menu-tooltip="Edges are partly feathered out"
+       inkscape:menu="Blurs"
+       inkscape:label="Apparition"
+       color-interpolation-filters="sRGB"
+       x="0"
+       width="1">
+      <feGaussianBlur
+         id="feGaussianBlur4587"
+         stdDeviation="5"
+         result="result6" />
+      <feComposite
+         id="feComposite4589"
+         in2="result6"
+         result="result8"
+         in="SourceGraphic"
+         operator="atop" />
+      <feComposite
+         id="feComposite4591"
+         in2="SourceAlpha"
+         result="result9"
+         operator="over"
+         in="result8" />
+      <feColorMatrix
+         id="feColorMatrix4593"
+         values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
+         result="result10" />
+      <feBlend
+         id="feBlend4595"
+         in2="result6"
+         in="result10"
+         mode="normal"
+         result="fbSourceGraphic" />
+      <feColorMatrix
+         result="fbSourceGraphicAlpha"
+         in="fbSourceGraphic"
+         values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
+         id="feColorMatrix4605" />
+      <feMorphology
+         id="feMorphology4607"
+         radius="4"
+         in="fbSourceGraphic"
+         result="result0" />
+      <feGaussianBlur
+         id="feGaussianBlur4609"
+         in="result0"
+         stdDeviation="8"
+         result="result91" />
+      <feComposite
+         id="feComposite4611"
+         in2="result91"
+         operator="in"
+         in="fbSourceGraphic" />
+    </filter>
+    <filter
+       id="filter4549-3"
+       y="-0.25"
+       height="1.5"
+       inkscape:menu-tooltip="Gives a fluid and wavy expressionist drawing effect to images"
+       inkscape:menu="Image effects"
+       inkscape:label="Liquid drawing"
+       color-interpolation-filters="sRGB"
+       x="-0.25"
+       width="1.5">
+      <feGaussianBlur
+         id="feGaussianBlur4551-0"
+         stdDeviation="5"
+         result="result6" />
+      <feComposite
+         id="feComposite4553-3"
+         in2="result6"
+         result="result8"
+         in="SourceGraphic"
+         operator="atop" />
+      <feComposite
+         id="feComposite4555-1"
+         in2="SourceAlpha"
+         result="result9"
+         operator="over"
+         in="result8" />
+      <feColorMatrix
+         id="feColorMatrix4557-0"
+         values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
+         result="result10" />
+      <feBlend
+         id="feBlend4559-5"
+         in2="result6"
+         in="result10"
+         mode="normal"
+         result="fbSourceGraphic" />
+      <feColorMatrix
+         result="fbSourceGraphicAlpha"
+         in="fbSourceGraphic"
+         values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
+         id="feColorMatrix4597-0" />
+      <feMorphology
+         id="feMorphology4599-3"
+         radius="4"
+         in="fbSourceGraphic"
+         result="result0" />
+      <feGaussianBlur
+         id="feGaussianBlur4601-0"
+         in="result0"
+         stdDeviation="8"
+         result="result91" />
+      <feComposite
+         id="feComposite4603-7"
+         in2="result91"
+         operator="in"
+         in="fbSourceGraphic"
+         result="fbSourceGraphic" />
+      <feColorMatrix
+         result="fbSourceGraphicAlpha"
+         in="fbSourceGraphic"
+         values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
+         id="feColorMatrix5344" />
+      <feGaussianBlur
+         id="feGaussianBlur5346"
+         result="result11"
+         stdDeviation="2"
+         in="fbSourceGraphic" />
+      <feGaussianBlur
+         id="feGaussianBlur5348"
+         in="fbSourceGraphic"
+         stdDeviation="0.5"
+         result="result8" />
+      <feTurbulence
+         id="feTurbulence5350"
+         result="result9"
+         baseFrequency="0.08"
+         numOctaves="1"
+         type="fractalNoise" />
+      <feDisplacementMap
+         id="feDisplacementMap5352"
+         in2="result11"
+         result="result10"
+         xChannelSelector="G"
+         scale="100"
+         yChannelSelector="R" />
+      <feConvolveMatrix
+         id="feConvolveMatrix5354"
+         bias="0"
+         result="result0"
+         preserveAlpha="true"
+         targetY="1"
+         targetX="1"
+         divisor="1"
+         in="result10"
+         kernelMatrix="1 1 1 1 -8 1 1 1 1 "
+         order="3 3" />
+      <feColorMatrix
+         id="feColorMatrix5356"
+         in="result0"
+         values="0 -6 0 0 1 0 -6 0 0 1 0 -6 0 0 1 0 0 0 1 0 "
+         result="result3" />
+      <feComposite
+         id="feComposite5358"
+         in2="fbSourceGraphic"
+         operator="in"
+         in="result3"
+         result="fbSourceGraphic" />
+      <feBlend
+         id="feBlend5360"
+         in2="result8"
+         mode="multiply"
+         result="result12" />
+      <feGaussianBlur
+         id="feGaussianBlur5362"
+         stdDeviation="0.01"
+         in="result12"
+         result="result7" />
+      <feBlend
+         id="feBlend5364"
+         in2="result12"
+         mode="screen"
+         result="result92" />
+      <feComposite
+         id="feComposite5366"
+         in2="fbSourceGraphic"
+         operator="in" />
+    </filter>
+    <filter
+       id="filter4561-6"
+       y="-0.25"
+       height="1.5"
+       inkscape:menu-tooltip="Gives a fluid and wavy expressionist drawing effect to images"
+       inkscape:menu="Image effects"
+       inkscape:label="Liquid drawing"
+       color-interpolation-filters="sRGB"
+       x="-0.25"
+       width="1.5">
+      <feGaussianBlur
+         id="feGaussianBlur4563-0"
+         stdDeviation="5"
+         result="result6" />
+      <feComposite
+         id="feComposite4565-7"
+         in2="result6"
+         result="result8"
+         in="SourceGraphic"
+         operator="atop" />
+      <feComposite
+         id="feComposite4567-4"
+         in2="SourceAlpha"
+         result="result9"
+         operator="over"
+         in="result8" />
+      <feColorMatrix
+         id="feColorMatrix4569-4"
+         values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
+         result="result10" />
+      <feBlend
+         id="feBlend4571-9"
+         in2="result6"
+         in="result10"
+         mode="normal"
+         result="fbSourceGraphic" />
+      <feColorMatrix
+         result="fbSourceGraphicAlpha"
+         in="fbSourceGraphic"
+         values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
+         id="feColorMatrix4613-4" />
+      <feMorphology
+         id="feMorphology4615-8"
+         radius="4"
+         in="fbSourceGraphic"
+         result="result0" />
+      <feGaussianBlur
+         id="feGaussianBlur4617-9"
+         in="result0"
+         stdDeviation="8"
+         result="result91" />
+      <feComposite
+         id="feComposite4619-5"
+         in2="result91"
+         operator="in"
+         in="fbSourceGraphic"
+         result="fbSourceGraphic" />
+      <feColorMatrix
+         result="fbSourceGraphicAlpha"
+         in="fbSourceGraphic"
+         values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
+         id="feColorMatrix5368" />
+      <feGaussianBlur
+         id="feGaussianBlur5370"
+         result="result11"
+         stdDeviation="2"
+         in="fbSourceGraphic" />
+      <feGaussianBlur
+         id="feGaussianBlur5372"
+         in="fbSourceGraphic"
+         stdDeviation="0.5"
+         result="result8" />
+      <feTurbulence
+         id="feTurbulence5374"
+         result="result9"
+         baseFrequency="0.08"
+         numOctaves="1"
+         type="fractalNoise" />
+      <feDisplacementMap
+         id="feDisplacementMap5376"
+         in2="result11"
+         result="result10"
+         xChannelSelector="G"
+         scale="100"
+         yChannelSelector="R" />
+      <feConvolveMatrix
+         id="feConvolveMatrix5378"
+         bias="0"
+         result="result0"
+         preserveAlpha="true"
+         targetY="1"
+         targetX="1"
+         divisor="1"
+         in="result10"
+         kernelMatrix="1 1 1 1 -8 1 1 1 1 "
+         order="3 3" />
+      <feColorMatrix
+         id="feColorMatrix5380"
+         in="result0"
+         values="0 -6 0 0 1 0 -6 0 0 1 0 -6 0 0 1 0 0 0 1 0 "
+         result="result3" />
+      <feComposite
+         id="feComposite5382"
+         in2="fbSourceGraphic"
+         operator="in"
+         in="result3"
+         result="fbSourceGraphic" />
+      <feBlend
+         id="feBlend5384"
+         in2="result8"
+         mode="multiply"
+         result="result12" />
+      <feGaussianBlur
+         id="feGaussianBlur5386"
+         stdDeviation="0.01"
+         in="result12"
+         result="result7" />
+      <feBlend
+         id="feBlend5388"
+         in2="result12"
+         mode="screen"
+         result="result92" />
+      <feComposite
+         id="feComposite5390"
+         in2="fbSourceGraphic"
+         operator="in" />
+    </filter>
+    <filter
+       id="filter4573-5"
+       y="-0.25"
+       height="1.5"
+       inkscape:menu-tooltip="Gives a fluid and wavy expressionist drawing effect to images"
+       inkscape:menu="Image effects"
+       inkscape:label="Liquid drawing"
+       color-interpolation-filters="sRGB"
+       x="-0.25"
+       width="1.5">
+      <feGaussianBlur
+         id="feGaussianBlur4575-8"
+         stdDeviation="5"
+         result="result6" />
+      <feComposite
+         id="feComposite4577-6"
+         in2="result6"
+         result="result8"
+         in="SourceGraphic"
+         operator="atop" />
+      <feComposite
+         id="feComposite4579-6"
+         in2="SourceAlpha"
+         result="result9"
+         operator="over"
+         in="result8" />
+      <feColorMatrix
+         id="feColorMatrix4581-0"
+         values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
+         result="result10" />
+      <feBlend
+         id="feBlend4583-2"
+         in2="result6"
+         in="result10"
+         mode="normal"
+         result="fbSourceGraphic" />
+      <feColorMatrix
+         result="fbSourceGraphicAlpha"
+         in="fbSourceGraphic"
+         values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
+         id="feColorMatrix4621-7" />
+      <feMorphology
+         id="feMorphology4623-3"
+         radius="4"
+         in="fbSourceGraphic"
+         result="result0" />
+      <feGaussianBlur
+         id="feGaussianBlur4625-0"
+         in="result0"
+         stdDeviation="8"
+         result="result91" />
+      <feComposite
+         id="feComposite4627-1"
+         in2="result91"
+         operator="in"
+         in="fbSourceGraphic"
+         result="fbSourceGraphic" />
+      <feColorMatrix
+         result="fbSourceGraphicAlpha"
+         in="fbSourceGraphic"
+         values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
+         id="feColorMatrix5392" />
+      <feGaussianBlur
+         id="feGaussianBlur5394"
+         result="result11"
+         stdDeviation="2"
+         in="fbSourceGraphic" />
+      <feGaussianBlur
+         id="feGaussianBlur5396"
+         in="fbSourceGraphic"
+         stdDeviation="0.5"
+         result="result8" />
+      <feTurbulence
+         id="feTurbulence5398"
+         result="result9"
+         baseFrequency="0.08"
+         numOctaves="1"
+         type="fractalNoise" />
+      <feDisplacementMap
+         id="feDisplacementMap5400"
+         in2="result11"
+         result="result10"
+         xChannelSelector="G"
+         scale="100"
+         yChannelSelector="R" />
+      <feConvolveMatrix
+         id="feConvolveMatrix5402"
+         bias="0"
+         result="result0"
+         preserveAlpha="true"
+         targetY="1"
+         targetX="1"
+         divisor="1"
+         in="result10"
+         kernelMatrix="1 1 1 1 -8 1 1 1 1 "
+         order="3 3" />
+      <feColorMatrix
+         id="feColorMatrix5404"
+         in="result0"
+         values="0 -6 0 0 1 0 -6 0 0 1 0 -6 0 0 1 0 0 0 1 0 "
+         result="result3" />
+      <feComposite
+         id="feComposite5406"
+         in2="fbSourceGraphic"
+         operator="in"
+         in="result3"
+         result="fbSourceGraphic" />
+      <feBlend
+         id="feBlend5408"
+         in2="result8"
+         mode="multiply"
+         result="result12" />
+      <feGaussianBlur
+         id="feGaussianBlur5410"
+         stdDeviation="0.01"
+         in="result12"
+         result="result7" />
+      <feBlend
+         id="feBlend5412"
+         in2="result12"
+         mode="screen"
+         result="result92" />
+      <feComposite
+         id="feComposite5414"
+         in2="fbSourceGraphic"
+         operator="in" />
+    </filter>
+    <filter
+       id="filter4585-6"
+       y="-0.25"
+       height="1.5"
+       inkscape:menu-tooltip="Gives a fluid and wavy expressionist drawing effect to images"
+       inkscape:menu="Image effects"
+       inkscape:label="Liquid drawing"
+       color-interpolation-filters="sRGB"
+       x="-0.25"
+       width="1.5">
+      <feGaussianBlur
+         id="feGaussianBlur4587-5"
+         stdDeviation="5"
+         result="result6" />
+      <feComposite
+         id="feComposite4589-1"
+         in2="result6"
+         result="result8"
+         in="SourceGraphic"
+         operator="atop" />
+      <feComposite
+         id="feComposite4591-1"
+         in2="SourceAlpha"
+         result="result9"
+         operator="over"
+         in="result8" />
+      <feColorMatrix
+         id="feColorMatrix4593-6"
+         values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 "
+         result="result10" />
+      <feBlend
+         id="feBlend4595-4"
+         in2="result6"
+         in="result10"
+         mode="normal"
+         result="fbSourceGraphic" />
+      <feColorMatrix
+         result="fbSourceGraphicAlpha"
+         in="fbSourceGraphic"
+         values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
+         id="feColorMatrix4605-7" />
+      <feMorphology
+         id="feMorphology4607-8"
+         radius="4"
+         in="fbSourceGraphic"
+         result="result0" />
+      <feGaussianBlur
+         id="feGaussianBlur4609-9"
+         in="result0"
+         stdDeviation="8"
+         result="result91" />
+      <feComposite
+         id="feComposite4611-9"
+         in2="result91"
+         operator="in"
+         in="fbSourceGraphic"
+         result="fbSourceGraphic" />
+      <feColorMatrix
+         result="fbSourceGraphicAlpha"
+         in="fbSourceGraphic"
+         values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
+         id="feColorMatrix5416" />
+      <feGaussianBlur
+         id="feGaussianBlur5418"
+         result="result11"
+         stdDeviation="2"
+         in="fbSourceGraphic" />
+      <feGaussianBlur
+         id="feGaussianBlur5420"
+         in="fbSourceGraphic"
+         stdDeviation="0.5"
+         result="result8" />
+      <feTurbulence
+         id="feTurbulence5422"
+         result="result9"
+         baseFrequency="0.08"
+         numOctaves="1"
+         type="fractalNoise" />
+      <feDisplacementMap
+         id="feDisplacementMap5424"
+         in2="result11"
+         result="result10"
+         xChannelSelector="G"
+         scale="100"
+         yChannelSelector="R" />
+      <feConvolveMatrix
+         id="feConvolveMatrix5426"
+         bias="0"
+         result="result0"
+         preserveAlpha="true"
+         targetY="1"
+         targetX="1"
+         divisor="1"
+         in="result10"
+         kernelMatrix="1 1 1 1 -8 1 1 1 1 "
+         order="3 3" />
+      <feColorMatrix
+         id="feColorMatrix5428"
+         in="result0"
+         values="0 -6 0 0 1 0 -6 0 0 1 0 -6 0 0 1 0 0 0 1 0 "
+         result="result3" />
+      <feComposite
+         id="feComposite5430"
+         in2="fbSourceGraphic"
+         operator="in"
+         in="result3"
+         result="fbSourceGraphic" />
+      <feBlend
+         id="feBlend5432"
+         in2="result8"
+         mode="multiply"
+         result="result12" />
+      <feGaussianBlur
+         id="feGaussianBlur5434"
+         stdDeviation="0.01"
+         in="result12"
+         result="result7" />
+      <feBlend
+         id="feBlend5436"
+         in2="result12"
+         mode="screen"
+         result="result92" />
+      <feComposite
+         id="feComposite5438"
+         in2="fbSourceGraphic"
+         operator="in" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.49497475"
+     inkscape:cx="441.6874"
+     inkscape:cy="528.34987"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1366"
+     inkscape:window-height="721"
+     inkscape:window-x="-2"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <g
+       id="g3257"
+       transform="translate(61.099361,200.3118)">
+      <g
+         transform="translate(64.649763,-153.54319)"
+         id="g3248">
+        <g
+           id="g3202"
+           transform="translate(-10,14.999996)">
+          <g
+             transform="translate(-74.28572,-52.857144)"
+             id="g3150">
+            <path
+               style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+               d="m 220.3557,785.92864 -139.543496,80.56547 393.959496,0"
+               id="path3130"
+               inkscape:connector-curvature="0" />
+            <path
+               style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+               d="m 473.61191,866.03514 139.5435,-80.56547 -393.9595,0"
+               id="path3130-8"
+               inkscape:connector-curvature="0" />
+          </g>
+          <path
+             inkscape:connector-curvature="0"
+             id="path3154"
+             d="m 206.16032,814.64712 141.81634,-81.8777"
+             style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+        </g>
+        <path
+           style="fill:#999999;fill-opacity:1;stroke:none"
+           d="m 3.901435,826.15591 c 1.549826,-1.06373 31.971124,-18.74675 67.602884,-39.29559 l 64.785021,-37.36152 97.35783,0.36701 97.35784,0.36701 -67.44137,38.92857 -67.44138,38.92858 -97.51935,0 c -82.439902,0 -97.083614,-0.29907 -94.701475,-1.93406 z"
+           id="path3208"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:#ffffff;fill-opacity:1;stroke:none"
+           d="m 206.7193,825.32967 c 2.35714,-1.49169 32.79327,-19.1641 67.63585,-39.27202 l 63.35013,-36.55986 92.05606,0.36752 92.05606,0.36751 -24.6919,14.20089 c -13.58056,7.81048 -43.93141,25.32834 -67.44637,38.92857 l -42.75446,24.72769 -92.24554,-0.0241 c -91.15912,-0.0238 -92.19507,-0.056 -87.95983,-2.73623 z"
+           id="path3210"
+           inkscape:connector-curvature="0" />
+      </g>
+      <path
+         transform="matrix(0.78309797,0,0,0.78309797,139.5213,-67.459932)"
+         inkscape:connector-curvature="0"
+         id="path4490-9"
+         d="m 99.277667,905.74418 c -13.43643,-2.09817 -14.63585,-2.83972 -20.73411,-12.81917 -2.91656,-4.77278 -5.30283,-9.10387 -5.30283,-9.62466 0,-0.5208 2.04556,-2.83243 4.54569,-5.13697 2.50012,-2.30453 4.54568,-4.44993 4.54568,-4.76755 0,-0.31761 -0.9161,-1.74211 -2.03578,-3.16554 -1.78003,-2.26295 -1.85399,-2.79058 -0.58874,-4.19995 2.37267,-2.64293 9.3291,-17.35827 11.02894,-23.33015 6.14297,-21.58146 10.095633,-59.88779 6.54584,-63.43758 -0.6667,-0.6667 -3.16683,-1.21218 -5.55584,-1.21218 -3.90592,0 -4.34366,-0.24318 -4.34366,-2.41314 0,-1.32723 0.56822,-2.39204 1.2627,-2.36625 3.50263,0.13008 4.79822,-0.43657 4.79822,-2.09861 0,-1.00498 0.6674,-2.70961 1.4831,-3.78807 1.88985,-2.4986 1.89274,-5.64536 0.0167,-18.12328 -1.54971,-10.30725 -3.92248,-16.49104 -9.53346,-24.84559 -3.42892,-5.10553 -2.57454,-7.74124 1.32257,-4.08009 1.79175,1.68325 3.08622,2.0908 5.06415,1.59437 2.54868,-0.63968 3.09046,-1.47956 2.73253,-4.23595 -0.30659,-2.36102 1.72277,-1.2751 2.35971,1.26269 0.84981,3.3859 4.358793,3.3859 5.646113,0 1.15688,-3.04282 2.60208,-3.26247 3.32315,-0.50508 0.73458,2.80903 5.07931,2.65465 7.10726,-0.25254 l 1.58545,-2.27284 0.053,2.27284 c 0.0402,1.72423 0.65044,2.27285 2.52817,2.27285 1.36135,0 2.94508,-0.7955 3.51939,-1.76777 0.95298,-1.61333 1.10003,-1.56921 1.68324,0.50508 0.74042,2.63344 4.89223,3.17395 5.81946,0.75761 0.61174,-1.59417 5.69562,-2.15511 5.69562,-0.62844 0,0.48773 -0.73588,2.64693 -1.63529,4.79822 -0.8994,2.15129 -2.03477,4.96104 -2.52303,6.24387 l -0.88775,2.33244 -4.99731,-2.80913 c -2.74853,-1.54502 -5.35019,-2.45626 -5.78147,-2.02497 -0.43129,0.43129 -0.1677,1.16515 0.58575,1.63081 1.07173,0.66236 0.90046,1.09789 -0.78687,2.00092 -1.18623,0.63485 -2.15678,2.04741 -2.15678,3.13903 0,2.90099 5.82119,2.80881 6.90066,-0.10927 0.75342,-2.03668 0.83386,-2.0436 2.93689,-0.25254 2.07415,1.76647 2.09728,1.99915 0.56765,5.71068 -1.30675,3.17072 -1.97954,3.76326 -3.72705,3.28245 -1.17285,-0.32269 -3.83709,-0.87186 -5.92053,-1.22036 -3.77527,-0.6315 -3.78807,-0.62172 -3.78807,2.89477 0,4.31971 3.147,8.58135 7.7603,10.5089 2.75912,1.15284 3.346,1.91945 3.19293,4.17074 -0.29577,4.35005 1.09164,7.24617 3.79657,7.92506 1.37133,0.34418 3.15429,1.90396 3.96214,3.46617 0.81626,1.57847 2.47895,2.98443 3.74249,3.16463 1.25051,0.17834 2.41309,1.05645 2.5835,1.95136 0.23769,1.24819 -1.06867,1.8983 -5.60983,2.79172 -3.25581,0.64054 -6.45893,1.70389 -7.11804,2.363 -1.64303,1.64303 -1.49165,13.07132 0.27145,20.4923 3.28415,13.8232 16.02038,50.91027 20.14773,58.66888 l 4.35264,8.1821 -1.89003,2.5946 -1.89003,2.5946 5.06574,4.43138 5.06574,4.43139 -3.01125,9.63346 c -3.48707,11.15567 -3.52556,11.1865 -16.87441,13.51435 -10.4107,1.81548 -24.90881,1.77792 -36.906653,-0.0956 l 0,-4e-5 z m 27.041983,-69.56407 c 1.89343,-1.89342 2.47947,-3.54741 2.47947,-6.99785 0,-3.80619 -0.47165,-4.88818 -2.99229,-6.86444 -1.83568,-1.43924 -4.10093,-5.05341 -5.86049,-9.35032 -1.57751,-3.85234 -3.46978,-7.20478 -4.20505,-7.44987 -0.82244,-0.27415 -1.11678,0.0888 -0.76494,0.94334 0.31455,0.76393 1.56741,4.5078 2.78413,8.31972 1.81704,5.69268 2.82013,7.28944 5.61528,8.93862 2.63979,1.55751 3.40305,2.67547 3.40305,4.98444 0,4.045 -4.25071,8.31498 -7.34042,7.3737 -4.34112,-1.3225 -6.02065,-3.66088 -5.40313,-7.52264 0.41787,-2.61325 -0.45141,-6.46962 -3.2531,-14.43155 -3.51698,-9.99468 -5.21655,-12.44991 -5.21655,-7.53594 0,1.06492 1.36239,5.33862 3.02754,9.49713 2.13553,5.33322 2.96508,8.99633 2.81556,12.43275 -0.22383,5.14436 1.09714,7.70929 4.72843,9.1812 3.89802,1.58002 7.64254,1.02169 10.18251,-1.51829 l 0,0 z"
+         style="fill:#483737;fill-opacity:1;stroke:#241c1c;filter:url(#filter4561-6)" />
+      <path
+         transform="matrix(1.6852156,0,0,1.6852156,-56.547594,-874.77105)"
+         inkscape:connector-curvature="0"
+         id="path4492-4"
+         d="m 164.77504,904.50679 c -2.95637,-0.30904 -4.12705,-1.04093 -5.30331,-3.31556 -2.21555,-4.28441 -1.94128,-5.52539 2.74475,-12.41863 6.58892,-9.69246 9.17854,-17.65576 9.26198,-28.48139 0.0681,-8.83503 -0.0512,-9.316 -4.2304,-17.05828 -3.8606,-7.15204 -4.19185,-8.29601 -3.23856,-11.1845 0.58404,-1.76967 2.67063,-4.77581 4.63687,-6.6803 3.23869,-3.13699 4.11958,-3.45972 9.36454,-3.43092 9.5091,0.0522 20.37167,7.42773 20.34201,13.81189 -0.0265,5.70983 -0.62823,5.99632 -9.95673,4.7409 -4.58302,-0.61678 -8.57843,-0.87575 -8.87869,-0.57549 -1.07992,1.07992 3.86321,8.30117 7.15732,10.4559 2.62822,1.71915 3.80732,3.59894 5.38577,8.58629 5.07523,16.03591 8.20757,23.11092 12.28057,27.7381 4.36373,4.95746 5.53297,7.68177 4.97009,11.5803 -0.31263,2.1653 -1.29463,2.4888 -13.97332,4.60324 -12.72266,2.12177 -21.41378,2.58485 -30.56289,1.62845 z m 26.52228,-24.5176 c 3.07537,-3.07538 2.46502,-5.89093 -2.27284,-10.48467 -2.36124,-2.2894 -4.80805,-5.07168 -5.43737,-6.18285 -0.62932,-1.11117 -1.45833,-1.72162 -1.84225,-1.35656 -1.1957,1.13696 2.2225,6.50875 6.14302,9.6539 2.60951,2.09342 3.55042,3.51531 3.10106,4.68631 -0.91144,2.37517 -5.13107,4.05887 -8.22568,3.28217 -2.27242,-0.57035 -2.47547,-0.93215 -1.52247,-2.71284 1.45943,-2.72697 0.45826,-6.84476 -2.56324,-10.54255 -2.97769,-3.64416 -3.26524,-1.84082 -0.55392,3.47382 1.68828,3.30929 1.80149,4.34763 0.77154,7.07627 -1.49906,3.97148 -0.16763,5.08929 6.0887,5.11183 2.96138,0.0107 4.91986,-0.61124 6.31345,-2.00483 z m -2.20259,-45.21465 c 0.24255,-1.70007 -0.18208,-2.26252 -1.70815,-2.26252 -2.41781,0 -3.56541,1.52796 -2.74782,3.65856 0.86409,2.25177 4.07925,1.24447 4.45597,-1.39604 l 0,0 z m 2.90387,-3.80967 c -2.41299,-2.12285 -7.77235,-3.51057 -7.77235,-2.01252 0,0.79341 7.45829,4.47954 9.09137,4.49325 0.98418,0.008 0.52189,-0.86117 -1.31902,-2.48073 l 0,0 z"
+         style="fill:#483737;fill-opacity:1;stroke:#241c1c;filter:url(#filter4549-3)" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path3027"
+         d="m 266.32874,561.55009 c -6.13008,0.35281 -12.14842,4.15546 -15.90625,11.18753 l -0.93743,4.21827 -0.375,-0.0625 c 0.0126,0.15488 0.12801,0.38864 0.25,0.6875 l -0.125,0.53125 0.40626,0.125 c 2.06207,4.29859 9.73634,16.29404 9.84376,21.40622 0.51805,15.60956 -7.05312,27.86951 -14.65625,37.53128 l 0.8748,3.56241 c -0.10437,9.09755 7.65295,7.28958 11.87504,7.78172 9.86917,2.90656 19.6596,-1.42084 29.5313,-2.40618 4.21272,-2.96319 10.66544,1.9058 14.12504,-3.84349 l -0.625,-4.59407 -3.1248,-7.46872 c -8.49039,-7.14543 -12.46753,-23.20379 -15.99999,-35.87497 0.5765,-0.15446 1.15704,-0.59592 1.71864,-1.40644 1.70712,-4.90707 6.3072,-5.82136 7.03152,-11.8125 0.1489,-13.81291 -11.00347,-15.69728 -17.81251,-18.75005 -1.9872,-0.65645 -4.05073,-0.93009 -6.09408,-0.8125 z m 0.75024,1.06254 c 0.70945,0.0112 1.38528,0.0804 2.03111,0.1875 2.13625,0.35521 4.19185,1.78534 6.6564,1.84401 1.49833,1.1511 7.47743,3.92588 10.03127,6.53076 2.65607,2.85199 4.0068,9.15005 0.93743,12.87494 -4.92336,-1.12432 -13.37687,-1.11402 -17.75001,-2.1879 l 1.78128,3.9063 3.06216,4.59408 c 2.00304,0.0326 4.1292,3.06615 6.21864,3.8435 0.94608,7.096 10.22126,27.6878 8.84376,27.09371 0.49892,1.21699 1.22832,2.83964 1.93752,3.687 2.94912,3.52947 6.60455,5.1758 8.21873,10.78125 l -0.0625,7.21852 c -7.34055,0.94827 -14.60621,2.4731 -21.93754,3.46873 -8.32766,2.45251 -16.55157,1.10785 -24.93756,0.28126 -4.20409,-0.14332 -6.97753,-7.83629 -3.93769,-12.34377 8.27431,-9.56395 15.00991,-25.31354 11.7188,-40.96872 -2.14056,-4.75777 -4.95144,-11.41682 -8.24997,-15.25002 l 0.9684,-4.40669 c 3.2688,-8.69085 9.50248,-11.23221 14.46876,-11.15622 z m 10.21874,7.8435 -3.09384,0.1875 0.40625,0.59375 5.59369,3.03114 3.00024,0.75 -5.8752,-4.56216 -0.0312,0 z m 0.6875,4.34387 -2.96856,0.12502 -0.9684,1.46924 c 0.46008,5.74207 6.0516,1.61749 3.93768,-1.59383 z m -1.4688,1.50014 c 0.79632,0.04 0.34077,3.09394 -0.7812,0.5625 0.32049,-0.41699 0.59754,-0.57174 0.7812,-0.5625 z m -4.84344,7.18764 c 0.5436,0.33729 1.06488,0.65506 1.40616,0.93749 0.18482,0.15296 0.20274,-0.59183 0.46875,0.43751 0.78768,3.04967 -2.5128,2.23835 -2.31263,-0.68751 l 0.4375,-0.68749 z m 3.96864,0.84374 2.59344,0.0937 8.24997,-0.0937 c -1.28304,1.39408 -3.2328,2.3825 -6.0624,2.59356 -1.48751,1.29215 -3.05784,-2.0942 -3.8124,-0.15625 l -1.68767,-1.09344 0.71875,-1.34362 z m -0.0625,3.90631 c 0.79632,0.04 0.37202,3.09394 -0.75024,0.5625 0.32049,-0.417 0.56629,-0.57174 0.75024,-0.5625 z m 2.1564,0.0937 2.46887,0.5 c 5.40577,1.33025 -0.8568,5.29936 0.71875,1.75032 l -2.03111,0.53125 -1.68769,-1.09343 0.53125,-1.68752 z m -6.6564,15.50001 1.00007,2.59356 c 1.61785,6.33204 7.27137,5.90682 9.62504,10.71875 -2.6712,6.17245 -8.93081,7.17323 -12.87497,3.25045 l 1.2816,-1.53101 c 2.29248,-6.21055 -2.10095,-9.03989 -4.3128,-12.62496 0.30385,3.01365 2.0736,5.22625 3.28105,7.49961 2.71583,4.19665 -3.69145,5.6731 -0.18752,9.06254 4.86073,1.89446 12.30899,2.47413 13.71874,-6.87464 -3.29184,-3.2731 -8.29605,-3.93616 -9.87501,-10.12509 l -1.656,-1.96859 z"
+         style="fill:#000000;filter:url(#filter4585)" />
+      <path
+         sodipodi:nodetypes="scssccsccccccscccscscccccccccccccccccccccccccscccccscsccccccccccccccccccccccccccccccccccsccccccccccccccsccccccsccccccscccsccccccssscccscscscccccsccccccscccsccsccscccccccsccsscccccsccccscsccccccccccccccccccccccccscccscccccccccsccscccscscccccscccccccccscccccccccssccccccccsccccscsscssccccscccccccscsccccccccccccccc"
+         inkscape:connector-curvature="0"
+         id="path3027-3"
+         d="m 195.00877,456.61765 c -2.39545,0 -4.03473,1.0801 -4.40626,2.9375 -0.26712,1.33643 -0.68563,1.875 -1.5625,1.875 -0.94608,0 -1.21875,-0.39855 -1.21875,-1.78125 0,-3.31942 -4.24302,-3.95161 -5.4375,-0.8125 -0.39808,1.04402 -0.37798,1.77542 0.0937,2.34375 0.54558,0.65832 0.41665,0.74378 -0.5625,0.84375 -0.66899,0.0683 -1.94086,0.48658 -2.6875,0.75001 -0.29011,-0.57227 -0.87736,-1.34051 -1.75001,-2.21875 l 0,-0.0312 c -1.52784,-1.53719 -3.09383,-2.2156 -4.34375,-2.125 -1.60704,0.116 -2.72451,1.53241 -2.71875,4.03125 l 1.375,1.5 c 0.20491,0.23865 0.44144,0.49723 0.65625,0.75 0.39605,0.46602 0.77176,0.91162 1,1.25 0.22248,0.32432 0.76774,1.63402 1.1875,2.9375 0.78336,2.43088 3.93309,8.21255 4.78126,8.75 0.26064,0.16473 0.75679,1.77958 1.09375,3.59375 0.33696,1.81416 0.90541,4.1146 1.28125,5.09375 0.37656,0.98223 0.96834,4.47622 1.3125,7.78125 0.3443,3.30605 0.77406,7.32272 0.9375,8.90625 0.0797,0.77246 0.20976,1.36256 0.34375,1.8125 -0.2737,0.77045 -0.6288,2.17011 -0.9375,2.375 -1.386,0.92147 -1.83156,1.65135 -2.625,4.34375 -0.48816,1.65147 -0.78994,1.82436 -3.81251,2.125 -1.80792,0.17967 -2.5609,0.38433 -2.3125,0.625 -0.11271,0.2428 0.11184,2.34957 0.0312,3.46875 -0.29665,4.1184 -0.16863,4.21166 5.65626,4.40625 l 5.21875,0.15625 0.1875,7.09375 c 0.10055,3.90321 -0.19043,10.87467 -0.625,15.46875 -0.43458,4.59716 -0.67662,8.95582 -0.53125,9.71875 0.14472,0.75882 -0.42986,4.20708 -1.28125,7.65625 -0.85032,3.44401 -1.53053,6.83421 -1.53125,7.53125 -7.2e-4,3.50682 -5.47692,22.17402 -7.12501,24.3125 -0.60624,0.78456 -1.82739,3.03448 -2.71875,5 -0.89064,1.96551 -2.28159,4.43436 -3.09375,5.49999 -0.53439,0.69923 -0.93406,1.41247 -1.1875,2.03125 l -1.875,2.1875 c -0.0281,0.0327 1.65959,-1.56807 -0.0625,0.12501 -0.37819,3.08364 1.99931,3.90996 2.46875,4.93749 0.84528,1.84917 -0.5432,3.07853 -7.28126,10.3125 -2.10888,2.26822 -2.13212,2.27698 -0.875,3.15625 1.99513,1.39512 5.68508,6.74863 5.96876,9.03125 3.7188,5.16138 3.6183,4.86982 4.6875,7.09376 0.55728,1.18094 1.407,2.15625 1.875,2.15625 0.46872,0 2.13086,0.62845 3.6875,1.40625 2.01529,1.00777 4.37402,1.54722 8.21876,1.84375 2.96929,0.23062 7.41188,0.80841 9.87501,1.3125 5.41369,1.10784 18.76176,1.32097 25.84377,0.40625 7.05026,-0.90709 12.78973,-2.03747 13.46876,-2.65625 0.31392,-0.28543 1.06974,-0.53125 1.6875,-0.53125 0.61776,0 2.31894,-0.67468 3.78125,-1.53125 2.03545,-1.19538 2.65626,-1.92722 2.65626,-3.09376 0,-1.72046 1.16651,-6.14342 1.875,-7.09375 0.25793,-0.34596 0.61609,-1.84326 0.8125,-3.31249 0.0797,-0.59562 0.15361,-1.04077 0.1875,-1.37501 0.3937,-0.47808 1.35948,-3.65182 1.5,-4.5 0.13159,-0.10937 0.2571,-0.2119 0.4375,-0.375 1.12824,-1.02238 1.12104,-1.18915 0.1875,-2.21875 -0.45301,-0.49997 -1.00535,-0.90002 -1.375,-1.03125 -0.53917,-0.68878 -2.55432,-2.71403 -3.6875,-3.62499 -3.39481,-2.72844 -3.69212,-3.94571 -1.62501,-6.15626 l 1.65626,-1.7813 -1.43751,-1.90624 c -0.78768,-1.04402 -2.16754,-3.63557 -3.0625,-5.78125 -0.89568,-2.14569 -2.12793,-4.62175 -2.75,-5.5 -0.62193,-0.87208 -1.12068,-1.96249 -1.125,-2.40625 -0.0157,-1.42498 -1.80046,-5.98954 -2.6875,-6.875 -0.63121,-1.18799 -1.26216,-2.69744 -1.875,-4.3125 -2.12669,-9.16863 -7.7558,-29.19099 -8.96876,-30.71875 -1.1304,-1.34467 -3.81254,-10.36983 -4.4375,-14.90625 -0.30173,-2.18893 -0.62395,-6.43278 -0.71875,-9.40625 l -0.1875,-5.375 2.09375,-0.71875 c 1.14623,-0.39269 3.09138,-0.73142 4.3125,-0.75 1.22112,-0.0188 3.59573,-0.326 5.28126,-0.6875 3.02184,-0.64763 3.05254,-0.69773 2.6875,-2.5625 -0.20376,-1.03682 -0.67928,-2.51112 -1.0625,-3.28125 -0.17981,-0.36293 -0.36135,-0.57504 -0.5,-0.71875 -0.0284,-0.0353 -0.055,-0.0866 -0.0937,-0.125 -0.0517,-0.039 -0.084,-0.0573 -0.125,-0.0625 -0.47055,-0.40798 -1.33846,-0.91925 -1.78126,-0.9375 -0.12113,-0.005 -1.20223,0.037 -1.84375,0.0625 -0.0586,-0.13473 -0.16919,-0.26469 -0.3125,-0.43751 -0.36864,-0.43963 -0.85112,-1.56167 -1.09375,-2.46875 -0.35857,-1.3323 -1.14045,-1.89348 -4.03125,-2.9375 -1.19377,-0.4306 -2.27929,-0.73543 -3,-0.90625 -0.142,-1.16757 -0.84375,-3.92701 -0.84375,-4.1875 0,-0.24086 -0.0377,-2.02152 -0.18751,-2.96875 0.65957,-2.20437 1.75811,-8.41702 2.31251,-13.53125 0.21456,-1.97992 0.78588,-4.7976 1.28125,-6.28125 1.23912,-3.72097 4.83703,-11.2509 5.59375,-11.71875 0.3422,-0.20977 0.45215,-0.59843 0.28125,-0.875 -0.17135,-0.27387 0.28672,-2.04163 1,-3.90625 1.19592,-3.12483 1.21105,-3.44387 0.3125,-4.34375 -0.53568,-0.54038 -2.11645,-1.17871 -3.53125,-1.40625 -1.16928,-0.18862 -1.96822,-0.30667 -2.53125,-0.3125 -0.12175,-0.001 -1.16467,0.38942 -2.0625,0.75 -0.35304,-0.0899 -0.78645,0.0923 -1.03125,0.4375 -0.009,0.004 -0.0901,0.0285 -0.0937,0.0312 -0.11588,0.0752 -0.10725,0.14732 -0.0312,0.1875 -0.07,0.17562 -0.0977,0.36999 -0.0625,0.59375 0.19943,1.26435 -0.1545,1.9375 -1.03125,1.9375 -0.75025,0 -0.91729,-0.38402 -0.65626,-1.6875 0.28728,-1.4332 0.11288,-1.80423 -1.25,-2.34375 -1.33992,-0.53072 -2.18019,-0.74628 -2.71875,-0.65625 -0.32334,0.054 -0.55132,0.23 -0.71875,0.5 -0.0835,0.13524 -0.0581,0.24435 0.0312,0.34375 -0.24972,0.77223 -0.62442,2.10549 -0.75,2.21875 -1.74889,1.58455 -2.5625,1.26333 -2.5625,-0.96875 0,-1.10167 -0.1334,-2.10277 -0.28125,-2.25 -0.13284,-0.13327 -0.50065,-0.1903 -1.00001,-0.1875 -1.404,0.007 -4.37789,2.38878 -4.53125,3.03125 -0.003,0.0143 5.6e-4,0.0188 0,0.0312 -0.16279,0.16054 -0.32879,0.35273 -0.53125,0.625 -1.11384,1.49704 -2.91433,0.27745 -3.15625,-2.15625 -0.1368,-1.37555 -0.49308,-1.875 -1.3125,-1.875 z m -0.59375,1.09375 c 0.55841,-0.1297 0.93131,0.25842 0.96875,1 0.1476,2.89009 0.30338,3.15508 2.03125,3.5 2.32848,0.46023 3.59375,-0.0495 3.59375,-1.46875 0,-0.25808 -0.0283,-0.45851 -0.0625,-0.625 0.57011,-0.55121 1.49182,-1.93343 1.9375,-2.03125 1.80217,-0.39641 2.03801,0.0389 1.75,2.875 -0.10943,1.07697 0.0246,1.11168 2.84376,1.21875 1.31544,0.0433 1.67527,-0.23232 1.84375,-1.40625 0.0539,-0.37767 0.29868,-1.80253 0.375,-2.37499 0.0708,0.007 0.13927,0 0.21875,0 1.51488,0 2.65625,1.43347 2.65625,3.31249 0,1.28598 0.25354,1.5 1.90626,1.5 2.37167,0 3.13981,-1.84693 2.78125,-3.71875 -0.002,-0.0112 0.003,-0.0207 0,-0.0312 0.19497,-0.0282 0.37682,-0.0562 0.4375,-0.0937 0.5184,-0.32432 5.91407,0.59435 6.59375,1.125 0.25056,0.19563 -1.52924,4.69333 -3.875,9.8125 -1.1088,2.42574 -2,4.63687 -2,4.9375 0,0.88547 -0.53203,0.65778 -2.90625,-1.25 -2.49481,-2.00153 -6.52896,-4.1875 -7.71876,-4.1875 -1.51561,0 -0.72712,0.94869 1.40625,1.71875 1.19304,0.43139 2.73334,1.30085 3.4375,1.90625 0.70488,0.60439 2.07006,1.77317 3.03126,2.59375 l 1.75,1.46875 -1.34375,4.25 c -1.30393,4.13797 -1.37859,4.25 -3.31251,4.25 -1.09152,0 -2.91813,-0.35932 -4.03125,-0.8125 -1.11312,-0.45378 -2.98798,-1.0039 -4.18751,-1.21875 -2.11464,-0.38197 -2.18378,-0.33567 -2.5625,1.6875 -0.954,5.08417 3.67847,10.62688 10.06251,12.03125 1.4364,0.31713 1.64457,0.62928 1.40625,1.875 -0.0994,0.51744 -0.0789,1.00519 0,1.34375 -0.2244,0.9771 -0.4375,2.29305 -0.4375,2.5 0,0.25257 1.00508,2.87059 1.62501,4.09375 -0.0984,-0.0156 -0.21855,-0.0616 -0.28125,-0.0625 -0.0671,-9.3e-4 -0.1045,0.014 -0.125,0.0312 -0.48601,0.4036 1.93641,1.9375 3.0625,1.9375 2.02752,0 2.92447,0.76464 4.09375,3.40625 0.69336,1.56603 1.46791,2.51292 1.84375,2.28125 0.34767,0.0155 1.28462,-0.13622 2.1875,0 0.60383,0.0911 1.1511,0.34822 1.53126,0.5 -0.0499,0.44212 0.0624,1.23858 0.46875,2.21875 0.97055,2.34028 0.40905,3 -2.59376,3 -3.64608,0 -9.17125,1.57643 -10.625,3.03125 -1.14985,1.14698 -1.21946,1.70669 -0.90626,7.34375 0.38089,6.85199 1.05182,10.90867 2.78126,16.625 1.20531,5.39345 10.20146,32.64303 12.75001,39.53125 0.2772,1.16465 0.43919,1.83823 0.75,3.15625 0.48096,2.09524 0.55889,1.67409 1.03125,2.21875 0.47231,0.54673 1.04941,1.77807 1.28125,2.75 0.23184,0.96474 0.90024,2.47029 1.5,3.3125 0.59976,0.8422 1.73709,3.08253 2.53125,4.96875 0.79489,1.88623 2.05261,4.10147 2.78125,4.9375 0.72865,0.84222 1.3125,1.77318 1.3125,2.0625 0,0.28727 -1.08505,1.49213 -2.40625,2.6875 -1.3212,1.19538 -2.07025,2.18648 -1.65625,2.1875 0.41329,0.007 1.25869,0.73427 1.875,1.65625 0.86006,1.28162 5.77306,5.23148 7.28126,5.8125 8.9e-4,0.002 0.0302,-0.003 0.0312,0 0.0715,0.21719 0.25996,0.53763 0.59375,0.90625 0.61586,0.68303 0.76824,1.21875 0.375,1.21875 -0.34896,0 -0.61039,0.39164 -0.65625,0.875 -0.49375,1.22483 -1.44235,4.678 -1.59375,5.4375 -0.46414,0.96429 -1.07574,2.85503 -1.46875,4.5 -0.43272,1.82137 -1.01126,3.56098 -1.28126,3.875 -0.26978,0.31713 -0.5,1.2866 -0.5,2.1875 0,1.20258 -0.50655,1.95352 -2,2.875 -1.11168,0.68379 -2.5503,1.25 -3.1875,1.25 -0.63793,0 -1.40555,0.2395 -1.71875,0.53125 -0.31298,0.29448 -3.67341,0.98789 -7.46875,1.53125 -3.79513,0.53952 -8.63076,1.26464 -10.71876,1.625 -4.02626,0.6988 -15.51552,0.27483 -19.34377,-0.71875 -1.18512,-0.30268 -5.49933,-0.92403 -9.59376,-1.375 -4.86361,-0.54053 -8.56357,-1.30101 -10.62501,-2.1875 -3.35881,-1.44452 -3.36525,-1.4929 -10.90626,-14.28125 -1.4148,-2.40412 -3.02682,-4.61421 -3.5625,-4.9375 -0.88416,-0.53156 -0.85608,-0.63093 0.125,-1.21875 0.594,-0.35932 2.61576,-2.59963 4.50001,-4.96875 2.30328,-2.90141 3.76603,-4.26091 4.46875,-4.125 1.30536,0.25224 1.35437,-0.6751 0.0937,-1.71875 -0.52199,-0.43242 -1.43514,-2.19343 -2.8125,-3.5 -0.39592,-0.57587 -0.31772,-1.56821 -0.15625,-2.5 0.0467,0.0135 0.0982,0.0331 0.15625,0.0312 0.684,-0.0185 4.70961,-6.5554 5.90625,-9.59375 0.58176,-1.47542 1.2323,-2.83422 1.4375,-3 1.13761,-0.91582 6.63509,-17.03235 6.62501,-19.4375 -0.003,-0.69807 0.36266,-3.01056 0.84375,-5.15625 2.73384,-12.18995 3.35961,-15.94503 3.65625,-22.1875 0.18008,-3.79511 0.53769,-8.81333 0.78125,-11.125 0.24359,-2.31145 0.2251,-5.53911 -0.0312,-7.1875 -0.25693,-1.64838 -0.29787,-4.33235 -0.0937,-5.9375 0.45864,-3.63242 0.0451,-3.95638 -5.25,-3.96875 -4.93489,-0.0144 -5.90626,-0.3612 -5.90626,-2.125 0,-0.63246 0.0357,-2.91516 -0.0937,-4.03125 0.59418,0.12523 1.42144,0.24747 2.50001,0.375 3.11832,0.36758 4.37268,-0.16895 4.125,-1.78125 -0.28224,-1.83577 0.60946,-4.4375 1.53125,-4.4375 0.92592,0 1.68749,-2.60272 1.53125,-3.8125 0.24902,-1.06563 0.0375,-3.25407 -0.59375,-5.46875 -0.28181,-0.99356 -0.67598,-4.20197 -0.875,-7.125 -0.46512,-6.83653 -2.55271,-14.44002 -4.84375,-17.5 -0.74161,-0.99252 -2.60148,-4.29098 -4.12501,-7.34375 -0.97056,-1.94387 -2.2538,-3.30405 -3.125,-4.09375 l -0.53125,-1.0625 c 0.49122,-0.9431 0.76248,-1.94591 0.59375,-2.21875 -0.16863,-0.27106 -0.0541,-0.66771 0.28125,-0.875 0.33538,-0.20722 0.625,-0.0999 0.625,0.21875 0,0.31863 0.50242,0.44419 1.125,0.28125 0.78624,-0.2018 1.65143,0.34542 2.84375,1.84375 0.94537,1.18095 1.93983,2.15625 2.18751,2.15625 0.19563,0 0.33465,-0.0551 0.40625,-0.15625 0.84456,-0.0387 2.30058,-0.24381 2.8125,-0.4375 1.38384,-0.52613 2.28464,-2.8103 1.25,-3.15625 -1.07208,-0.35315 0.0587,-2.25 1.34375,-2.25 1.47024,0 2.48773,1.75793 2.03125,3.5 -0.30744,1.17374 -0.11104,1.3125 2.125,1.3125 2.54665,0 2.5438,0.005 2.71876,-3.25 0.0338,-0.62917 0.44255,-1.20093 0.9375,-1.28125 0.49536,-0.0807 1.31786,-0.25777 1.8125,-0.375 z m 13.68751,15.78125 c -0.7632,0.0654 -1.33745,0.53614 -1.90625,1.40625 -1.61929,2.47002 -1.27389,3.3125 1.375,3.3125 1.29312,0 2.75925,-0.17468 3.28125,-0.375 1.42848,-0.54672 1.19521,-2.93177 -0.375,-3.6875 -0.8028,-0.386 -1.46965,-0.62228 -2.03125,-0.65625 -0.11706,-0.007 -0.23472,-0.009 -0.34375,0 z m 0.75,0.8125 c 0.39195,0.0288 1.44328,0.33082 1.75,0.8125 0.34776,0.54693 -0.056,1.283 0.0937,1.34375 0.64316,0.26325 -1.41756,0.46654 -2.625,0.5 -0.90793,0.0233 -1.65625,-0.23252 -1.65625,-0.5625 0.0781,-0.13562 0.12435,-0.69167 0.53125,-1.15625 0.47117,-0.53796 1.33457,-0.97955 1.90625,-0.9375 z m -4.87501,11.1875 c 0.15459,-0.0222 0.33564,-0.009 0.53125,0 0.78265,0.0364 1.89785,0.32057 3.40626,0.875 1.31976,0.48664 3.35016,0.81455 4.5,0.71875 2.32272,-0.19457 2.82599,0.70897 2.09376,3.625 -0.39384,1.56912 -0.41029,1.58044 -1.31251,0.40625 -0.63446,-0.82822 -0.99382,-0.98672 -1.1875,-0.46875 -0.4896,1.30657 -2.16314,0.90202 -1.8125,-0.4375 0.1726,-0.66257 0.0491,-1.21875 -0.25,-1.21875 -0.29911,0 -0.53125,0.39945 -0.53125,0.875 0,2.57709 -3.44789,1.63953 -3.78125,-1.03125 l -0.21875,-1.9375 -0.0937,2 c -0.0605,1.25612 -0.3632,1.89929 -0.81251,1.75 -0.83448,-0.27386 -1.81377,-3.39832 -1.40625,-4.5 0.13365,-0.36056 0.41125,-0.58947 0.875,-0.65625 z m 2.12501,6.59375 c 0.0538,-0.0204 0.0944,-0.01 0.15625,0 1.58256,0.24495 2.5625,0.69692 2.5625,1.1875 0,0.31212 0.678,0.39378 1.5,0.1875 1.71792,-0.4314 2.74445,1.14838 1.53125,2.34375 -0.55585,0.55002 -0.89909,0.45054 -1.53125,-0.40625 -0.45,-0.61316 -1.07692,-0.96557 -1.375,-0.78125 -0.64296,0.3964 -3.125,-1.21787 -3.125,-2.03125 0,-0.23348 0.11988,-0.43875 0.28125,-0.5 z m 7.5,1.71875 c 0.33,0 0.62501,0.51574 0.62501,1.15625 0,0.64133 -0.29501,1.35762 -0.62501,1.5625 -0.3403,0.20903 -0.59375,-0.31667 -0.59375,-1.1875 0,-0.84318 0.26375,-1.53125 0.59375,-1.53125 z m -17.65626,52.34375 c -0.116,0.0292 -0.23371,0.13993 -0.40625,0.3125 -0.45066,0.45303 -0.46095,1.25188 -0.0312,2.65625 0.33795,1.10888 0.76787,2.98493 0.96875,4.1875 0.2016,1.20978 0.86928,2.85728 1.5,3.65625 0.63072,0.79898 1.33498,2.25402 1.5625,3.21875 0.22752,0.96575 0.98809,3.03324 1.65625,4.625 1.14049,2.70683 1.15129,3.01283 0.25,4.90625 -2.04408,4.28314 0.36259,8.5043 5.68751,9.9375 6.03073,1.62368 9.96306,-1.2121 10.90626,-7.84375 0.47663,-3.35547 -1.03188,-6.1173 -4.12501,-7.59375 -1.68696,-0.80617 -2.35375,-1.66576 -3.34375,-4.34375 -2.63665,-7.13822 -5.00867,-12.65625 -5.46875,-12.65625 -0.76897,0 -0.59705,0.82353 1,4.4375 0.82584,1.86564 1.5,3.92107 1.5,4.5625 0,0.64763 0.51856,2.33843 1.15625,3.75 0.6372,1.41158 1.28414,2.9852 1.4375,3.5 0.15264,0.51789 1.35449,1.26603 2.65625,1.65625 1.69704,0.51068 2.68539,1.26393 3.46876,2.71875 1.05912,1.96552 1.04832,2.14218 -0.0625,5.5625 -0.97129,2.9879 -1.49293,3.67227 -3.37501,4.59375 -5.67145,2.77272 -12.3259,-2.72243 -10.03126,-8.28125 0.4087,-0.99355 0.72936,-1.92797 0.6875,-2.09375 -0.0425,-0.16577 -0.91509,-2.59852 -1.9375,-5.40625 -1.52136,-4.17606 -3.40665,-9.88208 -5.15625,-15.5625 -0.0936,-0.30327 -0.22911,-0.46697 -0.375,-0.5 -0.0365,-0.008 -0.0863,-0.01 -0.125,0 z m 28.78127,24.6875 c 0.0667,0.15373 0.56931,2.1331 1.37501,5.34375 -0.91403,-3.16487 -1.47071,-5.56417 -1.37501,-5.34375 z"
+         style="fill:#000000;filter:url(#filter4573)" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path4490"
+         d="m 188.6005,647.6796 c -13.43643,-2.09817 -14.63585,-2.83972 -20.73411,-12.81917 -2.91656,-4.77278 -5.30283,-9.10387 -5.30283,-9.62466 0,-0.5208 2.04556,-2.83243 4.54569,-5.13697 2.50012,-2.30453 4.54568,-4.44993 4.54568,-4.76755 0,-0.31761 -0.9161,-1.74211 -2.03578,-3.16554 -1.78003,-2.26295 -1.85399,-2.79058 -0.58874,-4.19995 2.37267,-2.64293 9.3291,-17.35827 11.02894,-23.33015 6.14297,-21.58146 10.09563,-59.88779 6.54584,-63.43758 -0.6667,-0.6667 -3.16683,-1.21218 -5.55584,-1.21218 -3.90592,0 -4.34366,-0.24318 -4.34366,-2.41314 0,-1.32723 0.56822,-2.39204 1.2627,-2.36625 3.50263,0.13008 4.79822,-0.43657 4.79822,-2.09861 0,-1.00498 0.6674,-2.70961 1.4831,-3.78807 1.88985,-2.4986 1.89274,-5.64536 0.0167,-18.12328 -1.54971,-10.30725 -3.92248,-16.49104 -9.53346,-24.84559 -3.42892,-5.10553 -2.57454,-7.74124 1.32257,-4.08009 1.79175,1.68325 3.08622,2.0908 5.06415,1.59437 2.54868,-0.63968 3.09046,-1.47956 2.73253,-4.23595 -0.30659,-2.36102 1.72277,-1.2751 2.35971,1.26269 0.84981,3.3859 4.35879,3.3859 5.64611,0 1.15688,-3.04282 2.60208,-3.26247 3.32315,-0.50508 0.73458,2.80903 5.07931,2.65465 7.10726,-0.25254 l 1.58545,-2.27284 0.053,2.27284 c 0.0402,1.72423 0.65044,2.27285 2.52817,2.27285 1.36135,0 2.94508,-0.7955 3.51939,-1.76777 0.95298,-1.61333 1.10003,-1.56921 1.68324,0.50508 0.74042,2.63344 4.89223,3.17395 5.81946,0.75761 0.61174,-1.59417 5.69562,-2.15511 5.69562,-0.62844 0,0.48773 -0.73588,2.64693 -1.63529,4.79822 -0.8994,2.15129 -2.03477,4.96104 -2.52303,6.24387 l -0.88775,2.33244 -4.99731,-2.80913 c -2.74853,-1.54502 -5.35019,-2.45626 -5.78147,-2.02497 -0.43129,0.43129 -0.1677,1.16515 0.58575,1.63081 1.07173,0.66236 0.90046,1.09789 -0.78687,2.00092 -1.18623,0.63485 -2.15678,2.04741 -2.15678,3.13903 0,2.90099 5.82119,2.80881 6.90066,-0.10927 0.75342,-2.03668 0.83386,-2.0436 2.93689,-0.25254 2.07415,1.76647 2.09728,1.99915 0.56765,5.71068 -1.30675,3.17072 -1.97954,3.76326 -3.72705,3.28245 -1.17285,-0.32269 -3.83709,-0.87186 -5.92053,-1.22036 -3.77527,-0.6315 -3.78807,-0.62172 -3.78807,2.89477 0,4.31971 3.147,8.58135 7.7603,10.5089 2.75912,1.15284 3.346,1.91945 3.19293,4.17074 -0.29577,4.35005 1.09164,7.24617 3.79657,7.92506 1.37133,0.34418 3.15429,1.90396 3.96214,3.46617 0.81626,1.57847 2.47895,2.98443 3.74249,3.16463 1.25051,0.17834 2.41309,1.05645 2.5835,1.95136 0.23769,1.24819 -1.06867,1.8983 -5.60983,2.79172 -3.25581,0.64054 -6.45893,1.70389 -7.11804,2.363 -1.64303,1.64303 -1.49165,13.07132 0.27145,20.4923 3.28415,13.8232 16.02038,50.91027 20.14773,58.66888 l 4.35264,8.1821 -1.89003,2.5946 -1.89003,2.5946 5.06574,4.43138 5.06574,4.43139 -3.01125,9.63346 c -3.48707,11.15567 -3.52556,11.1865 -16.87441,13.51435 -10.4107,1.81548 -24.90881,1.77792 -36.90665,-0.0956 l 0,-4e-5 z m 27.04198,-69.56407 c 1.89343,-1.89342 2.47947,-3.54741 2.47947,-6.99785 0,-3.80619 -0.47165,-4.88818 -2.99229,-6.86444 -1.83568,-1.43924 -4.10093,-5.05341 -5.86049,-9.35032 -1.57751,-3.85234 -3.46978,-7.20478 -4.20505,-7.44987 -0.82244,-0.27415 -1.11678,0.0888 -0.76494,0.94334 0.31455,0.76393 1.56741,4.5078 2.78413,8.31972 1.81704,5.69268 2.82013,7.28944 5.61528,8.93862 2.63979,1.55751 3.40305,2.67547 3.40305,4.98444 0,4.045 -4.25071,8.31498 -7.34042,7.3737 -4.34112,-1.3225 -6.02065,-3.66088 -5.40313,-7.52264 0.41787,-2.61325 -0.45141,-6.46962 -3.2531,-14.43155 -3.51698,-9.99468 -5.21655,-12.44991 -5.21655,-7.53594 0,1.06492 1.36239,5.33862 3.02754,9.49713 2.13553,5.33322 2.96508,8.99633 2.81556,12.43275 -0.22383,5.14436 1.09714,7.70929 4.72843,9.1812 3.89802,1.58002 7.64254,1.02169 10.18251,-1.51829 l 0,0 z"
+         style="fill:#483737;fill-opacity:1;stroke:#241c1c;filter:url(#filter4561)" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path4492"
+         d="m 254.09787,646.44221 c -2.95637,-0.30904 -4.12705,-1.04093 -5.30331,-3.31556 -2.21555,-4.28441 -1.94128,-5.52539 2.74475,-12.41863 6.58892,-9.69246 9.17853,-17.65576 9.26197,-28.48139 0.0681,-8.83503 -0.0512,-9.316 -4.23039,-17.05828 -3.8606,-7.15204 -4.19185,-8.29601 -3.23856,-11.1845 0.58404,-1.76967 2.67063,-4.77581 4.63687,-6.6803 3.23868,-3.13699 4.11957,-3.45972 9.36453,-3.43092 9.5091,0.0522 20.37167,7.42773 20.34201,13.81189 -0.0265,5.70983 -0.62823,5.99632 -9.95673,4.7409 -4.58302,-0.61678 -8.57843,-0.87575 -8.87869,-0.57549 -1.07992,1.07992 3.86321,8.30117 7.15732,10.4559 2.62822,1.71915 3.80732,3.59894 5.38577,8.58629 5.07523,16.03591 8.20757,23.11092 12.28057,27.7381 4.36373,4.95746 5.53297,7.68177 4.97009,11.5803 -0.31263,2.1653 -1.29463,2.4888 -13.97332,4.60324 -12.72266,2.12177 -21.41378,2.58485 -30.56288,1.62845 z m 26.52227,-24.5176 c 3.07537,-3.07538 2.46502,-5.89093 -2.27284,-10.48467 -2.36124,-2.2894 -4.80805,-5.07168 -5.43737,-6.18285 -0.62932,-1.11117 -1.45833,-1.72162 -1.84225,-1.35656 -1.1957,1.13696 2.2225,6.50875 6.14302,9.6539 2.60951,2.09342 3.55042,3.51531 3.10106,4.68631 -0.91144,2.37517 -5.13107,4.05887 -8.22568,3.28217 -2.27242,-0.57035 -2.47547,-0.93215 -1.52247,-2.71284 1.45943,-2.72697 0.45826,-6.84476 -2.56324,-10.54255 -2.97769,-3.64416 -3.26524,-1.84082 -0.55392,3.47382 1.68828,3.30929 1.80149,4.34763 0.77154,7.07627 -1.49906,3.97148 -0.16763,5.08929 6.0887,5.11183 2.96138,0.0107 4.91986,-0.61124 6.31345,-2.00483 z m -2.20259,-45.21465 c 0.24255,-1.70007 -0.18208,-2.26252 -1.70815,-2.26252 -2.41781,0 -3.56541,1.52796 -2.74782,3.65856 0.86409,2.25177 4.07925,1.24447 4.45597,-1.39604 l 0,0 z m 2.90387,-3.80967 c -2.41299,-2.12285 -7.77235,-3.51057 -7.77235,-2.01252 0,0.79341 7.45829,4.47954 9.09137,4.49325 0.98418,0.008 0.52189,-0.86117 -1.31902,-2.48073 l 0,0 z"
+         style="fill:#483737;fill-opacity:1;stroke:#241c1c;filter:url(#filter4549)" />
+      <g
+         transform="matrix(0.99878894,0.04920014,-0.04920014,0.99878894,50.659335,-19.667116)"
+         id="g3240">
+        <g
+           id="g4070"
+           transform="matrix(1.25,0,0,-1.25,-132.85714,1032.8764)">
+          <path
+             inkscape:connector-curvature="0"
+             id="path3027-8"
+             d="m 440.83954,503.80829 c -0.792,-0.087 -0.86285,-0.62516 -1.17504,-2.1498 -0.0887,-0.43714 -0.62438,-0.64593 -1.42502,-0.55001 -0.70906,0.0847 -1.44231,0.0388 -1.6249,-0.1 -0.18178,-0.13921 -0.15018,-1.88953 0.075,-3.87542 0.37959,-3.34579 0.49917,-3.62089 1.77524,-4.02532 1.3559,-0.42914 1.36454,-0.51272 1.1998,-4.29961 -0.20102,-4.52859 -0.38742,-5.03186 -1.90022,-4.82512 -0.90202,0.12273 -1.36224,-0.24378 -2.19974,-1.77503 -0.32104,-0.58928 -1.41005,-0.81815 -2.35008,-0.97524 -0.20587,0.0378 -0.51756,0.0562 -0.92506,0.05 -1.99814,-0.0302 -6.00157,-0.58953 -7.62503,-1.17539 -0.78278,-0.28116 -1.93306,-0.69594 -2.57472,-0.92499 -0.64166,-0.22899 -1.93939,-0.88464 -2.87482,-1.47521 -1.36224,-0.86157 -1.63584,-1.266 -1.35014,-1.9999 0.19872,-0.50327 0.70618,-2.26924 1.12493,-3.92483 0.41875,-1.6556 1.59897,-5.82507 2.62483,-9.25001 1.02586,-3.42486 2.26195,-8.33177 2.72506,-10.90001 0.46311,-2.56823 0.99417,-4.80535 1.1998,-4.97502 0.20909,-0.16968 0.61114,-1.46204 0.87495,-2.87465 0.47232,-2.53034 0.46514,-2.57565 -0.64973,-3.25024 -0.62035,-0.3769 -1.1641,-0.8871 -1.19981,-1.14986 -0.0359,-0.26299 -0.26562,-0.54322 -0.5,-0.6 -0.81734,-0.19767 -3.62534,-3.95531 -3.7751,-5.04998 -0.11693,-0.85251 -0.45157,-1.0889 -1.42503,-1.02466 -0.69177,0.0454 -1.69401,0.0852 -2.22509,0.10001 -0.5328,0.015 -1.18137,0.0395 -1.44979,0.05 -0.58118,0.0222 -1.38873,-5.40663 -0.90029,-6.04993 0.18524,-0.24381 2.88173,-0.8021 5.97502,-1.22481 3.096,-0.42294 5.7861,-0.97688 5.97502,-1.22481 0.42221,-0.55416 -3.26534,-27.48793 -4.82515,-35.275 -1.52064,-7.59351 -3.06144,-13.03935 -3.82521,-13.52499 -0.34964,-0.21909 -1.21076,-2.7165 -1.925,-5.57467 -0.71596,-2.85652 -2.07648,-6.90903 -3.02515,-9.00002 -0.95097,-2.09133 -1.76774,-4.15464 -1.82477,-4.57472 -0.0576,-0.4209 0.90317,-2.08062 2.15021,-3.67526 1.24704,-1.59547 2.21242,-3.26836 2.15021,-3.72468 -0.15206,-1.11115 -2.01773,-4.69663 -2.57472,-4.95032 -0.64454,-0.29364 -4.77792,-5.96591 -6.39999,-8.77499 l -1.40026,-2.4002 1.57479,-2.79969 c 0.86515,-1.54111 2.00966,-3.02208 2.54995,-3.27495 0.49821,-0.23353 0.99533,-0.6189 1.17504,-0.90029 -0.29697,-0.25545 -0.59386,-0.49437 -0.72519,-0.5 -0.10738,-0.005 -0.21787,-0.0227 -0.32499,-0.05 -0.42797,-0.10931 -1.5938,-0.1947 -2.60007,-0.2 -1.00685,-0.006 -1.96013,-0.17531 -2.12486,-0.375 -0.16105,-0.19933 -0.0694,-2.64483 0.225,-5.42475 0.2984,-2.77992 0.50792,-5.39922 0.45,-5.82507 -0.1044,-0.76362 1.57708,-2.24782 2.24985,-2.25029 0.47537,-0.27389 1.08058,-0.54739 1.49991,-0.7 2.17843,-0.7932 21.14962,-3.33591 24.02501,-3.22471 1.4498,0.0562 4.08269,0.15249 5.82503,0.22499 1.7424,0.0727 4.23015,0.0589 5.54976,-0.025 2.48832,-0.15815 5.77049,0.0654 15.4,1.02465 4.82688,0.48148 5.72256,0.44053 6.10001,-0.2 0.36749,-0.62579 0.57773,-0.56211 1.35014,0.325 0.7344,0.8418 1.04372,2.06332 1.4498,5.95026 0.46352,4.45199 0.40858,4.99233 -0.475,5.80036 -1.58573,1.45297 -4.65235,5.11752 -4.59994,5.49971 0.0265,0.19522 0.77703,1.29153 1.65024,2.44962 1.64794,2.19181 2.61274,2.87712 1.30003,5.37534 -0.14745,0.15321 -1.69171,3.64643 -3.45024,7.75 l -3.20025,7.45019 1.17504,2.57482 c 0.24392,0.53565 0.42363,1.03866 0.575,1.49992 0.134,-0.24349 0.26293,-0.39795 0.325,-0.275 0.0416,0.0836 -0.004,0.56253 -0.075,1.14986 0.0812,0.40157 0.0962,0.74015 0.025,0.90028 -0.0686,0.15435 -0.12672,0.23117 -0.2,0.25 -0.21443,1.39285 -0.49675,2.95043 -0.67508,3.3252 -0.31968,0.67789 -0.83692,2.66708 -1.15027,4.42481 -0.31161,1.75773 -0.9815,4.91984 -1.47513,7.04988 -2.35124,10.10087 -2.70029,11.86659 -3.02516,14.84996 -0.19521,1.75938 -0.5217,3.43392 -0.69984,3.72468 -0.18101,0.29159 -0.4934,1.75608 -0.69984,3.25024 -0.20851,1.49333 -0.62092,4.26831 -0.92505,6.17513 -0.30344,1.90682 -0.65031,5.76082 -0.77472,8.575 -0.12676,2.81534 -0.3458,5.68751 -0.5,6.37529 -0.6002,2.68519 -0.51321,11.41867 0.125,11.75004 0.76954,0.40109 8.78348,0.52009 9.99999,0.15 l 1.47514,-0.45 0.60019,3.14975 c 0.32601,1.72726 0.50603,3.31366 0.4,3.55006 -0.10713,0.23685 -1.23264,0.64304 -2.49984,0.90028 -1.60646,0.32536 -2.31494,0.69273 -2.32473,1.2001 -0.008,0.40114 -0.0607,1.06996 -0.1,1.47521 -0.0392,0.40524 0.20693,0.63511 0.52499,0.52501 0.83866,-0.28994 0.864,0.98265 0.05,1.8747 -0.38477,0.41843 -1.71706,1.37637 -2.97504,2.12509 -1.1641,0.69248 -2.42784,1.29318 -2.97504,1.44968 0.46396,2.02872 0.56734,6.60014 2.1502,10.20004 0.66528,1.50733 1.39392,2.93971 1.6249,3.17528 0.2281,0.23559 0.68026,1.25282 0.99994,2.27501 0.31968,1.02219 1.18771,3.1028 1.92499,4.60025 0.73958,1.49828 2.0471,4.67768 2.90016,7.07541 1.79366,5.04257 1.8288,5.1167 3.04992,4.95032 1.43251,-0.19522 1.18598,0.43864 -0.82483,2.10038 -1.27412,1.05184 -3.28493,1.98013 -6.425,2.9496 -2.5102,0.7746 -4.7255,1.4192 -4.95014,1.44968 -0.22808,0.0313 -0.57306,0.84262 -0.74995,1.79974 -0.17741,0.95712 -0.62784,1.77421 -0.99994,1.82527 -0.11794,0.0162 -0.2125,0.0301 -0.3,0.025 -0.12696,-0.007 -0.2128,-0.0627 -0.27499,-0.125 -0.77415,0.0286 -2.05229,-0.0392 -3.02516,0 l -2.40019,0.1 -0.25,1.77503 c -0.13302,0.97771 -0.19521,2.05756 -0.15,2.40021 0.0214,0.16152 -0.027,0.27484 -0.1,0.35 -0.005,0.005 0.005,0.0208 0,0.025 0.12678,0.66789 0.44008,2.2717 0.575,3.17528 0.96077,-0.633 2.42899,-1.3566 2.72506,-1.22481 0.37068,0.16556 0.97632,6.06393 0.74995,7.30028 -0.0576,0.3412 -0.7511,0.69076 -1.55002,0.79999 -1.53561,0.21005 -1.56844,0.25858 -1.94976,3.55007 l -0.25,2.07485 -3.04992,0.425 c -1.20672,0.16494 -1.94976,0.27721 -2.42496,0.22499 z m 1.15027,-1.12515 c 0.38068,-5.4e-4 0.84499,-0.058 1.40026,-0.175 2.01715,-0.42584 2.08051,-0.47528 2.40019,-2.77497 0.21715,-1.5617 0.59443,-2.41503 1.12493,-2.52541 0.43546,-0.0903 1.09901,-0.21271 1.47513,-0.3 0.80813,-0.1878 1.13933,-3.0995 0.55,-4.79958 -0.34905,-1.01807 -0.61977,-1.11609 -1.8,-0.775 -0.61517,0.17774 -1.13645,0.24225 -1.3248,0.175 -0.002,-4.1e-4 -0.024,8e-4 -0.025,0 -0.002,-0.002 0.002,-0.0221 0,-0.025 -7.6e-4,-8e-4 -0.0243,8e-4 -0.025,0 -0.0204,-0.0136 -0.0224,-0.0304 -0.025,-0.05 -0.002,-0.0123 -0.004,-0.0354 0,-0.05 -0.17477,-0.58538 -0.40485,-3.76752 -0.35,-4.32515 -0.1689,-0.42408 -0.32203,-1.08149 -0.375,-1.79974 l -0.15,-1.99989 -2.2752,0.225 c -2.15885,0.21251 -2.26771,0.28507 -2.12486,1.49992 0.0825,0.70261 0.15677,2.16134 0.175,3.22471 0.0182,1.06337 0.0883,2.67614 0.15,3.60031 0.0939,1.45214 -0.0653,1.73384 -1.19981,2.0246 -1.40947,0.36159 -2.18189,2.16793 -2.12486,4.97503 0.0248,1.32942 0.12093,1.42908 1.30003,1.12514 1.07366,-0.27644 1.31731,-0.14752 1.44979,0.77501 0.20218,1.41425 0.63302,1.97683 1.77523,1.97518 z m -4.22496,-19.475 c 0.44242,0.0598 3.3696,-0.28393 6.49999,-0.775 4.26585,-0.66927 6.62336,-0.64939 7.67503,-0.30001 0.11435,-0.38867 0.33867,-0.89781 0.72518,-1.67536 0.9481,-1.91011 2.05344,-2.49657 7.95001,-4.22466 3.10752,-0.91099 4.66906,-2.11768 3.97498,-3.07479 -0.30183,-0.42337 -0.95962,-2.06991 -1.47514,-3.64973 -0.5184,-1.57982 -2.90189,-7.1413 -5.29978,-12.35001 -4.67539,-10.16438 -6.51058,-16.21653 -5.90002,-16.29997 0.055,-0.007 0.48287,-0.44077 0.90029,-0.74999 0.004,-0.002 -0.004,-0.0224 0,-0.025 0.19976,-0.50933 1.00051,-1.3113 2.24985,-2.1498 2.33914,-1.57158 2.37024,-1.64736 2.32474,-4.1497 -0.0547,-3.03938 0.30585,-3.67938 1.8,-3.12504 0.60653,0.22467 1.64333,0.27281 2.29997,0.1 1.08518,-0.28417 1.17792,-0.54686 0.97516,-2.62507 l -0.22499,-2.275 -1.69978,0.52499 c -1.05926,0.33133 -2.35872,0.36432 -3.45024,0.075 -0.9648,-0.25552 -2.62598,-0.49104 -3.70022,-0.52501 -2.78324,-0.0865 -3.18068,-0.94888 -3.27514,-7.12483 -0.0402,-2.80298 0.0715,-6.41317 0.25,-8.02511 0.17485,-1.61277 0.33348,-3.89931 0.35,-5.10023 0.034,-2.60118 1.97165,-15.33 2.44973,-16.12502 0.1849,-0.30641 0.7655,-2.84087 1.30003,-5.64962 0.53453,-2.80875 1.09037,-5.24767 1.22515,-5.42476 0.13478,-0.17791 0.18233,-0.82293 0.1,-1.42496 -0.0824,-0.60211 0.43715,-3.64314 1.17504,-6.75006 0.73786,-3.10692 1.5529,-6.7583 1.8,-8.12478 0.35914,-1.98589 1.37895,-5.80694 2.12487,-7.92463 -0.0152,-0.041 -0.0343,-0.0559 -0.05,-0.1 -0.26727,-0.76108 -1.08807,-2.24782 -1.82477,-3.29966 l -1.3248,-1.92494 1.35014,-2.20005 c 0.74707,-1.21493 1.78503,-3.36803 2.32474,-4.77487 0.97056,-2.50893 2.18361,-5.28885 3.74976,-8.675 0.86227,-1.8574 0.90547,-1.69678 -2.22509,-5.80036 l -1.05005,-1.40025 1.42503,-2.29972 c 0.78508,-1.27423 2.15308,-2.90264 3.07526,-3.6003 1.62778,-1.2314 1.67904,-1.3286 1.24992,-3.69997 -0.24283,-1.34013 -0.59328,-3.34826 -0.77472,-4.45035 -0.2759,-1.67783 -0.50455,-2.01719 -1.42502,-2.07484 -0.6048,-0.0379 -3.53549,-0.27224 -6.49999,-0.525 -8.54571,-0.72853 -12.52495,-0.94971 -15.375,-0.87475 -1.46016,0.0384 -4.94784,0.0438 -7.75002,0 -5.50138,-0.0857 -24.9844,2.22805 -27.35003,3.25024 -0.64628,0.2785 -1.29658,0.39757 -1.65024,0.325 -0.18168,0.20364 -0.35556,0.41739 -0.42501,0.6 -0.35942,0.94394 -1.20672,9.8354 -1.02528,10.72497 0.053,0.25923 0.34784,0.47148 0.67508,0.45001 0.32832,-0.0217 1.4158,0.006 2.42496,0.075 1.19692,0.0814 2.18592,0.89699 2.54995,1.64983 0.26938,0.1183 0.50825,0.34465 0.55,0.65 0.0335,0.24612 -0.2121,0.4788 -0.55,0.52501 -0.67335,0.0914 -3.72039,4.11016 -4.27507,5.62491 -0.35943,0.98676 -0.002,1.69678 2.67494,5.49971 5.97894,8.48077 7.09592,10.23109 7.225,11.17503 0.0996,0.72731 -0.68026,2.01637 -2.37485,3.95037 -2.40653,2.74615 -2.86733,3.96025 -1.82477,4.82512 0.65607,0.54642 3.25325,6.37528 3.84999,8.65004 0.27417,1.02795 0.88646,2.88946 1.35014,4.12498 3.2567,8.68406 4.50893,14.39002 7.15,32.02501 2.91514,19.45351 3.0649,22.37066 1.12493,23.15002 -0.59789,0.23984 -3.31315,0.67024 -6.02502,0.94971 l -4.9248,0.49999 0.10001,1.90023 c 0.11232,2.0139 1.26374,3.19094 2.47507,2.52541 0.34099,-0.18582 1.40832,-0.20455 2.37485,-0.025 1.50912,0.27839 1.73491,0.50581 1.62489,1.49992 -0.22176,1.99331 3.59482,5.9725 5.50023,5.75011 0.65491,-0.0774 0.76435,0.24561 0.67507,2.07485 -0.0587,1.18775 -0.32949,2.98255 -0.60019,3.99979 -0.576,2.16545 -0.28239,2.69838 1.35014,2.47516 2.55399,-0.34924 6.4406,2.93724 7.55004,6.37528 0.77817,2.41833 0.50046,3.43063 -1.24992,4.57472 -2.19975,1.43815 -5.07226,1.67289 -7.75002,0.625 -1.2649,-0.49291 -2.39501,-0.86816 -2.52519,-0.85004 -0.2183,0.0298 -4.35341,12.62257 -5.22489,15.89999 -0.21032,0.79157 -0.2447,1.76597 -0.05,2.17534 0.55872,1.17457 6.02231,3.3532 9.14999,3.64973 1.31444,0.12469 3.21869,0.30304 3.9001,0.475 1.08749,-0.24984 3.7993,0.39167 3.97498,1.17539 0.44352,1.96859 0.864,1.52957 1.57478,1.62512 z m -6.82502,-9.69999 c -1.17792,-0.0348 -2.50963,-0.31913 -3.67488,-0.85004 -2.35181,-1.06996 -3.46637,-2.06249 -3.15015,-2.77497 0.35079,-0.79014 1.14048,-0.75183 1.24992,0.05 0.14279,1.04525 4.29293,2.56741 6.25001,2.29972 1.60934,-0.22074 3.05856,-1.39944 2.92492,-2.37467 -0.0328,-0.24288 0.28265,-0.47135 0.67508,-0.525 0.39079,-0.0534 0.70675,0.0526 0.72518,0.24999 0.0478,0.56094 -1.24186,2.47516 -2.19974,3.25025 -0.59328,0.47905 -1.62202,0.70978 -2.79994,0.67499 z m -1.69978,-5.475 c -0.9216,0 -1.04601,-0.28167 -1.24992,-1.77503 -0.18374,-1.34425 -0.009,-2.06908 0.64973,-2.64978 0.79949,-0.70345 1.06157,-0.69907 2.29997,0.025 1.60934,0.94476 2.0016,2.4521 0.92505,3.55006 -0.4078,0.41679 -1.38412,0.78222 -2.17497,0.82533 -0.16681,0.009 -0.31838,0.025 -0.45,0.025 z m 0.64973,-1.12515 c 0.54913,0.16086 1.4377,-1.25281 1.17504,-1.99989 -0.32429,-0.92582 -1.68595,-0.70736 -1.87488,0.29999 -0.0658,0.3504 0.0597,0.56934 0.275,0.50001 0.93139,-0.30031 1.28909,-0.0959 0.69984,0.39999 -0.3515,0.2959 -0.51552,0.64329 -0.375,0.75 0.0333,0.0255 0.0634,0.0393 0.1,0.05 z m -0.375,-9.07497 c 2.1145,-0.0194 4.32922,-0.5873 4.65005,-1.44968 0.77299,-2.08391 0.0562,-3.67938 -2.44973,-5.42476 -4.53658,-3.16375 -6.29988,-2.75191 -6.20001,1.47521 0.0274,1.22811 -0.11732,2.37879 -0.325,2.55012 -0.76781,0.63341 -0.14564,1.71408 1.37491,2.37467 0.55264,0.24011 1.27181,0.39556 2.04999,0.45 0.29191,0.0204 0.59789,0.0278 0.90029,0.025 z m 7.2,-48.50001 c -1.00282,-0.25581 -2.79418,-7.0194 -4.09997,-15.84999 -0.39458,-2.6679 -2.03731,-5.43712 -2.54995,-6.84973 -0.47141,0.40941 -4.50259,-2.62259 -5.2249,-3.95037 -0.4896,-0.89534 -0.35054,-2.36725 -0.1,-4.99973 0.29607,-3.14811 0.5289,-3.72139 1.99988,-5.12494 3.4462,-3.29307 7.01838,-3.10527 11.27502,0.6 2.28154,1.98589 2.36564,2.11851 2.65018,5.02527 0.16105,1.64572 0.0639,3.77905 -0.2,4.72463 -0.83635,2.99737 -0.94521,5.90332 -0.275,7.42465 0.3456,0.78332 0.80237,2.60942 0.99994,4.05004 0.34675,2.49245 2.87654,10.52053 3.84998,12.20002 l -0.025,0 c 0.24829,0.42908 0.29251,0.62471 0.075,0.64999 -0.0724,0.008 -0.17322,0.005 -0.29999,-0.025 -1.24301,-0.29183 -3.45197,-6.51202 -5.25024,-14.77501 -1.91232,-8.79937 -1.92672,-8.67953 -0.64973,-9.37504 1.21536,-0.66142 1.27065,-1.09303 0.5,-5.37534 -0.35654,-2.01307 -0.79027,-2.89524 -1.92499,-3.92484 -1.95091,-1.77503 -3.30739,-2.15557 -6.275,-1.75032 -2.96756,0.40607 -4.22554,1.4085 -4.95015,3.97508 -1.3392,4.74852 -0.60998,7.23521 2.67495,9.15002 0.48783,0.28436 0.8064,0.62952 0.99993,0.92499 0.0199,-0.50426 1.56039,0.15372 1.67501,0.175 0.49536,0.0918 2.6784,8.33465 4.0752,17.15001 0.35078,2.21652 0.88301,4.2436 1.17504,4.52529 0.29197,0.28088 0.3976,0.79248 0.25,1.12515 -0.10721,0.24178 -0.23177,0.33654 -0.375,0.29999 z m 22.05003,-59.97503 c 0.26154,-0.0357 0.43576,-0.28842 0.4,-0.54999 -0.0358,-0.26156 -0.26345,-0.43577 -0.525,-0.40001 -0.26155,0.0358 -0.46076,0.26346 -0.425,0.52501 0.0358,0.26158 0.28844,0.46075 0.55,0.42499 z"
+             style="fill:#000000" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path3092"
+             d="m 426.32893,449.41179 c -0.46598,0.46598 -0.72691,1.64159 -0.72806,3.28236 -6.6e-4,0.85498 -0.1294,1.77833 -0.30746,2.20417 -0.39427,0.94394 -0.2418,1.38049 0.68659,1.96612 1.51949,0.95877 3.87475,1.10621 6.42499,0.40183 1.35015,-0.37297 1.88295,-1.02136 1.87891,-2.28324 -0.005,-1.25529 -0.63763,-2.31537 -2.07532,-3.47346 -2.43764,-1.96365 -5.07341,-2.9043 -5.87929,-2.09874 z"
+             style="fill:#1a1a1a;fill-opacity:1;stroke:#000000;stroke-width:0.80812281;stroke-miterlimit:4;stroke-dasharray:none" />
+        </g>
+        <path
+           style="fill:#1a1a1a;fill-opacity:1;stroke:#000000;stroke-width:1.01015353;stroke-miterlimit:4;stroke-dasharray:none"
+           d="m 404.08148,451.81696 c -0.5595,-0.61822 -0.34155,-0.99442 0.48465,-0.83648 0.73151,0.13991 0.88631,-0.42614 0.25856,-0.9472 -0.20835,-0.17292 -0.37881,-0.43392 -0.37881,-0.58002 0,-0.47248 1.21464,0.86004 1.3788,1.51249 0.30384,1.2108 -0.88992,1.79356 -1.74312,0.85168 z"
+           id="path3094"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:#e6e6e6;fill-opacity:1;stroke:none"
+           d="m 400.34386,645.58253 c -2.75,-0.28097 -9.26814,-1.18845 -14.48477,-2.01664 -8.98763,-1.42684 -9.53049,-1.7344 -10.35714,-5.86766 -1.50156,-7.50781 -1.06919,-9.71901 1.90046,-9.71901 4.2941,0 4.83562,-2.4765 1.55035,-7.09023 l -3.00034,-4.21359 6.64279,-9.98982 6.64278,-9.98983 -3.07647,-4.97785 -3.07648,-4.97784 3.45922,-8.30898 c 6.89103,-16.55217 13.49708,-48.36714 14.17478,-68.26617 l 0.33911,-9.95716 -7.41834,-1.21023 c -5.56059,-0.90716 -7.22164,-1.72283 -6.63288,-3.25712 0.43201,-1.12579 2.32384,-2.0469 4.20406,-2.0469 2.00911,0 3.41859,-0.84074 3.41859,-2.03917 0,-1.12154 1.60714,-3.30335 3.57142,-4.84845 2.62991,-2.06869 3.57143,-4.16738 3.57143,-7.96083 0,-4.1345 0.5436,-5.15155 2.75346,-5.15155 3.22556,0 8.67511,-6.37127 8.67511,-10.14239 0,-3.50223 -4.97784,-5.97046 -10.69497,-5.30301 -4.60437,0.53753 -4.68961,0.43724 -7.77754,-9.15046 -1.71718,-5.33167 -2.75439,-10.28899 -2.30492,-11.01625 0.94822,-1.53424 7.74192,-3.75762 15.42029,-5.04661 2.94643,-0.49462 5.35714,-1.50318 5.35714,-2.24125 0,-1.9835 17.58836,0.16433 19.28572,2.3551 0.78571,1.01413 4.4698,3.1306 8.18686,4.70327 l 6.75829,2.85942 -5.1031,11.84823 c -7.89709,18.33524 -10.55634,25.32987 -10.55634,27.76633 0,1.23249 1.60715,4.15087 3.57143,6.48529 1.96429,2.33443 3.57143,5.15937 3.57143,6.27766 0,1.11828 1.28571,2.03325 2.85714,2.03325 1.5873,0 2.85715,0.95238 2.85715,2.14285 0,1.5848 -1.66109,2.14286 -6.37831,2.14286 -4.84397,0 -6.73405,0.66471 -7.85715,2.76323 -3.17543,5.93335 -1.29958,24.0451 6.50874,62.84321 4.09103,20.32756 4.71571,25.60186 3.40658,28.76236 -1.37961,3.33069 -0.99108,5.08257 2.7871,12.56711 4.88516,9.67746 5.26479,12.5023 2.22083,16.5255 -1.86887,2.4701 -1.71126,3.22859 1.56293,7.52128 2.552,3.34584 3.50796,6.1568 3.19534,9.39572 -0.44228,4.58236 -0.52488,4.62926 -9.73178,5.52605 -9.91327,0.96557 -31.75079,1.11313 -40,0.27028 l 0,0 z m 14.58317,-79.10955 c 4.09153,-4.09154 4.30748,-4.83898 3.46619,-11.99708 -0.68245,-5.80657 -0.0911,-10.4166 2.47047,-19.26072 2.01547,-6.95848 2.73061,-11.41954 1.78106,-11.11027 -2.91204,0.94847 -6.87351,15.83246 -7.18045,26.97833 -0.33516,12.1705 -2.01198,15.46741 -7.86679,15.46741 -7.91857,0 -10.1324,-8.95678 -3.50277,-14.17164 2.90824,-2.28763 4.36222,-5.60044 6.47219,-14.74655 1.49672,-6.48785 3.06643,-12.9211 3.48824,-14.2961 0.42182,-1.375 0.13062,-2.5 -0.64711,-2.5 -1.64375,0 -3.63148,5.87974 -5.94898,17.5972 -1.21277,6.13187 -2.7359,9.2845 -5.80811,12.02186 -7.72817,6.88583 -4.0859,20.38094 5.50073,20.38094 1.89978,0 5.34578,-1.93383 7.77533,-4.36338 l 0,0 z m -7.56592,-113.34241 c 1.27646,-1.53805 1.12743,-2.51688 -0.65454,-4.29884 -2.66481,-2.66482 -4.93414,-1.81356 -4.93414,1.85085 0,4.54198 2.82416,5.77903 5.58868,2.44799 z m -6.30296,-8.00849 c 0.4856,-0.78572 2.45211,-1.42858 4.37002,-1.42858 1.91792,0 3.48712,0.64286 3.48712,1.42858 0,0.78571 0.9869,1.42857 2.19312,1.42857 1.75044,0 1.88447,-0.57672 0.66402,-2.85715 -1.89102,-3.5334 -10.17182,-3.9098 -13.46938,-0.61224 -1.2347,1.23469 -2.2449,2.52041 -2.2449,2.85714 0,1.24187 4.14635,0.56491 5,-0.81632 z"
+           id="path3236"
+           inkscape:connector-curvature="0" />
+        <path
+           style="fill:#e6e6e6;fill-opacity:1;stroke:none"
+           d="m 420.09725,428.14616 c -1.95597,-0.29631 -1.96428,-0.32194 -1.96428,-6.06107 0,-5.23023 -0.16523,-5.91663 -1.78572,-7.41845 -2.3226,-2.15252 -2.61383,-6.80597 -0.38953,-6.22431 1.05492,0.27587 1.51032,-0.0897 1.86315,-1.49544 0.36247,-1.4442 0.90959,-1.86055 2.44493,-1.86055 2.24315,0 3.17557,0.91175 3.85981,3.77429 0.27306,1.14235 1.24162,2.33772 2.27605,2.80903 1.55826,0.70999 1.77199,1.21161 1.58743,3.72571 -0.19822,2.70034 -0.35181,2.89075 -2.17755,2.69965 -1.73832,-0.18196 -1.96429,0.0325 -1.96429,1.86459 0,3.22425 -0.86015,8.70994 -1.34708,8.59113 -0.24125,-0.0589 -1.32256,-0.24092 -2.40292,-0.40458 z"
+           id="path3238"
+           inkscape:connector-curvature="0" />
+      </g>
+    </g>
+    <g
+       id="g3325"
+       transform="translate(-5.7142855,-17.142862)">
+      <text
+         sodipodi:linespacing="125%"
+         id="text3280"
+         y="982.56226"
+         x="166.98186"
+         style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
+         xml:space="preserve"><tspan
+           y="982.56226"
+           x="166.98186"
+           id="tspan3282"
+           sodipodi:role="line">UCC::Progcomp 2013</tspan></text>
+      <text
+         sodipodi:linespacing="125%"
+         id="text3284"
+         y="1022.0576"
+         x="173.74623"
+         style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
+         xml:space="preserve"><tspan
+           style="font-size:20px"
+           y="1022.0576"
+           x="173.74623"
+           id="tspan3286"
+           sodipodi:role="line">http://progcomp.ucc.asn.au/2013/web</tspan></text>
+    </g>
+    <text
+       xml:space="preserve"
+       style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
+       x="228.57143"
+       y="135.21933"
+       id="text3331"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3333"
+         x="228.57143"
+         y="135.21933" /></text>
+    <image
+       y="108.98257"
+       x="172.44629"
+       id="image3446"
+       xlink:href="data:image/png;base64,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
+A1vHTOVXO1uPAAAAAElFTkSuQmCC
+"
+       height="405.237"
+       width="408.4216" />
+    <text
+       xml:space="preserve"
+       style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
+       x="83.842667"
+       y="78.575134"
+       id="text3449"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3451"
+         x="83.842667"
+         y="78.575134"
+         style="font-size:18px">What is the probability that white will win in 3 moves?</tspan></text>
+  </g>
+</svg>

UCC git Repository :: git.ucc.asn.au