class NodeNotFound(Exception):
    def __init__(self, node):
        super().__init__(f'Node {node} does not exist in the graph.')

class EdgeNotFound(Exception):
    def __init__(self, edge):
        super().__init__(f'Edge {edge} does not exist in the graph.')

class DuplicateNode(Exception):
    def __init__(self, node):
        super().__init__(f'Node {node} already exists in the graph.')

class DuplicateEdge(Exception):
    def __init__(self, edge):
        super().__init__(f'Edge {edge} already exists in the graph.')

class node:
    def __init__(self, label):
        """
        Parameter: a string indicating the label of the new node
        """
        self.label = label
        self.in_degree_val = 0
        self.out_degree_val = 0

    def in_degree(self):
        """
        Parameter: none
        Return value: integer representing the in-degree of
        this node
        """

        return self.in_degree_val

    def update_in_degree(self, new_edge=0):
        """
        Parameter: none
        Return value: integer representing the in-degree of
        this node
        """
        if new_edge == 1:
            self.in_degree_val += 1
        elif new_edge == -1:
            self.in_degree_val -= 1

        return self.in_degree_val

    def out_degree(self):
        """
        Parameter: none
        Return value: integer representing the out-degree of
        this node
        """

        return self.out_degree_val

    def update_out_degree(self, new_edge=0):
        """
        Parameter: none
        Return value: integer representing the out-degree of
        this node
        """
        if new_edge == 1:
            self.out_degree_val += 1
        elif new_edge == -1:
            self.out_degree_val -= 1
        return self.out_degree_val

    def __str__(self):
        """
        Parameter: none
        Return value: string label of the node
        """
        return self.label

class Graph:
    def __init__(self, directed=False):
        """
        Parameter: a boolean indicating whether the new instance
        of Graph will be directed (True) or undirected (False)
        Post condition: new instance of an empty graph is
        created
        """
        self.directed = directed
        self.num_vertices_val = 0
        self.num_edges_val = 0
        self.is_weighted_val = False
        self.graph = {}
        self.node_label_map = {}

    def set_graph(self, graph):
        self.graph = graph

    def num_vertices(self):
        """
        Parameters: none
        Return value: integer corresponding to the total number
        of vertices in the graph
        """

        return self.num_vertices_val

    def num_edges(self):
        """
        Parameters: none
        Return value: integer corresponding to the total number
        of edges in the graph
        """

        return self.num_edges_val

    def is_directed(self):
        """
        Parameters: none
        Return value: boolean - True if this instance of the
        Graph class is a directed graph, False otherwise
        """

        return self.directed

    def is_weighted(self):
        """
        Parameters: none
        Return value: boolean - True if any edge in the Graph
        has a weight other than 1, False otherwise
        """

        return self.is_weighted_val

    def __check_node_exists(self, label):
        if label not in self.graph.keys():
            raise NodeNotFound(label)

    def __check_node_duplicate(self, label):
        if label in self.graph.keys():
            raise DuplicateNode(label)

    def add_node(self, label):
        """
        Parameter: a string indicating the label of a new node
        in the Graph
        Return value: none
        Assumptions: labels of nodes in the Graph must be unique
        """
        self.__check_node_duplicate(label)
        new_node = node(label)
        self.node_label_map[label] = new_node
        self.graph[label] = set()

        self.num_vertices_val += 1

        return new_node

    def remove_node(self, label):
        """
        Parameter: a string indicating the label of an existing
        node in the Graph
        Return value: none
        Post conditions: the node with the given label, as well
        as any edges to/from that node, are removed from the
        graph
        """
        self.__check_node_exists(label)
        node = self.node_label_map[label]
        adjacent_vertices = self.graph[label]

        for vertex in adjacent_vertices:
            self.graph[vertex].remove(label)
            vertex_node = self.node_label_map[vertex]
            ## TO do: In degree
            self.num_edges_val -= 1

        del self.graph[label]
        del self.node_label_map[label]
        self.num_vertices_val -= 1

    def __edge_exists(self, n1, n2):
        try:
            edges_n1 = self.graph[n1]
            if n2 in edges_n1:
                return True
            else:
                raise EdgeNotFound((n1, n2))
        except KeyError:
            raise NodeNotFound(n1)

    def __check_duplicate_edge(self, n1, n2):
        try:
            edges_n1 = self.graph[n1]
            if n2 in edges_n1:
                raise DuplicateEdge((n1, n2))
        except KeyError:
            raise NodeNotFound(n1)

    def add_edge(self, n1, n2, weight = 1):
        """
        Parameters:
            two strings, indicating the labels of the
            nodes connected by the new edge. If this is a directed
            Graph, then the edge will be FROM n1 TO n2.
            a numeric value (int/float) for a weight of the edge
        Return value: none
        Assumptions: the combination of (n1, n2, weight) must
        be unique in the Graph
        Post conditions: one new edge is added to the Graph
        """
        self.__check_duplicate_edge(n1, n2)
        self.graph[n1].add(n2)
        node_n1 = self.node_label_map[n1]
        node_n2 = self.node_label_map[n2]
        node_n1.update_out_degree(1)
        node_n2.update_in_degree(1)

        if not self.directed:
            self.graph[n2].add(n1)
            node_n2.update_out_degree(1)
            node_n1.update_in_degree(1)

        self.num_edges_val += 1

    def remove_edge(self, n1, n2, weight = 1):
        """
        Parameters:
            two strings, indicating the labels of the
            nodes connected by the edge. If this is a directed
            Graph, then the edge will be FROM n1 TO n2.
            a numeric value (int/float) for a weight of the edge
        Return value: none
        Post conditions: the edge with the given nodes and weight
        is removed from the graph
        """
        self.__edge_exists(n1, n2)
        self.graph[n1].remove(n2)
        node_n1 = self.node_label_map[n1]
        node_n2 = self.node_label_map[n2]
        node_n1.update_out_degree(-1)
        node_n2.update_in_degree(-1)

        if not self.directed:
            self.graph[n2].remove(n1)
            node_n2.update_out_degree(-1)
            node_n1.update_in_degree(-1)

        self.num_edges_val -= 1

    def BFS(self, source):
        """
        Parameter: a string indicating the label of an existing
        node in the Graph
        Return value: a list of node objects, which is the
        Breadth First Search starting at source
        """

        visited_dict = {}
        result_list = []
        def do_bfs(source):
            result_list = []
            queue = [source]

            while queue:
                print(queue)
                current_node = queue.pop(0)
                visited_dict[current_node] = True
                result_list.append(current_node)
                for neighbor in self.graph[current_node]:
                    if not visited_dict.get(neighbor, False) and neighbor not in queue:
                        queue.append(neighbor)

            return result_list

        result_list = do_bfs(source)
        # for node in self.graph.keys():
        #     if not visited_dict.get(node, False):
        #         result_list += do_bfs(node)

        return result_list

    def DFS(self, source):
        """
        Parameter: a string indicating the label of an existing
        node in the Graph
        Return value: a list of node objects, which is the
        Depth First Search starting at source
        """
        visited_dict = {}
        result_list = []
        for node in self.graph.keys():
            visited_dict[node] = False

        def do_dfs(current_node):
            if visited_dict[current_node]:
                return
            visited_dict[current_node] = True
            for neighbour_node in self.graph[current_node]:
                do_dfs(neighbour_node)
            result_list.append(current_node)

        do_dfs(source)
        for node in visited_dict.keys():
            if not visited_dict[node]:
                do_dfs(node)

        return result_list

    def has_edge(self, n1, n2):
        """
        Parameters:
            two strings, indicating the labels of the
            nodes connected by the new edge. If this is a directed
            Graph, then the edge will be FROM n1 TO n2.
        Return value: a boolean - True if there is an edge in the
            Graph from n1 to n2, False otherwise
        """
        self.__check_node_exists(n1)
        self.__check_node_exists(n2)
        if n2 in self.graph.get(n1):
            return True
        else:
            return False

    def get_path(self, n1, n2):
        """
        Parameters:
            two strings, indicating the labels of the
            nodes you wish to find a path between. The path will be
            FROM n1 TO n2.
        Return value: a list L of node objects such that L[0] has
            label n1, L[-1] has label n2, and for 1 <= i <= len(L) - 1,
            the Graph has an edge from L[i-1] to L[i]
        """
        self.__check_node_exists(n1)
        self.__check_node_exists(n2)
        visited_dict = {}
        result_list = []
        for node in self.graph.keys():
            visited_dict[node] = False

        def do_bfs(current_node, result_list):
            if visited_dict[current_node]:
                return result_list
            if current_node == n2:
                result_list.append(current_node)
                return result_list
            visited_dict[current_node] = True
            result_list.append(current_node)
            for neighbour_node in self.graph[current_node]:
                result_list = do_bfs(neighbour_node, result_list)
                if n2 in result_list:
                    break

            return result_list

        result_list = do_bfs(n1, result_list)

        return result_list
        pass

    def get_adjacent_nodes(self, label):
        """
        Parameter: a string indicating the label of an existing
        node in the Graph
        Return value: a list of node objects containing all nodes
        adjacent to the node with the given label
        """
        self.__check_node_exists(label)
        return list(self.graph[label])

    def random_return(self):
        return self.graph


''' Function to convert the time to human readable'''
''' add import timeConverter to top of script using this module '''
''' usage example - print "RunTime -", time_readable(RunTime) '''

import time

def time_readable(secs):
    mins, secs = divmod(secs, 60)
    hours, mins = divmod(mins, 60)
    if (secs) < 1:
        return "Less than a second"
    else:
        return '%02d:%02d:%02d' % (hours, mins, secs)


import cv2
import numpy as np

class Classify():
    def __init__(self):
        self.means = 0
        self.number = 3

    def fit(self, X, y, number):
        M, N = X.shape
        means = np.zeros((number, N))
        for i in range(number):
            means[i, :] = (1/N) * np.sum(X[y == i, :], axis=0)
        self.means = means
        self.number = number

    def distance(self, X1, X2):
        diff = X1-X2
        d = np.sqrt(np.dot(diff, diff))
        return d

    def predict(self, test_img):
        min_dist = np.inf
        min_class = -1
        for i in range(self.number):
            d = self.distance(test_img, self.means[i, :])
            if d < min_dist:
                min_dist = d
                min_class = i
        return min_class

    def save_weights(self):
        np.save('Weights', self.means)

    def load_weights(self):
        self.means = np.load('./utilities/Weights.npy')


import sys
k = int(sys.stdin.readline())
for i in range(1,k+1):
    gap = 0
    print('Class', i)
    L=[int(x) for x in sys.stdin.readline().rstrip().split()]
    cnt = L[0]
    L = L[1:]
    L.sort(reverse=True)
    for i in range(len(L)-1):
        tmp = L[i]-L[i+1]
        if gap < tmp:
            gap = tmp

    print('Max',max(L),end='')
    print(', Min', min(L),end='')
    print(', Largest gap',gap)


import numpy as np

import crtomo.parManager as pM
import crtomo.grid as CRGrid

class test_parManager():
    def setup(self):
        grid = CRGrid.crt_grid()
        grid.load_elem_file('tomodir/grid/elem.dat')

        self.parman = pM.ParMan(grid)

    def test_adding_potentials(self):
        par = np.loadtxt('tomodir/inv/rho02.mag', skiprows=1)

        cid = self.parman.add_data(par[:, 2])
        assert cid == [0, ]


from django.db import models
from django.db.models import signals
from django.dispatch import receiver
from django.db.models.signals import post_save
from django.conf import settings
from django.core.mail import send_mail
import sendgrid
import os
from sendgrid.helpers.mail import *

class Contact(models.Model):
    email = models.EmailField()
    phone_number = models.CharField(max_length = 50, blank = True, null = True, default = 'No phone number')
    subject = models.CharField(max_length = 255, blank = True, null = True, default = 'No subject')
    body = models.TextField(blank = True, null = True, default = '\n')
    created_date = models.DateTimeField(auto_now = True, auto_now_add=False)
    updated_date = models.DateTimeField(auto_now= False, auto_now_add = True)

    class Meta:
        verbose_name = 'Email'
        verbose_name_plural = 'Emails'

    def send_contact_email(instance, **kwargs):
        if instance.body is '':
            instance.body = '\n'
        if instance.subject is '':
            instance.subject = 'No subject'
        if instance.phone_number is '':
            instance.phone_number = 'Not filled'

        sg = sendgrid.SendGridAPIClient(apikey=os.environ.get('SENDGRID_API_KEY'))
        from_email = Email(instance.email)
        subject = instance.subject if not '' else 'No subject'
        to_email = Email("app@wallpaperapp.uk")
        content = Content("text/plain", instance.body + "\n\nPhone number: " + instance.phone_number)
        mail = Mail(from_email, subject, to_email, content)
        response = sg.client.mail.send.post(request_body=mail.get())
    post_save.connect(send_contact_email, sender=Contact)


# @before-stub-for-debug-begin
from python3problem35 import *
from typing import *
# @before-stub-for-debug-end

#
# @lc app=leetcode id=35 lang=python3
#
# [35] Search Insert Position
#

# @lc code=start
class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        def binarySearch(arr, x):
            low = 0
            high = len(arr) - 1
            mid = 0
            while low <= high:
                mid = (low + high) // 2
                if arr[mid] < x:
                    low = mid + 1
                elif arr[mid] > x:
                    high = mid - 1
                else:
                    return mid
            return low
        return binarySearch(nums,target)

# @lc code=end


from __future__ import print_function

import time

import rospy
import tf2_ros

from nist_gear.msg import Order
from nist_gear.msg import VacuumGripperState
from nist_gear.srv import AGVControl
from nist_gear.srv import ConveyorBeltControl
from nist_gear.srv import DroneControl
from nist_gear.srv import SubmitShipment
from nist_gear.srv import VacuumGripperControl
from control_msgs.msg import JointTrajectoryControllerState
from std_msgs.msg import String
from std_srvs.srv import Trigger
from trajectory_msgs.msg import JointTrajectory
from trajectory_msgs.msg import JointTrajectoryPoint

from nist_gear.msg import Order, Model, LogicalCameraImage, VacuumGripperState
from geometry_msgs.msg import TransformStamped
from std_srvs.srv import Trigger
from nist_gear.srv import AGVControl, GetMaterialLocations, VacuumGripperControl

from math import pi, sqrt
import moveit_commander as mc

import sys
import copy
import yaml
import re

#TODO: submit agvs to deliver orders/kits
#TODO: listen and react to Faulty Products on agvs
#TODO: parse orders
#TODO: parse sensors data
#TODO: locate parts, plan movements
#TODO: number and places of sensors
#TODO

#TODO: control conveyor? (only for development)

def start_competition():
    rospy.loginfo("start_competition() method.")
    rospy.loginfo("Waiting for competition to be ready...")
    rospy.wait_for_service('/ariac/start_competition')
    rospy.loginfo("Competition is now ready.")
    rospy.loginfo("Requesting competition start...")

    try:
        start = rospy.ServiceProxy('/ariac/start_competition', Trigger)
        response = start()
    except rospy.ServiceException as exc:
        rospy.logerr("Failed to start the competition: %s" % exc)
        return False
    if not response.success:
        rospy.logerr("Failed to start the competition: %s" % response)
    else:
        rospy.loginfo("Competition started!")
    return response.success

def setup_competition(comp_class):

    connect_callbacks(comp_class)

    if not comp_class.arm_1_has_been_zeroed:
        comp_class.send_arm_to_state([0.0, -pi/4, pi/2, -pi/4, pi/2, 0], comp_class.arm_1_joint_names, comp_class.arm_1_joint_trajectory_publisher)
        comp_class.arm_1_has_been_zeroed = True

    if not comp_class.arm_2_has_been_zeroed:
        comp_class.send_arm_to_state([pi, -pi/4, pi/2, -pi/4, pi/2, 0], comp_class.arm_2_joint_names, comp_class.arm_2_joint_trajectory_publisher)
        comp_class.arm_2_has_been_zeroed = True

    # move gantry to zero
    comp_class.send_arm_to_state([0, 0, 0], comp_class.gantry_joint_names, comp_class.gantry_joint_trajectory_publisher)

    # reset Grippers
    comp_class.control_gripper(False, "left")
    comp_class.control_gripper(False, "right")

def end_competition():
    rospy.wait_for_service('/ariac/end_competition')
    rospy.ServiceProxy('/ariac/end_competition', Trigger)()

def run_competition():
    rate = rospy.Rate(1000) # big amount on purpose

    # # fake run competition body start
    # start = time.time()
    #
    # while not rospy.is_shutdown():
    #     rate.sleep()
    #
    #     time_elapsed = time.time() - start
    #
    #     if time_elapsed > 10:
    #         break;
    # # fake run competition body end

    group_names = ['Full_Robot', 'Left_Arm', 'Right_Arm', 'Gantry']
    moveit_runner = MoveitRunner(group_names, ns='/ariac/gantry')

    order = get_order()
    agv_states = {'agv1': [], 'agv2': []}

    all_known_parts = get_parts_from_cameras()

    for shipment in order.shipments:
        active_agv = 'agv1' if shipment.agv_id == 'agv1' else 'agv2'
        agv_state = agv_states[active_agv]

        while True:
            rate.sleep()

            valid_products = []
            for product in shipment.products:
                if product not in agv_state:
                    valid_products.append(product)

            candidate_moves = []
            for part in all_known_parts:
                for product in valid_products:
                    if part.type == product.type:
                        candidate_moves.append((part, product))

            if candidate_moves:
                part, target = candidate_moves[0]

                world_target = get_target_world_pose(target, active_agv)
                part_location = get_part_type_location(part)

                move_successful = moveit_runner.move_part(
                    part,
                    world_target,
                    part_location,
                    active_agv
                )
                if move_successful:
                    all_known_parts.remove(part)
                    agv_state.append(target)
            else:
                break

        submit_shipment(active_agv, shipment.shipment_type)
        agv_states[active_agv] = []

class MyCompetitionClass:
    def __init__(self):
        self.gantry_joint_trajectory_publisher = rospy.Publisher("/ariac/gantry/gantry_controller/command", JointTrajectory, queue_size=10)
        self.arm_1_joint_trajectory_publisher = rospy.Publisher("/ariac/gantry/left_arm_controller/command", JointTrajectory, queue_size=10)
        self.arm_2_joint_trajectory_publisher = rospy.Publisher("/ariac/gantry/right_arm_controller/command", JointTrajectory, queue_size=10)

        self.current_comp_state = None
        self.received_orders = []
        self.gantry_current_joint_state = None
        self.arm_1_current_joint_state = None
        self.arm_2_current_joint_state = None
        self.arm_1_current_gripper_state = None
        self.arm_2_current_gripper_state = None
        self.last_gantry_joint_state_print = time.time()
        self.last_arm_1_joint_state_print = time.time()
        self.last_arm_2_joint_state_print = time.time()
        self.last_arm_1_gripper_state_print = time.time()
        self.last_arm_2_gripper_state_print = time.time()
        self.arm_1_has_been_zeroed = False
        self.arm_2_has_been_zeroed = False
        self.gantry_joint_names = [
            'small_long_joint',
            'torso_rail_joint',
            'torso_base_main_joint',
        ]
        #left
        self.arm_1_joint_names = [
            'left_shoulder_pan_joint',
            'left_shoulder_lift_joint',
            'left_elbow_joint',
            'left_wrist_1_joint',
            'left_wrist_2_joint',
            'left_wrist_3_joint',
        ]
        #right
        self.arm_2_joint_names = [
            'right_shoulder_pan_joint',
            'right_shoulder_lift_joint',
            'right_elbow_joint',
            'right_wrist_1_joint',
            'right_wrist_2_joint',
            'right_wrist_3_joint',
        ]

    def comp_state_callback(self, msg):
        if self.current_comp_state != msg.data:
            rospy.loginfo("Competition state changed: " + str(msg.data))
        self.current_comp_state = msg.data

    def order_callback(self, msg):
        rospy.loginfo("order_callback")
        rospy.loginfo("Received order:\n" + str(msg))
        self.received_orders.append(msg)

    def gantry_joint_state_callback(self, msg):
        if time.time() - self.last_gantry_joint_state_print >= 10:
            rospy.loginfo("Current gantry Joint States (throttled to 0.1 Hz):\n" + str(msg))
            self.last_gantry_joint_state_print = time.time()
        self.gantry_current_joint_state = msg

    def arm_1_joint_state_callback(self, msg):
        if time.time() - self.last_arm_1_joint_state_print >= 10:
            rospy.loginfo("Current Arm 1 Joint States (throttled to 0.1 Hz):\n" + str(msg))
            self.last_arm_1_joint_state_print = time.time()
        self.arm_1_current_joint_state = msg

    def arm_2_joint_state_callback(self, msg):
        if time.time() - self.last_arm_2_joint_state_print >= 10:
            rospy.loginfo("Current Arm 2 Joint States (throttled to 0.1 Hz):\n" + str(msg))
            self.last_arm_2_joint_state_print = time.time()
        self.arm_2_current_joint_state = msg

    def arm_1_gripper_state_callback(self, msg):
        if time.time() - self.last_arm_1_gripper_state_print >= 10:
            rospy.loginfo("Current Arm 1 gripper state (throttled to 0.1 Hz):\n" + str(msg))
            self.last_arm_1_gripper_state_print = time.time()
        self.arm_1_current_gripper_state = msg

    def arm_2_gripper_state_callback(self, msg):
        if time.time() - self.last_arm_2_gripper_state_print >= 10:
            rospy.loginfo("Current Arm 2 gripper state (throttled to 0.1 Hz):\n" + str(msg))
            self.last_arm_2_gripper_state_print = time.time()
        self.arm_2_current_gripper_state = msg

    def send_arm_to_state(self, positions, joints_names, publisher):
        rospy.loginfo("send_arm_to_state method():\npositions" + str(positions))

        msg = JointTrajectory()
        msg.joint_names = joints_names
        point = JointTrajectoryPoint()
        point.positions = positions
        point.time_from_start = rospy.Duration(1.0)
        msg.points = [point]
        #TODO: rospy.loginfo("Sending command:\n" + str(msg))
        publisher.publish(msg)

    def send_arm1_to_state(self, positions):
        return self.send_arm_to_state(positions, self.arm_1_joint_names, self.arm_1_joint_trajectory_publisher)

    def send_arm2_to_state(self, positions):
        return self.send_arm_to_state(positions, self.arm_2_joint_names, self.arm_2_joint_trajectory_publisher)

    def send_gantry_to_state(self, positions):
        return self.send_arm_to_state(positions, self.gantry_joint_names, self.gantry_joint_trajectory_publisher)

    def control_gripper(self, enabled, arm):
        if arm not in ("left", "right"):
            raise ValueError('Only two arms ("left", "right")')

        rospy.loginfo("Waiting for gripper control to be ready...")

        service_name = '/ariac/gantry/{}_arm/gripper/control'.format(arm)
        rospy.wait_for_service(service_name)
        rospy.loginfo("Requesting gripper control...")

        try:
            gripper_control = rospy.ServiceProxy(service_name, VacuumGripperControl)
            response = gripper_control(enabled)
        except rospy.ServiceException as exc:
            rospy.logerr("Failed to control the gripper: %s" % exc)
            return False
        if not response.success:
            rospy.logerr("Failed to control the gripper: %s" % response)
        else:
            rospy.loginfo("Gripper controlled successfully")
        return response.success

class MoveitRunner():
    def __init__(self, group_names, node_name='ariac_moveit_example', ns='', robot_description='robot_description'):

        mc.roscpp_initialize(sys.argv)
        #rospy.init_node(node_name, anonymous=True)

        self.robot = mc.RobotCommander(ns+'/'+robot_description, ns)
        self.scene = mc.PlanningSceneInterface(ns)
        self.groups = {}
        for group_name in group_names:
            group = mc.MoveGroupCommander(
                group_name,
                robot_description=ns+'/'+robot_description,
                ns=ns
            )
            group.set_goal_tolerance(0.05)
            self.groups[group_name] = group

        self.define_preset_locations()
        self.goto_preset_location('start')

    def define_preset_locations(self):
        locations = {}

        name = 'start'
        gantry = [0, 0, 0]
        left = [0.0, -pi/4, pi/2, -pi/4, pi/2, 0]
        right = [pi, -pi/4, pi/2, -pi/4, pi/2, 0]
        locations[name] = (gantry, left, right)

        name = 'bin3'
        gantry = [4.0, -1.1, 0.]
        left = [0.0, 0.0, pi/4, 0, pi/2, 0]
        right = None
        locations[name] = (gantry, left, right)

        name = 'bin4'
        gantry = [5.0, -1.2, 0.]
        left = [0.0, 0.0, pi/4, 0, pi/2, 0]
        right = None
        locations[name] = (gantry, left, right)

        name = 'shelf1'
        gantry = [2.5, -2.3, 0.]
        left = [-pi/2, -pi, -pi/2, -pi/2, 0, 0]
        right = None
        locations[name] = (gantry, left, right)

        name = 'standby'
        gantry = None
        left = [0.0, -pi/4, pi/2, -pi/4, pi/2, 0]
        right = [pi, -pi/4, pi/2, -pi/4, pi/2, 0]
        locations[name] = (gantry, left, right)

        name = 'agv1'
        gantry = [-0.6, -6.9, 0]
        left = [0.0, 0.0, pi/4, 0, pi/2, 0]
        right = None
        locations[name] = (gantry, left, right)

        name = 'agv2'
        gantry = [0.6, 6.9, pi]
        left = [0.0, 0.0, pi/4, 0, pi/2, 0]
        right = None
        locations[name] = (gantry, left, right)

        self.locations = locations

    def goto_preset_location(self, location_name):
        group = self.groups['Full_Robot']
        gantry, left, right = self.locations[location_name]
        location_pose = group.get_current_joint_values()

        if gantry:
            location_pose[:3] = gantry
        if left:
            location_pose[3:-6] = left
        if right:
            location_pose[-6:] = right

        # If the robot controller reports a path tolerance violation,
        # this will automatically re-attempt the motion
        MAX_ATTEMPTS = 5
        attempts = 0
        while not group.go(location_pose, wait=True):
            attempts += 1
            assert(attempts < MAX_ATTEMPTS)

    def move_part(self, part, target, part_location, agv):
        # This example only uses the left arm
        group = self.groups['Left_Arm']
        gm = GripperManager(ns='/ariac/gantry/left_arm/gripper/')

        near_pick_pose = copy.deepcopy(part.pose)
        pick_pose = copy.deepcopy(part.pose)
        place_pose = copy.deepcopy(target.pose)

        near_pick_pose.position.z += 0.1
        pick_pose.position.z += 0.015
        place_pose.position.z += 0.1

        self.goto_preset_location(part_location)
        gm.activate_gripper()

        path = [near_pick_pose, pick_pose]
        self.cartesian_move(group, path)

        num_attempts = 0
        MAX_ATTEMPTS = 20
        while not gm.is_object_attached() and num_attempts < MAX_ATTEMPTS:
            num_attempts += 1
            rospy.sleep(0.1)

        if not gm.is_object_attached():
            self.goto_preset_location(part_location)
            self.goto_preset_location('standby')
            self.goto_preset_location('start')
            return False

        if 'shelf' in part_location:
            self.goto_preset_location(part_location)
        self.goto_preset_location('standby')
        self.goto_preset_location('start')
        self.goto_preset_location(agv)

        path = [place_pose]
        self.cartesian_move(group, path)

        gm.deactivate_gripper()

        self.goto_preset_location('standby')
        self.goto_preset_location('start')
        return True

    def cartesian_move(self, group, waypoints):
        (plan, fraction) = group.compute_cartesian_path(waypoints, 0.01, 0.0)
        group.execute(plan, wait=True)

class GripperManager():
    def __init__(self, ns):
        self.ns = ns

    def activate_gripper(self):
        rospy.wait_for_service(self.ns + 'control')
        rospy.ServiceProxy(self.ns + 'control', VacuumGripperControl)(True)

    def deactivate_gripper(self):
        rospy.wait_for_service(self.ns + 'control')
        rospy.ServiceProxy(self.ns + 'control', VacuumGripperControl)(False)

    def is_object_attached(self):
        status = rospy.wait_for_message(self.ns + 'state', VacuumGripperState)
        return status.attached

def submit_shipment(agv, name):
    rospy.wait_for_service('/ariac/' + agv)
    rospy.ServiceProxy('/ariac/' + agv, AGVControl)(name)

def get_order():
    order = rospy.wait_for_message('/ariac/orders', Order)
    return order

def get_part_type_location(part):
    if part.type == 'piston_rod_part_blue':
        reachable_location = 'bin4'
    elif part.type == 'gear_part_green':
        reachable_location = 'bin3'

    assert(reachable_location), "This implementation only reaches shelves/bins"
    return reachable_location

def get_parts_from_cameras():
    tf_buffer = tf2_ros.Buffer()
    tf_listener = tf2_ros.TransformListener(tf_buffer)

    # wait for all cameras to be broadcasting
    all_topics = rospy.get_published_topics()
    camera_topics = [t for t, _ in all_topics if '/ariac/logical_camera' in t]
    for topic in camera_topics:
        rospy.wait_for_message(topic, LogicalCameraImage)

    camera_frame_format = r"logical_camera_[0-9]+_(\w+)_[0-9]+_frame"
    all_frames = yaml.safe_load(tf_buffer.all_frames_as_yaml()).keys()
    part_frames = [f for f in all_frames if re.match(camera_frame_format, f)]

    objects = []
    for frame in part_frames:
        try:
            world_tf = tf_buffer.lookup_transform(
                'world',
                frame,
                rospy.Time(),
                rospy.Duration(0.1)
            )
            ee_tf = tf_buffer.lookup_transform(
                frame,
                'left_ee_link',
                rospy.Time(),
                rospy.Duration(0.1)
            )
        except (tf2_ros.LookupException, tf2_ros.ExtrapolationException) as e:
            continue

        # remove stale transforms
        tf_time = rospy.Time(
            world_tf.header.stamp.secs,
            world_tf.header.stamp.nsecs
        )
        if rospy.Time.now() - tf_time > rospy.Duration(1.0):
            continue

        model = Model()
        model.type = re.match(camera_frame_format, frame).group(1)
        model.pose.position = world_tf.transform.translation
        model.pose.orientation = ee_tf.transform.rotation
        objects.append(model)
    return objects

def get_target_world_pose(target, agv):
    tf_buffer = tf2_ros.Buffer()
    tf_listener = tf2_ros.TransformListener(tf_buffer)
    tf_broadcaster = tf2_ros.StaticTransformBroadcaster()

    tf_msg = TransformStamped()
    tf_msg.header.frame_id = 'kit_tray_1' if agv == 'agv1' else 'kit_tray_2'
    tf_msg.header.stamp = rospy.Time()
    tf_msg.child_frame_id = 'target_frame'
    tf_msg.transform.translation = target.pose.position
    tf_msg.transform.rotation = target.pose.orientation

    for _ in range(5):
        tf_broadcaster.sendTransform(tf_msg)

    # tf lookup fails occasionally, this automatically retries the lookup
    MAX_ATTEMPTS = 10
    attempts = 0
    while attempts < MAX_ATTEMPTS:
        try:
            world_target_tf = tf_buffer.lookup_transform(
                'world',
                'target_frame',
                rospy.Time(),
                rospy.Duration(0.1)
            )
            ee_target_tf = tf_buffer.lookup_transform(
                'target_frame',
                'left_ee_link',
                rospy.Time(),
                rospy.Duration(0.1)
            )
            break
        except:
            continue

    world_target = copy.deepcopy(target)
    world_target.pose.position = world_target_tf.transform.translation
    world_target.pose.orientation = ee_target_tf.transform.rotation
    return world_target

def connect_callbacks(comp_class):
    rospy.loginfo("connect_callbacks")

    comp_state_sub = rospy.Subscriber("ariac/competition_state", String, comp_class.comp_state_callback)
    order_sub = rospy.Subscriber("/ariac/orders", Order, comp_class.order_callback)
    gantry_state_sub = rospy.Subscriber("/ariac/gantry/gantry_controller/state", JointTrajectoryControllerState, comp_class.gantry_joint_state_callback)
    arm1_joint_state_sub = rospy.Subscriber("/ariac/gantry/left_arm_controller/state", JointTrajectoryControllerState, comp_class.arm_1_joint_state_callback)
    arm2_joint_state_sub = rospy.Subscriber("/ariac/gantry/right_arm_controller/state", JointTrajectoryControllerState, comp_class.arm_2_joint_state_callback)
    gripper1_state_sub = rospy.Subscriber("/ariac/gantry/left_arm/gripper/state", VacuumGripperState, comp_class.arm_1_gripper_state_callback)
    gripper2_state_sub = rospy.Subscriber("/ariac/gantry/right_arm/gripper/state", VacuumGripperState, comp_class.arm_2_gripper_state_callback)

def control_agv(shipment_type, agv_num):
    if agv_num not in (1,2):
        raise ValueError('agv_num must be 1 or 2')

    rospy.loginfo("Waiting for agv{} control to be ready...".format(agv_num))
    name = '/ariac/agv{}'.format(agv_num)
    rospy.wait_for_service(name)
    rospy.loginfo("agv{} control is now ready.".format(agv_num))
    rospy.loginfo("Requesting agv control...")

    try:
        agv_control = rospy.ServiceProxy(name, AGVControl)
        response = agv_control(shipment_type)
    except rospy.ServiceException as exc:
        rospy.logerr("Failed to control the agv: %s" % exc)
        return False
    if not response.success:
        rospy.logerr("Failed to control the agv: %s" % response)
    else:
        rospy.loginfo("agv controlled successfully")
    return response.success

def submit_shipment(shipment_type, agv_num):
    if agv_num not in (1,2):
        raise ValueError('agv_num must be 1 or 2')

    rospy.loginfo("Waiting for submit shipment to be ready...".format(agv_num))
    name = '/ariac/submit_shipment'
    rospy.wait_for_service(name)
    rospy.loginfo("submit_shipment is now ready.")
    rospy.loginfo("Requesting shipment")

    try:
        submit_shipment = rospy.ServiceProxy(name, SubmitShipment)
        response = submit_shipment(destination_id=str(agv_num), shipment_type=shipment_type)
    except rospy.ServiceException as exc:
        rospy.logerr("Failed to submit shipment: %s" % exc)
        return False
    if not response.success:
        rospy.logerr("Failed to submit shipment: %s" % response)
    else:
        rospy.loginfo("shipment submitted successfully")
    return response.success


# -*- coding: utf-8 -*-

import logging
import sys
from cron_parser import CronParser

class NextRun(object):

    def __init__(self):
        self.logger = logging.Logger(u'cron-admin')
        self.logger.setLevel(logging.WARNING)

        # create console handler
        console_log = logging.StreamHandler(sys.stdout)
        console_log.setLevel(logging.WARNING)

        # create formatter and add it to the handlers
        formatter = logging.Formatter(
            u'[%(asctime)s %(name)s %(filename)s:%'
            u'(lineno)d - %(levelname)s]: %(message)s',
            u'%d-%m-%Y %H:%M:%S'
        )
        console_log.setFormatter(formatter)

        # add the handlers to logger
        self.logger.addHandler(console_log)

    def find_next_run_times(
            self, current_time, cron_file_path=None, cron_string=None):
        """
        Given cron path / data and current time find next times each cron runs
        :param cron_string:
        :param cron_file_path:
        :param current_time:
        :return:
        """
        next_run_times = []

        # Check that a valid date and time have been passed
        valid_current = self.validate_datetime(current_time)

        # If we have been passed a valid current time
        if valid_current[u'minute'] and valid_current[u'hour']:

            if cron_file_path and not cron_string:
                # Parse data from a given file
                cron_data = (
                    CronParser(self.logger).parse_cron_file(cron_file_path)
                )
            else:
                # Parse data from a given string
                cron_data = (
                    CronParser(self.logger).parse_cron_string(cron_string)
                )

            for cron in cron_data:
                # Find how many hours until the next run time
                hour_delta = self.find_time_delta(
                    cron[u'hour'], valid_current[u'hour']
                )

                # Find how many minutes past the hour until the next run time
                minute_delta = self.find_time_delta(
                    cron[u'minute'], valid_current[u'minute']
                )

                # Calculate the next run time from the deltas
                next_run = self.find_next_run_time(
                    cron[u'hour'], cron[u'minute'],
                    valid_current[u'hour'], valid_current[u'minute'],
                    hour_delta, minute_delta
                )

                # Create a results list entry for each cron
                next_run_times.append([
                    self.format_date(next_run[u'hour'], next_run[u'minute']),
                    next_run[u'day'],
                    cron[u'path']
                ])

        return next_run_times

    def validate_datetime(self, current_date):
        """
        Check the given hour and minute figures are valid
        :param current_date:
        :return:
        """
        valid_minute = None
        valid_hour = None
        MIN_HOUR = 0
        MAX_HOUR = 23
        MIN_MINUTE = 0
        MAX_MINUTE = 59
        TIME_SEPARATOR = u':'

        hour, minute = current_date.split(TIME_SEPARATOR)

        try:
            if ((MIN_HOUR <= int(hour) <= MAX_HOUR) and
                    (MIN_MINUTE <= int(minute) <= MAX_MINUTE)):
                valid_minute = int(minute)
                valid_hour = int(hour)
        except ValueError as e:
            logging.error(u'Given current time is invalid %s', e)

        valid_datetime = {u'hour': valid_hour, u'minute': valid_minute}

        return valid_datetime

    def find_next_run_time(self, cron_hour, cron_minute, current_hour,
                           current_minute, hour_delta, minute_delta):
        """
        Find the next time / day to run the cron given the current time
        :param current_hour:
        :param current_minute:
        :param hour_delta:
        :param minute_delta:
        :param cron_minute:
        :param cron_hour:
        :return: the next time and next day
        """
        NOW = 0
        LAST_HOUR_OF_DAY = 23
        EVERY_MINUTE = u'*'
        EVERY_HOUR = u'*'
        CURRENT_DAY = u'today'
        NEXT_DAY = u'tomorrow'

        if cron_minute == EVERY_MINUTE and cron_hour == EVERY_HOUR:
            # Should run every minute of every hour in a day
            next_run_minute = current_minute
            next_run_hour = current_hour
            next_run_day = CURRENT_DAY

        elif cron_hour == EVERY_HOUR:
            # Minute is set but should run every hour of a day
            # Cron run time has passed
            if minute_delta < NOW:
                # Check for time going into next day (after 23:00)
                if current_hour != LAST_HOUR_OF_DAY:
                    next_run_hour = current_hour + 1
                    next_run_day = CURRENT_DAY
                else:
                    next_run_hour = NOW
                    next_run_day = NEXT_DAY
            else:
                next_run_hour = current_hour
                next_run_day = CURRENT_DAY

            next_run_minute = cron_minute

        elif cron_minute == EVERY_MINUTE:
            # Hour is set but should run every minute of that hour
            # Cron run time has passed
            if hour_delta < NOW:
                next_run_minute = NOW
                next_run_day = NEXT_DAY
            elif hour_delta == NOW:
                next_run_minute = current_minute
                next_run_day = CURRENT_DAY
            else:
                next_run_minute = NOW
                next_run_day = CURRENT_DAY

            next_run_hour = cron_hour

        else:
            # Both Hour and minute are specified and should only run then
            # Cron run time has passed
            if hour_delta < NOW:
                next_run_day = NEXT_DAY
            elif hour_delta == NOW:
                if minute_delta < NOW:
                    next_run_day = NEXT_DAY
                else:
                    next_run_day = CURRENT_DAY
            else:
                next_run_day = CURRENT_DAY

            next_run_minute = cron_minute
            next_run_hour = cron_hour

        # Convenient structure
        next_run_time = {
            u'day': next_run_day,
            u'hour': next_run_hour,
            u'minute': next_run_minute
        }

        return next_run_time

    def find_time_delta(self, cron, current):
        """
        Find difference (time to/from next/previous cron)
        :param cron:
        :param current:
        :return:
        """
        delta = 0
        EVERY_TIME = u'*'

        if not cron == EVERY_TIME and not current == EVERY_TIME:
            delta = cron - current

        return delta

    def format_date(self, hour, minute):
        """
        Create a formatted date string
        :param hour:
        :param minute:
        :return:
        """
        SINGLE_DIGIT = 9
        PADDING_DIGIT = u'0'
        TIME_SEPARATOR = u':'

        hour = unicode(hour)
        minute = (unicode(minute)
                  if minute > SINGLE_DIGIT
                  else PADDING_DIGIT + unicode(minute))

        date = TIME_SEPARATOR.join([hour, minute])

        return date


def run():
	t = int(input().strip())
	for _ in range(t):
		height,width = map(int,input().strip().split())
		print(ways_to_build_wall(width, height))

def ways_to_build_wall(width, height):
	modulus = 10**9 + 7
	row_memo = calculate_rows(width, modulus)
	wall_memo = calculate_walls(width, height, row_memo, modulus)
	solid_wall_memo = calculate_solid_walls(width, wall_memo, modulus)
	return solid_wall_memo[width]

def calculate_rows(width, modulus):
	row_memo = [0 for i in range(width+1)]
	row_memo[0] = 1
	for i in range(1, width + 1):
		for j in range(1,5):
			if i-j >= 0:
				row_memo[i] += row_memo[i-j]
		row_memo[i] %= modulus
	return row_memo

def calculate_walls(width, height, row_memo, modulus):
	wall_memo = [0 for i in range(width+1)]
	wall_memo[0] = 1
	for i in range(1, width+1):
		wall_memo[i] = (row_memo[i] ** height)%modulus
	return wall_memo

# height doesn't matter at this point :)
def calculate_solid_walls(width, wall_memo, modulus):
	solid_wall_memo = [0 for i in range(width+1)]
	solid_wall_memo[1] = 1
	for i in range(2, width+1):
		invalid_walls = 0
		for j in range(1,i):
			invalid_walls += solid_wall_memo[j] * wall_memo[i-j]
			invalid_walls %= modulus
		solid_wall_memo[i] = (wall_memo[i] - invalid_walls) % modulus
	return solid_wall_memo

run()


#
# @lc app=leetcode.cn id=199 lang=python
#
# [199] 二叉树的右视图
#
# https://leetcode-cn.com/problems/binary-tree-right-side-view/description/
#
# algorithms
# Medium (64.10%)
# Likes:    233
# Dislikes: 0
# Total Accepted:    46.4K
# Total Submissions: 72.9K
# Testcase Example:  '[1,2,3,null,5,null,4]'
#
# 给定一棵二叉树，想象自己站在它的右侧，按照从顶部到底部的顺序，返回从右侧所能看到的节点值。
#
# 示例:
#
# 输入: [1,2,3,null,5,null,4]
# 输出: [1, 3, 4]
# 解释:
#
#   1            <---
# /   \
# 2     3         <---
# \     \
#  5     4       <---
#
#
#

# @lc code=start
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def rightSideView(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        # 中-右-左 遍历,只储存每层第一个值
        if not root:
            return []
        res = {}
        stack = [(root,0)]
        while stack:
            node,depth = stack.pop()
            if not res.get(depth):
                res[depth] = node.val
            if node.left:
                stack.append((node.left, depth + 1))
            if node.right:
                stack.append((node.right, depth + 1))
        return list(res.values())

        # 层次遍历的变种
        stack,res  = [root],[]
        while stack:
            tmp = None
            tmp_stack = []
            for node in stack:
                if node:
                    tmp = node.val
                    tmp_stack.append(node.left)
                    tmp_stack.append(node.right)
            stack = tmp_stack
            if tmp:
                res.append(tmp)
        return res

# @lc code=end

199.二叉树的右视图.py

199.二叉树的右视图.py


import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches

def beam_solver(point_loads, point_moments, linear_loads, L, Xa, Xb, J):
    # function that numericaly solves initial beam

    E = 2.1 * 10 ** 11  # Youngův modul PRO ŽELEZO
    # J = (0.2 * 0.5 ** 3) / 12  -zadává se v okně
    EJ = E * J

    N = 10000                                       # počet dělení po délce nosníku
    dx = L / N                                      # délka kroku
    X = np.arange(dx, L + dx, dx)                   # vektor pozic po délce nosníku
    fi = np.zeros(len(X))                           # vektor natočení
    v = np.zeros(len(X))                            # vektor průhybů

    reaction_forces = np.array([0.0, 0, 0])

    Shear = np.zeros(len(X))
    Moment = np.zeros(len(X))

    support_index_A = int(Xa / dx)
    support_index_B = int(Xb / dx) - 1
    dFi = 0.00001                                   #krok natočení pro numerické řešení průhybů

    def reactions_PL(n):
        xp = point_loads[n, 0]                       # pozice síly
        fx = point_loads[n, 1]                       # horizontální složka
        fy = point_loads[n, 2]                       # vertikální složka

        la_p = Xa - xp                              # rameno vůči A
        mp = fy * la_p                              # moment vůči A
        la_Rb = Xb - Xa                             # rameno B vůči A

        Rb = mp / la_Rb                             # reakce B
        Ra = -fy - Rb                               # reakce A
        Ha = -fx                                    # reakce v horizontálním směru

        return Ra, Rb, Ha

    def shear_moment_PL(n, Shear, Moment):
        xp = point_loads[n, 0]                       # pozice síly
        fy = point_loads[n, 2]                       # síla do osy y
        Ra = PL_record[n, 0]                        # reakce v A od jednotlivých sil
        Rb = PL_record[n, 2]                        # reakce v B -||-

        # projede nosník a spočte posouvací sílu a ohybový moment od síly v každém bodě

        for i, x in enumerate(X):
            shear = 0
            moment = 0
            if x > Xa:
                shear += Ra
                moment -= Ra * (x - Xa)

            if x > Xb:
                shear += Rb
                moment -= Rb * (x - Xb)

            if x > xp:
                shear += fy
                moment -= fy * (x - xp)

            Shear[i] += shear
            Moment[i] += moment

        return Shear, Moment

    def reactions_PM(n):
        m = point_moments[n, 1]
        la_vb = Xb - Xa

        Rb = m / la_vb
        Ra = -Rb

        return Ra, Rb

    def shear_moment_PM(n, Shear, Moment):
        xm = point_moments[n, 0]
        m = point_moments[n, 1]
        la_vb = Xb - Xa

        Rb = m / la_vb
        Ra = -Rb

        # projede nosník a spočte posouvací sílu a ohybový moment od momentu v každém bodě

        for i, x in enumerate(X):
            shear = 0
            moment = 0
            if x > Xa:
                shear += Ra
                moment -= Ra * (x - Xa)

            if x > Xb:
                shear += Rb
                moment -= Rb * (x - Xb)

            if x > xm:
                moment -= m

            Shear[i] += shear
            Moment[i] += moment

        return Shear, Moment

    def reactions_DL(n):
        xStart = linear_loads[n, 0]
        xEnd = linear_loads[n, 1]
        fy = linear_loads[n, 2]

        fy_Res = fy * (xEnd - xStart)
        x_res = xStart + 0.5 * (xEnd - xStart)

        la_p = Xa - x_res  # rameno vůči A
        mp = fy_Res * la_p  # moment vůči A
        la_Rb = Xb - Xa  # rameno B vůči A

        Rb = mp / la_Rb  # reakce B
        Ra = -fy_Res - Rb  # reakce A

        return Ra, Rb

    def shear_moment_DL(n, Shear, Moment):
        xStart = linear_loads[n, 0]
        xEnd = linear_loads[n, 1]
        fy = linear_loads[n, 2]
        Ra = DL_record[n, 0]
        Rb = DL_record[n, 1]

        for i, x in enumerate(X):
            shear = 0
            moment = 0
            if x > Xa:
                shear += Ra
                moment -= Ra * (x - Xa)

            if x > Xb:
                shear += Rb
                moment -= Rb * (x - Xb)

            if x > xStart and x <= xEnd:
                shear += fy * (x - xStart)
                moment -= fy * (x - xStart) * 0.5 * (x - xStart)
            elif (x > xEnd):
                shear += fy * (xEnd - xStart)
                moment -= fy * (xEnd - xStart) * (x - xStart - 0.5 * (xEnd - xStart))

            Shear[i] += shear
            Moment[i] += moment

        return Shear, Moment

    def plot_out():
        fig, ax = plt.subplots(4, sharex=True, figsize=(12, 8))

        if len(point_loads) != 0:
            F_max = max(abs(point_loads[:, 2]))
        else:
            F_max = 0

        if len(point_moments) != 0:
            M_max = max(abs(point_moments[:, 1]))
        else:
            M_max = 0

        if len(linear_loads) != 0:
            q_max = max(abs(linear_loads[:, 2]))
        else:
            q_max = 0

        y_max = max(F_max, M_max, q_max) * 1.2
        y_min = -max(F_max, M_max, q_max) * 1.2
        y_abs = max(abs(y_max), abs(y_min))

        # VYKRESLIT SÍLY
        for n, f in enumerate(point_loads):
            if point_loads[n, 2] < 0:
                ax[0].arrow(point_loads[n, 0], -point_loads[n, 2], 0, -0.2*point_loads[n, 2] + point_loads[n, 2], head_width=L*0.05,
                            head_length=-0.2*point_loads[n, 2])
            else:
                ax[0].arrow(point_loads[n, 0], -point_loads[n, 2], 0, -0.2*y_abs + point_loads[n, 2], head_width=L*0.05,
                            head_length=0.2*y_abs)
        # VYKRESLIT MOMENTY
        for n, f in enumerate(point_moments):
            ax[0].plot([point_moments[n, 0], point_moments[n, 0]], [point_moments[n, 1], -point_moments[n, 1]], color='red')
            ax[0].plot([point_moments[n, 0], point_moments[n, 0] + abs(point_moments[n, 1]) * 0.005], [point_moments[n, 1], point_moments[n, 1]],
                       color='red')
            ax[0].plot([point_moments[n, 0], point_moments[n, 0] - abs(point_moments[n, 1]) * 0.005], [-point_moments[n, 1], -point_moments[n, 1]],
                       color='red')
        # VYKRESLIT SPOJITÉ ZATÍŽENÍ
        for n, f in enumerate(linear_loads):
            rect = mpatches.Rectangle((linear_loads[n, 0], 0), linear_loads[n, 1] - linear_loads[n, 0], -linear_loads[n, 2],
                                      # fill=False,
                                      alpha=0.1,
                                      facecolor="blue")
            ax[0].add_patch(rect)

        ax[0].set_ylim(y_min, y_max)
        ax[0].set_xlim([-L*0.1, L*1.1])
        ax[0].arrow(Xa, -0.4*y_abs, 0, 0.2*y_abs, head_width=0.05*L, head_length=0.2*y_abs, color='red')
        ax[0].arrow(Xb, -0.4*y_abs, 0, 0.2*y_abs, head_width=0.05*L, head_length=0.2*y_abs, color='red')
        ax[0].plot([L, 0], [0, 0], color='black', linewidth='2')

        ax[1].set_title('Posouvací síla [kN]')
        ax[1].plot(X, Shear, color='blue')

        ax[2].set_title('Ohybový moment [kNm]')
        ax[2].plot(X, Moment, color='red')

        ax[3].plot(X, -v)
        ax[3].set_title('Průhyb [mm]')

        plt.show()

    def solve_displacements(Moment, EJ, fi_guess):

        # INICIALIZACE ODHADU ŘEŠENÍ
        fi[support_index_A] = fi_guess

        # PROJEDE NOSNÍK OD PODPORY A A SPOČTE NATOČENÍ A PRŮHYB
        for i, m in enumerate(Moment[support_index_A::]):
            index = i + support_index_A
            if index < len(Moment) - 1:
                fi[index + 1] = fi[index] + dx / (2 * EJ) * (Moment[index + 1] + Moment[index]) * 1000
                v[index + 1] = v[index] + dx / 2 * (fi[index + 1] + fi[index])

        err = 0 - v[support_index_B]

        #POKUD PŘED PODPOROU A JE ČÁST NOSNÍKU, PROJEDE TUTO ČÁST A SPOČTE PRŮHYBY
        if Xa != 0 and abs(err) < 0.001:
            fi[support_index_A-1] = fi[support_index_A]
            for i in range(support_index_A - 1):
                index = support_index_A - i - 1
                fi[index - 1] = fi[index] - dx / (2 * EJ) * (Moment[index] + Moment[index - 1]) * 1000
                v[index - 1] = v[index] - dx / 2 * (fi[index] + fi[index - 1])

        return fi, v, err

    # PROJEDE VŠECHNA ZATÍŽENÍ A SPOČTE REAKCE V PODPORÁCH OD SÍLY
    PL_record = np.empty([0, 3])
    if (len(point_loads) > 0):
        for n, p in enumerate(point_loads):
            Ra, Rb, Ha = reactions_PL(n)
            PL_record = np.append(PL_record, [np.array([Ra, Ha, Rb])], axis=0)

            reaction_forces[0] += Ra
            reaction_forces[1] += Ha
            reaction_forces[2] += Rb

    # PROJEDE OHYBOVÉ MOMENTY A SPOČTE REAKCE V PODPORÁCH OD MOMENTU
    PM_record = np.empty([0, 2])
    if (len(point_moments) > 0):
        for n, p in enumerate(point_moments):
            Ra, Rb = reactions_PM(n)
            PM_record = np.append(PM_record, [np.array([Ra, Rb])], axis=0)

            reaction_forces[0] += Ra
            reaction_forces[2] += Rb

    # PROJEDE OHYBOVÉ MOMENTY A SPOČTE REAKCE V PODPORÁCH OD SPOJITÉHO ZATÍŽENÍ
    DL_record = np.empty([0, 2])
    if (len(linear_loads) > 0):
        for n, p in enumerate(linear_loads):
            Ra, Rb = reactions_DL(n)
            DL_record = np.append(DL_record, [np.array([Ra, Rb])], axis=0)

            reaction_forces[0] += Ra
            reaction_forces[2] += Rb

    # SPOČTE POSOUVACÍ SÍLU A MOMENT PO DÉLCE NOSNÍKU OD SÍLY
    if (len(point_loads) > 0):
        for n, p in enumerate(point_loads):
            Shear, Moment = shear_moment_PL(n, Shear, Moment)

    # SPOČTE POSOUVACÍ SÍLU A MOMENT PO DÉLCE NOSNÍKU OD MOMENTU
    if (len(point_moments) > 0):
        for n, p in enumerate(point_moments):
            Shear, Moment = shear_moment_PM(n, Shear, Moment)

    # SPOČTE POSOUVACÍ SÍLU A MOMENT PO DÉLCE NOSNÍKU OD SPOJITÉHO ZATÍŽENÍ
    if (len(linear_loads) > 0):
        for n, p in enumerate(linear_loads):
            Shear, Moment = shear_moment_DL(n, Shear, Moment)

    fi_guess = 0.001    #odhad počátečního natočení

    # SPOČTE NATOČENÍ NUMERICKY
    print("Solving...")
    while True:
        fi, v, err = solve_displacements(Moment, EJ, fi_guess)
        if err < 0:
            fi_guess -= dFi
        elif err > 0:
            fi_guess += dFi

        if abs(err) < 0.0001:
            break

    print(
        f"Ra = {round(reaction_forces[0], 2)} kN \t Rb = {round(reaction_forces[2], 2)} kN")
    print(f"Mo_max = {round(max(Moment), 3)} kNm, Mo_min = {round(min(Moment), 3)} kNm")

    plot_out()


from collections import deque
class Stack:
    def __init__(self,maxsize):
        self.container = deque()
        self.maxsize = maxsize
    def is_empty(self):
        return len(self.container) == 0
    def is_full(self):
        return len(self.container) == self.maxsize
    def push(self,item):
        if self.is_full():
            raise Exception("Stack is full")
        else:
            self.container.append(item)
    def pop(self):
        if self.is_empty():
            raise Exception("Stack is empty")
        else:
            return self.container.pop()
    def peek(self):
        if self.is_empty():
            raise Exception("Stack is empty")
        else:
            return self.container[-1]

def previous_smaller_index(array):
    stack = Stack(len(array))
    prev_small_index = []
    i = 0
    while i < len(array):
        curr = array[i]
        while not stack.is_empty() and array[stack.peek()] >= curr:
            stack.pop()
        if stack.is_empty():
            prev_small_index.append(-1)
        else:
            prev_small_index.append(stack.peek())
        stack.push(i)
        i += 1
    print("previous index : ",prev_small_index)
    return prev_small_index

def next_smaller_index(array):
    stack = Stack(len(array))
    next_smaller_index = []
    i = len(array)-1
    while i >= 0:
        curr = array[i]
        while not stack.is_empty() and array[stack.peek()] >= curr:
            stack.pop()
        if stack.is_empty():
            next_smaller_index.append(len(array))
        else:
            next_smaller_index.append(stack.peek())
        stack.push(i)
        i-=1
    next_smaller_index.reverse()
    print("next index : ",next_smaller_index)
    return next_smaller_index

def max_area_histogram(array):
    ns = next_smaller_index(array)
    ps = previous_smaller_index(array)

    i = 0
    max_area = 0
    while i < len(array):
        area = (ns[i]-ps[i]-1)*array[i]
        max_area = max(max_area,area)
        i += 1
    return max_area

if __name__ == '__main__':
    hist = [6, 2, 5, 4, 5, 1, 6]
    print("Maximum area is",
    max_area_histogram(hist))


import argparse
import datetime
import json
import random
import time
from pathlib import Path

import numpy as np
import torch
from torch.utils.data import DataLoader, DistributedSampler

import datasets
import util.misc as utils
from datasets import build_dataset, get_coco_api_from_dataset
from engine import evaluate, train_one_epoch
from models import build_model

from torch.nn.parameter import Parameter

import tqdm

from getpass import getuser
from socket import gethostname

# this is a fake commit
def get_args_parser():
    parser = argparse.ArgumentParser('Set transformer detector', add_help=False)
    parser.add_argument('--lr', default=1e-4, type=float)
    parser.add_argument('--lr_backbone', default=1e-5, type=float)
    parser.add_argument('--batch_size', default=2, type=int)
    parser.add_argument('--weight_decay', default=1e-4, type=float)
    parser.add_argument('--epochs', default=300, type=int)
    parser.add_argument('--lr_drop', default=200, type=int)
    parser.add_argument('--clip_max_norm', default=0.1, type=float,
                        help='gradient clipping max norm')

    # Model parameters
    parser.add_argument('--frozen_weights', type=str, default=None,
                        help="Path to the pretrained model. If set, only the mask head will be trained")
    # * Backbone
    parser.add_argument('--backbone', default='resnet50', type=str,
                        help="Name of the convolutional backbone to use")
    parser.add_argument('--dilation', action='store_true',
                        help="If true, we replace stride with dilation in the last convolutional block (DC5)")
    parser.add_argument('--position_embedding', default='sine', type=str, choices=('sine', 'learned'),
                        help="Type of positional embedding to use on top of the image features")

    # * Transformer
    parser.add_argument('--enc_layers', default=6, type=int,
                        help="Number of encoding layers in the transformer")
    parser.add_argument('--dec_layers', default=6, type=int,
                        help="Number of decoding layers in the transformer")
    parser.add_argument('--dim_feedforward', default=2048, type=int,
                        help="Intermediate size of the feedforward layers in the transformer blocks")
    parser.add_argument('--hidden_dim', default=256, type=int,
                        help="Size of the embeddings (dimension of the transformer)")
    parser.add_argument('--dropout', default=0.1, type=float,
                        help="Dropout applied in the transformer")
    parser.add_argument('--nheads', default=8, type=int,
                        help="Number of attention heads inside the transformer's attentions")
    parser.add_argument('--num_queries', default=100, type=int,
                        help="Number of query slots")
    parser.add_argument('--pre_norm', action='store_true')

    # * Segmentation
    parser.add_argument('--masks', action='store_true',
                        help="Train segmentation head if the flag is provided")

    # Loss
    parser.add_argument('--no_aux_loss', dest='aux_loss', action='store_false',
                        help="Disables auxiliary decoding losses (loss at each layer)")
    # * Matcher
    parser.add_argument('--set_cost_class', default=1, type=float,
                        help="Class coefficient in the matching cost")
    parser.add_argument('--set_cost_bbox', default=5, type=float,
                        help="L1 box coefficient in the matching cost")
    parser.add_argument('--set_cost_giou', default=2, type=float,
                        help="giou box coefficient in the matching cost")
    # * Loss coefficients
    parser.add_argument('--mask_loss_coef', default=1, type=float)
    parser.add_argument('--dice_loss_coef', default=1, type=float)
    parser.add_argument('--bbox_loss_coef', default=5, type=float)
    parser.add_argument('--giou_loss_coef', default=2, type=float)
    parser.add_argument('--eos_coef', default=0.1, type=float,
                        help="Relative classification weight of the no-object class")

    # dataset parameters
    parser.add_argument('--train_image_set', default='train')## add for train on sampled set, train_sampled_PER_CAT_THR_500, ...
    parser.add_argument('--dataset_file', default='coco')
    parser.add_argument('--coco_path', type=str)
    parser.add_argument('--coco_panoptic_path', type=str)
    parser.add_argument('--remove_difficult', action='store_true')

    parser.add_argument('--output_dir', default='',
                        help='path where to save, empty for no saving')
    parser.add_argument('--device', default='cuda',
                        help='device to use for training / testing')
    parser.add_argument('--seed', default=42, type=int)
    parser.add_argument('--resume', default='', help='resume from checkpoint')
    parser.add_argument('--start_epoch', default=0, type=int, metavar='N',
                        help='start epoch')
    parser.add_argument('--eval', action='store_true')
    parser.add_argument('--num_workers', default=2, type=int)

    # distributed training parameters
    parser.add_argument('--world_size', default=1, type=int,
                        help='number of distributed processes')
    parser.add_argument('--dist_url', default='env://', help='url used to set up distributed training')
    parser.add_argument('--sample_reg_loss', default=1e-4, type=float,
                        help="sample_reg_loss")
    parser.add_argument('--sample_topk_ratio', default=1/3., type=float)
    parser.add_argument('--score_pred_net', type=str, default='2layer-fc-256')
    parser.add_argument('--kproj_net', type=str, default='1layer-fc')
    parser.add_argument('--unsample_abstract_number', default=0, type=int,
                        help='unsample_abstract_number')
    parser.add_argument('--pos_embed_kproj', action='store_true',
                        help="add pos embeding for predicting unsampled aggregation attention")
    parser.add_argument('--sampler_lr_drop_epoch', default=1e5, type=int,
                        help='default is not drop')
    parser.add_argument('--reshape_param_group', action='store_true',
                        help="reshape_param_group of loaded state_dict to match with the 3 group setting")
    parser.add_argument('--notload_lr_scheduler', action='store_true',
                        help="notload_lr_scheduler")
    parser.add_argument('--sample_ratio_lower_bound', default=1/3., type=float)
    parser.add_argument('--sample_ratio_higher_bound', default=0.8, type=float)

    return parser

def get_host_info():
    return '{}@{}'.format(getuser(), gethostname())

def main(args):
    utils.init_distributed_mode(args)
    print("git:\n  {}\n".format(utils.get_sha()))

    if args.frozen_weights is not None:
        assert args.masks, "Frozen training is meant for segmentation only"
    print(args)
    print(get_host_info())
    device = torch.device(args.device)

    # fix the seed for reproducibility
    seed = args.seed + utils.get_rank()
    torch.manual_seed(seed)
    np.random.seed(seed)
    random.seed(seed)
    if args.unsample_abstract_number==0:# unsample_abstract_number not set
        if args.dilation:
            args.unsample_abstract_number=100
        else:
            args.unsample_abstract_number = 30

    model, criterion, postprocessors = build_model(args)
    model.to(device)
    criterion.weight_dict['sample_reg_loss'] = args.sample_reg_loss

    model_without_ddp = model
    if args.distributed:
        model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu])
        model_without_ddp = model.module
    n_parameters = sum(p.numel() for p in model.parameters() if p.requires_grad)
    print('number of params:', n_parameters)

    param_dicts = [
        {"params": [p for n, p in model_without_ddp.named_parameters() if "backbone" not in n and p.requires_grad]},
        {
            "params": [p for n, p in model_without_ddp.named_parameters() if "backbone" in n and p.requires_grad],
            "lr": args.lr_backbone,
        },
    ]
    optimizer = torch.optim.AdamW(param_dicts, lr=args.lr,
                                  weight_decay=args.weight_decay)
    lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, args.lr_drop)

    # dataset_train = build_dataset(image_set='train', args=args)
    dataset_train = build_dataset(image_set=args.train_image_set, args=args)
    dataset_val = build_dataset(image_set='val', args=args)
    # dataset_train.ids = dataset_train.ids[:100]
    # dataset_val.ids = dataset_val.ids[:100]

    if args.distributed:
        sampler_train = DistributedSampler(dataset_train)
        sampler_val = DistributedSampler(dataset_val, shuffle=False)
    else:
        sampler_train = torch.utils.data.RandomSampler(dataset_train)
        sampler_val = torch.utils.data.SequentialSampler(dataset_val)

    batch_sampler_train = torch.utils.data.BatchSampler(
        sampler_train, args.batch_size, drop_last=True)

    data_loader_train = DataLoader(dataset_train, batch_sampler=batch_sampler_train,
                                   collate_fn=utils.collate_fn, num_workers=args.num_workers)
    data_loader_val = DataLoader(dataset_val, args.batch_size, sampler=sampler_val,
                                 drop_last=False, collate_fn=utils.collate_fn, num_workers=args.num_workers)

    if args.dataset_file == "coco_panoptic":
        # We also evaluate AP during panoptic training, on original coco DS
        coco_val = datasets.coco.build("val", args)
        base_ds = get_coco_api_from_dataset(coco_val)
    else:
        base_ds = get_coco_api_from_dataset(dataset_val)

    if args.frozen_weights is not None:
        checkpoint = torch.load(args.frozen_weights, map_location='cpu')
        model_without_ddp.detr.load_state_dict(checkpoint['model'])

    output_dir = Path(args.output_dir)
    if args.resume:
        if args.resume.startswith('https'):
            checkpoint = torch.hub.load_state_dict_from_url(
                args.resume, map_location='cpu', check_hash=True)
        elif not args.resume.endswith('pth'):
            checkpoint = torch.load(args.output_dir+'/checkpoint.pth', map_location='cpu')
        else:
            checkpoint = torch.load(args.resume, map_location='cpu')

        def load_my_state_dict(module, state_dict):

            own_state = module.state_dict()
            for name, param in state_dict.items():
                if name not in own_state:
                    continue
                if isinstance(param, Parameter):
                    # backwards compatibility for serialized parameters
                    param = param.data
                own_state[name].copy_(param)

        # model_without_ddp.load_state_dict(checkpoint['model'])
        load_my_state_dict(model_without_ddp, checkpoint['model'])
        if not args.eval and 'optimizer' in checkpoint and 'lr_scheduler' in checkpoint and 'epoch' in checkpoint:
            try:
                optimizer.load_state_dict(checkpoint['optimizer'])
                if not args.notload_lr_scheduler:
                    lr_scheduler.load_state_dict(checkpoint['lr_scheduler'])
                args.start_epoch = checkpoint['epoch'] + 1
            except:
                print('skip loading optimizer and other training settings, supposed to be initing from trained model, but not resuming training')

    if args.eval:
        test_stats, coco_evaluator = evaluate(model, criterion, postprocessors,
                                              data_loader_val, base_ds, device, args.output_dir, args.sample_topk_ratio)
        if args.output_dir:
            utils.save_on_master(coco_evaluator.coco_eval["bbox"].eval, output_dir / "eval.pth")
        return

    print("Start training")
    start_time = time.time()
    best_ap = 0.
    lr_scheduler.step(epoch=args.start_epoch)
    for epoch in tqdm.tqdm(range(args.start_epoch, args.epochs)):
        if args.distributed:
            sampler_train.set_epoch(epoch)
        lr_scheduler.step(epoch=epoch)
        if epoch >= args.sampler_lr_drop_epoch:
            optimizer.param_groups[0]['lr'] *= 0.1
        train_stats = train_one_epoch(
            model, criterion, data_loader_train, optimizer, device, epoch, args.sample_ratio_lower_bound,args.sample_ratio_higher_bound,
            args.clip_max_norm)

        test_stats_all_sample_ratio = []
        sample_ratios = [0.333, 0.5, 0.65, 0.8]
        for sample_ratio in sample_ratios:
            test_stats, coco_evaluator = evaluate(
                model, criterion, postprocessors, data_loader_val, base_ds, device, args.output_dir, sample_ratio
            )
            test_stats_all_sample_ratio.append(test_stats)
        log_stats = {**{f'train_{k}': v for k, v in train_stats.items()},
                     **{f'test_ratio_{sample_ratios[0]}_{k}': v for k, v in test_stats_all_sample_ratio[0].items()},
                     **{f'test_ratio_{sample_ratios[1]}_{k}': v for k, v in test_stats_all_sample_ratio[1].items()},
                     **{f'test_ratio_{sample_ratios[2]}_{k}': v for k, v in test_stats_all_sample_ratio[2].items()},
                     **{f'test_ratio_{sample_ratios[3]}_{k}': v for k, v in test_stats_all_sample_ratio[3].items()},
                     'epoch': epoch,
                     'n_parameters': n_parameters,
                     'lrs':[optimizer.param_groups[i]['lr']for i in range(len(optimizer.param_groups))]}

        if args.output_dir:
            checkpoint_paths = [output_dir / 'checkpoint.pth']
            # extra checkpoint before LR drop and every 100 epochs
            if (epoch + 1) % args.lr_drop == 0 or (epoch + 1) % 100 == 0:
                checkpoint_paths.append(output_dir / f'checkpoint{epoch:04}.pth')
            if test_stats_all_sample_ratio[2]['coco_eval_bbox'][0] > best_ap:
                best_ap = test_stats['coco_eval_bbox'][0]
                checkpoint_paths.append(output_dir / f'checkpoint_best.pth')
            for checkpoint_path in checkpoint_paths:
                utils.save_on_master({
                    'model': model_without_ddp.state_dict(),
                    'optimizer': optimizer.state_dict(),
                    'lr_scheduler': lr_scheduler.state_dict(),
                    'epoch': epoch,
                    'args': args,
                }, checkpoint_path)

        if args.output_dir and utils.is_main_process():
            with (output_dir / "log.txt").open("a") as f:
                f.write(json.dumps(log_stats) + "\n")

            # for evaluation logs
            if coco_evaluator is not None:
                (output_dir / 'eval').mkdir(exist_ok=True)
                if "bbox" in coco_evaluator.coco_eval:
                    filenames = ['latest.pth']
                    if epoch % 50 == 0:
                        filenames.append(f'{epoch:03}.pth')
                    for name in filenames:
                        torch.save(coco_evaluator.coco_eval["bbox"].eval,
                                   output_dir / "eval" / name)

    total_time = time.time() - start_time
    total_time_str = str(datetime.timedelta(seconds=int(total_time)))
    print('Training time {}'.format(total_time_str))

if __name__ == '__main__':
    parser = argparse.ArgumentParser('DETR training and evaluation script', parents=[get_args_parser()])
    args = parser.parse_args()
    if args.output_dir:
        Path(args.output_dir).mkdir(parents=True, exist_ok=True)
    main(args)


from collections import Counter
class Solution(object):
    def findMaxForm(self, strs, m, n):
        """
        :type strs: List[str]
        :type m: int
        :type n: int
        :rtype: int
        """
        str_counter = []
        for s in strs:
            c0 = s.count('0')
            str_counter.append((c0, len(s) - c0))
        table = Counter()
        table[m, n] = 0
        ans = 0
        for c0, c1 in str_counter:
            for (remm, remn), cnt in table.items():
                if c0 <= remm and c1 <= remn:
                    nxtm, nxtn = remm - c0, remn - c1
                    table[nxtm, nxtn] = max(table[nxtm, nxtn], cnt + 1)
                    ans = max(table[nxtm, nxtn], ans)
        return ans


from rest_framework import serializers

# Models
from task_server.models import ProjectTeam

# Serializers
from task_server.api.serializers.team.index import TeamSerializer, TeamReadOnlySerializer
from task_server.api.serializers.project.index import ProjectSerializer

class ProjectTeamSerializer(serializers.ModelSerializer):
    class Meta:
        model = ProjectTeam
        fields = "__all__"
        read_only_fields = ['created_at', 'updated_at']
        required_fields = ['project', 'team']

class ProjectTeamReadOnlySerializer(serializers.ModelSerializer):
    team = TeamReadOnlySerializer(read_only=True)

    class Meta:
        model = ProjectTeam
        fields = "__all__"
        read_only_fields = ['created_at', 'updated_at']
        required_fields = ['project', 'team']


#!/usr/bin/env python3

# Python 3.9.7

# 09_numpy_array_arithmetic.py

# Dependency
import numpy as np

array = np.arange(5)

# Basic numpy operations:
np.add(array, 2)            # Addtion
np.subtract(array, 2)       # Subtraction
np.negative(array)          # Unary negation
np.multiply(array, 2)       # Multiplication
np.divide(array, 2)         # Division
np.floor_divide(array, 2)   # Floor divisioin
np.power(array, 3)          # Exponetiation
np.mod(array, 3)            # Modulus/Remainder

# Absolute value:
array = np.array([-5, -4, -3, -2, -1])
abs(array)
np.absolute(array)
np.abs(array)

# Calculation is also possible:
print('x      = ', array)
print('x + 4  = ', array + 4)
print('x - 6  = ', array - 6)
print('x * 3  = ', array * 3)
print('x / 4  = ', array / 4)
print('x // 3 = ', array // 3)

print("-x = ", -array)
print("x ** 2 = ", array ** 2)
print("x % 2 = ", array % 2)

# Written as a function:
-(0.125 * array + 4) ** 5


from __future__ import print_function
import collections
import os,sys
import tensorflow as tf
from keras.models import Sequential, load_model
from keras.layers import Dense, Activation, Embedding, Dropout, TimeDistributed
from keras.layers import LSTM
from keras.optimizers import Adam
from keras.utils import to_categorical
from keras.callbacks import ModelCheckpoint
import numpy as np
import argparse

from input_gen import *

data_x = []
data_y = []

SEQ_LENGTH = 60
sequences = generateInputSequences(SEQ_LENGTH)
sequences = getGameSequences()

for s in sequences:
    data_x.append(s[:30].copy())
    data_y.append(s[30:60].copy())

num_steps = 30

# model generation
hidden_size = 200
use_dropout=False
model = Sequential()
model.add(LSTM(hidden_size, return_sequences=True))
model.add(LSTM(hidden_size, return_sequences=False))
if use_dropout:
    model.add(Dropout(0.5))
#model.add(TimeDistributed(Dense(vocabulary)))
model.add(Activation('softmax'))
model.add(Dense(1))

optimizer = Adam()
model.compile(loss='mean_squared_error', optimizer='adam', metrics=['categorical_accuracy'])

model.build()

#print(model.summary())
#sys.exit()

resh_x = np.array(data_x).reshape(len(sequences),30,1)
#resh_y = np.array(data_y).reshape(len(sequences),30)

resh_y = np.zeros((len(sequences),1))
for i in range(len(data_y)):
    resh_y[i] = data_y[i][0]

# model training
model.fit(resh_x, resh_y, epochs=1000)

print("\nStart Evaluation")
pred = model.predict(resh_x[1].reshape(1,30,1))
print(resh_x[1])
print(pred, resh_y[1])

pred = model.predict(resh_x[3].reshape(1,30,1))
print(resh_x[3])
print(pred, resh_y[3])

print("\nEnd Of Network")


import os
import torch
import torch.nn as nn
from torchvision.transforms import transforms
from PIL import Image
from io import BytesIO
import requests
import logging
# 도커 컴포즈(2)를 위한 추가
import argparse
import time
# 추가 끝

from flask import Flask, request, jsonify
import sys

def init():
    # 도커 컴포즈(2)를 위한 추가
    # 명령행에서 --port, --model_key 옵션으로 값을 받아옴
    parser = argparse.ArgumentParser(description="Infer service for flyai tutorial")
    parser.add_argument('--port', '-p', type=int, default=5001, help='Port number (default: 5001)')
    parser.add_argument('--model_key', '-m', type=str, required=False, help='model key')

    args = parser.parse_args()
    # port는 init 함수 밖에서 사용하기 때문에 global로 지정
    global service_port
    service_port = args.port
    # 추가 끝

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

    lib_path = os.environ.get('LIBPATH')
    global model
    if lib_path is None:
        lib_path = '../lib/'

    sys.path.append(lib_path)
    from digit_recognizer import DigitRecognizer
    model = DigitRecognizer()

    model_path = os.environ.get('MODELPATH')
    if model_path is None:
        logging.warning("MODELPATH is not defined. Default value will be used.")
        model_path = '../model/'

    # 도커 컴포즈(2)를 위한 수정.
    # 기존의 MODELURL 대신 MODELHOST와 MODELENDPOINT를 사용하며
    # model_key 파라미터를 추가로 전달합니다.
    # 그리고 model_service가 살아 있는지 확인합니다. 이를 위해서 MSTIMEOUT 환경변수도 사용합니다.
    # 또한 model download 실패시 반복 횟수를 지정하기 위한 MODELGETRETRY 환경변수도 사용합니다.

    #model_url = os.environ.get("MODELURL")
    #if model_url is None:
    #    logging.warning("MODELURL is not defined. Default value will be used.")
    #    model_url = "http://localhost:5002/model"

    model_get_retry_str = os.environ.get("MODELGETRETRY")
    if model_get_retry_str is None:
        model_get_retry = 5
    else:
        model_get_retry = int(model_get_retry_str)

    modelservice_host = os.environ.get('MSHOST')
    modelservice_port = os.environ.get('MSPORT')
    modelservice_endpoint = os.environ.get('MSENDPOINT')
    ms_timeout_str = os.environ.get('MSTIMEOUT')
    if modelservice_host and modelservice_port and modelservice_endpoint:
        model_url = f"http://{modelservice_host}:{modelservice_port}{modelservice_endpoint}"
        health_check_url = f"http://{modelservice_host}:{modelservice_port}/"
    else:
        model_url = "http://localhost:5002/model"
        health_check_url = "http://localhost:5002/"

    logging.info(f"model url : {model_url}")
    # 옵션에 model_key가 포함되어 있으면 url에 쿼리를 추가합니다.
    if args.model_key:
        model_url += f"?model_key={args.model_key}"

    # MSTIMEOUT 환경변수가 있을 때만 확인
    # 오류 발생 시 1초마다 재확인해서, 시간이 다 되면 종료
    if ms_timeout_str is not None:
        logging.info("Checking model_service is alive")
        alive = False
        for i in range(int(ms_timeout_str)):
            try:
                response = requests.get(health_check_url)
                response.raise_for_status()
                logging.info("model_service is alive")
                alive = True
                break
            except:
                logging.error(f"Error occured while model_service_health check ({i + 1}/{int(ms_timeout_str)})")
                time.sleep(1)
        if alive == False:
            logging.critical("Model_service seems inactive, so exit.")
            exit(-1)
    else:
        logging.info("MSTIMEOUT is not setted, so skippiing model_service is alive")
    # 수정 끝

    try:
        # 도커 컴포즈(2)를 위한 수정
        # model download에 실패했을 때 MODELGETRETRY에 지정한 횟수 만큼 반복하고 그래도 실패하면 종료

        model_download_trial = 0
        while True:
            response = requests.get(model_url)
            if response.status_code == 200:
                model_bytes = response.content
                break
            # redis RESTAPI를 사용할 수 있는데 modelfile을 얻어올 수 없으면 종료
            else:
                model_download_trial += 1
                if model_download_trial == model_get_retry:
                    logging.critical('Modelservice seems active, but modelfile is not provided. Inferservice is shutdowned.')
                    exit(-1)
                else:
                    logging.error(f"Model download failed. Retry ({model_download_trial}/{model_get_retry})")
                    time.sleep(1)
        # 수정 끝

        model.load_state_dict(torch.load(BytesIO(model_bytes)))
        logging.info("Model is loaded successfully from redis server.")
    except Exception as e:
        # redis를 RESTAPI를 사용할 수 없으면 model/modelfile 파일을 읽어옴
        logging.warning("Modelservice seems inactive, so model will be loaded from file.")
        try:
            model.load_state_dict(torch.load(model_path + 'modelfile'))
            logging.info("Model is loaded successfully from file.")
        except Exception as e:
            logging.critical("Failed to load model from file. Inferservice is shutdowned.")
            exit(-1)

    model.eval()

def infer(image_file):
    try:
        transform = transforms.Compose([transforms.Grayscale(), transforms.ToTensor()])

        image = Image.open(image_file).convert('L')
        image = transform(image).unsqueeze(0)

        # 추론
        with torch.no_grad():
            output = model(image)

        # 결과 출력
        _, predicted = torch.max(output, 1)
        return None, predicted.item()
    except Exception as e:
        return e, -1

init()
app = Flask(__name__)

@app.route('/', methods=['GET'])
def i_am_alive():
    return "infer service is alive", 200

@app.route('/recognize', methods=['POST'])
def recog_image():
    if 'image' not in request.files:
        return "No image file uploaded", 400
    image_file = request.files['image']
    e, result = infer(image_file)
    if e == None:
        return jsonify({'result':result})
    else:
        return f"Error recognizing image: {str(e)}", 500

if __name__ == '__main__':
    # 도커 컴포즈(2)를 위한 수정.
    # --port로 추가한 port를 사용합니다.
    app.run(host='0.0.0.0', port=service_port)
    # 수정 끝


def listTrip(file,budget):
    content = open(file)
    directions = []
    for line in content:
        line = line.split(";")
        if int(line[1]) <= budget:
            directions.append(line[0])
    content.close()
    return directions

budget = int(input("Enter trip budget: "))
print("Suitable trips are:")
counter = 0
for i in listTrip("trips.txt", budget):
    print (i)
    counter += 1
if counter == 0:
    print("There are none")


from itu.algs4.sorting.max_pq import MaxPQ

def main():
    parties, seats = input().split()
    seat_list = []
    quotient_dict = {}
    parliament = MaxPQ()
    for _ in range(int(parties)):
        votes = int(input())
        parliament.insert(votes)
    # print(parliament.max())
    calculate_quotient(0, int(parties), int(parliament.max()), seat_list, parliament, quotient_dict)

def calculate_quotient(party, parties, max, seat_list, parliament, quotient_dict):
    if party >= parties:
        return print(seat_list, quotient_dict)
    elif party == 0:
        seat_list.append(1)
        quotient_dict.setdefault(0, 1)
        parliament.del_max()
        return calculate_quotient(1, parties, parliament.max(), seat_list, parliament, quotient_dict)
    elif party >= 0:
        quotient = max/parties
        if quotient > quotient_dict[party-1]:
            try:
                seat_list[party] += 1
            except IndexError:
                seat_list.append(1)
            quotient_dict[party] = quotient
            party+=1
            return calculate_quotient(party, parties, parliament.max(), seat_list, parliament, quotient_dict)
        else:
            seat_list[party-1] += 1
            quotient_dict[party] = quotient
            party+=1
            return calculate_quotient(party, parties, parliament.max(), seat_list, parliament, quotient_dict)

if __name__ == "__main__":
    main()


#%%
# puede tomar multiples argumentos pero solo una expresion
x = lambda a: a + 10
print(x(5))

x = lambda a, b : a * b
print(x(5, 6))
# %%
# sirve como plantilla de funciones
def myfunc(n):
  return lambda a : a * n
# aca se crea una funcion duplicadora
mydoubler = myfunc(2)
# aca se ejecuta la funcion
print(mydoubler(11))

# %%
full_name = lambda first, last: f'Full name: {first.title()} {last.title()}'
full_name('guido', 'van rossum')
# %%
_=lambda x, y: x + y
_(1, 2)


# RUN APPLICATION
import requests
from bs4 import BeautifulSoup
import urllib3
import re
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
import time
import os
from google_drive_downloader import GoogleDriveDownloader as gdd
import sys
from urllib.request import Request, urlopen

def scraping(url):
    print("\n\n\nScraping from " + url + "\n\n\n")
    f.write("\n\n\nScraping from " + url + "\n\n\n")
    r = requests.get(url)
    return BeautifulSoup(r.content, 'html.parser')

def advanced_scraping(url):
    req = Request(url, headers={'User-Agent' : 'Mozilla/5.0'})
    webpage = urlopen(req).read()
    print("Scraping from " + url)
    f.write("\n\n\n")
    f.write("Scraping from " + url + "\n\n\n")
    return BeautifulSoup(webpage, 'html.parser')

def gdownload(url, destination):
    print(url)
    splits = url.split("/")
    d_location = -1
    google_id = ""

    for i, split in enumerate(splits):
        if split == 'd':
            d_location = i
        elif 'id=' in split:
            google_id = split[split.find('id=')+3:]
    if d_location != -1 and google_id == "":
        google_id = splits[d_location + 1]
    gdd.download_file_from_google_drive(file_id=google_id,
                                    dest_path=destination)

def getPDFs(file_url, county):
    print("pdf url", file_url)
    print("A PDF HERE\n")
    f.write("A PDF HERE\n")
    title = file_url.split('/').pop() + '.pdf'
    r = requests.get(file_url, stream = True)
    with open("../data/" + county + "-PDF" + "/" + title,"wb") as pdf:
        for chunk in r.iter_content(chunk_size=1024*1024):
            pdf.write(chunk)
    return "data/" + title

def saveText(url):
    soup = scraping(url)
    textArea = soup.find('div', id='ColumnUserControl3')
    f.write(textArea.text)

    for a_tag in textArea.find_all('a'):
        link = a_tag.get('href')
        if link and link not in checked:
            checked.add(link)
            if 'showdocument' in link:
                if 'tpchd' not in link:
                    link = 'https://www.tpchd.org' + link
                getPDFs(link, 'pierce')
def saveBlogText(url):
    soup = scraping(url)
    textArea = soup.find('div', class_='blog-detail-view clearfix')
    f.write(textArea.text)

def saveNewsText(url):
    soup = scraping(url)
    textArea = soup.find('div', class_='item fr-view')
    f.write(textArea.get_text(separator = '\n'))

COUNTY = "pierce"
f = open("../data/" + COUNTY + ".txt", "w")

pdfPath = "../data/" + COUNTY + "-PDF"
os.mkdir(pdfPath)

# scraping from 'https://www.tpchd.org/healthy-people/human-coronavirus'
soup = scraping('https://www.tpchd.org/healthy-people/human-coronavirus')
textArea = soup.find('div', id='ColumnUserControl3')
f.write(textArea.text)

checked = set()

for icon_page in textArea.find_all('a', class_="button-link"):
    link = icon_page.get('href')
    if 'splash' not in link and 'pierce-county-cases' not in link:
        if 'tpchd' not in link:
            link = 'https://www.tpchd.org' + link
        saveText(link)
        checked.add(link)

for a_tag in textArea.find_all('a'):
    link = a_tag.get('href')
    if link and link not in checked:
        checked.add(link)
        if 'showdocument' in link:
            if 'tpchd' not in link:
                link = 'https://www.tpchd.org' + link
            getPDFs(link, 'pierce')
        elif 'Blog/Blog' in link and 'splash' not in link:
            saveBlogText(link)

# scraping 'https://www.co.pierce.wa.us/CivicAlerts.aspx?CID=1'

soup = scraping('https://www.co.pierce.wa.us/CivicAlerts.aspx?CID=1')
read_mores = soup.select('.more')
for read_more in read_mores:
    link = read_more.get('href')
    if int(link.split('=')[-1]) > 4400:
        saveNewsText('https://www.co.pierce.wa.us' + link)
    else:
        break

# scraping 'https://www.co.pierce.wa.us/6759/Safe-Start'
soup = scraping('https://www.co.pierce.wa.us/6759/Safe-Start')
textArea = soup.find('div', class_='fr-view')
f.write(textArea.get_text(separator = '\n'))
for a_tag in textArea.find_all('a'):
    link = a_tag.get('href')
    if 'DocumentCenter' in link:
        getPDFs(link, 'pierce')


# Standard Library
from builtins import str
import os
import time

# Third Party Stuff
from django.conf import settings
from django.db.models import Q

# Spoken Tutorial Stuff
from creation.models import *
from youtube.core import *
from youtube.utils import *

def upload_videos():
    service = get_youtube_credential()

    if service is None:
        print(('authenticate using the following url to continue: \n {}'.format(get_auth_url())))
        return

    tresource_list = TutorialResource.objects.filter(Q(status=1) | Q(status=2), video_id=None).select_related()
    error_log_file_head = open('{}/logs/youtube-error.log'.format(settings.BASE_DIR),"w")
    success_log_file_head = open('{}/logs/youtube-success.log'.format(settings.BASE_DIR),"w")

    for tresource in tresource_list:
        try:
            ogv_video_path = '{}videos/{}/{}/{}'.format(
                settings.MEDIA_ROOT, tresource.tutorial_detail.foss_id, tresource.tutorial_detail_id, tresource.video)
            mp4_video_path, file_extn = os.path.splitext(ogv_video_path)
            mp4_tmp_video_path = mp4_video_path + '-tmp.mp4'
            mp4_video_path = mp4_video_path + '.mp4'
            title_string = '{} - {}'.format(tresource.tutorial_detail.tutorial, tresource.language.name)

            if not os.path.isfile(mp4_video_path):
                convert_tmp_video(ogv_video_path, mp4_tmp_video_path)
                convert_video(mp4_tmp_video_path, mp4_video_path)
                if not os.path.isfile(mp4_video_path) or not os.path.getsize(mp4_video_path):
                    print((tresource.tutorial_detail.tutorial, '-', tresource.language.name, '-- MP4 video missing'))
                    continue

            options = {
                'title': title_string,
                'description': title_string,#tresource.outline.encode('utf-8').strip(),
                'tags': tresource.common_content.keyword.split(','),
                'file': mp4_video_path
            }

            # try:
            print(('uploading video', tresource.id, '-', tresource.tutorial_detail.tutorial, '-', tresource.tutorial_detail.foss.foss, '-', tresource.language.name))
            video_id = upload_video(service, options)
            # except:
            #     video_id = None
            print(('video id -', video_id))

            if video_id:
                tresource.video_id = video_id
                tresource.save()
                success_log_file_head.write('upload_video, {}, {}, {}\n'.format(tresource.id, title_string, video_id))
            else:
                error_log_file_head.write('upload_video, {}, {}\n'.format(tresource.id, title_string))

            time.sleep(1)
        except Exception as e:
            error_log_file_head.write('upload_video, {}, {}\n'.format(tresource.id, str(e)))

def create_playlists():
    service = get_youtube_credential()

    if service is None:
        return

    foss_list = FossCategory.objects.all()

    for foss_obj in foss_list:
        tr_lang_list = TutorialResource.objects.filter(
            Q(status=1) | Q(status=2),
            tutorial_detail__foss_id=foss_obj.id).values_list('language_id').distinct()
        lang_list = Language.objects.filter(id__in=tr_lang_list).exclude(
            id__in=PlaylistInfo.objects.filter(foss_id=foss_obj.id).values_list('language_id').distinct())

        for lang_obj in lang_list:
            title = '{} - {}'.format(foss_obj.foss, lang_obj.name)
            print(('creating playlist:', title))
            playlist_id = create_playlist(service, title, foss_obj.description)

            if playlist_id:
                playlist_obj = PlaylistInfo.objects.create(
                    foss=foss_obj, language=lang_obj, playlist_id=playlist_id)

            time.sleep(1)

def append_to_playlist():
    service = get_youtube_credential()

    if service is None:
        return

    rows = TutorialResource.objects.filter(
        Q(status=1)|Q(status=2), video_id__isnull=False, playlist_item_id__isnull=True
    ).values_list('tutorial_detail__foss_id', 'language_id').distinct()

    for row in rows:
        playlist_obj = PlaylistInfo.objects.filter(language_id=row[1], foss_id=row[0]).first()

        if not playlist_obj:
            continue

        tresource_list = TutorialResource.objects.filter(
            Q(status=1)|Q(status=2), tutorial_detail__foss_id=row[0],
            language_id=row[1]
        ).order_by(
            'tutorial_detail__foss__foss', 'tutorial_detail__level_id', 'tutorial_detail__order')
        counter = 1

        for tresource in tresource_list:
            if tresource.playlist_item_id:
                print(('updating palylist item position -', tresource.playlist_item_id))
                result = update_playlistitem_position(
                    service, tresource.playlist_item_id,
                    tresource.video_id, playlist_obj.playlist_id, counter)
            else:
                print(('adding item to playlist -', playlist_obj.playlist_id))
                result = add_to_playlist(service, tresource.video_id, playlist_obj.playlist_id, counter)

                if result:
                    tresource.playlist_item_id = result
                    tresource.save()
                    PlaylistItem.objects.create(playlist=playlist_obj, item_id=result)

            if not result:
                break

            counter += 1
            time.sleep(1)