<commit_before>import socket
import struct

#Room size
room_length = 5.5
room_width = 3.35
scale_img = 120.0

#Robot dimensions
rob_scale = 1.2
rob_rect_x = int(0.15 * scale_img * rob_scale)
rob_rect_y = int(0.2 * scale_img * rob_scale)
rob_trapz_wid = int(0.05 * scale_img * rob_scale)
rob_trapz_side = int(0.07 * scale_img * rob_scale)
rob_wheel_x = int(0.04 * scale_img * rob_scale)
rob_wheel_y = int(0.02 * scale_img * rob_scale)
rob_wheel_pos = 2.0/3.0 #Value between 1 and 0

UDP = "localhost"
PORT = 20000
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sock.bind((UDP,PORT))

print("\n\nPress ctrl + C to exit\n\n")

pix_x = int(room_width*scale_img)
pix_y = int(room_length*scale_img)

color_bot = {1: color(71,82,224),
			 2: color(0,255,30),
			 3: color(255,50,50),
			 4: color(240,255,0)}

data = []

def setup():
	size(pix_x,pix_y)
	colorMode(RGB)
	frameRate(600)
	noStroke()

def draw():
	fill(255,255,255)
	rectMode(CORNER)
	rect(0.0,0.0,width,height)
	udprecv, addr = sock.recvfrom(1024)
	x,y,yaw,rbid,status,dataRate = struct.unpack('<dddddd',udprecv)
	rbid = int(rbid)
	if status == 1:
		col = [row[3] for row in data]
		if (rbid in col) != 1:
			data.append([x,y,yaw,rbid])
		else:
			data[col.index(rbid)] = [x,y,yaw,rbid]
	for row in data:
		pushMatrix()
		translate(row[0],row[1])
		rotate(row[2])
		draw_robot(row[3])
		popMatrix()

def draw_robot(r_id):
	stroke(150)
	rectMode(CENTER)
	fill(color_bot[r_id])
	rect(0.0,0.0,rob_rect_x,rob_rect_y)
	stroke(50)
	fill(255)
	beginShape()
	vertex(rob_rect_x/2.0,rob_rect_y/2.0)
	vertex(rob_rect_x/2.0+rob_trapz_wid,rob_trapz_side/2.0)
	vertex(rob_rect_x/2.0+rob_trapz_wid,-rob_trapz_side/2.0)
	vertex(rob_rect_x/2.0,-rob_rect_y/2.0)
	endShape()
	noStroke()
	draw_wheel(rob_wheel_pos*rob_rect_x/2.0,rob_rect_y/2+rob_wheel_y/2)
	draw_wheel(rob_wheel_pos*rob_rect_x/2.0,-rob_rect_y/2-rob_wheel_y/2)
	draw_wheel(-rob_wheel_pos*rob_rect_x/2.0,rob_rect_y/2+rob_wheel_y/2)
	draw_wheel(-rob_wheel_pos*rob_rect_x/2.0,-rob_rect_y/2-rob_wheel_y/2)

def draw_wheel(wx,wy):
	fill(0)
	rectMode(CENTER)
	rect(wx,wy,rob_wheel_x,rob_wheel_y)
<commit_msg>Reversed rotation<commit_after>import socket
import struct

#Room size
room_length = 5.5
room_width = 3.35
scale_img = 120.0

#Robot dimensions
rob_scale = 1.2
rob_rect_x = 0.15 * scale_img * rob_scale
rob_rect_y = 0.2 * scale_img * rob_scale
rob_trapz_wid = 0.05 * scale_img * rob_scale
rob_trapz_side = 0.07 * scale_img * rob_scale
rob_wheel_x = 0.04 * scale_img * rob_scale
rob_wheel_y = 0.02 * scale_img * rob_scale
rob_wheel_pos = 2.0/3.0 #Value between 1 and 0

UDP = "localhost"
PORT = 20000
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sock.bind((UDP,PORT))

print("\n\nPress ctrl + C to exit\n\n")

pix_x = int(room_width*scale_img)
pix_y = int(room_length*scale_img)

color_bot = {1: color(71,82,224),
			 2: color(0,255,30),
			 3: color(255,50,50),
			 4: color(240,255,0)}

data = []

def setup():
	size(pix_x,pix_y)
	colorMode(RGB)
	frameRate(600)
	noStroke()

def draw():
	fill(255,255,255)
	rectMode(CORNER)
	rect(0.0,0.0,width,height)
	udprecv, addr = sock.recvfrom(1024)
	worldx,worldy,yaw,rbid,status,dataRate = struct.unpack('<dddddd',udprecv)
	x,y = convert_coord(worldx,worldy)
	yaw *= -1  #Reversing direction of rotation
	rbid = int(rbid)
	if status == 1:
		col = [row[3] for row in data]
		if (rbid in col) != 1:
			data.append([x,y,yaw,rbid])
		else:
			data[col.index(rbid)] = [x,y,yaw,rbid]
	for row in data:
		pushMatrix()
		translate(row[0],row[1])
		rotate(row[2])
		draw_robot(row[3])
		popMatrix()

def convert_coord(mocapx,mocapy):
	px = pix_x/2 + (mocapx*scale_img)
	py = pix_y/2 - (mocapy*scale_img)
	return (px,py)

def draw_robot(r_id):
	stroke(150)
	rectMode(CENTER)
	fill(color_bot[r_id])
	rect(0.0,0.0,rob_rect_x,rob_rect_y)
	stroke(50)
	fill(255)
	beginShape()
	vertex(rob_rect_x/2.0,rob_rect_y/2.0)
	vertex(rob_rect_x/2.0+rob_trapz_wid,rob_trapz_side/2.0)
	vertex(rob_rect_x/2.0+rob_trapz_wid,-rob_trapz_side/2.0)
	vertex(rob_rect_x/2.0,-rob_rect_y/2.0)
	endShape()
	noStroke()
	draw_wheel(rob_wheel_pos*rob_rect_x/2.0,rob_rect_y/2+rob_wheel_y/2)
	draw_wheel(rob_wheel_pos*rob_rect_x/2.0,-rob_rect_y/2-rob_wheel_y/2)
	draw_wheel(-rob_wheel_pos*rob_rect_x/2.0,rob_rect_y/2+rob_wheel_y/2)
	draw_wheel(-rob_wheel_pos*rob_rect_x/2.0,-rob_rect_y/2-rob_wheel_y/2)

def draw_wheel(wx,wy):
	fill(0)
	rectMode(CENTER)
	rect(wx,wy,rob_wheel_x,rob_wheel_y)
<|endoftext|>


<commit_before>import unittest

class FeatureFinderTestCase(unittest.TestCase):
    def setUp(self):
        import maxixe
        maxixe.init()

    def test_loads_name_from_file(self):
        from maxixe.features import basics
        self.assertEqual(basics.name, "Importable features")
<commit_msg>add a test for description<commit_after>import unittest

class FeatureFinderTestCase(unittest.TestCase):
    def setUp(self):
        import maxixe
        maxixe.init()

    def test_loads_name_from_file(self):
        from maxixe.features import basics
        self.assertEqual(basics.name, "Importable features")

    def test_loads_description_from_file(self):
        from maxixe.features import basics
        expected = "\n".join([
            "In order to interact programmatically with tests",
            "Developers should be able to import features as code",
        ])
        self.assertEqual(basics.description, expected)
<|endoftext|>


<commit_before>import discord
import re
import csv
import random
from discord.ext import commands

class MCOCTools:
    '''Tools for Marvel Contest of Champions'''
    lookup_links = {
            'event': (
                'Tiny MCoC Schedule',
                '<http://simians.tk/MCOC-Sched>',
                'Josh Morris Schedule',
                'https://d2jixqqjqj5d23.cloudfront.net/assets/developer/imgs/icons/google-spreadsheet-icon.png'),
            'hook': (
                'hook/champions',
                '<http://hook.github.io/champions>',
                'hook/champions for Collector',
                'https://assets-cdn.github.com/favicon.ico'),
            'spotlight': (
                'MCoC Spotlight',
                '<http://simians.tk/MCoCspotlight>'),
            'marvelsynergy': (
                'Team Builder',
                '<http://www.marvelsynergy.com/team-builder>',
                'Marvel Synergy',
                'http://www.marvelsynergy.com/images/marvelsynergy.png'),
            'alsciende':(
                'Alsciende Mastery Tool',
                '<https://alsciende.github.io/masteries/v10.0.1/#>',
                'by u/alsciende',
                'https://assets-cdn.github.com/favicon.ico'),
            'simulator': (
                'Mastery Simulator',
                '<http://simians.tk/msimSDF>'),
            'streak': (
                'Infinite Streak',
                'http://simians.tk/-sdf-streak')
                #'http://simians.tk/SDFstreak')
    }
    mcolor = discord.Color.gold()
    icon_sdf = 'https://raw.githubusercontent.com/JasonJW/mcoc-cogs/master/mcoc/data/sdf_icon.png'
    dataset = 'data/mcoc/masteries.csv'

    def __init__(self, bot):
        self.bot = bot

    def present(self, lookup):
        em=discord.Embed(color=self.mcolor,title=lookup[0],description=lookup[1])
        print(len(lookup))
        if len(lookup) > 2:
            em.set_footer(text=lookup[2],icon_url=lookup[3])
        else:
            em.set_footer(text='Presented by [-SDF-]',icon_url=self.icon_sdf)
        return em

    #Gold Realm disabled
    # @commands.command()
    # async def gold(self,msg = None):
    #     '''Gold Realm Schedule'''
    #     package = '```           PST      CST      EST\nJun 5    10:00    12:00    13:00\nJun 5    19:00    21:00    22:00\nJun 6     4:00     6:00     7:00\nJun 6    13:00    15:00    16:00\nJun 6    22:00     0:00     1:00\nJun 7     7:00     9:00    10:00\nJun 7    16:00    18:00    19:00\nJun 8     1:00     3:00     4:00\nJun 8    10:00    12:00    13:00\nJun 8    19:00    21:00    22:00\nJun 9     4:00     6:00     7:00\nJun 9    13:00    15:00    16:00\nJun 10   22:00     0:00     1:00\nJun 11    7:00     9:00    10:00\nJun 11   16:00    18:00    19:00\nJun 12    1:00     3:00     4:00```'
    #     # await self.bot.say('```'+package+'```')
    #     if msg is not None:
    #         package = msg+'\n'+package
    #     em = discord.Embed(color=discord.Color.gold(),title='Gold Realm Schedule',description=package)
    #     em.set_footer(text='Presented by [-SDF-]',icon_url=self.icon_sdf)
    #     await self.bot.say(embed=em)

    @commands.command(help=lookup_links['event'][0], aliases=['events','schedule',])
    async def event(self):
        lookup = self.lookup_links['event']
        await self.bot.say(embed=self.present(lookup))

    @commands.command(help=lookup_links['spotlight'][0],)
    async def spotlight(self):
        lookup = self.lookup_links['spotlight']
        await self.bot.say(embed=self.present(lookup))

    @commands.command(help=lookup_links['marvelsynergy'][0])
    async def marvelsynergy(self):
        lookup = self.lookup_links['marvelsynergy']
        await self.bot.say(embed=self.present(lookup))

    @commands.command(help=lookup_links['simulator'][0],aliases=['msim'])
    async def simulator(self):
        lookup = self.lookup_links['simulator']
        await self.bot.say(embed=self.present(lookup))

    @commands.command(help=lookup_links['alsciende'][0], aliases=('mrig',))
    async def alsciende(self):
        lookup = self.lookup_links['alsciende']
        await self.bot.say(embed=self.present(lookup))

    @commands.command(help=lookup_links['streak'][0])
    async def streak(self):
        lookup = self.lookup_links['streak']
        await self.bot.say(embed=self.present(lookup))

    @commands.command(help=lookup_links['hook'][0])
    async def hook(self):
        lookup = self.lookup_links['hook']
        await self.bot.say(embed=self.present(lookup))

    @commands.command()
    async def keygen(self, prefix='SECEMP99'):
        letters='ABCDEFGHIJKLMNOPQURSTUVWXYZ'
        package = []
        for i in range(0,9):
            lets='{}{}{}{}'.format(random.choice(letters),random.choice(letters),random.choice(letters),random.choice(letters))
            package.append(prefix+lets)
        em=discord.Embed(color=discord.Color.gold(),title='Email Code Generator',description='\n'.join(package))
        await self.bot.say(embed=em)
#### Mastery stuff###
# class MCOCMastery:
    masteryColor={'Offense': discord.Color.red(),
            'Defense': discord.Color.blue(),
            'Utility': discord.Color.green()}
    tokens={'Vitality','Greater Vitality','Salve','Recovery','Energy Resistance','Physical Resistance','Block Proficiency','Perfect Block','Stand Your Ground','Collar Tech','Serum Science','Willpower','Coagulate','Suture','Inequity','Resonate',
            'Strength','Greater Strength','Pierce','Lesser Precision','Precision','Lesser Cruelty','Cruelty','Courage','Extended Fury','Enhanced Fury','Pure Skill','Mutagenesis','Glass Canon','Recoil','Liquid Courage','Double Edge','Despair','DeepWounds','Unfazed','Assassin',
            'Wisdom','Intelligence','Limber','Parry','Stupefy','Petrify','Pacify','Dexterity','Pitance','Prosperity','Cosmic Awareness','Mystic Dispersion','Detect Cosmic','Detect Tech','Detect Mystic','Scouter Lens','Detect Mutant','Detect Science','Detect Skill'}

    @commands.group(pass_context=True, aliases=['masteries',])
    async def mastery(self, ctx):
        if ctx.invoked_subcommand is None:
            await self.bot.send_cmd_help(ctx)
            return

    @mastery.command(pass_context=True,)
    async def test(self,ctx):
        message = ctx.message.content
        # mastery='Resonate'
        # rank=3
        # rows = get_csv_rows(self.dataset,'Mastery',mastery)
        #  text = []
        # cost = {'ucarb': 'Carbonadium Mastery Core', 'ustony': 'Stony Mastery Core', 'uclass': '', 'uunit': 'Units', 'rgold': 'Gold', 'runit': 'Units'}
        # cores = {'Collar Tech': 'Tech Core', 'Serum Science': 'Mastery Serum', 'Mutagenesis': 'Mastery Core X', 'Pure Skill': 'Mastery Core of Apptitude', 'Cosmic Awareness':'Cosmic Mastery Core', 'Mystic Dispersion': 'Mystical Mastery Core',
        #         'Detect Tech': 'Tech Core', 'Detect Science': 'Mastery Serum', 'Detect Mutant': 'Mastery Core X', 'Detect Skill': 'Mastery Core of Apptitude', 'Detect Cosmic':'Cosmic Mastery Core', 'Detect Mystic': 'Mystical Mastery Core',}
        # if mastery in cores:
        #     cost['uclass'][1]=cores[mastery]
        for token in self.tokens:
            print(token+' found')
            if token in message:
                maxrank = rows[0]['Max Ranks']
                category = rows[0]['Category']

                em=discord.Embed(color=self.masteryColor[category],title=mastery,description=' '.join(t for t in text))
                # for r in maxrank:
                    # unlock, rankcost = _get_cost(mastery, r)
                unlock, rankcost = self._get_cost(mastery)

                em.add_field(name='Unlock Cost',value='\n'.join(u[0] for u in unlock))
                em.add_field(name='Rank Cost',value='\n'.join(r for r in rankcost))
                await self.bot.say(embed=em)

    @mastery.command(pass_context=True, name='cost')
    async def _cost(self,ctx):
        # message = ctx.message.content.split(' ')
        # stack = []
        # for i in range(0,len(message)-1):
        #     if i+1 < len(message):
        #         test='{} {}'.format(message[i],message[i+1])
        #         if test in self.tokens:
        #             stack.append(test)
        #             i=i+2
        #         elif message[i] in self.tokens:
        #             stack.append(message[i])
        #     else:
        #         if message[i] in self.tokens:
        #             stack.append(message[i])
        # await self.bot.say('\n'.join(stack))

        # args = ctx.split(' ')
        #
        # for arg in args:
        #     # parse_re = re.compile(r'''(?:r(?P<rank>[0-9]))|(?:d(?P<debug>[0-9]{1,2}))''', re.X)
        #     if arg in tokens:
        #         row = mcoc.csv_get_row(mcoc.data_files['masteries']['local'], 'MasteryExt', arg)

        await self.bot.say('Dummy message for cost')

    @mastery.command(pass_context=True, name='set')
    async def _set(self,ctx):
        await self.bot.say('Dummy message for set')

    def _get_cost(self, mastery):
        row = csv_get_row(self.dataset,'Mastery',mastery)
        cost = {'ucarb': 'Carbonadium Mastery Core', 'ustony': 'Stony Mastery Core', 'uclass': '', 'uunit': 'Units', 'rgold': 'Gold', 'runit': 'Units'}
        cores = {'Collar Tech': 'Tech Core', 'Serum Science': 'Mastery Serum', 'Mutagenesis': 'Mastery Core X', 'Pure Skill': 'Mastery Core of Apptitude', 'Cosmic Awareness':'Cosmic Mastery Core', 'Mystic Dispersion': 'Mystical Mastery Core',
                'Detect Tech': 'Tech Core', 'Detect Science': 'Mastery Serum', 'Detect Mutant': 'Mastery Core X', 'Detect Skill': 'Mastery Core of Apptitude', 'Detect Cosmic':'Cosmic Mastery Core', 'Detect Mystic': 'Mystical Mastery Core',}
        if mastery in cores:
            classcore=cores[mastery]
        unlockcost=[]
        rankcost=[]
        maxranks=row['maxranks']
        carbcost=row['ucarb'].split(',')
        stonycost=row['ustony'].split(',')
        classcost=row['uclass'].split(',')
        unitcost=row['uunit'].split(',')
        if len(carbcost) > 0:
            unlockcost.append({'ucarb':{carbcost,'Carbonadium Mastery Core'})
        if len(stonycost) > 0:
            unlockcost.append({'ustony':{stonycost,'Stony Mastery Core'})
        if len(classcost) > 0:
            unlockcost.append({'uclass':{classcost,classcore})
        if len(unitcost) > 0:
            unlockcost.append({'uunit':{unitcost,'Units'})
        goldrank=row['rgold'].split(',')
        unitrank=row['runit'].split(',')
        if len(goldrank) > 0:
            rankcost.append({'rgold':{goldrank,'Gold'})
        if len(unitrank) > 0:
            unlockcost.append({'runit':{unitrank,'Units'})

        return unlockcost, rankcost

    def _get_text(self, mastery, rank):
        rows = csv_get_rows(self.dataset,'Mastery',mastery)
        for row in rows:
            text.append(row['Text'].format(row[str(rank)]))
        return text

def load_csv(filename):
    return csv.DictReader(open(filename))

def get_csv_row(filecsv, column, match_val, default=None):
    print(match_val)
    csvfile = load_csv(filecsv)
    for row in csvfile:
        if row[column] == match_val:
            if default is not None:
                for k, v in row.items():
                    if v == '':
                        row[k] = default
            return row

def get_csv_rows(filecsv, column, match_val, default=None):
    print(match_val)
    csvfile = load_csv(filecsv)
    package =[]
    for row in csvfile:
        if row[column] == match_val:
            if default is not None:
                for k, v in row.items():
                    if v == '':
                        row[k] = default
            package.append(row)
    return package

def tabulate(table_data, width, rotate=True, header_sep=True):
    rows = []
    cells_in_row = None
    for i in iter_rows(table_data, rotate):
        if cells_in_row is None:
            cells_in_row = len(i)
        elif cells_in_row != len(i):
            raise IndexError("Array is not uniform")
        rows.append('|'.join(['{:^{width}}']*len(i)).format(*i, width=width))
    if header_sep:
        rows.insert(1, '|'.join(['-' * width] * cells_in_row))
    return chat.box('\n'.join(rows))

def setup(bot):
    bot.add_cog(MCOCTools(bot))
<commit_msg>_cost is screwed up.. Need to start over<commit_after>import discord
import re
import csv
import random
from discord.ext import commands

class MCOCTools:
    '''Tools for Marvel Contest of Champions'''
    lookup_links = {
            'event': (
                'Tiny MCoC Schedule',
                '<http://simians.tk/MCOC-Sched>',
                'Josh Morris Schedule',
                'https://d2jixqqjqj5d23.cloudfront.net/assets/developer/imgs/icons/google-spreadsheet-icon.png'),
            'hook': (
                'hook/champions',
                '<http://hook.github.io/champions>',
                'hook/champions for Collector',
                'https://assets-cdn.github.com/favicon.ico'),
            'spotlight': (
                'MCoC Spotlight',
                '<http://simians.tk/MCoCspotlight>'),
            'marvelsynergy': (
                'Team Builder',
                '<http://www.marvelsynergy.com/team-builder>',
                'Marvel Synergy',
                'http://www.marvelsynergy.com/images/marvelsynergy.png'),
            'alsciende':(
                'Alsciende Mastery Tool',
                '<https://alsciende.github.io/masteries/v10.0.1/#>',
                'by u/alsciende',
                'https://assets-cdn.github.com/favicon.ico'),
            'simulator': (
                'Mastery Simulator',
                '<http://simians.tk/msimSDF>'),
            'streak': (
                'Infinite Streak',
                'http://simians.tk/-sdf-streak')
                #'http://simians.tk/SDFstreak')
    }
    mcolor = discord.Color.gold()
    icon_sdf = 'https://raw.githubusercontent.com/JasonJW/mcoc-cogs/master/mcoc/data/sdf_icon.png'
    dataset = 'data/mcoc/masteries.csv'

    def __init__(self, bot):
        self.bot = bot

    def present(self, lookup):
        em=discord.Embed(color=self.mcolor,title=lookup[0],description=lookup[1])
        print(len(lookup))
        if len(lookup) > 2:
            em.set_footer(text=lookup[2],icon_url=lookup[3])
        else:
            em.set_footer(text='Presented by [-SDF-]',icon_url=self.icon_sdf)
        return em

    #Gold Realm disabled
    # @commands.command()
    # async def gold(self,msg = None):
    #     '''Gold Realm Schedule'''
    #     package = '```           PST      CST      EST\nJun 5    10:00    12:00    13:00\nJun 5    19:00    21:00    22:00\nJun 6     4:00     6:00     7:00\nJun 6    13:00    15:00    16:00\nJun 6    22:00     0:00     1:00\nJun 7     7:00     9:00    10:00\nJun 7    16:00    18:00    19:00\nJun 8     1:00     3:00     4:00\nJun 8    10:00    12:00    13:00\nJun 8    19:00    21:00    22:00\nJun 9     4:00     6:00     7:00\nJun 9    13:00    15:00    16:00\nJun 10   22:00     0:00     1:00\nJun 11    7:00     9:00    10:00\nJun 11   16:00    18:00    19:00\nJun 12    1:00     3:00     4:00```'
    #     # await self.bot.say('```'+package+'```')
    #     if msg is not None:
    #         package = msg+'\n'+package
    #     em = discord.Embed(color=discord.Color.gold(),title='Gold Realm Schedule',description=package)
    #     em.set_footer(text='Presented by [-SDF-]',icon_url=self.icon_sdf)
    #     await self.bot.say(embed=em)

    @commands.command(help=lookup_links['event'][0], aliases=['events','schedule',])
    async def event(self):
        lookup = self.lookup_links['event']
        await self.bot.say(embed=self.present(lookup))

    @commands.command(help=lookup_links['spotlight'][0],)
    async def spotlight(self):
        lookup = self.lookup_links['spotlight']
        await self.bot.say(embed=self.present(lookup))

    @commands.command(help=lookup_links['marvelsynergy'][0])
    async def marvelsynergy(self):
        lookup = self.lookup_links['marvelsynergy']
        await self.bot.say(embed=self.present(lookup))

    @commands.command(help=lookup_links['simulator'][0],aliases=['msim'])
    async def simulator(self):
        lookup = self.lookup_links['simulator']
        await self.bot.say(embed=self.present(lookup))

    @commands.command(help=lookup_links['alsciende'][0], aliases=('mrig',))
    async def alsciende(self):
        lookup = self.lookup_links['alsciende']
        await self.bot.say(embed=self.present(lookup))

    @commands.command(help=lookup_links['streak'][0])
    async def streak(self):
        lookup = self.lookup_links['streak']
        await self.bot.say(embed=self.present(lookup))

    @commands.command(help=lookup_links['hook'][0])
    async def hook(self):
        lookup = self.lookup_links['hook']
        await self.bot.say(embed=self.present(lookup))

    @commands.command()
    async def keygen(self, prefix='SECEMP99'):
        letters='ABCDEFGHIJKLMNOPQURSTUVWXYZ'
        package = []
        for i in range(0,9):
            lets='{}{}{}{}'.format(random.choice(letters),random.choice(letters),random.choice(letters),random.choice(letters))
            package.append(prefix+lets)
        em=discord.Embed(color=discord.Color.gold(),title='Email Code Generator',description='\n'.join(package))
        await self.bot.say(embed=em)
#### Mastery stuff###
# class MCOCMastery:
    masteryColor={'Offense': discord.Color.red(),
            'Defense': discord.Color.blue(),
            'Utility': discord.Color.green()}
    tokens={'Vitality','Greater Vitality','Salve','Recovery','Energy Resistance','Physical Resistance','Block Proficiency','Perfect Block','Stand Your Ground','Collar Tech','Serum Science','Willpower','Coagulate','Suture','Inequity','Resonate',
            'Strength','Greater Strength','Pierce','Lesser Precision','Precision','Lesser Cruelty','Cruelty','Courage','Extended Fury','Enhanced Fury','Pure Skill','Mutagenesis','Glass Canon','Recoil','Liquid Courage','Double Edge','Despair','DeepWounds','Unfazed','Assassin',
            'Wisdom','Intelligence','Limber','Parry','Stupefy','Petrify','Pacify','Dexterity','Pitance','Prosperity','Cosmic Awareness','Mystic Dispersion','Detect Cosmic','Detect Tech','Detect Mystic','Scouter Lens','Detect Mutant','Detect Science','Detect Skill'}

    @commands.group(pass_context=True, aliases=['masteries',])
    async def mastery(self, ctx):
        if ctx.invoked_subcommand is None:
            await self.bot.send_cmd_help(ctx)
            return

    @mastery.command(pass_context=True,)
    async def test(self,ctx):
        message = ctx.message.content
        # mastery='Resonate'
        # rank=3
        # rows = get_csv_rows(self.dataset,'Mastery',mastery)
        #  text = []
        # cost = {'ucarb': 'Carbonadium Mastery Core', 'ustony': 'Stony Mastery Core', 'uclass': '', 'uunit': 'Units', 'rgold': 'Gold', 'runit': 'Units'}
        # cores = {'Collar Tech': 'Tech Core', 'Serum Science': 'Mastery Serum', 'Mutagenesis': 'Mastery Core X', 'Pure Skill': 'Mastery Core of Apptitude', 'Cosmic Awareness':'Cosmic Mastery Core', 'Mystic Dispersion': 'Mystical Mastery Core',
        #         'Detect Tech': 'Tech Core', 'Detect Science': 'Mastery Serum', 'Detect Mutant': 'Mastery Core X', 'Detect Skill': 'Mastery Core of Apptitude', 'Detect Cosmic':'Cosmic Mastery Core', 'Detect Mystic': 'Mystical Mastery Core',}
        # if mastery in cores:
        #     cost['uclass'][1]=cores[mastery]
        for token in self.tokens:
            print(token+' found')
            if token in message:
                maxrank = rows[0]['Max Ranks']
                category = rows[0]['Category']

                em=discord.Embed(color=self.masteryColor[category],title=mastery,description=' '.join(t for t in text))
                # for r in maxrank:
                    # unlock, rankcost = _get_cost(mastery, r)
                unlock, rankcost = self._get_cost(mastery)

                em.add_field(name='Unlock Cost',value='\n'.join(u[0] for u in unlock))
                em.add_field(name='Rank Cost',value='\n'.join(r for r in rankcost))
                await self.bot.say(embed=em)

    @mastery.command(pass_context=True, name='cost')
    async def _cost(self,ctx):
        # message = ctx.message.content.split(' ')
        # stack = []
        # for i in range(0,len(message)-1):
        #     if i+1 < len(message):
        #         test='{} {}'.format(message[i],message[i+1])
        #         if test in self.tokens:
        #             stack.append(test)
        #             i=i+2
        #         elif message[i] in self.tokens:
        #             stack.append(message[i])
        #     else:
        #         if message[i] in self.tokens:
        #             stack.append(message[i])
        # await self.bot.say('\n'.join(stack))

        # args = ctx.split(' ')
        #
        # for arg in args:
        #     # parse_re = re.compile(r'''(?:r(?P<rank>[0-9]))|(?:d(?P<debug>[0-9]{1,2}))''', re.X)
        #     if arg in tokens:
        #         row = mcoc.csv_get_row(mcoc.data_files['masteries']['local'], 'MasteryExt', arg)

        await self.bot.say('Dummy message for cost')

    @mastery.command(pass_context=True, name='set')
    async def _set(self,ctx):
        await self.bot.say('Dummy message for set')

    # def _get_cost(self, mastery):
    #     row = csv_get_row(self.dataset,'Mastery',mastery)
    #     cost = {'ucarb': 'Carbonadium Mastery Core', 'ustony': 'Stony Mastery Core', 'uclass': '', 'uunit': 'Units', 'rgold': 'Gold', 'runit': 'Units'}
    #     cores = {'Collar Tech': 'Tech Core', 'Serum Science': 'Mastery Serum', 'Mutagenesis': 'Mastery Core X', 'Pure Skill': 'Mastery Core of Apptitude', 'Cosmic Awareness':'Cosmic Mastery Core', 'Mystic Dispersion': 'Mystical Mastery Core',
    #             'Detect Tech': 'Tech Core', 'Detect Science': 'Mastery Serum', 'Detect Mutant': 'Mastery Core X', 'Detect Skill': 'Mastery Core of Apptitude', 'Detect Cosmic':'Cosmic Mastery Core', 'Detect Mystic': 'Mystical Mastery Core',}
        # if mastery in cores:
        #     classcore=cores[mastery]
        # unlockcost=[]
        # rankcost=[]
        # maxranks=row['maxranks']
        # carbcost=row['ucarb'].split(',')
        # stonycost=row['ustony'].split(',')
        # classcost=row['uclass'].split(',')
        # unitcost=row['uunit'].split(',')
        # if len(carbcost) > 0:
        #     unlockcost.append({'ucarb':{carbcost,'Carbonadium Mastery Core'})
        # if len(stonycost) > 0:
        #     unlockcost.append({'ustony':{stonycost,'Stony Mastery Core'})
        # if len(classcost) > 0:
        #     unlockcost.append({'uclass':{classcost,classcore})
        # if len(unitcost) > 0:
        #     unlockcost.append({'uunit':{unitcost,'Units'})
        # goldrank=row['rgold'].split(',')
        # unitrank=row['runit'].split(',')
        # if len(goldrank) > 0:
        #     rankcost.append({'rgold':{goldrank,'Gold'})
        # if len(unitrank) > 0:
        #     unlockcost.append({'runit':{unitrank,'Units'})
        #
        # return unlockcost, rankcost

    def _get_text(self, mastery, rank):
        rows = csv_get_rows(self.dataset,'Mastery',mastery)
        for row in rows:
            text.append(row['Text'].format(row[str(rank)]))
        return text

def load_csv(filename):
    return csv.DictReader(open(filename))

def get_csv_row(filecsv, column, match_val, default=None):
    print(match_val)
    csvfile = load_csv(filecsv)
    for row in csvfile:
        if row[column] == match_val:
            if default is not None:
                for k, v in row.items():
                    if v == '':
                        row[k] = default
            return row

def get_csv_rows(filecsv, column, match_val, default=None):
    print(match_val)
    csvfile = load_csv(filecsv)
    package =[]
    for row in csvfile:
        if row[column] == match_val:
            if default is not None:
                for k, v in row.items():
                    if v == '':
                        row[k] = default
            package.append(row)
    return package

def tabulate(table_data, width, rotate=True, header_sep=True):
    rows = []
    cells_in_row = None
    for i in iter_rows(table_data, rotate):
        if cells_in_row is None:
            cells_in_row = len(i)
        elif cells_in_row != len(i):
            raise IndexError("Array is not uniform")
        rows.append('|'.join(['{:^{width}}']*len(i)).format(*i, width=width))
    if header_sep:
        rows.insert(1, '|'.join(['-' * width] * cells_in_row))
    return chat.box('\n'.join(rows))

def setup(bot):
    bot.add_cog(MCOCTools(bot))
<|endoftext|>


<commit_before># Copyright 2008 the Melange authors.
#
# 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.

"""Module containing Melange Django settings.
"""

__authors__ = [
  '"Madhusudan.C.S" <madhusudancs@gmail.com>',
  '"Augie Fackler" <durin42@gmail.com>',
  '"Sverre Rabbelier" <sverre@rabbelier.nl>',
  '"Lennard de Rijk" <ljvderijk@gmail.com>',
  '"Pawel Solyga" <pawel.solyga@gmail.com>',
  ]

import os

# Debug flag True only on App Engine development environment (dev_appserver.py)
# dev_appserver sets SERVER_SOFTWARE to 'Development/1.0'
DEBUG = os.environ['SERVER_SOFTWARE'].startswith('Dev')
TEMPLATE_DEBUG = DEBUG

ADMINS = (
    # ('Your Name', 'your_email@domain.com'),
)

MANAGERS = ADMINS

# 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
DATABASE_ENGINE = 'dummy'
# None of the following are used with appengine
DATABASE_NAME = ''             # Or path to database file if using sqlite3.
DATABASE_USER = ''             # Not used with sqlite3.
DATABASE_PASSWORD = ''         # Not used with sqlite3.
# Set to empty string for localhost. Not used with sqlite3.
DATABASE_HOST = ''
# Set to empty string for default. Not used with sqlite3.
DATABASE_PORT = ''

# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'UTC'

# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'

SITE_ID = 1

# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True

# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = ''

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
MEDIA_URL = ''

# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/media/'

# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.load_template_source',
    'django.template.loaders.app_directories.load_template_source',
#     'django.template.loaders.eggs.load_template_source',
)

# The order of the middleware is as follows because:
# - The ValueStore middleware should be before any other middleware
#   so that the value store is available to it.
# - The ExceptionHandler should be the outermost handler (after the
#   ValueStore) so as to catch as many errors as possible.
# - The Profile middleware should be as outmost as possible, so that
#   as many function calls as possible, but it cannot be before the
#   ExceptionHandler (so as to catch exceptions thrown by it).
# - The MaintenanceMiddleware should be after the Profiler, since we
#   do want it's actions profiled.
MIDDLEWARE_CLASSES = (
    'google.appengine.ext.appstats.recording.AppStatsDjangoMiddleware',
    'soc.middleware.value_store.ValueStoreMiddleware',
    'soc.middleware.exception_handler.ExceptionHandlerMiddleware',
#    'soc.middleware.profiler.ProfileMiddleware',
    'soc.middleware.maintenance.MaintenanceMiddleware',
    'soc.middleware.blobstore.BlobStoreMiddleware',
    'soc.middleware.xsrf.XsrfMiddleware',
#    'django.middleware.common.CommonMiddleware',
#    'django.contrib.sessions.middleware.SessionMiddleware',
#    'django.contrib.auth.middleware.AuthenticationMiddleware',
#    'django.middleware.doc.XViewMiddleware',
)

ROOT_URLCONF = 'urls'

ROOT_PATH = os.path.dirname(__file__)
TEMPLATE_DIRS = (
    # TODO(proto): customize the template search directories
    os.path.join(ROOT_PATH, 'soc', 'templates'),
    os.path.join(ROOT_PATH, 'shell', 'templates'),
)

INSTALLED_APPS = (
    'soc.views.helper',
    'soc.modules.gsoc.views.helper',
    'soc.modules.gci.views.helper',
#    'django.contrib.auth',
#    'django.contrib.contenttypes',
#    'django.contrib.sessions',
#    'django.contrib.sites',
)

GCI_TASK_QUOTA_LIMIT_ENABLED = False

MODULE_FMT = 'soc.modules.%s.callback'
MODULES = ['gsoc', 'statistic', 'gci']
<commit_msg>Disable ExceptionHandler middleware<commit_after># Copyright 2008 the Melange authors.
#
# 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.

"""Module containing Melange Django settings.
"""

__authors__ = [
  '"Madhusudan.C.S" <madhusudancs@gmail.com>',
  '"Augie Fackler" <durin42@gmail.com>',
  '"Sverre Rabbelier" <sverre@rabbelier.nl>',
  '"Lennard de Rijk" <ljvderijk@gmail.com>',
  '"Pawel Solyga" <pawel.solyga@gmail.com>',
  ]

import os

# Debug flag True only on App Engine development environment (dev_appserver.py)
# dev_appserver sets SERVER_SOFTWARE to 'Development/1.0'
DEBUG = os.environ['SERVER_SOFTWARE'].startswith('Dev')
TEMPLATE_DEBUG = DEBUG

ADMINS = (
    # ('Your Name', 'your_email@domain.com'),
)

MANAGERS = ADMINS

# 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
DATABASE_ENGINE = 'dummy'
# None of the following are used with appengine
DATABASE_NAME = ''             # Or path to database file if using sqlite3.
DATABASE_USER = ''             # Not used with sqlite3.
DATABASE_PASSWORD = ''         # Not used with sqlite3.
# Set to empty string for localhost. Not used with sqlite3.
DATABASE_HOST = ''
# Set to empty string for default. Not used with sqlite3.
DATABASE_PORT = ''

# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'UTC'

# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'

SITE_ID = 1

# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True

# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = ''

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
MEDIA_URL = ''

# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/media/'

# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.load_template_source',
    'django.template.loaders.app_directories.load_template_source',
#     'django.template.loaders.eggs.load_template_source',
)

# The order of the middleware is as follows because:
# - The ValueStore middleware should be before any other middleware
#   so that the value store is available to it.
# - The ExceptionHandler should be the outermost handler (after the
#   ValueStore) so as to catch as many errors as possible.
# - The Profile middleware should be as outmost as possible, so that
#   as many function calls as possible, but it cannot be before the
#   ExceptionHandler (so as to catch exceptions thrown by it).
# - The MaintenanceMiddleware should be after the Profiler, since we
#   do want it's actions profiled.
MIDDLEWARE_CLASSES = (
    'google.appengine.ext.appstats.recording.AppStatsDjangoMiddleware',
    'soc.middleware.value_store.ValueStoreMiddleware',
#    'soc.middleware.exception_handler.ExceptionHandlerMiddleware',
#    'soc.middleware.profiler.ProfileMiddleware',
    'soc.middleware.maintenance.MaintenanceMiddleware',
    'soc.middleware.blobstore.BlobStoreMiddleware',
    'soc.middleware.xsrf.XsrfMiddleware',
#    'django.middleware.common.CommonMiddleware',
#    'django.contrib.sessions.middleware.SessionMiddleware',
#    'django.contrib.auth.middleware.AuthenticationMiddleware',
#    'django.middleware.doc.XViewMiddleware',
)

ROOT_URLCONF = 'urls'

ROOT_PATH = os.path.dirname(__file__)
TEMPLATE_DIRS = (
    # TODO(proto): customize the template search directories
    os.path.join(ROOT_PATH, 'soc', 'templates'),
    os.path.join(ROOT_PATH, 'shell', 'templates'),
)

INSTALLED_APPS = (
    'soc.views.helper',
    'soc.modules.gsoc.views.helper',
    'soc.modules.gci.views.helper',
#    'django.contrib.auth',
#    'django.contrib.contenttypes',
#    'django.contrib.sessions',
#    'django.contrib.sites',
)

GCI_TASK_QUOTA_LIMIT_ENABLED = False

MODULE_FMT = 'soc.modules.%s.callback'
MODULES = ['gsoc', 'statistic', 'gci']
<|endoftext|>


<commit_before>class Deck(object):
    def __init__(self, name):
        self._name = name
        self._cards = []

    @property
    def name(self):
        return self._name

    @property
    def cards(self):
        return self._cards

    def add_card(self, card):
        self.cards.append(card)

class DeckReview(object):
    """
    Encapsulate a session where a Deck of cards is being reviewed.

    The state consists of the current card being displayed

    Clients can request for the next and previous card in the deck
    """

    def __init__(self, deck):
        self._deck = deck
        self._current_index = 0

    @property
    def deck(self):
        return self._deck

    @property
    def current_index(self):
        return self._current_index

    @property
    def number_of_cards(self):
        return len(self.deck.cards)

    def _card_adjoining(self, direction):
        self._current_index += direction
        next_index = self.current_index%self.number_of_cards
        return self.deck.cards[next_index]

    @property
    def next_card(self):
        return self._card_adjoining(1)

    @property
    def previous_card(self):
        return self._card_adjoining(-1)

if __name__ == '__main__':
    from flashcardapp.card import Card

    deck = Deck("Test1")

    for front, back in [('a', 'A'), ('and', 'AND'), ('can', 'CAN')]:
        card = Card(front, back)
        deck.add_card(card)

    for card in deck.cards:
        print(card)

    print("\n\nLet us now review a deck of cards\n\n")

    review = DeckReview(deck)

    print(review.deck.cards[review.current_index])
    for index in range(10):
        print(review.next_card)
<commit_msg>Added test case for reviewing a deck of cards in reverse<commit_after>class Deck(object):
    def __init__(self, name):
        self._name = name
        self._cards = []

    @property
    def name(self):
        return self._name

    @property
    def cards(self):
        return self._cards

    def add_card(self, card):
        self.cards.append(card)

class DeckReview(object):
    """
    Encapsulate a session where a Deck of cards is being reviewed.

    The state consists of the current card being displayed

    Clients can request for the next and previous card in the deck
    """

    def __init__(self, deck):
        self._deck = deck
        self._current_index = 0

    @property
    def deck(self):
        return self._deck

    @property
    def current_index(self):
        return self._current_index

    @property
    def number_of_cards(self):
        return len(self.deck.cards)

    def _card_adjoining(self, direction):
        self._current_index += direction
        next_index = self.current_index%self.number_of_cards
        return self.deck.cards[next_index]

    @property
    def next_card(self):
        return self._card_adjoining(1)

    @property
    def previous_card(self):
        return self._card_adjoining(-1)

if __name__ == '__main__':
    from flashcardapp.card import Card

    deck = Deck("Test1")

    for front, back in [('a', 'A'), ('and', 'AND'), ('can', 'CAN')]:
        card = Card(front, back)
        deck.add_card(card)

    for card in deck.cards:
        print(card)

    print("\n\nLet us now review a deck of cards\n\n")

    review = DeckReview(deck)

    print(review.deck.cards[review.current_index])
    for index in range(10):
        print(review.next_card)

    print("\n\nLet us now review a deck of cards (in reverse)\n\n")

    review = DeckReview(deck)

    print(review.deck.cards[review.current_index])
    for index in range(10):
        print(review.previous_card)
<|endoftext|>


<commit_before>from django.shortcuts import get_object_or_404
from rest_framework import viewsets, status, exceptions
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework.decorators import detail_route, list_route, api_view
from rest_framework.reverse import reverse
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser, FileUploadParser
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
from rest_framework.exceptions import PermissionDenied

from media_service.models import Course, Collection, Resource, MediaStore, CollectionResource
from media_service.iiif import CollectionManifestController
from media_service.serializers import UserSerializer, CourseSerializer, ResourceSerializer, CollectionSerializer, CollectionResourceSerializer

from media_auth.filters import CourseEndpointFilter, CollectionEndpointFilter, ResourceEndpointFilter
from media_auth.permissions import CourseEndpointPermission, CollectionEndpointPermission, ResourceEndpointPermission, CollectionResourceEndpointPermission

class APIRoot(APIView):
    def get(self, request, format=None):
        return Response({
            'courses': reverse('course-list', request=request, format=format),
            'collections': reverse('collection-list', request=request, format=format),
            'images': reverse('image-list', request=request, format=format),
        })

class CourseViewSet(viewsets.ModelViewSet):
    '''
A **course** resource contains a set of *images* which may be grouped into *collections*.

Courses Endpoints
----------------

- `/courses`  Lists courses
- `/courses/{pk}` Course detail
- `/courses/{pk}/collections` Lists a course's collections
- `/courses/{pk}/images`  Lists a course's images

LTI Attributes
--------------
A course associated with an LTI context must have the following attributes at minimum:

- `lti_context_id` Opaque identifier that uniquely identifies tool context (i.e. Canvas Course)
- `lti_tool_consumer_instance_guid` DNS of the consumer instance that launched the tool

Together, these two attributes should be unique. These attributes should be present in an
LTI launch as `context_id` and `tool_consumer_instance_guid`.

To search for a course associated with an LTI context:

- `/courses?lti_context_id=<context_id>&lti_tool_consumer_instance_guid=<tool_consumer_instance_guid>`

Since one and only one instance of a course can exist with those two attributes, the response should
be an empty list or a list with one object.
    '''
    queryset = Course.objects.prefetch_related('resources', 'collections', 'collections__resources', 'resources__media_store')
    serializer_class = CourseSerializer
    permission_classes = (CourseEndpointPermission,)

    def get_queryset(self):
        queryset = super(CourseViewSet, self).get_queryset()
        queryset = CourseEndpointFilter(self).filter_queryset(queryset)
        return queryset

    def list(self, request, format=None):
        queryset = self.get_queryset()

        # Filter queryset by LTI context params
        lti_params = ('lti_context_id', 'lti_tool_consumer_instance_guid')
        lti_filters = dict([(k, self.request.GET[k]) for k in lti_params if k in self.request.GET])
        if len(lti_filters.keys()) > 0:
            queryset = queryset.filter(**lti_filters)

        serializer = CourseSerializer(queryset, many=True, context={'request': request})
        return Response(serializer.data)

    def retrieve(self, request, pk=None, format=None):
        course = self.get_object()
        include = ['images', 'collections']
        serializer = CourseSerializer(course, context={'request': request}, include=include)
        return Response(serializer.data)

    @detail_route(methods=['get'])
    def manifests(self, request, pk=None, format=None):
        course = self.get_object()
        manifests = []
        for collection in course.collections.all():
            url = reverse('collection-manifest', kwargs={"pk": collection.pk})
            manifests.append({
                "label": collection.title,
                "url": request.build_absolute_uri(url),
            })
        return Response(manifests)

class CollectionViewSet(viewsets.ModelViewSet):
    '''
A **collection** resource is a grouping of *images*.

Collection Endpoints
----------------

- `/collections`  Lists collections
- `/collections/{pk}` Collection detail
- `/collections/{pk}/images`  Lists a collection's images
    '''
    queryset = Collection.objects.select_related('course').prefetch_related('resources__resource__media_store')
    serializer_class = CollectionSerializer
    permission_classes = (CollectionEndpointPermission,)

    def get_queryset(self):
        queryset = super(CollectionViewSet, self).get_queryset()
        queryset = CollectionEndpointFilter(self).filter_queryset(queryset)
        return queryset

    def list(self, request, format=None):
        collections = self.get_queryset()
        serializer = CollectionSerializer(collections, many=True, context={'request': request})
        return Response(serializer.data)

    def retrieve(self, request, pk=None, format=None):
        collection = self.get_object()
        include = ['images']
        serializer = CollectionSerializer(collection, context={'request': request}, include=include)
        return Response(serializer.data)

    @detail_route(methods=['get'])
    def manifest(self, request, pk=None, format=None):
        collection = self.get_object()
        collection_manifest_controller = CollectionManifestController(request, collection)
        data = collection_manifest_controller.get_data()
        return Response(data)

class CourseCollectionsView(GenericAPIView):
    queryset = Collection.objects.select_related('course').prefetch_related('resources__resource__media_store')
    serializer_class = CollectionSerializer
    permission_classes = (CollectionEndpointPermission,)

    def get(self, request, pk=None, format=None):
        course_pk = pk
        collections = self.get_queryset().filter(course__pk=course_pk).order_by('sort_order')
        include = ['images']
        serializer = CollectionSerializer(collections, many=True, context={'request': request}, include=include)
        return Response(serializer.data)

    def post(self, request, pk=None, format=None):
        course_pk = pk
        data = request.data.copy()
        course = get_object_or_404(Course, pk=pk)
        data['course_id'] = course.pk
        serializer = CollectionSerializer(data=data, context={'request': request})
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class CourseImagesListView(GenericAPIView):
    serializer_class = ResourceSerializer
    queryset = Resource.objects.select_related('course', 'media_store')
    parser_classes = (JSONParser, MultiPartParser, FormParser)
    permission_classes = (ResourceEndpointPermission,)

    def get(self, request, pk=None, format=None):
        course_pk = pk
        images = self.get_queryset().filter(course__pk=course_pk).order_by('sort_order')
        serializer = ResourceSerializer(images, many=True, context={'request': request})
        return Response(serializer.data)

    def post(self, request, pk=None, format=None):
        course_pk = pk
        course = get_object_or_404(Course, pk=pk)
        file_param = 'file'
        if file_param not in request.FILES:
            raise exceptions.APIException("Error: missing '%s' parameter in upload" % file_param)
        elif len(request.FILES) == 0:
            raise exceptions.APIException("Error: no files uploaded")

        response_data = []
        print "file_uploads=%s" % request.FILES.getlist(file_param)
        for file_upload in request.FILES.getlist(file_param):
            print "processing: %s" % (file_upload.name)
            data = request.data.copy()
            data['course_id'] = course.pk
            serializer = ResourceSerializer(data=data, context={'request': request}, file_upload=file_upload)
            if serializer.is_valid():
                serializer.save()
                response_data.append(serializer.data)
            else:
                return Response(response_data + [serializer.errors], status=status.HTTP_400_BAD_REQUEST)
        return Response(response_data, status=status.HTTP_201_CREATED)

class CollectionImagesListView(GenericAPIView):
    queryset = CollectionResource.objects.select_related('collection', 'resource').prefetch_related('resource__media_store')
    serializer_class = CollectionResourceSerializer
    permission_classes = (IsAuthenticated,)

    def get(self, request, pk=None, format=None):
        collection_resources = self.get_queryset().filter(collection__pk=pk).order_by('sort_order')
        serializer = CollectionResourceSerializer(collection_resources, many=True, context={'request': request})
        return Response(serializer.data)

    def post(self, request, pk=None, format=None):
        collection = get_object_or_404(Collection, pk=pk)
        data = []
        for collection_resource in request.data:
            collection_resource = collection_resource.copy()
            collection_resource['collection_id'] = collection.pk
            data.append(collection_resource)
        serializer = CollectionResourceSerializer(data=data, many=True, context={'request': request})
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class CollectionImagesDetailView(GenericAPIView):
    queryset = CollectionResource.objects.all()
    serializer_class = CollectionResourceSerializer
    permission_classes = (IsAuthenticated,)

    def get(self, request, pk=None, format=None):
         collection_resource = self.get_object()
         serializer = CollectionResourceSerializer(collection_resource, context={'request': request})
         return Response(serializer.data)

    def delete(self, request, pk=None, format=None):
        collection_resource = self.get_object()
        collection_resource.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

class CourseImageViewSet(viewsets.ModelViewSet):
    queryset = Resource.objects.select_related('course', 'media_store')
    serializer_class = ResourceSerializer
    permission_classes = (ResourceEndpointPermission,)

    def get_queryset(self):
        queryset = super(CourseImageViewSet, self).get_queryset()
        queryset = ResourceEndpointFilter(self).filter_queryset(queryset)
        return queryset
<commit_msg>Replaced prints with logs.<commit_after>from django.shortcuts import get_object_or_404
from rest_framework import viewsets, status, exceptions
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework.decorators import detail_route, list_route, api_view
from rest_framework.reverse import reverse
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser, FileUploadParser
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
from rest_framework.exceptions import PermissionDenied

from media_service.models import Course, Collection, Resource, MediaStore, CollectionResource
from media_service.iiif import CollectionManifestController
from media_service.serializers import UserSerializer, CourseSerializer, ResourceSerializer, CollectionSerializer, CollectionResourceSerializer

from media_auth.filters import CourseEndpointFilter, CollectionEndpointFilter, ResourceEndpointFilter
from media_auth.permissions import CourseEndpointPermission, CollectionEndpointPermission, ResourceEndpointPermission, CollectionResourceEndpointPermission

import logging

logger = logging.getLogger(__name__)

class APIRoot(APIView):
    def get(self, request, format=None):
        return Response({
            'courses': reverse('course-list', request=request, format=format),
            'collections': reverse('collection-list', request=request, format=format),
            'images': reverse('image-list', request=request, format=format),
        })

class CourseViewSet(viewsets.ModelViewSet):
    '''
A **course** resource contains a set of *images* which may be grouped into *collections*.

Courses Endpoints
----------------

- `/courses`  Lists courses
- `/courses/{pk}` Course detail
- `/courses/{pk}/collections` Lists a course's collections
- `/courses/{pk}/images`  Lists a course's images

LTI Attributes
--------------
A course associated with an LTI context must have the following attributes at minimum:

- `lti_context_id` Opaque identifier that uniquely identifies tool context (i.e. Canvas Course)
- `lti_tool_consumer_instance_guid` DNS of the consumer instance that launched the tool

Together, these two attributes should be unique. These attributes should be present in an
LTI launch as `context_id` and `tool_consumer_instance_guid`.

To search for a course associated with an LTI context:

- `/courses?lti_context_id=<context_id>&lti_tool_consumer_instance_guid=<tool_consumer_instance_guid>`

Since one and only one instance of a course can exist with those two attributes, the response should
be an empty list or a list with one object.
    '''
    queryset = Course.objects.prefetch_related('resources', 'collections', 'collections__resources', 'resources__media_store')
    serializer_class = CourseSerializer
    permission_classes = (CourseEndpointPermission,)

    def get_queryset(self):
        queryset = super(CourseViewSet, self).get_queryset()
        queryset = CourseEndpointFilter(self).filter_queryset(queryset)
        return queryset

    def list(self, request, format=None):
        queryset = self.get_queryset()

        # Filter queryset by LTI context params
        lti_params = ('lti_context_id', 'lti_tool_consumer_instance_guid')
        lti_filters = dict([(k, self.request.GET[k]) for k in lti_params if k in self.request.GET])
        if len(lti_filters.keys()) > 0:
            queryset = queryset.filter(**lti_filters)

        serializer = CourseSerializer(queryset, many=True, context={'request': request})
        return Response(serializer.data)

    def retrieve(self, request, pk=None, format=None):
        course = self.get_object()
        include = ['images', 'collections']
        serializer = CourseSerializer(course, context={'request': request}, include=include)
        return Response(serializer.data)

    @detail_route(methods=['get'])
    def manifests(self, request, pk=None, format=None):
        course = self.get_object()
        manifests = []
        for collection in course.collections.all():
            url = reverse('collection-manifest', kwargs={"pk": collection.pk})
            manifests.append({
                "label": collection.title,
                "url": request.build_absolute_uri(url),
            })
        return Response(manifests)

class CollectionViewSet(viewsets.ModelViewSet):
    '''
A **collection** resource is a grouping of *images*.

Collection Endpoints
----------------

- `/collections`  Lists collections
- `/collections/{pk}` Collection detail
- `/collections/{pk}/images`  Lists a collection's images
    '''
    queryset = Collection.objects.select_related('course').prefetch_related('resources__resource__media_store')
    serializer_class = CollectionSerializer
    permission_classes = (CollectionEndpointPermission,)

    def get_queryset(self):
        queryset = super(CollectionViewSet, self).get_queryset()
        queryset = CollectionEndpointFilter(self).filter_queryset(queryset)
        return queryset

    def list(self, request, format=None):
        collections = self.get_queryset()
        serializer = CollectionSerializer(collections, many=True, context={'request': request})
        return Response(serializer.data)

    def retrieve(self, request, pk=None, format=None):
        collection = self.get_object()
        include = ['images']
        serializer = CollectionSerializer(collection, context={'request': request}, include=include)
        return Response(serializer.data)

    @detail_route(methods=['get'])
    def manifest(self, request, pk=None, format=None):
        collection = self.get_object()
        collection_manifest_controller = CollectionManifestController(request, collection)
        data = collection_manifest_controller.get_data()
        return Response(data)

class CourseCollectionsView(GenericAPIView):
    queryset = Collection.objects.select_related('course').prefetch_related('resources__resource__media_store')
    serializer_class = CollectionSerializer
    permission_classes = (CollectionEndpointPermission,)

    def get(self, request, pk=None, format=None):
        course_pk = pk
        collections = self.get_queryset().filter(course__pk=course_pk).order_by('sort_order')
        include = ['images']
        serializer = CollectionSerializer(collections, many=True, context={'request': request}, include=include)
        return Response(serializer.data)

    def post(self, request, pk=None, format=None):
        course_pk = pk
        data = request.data.copy()
        course = get_object_or_404(Course, pk=pk)
        data['course_id'] = course.pk
        serializer = CollectionSerializer(data=data, context={'request': request})
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class CourseImagesListView(GenericAPIView):
    serializer_class = ResourceSerializer
    queryset = Resource.objects.select_related('course', 'media_store')
    parser_classes = (JSONParser, MultiPartParser, FormParser)
    permission_classes = (ResourceEndpointPermission,)

    def get(self, request, pk=None, format=None):
        course_pk = pk
        images = self.get_queryset().filter(course__pk=course_pk).order_by('sort_order')
        serializer = ResourceSerializer(images, many=True, context={'request': request})
        return Response(serializer.data)

    def post(self, request, pk=None, format=None):
        course_pk = pk
        course = get_object_or_404(Course, pk=pk)
        file_param = 'file'
        if file_param not in request.FILES:
            raise exceptions.APIException("Error: missing '%s' parameter in upload" % file_param)
        elif len(request.FILES) == 0:
            raise exceptions.APIException("Error: no files uploaded")

        response_data = []
        logger.debug("File uploads: %s" % request.FILES.getlist(file_param))
        for file_upload in request.FILES.getlist(file_param):
            logger.debug("Processing file upload: %s" % file_upload.name)
            data = request.data.copy()
            data['course_id'] = course.pk
            serializer = ResourceSerializer(data=data, context={'request': request}, file_upload=file_upload)
            if serializer.is_valid():
                serializer.save()
                response_data.append(serializer.data)
            else:
                logger.error(serializer.errors)
                return Response(response_data + [serializer.errors], status=status.HTTP_400_BAD_REQUEST)
        return Response(response_data, status=status.HTTP_201_CREATED)

class CollectionImagesListView(GenericAPIView):
    queryset = CollectionResource.objects.select_related('collection', 'resource').prefetch_related('resource__media_store')
    serializer_class = CollectionResourceSerializer
    permission_classes = (IsAuthenticated,)

    def get(self, request, pk=None, format=None):
        collection_resources = self.get_queryset().filter(collection__pk=pk).order_by('sort_order')
        serializer = CollectionResourceSerializer(collection_resources, many=True, context={'request': request})
        return Response(serializer.data)

    def post(self, request, pk=None, format=None):
        collection = get_object_or_404(Collection, pk=pk)
        data = []
        for collection_resource in request.data:
            collection_resource = collection_resource.copy()
            collection_resource['collection_id'] = collection.pk
            data.append(collection_resource)
        serializer = CollectionResourceSerializer(data=data, many=True, context={'request': request})
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class CollectionImagesDetailView(GenericAPIView):
    queryset = CollectionResource.objects.all()
    serializer_class = CollectionResourceSerializer
    permission_classes = (IsAuthenticated,)

    def get(self, request, pk=None, format=None):
         collection_resource = self.get_object()
         serializer = CollectionResourceSerializer(collection_resource, context={'request': request})
         return Response(serializer.data)

    def delete(self, request, pk=None, format=None):
        collection_resource = self.get_object()
        collection_resource.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

class CourseImageViewSet(viewsets.ModelViewSet):
    queryset = Resource.objects.select_related('course', 'media_store')
    serializer_class = ResourceSerializer
    permission_classes = (ResourceEndpointPermission,)

    def get_queryset(self):
        queryset = super(CourseImageViewSet, self).get_queryset()
        queryset = ResourceEndpointFilter(self).filter_queryset(queryset)
        return queryset
<|endoftext|>


<commit_before>from __future__ import division
import numpy as np
from functools import partial
import warnings
from menpo.transform import Scale
from menpo.feature import no_op
from menpofit.visualize import print_progress
from menpofit.base import batch, name_of_callable
from menpofit.builder import (normalization_wrt_reference_shape, scale_images,
                              rescale_images_to_reference_shape)
from menpofit.fitter import (MultiFitter, noisy_shape_from_bounding_box,
                             align_shape_with_bounding_box)
from menpofit.result import MultiFitterResult
import menpofit.checks as checks
from .algorithm import Newton

# TODO: document me!
class SupervisedDescentFitter(MultiFitter):
    r"""
    """
    def __init__(self, sd_algorithm_cls=Newton, holistic_feature=no_op,
                 patch_features=no_op, patch_shape=(17, 17), diagonal=None,
                 scales=(1, 0.5), iterations=6, n_perturbations=30,
                 perturb_from_bounding_box=noisy_shape_from_bounding_box):
        # check parameters
        checks.check_diagonal(diagonal)
        scales, n_levels = checks.check_scales(scales)
        patch_features = checks.check_features(patch_features, n_levels)
        patch_shape = checks.check_patch_shape(patch_shape, n_levels)
        # set parameters
        self.algorithms = []
        self.reference_shape = None
        self._sd_algorithm_cls = sd_algorithm_cls
        self._holistic_feature = holistic_feature
        self._patch_features = patch_features
        self._patch_shape = patch_shape
        self.diagonal = diagonal
        self.scales = list(scales)[::-1]
        self.n_perturbations = n_perturbations
        self.iterations = checks.check_max_iters(iterations, n_levels)
        self._perturb_from_bounding_box = perturb_from_bounding_box
        # set up algorithms
        self._reset_algorithms()

    def _reset_algorithms(self):
        if len(self.algorithms) > 0:
            for j in range(len(self.algorithms) - 1, -1, -1):
                del self.algorithms[j]
        for j in range(self.n_levels):
            self.algorithms.append(self._sd_algorithm_cls(
                features=self._patch_features[j],
                patch_shape=self._patch_shape[j],
                iterations=self.iterations[j]))

    def perturb_from_bounding_box(self, bounding_box):
        return self._perturb_from_bounding_box(self.reference_shape,
                                               bounding_box)

    def train(self, images, group=None, label=None, bounding_box_group=None,
              verbose=False, increment=False, **kwargs):
        # In the case where group is None, we need to get the only key so that
        # we can add landmarks below and not get a complaint about using None
        first_image = images[0]
        if group is None:
            group = first_image.landmarks.group_labels[0]

        if not increment:
            # Reset the algorithm classes
            self._reset_algorithms()
            # Normalize images and compute reference shape
            self.reference_shape, images = normalization_wrt_reference_shape(
                images, group, label, self.diagonal, verbose=verbose)
        else:
            if len(self.algorithms) == 0:
                raise ValueError('Must train before training incrementally.')
            # We are incrementing, so rescale to existing reference shape
            images = rescale_images_to_reference_shape(images, group, label,
                                                       self.reference_shape,
                                                       verbose=verbose)

        # No bounding box is given, so we will use the ground truth box
        if bounding_box_group is None:
            bounding_box_group = '__gt_bb_'
            for i in images:
                gt_s = i.landmarks[group][label]
                perturb_bbox_group = bounding_box_group + '0'
                i.landmarks[perturb_bbox_group] = gt_s.bounding_box()

        # Find all bounding boxes on the images with the given bounding box key
        all_bb_keys = list(first_image.landmarks.keys_matching(
            '*{}*'.format(bounding_box_group)))
        n_perturbations = len(all_bb_keys)

        # If there is only one example bounding box, then we will generate
        # more perturbations based on the bounding box.
        if n_perturbations == 1:
            msg = '- Generating {} new initial bounding boxes ' \
                  'per image'.format(self.n_perturbations)
            wrap = partial(print_progress, prefix=msg, verbose=verbose)

            for i in wrap(images):
                # We assume that the first bounding box is a valid perturbation
                # thus create n_perturbations - 1 new bounding boxes
                for j in range(1, self.n_perturbations):
                    gt_s = i.landmarks[group][label].bounding_box()
                    bb = i.landmarks[all_bb_keys[0]].lms

                    # This is customizable by passing in the correct method
                    p_s = self._perturb_from_bounding_box(gt_s, bb)
                    perturb_bbox_group = bounding_box_group + '_{}'.format(j)
                    i.landmarks[perturb_bbox_group] = p_s
        elif n_perturbations != self.n_perturbations:
            warnings.warn('The original value of n_perturbation {} '
                          'will be reset to {} in order to agree with '
                          'the provided bounding_box_group.'.
                          format(self.n_perturbations, n_perturbations))
            self.n_perturbations = n_perturbations

        # Re-grab all the bounding box keys for iterating over when calculating
        # perturbations
        all_bb_keys = list(first_image.landmarks.keys_matching(
            '*{}*'.format(bounding_box_group)))

        # Before scaling, we compute the holistic feature on the whole image
        msg = '- Computing holistic features ({})'.format(
            name_of_callable(self._holistic_feature))
        wrap = partial(print_progress, prefix=msg, verbose=verbose)
        images = [self._holistic_feature(im) for im in wrap(images)]

        # for each pyramid level (low --> high)
        for j in range(self.n_levels):
            if verbose:
                if len(self.scales) > 1:
                    level_str = '  - Level {}: '.format(j)
                else:
                    level_str = '  - '
            else:
                level_str = None

            # Scale images
            level_images = scale_images(images, self.scales[j],
                                        level_str=level_str, verbose=verbose)

            # Extract scaled ground truth shapes for current level
            level_gt_shapes = [i.landmarks[group][label] for i in level_images]

            if j == 0:
                msg = '{}Generating {} perturbations per image'.format(
                    level_str, self.n_perturbations)
                wrap = partial(print_progress, prefix=msg,
                               end_with_newline=False, verbose=verbose)

                # Extract perturbations at the very bottom level
                current_shapes = []
                for i in wrap(level_images):
                    c_shapes = []
                    for perturb_bbox_group in all_bb_keys:
                        bbox = i.landmarks[perturb_bbox_group].lms
                        c_s = align_shape_with_bounding_box(
                            self.reference_shape, bbox)
                        c_shapes.append(c_s)
                    current_shapes.append(c_shapes)

            # train supervised descent algorithm
            if increment:
                current_shapes = self.algorithms[j].increment(
                    level_images, level_gt_shapes, current_shapes,
                    verbose=verbose, **kwargs)
            else:
                current_shapes = self.algorithms[j].train(
                    level_images, level_gt_shapes, current_shapes,
                    level_str=level_str, verbose=verbose, **kwargs)

            # Scale current shapes to next level resolution
            if self.scales[j] != (1 or self.scales[-1]):
                transform = Scale(self.scales[j + 1] / self.scales[j], n_dims=2)
                for image_shapes in current_shapes:
                    for shape in image_shapes:
                        transform.apply_inplace(shape)

    def increment(self, images, group=None, label=None,
                  bounding_box_group=None, verbose=False,
                  **kwargs):
        return self.train(images, group=group, label=label,
                          bounding_box_group=bounding_box_group,
                          verbose=verbose,
                          increment=True, **kwargs)

    def train_incrementally(self, images, group=None, label=None,
                            batch_size=100, verbose=False, **kwargs):
        # Create a generator of fixed sized batches. Will still work even
        # on an infinite list.
        image_batches = batch(images, batch_size)

        # Train all batches
        for k, image_batch in enumerate(image_batches):
            n_images = len(image_batch)
            if verbose:
                print('Training batch {} of {} images.'.format(k, n_images))
            if k == 0:
                self.train(image_batch, group=group, label=label,
                           verbose=verbose, **kwargs)
            else:
                self.increment(image_batch, group=group, label=label,
                               verbose=verbose, **kwargs)

    def _prepare_image(self, image, initial_shape, gt_shape=None,
                       crop_image=0.5):
        r"""
        Prepares the image to be fitted.

        The image is first rescaled wrt the ``reference_landmarks`` and then
        a gaussian pyramid is applied. Depending on the
        ``pyramid_on_features`` flag, the pyramid is either applied to the
        features image computed from the rescaled imaged or applied to the
        rescaled image and features extracted at each pyramidal level.

        Parameters
        ----------
        image : :map:`Image` or subclass
            The image to be fitted.
        initial_shape : :map:`PointCloud`
            The initial shape from which the fitting will start.
        gt_shape : :map:`PointCloud`, optional
            The original ground truth shape associated to the image.
        crop_image: `None` or float`, optional
            If `float`, it specifies the proportion of the border wrt the
            initial shape to which the image will be internally cropped around
            the initial shape range.
            If `None`, no cropping is performed.

            This will limit the fitting algorithm search region but is
            likely to speed up its running time, specially when the
            modeled object occupies a small portion of the image.

        Returns
        -------
        images : `list` of :map:`Image` or subclass
            The list of images that will be fitted by the fitters.
        initial_shapes : `list` of :map:`PointCloud`
            The initial shape for each one of the previous images.
        gt_shapes : `list` of :map:`PointCloud`
            The ground truth shape for each one of the previous images.
        """
        # Attach landmarks to the image
        image.landmarks['initial_shape'] = initial_shape
        if gt_shape:
            image.landmarks['gt_shape'] = gt_shape

        # If specified, crop the image
        if crop_image:
            image = image.crop_to_landmarks_proportion(crop_image,
                                                       group='initial_shape')

        # Rescale image w.r.t the scale factor between reference_shape and
        # initial_shape
        image = image.rescale_to_reference_shape(self.reference_shape,
                                                 group='initial_shape')

        # Compute the holistic feature on the normalized image
        image = self._holistic_feature(image)

        # Obtain image representation
        images = []
        for s in self.scales:
            if s != 1:
                # scale image
                scaled_image = image.rescale(s)
            else:
                scaled_image = image
            images.append(scaled_image)

        # Get initial shapes per level
        initial_shapes = [i.landmarks['initial_shape'].lms for i in images]

        # Get ground truth shapes per level
        if gt_shape:
            gt_shapes = [i.landmarks['gt_shape'].lms for i in images]
        else:
            gt_shapes = None

        return images, initial_shapes, gt_shapes

    def _fitter_result(self, image, algorithm_results, affine_correction,
                       gt_shape=None):
        return MultiFitterResult(image, self, algorithm_results,
                                 affine_correction, gt_shape=gt_shape)

    def __str__(self):
        if self.diagonal is not None:
            diagonal = self.diagonal
        else:
            diagonal = np.sqrt(np.sum(np.asarray(self.reference_shape.bounds())
                                      ** 2))
        is_custom_perturb_func = (self._perturb_from_bounding_box !=
                                  noisy_shape_from_bounding_box)
        regressor_cls = self.algorithms[0]._regressor_cls

        # Compute level info strings
        level_info = []
        lvl_str_tmplt = r"""  - Level {} (Scale {})
   - {} iterations
   - Patch shape: {}"""
        for k, s in enumerate(self.scales):
            level_info.append(lvl_str_tmplt.format(k, s,
                                                   self.iterations[k],
                                                   self._patch_shape[k]))
        level_info = '\n'.join(level_info)

        cls_str = r"""Supervised Descent Method
 - Regression performed using the {reg_alg} algorithm
   - Regression class: {reg_cls}
 - Levels: {levels}
{level_info}
 - Perturbations generated per shape: {n_perturbations}
 - Images scaled to diagonal: {diagonal:.2f}
 - Custom perturbation scheme used: {is_custom_perturb_func}""".format(
            reg_alg=name_of_callable(self._sd_algorithm_cls),
                   reg_cls=name_of_callable(regressor_cls),
                   n_levels=len(self.scales),
                   levels=self.scales,
                   level_info=level_info,
                   n_perturbations=self.n_perturbations,
                   diagonal=diagonal,
                   is_custom_perturb_func=is_custom_perturb_func)
        return cls_str
<commit_msg>Calculate diagonal correctly.<commit_after>from __future__ import division
import numpy as np
from functools import partial
import warnings
from menpo.transform import Scale
from menpo.feature import no_op
from menpofit.visualize import print_progress
from menpofit.base import batch, name_of_callable
from menpofit.builder import (normalization_wrt_reference_shape, scale_images,
                              rescale_images_to_reference_shape)
from menpofit.fitter import (MultiFitter, noisy_shape_from_bounding_box,
                             align_shape_with_bounding_box)
from menpofit.result import MultiFitterResult
import menpofit.checks as checks
from .algorithm import Newton

# TODO: document me!
class SupervisedDescentFitter(MultiFitter):
    r"""
    """
    def __init__(self, sd_algorithm_cls=Newton, holistic_feature=no_op,
                 patch_features=no_op, patch_shape=(17, 17), diagonal=None,
                 scales=(1, 0.5), iterations=6, n_perturbations=30,
                 perturb_from_bounding_box=noisy_shape_from_bounding_box):
        # check parameters
        checks.check_diagonal(diagonal)
        scales, n_levels = checks.check_scales(scales)
        patch_features = checks.check_features(patch_features, n_levels)
        patch_shape = checks.check_patch_shape(patch_shape, n_levels)
        # set parameters
        self.algorithms = []
        self.reference_shape = None
        self._sd_algorithm_cls = sd_algorithm_cls
        self._holistic_feature = holistic_feature
        self._patch_features = patch_features
        self._patch_shape = patch_shape
        self.diagonal = diagonal
        self.scales = list(scales)[::-1]
        self.n_perturbations = n_perturbations
        self.iterations = checks.check_max_iters(iterations, n_levels)
        self._perturb_from_bounding_box = perturb_from_bounding_box
        # set up algorithms
        self._reset_algorithms()

    def _reset_algorithms(self):
        if len(self.algorithms) > 0:
            for j in range(len(self.algorithms) - 1, -1, -1):
                del self.algorithms[j]
        for j in range(self.n_levels):
            self.algorithms.append(self._sd_algorithm_cls(
                features=self._patch_features[j],
                patch_shape=self._patch_shape[j],
                iterations=self.iterations[j]))

    def perturb_from_bounding_box(self, bounding_box):
        return self._perturb_from_bounding_box(self.reference_shape,
                                               bounding_box)

    def train(self, images, group=None, label=None, bounding_box_group=None,
              verbose=False, increment=False, **kwargs):
        # In the case where group is None, we need to get the only key so that
        # we can add landmarks below and not get a complaint about using None
        first_image = images[0]
        if group is None:
            group = first_image.landmarks.group_labels[0]

        if not increment:
            # Reset the algorithm classes
            self._reset_algorithms()
            # Normalize images and compute reference shape
            self.reference_shape, images = normalization_wrt_reference_shape(
                images, group, label, self.diagonal, verbose=verbose)
        else:
            if len(self.algorithms) == 0:
                raise ValueError('Must train before training incrementally.')
            # We are incrementing, so rescale to existing reference shape
            images = rescale_images_to_reference_shape(images, group, label,
                                                       self.reference_shape,
                                                       verbose=verbose)

        # No bounding box is given, so we will use the ground truth box
        if bounding_box_group is None:
            bounding_box_group = '__gt_bb_'
            for i in images:
                gt_s = i.landmarks[group][label]
                perturb_bbox_group = bounding_box_group + '0'
                i.landmarks[perturb_bbox_group] = gt_s.bounding_box()

        # Find all bounding boxes on the images with the given bounding box key
        all_bb_keys = list(first_image.landmarks.keys_matching(
            '*{}*'.format(bounding_box_group)))
        n_perturbations = len(all_bb_keys)

        # If there is only one example bounding box, then we will generate
        # more perturbations based on the bounding box.
        if n_perturbations == 1:
            msg = '- Generating {} new initial bounding boxes ' \
                  'per image'.format(self.n_perturbations)
            wrap = partial(print_progress, prefix=msg, verbose=verbose)

            for i in wrap(images):
                # We assume that the first bounding box is a valid perturbation
                # thus create n_perturbations - 1 new bounding boxes
                for j in range(1, self.n_perturbations):
                    gt_s = i.landmarks[group][label].bounding_box()
                    bb = i.landmarks[all_bb_keys[0]].lms

                    # This is customizable by passing in the correct method
                    p_s = self._perturb_from_bounding_box(gt_s, bb)
                    perturb_bbox_group = bounding_box_group + '_{}'.format(j)
                    i.landmarks[perturb_bbox_group] = p_s
        elif n_perturbations != self.n_perturbations:
            warnings.warn('The original value of n_perturbation {} '
                          'will be reset to {} in order to agree with '
                          'the provided bounding_box_group.'.
                          format(self.n_perturbations, n_perturbations))
            self.n_perturbations = n_perturbations

        # Re-grab all the bounding box keys for iterating over when calculating
        # perturbations
        all_bb_keys = list(first_image.landmarks.keys_matching(
            '*{}*'.format(bounding_box_group)))

        # Before scaling, we compute the holistic feature on the whole image
        msg = '- Computing holistic features ({})'.format(
            name_of_callable(self._holistic_feature))
        wrap = partial(print_progress, prefix=msg, verbose=verbose)
        images = [self._holistic_feature(im) for im in wrap(images)]

        # for each pyramid level (low --> high)
        for j in range(self.n_levels):
            if verbose:
                if len(self.scales) > 1:
                    level_str = '  - Level {}: '.format(j)
                else:
                    level_str = '  - '
            else:
                level_str = None

            # Scale images
            level_images = scale_images(images, self.scales[j],
                                        level_str=level_str, verbose=verbose)

            # Extract scaled ground truth shapes for current level
            level_gt_shapes = [i.landmarks[group][label] for i in level_images]

            if j == 0:
                msg = '{}Generating {} perturbations per image'.format(
                    level_str, self.n_perturbations)
                wrap = partial(print_progress, prefix=msg,
                               end_with_newline=False, verbose=verbose)

                # Extract perturbations at the very bottom level
                current_shapes = []
                for i in wrap(level_images):
                    c_shapes = []
                    for perturb_bbox_group in all_bb_keys:
                        bbox = i.landmarks[perturb_bbox_group].lms
                        c_s = align_shape_with_bounding_box(
                            self.reference_shape, bbox)
                        c_shapes.append(c_s)
                    current_shapes.append(c_shapes)

            # train supervised descent algorithm
            if increment:
                current_shapes = self.algorithms[j].increment(
                    level_images, level_gt_shapes, current_shapes,
                    verbose=verbose, **kwargs)
            else:
                current_shapes = self.algorithms[j].train(
                    level_images, level_gt_shapes, current_shapes,
                    level_str=level_str, verbose=verbose, **kwargs)

            # Scale current shapes to next level resolution
            if self.scales[j] != (1 or self.scales[-1]):
                transform = Scale(self.scales[j + 1] / self.scales[j], n_dims=2)
                for image_shapes in current_shapes:
                    for shape in image_shapes:
                        transform.apply_inplace(shape)

    def increment(self, images, group=None, label=None,
                  bounding_box_group=None, verbose=False,
                  **kwargs):
        return self.train(images, group=group, label=label,
                          bounding_box_group=bounding_box_group,
                          verbose=verbose,
                          increment=True, **kwargs)

    def train_incrementally(self, images, group=None, label=None,
                            batch_size=100, verbose=False, **kwargs):
        # Create a generator of fixed sized batches. Will still work even
        # on an infinite list.
        image_batches = batch(images, batch_size)

        # Train all batches
        for k, image_batch in enumerate(image_batches):
            n_images = len(image_batch)
            if verbose:
                print('Training batch {} of {} images.'.format(k, n_images))
            if k == 0:
                self.train(image_batch, group=group, label=label,
                           verbose=verbose, **kwargs)
            else:
                self.increment(image_batch, group=group, label=label,
                               verbose=verbose, **kwargs)

    def _prepare_image(self, image, initial_shape, gt_shape=None,
                       crop_image=0.5):
        r"""
        Prepares the image to be fitted.

        The image is first rescaled wrt the ``reference_landmarks`` and then
        a gaussian pyramid is applied. Depending on the
        ``pyramid_on_features`` flag, the pyramid is either applied to the
        features image computed from the rescaled imaged or applied to the
        rescaled image and features extracted at each pyramidal level.

        Parameters
        ----------
        image : :map:`Image` or subclass
            The image to be fitted.
        initial_shape : :map:`PointCloud`
            The initial shape from which the fitting will start.
        gt_shape : :map:`PointCloud`, optional
            The original ground truth shape associated to the image.
        crop_image: `None` or float`, optional
            If `float`, it specifies the proportion of the border wrt the
            initial shape to which the image will be internally cropped around
            the initial shape range.
            If `None`, no cropping is performed.

            This will limit the fitting algorithm search region but is
            likely to speed up its running time, specially when the
            modeled object occupies a small portion of the image.

        Returns
        -------
        images : `list` of :map:`Image` or subclass
            The list of images that will be fitted by the fitters.
        initial_shapes : `list` of :map:`PointCloud`
            The initial shape for each one of the previous images.
        gt_shapes : `list` of :map:`PointCloud`
            The ground truth shape for each one of the previous images.
        """
        # Attach landmarks to the image
        image.landmarks['initial_shape'] = initial_shape
        if gt_shape:
            image.landmarks['gt_shape'] = gt_shape

        # If specified, crop the image
        if crop_image:
            image = image.crop_to_landmarks_proportion(crop_image,
                                                       group='initial_shape')

        # Rescale image w.r.t the scale factor between reference_shape and
        # initial_shape
        image = image.rescale_to_reference_shape(self.reference_shape,
                                                 group='initial_shape')

        # Compute the holistic feature on the normalized image
        image = self._holistic_feature(image)

        # Obtain image representation
        images = []
        for s in self.scales:
            if s != 1:
                # scale image
                scaled_image = image.rescale(s)
            else:
                scaled_image = image
            images.append(scaled_image)

        # Get initial shapes per level
        initial_shapes = [i.landmarks['initial_shape'].lms for i in images]

        # Get ground truth shapes per level
        if gt_shape:
            gt_shapes = [i.landmarks['gt_shape'].lms for i in images]
        else:
            gt_shapes = None

        return images, initial_shapes, gt_shapes

    def _fitter_result(self, image, algorithm_results, affine_correction,
                       gt_shape=None):
        return MultiFitterResult(image, self, algorithm_results,
                                 affine_correction, gt_shape=gt_shape)

    def __str__(self):
        if self.diagonal is not None:
            diagonal = self.diagonal
        else:
            y, x = self.reference_shape.range()
            diagonal = np.sqrt(x ** 2 + y ** 2)
        is_custom_perturb_func = (self._perturb_from_bounding_box !=
                                  noisy_shape_from_bounding_box)
        regressor_cls = self.algorithms[0]._regressor_cls

        # Compute level info strings
        level_info = []
        lvl_str_tmplt = r"""  - Level {} (Scale {})
   - {} iterations
   - Patch shape: {}"""
        for k, s in enumerate(self.scales):
            level_info.append(lvl_str_tmplt.format(k, s,
                                                   self.iterations[k],
                                                   self._patch_shape[k]))
        level_info = '\n'.join(level_info)

        cls_str = r"""Supervised Descent Method
 - Regression performed using the {reg_alg} algorithm
   - Regression class: {reg_cls}
 - Levels: {levels}
{level_info}
 - Perturbations generated per shape: {n_perturbations}
 - Images scaled to diagonal: {diagonal:.2f}
 - Custom perturbation scheme used: {is_custom_perturb_func}""".format(
            reg_alg=name_of_callable(self._sd_algorithm_cls),
            reg_cls=name_of_callable(regressor_cls),
            n_levels=len(self.scales),
            levels=self.scales,
            level_info=level_info,
            n_perturbations=self.n_perturbations,
            diagonal=diagonal,
            is_custom_perturb_func=is_custom_perturb_func)
        return cls_str
<|endoftext|>


<commit_before>#!/usr/bin/env python3
# vim:fileencoding=utf-8:ts=8:et:sw=4:sts=4:tw=79

"""
pearbot.py

The PearBot IRC bot entry point.
It sets up logging and starts up the IRC client.

Copyright (c) 2015 Twisted Pear <pear at twistedpear dot at>
See the file LICENSE for copying permission.
"""

import asyncio
import command
import config
import logging
import lrrfeed
import protocol
import signal

LOG_FORMAT = "{asctime} [{process}] {levelname}({name}): {message}"
logging.basicConfig(level=logging.INFO, format=LOG_FORMAT, style="{")

def main():
    logger = logging.getLogger("pearbot")
    logger.info("PearBot started.")

    loop = asyncio.get_event_loop()
    client_config = config.get_config("irc")
    client = protocol.Protocol(**client_config)

    feed_config = config.get_config("rss")
    feed = lrrfeed.LRRFeedParser(client, **feed_config)
    feed.start()

    cmdhdl_config = config.get_config("cmd")
    # we don't need to remember this instance
    command.CommandHandler(client, feed, **cmdhdl_config)

    def shutdown():
        logger.info("Shutdown signal received.")
        feed.stop()
        client.shutdown()
    loop.add_signal_handler(signal.SIGTERM, shutdown)

    logger.info("Running protocol activity.")
    task = client.run()
    loop.run_until_complete(task)
    logger.info("Protocol activity ceased.")
    logger.info("Exiting...")

if __name__ == "__main__":
    main()
<commit_msg>Add database connection<commit_after>#!/usr/bin/env python3
# vim:fileencoding=utf-8:ts=8:et:sw=4:sts=4:tw=79

"""
pearbot.py

The PearBot IRC bot entry point.
It sets up logging and starts up the IRC client.

Copyright (c) 2015 Twisted Pear <pear at twistedpear dot at>
See the file LICENSE for copying permission.
"""

import asyncio
import command
import config
import database
import logging
import lrrfeed
import protocol
import signal

LOG_FORMAT = "{asctime} [{process}] {levelname}({name}): {message}"
logging.basicConfig(level=logging.INFO, format=LOG_FORMAT, style="{")

def main():
    logger = logging.getLogger("pearbot")
    logger.info("PearBot started.")

    loop = asyncio.get_event_loop()
    client_config = config.get_config("irc")
    client = protocol.Protocol(**client_config)

    feed_config = config.get_config("rss")
    feed = lrrfeed.LRRFeedParser(client, **feed_config)
    feed.start()

    dbconn = loop.run_until_complete(database.create_connection())

    cmdhdl_config = config.get_config("cmd")
    # we don't need to remember this instance
    command.CommandHandler(client, feed, dbconn, **cmdhdl_config)

    def shutdown():
        logger.info("Shutdown signal received.")
        feed.stop()
        dbconn.close()
        client.shutdown()
    loop.add_signal_handler(signal.SIGTERM, shutdown)

    logger.info("Running protocol activity.")
    task = client.run()
    loop.run_until_complete(task)
    logger.info("Protocol activity ceased.")
    logger.info("Exiting...")

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