from collections import namedtuple
from itertools import combinations
import math
import random
import numpy as np
from numpy.linalg import inv
from numpy.matlib import repmat

from pylot.perception.detection.utils import DetectedObject,\
    DetectedSpeedLimit, get_bounding_boxes_from_segmented
from pylot.perception.segmentation.utils import get_traffic_sign_pixels

Orientation = namedtuple('Orientation', 'x, y, z')
Rotation = namedtuple('Rotation', 'pitch, yaw, roll')
Vehicle = namedtuple('Vehicle', 'id, transform, bounding_box, forward_speed')
Pedestrian = namedtuple('Pedestrian',
                        'id, transform, bounding_box, forward_speed')
TrafficLight = namedtuple('TrafficLight',
                          'id, transform, state, trigger_volume_extent')
SpeedLimitSign = namedtuple('SpeedLimitSign', 'transform, limit')
StopSign = namedtuple('StopSign', 'transform, bounding_box')
DetectedLane = namedtuple('DetectedLane', 'left_marking, right_marking')
LocationGeo = namedtuple('LocationGeo', 'latitude, longitude, altitude')
Extent = namedtuple('Extent', 'x, y, z')
Scale = namedtuple('Scale', 'x y z')
Scale.__new__.__defaults__ = (1.0, 1.0, 1.0)

class CameraSetup(object):
    def __init__(self,
                 name,
                 camera_type,
                 width,
                 height,
                 transform,
                 fov=90):
        self.name = name
        self.camera_type = camera_type
        self.width = width
        self.height = height
        self.transform = transform
        self.fov = fov
        self.intrinsic_mat = create_intrinsic_matrix(
            self.width, self.height, self.fov)

    def get_intrinsic(self):
        return self.intrinsic_mat

    def get_transform(self):
        return self.transform

    def get_unreal_transform(self):
        return camera_to_unreal_transform(self.transform)

    def __repr__(self):
        return self.__str__()

    def __str__(self):
        return 'CameraSetup(name: {}, type: {}, width: {}, height: {}, '\
            'transform: {}, fov: {}'.format(
                self.name, self.camera_type, self.width, self.height,
                self.transform, self.fov)

class LidarSetup(object):
    def __init__(self,
                 name,
                 lidar_type,
                 transform,
                 range,
                 rotation_frequency,
                 channels,
                 upper_fov,
                 lower_fov,
                 points_per_second):
        self.name = name
        self.lidar_type = lidar_type
        self.transform = transform
        self.range = range
        self.rotation_frequency = rotation_frequency
        self.channels = channels
        self.upper_fov = upper_fov
        self.lower_fov = lower_fov
        self.points_per_second = points_per_second

    def get_transform(self):
        return self.transform

    def get_unreal_transform(self):
        return lidar_to_unreal_transform(self.transform)

    def __repr__(self):
        return self.__str__()

    def __str__(self):
        return 'LidarSetup(name: {}, type: {}, transform: {}, range: {}, '\
            'rotation freq: {}, channels: {}, upper_fov: {}, lower_fov: {}, '\
            'points_per_second: {}'.format(
                self.name, self.lidar_type, self.transform, self.range,
                self.rotation_frequency, self.channels, self.upper_fov,
                self.lower_fov, self.points_per_second)

class CanBus(object):
    def __init__(self, transform, forward_speed):
        self.transform = transform
        # Forward speed in m/s.
        self.forward_speed = forward_speed

    def __repr__(self):
        return self.__str__()

    def __str__(self):
        return "CanBus(transform: {}, forward speed: {})".format(
            self.transform, self.forward_speed)

class BoundingBox(object):
    def __init__(self, bb):
        if hasattr(bb, 'location'):
            # Path for Carla 0.9.x.
            loc = Location(bb.location.x, bb.location.y, bb.location.z)
            # In Carla 0.9.x, the bounding box transform is relative
            # to the object transform (and so carla.BoundingBox doesn't
            # have a rotation).
            rot = Rotation(0, 0, 0)
        else:
            # Path for Carla 0.8.4.
            loc = Location(bb.transform.location.x,
                           bb.transform.location.y,
                           bb.transform.location.z)
            rot = Rotation(bb.transform.rotation.pitch,
                           bb.transform.rotation.yaw,
                           bb.transform.rotation.roll)
        self.transform = Transform(loc, rot)
        self.extent = Extent(bb.extent.x, bb.extent.y, bb.extent.z)

    def __repr__(self):
        return self.__str__()

    def __str__(self):
        return "BoundingBox(transform: {}, extent: {})".format(
            self.transform, self.extent)

class Location(object):
    def __init__(self, x=0, y=0, z=0, carla_loc=None):
        if carla_loc is not None:
            self.x = carla_loc.x
            self.y = carla_loc.y
            self.z = carla_loc.z
        else:
            self.x = x
            self.y = y
            self.z = z

    def __add__(self, other):
        return Location(x=self.x + other.x,
                        y=self.y + other.y,
                        z=self.z + other.z)

    def __repr__(self):
        return self.__str__()

    def __str__(self):
        return 'Location({}, {}, {})'.format(self.x, self.y, self.z)

class Transform(object):
    # Transformations are applied in the order: Scale, Rotation, Translation.
    # Rotations are applied in the order: Roll (X), Pitch (Y), Yaw (Z).
    # A 90-degree "Roll" rotation maps the positive Z-axis to the positive
    # Y-axis. A 90-degree "Pitch" rotation maps the positive X-axis to the
    # positive Z-axis. A 90-degree "Yaw" rotation maps the positive X-axis
    # to the positive Y-axis.
    # Warning: in general, the different stages of the transform
    # are non-commutative!

    def __init__(self, pos=None, rotation=None, orientation=None, scale=None,
                 matrix=None, orientation_matrix=None):
        self.rotation = rotation
        self.location = pos
        self.scale = scale
        if scale is None:
            scale = Scale()
        if matrix is None:
            self.matrix = self._create_matrix(pos, rotation, scale)
        else:
            self.matrix = matrix
            self.location = Location(matrix[0, 3], matrix[1, 3], matrix[2, 3])

        if orientation is not None:
            self.orientation_matrix = self._create_matrix(
                orientation, rotation, Scale())
            self.orientation = orientation
        elif orientation_matrix is not None:
            self.orientation_matrix = orientation_matrix
            self.orientation = Orientation(orientation_matrix[0, 3],
                                           orientation_matrix[1, 3],
                                           orientation_matrix[2, 3])
        else:
            # No orientation provided. We multiply the defautl world
            # orientation by the transform matrix to compute the orientation.
            self.orientation_matrix = np.dot(
                self._create_matrix(Location(1.0, 0, 0),
                                    Rotation(0, 0, 0),
                                    Scale()),
                self.matrix)
            self.orientation = Orientation(self.orientation_matrix[0, 3],
                                           self.orientation_matrix[1, 3],
                                           self.orientation_matrix[2, 3])

    def _create_matrix(self, pos, rotation, scale):
        matrix = np.matrix(np.identity(4))
        cy = math.cos(np.radians(rotation.yaw))
        sy = math.sin(np.radians(rotation.yaw))
        cr = math.cos(np.radians(rotation.roll))
        sr = math.sin(np.radians(rotation.roll))
        cp = math.cos(np.radians(rotation.pitch))
        sp = math.sin(np.radians(rotation.pitch))
        matrix[0, 3] = pos.x
        matrix[1, 3] = pos.y
        matrix[2, 3] = pos.z
        matrix[0, 0] = scale.x * (cp * cy)
        matrix[0, 1] = scale.y * (cy * sp * sr - sy * cr)
        matrix[0, 2] = -scale.z * (cy * sp * cr + sy * sr)
        matrix[1, 0] = scale.x * (sy * cp)
        matrix[1, 1] = scale.y * (sy * sp * sr + cy * cr)
        matrix[1, 2] = scale.z * (cy * sr - sy * sp * cr)
        matrix[2, 0] = scale.x * (sp)
        matrix[2, 1] = -scale.y * (cp * sr)
        matrix[2, 2] = scale.z * (cp * cr)
        return matrix

    def transform_points(self, points):
        """
        Given a 4x4 transformation matrix, transform an array of 3D points.
        Expected point format: [[X0,Y0,Z0],..[Xn,Yn,Zn]]
        """
        # Needed format: [[X0,..Xn],[Y0,..Yn],[Z0,..Zn]]. So let's transpose
        # the point matrix.
        points = points.transpose()
        # Add 1s row: [[X0..,Xn],[Y0..,Yn],[Z0..,Zn],[1,..1]]
        points = np.append(points, np.ones((1, points.shape[1])), axis=0)
        # Point transformation
        points = np.dot(self.matrix, points)
        # Return all but last row
        return points[0:3].transpose()

    def transform_locations(self, locs):
        """
        Using the transformation matrix, transform a list of locations.
        """
        print (np.shape(locs), len(locs))
        points = np.zeros((4, len(locs)))
        for idx in range(len(locs)):
            points[0][idx] = locs[idx].x
            points[1][idx] = locs[idx].y
            points[2][idx] = locs[idx].z
            points[3][idx] = 1
        points = np.dot(self.matrix, points)
        # Return all but last row
        return points[0:3].transpose()

    def inverse_transform(self):
        return Transform(matrix=inv(self.matrix),
                         orientation_matrix=inv(self.orientation_matrix))

    def __mul__(self, other):
        new_matrix = np.dot(self.matrix, other.matrix)
        new_orientation_matrix = np.dot(self.orientation_matrix,
                                        other.orientation_matrix)
        return Transform(matrix=new_matrix,
                         orientation_matrix=new_orientation_matrix)

    def __str__(self):
        if self.location:
            return "Transform(location: {}, rotation: {})".format(
                self.location, self.rotation)
        else:
            return "Transform({})".format(str(self.matrix))

def to_pylot_transform(transform):
    """ Converts a Carla transform into a Pylot transform."""
    orientation = None
    # get_forward_vector() is only available in carla 0.9.5.
    get_fwd_vector = getattr(transform, "get_forward_vector", None)
    if callable(get_fwd_vector):
        fwd_vector = transform.get_forward_vector()
        orientation = Orientation(fwd_vector.x, fwd_vector.y, fwd_vector.z)

    return Transform(
        Location(carla_loc=transform.location),
        Rotation(transform.rotation.pitch,
                 transform.rotation.yaw,
                 transform.rotation.roll),
        orientation)

def to_pylot_location(location):
    """ Converts a Carla location into a Pylot location. """
    return Location(carla_loc=location)

def depth_to_array(image):
    """
    Convert an image containing CARLA encoded depth-map to a 2D array
    containing the depth value of each pixel normalized between [0.0, 1.0].
    """
    array = to_bgra_array(image)
    array = array.astype(np.float32)
    # Apply (R + G * 256 + B * 256 * 256) / (256 * 256 * 256 - 1).
    normalized_depth = np.dot(array[:, :, :3], [65536.0, 256.0, 1.0])
    normalized_depth /= 16777215.0  # (256.0 * 256.0 * 256.0 - 1.0)
    return normalized_depth

def to_bgra_array(image):
    """Convert a CARLA raw image to a BGRA np array."""
    array = np.frombuffer(image.raw_data, dtype=np.dtype("uint8"))
    array = np.reshape(array, (image.height, image.width, 4))
    return array

def labels_to_array(image):
    """
    Convert an image containing CARLA semantic segmentation labels to a 2D
    array containing the label of each pixel.
    """
    return to_bgra_array(image)[:, :, 2]

def get_speed(velocity_vector):
    """ Compute the speed of the vehicle in m/s.

    Args:
        vehicle: A velocity vector.

    Returns:
        The speed of the given vehicle as a float in m/s.
    """
    speed = math.sqrt(velocity_vector.x**2 + velocity_vector.y**2 +
                      velocity_vector.z**2)
    return speed

def create_intrinsic_matrix(width, height, fov=90.0):
    # (Intrinsic) K Matrix
    k = np.identity(3)
    k[0, 2] = width / 2.0
    k[1, 2] = height / 2.0
    k[0, 0] = k[1, 1] = width / (2.0 * math.tan(fov * math.pi / 360.0))
    return k

def depth_to_local_point_cloud(depth_frame, width, height, fov, max_depth=0.9):
    """
    Convert a CARLA-encoded depth-map to a 2D array containing
    the 3D position (relative to the camera) of each pixel.
    "max_depth" is used to omit the points that are far enough.

    Args:
        depth_frame: the normalized depth frame
        width: frame width
        height: frame height
        fov: camera field of view
    """
    far = 1000.0  # max depth in meters.
    normalized_depth = depth_frame
    intrinsic_mat = create_intrinsic_matrix(width, height, fov)
    # 2d pixel coordinates
    pixel_length = width * height
    u_coord = repmat(np.r_[0:width:1], height, 1).reshape(pixel_length)
    v_coord = repmat(np.c_[0:height:1], 1, width).reshape(pixel_length)
    normalized_depth = np.reshape(normalized_depth, pixel_length)

    # Search for pixels where the depth is greater than max_depth to
    # delete them
    max_depth_indexes = np.where(normalized_depth > max_depth)
    normalized_depth = np.delete(normalized_depth, max_depth_indexes)
    u_coord = np.delete(u_coord, max_depth_indexes)
    v_coord = np.delete(v_coord, max_depth_indexes)

    # p2d = [u,v,1]
    p2d = np.array([u_coord, v_coord, np.ones_like(u_coord)])

    # P = [X,Y,Z]
    p3d = np.dot(inv(intrinsic_mat), p2d)
    p3d *= normalized_depth * far

    # [[X1,Y1,Z1],[X2,Y2,Z2], ... [Xn,Yn,Zn]]
    return np.transpose(p3d)

def camera_to_unreal_transform(transform):
    """
    Takes in a Transform that occurs in unreal coordinates,
    and converts it into a Transform that goes from camera
    coordinates to unreal coordinates.
    """
    to_unreal_transform = Transform(matrix=np.array(
        [[0, 0, 1, 0],
         [1, 0, 0, 0],
         [0, -1, 0, 0],
         [0, 0, 0, 1]]))
    return transform * to_unreal_transform

def lidar_to_unreal_transform(transform):
    """
    Takes in a Transform that occurs in unreal coordinates,
    and converts it into a Transform that goes from lidar
    coordinates to unreal coordinates.
    """
    to_unreal_transform = Transform(matrix=np.array(
        [[0, -1, 0, 0],
         [-1, 0, 0, 0],
         [0, 0, -1, 0],
         [0, 0, 0, 1]]))
    return transform * to_unreal_transform

def lidar_to_camera_transform(transform):
    """
    Takes in a Transform that occurs in camera coordinates,
    and converts it into a Transform that goes from lidar
    coordinates to camera coordinates.
    """
    to_camera_transform = Transform(matrix=np.array(
        [[1, 0, 0, 0],
         [0, 0, 1, 0],
         [0, -1, 0, 0],
         [0, 0, 0, 1]]))
    return transform * to_camera_transform

def get_3d_world_position_with_depth_map(
        x, y, depth_frame, width, height, fov, camera_transform):
    """ Gets the 3D world position from pixel coordinates using a depth frame.

        Args:
            x: Pixel x coordinate.
            y: Pixel y coordinate.
            depth_frame: Normalized depth frame.
            width: frame width
            height: frame height
            fov: camera field of view
            camera_transform: Camera transform relative to the world.

       Returns:
            3D world location.
    """
    far = 1.0
    point_cloud = depth_to_local_point_cloud(
        depth_frame, width, height, fov, max_depth=far)
    # Transform the points in 3D world coordinates.
    to_world_transform = camera_to_unreal_transform(camera_transform)
    point_cloud = to_world_transform.transform_points(point_cloud)
    (x, y, z) = point_cloud.tolist()[y * width + x]
    return Location(x, y, z)

def batch_get_3d_world_position_with_depth_map(
        xs, ys, depth_frame, width, height, fov, camera_transform):
    """ Gets the 3D world positions from pixel coordinates using a depth frame.

        Args:
            xs: List of pixel x coordinate.
            ys: List of pixel y coordinate.
            depth_frame: Normalized depth frame.
            width: frame width
            height: frame height
            fov: camera field of view
            camera_transform: Camera transform relative to the world.

       Returns:
            List of 3D world locations.
    """
    assert len(xs) == len(ys)
    far = 1.0
    point_cloud = depth_to_local_point_cloud(
        depth_frame, width, height, fov, max_depth=far)
    # Transform the points in 3D world coordinates.
    to_world_transform = camera_to_unreal_transform(camera_transform)
    point_cloud = to_world_transform.transform_points(point_cloud)
    point_cloud = point_cloud.tolist()
    locs = [point_cloud[ys[i] * width + xs[i]] for i in range(len(xs))]
    return [Location(loc[0], loc[1], loc[2]) for loc in locs]

def find_point_depth(x, y, point_cloud):
    """ Finds the closest depth normalized point cloud point to x, y."""
    if len(point_cloud) == 0:
        return None
    # Select only points that are in front.
    point_cloud = point_cloud[np.where(point_cloud[:, 2] > 0.0)]
    # Select x and y.
    pc_xy = point_cloud[:, 0:2]
    # Select z
    pc_z = point_cloud[:, 2]
    # Divize x, y by z
    normalized_pc = pc_xy / pc_z[:, None]
    xy = np.array([x, y]).transpose()
    # Compute distance
    dist = np.sum((normalized_pc - xy)**2, axis=1)
    # Select index of the closest point.
    closest_index = np.argmin(dist)
    # Return the closest point.
    return tuple(point_cloud[closest_index])

def lidar_point_cloud_to_camera_coordinates(point_cloud):
    """ Transforms a point cloud from lidar to camera coordinates."""
    identity_transform = Transform(
        matrix=np.array([[1, 0, 0, 0],
                         [0, 1, 0, 0],
                         [0, 0, 1, 0],
                         [0, 0, 0, 1]]))
    transform = lidar_to_camera_transform(identity_transform)
    return transform.transform_points(point_cloud)

def get_3d_world_position_with_point_cloud(
        u, v, pc, camera_transform, width, height, fov):
    """ Gets the 3D world position from pixel coordiantes using a Lidar
        point cloud.

        Args:
            u: Pixel x coordinate.
            v: Pixel y coordinate.
            pc: Point cloud in camera coordinates.
            camera_transform: Camera transform relative to the world.
            width: frame width
            height: frame height
            fov: camera field of view
       Returns:
            3D world location or None if it could not be computed.
    """
    intrinsic_mat = create_intrinsic_matrix(width, height, fov)
    # Project our 2D pixel location into 3D space, onto the z=1 plane.
    p3d = np.dot(inv(intrinsic_mat), np.array([[u], [v], [1.0]]))
    depth = find_point_depth(p3d[0], p3d[1], np.array(pc))
    if depth:
        # Normalize our point to have the same depth as our closest point.
        p3d *= np.array([depth[2]])
        # Convert from camera to unreal coordinates.
        to_world_transform = camera_to_unreal_transform(camera_transform)
        point_cloud = to_world_transform.transform_points(p3d.transpose())
        (x, y, z) = point_cloud.tolist()[0]
        return Location(x, y, z)
    else:
        return None

def get_bounding_box_from_corners(corners):
    """
    Gets the bounding box of the pedestrian given the corners of the plane.
    """
    # Figure out the opposite ends of the rectangle. Our 2D mapping doesn't
    # return perfect rectangular coordinates and also doesn't return them
    # in clockwise order.
    max_distance = 0
    opp_ends = None
    for (a, b) in combinations(corners, r=2):
        if abs(a[0] - b[0]) <= 0.8 or abs(a[1] - b[1]) <= 0.8:
            # The points are too close. They may be lying on the same axis.
            # Move forward.
            pass
        else:
            # The points possibly lie on different axis. Choose the two
            # points which are the farthest.
            distance = (b[0] - a[0])**2 + (b[1] - a[1])**2
            if distance > max_distance:
                max_distance = distance
                if a[0] < b[0] and a[1] < b[1]:
                    opp_ends = (a, b)
                else:
                    opp_ends = (b, a)

    # If we were able to find two points far enough to be considered as
    # possible bounding boxes, return the results.
    return opp_ends

def get_bounding_box_sampling_points(ends):
    """
    Get the sampling points given the ends of the rectangle.
    """
    a, b = ends

    # Find the middle point of the rectangle, and see if the points
    # around it are visible from the camera.
    middle_point = ((a[0] + b[0]) / 2, (a[1] + b[1]) / 2,
                    b[2].flatten().item(0))
    sampling_points = []
    for dx in range(0, 3):
        for dy in range(0, 3):
            sampling_points.append((middle_point[0] + dx,
                                    middle_point[1] + dy,
                                    middle_point[2]))
    return (middle_point, sampling_points)

def get_2d_bbox_from_3d_box(
        depth_array, vehicle_transform, obj_transform,
        bounding_box, rgb_transform, rgb_intrinsic, rgb_img_size,
        middle_depth_threshold, neighbor_threshold,
        width_percentage_threshold=0.015,
        height_percentage_threshold=0.01,
        box_area_percentage_threshold=0.0002):
    """ Transforms a 3D bounding box into a 2 bounding box projected on
    camera coordinates.

    Args:
        depth_array: Depth frame.
        vehicle_transform: Ego vehicle transform.
        obj_transform: The transform in world coordiantes of the object
            whose bounding box the method is transforming.
        bounding_box: 3D bounding box to transform.
        rgb_transform: The transform of the camera sensor.
        rgb_intrinsic: The intrinsic of the camera.
        rgb_img_size: The size of the camera frame.
        middle_depth_threshold: Max depth difference between estimation and
            depth frame for the bounding box middle point.
        neighbor_threshold: Max depth difference between estimations and
            depth frame for points sampled around the middle point.
    """
    corners = map_ground_bounding_box_to_2D(
        vehicle_transform, obj_transform,
        bounding_box, rgb_transform, rgb_intrinsic,
        rgb_img_size)
    width_size_threshold = rgb_img_size[0] * width_percentage_threshold
    height_size_threshold = rgb_img_size[1] * height_percentage_threshold
    box_area_threshold = (rgb_img_size[0] * rgb_img_size[1] *
                          box_area_percentage_threshold)
    if len(corners) == 8:
        ends = get_bounding_box_from_corners(corners)
        if ends:
            (middle_point, points) = get_bounding_box_sampling_points(ends)
            # Select bounding box if the middle point in inside the frame
            # and has the same depth
            if (inside_image(middle_point[0], middle_point[1],
                             rgb_img_size[0], rgb_img_size[1]) and
                have_same_depth(middle_point[0],
                                middle_point[1],
                                middle_point[2],
                                depth_array,
                                middle_depth_threshold)):
                (xmin, xmax, ymin, ymax) = select_max_bbox(
                    ends, rgb_img_size[0], rgb_img_size[1])
                width = xmax - xmin
                height = ymax - ymin
                # Filter out the small bounding boxes (they're far away).
                # We use thresholds that are proportional to the image size.
                # XXX(ionel): Reduce thresholds to 0.01, 0.01, and 0.0002 if
                # you want to include objects that are far away.
                if (width > width_size_threshold and
                    height > height_size_threshold and
                    width * height > box_area_threshold):
                    return (xmin, xmax, ymin, ymax)
            else:
                # The mid point doesn't have the same depth. It can happen
                # for valid boxes when the mid point is between the legs.
                # In this case, we check that a fraction of the neighbouring
                # points have the same depth.
                # Filter the points inside the image.
                points_inside_image = [
                    (x, y, z)
                    for (x, y, z) in points if inside_image(
                            x, y, rgb_img_size[0], rgb_img_size[1])
                ]
                same_depth_points = [
                    have_same_depth(x, y, z, depth_array, neighbor_threshold)
                    for (x, y, z) in points_inside_image
                ]
                if len(same_depth_points) > 0 and \
                   same_depth_points.count(True) >= 0.4 * len(same_depth_points):
                    (xmin, xmax, ymin, ymax) = select_max_bbox(
                        ends, rgb_img_size[0], rgb_img_size[1])
                    width = xmax - xmin
                    height = ymax - ymin
                    width = xmax - xmin
                    height = ymax - ymin
                    # Filter out the small bounding boxes (they're far away).
                    # Thresholds are proportional to the image size.
                    if (width > width_size_threshold and
                        height > height_size_threshold and
                        width * height > box_area_threshold):
                        return (xmin, xmax, ymin, ymax)

def have_same_depth(x, y, z, depth_array, threshold):
    x, y = int(x), int(y)
    return abs(depth_array[y][x] * 1000 - z) < threshold

def inside_image(x, y, img_width, img_height):
    return x >= 0 and y >= 0 and x < img_width and y < img_height

def select_max_bbox(ends, img_width, img_height):
    (xmin, ymin) = tuple(map(int, ends[0][:2]))
    (xmax, ymax) = tuple(map(int, ends[0][:2]))
    corner = tuple(map(int, ends[1][:2]))
    # XXX(ionel): This is not quite correct. We get the
    # minimum and maximum x and y values, but these may
    # not be valid points. However, it works because the
    # bboxes are parallel to x and y axis.
    xmin = min(xmin, corner[0])
    ymin = min(ymin, corner[1])
    xmax = max(xmax, corner[0])
    ymax = max(ymax, corner[1])
    # Make sure box vertices are within the image.
    xmin = max(xmin, 0)
    ymin = max(ymin, 0)
    xmax = min(xmax, img_width - 1)
    ymax = min(ymax, img_height - 1)
    return (xmin, xmax, ymin, ymax)

def add_noise_3D_bounding_box(bounding_box, sigma=.5):
    bounding_box.extent.x = bounding_box.extent.x + random.gauss(0,sigma)
    bounding_box.extent.y = bounding_box.extent.x + random.gauss(0,sigma)
    bounding_box.extent.z = bounding_box.extent.x + random.gauss(0,sigma)
    return bounding_box

def map_ground_bounding_box_to_2D(vehicle_transform,
                                  obj_transform,
                                  bounding_box,
                                  rgb_transform,
                                  rgb_intrinsic,
                                  rgb_img_size):
    (image_width, image_height) = rgb_img_size
    extrinsic_mat = vehicle_transform * rgb_transform

    # 8 bounding box vertices relative to (0,0,0)
    bbox = np.array([
        [  bounding_box.extent.x,   bounding_box.extent.y,   bounding_box.extent.z],
        [  bounding_box.extent.x, - bounding_box.extent.y,   bounding_box.extent.z],
        [  bounding_box.extent.x,   bounding_box.extent.y, - bounding_box.extent.z],
        [  bounding_box.extent.x, - bounding_box.extent.y, - bounding_box.extent.z],
        [- bounding_box.extent.x,   bounding_box.extent.y,   bounding_box.extent.z],
        [- bounding_box.extent.x, - bounding_box.extent.y,   bounding_box.extent.z],
        [- bounding_box.extent.x,   bounding_box.extent.y, - bounding_box.extent.z],
        [- bounding_box.extent.x, - bounding_box.extent.y, - bounding_box.extent.z]
    ])

    # Transform the vertices with respect to the bounding box transform.
    bbox = bounding_box.transform.transform_points(bbox)

    # The bounding box transform is with respect to the object transform.
    # Transform the points relative to its transform.
    bbox = obj_transform.transform_points(bbox)

    # Object's transform is relative to the world. Thus, the bbox contains
    # the 3D bounding box vertices relative to the world.

    coords = []
    for vertex in bbox:
        pos_vector = np.array([
            [vertex[0,0]],  # [[X,
            [vertex[0,1]],  #   Y,
            [vertex[0,2]],  #   Z,
            [1.0]           #   1.0]]
        ])
        # Transform the points to camera.
        transformed_3d_pos = np.dot(inv(extrinsic_mat.matrix), pos_vector)
        # Transform the points to 2D.
        pos2d = np.dot(rgb_intrinsic, transformed_3d_pos[:3])

        # Normalize the 2D points.
        loc_2d = Location(float(pos2d[0] / pos2d[2]),
                          float(pos2d[1] / pos2d[2]),
                          pos2d[2])
        # Add the points to the image.
        if loc_2d.z > 0: # If the point is in front of the camera.
            if (loc_2d.x >= 0 or loc_2d.y >= 0) and (loc_2d.x < image_width or loc_2d.y < image_height):
                coords.append((loc_2d.x, loc_2d.y, loc_2d.z))

    return coords

def map_ground_3D_transform_to_2D(location,
                                  vehicle_transform,
                                  rgb_transform,
                                  rgb_intrinsic,
                                  rgb_img_size):
    transform = vehicle_transform * rgb_transform
    extrinsic_mat = transform.matrix
    # The position in world 3D coordiantes.
    pos_vector = np.array([[location.x], [location.y], [location.z], [1.0]])
    transformed_3d_pos = np.dot(inv(extrinsic_mat), pos_vector)
    pos2d = np.dot(rgb_intrinsic, transformed_3d_pos[:3])
    (img_width, img_height) = rgb_img_size
    loc_2d = Location(img_width - pos2d[0] / pos2d[2],
                      img_height - pos2d[1] / pos2d[2],
                      pos2d[2])
    if (loc_2d.z > 0 and loc_2d.x >= 0 and loc_2d.x < img_width and
        loc_2d.y >= 0 and loc_2d.y < img_height):
        return (loc_2d.x, loc_2d.y, loc_2d.z)
    return None

def transform_traffic_light_bboxes(light, points):
    """ Transforms the bounding box specified in the points relative to the
    light.

    Args:
        light: TrafficLight object representing the light.
        points: An array of length 4 representing the 4 points of the
            rectangle.
    """

    def rotate(yaw, location):
        """ Rotate a given 3D vector around the Z-axis. """
        rotation_matrix = np.identity(3)
        rotation_matrix[0, 0] = np.cos(yaw)
        rotation_matrix[0, 1] = -np.sin(yaw)
        rotation_matrix[1, 0] = np.sin(yaw)
        rotation_matrix[1, 1] = np.cos(yaw)
        location_vector = np.array([[location.x], [location.y], [location.z]])
        transformed = np.dot(rotation_matrix, location_vector)
        return Location(x=transformed[0, 0],
                        y=transformed[1, 0],
                        z=transformed[2, 0])

    transformed_points = [
        rotate(np.radians(light.transform.rotation.yaw), point)
        for point in points
    ]
    base_relative_points = [
        light.transform.location + point for point in transformed_points
    ]
    return base_relative_points

def is_traffic_light_visible(camera_transform, tl, town_name=None):
    # We dot product the forward vectors (i.e., orientation).
    # Note: we have to rotate the traffic light forward vector
    # so that it's pointing out from the traffic light in the
    # opposite direction in which the ligth is beamed.
    prod = np.dot([tl.transform.orientation.y,
                   -tl.transform.orientation.x,
                   tl.transform.orientation.z],
                  [camera_transform.orientation.x,
                   camera_transform.orientation.y,
                   camera_transform.orientation.z])
    if town_name is None:
        return prod > -0.80
    else:
        if town_name == 'Town01' or town_name == 'Town02':
            return prod > 0.3
        return prod > -0.80

def get_traffic_lights_bbox_state(camera_transform, traffic_lights, town_name):
    bbox_state = []
    # Filter out the traffic lights that are not facing the vehicle.
    tls = []
    for tl in traffic_lights:
        if is_traffic_light_visible(camera_transform, tl, town_name):
            tls.append(tl)
    traffic_lights = tls
    # Carla has differing placemnts for different towns.
    if town_name == 'Town01' or town_name == 'Town02':
        points = [
            Location(x=-0.5, y=0.2, z=2),
            Location(x=0.1, y=0.2, z=2),
            Location(x=0.1, y=0.2, z=3),
            Location(x=-0.5, y=0.2, z=3)
        ]
        for light in traffic_lights:
            bbox_state.append(
                (transform_traffic_light_bboxes(light, points), light.state))
    elif town_name == 'Town03':
        for light in traffic_lights:
            if light.trigger_volume_extent.x > 2 or light.id in [
                    17, 18, 19, 22, 23, 24, 26, 28, 33
            ]:
                points = [
                    Location(x=-5.2, y=0.2, z=5.5),
                    Location(x=-4.8, y=0.2, z=5.5),
                    Location(x=-4.8, y=0.2, z=6.5),
                    Location(x=-5.2, y=0.2, z=6.5)
                ]
                bbox_state.append(
                    (transform_traffic_light_bboxes(light, points), light.state))
                right_points = [
                    point + Location(x=-3.0) for point in points
                ]
                bbox_state.append(
                    (transform_traffic_light_bboxes(light, right_points),
                     light.state))
                if light.id not in [2, 3, 4]:
                    left_points = [
                        point + Location(x=-6.5) for point in points
                    ]
                    bbox_state.append(
                        (transform_traffic_light_bboxes(light, left_points),
                         light.state))

            else:
                points = [
                    Location(x=-0.5, y=0.2, z=2),
                    Location(x=0.1, y=0.2, z=2),
                    Location(x=0.1, y=0.2, z=3),
                    Location(x=-0.5, y=0.2, z=3)
                ]
                bbox_state.append(
                    (transform_traffic_light_bboxes(light, points),
                     light.state))
    elif town_name == 'Town04':
        points = [
            Location(x=-5.2, y=0.2, z=5.5),
            Location(x=-4.8, y=0.2, z=5.5),
            Location(x=-4.8, y=0.2, z=6.5),
            Location(x=-5.2, y=0.2, z=6.5)
        ]
        middle_points = [  # Light in the middle of the pole.
            Location(x=-0.5, y=0.2, z=2.5),
            Location(x=0.1, y=0.2, z=2.5),
            Location(x=0.1, y=0.2, z=3.5),
            Location(x=-0.5, y=0.2, z=3.5)
        ]
        right_points = [point + Location(x=-3.0) for point in points]
        left_points = [point + Location(x=-5.5) for point in points]
        for light in traffic_lights:
            bbox_state.append(
                (transform_traffic_light_bboxes(light, points),
                 light.state))
            if light.trigger_volume_extent.x > 5:
                # This is a traffic light with 4 signs, we need to come up with
                # more bounding boxes.
                bbox_state.append(
                    (transform_traffic_light_bboxes(light, middle_points),
                     light.state))
                bbox_state.append(
                    (transform_traffic_light_bboxes(light, right_points),
                     light.state))
                bbox_state.append(
                    (transform_traffic_light_bboxes(light, left_points),
                     light.state))
    elif town_name == 'Town05':
        points = [
            Location(x=-5.2, y=0.2, z=5.5),
            Location(x=-4.8, y=0.2, z=5.5),
            Location(x=-4.8, y=0.2, z=6.5),
            Location(x=-5.2, y=0.2, z=6.5)
        ]
        middle_points = [  # Light in the middle of the pole.
            Location(x=-0.5, y=0.2, z=2.5),
            Location(x=0.1, y=0.2, z=2.5),
            Location(x=0.1, y=0.2, z=3.5),
            Location(x=-0.5, y=0.2, z=3.5)
        ]
        right_points = [point + Location(x=-3.0) for point in points]
        left_points = [point + Location(x=-5.5) for point in points]
        for light in traffic_lights:
            bbox_state.append(
                (transform_traffic_light_bboxes(light, points),
                 light.state))
            if light.id not in [2, 3]:
                # This is a traffic light with 4 signs, we need to come up with
                # more bounding boxes.
                bbox_state.append(
                    (transform_traffic_light_bboxes(light, middle_points),
                     light.state))
                bbox_state.append(
                    (transform_traffic_light_bboxes(light, right_points),
                     light.state))
                bbox_state.append(
                    (transform_traffic_light_bboxes(light, left_points),
                     light.state))
    else:
        raise ValueError('Could not find a town named {}'.format(town_name))
    return bbox_state

def get_traffic_light_det_objs(
        traffic_lights,
        camera_transform,
        depth_array,
        frame_width,
        frame_height,
        town_name,
        fov=90):
    """ Get the traffic lights that are within the camera frame.
    Note: This method should be used with Carla 0.9.*
    """
    # Get the location of the bounding boxes for these lights.
    bbox_state = get_traffic_lights_bbox_state(
        camera_transform, traffic_lights, town_name)

    # Convert the bounding boxes to a camera view.
    extrinsic_matrix = camera_transform.matrix
    intrinsic_matrix = create_intrinsic_matrix(frame_width, frame_height, fov)
    det_objs = []
    for box, tl_color in bbox_state:
        bounding_box = locations_3d_to_view(box, extrinsic_matrix, intrinsic_matrix)

        # Check if they are in front and visible.
        z_values = [loc.z > 0 for loc in bounding_box]
        if not any(z_values):
            continue

        # They are in the front, now find if they are visible in the view.
        x_min = x_max = int(bounding_box[0].x)
        y_min = y_max = int(bounding_box[0].y)
        for i in range(1, 4):
            x_min = min(x_min, int(bounding_box[i].x))
            x_max = max(x_max, int(bounding_box[i].x))
            y_min = min(y_min, int(bounding_box[i].y))
            y_max = max(y_max, int(bounding_box[i].y))
        x_bounds = (x_min >= 0 and x_min < frame_width and
                    x_max >= 0 and x_max < frame_width)
        y_bounds = (y_min >= 0 and y_min < frame_height
                    and y_max >= 0 and y_max < frame_height)
        if (x_bounds and y_bounds and x_max - x_min >= 3 and y_max - y_min > 6):
            middle_x = (x_min + x_max) / 2
            middle_y = (y_min + y_max) / 2
            depth = depth_array[middle_y][middle_x] * 1000
            # Ignore tl if it is occluded or far away.
            if abs(depth - bounding_box[0].z) > 2 or depth > 150:
                continue
            det_objs.append(
                DetectedObject(
                    (x_min, x_max, y_min, y_max), 1.0, tl_color.get_label()))
    return det_objs

def get_speed_limit_det_objs(
        speed_signs, vehicle_transform, camera_transform, depth_frame,
        frame_width, frame_height, fov, segmented_frame):
    """ Get the speed limit signs that are withing the camera frame.

    Args:
        speed_signs: List of speed limit signs in the world.
        vehicle_transform: Ego-vehicle transform in world coordinates.
        camera_transform: Camera transform in world coordinates.
        fov: Camera field of view.
        segmented_frame: Segmented frame.
    """
    # Compute the bounding boxes.
    traffic_signs_frame = get_traffic_sign_pixels(segmented_frame)
    bboxes = get_bounding_boxes_from_segmented(
        traffic_signs_frame, min_width=8, min_height=9)

    # Get the positions of the bounding box centers.
    x_mids = [(bbox[0] + bbox[1]) / 2 for bbox in bboxes]
    y_mids = [(bbox[2] + bbox[3]) / 2 for bbox in bboxes]
    pos_3d = batch_get_3d_world_position_with_depth_map(
        x_mids, y_mids, depth_frame, frame_width, frame_height,
        fov, camera_transform)
    pos_and_bboxes = zip(pos_3d, bboxes)
    ts_bboxes = _match_bboxes_with_speed_signs(
        vehicle_transform, pos_and_bboxes, speed_signs)

    det_objs = [DetectedSpeedLimit(bbox, limit, 1.0, 'speed limit')
                for (bbox, limit) in ts_bboxes]
    return det_objs

def _match_bboxes_with_speed_signs(vehicle_transform, pos_bboxes, speed_signs):
    result = []
    for pos, bbox in pos_bboxes:
        best_ts = None
        best_dist = 1000000
        for ts in speed_signs:
            dist = ((pos.x - ts.transform.location.x)**2 +
                    (pos.y - ts.transform.location.y)**2)
            if (dist < best_dist):
                best_dist = dist
                best_ts = ts
        if not best_ts:
            continue
        # Check that the sign is facing the ego vehicle.
        yaw_diff = (best_ts.transform.rotation.yaw -
                    vehicle_transform.rotation.yaw)
        if yaw_diff < 0:
            yaw_diff += 360
        elif yaw_diff >= 360:
            yaw_diff -= 360
        if best_dist < 5 ** 2 and yaw_diff > 30 and yaw_diff < 150:
            result.append((bbox, best_ts.limit))
    return result

def locations_3d_to_view(locations, extrinsic_matrix, intrinsic_matrix):
    """ Transforms 3D locations to 2D camera view."""
    world_points = np.ones((4, len(locations)))

    for i in range(len(locations)):
        world_points[0][i] = locations[i].x
        world_points[1][i] = locations[i].y
        world_points[2][i] = locations[i].z

    # Convert the points to the sensor coordinates.
    transformed_points = np.dot(
        np.linalg.inv(extrinsic_matrix), world_points)

    # Convert the points to an unreal space.
    unreal_points = np.concatenate([
        transformed_points[1, :],
        -transformed_points[2, :],
        transformed_points[0, :]
    ])

    # Convert to screen points.
    screen_points = np.dot(intrinsic_matrix, unreal_points)

    screen_points[0] /= screen_points[2]
    screen_points[1] /= screen_points[2]

    screen_locations = []
    for i in range(len(locations)):
        screen_locations.append(Location(float(screen_points[0, i]),
                                         float(screen_points[1, i]),
                                         float(screen_points[2, i])))
    return screen_locations

def _get_stop_markings_bbox(
        bbox3d,
        depth_frame,
        camera_transform,
        camera_intrinsic,
        frame_width,
        frame_height):
    """ Gets a 2D stop marking bouding box from a 3D bounding box."""
    # Offset trigger_volume by -0.85 so that the top plane is on the ground.
    ext = np.array([
        [bbox3d.extent.x, bbox3d.extent.y, bbox3d.extent.z - 0.85],
        [bbox3d.extent.x, -bbox3d.extent.y, bbox3d.extent.z - 0.85],
        [-bbox3d.extent.x, bbox3d.extent.y, bbox3d.extent.z - 0.85],
        [-bbox3d.extent.x, -bbox3d.extent.y, bbox3d.extent.z - 0.85],
    ])
    bbox = bbox3d.transform.transform_points(ext)
    coords = []
    for loc3d in bbox:
        loc = Location(loc3d[0, 0], loc3d[0, 1], loc3d[0, 2])
        loc_view = locations_3d_to_view(
            [loc],
            camera_transform.matrix,
            camera_intrinsic)[0]
        if (loc_view.z >= 0 and loc_view.x >= 0 and loc_view.y >= 0 and
            loc_view.x < frame_width and loc_view.y < frame_height):
            coords.append(loc_view)
    if len(coords) == 4:
        xmin = min(coords[0].x, coords[1].x, coords[2].x, coords[3].x)
        xmax = max(coords[0].x, coords[1].x, coords[2].x, coords[3].x)
        ymin = min(coords[0].y, coords[1].y, coords[2].y, coords[3].y)
        ymax = max(coords[0].y, coords[1].y, coords[2].y, coords[3].y)
        # Check if the bbox is not obstructed and if it's sufficiently
        # big for the text to be readable.
        if (ymax - ymin > 15 and
            have_same_depth(int(coords[0].x),
                            int(coords[0].y),
                            coords[0].z,
                            depth_frame,
                            0.4)):
            return (int(xmin), int(xmax), int(ymin), int(ymax))
    return None

def get_traffic_stop_det_objs(
        traffic_stops,
        camera_transform,
        depth_frame,
        frame_width,
        frame_height,
        fov):
    """ Get traffic stop lane markings that are withing the camera frame.

    Args:
        traffic_stops: List of traffic stop actors in the world.
        camera_transform: Camera transform in world coordinates.
        fov: Camera field of view.

    Returns:
        List of DetectedObjects.
    """
    det_objs = []
    bgr_intrinsic = create_intrinsic_matrix(frame_width, frame_height, fov)
    for transform, bbox in traffic_stops:
        bbox2d = _get_stop_markings_bbox(
            bbox, depth_frame, camera_transform, bgr_intrinsic,
            frame_width, frame_height)
        if bbox2d:
            det_objs.append(DetectedObject(bbox2d, 1.0, 'stop marking'))
    return det_objs


"""
Write a Python program that takes a file as the first argument
   and a search word as the second argument.
This script should print only those lines that have the search word
"""
import sys

def get_fname():
    if len(sys.argv)<2:
        fname=input("Enter the filename:")
    else:
        fname=sys.argv[1]
    return fname

def get_word():
    if len(sys.argv)<3:
        word=input("Enter the search word:")
    else:
        word=sys.argv[2]
    return word

def do_search(FH,word):
    word=word.lower()
    count=0
    line=list()
    content=FH.readline()
    while content!='':
        content=content.lower()
        parts=content.split()
        if word in parts:
            line.append(count+1)
        count+=1
        content=FH.readline()
    print('line numbers having',word,'in it are',line)

#main starts from here
if __name__=="__main__":
    file=get_fname()
    search_word=get_word()
    with open (file) as FH:
        do_search(FH,search_word)


#!/usr/bin/env python
# coding: utf-8

# ## Problem 2 - Plotting temperatures
#
# In this problem we will  plot monthly mean temperatures from the Helsinki-Vantaa airpot for the past 30 years.
#
# ## Input data
#
# File `data/helsinki-vantaa.csv` monthly average temperatures from Helsinki Vantaa airport. Column descriptions:
#
# ### Part 1
#
# Load the Helsinki temperature data (`data/helsinki-vantaa.csv`)
#
# - Read the data into variable called `data` using pandas
# - Parse dates from the column `'DATE'` and set the dates as index in the dataframe

# YOUR CODE HERE 1 to read the data into data and parse dates

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
fp = "data/helsinki-vantaa.csv"
data = pd.read_csv(
  fp, parse_dates = ['DATE'], index_col = ['DATE']
)

# This test print should print first five rows
print(data.head())

# Check the number of rows in the data frame
print(len(data))

# ### Part 2
#
# Select data for a 30 year period (January 1988 - December 2018)
#
# - Store the selection in a new variable `selection`

# YOUR CODE HERE 2

selection = data.loc['1988-01-01':'2018-12-31']
# Check that the data was read in correctly:
selection.head()

# Check how many rows of data you selected:
print("Number of rows:", len(selection))

# ### Part 3
#
# #### Part 3.1
#
# Create a line plot that displays the temperatures (`TEMP_C`) for yeach month in the 30 year time period:
#
# #### Part 3.2
#
# Save your figure as PNG file called `temp_line_plot.png`.
#

# YOUR CODE HERE 3

ax = selection['TEMP_C'].plot(
  figsize = (20, 6),
  color ='black',marker = '.',
  title = "Helsinki-Vantaa Airport",
  linestyle = 'solid',
  xlabel = 'Time', ylabel = 'Temperature[Celsius]'
)
plt.grid()

# Set output file name
outputfp = ""

# Save plot as image
# YOUR CODE HERE 4

outputfp = "temp_line_plot.png"
plt.savefig(outputfp)
import os

#Check that output file exists (also open the file and check that the plot looks ok!)
os.path.exists(outputfp)

# **REMINDER**: Don't forget to upload your figure and the modified notebook into your personal GitHub repository!
#
# ### Done!


# Exercicio 10
# Faça um programa que peça o nome de 2 produtos, a quantidade comprada de cada produto (inteiro) e o valor (float) de cada um.
#
# Mostre o nome a quantidade, preço por unidade e o total de cada produto.
class Produtos:
    def __init__ (self, nome, quantidade, valor):
        self.nome = nome
        self.quantidade = quantidade
        self.valor = valor

p = []
num = int(input('informe a quantidade de produtos diferentes que você deseja informar: '))
for i in range(0, num):
    nome_produto = input('Informe o nome do produto: ')
    quantidade_produto =  input('Informe a quantidade comprada do produto: ')
    valor_produto= input('Informe o valor do produto: ')
    print('\n')
    p.append(Produtos (nome_produto, quantidade_produto, valor_produto))

for i in p:
    print(f'''
    Nome: {i.nome}
    Quantidade: {i.quantidade}
    Valor Unitário: {i.valor}
    Valor Total: {int(i.quantidade)*float(i.valor)}
    ''')


import unittest

#Question 1.5 Write a function to check if two strings are one (or zero) edits away from each other.

def oneAway(stringOne, stringTwo):

    #zero away also counts.
    if stringOne == stringTwo:
        return True

    lengthOne = len(stringOne)
    lengthTwo = len(stringTwo)

    #either adding one character, or removing one character,
    #the two strings will be 1 or 0 characters off.
    if abs(lengthOne - lengthTwo) > 1:
        return False

    #count unique characters in string one and string two.
    stringOneUniqueCharacters = { x for x in stringOne }
    stringTwoUniqueCharacters = { x for x in stringTwo }

    #either one character difference or they are equal in length.
    return abs(len(stringOneUniqueCharacters) - len(stringTwoUniqueCharacters)) <= 1

class Test(unittest.TestCase):

    trueData = { 'pale':'ple', 'pales':'pale', 'kale':'bale', "aaab":"aaaz" }
    falseData = { 'hello':'smellos', 'pale':'bake12', 'kite':'right12' }

    def test_oneAway(self):
        for k,v in self.trueData.items():
            result = oneAway(k, v)
            self.assertTrue(result)

        for k,v in self.falseData.items():
            result = oneAway(k, v)
            self.assertFalse(result)

if __name__ == "__main__":
    unittest.main()


from tinydb import Query, TinyDB

db = TinyDB("test2.json", sort_keys=False, indent=4, separators=(",", ": "))
db.purge_table("opdep")
tbl = db.table("opdep")

tbl.insert(
    {
        "op": "gitbackup",
        "di": "git",
        "si": "scrdev",
        "dd": "git",
        "sd": "scrdev",
        "options": {"add": True, "commit": True},
    }
)

for row in tbl.all():
    print(row)

db.close()


# coding: utf-8
# Copyright (c) 2016, 2020, Oracle and/or its affiliates.  All rights reserved.
# This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license.

# These mappings are used by generated tests to look up operations that have been moved in code in the CLI.
MOVED_COMMANDS = {
    ('limits', 'limits', 'limit-definition', 'list'): ['limits', 'definition', 'list'],
    ('limits', 'limits', 'limit-value', 'list'): ['limits', 'value', 'list'],
    ('limits', 'limits', 'resource-availability', 'get'): ['limits', 'resource-availability', 'get'],
    ('limits', 'limits', 'service', 'list'): ['limits', 'service', 'list'],
    ('limits', 'quotas', 'quota', 'create'): ['limits', 'quota', 'create'],
    ('limits', 'quotas', 'quota', 'delete'): ['limits', 'quota', 'delete'],
    ('limits', 'quotas', 'quota', 'get'): ['limits', 'quota', 'get'],
    ('limits', 'quotas', 'quota', 'list'): ['limits', 'quota', 'list'],
    ('limits', 'quotas', 'quota', 'update'): ['limits', 'quota', 'update']
}


from pelican import signals
from datetime import datetime
import pytz

def hide_events(generator):

    for event in generator.context["filenames"].values():
        if hasattr(event, "event_start"):
            mytz = pytz.timezone(generator.settings["TIMEZONE"])
            dtnow = pytz.utc.localize(datetime.utcnow()).astimezone(mytz)
            delta = generator.settings.get("SHOW_FUTURE_EVENTS_IN_BLOG_UNTIL")
            if (delta and mytz.localize(event.event_start) - dtnow > delta) or\
                    mytz.localize(event.event_end) < dtnow:
                event.status = "draft"
                if event in generator.articles:
                    generator.articles.remove(event)
                if event not in generator.drafts:
                    generator.drafts.append(event)

def register():
    signals.article_generator_pretaxonomy.connect(hide_events)


"""
Manage per-step configurations.
"""

from typing import Any
from typing import Dict
from typing import List
from typing import Optional
from typing import Union
from typing.re import Pattern  # type: ignore # pylint: disable=import-error

import yaml

class Rule:  # pylint: disable=too-few-public-methods
    """
    A single configuration rule.
    """

    def __init__(self, path: str, index: int,
                 when: Dict[str, Any], then: Dict[str, Any]) -> None:
        """
        Create a configuration rule.
        """

        #: The path of the file this was loaded from.
        self.path = path

        #: The index of this rule in the file.
        self.index = index

        #: The conditions for when to apply the rule.
        self.when = when

        #: The parameter values provided by the rule.
        self.then = then

    _BUILTINS = ['step', 'context_contains']

    def is_match(self, context: Dict[str, Any]) -> bool:
        """
        Whether the rule is a match for a step invocation.
        """
        return self._match_builtins(context) \
            and self._verify_known_parameters(context) \
            and self._match_other_conditions(context)

    def _match_builtins(self, context: Dict[str, Any]) -> bool:
        for key in Rule._BUILTINS:
            if key in self.when and not self._key_is_match(key, self.when[key], context):
                return False
        return True

    def _verify_known_parameters(self, context: Dict[str, Any]) -> bool:
        for key in self.when:
            if key in Rule._BUILTINS:
                continue
            if key.startswith('lambda '):
                for name in key[7:].split(','):
                    self._parameter_name(name.strip(), context)
            else:
                self._parameter_name(key, context)
        return True

    def _match_other_conditions(self, context: Dict[str, Any]) -> bool:
        for key, condition in self.when.items():
            if key not in Rule._BUILTINS and not self._key_is_match(key, condition, context):
                return False
        return True

    def _key_is_match(self, key: str, condition: Any, context: Dict[str, Any]) -> bool:
        if key == 'context_contains':
            return Rule._match_context(condition, context)

        if key.startswith('lambda '):
            return self._match_lambda(key[7:],  # pylint: disable=protected-access
                                      condition, context)

        parameter_name = self._parameter_name(key, context)
        return parameter_name is not None and Rule._match_value(context[parameter_name], condition)

    @staticmethod
    def _match_context(required_parameters: Union[str, List[str]], context: Dict[str, Any]) -> bool:
        if isinstance(required_parameters, str):
            required_parameters = [required_parameters]
        for parameter in required_parameters:
            if parameter not in context:
                return False
        return True

    def _match_lambda(self, arguments: str, condition: str, context: Dict[str, Any]) -> bool:
        parameter_values: Dict[str, Any] = {}
        for argument in arguments.split(','):
            parameter_name = self._parameter_name(argument.strip(), context)
            if parameter_name is None:
                return False
            parameter_values[parameter_name] = context[parameter_name]
        evaluator = eval('lambda %s: %s'  # pylint: disable=eval-used
                         % (arguments.replace('?', ''), condition))
        return evaluator(**parameter_values)

    def _parameter_name(self, parameter_name: str, context: Dict[str, Any]) -> Optional[str]:
        is_optional = parameter_name.endswith('?')
        if is_optional:
            parameter_name = parameter_name[:-1]

        if parameter_name in context:
            return parameter_name

        if not is_optional:
            raise RuntimeError('Unknown parameter: %s '
                               'for the step: %s '
                               'in the rule: %s '
                               'of the file: %s'
                               % (parameter_name, context['step'], self.index, self.path))
        return None

    @staticmethod
    def _match_value(value: Any, condition: Any) -> bool:
        if isinstance(condition, list):
            for alternative in condition:
                if Rule._match_value(value, alternative):
                    return True
            return False

        if isinstance(condition, Pattern):
            return bool(condition.fullmatch(value))

        return value == condition

    @staticmethod
    def _load_rule(path: str, index: int, rule: Any) -> 'Rule':
        if not isinstance(rule, dict):
            raise RuntimeError('Non-mapping rule: %s '
                               'in the file: %s'
                               % (index, path))

        data = {key: Rule._load_value(path, index, rule, key)  # pylint: disable=protected-access
                for key in ['when', 'then']}

        for key in rule:
            raise RuntimeError('Unknown key: %s '
                               'in the rule: %s '
                               'in the file: %s'
                               % (key, index, path))

        return Rule(path, index, **data)

    @staticmethod
    def _load_value(path: str, index: int, rule: Dict[str, Any], key: str) -> Dict[str, Any]:
        if key not in rule:
            raise RuntimeError('Missing key: %s '
                               'in the rule: %s '
                               'in the file: %s'
                               % (key, index, path))

        value = rule[key]
        del rule[key]

        if value is None:
            value = {}

        if not isinstance(value, dict):
            raise RuntimeError('Value is not a mapping '
                               'in the key: %s '
                               'in the rule: %s '
                               'in the file: %s'
                               % (key, index, path))

        for sub_key in value:
            if not isinstance(sub_key, str):
                raise RuntimeError('Sub-key is not a string: %s '
                                   'in the key: %s '
                                   'in the rule: %s '
                                   'in the file: %s'
                                   % (sub_key, key, index, path))

        return value

    @staticmethod
    def load(path: str) -> List['Rule']:
        """
        Load configuration rules from a YAML file.
        """
        with open(path, 'r') as file:
            data = yaml.full_load(file.read())

        if data is None:
            data = []

        if not isinstance(data, list):
            raise RuntimeError('The file: %s '
                               'does not contain a top-level sequence'
                               % path)

        return ([Rule._load_rule(path, index, rule)  # pylint: disable=protected-access
                 for index, rule in enumerate(data)])

class Config:
    """
    Global configuration class.
    """

    #: All the known configuration rules (including for per-rule parameters).
    rules: List[Rule]

    @staticmethod
    def reset() -> None:
        """
        Reset all the current state, for tests.
        """
        Config.rules = []

    @staticmethod
    def values_for_context(context: Dict[str, Any]) -> Dict[str, Any]:
        """
        Return the configuration values for a specific step invocation.
        """
        values: Dict[str, Any] = {}
        for rule in Config.rules:
            if rule.is_match(context):
                for name, value in rule.then.items():
                    if name.endswith('?'):
                        other_name = name[:-1]
                    else:
                        other_name = name + '?'
                    if other_name in values:
                        del values[other_name]
                    values[name] = value
        return values

    @staticmethod
    def load(path: str) -> None:
        """
        Load a YAML configuration file into :py:attr:`dynamake.config.Config.rules`.

        The rules from the loaded files will override any values specified by previously loaded
        rules. In general, the last matching rule wins.

        The configuration YAML file should be empty, or contain a top-level sequence.
        Each entry must be a mapping with two keys: ``when`` and ``then``.
        The ``then`` value should be a mapping from parameter names to their values.
        The ``when`` value should be a mapping of conditions.

        The condition key can be either a parameter name, or ``lambda parameter_name, ...``.
        If the key starts with ``lambda``, the value should be a string containing a
        python boolean expression, which will be evaluated using the specified parameters.

        Otherwise, the condition value should be one of:

        * The exact value of the parameter.

        * A ``!r regexp-pattern`` or a ``!g glob-pattern`` to match the (string) parameter value
          against. While general regular expressions are more powerful, glob patterns are simpler
          and more familiar to most people, as they are used by the shell.

        * A list of alternative values or patterns to match the parameter value against.

        A rule is applicable to a step invocation if all the conditions in its ``when`` mapping
        match the parameters used in the invocation.

        Two additional parameters are also added for the purpose of the matching: ``step`` contains
        the step function name, and the call ``stack`` contains the path of step names
        ``/top/.../step``. This uses ``/`` to separate the step names to allow matching it against a
        glob pattern, as if it was a file path. Conditions on these parameters are evaluated first,
        and if they reject the invocation, no other condition is evaluated.

        It is normally an error for the rest of the conditions to specify a parameter which is not
        one of the arguments of the invoked step function. However, if the condition key ends with
        ``?``, then the condition will silently reject the step instead. This allows specifying
        rules that provide defaults without worrying about applying the rule to the exact list of
        steps that use it.

        Default rules are very useful when used responsibly. However, they have two important
        downsides:

        * Modifying the values in such default rules will trigger the re-computation of all the
          action steps that match them, even if they do not actually depend on the provided values.

        * Default rules silently ignore typos in parameter names.

        It is pretty annoying to modify the configuration file, to adjust some parameter, re-execute
        the full computation, wait a few hours, and then discover this was wasted effort because you
        wrote ``foo: 1`` instead of ``foos: 1`` in the default rule.

        It is therefore recommended to minimize the use of default rules, and when they are used, to
        restrict them to match as few steps as possible, typically by matching against the steps
        call ``stack``.
        """
        Config.rules += Rule.load(path)

Config.reset()


from bnv_site.secret_settings import email_name
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render, Http404
from django.views import generic
from .forms import ApplicationForm
from .models import Application_form_model
from django.core.mail import send_mail, EmailMessage
from django.core.exceptions import ValidationError
from django.core.files.storage import FileSystemStorage

def app_form(request):
    if request.method =="POST":
        formset = ApplicationForm(request.POST, request.FILES)
        if formset.is_valid():
            formset.save()

            save_data = Application_form_model(
                user_name=formset.cleaned_data['user_name'],
                phone_number=formset.cleaned_data['phone_number'],
                user_email=formset.cleaned_data['user_email'],
                user_question=formset.cleaned_data['user_question'],
                files=formset.cleaned_data['files']
            )
            text_of_email = save_data.user_name + '\n' + save_data.user_email + \
                '\n' + save_data.phone_number + '\n' + save_data.user_question

            msg = EmailMessage(
                'Питання з сайту',
                text_of_email,
                f'{email_name()}',
                [f'{email_name()}'],
            )
            if save_data.files != None:
                msg.attach_file(f'media/file_to_question/{save_data.files}')
            msg.send()
            return HttpResponseRedirect('')
    else:
        formset = ApplicationForm

    return render(
        request,
        'application_form/application_form.html',
        {
            'formset': formset
        }
    )


#!/usr/bin/env python3

# https://leetcode-cn.com/problems/pascals-triangle-ii
# 给定一个非负索引 k，其中 k ≤ 33，返回杨辉三角的第 k 行。
# 在杨辉三角中，每个数是它左上方和右上方的数的和。
#
# 示例:
# 输入: 3
# 输出: [1,3,3,1]
#
# 进阶：
# 你可以优化你的算法到 O(k) 空间复杂度吗？

class Solution:
    def getRow(self, rowIndex: int) -> [int]:
        result = [1] * (rowIndex + 1)
        for i in range(rowIndex):
            for j in range(i, 0, -1):
                result[j] = result[j] + result[j - 1]
        return result

print(Solution().getRow(2))  # [1,3,3,1]


import os
import cv2
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from tqdm.notebook import tqdm

try:
    from pybalu.feature_transformation import pca
    from pybalu.feature_selection import sfs
except:
    print('Can\'t import pybalu, some functions wont work')

N_PEOPLE_A = 16
N_PEOPLE_B = 40
N_PEOPLE_C = 100
N_PEOPLE_D = 166

BASE_FOLDER = 'FaceMask166'
PINERA_IMAGE = 'FM000020_03'

def load_image(image_name, gray=False, crop=False, flip=False, base_folder=BASE_FOLDER):
    """Carga una imagen con open-cv."""
    if not image_name.endswith('.jpg'):
        image_name = f'{image_name}.jpg'

    image_path = os.path.join(base_folder, image_name)
    image = cv2.imread(image_path, cv2.IMREAD_UNCHANGED)

    if image is None:
        raise Exception(f'Cant load image: {image_name}')

    # open-cv loads as BGR
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

    if gray:
        image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

    if crop:
        image = image[:128, :]

    if flip:
        image = cv2.flip(image, 1) # Flip around y-axis

    return image

def load_dataset(n_images, gray=True, crop=True, aug_flip=False):
    """Carga un dataset de las primeras N imagenes.

    Returns:
        dataset lista de: [image_cropped, image_name, i_image (label), j (image_number)]
    """
    dataset = []
    image_base_name = 'F'
    for i_image in range(1, n_images+1):
        base_name = f'FM{i_image:06d}'

        for j in range(1, 6+1):
            # Load image
            image_name = f'{base_name}_{j:02d}'
            image = load_image(image_name, gray=gray, crop=crop)

            dataset.append((image, image_name, i_image, j))

            is_training = j <= 3
            if is_training and aug_flip:
                image_flipped = load_image(image_name, gray=gray, crop=crop, flip=True)
                dataset.append((image_flipped, f'{image_name}_flipped', i_image, j))

    return dataset

def create_df(dataset, merge=None):
    """Crea un dataframe a partir de un dataset.

    Args:
        dataset -- formato que retorna `load_dataset()`
    """
    data = [sample[2:] for sample in dataset]
    image_names = [sample[1] for sample in dataset]
    df = pd.DataFrame(data, index=image_names, columns=['label', 'image_number'])

    if merge is not None:
        df = df.merge(merge, right_index=True, left_index=True)

    return df

def filter_df_by_dataset(df, dataset_name, include_flipped=True):
    if dataset_name == 'A':
        n_people = N_PEOPLE_A
    elif dataset_name == 'B':
        n_people = N_PEOPLE_B
    elif dataset_name == 'C':
        n_people = N_PEOPLE_C
    elif dataset_name == 'D':
        n_people = N_PEOPLE_D
    else:
        raise Exception(f'Unknown dataset: {dataset_name}')

    image_basenames = [f'FM{i_image:06d}' for i_image in range(1, n_people+1)]

    images_from_dataset = set([
        image_name
        for image_name in list(df.index) if any(
            image_name.startswith(basename)
            for basename in image_basenames
        )
    ])

    if not include_flipped:
        images_from_dataset = [image_name for image_name in images_from_dataset if 'flipped' not in image_name]

    return df.loc[df.index.isin(images_from_dataset)]

def calculate_features(dataset, feature_fn, max_images=None, show=False, **kwargs):
    """Calcula features para imagenes de un dataset.

    Nota: esta funcion podria ser reutilizada en calculate_features_df()
    """
    print(f'Calculating features')
    features = []

    if max_images is None:
        data = dataset
    else:
        data = dataset[:max_images]

    # Cargar imagenes y calcular vectores de features
    for sample in tqdm(data, disable=not show):
        image = sample[0]

        image_features = feature_fn(image, **kwargs)
        features.append(image_features)

    return features

def features_to_df(dataset, features, feature_name):
    """Transforma un array de features a un DataFrame.

    Nota: esta funcion podria ser reutilizada en calculate_feature_df()

    Args:
        dataset -- formato que retorna `load_dataset()`
        features -- np.array de shape n_images, n_features
        feature_name -- string que se usa como nombre base.

    Returns:
        dataframe
    """
    image_names = [sample[1] for sample in dataset]

    n_images, n_feats = features.shape

    columns = [f'{feature_name}_{idx}' for idx in range(n_feats)]

    feature_df = pd.DataFrame(features, index=image_names, columns=columns)

    return feature_df

def calculate_feature_df(dataset, feature_fn, feature_name, max_images=None, show=False,
                         fix_len_mode='pad',
                         **kwargs):
    """Calcula un feature con `feature_fn()` para todas las imagenes de un dataset, retorna un DF.

    Args:
        dataset -- formato que retorna `load_dataset()`
        feature_fn -- funcion de firma `features = feature_fn(image, **kwargs)`
        feature_name -- string para usar como nombre base del feature
        **kwargs -- entregados a `feature_fn()`
    """
    print(f'Calculating {feature_name}')
    image_names = []
    features = []

    if max_images is None:
        data = dataset
    else:
        data = dataset[:max_images]

    # Cargar imagenes y calcular vectores de features
    for sample in tqdm(data, disable=not show):
        image = sample[0]
        image_names.append(sample[1])

        image_features = feature_fn(image, **kwargs)
        features.append(image_features)

    # Pass to numpy
    features = np.array(features)

    # DEPRECATED: see new functions for SIFT and SURF features
    #     if len(features.shape) == 1 and len(features[0].shape) == 1:
    #         # HACK: assume that in this case the image_features have different lengths, so pad to the greatest
    #         if fix_len_mode == 'pad':
    #             max_len = max(len(f) for f in features)
    #             features = np.array([
    #                 np.pad(f, pad_width=(0, max_len-len(f)), mode='constant', constant_values=0) for f in features
    #             ])
    #         elif fix_len_mode == 'crop':
    #             min_len = min(len(f) for f in features)
    #             features = np.array([f[:min_len] for f in features])

    if len(features.shape) != 2:
        print('Cannot parse to DF')
        # HACK: for cases where image_features have different lengths
        return features

    n_images, n_feats = features.shape

    # Nombres de los features, e.g. 'hog_0', 'hog_1', etc
    columns = [f'{feature_name}_{idx}' for idx in range(n_feats)]

    # Crear DataFrame, el index son nombres de las imagenes
    feature_df = pd.DataFrame(features, index=image_names, columns=columns)

    # Retornar DataFrame con features calculados
    return feature_df

def calculate_feature_multiple_df(dataset, feature_fn, configs, basename='', **kwargs):
    """Calculate multiple configurations of a feature."""
    df = None

    for name, params in configs.items():
        feature_name = f'{basename}-{name}' if basename else name

        feature_df = calculate_feature_df(dataset, feature_fn, feature_name, **kwargs, **params)

        if df is None:
            df = feature_df
        else:
            df = df.merge(feature_df, right_index=True, left_index=True)

    return df

def plot_cm(cm, title='', labels=None, colorbar=False, setsize=True):
    """Plotear una matriz de confusion.

    Args:
        cm -- matriz de n_classes x n_classes
        title -- string para el titulo
        labels -- lista de nombres de n_classes
        colorbar -- si incluir la barra de color o no
    """
    n_labels = len(cm)
    ticks = np.arange(n_labels)

    if labels is None:
        labels = ticks + 1

    if setsize:
        n_classes = len(labels)
        plt.figure(figsize=(0.375 * n_classes, 0.25 * n_classes))

    plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Blues)
    if colorbar:
        plt.colorbar()

    plt.xticks(ticks, labels)
    plt.yticks(ticks, labels)
    plt.title(title)
    plt.xlabel('Predicción')
    plt.ylabel('Real')

    thresh = cm.max() / 2
    for row in range(n_labels):
        for col in range(n_labels):
            value = cm[row, col]
            color = 'white' if value > thresh else 'black'

            value_str = f'{int(value):d}'

            plt.text(col, row, value_str, ha='center', va='center', color=color)
    plt.show()

def normalize_df(df, keep_nonorm=True, ignore=['label', 'image_number']):
    """Normaliza los datos de un DataFrame.

    Args:
        df -- DataFrame con shape (n_imagenes, n_features)
        keep_nonorm -- Si es True, devuelve el dataframe incluyendo las columnas
            normalizadas y no normalizadas
        ignore -- set de columnas que NO son features
    Returns:
        DataFrame con columnas de features normalizadas
    """
    # Filter to normalize only with train data
    df_train = df.loc[df['image_number'] < 4]

    # Use only features
    feature_columns = [col for col in df.columns if col not in ignore and '_nonorm' not in col]

    # Fit normalization with training
    normalization = MinMaxScaler(feature_range=(0, 1))
    normalization.fit(df_train[feature_columns])

    # Normalize whole dataset
    data_norm = normalization.transform(df[feature_columns])
    df_norm = pd.DataFrame(data_norm, index=df.index, columns=feature_columns)

    # Keep both columns (normalized and not normalized)
    if keep_nonorm:
        # Rename no-normalized to '<col>_nonorm'
        rename = {col: f'{col}_nonorm' for col in feature_columns}
        df_nonorm = df.rename(columns=rename, inplace=False)

        # Merge norm and nonorm
        return df_nonorm.merge(df_norm, how='inner', right_index=True, left_index=True)

    # Add the ignored columns from the original dataset
    return df_norm.merge(df[ignore], how='inner', right_index=True, left_index=True)

def get_cols_startwith(df, name, suffix=None, color=False, norm=True):
    """Dado un DF retorna las columnas que empiezan con cierto nombre."""
    base_name = name
    if color:
        base_name += '-color'
    if suffix:
        base_name += f'-{suffix}'

    if norm:
        comply_norm = lambda col: not col.endswith('_nonorm')
    else:
        comply_norm = lambda col: col.endswith('_nonorm')

    return [col for col in df.columns if col.startswith(base_name) and compy_norm(col)]

def PCA(x_train, x_test, x_val, n_components):
    """
    Realiza la transformación PCA de los datos a tan solo 'n_components' características.
    n_components:   número de características.
    """
    x_train, _, A, Xm, _ = pca(x_train, n_components=n_components)
    x_test = np.matmul(x_test - Xm, A)
    x_val = np.matmul(x_val - Xm, A)
    return x_train, x_test, x_val

def SFS(x_train, y_train, x_test, x_val, n_features, method="fisher", show=False):
    """
    Realiza la selección de 'n_features' características secuencialmente.
    n_features:     número de características
    method:         método a ocupar en la selección
    show:           mostrar el progreso de la selección.
    """
    s_sfs = sfs(x_train, y_train, n_features=n_features, method="fisher", show=show)
    x_train = x_train[:, s_sfs]
    x_test = x_test[:, s_sfs]
    x_val = x_val[:, s_sfs]
    return x_train, x_test, x_val

##### SIFT ######
# Pickle sift stuff

import pickle

def pickle_keypoint(point):
    return (point.pt, point.size, point.angle, point.response, point.octave, point.class_id)

def unpickle_keypoint(t):
    (x, y), size, angle, response, octave, class_id = t
    return cv2.KeyPoint(x=x, y=y, _size=size, _angle=angle, _response=response, _octave=octave,
                        _class_id=class_id)

def pickle_sift(l, filepath):
    obj = [([pickle_keypoint(p) for p in keypoints], d) for keypoints, d in l]
    with open(filepath, 'wb') as f:
        pickle.dump(obj, f)

def unpickle_sift(filepath):
    with open(filepath, 'rb') as f:
        obj = pickle.load(f)

    l = [([unpickle_keypoint(p) for p in keypoints], d) for keypoints, d in obj]
    return l

def save_list_txt(l, filepath):
    with open(filepath, 'w') as f:
        for item in l:
            f.write(f'{item}\n')
    print(f'Saved to {filepath}')

def load_list_txt(filepath):
    with open(filepath, 'r') as f:
        return [l.strip() for l in f.readlines()]


from lofirrtlParser import lofirrtlParser
from antlr4 import Token, Lexer
from antlr4.Token import CommonToken

NEWLINE = lofirrtlParser.NEWLINE
INDENT = lofirrtlParser.INDENT
DEDENT = lofirrtlParser.DEDENT

class Denter:
    def __init__(self, lexer):
        self.lexer = lexer
        self.dents_buffer = []
        self.indentations = []
        self.reached_eof = False

    def apply_eof(self, t):
        if len(self.indentations) is 0:
            r = self.createToken(NEWLINE, t)
        else:
            r = self.unwindto(0, t)
        self.dents_buffer.append(t)
        self.reached_eof = True
        return r

    def next_token(self):
        self.init_if_first()
        if len(self.dents_buffer) is 0:
            t = self.pull_token()
        else:
            t = self.dents_buffer.pop(0)
        if self.reached_eof:
            return t
        if t.type is NEWLINE:
            r = self.handle_newline(t)
        elif t.type is Token.EOF:
            r = self.apply_eof(t)
        else:
            r = t
        return r

    def pull_token(self):
        return Lexer.nextToken(self.lexer)

    def init_if_first(self):
        # first invocation
        if len(self.indentations) is 0:
            self.indentations.append(0)

            # find first non-new line
            while True:
                first_real_token = self.pull_token()
                if first_real_token.type is not NEWLINE:
                    break

            if first_real_token.column > 0:
                self.indentations.append(first_real_token.column)
                self.dents_buffer.append(createToken(INDENT, first_real_token))
            self.dents_buffer.append(first_real_token)

    def handle_newline(self, t):
        nextnext = self.pull_token()
        while nextnext.type is NEWLINE:
            t = nextnext
            nextnext = self.pull_token()
        if nextnext.type is Token.EOF:
            return self.apply_eof(nextnext)

        nltext = t.text
        indent = len(nltext) - 1
        if indent > 0 and nltext[0] is '/r':
            indent -= 1
        previndent = self.indentations[-1]
        if indent is previndent:
            r = t # just a newline
        elif indent > previndent:
            r = self.createToken(INDENT, t)
            self.indentations.append(indent)
        else:
            r = self.unwindto(indent, t)
        self.dents_buffer.append(nextnext)

        return r

    def createToken(self, toktype, copyfrom):
        toktype_to_typestr = {NEWLINE: '<NEWLINE>',
                          INDENT:  '<INDENT>',
                          DEDENT:  '<DEDENT>'}
        typestr = toktype_to_typestr[toktype]
        r = copyfrom.clone()
        r.type = toktype
        return r

    def unwindto(self, targetindent, copyfrom):
        assert len(self.dents_buffer) is 0
        self.dents_buffer.append(self.createToken(NEWLINE, copyfrom))
        # To make things easier, we'll queue up ALL of the dedents, and then pop off the first one.
        # For example, here's how some text is analyzed:
        #
        #  Text          :  Indentation  :  Action         : Indents Deque
        #  [ baseline ]  :  0            :  nothing        : [0]
        #  [   foo    ]  :  2            :  INDENT         : [0, 2]
        #  [    bar   ]  :  3            :  INDENT         : [0, 2, 3]
        #  [ baz      ]  :  0            :  DEDENT x2      : [0]
        while True:
            previndent = self.indentations.pop()
            if previndent is targetindent:
                break
            if targetindent > previndent:
                self.indentations.append(previndent)
                self.dents_buffer.append(self.createToken(INDENT, copyfrom))
                break
            self.dents_buffer.append(self.createToken(DEDENT, copyfrom))
        self.indentations.append(targetindent)
        return self.dents_buffer.pop(0)


import collections
import sys
from collections import Counter, defaultdict
import matplotlib.pyplot as plt; plt.rcdefaults()
import numpy as np
import matplotlib.pyplot as plt

eng_freq_dict = {
    'a': 0.08167, 'b': 0.01492, 'c': 0.02782, 'd': 0.04253, 'e': 0.12702,
    'f': 0.02228, 'g': 0.02015, 'h': 0.06094, 'i': 0.06966, 'j': 0.00153,
    'k': 0.00772, 'l': 0.04025, 'm': 0.02506, 'n': 0.06749, 'o': 0.07507,
    'p': 0.01929, 'q': 0.00095, 'r': 0.05987, 's': 0.06327, 't': 0.09056,
    'u': 0.02758, 'v': 0.00978, 'w': 0.02360, 'x': 0.00150, 'y': 0.01974,
    'z': 0.00074
}

rus_freq_dict = {
    'о': 0.10983, 'е': 0.08483, 'а': 0.07998, 'и': 0.07367, 'н': 0.0670,
    'т': 0.06318, 'с': 0.05473, 'р': 0.04746, 'в': 0.04533, 'л': 0.04343,
    'к': 0.03486, 'м': 0.03203, 'д': 0.02977, 'п': 0.02804, 'у': 0.02615,
    'я': 0.02001, 'ы': 0.01898, 'ь': 0.01735, 'г': 0.01687, 'з': 0.01641,
    'б': 0.01592, 'ч': 0.01450, 'й': 0.01208, 'х': 0.00966, 'ж': 0.00940,
    'ш': 0.00718, 'ю': 0.00639, 'ц': 0.00486, 'щ': 0.00361, 'э': 0.00331,
    'ф': 0.00267, 'ъ': 0.00037,
}

eng = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
rus = ['а', 'б', 'в', 'г', 'д', 'е', 'ж', 'з', 'и', 'й', 'к', 'л', 'м', 'н', 'о', 'п', 'р', 'с', 'т', 'у', 'ф', 'х', 'ц', 'ч', 'ш', 'щ', 'ъ', 'ы', 'ь', 'э', 'ю', 'я']

def get_IC(text_part):
    global rus
    lang_list = rus

    text = "".join([x for x in text_part.split() if x.isalpha()])
    if len(text) > 1:
        N = len(text)
    else:
        return
    freqs = collections.Counter(text)
    freqsum = 0.0
    for letter in lang_list:
        freqsum += freqs[letter] * (freqs[letter] - 1)

    IC = freqsum / (N * (N - 1))
    return IC

def get_subseq(i, text):
    sub_seq = defaultdict(list)
    for j in range(0, len(text), i):
        for c in range(i):
            try:
                sub_seq[c].append(text[j + c])
            except IndexError:
                continue

    return sub_seq

def get_key_length(text):
    avrg_ics = dict()
    for i in range(1, 30):
        ic = 0.0
        seqs = get_subseq(i, text)
        for seq in seqs.values():
            seq_str = "".join(seq)
            val = get_IC(seq_str) if get_IC(seq_str) else 0.0
            ic += val
        avrg_ics[i] = ic / i

    sorted_ic = [(k, avrg_ics[k]) for k in sorted(avrg_ics, key=avrg_ics.get, reverse=True)]
    print("\nIC: ", sorted_ic[:6], '\n')

    plt.bar([x[0] for x in sorted_ic], [x[1] for x in sorted_ic], align='center', alpha=1)
    plt.ylabel('IC')
    plt.title('IC for different key length while decrypting')
    plt.show()

    return sorted_ic[0]

def get_key(key_len, text):
    global rus
    global rus_freq_dict
    lang_freq = rus_freq_dict

    subseqs = get_subseq(key_len, text)
    subseqs_counter = list()
    for seq in subseqs.values():
        counter = Counter(seq)
        subseqs_counter.append({key: counter[key] for key in lang_freq.keys()})

    key = find_key(subseqs_counter)
    return key

def find_key(freq_dicts):
    global rus
    global rus_freq_dict
    lang_list = rus
    lang_freq_dict = rus_freq_dict

    lang_list_len = len(lang_list)
    res = ""
    for freq_dict in freq_dicts:
        temp_max = 0
        for i in range(lang_list_len):
            temp_sum = 0
            for char in lang_freq_dict:
                try:
                    t_plus_g = lang_list[(lang_list.index(char) + i) % lang_list_len]
                    temp_sum += lang_freq_dict[char] * freq_dict[t_plus_g]

                except Exception as e:
                    print(e)
                    break

            if temp_sum > temp_max:
                temp_max = temp_sum
                letter = lang_list[i]

        res += letter
    return res

def main(in_file):
    with open(in_file, "r") as f:
        text = "".join([x.lower().strip() for x in f.read().split() if x.isalpha()])
        key_len = get_key_length(text)[0]
        key = get_key(key_len, text)
        print("Ключ: ", key)

if __name__ == "__main__":
    in_file = sys.argv[1]

    main(in_file)


'''
Jabari Dash

Write a program that reads in 10 integers, appending each onto a list.
It then displays the list from beginning to end using a loop, accessing
each element via its index. Next, it displays the list from end to beginning
using a loop, accessing each element via a negative index. Finally, it
displays the list from end to beginning, accessing the elements of the
list without using indices. Hint: Use the pop() method.
'''

'''
python problem05.py assets/problem05/in.txt

client149-99:hw1 jod$ cat assets/problem05/in.txt
1
2
3
4
5
6
7
8
9
10
client149-99:hw1 jod$ python problem05.py assets/problem05/in.txt
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
'''

import sys

# Read in command line args
file_i = sys.argv[1]

# Read in lines stripping off newline characters
lines = [line.rstrip('\n') for line in open(file_i)]

# Number of lines in lines
n = len(lines)

# String to print at end
s = ''

# Beginning to end using indexing
for i in range(0, n):
    s += lines[i] + ' '

s += '\n'

# End to beginning using indexing
for i in range(1, len(lines) + 1):
    s += lines[-i] + ' '

s += '\n'

# End to beginning using pop()
while lines:
    s += lines.pop() + ' '

# Display final result
print(s)


import torch
import itertools
from .base_model import BaseModel
from . import networks2 as networks
import sys, cv2, os, pickle
import torch.nn.functional as F
import numpy as np
sys.path.append("..")
from util import util

class TbrecLlocPreModel(BaseModel):
    """
    """
    @staticmethod
    def modify_commandline_options(parser, is_train=True):
        parser.add_argument('--rm_layers', type=str, default='', help='remove layers when load the pretrained model')
        return parser

    def __init__(self, opt):

        self.opt = opt

        BaseModel.__init__(self, self.opt)

        self.loss_names = ['cls_row', 'cls_col']

        self.model_names = ['Backbone','CellLlocPre']

        init_mode = False
        if self.isTrain:
            init_mode = not self.opt.continue_train

        self.netBackbone    = networks.resnet_fpn_backbone('resnet50', init_mode, self.opt.distributed, self.opt.gpu)
        #self.netCellBboxSeg = networks.cell_seg_head(self.opt.distributed, self.opt.gpu)
        self.netCellLlocPre = networks.cell_loc_head(self.opt.num_rows, self.opt.num_cols, self.opt.load_height, \
                                                    self.opt.load_width, self.opt.alpha, self.device, self.opt.distributed, self.opt.gpu)

        if self.isTrain:
            #self.criterionBbox = torch.nn.CrossEntropyLoss(weight = torch.FloatTensor([0.1,0.1,1.0])).to(self.device)
            #self.criterion_Lloc_cols = torch.nn.CrossEntropyLoss().to(self.device)
            #self.criterion_Lloc_rows = torch.nn.CrossEntropyLoss().to(self.device)
            gamma_dict = pickle.load(open(os.path.join(self.opt.dataroot,'gamma.pkl'), 'rb'))
            self.criterion_Lloc_cols = networks.OrdinalRegressionLoss(self.opt.num_cols, gamma_dict['col_gamma'])
            self.criterion_Lloc_rows = networks.OrdinalRegressionLoss(self.opt.num_rows, gamma_dict['row_gamma'])
            self.optimizer = torch.optim.Adam(itertools.chain(self.netBackbone.parameters(),\
                            self.netCellLlocPre.parameters()), lr=self.opt.lr, betas=(opt.beta1, 0.999))
            self.optimizers.extend([self.optimizer])

    def set_input(self, input):
        self.table_names = input['img_names']
        self.table_images = input['tb_imgs'].to(self.device)
        self.cell_gt_boxes = list(input['cell_boxes'])
        self.cell_pred_boxes = list(input['pred_boxes'])
        #self.seg_row_label = input['seg_row_label'].to(self.device)
        #self.seg_col_label = input['seg_col_label'].to(self.device)
        #self.seg_rc_label  = input['seg_rc_label'].to(self.device)
        self.cls_row_label = input['cls_row_label'].to(self.device)
        self.cls_col_label = input['cls_col_label'].to(self.device)
        self.im_scales = input['im_scales']
        self.pdls = input['pdls']
        self.pdts = input['pdts']

    def forward(self):
        inter_feat = self.netBackbone(self.table_images)
        #self.seg_row_score, self.seg_col_score, self.seg_rc_score, self.cell_pred_boxes = self.netCellBboxSeg(inter_feat)
        #self.seg_row_score, self.seg_col_score, self.cell_pred_boxes = self.netCellBboxSeg(inter_feat)
        if self.isTrain:
            self.cls_row_score, self.cls_col_score, self.cls_inds = self.netCellLlocPre(inter_feat, self.cell_pred_boxes, \
                                                                    self.im_scales, self.pdls, self.pdts, self.cell_gt_boxes)
        else:
            self.cls_row_score, self.cls_col_score, _ = self.netCellLlocPre(inter_feat, self.cell_pred_boxes, \
                                                                    self.im_scales, self.pdls, self.pdts, None)

    def backward(self):
        #loss_seg_row = self.criterionBbox(self.seg_row_score, self.seg_row_label)
        #loss_seg_col = self.criterionBbox(self.seg_col_score, self.seg_col_label)
        #loss_seg_rc = self.criterionBbox(self.seg_rc_score, self.seg_rc_label)
        loss_cls_row = self.criterion_Lloc_rows(self.cls_row_score, self.cls_row_label)
        loss_cls_col = self.criterion_Lloc_cols(self.cls_col_score, self.cls_col_label)
        #losses = (loss_seg_row + loss_seg_col + loss_seg_rc) + (loss_cls_row + loss_cls_col)
        losses = (loss_cls_row + loss_cls_col)
        #losses = loss_seg_row + loss_seg_col + loss_seg_rc
        #loss_dict = {'seg_row': loss_seg_row, 'seg_col': loss_seg_col, 'seg_rc': loss_seg_rc, \
        #            'cls_row': loss_cls_row, 'cls_col': loss_cls_col}
        loss_dict = {'cls_row': loss_cls_row, 'cls_col': loss_cls_col}
        #loss_dict = {'seg_row': loss_seg_row, 'seg_col': loss_seg_col, 'seg_rc': loss_seg_rc}
        loss_dict_reduced = util.reduce_dict(loss_dict)
        #self.loss_seg_row = loss_dict_reduced['seg_row']
        #self.loss_seg_col = loss_dict_reduced['seg_col']
        #self.loss_seg_rc  = loss_dict_reduced['seg_rc']
        self.loss_cls_row = loss_dict_reduced['cls_row']
        self.loss_cls_col = loss_dict_reduced['cls_col']
        losses.backward()

    def optimize_parameters(self):
        if not self.isTrain:
            self.isTrain = True
        self.netBackbone.train()
        #self.netCellBboxSeg.train()
        self.netCellLlocPre.train()
        self.forward()
        self.optimizer.zero_grad()
        self.backward()
        self.optimizer.step()

    @torch.no_grad()
    def test(self):
        if self.isTrain:
            self.isTrain = False
        self.forward()
        #cls_pred_row = torch.argmax(self.cls_row_score,dim=1) # [num_cells, 2]
        #cls_pred_col = torch.argmax(self.cls_col_score,dim=1) # [num_cells, 2]
        cls_pred_row = torch.argmax(1-F.softmax(self.cls_row_score,dim=-1),dim=-1) # [num_cells, 2, rows_classes-1]
        cls_pred_col = torch.argmax(1-F.softmax(self.cls_col_score,dim=-1),dim=-1) # [num_cells, 2, cols_classes-1]
        cls_pred_row = torch.sum(cls_pred_row, dim=-1) #
        cls_pred_col = torch.sum(cls_pred_col, dim=-1) #

        pred_lloc = torch.cat((cls_pred_row, cls_pred_col),dim=1).cpu().int().numpy() # [num_cells, 4]
        pred_box = [box.numpy() for box in self.cell_pred_boxes]
        #pred_box = [box.numpy() for box in self.cell_gt_boxes]
        preds = {}
        cell_count = 0
        for ind, tb_name in enumerate(self.table_names):
            num_cells = pred_box[ind].shape[0]
            preds[tb_name] = {'bbox': pred_box[ind], 'lloc': pred_lloc[cell_count:cell_count+num_cells,:]}
            #preds[tb_name] = {'lloc': pred_lloc[cell_count:cell_count+num_cells,:]}
            #preds[tb_name] = {'bbox': pred_box[ind]}
            cell_count += num_cells
        return preds
    '''
    @torch.no_grad()
    def test(self):
        if self.isTrain:
            self.isTrain = False
        self.forward()
        #cls_pred_row = torch.argmax(self.cls_row_score,dim=1) # [num_cells, 2]
        #cls_pred_col = torch.argmax(self.cls_col_score,dim=1) # [num_cells, 2]
        cls_pred_row = torch.argmax(1-F.softmax(self.cls_row_score,dim=-1),dim=-1) # [num_cells, 2, rows_classes-1]
        cls_pred_col = torch.argmax(1-F.softmax(self.cls_col_score,dim=-1),dim=-1) # [num_cells, 2, cols_classes-1]
        cls_pred_row = torch.sum(cls_pred_row, dim=-1) # [num_cells, 2]
        cls_pred_col = torch.sum(cls_pred_col, dim=-1) # [num_cells, 2]

        pred_lloc = torch.cat((cls_pred_row, cls_pred_col),dim=1).cpu().int().numpy()
        gt_lloc = torch.cat((self.cls_row_label,self.cls_col_label),dim=1).cpu().int().numpy()

        cls_rowSt = np.where(pred_lloc[:,0]==gt_lloc[:,0])[0].shape[0]
        cls_rowEd = np.where(pred_lloc[:,1]==gt_lloc[:,1])[0].shape[0]
        cls_colSt = np.where(pred_lloc[:,2]==gt_lloc[:,2])[0].shape[0]
        cls_colEd = np.where(pred_lloc[:,3]==gt_lloc[:,3])[0].shape[0]
        #print(pred_lloc.shape[0],gt_lloc.shape[0])
        cls_lloc  = np.where(np.sum(pred_lloc==gt_lloc,1)==4)[0].shape[0]

        cell_count = gt_lloc.shape[0]

        return (cls_rowSt, cls_rowEd, cls_colSt, cls_colEd, cls_lloc, cell_count)
    '''


from tkinter import *

root = Tk()

x = {
    "name": {"value": ""},
    "age": {"value": 0}
}

def dump_vars():
    print(x)
#     for element in x.keys():
#         print(element, x[element])

for element in x.keys():
    Label(root, text=element).pack()
    x[element]["var"] = StringVar()
    x[element]["entry"] = Entry(root, textvariable=x[element]["var"])
    x[element]["entry"].pack()

# Button(root, text='Ok', command=dump_vars).pack()
Button(root, text='Ok').pack()

root.mainloop()


import os
import speech_recognition as sr
import pyttsx3
def Hadoop():
	os.system("tput setaf 2")
	os.system("echo 'Hadoop' | figlet -f 3d_row -d ./fonts/ ")
	os.system("sleep 3")
	os.system("tput setaf 1")
	r=sr.Recognizer()
	with sr.Microphone() as source:
		os.system("clear")
		os.system("tput setaf 1")
		print("The available Requriments in Hadoop")
		os.system("tput setaf 5")
		print("\n\t\t\tConfigure Namenode\n\t\t\tConfigure Datanode\n\t\t\tConfigure Client\n\t\t\tTo go Main Menu")
		os.system("tput setaf 3")
		print("Start Saying your Requirement in Hadoop")
		pyttsx3.speak("Start Saying your Requirement in Hadoop")
		r.adjust_for_ambient_noise(source)
		audio = r.listen(source)
	print("Processing your Requirement, plz wait....")
	pyttsx3.speak("Processing your Requirement, please wait")
	hadoop= r.recognize_google(audio)
	print(hadoop)
	if(("configure namenode" in hadoop) or ("configure masternode" in hadoop)):
		Namenode.Namenode()
	elif(("configure datanode" in hadoop) or ("configure slavenode" in hadoop)):
		Datanode.Datanode()
	elif("configure client" in hadoop):
		Client.Client()
	elif("main menu" in Hadoop):
		 main.main()
	else :
        	print("select Correct requirement...")

while(True):
	Hadoop()