import rospy, sys, tf
import moveit_commander
from math import *
from geometry_msgs.msg import PoseStamped
from moveit_commander import MoveGroupCommander, PlanningSceneInterface
from moveit_msgs.msg import PlanningScene, ObjectColor
from moveit_msgs.msg import Grasp, GripperTranslation
from moveit_msgs.msg import MoveItErrorCodes
from trajectory_msgs.msg import JointTrajectory, JointTrajectoryPoint
from tf.transformations import quaternion_from_euler
from copy import deepcopy

GROUP_NAME_ARM = 'arm'
GROUP_NAME_GRIPPER = 'gripper'

GRIPPER_FRAME = 'gripper_link'
GRIPPER_JOINT_NAMES = ['gripper_joint']
GRIPPER_EFFORT = [1.0]
GRIPPER_PARAM = '/gripper_controller'

REFERENCE_FRAME = '/base_link'
ARM_BASE_FRAME = '/arm_base_link'

class MoveItDemo:
    def __init__(self):
        # Initialize the move_group API
        moveit_commander.roscpp_initialize(sys.argv)

        rospy.init_node('moveit_demo')

        self.gripper_opened = [rospy.get_param(GRIPPER_PARAM + "/max_opening") ]
        self.gripper_closed = [rospy.get_param(GRIPPER_PARAM + "/min_opening") ]
        self.gripper_neutral = [rospy.get_param(GRIPPER_PARAM + "/neutral") ]

        self.gripper_tighten = rospy.get_param(GRIPPER_PARAM + "/tighten")

        # We need a tf listener to convert poses into arm reference base
        self.tf_listener = tf.TransformListener()

        # Use the planning scene object to add or remove objects
        scene = PlanningSceneInterface()

        # Create a scene publisher to push changes to the scene
        self.scene_pub = rospy.Publisher('planning_scene', PlanningScene, queue_size=10)

        # Create a publisher for displaying gripper poses
        self.gripper_pose_pub = rospy.Publisher('target_pose', PoseStamped, queue_size=10)

        # Create a dictionary to hold object colors
        self.colors = dict()

        # Initialize the move group for the right arm
        arm = MoveGroupCommander(GROUP_NAME_ARM)

        # Initialize the move group for the right gripper
        gripper = MoveGroupCommander(GROUP_NAME_GRIPPER)

        # Get the name of the end-effector link
        end_effector_link = arm.get_end_effector_link()

        # Allow some leeway in position (meters) and orientation (radians)
        arm.set_goal_position_tolerance(0.04)
        arm.set_goal_orientation_tolerance(0.1)

        # Allow replanning to increase the odds of a solution
        arm.allow_replanning(True)

        # Set the right arm reference frame
        arm.set_pose_reference_frame(REFERENCE_FRAME)

        # Allow 5 seconds per planning attempt
        arm.set_planning_time(5)

        # Set a limit on the number of pick attempts before bailing
        max_pick_attempts = 3

        # Set a limit on the number of place attempts
        max_place_attempts = 3
        rospy.loginfo("Scaling for MoveIt timeout=" + str(rospy.get_param('/move_group/trajectory_execution/allowed_execution_duration_scaling')))

        # Give the scene a chance to catch up
        rospy.sleep(2)

        # Give each of the scene objects a unique name
        table_id = 'table'
        box1_id = 'box1'
        box2_id = 'box2'
        target_id = 'target'
        tool_id = 'tool'

        # Remove leftover objects from a previous run
        scene.remove_world_object(table_id)
        scene.remove_world_object(box1_id)
        scene.remove_world_object(box2_id)
        scene.remove_world_object(target_id)
        scene.remove_world_object(tool_id)

        # Remove any attached objects from a previous session
        scene.remove_attached_object(GRIPPER_FRAME, target_id)

        # Give the scene a chance to catch up
        rospy.sleep(1)

        # Start the arm in the "arm_up" pose stored in the SRDF file
        rospy.loginfo("Set Arm: right_up")
        arm.set_named_target('right_up')
        if arm.go() != True:
            rospy.logwarn("  Go failed")
        rospy.sleep(2)

        # Move the gripper to the closed position
        rospy.loginfo("Set Gripper: Close " + str(self.gripper_closed ) )
        gripper.set_joint_value_target(self.gripper_closed)
        if gripper.go() != True:
            rospy.logwarn("  Go failed")
        rospy.sleep(2)

        # Move the gripper to the neutral position
        rospy.loginfo("Set Gripper: Neutral " + str(self.gripper_neutral) )
        gripper.set_joint_value_target(self.gripper_neutral)
        if gripper.go() != True:
            rospy.logwarn("  Go failed")
        rospy.sleep(2)

        # Move the gripper to the open position
        rospy.loginfo("Set Gripper: Open " +  str(self.gripper_opened))
        gripper.set_joint_value_target(self.gripper_opened)
        if gripper.go() != True:
            rospy.logwarn("  Go failed")
        rospy.sleep(2)

        # Set the height of the table off the ground
        table_ground = 0.4

        # Set the dimensions of the scene objects [l, w, h]
        table_size = [0.2, 0.7, 0.01]
        box1_size = [0.1, 0.05, 0.05]
        box2_size = [0.05, 0.05, 0.15]

        # Set the target size [l, w, h]
        target_size = [0.02, 0.005, 0.12]

        # Add a table top and two boxes to the scene
        table_pose = PoseStamped()
        table_pose.header.frame_id = REFERENCE_FRAME
        table_pose.pose.position.x = 0.36
        table_pose.pose.position.y = 0.0
        table_pose.pose.position.z = table_ground + table_size[2] / 2.0
        table_pose.pose.orientation.w = 1.0
        scene.add_box(table_id, table_pose, table_size)

        box1_pose = PoseStamped()
        box1_pose.header.frame_id = REFERENCE_FRAME
        box1_pose.pose.position.x = table_pose.pose.position.x - 0.04
        box1_pose.pose.position.y = 0.0
        box1_pose.pose.position.z = table_ground + table_size[2] + box1_size[2] / 2.0
        box1_pose.pose.orientation.w = 1.0
        scene.add_box(box1_id, box1_pose, box1_size)

        box2_pose = PoseStamped()
        box2_pose.header.frame_id = REFERENCE_FRAME
        box2_pose.pose.position.x = table_pose.pose.position.x - 0.06
        box2_pose.pose.position.y = 0.2
        box2_pose.pose.position.z = table_ground + table_size[2] + box2_size[2] / 2.0
        box2_pose.pose.orientation.w = 1.0
        scene.add_box(box2_id, box2_pose, box2_size)

        # Set the target pose in between the boxes and on the table
        target_pose = PoseStamped()
        target_pose.header.frame_id = REFERENCE_FRAME
        target_pose.pose.position.x = table_pose.pose.position.x - 0.03
        target_pose.pose.position.y = 0.1
        target_pose.pose.position.z = table_ground + table_size[2] + target_size[2] / 2.0
        target_pose.pose.orientation.w = 1.0

        # Add the target object to the scene
        scene.add_box(target_id, target_pose, target_size)

        # Make the table red and the boxes orange
        self.setColor(table_id, 0.8, 0, 0, 1.0)
        self.setColor(box1_id, 0.8, 0.4, 0, 1.0)
        self.setColor(box2_id, 0.8, 0.4, 0, 1.0)

        # Make the target yellow
        self.setColor(target_id, 0.9, 0.9, 0, 1.0)

        # Send the colors to the planning scene
        self.sendColors()

        # Set the support surface name to the table object
        arm.set_support_surface_name(table_id)

        # Specify a pose to place the target after being picked up
        place_pose = PoseStamped()
        place_pose.header.frame_id = REFERENCE_FRAME
        place_pose.pose.position.x = table_pose.pose.position.x - 0.03
        place_pose.pose.position.y = -0.15
        place_pose.pose.position.z = table_ground + table_size[2] + target_size[2] / 2.0
        place_pose.pose.orientation.w = 1.0

        # Initialize the grasp pose to the target pose
        grasp_pose = target_pose

        # Shift the grasp pose by half the width of the target to center it
        grasp_pose.pose.position.y -= target_size[1] / 2.0

        # Generate a list of grasps
        grasps = self.make_grasps(grasp_pose, [target_id], [target_size[1] - self.gripper_tighten])

        # Track success/failure and number of attempts for pick operation
        result = MoveItErrorCodes.FAILURE
        n_attempts = 0

        # Repeat until we succeed or run out of attempts
        while result != MoveItErrorCodes.SUCCESS and n_attempts < max_pick_attempts:
            rospy.loginfo("Pick attempt #" + str(n_attempts))
            for grasp in grasps:
                # Publish the grasp poses so they can be viewed in RViz
                self.gripper_pose_pub.publish(grasp.grasp_pose)
                rospy.sleep(0.2)

                result = arm.pick(target_id, grasps)
                if result == MoveItErrorCodes.SUCCESS:
                    break

            n_attempts += 1
            rospy.sleep(0.2)

        # If the pick was successful, attempt the place operation
        if result == MoveItErrorCodes.SUCCESS:
            rospy.loginfo("  Pick: Done!")
            # Generate valid place poses
            places = self.make_places(place_pose)

            success = False
            n_attempts = 0

            # Repeat until we succeed or run out of attempts
            while not success and n_attempts < max_place_attempts:
                rospy.loginfo("Place attempt #" + str(n_attempts))
                for place in places:
                    # Publish the place poses so they can be viewed in RViz
                    self.gripper_pose_pub.publish(place)
                    rospy.sleep(0.2)

                    success = arm.place(target_id, place)
                    if success:
                        break

                n_attempts += 1
                rospy.sleep(0.2)

            if not success:
                rospy.logerr("Place operation failed after " + str(n_attempts) + " attempts.")
            else:
                rospy.loginfo("  Place: Done!")
        else:
            rospy.logerr("Pick operation failed after " + str(n_attempts) + " attempts.")

        # Return the arm to the "resting" pose stored in the SRDF file (passing through right_up)
        arm.set_named_target('right_up')
        arm.go()

        arm.set_named_target('resting')
        arm.go()

        # Open the gripper to the neutral position
        gripper.set_joint_value_target(self.gripper_neutral)
        gripper.go()

        rospy.sleep(1)

        # Shut down MoveIt cleanly
        moveit_commander.roscpp_shutdown()

        # Exit the script
        moveit_commander.os._exit(0)

    # Get the gripper posture as a JointTrajectory
    def make_gripper_posture(self, joint_positions):
        # Initialize the joint trajectory for the gripper joints
        t = JointTrajectory()

        # Set the joint names to the gripper joint names
        t.joint_names = GRIPPER_JOINT_NAMES

        # Initialize a joint trajectory point to represent the goal
        tp = JointTrajectoryPoint()

        # Assign the trajectory joint positions to the input positions
        tp.positions = joint_positions

        # Set the gripper effort
        tp.effort = GRIPPER_EFFORT

        tp.time_from_start = rospy.Duration(1.0)

        # Append the goal point to the trajectory points
        t.points.append(tp)

        # Return the joint trajectory
        return t

    # Generate a gripper translation in the direction given by vector
    def make_gripper_translation(self, min_dist, desired, vector):
        # Initialize the gripper translation object
        g = GripperTranslation()

        # Set the direction vector components to the input
        g.direction.vector.x = vector[0]
        g.direction.vector.y = vector[1]
        g.direction.vector.z = vector[2]

        # The vector is relative to the gripper frame
        g.direction.header.frame_id = GRIPPER_FRAME

        # Assign the min and desired distances from the input
        g.min_distance = min_dist
        g.desired_distance = desired

        return g

    # Generate a list of possible grasps
    def make_grasps(self, initial_pose_stamped, allowed_touch_objects, grasp_opening=[0]):
        # Initialize the grasp object
        g = Grasp()

        # Set the pre-grasp and grasp postures appropriately;
        # grasp_opening should be a bit smaller than target width
        g.pre_grasp_posture = self.make_gripper_posture(self.gripper_opened)
        g.grasp_posture = self.make_gripper_posture(grasp_opening)

        # Set the approach and retreat parameters as desired
        g.pre_grasp_approach = self.make_gripper_translation(0.01, 0.1, [1.0, 0.0, 0.0])
        g.post_grasp_retreat = self.make_gripper_translation(0.1, 0.15, [0.0, -1.0, 1.0])

        # Set the first grasp pose to the input pose
        g.grasp_pose = initial_pose_stamped

        # Pitch angles to try
        pitch_vals = [0, 0.1, -0.1, 0.2, -0.2, 0.4, -0.4]

        # Yaw angles to try; given the limited dofs of turtlebot_arm, we must calculate the heading
        # from arm base to the object to pick (first we must transform its pose to arm base frame)
        target_pose_arm_ref = self.tf_listener.transformPose(ARM_BASE_FRAME, initial_pose_stamped)
        x = target_pose_arm_ref.pose.position.x
        y = target_pose_arm_ref.pose.position.y

        self.pick_yaw = atan2(y, x)   # check in make_places method why we store the calculated yaw
        yaw_vals = [self.pick_yaw]

        # A list to hold the grasps
        grasps = []

        # Generate a grasp for each pitch and yaw angle
        for yaw in yaw_vals:
            for pitch in pitch_vals:
                # Create a quaternion from the Euler angles
                q = quaternion_from_euler(0, pitch, yaw)

                # Set the grasp pose orientation accordingly
                g.grasp_pose.pose.orientation.x = q[0]
                g.grasp_pose.pose.orientation.y = q[1]
                g.grasp_pose.pose.orientation.z = q[2]
                g.grasp_pose.pose.orientation.w = q[3]

                # Set and id for this grasp (simply needs to be unique)
                g.id = str(len(grasps))

                # Set the allowed touch objects to the input list
                g.allowed_touch_objects = allowed_touch_objects

                # Don't restrict contact force
                g.max_contact_force = 0

                # Degrade grasp quality for increasing pitch angles
                g.grasp_quality = 1.0 - abs(pitch)

                # Append the grasp to the list
                grasps.append(deepcopy(g))

        # Return the list
        return grasps

    # Generate a list of possible place poses
    def make_places(self, init_pose):
        # Initialize the place location as a PoseStamped message
        place = PoseStamped()

        # Start with the input place pose
        place = init_pose

        # A list of x shifts (meters) to try
        x_vals = [0, 0.005, -0.005] #, 0.01, -0.01, 0.015, -0.015]

        # A list of y shifts (meters) to try
        y_vals = [0, 0.005, -0.005, 0.01, -0.01] #, 0.015, -0.015]

        # A list of pitch angles to try
        pitch_vals = [0] #, 0.005, -0.005, 0.01, -0.01, 0.02, -0.02]

        # A list to hold the places
        places = []

        # Generate a place pose for each angle and translation
        for pitch in pitch_vals:
            for dy in y_vals:
                for dx in x_vals:
                    place.pose.position.x = init_pose.pose.position.x + dx
                    place.pose.position.y = init_pose.pose.position.y + dy

                    # Yaw angle: given the limited dofs of turtlebot_arm, we must calculate the heading from
                    # arm base to the place location (first we must transform its pose to arm base frame)
                    target_pose_arm_ref = self.tf_listener.transformPose(ARM_BASE_FRAME, place)
                    x = target_pose_arm_ref.pose.position.x
                    y = target_pose_arm_ref.pose.position.y
                    yaw = atan2(y, x) - self.pick_yaw;
                    # Note that we subtract the yaw we calculated for pick, as the picked object "carries"
                    # with him the orientation of the arm at pickup time. More details in this moveit-users
                    # group thread:  https://groups.google.com/forum/#!topic/moveit-users/-Eie-wLDbu0

                    # Create a quaternion from the Euler angles
                    q = quaternion_from_euler(0, pitch, yaw)

                    # Set the place pose orientation accordingly
                    place.pose.orientation.x = q[0]
                    place.pose.orientation.y = q[1]
                    place.pose.orientation.z = q[2]
                    place.pose.orientation.w = q[3]

                    # Append this place pose to the list
                    places.append(deepcopy(place))

        # Return the list
        return places

    # Set the color of an object
    def setColor(self, name, r, g, b, a=0.9):
        # Initialize a MoveIt color object
        color = ObjectColor()

        # Set the id to the name given as an argument
        color.id = name

        # Set the rgb and alpha values given as input
        color.color.r = r
        color.color.g = g
        color.color.b = b
        color.color.a = a

        # Update the global color dictionary
        self.colors[name] = color

    # Actually send the colors to MoveIt!
    def sendColors(self):
        # Initialize a planning scene object
        p = PlanningScene()

        # Need to publish a planning scene diff
        p.is_diff = True

        # Append the colors from the global color dictionary
        for color in self.colors.values():
            p.object_colors.append(color)

        # Publish the scene diff
        self.scene_pub.publish(p)

if __name__ == "__main__":
    MoveItDemo()


# Approach 1 - Breadth-First Search

# Time: O(N)
# Space: O(N)

from collections import deque

class Solution:
    def orangesRotting(self, grid: List[List[int]]) -> int:
        queue = deque()

        # build the initial set of rotten oranges
        fresh_oranges = 0
        ROWS, COLS = len(grid), len(grid[0])
        for r in range(ROWS):
            for c in range(COLS):
                if grid[r][c] == 2:
                    queue.append((r, c))
                elif grid[r][c] == 1:
                    fresh_oranges += 1

        queue.append((-1, -1))

        # Because the while loop will add one more minute when it try to find the neighbors of last rotten orange. Since that the last rotten orange won't affect any other orange so we shouldn't include that round. Also, if there isn't any fresh orange(fresh_orange = 0), the function will simply return -1.
        minutes_elapsed = -1
        directions = [(-1, 0), (0, 1), (1, 0), (0, -1)]
        while queue:
            row, col = queue.popleft()
            if row == -1: # processing of first round is complete
                minutes_elapsed += 1
                if queue:
                    queue.append((-1, -1))
            else:   # this is rotten orange
                for d in directions:
                    neighbor_row, neighbor_col = row + d[0], col + d[1]
                    if ROWS > neighbor_row >= 0 and COLS > neighbor_col >= 0:
                        if grid[neighbor_row][neighbor_col] == 1:
                            grid[neighbor_row][neighbor_col] = 2
                            fresh_oranges -= 1
                            queue.append((neighbor_row, neighbor_col))

        return minutes_elapsed if fresh_oranges == 0 else -1


from __future__ import annotations

import asyncio
import os
import platform
import re
from asyncio import IncompleteReadError, StreamReader, StreamWriter
from pathlib import Path
from typing import TYPE_CHECKING

from randovania.patching.patchers.exceptions import UnableToExportError

if TYPE_CHECKING:
    from collections.abc import Callable, Sequence

IO_LOOP: asyncio.AbstractEventLoop | None = None

def is_windows() -> bool:
    return platform.system() == "Windows"

def is_mac() -> bool:
    return platform.system() == "Darwin"

async def _write_data(stream: StreamWriter, data: str):
    stream.write(data.encode("UTF-8"))
    stream.close()

async def _read_data(stream: StreamReader, read_callback: Callable[[str], None]):
    while True:
        try:
            line = await stream.readuntil(b"\r")
        except IncompleteReadError as incomplete:
            line = incomplete.partial
        if line:
            try:
                decoded = line.decode()
            except UnicodeDecodeError:
                decoded = line.decode("latin1")
            for x in re.split(r"[\r\n]", decoded.strip()):
                if x:
                    read_callback(x)
        else:
            break

async def _process_command_async(
    args: list[str], input_data: str, read_callback: Callable[[str], None], additional_path_entries: Sequence[str] = ()
):
    environment_vars = os.environ.copy()
    if len(additional_path_entries) > 0:
        appending_paths = ":".join(additional_path_entries)
        environment_vars["PATH"] = f"{environment_vars['PATH']}:{appending_paths}"
    process = await asyncio.create_subprocess_exec(
        *args,
        stdin=asyncio.subprocess.PIPE,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.STDOUT,
        env=environment_vars,
    )

    await asyncio.gather(
        _write_data(process.stdin, input_data),
        _read_data(process.stdout, read_callback),
    )
    await process.wait()

def process_command(
    args: list[str], input_data: str, read_callback: Callable[[str], None], add_mono_if_needed: bool = True
):
    if not Path(args[0]).is_file():
        raise FileNotFoundError(f"{args[0]} not found")

    needs_mono = add_mono_if_needed and not is_windows()
    additional_paths = ()

    if needs_mono:
        args = ["mono", *args]
        # Add common Mono paths to PATH, as they aren't there by default
        if is_mac():
            additional_paths = (
                "/Library/Frameworks/Mono.framework/Versions/Current/Commands",
                "/usr/local/bin",
                "/opt/homebrew/bin",
            )

    work = _process_command_async(args, input_data, read_callback, additional_paths)

    try:
        if IO_LOOP is None:
            if is_windows():
                asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
            asyncio.run(work)
        else:
            asyncio.run_coroutine_threadsafe(work, IO_LOOP).result()

    except FileNotFoundError:
        if needs_mono:
            raise UnableToExportError(
                "Unable to find mono.

"
                "Please install it from the "
                "official website."
            )
        else:
            raise


from django.utils import timezone
from .models import Post, IP
from django.shortcuts import render, get_object_or_404, redirect
from .forms import PostForm, Login
from django.contrib.auth.decorators import login_required, PermissionDenied, user_passes_test
import json
from datetime import timedelta
from django.utils.timezone import now
from django.http import JsonResponse
from django.core import serializers
from django.http import HttpResponse
from django.db.models import Q
from django.contrib import messages
from flask import request
from django.contrib.auth.models import User

def get_ip(request):
    try:
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(",")[0]
        else:
            ip = request.META.get("REMOTE_ADDR")
    except:
        ip = ""
    return ip

@login_required
def post_list(request):
    last_ip = IP.objects.filter(User=request.user).latest('entr_date')
    form = Login(request.POST)
    if form.is_valid():
        new_ip = form.save(commit=False)
        new_ip.User = request.user
        new_ip.entr_date = timezone.now()
        new_ip.ip_address = get_ip(request)
        this_ip = IP.objects.filter(User=request.user).latest('entr_date')
        if this_ip != last_ip:
            messages.warning(request, 'Indirizzo ip diverso dal precedente.')
        new_ip.save()
    posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('-published_date')
    return render(request, 'blog/post_list.html', {'posts': posts})

@login_required
def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'blog/post_detail.html', {'post': post})

@login_required
def post_new(request):
    if request.method == "POST":
        form = PostForm(request.POST)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.published_date = timezone.now()
            post.writeOnChain()
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm()
    return render(request, 'blog/post_edit.html', {'form': form})

@login_required
def post_edit(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        form = PostForm(request.POST, instance=post)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.published_date = timezone.now()
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm(instance=post)
    return render(request, 'blog/post_edit.html', {'form': form})

def superuser_only(function):
    def _inner(request):
        if not request.user.is_superuser:
            raise PermissionDenied
        return function(request)
    return _inner

@login_required
def delete_post(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        post.delete()
        return redirect('post_list')
    return render(request, 'blog/delete.html', {'post': post})

@superuser_only
def info_superuser(request):
    n = {}
    users_id = User.objects.all().values_list('id', flat=True)
    for x in users_id:
        posts = Post.objects.filter(author=x)
        n[x] =  len(posts)
    return render(request, 'blog/info_superuser.html', {'n': n})

@superuser_only
def last_hour_post(request):
    dt = now()
    PostsLastHour = Post.objects.filter(published_date__range=(dt-timedelta(hours=1), dt))
    post_1h = serializers.serialize('json',PostsLastHour)
    return HttpResponse(post_1h, content_type="text/json-comment-filtered")

@superuser_only
def search_str(request):
    template = 'blog/info_superuser.html'
    query = request.GET.get('q')
    results_title = Post.objects.filter(Q(title__icontains=query))
    results_text = Post.objects.filter(Q(text__icontains=query))
    n = len(results_text) + len(results_title)
    return HttpResponse(n)


#works but need to find out how to add sound

import datetime
from playsound import playsound
alarmhour = int(input("Enter Hour: "))
alarmins = int(input("Enter Minutes: "))
alarmAm = input("AM / PM: ").upper()

if alarmAm == "pm".upper():
    alarmhour += 12

while True:
    if alarmhour == datetime.datetime.now().hour and alarmins == datetime.datetime.now().minute:
        playsound('/Users/chnguyen/Downloads/dsa.mp3')
        print("It's time mother f'er")
        break


# Databricks notebook source
# MAGIC %md
# MAGIC # Train Machine Learning Model
# MAGIC
# MAGIC This notebook aims to develop and register an MLFlow Model for deployment consisting of:
# MAGIC - a machine learning model to predict the liklihood of employee attrition.
# MAGIC
# MAGIC This example uses an adapted  version of the [`IBM HR Analytics Employee Attrition & Performance` dataset](https://www.kaggle.com/pavansubhasht/ibm-hr-analytics-attrition-dataset) available from Kaggle.
# MAGIC
# MAGIC > Ensure you have created managed Delta tables in the Hive Metastore with the associated dataset. These [instructions](https://learn.microsoft.com/en-au/azure/databricks/ingestion/add-data/upload-data#upload-the-file) can be used to learn how to upload the dataset.

# COMMAND ----------

# MAGIC %md
# MAGIC
# MAGIC #### Import dependencies and define constants

# COMMAND ----------

import json
from typing import Dict, Tuple, Union

import mlflow
import pandas as pd
from hyperopt import STATUS_OK, fmin, hp, tpe
from mlflow.models.signature import infer_signature
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import RandomForestClassifier
from sklearn.impute import SimpleImputer
from sklearn.metrics import (accuracy_score, f1_score, precision_score,
                             recall_score, roc_auc_score)
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder

# define notebook parameters
dbutils.widgets.text("curated_dataset_table",
                     "hive_metastore.default.employee_attrition_curated")

# define target column
TARGET = ["Attrition"]

# define categorical feature columns
CATEGORICAL_FEATURES = [
    "Gender",
    "Education",
    "EducationField",
    "Department",
    "JobRole",
    "JobLevel",
    "PerformanceRating",
    "JobInvolvement",
    "JobSatisfaction",
    "RelationshipSatisfaction",
    "EnvironmentSatisfaction",
    "BusinessTravel",
    "OverTime",
    "WorkLifeBalance",
    "MaritalStatus",
    "StockOptionLevel"
]

# define numeric feature columns
NUMERIC_FEATURES = [
    "Age",
    "DistanceFromHome",
    "MonthlyIncome",
    "NumCompaniesWorked",
    "PercentSalaryHike",
    "TotalWorkingYears",
    "TrainingTimesLastYear",
    "YearsAtCompany",
    "YearsInCurrentRole",
    "YearsSinceLastPromotion",
    "YearsWithCurrManager"
]

# COMMAND ----------

# MAGIC %md
# MAGIC
# MAGIC #### Define functions to build the model

# COMMAND ----------

def prepare_data(df: pd.DataFrame, random_state: int = 2023) -> Tuple[pd.DataFrame, pd.DataFrame]:
    # change data types of target and features
    df[TARGET] = df[TARGET].replace({"Yes": 1, "No": 0})
    df[NUMERIC_FEATURES] = df[NUMERIC_FEATURES].astype("float")
    df[CATEGORICAL_FEATURES] = df[CATEGORICAL_FEATURES].astype("str")

    # split into train and test datasets
    df_train, df_test = train_test_split(
        df[CATEGORICAL_FEATURES + NUMERIC_FEATURES + TARGET],
        test_size=0.20,
        random_state=random_state
    )

    return df_train, df_test

# COMMAND ----------

def make_classifer_pipeline(params: Dict[str, Union[str,  int]]) -> Pipeline:
    """Create sklearn pipeline to apply transforms and a final estimator"""
    # categorical features transformations
    categorical_transformer = Pipeline(steps=[
        ("imputer", SimpleImputer(strategy="constant", fill_value="missing")),
        ("ohe", OneHotEncoder())]
    )

    # numeric features transformations
    numeric_transformer = Pipeline(steps=[
        ("imputer", SimpleImputer(strategy="median"))]
    )

    # preprocessing pipeline
    preprocessor = ColumnTransformer(
        transformers=[
            ("numeric", numeric_transformer, NUMERIC_FEATURES),
            ("categorical", categorical_transformer, CATEGORICAL_FEATURES)
        ]
    )

    # model training pipeline
    classifer_pipeline = Pipeline([
        ("preprocessor", preprocessor),
        ("classifier", RandomForestClassifier(**params, n_jobs=-1))
    ])

    return classifer_pipeline

# COMMAND ----------

# define objective function
def hyperparameter_tuning(params):
    mlflow.sklearn.autolog(silent=True)

    with mlflow.start_run(nested=True):
        # read and process curated data
        df = spark.read.table(dbutils.widgets.get(
            "curated_dataset_table")).toPandas()
        df_train, df_test = prepare_data(df)

        # seperate features and target variables
        x_train, y_train = df_train[CATEGORICAL_FEATURES +
                                    NUMERIC_FEATURES], df_train[TARGET]
        x_test, y_test = df_test[CATEGORICAL_FEATURES +
                                 NUMERIC_FEATURES], df_test[TARGET]

        # train and model
        estimator = make_classifer_pipeline(params)
        estimator = estimator.fit(x_train, y_train.values.ravel())
        y_predict_proba = estimator.predict_proba(x_test)

        # train model
        estimator = make_classifer_pipeline(params)
        estimator.fit(x_train, y_train.values.ravel())

        # calculate evaluation metrics
        y_pred = estimator.predict(x_test)

        validation_accuracy_score = accuracy_score(
            y_test.values.ravel(), y_pred)
        validation_roc_auc_score = roc_auc_score(y_test.values.ravel(), y_pred)
        validation_f1_score = f1_score(y_test.values.ravel(), y_pred)
        validation_precision_score = precision_score(
            y_test.values.ravel(), y_pred)
        validation_recall_score = recall_score(y_test.values.ravel(), y_pred)

        # log evaluation metrics
        mlflow.log_metric("validation_accuracy_score",
                          validation_accuracy_score)
        mlflow.log_metric("validation_roc_auc_score", validation_roc_auc_score)
        mlflow.log_metric("validation_f1_score", validation_f1_score)
        mlflow.log_metric("validation_precision_score",
                          validation_precision_score)
        mlflow.log_metric("validation_recall_score", validation_recall_score)

        # log model
        input_example = x_test.iloc[0].to_dict()
        signature = infer_signature(x_train, y_pred)
        mlflow.sklearn.log_model(
            estimator, "model", signature=signature, input_example=input_example)

        return {"loss": -validation_roc_auc_score, "status": STATUS_OK}

# COMMAND ----------

def train_model():
    # set mlflow tracking uri
    mlflow_client = mlflow.tracking.MlflowClient(tracking_uri='databricks')
    mlflow.set_tracking_uri("databricks")
    # start model training run
    mlflow.set_experiment("/employee-attrition-classifier")
    with mlflow.start_run(run_name="employee-attrition-classifier") as run:
        # define search space
        search_space = {
            "n_estimators": hp.choice("n_estimators", range(100, 1000)),
            "max_depth": hp.choice("max_depth", range(1, 25)),
            "criterion": hp.choice("criterion", ["gini", "entropy"]),
        }

        # hyperparameter tuning
        best_params = fmin(
            fn=hyperparameter_tuning,
            space=search_space,
            algo=tpe.suggest,
            max_evals=10,
        )

        # end run
        mlflow.end_run()

        return run

# COMMAND ----------

# MAGIC %md
# MAGIC
# MAGIC #### Train and register the machine learning model

# COMMAND ----------

# Train model
run = train_model()

# Retreive model from best run
best_run = mlflow.search_runs(filter_string=f"tags.mlflow.parentRunId='{run.info.run_id}'", order_by=[
                              "metrics.testing_auc DESC"]).iloc[0]

# Register model artifact
model_name = "employee-attrition"
result = mlflow.register_model(f"runs:/{best_run.run_id}/model", model_name)

# Return notebook output
json_output = json.dumps(
    {"output": {"MODEL_NAME": result.name, "MODEL_VERSION": result.version}})
dbutils.notebook.exit(json_output)

# COMMAND ----------


from flask import Blueprint
from flask import  render_template, url_for, request
from flask import make_response, send_from_directory
from werkzeug.utils import secure_filename
import os
from apps.xmind2caseapp import write2excel, xmind2case

x2c = Blueprint('x2c',__name__)
# workpath = os.getcwd()
workpath=os.path.dirname(os.path.realpath(__file__))
upload_dir = os.path.join(workpath, "apps/xmind2caseapp" ,"upload")
download_dir = os.path.join(workpath,"apps/xmind2caseapp" , "download")

@x2c.route("/index")
def x2ch():
    return render_template("x2c/x2c.html")

@x2c.route("/x2conf")
def x2conf():
    return render_template("x2c/x2c.html")

@x2c.route('/uploader', methods=['GET', 'POST'])
def uploader():
    # print(os.path.join(workpath))

    if request.method == 'POST':
        f = request.files['file']
        if f.filename[f.filename.find("."):]!=".xmind":
            return "X101"  # X101:上传的不是xmind格式
        filename = f.filename[:f.filename.find(".")]+".xls"
        uppath = os.path.join(upload_dir, secure_filename(f.filename))
        dopath = os.path.join(download_dir, filename)
        f.save(uppath)
        p = xmind2case.xmind2dict(uppath)
        h = xmind2case.handle_xmind_msg(p)
        write2excel.writr_to_excel(dopath, h)

        dpath = url_for("x2c.download_file", filename=filename)
        print(dpath)
        return "True+"+dpath

    else:
        return 'False+'
        # return render_template('upload.html')

@x2c.route("/download/<filename>", methods=['GET'])
def download_file(filename):
    # directory=os.path.join(workpath,"download")
    response = make_response(send_from_directory(
        download_dir, filename, as_attachment=True))
    response.headers["Content-Disposition"] = "attachment; filename={}".format(
        filename.encode().decode('latin-1'))
    return response


import pandas as pd
import numpy as np
import json
from collections import defaultdict

from play_by_play import PlayByPlay

#define front end variables
DATE = '2015-12-25'
SEASON = '2015-16'
SEASON_TYPE = 'Regular+Season' # 'Regular+Season' or 'Playoffs'
HOME_TEAM = 'LAL'

def build_df(json):
    rows = []
    for frame_id in json:
        game_clock = json[frame_id]['time']
        quarter = json[frame_id]['quarter']
        row = [frame_id, game_clock, quarter]
        rows.append(row)
    df = pd.DataFrame(rows, columns = ['frame_id', 'game_clock', 'quarter'])
    return df

def encode_quarter(quarter):
    if quarter == '1st':
        return 1
    elif quarter == '2nd':
        return 2
    elif quarter == '3rd':
        return 3
    elif quarter == '4th':
        return 4
    else:
        #doublecheck: is all of OT just 5? 2OT, 3OT,...etc.
        return 5

def new_json_format(my_dict):
    ''' better organzition by nesting players on the court info  '''
    new_dict = defaultdict(dict)
    for frame_id in ocr_pbp_dict:
        game_clock = my_dict[frame_id]['game_clock']
        quarter = my_dict[frame_id]['game_clock']
        team1_id = my_dict[frame_id]['TEAM1_ID']
        team1_player1 = my_dict[frame_id]['TEAM1_PLAYER1']
        team1_player2 = my_dict[frame_id]['TEAM1_PLAYER2']
        team1_player3 = my_dict[frame_id]['TEAM1_PLAYER3']
        team1_player4 = my_dict[frame_id]['TEAM1_PLAYER4']
        team1_player5 = my_dict[frame_id]['TEAM1_PLAYER5']
        team2_id = my_dict[frame_id]['TEAM2_ID']
        team2_player1 = my_dict[frame_id]['TEAM2_PLAYER1']
        team2_player2 = my_dict[frame_id]['TEAM2_PLAYER2']
        team2_player3 = my_dict[frame_id]['TEAM2_PLAYER3']
        team2_player4 = my_dict[frame_id]['TEAM2_PLAYER4']
        team2_player5 = my_dict[frame_id]['TEAM2_PLAYER5']
        #assign to new format json
        new_dict[frame_id]['game_clock'] = game_clock
        new_dict[frame_id]['quarter'] = quarter
        #Team 1
        #for organizition, nest another dictionary for the team id and player ids of each team
        new_dict[frame_id]['team1'] = {}
        new_dict[frame_id]['team1']['id'] = team1_id
        new_dict[frame_id]['team1']['players'] = [team1_player1, team1_player2, team1_player3, team1_player4, team1_player5]
        #Team 2
        new_dict[frame_id]['team2'] = {}
        new_dict[frame_id]['team2']['id'] = team2_id
        new_dict[frame_id]['team2']['players'] = [team2_player1, team2_player2, team2_player3, team2_player4, team2_player5]
    return new_dict

if __name__ == "__main__":

    #read in the ocr results
    with open('./data/ocr_results.json') as ocr:
        ocr_json = json.load(ocr)

    #extract play by play data for the game uploaded
    pbp = PlayByPlay(DATE, SEASON, SEASON_TYPE, HOME_TEAM).get_pbp()

    #convert from json to DataFrame
    ocr_df = build_df(ocr_json)

    #fill in missing frames quarter by taking the last known quarter
    #future TODO: very small chance the last known quarter is incorrect if missing values occur at transition around 12:00 mark of new quarter
    ocr_df['quarter'] = ocr_df['quarter'].fillna(method = 'ffill')

    #convert game clock from string to seconds
    pbp['TimeSecs'] = [int(a) * 60 + int(b) for a, b in pbp['PCTIMESTRING'].str.split(':')]
    ocr_df['TimeSecs'] = [int(a) * 60 + int(b) for a, b in ocr_df['game_clock'].str.split(':')]

    #same for the quarter
    ocr_df['quarter'] = ocr_df['quarter'].apply(encode_quarter)

    #using pandas merge_asof to match up the corresponding pbp record for each frame to figure out who is on the court at each frame
    ocr_pbp = pd.merge_asof(ocr_df.sort_values('TimeSecs'), pbp[['TimeSecs', 'PERIOD','TEAM1_ID','TEAM1_PLAYER1', 'TEAM1_PLAYER2', 'TEAM1_PLAYER3', 'TEAM1_PLAYER4', 'TEAM1_PLAYER5', 'TEAM2_ID', 'TEAM2_PLAYER1', 'TEAM2_PLAYER2', 'TEAM2_PLAYER3', 'TEAM2_PLAYER4','TEAM2_PLAYER5']].sort_values('TimeSecs'), on='TimeSecs', left_by = 'quarter', right_by = 'PERIOD', direction='forward').sort_values('frame_id').drop(columns = ['TimeSecs', 'PERIOD'])

    #set index for .to_dict method
    ocr_pbp = ocr_pbp.set_index('frame_id')

    #convert to dictionary
    ocr_pbp_dict = ocr_pbp.to_dict(orient='index')

    #transform to final output form
    ocr_pbp_new = new_json_format(ocr_pbp_dict)

    #export the final ocr json
    with open('./ocr_w_players.json', 'w') as output:
        json.dump(ocr_pbp_new, output)


#%%
# 신호 기록 가져오기
with open('sample_20200601_pointfinger.txt', 'r') as openfile :
    samples = openfile.readlines()

tmp_timests = [ samples[i][:-1] for i in range(len(samples)) if i%3==0 ]
tmp_samples = [ samples[i][:-1] for i in range(len(samples)) if i%3==1 ]

#%%
# 중복된 시간 기록 제거
timests, samples = list(), list()
deleted = list()
for sinx in range(len(tmp_timests)-1) :
    if tmp_timests[sinx] != tmp_timests[sinx+1] :
        samples.append(float(tmp_samples[sinx]))
        timests.append(float(tmp_timests[sinx].replace('2020-06-01 09:', '')[3:]))
        if tmp_timests[sinx].replace('2020-06-01 09:', '')[:2] == '26' : timests[-1] += 60

#%%
# 플롭 해보기
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
import numpy as np
fm.get_fontconfig_fonts()
matplotlib.rc('font', family=fm.FontProperties(fname='C:/Windows/Fonts/NanumSquarel.ttf').get_name())
def plot(t, s, title='근전도 신호 데이터', xlabel='시간(초)', ylabel='신호 세기', style='-') :
    T = np.array(t)
    Y = np.array(s)
    mat = np.array([T, Y])

    plt.figure(figsize=(18, 5))
    plt.plot(T, Y, style, ms=15, lw=1)

    plt.xlabel(xlabel)
    plt.ylabel(ylabel)
    plt.title(title, fontsize=15, pad=20)
    plt.show()

plot(timests, samples)

#%%
# 초기화 시간 제거하기
init_end_inx = 0
while True :
    if samples[init_end_inx] < 190 :
        break
    init_end_inx += 1
timests, samples = timests[init_end_inx:], samples[init_end_inx:]
plot(timests[init_end_inx:], samples[init_end_inx:])

# # 기울기 값 계산
# grads = list()
# for i in range(1, len(timests)) :
#     grads.append((samples[i-1]-samples[i])/(timests[i-1]-timests[i]))

# plot(timests[1:], np.abs(grads))

#%%
# 바이어스 하기
bias_value = 173.5
plot(timests, np.abs(np.array(samples)-bias_value))

#%%
#구간 구하기
timespan = [51, 53.5] # 중간 신호
timespan = [53.5, 56.5] # 없는 신호

timespan = [75, 77] # 짧은 신호
timespan = [62, 66] # 긴 신호
span_indice = [0, 0]
while span_indice[0] < len(timests) :
    if timests[span_indice[0]] > timespan[0] : break
    span_indice[0] += 1
while span_indice[1] < len(timests) :
    if timests[span_indice[1]] > timespan[1] : break
    span_indice[1] += 1
span_indice

#%%
# 푸리에 주기적 곱
bias_samples = abs(np.array(samples)-bias_value)[span_indice[0]:span_indice[1]]
low_samples, high_samples = np.copy(bias_samples), np.copy(bias_samples)
pass_filter_value = 4
high_samples[bias_samples <= pass_filter_value] = 0
low_samples[bias_samples > pass_filter_value] = 0
plt.figure(figsize=(18, 8))
plt.plot(np.convolve(low_samples, high_samples), '-', ms=1, lw=1)

# plt.xlabel("")
# plt.ylabel("")
# plt.title(title, fontsize=15, pad=20)
plt.show()

#%%
bias_samples = abs(np.array(samples)-bias_value)
low_samples, high_samples = np.copy(bias_samples), np.copy(bias_samples)
high_samples[bias_samples <= pass_filter_value] = 0
low_samples[bias_samples > pass_filter_value] = 0
step_num = 5
pack_num = 30
pinx = 0
pvalues = list()
while pinx+pack_num < len(samples) :
    pvalues.append(np.sum(np.convolve(
        low_samples[pinx:pinx+pack_num],
        high_samples[pinx:pinx+pack_num]))/pack_num)
    pinx += step_num
plot(timests, samples)
plot(timests[:len(pvalues)], pvalues)

#%%
plot(timests[:len(pvalues)], pvalues)

#%%
# 그룹화하기
ginx = -1
group_area = list()
while ginx < len(pvalues) :
    ginx += 1
    while ginx < len(pvalues) and pvalues[ginx] < 1:
        ginx += 1
    tmp = ginx
    while ginx < len(pvalues) and pvalues[ginx] > 0:
        ginx += 1
    group_area.append((tmp, ginx))
group_area

#%%
# 최댓값 보기
maximums = list()
for area in group_area :
    if pvalues[area[0]:area[1]] :
        maximums.append(np.max(pvalues[area[0]:area[1]]))
plot([i for i in range(len(group_area)-1)], maximums, style='.')

#%%
(timests[0] - timests[1]) * 50

#%%
# CNN의 입력 행렬 만들기
# 이상점 제거
group_area = group_area[1:-1]

#%%
# 훈련 데이터 만들기
labels = []
for i in range(19) :
    labels.append(i)
len(labels)

#%%
def make_train(groups, areas, max_depth=40) :
    train_list = list()
    for area in areas :
        train_set = list()
        label_set = list()
        group_span = (area[1] - area[0])
        # if group_span : continue
        inx = 0
        while inx < max_depth and inx < group_span :
            a = labels[int(inx/group_span*len(labels))] # angle
            v = groups[inx:group_span]+[0 for i in range(max_depth-(group_span-inx))]
            train_set.insert(0, v)
            label_set.insert(0, a)
            inx += 1
        if train_set :
            train_list.append((train_set, label_set))
    return train_list

trains = make_train(pvalues, group_area)

#%%
tmp_train_inputs = list(map(lambda l: l[0], trains))
tmp_label_inputs = list(map(lambda l: l[1], trains))
train_inputs = list()
label_inputs = list()
for i in range(len(tmp_train_inputs)) :
    for j in range(len(tmp_train_inputs[i])) :
        train_inputs.append(tmp_train_inputs[i][j])
        label_inputs.append(tmp_label_inputs[i][j])
train_inputs = np.array(train_inputs)
label_inputs = np.array(label_inputs)
print(train_inputs.shape)

#%%
### 신경망 학습을 위한 모듈 가져오기
import tensorflow as tf
from tensorflow.keras import datasets, layers, Sequential

#%%
# 모델 만들기
model = Sequential()
model.add(layers.Dense(40, activation='relu'))
model.add(layers.Dense(50, activation='relu'))
model.add(layers.Dense(40, activation='relu'))
model.add(layers.Dense(30, activation='relu'))
model.add(layers.Dense(len(labels), activation='softmax'))
model.build(input_shape=(None, 40))
model.summary()

#%%
# 훈련 시작
model.compile(
    optimizer='adam',
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)

model.fit(train_inputs, label_inputs, epochs=500)

#%%
# 모델 평가
test_loss, test_acc = model.evaluate(train_inputs,  label_inputs, verbose=2)

#%%
predicts = list()
for i in range(len(train_inputs)) :
    p = model.predict(train_inputs[i:i+1]).tolist()[0]
    predicts.append(p)

#%%
predicts = [ p.index(max(p)) for p in predicts]
predicts

#%%
plot([i for i in range(len(predicts))], predicts, xlabel="필터링된 그룹", ylabel="카테고리", title="예측 데이터")
plot([i for i in range(len(predicts))], label_inputs, xlabel="필터링된 그룹", ylabel="카테고리", title="검증 데이터")

#%%
model.save('./my_model.h5')
#%%
print(train_inputs[0:1])
#%%
# len(pvalues)

# #%%
# # 스펙트럼 관찰
# import scipy.signal

# f, P = scipy.signal.periodogram(np.array(samples), int(1/(timests[1]-timests[0])), nfft=len(samples))

# plt.subplot(211)
# plt.plot(f, P)
# plt.title("선형 스케일")

# plt.subplot(212)
# plt.semilogy(f, P)
# plt.title("로그 스케일")

# plt.tight_layout()
# plt.show()


from fastapi import APIRouter
from app.libraries.libpermission import Permission
from app.schemas.permission import PermissionModel, PermissionUpdateModel, PermissionCreateModel

router = APIRouter(tags=["permission"])
oPermission = Permission()

@router.get("/permission/schema")
async def get_permission_schema(joined: bool = False):
  return await oPermission.get_permission_schema(joined=joined)

@router.get("/permission")
async def get_permission_list(joined: bool = False, limit: int = 100, offset: int = 0, sortField: str = None, sortOrder: str = "asc", search: str = ""):
    return await oPermission.get_permission_list(joined=joined, limit=limit, offset=offset, sortField=sortField, sortOrder=sortOrder, search=search)

@router.get("/permission/{permissionid}")
async def get_permission(permissionid: int, joined: bool = False):
    return await oPermission.get_permission(permissionid, joined=joined)

@router.post("/permission")
async def create_permission(permission: PermissionCreateModel):
    return await oPermission.create_permission(permission)

@router.put("/permission/{permissionid}")
async def update_permission(permissionid: int, permission: PermissionUpdateModel):
    return await oPermission.update_permission(permissionid, permission)

@router.delete("/permission/{permissionid}")
async def delete_permission(permissionid: int):
    return await oPermission.delete_permission(permissionid)


from django.test import TestCase
from django.utils.translation import ugettext_lazy as _

from social_links import forms

class LinksFormTests(TestCase):

    def taset_clean_url(self):
        valid_urls = [['https://www.example.com','https://www.example.com']
                      ['http://www.example.com','http://www.example.com']
                      ['www.example.com','http://www.example.com']
                      ['example.com','http://www.example.com']
        ]
        for url in valid_urls:
            cleaned_url = forms.clean_url(url[0])
            self.assertEqual(cleaned_url, url[1])

    def test_socail_form(self):
        invalid_data_dicts = [
            {'data': {'facebook': 'composerscouch.com',
                      'google_plus': '',
                      'twitter': ''},
            'error': ('facebook', [_(u'Must be a Facebook URL.')])},
            {'data': {'facebook': '',
                      'google_plus': 'composerscouch.com',
                      'twitter': ''},
            'error': ('google_plus', [_(u'Must be a Google Plus URL.')])},
            {'data': {'facebook': '',
                      'google_plus': '',
                      'twitter': 'composerscouch.com'},
            'error': ('twitter', [_(u'Must be a Twitter URL.')])},
        ]
        for invalid_dict in invalid_data_dicts:
            form = forms.SocialLinksForm(data=invalid_dict['data'])
            self.failIf(form.is_valid())
            self.assertEqual(form.errors[invalid_dict['error'][0]],
                             invalid_dict['error'][1])

        valid_data_dicts = [
            {'data': {'facebook': 'https://www.facebook.com/thekooksofficial',
                      'google_plus': 'https://plus.google.com/116651435444058665368/about',
                      'twitter': 'https://twitter.com/thekooksmusic'},},
        ]
        for valid_dict in valid_data_dicts:
            form = forms.SocialLinksForm(data=valid_dict['data'])
            self.failUnless(form.is_valid())

    def test_photo_form(self):
        invalid_data_dicts = [
            {'data': {'instagram': 'composerscouch.com',
                      'tumblr': ''},
            'error': ('instagram', [_(u'Must be a Instagram URL.')])},
            {'data': {'instagram': '',
                      'tumblr': 'composerscouch.com'},
            'error': ('tumblr', [_(u'Must be a Tumblr URL.')])},

        ]
        for invalid_dict in invalid_data_dicts:
            form = forms.PhotoLinksForm(data=invalid_dict['data'])
            self.failIf(form.is_valid())
            self.assertEqual(form.errors[invalid_dict['error'][0]],
                             invalid_dict['error'][1])

        valid_data_dicts = [
            {'data': {'instagram': 'http://instagram.com/thekooksmusic/',
                      'tumblr': 'http://thekooksmusic.tumblr.com/'},},
        ]
        for valid_dict in valid_data_dicts:
            form = forms.PhotoLinksForm(data=valid_dict['data'])
            self.failUnless(form.is_valid())

    def test_video_form(self):
        invalid_data_dicts = [
            {'data': {'youtube': 'composerscouch.com',
                      'vimeo': ''},
            'error': ('youtube', [_(u'Must be a Youtube URL.')])},
            {'data': {'youtube': '',
                      'vimeo': 'composerscouch.com'},
            'error': ('vimeo', [_(u'Must be a Vimeo URL.')])},

        ]
        for invalid_dict in invalid_data_dicts:
            form = forms.VideoLinksForm(data=invalid_dict['data'])
            self.failIf(form.is_valid())
            self.assertEqual(form.errors[invalid_dict['error'][0]],
                             invalid_dict['error'][1])

        valid_data_dicts = [
            {'data': {'youtube': 'https://www.youtube.com/user/thekooksofficial',
                      'vimeo': 'http://vimeo.com/davissilis'},},
        ]
        for valid_dict in valid_data_dicts:
            form = forms.VideoLinksForm(data=valid_dict['data'])
            self.failUnless(form.is_valid())

    def test_music_form(self):
        invalid_data_dicts = [
            {'data': {'bandcamp': 'composerscouch.com',
                      'itunes': '',
                      'spotify': '',
                      'soundcloud': ''},
            'error': ('bandcamp', [_(u'Must be a Bandcamp URL.')])},
            {'data': {'bandcamp': '',
                      'itunes': 'composerscouch.com',
                      'spotify': '',
                      'soundcloud': ''},
            'error': ('itunes', [_(u'Must be a iTunes URL.')])},
            {'data': {'bandcamp': '',
                      'itunes': '',
                      'spotify': 'composerscouch.com',
                      'soundcloud': ''},
            'error': ('spotify', [_(u'Must be a Spotify URL.')])},
            {'data': {'bandcamp': '',
                      'itunes': '',
                      'spotify': '',
                      'soundcloud': 'composerscouch.com'},
            'error': ('soundcloud', [_(u'Must be a SoundCloud URL.')])},
        ]
        for invalid_dict in invalid_data_dicts:
            form = forms.MusicLinksForm(data=invalid_dict['data'])
            self.failIf(form.is_valid())
            self.assertEqual(form.errors[invalid_dict['error'][0]],
                             invalid_dict['error'][1])

        valid_data_dicts = [
            {'data': {'bandcamp': 'http://sekinzer.bandcamp.com/track/junk-of-the-heart-cover',
                      'itunes': 'https://itunes.apple.com/us/artist/the-kooks/id68448386',
                      'spotify': 'https://play.spotify.com/artist/1GLtl8uqKmnyCWxHmw9tL4',
                      'soundcloud': 'https://soundcloud.com/kooksmusic'},},
        ]
        for valid_dict in valid_data_dicts:
            form = forms.MusicLinksForm(data=valid_dict['data'])
            self.failUnless(form.is_valid())


############################################################################################################
from colorama import *
import os
import requests
import re
############################################################################################################
def search_words_in_file(file_path, words):
    grabber_found = False
    with open(file_path, 'r', encoding='utf-8') as file:
        for line_number, line in enumerate(file):
            for word in words:
                if word in line:
                    grabber_found = True
                    os.system('title WARNING GRABBER WAS BEEN FOUNDED!')
                    print(f"{Fore.RED}[!]: {line.strip()}")
                    webhook_regex = r'(https?://(?:www\.)?discord(?:app)?\.com/api/webhooks/[^\s]+)'
                    webhook_match = re.search(webhook_regex, line)
                    if webhook_match:
                        webhook_url = webhook_match.group(1)
                        print(f"{Fore.LIGHTGREEN_EX}[SENDING]{Fore.WHITE} Sending a message to webhook :)")
                        title = '**Found Your Webhook LOL**'
                        description = f'Dont Grab People Nigga [>]: \nIf we see your webhook aigan its getting deleted this is a **WARNING**'
                        color = 0xFF5733
                        send_embed_to_webhook(webhook_url, title, description, color)
    if not grabber_found:
        print(f"{Fore.LIGHTGREEN_EX}NO GRABBER FOUND! :)")
        os.system('title NO GRABBER FOUND!')
############################################################################################################
def send_embed_to_webhook(webhook_url, title, description, color):
    embed = {
        "title": title,
        "description": description,
        "color": color
    }
    payload = {
        "username": "RainBow Blooded",
        "embeds": [embed]
    }
    try:
        response = requests.post(webhook_url, json=payload)
        response.raise_for_status()
        print(f"{Fore.LIGHTBLUE_EX}[SENT] {Fore.WHITE}Sent a warning to user's webhook")
    except requests.exceptions.RequestException as e:
        print(f"{Fore.LIGHTBLUE_EX}[ERROR] {Fore.WHITE}Failed to send message to webhook: {e}")
############################################################################################################
namefile = input(f"{Fore.LIGHTBLUE_EX}[{Fore.WHITE}>{Fore.LIGHTBLUE_EX}]: {Fore.WHITE}Filename?: ")
file_path = f'{namefile}'
words = ['b64decode', 'exec', "https://discord.com/api/webhooks/", "__t3mp__", "grabber", "stealer", "Hyperion", "OrionGrabber", "LunarStealer", "__import__('base64')", "__import__('builtins')", ".exec", ";exec", "__import__('tempfile')", "paste.fo", "paste.website", "<string>"]
search_words_in_file(file_path, words)
rem = input(f"{Fore.YELLOW}[{Fore.WHITE}+{Fore.YELLOW}]: {Fore.WHITE}do you want to remove the file? [y/n]: ")
if rem == "y":
    os.remove(namefile)
else:
    pass
############################################################################################################


from django.http import HttpResponse
from django.shortcuts import redirect, reverse, render
from cart.models import Cart, Item, OrderItem, Basket
from product_listing.models import Product
import cart.forms
import datetime
from django.contrib.auth import authenticate

# Create your views here.
def index(request):
	context={}
	total = 0
	if request.user.is_authenticated:
		carts = Cart.objects.filter(user=request.user)
		if carts is not None:
			this_cart = carts.first()
			context['cart'] = this_cart
			context['items'] = Item.objects.filter(cart=this_cart)
		else:
			this_cart = Cart(user=request.user)
			this_cart.save()
			context['cart'] = this_cart
		for item in context['items']:
			total += item.unit_price
		context['total'] = total
		return render(request, 'cart/cart.html', context)
	else:
		return redirect('/account/login')

#def viewCart(request):
#	context={}
#	user = request.user
#	cart = Cart.objects.get(user=user)
#	context['cart'] = cart
#	context['items'] = Item.objects.get(cart=cart)
#	return render(request, "cart.html", context)

def modifyCart(request, action, product_id, quantity):
	context = {}
	if request.user.is_authenticated:
		try:
			user_cart = Cart.objects.get(user=request.user)
		except:
			user_cart = Cart.objects.create(user=request.user)
		if (action=='add'):
			add_to_cart(request, product_id, quantity)
		elif (action=='remove'):
			remove_from_cart(request, product_id, quantity)
		elif (action=='clear'):
			clear_cart(request)
		else:
			return HttpResponse("Error")
	else:
		return reverse(request, 'account/login.html', context)
	return redirect('/')

def add_to_cart(request, product_id, quantity):
	print('getting to cart"s add to cart')
	user_cart = Cart.objects.get(user=request.user)
	product = Product.objects.get(id=product_id)
	itemsMatching = Item.objects.filter(product=product, cart=user_cart, unit_price=product.price_current)
	this_item= itemsMatching.first()
	if this_item is None:
		item = Item(
			product=product,
			cart = user_cart,
			quantity= quantity,
			unit_price= product.price_current
		)
		item.save()
	else:
		print('ok')
		new_q = this_item.quantity + quantity
		itemsMatching.update(quantity=new_q)

def remove_from_cart(request, product_id, quantity):
	this_cart = Cart.objects.get(user=request.user)
	items = Item.objects.filter(product=product_id, cart=this_cart)
	if items is not None:
		item = items.first()
		if (item.quantity > quantity):
			item.quantity = item.quantity-quantity
		else:
			item.delete()

def clear_cart(request):
	this_cart = Cart.objects.get(user=request.user)
	for item in this_cart.item_set.all():
		item.delete()
	this_cart.delete()

def checkout(request):
	context={}
	if request.user.is_authenticated == False:
		return reverse(request, 'account/login.html',context)
	try:
		this_cart = Cart.objects.get(user=request.user)
	except:
		return redirect('/cart')
	if this_cart.item_set.all() is None:
		form = forms.ShippingForm
		msg = "Your cart is empty"
		form.add_error(None, msg)
		return render (request, 'cart/checkout.html', context)
	user = request.user
	baskets = []
	items = this_cart.item_set.all()
	if request.method=='POST':
		form = cart.forms.ShippingForm(request.POST)
		if form.is_valid():
			try:
				shipaddr = form.cleaned_data['street_address']+", "+form.cleaned_data['postcode']
				for item in items:
					total = 0
					for basket in baskets:
						if (basket.seller != item.seller):
							total += 1
						else:
							thisBasket = basket
					if (total == len(baskets)):
						thisBasket = Basket(
							seller = item.product.seller,
							buyer = user,
							time = datetime.datetime.now(),
							shipping_to = shipaddr
						)
						thisBasket.save()
						baskets.append(thisBasket)
					orderItem = OrderItem(
						product_string = item.__str__(),
						unit_price = item.unit_price,
						product = item.product,
						buyer = user,
						seller = item.product.seller,
						basket = thisBasket,
						quantity = item.quantity,
						shipping_to = shipaddr
					)
					orderItem.save()
					product = item.product
					if product.stock > item.quantity:
						product.stock -= item.quantity
					else:
						Product.objects.filter(pk=product.pk).update(stock=0)
					item.delete()
				this_cart.delete()
			except:
				print('except')
				return HttpResponse("Please try again")
			return render(request, 'cart/checkoutsuccess.html', context)

		else:
			print('form is invalid')
			form = cart.forms.ShippingForm
			context['form'] = form
			return render (request, 'cart/checkout.html', context)
	else:
		form = cart.forms.ShippingForm
		context['form'] = form
		return render (request, 'cart/checkout.html', context)

def checkoutsuccess(request):
	return render(request, 'cart/checkoutsuccess.html')


import numpy as np
from sklearn.model_selection import train_test_split

class ToyDataset:

    def __init__(self, min_len, max_len):
        self.SOS = "<s>"
        self.EOS = "/<s>"

        self.characters = list("abcd")
        self.int2char = self.characters
        # 1 for SOS, 1 for EOS, 1 for padding
        self.char2int = {c: i+3 for i, c in enumerate(self.characters)}

        self.min_str_len = min_len
        self.max_str_len = max_len

        self.max_seq_len = max_len + 2
        self.vocab_size = len(self.characters) + 3

    def get_dataset(self, num_samples):
        inp_set = []
        tar_set = []
        for _ in range(num_samples):
            i, t = self._sample()
            inp_set.append(i)
            tar_set.append(t)
        return inp_set, tar_set

    def split_dataset(self, inp_set, tar_set, test_ratio=0.2):
        return train_test_split(inp_set, tar_set, test_size=test_ratio)

    def _sample(self):
        random_len = np.random.randint(self.min_str_len, self.max_str_len+1)
        random_char = np.random.choice(self.characters, random_len)

        inp = [self.char2int.get(c) for c in random_char]
        tar = inp[::-1]
        inp = [1] + inp + [2]
        tar = [1] + tar + [2]

        inp = np.pad(inp, (0, self.max_str_len+2-len(inp)), 'constant', constant_values='0')
        tar = np.pad(tar, (0, self.max_str_len+2-len(tar)), 'constant', constant_values='0')

        return inp, tar

    def char_index(self, char):
        if char == self.SOS:
            return 1
        elif char == self.EOS:
            return 2
        else:
            return self.char2int[char]

    def index_char(self, index):
        if index == 0:
            return ":"
        elif index == 1:
            return self.SOS
        elif index == 2:
            return self.EOS
        else:
            return self.characters[index-3]

if __name__ == '__main__':
    toy = ToyDataset(5, 10)
    inp_set, tar_set = toy.get_dataset(10)
    input_train, input_val, target_train, target_val = toy.split_dataset(inp_set, tar_set, 0.2)


import streamlit as st
import pandas as pd

st.set_page_config(layout="wide")

col1, col2 = st.columns([3, 1])
option = None

df = pd.read_csv('reuters_summaries.csv')

with col2:
    st.write("")
    st.write("")
    st.write("")
    st.write("")
    st.write("")
    option = st.selectbox('', ['Crude Oil', 'Biofuel'])

with col1:
    st.title('REUTERS')
    st.divider()
    if option == 'Crude Oil':
        #df = pd.read_csv('crude_oil_summary_new.csv')
        df_crude = df[df['keyword']=='crude oil']
        for index, series in df_crude.iterrows():
            st.markdown("### [{}]({})".format(series['title'], series['link']))
            st.markdown("*{}*".format(series['published']))
            st.markdown('**Keywords:  {}**'.format(series['keywords']))
            st.write(series['summary'])
            st.divider()

    if option == 'Biofuel':
        #df = pd.read_csv('biofuel_summary_new.csv')
        df_bio = df[df['keyword']=='biofuel']
        for index, series in df_bio.iterrows():
            st.markdown("### [{}]({})".format(series['title'], series['link']))
            st.markdown("*{}*".format(series['published']))
            st.markdown('**Keywords:  {}**'.format(series['keywords']))
            st.write(series['summary'])
            st.divider()


import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d

# index boundaries for time 3D plot
nStart = 140000
nEnd   = 160000

with open("time_series_stochastic_old.txt", "r") as file:
	lines = file.readlines()

time      = []
intensity = []
E_real    = []
E_imag    = []

for line in lines:
	time.append(float((line.split('	')[0])))
	intensity.append(float((line.split('	')[1])))
	E_real.append(float((line.split('	')[2])))
	E_imag.append(float((line.split('	')[3])))

time      = np.array(time)
intensity = np.array(intensity)
E_real    = np.array(E_real)
E_imag    = np.array(E_imag)

fig, ax = plt.subplots()
fig.set_size_inches(5.9, 4.8)
fig.subplots_adjust(top=0.99, bottom=0.15, left=0.16, right=0.95)
ax.plot(time, intensity, color="darkblue")
ax.set_xlabel(r"time $t$ / ns", fontsize=18.0)
ax.set_ylabel(r"intensity $|E|^2$", fontsize=18.0)
ax.set_xlim(140.0, 160.0)
ax.set_ylim(0.45, 2.05)
ax.set_yticks([0.5, 1.0, 1.5, 2.0])
ax.tick_params(axis="x", labelsize=18.0)
ax.tick_params(axis="y", labelsize=18.0)
ax.grid(color="lightgray")

fig, ax = plt.subplots()
fig.set_size_inches(5.9, 4.8)
plt.rcParams.update({"font.size": 18})
plt.subplots_adjust(top=1.06, bottom=0.05, left=-0.09, right=0.96)
ax = plt.axes(projection="3d")
ax.plot3D(time[nStart:nEnd], E_real[nStart:nEnd], E_imag[nStart:nEnd], color="darkblue")
ax.set_xlabel(r"time $t$ / ns")
ax.set_ylabel(r"Re($E$)")
ax.set_zlabel(r"Im($E$)")
ax.xaxis.labelpad=16
ax.yaxis.labelpad=11
ax.zaxis.labelpad=8
ax.set_xlim(140, 160.0)
ax.set_ylim(-1.5, 1.5)
ax.set_zlim(-1.1, 1.1)
ax.set_xticks([140.0, 145.0, 150.0, 155.0, 160.0])
ax.set_yticks([-1.0, 0.0, 1.0])
ax.set_zticks([-1.0, 0.0, 1.0])

plt.show()


# -*- coding: utf-8 -*-
r"""
    tests.test_state
    ~~~~~~~~~~~~~~~~

    Tests for the \p State class including movement mechanics and enumeration of the \p MoveSet
    class.

    :copyright: (c) 2019 by Zayd Hammoudeh.
    :license: MIT, see LICENSE for more details.
"""

from typing import Tuple
import pytest

from stratego import Move
from stratego.location import Location
from stratego.move import MoveStack
from stratego.piece import Color
from stratego.player import Player
from stratego.state import State

from testing_utils import STATES_PATH, SMALL_BRD, STD_BRD

def _get_move_from_player(plyr: Player, _orig: Tuple[int, int], new: Tuple[int, int]) -> Move:
    r"""
    Get the move from (row1, col1) in \p l1 to (row2, col2) in \p l2.

    :param plyr: Player whose move will be extracted
    :param _orig: Original location to move from
    :param new: New location to move to
    :return: Move corresponding to the move pair
    """
    available_moves = plyr.move_set.avail
    values = list(available_moves.values())
    v = [v for v in values if v.orig == Location(*_orig) and v.new == Location(*new)]
    assert v
    return v[0]

def _verify_num_pieces_and_move_set_size(state: State, num_red_p: int, num_blue_p: int,
                                         num_red_mv: int, num_blue_mv: int):
    r"""
    Verifies the number of pieces and size of the \p MoveSet

    :param state: State of the game
    :param num_red_p: Number of remaining RED pieces
    :param num_blue_p: Number of remaining BLUE pieces
    :param num_red_mv: Number of available moves for RED
    :param num_blue_mv: Number of available moves for BLUE
    """
    # Standardize assert tests
    assert state.red.num_pieces == num_red_p
    assert state.blue.num_pieces == num_blue_p
    assert len(state.red.move_set) == num_red_mv
    assert len(state.blue.move_set) == num_blue_mv

def test_duplicate_loc_in_state():
    r""" Verify that a \p State file with two pieces in same location raises an error """
    for dup_file in ["duplicate_loc_red.txt", "duplicate_loc_diff_color.txt"]:
        duplicate_path = STATES_PATH / dup_file
        assert duplicate_path.exists(), "Duplicate file path does not exist"

        with pytest.raises(Exception):
            State.importer(duplicate_path, STD_BRD)

def test_no_flag():
    r""" Verify an error is raised if the file has no flag """
    # Verify the "clean" passes
    path = STATES_PATH / "no_flag_clean.txt"
    assert path.exists(), "No flag test file does not exist"
    State.importer(path, STD_BRD)

    # Verify no flag checks are done for both players
    for file in ["no_flag_red.txt", "no_flag_blue.txt"]:
        path = STATES_PATH / file
        assert path.exists(), "No flag test file does not exist"

        with pytest.raises(Exception):
            State.importer(path, STD_BRD)

# noinspection PyProtectedMember
def test_state_basic_moves():
    r""" Verify the basic movement mechanics work without issue """
    path = STATES_PATH / "state_move_verify.txt"
    assert path.exists(), "Move verify file does not exist"

    state = State.importer(path, STD_BRD)

    # Verify initial state matches expectations
    _verify_num_pieces_and_move_set_size(state, 7, 7, 4 + 3, 4 + 3)

    move_stack = MoveStack()
    # Define a series of moves.  Entries in each tuple are:
    #   0: Original piece location
    #   1: Piece new location
    #   2: Number of red pieces
    #   3: Number of blue pieces
    #   4: Size of the red move set
    #   5: Size of the blue move set
    move_list = [((0, 1), (1, 1), 7, 7, 12, 7),
                 ((9, 1), (8, 1), 7, 7, 12, 12),
                 ((1, 1), (2, 1), 7, 7, 12, 12),
                 ((8, 1), (7, 1), 7, 7, 12, 12),
                 ((2, 1), (3, 1), 7, 7, 12, 12),
                 ((7, 1), (6, 1), 7, 7, 12, 12),
                 ((3, 1), (4, 1), 7, 7, 11, 12),  # One less due to blocked by (4, 2)
                 ((6, 1), (5, 1), 7, 7, 11, 11),  # One less due to blocked by (5, 2)
                 ((4, 1), (5, 1), 6, 6, 8, 8),  # Both lost piece in battle
                 ((9, 3), (6, 3), 6, 6, 8, 18),  # Move blue scout
                 ((0, 3), (3, 3), 6, 6, 18, 18),  # Move red scout
                 ((6, 3), (6, 5), 6, 6, 18, 23),  # Move blue scout
                 ((3, 3), (3, 5), 6, 6, 20, 20),  # Move red scout
                 ((6, 5), (6, 4), 6, 6, 23, 23),  # Move blue scout
                 ((3, 5), (9, 5), 6, 5, 16, 22),  # Red scout attack blue spy
                 ((6, 4), (0, 4), 6, 4, 16, 5)  # Blue scout attack red bomb
                 ]
    printer_out = []
    for orig, new, num_red_p, num_blue_p, num_red_mv, num_blue_mv in move_list:
        orig, new = Location(orig[0], orig[1]), Location(new[0], new[1])
        p = state.next_player.get_piece_at_loc(orig)
        assert p is not None
        attacked = state.get_other_player(state.next_player).get_piece_at_loc(new)

        move_stack.push(Move(p, orig, new, attacked))
        assert state.update(move_stack.top())
        assert state._printer._is_loc_empty(orig)

        _verify_num_pieces_and_move_set_size(state, num_red_p, num_blue_p, num_red_mv, num_blue_mv)
        printer_out.append(state.write_board())

    # Try to move red bomb then the red flag
    for orig in [Location(0, 4), Location(0, 6)]:
        p = state.next_player.get_piece_at_loc(orig)
        assert p is not None
        for new in [orig.left(), orig.right]:
            attacked = state.get_other_player(state.next_player).get_piece_at_loc(new)

            with pytest.raises(Exception):
                Move(p, orig, new, attacked)

    # Verify Undo
    for i in range(2, len(move_list) + 1):
        _, _, num_red_p, num_blue_p, num_red_mv, num_blue_mv = move_list[-i]
        state.undo()

        assert state.write_board() == printer_out[-i], "Printer mismatch after do/undo"
        _verify_num_pieces_and_move_set_size(state, num_red_p, num_blue_p, num_red_mv, num_blue_mv)

def test_small_direct_attack():
    r""" Test making a direct attack """
    move_list = [(None, None, None, None, 7, 7, 11, 11),
                 (Color.RED, Color.BLUE, (0, 3), (7, 3), 6, 6, 5, 5)
                 ]
    _helper_small_test(move_list)

def test_small_move_then_attack():
    r""" Test making a single move with a scout then a direct attack """
    move_list = [(None, None, None, None, 7, 7, 11, 11),
                 (Color.RED, Color.BLUE, (0, 3), (1, 3), 7, 7, 19, 10),
                 (Color.BLUE, Color.RED, (7, 3), (1, 3), 6, 6, 5, 5)
                 ]
    _helper_small_test(move_list)

def test_single_adjacent_scout():
    r""" Test making a single move with a scout then a direct attack """
    move_list = [(None, None, None, None, 2, 2, 11, 11),
                 (Color.BLUE, Color.BLUE, (2, 4), (2, 3), 1, 1, 0, 0)
                 ]
    _helper_small_test(move_list, state_file="moveset_two_scouts_adjacent.txt")

def test_scout_blocking_scout():
    r""" Test making a single move with a scout then a direct attack """
    move_list = [(None, None, None, None, 7, 7, 11, 11),
                 (Color.RED, Color.BLUE, (0, 5), (1, 5), 7, 7, 14, 11),
                 (Color.BLUE, Color.RED, (7, 3), (2, 3), 7, 7, 14, 19),
                 (Color.RED, Color.BLUE, (1, 5), (1, 4), 7, 7, 13, 19),
                 (Color.BLUE, Color.RED, (2, 3), (3, 3), 7, 7, 13, 13),
                 (Color.RED, Color.BLUE, (1, 4), (2, 4), 7, 7, 14, 13),
                 (Color.BLUE, Color.RED, (7, 2), (7, 3), 7, 7, 14, 13),
                 (Color.RED, Color.BLUE, (0, 0), (1, 0), 7, 7, 17, 13),
                 (Color.BLUE, Color.RED, (3, 3), (2, 3), 7, 7, 17, 16),
                 (Color.RED, Color.BLUE, (2, 4), (3, 4), 7, 7, 16, 19),
                 (Color.BLUE, Color.RED, (2, 3), (2, 4), 7, 7, 16, 16),
                 (Color.RED, Color.BLUE, (1, 0), (2, 0), 7, 7, 16, 16),
                 (Color.BLUE, Color.RED, (2, 4), (2, 1), 7, 7, 11, 19),
                 (Color.RED, Color.BLUE, (0, 2), (1, 2), 7, 7, 16, 19),
                 (Color.BLUE, Color.RED, (7, 5), (6, 5), 7, 7, 16, 22),
                 (Color.RED, Color.BLUE, (2, 0), (2, 1), 7, 6, 16, 9)
                 ]
    _helper_small_test(move_list, state_file="moveset_scout_block_scout.txt")

# noinspection PyProtectedMember
def _helper_small_test(move_info, state_file: str = "moveset_small_direct_attack.txt"):
    r"""
    Helper function for testing the movements on the small board

    :param move_info: List of move information.  For :math:`n` moves, the length of \p move_info
                      should be :math:`n+1`.  The first element is the initial board configuration.
    """
    path = STATES_PATH / state_file
    assert path.exists(), "Small direct attack state file not found"
    state = State.importer(path, SMALL_BRD)

    _, _, _, _, num_red_p, num_blue_p, num_red_mv, num_blue_mv = move_info[0]
    _verify_num_pieces_and_move_set_size(state, num_red_p, num_blue_p, num_red_mv, num_blue_mv)

    # Test doing moves
    moves, brd = [], [state.write_board()]
    for col, other_col, l1, l2, num_red_p, num_blue_p, num_red_mv, num_blue_mv in move_info[1:]:
        plyr, _ = state.get_player(col), state.get_player(other_col)

        m = _get_move_from_player(plyr, l1, l2)
        moves.append(m)
        state.update(moves[-1])
        brd.append(state.write_board())
        _verify_num_pieces_and_move_set_size(state, num_red_p, num_blue_p,
                                             num_red_mv, num_blue_mv)

    # Test undoing the moves
    for i in range(1, len(moves) - 1):
        assert brd[-i] == state.write_board()

        _, _, _, _, num_red_p, num_blue_p, num_red_mv, num_blue_mv = move_info[-i]
        _verify_num_pieces_and_move_set_size(state, num_red_p, num_blue_p,
                                             num_red_mv, num_blue_mv)
        assert moves[-i] == state._stack.top()  # pylint: disable=protected-access

        state.rollback()

        _, _, _, _, num_red_p, num_blue_p, num_red_mv, num_blue_mv = move_info[-i - 1]
        _verify_num_pieces_and_move_set_size(state, num_red_p, num_blue_p,
                                             num_red_mv, num_blue_mv)
        assert brd[-i - 1] == state.write_board()

def test_if_has_move():
    r""" Verify the \p piece_has_move method of the \p State class """
    path = STATES_PATH / "deep_q_verify.txt"
    state = State.importer(path, STD_BRD)

    # Marshall cannot move
    marshall_loc = Location(0, 0)
    p = state.get_player(Color.RED).get_piece_at_loc(marshall_loc)
    assert not state.piece_has_move(p)

    # Rank3 can move
    rank3_loc = Location(1, 0)
    p = state.get_player(Color.RED).get_piece_at_loc(rank3_loc)
    assert state.piece_has_move(p)

    # Bomb cannot move
    bomb_loc = Location(0, 4)
    p = state.get_player(Color.RED).get_piece_at_loc(bomb_loc)
    assert not state.piece_has_move(p)

    # Flag cannot move
    flag_loc = Location(0, 6)
    p = state.get_player(Color.RED).get_piece_at_loc(flag_loc)
    assert not state.piece_has_move(p)

    # verify pieces with known moves
    piece_col = (1, 2, 3, 5)
    for col in piece_col:
        flag_loc = Location(0, col)
        p = state.get_player(Color.RED).get_piece_at_loc(flag_loc)
        assert state.piece_has_move(p)

        flag_loc = Location(state.board.num_rows - 1, col)
        p = state.get_player(Color.BLUE).get_piece_at_loc(flag_loc)
        assert state.piece_has_move(p)

# noinspection PyProtectedMember
def test_cyclic_move():
    state = State.importer(STATES_PATH / "state_move_verify.txt", STD_BRD)
    assert len(state._stack) == 0, "Move stack to begin with"

    num_moves = 0
    orig, new = (0, 1), (1, 1)
    m = _get_move_from_player(state.next_player, orig, new)
    state.update(m)
    num_moves += 1
    assert len(state._stack) == num_moves
    assert len(state.get_cyclic_move()) == 0, "No cyclic move"

    # Dummy moves to ensure no premature cycle
    orig, new = (9, 1), (8, 1)
    m = _get_move_from_player(state.next_player, orig, new)
    state.update(m)
    num_moves += 1
    assert len(state._stack) == num_moves
    assert len(state.get_cyclic_move()) == 0, "No cyclic move"

    # Start of cycle
    orig, new = (0, 0), (1, 0)
    m = _get_move_from_player(state.next_player, orig, new)
    state.update(m)
    num_moves += 1
    assert len(state._stack) == num_moves
    assert len(state.get_cyclic_move()) == 0, "No cyclic move"

    orig, new = (9, 0), (8, 0)
    m = _get_move_from_player(state.next_player, orig, new)
    state.update(m)
    num_moves += 1
    assert len(state._stack) == num_moves
    assert len(state.get_cyclic_move()) == 0, "No cyclic move"

    orig, new = (1, 0), (0, 0)
    m = _get_move_from_player(state.next_player, orig, new)
    state.update(m)
    num_moves += 1
    assert len(state._stack) == num_moves
    assert len(state.get_cyclic_move()) == 0, "No cyclic move"

    orig, new = (8, 0), (9, 0)
    m = _get_move_from_player(state.next_player, orig, new)
    state.update(m)
    num_moves += 1
    assert len(state._stack) == num_moves
    assert len(state.get_cyclic_move()) == 0, "No cyclic move"

    orig, new = (0, 0), (1, 0)
    m = _get_move_from_player(state.next_player, orig, new)
    state.update(m)
    num_moves += 1
    assert len(state._stack) == num_moves
    assert len(state.get_cyclic_move()) == 0, "No cyclic move"

    orig, new = (9, 0), (8, 0)
    m = _get_move_from_player(state.next_player, orig, new)
    state.update(m)
    num_moves += 1
    assert len(state._stack) == num_moves
    assert len(state.get_cyclic_move()) == 1, "Cyclic move now"

    orig, new = (1, 1), (0, 1)
    m = _get_move_from_player(state.next_player, orig, new)
    state.update(m)
    num_moves += 1
    assert len(state._stack) == num_moves
    assert len(state.get_cyclic_move()) == 1, "Cyclic move now"

    orig, new = (8, 1), (9, 1)
    m = _get_move_from_player(state.next_player, orig, new)
    state.update(m)
    num_moves += 1
    assert len(state._stack) == num_moves
    assert len(state.get_cyclic_move()) == 0, "Cycle removed"


"""empty message

Revision ID: 073719702e2e
Revises: 23ecd00cae18
Create Date: 2020-03-29 13:31:19.799319

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = '073719702e2e'
down_revision = '23ecd00cae18'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('task_owners',
    sa.Column('user_id', sa.Integer(), nullable=False),
    sa.Column('task_id', sa.Integer(), nullable=False),
    sa.ForeignKeyConstraint(['task_id'], ['tasks.id'], ),
    sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
    sa.PrimaryKeyConstraint('user_id', 'task_id')
    )
    op.drop_table('tags')
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('tags',
    sa.Column('user_id', sa.INTEGER(), autoincrement=False, nullable=False),
    sa.Column('task_id', sa.INTEGER(), autoincrement=False, nullable=False),
    sa.ForeignKeyConstraint(['task_id'], ['tasks.id'], name='tags_task_id_fkey'),
    sa.ForeignKeyConstraint(['user_id'], ['users.id'], name='tags_user_id_fkey'),
    sa.PrimaryKeyConstraint('user_id', 'task_id', name='tags_pkey')
    )
    op.drop_table('task_owners')
    # ### end Alembic commands ###


from django.shortcuts import render
from django.http import HttpResponse
from django.utils.translation import get_language
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.decorators import login_required
from django.conf import settings

from . import Checksum

from paytm.models import PaytmHistory
# Create your views here.

@login_required
def home(request):
    return HttpResponse("PayNow")

def payment(request):
    MERCHANT_KEY = settings.PAYTM_MERCHANT_KEY
    MERCHANT_ID = settings.PAYTM_MERCHANT_ID
    get_lang = "/" + get_language() if get_language() else ''
    CALLBACK_URL = settings.HOST_URL + get_lang + settings.PAYTM_CALLBACK_URL
    # Generating unique temporary ids
    order_id = Checksum.__id_generator__()

    bill_amount = 100
    if bill_amount:
        data_dict = {
                    'MID':MERCHANT_ID,
                    'ORDER_ID':order_id,
                    'TXN_AMOUNT': bill_amount,
                    'CUST_ID':'harish@pickrr.com',
                    'INDUSTRY_TYPE_ID':'Retail',
                    'WEBSITE': settings.PAYTM_WEBSITE,
                    'CHANNEL_ID':'WEB',
                    #'CALLBACK_URL':CALLBACK_URL,
                }
        param_dict = data_dict
        param_dict['CHECKSUMHASH'] = Checksum.generate_checksum(data_dict, MERCHANT_KEY)
        return render(request,"payment.html",{'paytmdict':param_dict})
    return HttpResponse("Bill Amount Could not find. ?bill_amount=10")

@csrf_exempt
def response(request):
    if request.method == "POST":
        MERCHANT_KEY = settings.PAYTM_MERCHANT_KEY
        data_dict = {}
        for key in request.POST:
            data_dict[key] = request.POST[key]
        verify = Checksum.verify_checksum(data_dict, MERCHANT_KEY, data_dict['CHECKSUMHASH'])
        if verify:
            PaytmHistory.objects.create(user=request.user, **data_dict)
            return render(request,"response.html",{"paytm":data_dict})
        else:
            return HttpResponse("checksum verify failed")
    return HttpResponse(status=200)


# ==============================================================================
# Main runner entry point for the project
# Implemented using SAGE math library
#
# Author: Malo RANZETTI
# Date: Spring 2023
# ==============================================================================

import os
import msidh
import sidh
import sage.all as sage
import time
import argparse
import numpy as np

parser = argparse.ArgumentParser(
                    prog='M-SIDH Demo Runner',
                    description='This program is a demo built using SAGE of proposed countermeasures to the SIDH scheme.',
                    epilog='Written by M.Ranzetti')

def test_SIDH(curve, n_rounds=10):

    # ==============================================================================
    # TEST SIDH
    # NIST-LEVEL 5 (AES-256 security) 21s for the runtime
    # ==============================================================================
    print("Testing SIDH protocol...")

    scheme = sidh.create_protocol(sidh.get_curve(curve))
    results = []
    for i in range(n_rounds):
        print(f"Round {i+1}/{n_rounds}")
        results.append(scheme.run())

    print(f"Average time: {sum([r[1]for r in results])/n_rounds * 1e-9}s")
    print(f"Failure count: {sum([1 for r in results if not r[0]])}")

    average_time = sum([r[1]for r in results])/n_rounds * 1e-9
    std = np.std([r[1]for r in results])
    failure_count = sum([1 for r in results if not r[0]])

    data = {
        'settings': curve,
        'average_time': average_time,
        'std': std,
        'failure_count': failure_count
    }

    return data

def test_MSIDH(filename, n_rounds=10):

    # ==============================================================================
    # TEST MSIDH
    # Current maximum tested: t = 90 // 100 // 200
    # GOAL -> t = 572 for AES-128 security
    # Settings generation: 32.8s // 294.6s // 194.4s
    # Protocol execution: 5.3s // 35.0s // 320.9s
    # Currently the biggest bottlenecks are:
    # - prime verification in EllipticCurve (OVERRIDEN IN SAGE SOURCE CODE)
    # - computing the generators of the curve (=> there might be a way to optimize this)
    #
    # ==============================================================================
    print("Testing MSIDH protocol...")
    scheme = msidh.create_protocol_from_file(filename)

    results = []
    for i in range(n_rounds):

        print(f"Round {i+1}/{n_rounds}")
        results.append(scheme.run())

    print(f"Average time: {sum([r[1]for r in results])/n_rounds * 1e-9}s")
    print(f"Failure count: {sum([1 for r in results if not r[0]])}")

    average_time = sum([r[1]for r in results])/n_rounds * 1e-9
    std = np.std([r[1]for r in results])
    failure_count = sum([1 for r in results if not r[0]])

    data = {
        'settings': filename.split('AES-')[1].split('.')[0],
        'average_time': average_time,
        'std': std,
        'failure_count': failure_count
    }

    return data

def gen_MSIDH128():
    msidh.create_g128_protocol()

def create_msidh(lam):
    msidh.create_protocol(msidh.MSIDHpArbitrary, lam)

def output_data(filename, data):
    '''
    Write the data given as an array into csv format
    data: dict of the form {name: [data list]}
    '''

    # check if file exists
    if not os.path.exists(filename):
        with open(filename, 'w') as f:
            f.write(','.join(data.keys()) + '\n')

    with open(filename, 'a') as f:
        # add a line
        f.write(','.join([str(v) for v in data.values()]) + '\n')
    print(f"Data written to {filename}")

if __name__ == "__main__":
    parser.add_argument('-t', '--test', type=str, choices=['sidh', 'msidh'], help='Test to run (sidh, msidh)')
    parser.add_argument('-c', '--curve', type=str, choices=list(sidh.available_curves.keys()) ,help='Curve to use for SIDH')
    parser.add_argument('-f', '--file', type=str, help='File to use for MSIDH paramters')
    parser.add_argument('-r', '--rounds', type=int, default=10, help='Number of rounds to run tests for')
    parser.add_argument('-g', '--gen', type=int, help='generate MSIDH parameters for a given security level')
    parser.add_argument('-g128', '--gen128', action='store_true', help='generate MSIDH-128 parameters')
    args = parser.parse_args()

    if args.gen:
        create_msidh(args.gen)
    elif args.gen128:
        gen_MSIDH128()
    elif args.test == 'sidh':
        if not args.curve:
            print("Please provide a curve to use for SIDH using -c")
            exit(1)
        data = test_SIDH(args.curve, args.rounds)
        output_data("sidh_results.csv", data)

    elif args.test == 'msidh':
        if not args.file:
            print("Please provide a file to use for MSIDH using -f")
            print("You can generate a file using -g <security level>")
            exit(1)
        data = test_MSIDH(args.file, args.rounds)
        output_data("msidh_results.csv", data)
    else:
        print("Invalid arguments, use -h for help")
        exit(1)


import json
import requests

import constants
import tokens

def make_api_call(access_token, url, method, **kwargs):
    response = method(
        url=url,
        headers={
            "Accept": "application/json",
            "Content-Type": "application/json",
            "Authorization": f"Bearer {access_token}",
        },
        **kwargs,
    )
    if not response.ok:
        raise RuntimeError(f"Error making request to {url}: ", response.content)
    return response

def get_user_id_and_name_from_refresh_token(refresh_token):
    access_token = tokens.get_access_token(refresh_token)
    user_response = make_api_call(access_token, constants.API_URL + "/me", requests.get)
    return user_response.json()["id"], user_response.json()["display_name"]

def make_new_playlist(user):
    response = make_api_call(
        user.access_token,
        url=f"{constants.API_URL}/users/{user.user_id}/playlists",
        method=requests.post,
        data=json.dumps({"name": constants.DEFAULT_PLAYLIST_NAME, "description": f"Here are your most recently added songs from the last {user.recently_added_delta_days} days"})
    )
    return response.json()["id"]


import torch
import logging
import pickle

from core.utils import scale_image, save_layer_image
from data import image_corruption

def evaluate(model, loader, args, perturbation=False, pSize=0, **kwargs):
    objective_function= kwargs.get('objective_function', None)
    device = kwargs['device']
    if 'epoch' in kwargs:
        epoch = kwargs['epoch']
        ibatch = kwargs["ibatch"]
    else:
        epoch = 'Test'
        ibatch = 0

    validloss = 0
    for i, (images, _) in enumerate(loader):
        if i == 200:
            break
        corrupt_img, _ = image_corruption(images, args, perturbation=perturbation, pSize=pSize) #blurring, inpainting, noising
        corrupt_img_scale = scale_image(corrupt_img, args.nBits)
        restored_img, outsx, _ = model(corrupt_img_scale.to(device), objective_function=objective_function, noisyOuts=args.noisyOuts)
        validloss += (torch.norm(restored_img.detach().cpu() - images, p='fro')**2).item() #MSE
        if i == 0:
            if epoch == 'Test':
                with open(f'./results/{args.dataset}_{args.constrained}_{pSize}.pkl', 'wb') as ObjFile:
                    pickle.dump((images, corrupt_img, restored_img, epoch, ibatch), ObjFile)
            save_layer_image(images, corrupt_img, outsx, epoch, ibatch, args, perturbation=False)
            break
        del images, corrupt_img, restored_img, outsx, corrupt_img_scale
        torch.cuda.empty_cache()

    validloss /= (len(loader)*args.batchSize)

    logging.debug("Epoch {} - Batch {}, Loss {:.4f}".format(epoch, ibatch, validloss))

    return validloss


import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms

# 定义客户端类
class Client:
    def __init__(self, model, train_loader, test_loader, lr=0.1):
        self.model = model
        self.train_loader = train_loader
        self.test_loader = test_loader
        self.optimizer = optim.SGD(self.model.parameters(), lr=lr)

    def train(self, epochs=1):
        self.model.train()
        for epoch in range(epochs):
            for data, target in self.train_loader:
                self.optimizer.zero_grad()
                output = self.model(data)
                loss = nn.functional.cross_entropy(output, target)
                loss.backward()
                self.optimizer.step()

    def test(self):
        self.model.eval()
        test_loss = 0
        correct = 0
        with torch.no_grad():
            for data, target in self.test_loader:
                output = self.model(data)
                test_loss += nn.functional.cross_entropy(output, target, reduction='sum').item()
                pred = output.argmax(dim=1, keepdim=True)
                correct += pred.eq(target.view_as(pred)).sum().item()
        test_loss /= len(self.test_loader.dataset)
        accuracy = 100. * correct / len(self.test_loader.dataset)
        return test_loss, accuracy

    def get_topk_grads(self, k=0.01):
        grads = []
        for param in self.model.parameters():
            if param.grad is not None:
                importance = param.grad.abs().sum()
                k_ = int(importance.numel() * k)
                topk_values, _ = torch.topk(param.grad.abs().view(-1), k_)
                mask = torch.zeros_like(param.grad)
                mask[param.grad.abs() >= topk_values[-1]] = 1
                grads.append(mask * param.grad)
        return torch.cat(grads)

# 定义服务器类
class Server:
    def __init__(self, clients):
        self.clients = clients

    def aggregate(self):
        grads = None
        num_grads = 0
        for client in self.clients:
            client_grads = client.get_topk_grads()
            if grads is None:
                grads = client_grads
            else:
                grads += client_grads
            num_grads += 1
        grads /= num_grads
        return grads

# 定义主函数
def main():
    # 加载MNIST数据集
    train_dataset = datasets.MNIST('../data', train=True, download=True,
                       transform=transforms.Compose([
                           transforms.ToTensor(),
                           transforms.Normalize((0.1307,), (0.3081,))
                       ]))
    test_dataset = datasets.MNIST('../data', train=False, transform=transforms.Compose([
                           transforms.ToTensor(),
                           transforms.Normalize((0.1307,), (0.3081,))
                       ]))
    train_loaders = [torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True) for _ in range(10)]
    test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=1000, shuffle=True)

    # 初始化客户端和服务器
    clients = [Client(nn.Sequential(nn.Linear(784, 128), nn.ReLU(), nn.Linear(128, 10)), train_loader, test_loader) for train_loader in train_loaders]
    server = Server(clients)

    # 训练和聚合
    for round in range(num_rounds):
        print(f"\nRound {round + 1}")

        # 客户端训练并计算梯度
        grad_list = []
        for client in clients:
            client.train()
            client_optimizer.zero_grad()
            # 获取客户端的本地数据
            inputs, labels = client.get_data()
            # 前向传播
            outputs = client.model(inputs)
            # 计算局部loss
            loss = criterion(outputs, labels)
            # 反向传播
            loss.backward()
            # 获取梯度并压缩
            grad = client.get_topk_grads()
            grad_list.append(grad)

        # 服务器聚合梯度并更新模型
        server.aggregate(grad_list)
        server.update_model()

        # 客户端更新模型
        for client in clients:
            client.update_model(server.model)

        # 计算并打印全局loss
        global_loss = evaluate_global_loss(server.model, test_loader, criterion)
        print(f"Global Loss: {global_loss:.4f}")


from flask import Flask
from flask import render_template
import ffmpeg_streaming
from ffmpeg_streaming import Formats

import sys

app = Flask(__name__)

@app.route("/")
def streaming():
  return render_template('streaming.html')

@app.route('/video')
def video_server():
  video = ffmpeg_streaming.input('pexels_video.mp4')

  hls = video.hls(Formats.h264())
  hls.auto_generate_representations()
  hls.save_master_playlist('/var/media/hls.m3u8')

  return hls.output('/var/media/hls.m3u8')

def monitor(ffmpeg, duration, time_, time_left, process):
  per = round(time_ / duration * 100)
  sys.stdout.write(
    "\rTranscoding...(%s%%) %s left [%s%s]" %
    (per, datetime.timedelta(seconds=int(time_left)), '#' * per, '-' * (100 - per))
  )
  sys.stdout.flush()


from collections import defaultdict
ENTER = "Enter"
LEAVE = "Leave"
CHANGE = "Change"

ENTER_MESSAGE = "님이 들어왔습니다."
LEAVE_MESSAGE = "님이 나갔습니다."

class ChatRoom:

    def __init__(self):
        super().__init__()

def operation(result, command, chatRoom, nicknames, uid="", name=""):

    if command == ENTER:
        chatRoom.append(uid)
        nicknames[uid] = name
        result.append((uid, ENTER_MESSAGE))
        return
    elif command == LEAVE:
        chatRoom.remove(uid)
        result.append((uid, LEAVE_MESSAGE))
        return
    elif command == CHANGE:
        nicknames[uid] = name
        return

    return

def solution(record):
    answer = []
    nicknames = defaultdict(str)
    chatRoom = []
    result = []
    command, uid, name = "", "", ""

    for r in record:
        splited = r.split()
        if len(splited) == 2:
            command, uid = splited
        else:
            command, uid, name = splited

        operation(result, command, chatRoom, nicknames, uid, name)

    answer = list(map(lambda x: nicknames[x[0]]+x[1], result))
    return answer

if __name__ == "__main__":

    test = 1

    if test == 1:
        record = ["Enter uid1234 Muzi", "Enter uid4567 Prodo", "Leave uid1234", "Enter uid1234 Prodo", "Change uid4567 Ryan"]

    print(solution(record))