# -*- coding: utf-8 -*-
"""
Created on Thu Oct  4 10:16:53 2018

Catbot 2.0 uses discord.py version 1.x

@author: Mei Eisenbach
"""

import sys
import os
import re
import datetime as dt
import dotenv
import pickle
from discord import utils
from discord import Embed
from discord.ext import commands
from dateutil.parser import parse
from gyms import Gyms
from pokemon import Pokemon
from catbot_log import CatbotLog
from discord.ext.commands import CommandNotFound
import traceback

BOT_PREFIX = '!'
GYMFILE = 'gyms.csv'
POKEMONFILE = 'pokedex.csv'
PARAMSFILE = 'params.pickle'
HOST_LOGFILE = 'host.log'
ERROR_LOGFILE = 'error.log'
EGG_URL_BASE = 'https://ironcreek.net/catbot/eggs/'
EGG1 = 'egg1.png'
EGG3 = 'egg3.png'
EGG_LEGENDARY = 'legendary_egg.png'
EGG_MEGA = 'mega_egg.png'

gyms = None
pokemon = None
params = {}
params['legendaries'] = []

# =============================================================================
# String constants
# =============================================================================
MSG_HELP = "!whereis [gym] will return a location pin for the gym.\n\
Examples:\n\
    !whereis Irvington Community Park\n\
    !whereis icp\n\
    !whereis irvington\n\
will all return\n\
Irvington Community Park (ICP) is here http://maps.google.com/maps?q=37.522771,-121.963727"

REPORT_CHANNEL_NAME = 'raid_alerts_only'
LEGENDARY_ROLE_NAME = 'LegendaryRaid'

ERR_GYM_NOT_FOUND = '"{}" not found. Please check your spelling or use fewer words.'
ERR_TOO_MANY_RESULTS = 'Too many matches. Please be more specific.'
ERR_REPORT_MULTIPLE_MATCHES = 'More than one gym matches "{}"'

ERR_LEGENDARY_ROLE_MISSING = 'Legendary Raid role not found'

ERR_RAID_NOT_FOUND = 'Raid not found'
ERR_INVALID_DATETIME = "Invalid date or time"

# =============================================================================
# Helper and test functions
# =============================================================================

def generate_post(is_egg, identifier, mins, gym, reporter):
    time = dt.datetime.now() + dt.timedelta(minutes=int(mins))
    link = gyms.get_link(gym)
    gym_name = gyms.get_name(gym)
    if gyms.is_ex(gym):
        gym_name = gym_name + ' 🎫'
    if is_egg:
        content = "Level {} 🥚 at {}\n{}\nhatches at {} (in {} mins)\nreported by {}"\
            .format(identifier,
                    gym_name,
                    link,
                    time.strftime("%I:%M %p"),
                    mins,
                    reporter)
    else:
        content = "{} at {}\n{}\nuntil {} ({} mins remaining)\nreported by {}"\
            .format(identifier.title(),
                    gym_name,
                    link,
                    time.strftime("%I:%M %p"),
                    mins,
                    reporter)
    return content

def parse_args(arg_str):
    p = re.compile(r'^(.*) (at|in) (\S*) ?(\S*)? ?(\S*)?')
    m = p.match(arg_str)
    if m:
        return m.groups()
    return []

def format_do(gym, start, despawn, boss):
    link = gyms.get_link(gym)
    gym_name = gyms.get_name(gym)
    content = '-new "{}" {} {} {} {}'\
        .format(boss.title(),
                link,
                start.strftime("%I:%M%p"),
                despawn.strftime("%I:%M%p"),
                gym_name)
    return content

def process_do(arg_str):
    arguments = parse_args(arg_str)

    if len(arguments) == 0:
        return 'Usage: !do gym_name at/in start_time/min [despawn_time] [boss_name]'

    gym_name = arguments[0]

    # minutes given, calculate start time
    if arguments[1] == 'in':
        start = dt.datetime.now() + dt.timedelta(minutes=int(arguments[2]))
    else:
        try:
            start = parse(arguments[2])
        except:
            return 'Invalid start time. Valid formats: 00:00 or 0:00pm'

    # assign rest of arguments
    if arguments[3] == '':
        despawn = start + dt.timedelta(minutes=1)
        boss = "egg"
    elif arguments[4] == '':
        despawn = start + dt.timedelta(minutes=1)
        boss = arguments[3]
    else:
        try:
            despawn = parse(arguments[3])
        except:
            return 'Invalid despawn time. Valid formats: 00:00 or 0:00pm'
        boss = arguments[4]

    found = gyms.find(gym_name)
    if len(found) == 0:
        content = ERR_GYM_NOT_FOUND.format(gym_name)
    elif len(found) == 1:
        content = format_do(found[0], start, despawn, boss)
    else:
        content = ERR_REPORT_MULTIPLE_MATCHES.format(gym_name)

    return content

def parse_host_args(args: list):
    args = ' '.join(args)
    args = re.sub(r'[\[\](){}]', '', args)

    p = r'(.+) (hatch|end|start)\D*(\d+) ?(?:min)?(?:s|utes?)? ?(.*)'
    m = re.match(p, args, re.IGNORECASE)
    if m:
        return {'boss': m.groups()[0], 'verb': m.groups()[1],
                'mins': m.groups()[2], 'notes': m.groups()[3]}
    return {}

def parse_host_now(args: list):
    args = ' '.join(args)

    p = r'(.+) (start|hatch)\w* ?(now) ?(.*)'
    m = re.match(p, args, re.IGNORECASE)
    if m:
        return {'boss': m.groups()[0], 'verb': m.groups()[1],
                'mins': '0', 'notes': m.groups()[3]}
    return {}

def parse_host_mins_left(args: list):
    args = ' '.join(args)

    p = r'(.+) (\d+) ?(?:min)?(?:s|utes?)? ?(left) ?(.*)'
    m = re.match(p, args, re.IGNORECASE)
    if m:
        return {'boss': m.groups()[0], 'mins': m.groups()[1],
                'verb': 'end', 'notes': m.groups()[3]}

    return {}

def censor_notes(notes):
    friendcode_pat = re.compile(r'\d{4}[-\s]*\d{4}[-\s]*\d{4}')
    notes = friendcode_pat.sub('<Friend code removed>', notes)

    dm_me_pat = re.compile(r'[dp]\W*m(\s+|$)(me)?', re.IGNORECASE)
    notes = dm_me_pat.sub('...', notes)

    dm_me_pat2 = re.compile(r'(direct\s*)?me?ss?a?ge?(\s*|$)(me)?',
                            re.IGNORECASE)
    notes = dm_me_pat2.sub('...', notes)

    dm_me_pat3 = re.compile(r'te?xt me', re.IGNORECASE)
    notes = dm_me_pat3.sub('...', notes)

    return notes

def get_egg_url(level):
    if level <= 2:
        thumbnail = 'egg1.png'
    elif level <= 4:
        thumbnail = 'egg3.png'
    elif level == 5:
        thumbnail = 'legendary_egg.png'
    else:
        thumbnail = 'mega_egg.png'
    return EGG_URL_BASE+thumbnail

def save_params(paramsfile, params):
    with open(paramsfile, 'wb') as f:
        pickle.dump(params, f)

def load_params(paramsfile):
    with open(paramsfile, 'rb') as f:
        params = pickle.load(f)
    return params

# =============================================================================
# Test functions
# =============================================================================
def test_whereis(name):
    found = gyms.find(name)
    num_found = len(found)

    if num_found == 0:
        content = ERR_GYM_NOT_FOUND.format(name)
    elif num_found <= 3:
        locations = []
        for gym in found:
            link = gyms.get_link(gym)
            locations.append(gyms.get_name(gym) + " is here " + link)
        content = '\n'.join(locations)
    print(content)

def test_do():
    # absolute start time
    assert process_do('Rings Arch at 8:30pm 9:15pm Kyurem') ==\
        '-new "Kyurem" http://maps.google.com/maps?q=37.584377,-122.068447 08:30PM 09:15PM Rings Arch'
    assert process_do('Rings Arch at 20:30 Kyurem') ==\
        '-new "Kyurem" http://maps.google.com/maps?q=37.584377,-122.068447 08:30PM 08:31PM Rings Arch'
    assert process_do('Rings Arch at 8:30pm') ==\
        '-new "Egg" http://maps.google.com/maps?q=37.584377,-122.068447 08:30PM 08:31PM Rings Arch'

    # errors
    assert process_do('Rings Arch 8:30pm 9:15pm Kyurem') ==\
        'Usage: !do gym_name at/in start_time/min [despawn_time] [boss_name]'
    assert process_do('Ring Arch at 8:30pm 9:15pm Kyurem') ==\
        '"Ring Arch" not found. Please check your spelling or use fewer words.'
    assert process_do('Rings Arch at 20:30pm 9:15pm Kyurem') ==\
        'Invalid start time. Valid formats: 00:00 or 0:00pm'
    assert process_do('Rings Arch at 8:30pm 21:15pm Kyurem') ==\
        'Invalid despawn time. Valid formats: 00:00 or 0:00pm'
    print('All asserts passed.')

    # relative start time
    print('Check output from relative times...')
    print(process_do('Rings Arch in 30 9:15pm Kyurem'))
    print(process_do('Rings Arch in 30 Kyurem'))
    print(process_do('Rings Arch in 30'))

# =============================================================================
# Bot code
# =============================================================================
bot = commands.Bot(command_prefix=BOT_PREFIX)

@bot.event
async def on_ready():
    print('We have logged in as {0.user}'.format(bot))
    print('Bot Prefix: ', BOT_PREFIX)

@bot.event
async def on_message(message):
    content = ''
    if bot.user.mentioned_in(message) and message.mention_everyone is False:
        message_lowered = message.content.lower()
        if 'hello' in message_lowered or 'hi' in message_lowered:
            content = 'Hello, {}'.format(message.author.mention)
        elif 'thanks' in message_lowered:
            content = "{} You're welcome".format(message.author.mention)
        elif 'coming' in message_lowered or 'going' in message_lowered:
            content = "{} Sorry, I'm a bot and stuck in this server room."\
                .format(message.author.mention)
        await message.channel.send(content)

    await bot.process_commands(message)

@bot.event
async def on_command_error(ctx, exception):
    if isinstance(exception, CommandNotFound):
        log = open(ERROR_LOGFILE, 'a')
        log.write('{}, {}\n'.format(exception, ctx.guild))
        log.close()
        return

    print('Ignoring exception in command {}:'.format(ctx.command),
          file=sys.stderr)
    traceback.print_exception(type(exception), exception,
                              exception.__traceback__, file=sys.stderr)

@bot.command()
async def whereis(ctx, *args):
    name = ' '.join(args)

    found = gyms.find(name)
    num_found = len(found)

    if num_found == 0:
        content = ERR_GYM_NOT_FOUND.format(name)
    elif num_found <= 3:
        locations = []
        for gym in found:
            link = gyms.get_link(gym)
            locations.append(gyms.get_name(gym) + " is here " + link)
        content = '\n'.join(locations)
    else:
        content = ERR_TOO_MANY_RESULTS

    await ctx.send(content)

def parse_egg(args: list):
    args = ' '.join(args)
    args = re.sub(r'[\[\](){}]', '', args)

    p = r't?([1-6]) hatches in (\d+) at (.*)'
    m = re.match(p, args, re.IGNORECASE)
    if m:
        return {'egg': m.groups()[0], 'mins': m.groups()[1],
                'gym': m.groups()[2]}
    return {}

def parse_egg_old(args: list):
    args = ' '.join(args)
    p = r'([1-6]) (\d+) (.*)'
    m = re.match(p, args, re.IGNORECASE)
    if m:
        return {'egg': m.groups()[0], 'mins': m.groups()[1],
                'gym': m.groups()[2]}
    return {}

@bot.command()
async def egg(ctx, *args):
    if ctx.guild is None:
        await ctx.send('This command can only be used on a server.')
        return

    report_channel = utils.get(ctx.guild.channels, name=REPORT_CHANNEL_NAME)
    if report_channel is None:
        await ctx.send(REPORT_CHANNEL_NAME + ' channel not found')
        return

    parsed = parse_egg(args)
    if not parsed:
        parsed = parse_egg_old(args)

    if not parsed:
        CatbotLog.write('Parse Error', 'egg_new ' + ' '.join(args), ctx.guild)
        content = 'Usage: !egg [1-6] hatches in [mins] at [gym] \nExample: !egg 5 hatches in 10 at ICP'
        await ctx.send(content)
        return

    thumbnail = get_thumbnail(parsed['egg'])

    found = gyms.find(parsed['gym'])
    if len(found) == 0:
        CatbotLog.write('Gym Error', 'egg_new ' + ' '.join(args), ctx.guild)
        await ctx.send(ERR_GYM_NOT_FOUND.format(parsed['gym']))
        return
    elif len(found) == 1:
        time = dt.datetime.now() + dt.timedelta(minutes=int(parsed['mins']))
        when = 'hatches at {} (in {} mins)'.format(time.strftime("%I:%M %p"),
                                                   parsed['mins'])
        if parsed['egg'] == '6':
            title = 'Tier 6 - Mega Raid'
        else:
            title = 'Tier '+parsed['egg']
        embed = create_egg_raid_embed(title, ctx.author.mention,
                                      when, found[0], thumbnail)

        msg = await report_channel.send(embed=embed)
        await msg.add_reaction('👍')
        await ctx.send('Egg reported to ' + report_channel.mention)
    else:
        await ctx.send(ERR_REPORT_MULTIPLE_MATCHES.format(parsed['gym']))

@bot.command()
async def egg_old(ctx, egg_level, until_hatch, *args):
    report_channel = utils.get(ctx.guild.channels, name=REPORT_CHANNEL_NAME)
    if report_channel is None:
        print(REPORT_CHANNEL_NAME + ' channel not found')
        return

    legendary_role = utils.get(ctx.guild.roles, name=LEGENDARY_ROLE_NAME)
    if legendary_role is None:
        await ctx.send(ERR_LEGENDARY_ROLE_MISSING)
        return

    mega_role = utils.get(ctx.guild.roles, name='MegaRaid')

    if not egg_level.isnumeric():
        await ctx.send('"{}" is not a number. Egg levels should be 1-6'.format(egg_level))
        return
    if int(egg_level) < 1 or int(egg_level) > 6:
        await ctx.send('"{}" is not valid. Egg levels should be 1-6'.format(egg_level))
        return

    if not until_hatch.isnumeric():
        await ctx.send('"{}" is not a number. Minutes until hatch should be a number'.format(until_hatch))
        return

    gym = ' '.join(args)
    found = gyms.find(gym)
    if len(found) == 0:
        await ctx.send(ERR_GYM_NOT_FOUND.format(gym))
    elif len(found) == 1:
        reporter = ctx.message.author.mention
        content = generate_post(
            True, egg_level, until_hatch, found[0], reporter)

        if egg_level == '5':
            content = '{} {}'.format(legendary_role.mention, content)

        if egg_level == '6' and mega_role is not None:
            content = '{} {}'.format(mega_role.mention, content)

        await report_channel.send(content)
        await ctx.send('Egg reported to ' + report_channel.mention)
    else:
        await ctx.send(ERR_REPORT_MULTIPLE_MATCHES.format(gym))

def parse_raid(args: list):
    args = ' '.join(args)
    args = re.sub(r'[\[\](){}]', '', args)

    p = r'([\w\s]+) (ends|despawns) in (\d+) at (.*)'
    m = re.match(p, args, re.IGNORECASE)
    if m:
        return {'boss': m.groups()[0], 'mins': m.groups()[2],
                'gym': m.groups()[3]}
    return {}

def parse_raid_old(args: list):
    args = ' '.join(args)
    p = r'(.*) (\d+) (.*)'
    m = re.match(p, args, re.IGNORECASE)
    if m:
        return {'boss': m.groups()[0], 'mins': m.groups()[1],
                'gym': m.groups()[2]}
    return {}

def create_egg_raid_embed(title, reporter, when, gym, thumbnail=''):
    embed = Embed(title=title.title(),
                  description='React with thumbs up if interested')
    embed.add_field(name="Where", value=gyms.get_name(gym))
    embed.add_field(name="When",
                    value=when)
    embed.add_field(name="Reported by", value=reporter)
    embed.add_field(name="Location", value=gyms.get_link(gym))

    if thumbnail != '':
        embed.set_thumbnail(url=thumbnail)

    return embed

@bot.command()
async def raid(ctx, *args):
    if ctx.guild is None:
        await ctx.send('This command can only be used on a server.')
        return

    report_channel = utils.get(ctx.guild.channels, name=REPORT_CHANNEL_NAME)
    if report_channel is None:
        await ctx.send(REPORT_CHANNEL_NAME + ' channel not found')
        return

    parsed = parse_raid(args)
    if not parsed:
        parsed = parse_raid_old(args)

    if not parsed:
        CatbotLog.write('Parse Error', 'raid_new ' + ' '.join(args), ctx.guild)
        content = 'Usage: !raid [boss] ends|despawns in [mins] at [gym] \nExample: !raid Regirock ends in 30 at ICP'
        await ctx.send(content)
        return

    found = pokemon.find(parsed["boss"])
    if found != '' and found != parsed["boss"].lower():
        parsed["boss"] = found

    thumbnail = get_thumbnail(parsed['boss'])

    found = gyms.find(parsed['gym'])
    if len(found) == 0:
        CatbotLog.write('Gym Error', 'raid_new ' + ' '.join(args), ctx.guild)
        await ctx.send(ERR_GYM_NOT_FOUND.format(parsed['gym']))
        return
    elif len(found) == 1:
        time = dt.datetime.now() + dt.timedelta(minutes=int(parsed['mins']))
        when = 'despawns at {} (in {} mins)'.format(time.strftime("%I:%M %p"),
                                           parsed['mins'])
        embed = create_egg_raid_embed(parsed['boss'], ctx.author.mention,
                                      when, found[0], thumbnail)

        msg = await report_channel.send(embed=embed)
        await msg.add_reaction('👍')
        await ctx.send('Raid reported to ' + report_channel.mention)
    else:
        await ctx.send(ERR_REPORT_MULTIPLE_MATCHES.format(parsed['gym']))

@bot.command()
async def raid_old(ctx, boss, time_left, *args):
    mention = ['shinx']
    report_channel = utils.get(ctx.guild.channels, name=REPORT_CHANNEL_NAME)
    if report_channel is None:
        await ctx.send(REPORT_CHANNEL_NAME + ' channel not found')
        return

    legendary_role = utils.get(ctx.guild.roles, name=LEGENDARY_ROLE_NAME)
    if legendary_role is None:
        await ctx.send(ERR_LEGENDARY_ROLE_MISSING)
        return

    if boss.isnumeric():
        await ctx.send('"{}" is not a raid boss.'.format(boss))
        return

    if not time_left.isnumeric():
        await ctx.send('"{}" is not a number. \
                       Minutes remaining should be a number'.format(time_left))
        return

    if boss.lower() in mention:
        boss_role = utils.get(ctx.guild.roles, name=boss)
        if boss_role is not None:
            boss = boss_role

    gym = ' '.join(args)
    found = gyms.find(gym)
    if len(found) == 0:
        await ctx.send(ERR_GYM_NOT_FOUND.format(gym))
    elif len(found) == 1:
        reporter = ctx.message.author.mention
        content = generate_post(False, boss, time_left, found[0], reporter)

        if is_legendary(boss):
            content = '{} {}'.format(legendary_role.mention, content)

        await report_channel.send(content)
        await ctx.send('Raid reported to ' + report_channel.mention)
    else:
        await ctx.send(ERR_REPORT_MULTIPLE_MATCHES.format(gym))

@bot.command()
@commands.has_any_role('Developer', 'Admin', 'mod')
async def set_legendaries(ctx, *args):
    if len(args) == 0:
        await ctx.send('Usage: !set_legendaries leg1 leg2 ...')
        return

    params['legendaries'] = list(map(str.lower, args))
    await ctx.message.add_reaction('👍')
    save_params(PARAMSFILE, params)

@bot.command()
@commands.has_any_role('Developer', 'Admin', 'mod')
async def get_legendaries(ctx):
    legendaries = params.get('legendaries', [])
    msg = ', '.join([el.title() for el in legendaries])
    if msg == '':
        msg = 'No legendaries set.'
    await ctx.send(msg)

@bot.command()
@commands.has_any_role('Developer')
async def reload_gyms(ctx):
    gyms.read_csv(GYMFILE)
    await ctx.message.add_reaction('👍')

@bot.command()
@commands.has_any_role('Developer')
async def reload_pokemon(ctx):
    pokemon.read_csv(POKEMONFILE)
    await ctx.message.add_reaction('👍')

@bot.command(pass_context=True)
async def get_invite(ctx):
    if ctx.message.guild is None:
        msg = 'Please use this command from a server channel.'
        await ctx.message.author.send(msg)
        return

    if ctx.message.guild.name == "(Official) Pokémon GO: Fremont":
        link = await ctx.channel.create_invite(
            max_age=3600*24, max_use=1, unique=True)
        if link is not None:
            await ctx.message.author.send(
                'Here is your invite {}'.format(link))
            await ctx.send('Invite sent via dm')
        else:
            await ctx.send('Unable to create invite')
    else:
        await ctx.send('Sorry, this command is not allowed on this server.')

# Eventually add: 'Pin', 'UC Agent', 'FMT Agent', 'SF Agent', 'HWD Agent'
@commands.has_any_role('Developer', 'TR Scientist')
@bot.command()
async def do(ctx, *args):
    message = process_do(' '.join(args))
    await ctx.send(message)

@commands.has_any_role('TR Scientist', 'Admin', 'mod')
@bot.command()
async def purge_fc(ctx, limit=None):
    def check_msg(msg):
        if msg.pinned:
            return False
        if msg.id == ctx.message.id:
            return True
        if re.search(r'(^|\D)\d{4}[-\s]*\d{4}[-\s]*\d{4}($|\D)', msg.content)\
                is None:
            return False
        return True

    # limit is the number of messages to search through
    if limit is not None:
        limit = int(limit)
    deleted = await ctx.channel.purge(limit=limit, check=check_msg)

    # debug
    for msg in deleted:
        print(msg.content)

    await ctx.send('Deleted {} message(s)'.format(len(deleted)-1),
                   delete_after=5)

def get_reporting_channels(ctx):
    channel_names = {'mega': 'active-mega-raids',
                     'legendary': 'active-t5-raids',
                     'other': 'active-t1-t3-raids'}

    reporting_channels = {}

    if ctx.guild is not None:
        for key, name in channel_names.items():
            reporting_channels[key] = utils.get(ctx.guild.channels, name=name)

    return reporting_channels

def is_mega(boss):
    if re.search(r'mega(\s|$)', boss, re.IGNORECASE) is None:
        return False
    return True

def is_legendary(boss):
    if 'legendaries' in params and boss.lower() in params['legendaries']:
        return True
    return False

def get_thumbnail(boss):
    thumbnail = ''

    m = re.match('t?([123456])', boss, re.IGNORECASE)
    if m is not None:
        thumbnail = get_egg_url(int(m.groups()[0]))
        return thumbnail

    thumbnail = pokemon.get_boss_url(boss)
    if thumbnail != '':
        return thumbnail

    if is_mega(boss):
        thumbnail = EGG_URL_BASE + EGG_MEGA

    return thumbnail

def create_embed(title, host, when, notes='', thumbnail=''):
    embed = Embed(title=title.title(),
                  description='React with team emoji for invite')
    embed.add_field(name="Host", value=host)
    embed.add_field(name="When", value=when)

    if notes != '':
        embed.add_field(name="Notes", value=notes)

    if thumbnail != '':
        embed.set_thumbnail(url=thumbnail)

    return embed

def get_raid_tier(boss):
    if is_mega(boss):
        return 'mega'

    if is_legendary(boss) or\
            re.match('t5', boss, re.IGNORECASE) is not None:
        return 'legendary'

    return 'other'

@bot.command(aliases=["Host"])
async def host(ctx, *args):
    if ctx.guild is None:
        CatbotLog.write('Error', 'Host command sent via DM')
        await ctx.send('This command can only be used on a server.')
        return

    if ctx.channel.name != '💥-hosting-commands':
        await ctx.send('This command can only be used from #💥-hosting-commands.')
        return

    reporting_channels = get_reporting_channels(ctx)

    for key, channel in reporting_channels.items():
        if channel is None:
            await ctx.send('Reporting channels not found')
            return

    parsed = parse_host_now(args)
    if not parsed:
        parsed = parse_host_args(args)
    if not parsed:
        parsed = parse_host_mins_left(args)

    if not parsed:
        content = \
        'Usage: !host [T1-5 or boss] [hatches|starts|ends] in mins (optional notes)\nExample: !host heatran ends in 30 mins'
        await ctx.send(content)

        CatbotLog.write('Parse Error', 'host ' + ' '.join(args), ctx.guild)
        return

    when = '{}ing in {} mins'.format(parsed["verb"], parsed["mins"])

    if parsed["notes"] != '':
        parsed["notes"] = censor_notes(parsed["notes"])

    found = pokemon.find(parsed["boss"])
    if found != '' and found != parsed["boss"].lower():
        CatbotLog.write('Correction', '{} to {}'.format(parsed["boss"], found),
                        ctx.guild)
        parsed["boss"] = found

    thumbnail = get_thumbnail(parsed['boss'])

    embed = create_embed(parsed['boss'], ctx.author, when, parsed['notes'],
                         thumbnail)

    tier = get_raid_tier(parsed['boss'])

    msg = await reporting_channels[tier].send(embed=embed,
                                              delete_after=2*60*60)

    CatbotLog.write('Success', 'host ' + ' '.join(args), ctx.guild)

    for team_logo in ['instinctlogo', 'mysticlogo', 'valorlogo']:
        emoji = utils.get(ctx.guild.emojis, name=team_logo)
        if emoji is not None:
            await msg.add_reaction(emoji)

    await ctx.send('Raid reported to ' + reporting_channels[tier].mention,
                   delete_after=5)

    await ctx.message.delete()

def is_n_minutes_old(timestamp, minutes):
    return (dt.datetime.utcnow() - timestamp) > dt.timedelta(minutes=minutes)

@commands.has_any_role('TR Scientist', 'Admin', 'mod', 'Mod')
@bot.command(aliases=["purge_old"])
async def purge_old_messages(ctx, age_in_minutes=2*60):
    deleted = await ctx.channel.purge(limit=100,
                                      check=lambda m: is_n_minutes_old(m.created_at,
                                                                       age_in_minutes)
                                      and not m.pinned)
    await ctx.send('Deleted {} message(s)'.format(len(deleted)),
                   delete_after=10)
    await ctx.message.delete()

@commands.has_any_role('TR Scientist', 'Developer')
@bot.command()
async def shutdown(ctx):
    await bot.logout()

# =============================================================================
# Main
# =============================================================================

try:
    gyms = Gyms(GYMFILE)
    print('Gyms loaded')
except IOError:
    print('ERROR: Unable to load gyms from', GYMFILE)
    sys.exit()

try:
    pokemon = Pokemon(POKEMONFILE)
    print('Pokemon loaded')
except IOError:
    print('ERROR: Unable to load pokemon from', GYMFILE)
    sys.exit()

try:
    params = load_params(PARAMSFILE)
    print('Parameters loaded')
    if 'legendaries' not in params:
        print('WARNING: Legendaries not set')
except IOError:
    pass

CatbotLog.init(HOST_LOGFILE)

if __name__ == "__main__":
    dotenv.load_dotenv()
    key = os.getenv('DISCORD_TOKEN')
    if key is None:
        print('ERROR: Discord Key not found in the environment variables')
        sys.exit()
    bot.run(key)


"""Compute genre-weighted typicality as described by Askin and Mauskapf"""

import numpy as np
import pandas as pd
from scipy.spatial.distance import cosine
import string
import ast
import copy
import math
import string

fpath='data/genre_set.tsv'
df=pd.read_csv(fpath,sep='\t',encoding='utf8')

# Convert the release dates to datetime objects
df.release=pd.to_datetime(df.release)
dates=df.release.unique()

# Discogs genre
mat=df.discog_genre.as_matrix()
mat=[ast.literal_eval(x) for x in mat]
genres=['Blues', "Children's", 'Classical', 'Electronic','Folk, World, & Country', 'Funk / Soul', 'Hip Hop', 'Jazz',
'Latin', 'Non-Music', 'Pop', 'Reggae', 'Rock','Stage & Screen']

# Temporal genre data frame
df_tg=pd.DataFrame(columns=genres+['weight'])
missing=[]

def format_echo(tempo,time_signature):
	"""Simple method to normalize tempo and time signature"""
	return (tempo/max(tempo)).as_matrix(), ((time_signature==4)).as_matrix()

df.tempo,df.time_signature=format_echo(df.tempo,df.time_signature)

def key_match(a,b):
	"""Check for key match"""
	return sum([x==y for x in a for y in b])/float(len(a)*len(b))

# Iterate through dates and get the average distance between songs from genres over time
for d in dates:
	gv=[]
	# Iterate through genres
	for g in genres:
		# Find the mean values for tracks with release up to 1 year before date and with a specific genre
		record=df.loc[(df.release<=d) & (df.release>=d-np.timedelta64(52,'W'))&(df.discog_genre.str.contains(g)),['acousticness',
			'danceability','energy','instrumentalness','liveness','speechiness','tempo','valence','mode']].copy()
		if len(record)==0:
			missing.append((d,g))
			#print('No records found for genre '+g+' at date '+str(d))
			continue
		#key=record['key'].tolist()
		record=record.mean()
		gv.append([record,g])

	# Calculate the weight between genres
	for i in range(len(gv)):
		for j in range(i+1,len(gv)):
			genre_1=copy.copy(gv[i])
			genre_2=copy.copy(gv[j])

			#genre_1[0].key=1
			#genre_2[0].key=key_match(genre_1[1],genre_2[1])

			# Cosine similarity
			weight=1-cosine(genre_1[0],genre_2[0])

			# Store weights in DataFrame
			row=np.zeros(len(genres))
			row[genres.index(genre_1[1])]=1
			row[genres.index(genre_2[1])]=1
			row=row.tolist()+[weight]
			row=pd.DataFrame([row],columns=df_tg.columns)
			row=row.xs(0)
			row.name=d
			df_tg=df_tg.append(row)
	print("progress: "+str(np.where(dates==d)[0][0]/float(len(dates))))

def avg_typ(track_1,track_r,weights,genres):
	"""Find genre-weighted average typicality

		Parameters
		----------
		track_1 : Pandas DataFrame element
		Track of interest
		track_r : Pandas DataFrame
		Related tracks that were active one year from the track's release
		weights : Pandas DataFrame
		Genre weights at the release date
		genres : List
		Genres used
	"""
	# Song record that can be manipulated
	og_track_1=track_1.copy()

	# Aggregate typicality
	agr_typ=0

	# Iterate through comparison tracks
	for x in track_r.iterrows():
		track_1=og_track_1.copy()
		track_2=x[1].copy()

		# Matching genres, no need to change weight
		if track_1.discog_genre==track_2.discog_genre:
			weight=1
		# Different genres, find average distance between genres
		else:
			wm=[]
			genre_1=[x for x in genres if x in track_1.discog_genre]
			genre_2=[x for x in genres if x in track_2.discog_genre]

			for g1 in genre_1:
				for g2 in genre_2:
					if g1==g2:
						wm.append(1)
					else:
						wm.append(weights[(weights[g1]==1)&(weights[g2]==1)]['weight'].values[0])
			# Normalize weight
			weight=sum(wm)/len(genre_1)/len(genre_2)

		# track_1.key=1
		# track_2.key=key_match([track_1.key],[track_2.key])

		agr_typ+=weight*(1-cosine(track_1[:-1].astype(float),track_2[:-1].astype(float)))

	# Normalize aggregate similarity
	return agr_typ/len(track_r)

# Iterate through files alphabetically
file_list=['number']+list(string.ascii_uppercase)

# Typicality
df['typ']=0

# Missing records
missing_typ=[]

for fname in file_list:
	if fname=='number':
		numbers=[False if x in string.ascii_uppercase else True for x in df.artist.str[0]]
		df_sub=df.copy()[numbers]
	else:
		df_sub=df.copy()[df.artist.str[0]==fname]

	for x in df_sub.iterrows():
		artist=x[1].artist
		title=x[1].title
		release=x[1].release

		# Song record
		track_1=x[1][['acousticness','danceability','energy','instrumentalness','liveness','speechiness',
			'tempo','valence','mode','discog_genre']]

		# Songs released in the previous 52 weeks
		track_r=df.loc[(df.release<=release) & (df.release>=release-np.timedelta64(52,'W')),['acousticness','danceability','energy',
			'instrumentalness','liveness','speechiness','tempo','valence','mode','discog_genre']].drop(x[0])

		# Genre weights from past 52 weeks
		weights=df_tg.loc[df_tg.index==release]

		try:
			typ_score=avg_typ(track_1,track_r,weights,genres)
		except:
			print("No artists released in the previous year for track "+title+" by artist "+artist)
			missing_typ.append((artist,title))
			df_sub.drop(x[0],inplace=True)

		df_sub.loc[(df_sub.title == title) & (df_sub.artist == artist),'typ']=typ_score
	df_sub.to_csv('data/typ/'+fname+'.tsv',sep='\t',index=False,encoding='utf8')
	print(fname)

# Write missing records to file
with open('data/typ/missing.tsv','wb') as f:
	f.write('date\tgenre\n')
	for x in missing:
		date=str(x[0]).encode('utf8')
		genre=x[1].encode('utf8')
		f.write(date+'\t'+genre+'\n')


Import("env")
import os
import shutil

build_profile = env.subst("$PIOENV")

def post_program_action(source, target, env):
    build_dir = env.subst("$BUILD_DIR")
    progname = env.get("PROGNAME")

    if not os.path.exists("build"):
        # Create a new directory because it does not exist
        os.makedirs("build")

    # Removes all files from the build.
    for filename in os.listdir("build"):
        file_path = os.path.join("build", filename)
        if os.path.isfile(file_path):
            os.remove(file_path)

    # Copies all files from the assets directory to the build directory.
    for filename in os.listdir("assets"):
        source_path = os.path.join("assets", filename)
        destination_path = os.path.join("build", filename)
        if os.path.isfile(source_path):
            shutil.copy2(source_path, destination_path)

    # Copy build to build directory
    if build_profile == "custom-bootloader":
        source_path = os.path.join(build_dir, f"{progname}.bin")
        destination_path = os.path.join("build", f"{progname}.PP2")
        shutil.copy2(source_path, destination_path)
    else:
        source_path = os.path.join(build_dir, f"{progname}.uf2")
        destination_path = os.path.join("build", f"{progname}.uf2")
        shutil.copy2(source_path, destination_path)

env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", post_program_action)


import copy
import logging
import numpy as np
from tqdm import tqdm
import torch
import nni
from nni.utils import merge_parameter
import dgl

from graphmae.utils import (
    build_args,
    create_optimizer,
    set_random_seed,
    TBLogger,
    get_current_lr,
    load_best_configs
)
from graphmae.datasets.data_util import load_dataset
from graphmae.evaluation import node_classification_evaluation, link_prediction_for_transductive, \
    clustering_for_transductive, compute_auc, DotPredictor
from graphmae.models import build_model

logging.basicConfig(format="%(asctime)s - %(levelname)s - %(message)s", level=logging.INFO)

def pretrain(model, decoder, graph, x, optimizer, max_epoch, device, scheduler, logger=None, mute=False):
    logging.info("start training..")

    decoder.to(device)
    criterion = torch.nn.BCEWithLogitsLoss()
    graph = graph.to(device)
    x = x.to(device)

    num_nodes = graph.number_of_nodes()
    u, v = graph.edges()
    num_edges = graph.number_of_edges()
    eids = torch.randperm(num_edges).to(device)
    test_size = int(eids.shape[0] * 0.1)
    test_pos_u, test_pos_v = u[eids[:test_size]], v[eids[:test_size]]
    train_pos_u, train_pos_v = u[eids], v[eids]

    num_samples = num_edges
    neg_u, neg_v = dgl.sampling.global_uniform_negative_sampling(graph, num_samples, exclude_self_loops=True)
    neg_eids = torch.randperm(num_edges)
    test_neg_u, test_neg_v = neg_u[neg_eids[:test_size]], neg_v[neg_eids[:test_size]]
    train_neg_u, train_neg_v = neg_u[neg_eids], neg_v[neg_eids]

    # train_g = dgl.remove_edges(graph, eids[:test_size])
    train_g = graph
    # train_g = dgl.add_self_loop(train_g)
    # test_g = graph.edge_subgraph(eids[:test_size])
    train_pos_g = dgl.graph((train_pos_u, train_pos_v), num_nodes=num_nodes)
    train_neg_g = dgl.graph((train_neg_u, train_neg_v), num_nodes=num_nodes)
    test_pos_g = dgl.graph((test_pos_u, test_pos_v), num_nodes=num_nodes)
    test_neg_g = dgl.graph((test_neg_u, test_neg_v), num_nodes=num_nodes)

    best_test_auc = 0
    best_epoch = 0
    best_model = None

    epoch_iter = tqdm(range(max_epoch))
    for epoch in epoch_iter:
        model.train()
        loss, loss_dict = model(graph, x)
        out = model.embed(train_g, train_g.ndata["feat"])
        pos_score = decoder(train_pos_g, out)
        neg_score = decoder(train_neg_g, out)
        loss_lp = criterion(pos_score, neg_score)
        loss = loss + loss_lp
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        if scheduler is not None:
            scheduler.step()

        epoch_iter.set_description(f"# Epoch {epoch}: train_loss: {loss.item():.4f}")
        if logger is not None:
            loss_dict["lr"] = get_current_lr(optimizer)
            logger.note(loss_dict, step=epoch)

        if (epoch + 1) % 100 == 0:
            with torch.no_grad():
                model.eval()
                out = model.embed(train_g, train_g.ndata["feat"])
                pos_score_test = decoder(test_pos_g, out)
                neg_score_test = decoder(test_neg_g, out)
                test_auc = compute_auc(pos_score_test, neg_score_test)
                # test_auc = compute_ap(pos_score_test, neg_score_test)
                pos_score_train = decoder(train_pos_g, out)
                neg_score_train = decoder(train_neg_g, out)
                train_auc = compute_auc(pos_score_train, neg_score_train)
                # train_auc = compute_ap(pos_score_train, neg_score_train)
                test_loss = criterion(pos_score_test, neg_score_test)
            if test_auc >= best_test_auc:
                best_test_auc = test_auc
                # print('best', best_test_auc)
                best_epoch = epoch
                # print(best_epoch)
                best_model = copy.deepcopy(decoder)

            if not mute:
                epoch_iter.set_description(
                    f"# Epoch: {epoch}, train_loss:{loss.item(): .4f}, train_auc:{train_auc: .4f}, "
                    f"test_loss:{test_loss.item(): .4f}, test_auc:{test_auc: .4f}")

            best_model.eval()
            with torch.no_grad():
                pos_score = best_model(test_pos_g, out)
                neg_score = best_model(test_neg_g, out)
                estp_test_auc = compute_auc(pos_score, neg_score)
                # estp_test_auc = compute_ap(pos_score, neg_score)
            if mute:
                print(
                    f"# IGNORE: --- TestAUC: {test_auc:.4f}, early-stopping-TestAUC: {estp_test_auc:.4f} in epoch {best_epoch} --- ")
            else:
                print(
                    f"--- TestAUC: {test_auc:.4f}, early-stopping-TestAUC: {estp_test_auc:.4f} in epoch {best_epoch} --- ")

    # (final_acc, es_acc, best_acc)
    return test_auc, estp_test_auc

def main(args):
    device = args.device if args.device >= 0 else "cpu"
    seeds = args.seeds
    dataset_name = args.dataset
    max_epoch = args.max_epoch
    max_epoch_lp = args.max_epoch_lp
    num_hidden = args.num_hidden
    num_layers = args.num_layers
    encoder_type = args.encoder
    decoder_type = args.decoder
    replace_rate = args.replace_rate
    optim_type = args.optimizer
    loss_fn = args.loss_fn
    lr = args.lr
    weight_decay = args.weight_decay
    lr_lp = args.lr_lp
    weight_decay_lp = args.weight_decay_lp
    logs = args.logging
    use_scheduler = args.scheduler

    graph, (num_features, num_classes) = load_dataset(dataset_name)
    args.num_features = num_features

    auc_list = []
    estp_auc_list = []

    for i, seed in enumerate(seeds):
        print(f"####### Run {i} for seed {seed}")
        set_random_seed(seed)

        model = build_model(args)
        decoder = DotPredictor()
        # print(model)
        optimizer = torch.optim.Adam(
            list(decoder.parameters()) + list(model.parameters()), lr=lr, weight_decay=weight_decay
        )
        model.to(device)

        if use_scheduler:
            logging.info("Use schedular")
            scheduler = lambda epoch: (1 + np.cos((epoch) * np.pi / max_epoch)) * 0.5
            # scheduler = lambda epoch: epoch / warmup_steps if epoch < warmup_steps \
            # else ( 1 + np.cos((epoch - warmup_steps) * np.pi / (max_epoch - warmup_steps))) * 0.5
            scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=scheduler)
        else:
            scheduler = None

        x = graph.ndata["feat"]

        final_auc, estp_auc = pretrain(model,decoder, graph, x, optimizer, max_epoch, device, scheduler, )
        # model = model.cpu()
        #
        # model = model.to(device)
        # model.eval()
        #
        # final_auc, estp_auc = link_prediction_for_transductive(model, graph, x, lr_lp, weight_decay_lp,
        #                                                        max_epoch_lp,
        #                                                        device, test_ratio=0.1, mute=True)
        nni.report_final_result({'default': final_auc})
        auc_list.append(final_auc)
        estp_auc_list.append(estp_auc)
        #
        # if logger is not None:
        #     logger.finish()

    final_auc, final_auc_std = np.mean(auc_list), np.std(auc_list)
    estp_auc, estp_auc_std = np.mean(estp_auc_list), np.std(estp_auc_list)
    print(f"# final_auc: {final_auc:.4f}±{final_auc_std:.4f}")
    print(f"# early-stopping_auc: {estp_auc:.4f}±{estp_auc_std:.4f}")

# Press the green button in the gutter to run the script.
if __name__ == "__main__":
    args = build_args()
    args = load_best_configs(args, "configs_lp.yml")

    nni_params = nni.get_next_parameter()
    args = merge_parameter(args, nni_params)
    print(args)

    main(args)


from typing import Dict

from torch import tensor, cat, max, clamp, mean

from allennlp.models import Model
from allennlp.modules.feedforward import FeedForward
from allennlp.nn.activations import Activation
from allennlp.modules.text_field_embedders import TextFieldEmbedder
from allennlp.modules.similarity_functions.cosine import CosineSimilarity
from allennlp.data.vocabulary import Vocabulary

class CitationRanker(Model):
    def __init__(self,
                 vocab: Vocabulary,
                 title_embedder: TextFieldEmbedder,
                 abstract_embedder: TextFieldEmbedder,
                 dense_dim=75) -> None:

        super().__init__(vocab)

        self.title_embedder = title_embedder
        self.abstract_embedder = abstract_embedder
        self.intermediate_dim = 6
        self.n_layers = 3
        self.layer_dims = [dense_dim for i in range(self.n_layers-1)]
        self.layer_dims.append(1)

        self.activations = [Activation.by_name("elu")(),Activation.by_name("elu")(),Activation.by_name("sigmoid")()]
        self.layers = FeedForward(input_dim=self.intermediate_dim,
                                  num_layers=self.n_layers,
                                  hidden_dims=self.layer_dims,
                                  activations=self.activations)

    def forward(self,
                query_title: Dict[str, tensor],
                query_abstract: Dict[str, tensor],
                candidate_title: Dict[str, tensor],
                candidate_abstract: Dict[str, tensor],
                candidate_citations: tensor,
                title_intersection: tensor,
                abstract_intersection: tensor,
                cos_sim: tensor,
                label: tensor = None) -> Dict[str,tensor]:

        query_title_embed = self.title_embedder.forward(query_title["tokens"])
        query_abstract_embed = self.abstract_embedder.forward(query_abstract["tokens"])

        candidate_title_embed = self.title_embedder.forward(candidate_title["tokens"])
        candidate_abstract_embed = self.abstract_embedder.forward(candidate_title["tokens"])

        title_cos_sim = CosineSimilarity().forward(query_title_embed,candidate_title_embed).unsqueeze(-1)

        abstract_cos_sim = CosineSimilarity().forward(query_abstract_embed,candidate_abstract_embed).unsqueeze(-1)

        intermediate_output = cat((title_cos_sim, abstract_cos_sim, candidate_citations, title_intersection, abstract_intersection, cos_sim), dim = -1)

        pred = self.layers.forward(intermediate_output)

        output = {"cite_prob":pred}

        if label is not None:
            output["loss"] = self._compute_loss(pred,label)

        return output

    def _compute_loss(self, pred: tensor, label: tensor) -> tensor:
        #in existing implementation training examples with even indices are positive/odd indices are negative
        positive = pred[::2]
        negative = pred[1::2]

        #"margin is given by the difference in label"
        margin = label[::2] - label[1::2]
        delta = clamp(margin + negative - positive,min=0)

        return mean(delta)


import matplotlib.pyplot as plt
import numpy as np
import pdb

inputdir = '/Volumes/seagate_8/data/sami3/jan_2014/'
dims = 'glat', 'glon'

# jan:set no
tec_shape = 672, 96, 100
# jul
# tec_shape = 100, 96, 670A

with open(inputdir + 'time.dat', 'rb') as f:
    time = np.fromfile(f,dtype='float32')[1:-1]
with open(inputdir + 'zalt0B.dat', 'rb') as f:
    alt = np.fromfile(f,dtype='float32')[1:-1]
dim_shape = (tec_shape[1], len(alt), tec_shape[2])  # lon, alt, lat

with open(inputdir + 'glon0B.dat', 'rb') as f:
    lon = np.fromfile(f, dtype='float32')[1:-1]
    lon.shape = dim_shape
with open(inputdir + 'glat0B.dat', 'rb') as f:
    lat = np.fromfile(f, dtype='float32')[1:-1]
    lat.shape = dim_shape
with open(inputdir + 'tecuB.dat', 'rb') as f:
    tec = np.fromfile(f, dtype='float32')[1:-1]
    tec.shape = tec_shape

"""
fig, ax = plt.subplots(subplot_kw=dict(projection='polar'))
colat_r = 90 - lat[:, 0, :].flatten()
lon_r = lon[:, 0, :].flatten()

im = ax.tricontourf(lon_r, colat_r, tec[100, :, :].flatten(), 50, vmin=0, vmax=90)
ax.set_rlim(0, 45)
fig.colorbar(im)
plt.show()
"""
"""
phi = {}
for dim in dims:
    with open(dim + fname_tec, 'rb') as f:
        phi[dim] = np.fromfile(f, dtype='float32')[1:-1]
        phi[dim].shape = (96, 100, 100)
with open('phi' + fname_tec, 'rb') as f:
    phi['vals'] = np.fromfile(f, dtype='float32')[1:-1]
    phi['vals'].shape = (len(time), 100, 96)

"""


#list
persons = ['adam','fred','george','sandra']

# for person in persons:
#     print(person)

#break / continue
# for person in persons:
#     if person == 'fred':
#         break
#     print(person)

#range
# for i in range(len(persons)):
#     print(persons[i])

# for i in range(0,11):
#     print(f'Number {i}')

#while loops
count = 0
while count <= 10:
    print(f'Count: {count}')
    count += 1


import numpy as np
import sklearn.decomposition
import glob, os

from chemscripts.utils import wait_for_termination

def nbo_to_idx(nbo, reorder_nbo):
    return reorder_nbo.index(nbo)

CUBENPROC = 1
def generate_nbo_cube(logname, fchkname, cubename, nbo_indices, gdriver, logger, wait=False, nbo_reorder=True):
    # cubename is expected to have {nbo} at least in cases when len(nbo_indices) > 1
    logger.info("Processing logfile " + logname)
    if nbo_reorder:
        reorder_nbo = []
        loglines = open(logname, "r").readlines()
        for line in loglines:
            if "Reordering of NBOs for storage:" in line:
                parts = line.replace("Reordering of NBOs for storage:", "").replace("\n", "").split()
                for part in parts:
                    reorder_nbo.append(int(part))
        for i in range(len(nbo_indices)):
            nbo_indices[i] = {'real': nbo_indices[i], 'gauss': nbo_to_idx(nbo_indices[i], reorder_nbo)}
    else:
        for i in range(len(nbo_indices)):
            nbo_indices[i] = {'real': nbo_indices[i], 'gauss': nbo_indices[i]}

    for i in range(len(nbo_indices)):
        nbo_indices[i]['gauss'] += 1 # Indexing in cubegen start with 1

    waittasks = []
    cubefiles = []
    for nbo in nbo_indices:
        if "{nbo}" in cubename:
            newcube = cubename.format(nbo=nbo['real'])
        else:
            assert len(nbo_indices) == 1
            newcube = cubename
        cubefiles.append(newcube)
        logger.info("Generating cubefile %s" % newcube)
        command = 'cubegen {nproc} MO={corr_idx} {fchk} {cube} 150'.format(
                nproc=CUBENPROC, corr_idx=nbo['gauss'], fchk=fchkname, cube=newcube)
        waittasks.append(command)

        with gdriver['todo_lock']:
            gdriver['todo_files'].append({
                                            'command': command,
                                            'wd': '.', # os.path.dirname(newcube),
                                            'nproc': CUBENPROC,
                                            'resfile': newcube,
                                         })
    if wait:
        wait_for_termination(waittasks, gdriver)
    return waittasks, cubefiles

BOHR2A = 0.529177
def generate_isosurface(cubename, meshfile_template, ival):
    import mcubes
    cubelines = open(cubename, 'r').readlines()[2:] # First two lines are comments
    fline_parts = cubelines[0].split()
    natoms = int(fline_parts[0])
    if natoms < 0:
        natoms = abs(natoms) # Idk what the negative sign means here
    assert int(fline_parts[4]) == 1
    origin = np.array([
                                float(fline_parts[1]),
                                float(fline_parts[2]),
                                float(fline_parts[3]),
                           ])

    x_parts = cubelines[1].split()
    y_parts = cubelines[2].split()
    z_parts = cubelines[3].split()

    frame_data = {
                   'x': {'N': int(x_parts[0]), 'step': float(x_parts[1]), 'current': 0},
                   'y': {'N': int(y_parts[0]), 'step': float(y_parts[2]), 'current': 0},
                   'z': {'N': int(z_parts[0]), 'step': float(z_parts[3]), 'current': 0},
                 }
    assert float(x_parts[2]) == 0.0 and float(x_parts[3]) == 0.0
    assert float(y_parts[1]) == 0.0 and float(y_parts[3]) == 0.0
    assert float(z_parts[1]) == 0.0 and float(z_parts[2]) == 0.0

    syms = []
    xyzs = []
    for line in cubelines[4:4 + natoms]:
        parts = line.split()
        syms.append(int(parts[0]))
        xyzs.append(BOHR2A * np.array([
                                           float(parts[2]),
                                           float(parts[3]),
                                           float(parts[4])
                                      ]))

    voldata = np.empty([
                           frame_data['x']['N'],
                           frame_data['y']['N'],
                           frame_data['z']['N'],
                       ])
    for line in cubelines[5 + natoms:]:
        parts = line.split()
        for part in parts:
            voldata[frame_data['x']['current']] \
                   [frame_data['y']['current']] \
                   [frame_data['z']['current']] = float(part)
            frame_data['z']['current'] += 1
            if frame_data['z']['current'] == frame_data['z']['N']:
                frame_data['z']['current'] = 0
                frame_data['y']['current'] += 1
                if frame_data['y']['current'] == frame_data['y']['N']:
                    frame_data['y']['current'] = 0
                    frame_data['x']['current'] += 1

    for mode in [{'name': 'plus', 'ival': ival}, {'name': 'minus', 'ival': -ival}]:
        vertices, triangles = mcubes.marching_cubes(voldata, mode['ival'])
        for v in vertices:
            v[0] = (origin[0] + v[0] * frame_data['x']['step']) * BOHR2A
            v[1] = (origin[1] + v[1] * frame_data['y']['step']) * BOHR2A
            v[2] = (origin[2] + v[2] * frame_data['z']['step']) * BOHR2A
        edges = []
        for t in triangles:
            if {t[0], t[1]} not in edges:
                edges.append({t[0], t[1]})
            if {t[0], t[2]} not in edges:
                edges.append({t[0], t[2]})
            if {t[1], t[2]} not in edges:
                edges.append({t[1], t[2]})
        for i in range(len(edges)):
            edges[i] = tuple(edges[i])
        edges = np.array(edges).astype('int32')
        triangles = triangles.astype('int32')
        with open(meshfile_template.format(sign=mode['name'], type='vertices'), 'wb') as f:
            np.save(f, vertices)
        with open(meshfile_template.format(sign=mode['name'], type='edges'), 'wb') as f:
            np.save(f, edges)
        with open(meshfile_template.format(sign=mode['name'], type='triangles'), 'wb') as f:
            np.save(f, triangles)

def get_nbo_direction(surfnames):
    vertices = []
    for surfname in glob.glob(surfnames.format(type='vertices')):
        curvertices = list(np.load(surfname.format(type='vertices')))
        vertices += curvertices

    center = np.zeros(3)
    for v in vertices:
        center += v
    center /= len(vertices)

    for item in vertices:
        item -= center
    pca = sklearn.decomposition.PCA(3)
    pca.fit(vertices)
    return pca.components_[0], center


import openai

openai.api_key = "" #Replace openAI key

import openai

def mental_wellbeing(user_query):
    goal = """
    You are a mental wellbeing assistant. Your role is to provide comfort, mindfulness exercises,
    or general advice to users talking about their feelings or challenges. Remember, you are not a
    replacement for professional help.
    """

    messages = [
        {
            "role": "system",
            "content": goal,
        },
        {
            "role": "user",
            "content": user_query,
        }
    ]

    try:
        response = openai.ChatCompletion.create(
            model="gpt-4",
            messages=messages,
        )
        return response['choices'][0]['message']['content']
    except Exception as e:
        return f"Sorry, there was an error processing your request. Error: {e}"


import traceback
from typing import Any, Callable, Dict, List

from .abc import (
    CallbackClientABC,
    DataABC,
    LogABC,
    RpcServerABC,
)
from .definitions import Definition, DefinitionMemsync
from .mempkg import Mempkg
from .typeguard import typechecked

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# CALLBACK CLIENT CLASS
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

@typechecked
class CallbackClient(CallbackClientABC):
    """
    Representing a callback function
    """

    def __init__(
        self,
        name: str,
        handler: Callable,
        rpc_server: RpcServerABC,
        data: DataABC,
        log: LogABC,
        argtypes: List[Definition],
        restype: Definition,
        memsyncs: List[DefinitionMemsync],
    ):

        self._name = name
        self._handler = handler
        self._data = data
        self._log = log

        self._argtypes = argtypes
        self._restype = restype
        self._memsyncs = memsyncs

        rpc_server.register_function(self, public_name=name)

    def __call__(self, packed_args: List[Any], packed_mempkgs: List[Dict]) -> Dict:

        self._log.info(f'[callback-client] Trying to call callback routine "{self._name:s}" ...')

        try:
            args = self._data.unpack_args(packed_args, self._argtypes)
            retval = None
            mempkgs = [Mempkg.from_packed(packed_mempkg) for packed_mempkg in packed_mempkgs]
            DefinitionMemsync.unpkg_memories(
                args = args,
                retval = retval,
                mempkgs = mempkgs,
                memsyncs = self._memsyncs,
                is_server = True,
            )
        except Exception as e:
            self._log.error("[callback-client] ... call preparation failed!")
            self._log.error(traceback.format_exc())
            raise e

        try:
            retval = self._handler(*args)
        except Exception as e:
            self._log.error("[callback-client] ... call failed!")
            self._log.error(traceback.format_exc())
            return {
                "args": packed_args,  # unchanged
                "retval": retval,  # unchanged, still None
                "mempkgs": packed_mempkgs,  # unchanged
                "success": False,
                "exception": e,
            }

        try:
            DefinitionMemsync.update_memories(
                args = args,
                retval = retval,
                mempkgs = mempkgs,
                memsyncs = self._memsyncs,
            )
            self._log.info("[callback-client] ... done.")
            return {
                "args": self._data.pack_args(args, self._argtypes),
                "retval": self._data.pack_retval(retval, self._restype),
                "mempkgs": [mempkg.as_packed() for mempkg in mempkgs],
                "success": True,
                "exception": None,
            }
        except Exception as e:
            self._log.error("[callback-client] ... call post-processing failed!")
            self._log.error(traceback.format_exc())
            raise e


# -*- coding: utf-8 -*-
"""
Created on Wed Jun 20 17:05:31 2018

@author: Thomas Schatz

Command-line interface to precompute mp-scores for all result files
in a specified folder.

Usage example:
   cd path/2/ABX/results/folder/
   mkdir minimal_pair
   python precompute_mp_scores.py ./ minimal_pair
"""

import argparse
import os.path as path
import scone_phobia.utils.mp_scores as mp_scores

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('in_dir', help="ABX results files folder")
    parser.add_argument('out_dir', help="Folder where to store mp scores")
    parser.add_argument('--overwrite', action='store_true',
                        help=("use this if you want to overwrite existing"
                              " pickles in out_dir"))
    parser.add_argument('--mp_type', default='spk_first',
                        help="Type of minimal-pair scores to compute")
    args = parser.parse_args()
    assert path.exists(args.in_dir), \
        "Input folder {} missing".format(args.in_dir)
    assert path.exists(args.out_dir), \
        "Output folder {} missing".format(args.out_dir)
    if args.overwrite:
        filt = None
        print(("precompute_mp_scores.py: overwriting any pre-existing"
               " pickle in {}".format(args.out_dir)))
    else:
        filt = lambda x: not(path.exists(path.join(args.out_dir, x+'.pickle')))
        print(("precompute_mp_scores.py: mp scores in pre-existing pickles"
               " in {} will not be computed again, use the --overwrite"
               " switch if you want to force them to be computed again."
               ).format(args.out_dir))
    mp_scores.precompute_mp_scores(args.in_dir, args.out_dir, filt=filt, mp_type=args.mp_type)


from statsclasses import *

import ashlib.ling.tokenize
import ashlib.ling.corpus
import ashlib.util.stats
import scipy.stats

import math
import os
import sys
import csv
import ntpath
import collections

""" ngram """

def get_team_ngram_counts(sentences):
	MAX_PHRASE_SIZE = 3
	ngram_counts = collections.Counter()

	for sentence in sentences:
		words = ashlib.ling.tokenize.words(sentence)

		for phrase_size in range(1, MAX_PHRASE_SIZE + 1):
			for ngram_index in range(len(words) - phrase_size + 1):
				ngram = tuple(words[word_index] for word_index in range(ngram_index, ngram_index + phrase_size))

				def has_punctuation():
					for word_index in range(len(ngram) - 1):
						if ashlib.ling.corpus.isPunctuation(ngram[word_index]):
							return True
					return False

				if not has_punctuation():
					ngram = ashlib.ling.tokenize.reverse(ngram)
					ngram_counts[ngram] += 1

	return ngram_counts

def compare_ngram_counts(ngram_counts_1, ngram_counts_2):
	sig_ngrams = []

	n1 = 0
	n2 = 0

	for ngram in ngram_counts_1:
		n1 += ngram_counts_1[ngram]
	for ngram in ngram_counts_2:
		n2 += ngram_counts_2[ngram]

	for ngram in ngram_counts_1:
		count_1 = ngram_counts_1[ngram] + 1
		count_2 = ngram_counts_2[ngram] + 1

		if (max(count_1, count_2)) > 10:
			x_bar_1 = float(count_1) / float(n1)
			x_bar_2 = float(count_2) / float(n2)

			s1 = ashlib.util.stats.stdev([1] * count_1 + [0] * (n1 - count_1))
			s2 = ashlib.util.stats.stdev([1] * count_2 + [0] * (n2 - count_2))

			s_delta = math.sqrt((s1 ** 2 / n1) + (s2 ** 2 / n2))

			t = (x_bar_1 - x_bar_2) / s_delta

			df_numerator = math.pow(((s1 ** 2 / n1) + (s2 ** 2 / n2)), 2)
			df_denom_1 = ((s1 ** 2 / n1) ** 2) / (n1 - 1)
			df_denom_2 = ((s2 ** 2 / n2) ** 2) / (n2 - 1)

			df = df_numerator / (df_denom_1 + df_denom_2)

			p_val_1 = scipy.stats.t.cdf(t, df)
			p_val_2 = scipy.stats.t.cdf((x_bar_2 - x_bar_1) / s_delta, df)

			if (p_val_1 >= .975):
				sig_ngrams.append(ngramData(ngram, count_1, count_2, p_val_1))

	return sig_ngrams


import json
from typing import Any
from unittest.mock import MagicMock, Mock

import pytest
from airbyte_cdk.sources.declarative.partition_routers.substream_partition_router import ParentStreamConfig
from airbyte_cdk.sources.streams import Stream
from requests import Response
from source_monday.components import IncrementalSingleSlice, IncrementalSubstreamSlicer
from source_monday.extractor import MondayIncrementalItemsExtractor

def _create_response(content: Any) -> Response:
    response = Response()
    response._content = json.dumps(content).encode("utf-8")
    return response

def test_slicer():
    date_time_dict = {"updated_at": 1662459010}
    slicer = IncrementalSingleSlice(config={}, parameters={}, cursor_field="updated_at")
    slicer.close_slice(date_time_dict, date_time_dict)
    assert slicer.get_stream_state() == date_time_dict
    assert slicer.get_request_headers() == {}
    assert slicer.get_request_body_data() == {}
    assert slicer.get_request_body_json() == {}

@pytest.mark.parametrize(
    "last_record, expected, records",
    [
        (
            {"first_stream_cursor": 1662459010},
            {"parent_stream_name": {"parent_cursor_field": 1662459010}, "first_stream_cursor": 1662459010},
            [{"first_stream_cursor": 1662459010}],
        ),
        (None, {}, []),
    ],
)
def test_sub_slicer(last_record, expected, records):
    parent_stream = Mock(spec=Stream)
    parent_stream.name = "parent_stream_name"
    parent_stream.cursor_field = "parent_cursor_field"
    parent_stream.stream_slices.return_value = [{"a slice": "value"}]
    parent_stream.read_records = MagicMock(return_value=records)

    parent_config = ParentStreamConfig(
        stream=parent_stream,
        parent_key="id",
        partition_field="first_stream_id",
        parameters={},
        config={},
    )

    slicer = IncrementalSubstreamSlicer(
        config={}, parameters={}, cursor_field="first_stream_cursor", parent_stream_configs=[parent_config], nested_items_per_page=10
    )
    stream_slice = next(slicer.stream_slices()) if records else {}
    slicer.close_slice(stream_slice, last_record)
    assert slicer.get_stream_state() == expected

def test_null_records(caplog):
    extractor = MondayIncrementalItemsExtractor(
        field_path=["data", "boards", "*"],
        config={},
        parameters={},
    )
    content = {
        "data": {
            "boards": [
                {"board_kind": "private", "id": "1234561", "updated_at": "2023-08-15T10:30:49Z"},
                {"board_kind": "private", "id": "1234562", "updated_at": "2023-08-15T10:30:50Z"},
                {"board_kind": "private", "id": "1234563", "updated_at": "2023-08-15T10:30:51Z"},
                {"board_kind": "private", "id": "1234564", "updated_at": "2023-08-15T10:30:52Z"},
                {"board_kind": "private", "id": "1234565", "updated_at": "2023-08-15T10:30:43Z"},
                {"board_kind": "private", "id": "1234566", "updated_at": "2023-08-15T10:30:54Z"},
                None,
                None,
            ]
        },
        "errors": [{"message": "Cannot return null for non-nullable field Board.creator"}],
        "account_id": 123456,
    }
    response = _create_response(content)
    records = extractor.extract_records(response)
    warning_message = "Record with null value received; errors: [{'message': 'Cannot return null for non-nullable field Board.creator'}]"
    assert warning_message in caplog.messages
    expected_records = [
        {"board_kind": "private", "id": "1234561", "updated_at": "2023-08-15T10:30:49Z", "updated_at_int": 1692095449},
        {"board_kind": "private", "id": "1234562", "updated_at": "2023-08-15T10:30:50Z", "updated_at_int": 1692095450},
        {"board_kind": "private", "id": "1234563", "updated_at": "2023-08-15T10:30:51Z", "updated_at_int": 1692095451},
        {"board_kind": "private", "id": "1234564", "updated_at": "2023-08-15T10:30:52Z", "updated_at_int": 1692095452},
        {"board_kind": "private", "id": "1234565", "updated_at": "2023-08-15T10:30:43Z", "updated_at_int": 1692095443},
        {"board_kind": "private", "id": "1234566", "updated_at": "2023-08-15T10:30:54Z", "updated_at_int": 1692095454},
    ]
    assert records == expected_records


#
# @lc app=leetcode.cn id=977 lang=python3
#
# [977] 有序数组的平方
#

# @lc code=start
class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        n = len(nums)
        left, right = 0, n - 1
        res = [0] * n
        cur = n - 1
        while left <= right:
            if nums[left] ** 2 < nums[right] ** 2:
                res[cur] = nums[right] ** 2
                right -= 1
            else:
                res[cur] = nums[left] ** 2
                left += 1

            cur -= 1
        return res

# @lc code=end

977.有序数组的平方.py


import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
import pandas as pd

### Importation de la base de données

database = pd.read_csv("/Users/jeanprolhac/Desktop/Projet/Projet 16 - IA et fraude/Detection-de-fraudes/labelled_database.tsv", sep="\t")

### Création du trainset et du testset

trainset = []
testset = []

traindata = database.loc[1:50]
testdata = database.loc[50:100]
trainincome = list(traindata["income"])
traintaxclass = list(traindata["taxclass"])
trainfraud = list(traindata["fraud"])
testincome = list(testdata["income"])
testtaxclass = list(testdata["taxclass"])
testfraud = list(testdata["fraud"])

for i in range(len(trainincome)) :
    trainset.append((torch.tensor([[float(trainincome[i]), float(traintaxclass[i])]]), torch.tensor([trainfraud[i]])))
    testset.append((torch.tensor([[float(testincome[i]), float(testtaxclass[i])]]), torch.tensor([testfraud[i]])))

### Début duu réseau de neurones

class Net(nn.Module) :

    #define the layers
    def __init__(self) :
        super().__init__()
        self.fc1 = nn.Linear(2, 64)
        self.fc2 = nn.Linear(64, 64)
        self.fc3 = nn.Linear(64, 64)
        self.fc4 = nn.Linear(64, 2)

    def forward(self, x) :
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = F.relu(self.fc3(x))
        x = self.fc4(x)
        return F.log_softmax(x, dim=1)

net = Net()

### Début de l'entraînement

optimizer = optim.Adam(net.parameters(), lr =0.001)

# Le nombre de fois qu'on va parcourir le trainset pour entrainer notre algo

EPOCHS = 5

for epoch in range(EPOCHS) :
    for data in trainset :
        X, y = data
        net.zero_grad()
        output = net(X.view(-1, 1*2))
        loss = F.nll_loss(output, y)
        loss.backward()
        optimizer.step()
    print(loss)

### Début des mesures de performance

correct = 0
total = 0

with torch.no_grad() :
    for data in testset :
        X, y = data
        output = net(X.view(-1, 2))
        for idx, i in enumerate(output):
            if torch.argmax(i) == y[idx]:
                correct += 1
            total += 1

print("Accuracy: ", round(correct/total, 3))

### Test sur un cas

X = torch.tensor([50000., 50000.])
X = X.view(-1, 1*2)
output = net(X)
print(output)
for idx, i in enumerate(output):
    if torch.argmax(i) == 0:
        print("Non fraudeur")
    else :
        print("Fraudeur")


import requests
from bs4 import BeautifulSoup
import re
import time
import pandas as pd

start = time.perf_counter()

session = requests.Session()
sitemap_response = session.get('YOUR_SITEMAP_URL')
sitemap_soup = BeautifulSoup(sitemap_response.content, 'lxml')
sitemap_urls = sitemap_soup.find_all("loc")

unique_urls = set()
for sitemap_url in sitemap_urls:
    unique_urls.add(sitemap_url.text)

search_terms = {
    'Your keyword1': False,
    'Your keyword2': False,
    'Your keyword3': False,
    'Your keyword4': False
}

results = []
for url in unique_urls:
    print(f'Requesting {url}')
    source_response = session.get(url)
    source_soup = BeautifulSoup(source_response.text, 'html.parser')

    for search_term in search_terms:
        search_terms[search_term] = bool(source_soup(text=re.compile(search_term)))

    results.append({
        'url': url,
        **search_terms
    })
print(results)
results_df = pd.DataFrame(results)
results_df.to_excel('YOUR_PATH/results.xlsx')

elapsed = time.perf_counter() - start
print(f'Time elapsed: {elapsed:0.6f} seconds')


import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import time
import os
class helpers:
    def __init__(self):
        print('initialized')

    def loadData(self):
        with np.load("notMNIST.npz") as data:
            Data, Target = data["images"], data["labels"]
            np.random.seed(521)
            randIndx = np.arange(len(Data))
            np.random.shuffle(randIndx)
            Data = Data[randIndx] / 255.0
            Target = Target[randIndx]
            trainData, trainTarget = Data[:10000], Target[:10000]
            validData, validTarget = Data[10000:16000], Target[10000:16000]
            testData, testTarget = Data[16000:], Target[16000:]
        return trainData, validData, testData, trainTarget, validTarget, testTarget
    #data structure description, data is 3 dimensions matrix (10000,28,28)
    #target is number ranges from 0 to 9, 2 dimensions (10000,1)

    # Implementation of a neural network using only Numpy - trained using gradient descent with momentum
    def convertOneHot(self,trainTarget, validTarget, testTarget):
        newtrain = np.zeros((trainTarget.shape[0], 10))
        newvalid = np.zeros((validTarget.shape[0], 10))
        newtest = np.zeros((testTarget.shape[0], 10))

        for item in range(0, trainTarget.shape[0]):
            newtrain[item][trainTarget[item]] = 1
        for item in range(0, validTarget.shape[0]):
            newvalid[item][validTarget[item]] = 1
        for item in range(0, testTarget.shape[0]):
            newtest[item][testTarget[item]] = 1
        return newtrain, newvalid, newtest
    #the converted matrixes are (10000,10), in 10 column eacj column is 0 unless it is the target label
    #e.g:target=7 will have [0,0,0,0,0,0,0,1,0,0]

    def shuffle(self,trainData, trainTarget):
        np.random.seed(421)
        randIndx = np.arange(len(trainData))
        #create an array range from 0 to 10000
        target = trainTarget
        np.random.shuffle(randIndx)
        #shuffle the array
        data, target = trainData[randIndx], target[randIndx]
        #shuffle the trainning data and target with the shuffled array
        return data, target

    def relu(self, x):

        return np.maximum(0,x)
    '''def relu(self,x):
        minus=np.where(x<0)

        #find all positions where x equals minus and positive
        #replace value with relu
        x[minus]=0
        print('finish')
        return x'''
    def reshape_datamatrix(self,data_matrix):
        lines=data_matrix.shape[0]
        new_data=np.reshape(data_matrix,[lines,-1])
        return new_data

    def softmax(self,data_matrix):

        soft_func=np.exp(data_matrix)/np.sum(np.exp(data_matrix),axis=0,keepdims=True)
        #if want to add the columns use axis=1,keepdims=True
        return soft_func

    def compute(self,weight,data,bias):
        result=np.dot(weight,data)+bias
        return result

    def averageCE(self,target, prediction):
        # print("prediction")
        # print(np.log(prediction[0]))
        L_sum = np.sum(target * np.log(prediction + 10 ** -10))
        n = target.shape[0]
        L = (-1) * (1. / n) * L_sum
        return L
    '''def averageCE(self,target,predict):
        soft_result=self.softmax(predict)
        log_compute=np.log(soft_result)
        size=target.shape[0]
        #* multiply the corresponding places, while np.dot is standard matrix multiply
        production=(target)*log_compute
        loss=(-1/size)*np.sum(production)
        return loss'''
    def gradCE(self,target,out_prediction):
        gradient=np.mean(out_prediction-target)
        return gradient
        '''soft_result=self.softmax(out_prediction)
        grad=(-target/soft_result)+(target*soft_result)
        return grad'''

'''helps=helpers()
trainD,validD,testD,trainT,validT,testT=helps.loadData()
new_train,new_valid,new_test=helps.convertOneHot(trainT,validT,testT)
#sfunction=helps.softmax(new_train)
#error=helps.averageCE(new_train,new_train)
gra=helps.gradCE(new_train,new_train)
print(gra.shape,gra[0])

#helps.reshape_datamatrix(trainD)
#da,tar=helps.shuffle(trainD,trainT)'''

'''
#relu test
x=np.array([-1,2,-9,8])
k=helps.relu(x)
print(k)
'''

'''
#data structure test
print(trainD.shape)
print(testT[0])
train_new,valid_new,test_new=helps.convertOneHot(trainT,validT,testT)
print (test_new.shape)
print(test_new[0],test_new[1],test_new[2],test_new[3])'''


import sys
from time import perf_counter

Preamble_size = 25

def read_file(file):
    try:
        with open(file, 'r') as file:
            content = file.read().strip().split("\n")
            content = list(map(int, content))
            #print(content)

    except:
        print('Error to read file')
        sys.exit()

    return content

def is_sum_two_numbers(num: int, preamble: list):
    for i in range(len(preamble) - 1):
        for j in range(i + 1, len(preamble)):
            if preamble[i] + preamble[j] == num:
                return True
    return False

def part_one(data):
    for x in range(Preamble_size, len(data)):
        preamble = data[x - Preamble_size: x]
        if not is_sum_two_numbers(data[x], preamble):
            return data[x]

if __name__ == "__main__":
    start_timer = perf_counter()
    input_data = read_file("data.txt")
    print(part_one(input_data))
    end_timer = perf_counter()
    print(f'Time of execution {round(end_timer - start_timer, 5)} seconds')
    print('End of script')
    sys.exit(0)


'''
Path Sum II
Medium

Given the root of a binary tree and an integer targetSum, return all root-to-leaf paths where each path's sum equals targetSum.

A leaf is a node with no children.

Example 1:

Input: root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
Output: [[5,4,11,2],[5,8,4,5]]

Example 2:

Input: root = [1,2,3], targetSum = 5
Output: []

Example 3:

Input: root = [1,2], targetSum = 0
Output: []
'''

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
        if root == None:
            return []

        paths = []

        self.traverse(root, 0, targetSum, paths, "")

        return paths

    def traverse(self, root, cur_sum, targetSum, paths, path):
        if root == None:
            return

        if root.left == None and root.right == None and cur_sum + root.val == targetSum:
            path += f"->{root.val}"
            p = [int(char) for char in path.split("->") if char != ""]
            paths.append(p)
            return

        if path == "":
            self.traverse(root.left, cur_sum + root.val, targetSum, paths, f"{root.val}")
            self.traverse(root.right, cur_sum + root.val, targetSum, paths, f"{root.val}")
        else:
            self.traverse(root.left, cur_sum + root.val, targetSum, paths, f"{path}->{root.val}")
            self.traverse(root.right, cur_sum + root.val, targetSum, paths, f"{path}->{root.val}")


#!env/bin/python
from flask import Flask, jsonify
from tello import Tello

app = Flask(__name__)
tello = Tello()
tello.initialize()

@app.route('/drone/command/takeoff', methods=['POST'])
def drone_takeoff():
    print('Drone now taking off...')
    tello.takeoff()
    return jsonify({'status': 'OK'})

@app.route('/drone/command/land', methods=['POST'])
def drone_land():
    print('Drone now landing...')
    tello.land()
    return jsonify({'status': 'OK'})

if __name__ == '__main__':
    app.run(debug=False, host='10.0.0.3')
    tello.end()


import numpy as np
import random

# filling the missing age values

def nan_imputer(data, mode='mean_by_std'):

    '''NaN Imputer

    Provides five different options for imputing nan
    values within a a series / array of data.

    USE: nan_imputer(titanic.Age,'mean')

    OPTIONS: The default is 'mean_by_std', with other
    options 'mean', 'median', 'mode', and 'common'.

    '''

    l = []

    if mode == 'mean':
        val = data.mean()

    if mode == 'median':
        val = data.median()

    if mode == 'mode':
        val = data.mode()

    if mode == 'common':
        val = data.value_counts().index[0]

    if mode == 'mean_by_std':
        val = data.mean()
        std = data.std()
        lo = val - std
        hi = val + std

    else:
        # create dummmy values for random pick
        lo = val
        hi = val

    c = len(data)

    for i in range(c):

        if np.isnan(data[i]) == True:

            l.append(random.randint(int(lo), int(hi)))

        else:
            l.append(data[i])

    return l


from django.views.generic import TemplateView
from django.contrib.auth.models import User, Group
from django.views.generic.edit import CreateView, UpdateView
from .models import BaseRegisterForm
from django.shortcuts import redirect
from django.contrib.auth.decorators import login_required

class BaseRegisterView(CreateView):
    model = User
    form_class = BaseRegisterForm
    success_url = "/"

class IndexView(TemplateView):
    template_name = 'login/index.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['is_not_author'] = not self.request.user.groups.filter(name='author').exists()
        return context

@login_required
def upgrade_me(request):
    user = request.user
    author_group = Group.objects.get(name='author')
    if not request.user.groups.filter(name='author').exists():
        author_group.user_set.add(user)
    return redirect('/')


#Programa que ordena una lista de numeros
#Autor: Jhon Garcia

#Funcion que pide una lista de numeros
def pedir_lista():
    lista = []
    numero = (input("Introduce un numero y escriba salir para finalizar lista: "))
    while numero != "salir":
        lista.append(numero)
        numero = (input("Introduce otro numero: "))
    return lista

#Funcion que ordena la lista
def ordenar_lista(lista):
    for i in range(len(lista)):
        for j in range(i + 1, len(lista)):
            if lista[i] > lista[j]:
                lista[i], lista[j] = lista[j], lista[i]
    return lista

#Funcion que imprime el resultado
def imprimir_resultado(lista):
    print("La lista de menor a mayor es: ", lista)

#Funcion principal
def main():
    lista = pedir_lista()
    lista = ordenar_lista(lista)
    imprimir_resultado(lista)

#Llamada a la funcion principal
main()


#!/usr/bin/env python3

'''

'''
from matplotlib import pyplot as plt

import matplotlib.patches as patches
import numpy as np
import csv
import math

# Map storing a set of landmarks
# landmarks are stored in a dictionary mapping  cube-IDs on Frame2D (indicating their true position)
class Track:
    def __init__(self, landmarks):
        self.landmarks = landmarks
        self.minX = None
        self.minY = None
        self.maxX = None
        self.maxY = None

class Cone:
    def __init__(self):
        self.pos = np.identity(3)
        self.colour = 'red'
        self.size = None #change at a later time
        self.visible = False

    def __init__(self, pos: np.array, colour):
        self.pos = pos
        self.colour = colour
        self.size = None
        self.visible = False

#This function loads a "blergh.csv" file in. If you want to make your own then look at the format on Oval.csv and just
#change the filename from runSimTrack.py (line 15 or nearby)
def loadTrack(trackName):
    scale = 1

    coneArray = []
    with open(trackName, 'r') as file:
        reader = csv.reader(file, delimiter=',')
        for row in reader:
            conePos = np.array([[math.cos(0), -math.sin(0), float(row[0])*scale], [math.sin(0), math.cos(0), float(row[1])*scale], [0., 0.,1.]])
            coneColour = row[2]
            coneArray.append(Cone(conePos, coneColour))

    minX = coneArray[0].pos[0,2]
    minY = coneArray[0].pos[1,2]
    maxX = coneArray[0].pos[0,2]
    maxY = coneArray[0].pos[1,2]

    for cone in coneArray:
        x = cone.pos[0,2]
        y = cone.pos[1,2]
        if(x < minX):
            minX = x
        if (x > maxX):
            maxX = x
        if (y < minY):
            minY = y
        if (y > maxY):
            maxY = y

    T = Track(coneArray)
    border = 2
    T.minX = minX - border
    T.minY = minY - border
    T.maxX = maxX + border
    T.maxY = maxY + border
    return T

#Can be used as a standalone program if you don't want a sim but want to see the track
def plotTrack(ax, t: Track, gridOn, color="blue"):
    if(gridOn == True):
        minX = t.minX
        maxX = t.maxX
        minY = t.minY
        maxY = t.maxY
        tick = 0.5
        numX = abs(maxX-minX)
        numY = abs(maxY-minY)

        for xIndex in range(0, math.ceil(numX/tick) + 1):
            x = minX + xIndex * tick
            bold = 0.8 if (xIndex - 1) % 5 == 0 else 0.4
            plt.plot([x, x], [minY, maxY], color, alpha=bold, linewidth=bold)
        for yIndex in range(0, math.ceil(numY/tick) + 1):
            y = minY + yIndex * tick
            bold = 0.8 if (yIndex - 1) % 5 == 0 else 0.4
            plt.plot([minX, maxX], [y, y], color, alpha=bold, linewidth=bold)

    for landmark in t.landmarks:
        x = landmark.pos[0,2]
        y = landmark.pos[1,2]
        size = 0.25
        if(landmark.colour.lower()=="blue"):
            colour = "blue"
        elif(landmark.colour.lower()=="yellow"):
            colour = "yellow"
        elif(landmark.colour.lower()=="orange"):
            colour = "orange"
        else:
            colour = "red"
        rect = patches.Rectangle((float(x) - size, float(y) - size), 2 * size, 2 * size, linewidth=2, edgecolor=str(colour), facecolor="none", zorder=0)
        ax.add_patch(rect)


import sys

class LoxError:
    had_error = False

    @staticmethod
    def error(line, message):
        LoxError._report(line, "", message)

    @staticmethod
    def _report(line, where, message):
        print(f"[line {line}] Error{where}: {message}", file=sys.stderr)
        LoxError.had_error = True


# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
        tail = head

        while tail:
            if tail.next and tail.val == tail.next.val:
                tail.next = tail.next.next
            else:
                tail = tail.next

        return head


# parse.py

import requests
import json
import datetime

headers = {
	"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:103.0) Gecko/20100101 Firefox/103.0",
	"X-Requested-With": "XMLHttpRequest"
}

def get_data():
	start_time = datetime.datetime.now()
	url = "https://roscarservis.ru/catalog/legkovye/?set_filter=Y&sort%5Bprice%5D=asc&PAGEN_1=1"
	r = requests.get(url=url, headers=headers)

	#with open("index.html", "w") as file:
	#	file.write(r.text)
	#print(r.json())

	#with open("data.json", "w") as file:
	#	json.dump(r.json(), file, indent=4, ensure_ascii=False)

	pages_count = r.json()["pagesCount"]

	data_list = []

	for page in range(1, pages_count + 1):
		url = f"https://roscarservis.ru/catalog/legkovye/?set_filter=Y&sort%5Bprice%5D=asc&PAGEN_1={page}"
		r = requests.get(url=url, headers=headers)
		data = r.json()
		items = data["items"]
		possible_stores = ["discountStores", "externalStores", "commonStores"]

		for item in items:
			total_amount = 0

			item_id = item["id"]
			item_name = item["name"]
			item_url = f'https://roscarservis.ru{item["url"]}'
			item_season = item["season"]
			item_price = item["price"]
			item_image = f'https://roscarservis.ru{item["imgSrc"]}'

			stores = []

			for ps in possible_stores:
				if ps in item:
					if item[ps] is None or len(item[ps]) < 1:
						continue
					else:
						for store in item[ps]:
							store_name = store["STORE_NAME"]
							store_price = store["PRICE"]
							store_amount = store["AMOUNT"]
							total_amount += int(store["AMOUNT"])

							stores.append(
								{
									"store_name": store_name,
									"store_price": store_price,
									"store_amount": store_amount

								}
							)

			data_list.append(
				{
					"name": item_name,
					"price": item_price,
					"url": item_url,
					"img_url": item_image,
					"stores": stores,
					"total_amount": total_amount
				})
		print(f"[INFO] Обработал {page}/{pages_count}")

	cur_time = datetime.datetime.now().strftime("%d_%m_%Y_%H_%M")
	with open(f"data_{cur_time}.json", "a") as file:
		json.dump(data_list, file, indent=4, ensure_ascii=False)
	diff_time = datetime.datetime.now() - start_time
	print(diff_time)

def main():
	get_data()

if __name__ == '__main__':
		main()


import inspect

from exception import BotException

class CommandError(BotException):

    def __init__(self, message, *, quiet=False):
        super().__init__(message)
        self.message = message
        self.quiet = quiet

class CommandUsageError(CommandError):

    def __init__(self, command):
        super().__init__(
            "命令用法错误！\n"
            "正确用法： `%s %s`" % (command.prefixed_name, command.usage)
        )

class CheckFailure(CommandError):

    def __init__(self, check):
        message = getattr(check, 'message', None)
        super().__init__(message, quiet=message is not None)

def command(*, name, reinvoke=False):

    def wrapper(func):
        func.__command_attrs__ = {
            'name': name,
            'checks': getattr(func, '__commands_checks__', None),
            'reinvoke': reinvoke
        }
        return func

    return wrapper

def check(predicate, *, message=None):

    if message:
        predicate.message = message

    def wrapper(func):
        if isinstance(func, Command):
            func.checks.append(predicate)
        else:
            if not hasattr(func, '__command_checks__'):
                func.__command_checks__ = []
            func.__command_checks__.append(predicate)

        return func

    return wrapper

class Command:

    def __init__(self, callback, name, *, checks=None, reinvoke=False):
        self.callback = callback
        self.name = name
        self.prefixed_name = "/" + self.name
        self.reinvoke = reinvoke

        argnames, varargs, *_, annotations = inspect.getfullargspec(self.callback)

        self._varargs = varargs

        if self._varargs:
            self.usage = "%s [arguments]" % self.prefixed_name
        else:
            self.usage = "%s %s" % (self.prefixed_name, " ".join(argnames))
            # TODO make this not as scuffed?
            self.converters = [
                annotations[argname] if argname in annotations
                else None for argname in annotations
            ]

        self.checks = checks if checks else []

    def __str__(self):
        return '%s command' % self.prefixed_name

    def invoke(self, bot, ctx, *args):

        for check in self.checks:
            if not check(ctx):
                raise CheckFailure(check)

        if self._varargs:
            self.callback(bot, ctx, *args)
        else:
            cleaned = []
            try:
                for arg, converter in zip(args[:len(self.converters)], self.converters):
                    if converter is not None:
                            arg = converter(arg)
                    cleaned.append(arg)
                self.callback(bot, ctx, *cleaned)
            except:
                raise CommandUsageError(self)

        if self.reinvoke and self.name not in ctx.reinvoked_commands:
            bot.send_command(self.name, ctx, *args)


"""
Parts of the codes from https://git.iyunxiao.com/DeepVision/pytorch-ocr-framework
by hzc wt
"""

import os
import copy
import cv2
import torch
import torch.utils.data as data
import random
import numpy as np
# from functools import partial
# import math
# from losses.box_utils import jaccard
# from .utils import load_annoataion_quard, random_crop
from itertools import islice
from itertools import cycle
from torchvision import transforms
from PIL import Image
from . import register_dataset
label_prefix = 'labels'

def get_max_shape(arrays):
    """
    Args:
        images: list of arrays

    """
    shapes = list(map(lambda x: list(x.shape), arrays))
    ndim = len(arrays[0].shape)
    max_shape = []
    for d in range(ndim):
        max_shape += [max(shapes, key=lambda x: x[d])[d]]

    return max_shape

def pad_batch_images(images, max_shape=None):
    """
    Args:
        images: list of arrays
        target_shape: shape at which we want to pad

    """

    # 1. max shape
    if max_shape is None:
        max_shape = get_max_shape(images)

    # 2. apply formating
    batch_images = 255 * np.ones([len(images)] + list(max_shape))
    # batch_images = np.squeeze(batch_images, 1)
    # print(batch_images.shape, max_shape)
    for idx, img in enumerate(images):
        batch_images[idx, :, :img.shape[1], :img.shape[2]] = img

    return batch_images.astype(np.float32)

def pad_batch_formulas(formulas, id_pad, id_end, max_len=None):
    """Pad formulas to the max length with id_pad and adds and id_end token
    at the end of each formula

    Args:
        formulas: (list) of list of ints
        max_length: length maximal of formulas

    Returns:
        array: of shape = (batch_size, max_len) of type np.int32
        array: of shape = (batch_size) of type np.int32

    """
    if max_len is None:
        max_len = max(list(map(lambda x: len(x), formulas)))

    batch_formulas = id_pad * np.ones([len(formulas), max_len+1],
            dtype=np.int32)
    formula_length = np.zeros(len(formulas), dtype=np.int32)
    for idx, formula in enumerate(formulas):
        batch_formulas[idx, :len(formula)] = np.asarray(formula,
                dtype=np.int32)
        batch_formulas[idx, len(formula)] = id_end
        formula_length[idx] = len(formula) + 1

    return batch_formulas, formula_length

def img_sort_key(ex):
    """Sort using the size of the image: (width, height)."""
    return ex[0].shape[2], ex[0].shape[1]

def filter_example(ex, use_src_len=True, use_tgt_len=True,
                   min_src_len=1, max_src_len=float('inf'),
                   min_tgt_len=1, max_tgt_len=float('inf')):
    """Return whether an example is an acceptable length.
    If used with a dataset as ``filter_pred``, use :func:`partial()`
    for all keyword arguments.
    Args:
        ex (torchtext.data.Example): An object with a ``src`` and ``tgt``
            property.
        use_src_len (bool): Filter based on the length of ``ex.src``.
        use_tgt_len (bool): Similar to above.
        min_src_len (int): A non-negative minimally acceptable length
            (examples of exactly this length will be included).
        min_tgt_len (int): Similar to above.
        max_src_len (int or float): A non-negative (possibly infinite)
            maximally acceptable length (examples of exactly this length
            will be included).
        max_tgt_len (int or float): Similar to above.
    """
    src_len = len(ex.src[0])
    tgt_len = len(ex.tgt[0])
    return (not use_src_len or min_src_len <= src_len <= max_src_len) and \
        (not use_tgt_len or min_tgt_len <= tgt_len <= max_tgt_len)

def split_corpus(data, chunk_size):
    """
    Args:
        data: cycle iterator, 返回图片路径和对应的formula
        chunk_size: 一次性读取到内存中的图片张数
    Return:
        data_sort: yield 排序后的img和对应的formula
    """
    if chunk_size <= 0:
        yield data
    else:
        while True:
            shard = list(islice(data, chunk_size))  # 每次取shard size的图片进行排序
            if not shard:
                break
            data_pair = []
            # max_h, max_w = 0, 0
            for img_path, formula in shard:
                if not os.path.exists(img_path):
                    img_path = img_path.replace('media', 'home')
                img = transforms.ToTensor()(
                    Image.fromarray(cv2.imread(img_path, 0)))  # 1 * h * w
                data_pair.append((img, formula, img_path))
            data_sort = sorted(data_pair, key=img_sort_key)
            yield data_sort

@register_dataset
class ImageIm2LatexDataset(data.Dataset):
    @staticmethod
    def modify_commandline_options(parser, is_train):
        return parser
    def __init__(self, dataroot):
        super(ImageIm2LatexDataset, self).__init__()
        self.dataroot = dataroot
        data_list = []
        # if opt.isTrain:
        file_name = "all_train_random.txt"
        # else:
        #     file_name = "all_test.txt"
        with open(os.path.join(self.dataroot, file_name), encoding='utf-8') as f:
            for line in f.readlines():
                img_file, formula = line.split(" ", 1)
                data_list.append((img_file, formula))
        random.shuffle(data_list)
        print("load {} images".format(len(data_list)))
        self.data_len = len(data_list)
        self.data = cycle(data_list)
        self.chunk_size = 500  # 一次加载chunk_size数量的图片进入内存，并按照w,h的顺序排序
        self.chunk_data = iter(next(split_corpus(self.data, self.chunk_size)))
        pass

    def __len__(self):

        return self.data_len

    def __getitem__(self, index):
        err_count = 100
        while True and err_count:
            try:
                img, formula, img_name = next(self.chunk_data)
            except:
                self.chunk_data = iter(next(split_corpus(self.data, self.chunk_size)))
                img, formula, img_name = next(self.chunk_data)
            # print("img", img.shape, torch.max(img), torch.min(img), img.dtype)
            # print(img_name)
            if len(formula) == 0 or img.shape[1] > 1900 or img.shape[2] > 1900 \
                    or img.shape[1] < 20 or img.shape[2] < 20 \
                    or img.shape[1] * img.shape[2] > 600000:
                err_count -= 1
                continue
            # if self.opt.isTrain:
            return img, formula
            # else:
            #     return img, formula, img_name

    @staticmethod
    def name():
        return 'ImageIm2LatexDataset'

    @staticmethod
    def collate_fn(batch):
        images = []
        formulas = []
        filenames = []
        c = batch[-1][0].shape[0]
        max_h = max([t[0].shape[1] for t in batch])
        max_w = max([t[0].shape[2] for t in batch])
        batch_len = len(batch[0])
        if batch_len == 2:
            for item, formula in batch:
                img = np.ones((c, max_h, max_w))
                img[:, 0:item.shape[1], 0:item.shape[2]] = item
                images.append(img[np.newaxis, :, :, :])
                formulas.append(formula.strip())
        elif batch_len == 3:
            for item, formula, filename in batch:
                img = np.ones((c, max_h, max_w))
                img[:, 0:item.shape[1], 0:item.shape[2]] = item
                images.append(img[np.newaxis, :, :, :])
                formulas.append(formula.strip())
                filenames.append(filename)
        # random.shuffle(images)
        images = np.concatenate(images, axis=0)
        # formulas = np.concatenate((formulas), axis=0)
        images = images.astype(np.float32)

        # print(images.shape, np.max(images), np.min(images), images.dtype)
        if batch_len == 2:
            return images, formulas
        else:
            return images, formulas, filenames

if __name__ == '__main__':
    import argparse
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('--dataroot', type=str, default='/media/Data/hzc/datasets/formulas/')
    opt = parser.parse_known_args()
    opt = parser.parse_args()
    dataset = ImageIm2LatexDataset(opt)
    data_loader = torch.utils.data.DataLoader(
        dataset, shuffle=True, batch_size=5,
        num_workers=1, collate_fn=dataset.collate_fn)
    for i, _ in enumerate(data_loader):
        pass
    print("sa sa sa!")
    print("su su su!")
    os._exit(0)