from threading import Thread
import numpy as np
import cv2
import time
import math

class Window(Thread):
    def __init__(self, trackers):
        """
        This class defines the perception of the robot and implements the various detection and tracking algorithms needed
        :type name: Window
        """
        self.img = np.zeros((1080, 1920, 3), dtype=np.int32)
        self.first_frame = np.zeros((1080, 1920, 3), dtype=np.int32)
        self.trackers = trackers
        self.tracker_roi = (0, 0, 0, 0)
        self.tracking_success = False

    def detect_body_haar(self):
        """
        Summary line.
        implement fullbody detection with an haarcascade detector

        Parameters:
        self.img

        Returns:
        draw a box around the detected object, if a person is detected on self.img
        """
        fullbody_cascade = cv2.CascadeClassifier("haarcascade_fullbody.xml")

        gray = cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY)
        bodies = fullbody_cascade.detectMultiScale(gray)
        for (x, y, w, h) in bodies:
            cv2.rectangle(self.img, (x, y), (x + w, y + h), (255, 0, 0), 10)

        return bodies

    def detect_body_yolo(self):
        """

        :return:
        """

        def process_image(img):
            """Resize, reduce and expand image.

            # Argument:
                img: original image.

            # Returns
                image: ndarray(64, 64, 3), processed image.
            """
            image = cv2.resize(img, (1080, 1920),
                               interpolation=cv2.INTER_CUBIC)
            image = np.array(image, dtype='float32')
            image /= 255.
            image = np.expand_dims(image, axis=0)

            return image

        def get_classes(file):
            """Get classes name.

            # Argument:
                file: classes name for database.

            # Returns
                class_names: List, classes name.

            """
            with open(file) as f:
                class_names = f.readlines()
            class_names = [c.strip() for c in class_names]

            return class_names

        def draw(image, boxes, scores, classes, all_classes):
            for box, score, cl in zip(boxes, scores, classes):
                x, y, w, h = box

                top = max(0, np.floor(x + 0.5).astype(int))
                left = max(0, np.floor(y + 0.5).astype(int))
                right = min(image.shape[1], np.floor(x + w + 0.5).astype(int))
                bottom = min(image.shape[0], np.floor(y + h + 0.5).astype(int))

                cv2.rectangle(image, (top, left), (right, bottom), (255, 0, 0), 2)
                cv2.putText(image, '{0} {1:.2f}'.format(all_classes[cl], score),
                            (top, left - 6),
                            cv2.FONT_HERSHEY_SIMPLEX,
                            0.6, (0, 0, 255), 1,
                            cv2.LINE_AA)

                print('class: {0}, score: {1:.2f}'.format(all_classes[cl], score))
                print('box coordinate x,y,w,h: {0}'.format(box))

            print()

        def detect_image(image, yolo, all_classes):
            """Use yolo v3 to detect images.

            # Argument:
                image: original image.
                yolo: YOLO, yolo model.
                all_classes: all classes name.

            # Returns:
                image: processed image.
            """
            pimage = process_image(image)

            start = time.time()
            boxes, classes, scores = yolo.predict(pimage, image.shape)
            end = time.time()

            print('time: {0:.2f}s'.format(end - start))

            if boxes is not None:
                draw(image, boxes, scores, classes, all_classes)

            return image

        yolo = YOLO(0.3, 0.5)
        file = 'data/coco_classes.txt'
        all_classes = get_classes(file)

        # TODO get the boxes instead of directly drawing on the image
        self.img = detect_image(self.img, yolo, all_classes)

    def init_tracker(self, roi):
        """
        Summary line.
        used on the first frame to draw a box around the object to be tracked

        Parameters:
        self.first frame is used to define the ROI that initializes tracking

        Returns:
        set the new value for self.tracker_roi and self.tracker
        """

        roi = tuple(map(int, roi))
        tracker = cv2.TrackerMedianFlow_create
        self.trackers.add(tracker, self.img, roi)

    def tracker_display(self):
        """
        Summary line.
        implement tracking

        Parameters:
        the current value of self.tracker stored from the previous frame is used

        Returns:
        draw a box on self.img to keep track of the moving object. the value of self.roi is also modified and stored
        """
        (success, boxes) = self.trackers.update(self.img)

        for box in boxes:
            (x, y, w, h) = tuple(map(int, box))

        if success:
            p1 = (x,y)
            p2 = (x+w, y+h)
            cv2.rectangle((self.img, p1, p2, (0,255, 0), 3))
            self.tracking_success = True

        else:
            self.tracking_success = False

    def get_frame(self):
        """
        Summary line.
        simple accessor
        """
        return self.img

    def set_frame(self, frame):
        """
        Summary line.
        accessor used on every image received in UdpSocket except the first one to store the current frame in the
        window object for further treatment

        Parameters:
        the value of the current frame, of type np.array and normal shape is (1080, 1920, 3)

        Returns:
        set the value of self.img with value passed in argument

        """
        self.img = frame

    def set_first_frame(self, first_frame):
        """
        Summary line.
        accessor only used once in UdpSocket to set the first frame coming through the server

        Parameters:
        the value of the first frame, of type np.array and normal shape is (1080, 1920, 3)

        Returns:
        set the value of self.first_frame with value passsed in argument
        """
        self.first_frame = first_frame

    def is_tracking_success(self):
        return self.tracking_success

"""
    def __del__(self):
        cv2.destroyWindow(self.win_name)
        print("destructor called")
"""


import numpy as np
import cv2
import pyautogui as m
import sys
import time

k = 1
user_input = input('This application recognizes your face and eye using the trained data model sets'
                   '\n It detects eye blink and handles mouse click event\n Press 1 to start the program. '
                   '\n\n To stop the program bring back the window that records the eye movement,cover your camera and press Q ')

face_cascade = cv2.CascadeClassifier('C:\....\haarcascade_frontalface_default.xml')#Replace this with the path where you reside the file
eye_cascade = cv2.CascadeClassifier('C:\....\haarcascade_eye.xml')#Replace this with the path where you reside the file
cap = cv2.VideoCapture(0)
# Change these parameters to play with sensitivity
c1 = 7
c2 = 5
if user_input == 1:
    while (True):
        ret, img = cap.read()
        img = cv2.flip(img, 1)
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        faces = face_cascade.detectMultiScale(gray, 1.3, 5)
        for (x, y, w, h) in faces:
            k = 1
            img = cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
            u1 = x + w
            u2 = y + h
            cir = cv2.circle(img, (x + w / 2, y + h / 2), 1, (0, 255, 255), 2)
            # print x + w / 2, y + h / 2
            #The below code is responsible for moving the mouse cursor in near real-time. Uncomment the below line to test it out.
            # m.moveTo(c1 * x + w / 2, c2 * y + h / 2, 0)
            roi_gray = gray[y:y + h, x:x + w]
            roi_color = img[y:y + h, x:x + w]
            eyes = eye_cascade.detectMultiScale(roi_gray, 1.3, 5)
            for (ex, ey, ew, eh) in eyes:
                k = 0
                cv2.rectangle(roi_color, (ex, ey), (ex + ew, ey + eh), (255, 255, 0), 2)

        if k == 1:
            print "Blink"
            # The below snippet is responsible for mouse click events. At the moment this is would work but still needs enhancements
            # uncomment the below to enable mouse left click events.
            # m.click()
        if k == 0:
            print "No Blink"
        cv2.namedWindow("img", cv2.WINDOW_NORMAL)
        cv2.resizeWindow("img", 600, 450)
        cv2.imshow('img', img)
        if cv2.waitKey(1) & 0xff == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()
else:
    print "Oops you pressed the wrong key try restarting the application again"


import cv2
import os
import torch
import agent
import numpy as np
from copy import deepcopy
from parameters import Parameters
import util

p = Parameters()

def Demoing():
    print('Get agent')
    # lane_agent = agent.Agent()
    # lane_agent.load_state_dict(
    #     torch.load('savefile/804_tensor(0.5786)_lane_detection_network.pkl', map_location='cpu'), False)
    lane_agent = agent.Agent()
    lane_agent.load_weights(804, "tensor(0.5786)")
    if torch.cuda.is_available():
        lane_agent.cuda()
    lane_agent.evaluate_mode()

    # check model with a picture
    # test_image = cv2.imread("test_curves/000c698734a78dce648bdb0d26f24b4f.jpg")
    # test_image = cv2.resize(test_image, (512,256))/255.0
    # test_image = np.rollaxis(test_image, axis=2, start=0)
    # _, _, ti = test(lane_agent, np.array([test_image]))
    # cv2.imshow("test", ti[0])
    # cv2.waitKey(0)
    imgs_dir = "../dataset/powerline/imgs"
    imgs_save_dir = imgs_dir + "_rsts"
    os.makedirs(imgs_save_dir, exist_ok=True)
    for cur_f in os.listdir(imgs_dir):
        cur_img = os.path.join(imgs_dir, cur_f)
        cur_img_dst = os.path.join(imgs_save_dir, cur_f)
        test_image = cv2.imread(cur_img)
        test_image = cv2.resize(test_image, (512,256))/255.0
        test_image = np.rollaxis(test_image, axis=2, start=0)
        _, _, ti = test(lane_agent, np.array([test_image]))
        cv2.imwrite(cur_img_dst, ti[0])

############################################################################
## test on the input test image
############################################################################
def test(lane_agent, test_images, thresh=p.threshold_point, index=-1):
    result = lane_agent.predict_lanes_test(test_images)
    confidences, offsets, instances = result[index]

    num_batch = len(test_images)

    out_x = []
    out_y = []
    out_images = []

    for i in range(num_batch):
        # test on test data set
        image = deepcopy(test_images[i])
        image = np.rollaxis(image, axis=2, start=0)
        image = np.rollaxis(image, axis=2, start=0) * 255.0
        image = image.astype(np.uint8).copy()

        confidence = confidences[i].view(p.grid_y, p.grid_x).cpu().data.numpy()

        offset = offsets[i].cpu().data.numpy()
        offset = np.rollaxis(offset, axis=2, start=0)
        offset = np.rollaxis(offset, axis=2, start=0)

        instance = instances[i].cpu().data.numpy()
        instance = np.rollaxis(instance, axis=2, start=0)
        instance = np.rollaxis(instance, axis=2, start=0)

        # generate point and cluster
        raw_x, raw_y = generate_result(confidence, offset, instance, thresh)

        # eliminate fewer points
        in_x, in_y = eliminate_fewer_points(raw_x, raw_y)

        # sort points along y
        in_x, in_y = util.sort_along_y(in_x, in_y)

        result_image = util.draw_points(in_x, in_y, deepcopy(image))

        out_x.append(in_x)
        out_y.append(in_y)
        out_images.append(result_image)

    return out_x, out_y, out_images

############################################################################
## eliminate result that has fewer points than threshold
############################################################################
def eliminate_fewer_points(x, y):
    # eliminate fewer points
    out_x = []
    out_y = []
    for i, j in zip(x, y):
        if len(i)>2:
            out_x.append(i)
            out_y.append(j)
    return out_x, out_y

############################################################################
## generate raw output
############################################################################
def generate_result(confidance, offsets, instance, thresh):
    mask = confidance > thresh

    grid = p.grid_location[mask]
    offset = offsets[mask]
    feature = instance[mask]

    lane_feature = []
    x = []
    y = []
    for i in range(len(grid)):
        if (np.sum(feature[i] ** 2)) >= 0:
            point_x = int((offset[i][0] + grid[i][0]) * p.resize_ratio)
            point_y = int((offset[i][1] + grid[i][1]) * p.resize_ratio)
            if point_x > p.x_size or point_x < 0 or point_y > p.y_size or point_y < 0:
                continue
            if len(lane_feature) == 0:
                lane_feature.append(feature[i])
                x.append([point_x])
                y.append([point_y])
            else:
                flag = 0
                index = 0
                min_feature_index = -1
                min_feature_dis = 10000
                for feature_idx, j in enumerate(lane_feature):
                    dis = np.linalg.norm((feature[i] - j) ** 2)
                    if min_feature_dis > dis:
                        min_feature_dis = dis
                        min_feature_index = feature_idx
                if min_feature_dis <= p.threshold_instance:
                    lane_feature[min_feature_index] = (lane_feature[min_feature_index] * len(x[min_feature_index]) +
                                                       feature[i]) / (len(x[min_feature_index]) + 1)
                    x[min_feature_index].append(point_x)
                    y[min_feature_index].append(point_y)
                elif len(lane_feature) < 12:
                    lane_feature.append(feature[i])
                    x.append([point_x])
                    y.append([point_y])
    return x, y

if __name__ == '__main__':
    Demoing()


from random import shuffle

import cv2
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from matplotlib.colors import hsv_to_rgb, rgb_to_hsv
from PIL import Image
from torch.autograd import Variable
from utils.box_utils import log_sum_exp, match
from utils.config import Config

MEANS = (104, 117, 123)

class MultiBoxLoss(nn.Module):
    def __init__(self, num_classes, overlap_thresh, prior_for_matching,
                 bkg_label, neg_mining, neg_pos, neg_overlap, encode_target,
                 use_gpu=True, negatives_for_hard=100.0):
        super(MultiBoxLoss, self).__init__()
        self.use_gpu = use_gpu
        self.num_classes = num_classes
        self.threshold = overlap_thresh
        self.background_label = bkg_label
        self.encode_target = encode_target
        self.use_prior_for_matching = prior_for_matching
        self.do_neg_mining = neg_mining
        self.negpos_ratio = neg_pos
        self.neg_overlap = neg_overlap
        self.negatives_for_hard = negatives_for_hard
        self.variance = Config['variance']

    def forward(self, predictions, targets):
        #--------------------------------------------------#
        #   取出预测结果的三个值：回归信息，置信度，先验框
        #--------------------------------------------------#
        loc_data, conf_data, priors = predictions
        #--------------------------------------------------#
        #   计算出batch_size和先验框的数量
        #--------------------------------------------------#
        num = loc_data.size(0)
        num_priors = (priors.size(0))
        #--------------------------------------------------#
        #   创建一个tensor进行处理
        #--------------------------------------------------#
        loc_t = torch.zeros(num, num_priors, 4).type(torch.FloatTensor)
        conf_t = torch.zeros(num, num_priors).long()

        if self.use_gpu:
            loc_t = loc_t.cuda()
            conf_t = conf_t.cuda()
            priors = priors.cuda()

        for idx in range(num):
            # 获得真实框与标签
            truths = targets[idx][:, :-1]
            labels = targets[idx][:, -1]

            if(len(truths)==0):
                continue

            # 获得先验框
            defaults = priors
            #--------------------------------------------------#
            #   利用真实框和先验框进行匹配。
            #   如果真实框和先验框的重合度较高，则认为匹配上了。
            #   该先验框用于负责检测出该真实框。
            #--------------------------------------------------#
            match(self.threshold, truths, defaults, self.variance, labels, loc_t, conf_t, idx)

        #--------------------------------------------------#
        #   转化成Variable
        #   loc_t   (num, num_priors, 4)
        #   conf_t  (num, num_priors)
        #--------------------------------------------------#
        loc_t = Variable(loc_t, requires_grad=False)
        conf_t = Variable(conf_t, requires_grad=False)

        # 所有conf_t>0的地方，代表内部包含物体
        pos = conf_t > 0

        #--------------------------------------------------#
        #   求和得到每一个图片内部有多少正样本
        #   num_pos  (num, )
        #--------------------------------------------------#
        num_pos = pos.sum(dim=1, keepdim=True)

        #--------------------------------------------------#
        #   取出所有的正样本，并计算loss
        #   pos_idx (num, num_priors, 4)
        #--------------------------------------------------#
        pos_idx = pos.unsqueeze(pos.dim()).expand_as(loc_data)
        loc_p = loc_data[pos_idx].view(-1, 4)
        loc_t = loc_t[pos_idx].view(-1, 4)

        loss_l = F.smooth_l1_loss(loc_p, loc_t, size_average=False)
        #--------------------------------------------------#
        #   batch_conf  (num * num_priors, num_classes)
        #   loss_c      (num, num_priors)
        #--------------------------------------------------#
        batch_conf = conf_data.view(-1, self.num_classes)
        # 这个地方是在寻找难分类的先验框
        loss_c = log_sum_exp(batch_conf) - batch_conf.gather(1, conf_t.view(-1, 1))
        loss_c = loss_c.view(num, -1)

        # 难分类的先验框不把正样本考虑进去，只考虑难分类的负样本
        loss_c[pos] = 0
        #--------------------------------------------------#
        #   loss_idx    (num, num_priors)
        #   idx_rank    (num, num_priors)
        #--------------------------------------------------#
        _, loss_idx = loss_c.sort(1, descending=True)
        _, idx_rank = loss_idx.sort(1)
        #--------------------------------------------------#
        #   求和得到每一个图片内部有多少正样本
        #   num_pos     (num, )
        #   neg         (num, num_priors)
        #--------------------------------------------------#
        num_pos = pos.long().sum(1, keepdim=True)
        # 限制负样本数量
        num_neg = torch.clamp(self.negpos_ratio * num_pos, max = pos.size(1) - 1)
        num_neg[num_neg.eq(0)] =  self.negatives_for_hard
        neg = idx_rank < num_neg.expand_as(idx_rank)

        #--------------------------------------------------#
        #   求和得到每一个图片内部有多少正样本
        #   pos_idx   (num, num_priors, num_classes)
        #   neg_idx   (num, num_priors, num_classes)
        #--------------------------------------------------#
        pos_idx = pos.unsqueeze(2).expand_as(conf_data)
        neg_idx = neg.unsqueeze(2).expand_as(conf_data)

        # 选取出用于训练的正样本与负样本，计算loss
        conf_p = conf_data[(pos_idx + neg_idx).gt(0)].view(-1, self.num_classes)
        targets_weighted = conf_t[(pos + neg).gt(0)]
        loss_c = F.cross_entropy(conf_p, targets_weighted, size_average=False)

        N = torch.max(num_pos.data.sum(), torch.ones_like(num_pos.data.sum()))
        loss_l /= N
        loss_c /= N
        return loss_l, loss_c

def rand(a=0, b=1):
    return np.random.rand()*(b-a) + a

class Generator(object):
    def __init__(self,batch_size,
                 lines, image_size,num_classes,
                 ):

        self.batch_size = batch_size
        self.lines = lines
        self.image_size = image_size
        self.num_classes = num_classes-1

    def get_random_data(self, annotation_line, input_shape, jitter=.3, hue=.1, sat=1.5, val=1.5, random=True):
        """实时数据增强的随机预处理"""
        line = annotation_line.split()
        image = Image.open(line[0])
        iw, ih = image.size
        h, w = input_shape
        box = np.array([np.array(list(map(int, box.split(',')))) for box in line[1:]])

        if not random:
            # resize image
            scale = min(w/iw, h/ih)
            nw = int(iw*scale)
            nh = int(ih*scale)
            dx = (w-nw)//2
            dy = (h-nh)//2

            image = image.resize((nw,nh), Image.BICUBIC)
            new_image = Image.new('RGB', (w,h), (128,128,128))
            new_image.paste(image, (dx, dy))
            image_data = np.array(new_image, np.float32)

            # correct boxes
            box_data = np.zeros((len(box),5))
            if len(box)>0:
                np.random.shuffle(box)
                box[:, [0,2]] = box[:, [0,2]]*nw/iw + dx
                box[:, [1,3]] = box[:, [1,3]]*nh/ih + dy
                box[:, 0:2][box[:, 0:2]<0] = 0
                box[:, 2][box[:, 2]>w] = w
                box[:, 3][box[:, 3]>h] = h
                box_w = box[:, 2] - box[:, 0]
                box_h = box[:, 3] - box[:, 1]
                box = box[np.logical_and(box_w>1, box_h>1)]
                box_data = np.zeros((len(box),5))
                box_data[:len(box)] = box

            return image_data, box_data

        # 调整图片大小
        new_ar = w / h * rand(1 - jitter, 1 + jitter) / rand(1 - jitter, 1 + jitter)
        scale = rand(.25, 2)
        if new_ar < 1:
            nh = int(scale * h)
            nw = int(nh * new_ar)
        else:
            nw = int(scale * w)
            nh = int(nw / new_ar)
        image = image.resize((nw, nh), Image.BICUBIC)

        # 放置图片
        dx = int(rand(0, w - nw))
        dy = int(rand(0, h - nh))
        new_image = Image.new('RGB', (w, h),
                              (np.random.randint(0, 255), np.random.randint(0, 255), np.random.randint(0, 255)))
        new_image.paste(image, (dx, dy))
        image = new_image

        # 是否翻转图片
        flip = rand() < .5
        if flip:
            image = image.transpose(Image.FLIP_LEFT_RIGHT)

        # 色域变换
        hue = rand(-hue, hue)
        sat = rand(1, sat) if rand() < .5 else 1 / rand(1, sat)
        val = rand(1, val) if rand() < .5 else 1 / rand(1, val)
        x = cv2.cvtColor(np.array(image,np.float32)/255, cv2.COLOR_RGB2HSV)
        x[..., 0] += hue*360
        x[..., 0][x[..., 0]>1] -= 1
        x[..., 0][x[..., 0]<0] += 1
        x[..., 1] *= sat
        x[..., 2] *= val
        x[x[:,:, 0]>360, 0] = 360
        x[:, :, 1:][x[:, :, 1:]>1] = 1
        x[x<0] = 0
        image_data = cv2.cvtColor(x, cv2.COLOR_HSV2RGB)*255

        # 调整目标框坐标
        box_data = np.zeros((len(box), 5))
        if len(box) > 0:
            np.random.shuffle(box)
            box[:, [0, 2]] = box[:, [0, 2]] * nw / iw + dx
            box[:, [1, 3]] = box[:, [1, 3]] * nh / ih + dy
            if flip:
                box[:, [0, 2]] = w - box[:, [2, 0]]
            box[:, 0:2][box[:, 0:2] < 0] = 0
            box[:, 2][box[:, 2] > w] = w
            box[:, 3][box[:, 3] > h] = h
            box_w = box[:, 2] - box[:, 0]
            box_h = box[:, 3] - box[:, 1]
            box = box[np.logical_and(box_w > 1, box_h > 1)]  # 保留有效框
            box_data = np.zeros((len(box), 5))
            box_data[:len(box)] = box

        return image_data, box_data

    def generate(self, train=True):
        while True:
            shuffle(self.lines)
            lines = self.lines
            inputs = []
            targets = []

            for annotation_line in lines:
                if train:
                    img, y = self.get_random_data(annotation_line, self.image_size[0:2])
                else:
                    img, y = self.get_random_data(annotation_line, self.image_size[0:2], random=False)

                boxes = np.array(y[:,:4],dtype=np.float32)
                boxes[:,0] = boxes[:,0]/self.image_size[1]
                boxes[:,1] = boxes[:,1]/self.image_size[0]
                boxes[:,2] = boxes[:,2]/self.image_size[1]
                boxes[:,3] = boxes[:,3]/self.image_size[0]

                boxes = np.maximum(np.minimum(boxes,1), 0)

                y = np.concatenate([boxes, y[:,-1:]],axis=-1)

                inputs.append(np.transpose(img - MEANS, (2,0,1)))
                targets.append(y)
                if len(targets) == self.batch_size:
                    tmp_inp = np.array(inputs)
                    tmp_targets = targets
                    inputs = []
                    targets = []
                    yield tmp_inp, tmp_targets


# lamoda

import json
import numpy as np
import os
import pandas as pd
import pickle
import re
from collections import defaultdict

from solvers.solver_helpers import NgramManager, morph, Word2vecProcessor, CommonData, ALPHABET, AbstractSolver

class Solver(AbstractSolver):
    def __init__(self):
        self.morph = morph
        self.ngram_manager = NgramManager()
        self.w2v = Word2vecProcessor()
        self.common_data = CommonData()
        self.suffixes = {}
        self.paronyms = defaultdict(list)
        self.word2root = {}
        self.root2word = defaultdict(list)
        self.scaler = None
        self.lr = None
        self.alphabet = ALPHABET

    def predict_from_model(self, task):
        words = get_words(task)
        candidates = self.calc_features(words)
        rows = self.score_candidates(candidates)

        df = pd.DataFrame(rows)
        feature_names = list(range(5, df.shape[1]))
        df["id"] = 0
        _, df = filter_dataframe(df)
        feature_names.append("rank")

        x = self.scaler.transform(df[feature_names])
        df["pred"] = self.lr.predict_proba(x)[:, 1]
        ind = np.argsort(self.lr.predict_proba(x)[:, 1])[-1]
        return rows[ind][3]

    def load(self, path="data/models/solvers/solver5"):

        with open(os.path.join(path, "solver5_logreg.pkl"), "rb") as f:
            self.lr = pickle.load(f)

        with open(os.path.join(path, "solver5.pkl"), "rb") as f:
            self.scaler = pickle.load(f)

        with open(os.path.join(path, "suffixes.txt"), "r", encoding="utf-8") as f:
            for line in f:
                suffix = line.strip()
                if suffix.upper() == suffix or len(suffix) == 0:
                    continue
                self.suffixes[suffix.replace("-", "").replace("j", "")] = 1

        with open(os.path.join(path, "paronyms.csv"), "r", encoding="utf-8") as f:
            for line in f:
                array = line.strip().split()
                for i in range(len(array)):
                    for j in range(len(array)):
                        if i != j:
                            self.paronyms[array[i].lower()].append(array[j].lower())

        with open(
            os.path.join(path, "morph_annotated.txt"), "r", encoding="utf-8"
        ) as f:
            self.annotated = json.load(f)

        for k, v in self.annotated.items():
            array = v.lower().replace("}", "|").split("|")
            root = ""
            for e in array[1:]:
                if (
                    len(e) > 0
                    and e[0].isalpha()
                    and e[-1].isalpha()
                    and e.find("=") == -1
                ):
                    root += e
            self.word2root[k.lower()] = root
            self.root2word[root].append(k.lower())

        self.is_loaded = True

    def get_freq(self, t):
        return self.ngram_manager.gram_freq[
            tuple([self.ngram_manager.word2num.get(e, -1) for e in t])
        ]

    def calc_features(self, words):
        candidates = []
        for word, context in words:
            pars = self.find_paronyms(word.lower())

            features0 = self.calc_ngr_score(
                " ".join(context[0][-3:] + [word.lower()] + context[1][:3]),
                word.lower(),
                word.lower(),
            )
            p0 = self.morph.parse(word.lower())[0].tag
            word_norm = self.morph.normal_forms(word.lower())[0]
            s = " ".join(context[0][-3:] + [word.lower()] + context[1][:3])
            norm_cand_features = dict()
            w_candidates = []
            context_vector = self.w2v.text_vector(
                " ".join(context[0][-6:] + context[1][:6])
            )
            sim0 = self.w2v.distance(self.w2v.word_vector(word.lower()), context_vector)
            features0.append(sim0)

            t0 = (
                p0.aspect,
                p0.case,
                p0.gender,
                p0.number,
                p0.person,
                p0.tense,
                p0.transitivity,
                p0.voice,
            )

            for cand in pars:
                cand_vector = self.w2v.word_vector(cand)
                sim = self.w2v.distance(cand_vector, context_vector)
                cand_norm = self.morph.normal_forms(cand)[0]
                w_info = [
                    word,
                    str((context[0][-3:], context[1][:3])),
                    word_norm,
                    cand,
                    cand_norm,
                ]
                features = []
                ngr_features = self.calc_ngr_score(s, word.lower(), cand)
                features += ngr_features
                features.append(sim)
                features += [
                    custom_damerau_levenshtein_distance(word.lower(), cand)
                    / min(len(word), len(cand)),
                    custom_damerau_levenshtein_distance(word.lower()[-2:], cand[-2:]),
                ]
                p = self.morph.parse(cand)[0].tag
                coef = (
                    1
                    if p.POS == p0.POS
                    or p.POS in {"PRTF", "ADJF"}
                    and p0.POS in {"PRTF", "ADJF"}
                    else 0.01
                )
                score0 = features0[0]
                score = ngr_features[0]
                features += [
                    coef,
                    coef
                    * pars[cand]
                    * (
                        1 * (score - score0) / (1 + score0)
                        + 0.1 * (max(0, score - score0))
                    ),
                ]
                features += [int(pars[cand] == e) for e in range(1, 6)]

                t = (
                    p.aspect,
                    p.case,
                    p.gender,
                    p.number,
                    p.person,
                    p.tense,
                    p.transitivity,
                    p.voice,
                )
                for e1, e2 in zip(t0, t):
                    features.append(int(e1 == e2))
                if cand_norm not in norm_cand_features:
                    norm_cand_features[cand_norm] = features[:5].copy()
                else:
                    for i in range(5):
                        norm_cand_features[cand_norm][i] += features[i]
                w_candidates.append(w_info + features0 + features)
            for i in range(len(w_candidates)):
                w_candidates[i] += norm_cand_features[w_candidates[i][4]]
            candidates += w_candidates
        return candidates

    def score_candidates(self, candidates):
        return sorted(candidates, key=lambda x: -x[-1])

    def calc_ngr_score(self, s, from_w, to_w):
        s = (
            (" " + s + " ")
            .lower()
            .replace(" " + from_w + " ", " " + to_w + " ")
            .strip()
        )
        array = s.split()

        score1 = 0
        for i in range(0, len(array)):
            if array[i].lower().replace("ё", "е") == to_w.lower().replace("ё", "е"):
                score1 += np.log1p(min(100, self.get_freq((array[i],))))
        score2 = 0
        score2f = 0
        cc2 = 0
        for i in range(1, len(array)):
            if array[i].lower().replace("ё", "е") == to_w.lower().replace(
                "ё", "е"
            ) or array[i - 1].lower().replace("ё", "е") == to_w.lower().replace(
                "ё", "е"
            ):
                score2 += np.log1p(
                    min(1000, self.get_freq((array[i - 1], "", array[i])))
                )

                score2f += np.log1p(
                    min(1000, self.get_freq(("-", array[i - 1][-2:], "", array[i])))
                )
                score2f += np.log1p(
                    min(1000, self.get_freq(("-", array[i - 1], "", array[i][-2:])))
                )
                cc2 += 1
        if cc2 > 0:
            score2 /= cc2
            score2f /= cc2
        score3 = 0
        cc3 = 0
        for i in range(2, len(array)):
            if (
                array[i].lower().replace("ё", "е") == to_w.lower().replace("ё", "е")
                or array[i - 1].lower().replace("ё", "е")
                == to_w.lower().replace("ё", "е")
                or array[i - 2].lower().replace("ё", "е")
                == to_w.lower().replace("ё", "е")
            ):
                score3 += np.log1p(
                    min(
                        1000,
                        self.get_freq((array[i - 2], "", array[i - 1], "", array[i])),
                    )
                )
                cc3 += 1
        if cc3 > 0:
            score3 /= cc3

        score = 100 * score2 + 1000 * score3
        if score != -1:
            score += 10 * score2f
        if score == 0:
            score = 0.1 * score1
        return [score, score1, score2, score2f, score3]

    def find_paronyms(self, word):
        res = dict()
        if word in self.paronyms:
            for p in self.paronyms[word]:
                res[p] = 1
        for nf in self.morph.normal_forms(word):
            if nf in self.paronyms:
                for p in self.paronyms[nf]:
                    res[p] = 1

        for e in self.common_data.prefixes:
            if e in ("не", "анти"):
                continue
            if word.startswith(e):
                for e1 in self.common_data.prefixes:
                    if e != e1:
                        wn = e1 + word[len(e) :]
                        if self.morph.word_is_known(wn):
                            res[wn] = 2

        for e in self.suffixes:
            ind = word.rfind(e)
            if ind != -1:
                for e1 in self.suffixes:
                    if e != e1:
                        wn = word[:ind] + e1 + word[ind + len(e) :]
                        if self.morph.word_is_known(wn):
                            res[wn] = 3
                        if self.morph.word_is_known(wn.replace("ый", "ий")):
                            res[wn.replace("ый", "ий")] = 3
                        if self.morph.word_is_known(wn.replace("ий", "ый")):
                            res[wn.replace("ий", "ый")] = 3

        for ww in [word, self.morph.normal_forms(word)[0]]:
            if ww in self.word2root:
                root = self.word2root[ww]
                for root in [root, root.replace("ь", "")]:
                    k = 0
                    for w in self.root2word[root]:
                        if k == 1000:
                            break
                        if self.morph.word_is_known(w):
                            res[w] = 4
                        k += 1

        for ww in [word]:
            for ch in [""] + list(self.alphabet):
                for i in range(len(ww)):
                    wn = ww[:i] + ch + ww[i:]
                    if self.morph.word_is_known(wn):
                        res[wn] = 1
                    wn = ww[:i] + ch + ww[i + 1 :]
                    if self.morph.word_is_known(wn):
                        res[wn] = 5

        if word in res:
            del res[word]

        nfs = dict()
        for w in res:
            nf = self.morph.normal_forms(w)[0]
            nfs[nf] = min(nfs.get(nf, 6), res[w])
        for nf in nfs:
            if nf in self.common_data.norm2word:
                for w in {e.lower() for e in self.common_data.norm2word[nf]}:
                    res[w] = min(res.get(w, 6), nfs[nf])

        res_final = dict()
        init_nfs = set(self.morph.normal_forms(word))
        for w in res:
            fl = 1
            for e in self.morph.normal_forms(w):
                if e in init_nfs:
                    fl = 0
                    break
            if fl == 1:
                res_final[w] = res[w]

        return res_final

def clean_with_slot(word):
    return " ".join(re.sub("[^а-яё\. ]+", " ", word.lower()).split())

def clean(word):
    return " ".join(re.sub("[^а-яё ]+", " ", word.lower()).split())

def get_words(task):
    array = (
        task["text"]
        .replace("\xa0", "\n")
        .replace("НЕВЕРНО", "неверно")
        .replace("НЕПРАВИЛЬНО", "неправильно")
        .split(".")
    )

    words = []
    for e in array:
        context = [[]]
        e = (
            e.replace("?", ".")
            .replace("!", ".")
            .replace(".", " . ")
            .replace(",", " , ")
            .replace(":", " ")
            .replace("–", " ")
            .replace("—", " ")
            .replace('"', " ")
            .replace("«", " ")
            .replace("»", " ")
            .replace("( ", "(")
            .replace(" )", ")")
            .strip()
            .strip(".")
        )
        longest_word = ""
        for w in e.split():
            if len(w) > 1 and w.upper() == w and not w.isnumeric():
                if len(w) > len(longest_word):
                    longest_word = w
        word = None
        for w in e.split():
            if (
                len(w) > 1
                and w.upper() == w
                and not w.isnumeric()
                and w == longest_word
            ):
                word = w
                context.append([])
            else:
                context[len(context) - 1].append(w.lower())
        if word is not None:
            words.append((word, context))
    return words

def build_dataset(self, task):
    words = get_words(task)
    candidates = self.calc_features(words)
    return candidates

def filter_dataframe(df):
    f = 13
    df["pre_pred"] = df[f]
    df["rank"] = (
        df[["id", 0, "pre_pred"]]
        .groupby(["id", 0])["pre_pred"]
        .rank(ascending=False, method="first")
    )
    ind = (df["rank"] <= 10) & (df[19] == 1) & (df[29] == 1)
    ind |= df[4].isin(df[ind][4].unique()) & (df["rank"] <= 50)
    return ind, df

def remove_common_prefix_suffix(s1, s2):
    left = 0
    while s1[left] == s2[left]:
        left += 1
        if left == len(s1) or left == len(s2):
            break
    s1 = s1[left:]
    s2 = s2[left:]
    if len(s1) > 0 and len(s2) > 0:
        right = 0
        while s1[len(s1) - right - 1] == s2[len(s2) - right - 1]:
            right += 1
            if right == len(s1) or right == len(s2):
                break
        s1 = s1[: len(s1) - right]
        s2 = s2[: len(s2) - right]
    return s1, s2

def custom_damerau_levenshtein_distance(s1, s2):
    s1, s2 = remove_common_prefix_suffix(s1, s2)

    len1 = len(s1)
    len2 = len(s2)

    res = 0
    score = [[0] * (len2 + 1) for _ in range(len1 + 1)]

    for i in range(len1 + 1):
        for j in range(len2 + 1):
            if i == 0 or j == 0:
                if i == 0:
                    score[i][j] = j
                else:
                    score[i][j] = i
            elif s1[i - 1] == s2[j - 1]:
                score[i][j] = score[i - 1][j - 1]
            else:
                score[i][j] = min(
                    score[i - 1][j] + 1, score[i][j - 1] + 1, score[i - 1][j - 1] + 1
                )
                if (
                    i > 1
                    and j > 1
                    and s1[i - 2] == s2[j - 1]
                    and s1[i - 1] == s2[j - 2]
                ):
                    score[i][j] = min(score[i][j], score[i - 2][j - 2] + 1)

        res = score[len1][len2]
    return res


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# pylama:ignore=D213,D400,E501,E221,D103,D205,D209,E124,E127,E128

"""Find optimal nutritional combinations

This optimizer assumes that the foods to be targeted are in the file
foods.jsontxt.gz as created by build_foods.sh. That means that each line is the
JSON representation of a record as created by nndb-import (see
https://github.com/CraigKelly/nndb-import)
"""

import sys
import gzip

from functools import partial

# Try to use various speedy json libraries then fall back to stdlib
try:
    import ujson as json
except:
    try:
        sys.stderr.write("No ujson, trying cjson\n")
        import cjson as json
    except:
        sys.stderr.write("No cjson, using stdlib json\n")
        import json

import scipy
import scipy.stats
sp = scipy
stats = sp.stats

from micro_reqs import ALL_MICROS  #NOQA

# Parameters we use
INIT_RANDOMS    = 10000                       # Initial random members of population
RND_EXP_ENTRIES = 4                           # Exp value for # of non-zero entries
MAX_AMT         = 5.0                         # Non-zero entry max value
POP_SIZE        = 200                         # Pop size (after initial population)
MUTATE_RATE     = 0.20                        # Rate at which entry is mutated
MUTATE_BIG      = MUTATE_RATE * 0.20          # Part of mutate rate, chance of "big" mutation
IMMORTALS       = 5                           # Number of pop members that carry over
MERGE_SIZE      = 4                           # Number of solutions we sample for merge
SPARSITY_MAX    = (RND_EXP_ENTRIES-1) * (MAX_AMT*0.75)

# We pre-define random routines so that we can swap out (Python's native
# Mersenne twister is fine but a little slow for what we're doing)
randrange = partial(sp.random.randint, 0)
rand = sp.random.rand

def choice(lst):
    return lst[randrange(len(lst))]

# Simple logistic function for scipy arrays
def logistic(spa):
    return 1.0 / (1.0 + scipy.exp(-spa))

# Simple logging stand-in
def info(s, *args):
    if args:
        s = s % args
    print(s)

FILTER_WORDS = [i.replace('\s', ' ') for i in """
    applesauce        mashed
    bacon             meatless
    beverage          millet
    breaded           nectar
    bulgur            noodles
    candied           oil-roasted
    catsup            pork
    celery\sflakes
    chili             products
    chowchow          puffs
    cocktail          ranch
    cilantro
    cornmeal          relish
    cornstarch        rice
    couscous          soymilk
    dehydrated        spaghetti
    flour             spread
    franks            succotash
    fried             syrup
    groats            tapioca
    hash brown        taro
    hominy            tomato\sproducts
    hummus            vegetables
    juice             vegetarian
    lambsquarters     veggie
    liquid\sfrom      vermicelli
    macaroni          wheat
""".split()]

FILTER_SPLITS = ["sweet", "sweetened" "wheat", ]

def food_filter(line):
    line = line.strip()
    if not line:
        return None

    food = json.loads(line)
    if not food:
        return None

    descrip = food.get('descrip', '').lower()
    if not descrip:
        return None

    for word in FILTER_WORDS:
        if word in descrip:
            return None

    parts = descrip.split(',')
    for part in parts:
        part = part.strip()
        if not part:
            continue
        for check in FILTER_SPLITS:
            if check == part:
                return None

    return food

def read_foods(filename):
    # Test show zcat subprocess MUCH faster then `with gzip.open(filename, 'r')`
    with gzip.open(filename) as fh:
        for line in fh:
            food = food_filter(line.decode('utf-8'))
            if food:
                yield food

def extract_nutrients(food):
    contains = dict(
        (n["nutrient_id"], n["nutrient_val"]) for n in food["nutrients"]
    )
    return [contains.get(nid, 0.0) for _, nid, _, _, _ in ALL_MICROS]

class opt_engine(object):
    """Given a list of food objects from our file, perform the various
    optmization functions we want
    """

    def __init__(self, food_details):
        """Load initial matrices and create initial expanded population."""
        self.food_details = food_details
        self.food_count = len(food_details)

        # We want our random instances to have an expected number of entries
        # equal to RND_EXP_ENTRIES, which for Binomial(n,p) is np. So we know
        # p is RND_EXP_ENTRIES/n
        self.rnd_entries = partial(
            stats.binom.rvs,
            self.food_count,
            float(RND_EXP_ENTRIES) / float(self.food_count)
        )

        # |foods| x |nutrients| 2-d array
        self.foods = sp.array([extract_nutrients(f) for f in food_details])

        # RDA and UL vectors
        self.RDA, self.UL = [], []
        for _, _, _, r, u in ALL_MICROS:
            self.RDA.append(r)
            self.UL.append(u)
        self.RDA, self.UL = sp.array(self.RDA), sp.array(self.UL)

        # Our first generation contains all single foods and INIT_RANDOMS
        # inital random entries
        pop = []
        for i in range(self.food_count):
            one = [0.0] * self.food_count
            one[i] = 1.0
            pop.append(list(one))

        for _ in range(INIT_RANDOMS):
            pop.append(self.rand_inst())

        self.set_pop(pop)
        self.last_population = []
        self.last_popnutrition = []

    def set_pop(self, pop):
        """Directly set population and recalc the pop-nutrition grid."""
        # |members| x |foods| 2-d array
        self.population = sp.array(pop)
        self.popnutrition = sp.dot(self.population, self.foods)

    def rand_inst(self):
        """Return a random instance based on RND_EXP_ENTRIES and current foods."""
        inst = [0.0] * self.food_count

        entries = self.rnd_entries()
        if entries < 1:
            entries = RND_EXP_ENTRIES  # extra boost to our average

        idxs = set([randrange(len(inst))])
        while len(idxs) < entries:
            idxs.add(randrange(len(inst)))

        for idx in idxs:
            inst[idx] = choice([0.5, 1.0, 1.5, 2.0])

        return inst

    def calories(self, inst):
        """Given an instance, return the total calories and the total g's of sugar."""
        total_cals = 0.0
        total_sugar = 0.0

        for idx, amt in enumerate(inst):
            if abs(amt - 0.0) < 0.00001:
                continue

            food = self.food_details[idx]

            for n in food["nutrients"]:
                if n["nutrient_id"] == "208":
                    total_cals += float(n["nutrient_val"]) * amt
                if n["nutrient_id"] == "269":
                    total_sugar += float(n["nutrient_val"]) * amt

        return total_cals, total_sugar

    SCORE_WEIGHTS = sp.array([
        2.0,  # RDA
        1.0,  # nutrient per gram
        1.8,  # UL
        1.5,  # cals/gram
        1.2,  # sparsity
        1.0,  # sugar
    ])

    def score(self, inst, nutr):
        """Return a fitness score and the originating score vector for the given
        instance and it's nutrition space vector."""
        assert len(inst) == self.foods.shape[0]
        assert len(nutr) == self.foods.shape[1]
        assert len(self.RDA) == len(self.UL) == len(nutr)

        # Figure any nutrients above the upper limit in percentage units.
        too_much = (nutr - self.UL) / self.UL
        calories, sugar = self.calories(inst)
        grams = 100.0 * inst.sum()  # Our database measures everything in 100g units

        # nutrient as percent of RDA, clipped to remove advantage for going over
        nutr_scores = sp.clip(nutr / self.RDA, 0.0, 1.01)

        components = self.SCORE_WEIGHTS * sp.array([
            # good stuff (note that we want to MINIMIZE our score
            0.0 - nutr_scores.mean(),                                # RDA, but no credit for going over
            0.0 - (nutr_scores.sum() / grams),                       # Nutrient score per gram

            # bad stuff
            too_much[too_much > -0.01].sum(),                        # UL, but only as we get high
            logistic(calories / grams),                              # cals per gram
            logistic(len(inst[inst > 0]) / float(RND_EXP_ENTRIES)),  # Simpler is better
            logistic(sugar)                                          # sugar is bad, mmm-kay
        ])

        return components.mean(), components

    def mutate(self, inst):  #NOQA
        """Return a mutated copy of the given instance"""
        rnd_inst = list(inst)

        for idx, val in enumerate(inst):
            roll = rand()
            if roll > MUTATE_RATE:
                continue  # No mutation here

            if roll < MUTATE_BIG and val > 0.0:
                # Swapping with blank index - find the other, do the swap, and leave
                blank_idx = randrange(len(inst))
                while inst[blank_idx] > 0.0:
                    blank_idx = randrange(len(inst))
                rnd_inst[idx], rnd_inst[blank_idx] = rnd_inst[blank_idx], rnd_inst[idx]
                continue

            if roll < MUTATE_BIG:
                modifier = choice([1.5, 1.75, 2.0, 2.25])  # Big jump
            else:
                modifier = choice([0.25, 0.5, .75, 1.0, 1.25])  # Regular jump

            if val <= 0.0:
                val = modifier
            else:
                val = sp.clip(val + (choice([-1.0, 1.0]) * modifier), 0.0, MAX_AMT)

            rnd_inst[idx] = val

        # All of this is great, but we tend to just get bigger and bigger - we want
        # lots of sparsity AND a low total sum
        while sum(rnd_inst) > SPARSITY_MAX:
            for idx in range(len(rnd_inst)):
                if rnd_inst[idx] <= 0.1:
                    rnd_inst[idx] = 0.0
                elif rand() < 0.70:
                    rnd_inst[idx] *= 0.5
                else:
                    rnd_inst[idx] = 0.0

        return rnd_inst

    def crossover(self, inst1, inst2):
        """Return a new instance via cross over with the 2 given instances."""
        return [x if rand() < 0.5 else y for x, y in zip(inst1, inst2)]

    def winner(self):
        """Currently, chose a winner from the population with tournament sel."""
        idx1 = randrange(len(self.population))
        idx2 = randrange(len(self.population))
        return min(idx1, idx2)

    def generation(self):
        """Do a single generation of work."""
        all_scored = []
        for inst, nutr in zip(self.population, self.popnutrition):
            score, score_vector = self.score(inst, nutr)
            all_scored.append((score, inst))

        all_scored.sort(key=lambda one: one[0])

        # Keep previous generation in sorted order
        self.last_population = sp.array([inst for _, inst in all_scored])
        self.last_popnutrition = sp.dot(self.last_population, self.foods)

        # Now we are creating the next generation

        # Don't add dups to a generation
        new_gen = []
        seen = set()

        def add_to_gen(inst):
            key = tuple(inst)
            if key in seen:
                return
            seen.add(key)
            new_gen.append(inst)

        # Keep top N entries, top N entries with mutations, and top N entries with
        # one-off removed and then mutated
        for score, inst in all_scored[:IMMORTALS]:
            # top entries
            add_to_gen(inst)
            # mutated
            add_to_gen(self.mutate(inst))
            # one-off removed and then mutated
            for idx, val in enumerate(inst):
                if val > 0.0:
                    one_off = list(inst)
                    one_off[idx] = 0.0
                    add_to_gen(one_off)
                    add_to_gen(self.mutate(one_off))

        # Fill out the rest of the generation
        # Note we're actually TRIPLE our population size - We use the population
        # size for new random entries, tradition select/crossover/mutate entries,
        # and sample/sum/mutate entries. (NOte our sample/sum/mutate works because
        # our mutate routine has a final "re-balance + force sparsity step"
        for _ in range(POP_SIZE):
            # simple random entry
            add_to_gen(self.rand_inst())

            # Merged entry
            merged = sp.array(self.population[self.winner()])
            for _ in range(MERGE_SIZE-1):
                merged += sp.array(self.population[self.winner()])
            add_to_gen(self.mutate(list(merged)))

            # "Normal" creation via selection, crossover/breeding. and mutation
            add_to_gen(self.mutate(self.crossover(
                self.population[self.winner()],
                self.population[self.winner()]
            )))

        # Have a new generation
        self.set_pop(new_gen)

    def dump_instance(self, inst, nutr, info=info):
        """Given an instance and it's nutritional space vector (just like score),
        output a decent, printable representation of the instance
        """
        score, score_vector = self.score(inst, nutr)
        info("Solution with score %12.4f (vector %s)", score, score_vector)
        for mic, amt in zip(ALL_MICROS, nutr):
            name, _, units, rda, ul = mic
            info("  NUTR %-15s: %8.2f %-5s, %8.2f%% of RDA %8.2f (UL %8.2f)",
                         name,  amt, units, (amt/rda)*100.0, rda,      ul
            )

        total_cals = 0.0

        for idx, amt in enumerate(inst):
            if abs(amt - 0.0) < 0.00001:
                continue

            food = self.food_details[idx]

            cals = '?'*8
            for n in food["nutrients"]:
                if n["nutrient_id"] == "208":
                    cals = float(n["nutrient_val"]) * amt
                    total_cals += cals
                    cals = "%8.2f" % cals
                    break

            info("  FOOD %8.2f units (%s cals) of %s (grp %s)",
                amt,
                cals,
                food["short_descrip"],
                food["food_group_descrip"]
            )

        info("Total Calories: %8.2f", total_cals)

def food_scores(engine):
    """Just output all foods that we allow with the score that you would get."""
    one_hot = []
    for i in range(engine.food_count):
        one = [0.0] * engine.food_count
        one[i] = 1.0
        one_hot.append(list(one))

    engine.set_pop(one_hot)
    engine.generation()

    for food, nutr in zip(engine.last_population, engine.last_popnutrition):
        engine.dump_instance(food, nutr)
        info('='*78)

def main():
    input_file = "foods.jsontxt.gz"  # TODO: command line or stdin or...

    info("Micronutrients used for calcs: %d", len(ALL_MICROS))

    info("Reading input file %s", input_file)
    food_details = list(read_foods(input_file))

    engine = opt_engine(food_details)
    info("Init population shape: %s", engine.population.shape)
    info("Food matrix shape: %s", engine.foods.shape)

    if '-foodscores' in sys.argv[1:]:
        food_scores(engine)
        return
    elif '-topn' in sys.argv[1:]:
        print("TODO: top-n per nutrient output")
        return

    # Do our generations
    # TODO: good stopping criteria
    with open("results", "w") as results:
        def file_output(s, *args):
            if args:
                s = s % args
            results.write(s)
            results.write('\n')
            results.flush()

        info("Pre-Running 2 generations")
        engine.generation()
        engine.generation()

        seen = set()

        for gen in range(1, 5000+1):
            engine.generation()

            best_food, best_nutr = engine.last_population[0], engine.last_popnutrition[0]
            info("BEGIN Generation %d (pop size %d)", gen, len(engine.last_population))
            engine.dump_instance(best_food, best_nutr)
            info("END Generation %d", gen)
            info('-'*20)

            for food, nutr in zip(engine.last_population[:3], engine.last_popnutrition[:3]):
                key = tuple(food)
                if key in seen:
                    continue

                seen.add(key)

                file_output("First Seen Generation %d", gen)
                engine.dump_instance(food, nutr, info=file_output)
                file_output('='*78)

if __name__ == "__main__":
    main()


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

# In[ ]:
import os
import pickle
import torch
import numpy as np
import data_loader.dataLoader as datas
from math import ceil
import pdb
from model_vc import Generator

device = 'cpu'
G = Generator(32,256,512,32).eval().to(device)

g_checkpoint = torch.load('autovc.ckpt', map_location = torch.device('cpu')) #AutoVC model weights
G.load_state_dict(g_checkpoint['model'])

data = datas.voiceDataset()
metadata = [data[0]]

spect_vc = []

def pad_seq(x, base=32):
    len_out = int(base * ceil(float(x.shape[0])/base))
    len_pad = len_out - x.shape[0]
    assert len_pad >= 0
    return np.pad(x, ((0,len_pad),(0,0)), 'constant'), len_pad

datas = pickle.load(open("./metadata.pkl", "rb"))

cnt = 0

STYLE = np.array([0.07455144, 0.        , 0.12114633, 0.        , 0.        ,
       0.        , 0.        , 0.        , 0.13354202, 0.06428103,
       0.11323338, 0.00388092, 0.01991886, 0.        , 0.        ,
       0.00472786, 0.        , 0.        , 0.09635921, 0.        ,
       0.02857794, 0.01997942, 0.        , 0.        , 0.        ,
       0.        , 0.        , 0.        , 0.        , 0.        ,
       0.11416078, 0.07932603, 0.        , 0.        , 0.        ,
       0.        , 0.07932524, 0.        , 0.10757284, 0.        ,
       0.        , 0.        , 0.04887488, 0.        , 0.        ,
       0.        , 0.        , 0.        , 0.        , 0.        ,
       0.        , 0.23951118, 0.        , 0.        , 0.        ,
       0.        , 0.        , 0.        , 0.13313983, 0.        ,
       0.        , 0.        , 0.0476586 , 0.02469627, 0.03124238,
       0.        , 0.12234554, 0.16775778, 0.        , 0.        ,
       0.        , 0.        , 0.        , 0.03403261, 0.08957145,
       0.        , 0.        , 0.        , 0.08680469, 0.11483785,
       0.        , 0.        , 0.05680807, 0.05188186, 0.0010662 ,
       0.        , 0.        , 0.        , 0.        , 0.2253635 ,
       0.08855635, 0.        , 0.        , 0.        , 0.        ,
       0.        , 0.1521231 , 0.        , 0.        , 0.        ,
       0.        , 0.        , 0.        , 0.0920624 , 0.18382049,
       0.        , 0.        , 0.03435336, 0.        , 0.07573951,
       0.        , 0.0212077 , 0.00221749, 0.        , 0.        ,
       0.        , 0.10780004, 0.        , 0.        , 0.20989977,
       0.09164576, 0.        , 0.07453016, 0.        , 0.0996456 ,
       0.        , 0.        , 0.06146271, 0.12226561, 0.        ,
       0.        , 0.        , 0.11276817, 0.14291915, 0.03035145,
       0.05189263, 0.01310621, 0.        , 0.12610166, 0.        ,
       0.        , 0.        , 0.02976863, 0.        , 0.        ,
       0.09120885, 0.05921955, 0.        , 0.        , 0.02345497,
       0.        , 0.12934522, 0.        , 0.        , 0.        ,
       0.06953817, 0.        , 0.        , 0.04197983, 0.11345872,
       0.        , 0.        , 0.        , 0.        , 0.        ,
       0.09859626, 0.        , 0.        , 0.08322733, 0.13532178,
       0.        , 0.        , 0.        , 0.01039974, 0.        ,
       0.01795498, 0.06318911, 0.05866239, 0.01411526, 0.        ,
       0.14554003, 0.        , 0.05958405, 0.0886642 , 0.05158373,
       0.        , 0.        , 0.        , 0.        , 0.        ,
       0.        , 0.11440271, 0.        , 0.09032299, 0.        ,
       0.        , 0.        , 0.22942148, 0.        , 0.        ,
       0.00417617, 0.        , 0.        , 0.        , 0.        ,
       0.        , 0.        , 0.        , 0.        , 0.08205518,
       0.        , 0.        , 0.02919286, 0.        , 0.        ,
       0.        , 0.        , 0.        , 0.04605015, 0.        ,
       0.        , 0.06806254, 0.        , 0.        , 0.        ,
       0.        , 0.05524325, 0.        , 0.        , 0.        ,
       0.        , 0.        , 0.06999438, 0.        , 0.        ,
       0.09677133, 0.0486298 , 0.06449135, 0.13095243, 0.09665707,
       0.06848858, 0.07414442, 0.07359253, 0.32064927, 0.        ,
       0.01135445, 0.17175235, 0.        , 0.        , 0.16320835,
       0.        , 0.04071496, 0.01670725, 0.        , 0.10546494,
       0.        ], dtype=np.float32)

i = 0
j = 2

x_org = datas[i][2]
x_org, len_pad = pad_seq(x_org)
uttr_org = torch.from_numpy(x_org[np.newaxis, :, :]).to(device)

emb_org = torch.from_numpy(datas[i][1][np.newaxis, :]).to(device)
emb_trg = torch.from_numpy(datas[j][1][np.newaxis, :]).to(device)
#emb_trg = torch.from_numpy(STYLE[np.newaxis, :]).to(device)
#pdb.set_trace()
with torch.no_grad():
    _, x_identic_psnt, _ = G(uttr_org, emb_org, emb_trg)

uttr_trg = x_identic_psnt[0, :, :].cpu().numpy()

#spect_vc.append( ('{}x{}'.format(sbmt_i["person"], sbmt_j["person"]), uttr_trg) )
spect_vc.append( ('{}x{}'.format(datas[i][0], "p226"), uttr_trg) )

with open('results.pkl', 'wb') as handle:
    pickle.dump(spect_vc, handle)


#!/usr/bin/env python
import sys
import os
import json
import urllib2
import caffe
import contextlib
import numpy as np
import classify_nsfw

def make_transformer(nsfw_net):
    # Note that the parameters are hard-coded for best results
    transformer = caffe.io.Transformer({'data': nsfw_net.blobs['data'].data.shape})
    transformer.set_transpose('data', (2, 0, 1))  # move image channels to outermost
    transformer.set_mean('data', np.array([104, 117, 123]))  # subtract the dataset-mean value in each channel
    transformer.set_raw_scale('data', 255)  # rescale from [0, 1] to [0, 255]
    transformer.set_channel_swap('data', (2, 1, 0))  # swap channels from RGB to BGR

    return transformer

nsfw_net = caffe.Net(
    "/opt/open_nsfw/nsfw_model/deploy.prototxt",
    "/opt/open_nsfw/nsfw_model/resnet_50_1by2_nsfw.caffemodel",
    caffe.TEST
)
caffe_transformer = make_transformer(nsfw_net)

def classify_from_url(image_entry, nsfw_net):
    image_entry = image_entry.strip()
    headers = {'User-agent': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5'}
    result = {}
    try:
        req = urllib2.Request(image_entry, None, headers)
        with contextlib.closing(urllib2.urlopen(req)) as stream:
            score = classify(stream.read(), nsfw_net)
            result = {"sfw_score": score[0], "nsfw_score": score[1]}

    except urllib2.HTTPError as e:
        result = {"error_reason": e.reason}

    except urllib2.URLError as e:
        result = {"error_reason": str(e.reason)}

    except Exception as e:
        result = {"error_reason": str(e)}

    print(json.dumps(result))

def classify(image_data, nsfw_net):

    # disable stdout
    null_fds = [os.open(os.devnull, os.O_RDWR) for x in range(2)]
    save = os.dup(1), os.dup(2)
    os.dup2(null_fds[0], 1)
    os.dup2(null_fds[1], 2)

    scores = classify_nsfw.caffe_preprocess_and_compute(
        image_data,
        caffe_transformer=caffe_transformer,
        caffe_net=nsfw_net,
        output_layers=['prob']
    )

    # enable stdout
    os.dup2(save[0], 1)
    os.dup2(save[1], 2)
    os.close(null_fds[0])
    os.close(null_fds[1])

    return scores

def main(argv):
    url = sys.argv[1]
    classify_from_url(url, nsfw_net)

if __name__ == "__main__":
    main(sys.argv)


import numpy as np
import pandas as pd
import sys

from isanlp.annotation_rst import DiscourseUnit

class GreedyRSTParser:
    def __init__(self, tree_predictor, confidence_threshold=0.05, _same_sentence_bonus=0.):
        """
        :param RSTTreePredictor tree_predictor:
        :param float confidence_threshold: minimum relation probability to append the pair into the tree
        """
        self.tree_predictor = tree_predictor
        self.confidence_threshold = confidence_threshold
        self._same_sentence_bonus = _same_sentence_bonus

    def __call__(self, edus, annot_text, annot_tokens, annot_sentences, annot_lemma, annot_morph, annot_postag,
                 annot_syntax_dep_tree, genre=None):
        """
        :param list edus: DiscourseUnit
        :param str annot_text: original text
        :param list annot_tokens: isanlp.annotation.Token
        :param list annot_sentences: isanlp.annotation.Sentence
        :param list annot_postag: lists of str for each sentence
        :param annot_lemma: lists of str for each sentence
        :param annot_syntax_dep_tree: list of isanlp.annotation.WordSynt for each sentence
        :return: list of DiscourseUnit containing each extracted tree
        """

        def to_merge(_scores):
            return np.argmax(np.array(_scores))

        self.tree_predictor.genre = genre

        nodes = edus
        max_id = self._get_max_id(nodes)

        # initialize scores
        features = self.tree_predictor.initialize_features(nodes,
                                                           annot_text, annot_tokens,
                                                           annot_sentences,
                                                           annot_lemma, annot_morph, annot_postag,
                                                           annot_syntax_dep_tree)

        scores = self._get_proba(features)

        while len(scores) > 1 and any([score > self.confidence_threshold for score in scores]):
            # select two nodes to merge
            j = to_merge(scores)  # position of the pair in list
            if j + 1 >= len(nodes):
                return nodes

            # make the new node by merging node[j] + node[j+1]
            relation = self._get_relation(features.iloc[j])
            relation, nuclearity = relation.split('_')
            temp = DiscourseUnit(
                id=max_id + 1,
                left=nodes[j],
                right=nodes[j + 1],
                relation=relation,
                nuclearity=nuclearity,
                proba=min(1., scores[j]),
                text=annot_text[nodes[j].start:nodes[j + 1].end].strip()
            )

            max_id += 1

            # modify the node list
            nodes = nodes[:j] + [temp] + nodes[j + 2:]

            # modify the scores list
            if j == 0:
                _features = self.tree_predictor.extract_features(nodes[j], nodes[j + 1],
                                                                 annot_text, annot_tokens,
                                                                 annot_sentences,
                                                                 annot_lemma, annot_morph, annot_postag,
                                                                 annot_syntax_dep_tree)

                _scores = self._get_proba(_features)
                scores = _scores + scores[j + 2:]
                features = pd.concat([_features, features.iloc[j + 2:]])

            elif j + 1 < len(nodes):
                _features = self.tree_predictor.initialize_features([nodes[j - 1], nodes[j], nodes[j + 1]],
                                                                    annot_text, annot_tokens,
                                                                    annot_sentences,
                                                                    annot_lemma, annot_morph, annot_postag,
                                                                    annot_syntax_dep_tree)

                _scores = self._get_proba(_features)
                features = pd.concat([features.iloc[:j - 1], _features, features.iloc[j + 2:]])
                scores = scores[:j - 1] + _scores + scores[j + 2:]

            else:
                _features = self.tree_predictor.extract_features(nodes[j - 1], nodes[j],
                                                                 annot_text, annot_tokens,
                                                                 annot_sentences,
                                                                 annot_lemma, annot_morph, annot_postag,
                                                                 annot_syntax_dep_tree)
                _scores = self._get_proba(_features)

                scores = scores[:j - 1] + _scores
                features = pd.concat([features.iloc[:j - 1], _features])

        if len(scores) == 1 and scores[0] > self.confidence_threshold:
            relation = self._get_relation(features.iloc[0])
            relation, nuclearity = relation.split('_')
            root = DiscourseUnit(
                id=max_id + 1,
                left=nodes[0],
                right=nodes[1],
                relation=relation,
                nuclearity=nuclearity,
                proba=min(1., scores[0]),
                text=annot_text[nodes[0].start:nodes[1].end].strip()
            )
            nodes = [root]

        return nodes

    def _get_max_id(self, dus):
        max_id = dus[-1].id
        for du in dus[:-1]:
            if du.id > max_id:
                max_id = du.id

        return max_id

    def _get_relation(self, pair_feature):
        relation = 'joint_NN'

        try:
            relation = self.tree_predictor.predict_label(pair_feature)
        except RuntimeError as e:
            # Some vector sizes do not fit in the model
            print(e)

        return relation

    def _get_proba(self, pair_feature):
        proba = 0.0

        try:
            proba = self.tree_predictor.predict_pair_proba(pair_feature, _same_sentence_bonus=self._same_sentence_bonus)
        except RuntimeError as e:
            # Some vectors sizes do not fit in the model
            print(e)

        return proba


from landia.utils import TickPerSecCounter
from typing import Dict, Any

import pygame
from .object import GObject
from .common import Vector2, Line, Circle, Polygon, Rectangle
from .object_manager import GObjectManager
from PIL import Image
import numpy as np
import os

from .config import RendererConfig
from .asset_bundle import AssetBundle
from .player import Player
from . import gamectx
import math
from math import ceil
import time
import pkg_resources
import logging
from .player import Camera
from .spritesheet import Spritesheet
from .utils import colormap
import random

# Windows stuff
windows = []
try:
    import win32gui
    from ctypes import windll, Structure, c_long, byref #windows only

    def windowEnumerationHandler(hwnd, windows):
        windows.append((hwnd, win32gui.GetWindowText(hwnd)))

    win32gui.EnumWindows(windowEnumerationHandler, windows)
    def front(win_name):
        for i in windows:
            if i[1] == win_name:
                win32gui.ShowWindow(i[0],5)
                win32gui.SetForegroundWindow(i[0])
                break

    class Rect(Structure):
        _fields_ = [
        ('left',    c_long),
        ('top',     c_long),
        ('right',   c_long),
        ('bottom',  c_long),
        ]
        def width(self):  return self.right  - self.left
        def height(self): return self.bottom - self.top

    def onTop():
        # import win32gui
        window = pygame.display.get_wm_info()['window']
        SetWindowPos = windll.user32.SetWindowPos
        GetWindowRect = windll.user32.GetWindowRect
        rc = RECT()
        GetWindowRect(window, byref(rc))
        SetWindowPos(window, -1, rc.left, rc.top, 0, 0, 0x0001)
        # windll.user32.SetActiveWindow(window)

except Exception:
    pass

def scale(vec, vec2):
    return Vector2(vec.x * vec2.x, vec.y * vec2.y)

class Renderer:

    def __init__(self, config: RendererConfig, asset_bundle: AssetBundle):
        if config.sdl_audio_driver:
            os.environ['SDL_AUDIODRIVER'] = config.sdl_audio_driver
        if config.sdl_video_driver:
            os.environ["SDL_VIDEODRIVER"] = config.sdl_video_driver
        self.asset_bundle = asset_bundle
        self.config: RendererConfig = config
        self.format = config.format

        self.view_port_scale = config.view_port_scale
        self.border_h_offset = config.border_h_offset

        self._view_port_surf = None
        self._final_surf = None
        self.full_resolution = config.resolution
        self.border_aspect_ratio = (self.full_resolution[0] * 1.0) / self.full_resolution[0]
        if self.view_port_scale == (1,1):
            self.resolution = self.width, self.height= self.full_resolution
            self.view_port_offset = 0,0

        else:
            self.width = round(self.full_resolution[0] * self.view_port_scale[0])
            self.height = round(self.width / self.border_aspect_ratio)* self.view_port_scale[1]
            self.resolution = self.width,self.height
            self.view_port_offset= round(self.width*self.border_h_offset),(self.full_resolution[1]- self.height)/2

        self.aspect_ratio = (self.width * 1.0) / self.height

        self.initialized = False
        self.frame_cache = None
        self.debug = config.debug_render_bodies
        # These will be source object properties eventually
        self.view_height = 600000.0
        self.view_width = self.view_height * self.aspect_ratio
        self.min_distance = self.config.tile_size*5
        self.max_distance = self.config.tile_size*100

        self.images = {}
        self.image_cache = {}
        self.sounds = {}
        self.sprite_sheets = {}

        self.log_info = None
        self.font = {}
        self.fps_clock = pygame.time.Clock()
        self.background = None
        self.background_center = None
        self.background_size = None
        self.background_updates = 0
        self.background_screen_factor = None

    def set_log_info(self, log_info):
        self.log_info = log_info

    def get_asset_fullpath(self,path):
        if path.startswith("/"):
            return path
        filepath = os.path.join(self.asset_bundle.path,path)
        if os.path.exists(filepath):
            return filepath
        else:
            return pkg_resources.resource_filename(__name__, path)

    def load_sounds(self):
        if self.config.sound_enabled:
            pass
            for k, sound_data in self.asset_bundle.sound_assets.items():
                path = sound_data[0]
                vol = sound_data[1]
                sound = pygame.mixer.Sound(self.get_asset_fullpath(path))
                sound.set_volume(vol)
                self.sounds[k] = sound

    def load_images(self):
        self.images = {}
        for k, (path, frame_id) in self.asset_bundle.image_assets.items():
            full_path = self.get_asset_fullpath(path)
            try:

                if frame_id is None:
                    image = pygame.image.load(full_path).convert_alpha()
                else:
                    if path not in self.sprite_sheets:
                        self.sprite_sheets[path] = Spritesheet(full_path)
                    image = self.sprite_sheets[path].parse_sprite(frame_id)
                self.images[k] = image
            except Exception as e:
                print(f"Error loading {path} {full_path}")
                raise e

    def play_sounds(self, sound_ids):
        if self.config.sound_enabled:
            for sid in sound_ids:
                self.sounds[sid].play()

    def play_music(self, music_id):
        if self.config.sound_enabled:
            if self.config.sound_enabled:
                data = self.asset_bundle.music_assets[music_id]
                full_path = self.get_asset_fullpath(data[0])
                pygame.mixer.music.load(full_path)
                pygame.mixer.music.play(-1)
                pygame.mixer.music.set_volume(data[1])

    def get_image_by_id(self, image_id):
        return self.images.get(image_id)

    def get_scaled_image_by_id(self, image_id, scale_x, scale_y):
        image_sizes = self.image_cache.get(image_id, {})
        img = image_sizes.get((scale_x, scale_y))
        if img is None:
            img_orig = self.get_image_by_id(image_id)
            if img_orig is None:
                return None
            body_w, body_h = img_orig.get_size()
            image_size = ceil(body_w*scale_x), ceil(body_h*scale_y)
            if image_size[0] > 500:
                image_size = 500, 500
            img = pygame.transform.scale(img_orig, image_size)
            image_sizes[(scale_x, scale_y)] = img
            self.image_cache[image_id] = image_sizes
        return img

    def update_view(self, view_height):
        self.view_height = max(view_height, 10)
        self.view_width = self.view_height * self.aspect_ratio

    def initialize(self):
        if self.config.sound_enabled:
            pygame.mixer.pre_init(44100, -16, 4, 2048)
            pygame.mixer.init()
        pygame.init()

        if self.config.enable_resize:
            flags = pygame.HWSURFACE | pygame.DOUBLEBUF | pygame.RESIZABLE | pygame.SCALED
        else:
            flags = pygame.DOUBLEBUF

        if self.config.render_to_screen:
            self._final_surf = pygame.display.set_mode(self.full_resolution, flags)
            if os.name == "nt":
                pygame.display.set_caption("Landia")
                front("Landia")

        else:
            self._final_surf = pygame.Surface(self.full_resolution)

        self._view_port_surf = pygame.Surface(self.resolution)
        self.load_sounds()
        self.load_images()
        self.play_music("background")
        pygame.key.set_repeat(1000,1)

        self.initialized = True

    def render_text(self, lines, x, y, fsize=14, spacing=12, color=(255, 255, 255), use_view_port_surface=False):

        surface = self._view_port_surf if use_view_port_surface else self._final_surf
        font = self.font.get(fsize)
        if fsize>spacing:
            spacing = fsize
        if font is None:
            font = pygame.font.SysFont("consolas", fsize)
            self.font[fsize] = font
        for i, l in enumerate(lines):
            surface.blit(font.render(l, True, color), (x, y + spacing * i))

    def _draw_grid_line(self, p1, p2, angle, center, screen_view_center, color, screen_factor):
        p1 = (p1 - center).rotate(angle)
        p1 = scale(screen_factor, (p1)) + screen_view_center
        p1 = p1

        p2 = (p2 - center).rotate(angle)
        p2 = scale(screen_factor, (p2)) + screen_view_center
        pygame.draw.line(self._final_surf,
                         color,
                         p1,
                         p2,
                         1)

    def screen_pos_to_game_pos(self,player:Player,pos):
        camera: Camera = None
        center: Vector2 = None
        if player:
            camera = player.get_camera()
        else:
            camera = Camera(center=Vector2(self.view_width/2, self.view_height/2))

        center = camera.get_center()
        if center is None:
            center = Vector2(self.view_width/2, self.view_height/2)
        angle = camera.get_angle()

        center = center - camera.position_offset
        screen_factor = Vector2(self.width / self.view_width, self.height / self.view_height)
        screen_view_center = scale(screen_factor, Vector2(self.view_width, self.view_height) / 2.0)

        scaled_pos = (pos[0] - screen_view_center[0])/ screen_factor[0], (pos[1] - screen_view_center[1])/ screen_factor[1]
        screen_pos = scaled_pos[0] + center[0] , scaled_pos[1] + center[1]
        return screen_pos

    def _draw_grid(self, center, angle, screen_factor, screen_view_center, color=(50, 50, 50), size=20, view_type=0):
        line_num = int(self.view_width/size) + 4

        x = int(center.x/size) * size - size/2
        y = int(center.y/size) * size - size/2

        y_start = -(y - size * line_num)
        y_center = Vector2(center.x, -center.y)
        for line in range(line_num * 2):
            y_pos = y_start - size * line
            p1 = Vector2(x-self.view_width, y_pos)
            p2 = Vector2(x+self.view_width, y_pos)
            self._draw_grid_line(p1, p2, angle, y_center, screen_view_center, color, screen_factor)

        x_start = x - size * line_num
        for line in range(line_num * 2):
            x_pos = x_start + size * line
            p1 = Vector2(x_pos, y-self.view_height)
            p2 = Vector2(x_pos, y+self.view_height)
            self._draw_grid_line(p1, p2, angle, center, screen_view_center, color, screen_factor)

    def draw_rectangle(self, x, y, width, height, color):
        rect = pygame.Rect(x, y, width, height)
        # rect.center = Vector2(x,y)
        pygame.draw.rect(self._view_port_surf, color, rect)

    def _draw_image(self, pos, center, image_id, angle, screen_factor, screen_view_center, color=(255, 0, 0)):
        image = self.get_scaled_image_by_id(image_id, screen_factor[0], screen_factor[1])
        image_loc = scale(screen_factor, pos - center) + screen_view_center
        if image is not None:
            if angle != 0:
                image = pygame.transform.rotate(image, angle % 360)
            rect = image.get_rect()
            rect.center = image_loc
            self._view_port_surf.blit(image, rect)
        else:
            rect = pygame.Rect(0, 0, self.config.tile_size * screen_factor[0], self.config.tile_size * screen_factor[1])
            rect.center = image_loc
            pygame.draw.rect(self._view_port_surf, color, rect)

    def _draw_infobox(self, infobox, surface:pygame.Surface, screen_factor,size):

        w,h = size# surface.get_size()
        padding = infobox.get("padding",1) * screen_factor[0]
        rows = len(infobox['value'])

        row_h = infobox.get("row_h")
        if row_h is not None:
            row_h = round(row_h * w)
        else:
            row_h = round ((h -(padding * (rows +1))) / rows )

        x_max = w - padding * 2
        x = padding
        for i,renderable in enumerate(infobox['value']):
            y = row_h * i + padding *(i+1)

            bg_color = renderable.get("bg_color")
            color = renderable.get("color")
            label = renderable.get("label")
            loc = x,y
            barw = x_max
            if label is not None:
                fsize=row_h
                font = self.font.get(fsize)
                if font is None:
                    font = pygame.font.SysFont(None, fsize)
                    self.font[fsize] = font
                twidth,_ = font.size(label)

                surface.blit(font.render(label, True, (200,200,200)), loc)
                loc = x + twidth,y
                barw = barw - twidth

            if bg_color is not None:
                rect = pygame.Rect(loc[0], loc[1],
                                    barw,
                                    row_h)

                pygame.draw.rect(surface, bg_color, rect)

            if renderable.get("type") == "bar":
                width = round(barw * renderable.get("value"))

                rect = pygame.Rect(loc[0], loc[1],
                                    width,
                                    row_h)

                pygame.draw.rect(surface, color, rect)

            elif renderable.get("type") == "block_list":
                size = renderable.get("size",3)
                chunk = barw/size
                pygame.draw.rect(surface, bg_color, rect)
                for val in renderable.get('value'):
                    bloc = loc[0] + chunk * val,loc[1]
                    blockw = chunk

                    # Bar
                    rect = pygame.Rect(bloc[0], bloc[1],
                                        blockw,
                                        row_h)

                    pygame.draw.rect(surface, colormap[round((val/size)*len(colormap))], rect)

            elif renderable.get('type') == 'icon':
                if renderable['value'] is not None:
                    image_id = renderable['value'][0]
                    image_orig  = self.get_image_by_id(image_id)
                    iw,ih = image_orig.get_rect().size

                    image = self.get_scaled_image_by_id(image_id, row_h/iw,row_h/iw)
                    rect = image.get_rect()
                    rect.center = loc[0] + barw/2, loc[1] + row_h /2
                    surface.blit(image, rect)
            elif renderable.get("type") == "text":
                fsize=row_h
                font = self.font.get(fsize)
                if font is None:
                    font = pygame.font.SysFont(None, fsize)
                    self.font[fsize] = font
                text = renderable['value']
                twidth,_ = font.size(text)
                loc =  max(0,loc[0]+ barw/2 - twidth /2), loc[1]
                color = renderable.get('color',(255,255,255))

                surface.blit(font.render(text, True, color), loc)

    def _draw_object(self, center, obj: GObject, screen_angle, screen_factor, screen_view_center, color=None):

        renderables = obj.get_renderables(screen_angle,info_filter=set(self.config.info_filter))
        for renderable in renderables:
            if renderable.get("type") == "text":
                fsize = round(3 * screen_factor[0])
                color = (255, 255, 255)
                pos = obj.get_view_position() - Vector2(self.config.tile_size/2, self.config.tile_size/2)
                loc = scale(screen_factor, pos - center) + screen_view_center

                font = self.font.get(fsize)
                if font is None:
                    font = pygame.font.SysFont(None, fsize)
                    self.font[fsize] = font
        # for i, l in enumerate(lines):
                self._view_port_surf.blit(font.render(renderable.get("value"), True, color), loc)
            elif renderable.get("type") == "infobox":
                boxscale = renderable.get("scale",(1.0,1.0))
                background_color = renderable.get("background_color",(0,0,0))
                pos = obj.get_view_position() - Vector2(self.config.tile_size/2, self.config.tile_size/2)
                loc = scale(screen_factor, pos - center) + screen_view_center
                size = (self.config.tile_size * screen_factor[0] * boxscale[0],self.config.tile_size * screen_factor[1] * boxscale[1])
                surface_size = size[0]*2,size[1]*2
                surface = pygame.Surface(surface_size)

                if background_color is None:
                    surface.set_colorkey((0,0,0))
                else:
                    surface.fill(background_color)
                self._draw_infobox(renderable, surface=surface, screen_factor=screen_factor,size = size)

                self._view_port_surf.blit(surface,loc)

            elif renderable.get("type") == "bar":
                color = renderable.get("color")
                bg_color = renderable.get("bg_color")
                pos = obj.get_view_position() - Vector2(self.config.tile_size/2, self.config.tile_size/2)
                loc = scale(screen_factor, pos - center) + screen_view_center
                barw = round(self.config.tile_size * screen_factor[0] /2)
                barh = 1 * screen_factor[0]
                # Bar BG
                rect = pygame.Rect(loc[0], loc[1],
                                   barw,
                                   barh)

                pygame.draw.rect(self._view_port_surf, bg_color, rect)
                width = round(barw * renderable.get("value"))
                # Bar
                rect = pygame.Rect(loc[0], loc[1],
                                   width,
                                   barh)

                pygame.draw.rect(self._view_port_surf, color, rect)
            elif renderable.get("type") == "tag":
                color = renderable.get("color")
                index = renderable.get("index",0)
                # bg_color = renderable.get("bg_color")
                tw = 1.2 * screen_factor[0]#round(self.config.tile_size * screen_factor[0] /2)
                th = 1.2 * screen_factor[1]
                pos = obj.get_view_position() - Vector2(self.config.tile_size/2 - 1.2 * index, 0)
                loc = scale(screen_factor, pos - center) + screen_view_center

                # Bar
                rect = pygame.Rect(loc[0], loc[1],
                                   tw,
                                   th)

                pygame.draw.rect(self._view_port_surf, color, rect)
            else:
                position = renderable['position']
                image_id = renderable['image_id']
                angle = renderable['angle']
                pos = obj.get_view_position() - position - obj.image_offset
                self._draw_image(pos, center, image_id, angle, screen_factor, screen_view_center)

    def filter_objects_for_rendering(self, objs, camera: Camera):
        center = camera.get_center()
        object_list_visheight_sorted = [[], [], [], []]
        if center is None:
            return []
        for k, o in objs.items():
            o: GObject = o
            if o is not None and o.is_enabled() and o.is_visible():
                view_position = o.get_view_position()
                if view_position is not None:
                    within_range = o.get_view_position().distance_to(center) < self.view_width
                    if within_range:
                        object_list_visheight_sorted[o.visheight].append(o)

        # TODO: Need to adjust with angle
        center_bottom = center - Vector2(0, 100)

        for lst in object_list_visheight_sorted:
            lst.sort(key=lambda o: o.get_position().distance_to(center_bottom))
        return object_list_visheight_sorted

    def ta(self, val):
        return int((val//self.config.tile_size) * self.config.tile_size)

    def _draw_background_image(self, image, center,  angle, screen_factor, screen_view_center):

        rect = image.get_rect()
        image_loc = scale(
            Vector2(self.background_center[0] - center.x,
                    self.background_center[1] - center.y),
            screen_factor) + screen_view_center
        rect.center = image_loc
        self._view_port_surf.blit(image, rect)

    def check_bounds(self, cv, cs, bv, bs):
        return ((bv - bs/2) >= (cv - cs/2)) or ((bv+bs/2) <= (cv + cs/2))

    def get_background_image(self, center, screen_factor):
        #TODO: occationally shows black areas when moving right or down, but only during movement

        # Align with tile coords
        center = Vector2(self.ta(center.x), self.ta(center.y))

        # Align and make sure odd number of tiles so center can be a single tile
        surface_width = self.ta(self.view_width/2) * 5 + self.config.tile_size
        surface_height = self.ta(self.view_height/2) * 5 + self.config.tile_size

        if screen_factor == self.background_screen_factor and self.background is not None:
            need_update = self.check_bounds(
                center.x,
                self.view_width,
                self.background_center[0],
                self.background_size[0])
            if not need_update:
                need_update = self.check_bounds(
                    center.y,
                    self.view_height,
                    self.background_center[1],
                    self.background_size[1])
                if not need_update:
                    return self.background

        gamemap = self.asset_bundle.maploader.get("")

        # Center tile for tile image id lookup
        sur_center_x = surface_width/2 - center.x
        sur_center_y = surface_height/2 - center.y
        sur_center_tile_x = sur_center_x // self.config.tile_size
        sur_center_tile_y = sur_center_y // self.config.tile_size

        tmp_surface = pygame.Surface((surface_width, surface_height))
        for z in gamemap.get_layers():
            for tile_x in range(surface_width//self.config.tile_size):
                ltile_x = (tile_x - sur_center_tile_x)
                for tile_y in range(surface_height//self.config.tile_size):
                    ltile_y = (tile_y - sur_center_tile_y)
                    background_image_id = gamemap.get_image_by_loc(ltile_x, ltile_y, z)
                    if background_image_id is not None:
                        tile_image = self.get_image_by_id(background_image_id)

                        rect = tile_image.get_rect()
                        tile_pos = (int(tile_x * self.config.tile_size), int(tile_y * self.config.tile_size))
                        rect.topleft = tile_pos
                        tmp_surface.blit(tile_image, rect)

        image_size = int(surface_width*screen_factor[0]), int(surface_height*screen_factor[1])

        tmp_surface = pygame.transform.scale(tmp_surface, image_size)
        self.background = tmp_surface
        self.background_center = center
        self.background_size = surface_width, surface_height
        self.background_screen_factor = screen_factor
        self.background_updates += 1
        return self.background

    # TODO: Clean this up
    def process_frame(self,
                      player: Player = None):

        if not self.initialized:
            self.initialize()

        # import pdb;pdb.set_trace()
        self._view_port_surf.fill((0, 0, 0))
        self._final_surf.fill((0, 0, 0))

        angle = 0
        camera: Camera = None
        center: Vector2 = None
        if player:
            camera = player.get_camera()
        else:
            camera = Camera(center=Vector2(self.view_width/2, self.view_height/2))

        if camera.distance > self.max_distance:
            camera.distance = self.max_distance
        elif camera.distance < self.min_distance:
            camera.distance = self.min_distance

        center = camera.get_center()
        if center is None:
            center = Vector2(self.view_width/2, self.view_height/2)
        angle = camera.get_angle()

        # TODO: View Width/Height should only be in camera
        self.update_view(camera.get_distance())

        center = center - camera.position_offset
        screen_factor = Vector2(self.width / self.view_width, self.height / self.view_height)
        screen_view_center = scale(screen_factor, Vector2(self.view_width, self.view_height) / 2.0)

        background = self.get_background_image(center, screen_factor)
        self._draw_background_image(background, center, 0, screen_factor, screen_view_center)

        if self.config.draw_grid:
            self._draw_grid(center,
                            angle,
                            screen_factor,
                            screen_view_center,
                            size=self.config.tile_size,
                            view_type=self.config.view_type,
                            color=(20, 20, 20))

        obj_list_sorted_by_visheight = self.filter_objects_for_rendering(gamectx.object_manager.get_objects(), camera)

        for visheight, render_obj_dict in enumerate(obj_list_sorted_by_visheight):
            obj: GObject
            for obj in render_obj_dict:
                if not obj.enabled or not obj.is_visible():
                    continue
                self._draw_object(center, obj, angle, screen_factor, screen_view_center, obj.shape_color)

        if self.debug:
            pygame.draw.rect(self._view_port_surf,
                             (0, 250, 250),
                             pygame.Rect(center.x + self.width/2, center.y+self.height/2, 5, 5))

            pygame.draw.rect(self._view_port_surf,
                             (255, 255, 50),
                             pygame.Rect(self.width/2, self.height/2, 5, 5))

    def render_frame(self):

        self._final_surf.blit(self._view_port_surf,self.view_port_offset)
        self.fps_clock.tick()
        # if self.config.save_observation:
        #     self.frame_cache = self.get_last_frame()

        if self.config.render_to_screen:
            pygame.display.flip()

    def get_last_frame(self):
        img_st = pygame.image.tostring(self._final_surf, self.format)
        data = Image.frombytes(self.format, self.config.resolution, img_st)
        np_data = np.array(data)
        return np_data


from io import BytesIO
from flask import Flask, send_file, request
from PIL import Image
import requests
import numpy as np
import tensorflow as tf
from json import dumps
from object_detection.utils import label_map_util
from object_detection.utils import visualization_utils as vis_util
import os

PATH_TO_CKPT = '/app/my_frozen_inference_graph.pb'

detection_graph = tf.Graph()
with detection_graph.as_default():
    od_graph_def = tf.GraphDef()
    with tf.gfile.GFile(PATH_TO_CKPT, 'rb') as fid:
        serialized_graph = fid.read()
        od_graph_def.ParseFromString(serialized_graph)
        tf.import_graph_def(od_graph_def, name='')

PATH_TO_LABELS = '/app/my_label_map.pbtxt'
NUM_CLASSES = 90

label_map = label_map_util.load_labelmap(PATH_TO_LABELS)
categories = label_map_util.convert_label_map_to_categories(label_map, max_num_classes=NUM_CLASSES, use_display_name=True)
category_index = label_map_util.create_category_index(categories)
print('Loaded')
#
app = Flask(__name__)

def image2array(image):
    (w, h) = image.size
    return np.array(image.getdata()).reshape((h, w, 3)).astype(np.uint8)

def array2image(arr):
    return Image.fromarray(np.uint8(arr))

def detect_objects(sess, image):
    '''Plots the object detection result for a given image.'''
    image_np = image2array(image)
    image_np_expanded = np.expand_dims(image_np, axis=0)

    image_tensor = detection_graph.get_tensor_by_name('image_tensor:0')
    boxes = detection_graph.get_tensor_by_name('detection_boxes:0')
    scores = detection_graph.get_tensor_by_name('detection_scores:0')
    classes = detection_graph.get_tensor_by_name('detection_classes:0')
    num_detections = detection_graph.get_tensor_by_name('num_detections:0')

    (boxes, scores, classes, num_detections) = sess.run(
          [boxes, scores, classes, num_detections],
          feed_dict={image_tensor: image_np_expanded})

    boxes = np.squeeze(boxes)
    classes = np.squeeze(classes).astype(np.int32)
    scores = np.squeeze(scores)
    return [boxes, scores, classes, num_detections]

@app.route('/')
def detect():
    default_url = 'http://thecatapi.com/api/images/get?format=src&type=jpg'
    url = request.args.get('url', default_url)
    r = requests.get(url)
    image = Image.open(BytesIO(r.content))
    with detection_graph.as_default():
        with tf.Session(graph=detection_graph) as sess:
            detect_objects(sess, image)
    return "Hi"

if __name__ == '__main__':
    app.run(host="0.0.0.0", port="443", use_reloader=False)