| @@ -1,72 +0,0 @@ | |||
| ''' | |||
| The MIT License (MIT) | |||
| Copyright (c) 2013 Dave P. | |||
| ''' | |||
| import signal | |||
| import sys | |||
| import ssl | |||
| from SimpleWebSocketServer import WebSocket, SimpleWebSocketServer, SimpleSSLWebSocketServer | |||
| from optparse import OptionParser | |||
| class SimpleEcho(WebSocket): | |||
| def handleMessage(self): | |||
| print self.data | |||
| self.sendMessage(self.data) | |||
| def handleConnected(self): | |||
| pass | |||
| def handleClose(self): | |||
| pass | |||
| clients = [] | |||
| class SimpleChat(WebSocket): | |||
| def handleMessage(self): | |||
| for client in clients: | |||
| if client != self: | |||
| client.sendMessage(self.address[0] + u' - ' + self.data) | |||
| def handleConnected(self): | |||
| print (self.address, 'connected') | |||
| for client in clients: | |||
| client.sendMessage(self.address[0] + u' - connected') | |||
| clients.append(self) | |||
| def handleClose(self): | |||
| clients.remove(self) | |||
| print (self.address, 'closed') | |||
| for client in clients: | |||
| client.sendMessage(self.address[0] + u' - disconnected') | |||
| if __name__ == "__main__": | |||
| parser = OptionParser(usage="usage: %prog [options]", version="%prog 1.0") | |||
| parser.add_option("--host", default='', type='string', action="store", dest="host", help="hostname (localhost)") | |||
| parser.add_option("--port", default=8000, type='int', action="store", dest="port", help="port (8000)") | |||
| parser.add_option("--example", default='echo', type='string', action="store", dest="example", help="echo, chat") | |||
| parser.add_option("--ssl", default=0, type='int', action="store", dest="ssl", help="ssl (1: on, 0: off (default))") | |||
| parser.add_option("--cert", default='./cert.pem', type='string', action="store", dest="cert", help="cert (./cert.pem)") | |||
| parser.add_option("--ver", default=ssl.PROTOCOL_TLSv1, type=int, action="store", dest="ver", help="ssl version") | |||
| (options, args) = parser.parse_args() | |||
| cls = SimpleEcho | |||
| if options.example == 'chat': | |||
| cls = SimpleChat | |||
| if options.ssl == 1: | |||
| server = SimpleSSLWebSocketServer(options.host, options.port, cls, options.cert, options.cert, version=options.ver) | |||
| else: | |||
| server = SimpleWebSocketServer(options.host, options.port, cls) | |||
| def close_sig_handler(signal, frame): | |||
| server.close() | |||
| sys.exit() | |||
| signal.signal(signal.SIGINT, close_sig_handler) | |||
| server.serveforever() | |||
| @@ -1,694 +0,0 @@ | |||
| ''' | |||
| The MIT License (MIT) | |||
| Copyright (c) 2013 Dave P. | |||
| ''' | |||
| import sys | |||
| VER = sys.version_info[0] | |||
| if VER >= 3: | |||
| import socketserver | |||
| from http.server import BaseHTTPRequestHandler | |||
| from io import StringIO, BytesIO | |||
| else: | |||
| import SocketServer | |||
| from BaseHTTPServer import BaseHTTPRequestHandler | |||
| from StringIO import StringIO | |||
| import hashlib | |||
| import base64 | |||
| import socket | |||
| import struct | |||
| import ssl | |||
| import errno | |||
| import codecs | |||
| from collections import deque | |||
| from select import select | |||
| __all__ = ['WebSocket', | |||
| 'SimpleWebSocketServer', | |||
| 'SimpleSSLWebSocketServer'] | |||
| def _check_unicode(val): | |||
| if VER >= 3: | |||
| return isinstance(val, str) | |||
| else: | |||
| return isinstance(val, unicode) | |||
| class HTTPRequest(BaseHTTPRequestHandler): | |||
| def __init__(self, request_text): | |||
| if VER >= 3: | |||
| self.rfile = BytesIO(request_text) | |||
| else: | |||
| self.rfile = StringIO(request_text) | |||
| self.raw_requestline = self.rfile.readline() | |||
| self.error_code = self.error_message = None | |||
| self.parse_request() | |||
| _VALID_STATUS_CODES = [1000, 1001, 1002, 1003, 1007, 1008, | |||
| 1009, 1010, 1011, 3000, 3999, 4000, 4999] | |||
| HANDSHAKE_STR = ( | |||
| "HTTP/1.1 101 Switching Protocols\r\n" | |||
| "Upgrade: WebSocket\r\n" | |||
| "Connection: Upgrade\r\n" | |||
| "Sec-WebSocket-Accept: %(acceptstr)s\r\n\r\n" | |||
| ) | |||
| GUID_STR = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' | |||
| STREAM = 0x0 | |||
| TEXT = 0x1 | |||
| BINARY = 0x2 | |||
| CLOSE = 0x8 | |||
| PING = 0x9 | |||
| PONG = 0xA | |||
| HEADERB1 = 1 | |||
| HEADERB2 = 3 | |||
| LENGTHSHORT = 4 | |||
| LENGTHLONG = 5 | |||
| MASK = 6 | |||
| PAYLOAD = 7 | |||
| MAXHEADER = 65536 | |||
| MAXPAYLOAD = 33554432 | |||
| class WebSocket(object): | |||
| def __init__(self, server, sock, address): | |||
| self.server = server | |||
| self.client = sock | |||
| self.address = address | |||
| self.handshaked = False | |||
| self.headerbuffer = bytearray() | |||
| self.headertoread = 2048 | |||
| self.fin = 0 | |||
| self.data = bytearray() | |||
| self.opcode = 0 | |||
| self.hasmask = 0 | |||
| self.maskarray = None | |||
| self.length = 0 | |||
| self.lengtharray = None | |||
| self.index = 0 | |||
| self.request = None | |||
| self.usingssl = False | |||
| self.frag_start = False | |||
| self.frag_type = BINARY | |||
| self.frag_buffer = None | |||
| self.frag_decoder = codecs.getincrementaldecoder('utf-8')(errors='strict') | |||
| self.closed = False | |||
| self.sendq = deque() | |||
| self.state = HEADERB1 | |||
| # restrict the size of header and payload for security reasons | |||
| self.maxheader = MAXHEADER | |||
| self.maxpayload = MAXPAYLOAD | |||
| def handleMessage(self): | |||
| """ | |||
| Called when websocket frame is received. | |||
| To access the frame data call self.data. | |||
| If the frame is Text then self.data is a unicode object. | |||
| If the frame is Binary then self.data is a bytearray object. | |||
| """ | |||
| pass | |||
| def handleConnected(self): | |||
| """ | |||
| Called when a websocket client connects to the server. | |||
| """ | |||
| pass | |||
| def handleClose(self): | |||
| """ | |||
| Called when a websocket server gets a Close frame from a client. | |||
| """ | |||
| pass | |||
| def _handlePacket(self): | |||
| if self.opcode == CLOSE: | |||
| pass | |||
| elif self.opcode == STREAM: | |||
| pass | |||
| elif self.opcode == TEXT: | |||
| pass | |||
| elif self.opcode == BINARY: | |||
| pass | |||
| elif self.opcode == PONG or self.opcode == PING: | |||
| if len(self.data) > 125: | |||
| raise Exception('control frame length can not be > 125') | |||
| else: | |||
| # unknown or reserved opcode so just close | |||
| raise Exception('unknown opcode') | |||
| if self.opcode == CLOSE: | |||
| status = 1000 | |||
| reason = u'' | |||
| length = len(self.data) | |||
| if length == 0: | |||
| pass | |||
| elif length >= 2: | |||
| status = struct.unpack_from('!H', self.data[:2])[0] | |||
| reason = self.data[2:] | |||
| if status not in _VALID_STATUS_CODES: | |||
| status = 1002 | |||
| if len(reason) > 0: | |||
| try: | |||
| reason = reason.decode('utf8', errors='strict') | |||
| except: | |||
| status = 1002 | |||
| else: | |||
| status = 1002 | |||
| self.close(status, reason) | |||
| return | |||
| elif self.fin == 0: | |||
| if self.opcode != STREAM: | |||
| if self.opcode == PING or self.opcode == PONG: | |||
| raise Exception('control messages can not be fragmented') | |||
| self.frag_type = self.opcode | |||
| self.frag_start = True | |||
| self.frag_decoder.reset() | |||
| if self.frag_type == TEXT: | |||
| self.frag_buffer = [] | |||
| utf_str = self.frag_decoder.decode(self.data, final = False) | |||
| if utf_str: | |||
| self.frag_buffer.append(utf_str) | |||
| else: | |||
| self.frag_buffer = bytearray() | |||
| self.frag_buffer.extend(self.data) | |||
| else: | |||
| if self.frag_start is False: | |||
| raise Exception('fragmentation protocol error') | |||
| if self.frag_type == TEXT: | |||
| utf_str = self.frag_decoder.decode(self.data, final = False) | |||
| if utf_str: | |||
| self.frag_buffer.append(utf_str) | |||
| else: | |||
| self.frag_buffer.extend(self.data) | |||
| else: | |||
| if self.opcode == STREAM: | |||
| if self.frag_start is False: | |||
| raise Exception('fragmentation protocol error') | |||
| if self.frag_type == TEXT: | |||
| utf_str = self.frag_decoder.decode(self.data, final = True) | |||
| self.frag_buffer.append(utf_str) | |||
| self.data = u''.join(self.frag_buffer) | |||
| else: | |||
| self.frag_buffer.extend(self.data) | |||
| self.data = self.frag_buffer | |||
| self.handleMessage() | |||
| self.frag_decoder.reset() | |||
| self.frag_type = BINARY | |||
| self.frag_start = False | |||
| self.frag_buffer = None | |||
| elif self.opcode == PING: | |||
| self._sendMessage(False, PONG, self.data) | |||
| elif self.opcode == PONG: | |||
| pass | |||
| else: | |||
| if self.frag_start is True: | |||
| raise Exception('fragmentation protocol error') | |||
| if self.opcode == TEXT: | |||
| try: | |||
| self.data = self.data.decode('utf8', errors='strict') | |||
| except Exception as exp: | |||
| raise Exception('invalid utf-8 payload') | |||
| self.handleMessage() | |||
| def _handleData(self): | |||
| # do the HTTP header and handshake | |||
| if self.handshaked is False: | |||
| data = self.client.recv(self.headertoread) | |||
| if not data: | |||
| raise Exception('remote socket closed') | |||
| else: | |||
| # accumulate | |||
| self.headerbuffer.extend(data) | |||
| if len(self.headerbuffer) >= self.maxheader: | |||
| raise Exception('header exceeded allowable size') | |||
| # indicates end of HTTP header | |||
| if b'\r\n\r\n' in self.headerbuffer: | |||
| self.request = HTTPRequest(self.headerbuffer) | |||
| # handshake rfc 6455 | |||
| try: | |||
| key = self.request.headers['Sec-WebSocket-Key'] | |||
| k = key.encode('ascii') + GUID_STR.encode('ascii') | |||
| k_s = base64.b64encode(hashlib.sha1(k).digest()).decode('ascii') | |||
| hStr = HANDSHAKE_STR % {'acceptstr': k_s} | |||
| self.sendq.append((BINARY, hStr.encode('ascii'))) | |||
| self.handshaked = True | |||
| self.handleConnected() | |||
| except Exception as e: | |||
| raise Exception('handshake failed: %s', str(e)) | |||
| # else do normal data | |||
| else: | |||
| data = self.client.recv(8192) | |||
| if not data: | |||
| raise Exception("remote socket closed") | |||
| if VER >= 3: | |||
| for d in data: | |||
| self._parseMessage(d) | |||
| else: | |||
| for d in data: | |||
| self._parseMessage(ord(d)) | |||
| def close(self, status = 1000, reason = u''): | |||
| """ | |||
| Send Close frame to the client. The underlying socket is only closed | |||
| when the client acknowledges the Close frame. | |||
| status is the closing identifier. | |||
| reason is the reason for the close. | |||
| """ | |||
| try: | |||
| if self.closed is False: | |||
| close_msg = bytearray() | |||
| close_msg.extend(struct.pack("!H", status)) | |||
| if _check_unicode(reason): | |||
| close_msg.extend(reason.encode('utf-8')) | |||
| else: | |||
| close_msg.extend(reason) | |||
| self._sendMessage(False, CLOSE, close_msg) | |||
| finally: | |||
| self.closed = True | |||
| def _sendBuffer(self, buff): | |||
| size = len(buff) | |||
| tosend = size | |||
| already_sent = 0 | |||
| while tosend > 0: | |||
| try: | |||
| # i should be able to send a bytearray | |||
| sent = self.client.send(buff[already_sent:]) | |||
| if sent == 0: | |||
| raise RuntimeError('socket connection broken') | |||
| already_sent += sent | |||
| tosend -= sent | |||
| except socket.error as e: | |||
| # if we have full buffers then wait for them to drain and try again | |||
| if e.errno in [errno.EAGAIN, errno.EWOULDBLOCK]: | |||
| return buff[already_sent:] | |||
| else: | |||
| raise e | |||
| return None | |||
| def sendFragmentStart(self, data): | |||
| """ | |||
| Send the start of a data fragment stream to a websocket client. | |||
| Subsequent data should be sent using sendFragment(). | |||
| A fragment stream is completed when sendFragmentEnd() is called. | |||
| If data is a unicode object then the frame is sent as Text. | |||
| If the data is a bytearray object then the frame is sent as Binary. | |||
| """ | |||
| opcode = BINARY | |||
| if _check_unicode(data): | |||
| opcode = TEXT | |||
| self._sendMessage(True, opcode, data) | |||
| def sendFragment(self, data): | |||
| """ | |||
| see sendFragmentStart() | |||
| If data is a unicode object then the frame is sent as Text. | |||
| If the data is a bytearray object then the frame is sent as Binary. | |||
| """ | |||
| self._sendMessage(True, STREAM, data) | |||
| def sendFragmentEnd(self, data): | |||
| """ | |||
| see sendFragmentEnd() | |||
| If data is a unicode object then the frame is sent as Text. | |||
| If the data is a bytearray object then the frame is sent as Binary. | |||
| """ | |||
| self._sendMessage(False, STREAM, data) | |||
| def sendMessage(self, data): | |||
| """ | |||
| Send websocket data frame to the client. | |||
| If data is a unicode object then the frame is sent as Text. | |||
| If the data is a bytearray object then the frame is sent as Binary. | |||
| """ | |||
| opcode = BINARY | |||
| if _check_unicode(data): | |||
| opcode = TEXT | |||
| self._sendMessage(False, opcode, data) | |||
| def _sendMessage(self, fin, opcode, data): | |||
| payload = bytearray() | |||
| b1 = 0 | |||
| b2 = 0 | |||
| if fin is False: | |||
| b1 |= 0x80 | |||
| b1 |= opcode | |||
| if _check_unicode(data): | |||
| data = data.encode('utf-8') | |||
| length = len(data) | |||
| payload.append(b1) | |||
| if length <= 125: | |||
| b2 |= length | |||
| payload.append(b2) | |||
| elif length >= 126 and length <= 65535: | |||
| b2 |= 126 | |||
| payload.append(b2) | |||
| payload.extend(struct.pack("!H", length)) | |||
| else: | |||
| b2 |= 127 | |||
| payload.append(b2) | |||
| payload.extend(struct.pack("!Q", length)) | |||
| if length > 0: | |||
| payload.extend(data) | |||
| self.sendq.append((opcode, payload)) | |||
| def _parseMessage(self, byte): | |||
| # read in the header | |||
| if self.state == HEADERB1: | |||
| self.fin = byte & 0x80 | |||
| self.opcode = byte & 0x0F | |||
| self.state = HEADERB2 | |||
| self.index = 0 | |||
| self.length = 0 | |||
| self.lengtharray = bytearray() | |||
| self.data = bytearray() | |||
| rsv = byte & 0x70 | |||
| if rsv != 0: | |||
| raise Exception('RSV bit must be 0') | |||
| elif self.state == HEADERB2: | |||
| mask = byte & 0x80 | |||
| length = byte & 0x7F | |||
| if self.opcode == PING and length > 125: | |||
| raise Exception('ping packet is too large') | |||
| if mask == 128: | |||
| self.hasmask = True | |||
| else: | |||
| self.hasmask = False | |||
| if length <= 125: | |||
| self.length = length | |||
| # if we have a mask we must read it | |||
| if self.hasmask is True: | |||
| self.maskarray = bytearray() | |||
| self.state = MASK | |||
| else: | |||
| # if there is no mask and no payload we are done | |||
| if self.length <= 0: | |||
| try: | |||
| self._handlePacket() | |||
| finally: | |||
| self.state = self.HEADERB1 | |||
| self.data = bytearray() | |||
| # we have no mask and some payload | |||
| else: | |||
| #self.index = 0 | |||
| self.data = bytearray() | |||
| self.state = PAYLOAD | |||
| elif length == 126: | |||
| self.lengtharray = bytearray() | |||
| self.state = LENGTHSHORT | |||
| elif length == 127: | |||
| self.lengtharray = bytearray() | |||
| self.state = LENGTHLONG | |||
| elif self.state == LENGTHSHORT: | |||
| self.lengtharray.append(byte) | |||
| if len(self.lengtharray) > 2: | |||
| raise Exception('short length exceeded allowable size') | |||
| if len(self.lengtharray) == 2: | |||
| self.length = struct.unpack_from('!H', self.lengtharray)[0] | |||
| if self.hasmask is True: | |||
| self.maskarray = bytearray() | |||
| self.state = MASK | |||
| else: | |||
| # if there is no mask and no payload we are done | |||
| if self.length <= 0: | |||
| try: | |||
| self._handlePacket() | |||
| finally: | |||
| self.state = HEADERB1 | |||
| self.data = bytearray() | |||
| # we have no mask and some payload | |||
| else: | |||
| #self.index = 0 | |||
| self.data = bytearray() | |||
| self.state = PAYLOAD | |||
| elif self.state == LENGTHLONG: | |||
| self.lengtharray.append(byte) | |||
| if len(self.lengtharray) > 8: | |||
| raise Exception('long length exceeded allowable size') | |||
| if len(self.lengtharray) == 8: | |||
| self.length = struct.unpack_from('!Q', self.lengtharray)[0] | |||
| if self.hasmask is True: | |||
| self.maskarray = bytearray() | |||
| self.state = MASK | |||
| else: | |||
| # if there is no mask and no payload we are done | |||
| if self.length <= 0: | |||
| try: | |||
| self._handlePacket() | |||
| finally: | |||
| self.state = HEADERB1 | |||
| self.data = bytearray() | |||
| # we have no mask and some payload | |||
| else: | |||
| #self.index = 0 | |||
| self.data = bytearray() | |||
| self.state = PAYLOAD | |||
| # MASK STATE | |||
| elif self.state == MASK: | |||
| self.maskarray.append(byte) | |||
| if len(self.maskarray) > 4: | |||
| raise Exception('mask exceeded allowable size') | |||
| if len(self.maskarray) == 4: | |||
| # if there is no mask and no payload we are done | |||
| if self.length <= 0: | |||
| try: | |||
| self._handlePacket() | |||
| finally: | |||
| self.state = HEADERB1 | |||
| self.data = bytearray() | |||
| # we have no mask and some payload | |||
| else: | |||
| #self.index = 0 | |||
| self.data = bytearray() | |||
| self.state = PAYLOAD | |||
| # PAYLOAD STATE | |||
| elif self.state == PAYLOAD: | |||
| if self.hasmask is True: | |||
| self.data.append( byte ^ self.maskarray[self.index % 4] ) | |||
| else: | |||
| self.data.append( byte ) | |||
| # if length exceeds allowable size then we except and remove the connection | |||
| if len(self.data) >= self.maxpayload: | |||
| raise Exception('payload exceeded allowable size') | |||
| # check if we have processed length bytes; if so we are done | |||
| if (self.index+1) == self.length: | |||
| try: | |||
| self._handlePacket() | |||
| finally: | |||
| #self.index = 0 | |||
| self.state = HEADERB1 | |||
| self.data = bytearray() | |||
| else: | |||
| self.index += 1 | |||
| class SimpleWebSocketServer(object): | |||
| def __init__(self, host, port, websocketclass, selectInterval = 0.1): | |||
| self.websocketclass = websocketclass | |||
| self.serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |||
| self.serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |||
| self.serversocket.bind((host, port)) | |||
| self.serversocket.listen(5) | |||
| self.selectInterval = selectInterval | |||
| self.connections = {} | |||
| self.listeners = [self.serversocket] | |||
| def _decorateSocket(self, sock): | |||
| return sock | |||
| def _constructWebSocket(self, sock, address): | |||
| return self.websocketclass(self, sock, address) | |||
| def close(self): | |||
| self.serversocket.close() | |||
| for desc, conn in self.connections.items(): | |||
| conn.close() | |||
| conn.handleClose() | |||
| def serveforever(self): | |||
| while True: | |||
| writers = [] | |||
| for fileno in self.listeners: | |||
| if fileno == self.serversocket: | |||
| continue | |||
| client = self.connections[fileno] | |||
| if client.sendq: | |||
| writers.append(fileno) | |||
| if self.selectInterval: | |||
| rList, wList, xList = select(self.listeners, writers, self.listeners, self.selectInterval) | |||
| else: | |||
| rList, wList, xList = select(self.listeners, writers, self.listeners) | |||
| for ready in wList: | |||
| client = self.connections[ready] | |||
| try: | |||
| while client.sendq: | |||
| opcode, payload = client.sendq.popleft() | |||
| remaining = client._sendBuffer(payload) | |||
| if remaining is not None: | |||
| client.sendq.appendleft((opcode, remaining)) | |||
| break | |||
| else: | |||
| if opcode == CLOSE: | |||
| raise Exception('received client close') | |||
| except Exception as n: | |||
| client.client.close() | |||
| client.handleClose() | |||
| del self.connections[ready] | |||
| self.listeners.remove(ready) | |||
| for ready in rList: | |||
| if ready == self.serversocket: | |||
| try: | |||
| sock, address = self.serversocket.accept() | |||
| newsock = self._decorateSocket(sock) | |||
| newsock.setblocking(0) | |||
| fileno = newsock.fileno() | |||
| self.connections[fileno] = self._constructWebSocket(newsock, address) | |||
| self.listeners.append(fileno) | |||
| except Exception as n: | |||
| if sock is not None: | |||
| sock.close() | |||
| else: | |||
| if ready not in self.connections: | |||
| continue | |||
| client = self.connections[ready] | |||
| try: | |||
| client._handleData() | |||
| except Exception as n: | |||
| client.client.close() | |||
| client.handleClose() | |||
| del self.connections[ready] | |||
| self.listeners.remove(ready) | |||
| for failed in xList: | |||
| if failed == self.serversocket: | |||
| self.close() | |||
| raise Exception('server socket failed') | |||
| else: | |||
| if failed not in self.connections: | |||
| continue | |||
| client = self.connections[failed] | |||
| client.client.close() | |||
| client.handleClose() | |||
| del self.connections[failed] | |||
| self.listeners.remove(failed) | |||
| class SimpleSSLWebSocketServer(SimpleWebSocketServer): | |||
| def __init__(self, host, port, websocketclass, certfile, | |||
| keyfile, version = ssl.PROTOCOL_TLSv1, selectInterval = 0.1): | |||
| SimpleWebSocketServer.__init__(self, host, port, | |||
| websocketclass, selectInterval) | |||
| self.context = ssl.SSLContext(version) | |||
| self.context.load_cert_chain(certfile, keyfile) | |||
| def close(self): | |||
| super(SimpleSSLWebSocketServer, self).close() | |||
| def _decorateSocket(self, sock): | |||
| sslsock = self.context.wrap_socket(sock, server_side=True) | |||
| return sslsock | |||
| def _constructWebSocket(self, sock, address): | |||
| ws = self.websocketclass(self, sock, address) | |||
| ws.usingssl = True | |||
| return ws | |||
| def serveforever(self): | |||
| super(SimpleSSLWebSocketServer, self).serveforever() | |||
| @@ -0,0 +1,199 @@ | |||
| """ | |||
| Copied from Anders' original C++ implementation | |||
| S. Anders, H. J. Briegel: Fast Simulation of Stabilizer Circuits using a Graph State Formalism quant-ph/0504117 | |||
| """ | |||
| import numpy as np | |||
| cz_table = ((((1, 0, 0), (1, 0, 0), (1, 0, 3), (1, 0, 3), (1, 0, 5), (1, 0, 5), | |||
| (1, 0, 6), (1, 0, 6), (0, 3, 8), (0, 3, 8), (0, 0, 10), (0, 0, 10), | |||
| (1, 0, 3), (1, 0, 3), (1, 0, 0), (1, 0, 0), (1, 0, 6), (1, 0, 6), | |||
| (1, 0, 5), (1, 0, 5), (0, 0, 10), (0, 0, 10), (0, 3, 8), (0, 3, 8)), | |||
| ((1, 0, 0), (1, 0, 0), (1, 0, 3), (1, 0, 3), (1, 0, 5), (1, 0, 5), | |||
| (1, 0, 6), (1, 0, 6), (0, 2, 8), (0, 2, 8), (0, 0, 10), (0, 0, 10), | |||
| (1, 0, 3), (1, 0, 3), (1, 0, 0), (1, 0, 0), (1, 0, 6), (1, 0, 6), | |||
| (1, 0, 5), (1, 0, 5), (0, 0, 10), (0, 0, 10), (0, 2, 8), (0, 2, 8)), | |||
| ((1, 2, 3), (1, 0, 1), (1, 0, 2), (1, 2, 0), (1, 0, 4), (1, 2, 6), | |||
| (1, 2, 5), (1, 0, 7), (0, 0, 8), (0, 0, 8), (0, 2, 10), (0, 2, 10), | |||
| (1, 0, 2), (1, 0, 2), (1, 0, 1), (1, 0, 1), (1, 0, 7), (1, 0, 7), | |||
| (1, 0, 4), (1, 0, 4), (0, 2, 10), (0, 2, 10), (0, 0, 8), (0, 0, 8)), | |||
| ((1, 3, 0), (1, 0, 1), (1, 0, 2), (1, 3, 3), (1, 0, 4), (1, 3, 5), | |||
| (1, 3, 6), (1, 0, 7), (0, 0, 8), (0, 0, 8), (0, 3, 10), (0, 3, 10), | |||
| (1, 0, 2), (1, 0, 2), (1, 0, 1), (1, 0, 1), (1, 0, 7), (1, 0, 7), | |||
| (1, 0, 4), (1, 0, 4), (0, 3, 10), (0, 3, 10), (0, 0, 8), (0, 0, 8)), | |||
| ((1, 4, 3), (1, 4, 3), (1, 4, 0), (1, 4, 0), (1, 4, 6), (1, 4, 6), | |||
| (1, 4, 5), (1, 4, 5), (0, 6, 8), (0, 6, 8), (0, 4, 10), (0, 4, 10), | |||
| (1, 4, 0), (1, 4, 0), (1, 4, 3), (1, 4, 3), (1, 4, 5), (1, 4, 5), | |||
| (1, 4, 6), (1, 4, 6), (0, 4, 10), (0, 4, 10), (0, 6, 8), (0, 6, 8)), | |||
| ((1, 5, 0), (1, 5, 0), (1, 5, 3), (1, 5, 3), (1, 5, 5), (1, 5, 5), | |||
| (1, 5, 6), (1, 5, 6), (0, 6, 8), (0, 6, 8), (0, 5, 10), (0, 5, 10), | |||
| (1, 5, 3), (1, 5, 3), (1, 5, 0), (1, 5, 0), (1, 5, 6), (1, 5, 6), | |||
| (1, 5, 5), (1, 5, 5), (0, 5, 10), (0, 5, 10), (0, 6, 8), (0, 6, 8)), | |||
| ((1, 6, 0), (1, 5, 1), (1, 5, 2), (1, 6, 3), (1, 5, 4), (1, 6, 5), | |||
| (1, 6, 6), (1, 5, 7), (0, 5, 8), (0, 5, 8), (0, 6, 10), (0, 6, 10), | |||
| (1, 5, 2), (1, 5, 2), (1, 5, 1), (1, 5, 1), (1, 5, 7), (1, 5, 7), | |||
| (1, 5, 4), (1, 5, 4), (0, 6, 10), (0, 6, 10), (0, 5, 8), (0, 5, 8)), | |||
| ((1, 6, 0), (1, 4, 2), (1, 4, 1), (1, 6, 3), (1, 4, 7), (1, 6, 5), | |||
| (1, 6, 6), (1, 4, 4), (0, 4, 8), (0, 4, 8), (0, 6, 10), (0, 6, 10), | |||
| (1, 4, 1), (1, 4, 1), (1, 4, 2), (1, 4, 2), (1, 4, 4), (1, 4, 4), | |||
| (1, 4, 7), (1, 4, 7), (0, 6, 10), (0, 6, 10), (0, 4, 8), (0, 4, 8)), | |||
| ((0, 8, 3), (0, 8, 2), (0, 8, 0), (0, 8, 0), (0, 8, 6), (0, 8, 6), | |||
| (0, 8, 5), (0, 8, 4), (0, 8, 8), (0, 8, 8), (0, 8, 10), (0, 8, 10), | |||
| (0, 8, 0), (0, 8, 0), (0, 8, 2), (0, 8, 2), (0, 8, 4), (0, 8, 4), | |||
| (0, 8, 6), (0, 8, 6), (0, 8, 10), (0, 8, 10), (0, 8, 8), (0, 8, 8)), | |||
| ((0, 8, 3), (0, 8, 2), (0, 8, 0), (0, 8, 0), (0, 8, 6), (0, 8, 6), | |||
| (0, 8, 5), (0, 8, 4), (0, 8, 8), (0, 8, 8), (0, 8, 10), (0, 8, 10), | |||
| (0, 8, 0), (0, 8, 0), (0, 8, 2), (0, 8, 2), (0, 8, 4), (0, 8, 4), | |||
| (0, 8, 6), (0, 8, 6), (0, 8, 10), (0, 8, 10), (0, 8, 8), (0, 8, 8)), | |||
| ((0, 10, 0), (0, 10, 0), (0, 10, 2), (0, 10, 3), (0, 10, 4), (0, 10, 5), | |||
| (0, 10, 6), (0, 10, 6), (0, 10, 8), (0, 10, 8), (0, 10, 10), (0, 10, 10), | |||
| (0, 10, 2), (0, 10, 2), (0, 10, 0), (0, 10, 0), (0, 10, 6), (0, 10, 6), | |||
| (0, 10, 4), (0, 10, 4), (0, 10, 10), (0, 10, 10), (0, 10, 8), (0, 10, 8)), | |||
| ((0, 10, 0), (0, 10, 0), (0, 10, 2), (0, 10, 3), (0, 10, 4), (0, 10, 5), | |||
| (0, 10, 6), (0, 10, 6), (0, 10, 8), (0, 10, 8), (0, 10, 10), (0, 10, 10), | |||
| (0, 10, 2), (0, 10, 2), (0, 10, 0), (0, 10, 0), (0, 10, 6), (0, 10, 6), | |||
| (0, 10, 4), (0, 10, 4), (0, 10, 10), (0, 10, 10), (0, 10, 8), (0, 10, 8)), | |||
| ((1, 2, 3), (1, 0, 1), (1, 0, 2), (1, 2, 0), (1, 0, 4), (1, 2, 6), | |||
| (1, 2, 5), (1, 0, 7), (0, 0, 8), (0, 0, 8), (0, 2, 10), (0, 2, 10), | |||
| (1, 0, 2), (1, 0, 2), (1, 0, 1), (1, 0, 1), (1, 0, 7), (1, 0, 7), | |||
| (1, 0, 4), (1, 0, 4), (0, 2, 10), (0, 2, 10), (0, 0, 8), (0, 0, 8)), | |||
| ((1, 2, 3), (1, 0, 1), (1, 0, 2), (1, 2, 0), (1, 0, 4), (1, 2, 6), | |||
| (1, 2, 5), (1, 0, 7), (0, 0, 8), (0, 0, 8), (0, 2, 10), (0, 2, 10), | |||
| (1, 0, 2), (1, 0, 2), (1, 0, 1), (1, 0, 1), (1, 0, 7), (1, 0, 7), | |||
| (1, 0, 4), (1, 0, 4), (0, 2, 10), (0, 2, 10), (0, 0, 8), (0, 0, 8)), | |||
| ((1, 0, 0), (1, 0, 0), (1, 0, 3), (1, 0, 3), (1, 0, 5), (1, 0, 5), | |||
| (1, 0, 6), (1, 0, 6), (0, 2, 8), (0, 2, 8), (0, 0, 10), (0, 0, 10), | |||
| (1, 0, 3), (1, 0, 3), (1, 0, 0), (1, 0, 0), (1, 0, 6), (1, 0, 6), | |||
| (1, 0, 5), (1, 0, 5), (0, 0, 10), (0, 0, 10), (0, 2, 8), (0, 2, 8)), | |||
| ((1, 0, 0), (1, 0, 0), (1, 0, 3), (1, 0, 3), (1, 0, 5), (1, 0, 5), | |||
| (1, 0, 6), (1, 0, 6), (0, 2, 8), (0, 2, 8), (0, 0, 10), (0, 0, 10), | |||
| (1, 0, 3), (1, 0, 3), (1, 0, 0), (1, 0, 0), (1, 0, 6), (1, 0, 6), | |||
| (1, 0, 5), (1, 0, 5), (0, 0, 10), (0, 0, 10), (0, 2, 8), (0, 2, 8)), | |||
| ((1, 6, 0), (1, 4, 2), (1, 4, 1), (1, 6, 3), (1, 4, 7), (1, 6, 5), | |||
| (1, 6, 6), (1, 4, 4), (0, 4, 8), (0, 4, 8), (0, 6, 10), (0, 6, 10), | |||
| (1, 4, 1), (1, 4, 1), (1, 4, 2), (1, 4, 2), (1, 4, 4), (1, 4, 4), | |||
| (1, 4, 7), (1, 4, 7), (0, 6, 10), (0, 6, 10), (0, 4, 8), (0, 4, 8)), | |||
| ((1, 6, 0), (1, 4, 2), (1, 4, 1), (1, 6, 3), (1, 4, 7), (1, 6, 5), | |||
| (1, 6, 6), (1, 4, 4), (0, 4, 8), (0, 4, 8), (0, 6, 10), (0, 6, 10), | |||
| (1, 4, 1), (1, 4, 1), (1, 4, 2), (1, 4, 2), (1, 4, 4), (1, 4, 4), | |||
| (1, 4, 7), (1, 4, 7), (0, 6, 10), (0, 6, 10), (0, 4, 8), (0, 4, 8)), | |||
| ((1, 4, 3), (1, 4, 3), (1, 4, 0), (1, 4, 0), (1, 4, 6), (1, 4, 6), | |||
| (1, 4, 5), (1, 4, 5), (0, 6, 8), (0, 6, 8), (0, 4, 10), (0, 4, 10), | |||
| (1, 4, 0), (1, 4, 0), (1, 4, 3), (1, 4, 3), (1, 4, 5), (1, 4, 5), | |||
| (1, 4, 6), (1, 4, 6), (0, 4, 10), (0, 4, 10), (0, 6, 8), (0, 6, 8)), | |||
| ((1, 4, 3), (1, 4, 3), (1, 4, 0), (1, 4, 0), (1, 4, 6), (1, 4, 6), | |||
| (1, 4, 5), (1, 4, 5), (0, 6, 8), (0, 6, 8), (0, 4, 10), (0, 4, 10), | |||
| (1, 4, 0), (1, 4, 0), (1, 4, 3), (1, 4, 3), (1, 4, 5), (1, 4, 5), | |||
| (1, 4, 6), (1, 4, 6), (0, 4, 10), (0, 4, 10), (0, 6, 8), (0, 6, 8)), | |||
| ((0, 10, 0), (0, 10, 0), (0, 10, 2), (0, 10, 3), (0, 10, 4), (0, 10, 5), | |||
| (0, 10, 6), (0, 10, 6), (0, 10, 8), (0, 10, 8), (0, 10, 10), (0, 10, 10), | |||
| (0, 10, 2), (0, 10, 2), (0, 10, 0), (0, 10, 0), (0, 10, 6), (0, 10, 6), | |||
| (0, 10, 4), (0, 10, 4), (0, 10, 10), (0, 10, 10), (0, 10, 8), (0, 10, 8)), | |||
| ((0, 10, 0), (0, 10, 0), (0, 10, 2), (0, 10, 3), (0, 10, 4), (0, 10, 5), | |||
| (0, 10, 6), (0, 10, 6), (0, 10, 8), (0, 10, 8), (0, 10, 10), (0, 10, 10), | |||
| (0, 10, 2), (0, 10, 2), (0, 10, 0), (0, 10, 0), (0, 10, 6), (0, 10, 6), | |||
| (0, 10, 4), (0, 10, 4), (0, 10, 10), (0, 10, 10), (0, 10, 8), (0, 10, 8)), | |||
| ((0, 8, 3), (0, 8, 2), (0, 8, 0), (0, 8, 0), (0, 8, 6), (0, 8, 6), | |||
| (0, 8, 5), (0, 8, 4), (0, 8, 8), (0, 8, 8), (0, 8, 10), (0, 8, 10), | |||
| (0, 8, 0), (0, 8, 0), (0, 8, 2), (0, 8, 2), (0, 8, 4), (0, 8, 4), | |||
| (0, 8, 6), (0, 8, 6), (0, 8, 10), (0, 8, 10), (0, 8, 8), (0, 8, 8)), | |||
| ((0, 8, 3), (0, 8, 2), (0, 8, 0), (0, 8, 0), (0, 8, 6), (0, 8, 6), | |||
| (0, 8, 5), (0, 8, 4), (0, 8, 8), (0, 8, 8), (0, 8, 10), (0, 8, 10), | |||
| (0, 8, 0), (0, 8, 0), (0, 8, 2), (0, 8, 2), (0, 8, 4), (0, 8, 4), | |||
| (0, 8, 6), (0, 8, 6), (0, 8, 10), (0, 8, 10), (0, 8, 8), (0, 8, 8))), | |||
| (((0, 0, 0), (0, 3, 0), (0, 3, 2), (0, 0, 3), (0, 3, 4), (0, 0, 5), | |||
| (0, 0, 6), (0, 3, 6), (1, 5, 23), (1, 5, 22), (1, 5, 21), (1, 5, 20), | |||
| (0, 5, 2), (0, 6, 2), (0, 5, 0), (0, 6, 0), (0, 6, 6), (0, 5, 6), | |||
| (0, 6, 4), (0, 5, 4), (1, 5, 10), (1, 5, 11), (1, 5, 8), (1, 5, 9)), | |||
| ((0, 0, 3), (0, 2, 2), (0, 2, 0), (0, 0, 0), (0, 2, 6), (0, 0, 6), | |||
| (0, 0, 5), (0, 2, 4), (1, 4, 23), (1, 4, 22), (1, 4, 21), (1, 4, 20), | |||
| (0, 6, 0), (0, 4, 0), (0, 6, 2), (0, 4, 2), (0, 4, 4), (0, 6, 4), | |||
| (0, 4, 6), (0, 6, 6), (1, 4, 10), (1, 4, 11), (1, 4, 8), (1, 4, 9)), | |||
| ((0, 2, 3), (0, 0, 2), (0, 0, 0), (0, 2, 0), (0, 0, 6), (0, 2, 6), | |||
| (0, 2, 5), (0, 0, 4), (1, 4, 22), (1, 4, 23), (1, 4, 20), (1, 4, 21), | |||
| (0, 4, 0), (0, 6, 0), (0, 4, 2), (0, 6, 2), (0, 6, 4), (0, 4, 4), | |||
| (0, 6, 6), (0, 4, 6), (1, 4, 11), (1, 4, 10), (1, 4, 9), (1, 4, 8)), | |||
| ((0, 3, 0), (0, 0, 0), (0, 0, 2), (0, 3, 3), (0, 0, 4), (0, 3, 5), | |||
| (0, 3, 6), (0, 0, 6), (1, 5, 22), (1, 5, 23), (1, 5, 20), (1, 5, 21), | |||
| (0, 6, 2), (0, 5, 2), (0, 6, 0), (0, 5, 0), (0, 5, 6), (0, 6, 6), | |||
| (0, 5, 4), (0, 6, 4), (1, 5, 11), (1, 5, 10), (1, 5, 9), (1, 5, 8)), | |||
| ((0, 4, 3), (0, 6, 2), (0, 6, 0), (0, 4, 0), (0, 6, 6), (0, 4, 6), | |||
| (0, 4, 5), (0, 6, 4), (1, 0, 21), (1, 0, 20), (1, 0, 23), (1, 0, 22), | |||
| (0, 0, 0), (0, 2, 0), (0, 0, 2), (0, 2, 2), (0, 2, 4), (0, 0, 4), | |||
| (0, 2, 6), (0, 0, 6), (1, 0, 8), (1, 0, 9), (1, 0, 10), (1, 0, 11)), | |||
| ((0, 5, 0), (0, 6, 0), (0, 6, 2), (0, 5, 3), (0, 6, 4), (0, 5, 5), | |||
| (0, 5, 6), (0, 6, 6), (1, 0, 22), (1, 0, 23), (1, 0, 20), (1, 0, 21), | |||
| (0, 3, 2), (0, 0, 2), (0, 3, 0), (0, 0, 0), (0, 0, 6), (0, 3, 6), | |||
| (0, 0, 4), (0, 3, 4), (1, 0, 11), (1, 0, 10), (1, 0, 9), (1, 0, 8)), | |||
| ((0, 6, 0), (0, 5, 0), (0, 5, 2), (0, 6, 3), (0, 5, 4), (0, 6, 5), | |||
| (0, 6, 6), (0, 5, 6), (1, 0, 23), (1, 0, 22), (1, 0, 21), (1, 0, 20), | |||
| (0, 0, 2), (0, 3, 2), (0, 0, 0), (0, 3, 0), (0, 3, 6), (0, 0, 6), | |||
| (0, 3, 4), (0, 0, 4), (1, 0, 10), (1, 0, 11), (1, 0, 8), (1, 0, 9)), | |||
| ((0, 6, 3), (0, 4, 2), (0, 4, 0), (0, 6, 0), (0, 4, 6), (0, 6, 6), | |||
| (0, 6, 5), (0, 4, 4), (1, 0, 20), (1, 0, 21), (1, 0, 22), (1, 0, 23), | |||
| (0, 2, 0), (0, 0, 0), (0, 2, 2), (0, 0, 2), (0, 0, 4), (0, 2, 4), | |||
| (0, 0, 6), (0, 2, 6), (1, 0, 9), (1, 0, 8), (1, 0, 11), (1, 0, 10)), | |||
| ((1, 22, 6), (1, 20, 5), (1, 20, 6), (1, 22, 5), (1, 20, 3), (1, 22, 0), | |||
| (1, 22, 3), (1, 20, 0), (0, 0, 0), (0, 0, 2), (0, 2, 2), (0, 2, 0), | |||
| (0, 6, 6), (0, 4, 4), (0, 6, 4), (0, 4, 6), (0, 4, 2), (0, 6, 0), | |||
| (0, 4, 0), (0, 6, 2), (0, 2, 4), (0, 2, 6), (0, 0, 6), (0, 0, 4)), | |||
| ((1, 22, 5), (1, 20, 6), (1, 20, 5), (1, 22, 6), (1, 20, 0), (1, 22, 3), | |||
| (1, 22, 0), (1, 20, 3), (0, 2, 0), (0, 2, 2), (0, 0, 2), (0, 0, 0), | |||
| (0, 4, 6), (0, 6, 4), (0, 4, 4), (0, 6, 6), (0, 6, 2), (0, 4, 0), | |||
| (0, 6, 0), (0, 4, 2), (0, 0, 4), (0, 0, 6), (0, 2, 6), (0, 2, 4)), | |||
| ((1, 20, 6), (1, 20, 7), (1, 20, 4), (1, 20, 5), (1, 20, 1), (1, 20, 0), | |||
| (1, 20, 3), (1, 20, 2), (0, 2, 2), (0, 2, 0), (0, 0, 0), (0, 0, 2), | |||
| (0, 6, 4), (0, 4, 6), (0, 6, 6), (0, 4, 4), (0, 4, 0), (0, 6, 2), | |||
| (0, 4, 2), (0, 6, 0), (0, 0, 6), (0, 0, 4), (0, 2, 4), (0, 2, 6)), | |||
| ((1, 20, 5), (1, 20, 4), (1, 20, 7), (1, 20, 6), (1, 20, 2), (1, 20, 3), | |||
| (1, 20, 0), (1, 20, 1), (0, 0, 2), (0, 0, 0), (0, 2, 0), (0, 2, 2), | |||
| (0, 4, 4), (0, 6, 6), (0, 4, 6), (0, 6, 4), (0, 6, 0), (0, 4, 2), | |||
| (0, 6, 2), (0, 4, 0), (0, 2, 6), (0, 2, 4), (0, 0, 4), (0, 0, 6)), | |||
| ((0, 2, 5), (0, 0, 6), (0, 0, 4), (0, 2, 6), (0, 0, 0), (0, 2, 3), | |||
| (0, 2, 0), (0, 0, 2), (0, 6, 6), (0, 6, 4), (0, 4, 6), (0, 4, 4), | |||
| (1, 16, 18), (1, 16, 19), (1, 16, 16), (1, 16, 17), (1, 16, 12), | |||
| (1, 16, 13), (1, 16, 14), (1, 16, 15), (0, 4, 2), (0, 4, 0), (0, 6, 2), | |||
| (0, 6, 0)), ((0, 2, 6), (0, 0, 4), (0, 0, 6), (0, 2, 5), (0, 0, 2), | |||
| (0, 2, 0), (0, 2, 3), (0, 0, 0), (0, 4, 4), (0, 4, 6), (0, 6, 4), | |||
| (0, 6, 6), (1, 16, 17), (1, 16, 16), (1, 16, 19), (1, 16, 18), | |||
| (1, 16, 15), (1, 16, 14), (1, 16, 13), (1, 16, 12), (0, 6, 0), (0, 6, 2), | |||
| (0, 4, 0), (0, 4, 2)), ((0, 0, 5), (0, 2, 6), (0, 2, 4), (0, 0, 6), | |||
| (0, 2, 0), (0, 0, 3), (0, 0, 0), (0, 2, 2), (0, 4, 6), (0, 4, 4), | |||
| (0, 6, 6), (0, 6, 4), (1, 16, 16), (1, 16, 17), (1, 16, 18), (1, 16, 19), | |||
| (1, 16, 14), (1, 16, 15), (1, 16, 12), (1, 16, 13), (0, 6, 2), (0, 6, 0), | |||
| (0, 4, 2), (0, 4, 0)), ((0, 0, 6), (0, 2, 4), (0, 2, 6), (0, 0, 5), | |||
| (0, 2, 2), (0, 0, 0), (0, 0, 3), (0, 2, 0), (0, 6, 4), (0, 6, 6), | |||
| (0, 4, 4), (0, 4, 6), (1, 16, 19), (1, 16, 18), (1, 16, 17), (1, 16, 16), | |||
| (1, 16, 13), (1, 16, 12), (1, 16, 15), (1, 16, 14), (0, 4, 0), (0, 4, 2), | |||
| (0, 6, 0), (0, 6, 2)), ((0, 6, 6), (0, 4, 4), (0, 4, 6), (0, 6, 5), | |||
| (0, 4, 2), (0, 6, 0), (0, 6, 3), (0, 4, 0), (0, 2, 4), (0, 2, 6), | |||
| (0, 0, 4), (0, 0, 6), (1, 12, 16), (1, 12, 17), (1, 12, 18), (1, 12, 19), | |||
| (1, 12, 14), (1, 12, 15), (1, 12, 12), (1, 12, 13), (0, 0, 0), (0, 0, 2), | |||
| (0, 2, 0), (0, 2, 2)), ((0, 6, 5), (0, 4, 6), (0, 4, 4), (0, 6, 6), | |||
| (0, 4, 0), (0, 6, 3), (0, 6, 0), (0, 4, 2), (0, 0, 6), (0, 0, 4), | |||
| (0, 2, 6), (0, 2, 4), (1, 12, 19), (1, 12, 18), (1, 12, 17), (1, 12, 16), | |||
| (1, 12, 13), (1, 12, 12), (1, 12, 15), (1, 12, 14), (0, 2, 2), (0, 2, 0), | |||
| (0, 0, 2), (0, 0, 0)), ((0, 4, 6), (0, 6, 4), (0, 6, 6), (0, 4, 5), | |||
| (0, 6, 2), (0, 4, 0), (0, 4, 3), (0, 6, 0), (0, 0, 4), (0, 0, 6), | |||
| (0, 2, 4), (0, 2, 6), (1, 12, 18), (1, 12, 19), (1, 12, 16), (1, 12, 17), | |||
| (1, 12, 12), (1, 12, 13), (1, 12, 14), (1, 12, 15), (0, 2, 0), (0, 2, 2), | |||
| (0, 0, 0), (0, 0, 2)), ((0, 4, 5), (0, 6, 6), (0, 6, 4), (0, 4, 6), | |||
| (0, 6, 0), (0, 4, 3), (0, 4, 0), (0, 6, 2), (0, 2, 6), (0, 2, 4), | |||
| (0, 0, 6), (0, 0, 4), (1, 12, 17), (1, 12, 16), (1, 12, 19), (1, 12, 18), | |||
| (1, 12, 15), (1, 12, 14), (1, 12, 13), (1, 12, 12), (0, 0, 2), (0, 0, 0), | |||
| (0, 2, 2), (0, 2, 0)), ((1, 10, 5), (1, 8, 6), (1, 8, 5), (1, 10, 6), | |||
| (1, 8, 0), (1, 10, 3), (1, 10, 0), (1, 8, 3), (0, 4, 2), (0, 4, 0), | |||
| (0, 6, 0), (0, 6, 2), (0, 2, 4), (0, 0, 6), (0, 2, 6), (0, 0, 4), | |||
| (0, 0, 0), (0, 2, 2), (0, 0, 2), (0, 2, 0), (0, 6, 6), (0, 6, 4), | |||
| (0, 4, 4), (0, 4, 6)), ((1, 10, 6), (1, 8, 5), (1, 8, 6), (1, 10, 5), | |||
| (1, 8, 3), (1, 10, 0), (1, 10, 3), (1, 8, 0), (0, 6, 2), (0, 6, 0), | |||
| (0, 4, 0), (0, 4, 2), (0, 0, 4), (0, 2, 6), (0, 0, 6), (0, 2, 4), | |||
| (0, 2, 0), (0, 0, 2), (0, 2, 2), (0, 0, 0), (0, 4, 6), (0, 4, 4), | |||
| (0, 6, 4), (0, 6, 6)), ((1, 8, 5), (1, 8, 4), (1, 8, 7), (1, 8, 6), | |||
| (1, 8, 2), (1, 8, 3), (1, 8, 0), (1, 8, 1), (0, 6, 0), (0, 6, 2), | |||
| (0, 4, 2), (0, 4, 0), (0, 2, 6), (0, 0, 4), (0, 2, 4), (0, 0, 6), | |||
| (0, 0, 2), (0, 2, 0), (0, 0, 0), (0, 2, 2), (0, 4, 4), (0, 4, 6), | |||
| (0, 6, 6), (0, 6, 4)), ((1, 8, 6), (1, 8, 7), (1, 8, 4), (1, 8, 5), | |||
| (1, 8, 1), (1, 8, 0), (1, 8, 3), (1, 8, 2), (0, 4, 0), (0, 4, 2), | |||
| (0, 6, 2), (0, 6, 0), (0, 0, 6), (0, 2, 4), (0, 0, 4), (0, 2, 6), | |||
| (0, 2, 2), (0, 0, 0), (0, 2, 0), (0, 0, 2), (0, 6, 4), (0, 6, 6), | |||
| (0, 4, 6), (0, 4, 4)))) | |||
| cz_table = np.array(cz_table, dtype = int) | |||
| @@ -1,92 +0,0 @@ | |||
| import urlparse | |||
| from BaseHTTPServer import BaseHTTPRequestHandler | |||
| from SimpleHTTPServer import SimpleHTTPRequestHandler | |||
| import SocketServer | |||
| import sys | |||
| import json | |||
| import threading | |||
| import time | |||
| import os | |||
| from graphstate import GraphState | |||
| class VizHandler(SimpleHTTPRequestHandler): | |||
| """ Handles requests to the server """ | |||
| def __init__(self, *args, **kwargs): | |||
| SimpleHTTPRequestHandler.__init__(self, *args, **kwargs) | |||
| def get_state(self): | |||
| """ Get the current graphstate state """ | |||
| self.send_response(200) | |||
| self.send_header('Content-Type', 'application/json') | |||
| self.end_headers() | |||
| state = self.server.state | |||
| self.wfile.write(state.to_json()) | |||
| def do_GET(self, *args, **kwargs): | |||
| """ Someone belled the server """ | |||
| parsed_path = urlparse.urlparse(self.path) | |||
| if parsed_path.path == "/state": | |||
| return self.get_state() | |||
| else: | |||
| return SimpleHTTPRequestHandler.do_GET(self, *args, **kwargs) | |||
| class Server(SocketServer.TCPServer): | |||
| """ Serves the good stuff """ | |||
| allow_reuse_address = True | |||
| def __init__(self, port=8000): | |||
| self.port = port | |||
| self.state = None | |||
| SocketServer.TCPServer.__init__( | |||
| self, ("127.0.0.1", self.port), VizHandler) | |||
| def update(self, state): | |||
| """ Update the in-memory state """ | |||
| self.state = state | |||
| def run(self): | |||
| """ Run in such a way that keyboard interrupts are caught properly """ | |||
| try: | |||
| self.serve_forever() | |||
| except KeyboardInterrupt: | |||
| self.shutdown() | |||
| def start(self): | |||
| """ Start in a new thread """ | |||
| thread = threading.Thread(None, self.run) | |||
| thread.daemon = True | |||
| thread.start() | |||
| print "Server running at http://localhost:{}/".format(self.port) | |||
| def demograph(): | |||
| """ A graph for testing with """ | |||
| g = GraphState() | |||
| g.add_edge(0, 1) | |||
| g.add_edge(1, 2) | |||
| g.add_edge(2, 0) | |||
| g.add_edge(0, 3) | |||
| g.add_edge(100, 200) | |||
| return g | |||
| if __name__ == '__main__': | |||
| where = os.path.join(sys.path[0], "../static") | |||
| os.chdir(where) | |||
| server = Server() | |||
| server.start() | |||
| g = demograph() | |||
| g.layout() | |||
| while True: | |||
| server.update(g) | |||
| time.sleep(1) | |||
| server.shutdown() | |||
| @@ -1,26 +0,0 @@ | |||
| import networkx as nx | |||
| from matplotlib import pyplot as plt | |||
| import clifford | |||
| import numpy as np | |||
| from graphstate import GraphState | |||
| VOP_COLORS = ["red", "green", "blue", "orange", "yellow", "purple", "black", "white"] | |||
| def draw(state, filename="out.pdf", pos=None, ns=500): | |||
| """ Draw a graph with networkx layout """ | |||
| plt.clf() | |||
| graph = nx.from_edgelist(state.edgelist()) | |||
| pos = nx.spring_layout(graph) if pos==None else pos | |||
| colors = [VOP_COLORS[vop % len(VOP_COLORS)] for vop in state.vops.values()] | |||
| nx.draw_networkx_nodes(graph, pos, node_color="white", node_size=ns) | |||
| nx.draw_networkx_nodes(graph, pos, node_color=colors, node_size=ns, alpha=.4) | |||
| nx.draw_networkx_edges(graph, pos, edge_color="gray") | |||
| nx.draw_networkx_labels(graph, pos, font_family="FreeSans") | |||
| # tables.name_of(v) | |||
| labels = {i: "no name" for i, v in state.vops.items()} | |||
| pos = {k: v + np.array([0, -.1]) for k, v in pos.items()} | |||
| nx.draw_networkx_labels(graph, pos, labels, font_family="FreeSans") | |||
| plt.axis('off') | |||
| plt.savefig(filename) | |||
| return pos | |||
| @@ -1,13 +0,0 @@ | |||
| from abp.graphstate import GraphState | |||
| from abp import viz | |||
| def test_viz(): | |||
| g = GraphState(range(4)+[100, 200]) | |||
| g.add_edge(0, 1) | |||
| g.add_edge(1, 2) | |||
| g.add_edge(2, 0) | |||
| g.add_edge(0, 3) | |||
| g.add_edge(100, 200) | |||
| # g.remove_vop(0, 1) | |||
| viz.draw(g) | |||