from enum import Enum
import enum
import time
import threading
import math
import os
import glob
import pathlib
import simpleaudio as sa

from http.server import BaseHTTPRequestHandler,HTTPServer
from socketserver import ThreadingMixIn

from networktables import NetworkTables
import wpilib
import re
import cv2

import numpy as np

class BlurType(Enum):

    """

    Enums for different blur types

    """

    BOX = 1
    GAUSSIAN = 2
    MEDIAN = 3

"""

definition of all opencv cap props

"""

cap_prop_lookup = {

  "POS_MSEC": cv2.CAP_PROP_POS_MSEC,
  "POS_FRAMES": cv2.CAP_PROP_POS_FRAMES,
  "POS_AVI_RATIO": cv2.CAP_PROP_POS_AVI_RATIO,
  "FRAME_WIDTH": cv2.CAP_PROP_FRAME_WIDTH,
  "FRAME_HEIGHT": cv2.CAP_PROP_FRAME_HEIGHT,
  "FPS": cv2.CAP_PROP_FPS,
  "FOURCC": cv2.CAP_PROP_FOURCC,
  "FRAME_COUNT": cv2.CAP_PROP_FRAME_COUNT,
  "FORMAT": cv2.CAP_PROP_FORMAT,
  "MODE": cv2.CAP_PROP_MODE,
  "BRIGHTNESS": cv2.CAP_PROP_BRIGHTNESS,
  "CONTRAST": cv2.CAP_PROP_CONTRAST,
  "SATURATION": cv2.CAP_PROP_SATURATION,
  "HUE": cv2.CAP_PROP_HUE,
  "GAIN": cv2.CAP_PROP_GAIN,
  "EXPOSURE": cv2.CAP_PROP_EXPOSURE,
  "CONVERT_RGB": cv2.CAP_PROP_CONVERT_RGB,
  "RECTIFICATION": cv2.CAP_PROP_RECTIFICATION,

# not supported
#  "WHITE_BALANCE": cv2.CAP_PROP_WHITE_BALANCE,

}

# a list of valid image formats
valid_image_formats = [
    "png",
    "jpg", "jpeg", "jp2", ".jpe",
    "bmp",
    "dib",
    "webp",
    "pbm", "pgm", "ppm",
    "sr", "ras",
    "tiff", "tif"
]

# valid video formats (not official)
valid_video_formats = [
    "mov",
    "avi",
    "mp4",
    "mpeg",
    "flv"
]

class CameraProperties:

    def __init__(self, **kwargs):
        self.props = kwargs
        for x in kwargs:
            if x not in cap_prop_lookup.keys():
                raise KeyError("invalid CAP_PROP: %s" % x)

    def __str__(self):
        ret = "%s(" % (type(self).__name__)
        ss = []
        for p in self.props.keys():
            v = self.props[p]
            if isinstance(v, str):
                v = "'%s'" % v
            ss += ["%s=%s" % (p, v)]
        ret += ",".join(ss)
        ret += ")"
        return ret

    def __getitem__(self, key, default=None):
        return self.props.get(key, default)

    def __setitem__(self, key, val):
        self.props[key] = val

"""

vpl = video pipe line

Think of it similar to how VSTs handle audio, this is a plugin for video

"""

import cv2

class Pipeline:

    def __init__(self, name=None, chain=None):
        self.name = name

        # these are the VPL classes that process the image
        if chain is None:
            self.chain = []
        else:
            self.chain = chain

        self.chain_time = []
        self.chain_fps = (0, [])

        self.vals = {}

        self.is_quit = False

    def __str__(self):
        ret = "Pipeline("

        if self.name != None:
            ret += "name='%s', " % self.name

        ret += "[ \n"

        for vpl in self.chain:
            ret += "  " + str(vpl) + ", \n"
        ret += "])"
        return ret

    def quit(self):
        """

        sets quit flag

        """
        self.is_quit = True

    def add_vpl(self, vpl):
        """

        adds a plugin to the pipeline (at the end), and returns the index in the chain

        """
        self.chain += [vpl]
        return len(self.chain) - 1

    def remove_vpl(self, vpl):
        """

        removes a plugin from the pipeline, or if it is an int, remove that index

        returns either what you passed it, or if it was an int, return the removed plugin

        """
        if isinstance(vpl, int):
            return self.chain.pop(vpl)
        else:
            self.chain.remove(vpl)
            return vpl

    def __raw_chain(self, im, data):
        chain_time = []

        for vpl in self.chain:
            st = time.time()
            im, data = vpl.process(self, im, data)
            et = time.time()
            if self.is_quit:
                break
            chain_time += [et - st]

        def fps(t):
            return 1.0 / t if t != 0 else float('inf')

        self.chain_time = sum(chain_time), chain_time
        self.chain_fps = fps(sum(chain_time)), [fps(i) for i in chain_time]

        return im, data, chain_time

    def process(self, image, data=None, loop=False):
        """

        run through the chain, and process the image

        call it with image=None if you use a VideoSource() VPL plugin

        """

        if image is None:
            im = image
        else:
            im = image.copy()

        if data is None:
            data = dict()

        self.is_quit = False
        if loop:
            while not self.is_quit:
                im, data, chain_time = self.__raw_chain(im, data)
                if not self.is_quit:
                    pass
                    #print ("fps: " + "%.1f" % self.chain_fps[0])
        else:
            im, data, chain_time = self.__raw_chain(im, data)
            if not self.is_quit:
                pass
                #print ("fps: " + "%.1f" % self.chain_fps[0])

        return im, data

    def __getitem__(self, key, default=None):
        return self.vals.get(key, default)

    get = __getitem__

    def __setitem__(self, key, val):
        self.vals[key] = val

class VPL:

    def __init__(self, name=None, **kwargs):
        """

        initialized with a name, and arguments, which you can get later using self["key"], or set using self["key"] = val

        """

        self.name = name
        self.kwargs = kwargs

    def __str__(self):
        ret = "%s(" % (type(self).__name__)

        if self.name != None:
            ret += "name='%s'" % (self.name)

        ss = []
        for k in self.kwargs:
            v = self.kwargs[k]
            if isinstance(v, str):
                v = "'%s'" % v

            ss += ["%s=%s" % (k, v)]

        ret += ", ".join(ss)

        ret += ")"
        return ret

    """

    helper methods

    """

    def __getitem__(self, key, default=None):
        return self.kwargs.get(key, default)

    get = __getitem__

    def __setitem__(self, key, val):
        self.kwargs[key] = val

    """

    for async operations, you can call this and it doesn't stall

    """

    def do_async(self, method, args=( )):
        thread = threading.Thread(target=method, args=args)
        thread.daemon = True
        thread.start()

    def process(self, pipe, image, data):
        """

        this is what actually happens to the image (the functionality of the plugin).

          * pipe : the Pipeline() class that called this method (which can be useful)
          * image : the image being processed
          * data : generic data that can be passed between plugins (as a dictionary)

        """

        return image, data

class SubVPL(VPL):
    """

    This is a control VPL, it treats a Pipeline as a single VPL, so you can embed stuff in a VPL

    Usage: SubVPL(pipe=Pipeline(...))

      * "pipe" = pipeline to run as a VPL

    """

    def process(self, pipe, image, data):
        return self["pipe"].process(image, data)

class ForkVPL(VPL):
    """

    This is a control VPL, it forks and runs another Pipeline in another thread.

    This is useful for things that publish to network tables, or look for different vision targets

    Usage: ForkVPL(pipe=Pipeline(...))

      * "pipe" = pipeline to run as a VPL

    THIS ONLY RETURNS THE IMAGE PASSED TO IT

    """

    def process(self, pipe, image, data):
        self.do_async(self["pipe"].process, (image.copy(), data.copy()))
        return image, data

class ForkSyncVPL(VPL):
    """

    This is a control VPL, it forks and runs another Pipeline in another thread.

    This is useful for things that publish to network tables, or look for different vision targets

    Usage: ForkVPL(pipe=Pipeline(...))

      * "pipe" = pipeline to run as a VPL

    THIS ONLY RETURNS THE IMAGE PASSED TO IT

    """

    def process(self, pipe, image, data):
        self["pipe"].process(image.copy(), data.copy())
        return image, data

class VideoSource(VPL):
    """

    Usage: VideoSource(source=0)

    optional arguments:

      * "camera" = camera object (default of None)
      * "source" = camera index (default of 0), or a string containing a video file (like "VIDEO.mp4") or a string containing images ("data/*.png")
      * "properties" = CameraProperties() object with CAP_PROP values (see that class for info)
      * "repeat" = whether to repeat the image sequence (default False)

    this sets the image to a camera.

    THIS CLEARS THE IMAGE THAT WAS BEING PROCESSED, USE THIS AS THE FIRST PLUGIN

    """

    def camera_single_loop(self):
        self.camera_flag, self.camera_image = self.camera.read()

    def camera_loop(self):
        while True:
            try:
                self.camera_single_loop()
            except:
                pass

    def set_camera_props(self):
        props = self["properties"]
        if props != None:
            for p in props.props:
                #print ("setting: " + str(cap_prop_lookup[p]) + " to: " + str(type(props[p])))
                self.camera.set(cap_prop_lookup[p], props[p])

    def get_camera_image(self):
        return self.camera_flag, self.camera_image

    def get_video_reader_image(self):
        return self.video_reader.read()

    def get_image_sequence_image(self):
        my_idx = self.images_idx
        if self.get("repeat", False):
            my_idx = my_idx % len(self.images)
        self.images_idx += 1

        if my_idx >= len(self.images):
            return False, None

        if self.images[my_idx] is None:
            self.images[my_idx] = cv2.imread(self.image_sequence_sources[my_idx])
        return True, self.images[my_idx]

    def process(self, pipe, image, data):
        if not hasattr(self, "has_init"):
            # first time running, default camera
            self.has_init = True
            self.get_image = None

            source = self.get("source", 0)

            # default images
            self.camera_flag, self.camera_image = True, np.zeros((320, 240, 3), np.uint8)

            if isinstance(source, int) or source.isdigit():
                if not isinstance(source, int):
                    source = int(source)
                # create camera
                self.camera = cv2.VideoCapture(source)
                self.do_async(self.camera_loop)
                self.get_image = self.get_camera_image
                self.set_camera_props()

            elif isinstance(source, str):
                _, extension = os.path.splitext(source)
                extension = extension.replace(".", "").lower()
                if extension in valid_image_formats:
                    # have an image sequence
                    self.image_sequence_sources = glob.glob(source)
                    self.images = [None] * len(self.image_sequence_sources)
                    self.images_idx = 0
                    self.get_image = self.get_image_sequence_image
                elif extension in valid_video_formats:
                    # read from a video file
                    self.video_reader = cv2.VideoCapture(source)
                    self.get_image = self.get_video_reader_image

            else:
                # use an already instasiated camera
                self.camera = source
                self.do_async(self.camera_loop)
                self.get_image = self.get_camera_image
                self.set_camera_props()

        flag, image = self.get_image()

        #data["camera_flag"] = flag
        if image is None:
            pipe.quit()

        return image, data

class VideoSaver(VPL):
    """

    Usage: VideoSaver(path="data/{num}.png")

      * "path" = image format

    optional arguments:

      * "every" = save every N frames (default 1 for every frame)

    Saves images as they are received to their destination

    """

    def save_image(self, image, num):
        loc = pathlib.Path(self["path"].format(num="%08d" % num))
        if not loc.parent.exists():
            loc.parent.mkdir(parents=True)
        cv2.imwrite(str(loc), image)

    def process(self, pipe, image, data):
        if not hasattr(self, "num"):
            self.num = 0

        if self.num % self.get("every", 1) == 0:
            # async save it
            self.do_async(self.save_image, (image.copy(), self.num))

        self.num += 1

        return image, data

class Resize(VPL):
    """

    Usage: Resize(w=512, h=256)

      * "w" = width, in pixels
      * "h" = height, in pixels

    optional arguments:

      * "method" = opencv resize method, default is cv2.INTER_LINEAR

    """

    def process(self, pipe, image, data):
        height, width, depth = image.shape

        if width != self["w"] or height != self["h"]:
            resize_method = self.get("method", cv2.INTER_LINEAR)
            return cv2.resize(image, (self["w"], self["h"]), interpolation=resize_method), data
        else:
            # if it is the correct size, don't spend time resizing it
            return image, data

class Blur(VPL):
    """

    Usage: Blur(w=4, h=8)

      * "w" = width, in pixels (for guassian blur, w % 2 == 1) (for median blur, this must be an odd integer greater than 1 (3, 5, 7... are good))
      * "h" = height, in pixels (for guassian blur, w % 2 == 1) (for median blur, this is ignored)

    optional arguments:

      * "method" = opencv blur method, default is vpl.BlurType.BOX
      * "sx" = 'sigma x' for the Gaussian blur standard deviation, defaults to letting OpenCV choose based on image size
      * "sy" = 'sigma y' for the Gaussian blur standard deviation, defaults to letting OpenCV choose based on image size

    """

    def process(self, pipe, image, data):
        if self["w"] in (0, None) or self["h"] in (0, None):
            return image, data
        else:
            resize_method = self.get("method", BlurType.BOX)

            if resize_method == BlurType.GAUSSIAN:
                sx, sy = self.get("sx", 0), self.get("sy", 0)
                return cv2.GaussianBlur(image, (self["w"], self["h"]), sigmaX=sx, sigmaY=sy), data
            elif resize_method == BlurType.MEDIAN:
                return cv2.medianBlur(image, self["w"]), data
            else:
                # default is BlurType.BOX
                return cv2.blur(image, (self["w"], self["h"])), data

class Display(VPL):
    """

    Usage: Display(title="mytitle")

        * "title" = the window title

    """

    def process(self, pipe, image, data):

        cv2.imshow(self["title"], image)
        cv2.waitKey(1)

        return image, data

class PrintInfo(VPL):
    """

    Usage: PrintInfo()

    This prints out info about the image and pipeline

    """

    def process(self, pipe, image, data):
        h, w, d = image.shape
        print ("width=%s, height=%s" % (w, h))
        return image, data

class FPSCounter(VPL):
    """

    Usage: FPSCounter()

    Simply adds the FPS in the bottom left corner

    """

    def process(self, pipe, image, data):
        if not hasattr(self, "fps_records"):
            self.fps_records = []

        if not hasattr(self, "last_print"):
            self.last_print = (0, None)

        ctime = time.time()
        self.fps_records += [(ctime, pipe.chain_fps[0])]

        # filter only the last second of readings
        self.fps_records = list(filter(lambda tp: abs(ctime - tp[0]) < 1.0, self.fps_records))

        avg_fps = sum([fps for t, fps in self.fps_records]) / len(self.fps_records)

        if self.last_print[1] is None or abs(ctime - self.last_print[0]) > 1.0 / 3.0:
            self.last_print = (ctime, avg_fps)

        font = cv2.FONT_HERSHEY_SIMPLEX
        height, width, _ = image.shape
        geom_mean = math.sqrt(height * width)
        offset = geom_mean * .01

        return cv2.putText(image.copy(), "%2.1f" % self.last_print[1], (int(offset), int(height - offset)), font, offset / 6.0, (255, 0, 0), int(offset / 6.0 + 2)), data

class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    """Handle requests in a separate thread."""

    def update_image(self, image):
        self.RequestHandlerClass.image = image

class MJPGStreamHandle(BaseHTTPRequestHandler):
    """

    handles web requests for MJPG

    """

    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type', 'multipart/x-mixed-replace; boundary=--jpgboundary')
        self.end_headers()

        if not hasattr(self, "image"):
            return

        while True:
            # MAKE sure this refreshes the image every time
            im = self.image.copy()

            # encode image
            cv2s = cv2.imencode('.jpg', im)[1].tostring()

            # write a jpg
            self.wfile.write("--jpgboundary".encode())
            self.send_header('Content-type', 'image/jpeg')
            self.send_header('Content-length', str(len(cv2s)).encode())
            self.end_headers()
            self.wfile.write(cv2s)

            while np.array_equal(self.image, im):
                time.sleep(0.01)
        return

class MJPGServer(VPL):
    """

    Usage: MJPGServer(port=5802, fps_cap=None)

      * "port" = the port to host it on

    This is code to host a web server

    This only works on google chrome, connect to "localhost:PORT" to see the image. Or, if you are hosting it on another device (such as a raspi), connect like (raspberrypi.local:PORT) in your browser

    """

    def process(self, pipe, image, data):
        if not hasattr(self, "http_server"):
            self.http_server = ThreadedHTTPServer(('0.0.0.0', self["port"]), MJPGStreamHandle)
            self.http_server.daemon_threads = True
            self.do_async(self.http_server.serve_forever)

        self.http_server.update_image(image.copy())

        return image, data

class ConvertColor(VPL):
    """

    Usage: ConvertColor(conversion=None)

      * conversion = type of conversion (see https://docs.opencv.org/3.1.0/d7/d1b/group__imgproc__misc.html#ga4e0972be5de079fed4e3a10e24ef5ef0) ex: cv2.COLOR_BGR2HSL

    """

    def process(self, pipe, image, data):
        if self["conversion"] is None:
            return image, data
        else:
            return cv2.cvtColor(image, self["conversion"]), data

class ChannelSplit(VPL):
    """

    Usage: ChannelSplit(store=None)

      * store : the key to store in the data object

    """

    def process(self, pipe, image, data):
        height, width, depth = image.shape

        for i in range(0, depth):
            data[self["store"]][i] = image[:,:,i]

        return image, data

class ChannelRecombo(VPL):
    """

    Usage: ChannelSplit(store=None)

      * store : the key to store in the data object

    """

    def process(self, pipe, image, data):
        height, width = data[self["store"]][0].shape
        depth = len(data[self["store"]].keys())
        image = np.zeros((height, width, depth), dtype=data[self["store"]][0].dtype)

        for i in range(0, depth):
            image[:,:,i] = data[self["store"]][i]

        return image, data

class InRange(VPL):
    """

    Usage: InRange(H=(20, 40), S=(30, 60), V=(100, 200), mask_key=None)

    """
    def process(self, pipe, image, data):
        H = self.get("H", (23, 37))
        S = self.get("S", (79, 255))
        V = self.get("V", (103, 255))
        mask = cv2.inRange(image, (H[0],S[0],V[0]), (H[1],S[1],V[1]))
        mask_key = self.get("mask_key", None)
        if mask_key is not None:
            data[mask_key] = mask

        return image, data

class ApplyMask(VPL):
    """

    Usage: ApplyMask(mask_key=None)

    """
    def process(self, pipe, image, data):
        mask_key = self.get("mask_key", None)
        if mask_key is not None:
            res = cv2.bitwise_and(image, image, mask=data[mask_key])
            return res, data
        else:
            return image, data

class Erode(VPL):
    """

    Usage: Erode(mask, None, iterations)

    """
    def process(self, pipe, image, data):
        image = cv2.erode(image, None, iterations=2)
        return image, data

class Dilate(VPL):
    """

    Usage: Dilate(mask, None, iterations)

    """
    def process(self, pipe, image, data):
        image = cv2.dilate(image, None, iterations=2)
        return image, data

class FindContours(VPL):
    """

    Usage: FindCountours(key="contours")

    """
    def process(self, pipe, image, data):
        # find contours in the mask and initialize the current

        cnts = cv2.findContours(image, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]
        center = None

        data[self["key"]] = []

        # only proceed if at least one contour was found
        if len(cnts) > 0:
            # find the largest contour in the mask, then use
            # it to compute the minimum enclosing circle and
            # centroid
            c = max(cnts, key=cv2.contourArea)
            ct = 0
            #for c in filter(lambda x: cv2.contourArea(x) > 15, cnts):
            ((x, y), radius) = cv2.minEnclosingCircle(c)
            M = cv2.moments(c)
            center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
            # only proceed if the radius meets a minimum size
            if (radius > 10):
                data[self["key"]] += [[center, radius]]
                """
                # draw the circle and centroid on the frame,
                # then update the list of tracked points
                cv2.rectangle(image ,(int(x)-int(radius), int(y)+int(radius)),(int(x)+int(radius), int(y)-int(radius)),(0,255,0),3)
                cv2.putText(image,'LargestContour ' + str(round(x,1)) + ' ' + str(round(y,1)),(int(x)-int(radius), int(y)-int(radius)), cv2.FONT_HERSHEY_PLAIN, 2*(int(radius)/45),(255,255,255),2,cv2.LINE_AA)

                #cv.rectangle(frame , ((int(x)- int(radius), (int(y)+int(radius)) , (1,1),(0,255,0),3)
                cv2.circle(image, center, 5, (255 * (ct % 3 == 2), 255 * (ct % 3 == 1), 255 * (ct % 3 == 0)), -1)
                """
            ct += 1
        return image, data

class DrawContours(VPL):

    def process(self, pipe, image, data):
        contours = data[self["key"]]
        for center, radius in contours:
            cv2.circle(image, center, 5, (255, 0, 0), -1)
        return image, data

class StoreImage(VPL):

    def process(self, pipe, image, data):
        key = self.get("key", None)
        if key is not None:
            data[key] = image.copy()
        return image, data

class RestoreImage(VPL):

    def process(self, pipe, image, data):
        key = self.get("key", None)
        if key is not None:
            image = data[key]
        return image, data

class Distance(VPL):
    """

    Calculates Distance to Radius
    A: 17in
    B: 109in
    C: 109.32977636490435

    5150/x

    """
    def process(self, pipe, image, data):
        contours = data[self["key"]]
        if len(contours) != 0:
            contours = data[self["key"]]
            for center, radius in contours:
               distance = 5150/radius if radius != 0 else 0
               cv2.putText(image, str(distance), (100,100), cv2.FONT_HERSHEY_PLAIN, 2,  (0,255,255))

        return image, data

class KillSwitch(VPL):
    def process(self, pipe, image, data):
        c = cv2.waitKey(7) % 0x100
        if c in (10, 27, 113):
            pipe.quit()
        return image, data

class Beep(VPL):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.props = kwargs
        self.playstart = 0
        self.wave_beep = sa.WaveObject.from_wave_file("media/beep.wav")
        self.wave_lock = sa.WaveObject.from_wave_file("media/locked.wav")
        self.beep_length = 3.47
        self.lock_length = 1
    def process(self, pipe, image, data):
        contours = data[self["key"]]
        if len(contours) != 0:
            contours = data[self["key"]]
            for center, radius in contours:
                x = center[0]

                if (x > ((np.size(image, 1)/2)-50) and x < ((np.size(image, 1)/2)+50)):

                    if self.playstart < time.time() - self.lock_length:
                        play_obj = self.wave_lock.play()
                        print('locked')
                        self.playstart = time.time()
                else:
                    if self.playstart < time.time() - self.beep_length:
                        play_obj = self.wave_beep.play()
                        print('beep beep')
                        self.playstart = time.time()

        return image, data

class DrawMeter(VPL):
    '''

    Draws a rectangle in the lower left hand corner and scales the x values of the center point. Similar to our previous implementation of light on the robot.

    '''

    def process(self, pipe, image, data):
        contours = data[self["key"]]
        h,w,bpp = np.shape(image)
        bar_width = 290
        range_lower = int((w/2)-50)
        range_upper = int((w/2)+50)

        for center, radius in contours:
            x = center[0]
            if x > range_lower and x < range_upper:
                bar_color = (34,139,34)
            else:
                bar_color = (0,0,255)

            cv2.rectangle(image, (w-10,h-10), (w-300,h-50) , (0,255,255), cv2.FILLED)
            cv2.rectangle(image,((int(((x/w)*bar_width)+330)),h-5), ((int(((x/w)*bar_width)+350)),h-55), bar_color, cv2.FILLED)

        return image, data

class CoolChannelOffset(VPL):

    def process(self, pipe, image, data):
        h, w, nch = image.shape
        ch = cv2.split(image)
        for i in range(nch):
            xoff = 8 * i
            yoff = 0
            ch[i] = np.roll(np.roll(image[:,:,i], yoff, 0), xoff, 1)
            #image[:,:,i] = np.roll(image[:,:,i], 10, 1)

        image = cv2.merge(ch)

        return image, data

import math

class Bleed(VPL):

    def process(self, pipe, image, data):
        N = self.get("N", 18)
        if not hasattr(self, "buffer"):
            self.buffer = []

        self.buffer.insert(0, image.copy())

        if len(self.buffer) >= N:
            self.buffer = self.buffer[:N]

        #a = [len(self.buffer) - i + N for i in range(0, len(self.buffer))]
        a = [1.0 / (i + 1) for i in range(0, len(self.buffer))]

        # normalize
        a = [a[i] / sum(a) for i in range(len(a))]

        image[:,:,:] = 0

        for i in range(len(a)):
            image = cv2.addWeighted(image, 1.0, self.buffer[i], a[i], 0)

        return image, data

class Pixelate(VPL):

    def process(self, pipe, image, data):
        N = self.get("N", 7.5)

        h, w, d = image.shape

        image = cv2.resize(image, (int(w // N), int(h // N)), interpolation=cv2.INTER_NEAREST)
        image = cv2.resize(image, (w, h), interpolation=cv2.INTER_NEAREST)

        return image, data

class Noise(VPL):

    def process(self, pipe, image, data):
        level = self.get("level", .125)

        m = (100,100,100)
        s = (100,100,100)
        noise = np.zeros_like(image)

        image = cv2.addWeighted(image, 1 - level, cv2.randn(noise, m, s), level, 0)

        return image, data

class DetailEnhance(VPL):

    def process(self, pipe, image, data):
        image = cv2.detailEnhance(image, sigma_s=self.get("r", 10), sigma_r=self.get("s", .15))
        return image, data

class Cartoon(VPL):

    def process(self, pipe, image, data):
        down = self.get("down", 2)
        bilateral = self.get("bilateral", 7)

        for i in range(down):
            image = cv2.pyrDown(image)

        for i in range(bilateral):
            image = cv2.bilateralFilter(image, d=9,
                                    sigmaColor=9,
                                    sigmaSpace=7)

        for i in range(down):
            image = cv2.pyrUp(image)

        image_gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
        image_blur = cv2.medianBlur(image_gray, 7)

        image_edge = cv2.adaptiveThreshold(image_blur, 255,
                                 cv2.ADAPTIVE_THRESH_MEAN_C,
                                 cv2.THRESH_BINARY,
                                 blockSize=9,
                                 C=2)

        image_edge = cv2.cvtColor(image_edge, cv2.COLOR_GRAY2RGB)
        image_cartoon = cv2.bitwise_and(image, image_edge)

        return image_cartoon, data

class ShowGameInfo(VPL):

    def __init__(self):
            self.firstScroll = 0
            self.secondScroll = -400

    def process(self, pipe, image, data):

        def drawInfo(image):

            height, width, channels = image.shape

            if self.firstScroll < width:
                self.firstScroll = self.firstScroll + 1
            else:
                self.firstScroll = -(width+1000)
            if self.secondScroll < width:
                self.secondScroll = self.secondScroll + 1
            elif self.firstScroll == width/2:
                self.secondScroll = int((width/2.5)*-1)

            #draw rectangle
            cv2.rectangle(image, (0, height), (width,int(height-(height*.06))), (244,244,244), cv2.FILLED, lineType=8, shift=0)

            font = cv2.FONT_HERSHEY_SIMPLEX

            alliance = wpilib.DriverStation.getInstance().getAlliance()
            eventName = eventName = wpilib.DriverStation.getInstance().getEventName()
            matchTime = matchTime = wpilib.DriverStation.getInstance().getMatchTime()
            autonomous = autonomous = wpilib.DriverStation.getInstance().isAutonomous()
            systemAttached = systemAttached = wpilib.DriverStation.getInstance().isFMSAttached()

            infoText = "Alliance: " + (str(alliance) + "Event Name: " +  str(eventName) + "Match Time: " + str(matchTime) + "Autonomous: " + str(autonomous) + "System Attached: " + str(systemAttached))

            cv2.putText(image, infoText, (self.firstScroll,int(height-(height*.01))), font, 1, (0,0,255),2)
            cv2.putText(image, "L&N STEMpunks", (self.secondScroll,int(height-(height*.01))), font, 1, (0,0,255),2)
            auto = True
          #  if auto == True:
                #cv2.putText(image, "Autonomous Period", ((0, -(height/6) ), ((width/5),-(height/5))), font, 1, (0,0,255),2)

        drawInfo(image)

        return image, data

class DumpInfo(VPL):

    def write(self):
        if len(self.contours) != 0:
            for center, radius in self.contours:
                x,y = center
                print(center, radius)

                self.smartdashboard.putNumber("Radius", radius)
                self.smartdashboard.putNumber("centerX", x)
                self.smartdashboard.putNumber("centerY", y)
        else:
            self.smartdashboard.putNumber("Radius", -1)
            self.smartdashboard.putNumber("centerX", -1)
            self.smartdashboard.putNumber("centerY", -1)

    def process(self, pipe, image, data):
        self.contours = data[self["key"]]
        if not hasattr(self, "is_init"):
            self.is_init = True

            NetworkTables.initialize(server='roborio-3966-FRC.local')
            self.smartdashboard = NetworkTables.getTable('SmartDashboard')

        if not hasattr(self, "last_time") or time.time() - self.last_time > 1.0 / 24.0:
            self.write()
            self.last_time = time.time()
        return image, data


import asyncio
import time

from api.base_api import Direction
from db.cache import RedisHelper
from util.util_double_order import double_order

def process_binance_double(data):
    redis = RedisHelper()
    if data.get("s"):
        time.sleep(3)
        depth = {
            "asks": data.get("a"),
            "bids": data.get("b")
        }
        price = float(depth["asks"][0][0])
        target_dict = redis.get("BINANCE:STOP")
        if target_dict:
            up = float(target_dict["up"])
            down = float(target_dict["down"])
            print(down, up, price)
            symbol_id1 = 785
            symbol_id2 = 146
            api_id1 = 28
            api_id2 = 1
            if price > up:
                """大于做多止赢价格 止赢"""
                return asyncio.run(double_order(symbol_id=symbol_id1, symbol2_id=symbol_id2, api_id=api_id1, api2_id=api_id2, side=Direction.CLOSE_LONG, amount=0))

            if price < down:
                """小于做空止赢价格 止赢"""
                return asyncio.run(double_order(symbol_id=symbol_id1, symbol2_id=symbol_id2, api_id=api_id1, api2_id=api_id2, side=Direction.CLOSE_SHORT, amount=0))


class Solution:
    def isIsomorphic(self, s: str, t: str) -> bool:
        charMap = {}
        if len(s) != len(t):
            return False
        for i, ch in enumerate(s):
            if ch in charMap:
                if charMap[ch] != t[i]:
                    return False
            else:
                if t[i] in charMap.values():
                    return False
                charMap[ch] = t[i]
        return True


from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='home'),
    path('index/', views.index, name='home'),
    path('signup', views.signup, name='signup'),
    path('login', views.user_login, name='login'),
    path('main', views.main, name='main'),
    path('blog/<int:id>/<str:liked>', views.open_blog, name='blog'),
    path('create_blog/<int:user_id>', views.create_blog, name='create_blog'),
    path('edit_blog/<int:blog_id>', views.edit_blog, name='edit_blog'),
    path('drafts/<int:user_id>', views.drafts, name='drafts'),
    path('like_blog', views.like_blog, name='like_blog')
]


import os
import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont
from model.featureExtraction.dataModel import DataModel

def renderTxt(image, data:DataModel):
    '''Desenha os segmentos detectados'''
    data = str(data)

    altura, largura, _ = image.shape
    x,y = 50,100

    # Converter a imagem do OpenCV para o formato Pillow
    pillow_image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
    draw = ImageDraw.Draw(pillow_image)

    # Caminho absoluto para a fonte desejada
    #font_path = "/home/guest/Área de Trabalho/TCC/Tecnologico/Source/Programa/python/midia/static/Cabin-Bold.ttf"  # Substitua pelo caminho para a fonte que deseja usar

    # Caminho relativo
    font_path = "./midia/static/Cabin-Bold.ttf"

    font_size = int(min(largura, altura) * 0.03)  # Ajuste o fator multiplicador conforme necessário
    font = ImageFont.truetype(font_path, font_size)
    color = (255,255,0)
    lines = data.split("\n")

    for line in lines:
        draw.text((x, y), line, font=font, fill=color)
        y += font.getsize(line)[1]  # Espaçamento entre as linhas

    # Converter a imagem de volta para o formato OpenCV
    image_with_text = cv2.cvtColor(np.array(pillow_image), cv2.COLOR_RGB2BGR)

    return image_with_text


from collections import Counter

class Solution:
    def characterReplacement(self, s: str, k: int) -> int:
        res = 0
        c = Counter()
        n = len(s)
        left = 0
        for right in range(n):
            letter = s[right]
            c[letter] += 1
            _, count = c.most_common(1)[0]
            required_replacements = right - left - count + 1
            if required_replacements > k:
                letter = s[left]
                c[letter] -= 1
                left += 1
            res = max(res, right - left + 1)
        return res


from six.moves import queue
from six.moves import range
import ctypes
import ctypes.util
import logging
import sys
import threading

from pyu2f import errors
from pyu2f.hid import base

logger = logging.getLogger('pyu2f.macos')

# Constants
DEVICE_PATH_BUFFER_SIZE = 512
DEVICE_STRING_PROPERTY_BUFFER_SIZE = 512

HID_DEVICE_PROPERTY_VENDOR_ID = 'VendorId'
HID_DEVICE_PROPERTY_PRODUCT_ID = 'ProductID'
HID_DEVICE_PROPERTY_PRODUCT = 'Product'
HID_DEVICE_PROPERTY_PRIMARY_USAGE = 'PrimaryUsage'
HID_DEVICE_PROPERTY_PRIMARY_USAGE_PAGE = 'PrimaryUsagePage'
HID_DEVICE_PROPERTY_MAX_INPUT_REPORT_SIZE = 'MaxInputReportSize'
HID_DEVICE_PROPERTY_MAX_OUTPUT_REPORT_SIZE = 'MaxOutputReportSize'
HID_DEVICE_PROPERTY_REPORT_ID = 'ReportID'

# Declare C types
class _CFType(ctypes.Structure):
  pass

class _CFString(_CFType):
  pass

class _CFSet(_CFType):
  pass

class _IOHIDManager(_CFType):
  pass

class _IOHIDDevice(_CFType):
  pass

class _CFRunLoop(_CFType):
  pass

class _CFAllocator(_CFType):
  pass

# Linter isn't consistent about valid class names. Disabling some of the errors
CF_SET_REF = ctypes.POINTER(_CFSet)
CF_STRING_REF = ctypes.POINTER(_CFString)
CF_TYPE_REF = ctypes.POINTER(_CFType)
CF_RUN_LOOP_REF = ctypes.POINTER(_CFRunLoop)
CF_RUN_LOOP_RUN_RESULT = ctypes.c_int32
CF_ALLOCATOR_REF = ctypes.POINTER(_CFAllocator)
CF_TYPE_ID = ctypes.c_ulong  # pylint: disable=invalid-name
CF_INDEX = ctypes.c_long  # pylint: disable=invalid-name
CF_TIME_INTERVAL = ctypes.c_double  # pylint: disable=invalid-name
IO_RETURN = ctypes.c_uint
IO_HID_REPORT_TYPE = ctypes.c_uint
IO_OBJECT_T = ctypes.c_uint
MACH_PORT_T = ctypes.c_uint
IO_STRING_T = ctypes.c_char_p  # pylint: disable=invalid-name
IO_SERVICE_T = IO_OBJECT_T
IO_REGISTRY_ENTRY_T = IO_OBJECT_T

IO_HID_MANAGER_REF = ctypes.POINTER(_IOHIDManager)
IO_HID_DEVICE_REF = ctypes.POINTER(_IOHIDDevice)

IO_HID_REPORT_CALLBACK = ctypes.CFUNCTYPE(None, ctypes.py_object, IO_RETURN,
                                          ctypes.c_void_p, IO_HID_REPORT_TYPE,
                                          ctypes.c_uint32,
                                          ctypes.POINTER(ctypes.c_uint8),
                                          CF_INDEX)

# Define C constants
K_CF_NUMBER_SINT32_TYPE = 3
K_CF_STRING_ENCODING_UTF8 = 0x08000100
K_CF_ALLOCATOR_DEFAULT = None

K_IO_SERVICE_PLANE = b'IOService'
K_IO_MASTER_PORT_DEFAULT = 0
K_IO_HID_REPORT_TYPE_OUTPUT = 1
K_IO_RETURN_SUCCESS = 0

K_CF_RUN_LOOP_RUN_STOPPED = 2
K_CF_RUN_LOOP_RUN_TIMED_OUT = 3
K_CF_RUN_LOOP_RUN_HANDLED_SOURCE = 4

# Load relevant libraries
iokit = ctypes.cdll.LoadLibrary(ctypes.util.find_library('IOKit'))
cf = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation'))

# Only use iokit and cf if we're on macos, this way we can still run tests
# on other platforms if we properly mock
if sys.platform.startswith('darwin'):
  # Exported constants
  K_CF_RUNLOOP_DEFAULT_MODE = CF_STRING_REF.in_dll(cf, 'kCFRunLoopDefaultMode')

  # Declare C function prototypes
  cf.CFSetGetValues.restype = None
  cf.CFSetGetValues.argtypes = [CF_SET_REF, ctypes.POINTER(ctypes.c_void_p)]
  cf.CFStringCreateWithCString.restype = CF_STRING_REF
  cf.CFStringCreateWithCString.argtypes = [ctypes.c_void_p, ctypes.c_char_p,
                                           ctypes.c_uint32]
  cf.CFStringGetCString.restype = ctypes.c_int
  cf.CFStringGetCString.argtypes = [CF_STRING_REF, ctypes.c_char_p, CF_INDEX,
                                    ctypes.c_uint32]
  cf.CFStringGetLength.restype = CF_INDEX
  cf.CFStringGetLength.argtypes = [CF_STRING_REF]
  cf.CFGetTypeID.restype = CF_TYPE_ID
  cf.CFGetTypeID.argtypes = [CF_TYPE_REF]
  cf.CFNumberGetTypeID.restype = CF_TYPE_ID
  cf.CFNumberGetValue.restype = ctypes.c_int
  cf.CFRelease.restype = None
  cf.CFRelease.argtypes = [CF_TYPE_REF]
  cf.CFRunLoopGetCurrent.restype = CF_RUN_LOOP_REF
  cf.CFRunLoopGetCurrent.argTypes = []
  cf.CFRunLoopRunInMode.restype = CF_RUN_LOOP_RUN_RESULT
  cf.CFRunLoopRunInMode.argtypes = [CF_STRING_REF, CF_TIME_INTERVAL,
                                    ctypes.c_bool]

  iokit.IOObjectRelease.argtypes = [IO_OBJECT_T]
  iokit.IOHIDManagerCreate.restype = IO_HID_MANAGER_REF
  iokit.IOHIDManagerCopyDevices.restype = CF_SET_REF
  iokit.IOHIDManagerCopyDevices.argtypes = [IO_HID_MANAGER_REF]
  iokit.IOHIDManagerSetDeviceMatching.restype = None
  iokit.IOHIDManagerSetDeviceMatching.argtypes = [IO_HID_MANAGER_REF,
                                                  CF_TYPE_REF]
  iokit.IOHIDDeviceGetProperty.restype = CF_TYPE_REF
  iokit.IOHIDDeviceGetProperty.argtypes = [IO_HID_DEVICE_REF, CF_STRING_REF]
  iokit.IOHIDDeviceRegisterInputReportCallback.restype = None
  iokit.IOHIDDeviceRegisterInputReportCallback.argtypes = [
      IO_HID_DEVICE_REF, ctypes.POINTER(ctypes.c_uint8), CF_INDEX,
      IO_HID_REPORT_CALLBACK, ctypes.py_object]
  iokit.IORegistryEntryFromPath.restype = IO_REGISTRY_ENTRY_T
  iokit.IORegistryEntryFromPath.argtypes = [MACH_PORT_T, IO_STRING_T]
  iokit.IOHIDDeviceCreate.restype = IO_HID_DEVICE_REF
  iokit.IOHIDDeviceCreate.argtypes = [CF_ALLOCATOR_REF, IO_SERVICE_T]
  iokit.IOHIDDeviceScheduleWithRunLoop.restype = None
  iokit.IOHIDDeviceScheduleWithRunLoop.argtypes = [IO_HID_DEVICE_REF,
                                                   CF_RUN_LOOP_REF,
                                                   CF_STRING_REF]
  iokit.IOHIDDeviceUnscheduleFromRunLoop.restype = None
  iokit.IOHIDDeviceUnscheduleFromRunLoop.argtypes = [IO_HID_DEVICE_REF,
                                                     CF_RUN_LOOP_REF,
                                                     CF_STRING_REF]
  iokit.IOHIDDeviceSetReport.restype = IO_RETURN
  iokit.IOHIDDeviceSetReport.argtypes = [IO_HID_DEVICE_REF, IO_HID_REPORT_TYPE,
                                         CF_INDEX,
                                         ctypes.POINTER(ctypes.c_uint8),
                                         CF_INDEX]
else:
  logger.warn('Not running on MacOS')

def CFStr(s):
  """Builds a CFString from a python string.

  Args:
    s: source string

  Returns:
    CFStringRef representation of the source string

  Resulting CFString must be CFReleased when no longer needed.
  """
  return cf.CFStringCreateWithCString(None, s.encode(), 0)

def GetDeviceIntProperty(dev_ref, key):
  """Reads int property from the HID device."""
  cf_key = CFStr(key)
  type_ref = iokit.IOHIDDeviceGetProperty(dev_ref, cf_key)
  cf.CFRelease(cf_key)
  if not type_ref:
    return None

  if cf.CFGetTypeID(type_ref) != cf.CFNumberGetTypeID():
    raise errors.OsHidError('Expected number type, got {}'.format(
        cf.CFGetTypeID(type_ref)))

  out = ctypes.c_int32()
  ret = cf.CFNumberGetValue(type_ref, K_CF_NUMBER_SINT32_TYPE,
                            ctypes.byref(out))
  if not ret:
    return None

  return out.value

def GetDeviceStringProperty(dev_ref, key):
  """Reads string property from the HID device."""
  cf_key = CFStr(key)
  type_ref = iokit.IOHIDDeviceGetProperty(dev_ref, cf_key)
  cf.CFRelease(cf_key)
  if not type_ref:
    return None

  if cf.CFGetTypeID(type_ref) != cf.CFStringGetTypeID():
    raise errors.OsHidError('Expected string type, got {}'.format(
        cf.CFGetTypeID(type_ref)))

  type_ref = ctypes.cast(type_ref, CF_STRING_REF)
  out = ctypes.create_string_buffer(DEVICE_STRING_PROPERTY_BUFFER_SIZE)
  ret = cf.CFStringGetCString(type_ref, out, DEVICE_STRING_PROPERTY_BUFFER_SIZE,
                              K_CF_STRING_ENCODING_UTF8)
  if not ret:
    return None

  return out.value.decode('utf8')

def GetDevicePath(device_handle):
  """Obtains the unique path for the device.

  Args:
    device_handle: reference to the device

  Returns:
    A unique path for the device, obtained from the IO Registry

  """
  # Obtain device path from IO Registry
  io_service_obj = iokit.IOHIDDeviceGetService(device_handle)
  str_buffer = ctypes.create_string_buffer(DEVICE_PATH_BUFFER_SIZE)
  iokit.IORegistryEntryGetPath(io_service_obj, K_IO_SERVICE_PLANE, str_buffer)

  return str_buffer.value

def HidReadCallback(read_queue, result, sender, report_type, report_id, report,
                    report_length):
  """Handles incoming IN report from HID device."""
  del result, sender, report_type, report_id  # Unused by the callback function

  incoming_bytes = [report[i] for i in range(report_length)]
  read_queue.put(incoming_bytes)

# C wrapper around ReadCallback()
# Declared in this scope so it doesn't get GC-ed
REGISTERED_READ_CALLBACK = IO_HID_REPORT_CALLBACK(HidReadCallback)

def DeviceReadThread(hid_device):
  """Binds a device to the thread's run loop, then starts the run loop.

  Args:
    hid_device: The MacOsHidDevice object

  The HID manager requires a run loop to handle Report reads. This thread
  function serves that purpose.
  """

  # Schedule device events with run loop
  hid_device.run_loop_ref = cf.CFRunLoopGetCurrent()
  if not hid_device.run_loop_ref:
    logger.error('Failed to get current run loop')
    return

  iokit.IOHIDDeviceScheduleWithRunLoop(hid_device.device_handle,
                                       hid_device.run_loop_ref,
                                       K_CF_RUNLOOP_DEFAULT_MODE)

  # Run the run loop
  run_loop_run_result = K_CF_RUN_LOOP_RUN_TIMED_OUT
  while (run_loop_run_result == K_CF_RUN_LOOP_RUN_TIMED_OUT or
         run_loop_run_result == K_CF_RUN_LOOP_RUN_HANDLED_SOURCE):
    run_loop_run_result = cf.CFRunLoopRunInMode(
        K_CF_RUNLOOP_DEFAULT_MODE,
        1000,  # Timeout in seconds
        False)  # Return after source handled

  # log any unexpected run loop exit
  if run_loop_run_result != K_CF_RUN_LOOP_RUN_STOPPED:
    logger.error('Unexpected run loop exit code: %d', run_loop_run_result)

  # Unschedule from run loop
  iokit.IOHIDDeviceUnscheduleFromRunLoop(hid_device.device_handle,
                                         hid_device.run_loop_ref,
                                         K_CF_RUNLOOP_DEFAULT_MODE)

class MacOsHidDevice(base.HidDevice):
  """Implementation of HID device for MacOS.

  Uses IOKit HID Manager to interact with the device.
  """

  @staticmethod
  def Enumerate():
    """See base class."""
    # Init a HID manager
    hid_mgr = iokit.IOHIDManagerCreate(None, None)
    if not hid_mgr:
      raise errors.OsHidError('Unable to obtain HID manager reference')
    iokit.IOHIDManagerSetDeviceMatching(hid_mgr, None)

    # Get devices from HID manager
    device_set_ref = iokit.IOHIDManagerCopyDevices(hid_mgr)
    if not device_set_ref:
      raise errors.OsHidError('Failed to obtain devices from HID manager')

    num = iokit.CFSetGetCount(device_set_ref)
    devices = (IO_HID_DEVICE_REF * num)()
    iokit.CFSetGetValues(device_set_ref, devices)

    # Retrieve and build descriptor dictionaries for each device
    descriptors = []
    for dev in devices:
      d = base.DeviceDescriptor()
      d.vendor_id = GetDeviceIntProperty(dev, HID_DEVICE_PROPERTY_VENDOR_ID)
      d.product_id = GetDeviceIntProperty(dev, HID_DEVICE_PROPERTY_PRODUCT_ID)
      d.product_string = GetDeviceStringProperty(dev,
                                                 HID_DEVICE_PROPERTY_PRODUCT)
      d.usage = GetDeviceIntProperty(dev, HID_DEVICE_PROPERTY_PRIMARY_USAGE)
      d.usage_page = GetDeviceIntProperty(
          dev, HID_DEVICE_PROPERTY_PRIMARY_USAGE_PAGE)
      d.report_id = GetDeviceIntProperty(dev, HID_DEVICE_PROPERTY_REPORT_ID)
      d.path = GetDevicePath(dev)
      descriptors.append(d.ToPublicDict())

    # Clean up CF objects
    cf.CFRelease(device_set_ref)
    cf.CFRelease(hid_mgr)

    return descriptors

  def __init__(self, path):
    # Resolve the path to device handle
    device_entry = iokit.IORegistryEntryFromPath(K_IO_MASTER_PORT_DEFAULT, path)
    if not device_entry:
      raise errors.OsHidError('Device path does not match any HID device on '
                              'the system')

    self.device_handle = iokit.IOHIDDeviceCreate(K_CF_ALLOCATOR_DEFAULT,
                                                 device_entry)
    if not self.device_handle:
      raise errors.OsHidError('Failed to obtain device handle from registry '
                              'entry')
    iokit.IOObjectRelease(device_entry)

    self.device_path = path

    # Open device
    result = iokit.IOHIDDeviceOpen(self.device_handle, 0)
    if result != K_IO_RETURN_SUCCESS:
      raise errors.OsHidError('Failed to open device for communication: {}'
                              .format(result))

    # Create read queue
    self.read_queue = queue.Queue()

    # Create and start read thread
    self.run_loop_ref = None
    self.read_thread = threading.Thread(target=DeviceReadThread,
                                        args=(self,))
    self.read_thread.daemon = True
    self.read_thread.start()

    # Read max report sizes for in/out
    self.internal_max_in_report_len = GetDeviceIntProperty(
        self.device_handle,
        HID_DEVICE_PROPERTY_MAX_INPUT_REPORT_SIZE)
    if not self.internal_max_in_report_len:
      raise errors.OsHidError('Unable to obtain max in report size')

    self.internal_max_out_report_len = GetDeviceIntProperty(
        self.device_handle,
        HID_DEVICE_PROPERTY_MAX_OUTPUT_REPORT_SIZE)
    if not self.internal_max_out_report_len:
      raise errors.OsHidError('Unable to obtain max out report size')

    # Register read callback
    self.in_report_buffer = (ctypes.c_uint8 * self.internal_max_in_report_len)()
    iokit.IOHIDDeviceRegisterInputReportCallback(
        self.device_handle,
        self.in_report_buffer,
        self.internal_max_in_report_len,
        REGISTERED_READ_CALLBACK,
        ctypes.py_object(self.read_queue))

  def GetInReportDataLength(self):
    """See base class."""
    return self.internal_max_in_report_len

  def GetOutReportDataLength(self):
    """See base class."""
    return self.internal_max_out_report_len

  def Write(self, packet):
    """See base class."""
    report_id = 0
    out_report_buffer = (ctypes.c_uint8 * self.internal_max_out_report_len)()
    out_report_buffer[:] = packet[:]

    result = iokit.IOHIDDeviceSetReport(self.device_handle,
                                        K_IO_HID_REPORT_TYPE_OUTPUT,
                                        report_id,
                                        out_report_buffer,
                                        self.internal_max_out_report_len)

    # Non-zero status indicates failure
    if result != K_IO_RETURN_SUCCESS:
      raise errors.OsHidError('Failed to write report to device')

  def Read(self):
    """See base class."""

    result = None
    while result is None:
        try:
            result = self.read_queue.get(timeout=60)
        except queue.Empty:
            continue

    return result

  def __del__(self):
    # Unregister the callback
    if hasattr(self, 'in_report_buffer'):
        iokit.IOHIDDeviceRegisterInputReportCallback(
            self.device_handle,
            self.in_report_buffer,
            self.internal_max_in_report_len,
            None,
            None)

    # Stop the run loop
    if hasattr(self, 'run_loop_ref'):
        cf.CFRunLoopStop(self.run_loop_ref)

    # Wait for the read thread to exit
    if hasattr(self, 'read_thread'):
        self.read_thread.join()


#!/usr/bin/env python3

from datetime import time

# lunch between noon and 3pm
lunch_start = time(12, 0, 0)
lunch_end   = time(15, 0, 0)

# night betwen 10pm and 7am
night_start = time(22, 0, 0)
night_end   = time(7, 0, 0)


import numpy as np
import matplotlib.pyplot as plt

def parametric_track(d, samples):
    # function for the definition of a parametric track

    # define the extremal points of the segments
    length = (4 + np.pi) * d
    t_a = 2 * d / length
    t_b = t_a + (d * np.pi / 2) / length
    t_c = t_b + 2 * d / length
    t_d = 1

    t_interval = 1. / samples
    points = np.zeros((samples, 3)) # x, y, orientation respect to center
    sector = ['A']*samples

    # evaluate the points
    t = 0
    x = 0
    y = 0
    theta = 0
    for i in range(0, samples):
        if t <= t_a:
            x = t * 2 * d / t_a
            y = 0
            theta = 0
            sector[i] = 'A'
        elif t_a < t <= t_b:
            x = 2 * d + (d / 2.) * np.cos(-np.pi * (t - t_a) / (t_b - t_a) + np.pi / 2)
            y = -d / 2. + (d / 2.) * np.sin(-np.pi * (t - t_a) / (t_b - t_a) + np.pi / 2)
            theta = -np.pi * (t - t_a) / (t_b - t_a) #+ np.pi / 2
            sector[i] = 'B'
        elif t_b < t <= t_c:
            x = 2 * d - (t - t_b) * 2 * d / (t_c - t_b)
            y = -d
            theta = 0
            sector[i] = 'C'
        elif t_c < t <= t_d:
            x = (d / 2.) * np.cos(+np.pi * (1 - ((t - t_c) / (t_d - t_c))) + np.pi / 2)
            y = -d / 2. + (d / 2.) * np.sin(+np.pi * (1 - ((t - t_c) / (t_d - t_c))) + np.pi / 2)
            theta = np.pi*(1 - ((t - t_c) / (t_d - t_c))) #+ np.pi / 2
            sector[i] = 'D'

        points[i, 0] = x
        points[i, 1] = y
        points[i, 2] = theta
        t += t_interval
        # print("t = {}, point = {}".format(t, points[i, :]))
    return points, sector

#
# test code for the function
#
# d = 10
# samples = 100
# array = parametric_track(d, samples)
# # plot
# plt.plot(array[:, 0], array[:, 1], 'ro')
# plt.show()


from models import Recruiter, Programmer, Candidate, Vacancy

def main():
    recruiter1 = Recruiter('Natali', nata@gmail.com, 20)
    programmer1 = Programmer('Alex', alex@mail.ru, 50)
    programmer2 = Programmer('Roman', roman@gmail.com, 60)
    candidate1 = Candidate('Vasil', vasyok@gmail.com, 'Python')
    candidate2 = Candidate('Grisha', grigor@rambler.ru, 'Python')
    candidate3 = Candidate('Katya', kate@gmail.com, 'FrontEnd')
    vacancy1 = Vacancy('Python')
    vacancy2 = Vacancy('FrontEnd')

if __name__ == '__main__':
    main()


# Definition for a binary tree node.
class TreeNode(object):
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
class Solution(object):
    def invertTree(self, root):
        """
        :type root: TreeNode
        :rtype: TreeNode
        """
        # base case:
        # if root has no children or root is null
        if root is None:
            return

        # swap trees
        if root.right is None and root.left is None:
            return root
        else:
            temp = root.left
            root.left = root.right
            root.right = temp

        self.invertTree(root.left)
        self.invertTree(root.right)

        return root


# 1. Реализовать класс «Дата», функция-конструктор которого должна принимать дату в виде строки формата
# «день-месяц-год». В рамках класса реализовать два метода. Первый, с декоратором @classmethod, должен
# извлекать число, месяц, год и преобразовывать их тип к типу «Число». Второй, с декоратором @staticmethod,
# должен проводить валидацию числа, месяца и года (например, месяц — от 1 до 12). Проверить работу
# полученной структуры на реальных данных.
class Data:
    def __init__(self, day_month_year):
        # self.day = day
        # self.month = month
        # self.year = year
        self.day_month_year = str(day_month_year)

    @classmethod
    def extract(cls, day_month_year):
        my_date = []

        for i in day_month_year.split():
            if i != '-': my_date.append(i)

        return int(my_date[0]), int(my_date[1]), int(my_date[2])

    @staticmethod
    def check(day, month, year):

        if 1 <= day <= 31:
            if 1 <= month <= 12:
                if 2019 >= year >= 0:
                    return f'Верно'
                else:
                    return f'Неверный год'
            else:
                return f'Неверный месяц'
        else:
            return f'Неверный день'

    def __str__(self):
        return f'Текущая дата {Data.extract(self.day_month_year)}'

today = Data('11 - 1 - 2001')
print(today)
print(Data.check(12, 4, 2022))
print(today.check(11, 13, 2011))
print(Data.extract('11 - 11 - 2011'))
print(today.extract('11 - 11 - 2020'))
print(Data.check(1, 11, 2000))

# 2. Создайте собственный класс-исключение, обрабатывающий ситуацию деления на нуль.
# Проверьте его работу на данных, вводимых пользователем. При вводе пользователем нуля в качестве делителя
# программа должна корректно обработать эту ситуацию и не завершиться с ошибкой.

class DivisionByZero:
    def __init__(self, divider, denominator):
        self.divider = divider
        self.denominator = denominator

    @staticmethod
    def divide_by_null(divider, denominator):
        try:
            return (divider / denominator)
        except:
            return (f"Деление на ноль не разрешено")

div = DivisionByZero(10, 100)
print(DivisionByZero.divide_by_null(10, 0))
print(DivisionByZero.divide_by_null(10, 0.1))
print(div.divide_by_null(100, 0))

# 3. Создайте собственный класс-исключение, который должен проверять содержимое списка на наличие только чисел.
# Проверить работу исключения на реальном примере. Необходимо запрашивать у пользователя данные и заполнять список
# только числами. Класс-исключение должен контролировать типы данных элементов списка.
# Примечание: длина списка не фиксирована. Элементы запрашиваются бесконечно, пока пользователь сам не остановит
# работу скрипта, введя, например, команду “stop”. При этом скрипт завершается, сформированный список с числами выводится на экран.
# Подсказка: для данного задания примем, что пользователь может вводить только числа и строки. При вводе пользователем
# очередного элемента необходимо реализовать проверку типа элемента и вносить его в список, только если введено число.
# Класс-исключение должен не позволить пользователю ввести текст (не число) и отобразить соответствующее сообщение.
# При этом работа скрипта не должна завершаться.

class Error:
    def __init__(self, *args):
        self.my_list = []

    def my_input(self):
        while True:
            try:
                val = int(input('Введите значения'))
                self.my_list.append(val)
                print(f'Текущий список - {self.my_list} \n ')
            except:
                print(f"Недопустимое значение")
                y_or_n = input(f'Еще одна попытка? Y/N ')

                if y_or_n == 'Y' or y_or_n == 'y':
                    print(try_except.my_input())
                elif y_or_n == 'N' or y_or_n == 'n':
                    return f'Выход'
                else:
                    return f'Выход'

try_except = Error(1)
print(try_except.my_input())

# 4. Начните работу над проектом «Склад оргтехники». Создайте класс, описывающий склад.
# А также класс «Оргтехника», который будет базовым для классов-наследников. Эти классы — конкретные типы оргтехники
# (принтер, сканер, ксерокс). В базовом классе определить параметры, общие для приведенных типов.
# В классах-наследниках реализовать параметры, уникальные для каждого типа оргтехники.
from datetime import datetime

class Warehouse:
    def __init__(self, title):
        self.title = title
        self.lists = {}
        self.give_lists = {}

    def take_to_wh(self, equipment):
        t = datetime.now()
        self.lists.update({equipment.serial_number:[equipment.title, self,t]})
        print('На склад '+self.title+' получено оборудование:'+ '' +equipment.title+' ,серийный номер - '+ str(equipment.serial_number)+', Дата:'
              + str(t.day)+'.'+str(t.month)+'.'+str(t.year))

    def give_to_wh(self, equipment, other):
        t = datetime.now()
        self.give_lists.update({equipment.serial_number: [equipment.title,other, t]})
        print('Передано оборудование:' + '' + equipment.title + ' ,серийный номер - ' + str(
            equipment.serial_number) + ', Дата:'
              + str(t.day) + '.' + str(t.month) + '.' + str(t.year))
        other.take_to_wh(equipment)

    def list_equipments(self):
        print('На склад '+self.title + ' получено оборудование:')
        print(self.lists)
        print('Общее количество: ', len(self.lists))
        print('Со склада '+self.title + ' выдано оборудование:')
        print(self.give_lists)
        print('Общее количество: ', len(self.give_lists))

class Equipment:
    def __init__(self, title, serial_number):
        self.title = title
        self.serial_number = serial_number

    def __str__(self):
        return str(self.title)

class Printer(Equipment):
    def __init__(self,title,serial_number, print_velocity):
        Equipment.__init__(self, title, serial_number)
        self.print_velocity = print_velocity

    def __str__(self):
        return  'Название модели:' + Equipment.__str__(self) + ' ,Параметры: ' + str(self.print_velocity)

class Scanner(Equipment):
    def __init__(self, title,serial_number,resolution):
        Equipment.__init__(self, title, serial_number)
        self.resolution = resolution

    def __str__(self):
        return  'Название модели:' + Equipment.__str__(self) + ' ,Параметры: ' + str(self.resolution)

class Copier(Equipment):
    def __init__(self, title,serial_number, addit):
        Equipment.__init__(self, title, serial_number)
        self.addit = addit

    def __str__(self):
        return  'Название модели:' + Equipment.__str__(self) + ' ,Параметры: ' + str(self.addit)

store1 = Warehouse('First warehouse')
store2 = Warehouse('Second warehouse')
a = Printer('HP',345678,100)
b = Scanner('Epson',123456,4000)
c = Copier('Brother',987654, 50)
d = Printer('HP',245678,200)

print(a)
print(b)
print(c)

store1.take_to_wh(a)
store1.take_to_wh(b)
store1.take_to_wh(c)
store1.take_to_wh(d)

store1.give_to_wh(a, store2)

store1.list_equipments()
store2.list_equipments()

# 5. Продолжить работу над первым заданием. Разработать методы, отвечающие за приём оргтехники на склад и
# передачу в определенное подразделение компании. Для хранения данных о наименовании и количестве единиц оргтехники,
# а также других данных, можно использовать любую подходящую структуру, например словарь.

# 6. Продолжить работу над вторым заданием. Реализуйте механизм валидации вводимых пользователем данных.
# Например, для указания количества принтеров, отправленных на склад, нельзя использовать строковый тип данных.
# Подсказка: постарайтесь по возможности реализовать в проекте «Склад оргтехники» максимум возможностей,
# изученных на уроках по ООП.

# 7. Реализовать проект «Операции с комплексными числами». Создайте класс «Комплексное число»,
# реализуйте перегрузку методов сложения и умножения комплексных чисел. Проверьте работу проекта,
# создав экземпляры класса (комплексные числа) и выполнив сложение и умножение созданных экземпляров.
# Проверьте корректность полученного результата.
class ComplexNumber:
    def __init__(self, a, b, *args):
        self.a = a
        self.b = b
        self.z = 'a + b * i'

    def __add__(self, other):
        print(f'Сумма z1 и z2 равна')
        return f'z = {self.a + other.a} + {self.b + other.b} * i'

    def __mul__(self, other):
        print(f'Произведение z1 и z2 равно')
        return f'z = {self.a * other.a - (self.b * other.b)} + {self.b * other.a} * i'

    def __str__(self):
        return f'z = {self.a} + {self.b} * i'

z_1 = ComplexNumber(1, -2)
z_2 = ComplexNumber(3, 4)
print(z_1)
print(z_1 + z_2)
print(z_1 * z_2)


"""Conformer workload implemented in PyTorch."""

import contextlib
import functools
import math
import random
from typing import Dict, Iterator, Optional, Tuple

import torch
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP

from algorithmic_efficiency import data_utils
from algorithmic_efficiency import param_utils
from algorithmic_efficiency import pytorch_utils
from algorithmic_efficiency import spec
import algorithmic_efficiency.random_utils as prng
from algorithmic_efficiency.workloads.librispeech_conformer import metrics
from algorithmic_efficiency.workloads.librispeech_conformer import workload
from algorithmic_efficiency.workloads.librispeech_conformer.input_pipeline import \
    LibriSpeechDataset
from algorithmic_efficiency.workloads.librispeech_conformer.librispeech_pytorch import \
    models as conformer_model

USE_PYTORCH_DDP, RANK, DEVICE, N_GPUS = pytorch_utils.pytorch_setup()

MAX_INPUT_LENGTH = 320000

class LibriSpeechConformerWorkload(workload.BaseLibrispeechWorkload):

  def __init__(self,
               tokenizer_vocab_path: Optional[str] = None,
               use_specaug: bool = True) -> None:
    super().__init__()
    self.tokenizer = metrics.load_tokenizer(tokenizer_vocab_path)
    self.use_specaug = use_specaug

  def init_model_fn(
      self,
      rng: spec.RandomState,
      dropout_rate: Optional[float] = None,
      aux_dropout_rate: Optional[float] = None) -> spec.ModelInitState:
    """Conformer model init function.

    Here we use dropout_rate as residual_dropout_rate, and aux_dropout_rate as
    input_dropout_rate.
    """
    torch.random.manual_seed(rng[0])
    # Configure torch backends to avoid OOM errors.
    torch.backends.cudnn.benchmark = False
    torch.backends.cuda.enable_flash_sdp(False)
    torch.backends.cuda.enable_mem_efficient_sdp(False)
    torch.backends.cuda.enable_math_sdp(True)
    model = conformer_model.ConformerEncoderDecoder(
        conformer_model.ConformerConfig(
            attention_residual_dropout_rate=dropout_rate,
            feed_forward_residual_dropout_rate=dropout_rate,
            conv_residual_dropout_rate=dropout_rate,
            input_dropout_rate=aux_dropout_rate,
            use_specaug=self.use_specaug))
    self.ctc_loss = torch.nn.CTCLoss(blank=0, reduction='none')
    conformer_model.initialize(model)
    self._param_shapes = param_utils.pytorch_param_shapes(model)
    self._param_types = param_utils.pytorch_param_types(self._param_shapes)
    model.to(DEVICE)
    self.requires_sync_before_eval = False
    if N_GPUS > 1:
      if USE_PYTORCH_DDP:
        self.requires_sync_before_eval = True
        model = DDP(model, device_ids=[RANK], output_device=RANK)
      else:
        model = torch.nn.DataParallel(model)
    return model, None

  def is_output_params(self, param_key: spec.ParameterKey) -> bool:
    return param_key in ['lin.weight', 'lin.bias']

  def model_fn(
      self,
      params: spec.ParameterContainer,
      augmented_and_preprocessed_input_batch: Dict[str, spec.Tensor],
      model_state: spec.ModelAuxiliaryState,
      mode: spec.ForwardPassMode,
      rng: spec.RandomState,
      update_batch_norm: bool) -> Tuple[spec.Tensor, spec.ModelAuxiliaryState]:
    del model_state
    del rng

    model = params
    if mode == spec.ForwardPassMode.EVAL:
      model.eval()
    if mode == spec.ForwardPassMode.TRAIN:
      model.train()
      model.apply(
          functools.partial(
              pytorch_utils.update_batch_norm_fn,
              update_batch_norm=update_batch_norm))

    contexts = {
        spec.ForwardPassMode.EVAL: torch.no_grad,
        spec.ForwardPassMode.TRAIN: contextlib.nullcontext,
    }
    with contexts[mode]():
      inputs, input_paddings = augmented_and_preprocessed_input_batch['inputs']
      logits, logits_paddings = model(inputs.to(DEVICE),
                                      input_paddings.to(DEVICE))
    return (logits, logits_paddings), None

  def _build_input_queue(
      self,
      data_rng: spec.RandomState,
      split: str,
      data_dir: str,
      global_batch_size: int,
      cache: Optional[bool] = None,
      repeat_final_dataset: Optional[bool] = None,
      num_batches: Optional[int] = None) -> Iterator[Dict[str, spec.Tensor]]:
    del cache
    del repeat_final_dataset
    del num_batches

    is_train = split == 'train'
    if split == 'train':
      ds_split = 'train-clean-100+train-clean-360+train-other-500'
    elif split == 'eval_train':
      ds_split = 'train-clean-100+train-clean-360+train-other-500'
    elif split == 'validation':
      ds_split = 'dev-clean+dev-other'
    else:
      ds_split = 'test-clean'

    ds = LibriSpeechDataset(split=ds_split, data_dir=data_dir)
    if split == 'eval_train':
      indices = list(range(len(ds)))
      random.Random(data_rng[0]).shuffle(indices)
      ds = torch.utils.data.Subset(ds, indices[:self.num_eval_train_examples])

    sampler = None
    if USE_PYTORCH_DDP:
      per_device_batch_size = global_batch_size // N_GPUS
      ds_iter_batch_size = per_device_batch_size
    else:
      ds_iter_batch_size = global_batch_size
    if USE_PYTORCH_DDP:
      if is_train:
        sampler = torch.utils.data.distributed.DistributedSampler(
            ds, num_replicas=N_GPUS, rank=RANK, shuffle=True)
      else:
        sampler = data_utils.DistributedEvalSampler(
            ds, num_replicas=N_GPUS, rank=RANK, shuffle=False)
    dataloader = torch.utils.data.DataLoader(
        ds,
        batch_size=ds_iter_batch_size,
        shuffle=not USE_PYTORCH_DDP and is_train,
        sampler=sampler,
        num_workers=4,
        pin_memory=True,
        drop_last=is_train)

    dataloader = data_utils.cycle(
        dataloader, custom_sampler=USE_PYTORCH_DDP, use_mixup=False)
    return dataloader

  # Does NOT apply regularization, which is left to the submitter to do in
  # `update_params`.
  def loss_fn(
      self,
      label_batch: Tuple[spec.Tensor, spec.Tensor],  # (label_batch, padding)
      logits_batch: Tuple[spec.Tensor, spec.Tensor],  # (logits_batch, padding)
      mask_batch: Optional[spec.Tensor] = None,
      label_smoothing: float = 0.0) -> Dict[str, spec.Tensor]:  # differentiable
    """Evaluate the (masked) loss function at (label_batch, logits_batch).

    Return {'summed': scalar summed loss, 'n_valid_examples': scalar number of
    valid examples in batch, 'per_example': 1-d array of per-example losses}
    (not synced across devices).
    """
    del label_smoothing
    targets, target_paddings = label_batch
    logits, logit_paddings = logits_batch
    logprobs = torch.log_softmax(logits, dim=-1)
    input_lengths = torch.einsum('bh->b', 1 - logit_paddings).long()
    target_lengths = torch.einsum('bh->b', 1 - target_paddings).long()
    per_example_losses = self.ctc_loss(
        logprobs.permute(1, 0, 2),
        targets.long(),
        input_lengths,
        target_lengths)
    # mask_batch is assumed to be shape [batch].
    if mask_batch is not None:
      per_example_losses *= mask_batch
      mask_batch = torch.logical_and(mask_batch, target_lengths)
    else:
      mask_batch = target_lengths
    n_valid_examples = mask_batch.sum().to(per_example_losses)
    summed_loss = per_example_losses.sum()
    n_valid_examples = max(n_valid_examples, 1)
    return {
        'summed': summed_loss,
        'n_valid_examples': torch.as_tensor(n_valid_examples, device=DEVICE),
        'per_example': per_example_losses,
    }

  def greedy_decode(
      self, logits: spec.Tensor,
      logit_paddings: spec.Tensor) -> Tuple[spec.Tensor, spec.Tensor]:
    framewise_tokens = logits.max(dim=-1)[1]
    framewise_tokens = framewise_tokens * (1 - logit_paddings)

    # Add sentinel because unique_consecutive will flatten array
    # and then compute the unique.
    framewise_tokens = torch.cat(
        [framewise_tokens, -torch.ones_like(framewise_tokens[:, 0:1])], dim=1)
    _, indices = torch.unique_consecutive(framewise_tokens, return_inverse=True)
    indices -= indices.min(dim=1, keepdims=True)[0]
    result = torch.zeros_like(framewise_tokens)
    result = result.scatter_(1, indices, framewise_tokens)

    # Replace the sentinel column with 0s and remove it.
    result[result == -1] = 0
    result = result[:, :-1]

    # Remove blanks (id = 0).
    blank_id = 0
    fin_result = torch.zeros_like(result)
    idxs = torch.arange(
        fin_result.numel(), device=result.device).view(*fin_result.shape)
    mask = torch.arange(
        fin_result.shape[1], device=result.device).view(
            1, -1) < result.count_nonzero(dim=1).view(-1, 1)
    fin_result.view(-1)[idxs[mask != 0]] = result[result != blank_id]
    padding = fin_result == 0
    return fin_result, padding

  def sync_sd(self, params: spec.ParameterContainer) -> None:
    sd = params.state_dict()
    dist.barrier()
    for k in sd:
      dist.all_reduce(sd[k], op=dist.ReduceOp.SUM)
      # Assumes N_GPUS is the world size.
      sd[k] = sd[k] / N_GPUS
    params.load_state_dict(sd)

  def _eval_model_on_split(self,
                           split: str,
                           num_examples: int,
                           global_batch_size: int,
                           params: spec.ParameterContainer,
                           model_state: spec.ModelAuxiliaryState,
                           rng: spec.RandomState,
                           data_dir: str,
                           global_step: int = 0) -> Dict[str, float]:
    """Run a full evaluation of the model."""
    del global_step
    data_rng, model_rng = prng.split(rng, 2)
    if split not in self._eval_iters:
      # These iterators repeat indefinitely.
      self._eval_iters[split] = (
          self._build_input_queue(
              data_rng, split, data_dir, global_batch_size=global_batch_size))

    total_metrics = {
        'loss': torch.tensor(0., device=DEVICE),
        'lengths': torch.tensor(0., device=DEVICE),
        'word_errors': torch.tensor(0., device=DEVICE),
        'num_words': torch.tensor(0., device=DEVICE),
    }
    num_batches = int(math.ceil(num_examples / global_batch_size))
    if self.requires_sync_before_eval:
      self.sync_sd(params)
    for _ in range(num_batches):
      batch = next(self._eval_iters[split])

      (logits, logits_padding), _ = self.model_fn(
          params,
          batch,
          model_state,
          spec.ForwardPassMode.EVAL,
          model_rng,
          update_batch_norm=False)
      decoded, decoded_paddings = self.greedy_decode(logits, logits_padding)
      targets, target_paddings = batch['targets']
      word_errors, num_words = metrics.compute_wer(
          decoded=decoded.cpu().numpy(),
          decoded_paddings=decoded_paddings.cpu().numpy(),
          targets=targets.cpu().numpy(),
          target_paddings=target_paddings.cpu().numpy(),
          tokenizer=self.tokenizer)
      loss = self.loss_fn((targets, target_paddings), (logits, logits_padding))
      summed_loss = loss['summed']
      lengths = loss['n_valid_examples']
      batch_metrics = {
          'loss': summed_loss,
          'lengths': lengths,
          'word_errors': word_errors,
          'num_words': num_words,
      }
      total_metrics = {
          k: v + batch_metrics[k] for k, v in total_metrics.items()
      }
    if USE_PYTORCH_DDP:
      for metric in total_metrics.values():
        dist.all_reduce(metric)
    return {
        'ctc_loss':
            float(total_metrics['loss'].item() /
                  total_metrics['lengths'].item()),
        'wer':
            float(total_metrics['word_errors'].item() /
                  total_metrics['num_words'].item()),
    }


import pickle
import random
from collections import namedtuple
from typing import Tuple

import cv2
import lmdb
import numpy as np
from path import Path

Sample = namedtuple('Sample', 'gt_text, file_path')
Batch = namedtuple('Batch', 'imgs, gt_texts, batch_size')

class DataLoaderIAM:
    """
    Loads data which corresponds to IAM format,
    see: http://www.fki.inf.unibe.ch/databases/iam-handwriting-database
    """

    def __init__(self,
                 data_dir: Path,
                 batch_size: int,
                 data_split: float = 0.95,
                 fast: bool = True) -> None:
        """Loader for dataset."""

        assert data_dir.exists()

        self.fast = fast
        if fast:
            self.env = lmdb.open(str(data_dir / 'lmdb'), readonly=True)

        self.data_augmentation = False
        self.curr_idx = 0
        self.batch_size = batch_size
        self.samples = []

        f = open(data_dir / 'gt/words.txt')
        chars = set()
        bad_samples_reference = ['a01-117-05-02', 'r06-022-03-05']  # known broken images in IAM dataset
        for line in f:
            # ignore empty and comment lines
            line = line.strip()
            if not line or line[0] == '#':
                continue

            line_split = line.split(' ')
            assert len(line_split) >= 9

            # filename: part1-part2-part3 --> part1/part1-part2/part1-part2-part3.png
            file_name_split = line_split[0].split('-')
            file_name_subdir1 = file_name_split[0]
            file_name_subdir2 = f'{file_name_split[0]}-{file_name_split[1]}'
            file_base_name = line_split[0] + '.png'
            file_name = data_dir / 'img' / file_name_subdir1 / file_name_subdir2 / file_base_name

            if line_split[0] in bad_samples_reference:
                print('Ignoring known broken image:', file_name)
                continue

            # GT text are columns starting at 9
            gt_text = ' '.join(line_split[8:])
            chars = chars.union(set(list(gt_text)))

            # put sample into list
            self.samples.append(Sample(gt_text, file_name))

        # split into training and validation set: 95% - 5%
        split_idx = int(data_split * len(self.samples))
        self.train_samples = self.samples[:split_idx]
        self.validation_samples = self.samples[split_idx:]

        # put words into lists
        self.train_words = [x.gt_text for x in self.train_samples]
        self.validation_words = [x.gt_text for x in self.validation_samples]

        # start with train set
        self.train_set()

        # list of all chars in dataset
        self.char_list = sorted(list(chars))

    def train_set(self) -> None:
        """Switch to randomly chosen subset of training set."""
        self.data_augmentation = True
        self.curr_idx = 0
        random.shuffle(self.train_samples)
        self.samples = self.train_samples
        self.curr_set = 'train'

    def validation_set(self) -> None:
        """Switch to validation set."""
        self.data_augmentation = False
        self.curr_idx = 0
        self.samples = self.validation_samples
        self.curr_set = 'val'

    def get_iterator_info(self) -> Tuple[int, int]:
        """Current batch index and overall number of batches."""
        if self.curr_set == 'train':
            num_batches = int(np.floor(len(self.samples) / self.batch_size))  # train set: only full-sized batches
        else:
            num_batches = int(np.ceil(len(self.samples) / self.batch_size))  # val set: allow last batch to be smaller
        curr_batch = self.curr_idx // self.batch_size + 1
        return curr_batch, num_batches

    def has_next(self) -> bool:
        """Is there a next element?"""
        if self.curr_set == 'train':
            return self.curr_idx + self.batch_size <= len(self.samples)  # train set: only full-sized batches
        else:
            return self.curr_idx < len(self.samples)  # val set: allow last batch to be smaller

    def _get_img(self, i: int) -> np.ndarray:
        if self.fast:
            with self.env.begin() as txn:
                basename = Path(self.samples[i].file_path).basename()
                data = txn.get(basename.encode("ascii"))
                img = pickle.loads(data)
        else:
            img = cv2.imread(self.samples[i].file_path, cv2.IMREAD_GRAYSCALE)

        return img

    def get_next(self) -> Batch:
        """Get next element."""
        batch_range = range(self.curr_idx, min(self.curr_idx + self.batch_size, len(self.samples)))

        imgs = [self._get_img(i) for i in batch_range]
        gt_texts = [self.samples[i].gt_text for i in batch_range]

        self.curr_idx += self.batch_size
        return Batch(imgs, gt_texts, len(imgs))


from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
    # url(r'^index/(?P<page>[0-9]+)/$', views.index, name='index'),
    url(r'^login/$', views.login, name='login'),
    url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
    url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
    url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
    url(r'^ques/$', views.ques, name='ques'),
    url(r'^ques/(?P<question_id>[0-9]+)/$', views.ques, name='ques'),
    url(r'^signup/$', views.signup, name='signup'),
    url(r'^logout/$', views.logout, name='logout')
]


from __future__ import print_function

REQ_VER = (3,3)
import sys
if sys.version_info < REQ_VER:
    print('Need at least python {0}.{1} to run this script'.format(*REQ_VER), file=sys.stderr)
    sys.exit(1)

import os
import os.path
import venv

from subprocess import Popen, PIPE
from threading import Thread
from urllib.parse import urlparse
from urllib.request import urlretrieve
from shutil import rmtree

class ExtendedEnvBuilder(venv.EnvBuilder):
    """
    This builder installs setuptools and pip so that you can pip or
    easy_install other packages into the created environment.
    """

    def __init__(self, *args, **kwargs):
        self.verbose = kwargs.pop('verbose', False)
        super().__init__(*args, **kwargs)

    def post_setup(self, context):
        """
        Set up any packages which need to be pre-installed into the
        environment being created.

        :param context: The information for the environment creation request
                        being processed.
        """
        os.environ['VIRTUAL_ENV'] = context.env_dir
        self.install_setuptools(context)
        self.install_pip(context)
        setup = os.path.abspath(os.path.join(context.env_dir, '../setup.py'))
        self.install_script(context, 'sima', setup=setup)

    def reader(self, stream, context):
        """
        Read lines from a subprocess' output stream and write progress
        information to sys.stderr.
        """
        while True:
            s = stream.readline()
            if not s:
                break
            if not self.verbose:
                sys.stderr.write('.')
            else:
                sys.stderr.write(s.decode('utf-8'))
            sys.stderr.flush()
        stream.close()

    def install_script(self, context, name, url=None, setup=None):
        if url:
            binpath = context.bin_path
            _, _, path, _, _, _ = urlparse(url)
            fn = os.path.split(path)[-1]
            distpath = os.path.join(binpath, fn)
            # Download script into the env's binaries folder
            urlretrieve(url, distpath)
        if url:
            args = [context.env_exe, fn]
        else:
            args = [context.env_exe, setup, 'install']
            binpath = os.path.dirname(setup)
        if self.verbose:
            term = '\n'
        else:
            term = ''
        sys.stderr.write('Installing %s ...%s' % (name, term))
        sys.stderr.flush()
        # Install in the env
        p = Popen(args, stdout=PIPE, stderr=PIPE, cwd=binpath)
        t1 = Thread(target=self.reader, args=(p.stdout, 'stdout'))
        t1.start()
        t2 = Thread(target=self.reader, args=(p.stderr, 'stderr'))
        t2.start()
        p.wait()
        t1.join()
        t2.join()
        sys.stderr.write('done.\n')
        if url:
            # Clean up - no longer needed
            os.unlink(distpath)

    def install_setuptools(self, context):
        """
        Install setuptools in the environment.

        :param context: The information for the environment creation request
                        being processed.
        """
        url = 'https://bitbucket.org/pypa/setuptools/downloads/ez_setup.py'
        self.install_script(context, 'setuptools', url)
        # clear up the setuptools archive which gets downloaded
        pred = lambda o: o.startswith('setuptools-') and o.endswith('.tar.gz')
        files = filter(pred, os.listdir(context.bin_path))
        for f in files:
            f = os.path.join(context.bin_path, f)
            os.unlink(f)

    def install_pip(self, context):
        """
        Install pip in the environment.

        :param context: The information for the environment creation request
                        being processed.
        """
        url = 'https://raw.github.com/pypa/pip/master/contrib/get-pip.py'
        self.install_script(context, 'pip', url)
        # pip installs to "local/bin" on Linux, but it needs to be accessible
        # from "bin" since the "activate" script prepends "bin" to $PATH
        pip_path = os.path.join(context.env_dir, 'local', 'bin', 'pip')
        if sys.platform != 'win32' and os.path.exists(pip_path):
            self.symlink_or_copy(pip_path, os.path.join(context.bin_path, 'pip'))

def main(args=None):
    root = os.path.dirname(os.path.abspath(__file__))
    vdir = os.path.join(root, 'venv')
    builder = ExtendedEnvBuilder(clear=True, verbose=False)
    builder.create(vdir)
    # clean up
    for residu in ['MPD_sima.egg-info', 'dist', 'build']:
        if os.path.exists(os.path.join(root, residu)):
            rmtree(os.path.join(root, residu))
    # Write wrapper
    with open(os.path.join(root, 'vmpd-sima'),'w') as fd:
        fd.write('#!/bin/sh\n')
        fd.write('. "{}/venv/bin/activate"\n'.format(root))
        fd.write('"{}/venv/bin/mpd-sima" "$@"'.format(root))
    os.chmod(os.path.join(root, 'vmpd-sima'), 0o744)

if __name__ == '__main__':
    rc = 1
    try:
        main()
        rc = 0
    except ImportError as e:
        print('Error: %s' % e)
    sys.exit(rc)


from tree import Node
import random

class TreeNode(Node):
    def __init__(self, val=None):
        super().__init__(data=val)
        self._lock_state = False

    def insertNode(self, val):
        if self.left is None and self.right is not None:
            self.left = TreeNode(val)
            self.left.parent = self
        elif self.right is None and self.left is not None:
            self.right = TreeNode(val)
            self.right.parent = self
        elif self.left is None and self.right is None:
            choice = random.choice(['LEFT', 'RIGHT'])
            if choice=='LEFT':
                self.left = TreeNode(val)
                self.left.parent = self
            else:
                self.right = TreeNode(val)
                self.right.parent = self
        elif self.left is not None and self.right is not None:
            choice = random.choice(['LEFT', 'RIGHT'])
            if choice=='LEFT':
                self.left.insertNode(val)
            else:
                self.right.insertNode(val)

    def lock(self):
        if self.parent._lock_state or self.left._lock_state or self.right._lock_state:
            return False, 'Not possible'
        self._lock_state = True
        return True

    def unlock(self):
        if self.parent._lock_state or self.left._lock_state or self.right._lock_state:
            return False, 'Not possible'
        self._lock_state = False
        return True

    def is_locked(self):
        return self._lock_state

if __name__=='__main__':
    tree = TreeNode('*')
    for _ in range(20):
        val = random.randint(1, 100)
        tree.insertNode(val)
    tree.prettyPrint()
    print('\n\n\n')
    print(tree.left.lock()) #should lock and returnn true
    print(tree.is_locked()) #should be false
    print(tree.left.is_locked()) #should be true
    print(tree.left.left.is_locked()) #should be false
    print(tree.left.left.unlock()) #should not be possible
    print(tree.left.unlock()) #should be possible
    print(tree.left.left.is_locked()) #should be false


from typing import final
import pyhik.hikvision as hikvision
import asyncio
import json
import websockets
import time

class VehicleInfo:
    def findPlate(xml):
        start = xml.find("<licensePlate>") + len("<licensePlate>")
        end = xml.find("</licensePlate>")
        plate = xml[start:end]
        return plate

    def findVehicleType(xml):
        start = xml.find("<vehicleType>") + len("<vehicleType>")
        end = xml.find("</vehicleType>")
        Type = xml[start:end]
        return Type

    def findVehicleColor(xml):
        start = xml.find("<color>") + len("<color>")
        end = xml.find("</color>")
        Color = xml[start:end]
        return Color

    def findVehicleDirect(xml):
        start = xml.find("<direction>") + len("<direction>")
        end = xml.find("</direction>")
        Color = xml[start:end]
        return Color

class PlateDetector:
    def __init__(self, callback = None):
        self.token = None
        self.camHost = "192.168.1.64"
        self.cam = hikvision.HikCamera(f'http://{self.camHost}', 80, 'admin', 'Solid321')
        self.callback = callback

    def refresh_token(self):
        try:
            response = self.cam.hik_request.get(self.cam.root_url + "/ISAPI/Security/token?format=json")
            resobj = json.loads(response.text)
            self.token = resobj["Token"]["value"]
        except Exception as e:
            print(e)

    async def listen_ws(self):
        while True:
            try:
                uri = f"ws://{self.camHost}:7681/ISAPI/Event/notification/subscribeEventCap?token=" + self.token
                async with websockets.connect(uri) as websocket:
                    greeting = await websocket.recv()

                    with open('hikmessage.xml', 'r') as file:
                        init = file.read().replace('\n', '')
                        await websocket.send(init)

                    while True: # plaka loop
                        greeting = await websocket.recv()
                        if type(greeting)is str and greeting.startswith('<?xml version="1.0"'):
                            InfoClass = VehicleInfo
                            plate = VehicleInfo.findPlate(greeting)
                            VehicleType = VehicleInfo.findVehicleType(greeting)
                            VehicleColor = VehicleInfo.findVehicleColor(greeting)
                            VehicleDirect= VehicleInfo.findVehicleDirect(greeting)

                            if self.callback is not None:
                                self.callback(plate,VehicleType,VehicleColor,VehicleDirect)

            except Exception as e:
                print(e)
                self.refresh_token()

            # time.sleep(1)

    def run(self):
        self.refresh_token()
        asyncio.get_event_loop().run_until_complete(self.listen_ws())


"""
Class for monitoring expiration information in HashiCorp Vault.
"""
from abc import ABC, abstractmethod
from typing import Dict, List, Type, TypeVar

import hvac
from prometheus_client import Gauge

from vault_monitor.expiration_monitor.vault_time import ExpirationMetadata

ExpirationMonitorType = TypeVar("ExpirationMonitorType", bound="ExpirationMonitor")  # pylint: disable=invalid-name

class ExpirationMonitor(ABC):
    """
    Monitors and updates custom metadata in HashiCorp Vault for expiration based on custom metadata.
    """

    secret_last_renewal_timestamp_gauge: Gauge
    secret_expiration_timestamp_gauge: Gauge

    last_renewal_gauge_name: str
    last_renewal_gauge_description: str
    expiration_gauge_name: str
    expiration_gauge_description: str

    def __init__(self, mount_point: str, monitored_path: str, vault_client: hvac.Client, service: str, prometheus_labels: Dict[str, str] = None, metadata_fieldnames: Dict[str, str] = None) -> None:
        """
        Creates an instance of the ExpirationMonitor class.
        """
        self.mount_point = mount_point
        self.monitored_path = monitored_path
        self.vault_client = vault_client
        self.service = service
        # Add the secret specific labels to the provided labels
        self.prometheus_labels = {"monitored_path": monitored_path, "mount_point": mount_point, "service": service}

        if prometheus_labels is not None:
            self.prometheus_labels.update(prometheus_labels)

        prometheus_label_keys = list(self.prometheus_labels.keys())

        if metadata_fieldnames is None:
            metadata_fieldnames = {}
        self.last_renewed_timestamp_fieldname = metadata_fieldnames.get("last_renewal_timestamp", "last_renewal_timestamp")
        self.expiration_timestamp_fieldname = metadata_fieldnames.get("expiration_timestamp", "expiration_timestamp")

        self.create_metrics(prometheus_label_keys)

    @classmethod
    def create_metrics(cls: Type[ExpirationMonitorType], prometheus_label_keys: List[str]) -> None:
        """
        Create the metrics, only happens once during the entire lifetime of the exporter (not with every object creation.)
        """
        # Only create the metric once
        if not hasattr(cls, "secret_last_renewal_timestamp_gauge"):
            cls.secret_last_renewal_timestamp_gauge = Gauge(cls.last_renewal_gauge_name, cls.last_renewal_gauge_description, prometheus_label_keys)
        if not hasattr(cls, "secret_expiration_timestamp_gauge"):
            cls.secret_expiration_timestamp_gauge = Gauge(cls.expiration_gauge_name, cls.expiration_gauge_description, prometheus_label_keys)

    @abstractmethod
    def get_expiration_info(self) -> ExpirationMetadata:
        """
        Abstract method for getting the expiration information
        """

    def update_metrics(self) -> None:
        """
        Update the current value for the metrics.
        """

        expiration_info = self.get_expiration_info()

        self.secret_last_renewal_timestamp_gauge.labels(**self.prometheus_labels).set(expiration_info.get_last_renewal_timestamp())
        self.secret_expiration_timestamp_gauge.labels(**self.prometheus_labels).set(expiration_info.get_expiration_timestamp())