<commit_before>import math
import random
import sys

import pygame
from pygame.locals import *
from noise import pnoise1, pnoise2, snoise2

BEIGE  = (200, 200, 100)
BLACK  = (  0,   0,   0)
BLUE   = (  0,   0, 200)
GREEN  = (  0, 255,   0)
RED    = (255,   0,   0)
WHITE  = (255, 255, 255)
CYAN = (  0, 255, 255)

def setup_screen(screen_size=(900, 900)):
    surf = pygame.display.set_mode(screen_size, RESIZABLE)
    pygame.display.set_caption('Pyland Gen 1.0')
    return surf

class IslandGenerator():
    """ Generates a random graph of noise. (Not really an Island) """
    def __init__(self):
        """ Initialize some pnoise generator defaults. """
        self.span = 8.0
        self.octaves = 8
        self.scale = 40

    def gen_border(self):
        """
        Generate a border to apply to our island to build shoreline.

        Returns a list of (x, y) points of generated pnoise.
        """
        points = 360
        base = random.randint(0, 500)
        border = []
        for i in range(points):
            x = float(i) * self.span / points
            y = pnoise1(x + base, self.octaves) * 1.5
            y += pnoise1(x + base, self.octaves + 4) * 4
            y *= self.scale
            border.append((i, y))
        return border

def scale_to_polar(border, radius=200):
    """ Apply our border to our island. """
    radii = (radius + y for _, y in border)  # Adjust radii
    angles = (x * math.pi / 180.0 for x, _ in border)  # Convert to radians
    return zip(radii, angles)

def polar_to_rectangular(polar_coords):
    return [(r * math.cos(theta) + 450, r * math.sin(theta) + 450) \
            for r, theta in polar_coords]  # To rectangular coords

def render_island(surf, coords, radius):
    """ Renders an aaline of a series of points. """
    pygame.draw.circle(surf, RED, (450, 450), radius, 1)  # Original centre
    pygame.draw.aalines(surf, BEIGE, True, coords, False)  # Island shore
    for point in coords:  # Data points
        pygame.draw.circle(surf, GREEN, (int(point[0]), int(point[1])), 1)

def render_border(surf, points):
    """ Renders an aaline of a series of points. """
    point_list = [(x + 50, -y + 800) for x, y in points]  # Up is -ve
    pygame.draw.line(surf, CYAN, (50, 800), (410, 800), 1)  # x-axis
    pygame.draw.line(surf, CYAN, (50, 800), (50, 700), 1)  # y-axis

    pygame.draw.lines(surf, WHITE, False, point_list, 1)
    for x, y in point_list:  # points
        pygame.draw.circle(surf, RED, (int(x), int(y)), 1)

def flood_fill(surf):
    screen_size = surf.get_size()
    center_x, center_y = screen_size[0]/2, screen_size[1]/2
    start_color = surf.get_at((center_x, center_y))
    seen = []
    WHITE = (255, 255, 255, 255)
    for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
        x, y = center_x + dx, center_y + dy
        surf.set_at((x, y), WHITE)
        if surf.get_at((x, y)) == start_color:
            pass

def get_input():
    """ Wait for input. """
    for event in pygame.event.get():
        if event.type == QUIT:
            return 'quit'
        elif event.type == KEYDOWN:
            if event.key == (K_s):
                return 'span'
            elif event.key == (K_o):
                return 'octaves'
            elif event.key == (K_c):
                return 'scale'
            elif event.key in (K_q, K_ESCAPE):
                return 'quit'
            elif event.key == K_SPACE:
                return 'regen'

def main():
    print('Pyland Gen 1.0')
    pygame.init()
    clock = pygame.time.Clock()
    surface = setup_screen()

    generator = IslandGenerator()
    radius = 200
    result = 'regen'
    while True:
        clock.tick(10)

        if result == 'quit':
            pygame.quit()
            sys.exit()
        elif result == 'span':
            generator.span += 1
            result = 'regen'
        elif result == 'scale':
            generator.scale += 1
            result = 'regen'
        elif result == 'octaves':
            generator.octaves += 1
            result = 'regen'
        if result == 'regen':
            surface.fill(BLACK)
            border = generator.gen_border()  # Generate random noise
            render_border(surface, border)  # Draw it

            polar_coords = scale_to_polar(border, radius=radius)  # Wrap it around a circle
            rect_coords = polar_to_rectangular(polar_coords)  # Conver to (x, y)
            render_island(surface, rect_coords, radius)  # Graph island

            flood_fill(surface)  # Fill Island w/ color
            pygame.display.flip()

        result = get_input()

if __name__ == '__main__':
    main()

<commit_msg>Play with some params<commit_after>import math
import random
import sys

import pygame
from pygame.locals import *
from noise import pnoise1, pnoise2, snoise2

BEIGE  = (200, 200, 100)
BLACK  = (  0,   0,   0)
BLUE   = (  0,   0, 200)
GREEN  = (  0, 255,   0)
RED    = (255,   0,   0)
WHITE  = (255, 255, 255)
CYAN = (  0, 255, 255)

def setup_screen(screen_size=(900, 900)):
    surf = pygame.display.set_mode(screen_size, RESIZABLE)
    pygame.display.set_caption('Pyland Gen 1.0')
    return surf

class IslandGenerator():
    """ Generates a random graph of noise. (Not really an Island) """
    def __init__(self):
        """ Initialize some pnoise generator defaults. """
        self.span = 8.0
        self.octaves = 8
        self.scale = 40

    def gen_border(self):
        """
        Generate a border to apply to our island to build shoreline.

        Returns a list of (x, y) points of generated pnoise.
        """
        points = 360
        base = random.randint(0, 500)
        border = []
        for i in range(points):
            x = float(i) * self.span / points
            y = pnoise1(x + base, self.octaves) * 1
            y += pnoise1(x + base, self.octaves + 4) * 2
            y *= self.scale
            border.append((i, y))
        return border

def scale_to_polar(border, radius=200):
    """ Apply our border to our island. """
    radii = (radius + y for _, y in border)  # Adjust radii
    angles = (x * math.pi / 180.0 for x, _ in border)  # Convert to radians
    return zip(radii, angles)

def polar_to_rectangular(polar_coords):
    return [(r * math.cos(theta) + 450, r * math.sin(theta) + 450) \
            for r, theta in polar_coords]  # To rectangular coords

def render_island(surf, coords, radius):
    """ Renders an aaline of a series of points. """
    pygame.draw.circle(surf, RED, (450, 450), radius, 1)  # Original centre
    pygame.draw.aalines(surf, BEIGE, True, coords, False)  # Island shore
    for point in coords:  # Data points
        pygame.draw.circle(surf, GREEN, (int(point[0]), int(point[1])), 1)

def render_border(surf, points):
    """ Renders an aaline of a series of points. """
    point_list = [(x + 50, -y + 800) for x, y in points]  # Up is -ve
    pygame.draw.line(surf, CYAN, (50, 800), (410, 800), 1)  # x-axis
    pygame.draw.line(surf, CYAN, (50, 800), (50, 700), 1)  # y-axis

    pygame.draw.lines(surf, WHITE, False, point_list, 1)
    for x, y in point_list:  # points
        pygame.draw.circle(surf, RED, (int(x), int(y)), 1)

def flood_fill(surf):
    screen_size = surf.get_size()
    center_x, center_y = screen_size[0]/2, screen_size[1]/2
    start_color = surf.get_at((center_x, center_y))
    seen = []
    WHITE = (255, 255, 255, 255)
    for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
        x, y = center_x + dx, center_y + dy
        surf.set_at((x, y), WHITE)
        if surf.get_at((x, y)) == start_color:
            pass

def get_input():
    """ Wait for input. """
    for event in pygame.event.get():
        if event.type == QUIT:
            return 'quit'
        elif event.type == KEYDOWN:
            if event.key == (K_s):
                return 'span'
            elif event.key == (K_o):
                return 'octaves'
            elif event.key == (K_c):
                return 'scale'
            elif event.key in (K_q, K_ESCAPE):
                return 'quit'
            elif event.key == K_SPACE:
                return 'regen'

def main():
    print('Pyland Gen 1.0')
    pygame.init()
    clock = pygame.time.Clock()
    surface = setup_screen()

    generator = IslandGenerator()
    radius = 200
    result = 'regen'
    while True:
        clock.tick(10)

        if result == 'quit':
            pygame.quit()
            sys.exit()
        elif result == 'span':
            generator.span += 1
            result = 'regen'
        elif result == 'scale':
            generator.scale += 10
            result = 'regen'
        elif result == 'octaves':
            generator.octaves += 1
            result = 'regen'
        if result == 'regen':
            surface.fill(BLACK)
            border = generator.gen_border()  # Generate random noise
            render_border(surface, border)  # Draw it

            polar_coords = scale_to_polar(border, radius=radius)  # Wrap it around a circle
            rect_coords = polar_to_rectangular(polar_coords)  # Conver to (x, y)
            render_island(surface, rect_coords, radius)  # Graph island

            flood_fill(surface)  # Fill Island w/ color
            pygame.display.flip()

        result = get_input()

if __name__ == '__main__':
    main()

<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

# ————————————————————————————————————————————————————————————————————————————
# Copyright © 2014 - 2016, Sequømics Research, All rights reserved.
# Copyright © 2014 - 2016, Sequømics Corporation. All rights reserved.
# ————————————————————————————————————————————————————————————————————————————
# Licensed under the Apache License (the "License, version 2.0");
# you may not use this file except in compliance with the License.
# ————————————————————————————————————————————————————————————————————————————
<commit_msg>Initial commit<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

# ————————————————————————————————————————————————————————————————————————————
# Copyright © 2014 - 2016, Sequømics Research, All rights reserved.
# Copyright © 2014 - 2016, Sequømics Corporation. All rights reserved.
# ————————————————————————————————————————————————————————————————————————————
# Licensed under the Apache License (the "License, version 2.0");
# you may not use this file except in compliance with the License.
# ————————————————————————————————————————————————————————————————————————————
__author__        = ['"Prabhat Kumar" <prabhat.genome@gmail.com>']
__license__       = 'Apache License'
<|endoftext|>


<commit_before>#!/usr/bin/env python

import sys
from feature_classes import GenePart, CDS, Exon, MRNA, Gene

class GFF:

    def __init__(self):
        self.genes = []
        self.current_gene = None
        self.current_mrna = None
        self.current_exon = None
        self.current_cds = None

    def validate_line(self, line):
        if len(line) is not 9:
            return False
        return True

    def line_type(self, line):
        return line[2]

    def validate_first_line(self, line):
        if self.line_type(line) is 'gene':
            return self.validate_line(line)
        else:
            return False

    # returns a dict with id, name, parent_id (if present)
    def parse_attributes(self, attr):
        result = {}
        split_attr = attr.split(';')
        # make sure that worked :)
        if len(split_attr) < 2:
            sys.stderr.write('error trying to parse "' + attr + '"\n')
            return None
        try:
            result['identifier'] = split_attr[0].split('=')[1]
            result['name'] = split_attr[1].split('=')[1]
        except IndexError:
            sys.stderr.write('error trying to parse "' + attr + '"\n')
            return None
        if len(split_attr) is 3:
            try:
                result['parent_id'] = split_attr[2].split('=')[1]
            except IndexError:
                sys.stderr.write('error trying to parse "' + attr + '"\n')
                return None
        return result

    def extract_cds_args(self, line):
        result = {'indices': [int(line[3]), int(line[4])], 'phase': int(line[7])}
        attribs = self.parse_attributes(line[8])
        result.update(attribs)
        return result

    def extract_exon_args(self, line):
        result = {'indices': [int(line[3]), int(line[4])], 'score': line[5]}
        attribs = self.parse_attributes(line[8])
        result.update(attribs)
        return result

    def extract_other_feature_args(self, line):
        result = {'feature_type': line[2], 'indices': [int(line[3]), int(line[4])]}
        attribs = self.parse_attributes(line[8])
        result.update(attribs)
        return result

    def extract_mrna_args(self, line):
        result = {'indices': [int(line[3]), int(line[4])]}
        attribs = self.parse_attributes(line[8])
        result.update(attribs)
        return result

    # returns a dict
    def extract_gene_args(self, line):  # TODO 'score'
        result = {'seq_name': line[0], 'source': line[1], 'indices': [int(line[3]), int(line[4])], 'strand': line[6]}
        attribs = self.parse_attributes(line[8])
        result.update(attribs)
        return result

    def update_cds(self, line):
        # TODO
        print "foo"

    def process_cds_line(self, line):
        if self.current_cds:
            self.update_cds(line)
        else:
            args = self.extract_cds_args(line)

<commit_msg>clean up gff<commit_after>#!/usr/bin/env python

import sys
from feature_classes import GenePart, CDS, Exon, MRNA, Gene

class GFF:

    def __init__(self):
        self.genes = []
        self.current_gene = None
        self.current_mrna = None
        self.current_exon = None
        self.current_cds = None

    def validate_line(self, line):
        if len(line) is not 9:
            return False
        return True

    def line_type(self, line):
        return line[2]

    def validate_first_line(self, line):
        if self.line_type(line) is 'gene':
            return self.validate_line(line)
        else:
            return False

    # returns a dict with id, name, parent_id (if present)
    def parse_attributes(self, attr):
        result = {}
        split_attr = attr.split(';')
        # make sure that worked :)
        if len(split_attr) < 2:
            sys.stderr.write('error trying to parse "' + attr + '"\n')
            return None
        try:
            result['identifier'] = split_attr[0].split('=')[1]
            result['name'] = split_attr[1].split('=')[1]
        except IndexError:
            sys.stderr.write('error trying to parse "' + attr + '"\n')
            return None
        if len(split_attr) is 3:
            try:
                result['parent_id'] = split_attr[2].split('=')[1]
            except IndexError:
                sys.stderr.write('error trying to parse "' + attr + '"\n')
                return None
        return result

    def extract_cds_args(self, line):
        result = {'indices': [int(line[3]), int(line[4])], 'phase': int(line[7])}
        attribs = self.parse_attributes(line[8])
        result.update(attribs)
        return result

    def extract_exon_args(self, line):
        result = {'indices': [int(line[3]), int(line[4])], 'score': line[5]}
        attribs = self.parse_attributes(line[8])
        result.update(attribs)
        return result

    def extract_other_feature_args(self, line):
        result = {'feature_type': line[2], 'indices': [int(line[3]), int(line[4])]}
        attribs = self.parse_attributes(line[8])
        result.update(attribs)
        return result

    def extract_mrna_args(self, line):
        result = {'indices': [int(line[3]), int(line[4])]}
        attribs = self.parse_attributes(line[8])
        result.update(attribs)
        return result

    def extract_gene_args(self, line):  # TODO 'score'
        result = {'seq_name': line[0], 'source': line[1], 'indices': [int(line[3]), int(line[4])], 'strand': line[6]}
        attribs = self.parse_attributes(line[8])
        result.update(attribs)
        return result

    def update_cds(self, line):
        # TODO
        print "foo"

    def process_cds_line(self, line):
        if self.current_cds:
            self.update_cds(line)
        else:
            args = self.extract_cds_args(line)

<|endoftext|>


<commit_before>import re

def pre_engine(s):
    s = re.sub("[^\t\n -~]", "", s)
    s = s.split("#")[0]
    s = s.replace("\t", " ")
    return s

def pre_controller(s):
    s = re.sub("[^\t\n -~]", "", s)
    s = s.replace("\t", " ")
    return s

def gtp_boolean(b):
    return "true" if b else "false"

def gtp_list(l):
    return "\n".join(l)

def gtp_color(color):
    # an arbitrary choice amongst a number of possibilities
    return {BLACK: "B", WHITE: "W"}[color]

def gtp_vertex(x, y):
    return "{}{}".format("ABCDEFGHJKLMNOPQRSTYVWYZ"[x - 1], y)

def gtp_move(color, x, y):
    return " ".join([gtp_color(color), gtp_vertex(x, y)])

def parse_message(message):
    message = pre_engine(message).strip()
    first, rest = (message.split(" ", 1) + [None])[:2]
    if first.isdigit():
        message_id = int(first)
        if rest is not None:
            command, arguments = (rest.split(" ", 1) + [None])[:2]
        else:
            command, arguments = None, None
    else:
        message_id = None
        command, arguments = first, rest

    return message_id, command, arguments

WHITE = -1
BLACK = +1
EMPTY = 0

def parse_color(color):
    if color.lower() in ["b", "black"]:
        return BLACK
    elif color.lower() in ["w", "white"]:
        return WHITE
    else:
        return False

def parse_move(move):
    color, vertex = (move.split(" ") + [None])[:2]
    color = parse_color(color)
    if color is False:
        return False
    if vertex and len(vertex) > 1:
        x = "abcdefghjklmnopqrstuvwxyz".find(vertex[0].lower()) + 1
        if x == 0:
            return False
        if vertex[1:].isdigit():
            y = int(vertex[1:])
        else:
            return False
    else:
        return False

    return color, x, y

MIN_BOARD_SIZE = 7
MAX_BOARD_SIZE = 19

def format_success(message_id, response=None):
    if response is None:
        response = ""
    else:
        response = " {}".format(response)
    if message_id:
        return "={}{}\n\n".format(message_id, response)
    else:
        return "={}\n\n".format(response)

def format_error(message_id, response):
    if response is None:
        response = ""
    else:
        response = " {}".format(response)
    if message_id:
        return "?{}{}\n\n".format(message_id, response)
    else:
        return "?{}\n\n".format(response)

class Engine(object):

    def __init__(self):

        self.size = 19
        self.komi = 6.5
        # self.time_settings
        self.clear()

        self.disconnect = False

        self.known_commands = [
            field[4:] for field in dir(self) if field.startswith("cmd_")]

    def clear(self):
        self.board_configuration = [EMPTY] * (self.size * self.size)
        self.captured_B = 0
        self.captured_W = 0
        self.move_history = []

    def send(self, message):
        message_id, command, arguments = parse_message(message)
        if command in self.known_commands:
            try:
                return format_success(
                    message_id, getattr(self, "cmd_" + command)(arguments))
            except ValueError as exception:
                return format_error(message_id, exception.args[0])
        else:
            return format_error(message_id, "unknown command")

    def make_move(self, color, x, y):
        offset = self.size * (x - 1) + y - 1
        if self.board_configuration[offset] != EMPTY:
            return False
        # @@@ no other checks for now (e.g. suicide, ko)
        self.board_configuration[offset] = color
        self.move_history.append((color, x, y))
        return True

    # commands

    def cmd_protocol_version(self, arguments):
        return 2

    def cmd_name(self, arguments):
        return "gtp (python library)"

    def cmd_version(self, arguments):
        return "0.1"

    def cmd_known_command(self, arguments):
        return gtp_boolean(arguments in self.known_commands)

    def cmd_list_commands(self, arguments):
        return gtp_list(self.known_commands)

    def cmd_quit(self, arguments):
        self.disconnect = True

    def cmd_boardsize(self, arguments):
        if arguments.isdigit:
            size = int(arguments)
            if MIN_BOARD_SIZE <= size <= MAX_BOARD_SIZE:
                self.size = size
            else:
                raise ValueError("unacceptable size")

    def cmd_clear_board(self, arguments):
        self.clear()

    def cmd_komi(self, arguments):
        try:
            self.komi = float(arguments)
        except ValueError:
            raise ValueError("syntax error")

    def cmd_play(self, arguments):
        move = parse_move(arguments)
        if move:
            color, x, y = move
            if 1 <= x <= self.size and 1 <= y <= self.size:
                if self.make_move(color, x, y):
                    return
        raise ValueError("illegal move")

    def cmd_genmove(self, arguments):
        parse_color(arguments)
        # @@@ return a fixed vertex for now
        return gtp_vertex(16, 16)
<commit_msg>response is never None in error<commit_after>import re

def pre_engine(s):
    s = re.sub("[^\t\n -~]", "", s)
    s = s.split("#")[0]
    s = s.replace("\t", " ")
    return s

def pre_controller(s):
    s = re.sub("[^\t\n -~]", "", s)
    s = s.replace("\t", " ")
    return s

def gtp_boolean(b):
    return "true" if b else "false"

def gtp_list(l):
    return "\n".join(l)

def gtp_color(color):
    # an arbitrary choice amongst a number of possibilities
    return {BLACK: "B", WHITE: "W"}[color]

def gtp_vertex(x, y):
    return "{}{}".format("ABCDEFGHJKLMNOPQRSTYVWYZ"[x - 1], y)

def gtp_move(color, x, y):
    return " ".join([gtp_color(color), gtp_vertex(x, y)])

def parse_message(message):
    message = pre_engine(message).strip()
    first, rest = (message.split(" ", 1) + [None])[:2]
    if first.isdigit():
        message_id = int(first)
        if rest is not None:
            command, arguments = (rest.split(" ", 1) + [None])[:2]
        else:
            command, arguments = None, None
    else:
        message_id = None
        command, arguments = first, rest

    return message_id, command, arguments

WHITE = -1
BLACK = +1
EMPTY = 0

def parse_color(color):
    if color.lower() in ["b", "black"]:
        return BLACK
    elif color.lower() in ["w", "white"]:
        return WHITE
    else:
        return False

def parse_move(move):
    color, vertex = (move.split(" ") + [None])[:2]
    color = parse_color(color)
    if color is False:
        return False
    if vertex and len(vertex) > 1:
        x = "abcdefghjklmnopqrstuvwxyz".find(vertex[0].lower()) + 1
        if x == 0:
            return False
        if vertex[1:].isdigit():
            y = int(vertex[1:])
        else:
            return False
    else:
        return False

    return color, x, y

MIN_BOARD_SIZE = 7
MAX_BOARD_SIZE = 19

def format_success(message_id, response=None):
    if response is None:
        response = ""
    else:
        response = " {}".format(response)
    if message_id:
        return "={}{}\n\n".format(message_id, response)
    else:
        return "={}\n\n".format(response)

def format_error(message_id, response):
    if response:
        response = " {}".format(response)
    if message_id:
        return "?{}{}\n\n".format(message_id, response)
    else:
        return "?{}\n\n".format(response)

class Engine(object):

    def __init__(self):

        self.size = 19
        self.komi = 6.5
        # self.time_settings
        self.clear()

        self.disconnect = False

        self.known_commands = [
            field[4:] for field in dir(self) if field.startswith("cmd_")]

    def clear(self):
        self.board_configuration = [EMPTY] * (self.size * self.size)
        self.captured_B = 0
        self.captured_W = 0
        self.move_history = []

    def send(self, message):
        message_id, command, arguments = parse_message(message)
        if command in self.known_commands:
            try:
                return format_success(
                    message_id, getattr(self, "cmd_" + command)(arguments))
            except ValueError as exception:
                return format_error(message_id, exception.args[0])
        else:
            return format_error(message_id, "unknown command")

    def make_move(self, color, x, y):
        offset = self.size * (x - 1) + y - 1
        if self.board_configuration[offset] != EMPTY:
            return False
        # @@@ no other checks for now (e.g. suicide, ko)
        self.board_configuration[offset] = color
        self.move_history.append((color, x, y))
        return True

    # commands

    def cmd_protocol_version(self, arguments):
        return 2

    def cmd_name(self, arguments):
        return "gtp (python library)"

    def cmd_version(self, arguments):
        return "0.1"

    def cmd_known_command(self, arguments):
        return gtp_boolean(arguments in self.known_commands)

    def cmd_list_commands(self, arguments):
        return gtp_list(self.known_commands)

    def cmd_quit(self, arguments):
        self.disconnect = True

    def cmd_boardsize(self, arguments):
        if arguments.isdigit:
            size = int(arguments)
            if MIN_BOARD_SIZE <= size <= MAX_BOARD_SIZE:
                self.size = size
            else:
                raise ValueError("unacceptable size")

    def cmd_clear_board(self, arguments):
        self.clear()

    def cmd_komi(self, arguments):
        try:
            self.komi = float(arguments)
        except ValueError:
            raise ValueError("syntax error")

    def cmd_play(self, arguments):
        move = parse_move(arguments)
        if move:
            color, x, y = move
            if 1 <= x <= self.size and 1 <= y <= self.size:
                if self.make_move(color, x, y):
                    return
        raise ValueError("illegal move")

    def cmd_genmove(self, arguments):
        parse_color(arguments)
        # @@@ return a fixed vertex for now
        return gtp_vertex(16, 16)
<|endoftext|>


<commit_before>#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
from PySide.QtGui import *
from PySide.QtCore import *
import os
import socket as sok
from time import *
from SimpleCV import Camera
import json

_main_path = "test_images/"
LOCALHOST, PORT, BUFFER_S = '127.0.0.1', 8008, 1024
IO_TIMEOUT_S = 0.1
MESSAGE_LIMIT = 40

class CryptoPear(QWidget):

    def __init__(self):
        super(CryptoPear, self).__init__()

        self.initUI()

    def list_files(self):
        path = os.getcwd() + '/test_images/'
        files = os.listdir(path)
        return map(lambda f: path + f, files)

    def initUI(self):
        self.paths = self.list_files()

        pixmap = QPixmap(self.paths.pop(0)).scaledToHeight(200)
        self.lbl = QLabel(self)
        self.lbl.setPixmap(pixmap)

        self.btn_connect = QPushButton("Connect")
        self.btn_connect.clicked.connect(self.connect_to_server)
        self.btn_accept = QPushButton("Accept")
        self.btn_reject = QPushButton("Reject")
        self.btn_accept.clicked.connect(self.accept_participent)
        self.btn_reject.clicked.connect(self.reject_participent)
        self.btn_accept.setDisabled(True)
        self.btn_reject.setDisabled(True)

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(self.btn_connect)
        hbox.addWidget(self.btn_accept)
        hbox.addWidget(self.btn_reject)

        self.chatbox = QTextEdit(self)
        self.chatbox.setMinimumHeight(400)
        self.chatbox.setReadOnly(True)

        self.text_entry = QTextEdit(self)
        btn_submit = QPushButton("Submit")
        btn_submit.clicked.connect(self.submit_message)
        text_hbox = QHBoxLayout()
        text_hbox.addWidget(self.text_entry)
        text_hbox.addWidget(btn_submit)

        vbox = QVBoxLayout()
        vbox.addStretch(1)
        vbox.addWidget(self.lbl)
        vbox.addLayout(hbox)
        vbox.addWidget(self.chatbox)
        vbox.addLayout(text_hbox)
        self.setLayout(vbox)

        #starting x, starting y, width, height
        self.setGeometry(0, 0, 500, 700)
        self.setWindowTitle('CryptoPear')
        self.show()

    def get_camera(self):
        cam = Camera()
        img = cam.getImage()
        img.save("mZOMGGUYS.png")
        return voting.encode_image("mZOMGGUYS.png")

    def connect_to_server(self):
        self.get_camera()

        self.server_handler = ServerHandler()
        self.btn_accept.setDisabled(False)
        self.btn_reject.setDisabled(False)
        self.btn_connect.setDisabled(True)

        self.thread = MessageThread(self.chatbox, self.server_handler)
        self.thread.message.connect(self.append_messages, Qt.QueuedConnection)
        self.handletoggle()

    def append_messages(self, messages):
        if messages:
            self.chatbox.setReadOnly(False)
            self.chatbox.clear()
            self.chatbox.append(messages)
            self.chatbox.setReadOnly(True)

    def handletoggle(self):
        if self.thread.isRunning():
            self.thread.exiting=True
        else:
            self.thread.exiting=False
            self.thread.start()

    def submit_message(self):
        message = self.text_entry.toPlainText()
        if message:
            self.server_handler.send_message(message)
            self.text_entry.clear()

    def set_picture(self, file_path):
        image = QImage(file_path)
        if image.isNull():
            QMessageBox.information(self, "Image Viewer",
                    "Cannot load file")
            return

        self.lbl.setPixmap(QPixmap.fromImage(image).scaledToHeight(200))
        self.lbl.adjustSize()

    def accept_participent(self):
        self.set_picture(self.paths.pop(0))

    def reject_participent(self):
        print "participant rejected"

class MessageThread(QThread):

    message = Signal(str)

    def __init__(self, chatbox, server_handler):
        super(MessageThread, self).__init__()
        self.chatbox = chatbox
        self.server_handler = server_handler

    def run(self):
        while True:
            new_messages = None
            try:
                new_messages = self.server_handler.receive_messages()
            except:
                pass
            self.message.emit(new_messages)
            sleep(1)

class ServerHandler(object):

    def __init__(self):
        if True:
            DESTINATION = '198.211.120.146'
        else:
            DESTINATION = LOCALHOST

        self.server = sok.socket(sok.AF_INET, sok.SOCK_STREAM)
        self.server.connect((DESTINATION, PORT))
        self.server.setblocking(0)

        self.server.send("The magic word\n")
        self.messages = []

    def send_message(self, outgoing_message):
        self.server.send(outgoing_message+'\n')

    def receive_messages(self):
        data = self.server.recv(BUFFER_S)
        self.messages.append(data)
        return "".join(self.messages[-MESSAGE_LIMIT:])

def main():
    app = QApplication(sys.argv)
    cp = CryptoPear()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
<commit_msg>done some stuff with angus<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
from PySide.QtGui import *
from PySide.QtCore import *
import os
import socket as sok
from time import *
try:
    from SimpleCV import Camera
except:
    print "no simple cv"
import json

_main_path = "test_images/"
LOCALHOST, PORT, BUFFER_S = '127.0.0.1', 8008, 1024
IO_TIMEOUT_S = 0.1
MESSAGE_LIMIT = 40

class CryptoPear(QWidget):

    def __init__(self):
        super(CryptoPear, self).__init__()

        self.initUI()

    def list_files(self):
        path = os.getcwd() + '/test_images/'
        files = os.listdir(path)
        return map(lambda f: path + f, files)

    def initUI(self):
        self.paths = self.list_files()

        pixmap = QPixmap(self.paths.pop(0)).scaledToHeight(200)
        self.lbl = QLabel(self)
        self.lbl.setPixmap(pixmap)

        self.btn_connect = QPushButton("Connect")
        self.btn_connect.clicked.connect(self.connect_to_server)
        self.btn_accept = QPushButton("Accept")
        self.btn_reject = QPushButton("Reject")
        self.btn_accept.clicked.connect(self.accept_participent)
        self.btn_reject.clicked.connect(self.reject_participent)
        self.btn_accept.setDisabled(True)
        self.btn_reject.setDisabled(True)

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(self.btn_connect)
        hbox.addWidget(self.btn_accept)
        hbox.addWidget(self.btn_reject)

        self.chatbox = QTextEdit(self)
        self.chatbox.setMinimumHeight(400)
        self.chatbox.setReadOnly(True)

        self.text_entry = QTextEdit(self)
        btn_submit = QPushButton("Submit")
        btn_submit.clicked.connect(self.submit_message)
        text_hbox = QHBoxLayout()
        text_hbox.addWidget(self.text_entry)
        text_hbox.addWidget(btn_submit)

        vbox = QVBoxLayout()
        vbox.addStretch(1)
        vbox.addWidget(self.lbl)
        vbox.addLayout(hbox)
        vbox.addWidget(self.chatbox)
        vbox.addLayout(text_hbox)
        self.setLayout(vbox)

        #starting x, starting y, width, height
        self.setGeometry(0, 0, 500, 700)
        self.setWindowTitle('CryptoPear')
        self.show()

    def get_camera(self):
        try:
            cam = Camera()
            img = cam.getImage()
            img.save("mZOMGGUYS.png")
        except:
            pass
        return voting.encode_image("test_images/test_james.jpeg")

    def get_user(self):
        text, ok = QInputDialog.getText(self, 'Input Dialog',
            'Enter your name:')

        if ok:
            return text
        else:
            return None

    def get_pubkey(self):
        return 'abc'

    def get_json(self):
        data = [{ 'name':self.get_user(), 'photo':self.get_camera(), 'publicKey':self.get_pubkey() }]
        data_string = json.dumps(data)
        return data_string

    def connect_to_server(self):
        self.get_json()

        self.server_handler = ServerHandler()
        self.btn_accept.setDisabled(False)
        self.btn_reject.setDisabled(False)
        self.btn_connect.setDisabled(True)

        self.thread = MessageThread(self.chatbox, self.server_handler)
        self.thread.message.connect(self.append_messages, Qt.QueuedConnection)
        self.handletoggle()

    def append_messages(self, messages):
        if messages:
            self.chatbox.setReadOnly(False)
            self.chatbox.clear()
            self.chatbox.append(messages)
            self.chatbox.setReadOnly(True)

    def handletoggle(self):
        if self.thread.isRunning():
            self.thread.exiting=True
        else:
            self.thread.exiting=False
            self.thread.start()

    def submit_message(self):
        message = self.text_entry.toPlainText()
        if message:
            self.server_handler.send_message(message)
            self.text_entry.clear()

    def set_picture(self, file_path):
        image = QImage(file_path)
        if image.isNull():
            QMessageBox.information(self, "Image Viewer",
                    "Cannot load file")
            return

        self.lbl.setPixmap(QPixmap.fromImage(image).scaledToHeight(200))
        self.lbl.adjustSize()

    def accept_participent(self):
        self.set_picture(self.paths.pop(0))

    def reject_participent(self):
        print "participant rejected"

class MessageThread(QThread):

    message = Signal(str)

    def __init__(self, chatbox, server_handler):
        super(MessageThread, self).__init__()
        self.chatbox = chatbox
        self.server_handler = server_handler

    def run(self):
        while True:
            new_messages = None
            try:
                new_messages = self.server_handler.receive_messages()
            except:
                pass
            self.message.emit(new_messages)
            sleep(1)

class ServerHandler(object):

    def __init__(self):
        if True:
            DESTINATION = '198.211.120.146'
        else:
            DESTINATION = LOCALHOST

        self.server = sok.socket(sok.AF_INET, sok.SOCK_STREAM)
        self.server.connect((DESTINATION, PORT))
        self.server.setblocking(0)

        self.server.send("The magic word\n")
        self.messages = []

    def send_message(self, outgoing_message):
        self.server.send(outgoing_message+'\n')

    def receive_messages(self):
        data = self.server.recv(BUFFER_S)
        self.messages.append(data)
        return "".join(self.messages[-MESSAGE_LIMIT:])

def main():
    app = QApplication(sys.argv)
    cp = CryptoPear()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
<|endoftext|>


<commit_before>#! /usr/bin/env python

import sys
import subprocess
from PyQt4 import QtGui, QtCore

DEBUG = True
WINDOW_TITLE = 'brsaneconfig3'
WIDTH_FUDGE = 30

class BrotherDevice:
    def __init__(self, info):
        # Parse info
        num, friendlyName, modelName, ipOrNode = info.split()
        # Check if IP or node name is specified
        self.usesIP = ipOrNode.startswith("I:")
        self.devID = num
        self.name = friendlyName
        # Remove quotation marks surrounding the model name
        self.model = modelName.replace('"', '')
        # Remove prefixes
        self.addr = ipOrNode.replace("I:", '').replace("N:BRN_", "")

    def __str__(self):
        return "devID: {}, name: {}, model: {}, addr: {} ({})".format(self.devID, self.name, self.model, self.addr,
                                                                      'IP' if self.usesIP else 'node')

    @staticmethod
    def addDevice(device):
        try:
            output = subprocess.check_output(["brsaneconfig3", "-a",
                                              "name={}".format(device.name),
                                              "model={}".format(device.model),
                                              "ip={}".format(device.addr) if device.usesIP else "nodename=BRN_{}".format(device.addr)])
        except subprocess.CalledProcessError:
            # TODO: Handle this
            pass

    @staticmethod
    def removeDevice(name):
        try:
            output = subprocess.check_output(["brsaneconfig3", "-r", name])
        except subprocess.CalledProcessError:
            # TODO: Handle this
            pass

class ConfigWindow(QtGui.QMainWindow):
    HEADER = "Devices on network"

    def __init__(self):
        # The super() method returns the parent object of the given class
        super(ConfigWindow, self).__init__()

        # Data structures and variables
        self.supportedModels = []
        self.myDevices = []
        self.currentDevice = []
        self.noWhitespaceRegex = QtCore.QRegExp('[^\s]+')
        self.hasEditedCurrentDevice = False
        self.ipEdits = []

        # Interface elements
        self.deviceList = QtGui.QListWidget()
        self.friendlyNameEdit = QtGui.QLineEdit()
        self.modelNameSelect = QtGui.QComboBox()
        self.saveBtn = QtGui.QPushButton("Save")
        self.ipRadio = QtGui.QRadioButton("IP:")
        self.nodeRadio = QtGui.QRadioButton("Node:")
        self.ipWidget = QtGui.QWidget()
        self.nodeEdit = QtGui.QLineEdit()
        self.nodeNameWidget = QtGui.QWidget()

        self.gatherInfo()
        self.initUI()

    def gatherInfo(self):
        try:
            output = subprocess.check_output(["brsaneconfig3", "-q"]).splitlines()
        except subprocess.CalledProcessError:
            # TODO: Handle this
            pass

        # Get index of the header that separates the list of supported models from the user's devices
        headerLoc = output.index(ConfigWindow.HEADER)

        # Strip out blank lines from list of models
        modelNames = [item for item in output[0:headerLoc] if len(item) > 0]
        # Don't include the header in the user's devices
        myDevicesInfo = output[headerLoc + 1:]

        # Populate self.supportedModels and set self.devicesList
        for model in modelNames:
            try:
                num, name = model.split()
                # Remove surrounding quotation marks
                self.supportedModels.append(name.replace('"', ''))
            except ValueError:
                #print "Ignoring model {}, no model name given".format(num)
                continue
        self.supportedModels.sort()

        # Populate self.myDevices
        for deviceInfo in myDevicesInfo:
            device = BrotherDevice(deviceInfo)
            self.myDevices.append(device)

        # self.deviceList contains only the names from self.myDevices
        self.deviceList.addItems([d.name for d in self.myDevices])
        self.deviceList.setCurrentRow(0)

    def initUI(self):
        # TODO: Possibly separate each block of code into its own function
        # Device list on left
        deviceListPanel = QtGui.QVBoxLayout()
        deviceListPanel.addWidget(self.deviceList)
        addDeviceBtn = QtGui.QPushButton("Add New Device")
        deviceListPanel.addWidget(addDeviceBtn)
        self.deviceList.currentItemChanged.connect(self.onSelectedDeviceChange)

        # Main layout
        mainHBox = QtGui.QHBoxLayout()
        mainHBox.addLayout(deviceListPanel)
        mainWidget = QtGui.QWidget()
        mainWidget.setLayout(mainHBox)
        self.setCentralWidget(mainWidget)
        # Do not allow resizing the devices list
        self.deviceList.setMaximumWidth(self.deviceList.sizeHintForColumn(0) + WIDTH_FUDGE)
        self.deviceList.setMinimumWidth(addDeviceBtn.minimumSizeHint().width())

        # Friendly name, user input
        friendlyName = QtGui.QLabel('Name:')
        # Verify text as it is typed so that we can display a message
        self.friendlyNameEdit.textEdited.connect(self.onNameInputChange)

        # Model name, combo box
        modelName = QtGui.QLabel('Model:')
        self.modelNameSelect.addItems(self.supportedModels)
        # http://stackoverflow.com/a/11254459/1693087
        # Apply stylesheet to allow limiting max number of items
        self.modelNameSelect.setStyleSheet("QComboBox { combobox-popup: 0; }")
        self.modelNameSelect.setMaxVisibleItems(10)
        self.modelNameSelect.currentIndexChanged.connect(self.onModelNameChange)

        # IP address or node name, radio buttons
        group = QtGui.QButtonGroup()
        group.addButton(self.ipRadio)
        group.addButton(self.nodeRadio)
        group.setExclusive(True)

        # IP address, split into four 3-digit sections
        # TODO: React to changes
        ipSegmentValidator = QtGui.QIntValidator(001, 999)
        ipEdit1 = QtGui.QLineEdit()
        ipEdit2 = QtGui.QLineEdit()
        ipEdit3 = QtGui.QLineEdit()
        ipEdit4 = QtGui.QLineEdit()
        self.ipEdits = [ipEdit1, ipEdit2, ipEdit3, ipEdit4]
        ipLayout = QtGui.QHBoxLayout()
        ipLayout.setSpacing(0)

        # Only allow 3 digits in each part of the IP
        for i, textbox in enumerate(self.ipEdits):
            textbox.setValidator(ipSegmentValidator)
            textbox.setMaxLength(3)
            textbox.setAlignment(QtCore.Qt.AlignCenter)
            if i > 0:
                ipLayout.addWidget(QtGui.QLabel("."))
            ipLayout.addWidget(self.ipEdits[i])

        self.ipWidget.setLayout(ipLayout)
        self.ipWidget.setContentsMargins(0, 0, 0, 0)
        self.ipWidget.layout().setContentsMargins(0, 0, 0, 0)

        # Node name, user does not need to worry about the "BRN_" prefix
        # TODO: React to changes
        nodePrefix = QtGui.QLabel("BRN_")
        nodeNameLayout = QtGui.QHBoxLayout()
        nodeNameLayout.setSpacing(0)
        nodeNameLayout.addWidget(nodePrefix)
        nodeNameLayout.addWidget(self.nodeEdit)
        self.nodeNameWidget = QtGui.QWidget()
        self.nodeNameWidget.setLayout(nodeNameLayout)
        self.nodeNameWidget.setContentsMargins(0, 0, 0, 0)
        self.nodeNameWidget.layout().setContentsMargins(0, 0, 0, 0)

        # "Save" and "delete" buttons
        # TODO: Attach actions
        self.saveBtn.setEnabled(False)
        deleteButton = QtGui.QPushButton("Delete")

        buttonsLayout = QtGui.QHBoxLayout()
        buttonsLayout.addWidget(deleteButton)
        buttonsLayout.addWidget(self.saveBtn)
        buttonsWidget = QtGui.QWidget()
        buttonsWidget.setLayout(buttonsLayout)
        buttonsWidget.setContentsMargins(0, 0, 0, 0)
        buttonsWidget.layout().setContentsMargins(0, 0, 0, 0)

        # Info for the selected device is displayed to the right of the device list
        grid = QtGui.QGridLayout()
        grid.setSpacing(10)

        grid.addWidget(friendlyName, 0, 0)
        grid.addWidget(self.friendlyNameEdit, 0, 1)

        grid.addWidget(modelName, 1, 0)
        grid.addWidget(self.modelNameSelect, 1, 1)

        grid.addWidget(self.ipRadio, 2, 0)
        grid.addWidget(self.ipWidget, 2, 1)
        grid.addWidget(self.nodeRadio, 3, 0)
        grid.addWidget(self.nodeNameWidget, 3, 1)

        grid.setRowStretch(4, 1)
        grid.addWidget(buttonsWidget, 5, 0, 1, 2)

        mainHBox.addLayout(grid)

        # Get info about currently-selected device and populate fields
        self.currentDevice = self.myDevices[self.deviceList.currentRow()]
        self.updateFields()
        print "Initially selected device is", self.currentDevice

        # Resize and show
        self.resize(self.minimumSizeHint().width(), self.minimumSizeHint().height())
        self.setWindowTitle(WINDOW_TITLE)
        self.center()
        self.show()

    # Center the window on the screen
    def center(self):
        ourRect = self.frameGeometry()
        screenCenter = QtGui.QDesktopWidget().availableGeometry().center()
        ourRect.moveCenter(screenCenter)
        self.move(ourRect.topLeft())

    def updateFields(self):
        self.friendlyNameEdit.setText(self.currentDevice.name)

        # Set content of model name dropdown
        self.modelNameSelect.setCurrentIndex(self.modelNameSelect.findText(self.currentDevice.model))

        # Populate IP or node name
        if self.currentDevice.usesIP:
            self.ipWidget.setEnabled(True)
            self.ipRadio.setChecked(True)
            for textbox, segment in zip(self.ipEdits, self.currentDevice.addr.split('.')):
                textbox.setText(segment)
            self.nodeNameWidget.setEnabled(False)
            self.nodeEdit.setText("")
        else:
            self.nodeNameWidget.setEnabled(True)
            self.nodeRadio.setChecked(True)
            self.nodeEdit.setText(self.currentDevice.addr)
            self.ipWidget.setEnabled(False)
            for textbox in self.ipEdits:
                textbox.setText("")

    # React when self.friendlyNameEdit changes
    def onNameInputChange(self):
        # Disallow whitespace
        if not self.noWhitespaceRegex.exactMatch(self.friendlyNameEdit.text()) and len(self.friendlyNameEdit.text()) > 0:
            QtGui.QMessageBox.warning(None, "Error", "The name cannot contain whitespace.")
            self.friendlyNameEdit.setText(self.friendlyNameEdit.text()[:-1])
        # Check if modified from original
        if self.friendlyNameEdit.text() != self.currentDevice.name:
            self.hasEditedCurrentDevice = True
            self.saveBtn.setEnabled(True)
        else:
            self.hasEditedCurrentDevice = False
            self.saveBtn.setEnabled(False)

    # React when self.modelNameSelect changes
    def onModelNameChange(self):
        selectedModel = self.modelNameSelect.currentText()
        if selectedModel != self.currentDevice.model:
            self.hasEditedCurrentDevice = True
            self.saveBtn.setEnabled(True)
        else:
            self.hasEditedCurrentDevice = False
            self.saveBtn.setEnabled(False)

    # React when a different device is selected in self.deviceList
    # TODO: Don't save if the name is empty
    def onSelectedDeviceChange(self, currentItem, previousItem):
        if self.hasEditedCurrentDevice:
            saveChanges = QtGui.QMessageBox.question(None, "", "Save changes to current device?",
                                                     QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
            if saveChanges:
                BrotherDevice.removeDevice(self.currentDevice.name)
                self.updateCurrentDevice()
                BrotherDevice.addDevice(self.currentDevice)
                # Apparently changing the underlying list isn't enough, must manually update the label
                previousItem.setText(self.friendlyNameEdit.text())

        self.hasEditedCurrentDevice = False
        self.saveBtn.setEnabled(False)

        row = self.deviceList.currentRow()
        self.currentDevice = self.myDevices[row]
        self.updateFields()
        print "Device at row {} is {}".format(row, self.myDevices[row])

    # Update the properties of self.currentDevice based on the entered values
    def updateCurrentDevice(self):
        self.currentDevice.name = self.friendlyNameEdit.text()
        self.currentDevice.model = self.modelNameSelect.currentText()
        if self.ipRadio.isChecked():
            self.currentDevice.usesIP = True
            ip = ''
            for i, textbox in enumerate(self.ipEdits):
                if i > 0:
                    ip += "."
                ip += textbox.text().rightJustified(3)
            self.currentDevice.addr = ip
        else:
            self.currentDevice.usesIP = False
            self.currentDevice.addr = self.nodeEdit.text()

def main():
    # Every PyQt4 application must create an application object
    app = QtGui.QApplication(sys.argv)

    window = ConfigWindow()

    # Because 'exec' is a Python keyword, Qt uses 'exec_' instead
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()<commit_msg>Detect IP addr change, correctly pad with zeros<commit_after>#! /usr/bin/env python

import sys
import subprocess
from PyQt4 import QtGui, QtCore

DEBUG = True
WINDOW_TITLE = 'brsaneconfig3'
WIDTH_FUDGE = 30

class BrotherDevice:
    def __init__(self, info):
        # Parse info
        num, friendlyName, modelName, ipOrNode = info.split()
        # Check if IP or node name is specified
        self.usesIP = ipOrNode.startswith("I:")
        self.devID = num
        self.name = friendlyName
        # Remove quotation marks surrounding the model name
        self.model = modelName.replace('"', '')
        # Remove prefixes
        self.addr = ipOrNode.replace("I:", '').replace("N:BRN_", "")

    def __str__(self):
        return "devID: {}, name: {}, model: {}, addr: {} ({})".format(self.devID, self.name, self.model, self.addr,
                                                                      'IP' if self.usesIP else 'node')

    @staticmethod
    def addDevice(device):
        try:
            output = subprocess.check_output(["brsaneconfig3", "-a",
                                              "name={}".format(device.name),
                                              "model={}".format(device.model),
                                              "ip={}".format(device.addr) if device.usesIP else "nodename=BRN_{}".format(device.addr)])
        except subprocess.CalledProcessError:
            # TODO: Handle this
            pass

    @staticmethod
    def removeDevice(name):
        try:
            output = subprocess.check_output(["brsaneconfig3", "-r", name])
        except subprocess.CalledProcessError:
            # TODO: Handle this
            pass

class ConfigWindow(QtGui.QMainWindow):
    HEADER = "Devices on network"

    def __init__(self):
        # The super() method returns the parent object of the given class
        super(ConfigWindow, self).__init__()

        # Data structures and variables
        self.supportedModels = []
        self.myDevices = []
        self.currentDevice = []
        self.noWhitespaceRegex = QtCore.QRegExp('[^\s]+')
        self.hasEditedCurrentDevice = False
        self.ipEdits = []

        # Interface elements
        self.deviceList = QtGui.QListWidget()
        self.friendlyNameEdit = QtGui.QLineEdit()
        self.modelNameSelect = QtGui.QComboBox()
        self.saveBtn = QtGui.QPushButton("Save")
        self.ipRadio = QtGui.QRadioButton("IP:")
        self.nodeRadio = QtGui.QRadioButton("Node:")
        self.ipWidget = QtGui.QWidget()
        self.nodeEdit = QtGui.QLineEdit()
        self.nodeNameWidget = QtGui.QWidget()

        self.gatherInfo()
        self.initUI()

    def gatherInfo(self):
        try:
            output = subprocess.check_output(["brsaneconfig3", "-q"]).splitlines()
        except subprocess.CalledProcessError:
            # TODO: Handle this
            pass

        # Get index of the header that separates the list of supported models from the user's devices
        headerLoc = output.index(ConfigWindow.HEADER)

        # Strip out blank lines from list of models
        modelNames = [item for item in output[0:headerLoc] if len(item) > 0]
        # Don't include the header in the user's devices
        myDevicesInfo = output[headerLoc + 1:]

        # Populate self.supportedModels and set self.devicesList
        for model in modelNames:
            try:
                num, name = model.split()
                # Remove surrounding quotation marks
                self.supportedModels.append(name.replace('"', ''))
            except ValueError:
                #print "Ignoring model {}, no model name given".format(num)
                continue
        self.supportedModels.sort()

        # Populate self.myDevices
        for deviceInfo in myDevicesInfo:
            device = BrotherDevice(deviceInfo)
            self.myDevices.append(device)

        # self.deviceList contains only the names from self.myDevices
        self.deviceList.addItems([d.name for d in self.myDevices])
        self.deviceList.setCurrentRow(0)

    def initUI(self):
        # TODO: Possibly separate each block of code into its own function
        # Device list on left
        deviceListPanel = QtGui.QVBoxLayout()
        deviceListPanel.addWidget(self.deviceList)
        addDeviceBtn = QtGui.QPushButton("Add New Device")
        deviceListPanel.addWidget(addDeviceBtn)
        self.deviceList.currentItemChanged.connect(self.onSelectedDeviceChange)

        # Main layout
        mainHBox = QtGui.QHBoxLayout()
        mainHBox.addLayout(deviceListPanel)
        mainWidget = QtGui.QWidget()
        mainWidget.setLayout(mainHBox)
        self.setCentralWidget(mainWidget)
        # Do not allow resizing the devices list
        self.deviceList.setMaximumWidth(self.deviceList.sizeHintForColumn(0) + WIDTH_FUDGE)
        self.deviceList.setMinimumWidth(addDeviceBtn.minimumSizeHint().width())

        # Friendly name, user input
        friendlyName = QtGui.QLabel('Name:')
        # Verify text as it is typed so that we can display a message
        self.friendlyNameEdit.textEdited.connect(self.onNameInputChange)

        # Model name, combo box
        modelName = QtGui.QLabel('Model:')
        self.modelNameSelect.addItems(self.supportedModels)
        # http://stackoverflow.com/a/11254459/1693087
        # Apply stylesheet to allow limiting max number of items
        self.modelNameSelect.setStyleSheet("QComboBox { combobox-popup: 0; }")
        self.modelNameSelect.setMaxVisibleItems(10)
        self.modelNameSelect.currentIndexChanged.connect(self.onModelNameChange)

        # IP address or node name, radio buttons
        group = QtGui.QButtonGroup()
        group.addButton(self.ipRadio)
        group.addButton(self.nodeRadio)
        group.setExclusive(True)

        # IP address, split into four 3-digit sections
        # TODO: React to changes
        ipSegmentValidator = QtGui.QIntValidator(001, 999)
        ipEdit1 = QtGui.QLineEdit()
        ipEdit2 = QtGui.QLineEdit()
        ipEdit3 = QtGui.QLineEdit()
        ipEdit4 = QtGui.QLineEdit()
        self.ipEdits = [ipEdit1, ipEdit2, ipEdit3, ipEdit4]
        ipLayout = QtGui.QHBoxLayout()
        ipLayout.setSpacing(0)

        # Only allow 3 digits in each part of the IP
        for i, textbox in enumerate(self.ipEdits):
            textbox.setValidator(ipSegmentValidator)
            textbox.setMaxLength(3)
            textbox.setAlignment(QtCore.Qt.AlignCenter)
            textbox.textEdited.connect(self.onIPChange)
            if i > 0:
                ipLayout.addWidget(QtGui.QLabel("."))
            ipLayout.addWidget(self.ipEdits[i])

        self.ipWidget.setLayout(ipLayout)
        self.ipWidget.setContentsMargins(0, 0, 0, 0)
        self.ipWidget.layout().setContentsMargins(0, 0, 0, 0)

        # Node name, user does not need to worry about the "BRN_" prefix
        # TODO: React to changes
        nodePrefix = QtGui.QLabel("BRN_")
        nodeNameLayout = QtGui.QHBoxLayout()
        nodeNameLayout.setSpacing(0)
        nodeNameLayout.addWidget(nodePrefix)
        nodeNameLayout.addWidget(self.nodeEdit)
        self.nodeNameWidget = QtGui.QWidget()
        self.nodeNameWidget.setLayout(nodeNameLayout)
        self.nodeNameWidget.setContentsMargins(0, 0, 0, 0)
        self.nodeNameWidget.layout().setContentsMargins(0, 0, 0, 0)

        # "Save" and "delete" buttons
        # TODO: Attach actions
        self.saveBtn.setEnabled(False)
        deleteButton = QtGui.QPushButton("Delete")

        buttonsLayout = QtGui.QHBoxLayout()
        buttonsLayout.addWidget(deleteButton)
        buttonsLayout.addWidget(self.saveBtn)
        buttonsWidget = QtGui.QWidget()
        buttonsWidget.setLayout(buttonsLayout)
        buttonsWidget.setContentsMargins(0, 0, 0, 0)
        buttonsWidget.layout().setContentsMargins(0, 0, 0, 0)

        # Info for the selected device is displayed to the right of the device list
        grid = QtGui.QGridLayout()
        grid.setSpacing(10)

        grid.addWidget(friendlyName, 0, 0)
        grid.addWidget(self.friendlyNameEdit, 0, 1)

        grid.addWidget(modelName, 1, 0)
        grid.addWidget(self.modelNameSelect, 1, 1)

        grid.addWidget(self.ipRadio, 2, 0)
        grid.addWidget(self.ipWidget, 2, 1)
        grid.addWidget(self.nodeRadio, 3, 0)
        grid.addWidget(self.nodeNameWidget, 3, 1)

        grid.setRowStretch(4, 1)
        grid.addWidget(buttonsWidget, 5, 0, 1, 2)

        mainHBox.addLayout(grid)

        # Get info about currently-selected device and populate fields
        self.currentDevice = self.myDevices[self.deviceList.currentRow()]
        self.updateFields()
        print "Initially selected device is", self.currentDevice

        # Resize and show
        self.resize(self.minimumSizeHint().width(), self.minimumSizeHint().height())
        self.setWindowTitle(WINDOW_TITLE)
        self.center()
        self.show()

    # Center the window on the screen
    def center(self):
        ourRect = self.frameGeometry()
        screenCenter = QtGui.QDesktopWidget().availableGeometry().center()
        ourRect.moveCenter(screenCenter)
        self.move(ourRect.topLeft())

    def updateFields(self):
        self.friendlyNameEdit.setText(self.currentDevice.name)

        # Set content of model name dropdown
        self.modelNameSelect.setCurrentIndex(self.modelNameSelect.findText(self.currentDevice.model))

        # Populate IP or node name
        if self.currentDevice.usesIP:
            self.ipWidget.setEnabled(True)
            self.ipRadio.setChecked(True)
            for textbox, segment in zip(self.ipEdits, self.currentDevice.addr.split('.')):
                textbox.setText(segment)
            self.nodeNameWidget.setEnabled(False)
            self.nodeEdit.setText("")
        else:
            self.nodeNameWidget.setEnabled(True)
            self.nodeRadio.setChecked(True)
            self.nodeEdit.setText(self.currentDevice.addr)
            self.ipWidget.setEnabled(False)
            for textbox in self.ipEdits:
                textbox.setText("")

    # React when self.friendlyNameEdit changes
    def onNameInputChange(self):
        # Disallow whitespace
        if not self.noWhitespaceRegex.exactMatch(self.friendlyNameEdit.text()) and len(self.friendlyNameEdit.text()) > 0:
            QtGui.QMessageBox.warning(None, "Error", "The name cannot contain whitespace.")
            self.friendlyNameEdit.setText(self.friendlyNameEdit.text()[:-1])
        # Check if modified from original
        if self.friendlyNameEdit.text() != self.currentDevice.name:
            self.hasEditedCurrentDevice = True
            self.saveBtn.setEnabled(True)
        else:
            self.hasEditedCurrentDevice = False
            self.saveBtn.setEnabled(False)

    # React when self.modelNameSelect changes
    def onModelNameChange(self):
        selectedModel = self.modelNameSelect.currentText()
        if selectedModel != self.currentDevice.model:
            self.hasEditedCurrentDevice = True
            self.saveBtn.setEnabled(True)
        else:
            self.hasEditedCurrentDevice = False
            self.saveBtn.setEnabled(False)

    # React when a different device is selected in self.deviceList
    # TODO: Don't save if the name is empty
    def onSelectedDeviceChange(self, currentItem, previousItem):
        if self.hasEditedCurrentDevice:
            saveChanges = QtGui.QMessageBox.question(None, "", "Save changes to current device?",
                                                     QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
            if saveChanges:
                BrotherDevice.removeDevice(self.currentDevice.name)
                self.updateCurrentDevice()
                BrotherDevice.addDevice(self.currentDevice)
                # Apparently changing the underlying list isn't enough, must manually update the label
                previousItem.setText(self.friendlyNameEdit.text())

        self.hasEditedCurrentDevice = False
        self.saveBtn.setEnabled(False)

        row = self.deviceList.currentRow()
        self.currentDevice = self.myDevices[row]
        self.updateFields()
        print "Device at row {} is {}".format(row, self.myDevices[row])

    # React when IP address changes
    def onIPChange(self):
        ip = ''
        for i, textbox in enumerate(self.ipEdits):
            if i > 0:
                ip += "."
            ip += textbox.text().rightJustified(3, QtCore.QChar('0'))
        print "ip is", ip
        if self.currentDevice.addr != ip:
            self.hasEditedCurrentDevice = True
            self.saveBtn.setEnabled(True)
        else:
            self.hasEditedCurrentDevice = False
            self.saveBtn.setEnabled(False)

    # Update the properties of self.currentDevice based on the entered values
    def updateCurrentDevice(self):
        self.currentDevice.name = self.friendlyNameEdit.text()
        self.currentDevice.model = self.modelNameSelect.currentText()
        if self.ipRadio.isChecked():
            self.currentDevice.usesIP = True
            ip = ''
            for i, textbox in enumerate(self.ipEdits):
                if i > 0:
                    ip += "."
                ip += textbox.text().rightJustified(3, QtCore.QChar('0'))
            self.currentDevice.addr = ip
        else:
            self.currentDevice.usesIP = False
            self.currentDevice.addr = self.nodeEdit.text()

def main():
    # Every PyQt4 application must create an application object
    app = QtGui.QApplication(sys.argv)

    window = ConfigWindow()

    # Because 'exec' is a Python keyword, Qt uses 'exec_' instead
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()<|endoftext|>


<commit_before>import helper
import kivy
import os
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.config import Config
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
from kivy.lang import Builder
from kivy.clock import Clock

kivy.require("1.9.1")
Config.set('graphics', 'fullscreen', '1')

os.environ['DISPLAY'] = ":0"

class HomeScreen(Screen):
    pass

class AlarmScreen(Screen):
    pass

class LightScreen(Screen):
    pass

class MediaScreen(Screen):
    pass

class OptionScreen(Screen):
    pass

class ScreenManagement(ScreenManager):
    pass

class TriggerScreen(Screen):
    pass

class Profile1(Label):
    def __init__(self, **kwargs):
        # kivy stuff
        super(Profile1, self).__init__(**kwargs)

class Profile2(Label):
    def __init__(self, **kwargs):
        # kivy stuff
        super(Profile2, self).__init__(**kwargs)

class LightLabel(Label):
    def __init__(self, **kwargs):
        # kivy stuff
        super(LightLabel, self).__init__(**kwargs)
        Clock.schedule_interval(self.update, 1)

    def update(self, *args):
        comms = helper.get_comms()
        ## DISPLAY DETECTED USERS HERE
        self.text = "Hello Light Label!"

class SystemInfo(Label):
    def __init__(self, **kwargs):
        # kivy stuff
        super(SystemInfo, self).__init__(**kwargs)

class StatusBox(BoxLayout):
    def __init__(self, **kwargs):
        # kivy stuff
        super(StatusBox, self).__init__(**kwargs)
        # make the button update
        Clock.schedule_interval(self.update, .1)
        self.id = 'status'
        self.alarm = helper.get_alarm()
        self.p1 = Profile1()
        self.p2 = Profile2()
        self.sys = SystemInfo()
        self.add_widget(self.p1)
        self.add_widget(self.sys)
        self.add_widget(self.p2)

    def update(self, *args):
        self.p1.text = self.alarm.fetch(0)
        self.p2.text = self.alarm.fetch(1)
        self.sys.text = self.alarm.now()
        for profile in self.alarm.profiles:
            if profile.running:
                # if the alarm is running, change screen
                App.get_running_app().root.current = 'trigger'
                comms = helper.get_comms()
                comms.play_fx(helper.DING2)

class MyButton(Button):
    def __init__(self, **kwargs):
        # kivy stuff
        super(MyButton, self).__init__(**kwargs)
        self.alarm = helper.get_alarm()
        self.active_profile = "PROFILE 1"

    def ding1(self):
        helper.comms.play_fx(helper.DING1)

    def ding2(self):
        helper.comms.play_fx(helper.DING2)

    def adjust_alarm(self, btn, change):
        self.alarm.adjust_alarm(btn.text, change)

class MyProfileButton(MyButton):
    def __init__(self, **kwargs):
        # kivy stuff
        super(MyProfileButton, self).__init__(**kwargs)
        self.active_profile = "PROFILE 1"

    def switch_profile(self):
        if self.active_profile == "PROFILE 2":

            self.active_profile = "PROFILE 1"
        else:
            self.active_profile = "PROFILE 2"
        self.text = self.active_profile
<commit_msg>testing the label<commit_after>import helper
import kivy
import os
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.config import Config
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
from kivy.lang import Builder
from kivy.clock import Clock

kivy.require("1.9.1")
Config.set('graphics', 'fullscreen', '1')

os.environ['DISPLAY'] = ":0"

class HomeScreen(Screen):
    pass

class AlarmScreen(Screen):
    pass

class LightScreen(Screen):
    pass

class MediaScreen(Screen):
    pass

class OptionScreen(Screen):
    pass

class ScreenManagement(ScreenManager):
    pass

class TriggerScreen(Screen):
    pass

class Profile1(Label):
    def __init__(self, **kwargs):
        # kivy stuff
        super(Profile1, self).__init__(**kwargs)

class Profile2(Label):
    def __init__(self, **kwargs):
        # kivy stuff
        super(Profile2, self).__init__(**kwargs)

class LightLabel(Label):
    def __init__(self, **kwargs):
        # kivy stuff
        super(LightLabel, self).__init__(**kwargs)
        Clock.schedule_interval(self.update, 1)

    def update(self, *args):
        comms = helper.get_comms()
        ## DISPLAY DETECTED USERS HERE
        self.text = "Hello Light Label!"
        self.text = self.text + "\nHello again!"

class SystemInfo(Label):
    def __init__(self, **kwargs):
        # kivy stuff
        super(SystemInfo, self).__init__(**kwargs)

class StatusBox(BoxLayout):
    def __init__(self, **kwargs):
        # kivy stuff
        super(StatusBox, self).__init__(**kwargs)
        # make the button update
        Clock.schedule_interval(self.update, .1)
        self.id = 'status'
        self.alarm = helper.get_alarm()
        self.p1 = Profile1()
        self.p2 = Profile2()
        self.sys = SystemInfo()
        self.add_widget(self.p1)
        self.add_widget(self.sys)
        self.add_widget(self.p2)

    def update(self, *args):
        self.p1.text = self.alarm.fetch(0)
        self.p2.text = self.alarm.fetch(1)
        self.sys.text = self.alarm.now()
        for profile in self.alarm.profiles:
            if profile.running:
                # if the alarm is running, change screen
                App.get_running_app().root.current = 'trigger'
                comms = helper.get_comms()
                comms.play_fx(helper.DING2)

class MyButton(Button):
    def __init__(self, **kwargs):
        # kivy stuff
        super(MyButton, self).__init__(**kwargs)
        self.alarm = helper.get_alarm()
        self.active_profile = "PROFILE 1"

    def ding1(self):
        helper.comms.play_fx(helper.DING1)

    def ding2(self):
        helper.comms.play_fx(helper.DING2)

    def adjust_alarm(self, btn, change):
        self.alarm.adjust_alarm(btn.text, change)

class MyProfileButton(MyButton):
    def __init__(self, **kwargs):
        # kivy stuff
        super(MyProfileButton, self).__init__(**kwargs)
        self.active_profile = "PROFILE 1"

    def switch_profile(self):
        if self.active_profile == "PROFILE 2":

            self.active_profile = "PROFILE 1"
        else:
            self.active_profile = "PROFILE 2"
        self.text = self.active_profile
<|endoftext|>


<commit_before># GUI port

import Tkinter as tk
top = Tkinter.Tk()
# Code to add widgets will go here...

top.mainloop()
<commit_msg>Delete gui.py<commit_after><|endoftext|>


<commit_before>#!/usr/bin/env python
# Contact: Jacob Schreiber
#          jacobtribe@yahoo.com
# hmm.py

'''
This module serves as a collection for the various HMMs which are written for the nanopore lab.
HMMs must be written using Yet Another Hidden Markov Model (yahmm) package. When adding a new
HMM to the list, please follow the pattern set up, and also remember to update the factory at
the bottom. Use the format that the string is the same as the name of the function which returns
that HMM.
'''

import numpy as np
import pyximport
pyximport.install( setup_args={'include_dirs':np.get_include()})
from yahmm import *

def AbasicFinder():
	'''
	This HMM will attempt to find abasics, when abasics are seen as
	spikes of current up to approximately ~30 pA. Usual conditions
	this works for are 180 mV in a-haemolysin porin.
	'''

	model = Model( name="Abasic Finder" )

	s1 = State( NormalDistribution( 40.00, 7 ), name="1" )
	s2 = State( NormalDistribution( 20.00, 5 ), name="2" )
	s3 = State( NormalDistribution( 30.75, 2 ), name="3" )

	model.add_state( s1 )
	model.add_state( s2 )
	model.add_state( s3 )

	model.add_transition( model.start, s1, 1.00 )
	model.add_transition( s1, s2, 1.00 )
	model.add_transition( s2, s2, 0.80 )
	model.add_transition( s2, s3, 0.10 )
	model.add_transition( s3, s2, 0.80 )
	model.add_transition( s3, s3, 0.10 )
	model.add_transition( s2, model.end, 0.10 )
	model.add_transition( s3, model.end, 0.10 )

	model.bake()
	return model

def tRNAbasic_A8T0H11():
	model = Model( name="A8T0H115_Model")

	s1 = State( NormalDistribution( 40, 7.75 ), name="1", color='r' )
	s2 = State( NormalDistribution( 29.1, 1.15 ), name="2", color='y' )
	s3 = State( NormalDistribution( 24.29, 0.155), name="3", color='b' )
	s4 = State( NormalDistribution( 26.04, 0.352 ), name="4", color='b' )
	s5 = State( NormalDistribution( 23.8, 0.427 ), name="5", color='b' )
	s6 = State( NormalDistribution( 28.37, 0.464 ), name="6", color='g' )
	s7 = State( NormalDistribution( 26.8, 0.8678 ), name="7", color='b' )
	s8 = State( NormalDistribution( 25.4, 0.533 ), name="8", color='b' )
	s9 = State( NormalDistribution( 22.77, 0.481 ), name="9", color='b' )
	s10 = State( NormalDistribution( 30.06, 1.46 ), name="10", color='m' )
	s11 = State( NormalDistribution( 24.9, 2.19 ), name="11", color='b' )

	states = [ s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11 ]
	for state in states:
		model.add_state( state )

	model.add_transition( model.start, s1, 0.10 )
	model.add_transition( model.start, s2, 0.10 )
	model.add_transition( model.start, s3, 0.70 )
	model.add_transition( model.start, s4, 0.10 )
	model.add_transition( s1, s1, 0.10 )
	model.add_transition( s1, s2, 0.30 )
	model.add_transition( s1, s3, 0.60 )
	model.add_transition( s2, s2, 0.30 )
	model.add_transition( s2, s3, 0.70 )
	model.add_transition( s3, s3, 0.80 )
	model.add_transition( s3, s4, 0.20 )
	model.add_transition( s4, s4, 0.80 )
	model.add_transition( s4, s5, 0.20 )
	model.add_transition( s5, s5, 0.80 )
	model.add_transition( s5, s6, 0.20 )
	model.add_transition( s6, s6, 0.25 )
	model.add_transition( s6, s7, 0.70 )
	model.add_transition( s6, s8, 0.05 )
	model.add_transition( s7, s7, 0.30 )
	model.add_transition( s7, s8, 0.50 )
	model.add_transition( s7, model.end, 0.20 )
	model.add_transition( s8, s8, 0.70 )
	model.add_transition( s8, s9, 0.20 )
	model.add_transition( s8, model.end, 0.10 )
	model.add_transition( s9, s9, 0.70 )
	model.add_transition( s9, s10, 0.20 )
	model.add_transition( s9, model.end, 0.10 )
	model.add_transition( s10, s10, 0.10 )
	model.add_transition( s10, s11, 0.80 )
	model.add_transition( s10, model.end, 0.10 )
	model.add_transition( s11, s11, 0.5 )
	model.add_transition( s11, model.end, 0.5 )

	model.bake()
	return model

def Bifurcator():
	'''
	Attempts to parse an ionic current sequence that bifurcates between two
	ionic current states quickly, and many times.
	'''

	model = Model( name="Bifurcator" )

	s1 = State( NormalDistribution( 27.00, 1.00 ), name="1" )
	s2 = State( NormalDistribution( 33.00, 0.50 ), name="2" )

	model.add_state( s1 )
	model.add_state( s2 )

	model.add_transition( model.start, s1, 1.00 )
	model.add_transition( s1, s1, 0.45 )
	model.add_transition( s1, s2, 0.45 )
	model.add_transition( s1, model.end, 0.10 )
	model.add_transition( s2, s1, 0.45 )
	model.add_transition( s2, s2, 0.45 )
	model.add_transition( s2, model.end, 0.10 )

	model.bake()
	return model

hmm_factory = { 'Abasic Finder': AbasicFinder(),
		 		'Bifurcator': Bifurcator(),
		 		'tRNAbasic_A8T0H11': tRNAbasic_A8T0H11(),
		 	 }
<commit_msg>Added correct Profile HMMs<commit_after>#!/usr/bin/env python
# Contact: Jacob Schreiber
#          jacobtribe@yahoo.com
# hmm.py

'''
This module serves as a collection for the various HMMs which are written for the nanopore lab.
HMMs must be written using Yet Another Hidden Markov Model (yahmm) package. When adding a new
HMM to the list, please follow the pattern set up, and also remember to update the factory at
the bottom. Use the format that the string is the same as the name of the function which returns
that HMM.
'''

import numpy as np
import pyximport
pyximport.install( setup_args={'include_dirs':np.get_include()})
from yahmm import *

def Phi29ProfileHMM( distributions, name="Phi29 Profile HMM", low=0, high=50 ):
	"""
	Build a profile HMM based on a list of distributions. Includes:
		* Short backslips
	"""

	model = Model( name="{}-{}".format( name, len(distributions) ) )

	insert_distribution = UniformDistribution( low, high )
	last_match = model.start
	last_insert = State( insert_distribution, name="I0" )
	last_delete, last_sb = None, None

	model.add_transition( model.start, last_insert, 0.02 )
	model.add_transition( last_insert, last_insert, 0.70 )

	for i, distribution in enumerate( distributions ):
		match = State( distribution, name="M"+str(i+1), color=['r', 'y', 'g', 'm', 'b', '0.75', '0.50', '0.25', 'r', 'y', 'g' ][i] )
		insert = State( insert_distribution, name="I"+str(i+1) )
		delete = State( None, name="D"+str(i+1) )
		short_backslip = State( None, name="S"+str(i+1) ) if i >= 1 else None

		model.add_transition( last_match, match, 0.60 if last_sb is None else 0.55 if not last_match.is_silent() else 0.90 )
		model.add_transition( match, match, 0.30 )
		model.add_transition( last_match, delete, 0.08 if last_sb is None else 0.03 )
		model.add_transition( match, insert, 0.02 )

		model.add_transition( insert, insert, 0.70 )
		model.add_transition( last_insert, delete, 0.10 )
		model.add_transition( last_insert, match, 0.20 )

		model.add_transition( delete, insert, 0.10 )

		if short_backslip is not None:
			model.add_transition( match, short_backslip, 0.10 )
			model.add_transition( short_backslip, last_match, 0.95 if last_sb is not None else 1.00 )

			if last_sb is not None:
				model.add_transition( short_backslip, last_sb, 0.05 )

		if last_delete is not None:
			model.add_transition( last_delete, match, 0.70 )
			model.add_transition( last_delete, delete, 0.20 )

		last_match, last_insert, last_delete = match, insert, delete
		last_sb = short_backslip

	model.add_transition( last_delete, model.end, 0.95 )
	model.add_transition( last_insert, model.end, 0.70 )
	model.add_transition( last_match, model.end, 0.50 )

	model.bake()
	return model

def Hel308ProfileHMM( distributions, name="Hel308 Profile HMM",low=0, high=90,
	sb_length=1, lb_length=9 ):
	"""
	Generates a profile HMM for Hel308 specific data. Includes:
		* Short backslips
		* Long backslips
		* Oversegmentation handling via mixture model
		* Repeat backslip handling
	"""

	def match_model( distribution, name ):
		model = Model( name=name )

		match = State( distribution, name=name ) # Match without oversegmentation
		match_os = State( distribution, name=name ) # Match with oversegmentation

		model.add_transition( model.start, match, 0.75 )
		model.add_transition( model.start, match_os, 0.25 )

		model.add_transition( match, match, 0.10 )
		model.add_transition( match, model.end, 0.90 )

		model.add_transition( match_os, match_os, 0.80 )
		model.add_transition( match_os, model.end, 0.20 )
		return model

	model = Model("{}-{}".format( name, len(distributions) ) )

	insert_distribution = UniformDistribution( low, high )

	long_backslip_to = last_match = model.start
	last_insert = State( insert_distribution, name="I0" )
	last_delete, last_sb, last_lb = None, None, None

	matches = []
	model.add_transition( model.start, last_insert, 0.02 )
	model.add_transition( last_insert, last_insert, 0.70 )

	for i, distribution in enumerate( distributions ):
		match = match_model( distribution, name="M"+str(i+1) ) # Match state is now a short model
		insert = State( insert_distribution, name="I"+str(i+1) ) # Uniform distribution across the space
		delete = State( None, name="D"+str(i+1) ) # Silent state
		short_backslip = State( None, name="S"+str(i+1) ) if i >= sb_length else None # Silent state for moving backwards
		long_backslip = State( None, name="L"+str(i+1) ) if i >= lb_length else None # Silent state for moving backwards a lot

		model.add_model( match ) # Add that model to the main model

		model.add_transition( last_match.end if i > 0 else last_match, match.start,
			0.90 if i == 0 else 0.80 if i <= sb_length else 0.77 if i <= lb_length else 0.75 )

		model.add_transition( last_match if i == 0 else last_match.end, delete, 0.08 if i == 0 else 0.03 )
		model.add_transition( match.end, insert, 0.02 )

		model.add_transition( insert, insert, 0.50 )
		model.add_transition( insert, match.start, 0.20 )
		model.add_transition( last_insert, delete, 0.10 )
		model.add_transition( last_insert, match.start, 0.20 )

		model.add_transition( delete, insert, 0.10 )

		if short_backslip is not None:
			model.add_transition( match.end, short_backslip, 0.03 )
			model.add_transition( short_backslip, last_match.start, 0.80 if last_sb is not None else 0.95 )

			repeat_match = State( distribution=distribution, name=match.name )
			repeat_last_match = State( distribution=distributions[i-1], name=last_match.name )

			model.add_transition( short_backslip, repeat_last_match, .05 )
			model.add_transition( repeat_last_match, repeat_match, 0.70 )
			model.add_transition( repeat_last_match, match.start, 0.10 )
			model.add_transition( repeat_last_match, repeat_last_match, 0.20 )

			model.add_transition( repeat_match, repeat_match, 0.20 )
			model.add_transition( repeat_match, repeat_last_match, 0.80 )

			if last_sb is not None:
				model.add_transition( short_backslip, last_sb, 0.15 )

		if long_backslip is not None:
			model.add_transition( match.end, long_backslip, 0.02 )
			model.add_transition( long_backslip, matches[-lb_length].start, 0.75 if last_lb is not None else 1.00 )

			if last_lb is not None:
				model.add_transition( long_backslip, last_lb, 0.25 )

		if last_delete is not None:
			model.add_transition( last_delete, match.start, 0.70 )
			model.add_transition( last_delete, delete, 0.20 )

		last_match, last_insert, last_delete = match, insert, delete
		last_sb, last_lb = short_backslip, long_backslip
		matches.append( match ) # Append after, so index -i means move i states back

	model.add_transition( last_delete, model.end, 0.95 )
	model.add_transition( last_insert, model.end, 0.70 )
	model.add_transition( last_match.end, model.end, 0.50 )
	model.bake()
	return model

def tRNAbasic():
	mean_stds = [ ( 33, 1.75 ), ( 29.1, 1.15 ), ( 24.01, 0.45 ), ( 26.04, 0.43 ),
				  ( 24.4, 0.43 ), ( 29.17, 0.46 ), ( 26.5, 0.46 ),
				  ( 25.7, 0.43 ), ( 22.77, 0.48 ), ( 30.06, 0.46 ), ( 24.9, 1.19 ) ]

	distributions = [ NormalDistribution( m, s ) for m, s in mean_stds ]
	return Phi29ProfileHMM( distributions )

def tRNAbasic2():
	mean_stds = [ ( 33, 1.75 ), ( 29.1, 1.15 ), ( 24.01, 0.45 ), ( 26.04, 0.43 ), ( 24.4, 0.43 ), ( 29.17, 0.46 ), ( 26.5, 0.46 ), ( 25.7, 0.43 ), ( 22.77, 0.48 ), ( 30.06, 0.46 ), ( 24.9, 1.19 ) ]

	distributions = [ NormalDistribution( m, s ) for m, s in mean_stds ]
	return Hel308ProfileHMM( distributions )

def AbasicFinder():
	'''
	This HMM will attempt to find abasics, when abasics are seen as
	spikes of current up to approximately ~30 pA. Usual conditions
	this works for are 180 mV in a-haemolysin porin.
	'''

	model = Model( name="Abasic Finder" )

	s1 = State( NormalDistribution( 40.00, 7 ), name="1" )
	s2 = State( NormalDistribution( 20.00, 5 ), name="2" )
	s3 = State( NormalDistribution( 30.75, 2 ), name="3" )

	model.add_state( s1 )
	model.add_state( s2 )
	model.add_state( s3 )

	model.add_transition( model.start, s1, 1.00 )
	model.add_transition( s1, s2, 1.00 )
	model.add_transition( s2, s2, 0.80 )
	model.add_transition( s2, s3, 0.10 )
	model.add_transition( s3, s2, 0.80 )
	model.add_transition( s3, s3, 0.10 )
	model.add_transition( s2, model.end, 0.10 )
	model.add_transition( s3, model.end, 0.10 )
	model.bake()
	return model

def tRNAbasic_A8T0H11():
	model = Model( name="A8T0H115_Model")

	s1 = State( NormalDistribution( 33, 1.75 ), name="1", color='r' )
	s2 = State( NormalDistribution( 29.1, 1.15 ), name="2", color='y' )
	s3 = State( NormalDistribution( 24.01, 0.155), name="3", color='g' )
	s4 = State( NormalDistribution( 26.04, 0.43 ), name="4", color='m' )
	s5 = State( NormalDistribution( 24.4, 0.427 ), name="5", color='b' )
	s6 = State( NormalDistribution( 29.17, 0.464 ), name="6", color='0.25' )
	s7 = State( NormalDistribution( 27.1, 0.66 ), name="7", color='0.75' )
	s8 = State( NormalDistribution( 25.7, 0.43 ), name="8", color='k' )
	s9 = State( NormalDistribution( 22.77, 0.481 ), name="9", color='c' )
	s10 = State( NormalDistribution( 30.06, 0.46 ), name="10", color='0.10' )
	s11 = State( NormalDistribution( 24.9, 1.19 ), name="11", color='r' )

	states = [ s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11 ]
	for state in states:
		model.add_state( state )

	model.add_transition( model.start, s1, 0.10 )
	model.add_transition( model.start, s2, 0.70 )
	model.add_transition( model.start, s3, 0.10 )
	model.add_transition( model.start, s4, 0.10 )
	model.add_transition( s1, s1, 0.10 )
	model.add_transition( s1, s2, 0.30 )
	model.add_transition( s1, s3, 0.60 )
	model.add_transition( s2, s2, 0.30 )
	model.add_transition( s2, s3, 0.70 )
	model.add_transition( s3, s3, 0.60 )
	model.add_transition( s3, s4, 0.30 )
	model.add_transition( s4, s3, 0.10 )
	model.add_transition( s4, s4, 0.30 )
	model.add_transition( s4, s5, 0.60 )
	model.add_transition( s4, s6, 0.05 )
	model.add_transition( s5, s5, 0.49 )
	model.add_transition( s5, s6, 0.50 )
	model.add_transition( s6, s6, 0.25 )
	model.add_transition( s6, s7, 0.70 )
	model.add_transition( s6, s8, 0.05 )
	model.add_transition( s7, s7, 0.10 )
	model.add_transition( s7, s8, 0.90 )
	model.add_transition( s8, s8, 0.70 )
	model.add_transition( s8, s9, 0.20 )
	model.add_transition( s8, model.end, 0.10 )
	model.add_transition( s9, s9, 0.70 )
	model.add_transition( s9, s10, 0.20 )
	model.add_transition( s9, model.end, 0.10 )
	model.add_transition( s10, s10, 0.10 )
	model.add_transition( s10, s11, 0.80 )
	model.add_transition( s10, model.end, 0.10 )
	model.add_transition( s11, s11, 0.25 )
	model.add_transition( s11, model.end, 0.75 )

	model.bake()
	return model

def Bifurcator():
	'''
	Attempts to parse an ionic current sequence that bifurcates between two
	ionic current states quickly, and many times.
	'''

	model = Model( name="Bifurcator" )

	s1 = State( NormalDistribution( 27.00, 1.00 ), name="1" )
	s2 = State( NormalDistribution( 33.00, 0.50 ), name="2" )

	model.add_state( s1 )
	model.add_state( s2 )

	model.add_transition( model.start, s1, 1.00 )
	model.add_transition( s1, s1, 0.45 )
	model.add_transition( s1, s2, 0.45 )
	model.add_transition( s1, model.end, 0.10 )
	model.add_transition( s2, s1, 0.45 )
	model.add_transition( s2, s2, 0.45 )
	model.add_transition( s2, model.end, 0.10 )

	model.bake()
	return model

hmm_factory = { 'Abasic Finder': AbasicFinder(),
		 		'Bifurcator': Bifurcator(),
		 		'tRNAbasic_A8T0H11': tRNAbasic_A8T0H11(),
		 	 }
<|endoftext|>