<commit_before>import os
import logging
from threading import Thread
from time import sleep
from color import Color
import config as cfg
from neopixel import Adafruit_NeoPixel

class SequenceManager:
    def __init__(self):
        self.currentsequence = None
        self.thread = None

        self.strip = Adafruit_NeoPixel(
            cfg.LED_COUNT,
            cfg.LED_DATA_PIN,
            cfg.LED_FREQ_HZ,
            cfg.LED_DMA,
            cfg.LED_INVERT,
            cfg.LED_BRIGHTNESS,
            cfg.LED_CHANNEL,
            cfg.LED_STRIP)
        self.strip.begin()

    def stop(self):
        self.stopcurrentsequence()
        sleep(2)
        self.clear()

    def runsequence(self, sequence):
        if self.currentsequence == sequence:
            return

        print("Running sequence {}".format(sequence.name))
        self.currentsequence = sequence
        self.thread = Thread(target=self.runthread)
        self.thread.start()

    def stopcurrentsequence(self):
        self.currentsequence = None
        self.thread = None

    def runthread(self):
        seq = self.currentsequence
        loop = True
        while loop:
            for x in seq.data:
                if seq != self.currentsequence:
                    loop = False
                    break

                self.setrangecolor(x.startid, x.endid, x.color, x.delay > 2)
                if x.delay > 2:
                    sleep(x.delay/1000)

        if seq == self.currentsequence:
            self.thread = None

    def clear(self):
        self.setrangecolor(0, cfg.LED_COUNT, Color.black())

    def setrangecolor(self, start, end, color, write=True):
        if start == end:
            self.setcolor(start, color, False)
        else:
            for i in range(min(start, end), min(max(start, end), cfg.LED_COUNT)):
                self.setcolor(i, color, False)
        if write:
            self.strip.show()

    def setcolor(self, led, color, write=True):
        self.strip.setPixelColor(led, color.topixel())
        if write:
            self.strip.show()

class Sequence:
    def __init__(self):
        self.name = ""
        self.data = []

    def __eq__(self, other):
        if self is None or other is None:
            return False
        return self.name == other.name

    def __str__(self):
        return self.name

    @staticmethod
    def parsefile(path):
        print("Parsing file {}".format(path))
        file = open(path)
        seq = Sequence()
        seq.name = os.path.basename(os.path.splitext(path)[0])

        for i, line in enumerate(iter(file.readline, '')):
            line = line.strip()

            if line == "" or line.startswith("#") or line.startswith(";"):
                continue

            data = SequenceData.parseline(line)
            if data != None:
                seq.data.append(data)
            else:
                logging.error("Failed to parse line %s in file \\'%s\\'", i, path)

        return seq

class SequenceData:
    def __init__(self, startID, endID, color, delay):
        self.startid = startID
        self.endid = endID
        self.color = color
        self.delay = int(delay)

    def __str__(self):
        return "{},{},{},{}".format(self.startid, self.endid, str(self.color), self.delay)

    @staticmethod
    def parseline(line):
        items = line.split(",")
        if len(items) == 6:
            return SequenceData(
                int(items[0]),
                int(items[1]),
                Color(int(items[2]), int(items[3]), int(items[4])),
                int(items[5]))
        else:
            return None
<commit_msg>Added method for parsing a sequence from string<commit_after>import os
import logging
from threading import Thread
from time import sleep
from color import Color
import config as cfg
from neopixel import Adafruit_NeoPixel

class SequenceManager:
    def __init__(self):
        self.currentsequence = None
        self.thread = None

        self.strip = Adafruit_NeoPixel(
            cfg.LED_COUNT,
            cfg.LED_DATA_PIN,
            cfg.LED_FREQ_HZ,
            cfg.LED_DMA,
            cfg.LED_INVERT,
            cfg.LED_BRIGHTNESS,
            cfg.LED_CHANNEL,
            cfg.LED_STRIP)
        self.strip.begin()

    def stop(self):
        self.stopcurrentsequence()
        sleep(2)
        self.clear()

    def runsequence(self, sequence):
        if self.currentsequence == sequence:
            return

        print("Running sequence {}".format(sequence.name))
        self.currentsequence = sequence
        self.thread = Thread(target=self.runthread)
        self.thread.start()

    def stopcurrentsequence(self):
        self.currentsequence = None
        self.thread = None

    def runthread(self):
        seq = self.currentsequence
        loop = True
        while loop:
            for x in seq.data:
                if seq != self.currentsequence:
                    loop = False
                    break

                self.setrangecolor(x.startid, x.endid, x.color, x.delay > 2)
                if x.delay > 2:
                    sleep(x.delay/1000)

        if seq == self.currentsequence:
            self.thread = None

    def clear(self):
        self.setrangecolor(0, cfg.LED_COUNT, Color.black())

    def setrangecolor(self, start, end, color, write=True):
        if start == end:
            self.setcolor(start, color, False)
        else:
            for i in range(min(start, end), min(max(start, end), cfg.LED_COUNT)):
                self.setcolor(i, color, False)
        if write:
            self.strip.show()

    def setcolor(self, led, color, write=True):
        self.strip.setPixelColor(led, color.topixel())
        if write:
            self.strip.show()

class Sequence:
    def __init__(self):
        self.name = ""
        self.data = []

    def __eq__(self, other):
        if self is None or other is None:
            return False
        return self.name == other.name

    def __str__(self):
        return self.name

    @staticmethod
    def parsefile(path):
        print("Parsing sequence file {}".format(path))
        file = open(path)
        seq = Sequence()
        seq.name = os.path.basename(os.path.splitext(path)[0])

        for i, line in enumerate(iter(file.readline, '')):
            line = line.strip()

            if line == "" or line.startswith("#") or line.startswith(";"):
                continue

            data = SequenceData.parseline(line)
            if data != None:
                seq.data.append(data)
            else:
                logging.error("Failed to parse line %s in file \\'%s\\'", i, path)

        return seq

    @staticmethod
    def parsestring(string):
        print("Parsing sequence string")
        seq = Sequence()

        for i, line in enumerate(iter(string, '')):
            line = line.strip()

            if line == "" or line.startswith("#") or line.startswith(";"):
                continue

            data = SequenceData.parseline(line)
            if data != None:
                seq.data.append(data)
            else:
                logging.error("Failed to parse line %s (%s)", i, line)

        return seq

class SequenceData:
    def __init__(self, startID, endID, color, delay):
        self.startid = startID
        self.endid = endID
        self.color = color
        self.delay = int(delay)

    def __str__(self):
        return "{},{},{},{}".format(self.startid, self.endid, str(self.color), self.delay)

    @staticmethod
    def parseline(line):
        items = line.split(",")
        if len(items) == 6:
            return SequenceData(
                int(items[0]),
                int(items[1]),
                Color(int(items[2]), int(items[3]), int(items[4])),
                int(items[5]))
        else:
            return None
<|endoftext|>


<commit_before>"""
Create Triangulated Surface
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Create a surface from a set of points through a Delaunay triangulation.
"""

# sphinx_gallery_thumbnail_number = 2
import vtki
import numpy as np

################################################################################
#  First, create some points for the surface.

# Define a simple Gaussian surface
xx, yy = np.meshgrid(np.linspace(-200,200,20), np.linspace(-200,200,20))
A, b = 100, 100
zz = A*np.exp(-0.5*((xx/b)**2. + (yy/b)**2.))

# Get the points as a 2D NumPy array (N by 3)
points = np.c_[xx.reshape(-1), yy.reshape(-1), zz.reshape(-1)]
print(points[0:5, :])

################################################################################
# Now use those points to create a point cloud ``vtki`` data object. This will
# be encompassed in a :class:`vtki.PolyData` object.

# simply pass the numpy points to the PolyData constructor
cloud = vtki.PolyData(points)
vtki.set_plot_theme('doc')
cloud.plot(point_size=15, use_panel=False)

################################################################################
# Now that we have a ``vtki`` data structure of the points, we can perform a
# triangulation to turn those boring discrete points into a connected surface.

surf = cloud.delaunay_2d()
surf.plot(show_edges=True)
<commit_msg>remove bad argument from example<commit_after>"""
Create Triangulated Surface
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Create a surface from a set of points through a Delaunay triangulation.
"""

# sphinx_gallery_thumbnail_number = 2
import vtki
import numpy as np

################################################################################
#  First, create some points for the surface.

# Define a simple Gaussian surface
xx, yy = np.meshgrid(np.linspace(-200,200,20), np.linspace(-200,200,20))
A, b = 100, 100
zz = A*np.exp(-0.5*((xx/b)**2. + (yy/b)**2.))

# Get the points as a 2D NumPy array (N by 3)
points = np.c_[xx.reshape(-1), yy.reshape(-1), zz.reshape(-1)]
print(points[0:5, :])

################################################################################
# Now use those points to create a point cloud ``vtki`` data object. This will
# be encompassed in a :class:`vtki.PolyData` object.

# simply pass the numpy points to the PolyData constructor
cloud = vtki.PolyData(points)
vtki.set_plot_theme('doc')
cloud.plot(point_size=15)

################################################################################
# Now that we have a ``vtki`` data structure of the points, we can perform a
# triangulation to turn those boring discrete points into a connected surface.

surf = cloud.delaunay_2d()
surf.plot(show_edges=True)
<|endoftext|>


<commit_before># encoding=utf-8

import sys
import importlib
import math
from exc import (
    InvalidBotOutput,
    BotTimeoutException,
    MissedTargetException,
)

#Exit error codes
EXIT_ERROR_NUMBER_OF_PARAMS  = 1
EXIT_ERROR_MODULE = 2
EXIT_ERROR_BOT_INSTANCE = 3

FREE = 0
DAMAGE_DELTA = 5
INITIAL_HEALTH = 100
MISSED_TARGED = 'FAILED'
TARGET_HIT = 'SUCCESS'

def shoot_projectile(speed, angle, starting_height=0.0, gravity=9.8):
    '''
    returns a list of (x, y) projectile motion data points
    where:
    x axis is distance (or range) in meters
    y axis is height in meters
    '''
    data_xy = []
    t = 0.0
    angle = math.radians(angle)
    while True:
        # now calculate the height y
        y = starting_height + (t * speed * math.sin(angle)) - (gravity * t * t)/2
        # projectile has hit ground level
        if y < 0:
            break
        # calculate the distance x
        x = speed * math.cos(angle) * t
        # append the (x, y) tuple to the list
        data_xy.append((x, y))
        # use the time in increments of 0.1 seconds
        t += 0.1
    # TODO: match every (x, y) (or at least the last one), with our grid.
    return data_xy

class ArenaGrid(object):
    """The grid that represents the arena over which the players are playing.
    """
    def __init__(self, width, height):
        self.width = width
        self.height = height
        # TODO: we only need the X axis, not the whole matrix
        self.arena = [[FREE for _ in xrange(self.height)] for __ in xrange(self.width)]

    def copy_for_player(self):
        """Return just a copy of the portion we provide to the player."""
        return [self.arena[i][0] for i in xrange(self.width)]

    def __getitem__(self, (x, y)):
        return self.arena[x][y]

    def __setitem__(self, (x, y), value):
        self.arena[x][y] = value

class Context(object):
    FEEDBACK = 1
    LIFE = 2

    def __init__(self, players):
        self.info = {player: {self.FEEDBACK: None,
                              self.LIFE: INITIAL_HEALTH} for player in players}

    def feedback(self, player):
        return self.info[player][self.FEEDBACK]

    def provide_feedback(self, player, feedback):
        self.info[player][self.FEEDBACK] = feedback

    def decrease_life(self, player, amount):
        self.info[player][self.LIFE] -= amount

    def life(self, player):
        return self.info[player][self.LIFE]

class BattleGroundArena(object):
    """The game arena."""

    PLAYING = 0
    LOST = 1
    WINNER = 2

    def __init__(self, players, width=100, height=50):
        self.width = width
        self.height = height
        self.players = players
        self.match = BattleGroundMatchLog(width, height, players)
        self.arena = ArenaGrid(self.width, self.height)
        self.context = Context(players)
        self.setup()

    def setup(self):
        self.match.trace_action(dict(action="new_arena",
                                     width=self.width,
                                     height=self.height,))
        for i, player in enumerate(self.players, start=1):
            player.color = i
            player.status = self.PLAYING

            x = i if i % 2 != 0 else self.width - i
            y = 0
            self.setup_new_player(player, x, y, self.width)

    def setup_new_player(self, player, x, y, width):
        """Register the new player at the (x, y) position on the arena."""
        player.x, player.y = x, y
        self.arena[x, y] = player.color
        x_factor = 1 if x <= (width // 2) else -1
        player.assign_team(x_factor)
        self.match.trace_action(dict(action="new_player",
                                     name=player.username,
                                     position=[x, y],
                                     tank=player.bot.__class__.__name__,
                                     ))

    def _validate_bot_output(self, bot_output):
        try:
            if bot_output is None:
                # None is a valid command, do nothing
                return
            if bot_output['ACTION'] == 'MOVE':
                if int(bot_output['WHERE']) not in (-1, 1):
                    # for moving, valid integers are: -1 or 1
                    raise InvalidBotOutput("Moving must be -1 or 1.")
            elif bot_output['ACTION'] == 'SHOOT':
                if int(bot_output['VEL']) not in range(1, 151):
                    # velocity must be an integer between 1 and 150
                    raise InvalidBotOutput("Velocity not in range [1, 150].")
                if int(bot_output['ANGLE']) not in range(10, 90):
                    # angle must be an integer between 10 and 89
                    raise InvalidBotOutput("Angle must be between 10 and 89")
        except:
            raise InvalidBotOutput()

    def start(self):
        try:
            for player in self.players:
                arena_snapshot = self.arena.copy_for_player()
                try:
                    bot_response = player.evaluate_turn(arena_snapshot,
                                                        self.context.feedback(player),
                                                        self.context.life(player))
                    self._validate_bot_output(bot_response)
                    # Here the engine calculates the new status
                    # according to the response and updates all tables
                    if bot_response['ACTION'] == 'MOVE':
                        self.resolve_move_action(player, bot_response['WHERE'])
                    elif bot_response['ACTION'] == 'SHOOT':
                        self.resolve_shoot_action(player,
                                                  bot_response['VEL'],
                                                  bot_response['ANGLE'])
                except InvalidBotOutput:
                    self.match.lost(player, u'Invalid output')
                except BotTimeoutException:
                    self.match.lost(player, u'Timeout')
                except Exception as e:
                    self.match.lost(player, u'Crashed')
        finally:
            # TODO: self.match.trace_action(GAME OVER)
            return self.match.__json__()

    def resolve_move_action(self, player, where):
        new_x = player.x + (player.x_factor * where)
        if 0 <= new_x <= self.arena.width:
            self.arena[player.x, player.y] = FREE
            player.x = new_x
            self.arena[player.x, player.y] = player.color
            # Trace what just happened in the match
            self.match.trace_action(dict(action="make_move",
                                         player=player.username,
                                         position=[player.x, player.y], ))

    def resolve_shoot_action(self, player, speed, angle):
        trajectory = shoot_projectile(speed, angle)
        # Log the shoot made by the player
        self.match.trace_action(dict(action="make_shoot",
                                     player=player.username,
                                     angle=angle,
                                     trajectory=trajectory))
        # Get the impact coordinates
        x_imp, y_imp = trajectory[-1]
        try:
            affected_players = [p for p in self.players
                                if p.x == x_imp and p.y == y_imp]
            if not affected_players:
                raise MissedTargetException
        except MissedTargetException:
            self.context.provide_feedback(player, MISSED_TARGED)
        else:
            self.context.provide_feedback(player, TARGET_HIT)
            for p in affected_players:
                self.context.decrease_life(p, DAMAGE_DELTA)
                self.match.trace_action(dict(action="health_status",
                                             player=p.username,
                                             health=self.context.life(p)))

class BattleGroundMatchLog(object):
    """Represents the match log among players, the entire game."""

    def __init__(self, width, height, players):
        self.width = width
        self.height = height
        self.players = players
        self.trace = []   # All actions performed during the match
        self.result = {}

    def trace_action(self, arena_action):
        """Receive an action performed on the arena, and log it as a part of
        the match."""
        # TODO: review
        self.trace.append(arena_action)

    def winner(self, player):  # FIXME
        player.status = BattleGroundArena.WINNER
        self.result['winner'] = player.username

    def lost(self, player, cause): # FIXME
        player.status = BattleGroundArena.LOST
        if 'lost' not in self.result:
            self.result['lost'] = {}
        self.result['lost'][player.username] = cause

    def __json__(self):
        data = dict(
                width=self.width,
                height=self.height,
                players=[player.username for player in self.players],
                actions=self.trace,
                result=self.result,
                )
        return data

class BotPlayer(object):

    def __init__(self, bot_name, bot):
        self._bot = bot
        self.x_factor = None
        self.username = bot_name

    @property
    def bot(self):
        return self._bot

    def evaluate_turn(self, arena_array, feedback, life):
        # Ask bot what to do this turn
        return self._bot.evaluate_turn(arena_array, feedback, life)

    def assign_team(self, x_factor):
        """Assign team depending on which side is allocated
        x_factor -> -1 | 1"""
        self.x_factor = x_factor

def usage():
    print "Usage: python %s player1.py player2.py. Make sure both files are valid Python scripts, importable, and implement a Bot class." % sys.argv[0]

def main(argv):
    bot_mod1 = argv[0].replace(".py", "")
    bot1_username = bot_mod1.split("/")[-1]
    bot_mod1 = bot_mod1.replace('/', '.')

    bot_mod2 = argv[1].replace(".py", "")
    bot2_username = bot_mod1.split("/")[-1]
    bot_mod2 = bot_mod2.replace('/', '.')
    try:
        bot_module1 = importlib.import_module(bot_mod1, package='bots')
        bot_module2 = importlib.import_module(bot_mod2, package='bots')
        bot1 = bot_module1.Bot()
        bot2 = bot_module2.Bot()
    except ImportError, e:
        print "Error importing bot scripts: %s." % str(e)
        usage()
        sys.exit(EXIT_ERROR_MODULE)
    except AttributeError, e:
        print "Error instancing Bot : %s." % str(e)
        usage()
        sys.exit(EXIT_ERROR_BOT_INSTANCE)

    bot1 = BotPlayer(bot1_username, bot1)
    bot2 = BotPlayer(bot2_username, bot2)

    engine = BattleGroundArena(players=[bot1, bot2])
    game_result = engine.start()
    print game_result
    sys.exit(0)

if __name__ == "__main__":
    if len(sys.argv) < 3:
        print("Please specify 2 bot files")
        usage()
        sys.exit(EXIT_ERROR_NUMBER_OF_PARAMS)

    main(sys.argv[1:])
<commit_msg>Adding method in arena that returns distance between two players<commit_after># encoding=utf-8

import sys
import importlib
import math
from exc import (
    InvalidBotOutput,
    BotTimeoutException,
    MissedTargetException,
)

#Exit error codes
EXIT_ERROR_NUMBER_OF_PARAMS  = 1
EXIT_ERROR_MODULE = 2
EXIT_ERROR_BOT_INSTANCE = 3

FREE = 0
DAMAGE_DELTA = 5
INITIAL_HEALTH = 100
MISSED_TARGED = 'FAILED'
TARGET_HIT = 'SUCCESS'

def shoot_projectile(speed, angle, starting_height=0.0, gravity=9.8):
    '''
    returns a list of (x, y) projectile motion data points
    where:
    x axis is distance (or range) in meters
    y axis is height in meters
    '''
    data_xy = []
    t = 0.0
    angle = math.radians(angle)
    while True:
        # now calculate the height y
        y = starting_height + (t * speed * math.sin(angle)) - (gravity * t * t)/2
        # projectile has hit ground level
        if y < 0:
            break
        # calculate the distance x
        x = speed * math.cos(angle) * t
        # append the (x, y) tuple to the list
        data_xy.append((x, y))
        # use the time in increments of 0.1 seconds
        t += 0.1
    # TODO: match every (x, y) (or at least the last one), with our grid.
    return data_xy

class ArenaGrid(object):
    """The grid that represents the arena over which the players are playing.
    """
    def __init__(self, width, height):
        self.width = width
        self.height = height
        # TODO: we only need the X axis, not the whole matrix
        self.arena = [[FREE for _ in xrange(self.height)] for __ in xrange(self.width)]

    def copy_for_player(self):
        """Return just a copy of the portion we provide to the player."""
        return [self.arena[i][0] for i in xrange(self.width)]

    def players_distance(self):
        """Return the distance between the bots. Only two players."""
        p1, p2 = [i for i in xrange(self.width) if self.arena[i][0] != FREE]
        return p2 - p1

    def __getitem__(self, (x, y)):
        return self.arena[x][y]

    def __setitem__(self, (x, y), value):
        self.arena[x][y] = value

class Context(object):
    FEEDBACK = 1
    LIFE = 2

    def __init__(self, players):
        self.info = {player: {self.FEEDBACK: None,
                              self.LIFE: INITIAL_HEALTH} for player in players}

    def feedback(self, player):
        return self.info[player][self.FEEDBACK]

    def provide_feedback(self, player, feedback):
        self.info[player][self.FEEDBACK] = feedback

    def decrease_life(self, player, amount):
        self.info[player][self.LIFE] -= amount

    def life(self, player):
        return self.info[player][self.LIFE]

class BattleGroundArena(object):
    """The game arena."""

    PLAYING = 0
    LOST = 1
    WINNER = 2

    def __init__(self, players, width=100, height=50):
        self.width = width
        self.height = height
        self.players = players
        self.match = BattleGroundMatchLog(width, height, players)
        self.arena = ArenaGrid(self.width, self.height)
        self.context = Context(players)
        self.setup()

    def setup(self):
        self.match.trace_action(dict(action="new_arena",
                                     width=self.width,
                                     height=self.height,))
        for i, player in enumerate(self.players, start=1):
            player.color = i
            player.status = self.PLAYING

            x = i if i % 2 != 0 else self.width - i
            y = 0
            self.setup_new_player(player, x, y, self.width)

    def setup_new_player(self, player, x, y, width):
        """Register the new player at the (x, y) position on the arena."""
        player.x, player.y = x, y
        self.arena[x, y] = player.color
        x_factor = 1 if x <= (width // 2) else -1
        player.assign_team(x_factor)
        self.match.trace_action(dict(action="new_player",
                                     name=player.username,
                                     position=[x, y],
                                     tank=player.bot.__class__.__name__,
                                     ))

    def _validate_bot_output(self, bot_output):
        try:
            if bot_output is None:
                # None is a valid command, do nothing
                return
            if bot_output['ACTION'] == 'MOVE':
                if int(bot_output['WHERE']) not in (-1, 1):
                    # for moving, valid integers are: -1 or 1
                    raise InvalidBotOutput("Moving must be -1 or 1.")
            elif bot_output['ACTION'] == 'SHOOT':
                if int(bot_output['VEL']) not in range(1, 151):
                    # velocity must be an integer between 1 and 150
                    raise InvalidBotOutput("Velocity not in range [1, 150].")
                if int(bot_output['ANGLE']) not in range(10, 90):
                    # angle must be an integer between 10 and 89
                    raise InvalidBotOutput("Angle must be between 10 and 89")
        except:
            raise InvalidBotOutput()

    def start(self):
        try:
            for player in self.players:
                arena_snapshot = self.arena.copy_for_player()
                try:
                    bot_response = player.evaluate_turn(arena_snapshot,
                                                        self.context.feedback(player),
                                                        self.context.life(player))
                    self._validate_bot_output(bot_response)
                    # Here the engine calculates the new status
                    # according to the response and updates all tables
                    if bot_response['ACTION'] == 'MOVE':
                        self.resolve_move_action(player, bot_response['WHERE'])
                    elif bot_response['ACTION'] == 'SHOOT':
                        self.resolve_shoot_action(player,
                                                  bot_response['VEL'],
                                                  bot_response['ANGLE'])
                except InvalidBotOutput:
                    self.match.lost(player, u'Invalid output')
                except BotTimeoutException:
                    self.match.lost(player, u'Timeout')
                except Exception as e:
                    self.match.lost(player, u'Crashed')
        finally:
            # TODO: self.match.trace_action(GAME OVER)
            return self.match.__json__()

    def resolve_move_action(self, player, where):
        new_x = player.x + (player.x_factor * where)
        if 0 <= new_x <= self.arena.width:
            self.arena[player.x, player.y] = FREE
            player.x = new_x
            self.arena[player.x, player.y] = player.color
            # Trace what just happened in the match
            self.match.trace_action(dict(action="make_move",
                                         player=player.username,
                                         position=[player.x, player.y], ))

    def resolve_shoot_action(self, player, speed, angle):
        trajectory = shoot_projectile(speed, angle)
        # Log the shoot made by the player
        self.match.trace_action(dict(action="make_shoot",
                                     player=player.username,
                                     angle=angle,
                                     trajectory=trajectory))
        # Get the impact coordinates
        x_imp, y_imp = trajectory[-1]
        try:
            affected_players = [p for p in self.players
                                if p.x == x_imp and p.y == y_imp]
            if not affected_players:
                raise MissedTargetException
        except MissedTargetException:
            self.context.provide_feedback(player, MISSED_TARGED)
        else:
            self.context.provide_feedback(player, TARGET_HIT)
            for p in affected_players:
                self.context.decrease_life(p, DAMAGE_DELTA)
                self.match.trace_action(dict(action="health_status",
                                             player=p.username,
                                             health=self.context.life(p)))

class BattleGroundMatchLog(object):
    """Represents the match log among players, the entire game."""

    def __init__(self, width, height, players):
        self.width = width
        self.height = height
        self.players = players
        self.trace = []   # All actions performed during the match
        self.result = {}

    def trace_action(self, arena_action):
        """Receive an action performed on the arena, and log it as a part of
        the match."""
        # TODO: review
        self.trace.append(arena_action)

    def winner(self, player):  # FIXME
        player.status = BattleGroundArena.WINNER
        self.result['winner'] = player.username

    def lost(self, player, cause): # FIXME
        player.status = BattleGroundArena.LOST
        if 'lost' not in self.result:
            self.result['lost'] = {}
        self.result['lost'][player.username] = cause

    def __json__(self):
        data = dict(
                width=self.width,
                height=self.height,
                players=[player.username for player in self.players],
                actions=self.trace,
                result=self.result,
                )
        return data

class BotPlayer(object):

    def __init__(self, bot_name, bot):
        self._bot = bot
        self.x_factor = None
        self.username = bot_name

    @property
    def bot(self):
        return self._bot

    def evaluate_turn(self, arena_array, feedback, life):
        # Ask bot what to do this turn
        return self._bot.evaluate_turn(arena_array, feedback, life)

    def assign_team(self, x_factor):
        """Assign team depending on which side is allocated
        x_factor -> -1 | 1"""
        self.x_factor = x_factor

def usage():
    print "Usage: python %s player1.py player2.py. Make sure both files are valid Python scripts, importable, and implement a Bot class." % sys.argv[0]

def main(argv):
    bot_mod1 = argv[0].replace(".py", "")
    bot1_username = bot_mod1.split("/")[-1]
    bot_mod1 = bot_mod1.replace('/', '.')

    bot_mod2 = argv[1].replace(".py", "")
    bot2_username = bot_mod1.split("/")[-1]
    bot_mod2 = bot_mod2.replace('/', '.')
    try:
        bot_module1 = importlib.import_module(bot_mod1, package='bots')
        bot_module2 = importlib.import_module(bot_mod2, package='bots')
        bot1 = bot_module1.Bot()
        bot2 = bot_module2.Bot()
    except ImportError, e:
        print "Error importing bot scripts: %s." % str(e)
        usage()
        sys.exit(EXIT_ERROR_MODULE)
    except AttributeError, e:
        print "Error instancing Bot : %s." % str(e)
        usage()
        sys.exit(EXIT_ERROR_BOT_INSTANCE)

    bot1 = BotPlayer(bot1_username, bot1)
    bot2 = BotPlayer(bot2_username, bot2)

    engine = BattleGroundArena(players=[bot1, bot2])
    game_result = engine.start()
    print game_result
    sys.exit(0)

if __name__ == "__main__":
    if len(sys.argv) < 3:
        print("Please specify 2 bot files")
        usage()
        sys.exit(EXIT_ERROR_NUMBER_OF_PARAMS)

    main(sys.argv[1:])
<|endoftext|>


<commit_before>#!/usr/bin/env python
#
# xdp_drop_count.py Drop incoming packets on XDP layer and count for which
#                   protocol type
#
# Copyright (c) 2016 PLUMgrid
# Copyright (c) 2016 Jan Ruth
# Licensed under the Apache License, Version 2.0 (the "License")

from bcc import BPF
import time
import sys

if (len(sys.argv) != 2):
    print("Usage: {0} <ifdev>\n\ne.g.: {0} eth0".format(sys.argv[0]))
    exit(1)

device = sys.argv[1]

# load BPF program
b = BPF(text = """
#define KBUILD_MODNAME "foo"
#include <uapi/linux/bpf.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/ipv6.h>

BPF_TABLE("percpu_array", uint32_t, long, dropcnt, 256);

static inline int parse_ipv4(void *data, u64 nh_off, void *data_end) {
    struct iphdr *iph = data + nh_off;

    if ((void*)&iph[1] > data_end)
        return 0;
    return iph->protocol;
}

static inline int parse_ipv6(void *data, u64 nh_off, void *data_end) {
    struct ipv6hdr *ip6h = data + nh_off;

    if ((void*)&ip6h[1] > data_end)
        return 0;
    return ip6h->nexthdr;
}

int xdp_prog1(struct xdp_md *ctx) {

    void* data_end = (void*)(long)ctx->data_end;
    void* data = (void*)(long)ctx->data;

    struct ethhdr *eth = data;

    // drop packets
    int rc = XDP_DROP; // let pass XDP_PASS or redirect to tx via XDP_TX
    long *value;
    uint16_t h_proto;
    uint64_t nh_off = 0;
    uint32_t index;

    nh_off = sizeof(*eth);

    if (data + nh_off  > data_end)
        return rc;

    h_proto = eth->h_proto;

    if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) {
        struct vlan_hdr *vhdr;

        vhdr = data + nh_off;
        nh_off += sizeof(struct vlan_hdr);
        if (data + nh_off > data_end)
            return rc;
            h_proto = vhdr->h_vlan_encapsulated_proto;
    }
    if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) {
        struct vlan_hdr *vhdr;

        vhdr = data + nh_off;
        nh_off += sizeof(struct vlan_hdr);
        if (data + nh_off > data_end)
            return rc;
            h_proto = vhdr->h_vlan_encapsulated_proto;
    }

    if (h_proto == htons(ETH_P_IP))
        index = parse_ipv4(data, nh_off, data_end);
    else if (h_proto == htons(ETH_P_IPV6))
       index = parse_ipv6(data, nh_off, data_end);
    else
        index = 0;

    value = dropcnt.lookup(&index);
    if (value)
        *value += 1;

    return rc;
}
""", cflags=["-w"])

xdp_func = b.load_func("xdp_prog1", BPF.XDP)
b.attach_xdp(device, xdp_func)
dropcnt = b.get_table("dropcnt")

prev = [0] * 256
print("Printing drops per IP protocol-number, hit CTRL+C to stop")
while 1:
    try:
        for k in dropcnt.keys():
            val = dropcnt.sum(k).value
            i = k.value
            if val:
                delta = val - prev[i]
                prev[i] = val
                print("{}: {} pkt/s".format(i, delta))
        time.sleep(1)
    except KeyboardInterrupt:
        print("Removing filter from device")
        break;

b.remove_xdp(device)
<commit_msg>Add support to xdp_drop_count for clsact mode<commit_after>#!/usr/bin/env python
#
# xdp_drop_count.py Drop incoming packets on XDP layer and count for which
#                   protocol type
#
# Copyright (c) 2016 PLUMgrid
# Copyright (c) 2016 Jan Ruth
# Licensed under the Apache License, Version 2.0 (the "License")

from bcc import BPF
import pyroute2
import time
import sys

if len(sys.argv) != 2:
    print("Usage: {0} <ifdev>\n\ne.g.: {0} eth0".format(sys.argv[0]))
    exit(1)

device = sys.argv[1]

mode = BPF.XDP
#mode = BPF.SCHED_CLS

if mode == BPF.XDP:
    ret = "XDP_DROP"
    ctxtype = "xdp_md"
else:
    ret = "TC_ACT_SHOT"
    ctxtype = "__sk_buff"

# load BPF program
b = BPF(text = """
#define KBUILD_MODNAME "foo"
#include <uapi/linux/bpf.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/ipv6.h>

BPF_TABLE("percpu_array", uint32_t, long, dropcnt, 256);

static inline int parse_ipv4(void *data, u64 nh_off, void *data_end) {
    struct iphdr *iph = data + nh_off;

    if ((void*)&iph[1] > data_end)
        return 0;
    return iph->protocol;
}

static inline int parse_ipv6(void *data, u64 nh_off, void *data_end) {
    struct ipv6hdr *ip6h = data + nh_off;

    if ((void*)&ip6h[1] > data_end)
        return 0;
    return ip6h->nexthdr;
}

int xdp_prog1(struct CTXTYPE *ctx) {

    void* data_end = (void*)(long)ctx->data_end;
    void* data = (void*)(long)ctx->data;

    struct ethhdr *eth = data;

    // drop packets
    int rc = RETURNCODE; // let pass XDP_PASS or redirect to tx via XDP_TX
    long *value;
    uint16_t h_proto;
    uint64_t nh_off = 0;
    uint32_t index;

    nh_off = sizeof(*eth);

    if (data + nh_off  > data_end)
        return rc;

    h_proto = eth->h_proto;

    if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) {
        struct vlan_hdr *vhdr;

        vhdr = data + nh_off;
        nh_off += sizeof(struct vlan_hdr);
        if (data + nh_off > data_end)
            return rc;
            h_proto = vhdr->h_vlan_encapsulated_proto;
    }
    if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) {
        struct vlan_hdr *vhdr;

        vhdr = data + nh_off;
        nh_off += sizeof(struct vlan_hdr);
        if (data + nh_off > data_end)
            return rc;
            h_proto = vhdr->h_vlan_encapsulated_proto;
    }

    if (h_proto == htons(ETH_P_IP))
        index = parse_ipv4(data, nh_off, data_end);
    else if (h_proto == htons(ETH_P_IPV6))
       index = parse_ipv6(data, nh_off, data_end);
    else
        index = 0;

    value = dropcnt.lookup(&index);
    if (value)
        *value += 1;

    return rc;
}
""", cflags=["-w", "-DRETURNCODE=%s" % ret, "-DCTXTYPE=%s" % ctxtype])

fn = b.load_func("xdp_prog1", mode)

if mode == BPF.XDP:
    b.attach_xdp(device, fn)
else:
    ip = pyroute2.IPRoute()
    ipdb = pyroute2.IPDB(nl=ip)
    idx = ipdb.interfaces[device].index
    ip.tc("add", "clsact", idx)
    ip.tc("add-filter", "bpf", idx, ":1", fd=fn.fd, name=fn.name,
          parent="ffff:fff2", classid=1, direct_action=True)

dropcnt = b.get_table("dropcnt")
prev = [0] * 256
print("Printing drops per IP protocol-number, hit CTRL+C to stop")
while 1:
    try:
        for k in dropcnt.keys():
            val = dropcnt.sum(k).value
            i = k.value
            if val:
                delta = val - prev[i]
                prev[i] = val
                print("{}: {} pkt/s".format(i, delta))
        time.sleep(1)
    except KeyboardInterrupt:
        print("Removing filter from device")
        break;

if mode == BPF.XDP:
    b.remove_xdp(device)
else:
    ip.tc("del", "clsact", idx)
    ipdb.release()
<|endoftext|>


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

from gevent import Greenlet, monkey, core; monkey.patch_all()

import bottle, bitcoinrpc.authproxy, math, sys
import logging, logging.config

try:
    from recaptcha.client import captcha
except ImportError:
    captcha = None

try:
    import qrcode
except ImportError:
    qrcode = None

class DuplicateKeyError(Exception):
    pass

def c_bool(orig):
    '''Convert a config value to a boolean value, or die trying'''
    norm = orig.lower().strip()
    if norm in ('yes', 'y', 'true', 't', '1'):
        return True
    if norm in ('no', 'n', 'false', 'f', '0'):
        return False
    raise TypeError

class CoinBank(object):
    def __init__(self, config):
        self.url       = config['rpc.url']
        self.acct      = config['faucet.acct']
        self.ratio     = float(config['faucet.ratio'])
        self.txfee     = float(config['faucet.txfee'])
        self.interval  = float(config['faucet.interval'])
        self.max_pay   = float(config['faucet.max_payout'])
        self.qr_regen  = c_bool(config['qrcode.generate'])
        self.qr_path   = config['qrcode.path']
        self.qr_file   = config['qrcode.file']

        svc = self.get_proxy()

        try:
            reuse_addr = config['faucet.reuse_addr']
            self.reuse_addr = c_bool(reuse_addr)
            self._public_address = False
        except TypeError:
            self.reuse_addr = True
            if svc.validateaddress(reuse_addr)['isvalid']:
                self._public_address = reuse_addr
            else:
                raise ValueError

        logging.config.fileConfig(config['logging.config_file'])
        self.log = logging.getLogger('CoinBank')

        self.pending = {}
        self.paid = [(0,0)]
        self.pay_periods = 0
        self.last_pay_time = core.time()

        self._balance_stat = 0
        self._balance = self.balance

        self._public_address_stat = 0
        self._public_address = self.public_address

        self._all_addresses_stat = 0
        self._all_addresses = self.all_addresses

        self.coin, self.symbol = {
            '1': ('BTC',  u'\u0243'),
            'L': ('LTC',  u'\u0141'),
            'D': ('DOGE', u'\u0189'),
            'N': ('NAME', u'\u2115'),
            'P': ('PPC',  u'\u2C63'),
            'm': ('test-coin', u'\u0166'),
            'n': ('test-coin', u'\u0166'),
        }.get(self.public_address[0], ('UNK', '?'))

        if 'recaptcha.pub_key' in config:
            if captcha:
                self.captcha_html =  captcha.displayhtml(config['recaptcha.pub_key'])
                self.captcha_priv_key = config['recaptcha.priv_key']
            else:
                raise Exception("Can't use api keys: failed to import from recaptcha.client")
        else:
            self.captcha_html =  ''
            self.captcha_priv_key = None

        svc.settxfee(self.txfee)

        self.log.info('Started new CoinBank instance (%s)', self.coin)

    @property
    def balance(self):
        svc = None
        while self._balance_stat != self.get_pay_status():
            if svc is None:
                svc = self.get_proxy()
            self._balance_stat = self.get_pay_status()
            self._balance = float(svc.getbalance(self.acct))
        return self._balance

    @property
    def public_address(self):
        svc = None
        if not (self.reuse_addr and self._public_address):
            while self._public_address_stat != self.get_pay_status():
                if svc is None:
                    svc = self.get_proxy()
                self._public_address_stat = self.get_pay_status()
                self._public_address = svc.getaccountaddress(self.acct)
                if self.qr_regen:
                    qr = qrcode.QRCode()
                    qr.add_data(self._public_address)
                    qr_img = qr.make_image()
                    qr_img.save(self.qr_path + '/' + self.qr_file)
        return self._public_address

    @property
    def all_addresses(self):
        svc = None
        while self._all_addresses_stat != self.get_pay_status():
            if svc is None:
                svc = self.get_proxy()
            self._all_addresses_stat = self.get_pay_status()
            self._all_addresses = svc.getaddressesbyaccount(self.acct)
        return self._all_addresses

    def get_total_tx_fee(self, ins=None, outs=None):
        '''Estimate the transaction fee given the number of inputs and outputs'''
        if ins is None:
            ins = len(self.all_addresses)
        if outs is None:
            outs = len(self.pending)
        sz = ins*149 + outs*34 + 10
        return math.ceil(sz / 1024.0) * self.txfee

    def get_proxy(self):
        return bitcoinrpc.authproxy.AuthServiceProxy(self.url)

    def get_total_pending(self):
        return sum(self.pending.values())

    def get_available(self):
        adj_outs = len(self.pending) + 1
        net = self.balance - self.get_total_pending() - self.get_total_tx_fee(outs=adj_outs)
        if net < 0:
            net = 0
        return net

    def get_current_payout(self):
        return min(self.ratio * self.get_available(), self.max_pay)

    def get_pay_status(self):
        '''This method should be greenthread-atomic'''
        return (len(self.paid), sum(self.pending.values()), self.pay_periods)

    def get_public_status(self):

        time = core.time()
        last_time, last_amt = self.paid[-1]
        return {
            'coin':              self.coin,
            'symbol':            self.symbol,
            'current_funds':     self.get_available(),
            'current_payout':    self.get_current_payout(),
            'last_payout_time':  last_time,
            'last_payout_total': last_amt,
            'total_pay_periods': self.pay_periods,
            'payout_interval':   self.interval,
            'current_address':   self.public_address,
            'current_time':      time,
            'next_payout_time':  self.last_pay_time + self.interval,
            'next_payout_total': self.get_total_pending(),
        }

    def schedule_payment(self, addr):
        svc = self.get_proxy()
        if not svc.validateaddress(addr)['isvalid']:
            raise ValueError
        if addr in self.pending:
            raise DuplicateKeyError

        while 1:
            pay_status = self.get_pay_status()
            amt = self.get_current_payout()
            # Check to make sure nothing happened
            if pay_status == self.get_pay_status():
                break

        if amt > 0:
            self.pending[addr] = amt
            self.log.info('Scheduled payment of %f to %s', amt, addr)
        else:
            self.log.warning('Attempted to schedule a payment with zero funds')
        return amt

def with_bank(orig_func):
    '''Function decorator to provide CoinBank instance'''
    def wrapped_func(*arg, **kwarg):
        app = bottle.default_app()
        bank = app.config['sericata.bank']
        return orig_func(bank, *arg, **kwarg)
    return wrapped_func

@with_bank
def make_payments(bank):

    bank.pay_periods += 1
    bank.last_pay_time = core.time()
    amt = bank.get_total_pending()
    Greenlet.spawn_later(bank.interval, globals()['make_payments'])

    if amt == 0:
        bank.log.debug('Payment period ended with no scheduled payments')
        return False

    svc = bank.get_proxy()
    to_pay = bank.pending
    bank.pending = {}
    bank.paid += [(core.time(), amt)]

    svc.sendmany(bank.acct, to_pay)
    vals = to_pay.values()
    bank.log.info('Made payments totalling %f to %d addresses', sum(vals), len(vals))

def http_err(code, body):
    code_map = {
        400: 'Bad Request',
        403: 'Forbidden',
        595: 'Insufficient Funds',
    }

    return bottle.HTTPResponse(
        status = code,
        body = '
%d %s
\n%s
Go Back' % (code, code_map[code], body)
    )

@bottle.get('/')
@with_bank
def make_main_page(bank):
    return bottle.template(
        'main',
        captcha_html = bank.captcha_html,
        **bank.get_public_status()
    )

@bottle.get('/stats')
@with_bank
def make_stats_page(bank):
    return bottle.template('stats', **bank.get_public_status())

@bottle.get('/donate.png')
@with_bank
def show_donate(bank):
    return bottle.static_file(bank.qr_file, bank.qr_path)

@bottle.get('/style.css')
def show_style():
    app = bottle.default_app()
    return bottle.static_file(
        app.config['style.file'],
        app.config['style.path'],
    )

@bottle.post('/payout')
@with_bank
def attempt_payout(bank):
    form = bottle.request.forms
    addr = form.get('addr')

    if captcha and bank.captcha_priv_key:
        response = captcha.submit(
            form.get('recaptcha_challenge_field'),
            form.get('recaptcha_response_field'),
            bank.captcha_priv_key,
            bottle.request['REMOTE_ADDR'],
        )
        if not response.is_valid:
            return http_err(403, "I think you're a robot!")

    try:
        amt = bank.schedule_payment(addr)
    except ValueError:
        return http_err(400, "Invalid address: "+addr)
    except DuplicateKeyError:
        return http_err(400, "Address "+addr+" already queued")

    if amt == 0:
        return http_err(595, "Out of "+bank.coin)

    return bottle.template('payout', amount=amt, address=addr, **bank.get_public_status())

if __name__ == '__main__':
    app = bottle.default_app()
    try:
        conf_file = sys.argv[1]
    except IndexError:
        conf_file = 'sericata.conf'

    config = app.config.load_config(conf_file)

    url = 'http://%s:%s@%s:%s' % (
        config['rpc.user'],
        config['rpc.pass'],
        config['rpc.host'],
        config['rpc.port'],
    )
    config['rpc.url'] = url

    bank = CoinBank(config)
    config['sericata.bank'] = bank

    # GeventServer is more fragile than the default WSGIRefServer: extra
    # arguments must be filtered out of config
    gevent_conf = {'server': 'gevent'}
    for key, val in config.items():
        if '.' not in key and key not in ('catchall','autojson'):
            gevent_conf[key] = val

    Greenlet.spawn_later(bank.interval, make_payments)
    app.run(**gevent_conf)
<commit_msg>Fix transaction fee calculation<commit_after>#!/usr/bin/env python

from gevent import Greenlet, monkey, core; monkey.patch_all()

import bottle, bitcoinrpc.authproxy, math, sys
import logging, logging.config

try:
    from recaptcha.client import captcha
except ImportError:
    captcha = None

try:
    import qrcode
except ImportError:
    qrcode = None

class DuplicateKeyError(Exception):
    pass

def c_bool(orig):
    '''Convert a config value to a boolean value, or die trying'''
    norm = orig.lower().strip()
    if norm in ('yes', 'y', 'true', 't', '1'):
        return True
    if norm in ('no', 'n', 'false', 'f', '0'):
        return False
    raise TypeError

class CoinBank(object):
    def __init__(self, config):
        self.url       = config['rpc.url']
        self.acct      = config['faucet.acct']
        self.ratio     = float(config['faucet.ratio'])
        self.txfee     = float(config['faucet.txfee'])
        self.interval  = float(config['faucet.interval'])
        self.max_pay   = float(config['faucet.max_payout'])
        self.qr_regen  = c_bool(config['qrcode.generate'])
        self.qr_path   = config['qrcode.path']
        self.qr_file   = config['qrcode.file']

        svc = self.get_proxy()

        try:
            reuse_addr = config['faucet.reuse_addr']
            self.reuse_addr = c_bool(reuse_addr)
            self._public_address = False
        except TypeError:
            self.reuse_addr = True
            if svc.validateaddress(reuse_addr)['isvalid']:
                self._public_address = reuse_addr
            else:
                raise ValueError

        logging.config.fileConfig(config['logging.config_file'])
        self.log = logging.getLogger('CoinBank')

        self.pending = {}
        self.paid = [(0,0)]
        self.pay_periods = 0
        self.last_pay_time = core.time()

        self._balance_stat = 0
        self._balance = self.balance

        self._public_address_stat = 0
        self._public_address = self.public_address

        self._utxo_count_stat = 0
        self._utxo_count = self.utxo_count

        self.coin, self.symbol = {
            '1': ('BTC',  u'\u0243'),
            'L': ('LTC',  u'\u0141'),
            'D': ('DOGE', u'\u0189'),
            'N': ('NAME', u'\u2115'),
            'P': ('PPC',  u'\u2C63'),
            'm': ('test-coin', u'\u0166'),
            'n': ('test-coin', u'\u0166'),
        }.get(self.public_address[0], ('UNK', '?'))

        if 'recaptcha.pub_key' in config:
            if captcha:
                self.captcha_html =  captcha.displayhtml(config['recaptcha.pub_key'])
                self.captcha_priv_key = config['recaptcha.priv_key']
            else:
                raise Exception("Can't use api keys: failed to import from recaptcha.client")
        else:
            self.captcha_html =  ''
            self.captcha_priv_key = None

        svc.settxfee(self.txfee)

        self.log.info('Started new CoinBank instance (%s)', self.coin)

    @property
    def balance(self):
        svc = None
        while self._balance_stat != self.get_pay_status():
            if svc is None:
                svc = self.get_proxy()
            self._balance_stat = self.get_pay_status()
            self._balance = float(svc.getbalance(self.acct))
        return self._balance

    @property
    def public_address(self):
        svc = None
        if not (self.reuse_addr and self._public_address):
            while self._public_address_stat != self.get_pay_status():
                if svc is None:
                    svc = self.get_proxy()
                self._public_address_stat = self.get_pay_status()
                self._public_address = svc.getaccountaddress(self.acct)
                if self.qr_regen:
                    qr = qrcode.QRCode()
                    qr.add_data(self._public_address)
                    qr_img = qr.make_image()
                    qr_img.save(self.qr_path + '/' + self.qr_file)
        return self._public_address

    @property
    def utxo_count(self):
        svc = None
        while self._utxo_count_stat != self.get_pay_status():
            if svc is None:
                svc = self.get_proxy()
            self._utxo_count_stat = self.get_pay_status()
            addrs = set(svc.getaddressesbyaccount(self.acct))
            self._utxo_count = len([
                1 for utxo in svc.listunspent(1)
                if utxo['address'] in addrs
            ])
        return self._utxo_count

    def get_total_tx_fee(self, ins=None, outs=None):
        '''Estimate the transaction fee given the number of inputs and outputs'''
        if ins is None:
            ins = self.utxo_count
        if outs is None:
            outs = len(self.pending)
        sz = ins*149 + outs*34 + 10
        return math.ceil(sz / 1024.0) * self.txfee

    def get_proxy(self):
        return bitcoinrpc.authproxy.AuthServiceProxy(self.url)

    def get_total_pending(self):
        return sum(self.pending.values())

    def get_available(self):
        adj_outs = len(self.pending) + 1
        net = self.balance - self.get_total_pending() - self.get_total_tx_fee(outs=adj_outs)
        if net < 0:
            net = 0
        return net

    def get_current_payout(self):
        return min(self.ratio * self.get_available(), self.max_pay)

    def get_pay_status(self):
        '''This method should be greenthread-atomic'''
        return (len(self.paid), sum(self.pending.values()), self.pay_periods)

    def get_public_status(self):

        time = core.time()
        last_time, last_amt = self.paid[-1]
        return {
            'coin':              self.coin,
            'symbol':            self.symbol,
            'current_funds':     self.get_available(),
            'current_payout':    self.get_current_payout(),
            'last_payout_time':  last_time,
            'last_payout_total': last_amt,
            'total_pay_periods': self.pay_periods,
            'payout_interval':   self.interval,
            'current_address':   self.public_address,
            'current_time':      time,
            'next_payout_time':  self.last_pay_time + self.interval,
            'next_payout_total': self.get_total_pending(),
        }

    def schedule_payment(self, addr):
        svc = self.get_proxy()
        if not svc.validateaddress(addr)['isvalid']:
            raise ValueError
        if addr in self.pending:
            raise DuplicateKeyError

        while 1:
            pay_status = self.get_pay_status()
            amt = self.get_current_payout()
            # Check to make sure nothing happened
            if pay_status == self.get_pay_status():
                break

        if amt > 0:
            self.pending[addr] = amt
            self.log.info('Scheduled payment of %f to %s', amt, addr)
        else:
            self.log.warning('Attempted to schedule a payment with zero funds')
        return amt

def with_bank(orig_func):
    '''Function decorator to provide CoinBank instance'''
    def wrapped_func(*arg, **kwarg):
        app = bottle.default_app()
        bank = app.config['sericata.bank']
        return orig_func(bank, *arg, **kwarg)
    return wrapped_func

@with_bank
def make_payments(bank):

    bank.pay_periods += 1
    bank.last_pay_time = core.time()
    amt = bank.get_total_pending()
    Greenlet.spawn_later(bank.interval, globals()['make_payments'])

    if amt == 0:
        bank.log.debug('Payment period ended with no scheduled payments')
        return False

    svc = bank.get_proxy()
    to_pay = bank.pending
    bank.pending = {}
    bank.paid += [(core.time(), amt)]

    svc.sendmany(bank.acct, to_pay)
    vals = to_pay.values()
    bank.log.info('Made payments totalling %f to %d addresses', sum(vals), len(vals))

def http_err(code, body):
    code_map = {
        400: 'Bad Request',
        403: 'Forbidden',
        595: 'Insufficient Funds',
    }

    return bottle.HTTPResponse(
        status = code,
        body = '
%d %s
\n%s
Go Back' % (code, code_map[code], body)
    )

@bottle.get('/')
@with_bank
def make_main_page(bank):
    return bottle.template(
        'main',
        captcha_html = bank.captcha_html,
        **bank.get_public_status()
    )

@bottle.get('/stats')
@with_bank
def make_stats_page(bank):
    return bottle.template('stats', **bank.get_public_status())

@bottle.get('/donate.png')
@with_bank
def show_donate(bank):
    return bottle.static_file(bank.qr_file, bank.qr_path)

@bottle.get('/style.css')
def show_style():
    app = bottle.default_app()
    return bottle.static_file(
        app.config['style.file'],
        app.config['style.path'],
    )

@bottle.post('/payout')
@with_bank
def attempt_payout(bank):
    form = bottle.request.forms
    addr = form.get('addr')

    if captcha and bank.captcha_priv_key:
        response = captcha.submit(
            form.get('recaptcha_challenge_field'),
            form.get('recaptcha_response_field'),
            bank.captcha_priv_key,
            bottle.request['REMOTE_ADDR'],
        )
        if not response.is_valid:
            return http_err(403, "I think you're a robot!")

    try:
        amt = bank.schedule_payment(addr)
    except ValueError:
        return http_err(400, "Invalid address: "+addr)
    except DuplicateKeyError:
        return http_err(400, "Address "+addr+" already queued")

    if amt == 0:
        return http_err(595, "Out of "+bank.coin)

    return bottle.template('payout', amount=amt, address=addr, **bank.get_public_status())

if __name__ == '__main__':
    app = bottle.default_app()
    try:
        conf_file = sys.argv[1]
    except IndexError:
        conf_file = 'sericata.conf'

    config = app.config.load_config(conf_file)

    url = 'http://%s:%s@%s:%s' % (
        config['rpc.user'],
        config['rpc.pass'],
        config['rpc.host'],
        config['rpc.port'],
    )
    config['rpc.url'] = url

    bank = CoinBank(config)
    config['sericata.bank'] = bank

    # GeventServer is more fragile than the default WSGIRefServer: extra
    # arguments must be filtered out of config
    gevent_conf = {'server': 'gevent'}
    for key, val in config.items():
        if '.' not in key and key not in ('catchall','autojson'):
            gevent_conf[key] = val

    Greenlet.spawn_later(bank.interval, make_payments)
    app.run(**gevent_conf)
<|endoftext|>


<commit_before>"""
CLI entrypoint & parser configuration.

Builds on top of Invoke's core functionality for same.
"""

from invoke import Program, __version__ as invoke, FilesystemLoader
from paramiko import __version__ as paramiko

from . import __version__ as fabric

class Fab(Program):
    def print_version(self):
        super(Fab, self).print_version()
        print("Paramiko {0}".format(paramiko))
        print("Invoke {0}".format(invoke))

class FabfileLoader(FilesystemLoader):
    # TODO: we may run into issues re: swapping loader "strategies" (eg
    # FilesystemLoader vs...something else eventually) versus this sort of
    # "just tweaking DEFAULT_COLLECTION_NAME" setting. Maybe just make the
    # default collection name itself a runtime option?
    DEFAULT_COLLECTION_NAME = 'fabfile'

program = Fab(
    name="Fabric",
    version=fabric,
    loader_class=FabfileLoader,
)
<commit_msg>SO EASY boy that invoke maintainer is great isn't he??<commit_after>"""
CLI entrypoint & parser configuration.

Builds on top of Invoke's core functionality for same.
"""

from invoke import Program, __version__ as invoke, FilesystemLoader, Argument
from paramiko import __version__ as paramiko

from . import __version__ as fabric

class Fab(Program):
    def print_version(self):
        super(Fab, self).print_version()
        print("Paramiko {0}".format(paramiko))
        print("Invoke {0}".format(invoke))

    def core_args(self):
        core_args = super(Fab, self).core_args()
        my_args = [
            Argument(
                names=('H', 'hosts'),
                help="Host name(s) to execute tasks against.",
            ),
        ]
        return core_args + my_args

class FabfileLoader(FilesystemLoader):
    # TODO: we may run into issues re: swapping loader "strategies" (eg
    # FilesystemLoader vs...something else eventually) versus this sort of
    # "just tweaking DEFAULT_COLLECTION_NAME" setting. Maybe just make the
    # default collection name itself a runtime option?
    DEFAULT_COLLECTION_NAME = 'fabfile'

program = Fab(
    name="Fabric",
    version=fabric,
    loader_class=FabfileLoader,
)
<|endoftext|>


<commit_before>"""
Getting started: 5 minutes tutorial for `tofu`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This is a tutorial that aims to get a new user a little familiar with tofu's
 structure.
"""
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use('Qt5Agg')

###############################################################################
# We start by loading `tofu`. You might see some warnings at this stage since
# optional modules for `tofu` could
# be missing on the machine you are working on. This can be ignored safely.

import tofu as tf

###############################################################################
# We can now create our first configuration.
# In `tofu` speak, a configuration is the geometry of the device and its structures.
# `tofu` provides pre-defined ones for your to try, so we're going to do just that:

configB2 = tf.geom.utils.create_config("B2")

###############################################################################
# The configuration can easily be visualized using the `.plot()` method:

configB2.plot()

###############################################################################
# Since `tofu` is all about tomography, let's create a 1D camera and plot its output.

import numpy as np

cam1d = tf.geom.utils.create_CamLOS1D(
    config=configB2,
    P=[3.4, 0, 0],
    N12=100,
    F=0.1,
    D12=0.1,
    angs=[np.pi, 0, 0],
    Name="",
    Exp="",
    Diag="",
)
# interactive plot
cam1d.plot_touch()

###############################################################################
# The principle is similar for 2D cameras.

cam2d = tf.geom.utils.create_CamLOS2D(
    config=configB2,
    P=[3.4, 0, 0],
    N12=100,
    F=0.1,
    D12=0.1,
    angs=[np.pi, 0, 0],
    Name="",
    Exp="",
    Diag="",
)
cam2d.plot_touch()

###############################################################################
# What comes next is up to you!
# You could now play with the function parameters (change the cameras direction,
# refinement, aperture),
# with the plots (many are interactive) or create you own tomographic configuration.
<commit_msg>Update plot_basic_tutorial.py<commit_after>"""
Getting started: 5 minutes tutorial for `tofu`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This is a tutorial that aims to get a new user a little familiar with tofu's
 structure.
"""
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use('Qt5Agg')

###############################################################################
# We start by loading `tofu`. You might see some warnings at this stage since
# optional modules for `tofu` could
# be missing on the machine you are working on. This can be ignored safely.

import tofu as tf

###############################################################################
# We can now create our first configuration.
# In `tofu` speak, a configuration is the geometry of the device and its structures.
# `tofu` provides pre-defined ones for your to try, so we're going to do just that:

configB2 = tf.geom.utils.create_config("B2")

###############################################################################
# The configuration can easily be visualized using the `.plot()` method:

configB2.plot()

###############################################################################
# Since `tofu` is all about tomography, let's create a 1D camera and plot its output.

import numpy as np

cam1d = tf.geom.utils.create_CamLOS1D(
    config=configB2,
    P=[3.4, 0, 0],
    N12=100,
    F=0.1,
    D12=0.1,
    angs=[np.pi, 0, 0],
    Name="",
    Exp="",
    Diag="",
)
# interactive plot
cam1d.plot_touch()

###############################################################################
# The principle is similar for 2D cameras.

cam2d = tf.geom.utils.create_CamLOS2D(
    config=configB2,
    P=[3.4, 0, 0],
    N12=100,
    F=0.1,
    D12=0.1,
    angs=[np.pi, 0, 0],
    Name="",
    Exp="",
    Diag="",
)
cam2d.plot_touch()

###############################################################################
# What comes next is up to you!
# You could now play with the function parameters (change the cameras
# direction, refinement, aperture),
# with the plots (many are interactive) or create you own tomographic
# configuration.
<|endoftext|>


<commit_before>#!/usr/bin/env python
# ----------------------------------------------------------------------
# Numenta Platform for Intelligent Computing (NuPIC)
# Copyright (C) 2013, Numenta, Inc.  Unless you have purchased from
# Numenta, Inc. a separate commercial license for this software code, the
# following terms and conditions apply:
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see http://www.gnu.org/licenses.
#
# http://numenta.org/licenses/
# ----------------------------------------------------------------------
"""
A simple example that streams your mic input into the temporal pooler (TP),
and outputs an anomaly score, based on how familiar the TP has become to that
particular mic input sequence. Think of it as being able to recognize a song,
or become more familiar with your speech pattern.

This script will run automatically & forever.
To stop it, use KeyboardInterrupt (CRTL+C).

General algorithm:
1. Mic input is received (voltages in the time domain)
2. Mic input is transformed into the frequency domain, using fast fourier transform
3. The few strongest frequencies (in Hz) are identified
4. Those frequencies are encoded into an SDR
5. That SDR is passed to the temporal pooler
6. The temporal pooler provides a prediction
7. We calculate an anomaly score off that prediction against the next input
8. A low anomaly score means that the temporal pooler is properly predicting
	the next frequency pattern.

Next steps:
 Implement real-time visualization
 Implement anomaly smoother (or make TP pull from a longer history)
 Implement spatial pooler
  Need boosting to account for how the bandpass filter falls on the spectrum
 Look into better algorithms to pick out the frequency peaks (sound fingerprinting)
"""

import numpy
import pyaudio
import matplotlib.pyplot as mpl

# The BitmapArray encoder encodes an array of indices into an SDR
# (This will convert that array of the strongest frequencies)
from nupic.encoders.bitmaparray import BitmapArrayEncoder
# This is the C++ optimized temporal pooler that iandanforth & rhyolight using
from nupic.research.TP10X2 import TP10X2 as TP

# The number of columns in the input and therefore the TP
numCols = 2**8 # 2**8 = 256
sparsity = 0.10
numInput = int(numCols * sparsity)

# Create a bit map encoder
# From the encoder's __init__ method:
#   1st arg: the total bits in input
#   2nd arg: the number of bits used to encode each input bit
encoder = BitmapArrayEncoder
e = encoder(numCols, 1)

# Sampling details
#  rate: The sampling rate in Hz of my soundcard
#  buffersize: The size of the array to which we will save audio segments (2^12 = 4096 is very good)
#  secToRecord: The length of each sampling
#  buffersToRecord: how many multiples of buffers are we recording?
rate=44100
buffersize=2**12
secToRecord=.1
buffersToRecord=int(rate*secToRecord/buffersize)
if not buffersToRecord: buffersToRecord=1
bufToCol = buffersize / 2 / numCols

# Filters in Hertz
#  highHertz: lower limit of the bandpass filter, in Hertz
#  lowHertz: upper limit of the bandpass filter, in Hertz
#    max lowHertz = (buffersize / 2 - 1) * rate / buffersize
highHertz = 1000
lowHertz = 22000

# Convert filters from Hertz to bins
#  highpass: convert the highHertz into a bin for the FFT
#  lowpass: convert the lowHertz into a bin for the FFt
#  NOTES:
#   highpass is at least the 1st bin since most mics only pick up >=20Hz
#   lowpass is no higher than buffersize/2 - 1 (highest array index)
#   passband needs to be wider than size of numInput - not checking for that
highpass = max(int(highHertz * buffersize / rate),1)
lowpass = min(int(lowHertz * buffersize / rate), buffersize/2 - 1)

# The call to create the temporal pooler region
tp = TP(numberOfCols=numCols, cellsPerColumn=4,
		initialPerm=0.5, connectedPerm=0.5,
		minThreshold=10, newSynapseCount=10,
		permanenceInc=0.1, permanenceDec=0.05,
		activationThreshold=8,
		globalDecay=0.01, burnIn=2,
		checkSynapseConsistency=False,
		pamLength=10)

# Fast fourier transform conditioning
# Output:
#  'output' contains the strength of each frequency in the audio signal
#  frequencies are marked by its position in 'output':
#   frequency = index * rate / buffesize
#  output.size = buffersize/2
#
# Method:
#  Use numpy's FFT (numpy.fft.fft)
#  Find the magnitude of the complex numbers returned (abs value)
#  Split the FFT array in half, because we have mirror frequencies
#   (they're the complex conjugates)
#  Use just the first half to apply the bandpass filter
#
# Great info here: http://stackoverflow.com/questions/4364823/how-to-get-frequency-from-fft-result

def fft(audio):
	left,right = numpy.split(numpy.abs(numpy.fft.fft(audio)),2)
	output = left[highpass:lowpass]
	return output

# Calculates the anomaly of two SDRs
# Uses the equation presented on the wiki:
# https://github.com/numenta/nupic/wiki/Anomaly-Score-Memo
#
# To put this in terms of the temporal pooler:
# A is the actual input array at a given timestep
# P is the predicted array that was produced from the previous timestep(s)
# [A - (A && P)] / [A]
# What are the similarities between the two SDRs?
# What bits are on in A that are not on in P?
# How does that compare to total on bits in A?
#
# Outputs 0 is there's no difference between P and A.
# Outputs 1 if P and A are totally distinct.
#
# Not a perfect metric - it doesn't credit proximity
# Next step: combine with a metric for a spatial pooler

def calcAnomaly(actual, predicted):
	combined = numpy.logical_and(actual, predicted)
	delta = numpy.logical_xor(actual,combined)
	delta_score = sum(delta)
	actual_score = float(sum(actual))
	return delta_score / actual_score

def compareArray(actual, predicted):
	compare = []
	for i in range(actual.size):
		if actual[i] and predicted[i]:
			compare.append('E')
		elif actual[i]:
			compare.append('A')
		elif predicted[i]:
			compare.append('P')
		else:
			compare.append(' ')
	return compare

# Basic print out method to visualize the anomaly score
# Scale is from one hashtag to 50
def hashtagAnomaly(anomaly):
	hash = '#'
	for i in range(int(anomaly / 0.02)):
		hash += '#'
	for j in range(int((1 - anomaly) / 0.02)):
		hash += '.'
	return hash

#######################
# The meat & potatoes #
#######################

# Creating the audio stream from our mic
p = pyaudio.PyAudio()
inStream = p.open(format=pyaudio.paInt32,channels=1,rate=rate,input=True,frames_per_buffer=buffersize)

# Setting up the array that will handle the timeseries of audio data from our input
audio=numpy.empty((buffersToRecord*buffersize),dtype="uint32")

print "Number of columns:\t" + str(numCols)
print "Max size of input:\t" + str(numInput)

print "Sampling rate (Hz):\t" + str(rate)
print "Passband filter (Hz):\t" + str(highHertz) + " - " + str(lowHertz)

print "Buffersize:\t\t" + str(buffersize)
print "Buffer/columns:\t\t" + str(bufToCol)

# Record and pass the TP forever
while True:
	# for the multiples of buffers that we're sampling at once
	for i in range(buffersToRecord):
		# sample audio for the number of frames in a buffersize
		#  saves mic voltage-level timeseries as 32-bit binary
		audioString=inStream.read(buffersize)
		# convert that 32-bit binary into integers, and save to array for the FFT
		audio[i*buffersize:(i+1)*buffersize]=numpy.fromstring(audioString,dtype="uint32")
	# Getting an int array of all the frequencies in our audio via the fast fourier transform
	ys = fft(audio)
	# Get the indices of our top frequencies (top numInput)
	fs = numpy.sort(ys.argsort()[-numInput:])
	# Scale those indicies so that they fit to our number of columns
	rfs = fs/bufToCol
	# Pick out the unique indices (we've reduced the mapping)
	ufs = numpy.unique(rfs)
	if(False):
		# Convert the indices back to frequencies for debugging
		print fs * rate/buffersize + highHertz
		# Develop an x-axis for the plot, and convert back to frequencies
		bin = numpy.arange(ys.size)*rate/buffersize + highHertz
		mpl.plot(bin,ys)
		mpl.show()
		quit()
	# Encoding our array of frequency indices into an SDR via the BitmapArrayEncoder
	actualInt = e.encode(ufs)
	# Casting the SDR as a float for the TP
	actual = actualInt.astype(numpy.float32)
	# Passing the SDR to the TP
	tp.compute(actual, enableLearn = True, computeInfOutput = True)
	# Collecting the prediction SDR
	predictedInt = tp.getPredictedState().max(axis=1)
	# Passing the prediction & actual SDRs to the anomaly calculator & array comparer
	compare = compareArray(actualInt, predictedInt)
	anomaly = calcAnomaly(actualInt, predictedInt)
	print '.' .join(compare)
	print hashtagAnomaly(anomaly)<commit_msg>Added real-time FFT plotting.<commit_after>#!/usr/bin/env python
# ----------------------------------------------------------------------
# Numenta Platform for Intelligent Computing (NuPIC)
# Copyright (C) 2013, Numenta, Inc.  Unless you have purchased from
# Numenta, Inc. a separate commercial license for this software code, the
# following terms and conditions apply:
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see http://www.gnu.org/licenses.
#
# http://numenta.org/licenses/
# ----------------------------------------------------------------------
"""
A simple example that streams your mic input into the temporal pooler (TP),
and outputs an anomaly score, based on how familiar the TP has become to that
particular mic input sequence. Think of it as being able to recognize a song,
or become more familiar with your speech pattern.

This script will run automatically & forever.
To stop it, use KeyboardInterrupt (CRTL+C).

General algorithm:
1. Mic input is received (voltages in the time domain)
2. Mic input is transformed into the frequency domain, using fast fourier transform
3. The few strongest frequencies (in Hz) are identified
4. Those frequencies are encoded into an SDR
5. That SDR is passed to the temporal pooler
6. The temporal pooler provides a prediction
7. We calculate an anomaly score off that prediction against the next input
8. A low anomaly score means that the temporal pooler is properly predicting
	the next frequency pattern.

Next steps:
 X Implement real-time visualization
 Implement anomaly smoother (or make TP pull from a longer history)
 Implement spatial pooler
  Need boosting to account for how the bandpass filter falls on the spectrum
 Look into better algorithms to pick out the frequency peaks (sound fingerprinting)
"""

import numpy
import pyaudio
import matplotlib.pyplot as plt

# The BitmapArray encoder encodes an array of indices into an SDR
# (This will convert that array of the strongest frequencies)
from nupic.encoders.bitmaparray import BitmapArrayEncoder
# This is the C++ optimized temporal pooler that iandanforth & rhyolight using
from nupic.research.TP10X2 import TP10X2 as TP

# The number of columns in the input and therefore the TP
numCols = 2**8 # 2**8 = 256
sparsity = 0.10
numInput = int(numCols * sparsity)

# Create a bit map encoder
# From the encoder's __init__ method:
#   1st arg: the total bits in input
#   2nd arg: the number of bits used to encode each input bit
encoder = BitmapArrayEncoder
e = encoder(numCols, 1)

# Sampling details
#  rate: The sampling rate in Hz of my soundcard
#  buffersize: The size of the array to which we will save audio segments (2^12 = 4096 is very good)
#  secToRecord: The length of each sampling
#  buffersToRecord: how many multiples of buffers are we recording?
rate=44100
buffersize=2**12
secToRecord=.1
buffersToRecord=int(rate*secToRecord/buffersize)
if not buffersToRecord: buffersToRecord=1
bufToCol = buffersize / 2 / numCols

# Filters in Hertz
#  highHertz: lower limit of the bandpass filter, in Hertz
#  lowHertz: upper limit of the bandpass filter, in Hertz
#    max lowHertz = (buffersize / 2 - 1) * rate / buffersize
highHertz = 1000
lowHertz = 22000

# Convert filters from Hertz to bins
#  highpass: convert the highHertz into a bin for the FFT
#  lowpass: convert the lowHertz into a bin for the FFt
#  NOTES:
#   highpass is at least the 1st bin since most mics only pick up >=20Hz
#   lowpass is no higher than buffersize/2 - 1 (highest array index)
#   passband needs to be wider than size of numInput - not checking for that
highpass = max(int(highHertz * buffersize / rate),1)
lowpass = min(int(lowHertz * buffersize / rate), buffersize/2 - 1)

# The call to create the temporal pooler region
tp = TP(numberOfCols=numCols, cellsPerColumn=4,
		initialPerm=0.5, connectedPerm=0.5,
		minThreshold=10, newSynapseCount=10,
		permanenceInc=0.1, permanenceDec=0.05,
		activationThreshold=8,
		globalDecay=0.01, burnIn=2,
		checkSynapseConsistency=False,
		pamLength=10)

# Fast fourier transform conditioning
# Output:
#  'output' contains the strength of each frequency in the audio signal
#  frequencies are marked by its position in 'output':
#   frequency = index * rate / buffesize
#  output.size = buffersize/2
#
# Method:
#  Use numpy's FFT (numpy.fft.fft)
#  Find the magnitude of the complex numbers returned (abs value)
#  Split the FFT array in half, because we have mirror frequencies
#   (they're the complex conjugates)
#  Use just the first half to apply the bandpass filter
#
# Great info here: http://stackoverflow.com/questions/4364823/how-to-get-frequency-from-fft-result

def fft(audio):
	left,right = numpy.split(numpy.abs(numpy.fft.fft(audio)),2)
	output = left[highpass:lowpass]
	return output

# Calculates the anomaly of two SDRs
# Uses the equation presented on the wiki:
# https://github.com/numenta/nupic/wiki/Anomaly-Score-Memo
#
# To put this in terms of the temporal pooler:
# A is the actual input array at a given timestep
# P is the predicted array that was produced from the previous timestep(s)
# [A - (A && P)] / [A]
# What are the similarities between the two SDRs?
# What bits are on in A that are not on in P?
# How does that compare to total on bits in A?
#
# Outputs 0 is there's no difference between P and A.
# Outputs 1 if P and A are totally distinct.
#
# Not a perfect metric - it doesn't credit proximity
# Next step: combine with a metric for a spatial pooler

def calcAnomaly(actual, predicted):
	combined = numpy.logical_and(actual, predicted)
	delta = numpy.logical_xor(actual,combined)
	delta_score = sum(delta)
	actual_score = float(sum(actual))
	return delta_score / actual_score

def compareArray(actual, predicted):
	compare = []
	for i in range(actual.size):
		if actual[i] and predicted[i]:
			compare.append('E')
		elif actual[i]:
			compare.append('A')
		elif predicted[i]:
			compare.append('P')
		else:
			compare.append(' ')
	return compare

# Basic print out method to visualize the anomaly score
# Scale is from one hashtag to 50
def hashtagAnomaly(anomaly):
	hash = '#'
	for i in range(int(anomaly / 0.02)):
		hash += '#'
	for j in range(int((1 - anomaly) / 0.02)):
		hash += '.'
	return hash

#######################
# The meat & potatoes #
#######################

# Creating the audio stream from our mic
p = pyaudio.PyAudio()
inStream = p.open(format=pyaudio.paInt32,channels=1,rate=rate,input=True,frames_per_buffer=buffersize)

# Setting up the array that will handle the timeseries of audio data from our input
audio=numpy.empty((buffersToRecord*buffersize),dtype="uint32")

print "Number of columns:\t" + str(numCols)
print "Max size of input:\t" + str(numInput)

print "Sampling rate (Hz):\t" + str(rate)
print "Passband filter (Hz):\t" + str(highHertz) + " - " + str(lowHertz)

print "Buffersize:\t\t" + str(buffersize)
print "Buffer/columns:\t\t" + str(bufToCol)

plt.ion()
bin = range(highpass,lowpass)
xs = numpy.arange(len(bin))*rate/buffersize + highHertz
graph = plt.plot(xs,xs)[0]
plt.ylim(0, 1000000000000)

# Record and pass the TP forever
while True:
	# for the multiples of buffers that we're sampling at once
	for i in range(buffersToRecord):
		# sample audio for the number of frames in a buffersize
		#  saves mic voltage-level timeseries as 32-bit binary
		audioString=inStream.read(buffersize)
		# convert that 32-bit binary into integers, and save to array for the FFT
		audio[i*buffersize:(i+1)*buffersize]=numpy.fromstring(audioString,dtype="uint32")
	# Getting an int array of all the frequencies in our audio via the fast fourier transform
	ys = fft(audio)
	# Get the indices of our top frequencies (top numInput)
	fs = numpy.sort(ys.argsort()[-numInput:])
	# Scale those indicies so that they fit to our number of columns
	rfs = fs/bufToCol
	# Pick out the unique indices (we've reduced the mapping)
	ufs = numpy.unique(rfs)
	graph.set_ydata(ys)
	plt.draw()
	# Encoding our array of frequency indices into an SDR via the BitmapArrayEncoder
	actualInt = e.encode(ufs)
	# Casting the SDR as a float for the TP
	actual = actualInt.astype(numpy.float32)
	# Passing the SDR to the TP
	tp.compute(actual, enableLearn = True, computeInfOutput = True)
	# Collecting the prediction SDR
	predictedInt = tp.getPredictedState().max(axis=1)
	# Passing the prediction & actual SDRs to the anomaly calculator & array comparer
	compare = compareArray(actualInt, predictedInt)
	anomaly = calcAnomaly(actualInt, predictedInt)
	print '.' .join(compare)
	print hashtagAnomaly(anomaly)<|endoftext|>