<commit_before># -*- coding: utf-8 -*_
from django.db import models

from ..base import ModelTranslationBase
from ..mixins import ModelMixin, ManagerMixin

class FooManager(ManagerMixin, models.Manager):
    pass

class BarManager(ManagerMixin, models.Manager):
    pass

class FooModel(ModelMixin, models.Model):
    title = models.CharField(max_length=255, null=True, blank=True)
    excerpt = models.TextField(blank=True)
    body = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    objects = FooManager()

class FooTranslation(ModelTranslationBase):
    model = FooModel
    identifier = 'foo'
    fields = ('title', 'excerpt', 'body')

class BarModel(ModelMixin, models.Model):
    title = models.CharField(max_length=255, null=True, blank=True)
    objects = BarManager()

class BarTranslation(ModelTranslationBase):
    model = BarModel
    identifier = 'bar'
    fields = ('title', )

class BadTranslation(object):
    pass

class BadModel(object):
    pass
<commit_msg>Tests: add null fields to FooModel.<commit_after># -*- coding: utf-8 -*_
from django.db import models

from ..base import ModelTranslationBase
from ..mixins import ModelMixin, ManagerMixin

class FooManager(ManagerMixin, models.Manager):
    pass

class BarManager(ManagerMixin, models.Manager):
    pass

class FooModel(ModelMixin, models.Model):
    title = models.CharField(max_length=255, null=True, blank=True)
    excerpt = models.TextField(null=True, blank=True)
    body = models.TextField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    objects = FooManager()

class FooTranslation(ModelTranslationBase):
    model = FooModel
    identifier = 'foo'
    fields = ('title', 'excerpt', 'body')

class BarModel(ModelMixin, models.Model):
    title = models.CharField(max_length=255, null=True, blank=True)
    objects = BarManager()

class BarTranslation(ModelTranslationBase):
    model = BarModel
    identifier = 'bar'
    fields = ('title', )

class BadTranslation(object):
    pass

class BadModel(object):
    pass
<|endoftext|>


<commit_before>#!/usr/bin/python
# -*- coding: utf-8 -*-
"""production configuration (imported by __init__.py)"""
from __future__ import division  # 1/2 == 0.5, as in Py3
from __future__ import absolute_import  # avoid hiding global modules with locals
from __future__ import print_function  # force use of print("hello")
from __future__ import unicode_literals  # force unadorned strings "" to be unicode without prepending u""

db_filename = "stuff.sqlite3"
<commit_msg>minor<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-
"""production configuration (imported by __init__.py)"""
from __future__ import division  # 1/2 == 0.5, as in Py3
from __future__ import absolute_import  # avoid hiding global modules with locals
from __future__ import print_function  # force use of print("hello")
from __future__ import unicode_literals  # force unadorned strings "" to be unicode without prepending u""

db_filename = "data.sqlite"
<|endoftext|>


<commit_before>from .cgc_type1_exploit import CGCType1Exploit
from .cgc_type2_exploit import CGCType2Exploit
from .cgc_exploit import CGCExploit
from .type1 import CGCType1RopExploit, CGCType1ShellcodeExploit, CGCType1CircumstantialExploit
from .type2 import CGCType2RopExploit, CGCType2ShellcodeExploit
from .derander import Derander<commit_msg>one last ref to remove<commit_after>from .cgc_type1_exploit import CGCType1Exploit
from .cgc_type2_exploit import CGCType2Exploit
from .cgc_exploit import CGCExploit
from .type1 import CGCType1RopExploit, CGCType1ShellcodeExploit, CGCType1CircumstantialExploit
from .type2 import CGCType2RopExploit, CGCType2ShellcodeExploit
<|endoftext|>


<commit_before>import time
from bokeh.plotting import figure, output_server, cursession, show

#prepare some data
x = [1, 2, 3, 4, 5]
y = [6, 7, 2, 4, 5]

# output to static HTML file
output_server("animated_line")

# Plot a `line` renderer setting the color, line thickness, title, and legend value.
p = figure(title="One Line")
p.line(x, y, legend="Temp.", x_axis_label='x', y_axis_label='y', name='example1')

show(p)

# create some simple animation..
# first get our figure example data source
renderer = p.select(dict(name="example1"))
ds = renderer[0].data_source

# now all we need to do is update the y values in that data source and
# the the current session to store the change
while True:
    values = []
    for i in range(1, 20):
        new_values = ds.data["y"] = [y_ ** i for y_ in y]
        cursession().store_objects(ds)
        time.sleep(0.1)
        values.append(new_values)

    for new_values in values[::-1]:
        ds.data["y"] = new_values
        cursession().store_objects(ds)
        time.sleep(0.1)<commit_msg>update quickstart animated line server example<commit_after>import time
from bokeh.plotting import figure, output_server, cursession, show

#prepare some data
x = [1, 2, 3, 4, 5]
y = [6, 7, 2, 4, 5]

# output to static HTML file
output_server("animated_line")

# Plot a `line` renderer setting the color, line thickness, title, and legend value.
p = figure(title="One Line")
p.line(x, y, legend="Temp.", x_axis_label='x', y_axis_label='y', name='example1')

show(p)

# create some simple animation..
# first get our figure example data source
renderer = p.select(dict(name="example1"))
ds = renderer[0].data_source

# we create 19 new lists of y-values to use them as steps in our animation
values = []
for i in range(1, 20):
    values.append([y_ ** i for y_ in y])

while True:
    # now we update the y column in the datasource with each y-value list in the values list
    for val in values:
        ds.data["y"] = val
        cursession().store_objects(ds)
        time.sleep(0.1)

    # and now we go back to the initial state just reversing the values list
    for val in values[::-1]:
        ds.data["y"] = val
        cursession().store_objects(ds)
        time.sleep(0.1)<|endoftext|>


<commit_before>from numpy import array, sign

from .. import Play
from ..tactics.goalkeeper import Goalkeeper
from ..tactics.zickler43 import Zickler43
from ..tactics.blocker import Blocker
from ..tactics.defender import Defender
from ..tactics.executepass import ExecutePass
from ..tactics.receivepass import ReceivePass
from ..tactics.receivepassandkick import ReceivePassAndKick
from ...utils.mathutils import angle_between
from ...utils.geom import Point, Line

from numpy import linspace

class Ifrit(Play):
    """
    This is the first cooperative play in this project.

    Basically, set the closest robot to the ball to be either an attacker
    - in case he has a clear shot to the goal - or a passer, if he does not.

    We'll have a second robot in a receiving position: a pivot, which will
    be ready to receive the ball and immediately kick it towards the goal.

    The rest is the same as the autoretaliate play.
    """

    def __init__(self, team, **kwargs):
        """
        team: duh
        """
        super(Ifrit, self).__init__(team, **kwargs)
        self.players = {}
        self.last_passer = None
        self.tactics_factory.update({
            'goalkeeper': lambda robot: Goalkeeper(robot, aggressive=False, angle=0),
            'attacker': lambda robot: Zickler43(robot),
            'blocker': lambda robot: Blocker(robot, arc=0),
            'defender': lambda robot: Defender(robot, enemy=self.ball, distance=0.6),
            'passer': lambda robot: ExecutePass(robot),
            'receiver': lambda robot: ReceivePassAndKick(robot),
        })

    def setup_tactics(self):
        # Make sure that the robot receiving the ball keeps kicking it even if its tactic changes.
        for attacker in [self.players[x.uid]['attacker'] for x in self.team]:
            if attacker.time_of_last_kick + .5 < self.world.timestamp:
                self.hold_down_passer = self.last_passer
            if attacker.time_of_last_kick + 8 < self.world.timestamp and self.last_passer is not None:
                print self.hold_down_passer.uid
                self.hold_down_passer.action.kick = 1

        # list of the ids of the robots in order of proximity to the ball
        closest_robots = [r.uid for r in self.team.closest_robots_to_ball(can_kick=True)]
        # make sure we do not account for the goalkeeper on that list
        gk_id = self.goalie
        if gk_id in closest_robots:
            closest_robots.remove(gk_id)

        atk_id = closest_robots[0] if len(closest_robots) > 0 else None

        # Here we split from autoretaliate.
        # We'll find now the best position for our pivot to receive a possible pass.
        best_position = self.best_receiver_positions(self.team[atk_id])[0][0]
        robots_closest_to_bathtub = self.team.closest_robots_to_point(point=best_position)
        if self.team[atk_id] in robots_closest_to_bathtub:
            robots_closest_to_bathtub.remove(self.team[atk_id])
        if self.team[gk_id] in robots_closest_to_bathtub:
            robots_closest_to_bathtub.remove(self.team[gk_id])

        # Here, we'll get a pivot.
        pvt_id = robots_closest_to_bathtub[0].uid if len(robots_closest_to_bathtub) > 0 else None
        if pvt_id in closest_robots:
            closest_robots.remove(pvt_id)

        blk_id = closest_robots[1] if len(closest_robots) > 1 else None

        # gather the defenders (not goalkeeper, attacker, pivot or blocker)
        defenders = [r for r in self.team if r.uid not in [gk_id, atk_id, blk_id, pvt_id]]

        # iterate over list of enemies by proximity to the goal
        for enemy in self.enemy_team.closest_robots_to_point(self.team.goal):
            # if there are free defenders, assign the closest to the enemy, to follow it
            if len(defenders) > 0:
                defender = enemy.closest_to(defenders)
                defenders.remove(defender)
                self.players[defender.uid]['defender'].enemy = enemy

        # for any remaining defender, let them guard the ball
        for defender in defenders:
            self.players[defender.uid]['defender'].enemy = self.ball

        # Setting position for the pivot
        if pvt_id is not None:
            self.players[pvt_id]['receiver'].point = best_position
        goal_kick = True
        # Check if we want to pass or if we want to kick.
        if atk_id is not None and pvt_id is not None:
            if self.world.has_clear_shot(self.players[atk_id]['attacker'].lookpoint):
                goal_kick = True
                self.players[pvt_id]['receiver'].companion = self.players[atk_id]['attacker']
            #print self.players[pvt_id]['receiver'].companion, self.players[atk_id]['attacker']
            else:
                self.players[atk_id]['passer'].companion = self.players[pvt_id]['receiver']
                self.players[pvt_id]['receiver'].companion = self.players[atk_id]['passer']
                goal_kick = False
        #print self.is_valid_position(self.team[0], self.team[1], verbose=True)
        # step'em, this is needed to guarantee we're only stepping active robots
        for robot in self.team:
            r_id = robot.uid
            if r_id == gk_id:
                robot.current_tactic = self.players[r_id]['goalkeeper']
            elif r_id == atk_id and goal_kick:
                robot.current_tactic = self.players[r_id]['attacker']
            elif r_id == atk_id and not goal_kick:
                robot.current_tactic = self.players[r_id]['passer']

                self.last_passer = robot
            elif r_id == blk_id:
                robot.current_tactic = self.players[r_id]['blocker']
            elif r_id == pvt_id:
                robot.current_tactic = self.players[r_id]['receiver']
            else:
                robot.current_tactic = self.players[r_id]['defender']

    def is_valid_position(self, point, passer, verbose=False):
        base_array = array(point) - array(self.world.ball)
        p0, p1 = array(passer.enemy_goal.p1), array(passer.enemy_goal.p2)
        angle1, angle2 = angle_between(base_array, p0), angle_between(base_array, p1)
        for angle in [angle1, angle2]:
            angle = angle if angle < 180 else angle - 360
        if verbose:
            print angle1, angle2
        return abs(angle1) < 70 and abs(angle2) < 70 and (not Line(point, passer.enemy_goal.p1).crosses(passer.body)) and (not Line(point, passer.enemy_goal.p2).crosses(passer.body))

    def best_receiver_positions(self, passer, target=None, precision=6):
        """
        Discretizes points over the field (respecting a minimum border from the field,
        and without entering none of the defense areas), according to given precision.
        Searches for clear paths between initial position (ball), intermediate position,
        and the target.

        Returns a sorted list of tuples (Points that are closer to the target come
        first):
        [(point, distance_to_target), (point, distance_to_target), (point, distance_to_target), ...]
        """
        # TODO: aim for the best spot in the goal, not only to the middle of the enemy goal

        #t = self.team
        b = self.world.ball

        if target is None:
            #target = self.team.enemy_goal
            target = self.team.enemy_goal

        candidate = []
        safety_margin = 2 * self.team[0].radius + 0.1

        # field params:
        f_l = self.world.length - self.world.defense_radius - safety_margin
        f_w = self.world.width - safety_margin

        # candidate points in the field range
        for x in linspace(-f_l / 2, f_l / 2, precision):
            for y in linspace(-f_w / 2, f_w / 2, precision - 2):
                pt = Point(x, y)
                if not self.is_valid_position(pt, passer):
                    continue
                acceptable = True
                final_line = Point(0, 0)
                for enemy in self.team.enemy_team.iterrobots():
                    # if the robot -> pt line doesn't cross any enemy body...
                    start_line = Line(b, pt)
                    if not start_line.crosses(enemy.body):
                        final_line = Line(pt, target)
                        # if the pt -> target line crosses any enemy body...
                        if final_line.crosses(enemy.body):
                            acceptable = False
                if acceptable:
                    candidate += [(pt, start_line.length + final_line.length)]
        if not candidate:
            #goal_point = self.enemy_goal
            return [(Point(self.team.enemy_goal.x - sign(self.team.enemy_goal.x), self.team.enemy_goal.y), 1)]
        else:
            return sorted(candidate, key=lambda tup: tup[1])
<commit_msg>Minor alterations to ifrit.<commit_after>from numpy import array, sign

from .. import Play
from ..tactics.goalkeeper import Goalkeeper
from ..tactics.zickler43 import Zickler43
from ..tactics.blocker import Blocker
from ..tactics.defender import Defender
from ..tactics.executepass import ExecutePass
from ..tactics.receivepass import ReceivePass
from ..tactics.receivepassandkick import ReceivePassAndKick
from ...utils.mathutils import angle_between
from ...utils.geom import Point, Line

from numpy import linspace

class Ifrit(Play):
    """
    This is the first cooperative play in this project.

    Basically, set the closest robot to the ball to be either an attacker
    - in case he has a clear shot to the goal - or a passer, if he does not.

    We'll have a second robot in a receiving position: a pivot, which will
    be ready to receive the ball and immediately kick it towards the goal.

    The rest is the same as the autoretaliate play.
    """

    def __init__(self, team, **kwargs):
        """
        team: duh
        """
        super(Ifrit, self).__init__(team, **kwargs)
        self.players = {}
        self.last_passer = None
        self.tactics_factory.update({
            'goalkeeper': lambda robot: Goalkeeper(robot, aggressive=False, angle=0),
            'attacker': lambda robot: Zickler43(robot),
            'blocker': lambda robot: Blocker(robot, arc=0),
            'defender': lambda robot: Defender(robot, enemy=self.ball, distance=0.6),
            'passer': lambda robot: ExecutePass(robot),
            'receiver': lambda robot: ReceivePassAndKick(robot),
        })

    def setup_tactics(self):
        # Make sure that the robot receiving the ball keeps kicking it even if its tactic changes.
        for attacker in [self.players[x.uid]['attacker'] for x in self.team]:
            if attacker.time_of_last_kick + .5 < self.world.timestamp:
                self.hold_down_passer = self.last_passer
            if attacker.time_of_last_kick + 8 < self.world.timestamp and self.last_passer is not None:
                print self.hold_down_passer.uid
                self.hold_down_passer.action.kick = 1

        # list of the ids of the robots in order of proximity to the ball
        closest_robots = [r.uid for r in self.team.closest_robots_to_ball(can_kick=True)]
        # make sure we do not account for the goalkeeper on that list
        gk_id = self.goalie
        if gk_id in closest_robots:
            closest_robots.remove(gk_id)

        atk_id = closest_robots[0] if len(closest_robots) > 0 else None

        # Here we split from autoretaliate.
        # We'll find now the best position for our pivot to receive a possible pass.
        best_position = self.best_receiver_positions(self.team[atk_id])[0][0]
        robots_closest_to_bathtub = self.team.closest_robots_to_point(point=best_position)
        if self.team[atk_id] in robots_closest_to_bathtub:
            robots_closest_to_bathtub.remove(self.team[atk_id])
        if self.team[gk_id] in robots_closest_to_bathtub:
            robots_closest_to_bathtub.remove(self.team[gk_id])

        # Here, we'll get a pivot.
        pvt_id = robots_closest_to_bathtub[0].uid if len(robots_closest_to_bathtub) > 0 else None
        if pvt_id in closest_robots:
            closest_robots.remove(pvt_id)

        blk_id = closest_robots[1] if len(closest_robots) > 1 else None

        # gather the defenders (not goalkeeper, attacker, pivot or blocker)
        defenders = [r for r in self.team if r.uid not in [gk_id, atk_id, blk_id, pvt_id]]

        # iterate over list of enemies by proximity to the goal
        for enemy in self.enemy_team.closest_robots_to_point(self.team.goal):
            # if there are free defenders, assign the closest to the enemy, to follow it
            if len(defenders) > 0:
                defender = enemy.closest_to(defenders)
                defenders.remove(defender)
                self.players[defender.uid]['defender'].enemy = enemy

        # for any remaining defender, let them guard the ball
        for defender in defenders:
            self.players[defender.uid]['defender'].enemy = self.ball

        # Setting position for the pivot
        if pvt_id is not None:
            self.players[pvt_id]['receiver'].point = best_position
        goal_kick = True
        # Check if we want to pass or if we want to kick.
        if atk_id is not None and pvt_id is not None:
            if self.world.has_clear_shot(self.players[atk_id]['attacker'].lookpoint):
                goal_kick = True
                self.players[pvt_id]['receiver'].companion = self.players[atk_id]['attacker']
            #print self.players[pvt_id]['receiver'].companion, self.players[atk_id]['attacker']
            else:
                self.players[atk_id]['passer'].companion = self.players[pvt_id]['receiver']
                self.players[pvt_id]['receiver'].companion = self.players[atk_id]['passer']
                goal_kick = False
        #print self.is_valid_position(self.team[0], self.team[1], verbose=True)
        # step'em, this is needed to guarantee we're only stepping active robots
        for robot in self.team:
            r_id = robot.uid
            if r_id == gk_id:
                robot.current_tactic = self.players[r_id]['goalkeeper']
            elif r_id == atk_id and goal_kick:
                robot.current_tactic = self.players[r_id]['attacker']
            elif r_id == atk_id and not goal_kick:
                robot.current_tactic = self.players[r_id]['passer']

                self.last_passer = robot
            elif r_id == blk_id:
                robot.current_tactic = self.players[r_id]['blocker']
            elif r_id == pvt_id:
                robot.current_tactic = self.players[r_id]['receiver']
            else:
                robot.current_tactic = self.players[r_id]['defender']

    def is_valid_position(self, point, passer, verbose=False):
        base_array = array(point) - array(self.world.ball)
        p0, p1 = array(passer.enemy_goal.p1), array(passer.enemy_goal.p2)
        angle1, angle2 = angle_between(base_array, p0), angle_between(base_array, p1)
        for angle in [angle1, angle2]:
            angle = angle if angle < 180 else angle - 360
        if verbose:
            print angle1, angle2
        return abs(angle1) < 70 and abs(angle2) < 70 and (not Line(point, passer.enemy_goal.p1).crosses(passer.body)) and (not Line(point, passer.enemy_goal.p2).crosses(passer.body))

    def best_receiver_positions(self, passer, target=None, precision=6):
        """
        Discretizes points over the field (respecting a minimum border from the field,
        and without entering none of the defense areas), according to given precision.
        Searches for clear paths between initial position (ball), intermediate position,
        and the target.

        Returns a sorted list of tuples (Points that are closer to the target come
        first):
        [(point, distance_to_target), (point, distance_to_target), (point, distance_to_target), ...]
        """
        # TODO: aim for the best spot in the goal, not only to the middle of the enemy goal

        #t = self.team
        b = self.world.ball

        if target is None:
            #target = self.team.enemy_goal
            target = self.team.enemy_goal

        candidate = []
        candidate_no_vision = []
        safety_margin = 2 * self.team[0].radius + 0.1

        # field params:
        f_l = self.world.length - self.world.defense_radius - safety_margin
        f_w = self.world.width - safety_margin

        # candidate points in the field range
        for x in linspace(-f_l / 2, f_l / 2, precision):
            for y in linspace(-f_w / 2, f_w / 2, precision - 2):
                pt = Point(x, y)
                if not self.is_valid_position(pt, passer):
                    continue
                acceptable = True
                final_line = Point(0, 0)
                for enemy in self.team.enemy_team.iterrobots():
                    # if the robot -> pt line doesn't cross any enemy body...
                    start_line = Line(b, pt)
                    if start_line is not None and not start_line.crosses(enemy.body):
                        final_line = Line(pt, target)
                        # if the pt -> target line crosses any enemy body...
                        if final_line.crosses(enemy.body):
                            acceptable = False
                if acceptable:
                    candidate += [(pt, start_line.length + final_line.length)]
                candidate_no_vision += [(pt, start_line.length + final_line.length)]
        if candidate:
            #goal_point = self.enemy_goal
            return sorted(candidate, key=lambda tup: tup[1])
        elif candidate_no_vision:
             return sorted(candidate_no_vision, key=lambda tup: tup[1])
        else:
            return [(Point(self.team.enemy_goal.x - sign(self.team.enemy_goal.x), self.team.enemy_goal.y), 1)]

<|endoftext|>


<commit_before>from argparse import ArgumentParser
from .config import ConfigReader, ReadingError
from .dispatcher import Dispatcher, DispatchError
from .messenger import Messenger
from .messenger import Level

def add_options(parser):
    parser.add_argument('-Q', '--super-quiet', dest = 'super_quiet', action = 'store_true',
        help = 'suppress almost all output')
    parser.add_argument('-q', '--quiet', dest = 'quiet', action = 'store_true',
        help = 'suppress most output')
    parser.add_argument('-v', '--verbose', dest = 'verbose', action = 'store_true',
        help = 'enable verbose output')
    parser.add_argument('-d', '--base-directory', nargs = 1,
        dest = 'base_directory', help = 'execute commands from within BASEDIR',
        metavar = 'BASEDIR', required = True)
    parser.add_argument('-c', '--config-file', nargs = 1, dest = 'config_file',
        help = 'run commands given in CONFIGFILE', metavar = 'CONFIGFILE',
        required = True)

def read_config(config_file):
    reader = ConfigReader(config_file)
    return reader.get_config()

def main():
    log = Messenger()
    try:
        parser = ArgumentParser()
        add_options(parser)
        options = parser.parse_args()
        if (options.super_quiet):
            log.set_level(Level.WARNING)
        if (options.quiet):
            log.set_level(Level.INFO)
        if (options.verbose):
            log.set_level(Level.DEBUG)
        tasks = read_config(options.config_file[0])
        dispatcher = Dispatcher(options.base_directory[0])
        success = dispatcher.dispatch(tasks)
        if success:
            log.info('\n==> All tasks executed successfully')
        else:
            raise DispatchError('\n==> Some tasks were not executed successfully')
    except (ReadingError, DispatchError) as e:
        log.error('%s' % e)
        exit(1)
<commit_msg>Add keyboard interrupt handler<commit_after>from argparse import ArgumentParser
from .config import ConfigReader, ReadingError
from .dispatcher import Dispatcher, DispatchError
from .messenger import Messenger
from .messenger import Level

def add_options(parser):
    parser.add_argument('-Q', '--super-quiet', dest = 'super_quiet', action = 'store_true',
        help = 'suppress almost all output')
    parser.add_argument('-q', '--quiet', dest = 'quiet', action = 'store_true',
        help = 'suppress most output')
    parser.add_argument('-v', '--verbose', dest = 'verbose', action = 'store_true',
        help = 'enable verbose output')
    parser.add_argument('-d', '--base-directory', nargs = 1,
        dest = 'base_directory', help = 'execute commands from within BASEDIR',
        metavar = 'BASEDIR', required = True)
    parser.add_argument('-c', '--config-file', nargs = 1, dest = 'config_file',
        help = 'run commands given in CONFIGFILE', metavar = 'CONFIGFILE',
        required = True)

def read_config(config_file):
    reader = ConfigReader(config_file)
    return reader.get_config()

def main():
    log = Messenger()
    try:
        parser = ArgumentParser()
        add_options(parser)
        options = parser.parse_args()
        if (options.super_quiet):
            log.set_level(Level.WARNING)
        if (options.quiet):
            log.set_level(Level.INFO)
        if (options.verbose):
            log.set_level(Level.DEBUG)
        tasks = read_config(options.config_file[0])
        dispatcher = Dispatcher(options.base_directory[0])
        success = dispatcher.dispatch(tasks)
        if success:
            log.info('\n==> All tasks executed successfully')
        else:
            raise DispatchError('\n==> Some tasks were not executed successfully')
    except (ReadingError, DispatchError) as e:
        log.error('%s' % e)
        exit(1)
    except KeyboardInterrupt:
        log.error('\n==> Operation aborted')
        exit(1)
<|endoftext|>


<commit_before>#!/usr/bin/env python3
import argparse
import os
import re
import sqlite3
from datetime import datetime
from urllib.parse import urljoin

import requests
import yaml
from bs4 import BeautifulSoup

def course_loop():
    download_count = 0
    skip_count = 0

    # import config
    with open(os.path.join(os.path.dirname(__file__), 'data', 'config.yaml'), 'r', encoding='utf-8') as config_file:
        config = yaml.load(config_file)

    # load the sources module
    module = __import__('sources')

    # make the initial request to get the token
    session = requests.Session()

    # Loop through moodles
    for moodle in config:
        if verbose_output:
            print('\nMoodle: %s' % moodle['name'])

        # load dynamically the source class
        source_class = getattr(module, moodle['class'])
        source = source_class()
        # source = Source()

        # login
        source.login(session, moodle['login_url'], moodle['username'], moodle['password'])

        if 'courses' not in moodle:
            continue

        # loop through courses
        for course in moodle['courses']:

            # check if only some courses should be checked
            if course_part is not None and course['name'] not in course_part:
                continue

            if verbose_output:
                print('Course: %s' % course['name'])

            course_url = urljoin(moodle['base_url'], '/course/view.php?id=' + str(course['id']))

            # search only main content
            course_content = BeautifulSoup(session.get(course_url).text, 'html.parser').find(id='region-main')

            links = source.generate_link_list(session, course_url)

            for link_text in course_content.find_all(string=re.compile(course['pattern'])):
                link = link_text.find_parent('a')
                if link is not None and link['href'].find('resource') != -1:
                    # request file http header
                    file_request = session.head(link['href'], allow_redirects=True)

                    # get file name
                    if 'Content-Disposition' in file_request.headers:
                        file_disposition = file_request.headers['Content-Disposition']
                        file_name = file_disposition[
                                    file_disposition.index('filename=') + 10:len(file_disposition) - 1].encode(
                            'latin-1').decode('utf8')
                    else:
                        file_name = link_text

                    # check extension
                    if 'ext' in course and course['ext'] is not False:
                        file_ext = os.path.splitext(file_name)[1]
                        if file_ext != course['ext']:
                            continue

                    # get last modified date as timestamp
                    file_last_modified = int(datetime.strptime(file_request.headers['Last-Modified'],
                                                               '%a, %d %b %Y %H:%M:%S %Z').timestamp())
                    # adjust file name
                    if 'rename' in course and course['rename'] is not False:
                        # find a number
                        num = re.search('\d{1,2}', link_text)
                        if num is None:
                            num = re.search('\d{1,2}', file_name)
                        if num is None:
                            num = file_last_modified
                        else:
                            num = num.group(0)
                        file_name = course['rename'].replace('%', str(num))

                    # fetch old timestamp from database
                    file_last_modified_old = c.execute(
                        'SELECT last_modified FROM file_modifications WHERE course=? AND file_name=?',
                        (course['name'], file_name)).fetchone()

                    # save file and timestamp in the database if it doesn't exists
                    if file_last_modified_old is None:
                        c.execute('INSERT INTO file_modifications (course, file_name, last_modified) VALUES (?,?,?)',
                                  (course['name'], file_name, file_last_modified))
                    # update timestamp if there's a newer version of the file
                    elif file_last_modified > file_last_modified_old[0]:
                        c.execute('UPDATE file_modifications SET last_modified=? WHERE course=? and file_name=?',
                                  (file_last_modified, course['name'], file_name))
                    # otherwise skip saving
                    else:
                        skip_count += 1
                        if verbose_output:
                            print(file_name + ' (skipped)')
                        continue

                    if verbose_output:
                        print(file_name + ' (new)')

                    # request whole file
                    file_request = session.get(link['href'])

                    file_name = os.path.join(course['local_folder'], file_name)

                    # write file
                    try:
                        # os.makedirs(os.path.dirname(file_name), exist_ok=True)
                        with open(file_name, 'wb') as f:
                            f.write(file_request.content)
                            download_count += 1
                    except FileNotFoundError:
                        print('Can\'t write file to %s' % os.path.join(course['local_folder'], file_name))
                        conn.rollback()

                    # save changes to the database
                    conn.commit()

    # display count of downloaded files
    if verbose_output:
        print('\nDownloaded %i file(s), skipped %i file(s)' % (download_count, skip_count))

def clear_course():
    if course_to_clear[0] == 'all':
        c.execute("DELETE from file_modifications")
        print('\nCleared all courses')
    else:
        c.execute("DELETE from file_modifications WHERE course=?", course_to_clear)
        print('\nCleared course %s' % course_to_clear[0])
    conn.commit()

# command line args
parser = argparse.ArgumentParser(description='A simple script for downloading slides and exercises from moodles.')
parser.add_argument('-v', '--verbose', action='store_true', help='verbose output')
parser.add_argument('-c', '--course', action='append', help='specify a course which should be checked')
parser.add_argument('--clear', action='append',
                    help='specify a course which files should be deleted from the database (not from file system).'
                         + 'Use keyword \'all\' to clear the whole database')
args = parser.parse_args()

verbose_output = args.verbose
course_part = args.course
course_to_clear = args.clear

# database for timestamps
conn = sqlite3.connect(os.path.join(os.path.dirname(__file__), 'data', 'file_modifications.db'))
c = conn.cursor()

# check if table exists otherwise create it
c.execute(
    '''
    CREATE TABLE IF NOT EXISTS file_modifications (
        id	INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
        moodle TEXT,
        course	TEXT,
        file_name	TEXT,
        file_path TEXT,
        last_modified	INTEGER
    );
    ''')

if course_to_clear is not None:
    clear_course()
else:
    course_loop()

# close cursor
c.close()
<commit_msg>add function for logging<commit_after>#!/usr/bin/env python3
import argparse
import os
import re
import sqlite3
from datetime import datetime
from urllib.parse import urljoin

import requests
import yaml
from bs4 import BeautifulSoup

def log(msg):
    if verbose_output:
        print(msg)

def course_loop():
    download_count = 0
    skip_count = 0

    # import config
    with open(os.path.join(os.path.dirname(__file__), 'data', 'config.yaml'), 'r', encoding='utf-8') as config_file:
        config = yaml.load(config_file)

    # load the sources module
    module = __import__('sources')

    # make the initial request to get the token
    session = requests.Session()

    # Loop through moodles
    for src in config:
        log('\nSource: %s' % src['name'])

        # check if there are courses to download from
        if 'courses' not in src:
            continue

        # load dynamically the source class
        source_class = getattr(module, src['class'])
        source = source_class()
        # source = Source()

        # login
        source.login(session, src['login_url'], src['username'], src['password'])

        # loop through courses
        for course in src['courses']:

            # check if only some courses should be checked
            if course_part is not None and course['name'] not in course_part:
                continue

            log('Course: %s' % course['name'])

            course_url = urljoin(src['base_url'], '/course/view.php?id=' + str(course['id']))

            # search only main content
            course_content = BeautifulSoup(session.get(course_url).text, 'html.parser').find(id='region-main')

            links = source.generate_link_list(session, course_url)

            for link_text in course_content.find_all(string=re.compile(course['pattern'])):
                link = link_text.find_parent('a')
                if link is not None and link['href'].find('resource') != -1:
                    # request file http header
                    file_request = session.head(link['href'], allow_redirects=True)

                    # get file name
                    if 'Content-Disposition' in file_request.headers:
                        file_disposition = file_request.headers['Content-Disposition']
                        file_name = file_disposition[
                                    file_disposition.index('filename=') + 10:len(file_disposition) - 1].encode(
                            'latin-1').decode('utf8')
                    else:
                        file_name = link_text

                    # check extension
                    if 'ext' in course and course['ext'] is not False:
                        file_ext = os.path.splitext(file_name)[1]
                        if file_ext != course['ext']:
                            continue

                    # get last modified date as timestamp
                    file_last_modified = int(datetime.strptime(file_request.headers['Last-Modified'],
                                                               '%a, %d %b %Y %H:%M:%S %Z').timestamp())
                    # adjust file name
                    if 'rename' in course and course['rename'] is not False:
                        # find a number
                        num = re.search('\d{1,2}', link_text)
                        if num is None:
                            num = re.search('\d{1,2}', file_name)
                        if num is None:
                            num = file_last_modified
                        else:
                            num = num.group(0)
                        file_name = course['rename'].replace('%', str(num))

                    # fetch old timestamp from database
                    file_last_modified_old = c.execute(
                        'SELECT last_modified FROM file_modifications WHERE course=? AND file_name=?',
                        (course['name'], file_name)).fetchone()

                    # save file and timestamp in the database if it doesn't exists
                    if file_last_modified_old is None:
                        c.execute('INSERT INTO file_modifications (course, file_name, last_modified) VALUES (?,?,?)',
                                  (course['name'], file_name, file_last_modified))
                    # update timestamp if there's a newer version of the file
                    elif file_last_modified > file_last_modified_old[0]:
                        c.execute('UPDATE file_modifications SET last_modified=? WHERE course=? and file_name=?',
                                  (file_last_modified, course['name'], file_name))
                    # otherwise skip saving
                    else:
                        skip_count += 1
                        log(file_name + ' (skipped)')
                        continue

                    log(file_name + ' (new)')

                    # request whole file
                    file_request = session.get(link['href'])

                    file_name = os.path.join(course['local_folder'], file_name)

                    # write file
                    try:
                        os.makedirs(os.path.dirname(file_name), exist_ok=True)
                        with open(file_name, 'wb') as f:
                            f.write(file_request.content)
                            download_count += 1
                    except FileNotFoundError:
                        print('Can\'t write file to %s' % os.path.join(course['local_folder'], file_name))
                        conn.rollback()

                    # save changes to the database
                    conn.commit()

    # display count of downloaded files
    log('\nDownloaded %i file(s), skipped %i file(s)' % (download_count, skip_count))

def clear_course():
    if course_to_clear[0] == 'all':
        c.execute("DELETE from file_modifications")
        log('\nCleared all courses')
    else:
        c.execute("DELETE from file_modifications WHERE course=?", course_to_clear)
        log('\nCleared course %s' % course_to_clear[0])
    conn.commit()

# command line args
parser = argparse.ArgumentParser(description='A simple script for downloading slides and exercises from moodles.')
parser.add_argument('-v', '--verbose', action='store_true', help='verbose output')
parser.add_argument('-c', '--course', action='append', help='specify a course which should be checked')
parser.add_argument('--clear', action='append',
                    help='specify a course which files should be deleted from the database (not from file system).'
                         + 'Use keyword \'all\' to clear the whole database')
args = parser.parse_args()

verbose_output = args.verbose
course_part = args.course
course_to_clear = args.clear

# database for timestamps
conn = sqlite3.connect(os.path.join(os.path.dirname(__file__), 'data', 'file_modifications.db'))
c = conn.cursor()

# check if table exists otherwise create it
c.execute(
    '''
    CREATE TABLE IF NOT EXISTS file_modifications (
        id	INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
        moodle TEXT,
        course	TEXT,
        file_name	TEXT,
        file_path TEXT,
        last_modified	INTEGER
    );
    ''')

if course_to_clear is not None:
    clear_course()
else:
    course_loop()

# close cursor
c.close()
<|endoftext|>


<commit_before>import sublime, sublime_plugin, locale, datetime
import calendar,locale

# view.run_command("dr_calendar_insert_month")

def add_month(y,m,x):
        r_m = m + x
        r_y = y
        if (r_m < 1):
            r_y -= 1
            r_m = 12
        if (r_m > 12):
            r_m = 1
            r_y += 1
        return (r_y,r_m)

class TDrCalend():
    def __init__(self,y,m):
        self.y = y
        self.m = m
        self.mc = self.GetMonthCalendarAsText()

    def GetMonthCalendarAsText(self):
        c = calendar.TextCalendar()
        mc = c.monthdatescalendar(self.y, self.m)
        today = datetime.date.today()#+datetime.timedelta(days=10) #debug
        self.dd = datetime.date(self.y, self.m, 1)
        # s = '{:      %B %Y}\n'.format(self.dd)
        s = '{0: %B %Y}'.format(self.dd)
        s = '{0: ^21}'.format(s)+"\n"
        # s += '\n'

        for w in mc:
            for d in w:
            	s += ' ' + '{0:%a}'.format(d)[0:2]
            s += '\n'
            break

        for w in mc:
            for d in w:
                if (d.month == self.m):
                    if d == today:
                        s += '{0:>3}'.format('*'+str(d.day))
                    else:
                        s += '{0:>3}'.format(d.day)
                else:
                    s += "   "
            s += "\n"
        return (s)

class DrMonthsCalendarOpen(sublime_plugin.TextCommand):
	def is_visible(self):
		return True
	def is_enabled(self):
		return True
	def run(self, edit):
		loc = locale.getlocale() # get current locale
		if sys.version[0] == "2":
			locale.setlocale(locale.LC_ALL, 'C')
		else:
			locale.setlocale(locale.LC_ALL, '')
		c = calendar.TextCalendar()
		# self.view.insert(edit, self.view.sel().begin(), c.formatmonth(2013,9))
		today = datetime.date.today()#+datetime.timedelta(days=10) #debug
		(pr_y, pr_m) = add_month(today.year,today.month,-1)
		c1 = TDrCalend(pr_y,pr_m).GetMonthCalendarAsText()
		c11 = c1.splitlines()
		c2 = TDrCalend(today.year,today.month).GetMonthCalendarAsText()
		c22 = c2.splitlines()
		(n_y, n_m) = add_month(today.year,today.month,1)
		c3 = TDrCalend(n_y,n_m).GetMonthCalendarAsText()
		c33 = c3.splitlines()
		c4 = []

		for x in range(0,8):
			if len(c11) <= x:
				c4.append('{0: >23}'.format(""))
			else:
				c4.append('{0: >23}'.format(c11[x]))   # use '*' as a fill char
			if len(c22) <= x:
				c4[x] = c4[x] + '  ' +'{0: <21}'.format("")
			else:
				c4[x] = c4[x] + '  ' +'{0: <21}'.format(c22[x])
			if len(c33) <= x:
				c4[x] = c4[x] + '  ' +'{0: <21}'.format("")
			else:
				c4[x] = c4[x] + '  ' +'{0: <21}'.format(c33[x])

		# for pos in self.view.sel():
		# 	b = pos.begin()
		# 	rr = self.view.insert(edit, pos.begin(), "\n".join(c4)+'\n')
		# 	r = sublime.Region(b, b+rr)
		# 	print ("\n".join(c4)+'\n')
		# 	self.view.add_regions('DrCalendar',[r],"keyword",'',sublime.HIDDEN)

		self.output_view = self.view.window().get_output_panel("textarea_drcalendar")
		self.view.window().run_command("show_panel", {"panel": "output.textarea_drcalendar"})
		# self.output_view.run_command("set_file_type", {"Packages/DrCalendar/DrCalendar.tmLanguage"})
		self.output_view.set_syntax_file("Packages/DrMonthsCalendar/DrCalendar.tmLanguage")
		self.output_view.set_read_only(False)

		# self.output_view.insert(edit, self.output_view.size(), today.strftime('   %A %x')+"\n\n")
		self.output_view.insert(edit, self.output_view.size(),"\n".join(c4))
		self.output_view.insert(edit, self.output_view.size(), "\n"+today.strftime('   %A %x'))

		locale.setlocale(locale.LC_ALL, loc)

		# self.output_view.insert(edit, self.output_view.size(),"\n".join(c22)+'\n')

		# self.output_view.run_command("append", {"characters": "Hello, World!"})
		# self.output_view.set_read_only(True)
		# r = sublime.Region(1, 100)
		# # DRAW_OUTLINED
		# self.output_view.add_regions('DrCalendar',[r],"keyword",'',sublime.HIDDEN)
		# self.view.window().focusView(self.output_view)

		# self.view.window().show_quick_panel("123", None, sublime.MONOSPACE_FONT)

class DrCalendarInsertMonthCommand1(sublime_plugin.TextCommand):
	def run(self, edit):
		loc = locale.getlocale() # get current locale
		locale.setlocale(locale.LC_ALL, '')
		c = calendar.TextCalendar()
		# self.view.insert(edit, self.view.sel().begin(), c.formatmonth(2013,9))
		i = len(self.view.sel())
		if i > 1 :
			i = -1
		for pos in self.view.sel():
			self.view.insert(edit, pos.begin(), c.formatmonth(2013,9+i))
			i = i + 1;
<commit_msg>import sys<commit_after>import sublime, sublime_plugin, locale, datetime
import calendar,locale,sys

# view.run_command("dr_calendar_insert_month")

def add_month(y,m,x):
        r_m = m + x
        r_y = y
        if (r_m < 1):
            r_y -= 1
            r_m = 12
        if (r_m > 12):
            r_m = 1
            r_y += 1
        return (r_y,r_m)

class TDrCalend():
    def __init__(self,y,m):
        self.y = y
        self.m = m
        self.mc = self.GetMonthCalendarAsText()

    def GetMonthCalendarAsText(self):
        c = calendar.TextCalendar()
        mc = c.monthdatescalendar(self.y, self.m)
        today = datetime.date.today()#+datetime.timedelta(days=10) #debug
        self.dd = datetime.date(self.y, self.m, 1)
        # s = '{:      %B %Y}\n'.format(self.dd)
        s = '{0: %B %Y}'.format(self.dd)
        s = '{0: ^21}'.format(s)+"\n"
        # s += '\n'

        for w in mc:
            for d in w:
            	s += ' ' + '{0:%a}'.format(d)[0:2]
            s += '\n'
            break

        for w in mc:
            for d in w:
                if (d.month == self.m):
                    if d == today:
                        s += '{0:>3}'.format('*'+str(d.day))
                    else:
                        s += '{0:>3}'.format(d.day)
                else:
                    s += "   "
            s += "\n"
        return (s)

class DrMonthsCalendarOpen(sublime_plugin.TextCommand):
	def is_visible(self):
		return True
	def is_enabled(self):
		return True
	def run(self, edit):
		loc = locale.getlocale() # get current locale
		if sys.version[0] == "2":
			locale.setlocale(locale.LC_ALL, 'C')
		else:
			locale.setlocale(locale.LC_ALL, '')
		c = calendar.TextCalendar()
		# self.view.insert(edit, self.view.sel().begin(), c.formatmonth(2013,9))
		today = datetime.date.today()#+datetime.timedelta(days=10) #debug
		(pr_y, pr_m) = add_month(today.year,today.month,-1)
		c1 = TDrCalend(pr_y,pr_m).GetMonthCalendarAsText()
		c11 = c1.splitlines()
		c2 = TDrCalend(today.year,today.month).GetMonthCalendarAsText()
		c22 = c2.splitlines()
		(n_y, n_m) = add_month(today.year,today.month,1)
		c3 = TDrCalend(n_y,n_m).GetMonthCalendarAsText()
		c33 = c3.splitlines()
		c4 = []

		for x in range(0,8):
			if len(c11) <= x:
				c4.append('{0: >23}'.format(""))
			else:
				c4.append('{0: >23}'.format(c11[x]))   # use '*' as a fill char
			if len(c22) <= x:
				c4[x] = c4[x] + '  ' +'{0: <21}'.format("")
			else:
				c4[x] = c4[x] + '  ' +'{0: <21}'.format(c22[x])
			if len(c33) <= x:
				c4[x] = c4[x] + '  ' +'{0: <21}'.format("")
			else:
				c4[x] = c4[x] + '  ' +'{0: <21}'.format(c33[x])

		# for pos in self.view.sel():
		# 	b = pos.begin()
		# 	rr = self.view.insert(edit, pos.begin(), "\n".join(c4)+'\n')
		# 	r = sublime.Region(b, b+rr)
		# 	print ("\n".join(c4)+'\n')
		# 	self.view.add_regions('DrCalendar',[r],"keyword",'',sublime.HIDDEN)

		self.output_view = self.view.window().get_output_panel("textarea_drcalendar")
		self.view.window().run_command("show_panel", {"panel": "output.textarea_drcalendar"})
		# self.output_view.run_command("set_file_type", {"Packages/DrCalendar/DrCalendar.tmLanguage"})
		self.output_view.set_syntax_file("Packages/DrMonthsCalendar/DrCalendar.tmLanguage")
		self.output_view.set_read_only(False)

		# self.output_view.insert(edit, self.output_view.size(), today.strftime('   %A %x')+"\n\n")
		self.output_view.insert(edit, self.output_view.size(),"\n".join(c4))
		self.output_view.insert(edit, self.output_view.size(), "\n"+today.strftime('   %A %x'))

		locale.setlocale(locale.LC_ALL, loc)

		# self.output_view.insert(edit, self.output_view.size(),"\n".join(c22)+'\n')

		# self.output_view.run_command("append", {"characters": "Hello, World!"})
		# self.output_view.set_read_only(True)
		# r = sublime.Region(1, 100)
		# # DRAW_OUTLINED
		# self.output_view.add_regions('DrCalendar',[r],"keyword",'',sublime.HIDDEN)
		# self.view.window().focusView(self.output_view)

		# self.view.window().show_quick_panel("123", None, sublime.MONOSPACE_FONT)

class DrCalendarInsertMonthCommand1(sublime_plugin.TextCommand):
	def run(self, edit):
		loc = locale.getlocale() # get current locale
		locale.setlocale(locale.LC_ALL, '')
		c = calendar.TextCalendar()
		# self.view.insert(edit, self.view.sel().begin(), c.formatmonth(2013,9))
		i = len(self.view.sel())
		if i > 1 :
			i = -1
		for pos in self.view.sel():
			self.view.insert(edit, pos.begin(), c.formatmonth(2013,9+i))
			i = i + 1;
<|endoftext|>


<commit_before># Copyright 2015 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import shutil
import sys
import tarfile
import zipfile

from .__main__ import get_args
from .__main__ import run
from .util import info

def main(sysargv=None):
    args = get_args(sysargv=sysargv, skip_white_space_in=True, skip_connext=True, add_ros1=True)
    return run(args, build_and_package)

def build_and_package(args, job):
    # ignore ROS 1 bridge package for now
    ros1_bridge_path = os.path.join(args.sourcespace, 'ros2', 'ros1_bridge')
    info('ROS1 bridge path: %s' % ros1_bridge_path)
    ros1_bridge_ignore_marker = None
    if os.path.exists(ros1_bridge_path):
        ros1_bridge_ignore_marker = os.path.join(ros1_bridge_path, 'AMENT_IGNORE')
        info('ROS1 bridge path ignore file: %s' % ros1_bridge_ignore_marker)
        with open(ros1_bridge_ignore_marker, 'w'):
            pass

    ament_py = '"%s"' % os.path.join(
        '.', args.sourcespace, 'ament', 'ament_tools', 'scripts', 'ament.py'
    )
    # Now run ament build
    job.run([
        job.python, '-u', ament_py, 'build',
        '--build-space', '"%s"' % args.buildspace,
        '--install-space', '"%s"' % args.installspace,
        '"%s"' % args.sourcespace
    ] + (['--isolated'] if args.isolated else []))

    if ros1_bridge_ignore_marker:
        os.remove(ros1_bridge_ignore_marker)

    # It only makes sense to build the bridge for Linux or OSX, since
    # ROS1 is not supported on Windows
    if args.os in ['linux', 'osx']:
        # Now run ament build only for the bridge
        job.run([
            job.python, '-u', ament_py, 'build',
            '--build-space', '"%s"' % args.buildspace,
            '--install-space', '"%s"' % args.installspace,
            '--only', 'ros1_bridge',
            '"%s"' % args.sourcespace,
        ] + (['--isolated'] if args.isolated else []) + [
            '--make-flags', '-j1'
        ])

    # Remove "unnecessary" executables
    install_bin_path = os.path.join(args.installspace, 'bin')
    for filename in os.listdir(install_bin_path):
        if (
            '__rmw_' in filename or
            filename.startswith('simple_bridge') or
            filename.startswith('static_bridge')
        ):
            os.remove(os.path.join(install_bin_path, filename))

    # create an archive
    if args.os == 'linux' or args.os == 'osx':
        archive_path = 'ros2-package-%s.tar.bz2' % args.os
        with tarfile.open(archive_path, 'w:bz2') as h:
            h.add(args.installspace, arcname='ros2')
    elif args.os == 'windows':
        archive_path = 'ros2-package-windows.zip'
        # NOTE(esteve): hack to copy our custom built VS2015-compatible OpenCV DLLs
        opencv_libdir = os.path.join('c:/', 'opencv', 'build', 'x64', 'vc14', 'bin')
        for libfile in ['opencv_core2412.dll', 'opencv_highgui2412.dll']:
            libpath = os.path.join(opencv_libdir, libfile)
            shutil.copy(libpath, os.path.join(args.installspace, 'bin', libfile))
        with zipfile.ZipFile(archive_path, 'w') as zf:
            for dirname, subdirs, files in os.walk(args.installspace):
                arcname = os.path.join('ros2', os.path.relpath(dirname, start=args.installspace))
                zf.write(dirname, arcname=arcname)
                for filename in files:
                    filearcname = os.path.join(
                        'ros2', os.path.relpath(dirname, start=args.installspace), filename)
                    zf.write(os.path.join(dirname, filename), arcname=filearcname)
    else:
        raise RuntimeError('Unsupported operating system: %s' % args.os)
    info("created archive: '{0}'".format(archive_path))

    return 0

if __name__ == '__main__':
    sys.exit(main())
<commit_msg>use platform specific folder name in archives<commit_after># Copyright 2015 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import shutil
import sys
import tarfile
import zipfile

from .__main__ import get_args
from .__main__ import run
from .util import info

def main(sysargv=None):
    args = get_args(sysargv=sysargv, skip_white_space_in=True, skip_connext=True, add_ros1=True)
    return run(args, build_and_package)

def build_and_package(args, job):
    # ignore ROS 1 bridge package for now
    ros1_bridge_path = os.path.join(args.sourcespace, 'ros2', 'ros1_bridge')
    info('ROS1 bridge path: %s' % ros1_bridge_path)
    ros1_bridge_ignore_marker = None
    if os.path.exists(ros1_bridge_path):
        ros1_bridge_ignore_marker = os.path.join(ros1_bridge_path, 'AMENT_IGNORE')
        info('ROS1 bridge path ignore file: %s' % ros1_bridge_ignore_marker)
        with open(ros1_bridge_ignore_marker, 'w'):
            pass

    ament_py = '"%s"' % os.path.join(
        '.', args.sourcespace, 'ament', 'ament_tools', 'scripts', 'ament.py'
    )
    # Now run ament build
    job.run([
        job.python, '-u', ament_py, 'build',
        '--build-space', '"%s"' % args.buildspace,
        '--install-space', '"%s"' % args.installspace,
        '"%s"' % args.sourcespace
    ] + (['--isolated'] if args.isolated else []))

    if ros1_bridge_ignore_marker:
        os.remove(ros1_bridge_ignore_marker)

    # It only makes sense to build the bridge for Linux or OSX, since
    # ROS1 is not supported on Windows
    if args.os in ['linux', 'osx']:
        # Now run ament build only for the bridge
        job.run([
            job.python, '-u', ament_py, 'build',
            '--build-space', '"%s"' % args.buildspace,
            '--install-space', '"%s"' % args.installspace,
            '--only', 'ros1_bridge',
            '"%s"' % args.sourcespace,
        ] + (['--isolated'] if args.isolated else []) + [
            '--make-flags', '-j1'
        ])

    # Remove "unnecessary" executables
    install_bin_path = os.path.join(args.installspace, 'bin')
    for filename in os.listdir(install_bin_path):
        if (
            '__rmw_' in filename or
            filename.startswith('simple_bridge') or
            filename.startswith('static_bridge')
        ):
            os.remove(os.path.join(install_bin_path, filename))

    # create an archive
    folder_name = 'ros2-' + args.os
    if args.os == 'linux' or args.os == 'osx':
        archive_path = 'ros2-package-%s.tar.bz2' % args.os
        with tarfile.open(archive_path, 'w:bz2') as h:
            h.add(args.installspace, arcname=folder_name)
    elif args.os == 'windows':
        archive_path = 'ros2-package-windows.zip'
        # NOTE(esteve): hack to copy our custom built VS2015-compatible OpenCV DLLs
        opencv_libdir = os.path.join('c:/', 'opencv', 'build', 'x64', 'vc14', 'bin')
        for libfile in ['opencv_core2412.dll', 'opencv_highgui2412.dll']:
            libpath = os.path.join(opencv_libdir, libfile)
            shutil.copy(libpath, os.path.join(args.installspace, 'bin', libfile))
        with zipfile.ZipFile(archive_path, 'w') as zf:
            for dirname, subdirs, files in os.walk(args.installspace):
                arcname = os.path.join(
                    folder_name, os.path.relpath(dirname, start=args.installspace))
                zf.write(dirname, arcname=arcname)
                for filename in files:
                    filearcname = os.path.join(
                        'ros2', os.path.relpath(dirname, start=args.installspace), filename)
                    zf.write(os.path.join(dirname, filename), arcname=filearcname)
    else:
        raise RuntimeError('Unsupported operating system: %s' % args.os)
    info("created archive: '{0}'".format(archive_path))

    return 0

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


<commit_before># This class handles sprite sheets
# This was taken from www.scriptefun.com/transcript-2-using
# sprite-sheets-and-drawing-the-background
# I've added some code to fail if the file wasn't found..
# Note: When calling images_at the rect is the format:
# (x, y, x + offset, y + offset)

import pygame

class spritesheet(object):
    def __init__(self, filename):
        try:
            self.sheet = pygame.image.load(filename).convert()
        except pygame.error, message:
            print 'Unable to load spritesheet image:', filename
            raise SystemExit, message
    # Load a specific image from a specific rectangle
    def image_at(self, rectangle, colorkey = None):
        "Loads image from x,y,x+offset,y+offset"
        rect = pygame.Rect(rectangle)
        image = pygame.Surface(rect.size).convert()
        image.blit(self.sheet, (0, 0), rect)
        if colorkey is not None:
            if colorkey is -1:
                colorkey = image.get_at((0,0))
            image.set_colorkey(colorkey, pygame.RLEACCEL)
        return image
    # Load a whole bunch of images and return them as a list
    def images_at(self, rects, colorkey = None):
        "Loads multiple images, supply a list of coordinates"
        return [self.image_at(rect, colorkey) for rect in rects]
    # Load a whole strip of images
    def load_strip(self, rect, image_count, colorkey = None):
        "Loads a strip of images and returns them as a list"
        tups = [(rect[0]+rect[2]*x, rect[1], rect[2], rect[3])
                for x in range(image_count)]
        return self.images_at(tups, colorkey)
<commit_msg>fix spritesheet for python3<commit_after># This class handles sprite sheets
# This was taken from www.scriptefun.com/transcript-2-using
# sprite-sheets-and-drawing-the-background
# I've added some code to fail if the file wasn't found..
# Note: When calling images_at the rect is the format:
# (x, y, x + offset, y + offset)
# Adapted for Py3k by Andy Russell

import pygame

class SpriteSheet(object):
    def __init__(self, filename):
        try:
            self.sheet = pygame.image.load(filename).convert()
        except pygame.error as message:
            print('Unable to load spritesheet image:', filename)
            raise SystemExit(message)
    # Load a specific image from a specific rectangle
    def image_at(self, rectangle, colorkey = None):
        "Loads image from x,y,x+offset,y+offset"
        rect = pygame.Rect(rectangle)
        image = pygame.Surface(rect.size).convert()
        image.blit(self.sheet, (0, 0), rect)
        if colorkey is not None:
            if colorkey is -1:
                colorkey = image.get_at((0,0))
            image.set_colorkey(colorkey, pygame.RLEACCEL)
        return image
    # Load a whole bunch of images and return them as a list
    def images_at(self, rects, colorkey = None):
        "Loads multiple images, supply a list of coordinates"
        return [self.image_at(rect, colorkey) for rect in rects]
    # Load a whole strip of images
    def load_strip(self, rect, image_count, colorkey = None):
        "Loads a strip of images and returns them as a list"
        tups = [(rect[0]+rect[2]*x, rect[1], rect[2], rect[3])
                for x in range(image_count)]
        return self.images_at(tups, colorkey)
<|endoftext|>


<commit_before>import pytz
import six

import pandas as pd
from ..instruments import Instrument

class LocalDataSource:
    DAILY = 'daily.bcolz'
    INSTRUMENTS = 'instruments.pk'
    DIVIDEND = 'dividend.bcolz'
    TRADING_DATES = 'trading_dates.bcolz'
    YIELD_CURVE = 'yield_curve.bcolz'

    YIELD_CURVE_TENORS = {
        0: 'S0',
        30: 'M1',
        60: 'M2',
        90: 'M3',
        180: 'M6',
        270: 'M9',
        365: 'Y1',
        365 * 2: 'Y2',
        365 * 3: 'Y3',
        365 * 4: 'Y4',
        365 * 5: 'Y5',
        365 * 6: 'Y6',
        365 * 7: 'Y7',
        365 * 8: 'Y8',
        365 * 9: 'Y9',
        365 * 10: 'Y10',
        365 * 15: 'Y15',
        365 * 20: 'Y20',
        365 * 30: 'Y30',
        365 * 40: 'Y40',
        365 * 50: 'Y50',
    }

    YIELD_CURVE_DURATION = sorted(YIELD_CURVE_TENORS.keys())

    PRICE_SCALE = 1000.

    def __init__(self, root_dir):
        self._root_dir = root_dir
        import bcolz
        import os
        import pickle
        self._daily_table = bcolz.open(os.path.join(root_dir, LocalDataSource.DAILY))
        self._instruments = {d['order_book_id']: Instrument(d)
                             for d in pickle.load(open(os.path.join(root_dir, LocalDataSource.INSTRUMENTS), 'rb'))}
        self._dividend = bcolz.open(os.path.join(root_dir, LocalDataSource.DIVIDEND))
        self._yield_curve = bcolz.open(os.path.join(root_dir, LocalDataSource.YIELD_CURVE))
        self._trading_dates = pd.Index(pd.Timestamp(str(d), tz=pytz.utc) for d in
                                       bcolz.open(os.path.join(root_dir, LocalDataSource.TRADING_DATES)))

    def instruments(self, order_book_ids):
        if isinstance(order_book_ids, six.string_types):
            try:
                return self._instruments[order_book_ids]
            except KeyError:
                print('ERROR: order_book_id {} not exists!'.format(order_book_ids))
                return None

        return [self._instruments[ob] for ob in order_book_ids
                if ob in self._instruments]

    def all_instruments(self, itype='CS'):
        if itype is None:
            return pd.DataFrame([[v.order_book_id, v.symbol, v.abbrev_symbol, v.type]
                                 for v in self._instruments.values()],
                                columns=['order_book_id', 'symbol', 'abbrev_symbol', 'type'])

        if itype not in ['CS', 'ETF', 'LOF', 'FenjiA', 'FenjiB', 'FenjiMu', 'INDX', 'Future']:
            raise ValueError('Unknown type {}'.format(itype))

        return pd.DataFrame([v.__dict__ for v in self._instruments.values() if v.type == itype])

    def sector(self, code):
        return [v.order_book_id for v in self._instruments.values()
                if v.type == 'CS' and v.sector_code == code]

    def industry(self, code):
        return [v.order_book_id for v in self._instruments.values()
                if v.type == 'CS' and v.industry_code == code]

    def concept(self, *concepts):
        return [v.order_book_id for v in self._instruments.values()
                if v.type == 'CS' and any(c in v.concept_names.split('|') for c in concepts)]

    def get_trading_dates(self, start_date, end_date):
        left, right = self._trading_dates.searchsorted(start_date), self._trading_dates.searchsorted(end_date)
        return self._trading_dates[left:right]

    def get_yield_curve(self, start_date, end_date):
        duration = (end_date - start_date).days
        tenor = 0
        for t in LocalDataSource.YIELD_CURVE_DURATION:
            if duration >= t:
                tenor = t
            else:
                break

        d = start_date.year * 10000 + start_date.month * 100 + start_date.day
        return self._yield_curve.fetchwhere('date<={}'.format(d)).cols[self.YIELD_CURVE_TENORS[tenor]][-1] / 10000.0

    def get_dividends(self, order_book_id):
        try:
            sid = self._dividend.attrs['stock_id'][order_book_id]
        except KeyError:
            return pd.DataFrame()

        dividends = self._dividend.fetchwhere('id=={}'.format(sid))
        return pd.DataFrame({
            'book_closure_date': pd.Index(pd.Timestamp(str(d)) for d in dividends.cols['closure_date']),
            'ex_dividend_date': pd.Index(pd.Timestamp(str(d)) for d in dividends.cols['ex_date']),
            'payable_date': pd.Index(pd.Timestamp(str(d)) for d in dividends.cols['payable_date']),
            'dividend_cash_before_tax': dividends.cols['cash_before_tax'][:] / 10000.0,
            'round_lot': dividends.cols['round_lot']
        }, index=pd.Index(pd.Timestamp(str(d)) for d in dividends.cols['announcement_date']))

    def get_all_bars(self, order_book_id):
        try:
            sid = self._daily_table.attrs['id_map'][order_book_id]
        except KeyError:
            raise RuntimeError('No data for {}'.format(order_book_id))

        bars = self._daily_table.fetchwhere('id=={}'.format(sid))
        return pd.DataFrame({
            'open': (bars.cols['open'][:] / self.PRICE_SCALE).round(2),
            'close': (bars.cols['close'][:] / self.PRICE_SCALE).round(2),
            'high': (bars.cols['high'][:] / self.PRICE_SCALE).round(2),
            'low': (bars.cols['low'][:] / self.PRICE_SCALE).round(2),
            'volume': bars.cols['volume'],
        }, index=pd.Index(pd.Timestamp(str(d)) for d in bars.cols['date']))
<commit_msg>fix get_trading_dates<commit_after>import pytz
import six

import pandas as pd
from ..instruments import Instrument

class LocalDataSource:
    DAILY = 'daily.bcolz'
    INSTRUMENTS = 'instruments.pk'
    DIVIDEND = 'dividend.bcolz'
    TRADING_DATES = 'trading_dates.bcolz'
    YIELD_CURVE = 'yield_curve.bcolz'

    YIELD_CURVE_TENORS = {
        0: 'S0',
        30: 'M1',
        60: 'M2',
        90: 'M3',
        180: 'M6',
        270: 'M9',
        365: 'Y1',
        365 * 2: 'Y2',
        365 * 3: 'Y3',
        365 * 4: 'Y4',
        365 * 5: 'Y5',
        365 * 6: 'Y6',
        365 * 7: 'Y7',
        365 * 8: 'Y8',
        365 * 9: 'Y9',
        365 * 10: 'Y10',
        365 * 15: 'Y15',
        365 * 20: 'Y20',
        365 * 30: 'Y30',
        365 * 40: 'Y40',
        365 * 50: 'Y50',
    }

    YIELD_CURVE_DURATION = sorted(YIELD_CURVE_TENORS.keys())

    PRICE_SCALE = 1000.

    def __init__(self, root_dir):
        self._root_dir = root_dir
        import bcolz
        import os
        import pickle
        self._daily_table = bcolz.open(os.path.join(root_dir, LocalDataSource.DAILY))
        self._instruments = {d['order_book_id']: Instrument(d)
                             for d in pickle.load(open(os.path.join(root_dir, LocalDataSource.INSTRUMENTS), 'rb'))}
        self._dividend = bcolz.open(os.path.join(root_dir, LocalDataSource.DIVIDEND))
        self._yield_curve = bcolz.open(os.path.join(root_dir, LocalDataSource.YIELD_CURVE))
        self._trading_dates = pd.Index(pd.Timestamp(str(d), tz=pytz.utc) for d in
                                       bcolz.open(os.path.join(root_dir, LocalDataSource.TRADING_DATES)))

    def instruments(self, order_book_ids):
        if isinstance(order_book_ids, six.string_types):
            try:
                return self._instruments[order_book_ids]
            except KeyError:
                print('ERROR: order_book_id {} not exists!'.format(order_book_ids))
                return None

        return [self._instruments[ob] for ob in order_book_ids
                if ob in self._instruments]

    def all_instruments(self, itype='CS'):
        if itype is None:
            return pd.DataFrame([[v.order_book_id, v.symbol, v.abbrev_symbol, v.type]
                                 for v in self._instruments.values()],
                                columns=['order_book_id', 'symbol', 'abbrev_symbol', 'type'])

        if itype not in ['CS', 'ETF', 'LOF', 'FenjiA', 'FenjiB', 'FenjiMu', 'INDX', 'Future']:
            raise ValueError('Unknown type {}'.format(itype))

        return pd.DataFrame([v.__dict__ for v in self._instruments.values() if v.type == itype])

    def sector(self, code):
        return [v.order_book_id for v in self._instruments.values()
                if v.type == 'CS' and v.sector_code == code]

    def industry(self, code):
        return [v.order_book_id for v in self._instruments.values()
                if v.type == 'CS' and v.industry_code == code]

    def concept(self, *concepts):
        return [v.order_book_id for v in self._instruments.values()
                if v.type == 'CS' and any(c in v.concept_names.split('|') for c in concepts)]

    def get_trading_dates(self, start_date, end_date):
        left, right = self._trading_dates.searchsorted(start_date), self._trading_dates.searchsorted(end_date)
        return self._trading_dates[left:right + 1]

    def get_yield_curve(self, start_date, end_date):
        duration = (end_date - start_date).days
        tenor = 0
        for t in LocalDataSource.YIELD_CURVE_DURATION:
            if duration >= t:
                tenor = t
            else:
                break

        d = start_date.year * 10000 + start_date.month * 100 + start_date.day
        return self._yield_curve.fetchwhere('date<={}'.format(d)).cols[self.YIELD_CURVE_TENORS[tenor]][-1] / 10000.0

    def get_dividends(self, order_book_id):
        try:
            sid = self._dividend.attrs['stock_id'][order_book_id]
        except KeyError:
            return pd.DataFrame()

        dividends = self._dividend.fetchwhere('id=={}'.format(sid))
        return pd.DataFrame({
            'book_closure_date': pd.Index(pd.Timestamp(str(d)) for d in dividends.cols['closure_date']),
            'ex_dividend_date': pd.Index(pd.Timestamp(str(d)) for d in dividends.cols['ex_date']),
            'payable_date': pd.Index(pd.Timestamp(str(d)) for d in dividends.cols['payable_date']),
            'dividend_cash_before_tax': dividends.cols['cash_before_tax'][:] / 10000.0,
            'round_lot': dividends.cols['round_lot']
        }, index=pd.Index(pd.Timestamp(str(d)) for d in dividends.cols['announcement_date']))

    def get_all_bars(self, order_book_id):
        try:
            sid = self._daily_table.attrs['id_map'][order_book_id]
        except KeyError:
            raise RuntimeError('No data for {}'.format(order_book_id))

        bars = self._daily_table.fetchwhere('id=={}'.format(sid))
        return pd.DataFrame({
            'open': (bars.cols['open'][:] / self.PRICE_SCALE).round(2),
            'close': (bars.cols['close'][:] / self.PRICE_SCALE).round(2),
            'high': (bars.cols['high'][:] / self.PRICE_SCALE).round(2),
            'low': (bars.cols['low'][:] / self.PRICE_SCALE).round(2),
            'volume': bars.cols['volume'],
        }, index=pd.Index(pd.Timestamp(str(d)) for d in bars.cols['date']))
<|endoftext|>


<commit_before>import json
import logging

from google.appengine.api import taskqueue
from google.appengine.ext import ndb

from helpers.cache_clearer import CacheClearer
from helpers.firebase.firebase_pusher import FirebasePusher
from helpers.notification_helper import NotificationHelper
from helpers.manipulator_base import ManipulatorBase

class MatchManipulator(ManipulatorBase):
    """
    Handle Match database writes.
    """
    @classmethod
    def getCacheKeysAndControllers(cls, affected_refs):
        return CacheClearer.get_match_cache_keys_and_controllers(affected_refs)

    @classmethod
    def postUpdateHook(cls, matches):
        '''
        To run after the match has been updated.
        Send push notifications to subscribed users
        Only if the match is part of an active event
        '''
        unplayed_matches = []
        for match in matches:
            event = match.event.get()
            if event.now and match.has_been_played():
                logging.info("Sending push notifications for "+match.key_name)
                try:
                    NotificationHelper.send_match_score_update(match)
                except Exception, exception:
                    logging.error("Error sending match updates: "+str(exception))
            elif not match.has_been_played() not event in unplayed_matches:
                unplayed_matches.append(event)

        '''
        If we have an unplayed match, send out a schedule update notification
        '''
        for event in unplayed_matches:
            try:
                NotificationHelper.send_schedule_update(event)
            except Exception, exception:
                logging.error("Eror sending schedule updates for: {}".format(event.id()))

        '''
        Enqueue firebase push
        '''
        if matches:
            event_key = matches[0].event.id()
            try:
                FirebasePusher.updated_event(event_key)
            except Exception:
                logging.warning("Enqueuing Firebase push failed!")

            # Enqueue task to calculate matchstats
            taskqueue.add(
                    url='/tasks/math/do/event_matchstats/' + event_key,
                    method='GET')

    @classmethod
    def updateMerge(self, new_match, old_match, auto_union=True):
        """
        Given an "old" and a "new" Match object, replace the fields in the
        "old" team that are present in the "new" team, but keep fields from
        the "old" team that are null in the "new" team.
        """
        immutable_attrs = [
            "comp_level",
            "event",
            "set_number",
            "match_number",
        ]  # These build key_name, and cannot be changed without deleting the model.

        attrs = [
            "game",
            "no_auto_update",
            "time",
            "time_string",
        ]

        json_attrs = [
            "alliances_json",
            "score_breakdown_json",
        ]

        list_attrs = [
            "team_key_names"
        ]

        auto_union_attrs = [
            "tba_videos",
            "youtube_videos"
        ]

        # if not auto_union, treat auto_union_attrs as list_attrs
        if not auto_union:
            list_attrs += auto_union_attrs
            auto_union_attrs = []

        for attr in attrs:
            if getattr(new_match, attr) is not None:
                if getattr(new_match, attr) != getattr(old_match, attr):
                    setattr(old_match, attr, getattr(new_match, attr))
                    old_match.dirty = True

        for attr in json_attrs:
            if getattr(new_match, attr) is not None:
                if (getattr(old_match, attr) is None) or (json.loads(getattr(new_match, attr)) != json.loads(getattr(old_match, attr))):
                    setattr(old_match, attr, getattr(new_match, attr))
                    # changinging 'attr_json' doesn't clear lazy-loaded '_attr'
                    setattr(old_match, '_{}'.format(attr.replace('_json', '')), None)
                    old_match.dirty = True

        for attr in list_attrs:
            if len(getattr(new_match, attr)) > 0:
                if set(getattr(new_match, attr)) != set(getattr(old_match, attr)):  # lists are treated as sets
                    setattr(old_match, attr, getattr(new_match, attr))
                    old_match.dirty = True

        for attr in auto_union_attrs:
            old_set = set(getattr(old_match, attr))
            new_set = set(getattr(new_match, attr))
            unioned = old_set.union(new_set)
            if unioned != old_set:
                setattr(old_match, attr, list(unioned))
                old_match.dirty = True

        return old_match
<commit_msg>Fix syntax error<commit_after>import json
import logging

from google.appengine.api import taskqueue
from google.appengine.ext import ndb

from helpers.cache_clearer import CacheClearer
from helpers.firebase.firebase_pusher import FirebasePusher
from helpers.notification_helper import NotificationHelper
from helpers.manipulator_base import ManipulatorBase

class MatchManipulator(ManipulatorBase):
    """
    Handle Match database writes.
    """
    @classmethod
    def getCacheKeysAndControllers(cls, affected_refs):
        return CacheClearer.get_match_cache_keys_and_controllers(affected_refs)

    @classmethod
    def postUpdateHook(cls, matches):
        '''
        To run after the match has been updated.
        Send push notifications to subscribed users
        Only if the match is part of an active event
        '''
        unplayed_matches = []
        for match in matches:
            event = match.event.get()
            if event.now and match.has_been_played():
                logging.info("Sending push notifications for "+match.key_name)
                try:
                    NotificationHelper.send_match_score_update(match)
                except Exception, exception:
                    logging.error("Error sending match updates: "+str(exception))
            elif not match.has_been_played() and not event in unplayed_matches:
                unplayed_matches.append(event)

        '''
        If we have an unplayed match, send out a schedule update notification
        '''
        for event in unplayed_matches:
            try:
                NotificationHelper.send_schedule_update(event)
            except Exception, exception:
                logging.error("Eror sending schedule updates for: {}".format(event.id()))

        '''
        Enqueue firebase push
        '''
        if matches:
            event_key = matches[0].event.id()
            try:
                FirebasePusher.updated_event(event_key)
            except Exception:
                logging.warning("Enqueuing Firebase push failed!")

            # Enqueue task to calculate matchstats
            taskqueue.add(
                    url='/tasks/math/do/event_matchstats/' + event_key,
                    method='GET')

    @classmethod
    def updateMerge(self, new_match, old_match, auto_union=True):
        """
        Given an "old" and a "new" Match object, replace the fields in the
        "old" team that are present in the "new" team, but keep fields from
        the "old" team that are null in the "new" team.
        """
        immutable_attrs = [
            "comp_level",
            "event",
            "set_number",
            "match_number",
        ]  # These build key_name, and cannot be changed without deleting the model.

        attrs = [
            "game",
            "no_auto_update",
            "time",
            "time_string",
        ]

        json_attrs = [
            "alliances_json",
            "score_breakdown_json",
        ]

        list_attrs = [
            "team_key_names"
        ]

        auto_union_attrs = [
            "tba_videos",
            "youtube_videos"
        ]

        # if not auto_union, treat auto_union_attrs as list_attrs
        if not auto_union:
            list_attrs += auto_union_attrs
            auto_union_attrs = []

        for attr in attrs:
            if getattr(new_match, attr) is not None:
                if getattr(new_match, attr) != getattr(old_match, attr):
                    setattr(old_match, attr, getattr(new_match, attr))
                    old_match.dirty = True

        for attr in json_attrs:
            if getattr(new_match, attr) is not None:
                if (getattr(old_match, attr) is None) or (json.loads(getattr(new_match, attr)) != json.loads(getattr(old_match, attr))):
                    setattr(old_match, attr, getattr(new_match, attr))
                    # changinging 'attr_json' doesn't clear lazy-loaded '_attr'
                    setattr(old_match, '_{}'.format(attr.replace('_json', '')), None)
                    old_match.dirty = True

        for attr in list_attrs:
            if len(getattr(new_match, attr)) > 0:
                if set(getattr(new_match, attr)) != set(getattr(old_match, attr)):  # lists are treated as sets
                    setattr(old_match, attr, getattr(new_match, attr))
                    old_match.dirty = True

        for attr in auto_union_attrs:
            old_set = set(getattr(old_match, attr))
            new_set = set(getattr(new_match, attr))
            unioned = old_set.union(new_set)
            if unioned != old_set:
                setattr(old_match, attr, list(unioned))
                old_match.dirty = True

        return old_match
<|endoftext|>