from math import pi, cos, sin, sqrt
from typing import Type

import bpy
from bpy.props import *
from bpy.types import NodeSocket
import mathutils

import arm.node_utils
import arm.utils

if arm.is_reload(__name__):
    arm.node_utils = arm.reload_module(arm.node_utils)
    arm.utils = arm.reload_module(arm.utils)
else:
    arm.enable_reload(__name__)

# See Blender sources: /source/blender/editors/space_node/drawnode.cc
# Permalink for 3.2.2: https://github.com/blender/blender/blob/bcfdb14560e77891d674c2701a5071a7c07baba3/source/blender/editors/space_node/drawnode.cc#L1152-L1167
socket_colors = {
    'ArmNodeSocketAction': (0.8, 0.3, 0.3, 1),
    'ArmNodeSocketAnimAction': (0.8, 0.8, 0.8, 1),
    'ArmRotationSocket': (0.68, 0.22, 0.62, 1),
    'ArmNodeSocketArray': (0.8, 0.4, 0.0, 1),
    'ArmBoolSocket': (0.80, 0.65, 0.84, 1.0),
    'ArmColorSocket': (0.78, 0.78, 0.16, 1.0),
    'ArmDynamicSocket': (0.39, 0.78, 0.39, 1.0),
    'ArmFloatSocket': (0.63, 0.63, 0.63, 1.0),
    'ArmIntSocket': (0.059, 0.522, 0.149, 1),
    'ArmNodeSocketObject': (0.15, 0.55, 0.75, 1),
    'ArmStringSocket': (0.44, 0.70, 1.00, 1.0),
    'ArmVectorSocket': (0.39, 0.39, 0.78, 1.0),
    'ArmAnySocket': (0.9, 0.9, 0.9, 1)
}

def _on_update_socket(self, context):
    self.node.on_socket_val_update(context, self)

class ArmCustomSocket(NodeSocket):
    """
    A custom socket that can be used to define more socket types for
    logic node packs. Do not use this type directly (it is not
    registered)!
    """

    bl_idname = 'ArmCustomSocket'
    bl_label = 'Custom Socket'
    # note: trying to use the `type` property will fail. All custom nodes will have "VALUE" as a type, because it is the default.
    arm_socket_type = 'NONE'
    # please also declare a property named "default_value_raw" of arm_socket_type isn't "NONE"

    def get_default_value(self):
        """Override this for values of unconnected input sockets."""
        return None

    def on_node_update(self):
        """Called when the update() method of the corresponding node is called."""
        pass

    def copy_defaults(self, socket):
        """Called when this socket default values are to be copied to the given socket"""
        pass

class ArmActionSocket(ArmCustomSocket):
    bl_idname = 'ArmNodeSocketAction'
    bl_label = 'Action Socket'
    arm_socket_type = 'NONE'

    def draw(self, context, layout, node, text):
        layout.label(text=self.name)

    def draw_color(self, context, node):
        return socket_colors[self.bl_idname]

class ArmAnimActionSocket(ArmCustomSocket):
    bl_idname = 'ArmNodeSocketAnimAction'
    bl_label = 'Action Socket'
    arm_socket_type = 'STRING'

    default_value_get: PointerProperty(name='Action', type=bpy.types.Action)  # legacy version of the line after this one
    default_value_raw: PointerProperty(name='Action', type=bpy.types.Action, update=_on_update_socket)

    def __init__(self):
        super().__init__()
        if self.default_value_get is not None:
            self.default_value_raw = self.default_value_get
            self.default_value_get = None

    def get_default_value(self):
        if self.default_value_raw is None:
            return ''
        if self.default_value_raw.name not in bpy.data.actions:
            return self.default_value_raw.name
        name = arm.utils.asset_name(bpy.data.actions[self.default_value_raw.name])
        return arm.utils.safestr(name)

    def draw(self, context, layout, node, text):
        if self.is_output:
            layout.label(text=self.name)
        elif self.is_linked:
            layout.label(text=self.name)
        else:
            layout.prop_search(self, 'default_value_raw', bpy.data, 'actions', icon='NONE', text='')

    def draw_color(self, context, node):
        return socket_colors[self.bl_idname]

    def copy_defaults(self, socket):
        if socket.bl_idname == self.bl_idname:
            socket.default_value_raw = self.default_value_raw

class ArmRotationSocket(ArmCustomSocket):
    bl_idname = 'ArmRotationSocket'
    bl_label = 'Rotation Socket'
    arm_socket_type = 'ROTATION'  # the internal representation is a quaternion, AKA a '4D vector' (using mathutils.Vector((x,y,z,w)))

    def get_default_value(self):
        if self.default_value_raw is None:
            return mathutils.Vector((0.0,0.0,0.0,1.0))
        else:
            return self.default_value_raw

    def on_unit_update(self, context):
        if self.default_value_unit == 'Rad':
            fac = pi/180  # deg->rad conversion
        else:
            fac = 180/pi  # rad->deg conversion
        if self.default_value_mode == 'AxisAngle':
            self.default_value_s3 *= fac
        elif self.default_value_mode == 'EulerAngles':
            self.default_value_s0 *= fac
            self.default_value_s1 *= fac
            self.default_value_s2 *= fac
        self.do_update_raw(context)

    def on_mode_update(self, context):
        if self.default_value_mode == 'Quaternion':
            summ = abs(self.default_value_s0)
            summ+= abs(self.default_value_s1)
            summ+= abs(self.default_value_s2)
            summ+= abs(self.default_value_s3)
            if summ<0.01:
                self.default_value_s3 = 1.0
        elif self.default_value_mode == 'AxisAngle':
            summ = abs(self.default_value_s0)
            summ+= abs(self.default_value_s1)
            summ+= abs(self.default_value_s2)
            if summ<1E-5:
                self.default_value_s3 = 0.0
        self.do_update_raw(context)

    @staticmethod
    def convert_to_quaternion(part1,part2,param1,param2,param3):
        """converts a representation of rotation into a quaternion.
        ``part1`` is a vector, ``part2`` is a scalar or None,
        ``param1`` is in ('Quaternion', 'EulerAngles', 'AxisAngle'),
        ``param2`` is in ('Rad','Deg') for both EulerAngles and AxisAngle,
        ``param3`` is a len-3 string like "XYZ", for EulerAngles """
        if param1=='Quaternion':
            qx, qy, qz = part1[0], part1[1], part1[2]
            qw = part2
            # need to normalize the quaternion for a rotation (having it be 0 is not an option)
            ql = sqrt(qx**2+qy**2+qz**2+qw**2)
            if abs(ql)<1E-5:
                qx, qy, qz, qw = 0.0,0.0,0.0,1.0
            else:
                qx /= ql
                qy /= ql
                qz /= ql
                qw /= ql
            return mathutils.Vector((qx,qy,qz,qw))

        elif param1 == 'AxisAngle':
            if param2 == 'Deg':
                angle = part2 * pi/180
            else:
                angle = part2
            cang, sang = cos(angle/2), sin(angle/2)
            x,y,z = part1[0], part1[1], part1[2]
            veclen = sqrt(x**2+y**2+z**2)
            if veclen<1E-5:
                return mathutils.Vector((0.0,0.0,0.0,1.0))
            else:
                return mathutils.Vector((
                    x/veclen * sang,
                    y/veclen * sang,
                    z/veclen * sang,
                    cang
                ))
        else:  # param1 == 'EulerAngles'
            x,y,z = part1[0], part1[1], part1[2]
            if param2 == 'Deg':
                x *= pi/180
                y *= pi/180
                z *= pi/180
            cx, sx = cos(x/2), sin(x/2)
            cy, sy = cos(y/2), sin(y/2)
            cz, sz = cos(z/2), sin(z/2)

            qw, qx, qy, qz  = 1.0,0.0,0.0,0.0
            for direction in param3[::-1]:
                qwi, qxi,qyi,qzi = {'X': (cx,sx,0,0), 'Y': (cy,0,sy,0), 'Z': (cz,0,0,sz)}[direction]

                qw = qw*qwi -qx*qxi -qy*qyi -qz*qzi
                qx = qx*qwi +qw*qxi +qy*qzi -qz*qyi
                qy = qy*qwi +qw*qyi +qz*qxi -qx*qzi
                qz = qz*qwi +qw*qzi +qx*qyi -qy*qxi
            return mathutils.Vector((qx,qy,qz,qw))

    def do_update_raw(self, context):
        part1 = mathutils.Vector((
            self.default_value_s0,
            self.default_value_s1,
            self.default_value_s2, 1
        ))
        part2 = self.default_value_s3

        self.default_value_raw = self.convert_to_quaternion(
            part1,
            self.default_value_s3,
            self.default_value_mode,
            self.default_value_unit,
            self.default_value_order
        )

    def draw(self, context, layout, node, text):
        if (self.is_output or self.is_linked):
            layout.label(text=self.name)
        else:
            coll1 = layout.column(align=True)
            coll1.label(text=self.name)
            bx=coll1.box()
            coll = bx.column(align=True)
            coll.prop(self, 'default_value_mode')
            if self.default_value_mode in ('EulerAngles', 'AxisAngle'):
                coll.prop(self, 'default_value_unit')

            if self.default_value_mode == 'EulerAngles':
                coll.prop(self, 'default_value_order')
                coll.prop(self, 'default_value_s0', text='X')
                coll.prop(self, 'default_value_s1', text='Y')
                coll.prop(self, 'default_value_s2', text='Z')
            elif self.default_value_mode == 'Quaternion':
                coll.prop(self, 'default_value_s0', text='X')
                coll.prop(self, 'default_value_s1', text='Y')
                coll.prop(self, 'default_value_s2', text='Z')
                coll.prop(self, 'default_value_s3', text='W')
            elif self.default_value_mode == 'AxisAngle':
                coll.prop(self, 'default_value_s0', text='X')
                coll.prop(self, 'default_value_s1', text='Y')
                coll.prop(self, 'default_value_s2', text='Z')
                coll.separator()
                coll.prop(self, 'default_value_s3', text='Angle')

    def draw_color(self, context, node):
        return socket_colors[self.bl_idname]

    default_value_mode: EnumProperty(
        items=[('EulerAngles', 'Euler Angles', 'Euler Angles'),
               ('AxisAngle', 'Axis/Angle', 'Axis/Angle'),
               ('Quaternion', 'Quaternion', 'Quaternion')],
        name='', default='EulerAngles',
        update=on_mode_update)

    default_value_unit: EnumProperty(
        items=[('Deg', 'Degrees', 'Degrees'),
               ('Rad', 'Radians', 'Radians')],
        name='', default='Rad',
        update=on_unit_update)
    default_value_order: EnumProperty(
        items=[('XYZ','XYZ','XYZ'),
               ('XZY','XZY (legacy Armory euler order)','XZY (legacy Armory euler order)'),
               ('YXZ','YXZ','YXZ'),
               ('YZX','YZX','YZX'),
               ('ZXY','ZXY','ZXY'),
               ('ZYX','ZYX','ZYX')],
        name='', default='XYZ'
    )

    default_value_s0: FloatProperty(update=do_update_raw)
    default_value_s1: FloatProperty(update=do_update_raw)
    default_value_s2: FloatProperty(update=do_update_raw)
    default_value_s3: FloatProperty(update=do_update_raw)

    default_value_raw: FloatVectorProperty(
        name='Value',
        description='Raw quaternion obtained for the default value of a ArmRotationSocket socket',
        size=4, default=(0,0,0,1),
        update = _on_update_socket
    )

    def copy_defaults(self, socket):
        if socket.bl_idname == self.bl_idname:
            socket.default_value_mode = self.default_value_mode
            socket.default_value_unit = self.default_value_unit
            socket.default_value_order = self.default_value_order
            socket.default_value_s0 = self.default_value_s0
            socket.default_value_s1 = self.default_value_s1
            socket.default_value_s2 = self.default_value_s2
            socket.default_value_s3 = self.default_value_s3
            socket.default_value_raw = self.default_value_raw

class ArmArraySocket(ArmCustomSocket):
    bl_idname = 'ArmNodeSocketArray'
    bl_label = 'Array Socket'
    arm_socket_type = 'NONE'

    def draw(self, context, layout, node, text):
        layout.label(text=self.name)

    def draw_color(self, context, node):
        return socket_colors[self.bl_idname]

class ArmBoolSocket(ArmCustomSocket):
    bl_idname = 'ArmBoolSocket'
    bl_label = 'Boolean Socket'
    arm_socket_type = 'BOOLEAN'

    default_value_raw: BoolProperty(
        name='Value',
        description='Input value used for unconnected socket',
        update=_on_update_socket
    )

    def draw(self, context, layout, node, text):
        draw_socket_layout(self, layout)

    def draw_color(self, context, node):
        return socket_colors[self.bl_idname]

    def get_default_value(self):
        return self.default_value_raw

    def copy_defaults(self, socket):
        if socket.bl_idname == self.bl_idname:
            socket.default_value_raw = self.default_value_raw

class ArmColorSocket(ArmCustomSocket):
    bl_idname = 'ArmColorSocket'
    bl_label = 'Color Socket'
    arm_socket_type = 'RGBA'

    default_value_raw: FloatVectorProperty(
        name='Value',
        size=4,
        subtype='COLOR',
        min=0.0,
        max=1.0,
        default=[0.0, 0.0, 0.0, 1.0],
        description='Input value used for unconnected socket',
        update=_on_update_socket
    )

    def draw(self, context, layout, node, text):
        draw_socket_layout_split(self, layout)

    def draw_color(self, context, node):
        return socket_colors[self.bl_idname]

    def get_default_value(self):
        return self.default_value_raw

    def copy_defaults(self, socket):
        if socket.bl_idname == self.bl_idname:
            socket.default_value_raw = self.default_value_raw

class ArmDynamicSocket(ArmCustomSocket):
    bl_idname = 'ArmDynamicSocket'
    bl_label = 'Dynamic Socket'
    arm_socket_type = 'NONE'

    def draw(self, context, layout, node, text):
        layout.label(text=self.name)

    def draw_color(self, context, node):
        return socket_colors[self.bl_idname]

class ArmAnySocket(ArmCustomSocket):
    bl_idname = 'ArmAnySocket'
    bl_label = 'Any Socket'
    arm_socket_type = 'NONE'

    # Callback function when socket label is changed
    def on_disp_label_update(self, context):
        node = self.node
        if node.bl_idname == 'LNGroupInputsNode' or node.bl_idname == 'LNGroupOutputsNode':
            if not node.invalid_link:
                node.socket_name_update(self)
                self.on_node_update()
                self.name = self.display_label

    display_label: StringProperty(
        name='display_label',
        description='Property to store socket display name',
        update=on_disp_label_update)

    display_color: FloatVectorProperty(
        name='Color',
        size=4,
        subtype='COLOR',
        min=0.0,
        max=1.0,
        default=socket_colors['ArmAnySocket']
    )

    def draw(self, context, layout, node, text):
        layout.label(text=self.display_label)

    def draw_color(self, context, node):
        return self.display_color

    def on_node_update(self):
        # Cache name and color of connected socket
        if self.is_output:
            c_node, c_socket = arm.node_utils.output_get_connected_node(self)
        else:
            c_node, c_socket = arm.node_utils.input_get_connected_node(self)

        if c_node is None:
            self.display_color = socket_colors[self.__class__.bl_idname]
        else:
            if self.display_label == '':
                self.display_label = c_socket.name
            self.display_color = c_socket.draw_color(bpy.context, c_node)

class ArmFloatSocket(ArmCustomSocket):
    bl_idname = 'ArmFloatSocket'
    bl_label = 'Float Socket'
    arm_socket_type = 'VALUE'

    default_value_raw: FloatProperty(
        name='Value',
        description='Input value used for unconnected socket',
        precision=3,
        update=_on_update_socket
    )

    def draw(self, context, layout, node, text):
        draw_socket_layout(self, layout)

    def draw_color(self, context, node):
        return socket_colors[self.bl_idname]

    def get_default_value(self):
        return self.default_value_raw

    def copy_defaults(self, socket):
        if socket.bl_idname == self.bl_idname:
            socket.default_value_raw = self.default_value_raw

class ArmIntSocket(ArmCustomSocket):
    bl_idname = 'ArmIntSocket'
    bl_label = 'Integer Socket'
    arm_socket_type = 'INT'

    default_value_raw: IntProperty(
        name='Value',
        description='Input value used for unconnected socket',
        update=_on_update_socket
    )

    def draw(self, context, layout, node, text):
        draw_socket_layout(self, layout)

    def draw_color(self, context, node):
        return socket_colors[self.bl_idname]

    def get_default_value(self):
        return self.default_value_raw

    def copy_defaults(self, socket):
        if socket.bl_idname == self.bl_idname:
            socket.default_value_raw = self.default_value_raw

class ArmObjectSocket(ArmCustomSocket):
    bl_idname = 'ArmNodeSocketObject'
    bl_label = 'Object Socket'
    arm_socket_type = 'OBJECT'

    default_value_get: PointerProperty(name='Object', type=bpy.types.Object)  # legacy version of the line after this one
    default_value_raw: PointerProperty(name='Object', type=bpy.types.Object, update=_on_update_socket)

    def __init__(self):
        super().__init__()
        if self.default_value_get is not None:
            self.default_value_raw = self.default_value_get
            self.default_value_get = None

    def get_default_value(self):
        if self.default_value_raw is None:
            return ''
        if self.default_value_raw.name not in bpy.data.objects:
            return self.default_value_raw.name
        return arm.utils.asset_name(bpy.data.objects[self.default_value_raw.name])

    def draw(self, context, layout, node, text):
        if self.is_output:
            layout.label(text=self.name)
        elif self.is_linked:
            layout.label(text=self.name)
        else:
            row = layout.row(align=True)
            row.prop_search(self, 'default_value_raw', context.scene, 'objects', icon='NONE', text=self.name)

    def draw_color(self, context, node):
        return socket_colors[self.bl_idname]

    def copy_defaults(self, socket):
        if socket.bl_idname == self.bl_idname:
            socket.default_value_raw = self.default_value_raw

class ArmStringSocket(ArmCustomSocket):
    bl_idname = 'ArmStringSocket'
    bl_label = 'String Socket'
    arm_socket_type = 'STRING'

    default_value_raw: StringProperty(
        name='Value',
        description='Input value used for unconnected socket',
        update=_on_update_socket
    )

    def draw(self, context, layout, node, text):
        draw_socket_layout_split(self, layout)

    def draw_color(self, context, node):
        return socket_colors[self.bl_idname]

    def get_default_value(self):
        return self.default_value_raw

    def copy_defaults(self, socket):
        if socket.bl_idname == self.bl_idname:
            socket.default_value_raw = self.default_value_raw

class ArmVectorSocket(ArmCustomSocket):
    bl_idname = 'ArmVectorSocket'
    bl_label = 'Vector Socket'
    arm_socket_type = 'VECTOR'

    default_value_raw: FloatVectorProperty(
        name='Value',
        size=3,
        precision=3,
        description='Input value used for unconnected socket',
        update=_on_update_socket
    )

    def draw(self, context, layout, node, text):
        if not self.is_output and not self.is_linked:
            col = layout.column(align=True)
            col.label(text=self.name + ":")
            col.prop(self, 'default_value_raw', text='')
        else:
            layout.label(text=self.name)

    def draw_color(self, context, node):
        return socket_colors[self.bl_idname]

    def get_default_value(self):
        return self.default_value_raw

    def copy_defaults(self, socket):
        if socket.bl_idname == self.bl_idname:
            socket.default_value_raw = self.default_value_raw

def draw_socket_layout(socket: bpy.types.NodeSocket, layout: bpy.types.UILayout, prop_name='default_value_raw'):
    if not socket.is_output and not socket.is_linked:
        layout.prop(socket, prop_name, text=socket.name)
    else:
        layout.label(text=socket.name)

def draw_socket_layout_split(socket: bpy.types.NodeSocket, layout: bpy.types.UILayout, prop_name='default_value_raw'):
    if not socket.is_output and not socket.is_linked:
        # Blender layouts use 0.4 splits
        layout = layout.split(factor=0.4, align=True)

    layout.label(text=socket.name)

    if not socket.is_output and not socket.is_linked:
        layout.prop(socket, prop_name, text='')

def _make_socket_interface(interface_name: str, bl_idname: str) -> Type[bpy.types.NodeSocketInterface]:
    """Create a socket interface class that is used by Blender for node
    groups. We currently don't use real node groups, but without these
    classes Blender will (incorrectly) draw the socket borders in light grey.
    """
    def draw(self, context, layout):
        pass

    def draw_color(self, context):
        # This would be used if we were using "real" node groups
        return 0, 0, 0, 1

    cls = type(
        interface_name,
        (bpy.types.NodeSocketInterface, ), {
            'bl_socket_idname': bl_idname,
            'draw': draw,
            'draw_color': draw_color,
        }
    )
    return cls

ArmActionSocketInterface = _make_socket_interface('ArmActionSocketInterface', 'ArmNodeSocketAction')
ArmAnimSocketInterface = _make_socket_interface('ArmAnimSocketInterface', 'ArmNodeSocketAnimAction')
ArmRotationSocketInterface = _make_socket_interface('ArmRotationSocketInterface', 'ArmRotationSocket')
ArmArraySocketInterface = _make_socket_interface('ArmArraySocketInterface', 'ArmNodeSocketArray')
ArmBoolSocketInterface = _make_socket_interface('ArmBoolSocketInterface', 'ArmBoolSocket')
ArmColorSocketInterface = _make_socket_interface('ArmColorSocketInterface', 'ArmColorSocket')
ArmDynamicSocketInterface = _make_socket_interface('ArmDynamicSocketInterface', 'ArmDynamicSocket')
ArmFloatSocketInterface = _make_socket_interface('ArmFloatSocketInterface', 'ArmFloatSocket')
ArmIntSocketInterface = _make_socket_interface('ArmIntSocketInterface', 'ArmIntSocket')
ArmObjectSocketInterface = _make_socket_interface('ArmObjectSocketInterface', 'ArmNodeSocketObject')
ArmStringSocketInterface = _make_socket_interface('ArmStringSocketInterface', 'ArmStringSocket')
ArmVectorSocketInterface = _make_socket_interface('ArmVectorSocketInterface', 'ArmVectorSocket')
ArmAnySocketInterface = _make_socket_interface('ArmAnySocketInterface', 'ArmAnySocket')

__REG_CLASSES = (
    ArmActionSocketInterface,
    ArmAnimSocketInterface,
    ArmRotationSocketInterface,
    ArmArraySocketInterface,
    ArmBoolSocketInterface,
    ArmColorSocketInterface,
    ArmDynamicSocketInterface,
    ArmFloatSocketInterface,
    ArmIntSocketInterface,
    ArmObjectSocketInterface,
    ArmStringSocketInterface,
    ArmVectorSocketInterface,
    ArmAnySocketInterface,

    ArmActionSocket,
    ArmAnimActionSocket,
    ArmRotationSocket,
    ArmArraySocket,
    ArmBoolSocket,
    ArmColorSocket,
    ArmDynamicSocket,
    ArmFloatSocket,
    ArmIntSocket,
    ArmObjectSocket,
    ArmStringSocket,
    ArmVectorSocket,
    ArmAnySocket,
)
register, unregister = bpy.utils.register_classes_factory(__REG_CLASSES)


import discord
import sys
import foods
import dice
import scores
from game_logic import is_over, play_game

MAX_RANGE = 1000
intents = discord.Intents.default()
intents.message_content = True

client = discord.Client(intents=intents)

playing = False

@client.event
async def on_ready():

    print(f'We have logged in as {client.user}')
    # Load the list of foods from the file
    foods.load_foods()
    scores.load_scores()

@client.event
async def on_message(message):
    global MAX_RANGE
    global playing

    if message.author == client.user:
        return

    # Handle the "foods" and "food" commands
    if message.content.lower().startswith('$foods') or message.content.lower().startswith('$food'):
        await message.channel.send(f'Pierre should eat {foods.get_random_food()}.')

    elif message.content.lower().startswith('$addfood'):
        await message.channel.send(f'```Please enter the name of the food you would like to add to the list or type $cancel to cancel adding a food to the list```')
        message = await client.wait_for('message')
        if message.content.lower().startswith('$cancel'):
            return
        while message.author == client.user:
            message = await client.wait_for('message')
        food = message.content
        foods.add_food(food)
        await message.channel.send(f'```Added {food} to the list```')
        food.load_foods()

    elif message.content.lower().startswith('$reload'):
        foods.load_foods()
        await message.channel.send("```Food list has been reloaded```")

    elif message.content.lower().startswith('$d20'):
      await message.channel.send(f'```{str(message.author).split("#")[0]} {dice.roll_d20()}```')

    elif message.content.lower().startswith('$scores'):
        await message.channel.send(scores.print_scores())

#edit to make sure game aint going
    if message.content.lower() =='$stop' and is_over() == True:
        await message.channel.send(f'```Shutting down.```')
        sys.exit(0)
    elif message.content.lower() =='$stop':
        await message.channel.send(f'```There is currently a game going on, please wait.```')
    if message.content.lower().startswith('$start'):
        scores_dict = scores.get_scores()
        print(scores_dict)
        await play_game(message, client, scores_dict)

    if message.content.lower().startswith('$help'):
      await message.channel.send(f'```Commands:\n$foods or $food: Return a random food for Pierre to eat.\n$addfood: Add a new food to the list.\n$reload: Reload the list of foods.\n$scores: Get the current scores.\n$d20: Roll a d20.\n$start: Start the random number game.```')

#token here
client.run('')


from omegaconf import OmegaConf
import torch

import logging
from agent.polybeast.models.base import BaseNet, RandomNet, HalfCheetahAgent
from nle.env.base import DUNGEON_SHAPE
from envs.skills_all import HalfCheetah
from agent.common.envs import tasks
from agent.polybeast.models import BaseNet

def create_basenet(flags, device):
    model_string = flags.model
    logging.critical(flags.model)
    if model_string == "baseline":
        model_cls = BaseNet
    elif model_string == "baseline_c":
        model_cls = HalfCheetahAgent
    elif model_string == "cnn" or model_string == "transformer":
        raise RuntimeError(
            "model=%s deprecated, use model=baseline crop_model=%s instead"
            % (model_string, model_string)
        )
    else:
        raise NotImplementedError("model=%s" % model_string)

    if flags.model in ["baseline_c","hks_c"]:
        logging.critical(flags.model)
        print(flags.model)
        env = HalfCheetah()()#have a functor, first brackets is constructor and second is a function call
        model = model_cls(env.observation_space,env.action_space,flags,device)
    else:
        num_actions = len(
            tasks.ENVS[flags.env](savedir=None, archivefile=None).actions
        )
        model = model_cls(DUNGEON_SHAPE, num_actions, flags, device)

    model.to(device=device)
    return model

def load_model(env, pretrained_path, pretrained_config_path, device):
    flags = OmegaConf.load(pretrained_config_path)
    flags["env"] = env
    model = create_basenet(flags, device)

    checkpoint_states = torch.load(pretrained_path, map_location=device)

    model.load_state_dict(checkpoint_states["model_state_dict"])
    # model.training = False

    hidden = model.initial_state(batch_size=1)
    return model, hidden


from django.shortcuts import render, redirect
from .models import tournament as t_db
from .models import registration
from .models import tournamentMatch
from .forms import NewTournamentForm
from users.models import Profile
from django.contrib import messages
from underscore import _
from django.core import serializers
import json

# Create your views here.

def updateScore(request, id=0):
    match = tournamentMatch.objects.get(pk=id)
    if request.method == 'POST':
        if match.tourn_id.completed:
            messages.warning(request, 'This tournament is already completed!')
            return redirect('tournamentView', tid=match.tourn_id.id)
        win_id = int(request.POST.get('winner'))
        win = registration.objects.get(pk=win_id)
        match.winner = win
        match.save()
        if match.nextGame:
            next = tournamentMatch.objects.get(tourn_id=match.tourn_id, bracketNo=match.nextGame)
            if next.p1 is None:
                next.p1 = win
            elif next.p2 is None:
                next.p2 = win
            else:
                messages.warning(request, 'Winners already selected!')
                return redirect('tournamentView', tid=match.tourn_id.id)
            next.save()
        else:
            match.tourn_id.winner = win.player
            match.tourn_id.completed = True
            match.tourn_id.save()
        return redirect('tournamentView', tid=match.tourn_id.id)

    context = {
        'match': match,
    }
    return render(request, 'tournament/updateScore.html', context)

def tournament(request, tid=0):
    tm = t_db.objects.get(id=tid)
    regs = registration.objects.filter(tournament=tid)
    matches = tournamentMatch.objects.filter(tourn_id=tid)
    if request.method == 'POST' and 'register' in request.POST:
        reg = registration(player=request.user, tournament=tm)
        reg.save()

    if request.method == "POST" and 'start' in request.POST:
        if regs.count() != tm.no_of_players:
            messages.warning(request, 'Incorrect number of players registered!')
            return redirect(str(tid))
        tm.started = True
        tm.save()
        startBracket(regs, tm.no_of_players, tm)

    jsons = serializers.serialize('json', matches)

    users = {}

    for reg in regs:
        users[reg.id] = reg.player.username

    users = json.dumps(users)

    print(users)

    context = {
        'tournament': tm,
        'regs': regs,
        'matches': jsons,
        'users': users
    }

    return render(request, 'tournament/tournament.html', context)

def new(request):
    if request.method == 'POST':
        tournament = t_db(creator=request.user)
        form = NewTournamentForm(request.POST, instance=tournament)
        if form.is_valid():
            form.save()
            messages.success(request, 'You have successfully created a new tournament!')
            return redirect('dashboard')
    else:
        form = NewTournamentForm()
    context = {
        'form': form
    }
    return render(request, 'tournament/new.html', context)

def startBracket(regs, base, tm):
    knownBrackets = [2, 4, 8, 16, 32]
    bracketCount = 0
    teams = _.shuffle(list(regs))
    closest = _.find(knownBrackets, lambda k, *a: k >= base)
    byes = closest - base

    if byes > 0:
        base = closest

    brackets = []
    rounds = 1
    baseT = base / 2
    baseC = base / 2
    teamMark = 0
    nextInc = base / 2

    print(teams[1])

    for i in range(1, base):
        print(teamMark)
        baseR = i / baseT
        isBye = False

        if byes > 0 and (i % 2 != 0 or byes >= baseT - i):
            isBye = True
            byes - 1
        last = _.map(_.filter(brackets, lambda b, *a: b['nextGame'] == i), lambda c, *a: { 'game': c['bracketNo']})
        brackets.append({
            'lastGames': None if rounds == 1 else [last[0]['game'], last[1]['game']],
            'nextGame': None if nextInc + i > base - 1 else nextInc + i,
            'p1': teams[teamMark] if rounds == 1 else None,
            'p2': teams[teamMark + 1] if rounds == 1 else None,
            'bracketNo': i,
            'roundNo': rounds,
            'bye': isBye,
        })

        teamMark += 2
        if i % 2 != 0:
            nextInc -= 1

        while baseR >= 1:
            rounds += 1
            baseC /= 2
            baseT = baseT + baseC
            baseR = i / baseT

    for match in brackets:
        match = tournamentMatch(tourn_id=tm, p1=match['p1'], p2=match['p2'], roundNo=match['roundNo'], bye=match['bye'], lastGames=match['lastGames'], nextGame=match['nextGame'], bracketNo=match['bracketNo'])
        match.save()
    return brackets


from collections import deque

with open('input.txt', 'r') as f:
    n, m = map(int, f.readline().split())
    b = []
    for i in range(n):
        b.append(int(f.readline()))

print(b)

feed = []
i = 0
type = None
add_later = deque([])
while i < n:
    if b[i] != type:
        feed.append(i)
        type = b[i]
    else:
        for j in range(len(add_later)):
            if type != b[add_later[j]]:
                feed.append(add_later[j])
                del add_later[j]
                break
        add_later.append(i)
    i += 1

print(feed)

# def value(i, j):
#     return 2**(-i) * 2**(-j)
#
# def printknapSack(W, wt, n):
#     K = [[0 for w in range(W + 1)]
#             for i in range(n + 1)]
#
#     # Build table K[][] in bottom
#     # up manner
#     for i in range(n + 1):
#         for w in range(W + 1):
#             if i == 0 or w == 0:
#                 K[i][w] = 0
#             elif wt[i - 1] <= w:
#                 K[i][w] = max(value(i-1, w-1)
#                   + K[i - 1][w - wt[i - 1]],
#                                K[i - 1][w])
#             else:
#                 K[i][w] = K[i - 1][w]
#
#
#
#     res = K[n][W]
#     print(res)
#
#     w = W
#     for i in range(n, 0, -1):
#         if res <= 0:
#             break
#         # either the result comes from the
#         # top (K[i-1][w]) or from (val[i-1]
#         # + K[i-1] [w-wt[i-1]]) as in Knapsack
#         # table. If it comes from the latter
#         # one/ it means the item is included.
#         if res == K[i - 1][w]:
#             continue
#         else:
#
#             # This item is included.
#             print(w)
#
#             # Since this weight is included
#             # its value is deducted
#             res = res - value(i,w)
#             w = w - wt[i - 1]
#
# # Driver code
# wt = [ 1 for i in range(n) ]
# W = n
#
# printknapSack(W, wt, n)


import logging

import numpy as np
from timeit import default_timer as timer

import alphai_crocubot_oracle.crocubot.evaluate as crocubot_eval
import pandas as pd
from alphai_crocubot_oracle.oracle import CrocubotOracle
from alphai_feature_generation.transformation import GymDataTransformation
from copy import deepcopy

from alphai_metacrocubot_oracle.result import FeatureSensitivity, OraclePrediction

class MetaCrocubotOracle(CrocubotOracle):

    def _init_data_transformation(self):
        data_trans_conf = self.config['data_transformation']
        data_trans_conf[GymDataTransformation.KEY_EXCHANGE] = self.calendar_name
        data_trans_conf["features_start_market_minute"] = self.scheduling['training_frequency']['minutes_offset']
        data_trans_conf["prediction_market_minute"] = self.scheduling['prediction_frequency']['minutes_offset']
        data_trans_conf["target_delta"] = self.prediction_horizon
        data_trans_conf["target_market_minute"] = self.scheduling['prediction_frequency']['minutes_offset']
        data_trans_conf["n_classification_bins"] = self.config['model']["n_classification_bins"]
        data_trans_conf["classify_per_series"] = self.config['model']["classify_per_series"]
        data_trans_conf["normalise_per_series"] = self.config['model']["normalise_per_series"]
        data_trans_conf["n_assets"] = self.config['model']["n_assets"]

        self._data_transformation = GymDataTransformation(data_trans_conf)

        self._target_feature = self._data_transformation.get_target_feature()
        self._n_features = len(self._data_transformation.features)

    def _sanity_check(self):
        pass

    def _init_universe_provider(self):
        pass

    def get_universe(self, data):
        return None

    def _preprocess_outputs(self, train_y_dict):

        train_y = list(train_y_dict.values())[0]
        train_y = np.swapaxes(train_y, axis1=1, axis2=2)

        if self._tensorflow_flags.predict_single_shares:
            n_feat_y = train_y.shape[3]
            train_y = np.reshape(train_y, [-1, 1, 1, n_feat_y])

        if self.network == 'dropout':
            train_y = np.squeeze(train_y)

        self.verify_y_data(train_y)

        return train_y.astype(np.float32)

    def _filter_universe_from_data_for_prediction(self, data, *args):
        return data

    def verify_pricing_data(self, predict_data):
        pass

    def predict(self, data, current_timestamp, *args, **kwargs):
        """
             Main method that gives us a prediction after the training phase is done

             :param data: The dict of dataframes to be used for prediction
             :type data: dict
             :param current_timestamp: The timestamp of the time when the prediction is executed
             :type current_timestamp: datetime.datetime
             :return: Mean vector or covariance matrix together with the timestamp of the prediction
             :rtype: PredictionResult
             """

        if self._topology is None:
            logging.warning('Not ready for prediction - safer to run train first')

        logging.info('Crocubot Oracle prediction on {}.'.format(current_timestamp))

        self.verify_pricing_data(data)
        latest_train_file = self._train_file_manager.latest_train_filename(current_timestamp)
        predict_x, symbols, prediction_timestamp, target_timestamp = self._data_transformation.create_predict_data(data)

        feature_list = list(predict_x.keys())

        predict_x = self._preprocess_inputs(predict_x)

        logging.info('Executing Main Prediction')
        prediction_result = self._do_single_prediction(
            predict_x,
            latest_train_file,
            symbols,
            current_timestamp,
            target_timestamp
        )

        for i in range(predict_x.shape[3]):
            feature_name = feature_list[i]
            perturbed_x = deepcopy(predict_x)
            perturbed_x[:, :, :, i] = 0

            try:
                logging.info('Executing sensitivity prediction for feature {}'.format(feature_name))
                perturbed_result = self._do_single_prediction(
                    perturbed_x,
                    latest_train_file,
                    symbols,
                    current_timestamp,
                    target_timestamp
                )

                perturbation = perturbed_result.mean_vector - prediction_result.mean_vector

                logging.info("Calculated sensitivity for feature [{}]".format(feature_name))

                prediction_result.add_feature_sensitivity(FeatureSensitivity(feature_name, perturbation))
            except Exception as e:
                logging.error("Error calculating sensitivy for feature [{}]. Reason: {}".format(
                    feature_name, e
                ))
        return prediction_result

    def _do_single_prediction(self, predict_x, latest_train_file, symbols, current_timestamp,
                              target_timestamp):

        start_time = timer()

        if self._topology is None:
            n_timesteps = predict_x.shape[2]
            self.initialise_topology(n_timesteps)

        network_input_shape = self._topology.get_network_input_shape()
        data_input_shape = predict_x.shape[-3:]

        if data_input_shape != network_input_shape:
            err_msg = 'Data shape' + str(data_input_shape) + " doesnt match network input " + str(
                network_input_shape)
            raise ValueError(err_msg)

        predict_y = crocubot_eval.eval_neural_net(
            predict_x, self._topology,
            self._tensorflow_flags,
            latest_train_file
        )

        end_time = timer()
        eval_time = end_time - start_time
        logging.info("Network evaluation took: {} seconds".format(eval_time))

        means, conf_low, conf_high = self._data_transformation.inverse_transform_multi_predict_y(predict_y, symbols)
        self.log_validity_of_predictions(means, conf_low, conf_high)

        means_series = pd.Series(np.squeeze(means), index=symbols)
        conf_low_series = pd.Series(np.squeeze(conf_low), index=symbols)
        conf_high_series = pd.Series(np.squeeze(conf_high), index=symbols)

        return OraclePrediction(means_series, conf_low_series, conf_high_series, current_timestamp, target_timestamp)

    @staticmethod
    def log_validity_of_predictions(means, conf_low, conf_high):
        """ Checks that the network outputs are sensible. """

        if not (np.isfinite(conf_low).all() and np.isfinite(conf_high).all()):
            logging.warning('Confidence interval contains non-finite values.')

        if not np.isfinite(means).all():
            logging.warning('Means found to contain non-finite values.')

        logging.debug('Samples from predicted means: {}'.format(means.flatten()[0:10]))


import discord
from discord.ext import commands, tasks
from discord import Embed
import api
import database as db
from util import checks, log
import logging
from datetime import datetime, timezone, timedelta
from dateutil import parser
import pytz

logger = logging.getLogger('__name__')
logger.setLevel(logging.INFO)
handler = logging.FileHandler(
    filename='discord.log', encoding='utf-8', mode='w')
handler.setFormatter(logging.Formatter(
    '%(asctime)s:%(levelname)s:%(name)s: %(message)s'))
logger.addHandler(handler)

class Diamond(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.diamond_check.start()

    @commands.group(aliases=['d'], hidden=True)
    async def diamond(self, ctx):
        if ctx.invoked_subcommand is None:

            pass

    @diamond.command()
    @checks.is_owner()
    async def setup(self, ctx, channel: discord.TextChannel, role: discord.Role):
        try:
            await db.add_diamond_role(ctx.guild.id, role.id)
            await db.add_diamond_channel(ctx.guild.id, channel.id)
            await db.update_timestamp(ctx.guild.id, datetime.utcnow())
            await ctx.send("Succesfully added the channel and role")
        except Exception as e:
            await ctx.send(e)
            raise e

    @diamond.command()
    @checks.is_owner()
    async def toggle(self, ctx, boolean: bool):
        try:
            await db.enable_diamond_ping(ctx.guild.id, boolean)
            await ctx.send(f"Diamond pings have been set to: {boolean}")
        except Exception as e:
            await ctx.send(e)
            raise e

    @diamond.command()
    @checks.is_owner()
    async def config(self, ctx):

        config = await db.server_config(ctx.guild.id)
        print(config)
        ID, ping_bool, role, channel, timestamp = config[0]
        embed = Embed(title="Server Config",
                      description=f"ID: {ID}\nDiamond Ping: {ping_bool}\nPinged Role: {ctx.guild.get_role(role)}\nChannel: {ctx.guild.get_channel(channel)}")
        await ctx.send(embed=embed)

    @tasks.loop(minutes=1, reconnect=True)
    async def diamond_check(self):
        # print('starting diamond check')
        cheap_diamonds = False
        more_than_200 = False
        string = ""
        listings = await api.diamond_market()
        allservers = await db.all_servers()
        # listings = [{"price_per_diamond": 1, "diamonds_remaining": 5}]

        # Servers who have premium and have a properly configured diamond pings
        filtered = [
            x for x in allservers if x.premium and x.diamond_ping and x.diamond_role is not None and x.diamond_channel is not None]

        for server in filtered:
            diamond = [x for x in listings if x['price_per_diamond']
                       < server.diamond_amount]

            if diamond is not []:
                embed = Embed(title="Cheap Diamonds!!!")
                string = ""
                for list in diamond:
                    string += f"There are {list['diamonds_remaining']} diamonds left at {list['price_per_diamond']:,} each.\n"

                embed.description = string
                guild = self.bot.get_guild(server.serverid)
                if guild is None:
                    continue
                chan = self.bot.get_channel(server.diamond_channel)
                role = guild.get_role(server.diamond_role)

                if chan is None or role is None:
                    embed = Embed(title="Diamond Config is missing role or channel",
                                  description=f"Role: {role}\nChannel: {chan}")
                    await log.server_log_embed(self.bot, server.serverid, embed)
                    continue
                if server.last_pinged is None:
                    await db.update_timestamp(server.serverid, datetime.now(timezone.utc))
                    continue
                plus30min = server.last_pinged + timedelta(minutes=29)
                plus30min = pytz.utc.localize(plus30min)

                if plus30min < datetime.now(timezone.utc):
                    await chan.send(f'{role.mention}', embed=embed)
                    await db.update_timestamp(server.serverid, datetime.now(timezone.utc))

    @diamond_check.before_loop
    async def before_diamodn_check(self):
        await self.bot.wait_until_ready()

def setup(bot):
    bot.add_cog(Diamond(bot))
    print("Diamond Cog Loaded")


import json
import os
from os.path import dirname, join
import tempfile
from pathlib import Path
from shutil import copyfile, rmtree
from unittest import TestCase

from unittest.mock import call, Mock, patch

from msm import MycroftSkillsManager, AlreadyInstalled, AlreadyRemoved
from msm.exceptions import MsmException
from msm.skill_state import device_skill_state_hash

class TestMycroftSkillsManager(TestCase):
    def setUp(self):
        temp_dir = tempfile.mkdtemp()
        self.temp_dir = Path(temp_dir)
        self.skills_json_path = self.temp_dir.joinpath('skills.json')
        self.skills_dir = self.temp_dir.joinpath('skills')
        self._build_fake_skills()
        self._mock_skills_json_path()
        self._mock_skill_entry()
        self._mock_skill_repo()
        copyfile(join(dirname(__file__), 'skills_test.json'),
                 str(self.skills_json_path))
        self.msm = MycroftSkillsManager(
            platform='default',
            skills_dir=str(self.temp_dir.joinpath('skills')),
            repo=self.skill_repo_mock,
            versioned=True
        )

    def _build_fake_skills(self):
        foo_skill_dir = self.skills_dir.joinpath('skill-foo')
        foo_skill_dir.mkdir(parents=True)
        foo_skill_dir.joinpath('__init__.py').touch()
        bar_skill_dir = self.skills_dir.joinpath('skill-bar')
        bar_skill_dir.mkdir(parents=True)
        bar_skill_dir.joinpath('__init__.py').touch()

    def _mock_log(self):
        log_patch = patch('msm.mycroft_skills_manager.LOG')
        self.addCleanup(log_patch.stop)
        self.log_mock = log_patch.start()

    def _mock_skills_json_path(self):
        savedatapath_patch = patch('msm.skill_state.get_state_path')
        self.skills_json_path_mock = savedatapath_patch.start()
        self.skills_json_path_mock.return_value = str(
            self.temp_dir.joinpath('skills.json')
        )

        self.addCleanup(savedatapath_patch.stop)

    def _mock_skill_entry(self):
        skill_entry_patch = patch(
            'msm.mycroft_skills_manager.SkillEntry.install',
            spec=True
        )
        self.addCleanup(skill_entry_patch.stop)
        self.skill_entry_mock = skill_entry_patch.start()

    def _mock_skill_repo(self):
        skill_repo_patch = patch(
            'msm.mycroft_skills_manager.SkillRepo',
            spec=True

        )
        self.addCleanup(skill_repo_patch.stop)
        self.skill_repo_mock = skill_repo_patch.start()
        self.skill_repo_mock.skills_meta_info = {
            'https://skill_foo_url': None
        }

    def teardown(self):
        rmtree(str(self.temp_dir))

    def test_device_skill_state(self):
        """Contents of skills.json are loaded into memory"""
        state = self.msm.device_skill_state
        initial_state = [
            dict(
                name='skill-foo',
                origin='default',
                beta=False,
                status='active',
                installed=12345,
                updated=0,
                installation='installed',
                skill_gid='@|skill-foo'
            ),
            dict(
                name='skill-bar',
                origin='default',
                beta=False,
                status='active',
                installed=23456,
                updated=0,
                installation='installed',
                skill_gid='@|skill-bar'
            )
        ]

        self.assertListEqual(initial_state, state['skills'])
        self.assertListEqual([], state['blacklist'])
        self.assertEqual(2, state['version'])

        new_hash = device_skill_state_hash(self.msm.device_skill_state)
        self.assertEqual(new_hash, self.msm.device_skill_state_hash)

    def test_build_device_skill_state(self):
        """No skill.json file so build one."""
        os.remove(str(self.skills_json_path))
        self.msm._device_skill_state = None
        self.msm._init_skills_data()
        state = self.msm.device_skill_state

        initial_state = [
            dict(
                name='skill-bar',
                origin='non-msm',
                beta=False,
                status='active',
                installed=0,
                updated=0,
                installation='installed',
                skill_gid='@|skill-bar'
            ),
            dict(
                name='skill-foo',
                origin='non-msm',
                beta=False,
                status='active',
                installed=0,
                updated=0,
                installation='installed',
                skill_gid='@|skill-foo'
            )
        ]

        self.assertTrue(self.skills_json_path.exists())
        with open(str(self.skills_json_path)) as skills_json:
            device_skill_state = json.load(skills_json)
        self.assertListEqual(sorted(initial_state, key=lambda x: x['name']),
                             sorted(device_skill_state['skills'], key=lambda x: x['name']))
        self.assertListEqual(sorted(initial_state, key=lambda x: x['name']),
                             sorted(device_skill_state['skills'], key=lambda x: x['name']))
        self.assertListEqual([], state['blacklist'])
        self.assertListEqual([], device_skill_state['blacklist'])
        self.assertEqual(2, state['version'])
        self.assertEqual(2, device_skill_state['version'])
        new_hash = device_skill_state_hash(self.msm.device_skill_state)
        self.assertEqual(new_hash, self.msm.device_skill_state_hash)

    def test_remove_from_device_skill_state(self):
        """Remove a file no longer installed from the device's skill state.

        Delete skill-bar from the local skills.  This should trigger it being
        removed from the device skill state.
        """

        del(self.msm.local_skills['skill-bar'])
        self.msm._device_skill_state = None
        state = self.msm.device_skill_state

        initial_state = [
            dict(
                name='skill-foo',
                origin='default',
                beta=False,
                status='active',
                installed=12345,
                updated=0,
                installation='installed',
                skill_gid='@|skill-foo'
            )
        ]

        self.assertListEqual(initial_state, state['skills'])
        self.assertListEqual([], state['blacklist'])
        self.assertEqual(2, state['version'])

    def test_skill_list(self):
        """The skill.list() method is called."""
        all_skills = self.msm.list()

        skill_names = [skill.name for skill in all_skills]
        self.assertIn('skill-foo', skill_names)
        self.assertIn('skill-bar', skill_names)
        self.assertEqual(2, len(all_skills))
        self.assertIsNone(self.msm._local_skills)
        self.assertIsNone(self.msm._default_skills)
        self.assertEqual(all_skills, self.msm._all_skills)

    def test_install(self):
        """Install a skill

        Test that the install method was called on the skill being installed
        and that the new skill was added to the device's skill state.
        """
        skill_to_install = self.skill_entry_mock()
        skill_to_install.name = 'skill-test'
        skill_to_install.skill_gid = 'test-skill|99.99'
        skill_to_install.is_beta = False
        with patch('msm.mycroft_skills_manager.isinstance') as isinstance_mock:
            isinstance_mock.return_value = True
            with patch('msm.mycroft_skills_manager.time') as time_mock:
                time_mock.time.return_value = 100
                self.msm.install(skill_to_install, origin='voice')

        with open(str(self.skills_json_path)) as skills_json:
            device_skill_state = json.load(skills_json)

        skill_test_state = dict(
            name='skill-test',
            origin='voice',
            beta=False,
            status='active',
            installed=100,
            updated=0,
            installation='installed',
            skill_gid='test-skill|99.99'
        )
        self.assertIn(skill_test_state, device_skill_state['skills'])
        self.assertListEqual(
            [call.install(None)],
            skill_to_install.method_calls
        )

    def test_already_installed(self):
        """Attempt install of skill already on the device.

        When this happens, an AlreadyInstalled exception is raised and the
        device skill state is not modified.
        """
        skill_to_install = self.skill_entry_mock()
        skill_to_install.name = 'skill-foo'
        skill_to_install.skill_gid = 'skill-foo|99.99'
        skill_to_install.is_beta = False
        skill_to_install.install = Mock(side_effect=AlreadyInstalled())
        pre_install_hash = device_skill_state_hash(
            self.msm.device_skill_state
        )
        with patch('msm.mycroft_skills_manager.isinstance') as isinstance_mock:
            isinstance_mock.return_value = True
            with self.assertRaises(AlreadyInstalled):
                self.msm.install(skill_to_install)

        self.assertIsNotNone(self.msm._local_skills)
        self.assertIn('all_skills', self.msm._cache)
        post_install_hash = device_skill_state_hash(
            self.msm.device_skill_state
        )
        self.assertEqual(pre_install_hash, post_install_hash)

    def test_install_failure(self):
        """Install attempt fails for whatever reason

        When an install fails, the installation will raise a MsmException.  The
        skill install will be saved to the device skill state as failed and
        the error that caused the exception will be included in the state.
        """
        skill_to_install = self.skill_entry_mock()
        skill_to_install.name = 'skill-test'
        skill_to_install.skill_gid = 'skill-test|99.99'
        skill_to_install.is_beta = False
        skill_to_install.install = Mock(side_effect=MsmException('RED ALERT!'))
        with patch('msm.mycroft_skills_manager.isinstance') as isinstance_mock:
            with self.assertRaises(MsmException):
                isinstance_mock.return_value = True
                self.msm.install(skill_to_install, origin='cli')

        with open(str(self.skills_json_path)) as skills_json:
            device_skill_state = json.load(skills_json)

        skill_test_state = dict(
            name='skill-test',
            origin='cli',
            beta=False,
            status='error',
            installed=0,
            updated=0,
            installation='failed',
            skill_gid='skill-test|99.99',
            failure_message='RED ALERT!'
        )
        self.assertIn(skill_test_state, self.msm.device_skill_state['skills'])
        self.assertIn(skill_test_state, device_skill_state['skills'])
        self.assertListEqual(
            [call.install(None)],
            skill_to_install.method_calls
        )

    def test_remove(self):
        """Remove a skill

        Test that the remove method was called on the skill being installed
        and that the new skill was removed from the device's skill state.
        """
        skill_to_remove = self.skill_entry_mock()
        skill_to_remove.name = 'skill-foo'
        pre_install_hash = device_skill_state_hash(
            self.msm.device_skill_state
        )
        with patch('msm.mycroft_skills_manager.isinstance') as isinstance_mock:
            isinstance_mock.return_value = True
            self.msm.remove(skill_to_remove)

        with open(str(self.skills_json_path)) as skills_json:
            device_skill_state = json.load(skills_json)

        skill_names = [skill['name'] for skill in device_skill_state['skills']]
        self.assertNotIn('skill_foo', skill_names)
        skill_names = [
            skill['name'] for skill in self.msm.device_skill_state['skills']
        ]
        self.assertNotIn('skill_foo', skill_names)
        self.assertListEqual([call.remove()], skill_to_remove.method_calls)
        self.assertNotIn('all_skills', self.msm._cache)
        self.assertIsNone(self.msm._local_skills)
        post_install_hash = device_skill_state_hash(
            self.msm.device_skill_state
        )
        self.assertNotEqual(pre_install_hash, post_install_hash)

    def test_already_removed(self):
        """Attempt removal of skill already removed from the device.

        When this happens, an AlreadyRemoved exception is raised and the
        device skill state is not modified.
        """
        skill_to_remove = self.skill_entry_mock()
        skill_to_remove.name = 'skill-foo'
        skill_to_remove.remove = Mock(side_effect=AlreadyRemoved())
        pre_install_hash = device_skill_state_hash(
            self.msm.device_skill_state
        )
        with patch('msm.mycroft_skills_manager.isinstance') as isinstance_mock:
            isinstance_mock.return_value = True
            with self.assertRaises(AlreadyRemoved):
                self.msm.remove(skill_to_remove)

        self.assertListEqual([call.remove()], skill_to_remove.method_calls)
        self.assertIsNotNone(self.msm._local_skills)
        self.assertIn('all_skills', self.msm._cache)
        post_install_hash = device_skill_state_hash(
            self.msm.device_skill_state
        )
        self.assertEqual(pre_install_hash, post_install_hash)

    def test_remove_failure(self):
        """Skill removal attempt fails for whatever reason

        When n removal fails, a MsmException is raised.  The removal will not
        be saved to the device skill state.
        """
        skill_to_remove = self.skill_entry_mock()
        skill_to_remove.name = 'skill-test'
        skill_to_remove.remove = Mock(side_effect=MsmException('RED ALERT!'))
        pre_install_hash = device_skill_state_hash(
            self.msm.device_skill_state
        )
        with patch('msm.mycroft_skills_manager.isinstance') as isinstance_mock:
            isinstance_mock.return_value = True
            with self.assertRaises(MsmException):
                self.msm.remove(skill_to_remove)

        self.assertListEqual(
            [call.remove()],
            skill_to_remove.method_calls
        )
        self.assertIsNotNone(self.msm._local_skills)
        self.assertIn('all_skills', self.msm._cache)
        post_install_hash = device_skill_state_hash(
            self.msm.device_skill_state
        )
        self.assertEqual(pre_install_hash, post_install_hash)

    def test_update(self):
        """Remove a skill

        Test that the remove method was called on the skill being installed
        and that the new skill was removed from the device's skill state.
        """
        skill_to_update = self.skill_entry_mock()
        skill_to_update.name = 'skill-foo'
        skill_to_update.is_beta = False
        pre_install_hash = device_skill_state_hash(
            self.msm.device_skill_state
        )
        with patch('msm.mycroft_skills_manager.time') as time_mock:
            time_mock.time.return_value = 100
            self.msm.update(skill_to_update)

        with open(str(self.skills_json_path)) as skills_json:
            device_skill_state = json.load(skills_json)

        skill_names = [skill['name'] for skill in device_skill_state['skills']]
        self.assertIn('skill-foo', skill_names)

        for skill in self.msm.device_skill_state['skills']:
            if skill['name'] == 'skill-foo':
                self.assertEqual(100, skill['updated'])
        self.assertListEqual([call.update()], skill_to_update.method_calls)
        self.assertNotIn('all_skills', self.msm._cache)
        self.assertIsNone(self.msm._local_skills)
        post_install_hash = device_skill_state_hash(
            self.msm.device_skill_state
        )
        self.assertNotEqual(pre_install_hash, post_install_hash)


import torch
from bench.core.executer import Executer

def __split_heads_qkv(queries, keys, values, n_head, d_key, d_value):
    """
    Reshape input tensors at the last dimension to split multi-heads
    and then transpose. Specifically, transform the input tensor with shape
    [bs, max_sequence_length, n_head * hidden_dim] to the output tensor
    with shape [bs, n_head, max_sequence_length, hidden_dim].
    """
    # The value 0 in shape attr means copying the corresponding dimension
    # size of the input as the output dimension size.
    reshaped_q = torch.reshape(queries, shape=[1, 1, n_head, d_key])
    # permuate the dimensions into:
    # [batch_size, n_head, max_sequence_len, hidden_size_per_head]
    q = torch.transpose(reshaped_q, 1, 2)
    # For encoder-decoder attention in inference, insert the ops and vars
    # into global block to use as cache among beam search.
    reshaped_k = torch.reshape(keys, [1, 1, n_head, d_key])
    k = torch.transpose(reshaped_k, 1, 2)
    reshaped_v = torch.reshape(values, shape=[1, 1, n_head, d_value])
    v = torch.transpose(reshaped_v, 1, 2)
    return q, k, v

def args_adaptor(np_args):
    queries = torch.from_numpy(np_args[0]).cuda()
    keys = torch.from_numpy(np_args[1]).cuda()
    values = torch.from_numpy(np_args[2]).cuda()
    n_head = 12
    d_key = -1
    d_value = -1
    return [queries, keys, values, n_head, d_key, d_value]

def executer_creator():
    return Executer(__split_heads_qkv, args_adaptor)


from flask import Flask, render_template, request, redirect, url_for, send_file, flash
from youtube_downloader import VideoDownloader, PlaylistDownloader
from io import BytesIO
from zipfile import ZipFile

app = Flask(__name__)
app.config['SECRET_KEY'] = 'Powerful Secret Key'

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'GET':
        return render_template('index.html')

    if "VideoLinkInput" in request.form:
        if request.form["VideoLinkInput"] == '':
            flash("Enter the URL.")
            return render_template('index.html')
        elif str(request.form["VideoLinkInput"]).find('?v=') == -1:
            flash("Enter a valid URL.")
            return render_template('index.html')

        video_id = request.form["VideoLinkInput"].split('?v=')[1]
        return redirect(url_for('download_video',vid_id = video_id))

    if "PlaylistLinkInput" in request.form:
        if request.form["PlaylistLinkInput"] == '':
            flash("Enter the URL.")
            return render_template('index.html')
        elif str(request.form["PlaylistLinkInput"]).find('playlist?list=') == -1:
            flash("Enter a valid URL.")
            return render_template('index.html')

        playlist_id = request.form["PlaylistLinkInput"].split('playlist?list=')[1]
        return redirect(url_for('download_playlist',pl_id = playlist_id))

@app.route('/download/video/<string:vid_id>', methods=['GET', 'POST'])
def download_video(vid_id):
    try:
        video = VideoDownloader(f"""https://www.youtube.com/watch?v={vid_id}""")
    except:
        flash("Enter a valid URL.")
        return redirect(url_for('index'))
    if request.method == 'GET':
        return render_template('download_video.html', title = video.title, thumbnail = video.thumbnail_url,
                                resolutions = video.GetAvailableResolutions())

    if request.form['SelectedResolution'] == 'audio':
        return send_file(
            BytesIO(video.StreamToBuffer(request.form['SelectedResolution'])),
            as_attachment = True,
            download_name=f"""{video.title}.mp3""")

    return send_file(
        BytesIO(video.StreamToBuffer(request.form['SelectedResolution'])),
        as_attachment = True,
        download_name=f"""{video.title}.mp4""")

@app.route('/download/playlist/<string:pl_id>', methods=['GET', 'POST'])
def download_playlist(pl_id):
    try:
        playlist = PlaylistDownloader(f"""https://www.youtube.com/playlist?list={pl_id}""")
        videos = playlist.GetVideos()
    except:
        flash("Enter a valid URL.")
        return redirect(url_for('index'))

    if request.method == 'GET':
        return render_template('download_playlist.html', title = playlist.title, videos = videos)

    # Create a ZipFile object in memory
    in_memory = BytesIO()
    with ZipFile(in_memory, 'w') as zip:
        # Add multiple files to the zip file
        for file in videos:
            if request.form['SelectedResolution'] == 'audio':
                zip.writestr(f"""{file.title}.mp3""",file.StreamToBuffer(request.form['SelectedResolution']))
            else:
                zip.writestr(f"""{file.title}.mp4""",file.StreamToBuffer(request.form['SelectedResolution']))

    # Set the zip file as the response
    in_memory.seek(0)
    return send_file(in_memory, download_name=f"""{playlist.title}.zip""", as_attachment=True)


from tkinter import *
from PIL import ImageTk, Image

import t
import callfunction
#from tqdm import tqdm
class MyWindow:
    data=[]
    def __init__(self, win):

        #replace data with values of list
        ima=Image.open('hevo1.png')
        pho=ImageTk.PhotoImage(ima)
        i4=Label(win,bg='black')
        i4.config(image=pho)
        i4.img=pho
        i4.place(x=150,y=5)
        #canvas.create_image(20,20, anchor=NW, image=img)
        self.lab = Label( text="HevoValYou",font="-weight bold")
        self.lab.config(font=("Courier", 48))
        self.lab.config(fg='white')
        self.lab.config(bg='black')
        self.lb = Listbox(win,width=80, height=20, selectmode='multiple')
        data=[]
        for num in data:
            self.lb.insert(END,num)
        self.btn1 = Button(win, text='Select All')
        self.btn2 = Button(win, text='Search the web')
        self.lab.place(x=250, y=5)
        self.lb.place(x=150, y=100)
        self.b1=Button(win, text='    Select All    ',command=self.selectall)
        self.b2=Button(win, text='Search the Web', command=self.search)
        self.b3=Button(win, text='      Load        ', command=self.load)
        self.b3.place(x=200, y=450)
        self.b1.place(x=350, y=450)
        self.b2.place(x=500, y=450)
    def selectall(self):
        callfunction.callfunction(self.data)
    def load(self):
        self.data=[]
        self.lb.delete(0,'end')
        self.data=t.check()
        for num in self.data:
            self.lb.insert(END,num)
    def search(self):
        selection = self.lb.curselection()
        selection=list(selection)
        print(selection)
        l=[]
        for x in range(len(selection)):
            l.append(self.data[selection[x]])
        callfunction.callfunction(l)

window=Tk()
mywin=MyWindow(window)
window.title('HevoValYou')
window.geometry("800x500+10+10")
window.configure(bg="#000000")
p1 = PhotoImage(file = 'hevo1.png')
window.iconphoto(False, p1)
window.mainloop()


import sys
import submodels_module as modelbank
import numpy as np
import matplotlib as mpl
mpl.use('Agg')
import matplotlib.pyplot as plt
from scipy.stats import ttest_ind_from_stats as ttest
import load_format_data

def main():
    '''
    train a model if we only had sorted into 2 gates instead of 4
    '''

    a=int(sys.argv[1])
    if a<4:
        b=0
    elif a<8:
        a=a-4
        b=1
    elif a<12:
        a=a-8
        b=2
    else:
        print('incorrect toggle number')

    arch_list=['ridge','svm','forest','fnn']
    stringency_list= ['high','medium','low']

    mdl=modelbank.twogate_assay_to_yield_model([1,8,10],stringency_list[b],arch_list[a],1)
    mdl.cross_validate_model()
    mdl.limit_test_set([1,8,10])
    mdl.test_model()

    mdl=modelbank.seqandtwogateassay_to_yield_model([1,8,10],stringency_list[b],arch_list[a],1)
    mdl.cross_validate_model()
    mdl.limit_test_set([1,8,10])
    mdl.test_model()

# if __name__ == '__main__':
#     main()

arch_list=['ridge','svm','forest','fnn']
stringency_list= ['high','medium','low','4-gate']

loss_per_mdl,std_per_mdl=[],[]
for i in range (2):
    loss_per_str,std_per_str=[],[]
    for stringency in stringency_list:
        cv_loss,test_loss,test_std=np.inf,np.inf,0
        for arch in arch_list:
            if i==0:
                if stringency=='4-gate':
                    mdl=modelbank.assay_to_yield_model([1,8,10],arch,1)
                else:
                    mdl=modelbank.twogate_assay_to_yield_model([1,8,10],stringency,arch,1)
            else:
                if stringency=='4-gate':
                    mdl=modelbank.seqandassay_to_yield_model([1,8,10],arch,1)
                else:
                    mdl=modelbank.seqandtwogateassay_to_yield_model([1,8,10],stringency,arch,1)
            if mdl.model_stats['cv_avg_loss'] < cv_loss:
                cv_loss=mdl.model_stats['cv_avg_loss']
                test_loss=mdl.model_stats['test_avg_loss']
                test_std=mdl.model_stats['test_std_loss']
        loss_per_str.append(test_loss)
        std_per_str.append(test_std)
    loss_per_mdl.append(loss_per_str)
    std_per_mdl.append(std_per_str)

seq_model=modelbank.seq_to_yield_model('forest',1)
seq_loss=seq_model.model_stats['test_avg_loss']
seq_std=seq_model.model_stats['test_std_loss']
x=[-0.3,2.3]
seq_plus=[seq_loss+seq_std]*2
seq_min=[seq_loss-seq_std]*2

control_model=modelbank.control_to_yield_model('ridge',1)
control_loss=control_model.model_stats['test_avg_loss']
control_model.limit_test_set([1,8,10])
exploded_df,_,_=load_format_data.explode_yield(control_model.testing_df)
exp_var=np.average(np.square(np.array(exploded_df['y_std'])))

fig,ax=plt.subplots(1,1,figsize=[2,2],dpi=300)

xloc=[1.2,0.6,0,2]
ax.axhline(seq_loss,-0.5,4.5,color='green',linestyle='--',label='Sequence Model')
ax.axhline(control_loss,-0.5,2.5,color='red',linestyle='--',label='Control')
ax.axhline(exp_var,-0.5,2.5,color='purple',linestyle='--',label='Experimental')
ax.bar(np.subtract(xloc,0.075),loss_per_mdl[0],yerr=std_per_mdl[0],label='Assay',width=0.15,color='blue')
ax.bar(np.add(xloc,0.075),loss_per_mdl[1],yerr=std_per_mdl[1],label='Seq and Assay',width=0.15,color='orange')
ax.fill_between(x,seq_plus,seq_min,alpha=0.2,color='green')
ax.set_xticks(xloc)
ticklabels=['High','Medium','Low','4-Gate']
ax.set_xlabel('Sort Stringency',fontsize=6)
ax.set_xticklabels(ticklabels)

# ax.legend(fontsize=6)
ax.tick_params(axis='both', which='major', labelsize=6)
ax.set_ylabel('$Test^2$ Loss',fontsize=6)
ax.set_ylim([0.35,0.8])
ax.set_xlim([-0.3,2.3])

fig.tight_layout()
fig.savefig('./two_gate.png')
plt.close()


from fastapi import status
from fastapi.responses import JSONResponse

from app.apis.schemas.errors_schema import ApiError

# Function that wraps the error response into predefined schema
def generate_api_error_response(status_code: int, detail: str) -> JSONResponse:
    return JSONResponse(
        status_code=status_code,
        content=ApiError(detail=detail).dict(),
    )

# Function that generates error responses for the OpenAPI documentation
def generate_error_responses(*args) -> dict[int, dict[str, str]]:
    error_responses = {}
    for arg in args:
        if arg == status.HTTP_400_BAD_REQUEST:
            description = "Bad Request Error"
        elif arg == status.HTTP_404_NOT_FOUND:
            description = "Not Found Error"
        elif arg == status.HTTP_403_FORBIDDEN:
            description = "Forbidden Error"
        elif arg == status.HTTP_401_UNAUTHORIZED:
            description = "Unauthorized Error"
        error_responses[arg] = {
            "description": description,
            "model": ApiError,
        }

    return error_responses


import sys
from streamlit import cli as stcli

from folium.plugins import HeatMap
import folium
from streamlit_folium import folium_static

import tempfile

import streamlit as st
import pandas as pd
import numpy as np
from PIL import Image
import time
import os
import json

import torch
import cv2

from stqdm import stqdm

import tkinter as tk
from tkinter import filedialog

@st.cache()
def load_model(path='models/best.pt'):
    detection_model = torch.hub.load('ultralytics/yolov5', 'custom', path=path)
    return detection_model

def detect_image(image, model):
    pred = model(image)
    pred_df = pred.pandas().xyxy[0].sort_values('confidence', ascending=False)
    pred_image = pred.render()[0]
    if pred_df.shape[0] > 0:
        if pred_df.confidence.iloc[0] > 0.5:
            return pred_image, pred_df.name.iloc[0]
        else:
            return pred_image, 'Неизвестное животное'
    else:
        return image, 'Нет животного'

def plot_map():
    map_df = pd.read_csv('lisa_tracking.csv')
    map_heatmap = folium.Map(location=[map_df.latitude.mean(), map_df.longitude.mean()], zoom_start=11)
    # Filter the DF for columns, then remove NaNs
    heat_df = map_df[["latitude", "longitude"]]
    heat_df = heat_df.dropna(axis=0, subset=["latitude", "longitude"])
    # List comprehension to make list of lists
    heat_data = [
        [row["latitude"], row["longitude"]] for index, row in heat_df.iterrows()
    ]
    # Plot it on the map
    HeatMap(heat_data).add_to(map_heatmap)
    # Display the map using the community component
    folium_static(map_heatmap)

def process_video(cap, model, save=True, path_to_save='temp.mp4'):
    frame_width = int(cap.get(3))
    frame_height = int(cap.get(4))
    stframe = st.empty()
    preds = []
    if save:
        fourcc = cv2.VideoWriter_fourcc(*'mp4v')
        out = cv2.VideoWriter(path_to_save, fourcc, 25.0, (frame_width, frame_height))
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            print("Can't receive frame (stream end?). Exiting ...")
            break
        frame, pred = detect_image(frame, model)
        #st.write(pred)
        if pred != 'Неизвестное животное' and pred != 'Нет животного':
            if save:
                out.write(frame)
            stframe.image(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
            preds.append(pred)
        elif pred == 'Неизвестное животное':
            preds.append(pred)
    cap.release()
    if save:
        out.release()
    if len(preds) > 0:
        return pd.DataFrame(preds).reset_index().groupby(0).count().sort_values('index').index[-1]
    else:
        return 'Нет животного'

def main():

    st.title('Обработка данных из фотоловушек')

    model = load_model('best.pt')

    data_type = st.radio(
        "Выберите тип данных",
        ('Директория с фото', 'Директория с видео',
         'Фото', 'Видео'))

    if data_type == 'Директория с фото':

        st.header('Обработка директории с фотографиями')
        root = tk.Tk()
        root.withdraw()
        root.wm_attributes('-topmost', 1)

        st.write('Выберите папку с фотографиями:')
        clicked = st.button('Выбор папки')

        if clicked:
        # Создать папки, в которых будут лежать обработанные фотографии

            dirname = st.text_input('Выбранная папка:', filedialog.askdirectory(master=root))
            #directory = "ProcessedImages"
            path = './ProcessedImages' #os.path.join(dirname, directory)
            try:
                os.mkdir(path)
            except:
                st.write('WARNING: Папка ProcessedImages уже существует.')

            for i in ['Bear', 'Deer', 'Lynx', 'Fox', 'Tiger', 'Leopard', 'Wolf', 'Eagle', 'Boar', 'Saiga', 'Squirrel', 'Raccoon', 'Man','Weasel', 'Unknown_Animal', 'No_Animal']:
                os.mkdir(os.path.join(path, i))
            # Загрузка модели
            labels = {}
            for img_path in stqdm([dirname + '\\' + x for x in os.listdir(dirname)]):
                try:
                    image = np.array(Image.open(img_path))
                    image, prediction = detect_image(image, model)
                except :
                    continue

                image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
                labels[img_path.split('\\')[-1]]=[prediction]

                with open('labels.json', 'w') as outfile:
                    json.dump(labels, outfile)

                for i, p in zip(['Медведь', 'Олень', 'Рысь', 'Лиса', 'Тигр', 'Леопард', 'Волк', 'Орёл', 'Кабан', 'Сайгак', 'Белка', 'Енот', 'Человек', 'Ласка', 'Неизвестное животное', 'Нет животного'],
                ['Bear', 'Deer', 'Lynx', 'Fox', 'Tiger', 'Leopard', 'Wolf', 'Eagle', 'Boar', 'Saiga', 'Squirrel', 'Raccoon', 'Man','Weasel', 'Unknown_Animal', 'No_Animal']):
                    if prediction == i:
                        path_init = os.path.join(path, p)
                        path_to_save = os.path.join(path_init, img_path.split('\\')[-1])
                        cv2.imwrite(path_to_save, np.array(image))
                        break

            st.write('Фотографии обработаны')

    elif data_type == 'Директория с видео':
        st.header('Обработка директории с видео')
        root = tk.Tk()
        root.withdraw()
        root.wm_attributes('-topmost', 1)

        st.write('Выберите папку с видео:')
        clicked = st.button('Выбор папки')

        if clicked:
        # Создать папки, в которых будут лежать обработанные фотографии

            dirname = st.text_input('Выбранная папка:', filedialog.askdirectory(master=root))
            #directory = "ProcessedImages"
            path = './ProcessedVideos' #os.path.join(dirname, directory)
            try:
                os.mkdir(path)
            except:
                st.write('WARNING: Папка ProcessedVideos уже существует.')

            labels_video = {}
            for video_path in stqdm([dirname + '\\' + x for x in os.listdir(dirname)]):
                cap = cv2.VideoCapture(video_path)

                prediction = process_video(cap, model, save=True, path_to_save='./ProcessedVideos/'+video_path.split('\\')[-1].split('.')[0] + '.mp4')
                st.write(prediction)

                labels_video[video_path.split('\\')[-1]]=[prediction]

                with open('labels_video.json', 'w') as outfile:
                    json.dump(labels_video, outfile)

            st.write('Видео обработаны')

    elif data_type == 'Фото':
        st.header('Обработка фото')
        file = st.file_uploader('Загрузите изображение')
        if file:
            image = np.array(Image.open(file))
            image, pred = detect_image(image, model)
            st.header('Результаты распознавания')
            st.metric('Вид', pred)
            st.image(image)
            if pred == 'Лиса':
                plot_or_not = st.checkbox('Показать карту активности вида - {}'.format(pred))
                if plot_or_not:
                    plot_map()

    elif data_type == 'Видео':
        st.header('Обработка видео')
        file = st.file_uploader('Загрузите изображение')
        if file:
            st.header('Результаты распознавания')
            tfile = tempfile.NamedTemporaryFile(delete=False)
            tfile.write(file.read())
            cap = cv2.VideoCapture(tfile.name)
            pred = process_video(cap, model)
            st.text('Видео обработано')
            st.metric('Вид', pred)
            if pred == 'Лиса':
                plot_or_not = st.checkbox('Показать карту активности вида - {}'.format(pred))
                if plot_or_not:
                    plot_map()

if __name__ == '__main__':
    if st._is_running_with_streamlit:
        main()
    else:
        sys.argv = ["streamlit", "run", sys.argv[0]]
        sys.exit(stcli.main())


# Задание №4
# Создать программу, которая будет производить подсчет количества слов в
# каждом файле в указанной директории и выводить результаты в консоль.
# Используйте потоки.
import os
import asyncio

import aiofiles as aiofiles
import aiohttp
import time

async def word_counter(file_path):
    # вариант 1 - with open (он блокирует доступ к файлу)
    # with open(file_path, 'r', encoding='utf-8') as file:
    #     text = file.read()
    #вариант 2 - async with aiofiles.open (нужен при одновременном доступе нескольких пользователей к файлу)
    async with aiofiles.open(file_path, mode='r', encoding='utf-8') as file:
        text = await file.read()
        words_count = len(text.split(' '))
        print(f'файл - {file_path}, слов-{words_count}')

async def main():
    tasks = []

    for root, dirs, files in os.walk('htmls'):
        for file_name in files:
            file_path = os.path.join(root, file_name)
            tasks.append(asyncio.create_task(word_counter(file_path)))
    await asyncio.gather(*tasks)

if __name__ == '__main__':
    start = time.time()
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    end = time.time()

    print(end - start)
    print('Готово')


from typing import Optional
from datetime import datetime
from uuid import UUID

class User:
    def __init__(
        self,
        id: str,
        display_name: str,
        email: str,
        created_at: int,
    ) -> None:
        self.id = id
        self.email = email
        self.created_at = created_at
        self.display_name = display_name

class Entry:
    def __init__(
        self,
        id: UUID,
        campaign_id: str,
        title: str,
        entry_text_rich: str,
        entry_text_raw: str,
        created_at: datetime,
        last_modified_at: datetime,
        created_by: str,
        last_modified_by: str,
        entry_text_summary: Optional[str],
        category_id: Optional[str],
    ) -> None:
        self.id = id
        self.campaign_id = campaign_id
        self.title = title
        self.entry_text_rich = entry_text_rich
        self.entry_text_raw = entry_text_raw
        self.created_at = created_at
        self.last_modified_at = last_modified_at
        self.created_by = created_by
        self.last_modified_by = last_modified_by
        self.entry_text_summary = entry_text_summary
        self.category_id = category_id

class EntryMetadata:
    def __init__(
        self,
        id: str,
        campaign_id: str,
        title: str,
        created_at: datetime,
        created_by: str,
        last_modified_at: datetime,
        last_modified_by: str,
        category_id: Optional[str],
    ) -> None:
        self.id = id
        self.campaign_id = campaign_id
        self.title = title
        self.created_at = created_at
        self.created_by = created_by
        self.last_modified_at = last_modified_at
        self.last_modified_by = last_modified_by
        self.category_id = category_id

class Campaign:
    def __init__(
        self, id: UUID, title: str, created_at: datetime, created_by: str
    ) -> None:
        self.id = id
        self.title = title
        self.created_at = created_at
        self.created_by = created_by

class CampaignMember:
    def __init__(self, campaign_id: str, user_id: str, is_dm: bool) -> None:
        self.campaign_id = campaign_id
        self.user_id = user_id
        self.is_dm = is_dm

class Category:
    def __init__(
        self,
        id: UUID,
        campaign_id: UUID,
        title: str,
        created_at: datetime,
        parent_id: Optional[UUID],
    ) -> None:
        self.id = id
        self.campaign_id = campaign_id
        self.title = title
        self.created_at = created_at
        self.parent_id = parent_id


import os
import sys
import time
import unittest
import uuid

from ament_index_python.packages import get_package_share_directory

from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.actions import IncludeLaunchDescription

import launch
import launch_ros
import launch_ros.actions
import launch_testing.actions
import launch_testing_ros

import pytest

import rclpy

import std_msgs.msg

@pytest.mark.rostest
def generate_test_description():
  # Normally, talker publishes on the 'chatter' topic and listener listens on the
  # 'chatter' topic, but we want to show how to use remappings to munge the data so we
  # will remap these topics when we launch the nodes and insert our own node that can
  # change the data as it passes through
  path_to_test = os.path.dirname(__file__)
  package_prefix = get_package_share_directory('perception')
  perception_node = launch_ros.actions.Node(
      executable=sys.executable,
      arguments=[os.path.join(
          path_to_test, '../perception/perception_node.py')],
      additional_env={'PYTHONUNBUFFERED': '1'},
      remappings=[('topic', 'topic2')]
  )

  # return launch.LaunchDescription([
  #     IncludeLaunchDescription(
  #         PythonLaunchDescriptionSource(
  #             [package_prefix, '/launch/perception.launch.py'])
  #     ),
  #     launch_testing.actions.ReadyToTest()
  # ])
  return (
      launch.LaunchDescription([
          perception_node,
          # Start tests right away - no need to wait for anything
          launch_testing.actions.ReadyToTest(),
      ]),
      {
          'perception': perception_node,
      }
  )

class TestTalkerListenerLink(unittest.TestCase):

  @classmethod
  def setUpClass(cls):
    # Initialize the ROS context for the test node
    rclpy.init()

  @classmethod
  def tearDownClass(cls):
    # Shutdown the ROS context
    rclpy.shutdown()

  def setUp(self):
    # Create a ROS node for tests
    self.node = rclpy.create_node('test_talker_listener_link')

  def tearDown(self):
    self.node.destroy_node()

  def test_perception_transmits(self, launch_service, perception, proc_output):
    # Expect the talker to publish strings on '/talker_chatter' and also write to stdout
    msgs_rx = []

    sub = self.node.create_subscription(
        std_msgs.msg.String,
        'topic2',
        lambda msg: msgs_rx.append(msg),
        10
    )
    try:
      # Wait until the talker transmits two messages over the ROS topic
      end_time = time.time() + 20
      while time.time() < end_time:
        rclpy.spin_once(self.node, timeout_sec=0.1)
        if len(msgs_rx) > 2:
          break

      self.assertGreater(len(msgs_rx), 2)

      # Make sure the talker also output the same data via stdout
      for msg in msgs_rx:
        proc_output.assertWaitFor(
            expected_output=msg.data, process=perception
        )
    finally:
      self.node.destroy_subscription(sub)


import json
import logging
import requests
from models import User
from oauth2client.crypt import AppIdentityError
from oauth2client import client
from app_config import config
from stormpath.resources import Provider
from stormpath.error import Error as StormpathError

def get_auth_application():
    return config.STORMPATH_CLIENT.applications.search(config.STORMPATH_AUTH_APP)[0]

def get_google_directory():
    return config.STORMPATH_CLIENT.directories.items(Provider.GOOGLE)[0]

def google_login(id_token, access_token, code):
    user = None
    if id_token is not None:
        # Check that the ID Token is valid.
        try:
            # Client library can verify the ID token.
            client.verify_id_token(id_token, config.OAUTH_CLIENT_ID)  # returns jwt. jwt["sub"] = gplus id
        except AppIdentityError:
            logging.error('Invalid ID Token.')

    if access_token is not None:
        # Check that the Access Token is valid.
        url = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={}'.format(access_token)
        result = json.loads(requests.get(url).text)

        if result.get('error') is not None:
            # This is not a valid token.
            logging.error('Invalid Access Token.')
        elif result['issued_to'] != config.OAUTH_CLIENT_ID:
            # This is not meant for this app. It is VERY important to check
            # the client ID in order to prevent man-in-the-middle attacks.
            logging.error('Access Token not meant for this app.')
        else:
            stormpath_app = get_auth_application()
            try:
                account = stormpath_app.get_provider_account(provider=Provider.GOOGLE, code=code)
                if account:
                    user = User.update_or_create_with_api_account(account)

            except StormpathError as e:
                logging.exception(e)

    return user

def cloud_login(email, password):
    user = None
    stormpath_app = get_auth_application()

    try:
        resp = stormpath_app.authenticate_account(email, password)
        if resp and resp.account:
            user = User.update_or_create_with_api_account(resp.account)

    except StormpathError as e:
        logging.exception(e)

    return user


from collections import OrderedDict
from typing import List

import pandas as pd

class TaskField:
    def __init__(self, name: str = None):
        if name is None:
            self.name = type(self).__name__
        else:
            self.name = name

    def get(self, task_id: int):
        return task_id

class TaskFieldList(List[TaskField]):
    """List of Field types"""

    def get_names(self):
        return [field.name for field in self]

    def to_data(self, task_ids: list[int]) -> pd.DataFrame:
        """
        Given a list of task_ids, calls all the TaskFields to get the data for each task_id
        and returns a dataframe with the data
        """
        task_list = [Task(task_id, self) for task_id in task_ids]
        data = []
        for i, task in enumerate(task_list):
            print("working on", i, "out of", len(task_list))
            task.append_to_data(data)
        return pd.DataFrame(data)

    def append_to_data(self, data: pd.DataFrame):
        """ Creates a new dataframe from the triallist and appends it to the supplied dataframe
        This is used to add new columns (fields) to an existing dataframe"""
        # get first column
        new_data = []
        task_ids = data[data.columns[0]]
        task_list = [Task(task_id, self) for task_id in task_ids]
        for i, task in enumerate(task_list):
            print("working on", i, "out of", len(task_list))
            task.append_to_data(new_data)

        new_df = pd.DataFrame(new_data, columns=self.get_names())
        data = pd.concat([data, new_df], axis=1)
        return data

class Task:
    def __init__(self, task_id: int, fields: TaskFieldList):
        self.task_id = task_id
        self.fields = fields

    def append_to_data(self, data):
        field_values = [field.get(self.task_id) for field in self.fields]
        names = self.fields.get_names()
        new_row = OrderedDict(zip(names, field_values))
        data.append(new_row)

def get_data_from_tasks(fields: TaskFieldList, task_ids: list[int]) -> pd.DataFrame:
    task_list = [Task(task_id, fields) for task_id in task_ids]
    data = []
    for i, task in enumerate(task_list):
        print("working on", i, "out of", len(task_list))
        task.append_to_data(data)
    return pd.DataFrame(data)


import pandas as pd
import numpy as np
import datetime

def ex1():
    dt_rng = pd.date_range('2015-03-02 00:00:00', '2015-03-03 23:00:00', freq='H')
    print(dt_rng)

def ex2():
    dt_rng = pd.date_range('2015-03-02 00:00:00', '2015-03-03 23:00:00', freq='H')
    print(dt_rng)

def ex3():
    dt_rng = pd.date_range('2015-03-02 00:00:00', '2015-03-03 23:00:00', freq='2H')
    print(dt_rng)

def ex4():
    dt_rng = pd.date_range('2015-03-02 00:00:00', '2015-03-02 3:00:00', freq='15min')
    print(dt_rng)

    dt1 = datetime.datetime.strptime('2015-03-02 00:00:00', '%Y-%m-%d %H:%M:%S')
    dt2 = datetime.datetime.strptime('2015-03-02 02:00:00', '%Y-%m-%d %H:%M:%S')
    tdelta = dt2 - dt1
    print(tdelta)
    print(type(tdelta))

    dt_rng = pd.date_range('2015-03-02 00:00:00', '2015-03-03 23:00:00', freq=tdelta)
    print(dt_rng)

def ex5():
    input_data = 'Resources/internet_traffic_raw_data.csv'
    df = pd.read_csv(input_data, lineterminator='\n')
    dt1 = datetime.datetime.strptime(df['_time'][0], '%Y-%m-%dT%H:%M:%S')
    dt2 = datetime.datetime.strptime(df['_time'][1], '%Y-%m-%dT%H:%M:%S')

    tdelta = dt2 - dt1
    print(tdelta)
    print(type(tdelta))

    dt_rng = pd.date_range('2015-03-02 00:00:00', '2015-03-03 23:00:00', freq=tdelta)
    print(dt_rng)

if __name__ == '__main__':
    ex1()
    ex2()
    ex3()
    ex4()
    ex5()


from models import *
from flask import abort

def clean_posts():
    [db.session.delete(post) for post in DeletedPost.query.all()
     if User.query.filter_by(email=post.json_column["author_email"]).first() is None]
    for post in BlogPost.query.all():
        try:
            user = User.query.filter_by(email=post.author.email).first()
            if user is None:
                db.session.delete(post)
        except AttributeError:
            db.session.delete(post)
    for comment in Comment.query.all():
        try:
            comment = comment.author.email
        except (AttributeError, TypeError):
            db.session.delete(comment)
    for api_key in ApiKey.query.all():
        try:
            key = api_key.developer.email
        except (AttributeError, TypeError):
            db.session.delete(api_key)
    for deletion_report in DeletionReport.query.all():
        try:
            report = deletion_report.user.email
        except (AttributeError, TypeError):
            db.session.delete(deletion_report)
    for reply_item in Reply.query.all():
        try:
            reply = reply_item.parent_comment.post_id
        except (AttributeError, TypeError):
            db.session.delete(reply_item)
    for post in DeletedPost.query.all():
        post.json_column["comments"] = [comment for comment in post.json_column['comments']
                                        if User.query.filter_by(email=comment["author_email"]).first() is not None]
        for comment in post.json_column["comments"]:
            comment["replies"] = [reply for reply in comment["replies"] if
                                  User.query.filter_by(email=reply["author_email"]).first() is not None]

def clean_notifications(category):
    if category in ['comment', 'reply']:
        [db.session.delete(notification) for notification in Notification.query.filter_by(category=category).all()
         if eval(f"notification.parent_{category}") is None]
    else:
        return abort(403)