from datetime import date, datetime, time, timedelta
from typing import List, Optional, Callable

import plotly.graph_objects as go
from colour import Color

from input_reading import BusLeg
from others import Employee

class VisualInterval:
    """Container for the data associated with an interval for visualisation."""

    def __init__(self, start, end, pos: int,  hover: Optional[str], text: Optional[str]) -> None:
        """Set the content.

        Start and end might be integers, datetime, or datetime strings.
        :param start: Start of the interval
        :param end: End of the interval
        :param hover: Text to show on hover, supports plotly formatting
        :param text: Text to show in the center of the interval, supports plotly formatting
        """
        self.start = start
        self.end = end
        self.pos = pos
        self.hover = hover
        self.text = text

class IntervalVisualizer:
    """Factory for creating plotly figures for interval visualisation."""

    AXIS_VAL = 0
    AXIS_HOURS = 1
    AXIS_DAYS = 2
    AXIS_DATE = 3

    def __init__(self, axis: int = AXIS_VAL, axis_delta: timedelta = timedelta(minutes=1), axis_date: date = None) -> \
            None:
        """Initialize the visualizer.

        :param axis: Scale on the time axis, one of AXIS_VAL for integers, AXIS_HOURS for HH:MM, AXIS_DAYS for 'dd hh',
        or AXIS_DATE for date and time
        :param axis_delta: Time granularity in the given intervals
        :param axis_date: Start date for AXIS_DATE, otherwise ignored
        """
        self.height = .4
        self.axis = axis
        self.axis_format = None
        self.hover_format = '%H:%M'
        if axis == self.AXIS_HOURS:
            self.axis_format = '%H:%M'
            axis_date = date(2020, 1, 1)
        elif axis == self.AXIS_DAYS:
            self.axis_format = '%-jd %Hh'
            self.hover_format = '%jd %H:%M'
            axis_date = date(2020, 1, 1)
        elif axis == self.AXIS_DATE:
            self.hover_format = '%Y-%m-%d %H:%M'
        if axis_delta < timedelta(minutes=1):
            self.hover_format += ':%S'
        self.axis_delta = axis_delta
        self.axis_start = datetime.combine(axis_date if axis_date is not None else date.today(), time())

    def __build_hover(self, interval: BusLeg, hover: Optional[str]) -> Optional[str]:
        """Build the hover text from the interval based on the template."""

        if hover is None:
            return None

        index = 0
        while '%' in hover[index:]:

            pos = hover.find('%', index)
            if hover[pos + 1] == '%':
                index += 2
                continue
            end_pos = hover.find('}', index)

            attr = hover[pos + 2:end_pos]
            replace = getattr(interval, hover[pos + 2:end_pos], None)
            if self.axis != self.AXIS_VAL and (attr == 'start' or attr == 'end'):
                replace = (self.axis_start + self.axis_delta * replace).strftime(self.hover_format)
                if self.axis == self.AXIS_DAYS:
                    replace = replace.lstrip('0')
            else:
                replace = str(replace)

            hover = hover.replace(hover[pos:end_pos + 1], replace)

        hover = hover.replace('%%', '%')
        return hover

    @staticmethod
    def __contrast_color(col: Color) -> Color:
        """Return the appropriate text color (black or white) for the given background color."""
        if 0.299 * col.red + 0.587 * col.green + 0.114 * col.blue > 0.5:
            return Color('black')
        else:
            return Color('white')

    def create(self, intervals: List[Employee], title: str, type_attr: Optional[str] = None,
               hovertext: Callable[[BusLeg], str] = lambda x: None, text_attr: Optional[str] = None,
               hidden: Optional[List[str]] = None) -> go.Figure:
        """Create the figure for the given interval sequences.

        :param intervals: List of sequences, each sequence corresponds to one row with the attribute 'name' on the axis
        :param title: Title of the figure
        :param type_attr: BusLeg attribute for grouping the intervals, each type corresponds to a legend entry and a
        (most likely) unique color
        :param hovertext: Function returing the hover text template for each interval, allows plotly formatting like
        ... or
 and using interval attributes with %{attr}, %{start} and %{end} are formatted according to
        self.axis, no hover text if None is returned
        :param text_attr: BusLeg attribute to show as text in the center of each interval, formatted like hovertext
        :param hidden: List of types that are initially hidden
        """

        types = {}
        if hidden is None:
            hidden = []

        for i, sequence in enumerate(intervals):
            for interval in sequence:
                t = None
                if type_attr is not None:
                    t = getattr(interval, type_attr, None)
                if t not in types:
                    types[t] = []
                text = None
                if text_attr is not None:
                    text = getattr(interval, text_attr, None)
                if self.axis == 0:
                    types[t].append(VisualInterval(interval.start,
                                                   interval.end,
                                                   i,
                                                   self.__build_hover(interval, hovertext(interval)),
                                                   text))
                else:
                    types[t].append(VisualInterval(self.axis_start + self.axis_delta * interval.start,
                                                   self.axis_start + self.axis_delta * interval.end,
                                                   i,
                                                   self.__build_hover(interval, hovertext(interval)),
                                                   text))

        data = []
        count = 0
        for t, values in types.items():
            text = []
            text_x = []
            text_y = []
            first = True
            col = Color(pick_for=t, pick_key=None)
            text_col = self.__contrast_color(col)
            for interval in values:
                data.append(go.Scatter(fill='toself',
                                       hoverinfo='none' if interval.hover is None else 'text',
                                       hoverlabel=go.scatter.Hoverlabel(bgcolor=col.hex,
                                                                        font=dict(color=text_col.hex)),
                                       hoveron='fills+points',
                                       legendgroup=t,
                                       line=dict(color=col.hex),
                                       mode='lines',
                                       name=t,
                                       showlegend=first,
                                       text=interval.hover,
                                       visible='legendonly' if t in hidden else True,
                                       x=[interval.start, interval.end, interval.end, interval.start, interval.start],
                                       y=[interval.pos - self.height, interval.pos - self.height,
                                          interval.pos + self.height, interval.pos + self.height,
                                          interval.pos - self.height]))
                first = False
                if interval.text is not None:
                    text.append(interval.text)
                    text_x.append(interval.start + (interval.end - interval.start) / 2)
                    text_y.append(interval.pos)
            data.append(go.Scatter(hoverinfo='skip', legendgroup=t, mode='text', showlegend=False, text=text,
                                   textfont=dict(color=text_col.hex), x=text_x, y=text_y))
            count += 1

        fig = go.Figure(
            data=data,
            layout=go.Layout(
                hoverdistance=3,
                title=go.layout.Title(text=title),
                xaxis=go.layout.XAxis(showspikes=True, spikedash='solid', spikemode='across', spikethickness=1),
                yaxis=go.layout.YAxis(
                    autorange='reversed',
                    ticktext=list(map(lambda v: v.name, intervals)),
                    tickvals=list(range(len(intervals))),
                    zeroline=False
                )
            )
        )

        if self.axis_format is not None:
            fig.update_xaxes(tickformat=self.axis_format)

        return fig


import json
import pika

class QueuePusher(object):

    def __init__(self, queue_server: str, queue_port: int, queue_name: str):
        super().__init__()
        self._queue_name = queue_name
        self._connection = pika.BlockingConnection(
            pika.ConnectionParameters(queue_server, queue_port))
        self._channel = self._connection.channel()

    def __del__(self):
        _connection = getattr(self, "_connection", None)
        if _connection and _connection.is_open:
            _connection.close()

    def put_message_to_queue(self, message: dict) -> bool:
        if self._channel:
            return self._channel.basic_publish(
                exchange='',
                routing_key=self._queue_name,
                body=json.dumps(message),
                properties=pika.BasicProperties(delivery_mode=2))
        raise Exception("Channel is not set")


# coding: utf-8

import config as cfg
import tensorflow as tf
import numpy as np

class Yolo(object):
    def __init__(self):
        self.__classes = cfg.CLASSES
        self.__num_class = len(self.__classes)
        self.__box_per_cell = cfg.BOX_PRE_CELL
        self.__batch_size = cfg.BATCH_SIZE
        self.__image_size = cfg.IMAGE_SIZE
        self.__cell_size = cfg.CELL_SIZE
        self.__down_sample_size = 1.0 * self.__image_size / self.__cell_size
        self.__anchor = cfg.ANCHOR

        self.__obj_conf = 1.0
        self.__noobj_conf = 0.5
        self.__obj_coor = 5.0
        self.__obj_prob = 1.0

    def __batch_normalization(self, input_data, is_training, decay=0.95):
        """
        :param input_data: 输入数据，shape为'NHWC'
        :param is_training: 是否在训练，即bn会根据该参数选择mean and variance
        :param decay: 均值方差滑动参数
        :return: BN后的数据
        """
        with tf.variable_scope('BN'):
            input_depth = input_data.get_shape()[-1]
            moving_mean = tf.get_variable(name='moving_mean', shape=input_depth, dtype=tf.float32,
                                          initializer=tf.zeros_initializer, trainable=False)
            moving_var = tf.get_variable(name='moving_var', shape=input_depth, dtype=tf.float32,
                                         initializer=tf.ones_initializer, trainable=False)

            def mean_and_var_update():
                axes = range(len(input_data.get_shape()) - 1)
                batch_mean = tf.reduce_mean(input_data, axis=axes)
                batch_var = tf.reduce_mean(tf.pow(input_data - batch_mean, 2), axis=axes)
                with tf.control_dependencies([tf.assign(moving_mean, moving_mean * decay + batch_mean * (1 - decay)),
                                              tf.assign(moving_var, moving_var * decay + batch_var * (1 - decay))]):
                    return tf.identity(batch_mean), tf.identity(batch_var)

            mean, variance = tf.cond(is_training, mean_and_var_update, lambda:(moving_mean, moving_var))
            shift = tf.get_variable(name='shift', shape=input_depth, dtype=tf.float32,
                                    initializer=tf.zeros_initializer, trainable=True)
            scale = tf.get_variable(name='scale', shape=input_depth, dtype=tf.float32,
                                    initializer=tf.ones_initializer, trainable=True)
            return tf.nn.batch_normalization(input_data, mean, variance, shift, scale, 1e-8)

    def __conv(self, var_scope, input_data, filter_size, is_training,
               stride=(1, 1, 1, 1), padding='SAME', activation=True, BN=True):
        """
        :param var_scope: conv层的名称空间
        :param input_data: conv层的输入数据，格式为'NHWC'
        :param filter_size: filter的size，格式为[filter_height, filter_width, in_channels, out_channels]
        :param stride: filter的stride，格式为[1, stride, stride, 1]
        :param padding: 是否padding，'SAME' or 'VALID'
        :param activation: 是否添加激活函数，默认使用relu激活函数
        :param BN: 是否BN，True or False
        :param is_training: 是否在训练，True or False
        :return: 卷积后的数据
        """
        with tf.variable_scope(var_scope):
            weight = tf.get_variable(name='weight', shape=filter_size, dtype=tf.float32, trainable=True,
                                      initializer=tf.random_normal_initializer(stddev=0.01))
            bias = tf.get_variable(name='bias', shape=filter_size[-1], trainable=True,
                                   dtype=tf.float32, initializer=tf.constant_initializer(0.0))
            conv = tf.nn.conv2d(input=input_data, filter=weight, strides=stride, padding=padding)
            if BN:
                conv = self.__batch_normalization(input_data=conv, is_training=is_training)
            if activation:
                conv = tf.nn.relu(tf.nn.bias_add(conv, bias))
        return conv

    def __pool(self, var_scope, input_data, ksize=(1,2,2,1), stride=(1,2,2,1),
               padding='SAME', pooling=tf.nn.max_pool):
        """
        :param var_scope: pooling层的命名空间
        :param input_data: pooling层的输入数据，格式为'NHWC'
        :param ksize: pooling的size，格式为[1, pooling_height, pooling_width, 1]
        :param stride: pooling的stride，格式为[1, stride, stride, 1]
        :param padding: 是否padding 'SAME' or 'VALID'
        :param pooling: 选择用哪个pooling层
        :return: 池化后的数据
        """
        with tf.variable_scope(var_scope):
            pool_output = pooling(value=input_data, ksize=ksize, strides=stride, padding=padding)
        return pool_output

    def __reorg(self, input_data):
        """
        :param input_data: 输入数据shape为(batch_size, height, width, channel)
        :return: 返回数据的shape为(batch_size, height/2, width/2, channel*4)
        """
        with tf.name_scope('reorg'):
            output1 = input_data[:, ::2, ::2, :]
            output2 = input_data[:, ::2, 1::2, :]
            output3 = input_data[:, 1::2, ::2, :]
            output4 = input_data[:, 1::2, 1::2, :]
            output_data = tf.concat([output1, output2, output3, output4], axis=-1)
        return output_data

    def build_network(self, input_data, is_training):
        """
        :param input_data: 输入数据，格式为'NHWC'
        :param is_training: 是否在训练，需要是类型为bool的tensorflow 变量，不能使用python的bool类型
        :return: yolo的输出数据，shape为(batch_size, cell_size, cell_size, box_per_cell * (5+num_classes))
        """
        with tf.variable_scope('YOLO'):
            net = self.__conv('conv_0', input_data, [3, 3, 3, 32], is_training)
            net = self.__pool('pool_0', net)

            net = self.__conv('conv_1', net, [3, 3, 32, 64], is_training)
            net = self.__pool('pool_1', net)

            net = self.__conv('conv_2', net, [3, 3, 64, 128], is_training)
            net = self.__conv('conv_3', net, [1, 1, 128, 64], is_training)
            net = self.__conv('conv_4', net, [3, 3, 64, 128],is_training)
            net = self.__pool('pool_2', input_data=net)

            net = self.__conv('conv_5', net, [3, 3, 128, 256], is_training)
            net = self.__conv('conv_6', net, [1, 1, 256, 128], is_training)
            net = self.__conv('conv_7', net, [3, 3, 128, 256], is_training)
            net = self.__pool('pool_3', net)

            net = self.__conv('conv_8', net, [3, 3, 256, 512], is_training)
            net = self.__conv('conv_9', net, [1, 1, 512, 256], is_training)
            net = self.__conv('conv_10', net, [3, 3, 256, 512], is_training)
            net = self.__conv('conv_11', net, [1, 1, 512, 256], is_training)
            net17 = self.__conv('conv_12', net, [3, 3, 256, 512], is_training)
            net = self.__pool('pool_4', net17)

            net = self.__conv('conv_13', net, [3, 3, 512, 1024], is_training)
            net = self.__conv('conv_14', net, [1, 1, 1024, 512], is_training)
            net = self.__conv('conv_15', net, [3, 3, 512, 1024], is_training)
            net = self.__conv('conv_16', net, [1, 1, 1024, 512], is_training)
            net = self.__conv('conv_17', net, [3, 3, 512, 1024], is_training)

            net = self.__conv('conv_18', net, [3, 3, 1024, 1024], is_training)
            net25 = self.__conv('conv_19', net, [3, 3, 1024, 1024], is_training)

            shortcut = self.__conv('shortcut', net17, [1, 1, 512, 64], is_training)
            shortcut = self.__reorg(shortcut)
            net = tf.concat([net25, shortcut], axis=3)

            net = self.__conv('conv_20', net, [3, 3, net.get_shape()[-1], 1024], is_training)
            net = self.__conv('conv_21', net, [1, 1, 1024, self.__box_per_cell * (5 + self.__num_class)],
                              activation=False, BN=False, is_training=is_training)
            return net

    def loss(self, predict, label):
        """
        :param predict: predict是yolo的输出，shape为(batch_size, cell_size, cell_size, box_per_cell * (5 + num_class))
        :param label: label是标签，shape为(batch_size, cell_size, cell_size, box_per_cell, 5 + num_class)
        :return: YOLO的loss
        """
        with tf.name_scope('yolo_loss'):
            predict = tf.reshape(predict, (self.__batch_size, self.__cell_size, self.__cell_size,
                                           self.__box_per_cell, self.__num_class + 5))
            pred_conf = predict[:, :, :, :, 0:1]
            pred_coor = predict[:, :, :, :, 1:5]
            pred_prob = predict[:, :, :, :, 5:]

            # 1、将yolo的输出转换成用于计算loss的形式
            # coor存储的是(dx,dy,dw,dh)，(dx,dy,dw,dh)的大小都是相对于down_sample_size的
            # (down_sample_size = image_size / cell_size)
            # dx,dy是预测框的中心坐标相对于其所在grid的左上角坐标的偏移量、dw,dh是预测框的宽高相对于Anchor宽高的缩放量
            pred_conf = tf.sigmoid(pred_conf)
            pred_coor = tf.concat([tf.sigmoid(pred_coor[:, :, :, :, 0:2]),
                                   tf.exp(pred_coor[:, :, :, :, 2:])], axis=-1)
            pred_prob = tf.nn.softmax(pred_prob)

            # 2、将标签转换成用于计算loss的形式
            # (1)计算所有Anchor与相应GT的IOU
            GT_coor = label[:, :, :, :, 1:5]
            y, x = np.mgrid[:self.__cell_size, :self.__cell_size]
            grid_coor = np.concatenate([x[:, :, np.newaxis], y[:, :, np.newaxis]], axis=-1)
            grid_coor = np.repeat(grid_coor[:, :, np.newaxis, :], self.__box_per_cell, axis=-2)
            grid_coor = np.repeat(grid_coor[np.newaxis, :, :, :, :], self.__batch_size, axis=0)

            anchor_coor = np.zeros((self.__batch_size, self.__cell_size, self.__cell_size, self.__box_per_cell, 4))
            anchor_coor[:, :, :, :, :2] = grid_coor + 0.5
            anchor_coor[:, :, :, :, 2:] = [[w, h] for w, h in self.__anchor]
            anchor_coor = tf.constant(anchor_coor, dtype=tf.float32, name='Anchors')
            iou = self.__calc_iou(GT_coor, anchor_coor)

            # (2)将label转换成用于计算loss的形式(tx, ty, tw, th)
            # GT_coor存储的是(x,y,w,h)，(x,y,w,h)的大小都是相对于down_sample_size的，其中(x,y)是GT的中心坐标
            # 此处计算出GT的中心坐标相对于其所在grid的左上角坐标的偏移量(tx, ty)、以及GT的宽高相对于Anchor宽高的缩放量(tw, th)
            # GT落入某个grid，那么该grid的所有Anchor全部先打上位置标签、置信度标签、类别标签，其他grid的Anchor的标签为0
            xy_shift = tf.maximum(GT_coor[:, :, :, :, :2] - grid_coor, 0.0)
            wh_scale = 1.0 * GT_coor[:, :, :, :, 2:] / anchor_coor[:, :, :, :, 2:]
            label_coor = tf.concat([xy_shift, wh_scale], axis=-1)
            label_conf = label[:, :, :, :, 0:1]
            label_prob = label[:, :, :, :, 5:]

            # 3、计算loss
            # iou是GT与相应grid中所有Anchor的iou
            # 只有当某个grid中的某个Anchor要负责某个GT时，该Anchor对应的responsible_obj中的位置才为1，否则为0
            max_iou = tf.reduce_max(iou, axis=-1, keep_dims=True)
            # 因为[0, 0, 0...]的最大值为0，所以需要在后面减去tf.to_float(tf.equal(max_iou, 0))，以解决这种情况
            responsible_obj = tf.to_float(tf.equal(max_iou, iou)) - tf.to_float(tf.equal(max_iou, 0))
            responsible_obj = responsible_obj[:, :, :, :, tf.newaxis]
            no_responsible_obj = 1.0 - responsible_obj
            iou_lessthan_thr = tf.to_float(iou < 0.6)
            iou_lessthan_thr = iou_lessthan_thr[:, :, :, :, tf.newaxis]

            loss_coor = self.__obj_coor * responsible_obj * tf.square(pred_coor - label_coor)
            loss_conf = self.__obj_conf * responsible_obj * tf.square(pred_conf - label_conf) + \
                        self.__noobj_conf * no_responsible_obj * iou_lessthan_thr * tf.square(pred_conf)
            loss_prob = self.__obj_prob * responsible_obj * tf.square(pred_prob - label_prob)

            loss = tf.concat([loss_conf, loss_coor, loss_prob], axis=-1)
            loss = tf.reduce_mean(tf.reduce_sum(loss, axis=[1, 2, 3, 4]), name='yolo_v2_loss')
            return loss

    def __calc_iou(self, boxes1, boxes2):
        """
        :param boxes1: 输入boxes的shape为必须(batch_size, image_height, image_width, box_per_cell, 4)
        存储结构为(x,y,w,h)，其中(x,y)是bbox的中心坐标
        :param boxes2:
        :return: 返回boxes1和boxes2的IOU，IOU的shape为(batch_size, image_height, image_width, box_per_cell)
        """
        boxes1_area = boxes1[:, :, :, :, 2] * boxes1[:, :, :, :, 3]
        boxes2_area = boxes2[:, :, :, :, 2] * boxes2[:, :, :, :, 3]

        # 分别计算出boxes1和boxes2的左上角坐标、右下角坐标
        # 存储结构为(xmin, ymin, xmax, ymax)，其中(xmin,ymin)是bbox的左上角坐标，(xmax,ymax)是bbox的右下角坐标
        boxes1 = tf.concat([boxes1[:, :, :, :, :2] - boxes1[:, :, :, :, 2:] * 0.5,
                            boxes1[:, :, :, :, :2] + boxes1[:, :, :, :, 2:] * 0.5], axis=-1)
        boxes2 = tf.concat([boxes2[:, :, :, :, :2] - boxes2[:, :, :, :, 2:] * 0.5,
                            boxes2[:, :, :, :, :2] + boxes2[:, :, :, :, 2:] * 0.5], axis=-1)

        # 计算出boxes1与boxes1相交部分的左上角坐标、右下角坐标
        left_up = tf.maximum(boxes1[:, :, :, :, :2], boxes2[:, :, :, :, :2])
        right_down = tf.minimum(boxes1[:, :, :, :, 2:], boxes2[:, :, :, :, 2:])

        # 因为两个boxes没有交集时，(right_down - left_up) < 0，所以maximum可以保证当两个boxes没有交集时，它们之间的iou为0
        inter_section = tf.maximum(right_down - left_up, 0.0)
        inter_area = inter_section[:, :, :, :, 0] * inter_section[:, :, :, :, 1]
        union_area = boxes1_area + boxes2_area - inter_area
        IOU = 1.0 * inter_area / union_area
        return IOU


import os
from termcolor import colored
import cv2
from fastai import *
from fastai.vision.all import *
import gesture_recorder as gr
from time import sleep
from IPython.display import clear_output
from clear import clear

num_rcdings=10

grs=open('gestures.txt','r')
gestures=grs.read().split(',')
clear()
print(colored("Gestures :",'blue'))
print(gestures)
print(colored(f"The gesture record will strart in 10 seconds, with {num_rcdings} recordings per gesture",'cyan'))
sleep(5)
clear()

for gesture in gestures:
    try:
        os.mkdir('dataset/'+gesture)
    except Exception:
        pass

    cont=36
    for i in range(0,num_rcdings):

        print(colored(f'Do a {gesture} in 5 seconds','blue'))
        sleep(1)
        print(colored("4 seconds",'yellow'))
        sleep(1)
        print(colored("3 seconds",'yellow'))
        sleep(1)
        print(colored("2 seconds",'red'))
        sleep(1)
        print(colored("1 seconds",'red'))
        sleep(1)
        print(colored('Recording ... ','blue'))

        gr.record('dataset/'+gesture+'/'+str(cont),3)
        cont=cont+1
        clear()
        print(colored(f"Gesture recorded : {gesture}",'green'))
        sleep(1)
        clear()


# not needed
# from PIL import Image
import pytesseract
import cv2
# we might need for speed
import imutils
from imutils.video import VideoStream

def ocr_core(filename):
    text = pytesseract.image_to_string(Image.open(filename))
    return text

#print(ocr_core('example.png'))

# see image_to_data
# https://stackoverflow.com/questions/20831612/getting-the-bounding-box-of-the-recognized-words-using-python-tesseract
cap = cv2.VideoCapture(0)

while True:
	# read image ----
	ret, img = cap.read()
	if ret:
		# process image ---
		# if needed grayscale
		gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
		# blur
		gray = cv2.GaussianBlur(gray, (3,3), 0)
		img2 = cv2.GaussianBlur(img, (31,31), 0)
		# if needed do some sort of edge detection to reduce ROI
		mask = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
		# get ROI to work and crop image
		# invert the mask
		#mask = 255 - mask

		condition = False
		# only call tesseract if needed
		if condition:
			print(pytesseract.image_to_string(img))
			# feed to tesseract
			d = pytesseract.image_to_data(img, output_type=pytesseract.Output.DICT)
			# there might be good stuff inside here --> print(d.keys())
			n_boxes = len(d['level'])

			for i in range(n_boxes):
			    (x, y, w, h) = (d['left'][i], d['top'][i], d['width'][i], d['height'][i])
			    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

		cv2.imshow('img', img)
		cv2.imshow("mask", mask)
		cv2.imshow("img-blur", img2)
		k = cv2.waitKey(1)
		if k == ord("q"):
			break

cv2.destroyAllWindows()


#!/usr/bin/env python3
# encoding: utf-8

#Linea 1 - “Shebang”,le indicamos a la máquina con qué programa lo vamos a ejecutar.
#Linea 2 - Python 3 - asume que solo se utiliza ASCII en el código fuente
#para usar utf-8 hay que indicarlo al principio de nuestro script encoding: utf-8

#!/usr/bin/env python3
# encodingc: utf-8

#Linea 1 - “Shebang”,le indicamos a la máquina con qué programa lo vamos a ejecutar.
#Linea 2 - Python 3 - asume que solo se utiliza ASCII en el código fuente
#para usar utf-8 hay que indicarlo al principio de nuestro script encoding: utf-8

#IMPORTA LIRBRERÍAS

#Importar la API de Ros para python
import rospy
#Importa el tipo de mensaje Vector3 del paquete geometry_msgs
from geometry_msgs.msg import Vector3
#Importa el tipo de mensaje Twist del paquete geometry_msgs
from geometry_msgs.msg import Twist
#Importa el tipo de mensaje Odometry del paquete nav_msgs
from nav_msgs.msg import Odometry
#Importa el tipo de mensaje Float32 del paquete std_msgs
from std_msgs.msg import Float32

#Otras librerías adicionales
import time
import numpy as np

######################################################################################333
#DEFINICIONES

#Se define variable global L
global L

#Imprimir en pantalla y pedir el L en cm
print('Hola, usuario')
L = float(input("Ingrese el valor de Distancia ( cm ): "))
#Pasar de cm a m
result = L/100.0

##############################################################################33

def desplazamiento_x():
    #Para el desplazamiento del robot
    vel_bot.linear.x = result/1.0
    vel_bot.angular.z = 0.0
    #Imprime en pantalla
    print('AVANCE')
    #Retardo
    time.sleep(3.0)
    #Se publica el mensaje de velocidad
    pub_vel.publish(vel_bot)

def giro():
    #Para el giro del robot
    vel_bot.linear.x = 0.0
    vel_bot.angular.z = 1.52
    #Imprime en pantalla
    print('GIRO')
    #Retardo
    time.sleep(1.0)
    #Se publica el mensaje de velocidad
    pub_vel.publish(vel_bot)

def pare():
    #Para detener el robot
    vel_bot.linear.x = 0.0
    vel_bot.angular.z = 0.0
    #Se publica el mensaje de velocidad
    pub_vel.publish(vel_bot)

########################################################################################

#Se crea nodo y se inicializa
rospy.init_node('desplazamiento')

#Se crea una variable tipo Twist()
vel_bot = Twist()
#Se crea una variable tipo Float32()
distance = Float32()

#Se crea un objeto publicador
pub_vel = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=1)

#########################################################################################

#Función principal
if __name__ == '__main__':
    try:
            #Llama la función
            desplazamiento_x()
            #Retardo
            time.sleep(2.0)
            #Llama la función
            pare()
            #Retardo
            time.sleep(2.0)
            #Llama la función
            giro()
            #Retardo
            time.sleep(2.0)
            #Llama la función
            pare()
            #Retardo
            time.sleep(2.0)

            #Llama la función
            desplazamiento_x()
            #Retardo
            time.sleep(2.0)
            #Llama a la función
            pare()
            #Retardo
            time.sleep(2.0)
            #Llama la función
            giro()
            #Retardo
            time.sleep(2.0)
            #Llama la función
            pare()
            #Retardo
            time.sleep(2.0)

            #Llama la función
            desplazamiento_x()
            #Retardo
            time.sleep(2.0)
            #Llama la función
            pare()
            #Retardo
            time.sleep(2.0)
            #Llama la función
            giro()
            #Retardo
            time.sleep(2.0)
            #Llama la función
            pare()
            #Retardo
            time.sleep(2.0)

            #Llama la función
            desplazamiento_x()
            #Retardo
            time.sleep(2.0)
            #Llama la función
            pare()
            #Retardo
            time.sleep(2.0)
            #Llama la función
            giro()
            #Retardo
            time.sleep(2.0)
            #Llama la función
            pare()

            #Para crear un archivo de texto. El "a" indica que lo que se añade no se vaya a borrar
            archive = open('distancia_txt',"a")
            #Para grabar los datos se utiliza .write()
            archive.write('%f\n'%result)
            #Se cierra
            archive.close()

    except rospy.ROSInterruptException:
        pass


import numpy as np
import pytest

from modules.knn import (
    classify_with_mode,
    compute_accuracy,
    distance_matrix,
    evaluate_knn,
    knn_predict,
)

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
c = np.array([7, 8, 9])

a1 = np.array([a, a, a])
b1 = np.array([b, b])
c1 = np.array([c, c])

def test_distance_matrix():
    dists = distance_matrix(a1, b1)
    assert np.shape(dists) == (3, 2)
    assert np.array_equal(
        dists,
        [
            [np.sqrt(27), np.sqrt(27)],
        ]
        * 3,
    )

    dists1 = distance_matrix(a1, c1)
    assert np.shape(dists1) == (3, 2)
    assert np.array_equal(
        dists1,
        [
            [np.sqrt(108), np.sqrt(108)],
        ]
        * 3,
    )

    return

def test_distance_matrix_incompatible_arrays():
    d1 = np.array([[1, 2], [1, 2]])
    with pytest.raises(ValueError):
        distance_matrix(a1, d1)
    return

def test_knn_predict():
    predicts = np.array([0, 1, 2])

    dists = distance_matrix(a1, b1)
    results = knn_predict(dists, predicts, 2)
    assert np.shape(results) == (2, 2)
    assert np.array_equal(results, np.array([[0, 0], [1, 1]]))

    dists1 = distance_matrix(a1, c1)
    results1 = knn_predict(dists1, predicts)
    assert np.shape(results1) == (1, 2)
    assert np.array_equal(results1, np.array([[0, 0]]))

    assert len(knn_predict(dists, predicts, -1)) == 0
    assert len(knn_predict(dists, predicts, 4)) == 0

    return

def test_knn_predict_incompatible_arrays():
    predicts = np.array([0, 1])
    dists = distance_matrix(a1, b1)

    with pytest.raises(IndexError):
        knn_predict(dists, predicts, 3)
    return

def test_classify_with_mode():
    labels = np.array([[0, 0, 1, 2], [0, 0, 1, 2], [0, 0, 1, 2]])
    labels1 = np.array([[1, 5, 3, 6], [0, 9, 9, 9], [1, 9, 9, 9]])

    classification = classify_with_mode(labels)
    classification1 = classify_with_mode(labels1)

    assert np.array_equal(classification, [0, 0, 1, 2])
    assert np.array_equal(classification1, [1, 9, 9, 9])

    return

def test_compute_accuracy():
    predicts = np.array([0, 1, 2, 3])
    true_values = np.array([0, 0, 2, 3])
    assert compute_accuracy(true_values, predicts) == 0.75
    return

def test_compute_accuracy_incompatible_arrays():
    predicts = np.array([0, 1, 2])
    true_values = np.array([0, 0])
    with pytest.raises(ValueError):
        compute_accuracy(true_values, predicts)

def test_evaluate_knn():
    assert evaluate_knn([], [], [], [], -1) == None
    assert evaluate_knn([0, 1], [], [], [], 3) == None

    data_train = np.array([a, b, a, a])
    labels_train = np.array([0, 1, 0, 0])
    data_test = np.array([a, a, b, a])
    labels_test = np.array([0, 0, 0, 2])
    k = 1

    accuracy = evaluate_knn(data_train, labels_train, data_test, labels_test, k)
    assert accuracy == 0.5

    k = 4
    accuracy = evaluate_knn(data_train, labels_train, data_test, labels_test, k)
    assert accuracy == 0.75
    return


import torch
import copy
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import os
import tqdm.notebook as tqdmn
from tqdm import tqdm

def in_ipynb():
    try:
        cfg = get_ipython().config
        return True
    except Exception as e:
        return False

if in_ipynb():
    tqdm = tqdmn.tqdm

from . import utils

def summarize_metrics(metrics):
    summarizable = dict(filter(lambda m: m[1].summarizable if hasattr(m[1], 'summarizable') else True, metrics.items()))
    return ' - '.join(list(map(lambda kv: '{}: {:.4f}'.format(kv[0], float(str(kv[1]))), summarizable.items())))

def report_metrics(metrics, end='\n'):
    print(summarize_metrics(metrics), end=end, flush=True)

def update_df(df, epoch, metrics):
    summarizable = dict(filter(lambda m: m[1].summarizable if hasattr(m[1], 'summarizable') else True, metrics.items()))
    summarizable = {k: float(str(v)) for k,v in summarizable.items()}
    summarizable.update({'epoch': epoch})

    df2 = pd.DataFrame([summarizable]).set_index('epoch')
    return pd.concat((df, df2)).apply(pd.to_numeric, errors='ignore')

def run(model, dataloader, criterion, optimizer, metrics, phase,
        device=torch.device('cuda:0'), weight=None, tta=False, silence=False,
        accumulation_steps=1, label_offset=-1):
    num_batches = 0.
    loss = 0.

    if phase == 'train':
        model.train()
    else:
        model.eval()

    for metric in metrics:
        metric.reset()

    itr = None
    if silence:
        itr = iter(dataloader)
    if not silence:
        itr = iter(tqdm(dataloader, desc=phase, leave=False))

    for step, (data, labels) in enumerate(itr):
        data, labels = data.to(device), labels.to(device)

        running_loss = 0.
        output = None

        with torch.set_grad_enabled(phase == 'train'):
            if tta:
                batch_size, n_crops, c, h, w = data.size()
                data = data.view(-1, c, h, w)
                output = model(data)
                output = output.view(batch_size, n_crops, -1).mean(1)
            else:
                output = model(data)

            for metric in metrics:
                if label_offset == -1:
                    metric.accumulate(output.clone(), labels.clone())
                else:
                    metric.accumulate(output.clone(), labels[:, label_offset].clone())

            running_loss = criterion(output, labels, weight=weight)

        if phase == 'train':
            running_loss.backward()

            if (step + 1) % accumulation_steps == 0:
                if isinstance(optimizer, torch.optim.Optimizer):
                    optimizer.step()
                else:
                    for opt in optimizer:
                        opt.step()

                if isinstance(optimizer, torch.optim.Optimizer):
                    optimizer.zero_grad()
                else:
                    for opt in optimizer:
                        opt.zero_grad()

        loss += running_loss.item()

        if (step + 1) % accumulation_steps == 0:
            num_batches += 1

    logs = { metric.__name__: copy.deepcopy(metric) for metric in metrics }
    logs.update({'loss': loss / num_batches})
    return logs

def make_checkpoint(epoch, model, optimizer, metrics, checkpoint_params=None):
    checkpoint = {
        'epoch': epoch, 'model': model.state_dict()
    }

    if isinstance(optimizer, torch.optim.Optimizer):
        checkpoint.update({'optimizer': optimizer.state_dict()})
    else:
        checkpoint.update({'optimizers': []})
        for opt in optimizer:
            checkpoint['optimizers'].append(opt.state_dict())

    if checkpoint_params is not None:
        checkpoint.update(checkpoint_params)
    return checkpoint

def is_better(a, b, mode='min'):
    if mode == 'min':
        return a < b
    elif mode == 'max':
        return a > b

    return False

def plot_losses(train, val, test, name, path):
    df = pd.DataFrame({'train': train, 'val': val, 'test': test})
    ax = sns.lineplot(data=df)
    ax.set_title(name)
    hm = ax.get_figure()
    hm.savefig(path)
    hm.clf()
    plt.close(hm)

def plot_metrics(df, path, name):
    ax = df.drop(['loss'], axis=1).plot()
    plt.title(name)
    plt.savefig(path)
    plt.close(ax.get_figure())

def fit(model, train_dataloader, val_dataloader, test_dataloader, test_every,
        criterion, optimizer, scheduler, metrics, n_epochs, name, path='',
        weight={'train': None, 'val': None, 'test': None},
        metric_choice='loss', mode='min', device=torch.device('cuda:0'), checkpoint_params=None,
        callbacks={'train': None, 'val': None, 'test':None}, silence=False, accumulation_steps=1, label_offset=-1):
    utils.ensure_dir(name)

    best_metric = 0.
    best_model = None

    train_losses = []
    val_losses = []
    test_losses = []

    test_logs = {'loss': 1.}

    df_train = pd.DataFrame()
    df_valid = pd.DataFrame()

    for epoch in range(n_epochs):

        train_logs = run(
            model=model, dataloader=train_dataloader,
            criterion=criterion, weight=weight['train'], optimizer=optimizer,
            metrics=metrics, phase='train', device=device, silence=silence,
            accumulation_steps=accumulation_steps, label_offset=label_offset
        )

        if 'train' in callbacks and callbacks['train'] is not None:
            callbacks['train']()

        val_logs = run(
            model=model, dataloader=val_dataloader,
            criterion=criterion, weight=weight['val'], optimizer=None,
            metrics=metrics, phase='val', device=device, silence=silence,
            label_offset=label_offset
        )

        if 'val' in callbacks and callbacks['val'] is not None:
            callbacks['val']()

        if not silence:
            print(f'Epoch: {epoch:03d} | VAL ', end='')
            report_metrics(val_logs, end=' | TRAIN ')
            report_metrics(train_logs, end=' |\n')

            df_train = update_df(df_train, epoch, train_logs)
            df_valid = update_df(df_valid, epoch, val_logs)
            df_train.to_csv(f'{name}/metrics-train.csv')
            df_valid.to_csv(f'{name}/metrics-val.csv')

            plot_metrics(df_train, f'{name}/metrics-train.png', name)
            plot_metrics(df_valid, f'{name}/metrics-val.png', name)

            torch.save(
                make_checkpoint(epoch, model, optimizer, metrics, checkpoint_params),
                os.path.join(path, f'{name}/final.pt')
            )

        if scheduler is not None:
            if isinstance(scheduler, torch.optim.lr_scheduler.ReduceLROnPlateau):
                scheduler.step(val_logs['loss'])
            else:
                scheduler.step()

        if best_model is None or is_better(float(str(val_logs[metric_choice])), best_metric, mode):
            best_metric = float(str(val_logs[metric_choice]))
            best_model = copy.deepcopy(model)
            if not silence:
                torch.save(
                    make_checkpoint(epoch, model, optimizer, metrics, checkpoint_params),
                    os.path.join(f'{name}/best.pt')
                )

        if test_dataloader is not None and (epoch+1) % test_every == 0:
            test_logs = test(
                model=model, test_dataloader=test_dataloader,
                criterion=criterion, metrics=metrics,
                device=device,
                weight=weight['test'],
                silence=silence,
                label_offset=label_offset
            )

            if 'test' in callbacks and callbacks['test'] is not None:
                callbacks['test']()

        if not silence:
            train_losses.append(train_logs['loss'])
            val_losses.append(val_logs['loss'])
            test_losses.append(test_logs['loss'])

            plot_losses(train_losses, val_losses, test_losses, name, os.path.join(path, f'{name}/loss.png'))

    if not silence:
        print('Training finished')

    return best_model

def test(model, test_dataloader, criterion, metrics,
        weight=None, device=torch.device('cuda:0'),
        tta=False, silence=False, label_offset=-1):
    test_logs = run(
        model=model, dataloader=test_dataloader,
        criterion=criterion, weight=weight, optimizer=None,
        metrics=metrics, phase='test', device=device,
        tta=tta, label_offset=label_offset
    )

    if not silence:
        print('TEST | ', end='')
        report_metrics(test_logs)
    return test_logs


#https://www.upgrad.com/blog/python-projects-ideas-topics-beginners/
# Ex:2 Number Guessing
import random
print("Guess a number between 1- 100 in 5 guesses")

#a = 45
a = random.randint(1,100)

for i in range(5):

    num = int(input("Enter the number:"))
    diff = num-a

    if num == a:
        print('Great, You win!!!')
        break

    elif diff <= -5:
        print('Your Guess too less than the hidden number')

    elif diff >= 5:
        print('Your Guess is too far than hidden number')

    else:
        print('you were almost near!!')
else:
    print("your Chance is over")
    print('The number is :',a)


from datetime import datetime
from enum import Enum

class RideType(Enum):
    short = 15
    medium = 40
    long = -1

class RidePrice(Enum):
    short = 5.5
    medium = 12
    long = 23

class RavKav:
    def __init__(self, holder_id: str, holder_name: str, balance: float = 0):
        self.__holder_id = holder_id
        self.__holder_name = holder_name
        self._set_balance(balance)

        self.__dates_log: dict[datetime, int] = {}
        self.__ride_type_log: dict[RideType, int] = {}

    @property
    def get_holder_id(self) -> str:
        return self.__holder_id

    @property
    def get_holder_name(self) -> str:
        return self.__holder_name

    @property
    def get_balance(self) -> float:
        return self.__balance

    def _set_balance(self, value) -> None:
        if value < 0:
            raise ValueError
        self.__balance = value

    def top_up(self, amount: float) -> None:
        if amount < 0:
            raise ValueError
        self._set_balance(amount + self.__balance)

    def _use_balance(self, amount: float) -> None:
        if self.__balance - amount < 0:
            raise ValueError
        self._set_balance(self.__balance - amount)

    def ride(self, ride_km: int, date: datetime.date) -> None:
        if ride_km <= RideType.short.value:
            self._use_balance(RidePrice.short.value)
            self._update_num_rides_by_type(RideType.short)
        elif ride_km <= RideType.medium.value:
            self._use_balance(RidePrice.medium.value)
            self._update_num_rides_by_type(RideType.medium)
        else:
            self._use_balance(RidePrice.long.value)
            self._update_num_rides_by_type(RideType.long)
        self._update_num_rides_by_date(date)

    def get_num_rides_by_date(self, date: datetime.date) -> int:
        if date not in self.__dates_log:
            raise KeyError
        return self.__dates_log[date]

    def _update_num_rides_by_date(self, date: datetime.date) -> None:
        if date not in self.__dates_log:
            self.__dates_log[date] = 0
        self.__dates_log[date] += 1

    def get_num_rides_by_type(self, ride_type: RideType) -> int:
        if ride_type not in self.__ride_type_log:
            raise KeyError
        return self.__ride_type_log[ride_type]

    def _update_num_rides_by_type(self, ride_type: RideType) -> None:
        if ride_type not in self.__ride_type_log:
            self.__ride_type_log[ride_type] = 0
        self.__ride_type_log[ride_type] += 1

    def display_num_rides_by_dates_log(self) -> None:
        print("Rides by Date")
        for k, v in self.__dates_log.items():
            print(f"Date: {k}")
            print(f"\tNumber of rides: {v}")
        return

    def display_num_rides_by_type_log(self) -> None:
        print("Rides by Type")
        for k, v in self.__ride_type_log.items():
            print(f"Type: {k.name}")
            print(f"\tNumber of rides: {v}")
        return

    def __str__(self):
        to_str = f"<RavKav: id={self.__holder_id}>\n" \
                 f"Name: {self.__holder_name}\n" \
                 f"Balance: {self.__balance}"
        return to_str

    def __repr__(self):
        return f"<RavKav: id={self.__holder_id}>"


import yfinance as yf
import datetime as dt
import pandas as pd
import pandas_datareader as pdr
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.ticker as mticker
import datetime as datetime
import numpy as np

yf.pdr_override()

# Moving averages we want to use. We use simple 10,30 and 50 day averages
smasUsed = [10, 30, 50]

start = dt.datetime(2020, 1, 1) - dt.timedelta(days=max(smasUsed))  # This sets the start point for the dataframe, the
# The time delta makes sure we're going far enough in our data to make use of the smas used
now = dt.datetime.now() # Sets end point for dataframe
stock = input("Enter the stock symbol: " ) # Asks for the stock ticker

while stock.upper() != "QUIT":
    prices = pdr.get_data_yahoo(stock, start, now)  # we used prices instead of df as the name

    fig = plt.subplots()  # Create plots
    ax1 = plt.subplots()

    # Calculate the moving averages for all those days
    for x in smasUsed: # This for loop calculates the SMAs for the stated periods and appends to dataframe
        sma = x
        prices['SMA' + str(sma)] = prices.iloc[:, 4].rolling(window=sma).mean()  # calcs the sma and creates col for it

    # Now we will calc the Bollinger Bands. Bollinger Bands are a certain std above and below the sma, and says that
    # the price will be likely between the bands. If the price is above the band, it will most likely come back down
    # and if it is below it will most likely come back up
    bb_period = 20  # this is the moving average we will chose
    st_dev = 2
    # This calcs the sma and creates a col
    prices['SMA' + str(bb_period)] = prices.iloc[:, 4].rolling(window=bb_period).mean()
    prices['STDEV'] = prices.iloc[:, 4].rolling(window=bb_period).std() # calcs the std dev and creates a col
    prices['LowerBand'] = prices["SMA" + str(bb_period)] - (st_dev * prices['STDEV']) # calcs lower bollinger band
    prices['UpperBand'] = prices["SMA" + str(bb_period)] + (st_dev * prices["STDEV"]) # calcs upper bollinger band
    prices['Date'] = mdates.date2num(prices.index)  # creates a date column stored in number format

    # Calculate 10.4.4 stochastic
    Period = 10  # the stoc period
    K = 4  # the K parameter
    D = 4  # the D parameter

    prices["RolHigh"] = prices["High"].rolling(window=Period).max()  # Finds high of the period
    prices["RollLow"] = prices["Low"].rolling(window=Period).min()  # Finds low of the period
    #prices["stoch"] = ((prices["Adj Close"] - prices["RolLow"])/prices["RolHigh"] - prices["RolLow"]) * 100
    #prices["K"] = prices["stoch"].rolling(window=K).mean()  # Finds 10.4 stoch
    #prices["D"] = prices["K"].rolling(window=D).mean()  # Finds 10.4.4 stoch
    #prices["GD"] = prices["High"]  # Creates GD column to store green dots
    ohlc = []

    # Delete extra dates
    prices = prices.iloc[max(smasUsed):]

    greenDotDate=[]  # Stores dates of Green Dots
    greenDot = []  # Stores Values of Green Dots
    lastK = 0  # Will store yesterday's fast stoch
    lastD = 0  # Will store yesterday's slow stoch
    lastLow = 0  # Store yesterday's lower
    lastClose = 0   # Store yesteday's close
    lastLowBB = 0 # stores yesterday's lower bband

    # Plot Moving averages and BBands
    for x in smasUsed:  # This for loop calcs the EMAs for the stated periods and appends to dataframe
        sma = x
        prices["Sma" + str(sma)].plot(Label="close")
    prices["UpperBand"].plot(Label="close", color="lightgray")
    prices["LowerBand"].plot(Label="close", color="lightgray")


# Skriv ett program som frågar användaren om ett tal och sen adderar ihop
# alla tal upp till och med det talet. När alla tal adderats så ska summan
# skrivas ut.

# Skriv programmet både med en for-loop och en while-loop. Det ska alltså
# räkna ut summan två gånger, en gång med en for-loop och en gång
# med en while-loop, resultatet ska också skrivas ut två gånger.

# T.ex.: Om man svarar att 10 ska vara sista talet i följden ska 55
# skrivas ut två gånger.

# Ett exempel på hur delar av programmet kan se ut finns nedan, ni
# är välkomna att ta bort det och skriva det helt annorlunda om ni vill.

n = int(input("Vilket tal ska vara det sista i följden? "))

summa = 0
i = 1
while i <= n:
    summa += i
    i += 1
print(summa)

summa = 0
for x in range(n + 1):
    summa += x

print(summa)


import sys
import os
import numpy as np

# importのサーチパスを追加
sys.path.insert(0,os.path.join(os.path.dirname(__file__),"../common"))

# ユーザ定義モジュール
from detector import Detector

# 顔検出器クラス
class FaceDetector(Detector):
    # 結果クラス
    class Result:
        # モデルの出力ノードの数(image_id, label, confidence, x1, y1, x2, y2)
        OUTPUT_SIZE = 7

        def __init__(self, output, frame_width, frame_height):
            self.raw_result = output
            self.image_id = output[0]
            self.label = int(output[1])
            self.confidence = output[2]
            self.position = np.array((output[3], output[4]))    # (x1, y1)
            self.size = np.array((output[5], output[6]))        # (x2, y2)  ここではまだ右下座標

            # pixel座標に変換
            self.position[0] *= frame_width
            self.position[1] *= frame_height
            self.size[0] = self.size[0] * frame_width - self.position[0]        # ここでsizeに変換される
            self.size[1] = self.size[1] * frame_height - self.position[1]

        def __getitem__(self, idx):
            return self.raw_result[idx]

        # ROIの拡大/縮小
        def rescale_roi(self, roi_scale_factor=1.0):
            self.position -= self.size * 0.5 * (roi_scale_factor - 1.0)
            self.size *= roi_scale_factor

        # ROIを元画像範囲に収める
        def clip(self, width, height):
            min = [0, 0]
            max = [width, height]
            self.position[:] = np.clip(self.position, min, max)
            self.size[:] = np.clip(self.size, min, max)

        # ROI範囲の画像切り取り
        def extract_image(self, frame):
            p1 = self.position.astype(int)
            p1 = np.clip(p1, [0, 0], [frame.shape[-1], frame.shape[-2]])
            p2 = (self.position + self.size).astype(int)
            p2 = np.clip(p2, [0, 0], [frame.shape[-1], frame.shape[-2]])
            return np.array(frame[:, :, p1[1]:p2[1], p1[0]:p2[0]])

    def __init__(self, model, confidence_threshold=0.5, roi_scale_factor=1.15):
        super(FaceDetector, self).__init__(model)

        assert len(model.inputs) == 1, "Expected 1 input blob"
        assert len(model.outputs) == 1, "Expected 1 output blob"
        self.input_blob = next(iter(model.inputs))
        self.output_blob = next(iter(model.outputs))
        self.input_shape = model.inputs[self.input_blob].shape
        self.output_shape = model.outputs[self.output_blob].shape

        assert len(self.output_shape) == 4 and \
               self.output_shape[3] == self.Result.OUTPUT_SIZE, \
            "Expected model output shape with %s outputs" % \
            (self.Result.OUTPUT_SIZE)

        assert 0.0 <= confidence_threshold and confidence_threshold <= 1.0, \
            "Confidence threshold is expected to be in range [0; 1]"
        self.confidence_threshold = confidence_threshold

        assert 0.0 < roi_scale_factor, "Expected positive ROI scale factor"
        self.roi_scale_factor = roi_scale_factor

    # 前処理
    def preprocess(self, frame):
        assert len(frame.shape) == 4, "Frame shape should be [1, c, h, w]"
        assert frame.shape[0] == 1
        assert frame.shape[1] == 3
        input = self.resize_input(frame, self.input_shape)
        return input

    # 認識処理開始
    def start_async(self, frame):
        input = self.preprocess(frame)
        self.enqueue(input)

    # 認識処理要求をキューイング
    def enqueue(self, input):
        return super(FaceDetector, self).enqueue({self.input_blob: input})

    # 認識結果取得
    def get_roi_proposals(self, frame):
        outputs = self.get_outputs()[0][self.output_blob]
        # outputs shape is [N_requests, 1, 1, N_max_faces, 7]

        frame_width = frame.shape[-1]
        frame_height = frame.shape[-2]

        results = []
        for output in outputs[0][0]:
            result = FaceDetector.Result(output, frame_width, frame_height)
            if result.confidence < self.confidence_threshold:
                break # results are sorted by confidence decrease

            result.rescale_roi(self.roi_scale_factor)
            result.clip(frame_width, frame_height)

            results.append(result)

        return results


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

@file: __init__.py.py
@time: 2018/10/22 10:49
Created by Junyi.
"""
from settings import (
    MONGODB_HOST,
    MONGODB_PORT,
    MONGODB_DATABASE_NAME,
    MONGODB_COLLECTION_NAME,
)
from .mongo_pipline import MongoPipline
from .normal_pipline import NormalPipline

def get_pipline_object(pipline_type):
    """
    获取共享url队列对象
    :param pipline_type:采用队列的类型
    :return: ->queue object
    """
    if pipline_type == "MongoDB":
        return MongoPipline(
            host=MONGODB_HOST,
            port=MONGODB_PORT,
            db_name=MONGODB_DATABASE_NAME,
            collection_name=MONGODB_COLLECTION_NAME,
        )
    elif pipline_type == "normal":
        return NormalPipline()
    else:
        print(f"{pipline_type} is not support!")
        exit(-1)


import os, requests
from flask import Flask, request, json, jsonify
app = Flask(__name__)
import json, time, random, hashlib, copy

s_address = os.environ.get('SOCKET_ADDRESS')
print(s_address, flush = True)

#Creates a view
full_view = os.environ.get('VIEW').split(',')
view = os.environ.get('VIEW').split(',')

#Create a dictionary for our key-value store
store = {}

#the addresses of the nodes in our shard
shard = {}

#Vector clock
'''
Vector clock dictionary, each IP address mapped
to a specific value, starting at 0 for each
'''
VC = {}

sharding_done = False

#This will send the socket address to the other replicas to add to their view
for socket in full_view:
    if socket != s_address:
        try:
            requests.put('http://' + socket + '/key-value-store-view', json = {"s_address":s_address}, timeout=2)
        except:
            view.remove(socket)
            continue
#should have regardless
shard_cnt = 0
curr_shard = 0
#Initialize if it is one of the first nodes created
if os.environ.get('SHARD_COUNT') is not None:
    #determining which shard each node is in, odds in shard1 even shard2
    shard_cnt = int(os.environ.get('SHARD_COUNT'))
    count = 1
    for i in full_view:
        if count == shard_cnt + 1:
            count = 1
        if count in shard:
            shard[count] = shard[count] + [i]
        else:
            shard[count] = [i]
        count += 1

    #just gets the shard of the current replica
    curr_shard = 0
    for i in range(1, len(shard) + 1):
        if s_address in shard[i]:
            curr_shard = i

    for socket in shard[curr_shard]:
        VC[socket] = 0

# ****************************************  This is the shard request endpoint ****************************************

@app.route('/key-value-store-shard/shard-ids', methods=["GET"])
def shard_ids_requests_endpoint():
    global store, VC, shard, curr_shard, s_address, view
    rnt_lst = []
    for i in range(1, len(shard) + 1):
        rnt_lst = rnt_lst + [i]
    return jsonify({'message': 'Shard IDs retrieved successfully', 'shard-ids': rnt_lst}), 200

@app.route('/key-value-store-shard/node-shard-id', methods=["GET"])
def node_shard_requests_endpoint():
    global store, VC, shard, curr_shard, s_address, view
    return jsonify({'message': 'Shard ID of the node retrieved successfully', 'shard-id': curr_shard}), 200

@app.route('/key-value-store-shard/shard-id-members/<shard_id>', methods=["GET"])
def shard_id_members_requests_endpoint(shard_id = None):
    global store, VC, shard, curr_shard, s_address, view
    if int(shard_id) in shard:
        return jsonify({'message': 'Members of shard ID retrieved successfully', 'shard-id-members': shard[int(shard_id)]}), 200
    return 'error'

@app.route('/key-value-store-shard/shard-id-key-count/<shard_id>', methods=["GET"])
def shard_id_key_count(shard_id = None):
    global store, VC, shard, curr_shard, s_address, view
    if int(shard_id) == curr_shard:
        return jsonify({'message':'"Key count of shard ID retrieved successfully', 'shard-id-key-count': len(store)}), 200
    if int(shard_id) in shard:
        forward_shard = shard[int(shard_id)]
    else:
        return 'error'
    for socket in forward_shard:
        try:
            #Ask node located on other shard to fulfil the request
            rsp = requests.get('http://' + socket + '/store-return')
            rsp_json = rsp.json()
            key_length_store = len(rsp_json['store'])
            return jsonify({'message':'"Key count of shard ID retrieved successfully', 'shard-id-key-count': key_length_store}), 200
        except Exception as e:
            print(e,flush=True)
            continue

    return jsonify({'message': 'Key count of shard ID retrieved successfully', 'shard-id-key-count': len(shard)}), 200

# ****************************************  This is the add node to shard endpoint ************************************
#  Add node to any shard
# INFO:
# - First a docker run command to create the node
# - Then a put request send to the newly created node

@app.route('/key-value-store-shard/add-member/<shard_id>', methods=["PUT"])
def add_node_to_shard_endpoint(shard_id = None):
    global store, VC, shard, curr_shard, s_address, view, shard_cnt
    if int(shard_id) not in shard:
        return 'error'
    newSocketAddr = request.get_json(force=True)['socket-address']
    #updating shard
    if newSocketAddr not in shard[int(shard_id)]:
        shard[int(shard_id)] = shard[int(shard_id)] + [newSocketAddr]
    if int(shard_id) != curr_shard:
        for socket in shard[int(shard_id)]:
            try:
                #Ask node located on other shard to fulfil the request
                jsonDict = {'socket-address': newSocketAddr}
                rsp = requests.put('http://' + socket + '/key-value-store-shard/add-member/' + shard_id, json = jsonDict, timeout=2)
                return rsp.text, rsp.status_code
            except:
                continue
    else:
        #updates personal shard list and view and sends new info to all
        if newSocketAddr not in view:
            view = view + [newSocketAddr]
        if newSocketAddr not in shard[int(shard_id)]:
            shard[int(shard_id)] = shard[int(shard_id)] + [newSocketAddr]
        jsonDict = json.dumps({'socket-address': newSocketAddr, 'store': store, 'shard': shard, 'view': view})
        try:
            for socket in view:
                rsp = requests.put('http://' + socket + '/key-value-store-shard/add-member-helper', json = jsonDict, timeout=1)
        except Exception as e:
                print(e, flush=True)
    return jsonify({}), 200

@app.route('/key-value-store-shard/add-member-helper', methods=["PUT"])
def add_node_to_shard_endpoint_helper():
    global store, VC, shard, curr_shard, s_address, view, shard_cnt
    loadDict = json.loads(request.get_json())
    newSocketAddr = loadDict['socket-address']
    #global changes, taken in from json data attatched
    #below updates shard we have accounting for json changing ints to string
    temp_shard = loadDict['shard']
    for i in temp_shard:
        shard[int(i)] = temp_shard[i]
    #shard = loadDict['shard']
    view = loadDict['view']
    shard_cnt = len(shard)
    #if the address matches then work with added node
    if newSocketAddr == s_address:
        store = loadDict['store']
        #updating curr_shard for it
        for i in shard:
            if newSocketAddr in shard[i]:
                #sets curr_shard for new node
                curr_shard = i

                #requests store VC from node in the same shard
                for socket in shard[i]:
                    if socket in view:
                        try:
                            #Ask node located on other shard to fulfil the request
                            rsp = requests.get('http://' + socket + '/store-return', timeout=2)
                            data = rsp.json()
                            #updates gloabal VC
                            VC = data['VC']
                            break
                            #return rsp.text, rsp.status_code
                        except:
                            continue

    #others, updates VC with new node for correct shard value: 0
    for i in shard:
        if newSocketAddr in shard[i] and i == curr_shard:
            VC[newSocketAddr] = 0
            break
    #Anyone's code here
    return 'ok'

# ****************************************  This is the resharding endpoint *******************************************

@app.route('/key-value-store-shard/reshard', methods=["PUT"])
def reshard_endpoint():
    global store, VC, shard, curr_shard, s_address, view, shard_cnt

    shard_cnt = request.get_json(force=True)['shard-count']#update global shard_cnt on local replica

    if len(view) / shard_cnt < 2: #if not possible to reshard with 2 in each
        return jsonify({'message': 'Not enough nodes to provide fault-tolerance with the given shard count!'}), 400

    new_shard = {} #create new shard and fill it with values
    giant_dic = {} #store every store object added into here to then redistribute
    sharding_done = True

    #reshard based off of local shard count given
    count = 1
    for i in view:
        if count == shard_cnt + 1:
            count = 1
        if count in new_shard:
            new_shard[count] = new_shard[count] + [i]
        else:
            new_shard[count] = [i]
        count += 1

    temp_dic_for_store_vc = {} #dictionary to store stores
    for i in shard:
        for socket in shard[i]:
            if socket in view:
                try:
                    #Ask node located on other shard to fulfil the request
                    #jsonDict = {'socket-address': newSocketAddr}
                    rsp = requests.get('http://' + socket + '/store-return', timeout=2)
                    data = rsp.json()
                    temp_dic_for_store_vc[i] = data['store']
                    break
                    #return rsp.text, rsp.status_code
                except:
                    continue

    #fill giant dic with ALL stores together
    for i in temp_dic_for_store_vc:
        for l in temp_dic_for_store_vc[i]:
            giant_dic[l] = temp_dic_for_store_vc[i][l]

    #below basically reshards each store
    new_shard_store = {}
    #set up new shard with the correct keys equal to []
    for i in range(1, shard_cnt + 1):
        new_shard_store[i] = {}

    print(giant_dic, flush = True) #is all stores merged together, big dictionary
    #this reshards each store to be sent
    for i in giant_dic:
        new_shard_store[calc_hash(i)][i] = giant_dic[i]
    print(new_shard_store, flush = True) # should contain number key for shard, then dictionary of correct store as value

    #send the stores to each replica for update, and send new shard list
    for socket in view:
        for i_shard in new_shard:
            if socket in new_shard[i_shard]:
                 json_update = json.dumps({'store': new_shard_store[i_shard], 'shard': new_shard, 'shard_id': i_shard, 'shard_count': shard_cnt})
        if(socket != s_address):
            try:
                requests.put('http://' + socket + '/key-value-store-shard/reshard-update' ,json = json_update , timeout=2)
            except Exception as e:
                print(e, flush = True)
    #update itself now
    shard = new_shard

    #update curr_shard
    for i_shard in new_shard:
        if s_address in new_shard[i_shard]:
            curr_shard = i_shard
    #update store
    store = new_shard_store[curr_shard]
    #VC
    VC = {} #we need to basically keep original vector clock values for each
    for socket in shard[curr_shard]:
        VC[socket] = 0
    return jsonify({"message":"Resharding done successfully"}), 200

@app.route('/key-value-store-shard/reshard-update', methods=["PUT"])
def reshard_endpoint_update():
    global store, VC, shard, curr_shard, s_address, shard_cnt
    sharding_done = True
    loadDict = json.loads(request.get_json())
    #updates shard
    temp_shard = loadDict['shard']
    for i in temp_shard:
        shard[int(i)] = temp_shard[i]

    shard_cnt = loadDict['shard_count']
    store = loadDict['store']
    curr_shard = loadDict['shard_id']
    VC = {}
    for socket in shard[curr_shard]:
        VC[socket] = 0
    return jsonify({"message":"Resharding done successfully"}), 200

# ****************************************  This is the store return endpoint  ****************************************
@app.route('/store-return', methods=["GET"])
def store_return_endpoint():
    global store, VC, shard, curr_shard, s_address, view
    return jsonify(message = "Store retrieved successfully", store = store, VC = VC), 200

# ****************************************  This is the ping endpoint  ************************************************
@app.route('/ping', methods=["GET"])
def ping_endpoint():
    global store, VC, shard, curr_shard, s_address, view
    return jsonify(message = "View retrieved request successfully"), 200

# ****************************************  This is the view endpoint  ************************************************
@app.route('/key-value-store-view', methods=["GET", "PUT", "DELETE"])
def view_endpoint():
    #Initialize globals
    global store, VC, shard, curr_shard, s_address, view

    #------------------------------------Handles GET requests------------------------------------------------
    if request.method == 'GET':
        update_nodes()
        string_view = (',').join(view)
        return jsonify(message = "View retrieved successfully", view = string_view), 200

    #------------------------------------Handles PUT requests------------------------------------------------
    elif request.method == 'PUT':
        #Get socket of replica to be added
        new_replica = request.get_json(force=True)['s_address']

        if new_replica not in view:
            #Sets the socket address to '1' meaning it's running
            view.append(new_replica)
            #Sends OK response
            return jsonify(message = "Replica added successfully to the view"), 201
        #If replica already exists in view
        else:
            return jsonify(error = "Socket address already exists in the view", message = "Error in PUT"), 404

    #------------------------------------Handles DELETE requests------------------------------------------------
    elif request.method == 'DELETE':
        #Get ip of replica to be added
        removed_replica = request.get_json(force=True)['s_address']

        #This ensures that we will not have an infinite loop of put requests
        if removed_replica in view:
            #Remove replica from current view
            view.remove(removed_replica)
            return jsonify(message = "Replica deleted successfully from the view"), 200
        else:
            return jsonify(error = "Socket address does not exist in the view", message = "Error in DELETE"), 404

# ****************************************  This is the key/store endpoint  *******************************************
@app.route('/key-value-store/<key>', methods=["GET", "PUT", "DELETE"])
def key_val_store_endpoint(key=None):
    #maybe not the best but so we can access global variables, saying we do not plan on defining these
    global store, VC, shard, curr_shard, s_address, view, shard_cnt

    #Check if this is the first replica that recieved the request
    if request.get_json(silent=True) is not None and 'update' not in request.get_json(silent=True):
        update_nodes()

    #This is used for creating a shard list that only contains nodes that are currently running
    forward_shard = [i for i in shard[calc_hash(key)] if i in view]
    current_shard = [i for i in shard[curr_shard] if i in view]

    #---------------------------------------------- GET REQUESTS -----------------------------------
    #Handles GET request
    if request.method == "GET":
        #Used to forward to other shard if current shard does not have the key
        if(curr_shard != calc_hash(key)):
            for socket in forward_shard:
                try:
                    #Ask node located on other shard to fulfil the request
                    rsp = requests.get('http://' + socket + '/key-value-store/' + key)
                    rsp_json = rsp.json()
                    r_meta = rsp_json['causal-metadata']
                    r_val = rsp_json['value']
                    if rsp.status_code == 200:
                        return jsonify({'message':'Retrieved successfully', 'causal-metadata' : r_meta, 'value' : r_val}), 200
                    elif rsp.status_code == 404:
                        return jsonify(doesExist=False, error="Key does not exist", message="Error in GET"), 404
                except Exception as e:
                    print(e,flush=True)
                    continue

            return jsonify(error="Other shard not available", message="Error in GET"), 500
        else:
            #Check if key is in our store
            if key not in store:
                return json.dumps({"doesExist":False, "error":"Key does not exist", "message":"Error in GET"}), 404
            return json.dumps({'message':'Retrieved successfully', 'causal-metadata' : json.dumps(VC), 'value' : store[key]}), 200

    #--------------------------------------------- PUT REQUESTS --------------------------------------------
    #Handles PUT request
    elif request.method == "PUT":
        #Ends if key is too long
        if len(key) > 50:
            return jsonify(error="Key is too long", message="Error in PUT"), 400

        #Used to forward to other shard if current shard does not have the key
        if(curr_shard != calc_hash(key)):
            #Forwarding request to other shard
            C_val = request.get_json(force=True)['value']
            C_meta = request.get_json(force=True)['causal-metadata']
            if 'shard-id' in request.get_json():
                C_shard = request.get_json(force=True)['shard-id']
            else:
                C_shard = curr_shard
            jsonForSend = {'value':C_val, 'causal-metadata':C_meta, 'update':False}
            for socket in forward_shard:
                try:
                    #Ask node located on other shard to fulfil the request
                    rsp = requests.put('http://' + socket + '/key-value-store/' + key, json=jsonForSend)
                    rsp_json = rsp.json()
                    r_meta = rsp_json['causal-metadata']
                    if rsp.status_code == 200:
                        return json.dumps({'message':'Updated successfully', 'causal-metadata':r_meta, 'shard-id':C_shard}), 200
                    elif rsp.status_code == 201:
                        return json.dumps({'message':'Added successfully', 'causal-metadata':r_meta, 'shard-id':C_shard}), 201
                    else:
                        return json.dumps({'error':'PUT failed', 'message':'Error in PUT'}), 500
                except Exception as e:
                    print(e,flush=True)
                    continue
            return jsonify(error="Other shard not available", message="Error in PUT"), 500
        else:
        #---------------------------------- PUT FROM REPLICA -----------------------------------------
            #If PUT is from other Replica, then VC, address,  included!

            if 'causal-metadata' in request.get_json() and 'address' in request.get_json() and 'value' in request.get_json():

                #taking VC string, address, causal-metadata, and value from the message from sending replica
                T_dict = json.loads(request.get_json())
                T_meta = T_dict['causal-metadata']
                T_value = T_dict['value']
                T_addr = T_dict['address']

                #If not valid VC keep looping
                while not VC_compare_replica(T_meta, T_addr):
                    time.sleep(1)

                #sets VC to senders, and updates meta
                VC = json.loads(T_meta)

                if key in store:
                #Store the JSON value into our store and replace old (key,val) pair with new val
                    store[key] = T_value
                    return jsonify(message="Updated successfully", replaced=True), 200
                else:
                    #Store the JSON value into our store and add new (key,val) pair
                    store[key] = T_value
                    return jsonify(message="Added successfully", replaced=False), 201

            #------------------------------- PUT FROM CLIENT ------------------------------------------
            #If PUT is from client
            elif 'value' in request.get_json() and 'causal-metadata' in request.get_json():
                #simply extracting value and causal-metadata
                j_string = json.dumps(request.get_json())
                j_data = json.loads(j_string)
                C_val = j_data['value']
                C_meta = j_data['causal-metadata']

                while not VC_compare_client(C_meta):
                    for i in current_shard:
                        if i != s_address:
                            store_rsp = requests.get('http://' + i + '/store-return', timeout=2)
                            VC_data = store_rsp.json()
                            #Comparing local VC to recieved VC
                            for socket in current_shard:
                                if VC[socket] < VC_data['VC'][socket]:
                                    VC = VC_data['VC']
                                    store = VC_data['store']
                    time.sleep(1)

                #updates VC and then generates json to send to other requests
                VC[s_address] = VC[s_address] + 1
                jsonForSend = json.dumps({'value':C_val, 'causal-metadata':json.dumps(VC), 'address':s_address, 'update':False})

                #send to other nodes in shard!
                for i in current_shard:
                    if i != s_address:
                        requests.put('http://' + i + '/key-value-store/' + key, json = jsonForSend)

                #adding key and sending return message
                if key in store:
                    #Store the JSON value into our store and replace old (key,val) pair with new val
                    store[key] = C_val
                    return json.dumps({'message':'Updated successfully', 'causal-metadata':json.dumps(VC), 'shard-id':curr_shard}), 200
                else:

                    #Store the JSON value into our store and add new (key,val) pair
                    store[key] = C_val
                    return json.dumps({'message':'Added successfully', 'causal-metadata':json.dumps(VC), 'shard-id':curr_shard}), 201

            #runs if basically anything is missing

            else:
                return jsonify(error="Value is missing", message="Error in PUT"), 400

    #*************************************************** DELETE REQUESTS ***********************************************************
        #Handles DELETE request
    elif request.method == "DELETE":

        #Ends if key is too long
        if len(key) > 50:
            return jsonify(error="Key is too long", message="Error in PUT"), 400

        #Used to forward to other shard if current shard does not have the key
        if(curr_shard != calc_hash(key)):
            C_meta = request.get_json(force=True)['causal-metadata']
            C_shard = request.get_json(force=True)['shard-id']
            jsonForSend = {'causal-metadata':C_meta, 'update':False}
            for socket in forward_shard:
                try:
                    #Ask node located on other shard to fulfil the request
                    rsp = requests.delete('http://' + socket + '/key-value-store/' + key, json=jsonForSend, timeout=2)
                    rsp_json = rsp.json()
                    r_meta = rsp_json['causal-metadata']
                    if rsp.status_code == 200:
                        return json.dumps({'message':'Deleted successfully', 'causal-metadata':r_meta, 'shard-id':C_shard}), 200
                    elif rsp.status_code == 404:
                        return json.dumps({'doesExist':False, 'error':"Key does not exist", 'message':"Error in DELETE", 'shard-id':curr_shard}), 404
                except:
                    continue
            return jsonify(error="Other shard not available", message="Error in DELETE"), 500
        else:
            #--------------------------------- DELETE FROM REPLICA -----------------------------------------------
            #If DELETE is from other replica, then VC, address, causal-metadata, and value included!
            if 'causal-metadata' in request.get_json() and 'address' in request.get_json():

                #taking VC string, address, causal-metadata, and value from the message from sending replica
                T_dict = json.loads(request.get_json())
                T_meta = T_dict['causal-metadata']
                T_addr = T_dict['address']

                #if is valid VC sent, then put it into store, and update meta, if not keep looping
                while not VC_compare_replica(T_meta, T_addr):
                    time.sleep(1)

                #sets VC to senders, and updates meta
                VC = json.loads(T_meta)

                #Delete the key from store[]
                if key in store:
                #Success deleting!
                    store[key]=None
                    return jsonify(message="Deleted successfully", replaced=True), 200
                else:
                    #Error we cannot find the key
                    jsonify(doesExist=False, error="Key does not exist", message="Error in DELETE"), 404

            #------------------------------------ DELETE FROM CLIENT --------------------------------------------
            #If DELETE is from client
            elif 'causal-metadata' in request.get_json():
                #simply extracting value and causal-metadata
                j_string = json.dumps(request.get_json())
                j_data = json.loads(j_string)
                C_meta = j_data['causal-metadata']

                #if meta is present continue, if not loop until it is
                while not VC_compare_client(C_meta):
                    time.sleep(1)

                #updates VC and then generates json to send to other requests
                VC[s_address] = VC[s_address] + 1
                jsonForSend = json.dumps({'causal-metadata':json.dumps(VC),'address':s_address, 'update':False})

                #send to other nodes in the shard!
                for i in current_shard:
                    if i != s_address:
                        requests.delete('http://' + i + '/key-value-store/' + key, json = jsonForSend)

                #Delete the key from store[]
                if key in store:
                    #Success deleting!
                    store[key]=None
                    return jsonify({'message':'Deleted successfully', 'causal-metadata':json.dumps(VC)}), 200
                else:
                    #Error we cannot find the key
                    return jsonify(doesExist=False, error="Key does not exist", message="Error in DELETE"), 404

            #runs if basically anything is missing
    else:
        return jsonify(error="Value is missing", message="Error in request"), 400

#*************************************************** HELPER FUNCTIONS ***********************************************************

#essentially compares VC of recieved to VC of replica
def VC_compare_client(s):
    #maybe not the best but so we can access global variables, saying we do not plan on defining these
    global store, VC, shard, curr_shard, s_address, view

    #if metadata is '' then its good
    if s == '':
        return True

    if sharding_done:
        return True

    #this is the recieved VC string loaded to a dictionary
    T = json.loads(s)

    #Now we compare the VC's, if one is bigger than
    for i in VC.keys():
        if (i in T.keys()) and (T[i] > VC[i]):
            return False

    #true if no causal inconsistencies found in VC
    return True

def VC_compare_replica(s, addr):
    #maybe not the best but so we can access global variables, saying we do not plan on defining these
    global store, VC, shard, curr_shard, s_address, view
    #if metadata is '' then its good
    if s == '':
        return True
    #this is the recieved VC string loaded to a dictionary
    T = json.loads(s)
    if sharding_done:
        return True

    #Now we compare the VC's, if one is bigger
    for i in VC.keys():
        if i == addr:
            if i in T.keys() and T[i] != VC[i] + 1:
                return False
        else:
            if i in T.keys() and T[i] > VC[i]:
                return False
    #true if no causal inconsistencies found in VC
    return True

#Getting current status of view
def update_nodes():
    #Use the global view as well as current working socket
    global store, VC, shard, curr_shard, s_address, view, full_view
    remove_list = []
    # Check if any replicas have crashed or failed
    for replica_ip in full_view:
        if replica_ip != s_address:
            try:
                resp = requests.get('http://' + replica_ip + '/ping', timeout=0.5)
                # Won't get to this line if we get a timeout error
            except:
                if replica_ip in view:
                    view.remove(replica_ip)
                    remove_list.append(replica_ip)
                continue

    #Broadcast to other replicas that the view needs to be updated
    for replica_ip in view:
        if replica_ip != s_address:
            for r_ip in remove_list:
                requests.delete('http://' + replica_ip + '/key-value-store-view', json = {"s_address":r_ip}, timeout=5)

    #updates this current node's shard lists
    #update_shard()

    return None

# Calculates the hash of the key
# Returns the shard number that the key is located on
def calc_hash(key_str):
    global store, VC, shard, curr_shard, s_address, view, full_view, shard_cnt
    hashed = hashlib.sha256(key_str.encode())
    hashed_int = int(hashed.hexdigest(), 16)

    return((hashed_int % shard_cnt) + 1)

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=8085, debug=True)


import requests
from bs4 import BeautifulSoup as BS

class GetAllUrl(object):

    header={
    "Accept": "application/json,text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "zh-cn",
    "Accept-Encoding": "gzip, deflate",
    "Connection": "keep-alive",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.4 Safari/605.1.15"
    }
    def __init__(self,h=None):
        if(h is not None):
            self.header=h

    def getAllPagesUrl(self,pagesUrlsList,bs_s, header=header):
        #对于多页的情况，获取每一页的url
        bs_s_url = bs_s.find(class_="pager").find_all("a")
        for u in bs_s_url:
            if u["href"] not in pagesUrlsList:
                pagesUrlsList.append(u["href"])
        return pagesUrlsList

    def getAllUrlListInPages(self,pagesUrlsList, header=header):
        #获取页面表内，全部的文章链接，返回一个列表
        contextUrlsList = []
        for pages in pagesUrlsList:
            r_s = requests.get(pages, header)
            bs_s = BS(r_s.text,"lxml")
            urls = bs_s.find_all(class_="entrylistItemTitle")

            for u in urls:
                if u["href"] not in contextUrlsList:
                    contextUrlsList.append(u["href"])
        return contextUrlsList

    def getAllUrlDicInPages(self,pagesUrlsList, header=header):
        #获取页面表内，全部的文章链接，返回一个字典，键为文章标题，值为文章链接
        contextUrlsDic = {}
        for pages in pagesUrlsList:
            r_s = requests.get(pages, header)
            bs_s = BS(r_s.text,"lxml")
            urls = bs_s.find_all(class_="entrylistItemTitle")

            for u in urls:
                if u.find("span").string not in contextUrlsDic:
                    contextUrlsDic[u.find("span").string]=u["href"]
        return contextUrlsDic

    def getUrlsList(self,url,header=header):
        #获取url系列页的所有文章链接，返回一个列表
        pagesUrlsList = []
        pagesUrlsList.append(url)
        r_s = requests.get(url, header)
        bs_s = BS(r_s.text,"lxml")
        pagesUrlsList = self.getAllPagesUrl(pagesUrlsList,bs_s, header)
        contextUrlsList = self.getAllUrlListInPages(pagesUrlsList,header)
        return contextUrlsList

    def getUrlsDic(self,url,header=header):
        #获取url系列页的所有文章链接，返回一个字典，键为文章标题，值为文章链接
        pagesUrlsList = []
        pagesUrlsList.append(url)
        r_s = requests.get(url, header)
        bs_s = BS(r_s.text,"lxml")
        pagesUrlsList = self.getAllPagesUrl(pagesUrlsList,bs_s, header)
        contextUrlsList = self.getAllUrlDicInPages(pagesUrlsList,header)
        return contextUrlsList
if __name__ == '__main__':
    url = "https://www.cnblogs.com/ghosteq/category/2100349.html?page=1"
    header={
    "Accept": "application/json,text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "zh-cn",
    "Accept-Encoding": "gzip, deflate",
    "Connection": "keep-alive",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.4 Safari/605.1.15"
    }
    ga = GetAllUrl(header)
    contextUrlsList = ga.getUrlsList(url)
    contextUrlsDic = ga.getUrlsDic(url)
    print(contextUrlsList)
    print(len(contextUrlsList))
    print(contextUrlsDic)
    print(len(contextUrlsDic))


from django.urls import path
from fron.views import home,login,padre,FormularioCLienteView,FormularioCategoriaView
from fron.views import FormularioProductoView,FormularioVentaView,FormularioCLienteView,ReporteVenta
from fron.views import FormularioProveedorView,FormularioCreditoView,FormularioUsuariosView,verificacion
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('',login,name="Login"),
    path('verificacion/<str:id_persona>',verificacion,name="Verificacion"),
    path('home',home,name="Home"),
    path('padre',padre,name="Padre"),

    path('cliente',FormularioCLienteView.cliente,name="Cliente"),
    path('agregarcliente',FormularioCLienteView.agregar_cliente,name="AGRcliente"),
    path('procesar_cliente',FormularioCLienteView.procesar_cliente,name="PRcliente"),
    path('modicliente',FormularioCLienteView.modificar_cliente,name="MODcliente"),
    path('eliminarcliente/<int:id_cliente>',FormularioCLienteView.eliminar_cliente,name="ELIcliente"),
    path('resulmodicliente/<int:id_cliente>',FormularioCLienteView.resultados_cliente),

    path('proveedor',FormularioProveedorView.proveedor,name="Proveedor"),
    path('agregarproveedor',FormularioProveedorView.agregar_proveedor,name="AGRproveedor"),
    path('procesar_proveedor',FormularioProveedorView.procesar_proveedor,name="PRproveedor"),
    path('modiproveedor',FormularioProveedorView.modificar_proveedor,name="MODproveedor"),
    path('eliminarproveedor/<int:id_proveedor>',FormularioProveedorView.eliminar_proveedor,name="ELIproveedor"),
    path('resulmodiproveedor/<int:id_proveedor>',FormularioProveedorView.resultados_proveedor),

    path('categoria',FormularioCategoriaView.categoria ,name="Categoria"),
    path('agregar_categoria',FormularioCategoriaView.agregar_categoria ,name="AGRcategoria"),
    path('procesar_categoria',FormularioCategoriaView.procesar_categoria, name="PRcategoria"),
    path('modicategoria',FormularioCategoriaView.modificar_categoria, name="MODcategoria"),
    path('resulmodicategoria/<int:codigo_categoria>',FormularioCategoriaView.resultados_categoria),
    path('eliminarcategoria/<int:codigo_categoria>',FormularioCategoriaView.eliminar_categoria, name="ELIcategoria"),

    path('Producto',FormularioProductoView.producto,name="Producto"),
    path('agregarproducto',FormularioProductoView.agregarproducto,name="AGRproducto"),
    path('procesar_producto',FormularioProductoView.procesar_producto,name="PRproducto"),
    path('modiproducto',FormularioProductoView.modificar_producto,name="MODproducto"),
    path('resulmodipro/<int:id_producto>',FormularioProductoView.resultados_modi),
    path('eliminarproducto/<int:id_producto>',FormularioProductoView.eliminar_producto,name="ELIproducto"),
    path('buscar/',FormularioProductoView.buscar,name="Buscar"),

    path('venta',FormularioVentaView.venta,name="Venta"),
    path('agregarventa',FormularioVentaView.agregarventa,name="AGRventa"),
    path('procesar_venta',FormularioVentaView.procesar_venta,name="PRventa"),
    path('modigeneral',FormularioVentaView.modifi_venta_general,name="MODventageneral"),
    path('modiventa',FormularioVentaView.modificar_venta,name="MODventa"),
    path('resulmodiventa/<int:id_venta>',FormularioVentaView.resultados_venta),
    path('eliminarventa/<int:id_venta>',FormularioVentaView.eliminar_venta,name="ELIventa"),
    path('reporte_ventas',ReporteVenta.reporte_ventas,name="reporte_ventas_pdf"),

    path('agregarcredito',FormularioCreditoView.agregarcredito, name="AGRcredito"),
    path('procesar_credito',FormularioCreditoView.procesar_credito, name="PRcredito"),
    path('modicredito',FormularioCreditoView.modificar_credito, name="MODcredito"),
    path('resulmodicredito/<int:id_credito>',FormularioCreditoView.resultados_credito),
    path('eliminarcredito/<int:id_credito>',FormularioCreditoView.eliminar_credito, name="ELIcredito"),

    path('usuario',FormularioUsuariosView.usuarios,name="Usuario"),
    path('agregarusuario',FormularioUsuariosView.agregarusuario,name="AGRusuario"),
    path('procesar_usuario',FormularioUsuariosView.procesar_usuario,name="PRusuario"),
    path('modiusuario',FormularioUsuariosView.modificar_usuario,name="MODusuario"),
    path('eliminarusuario/<int:id_persona>',FormularioUsuariosView.eliminar_usuario,name="ELIusuario"),
    path('resulmodiusuario/<int:id_persona>',FormularioUsuariosView.resultados_usuario),

]

urlpatterns+=static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)


import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

class RNN_v4(nn.Module):

    def __init__(self, num_layers, feature_size, embedding_size, hidden_size, taget_size):
        super(RNN_v4, self).__init__()
        self.num_layers = num_layers
        self.feature_size = feature_size
        self.embedding_size = embedding_size
        self.hidden_size = hidden_size
        self.taget_size = taget_size

        self.fc1 = nn.Linear(feature_size, embedding_size)
        self.fc2 = nn.Linear(embedding_size, embedding_size)

        self.rnn = nn.GRU(embedding_size, hidden_size, num_layers)
        self.fc_out = nn.Linear(hidden_size, taget_size)

    def forward(self, inputs):
        output = F.relu(self.fc1(inputs))
        output = F.relu(self.fc2(output))

        output, _ = self.rnn(output)
        output = self.fc_out(output) # map hidden dim to output dim
        # output[:,:,0:4] = torch.cumsum(output[:,:,0:4], dim=0) # cdf sum of probability
        output[:,:,0:4] = torch.sigmoid(output[:,:,0:4])

        return output