import secrets
import random

from flask import Flask, render_template, redirect, flash, url_for, make_response
from forms import SearchForm, BookDeletion

from db_handler import GalleryDB
import local_search

# WARNING!!!! THIS IS ONLY FOR DEVELOPMENT!!!!
# NO SECURITY PRACTICE!!!!
# Run this before starting the main.py program.
# <directory to mongodb>/mongodb/bin/mongod --config <directory to mongodb>/mongodb/mongod.conf --fork

db_host="localhost"
db_port = 23456
flask_port = 12345
debug = False

app = Flask(__name__)
app.config["SECRET_KEY"] = secrets.token_hex(16)

galleryDB = GalleryDB(host=db_host, port=db_port)

@app.route("/")
@app.route("/home")
def home():
    books = galleryDB.get_all_books()
    unread_books = galleryDB.get_books_by_wether_read(read=False)
    random.shuffle(unread_books)
    return render_template("home.html",
                           title="Home Page",
                           books=unread_books[:5],
                           total_length=len(books),
                           unread_length=len(unread_books),
                           allbooks=True,
                           read=False
                          )

@app.route("/gallery")
def gallery():
    return render_gallery(1, "None", 1, 0)

@app.route("/gallery/p<int:page>.<int:allbooks>.<int:read>.<string:tag>")
def render_gallery(page, tag, allbooks, read):
    split_tag = tag.split("+")
    if len(set(split_tag)) < len(split_tag):
        tag = "+".join(list(set(split_tag)))
        return redirect(url_for("render_gallery", page=page, tag=tag, allbooks=allbooks, read=read))

    if tag == "None":
        tag = ""
        if allbooks:
            books = galleryDB.get_all_books()
        else:
            books = galleryDB.get_books_by_wether_read(read=read)
    else:
        if allbooks:
            books = galleryDB.get_books_bytags(split_tag)
        else:
            books = galleryDB.get_books_bytags(split_tag, bool(read))

    tagdict = galleryDB.get_all_tags(books)
    valcounts = sorted([b for value in tagdict.values() for a, b in value])
    maxcounts = [1, 1, 1, 1]
    maxcounts_length = len(maxcounts)
    valcounts_length = len(valcounts)
    if valcounts_length:
        for i in range(maxcounts_length):
            maxcounts[i] = valcounts[-1] * (i+1) // maxcounts_length
    total_pages = (len(books) - 1) // 25 + 1 if len(books) else 1
    if 0 <= (page - 1) * 25 < len(books):
        books = books[-1-(page-1)*25:-1-page*25:-1]
    else:
        books = []
    return render_template("gallery.html",
                           title="Gallery",
                           page=page,
                           total_pages=total_pages,
                           books=books,
                           tagtypes=sorted(list(tagdict.keys())),
                           tagdict=tagdict,
                           selected_tag=tag,
                           maxcounts=maxcounts,
                           allbooks=allbooks,
                           read=read
                        )

@app.route("/search", methods=["GET", "POST"])
def search_title():
    all_books = galleryDB.get_all_books()
    books = []
    form = SearchForm(csrf_enabled=False)
    if form.validate_on_submit():
        for book in all_books:
            if local_search.title_found(book["title"], form.key_phrases.data):
                books.append(book)
    # if form.errors:
    #     flash(form.errors, "danger")
    return render_template("search.html",
                            title="Book",
                            books=books,
                            form=form
                          )

@app.route("/book-<string:book_id>", methods=["GET", "POST"])
def bookpage(book_id):
    book = galleryDB.get_book_byid(book_id)
    read = book["read"]
    form = BookDeletion(csrf_enabled=False)
    if form.validate_on_submit():
        if form.confirm.data:
            galleryDB.delete_book(book_id)
            flash("Book Deleted", "success")
            return redirect(url_for("home"))
        flash("Book Not Deleted: Please confirm the deletion.", "danger")
    return render_template("book.html",
                            title=book["title"],
                            book_id=book_id,
                            imgs=book["contents"],
                            tags=book["tags"],
                            read=read,
                            form=form
                          )

@app.route("/book-<string:book_id>/toggle", methods=["GET", "POST"])
def bookpage_toggle_read(book_id):
    book = galleryDB.get_book_byid(book_id)
    read = book["read"]
    galleryDB.toggle_read(book, read)
    return redirect(url_for("bookpage", book_id=book_id))

@app.route('/images/<string:pid>.jpg')
def get_image(pid):
    response = make_response(galleryDB.get_img(pid))
    response.headers.set('Content-Type', 'image/jpeg')
    response.headers.set(
        'Content-Disposition', 'attachment', filename=f'{pid}.jpg')
    return response

if __name__ == "__main__":
    app.run(debug=debug, port=flask_port)


import os
import json
import glob
import argparse

import numpy as np
import embag as rosbag
from tqdm import tqdm
from cv_bridge import CvBridge

def timestamp_float(ts):
    return ts.secs + ts.nsecs / float(1e9)

def bag_to_npy(bag_path, output_pth, event_topic, image_topic):
    metadata_path = os.path.join(output_pth, 'metadata.json')
    events_ts_path = os.path.join(output_pth, 'events_ts.npy')
    events_xy_path = os.path.join(output_pth, 'events_xy.npy')
    events_p_path = os.path.join(output_pth, 'events_p.npy')
    images_path = os.path.join(output_pth, 'images.npy')
    images_ts_path = os.path.join(output_pth, 'images_ts.npy')
    image_event_indices_path = os.path.join(output_pth, 'image_event_indices.npy')
    sensor_size = None
    topics = [image_topic, event_topic]
    xs, ys, ts, ps = [], [], [], []
    image_list, image_ts_list, image_event_indices_list = [], [], []
    bag = rosbag.Bag(bag_path)
    for topic, msg, t in tqdm(bag.read_messages(topics)):
        if topic == event_topic:
            for e in msg.events:
                timestamp = timestamp_float(e.ts)
                xs.append(e.x)
                ys.append(e.y)
                ts.append(timestamp)
                ps.append(1 if e.polarity else 0)
        elif topic == image_topic:
            timestamp = timestamp_float(msg.header.stamp)
            image_ts_list.append(timestamp)
            image = CvBridge().imgmsg_to_cv2(msg, "mono8")
            image_list.append(image)
            if sensor_size is None:
                sensor_size = image.shape[:2]
    bag.close()

    events_ts = np.array(ts)
    events_xy = np.array([xs, ys]).transpose()
    events_p = np.array(ps)
    # assert np.all(events_ts[:-1] <= events_ts[1:])

    images = np.stack(image_list)
    images = np.expand_dims(images, axis=-1)
    images_ts = np.expand_dims(np.stack(image_ts_list), axis=1)
    # assert np.all(images_ts[:-1] <= images_ts[1:])

    # zero timestamps
    img_min_ts = np.min(images_ts)
    events_min_ts = np.min(events_ts)
    min_ts = min(img_min_ts, events_min_ts)
    events_ts -= min_ts
    images_ts -= min_ts
    # assert np.all(events_ts >= 0)
    # assert np.all(images_ts >= 0)

    # calculate image_event_indices
    image_event_indices = np.searchsorted(events_ts, images_ts, 'right') - 1
    image_event_indices = np.clip(image_event_indices, 0, len(events_ts) - 1)

    np.save(events_ts_path, events_ts, allow_pickle=False, fix_imports=False)
    np.save(events_xy_path, events_xy, allow_pickle=False, fix_imports=False)
    np.save(events_p_path, events_p, allow_pickle=False, fix_imports=False)

    np.save(images_path, images, allow_pickle=False, fix_imports=False)
    np.save(images_ts_path, images_ts, allow_pickle=False, fix_imports=False)
    np.save(image_event_indices_path, image_event_indices, allow_pickle=False, fix_imports=False)

    # write sensor size to metadata
    metadata = {"sensor_resolution": sensor_size}
    with open(metadata_path, 'w') as f:
        json.dump(metadata, f)

if __name__ == "__main__":
    """ Tool for converting rosbag events and images to numpy format.
    """
    parser = argparse.ArgumentParser()
    parser.add_argument("path", help="Directory of ROS bags")
    parser.add_argument("--event_topic", default="/dvs/events", help="Event topic")
    parser.add_argument("--image_topic", default="/dvs/image_raw", help="Image topic")
    parser.add_argument("--remove", help="Remove rosbags after conversion", action="store_true")
    args = parser.parse_args()
    rosbag_paths = sorted(glob.glob(os.path.join(args.path, "*.bag")))
    for path in rosbag_paths:
        print("Processing {}".format(path))
        output_pth = os.path.splitext(path)[0]
        os.makedirs(output_pth, exist_ok=True)
        bag_to_npy(path, output_pth, args.event_topic, args.image_topic)
        if args.remove:
            os.remove(path)


from hyperopt import Trials, STATUS_OK, tpe
from hyperas import optim
from hyperas.distributions import choice

from tensorflow import keras
from keras.models import Sequential
from keras.layers import Dense, Activation, Dropout, LSTM

import pandas as pd
import numpy as np
import collections

import gc
from tensorflow.python.keras import backend as K
K.clear_session()
gc.collect()

def model(x_train, y_train):
    model = Sequential()
    model.add(Dense(x_train.shape[1],
                   input_shape=(x_train.shape[1], x_train.shape[2])))
    model.add(Dropout({{uniform(0, 0.5)}}))
    model.add(LSTM(16,
                   return_sequences=False))
    model.add(Dropout({{uniform(0, 0.5)}}))
    model.add(Dense(1, activation='sigmoid'))

    model.compile(loss = 'binary_crossentropy',
                  optimizer = 'adam',
                  metrics = ['acc'])

    history = model.fit(x_train,
              y_train,
              epochs = {{choice([16, 32 ,64])}},
              batch_size = {{choice([32 ,64 ,128])}},
              validation_split = 0.1,
              shuffle = False)

    val_acc = np.amax(history.history['val_acc'])
    print(f'Best epoch acc:{val_acc}')

    return {'loss': -val_acc, 'status': STATUS_OK, 'model': model}

def data():
    df = pd.read_csv('../csv/tmp.csv', header=0)
    data = df[(df['STATE'] >= 2) & (df['STATE'] <= 5)]
    X = data[['GSR', 'Delta', 'Theta', 'Low_Alpha', 'High_Alpha', 'Low_Beta', 'High_Beta', 'Low_Gamma', 'Mid_Gamma']].values
    mean = X.mean(axis = 0)
    std = X.std(axis = 0)

    # Train data
    data = df[(df['STATE'] >= 2) & (df['STATE'] <= 3)]
    X = data[['GSR', 'Delta', 'Theta', 'Low_Alpha', 'High_Alpha', 'Low_Beta', 'High_Beta', 'Low_Gamma', 'Mid_Gamma']].values
    X = (X - mean) / std
    y = data['STATE']
    x_train, y_train = create_data(X, y)

    # Test data
    data = df[(df['STATE'] >= 4) & (df['STATE'] <= 5)]
    X = data[['GSR', 'Delta', 'Theta', 'Low_Alpha', 'High_Alpha', 'Low_Beta', 'High_Beta', 'Low_Gamma', 'Mid_Gamma']].values
    X = (X - mean) / std
    y = data['STATE']
    x_test, y_test = create_data(X, y)

    return x_train, y_train, x_test, y_test, mean, std

def create_data(X, y):
    time_step=30;
    x_data, y_data = [], []

    for i in range(0, len(X) -time_step, 1):
        #x_data
        tmp = X[i:(i+time_step)].tolist()
        x_data.append(tmp)
        #y_data
        labels = y[i:(i+time_step)]
        mode = collections.Counter(labels).most_common()[0][0]
        if mode % 2 == 0:
            y_data.append(1)
        if mode % 2 == 1:
            y_data.append(0)

    return np.array(x_data), np.array(y_data).reshape(-1,1)

def auto_tuning(filename: str):
    best_run, best_model = optim.minimize(model=model,
                                      data=data,
                                      algo=tpe.suggest,
                                      max_evals=3,
                                      eval_space=True,
                                      trials=Trials(),
                                      functions=[create_data])

    x_train, y_train, x_test, y_test, mean, std = data()
    test_loss, test_acc = best_model.evaluate(x_test, y_test)
    print(f'Test loss:{test_loss}, Test acc:{test_acc}')
    print(f'Best Run:{best_run}')

    best_model.save('../keras_model/' + filename)

    return best_model, mean, std

if __name__ == '__main__':
    auto_tuning('test')


import unittest
from typing import List
from machine.machine import Machine

def create_machine():
    return Machine("Start") \
    .add("Start", "red", "R1") \
    .add("Start", "yellow", "Y1") \
    .add("R1", "red", "R2") \
    .add("R1", "yellow", "Y1") \
    .add("R2", "red", "R3") \
    .add("R2", "yellow", "Y1") \
    .add("R3", "red", "R4") \
    .add("R3", "yellow", "Y1") \
    .add("R4", "red", "R4") \
    .add("R4", "yellow", "Y1") \
    .add("Y1", "red", "R1") \
    .add("Y1", "yellow", "Y2") \
    .add("Y2", "red", "R1") \
    .add("Y2", "yellow", "Y3") \
    .add("Y3", "red", "R1") \
    .add("Y3", "yellow", "Y4") \
    .add("Y4", "red", "R1") \
    .add("Y4", "yellow", "Y4")

A = "red" # red event
B = "yellow" # yellow event

LINE_1 = [A, B, A, B, A, B, A, B, A]
LINE_2 = [A, B, A, A, B, A, B, A]
LINE_3 = [A, B, A, A, A]
LINE_4 = [A, B, A, A, A, A, A, B, B, B, B]

def iterate_factory_line(input: List[int], start_state=0):
    print(f'\nRuning: {input} ')

    for state in create_machine().iterate_input(input):
        if state=="R3":
            print('Oh No! Too many RED Lolipops :(')
        elif state=="Y3":
            print('Oh No! Too many Yellow Lolipops :(')

    print('Run finished.')

class TestSum(unittest.TestCase):

    def test_1(self):
        iterate_factory_line(LINE_1)

    def test_2(self):
        iterate_factory_line(LINE_2)

    def test_3(self):
        iterate_factory_line(LINE_3)

    def test_4(self):
        iterate_factory_line(LINE_4)

    def test_sanity(self):
        for state in create_machine().iterate_input(['red', 'yellow', 'red', 'yellow', 'red', 'yellow', 'red', 'yellow']):
            print(state)

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


import socket
import sys
import threading
from time import sleep

import serial

from convert import *

#####################工作模式####################
work_mode = 1
debug_mode = 2
fault_mode = 3
#################协议转换全局变量################
addr645 = bytearray()
ctrl = 0
di_data = []
di_num = 0
################接收缓存区变量###################
recv_count = 0
read_spdata = bytes()

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

class Communication_645:
    def __init__(self, com, bps, timeout):
        self.port = com
        self.bps = bps
        self.timeout = timeout

        try:
            self.engine = serial.Serial(self.port, self.bps, timeout=self.timeout)
            if self.engine.is_open:
                print("Serial open success")
        except Exception as e:
            print("---Serial_error--- ", e)

    def print_hex_list(self, frame, endl=1):
        for x in frame:
            sys.stdout.write('%02x ' % (x))
        if endl:
            sys.stdout.write('\n')

    def Recive645Data(self):  # 将645数据转换成modbus TCP数据发送到平台
        global recv_count, read_spdata
        while True:
            recv_count = self.engine.inWaiting()  # 接收缓存区字节数
            if recv_count > 0:
                print("--------------串口接收到645响应帧,开始上行传输响应帧----------------------")
                read_spdata = self.engine.readline()  # 读取16进制帧结构
                self.print_hex_list(read_spdata, endl=1)  # 将接收的响应帧打印出来
                decode_data = dlt645.decode(read_spdata)  # 解析出645响应帧的数据，list类型的data
                mb_resp_list = mbtcp2dlt645.encode_resp(decode_data)  # 拿到响应的数据之后，组modbusTCP格式响应帧
                print(f"转换的mb_resp帧为: {mb_resp_list}")
                mb_resp = " ".join(mb_resp_list)
                mb_resp_bytes = bytes(mb_resp.encode('utf-8'))
                modbus_tcp_engine.con.send(
                    mb_resp_bytes)  # 上行发送命令到JAVA端     # modbus_tcp_engine.con在Communication_MBTCP类中定义

    def Send645Data(self):  # 将解析完的modbus TCP中的地址以及数据标识，组成645格式的帧发送到串口
        global addr645, ctrl, di_data, di_num, read_spdata, recv_count, write_data_all, data_register
        i = 0
        while True:
            di_bytearry = bytearray()  # Communication_MBTCP类中的tcplink函数返回需要的参数
            if addr645 != "" and ctrl == ReadData and di_data != None and di_num != 0:  # 如果数据转换成功
                print("--------------数据转换成功,开始组下行传输读数据命令帧----------------------")
                if di_num == 1:  # di_num是全局变量，在执行到Communication_MBTCP类中的tcplink函数的addr645,ctrl,di_data,di_num= mbtcp2dlt645.convert()时，被赋值
                    print("主站请求读一个数据")
                    di_temp = bytearray.fromhex(di_data[0])  # di_data是数据标识（一个或多个）
                    di_bytearry.extend(di_temp)
                    encode_data = dlt645.encode(addr645, ctrl, di_bytearry)  # 组645格式的命令帧，发给下位机
                    self.engine.write(encode_data)
                    print(f"645命令帧为:{encode_data}")
                else:
                    print("主站请求读多个数据")
                    while i < di_num:
                        di_temp = bytearray.fromhex(di_data[i])
                        di_bytearry.extend(di_temp)
                        encode_data = dlt645.encode(addr645, ctrl, di_bytearry)  # 组645格式的命令帧
                        di_bytearry = bytearray()  # 发送完数组清空
                        if i == 0:
                            print("发送第一条请求读多条数据命令")
                            self.engine.write(encode_data)
                            i = i + 1
                            print(f"645命令帧为:{encode_data}")
                        else:
                            if recv_count == 0 and read_spdata != b'':  # 初始时count = 0能够顺利进入 ,第二次发送时由于串口调用了inWaiting函数，count自动会清零了
                                read_spdata = bytes()  # 清空接收缓存字节数组
                                self.engine.write(encode_data)
                                print(f"645命令帧为:{encode_data}")
                                i = i + 1
                                # 清空缓存重新接收
                addr645 = bytearray()
                ctrl = 0
                di_data = []
                di_num = 0

            if addr645 != "" and ctrl == WriteData and di_data != None:  # 如果数据转换成功
                print("--------------数据转换成功,开始组下行传输写数据命令帧----------------------")
                if di_num == 1:
                    print("主站请求写一个数据")
                    di_temp0 = bytearray.fromhex(write_data_all[0])  # 组 写的数据域
                    di_temp1 = bytearray.fromhex(write_data_all[1])
                    di_temp2 = bytearray.fromhex(write_data_all[2])
                    di_temp3 = bytearray.fromhex(write_data_all[3])
                    di_bytearry.extend(di_temp0)
                    di_bytearry.extend(di_temp1)
                    di_bytearry.extend(di_temp2)
                    di_bytearry.extend(di_temp3)
                    encode_data = dlt645.encode(addr645, ctrl, di_bytearry)  # 组645格式的命令帧，发给下位机
                    self.engine.write(encode_data)
                    print(f"645命令帧为:{encode_data}")
                else:
                    print("主站请求写多个数据")
                    b = []
                    for j in range(0, len(write_data_all), 4):  # 写多个数据时，write_data_all中存储的是数据标识1，密码，操作者代码，写的具体数据1，。。。
                        b.append(write_data_all[j:j + 4])  # 4个一组，分别组帧发送到下位机
                    print("对645帧的数据域进行分组重装：")
                    print(b)
                    while i < di_num:
                        di_temp0 = bytearray.fromhex(b[i][0])  # 组 写的数据域
                        di_temp1 = bytearray.fromhex(b[i][1])
                        di_temp2 = bytearray.fromhex(b[i][2])
                        di_temp3 = bytearray.fromhex(
                            b[i][3].zfill(2))  # 写线圈的时候，每位写一位数据，不符合16进制字符，进而组帧不成功，所有将不足2位的数据进行高位补0；但是写寄存器就不用，已经满足了2位数据
                        di_bytearry.extend(di_temp0)
                        di_bytearry.extend(di_temp1)
                        di_bytearry.extend(di_temp2)
                        di_bytearry.extend(di_temp3)

                        encode_data = dlt645.encode(addr645, ctrl, di_bytearry)  # 组645格式的命令帧
                        di_bytearry = bytearray()  # 发送完数组清空

                        if i == 0:
                            print("发送第一条写数据的命令")
                            print(encode_data)
                            self.engine.write(encode_data)
                            i = i + 1
                            print(f"645命令帧为:{encode_data}")
                        else:
                            if recv_count == 0 and read_spdata != b'':  # 初始时count = 0能够顺利进入 ,第二次发送时由于串口调用了inWaiting函数，count自动会清零了
                                print(f"发送第{i + 1}条写数据的命令")
                                print(encode_data)
                                read_spdata = bytes()  # 清空接收缓存字节数组
                                self.engine.write(encode_data)
                                print(f"其645命令帧为:{encode_data}")
                                i = i + 1
                # 清空缓存重新接收
                addr645 = bytearray()
                ctrl = 0
                di_data = []
                # di_num = 0

class Communication_MBTCP:
    def __init__(self, ip, port, time_out):
        self.ip = ip
        self.port = port
        self.tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.tcp_server.bind((self.ip, self.port))

        try:
            self.tcp_server.listen(time_out)
            print("Waiting for connection...")
            self.con, address = self.tcp_server.accept()
            if self.con is None:
                print("Server> 未连接到客户端")
            else:
                print(f"Server> 已与{address}建立连接")
        except Exception as e:
            print("---TCP_error--- ", e)

    def tcplink(self):
        global addr645, ctrl, di_data, di_num, di_bytearry, write_data_all, data_register  # 这个函数中的全局变量最后都被赋值，在Communication_645类中用到时，已经有对应的值了(在程序运行时，最先执行的函数是这个，详细可见main中的代码）
        while True:
            recv_data = self.con.recv(1024)  # 接收数据，每次最多接收1024个字节
            print("----------------接收到上位机命令----------------------")
            print(f"recv_data: {recv_data}")
            if recv_data == b"quit":  # 接收到quit就断开socket连接
                break
            recv_str = str(recv_data, encoding="utf-8")  # 字节串转字符串,为了方便modbusTCP解帧
            recv_ss = recv_str.split(" ")  # 通过空格将字符串进行分割，转成字符串数组

            mbtcp2dlt645.requ_cache.clear()  # 645->mbTCP的缓冲区预处理
            mbtcp2dlt645.resp_cache.clear()  # mbTCP->645的缓冲区预处理

            mbtcp2dlt645.decode_requ(recv_ss)  # 解析向下的请求帧---将645需要的属性放在一个list，即requ_cache中
            print(f"打印当前MBTCP的缓存区: {mbtcp2dlt645.requ_cache}")

            addr645, ctrl, di_data, di_num, write_data_all, data_register = mbtcp2dlt645.convert()  # 协议转换，将这些全局变量给赋值
            print(f"协议转换成功 addr645:{addr645},ctrl:{hex(ctrl)},di_data:{di_data},write_data_all:{write_data_all}")

            # 模拟循环发送响应帧
            # print(mbtcp2dlt645.rand)
            resp_data = mbtcp2dlt645.rand + ' 0000' + ''
            resp_data = b'0000 0000 0000 2204 2204 2204 2022-11-03 13:03:43'
            # while True:
            #     self.con.send(resp_data)
            #     sleep(1)
            self.con.send(resp_data)

if __name__ == '__main__':
    # 实例初始化
    dlt645 = dlt_645_2007()  # DLT645.py中的类的实例化
    mbtcp2dlt645 = MBTCP_TO_DLT645()  # convert.py中的类的实例化

    # 开启引擎-
    # modbus_tcp_engine = Communication_MBTCP('127.0.0.1',9090,5)
    modbus_tcp_engine = Communication_MBTCP('localhost', 10000, 5)
    modbus_tcp_engine2 = Communication_MBTCP('localhost', 40000, 5)

    # serial_engine = Communication_645("COM7", 115200, 0.5)

    # 开启线程
    tcp_recv_thread = threading.Thread(target=modbus_tcp_engine.tcplink)
    tcp_recv_thread2 = threading.Thread(target=modbus_tcp_engine.tcplink)
    # serial_send_thread = threading.Thread(target = serial_engine.Send645Data)   #运行线程内容的前提条件是接收到下行传输且转化好的指令
    # serial_recv_thread = threading.Thread(target = serial_engine.Recive645Data)

    tcp_recv_thread.start()  # 程序运行结束，线程结束，不用join()也可以
    tcp_recv_thread2.start()
    # serial_send_thread.start()
    # serial_recv_thread.start()


from matplotlib import pyplot as plt

# https://www.geeksforgeeks.org/bresenhams-line-generation-algorithm/
def bresenhamLine(start, end):
    start = list(start)
    end = list(end)
    path = []
    steep = abs(end[1]-start[1]) > abs(end[0]-start[0])

    def swap(n1,n2):
        return [n2,n1]

    if steep:
        start = swap(start[0],start[1])
        end = swap(end[0],end[1])

    if start[0] > end[0]:
        _x0 = int(start[0])
        _x1 = int(end[0])
        start[0] = _x1
        end[0] = _x0

        _y0 = int(start[1])
        _y1 = int(end[1])
        start[1] = _y1
        end[1] = _y0

    dx = end[0] - start[0]
    dy = abs(end[1] - start[1])
    error = 0
    derr = dy/float(dx)

    ystep = 0
    y = start[1]

    if start[1] < end[1]: ystep = 1
    else: ystep = -1

    for x in range(start[0],end[0]+1):
        if steep:
            path.append((y,x))
        else:
            path.append((x,y))

        error += derr

        if error >= 0.5:
            y += ystep
            error -= 1.0

    return path

# Variation of the bresenham line algorithm
def bresenhamCircle(radius):
    # init vars
    switch = 3 - (2 * radius)
    points = set()
    x = 0
    y = radius
    # first quarter/octant starts clockwise at 12 o'clock
    while x <= y:
        # first quarter first octant
        points.add((x,-y))
        # first quarter 2nd octant
        points.add((y,-x))
        # second quarter 3rd octant
        points.add((y,x))
        # second quarter 4.octant
        points.add((x,y))
        # third quarter 5.octant
        points.add((-x,y))
        # third quarter 6.octant
        points.add((-y,x))
        # fourth quarter 7.octant
        points.add((-y,-x))
        # fourth quarter 8.octant
        points.add((-x,-y))
        if switch < 0:
            switch = switch + (4 * x) + 6
        else:
            switch = switch + (4 * (x - y)) + 10
            y = y - 1
        x = x + 1
    return points

# Creates progress bar on command line during runtime get an estimate of how long the program will run for
def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = '█', printEnd = "\r"):
    """
    Call in a loop to create terminal progress bar
    @params:
        iteration   - Required  : current iteration (Int)
        total       - Required  : total iterations (Int)
        prefix      - Optional  : prefix string (Str)
        suffix      - Optional  : suffix string (Str)
        decimals    - Optional  : positive number of decimals in percent complete (Int)
        length      - Optional  : character length of bar (Int)
        fill        - Optional  : bar fill character (Str)
        printEnd    - Optional  : end character (e.g. "\r", "\r\n") (Str)
    """
    percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
    filledLength = int(length * iteration // total)
    bar = fill * filledLength + '-' * (length - filledLength)
    print(f'\r{prefix} |{bar}| {percent}% {suffix}', end = printEnd)
    # Print New Line on Complete
    if iteration == total:
        print()

# imshow with better defaults
def imshow(img, scale=1):
    plt.figure(figsize=(scale*8,scale*8))
    plt.imshow(img, cmap="gray", vmin=0, vmax=255, interpolation="nearest")
    plt.axis('off')
    plt.show()


import pygame

class TimerService:
    """ Luokka joka määrittää ajastimen toiminnallisuuden.
    """
    def __init__(self, timer):
        """ Konstruktorissa annetaan luokalla ajastin.

        Args:
            timer: ajastin, jota luokka hallinnoi.
        """
        self.timer = timer
        pygame.mixer.init()

    def count_down(self):
        """ Metodi joka vähentää jäljellä olevaa aikaa ja vaihtaa ajastimen statuksen.

        Returns:
            Merkkijonon, joka kertoo jäljellä olevan ajan.
        """
        if self.timer.remaining_time <= 0:
            if self.timer.study_status is True:
                self.timer.remaining_time = self.timer.rest
                self.timer.study_status = False
                self.play_status_change()
                self.start()
            else:
                self.timer.remaining_time = self.timer.study
                self.timer.study_status = True
                self.play_status_change()
                self.start()

        minutes, seconds = divmod(self.timer.remaining_time, 60)

        if self.timer.timer_on:
            self.timer.remaining_time -= 1

        return f"{minutes:02d}:{seconds:02d}"

    def start(self):
        """ Metodi joka aloittaa ajastimen.

        Returns:
            False, jos ajastin on jo päällä.
        """
        if self.timer.timer_on:
            return False
        self.timer.timer_on = True
        if self.timer.study_status:
            self.timer.remaining_time = self.timer.study
        else:
            self.timer.remaining_time = self.timer.rest

        self.play_status_change()
        self.count_down()

    def play_status_change(self):
        sound = pygame.mixer.Sound("sounds/sound.mp3")
        sound.play()


"""
PyTorch implementation for "Adversarial Time-to-Event Modeling"
Paper: https://arxiv.org/pdf/1804.03184.pdf
"""
# stdlib
from typing import Any, Callable, List, Optional, Tuple

# third party
import numpy as np
import pandas as pd
import torch
from pydantic import validate_arguments
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from torch import nn
from torch.utils.data import DataLoader, TensorDataset

# synthcity absolute
import synthcity.logger as log
from synthcity.plugins.core.distribution import (
    CategoricalDistribution,
    Distribution,
    FloatDistribution,
    IntegerDistribution,
)
from synthcity.plugins.core.models.mlp import MLP
from synthcity.plugins.core.models.time_to_event.metrics import (
    c_index,
    expected_time_error,
)
from synthcity.utils.constants import DEVICE
from synthcity.utils.reproducibility import enable_reproducible_results

# synthcity relative
from ._base import TimeToEventPlugin

class TimeEventGAN(nn.Module):
    @validate_arguments(config=dict(arbitrary_types_allowed=True))
    def __init__(
        self,
        n_features: int,
        n_units_latent: int,
        model_search_n_iter: Optional[int] = None,
        generator_n_layers_hidden: int = 2,
        generator_n_units_hidden: int = 250,
        generator_nonlin: str = "leaky_relu",
        generator_nonlin_out: Optional[List[Tuple[str, int]]] = None,
        generator_n_iter: int = 1000,
        generator_batch_norm: bool = False,
        generator_dropout: float = 0,
        generator_loss: Optional[Callable] = None,
        generator_lr: float = 2e-4,
        generator_weight_decay: float = 1e-3,
        generator_residual: bool = True,
        generator_opt_betas: tuple = (0.9, 0.999),
        discriminator_n_layers_hidden: int = 3,
        discriminator_n_units_hidden: int = 300,
        discriminator_nonlin: str = "leaky_relu",
        discriminator_n_iter: int = 1,
        discriminator_batch_norm: bool = False,
        discriminator_dropout: float = 0.1,
        discriminator_loss: Optional[Callable] = None,
        discriminator_lr: float = 2e-4,
        discriminator_weight_decay: float = 1e-3,
        discriminator_opt_betas: tuple = (0.9, 0.999),
        patience: int = 10,
        batch_size: int = 100,
        n_iter_print: int = 50,
        random_state: int = 0,
        n_iter_min: int = 100,
        clipping_value: int = 0,
        device: Any = DEVICE,
    ) -> None:
        super(TimeEventGAN, self).__init__()

        self.device = device
        self.n_features = n_features
        self.n_units_latent = n_units_latent

        if model_search_n_iter is not None:
            generator_n_iter = model_search_n_iter

        self.generator = MLP(
            task_type="regression",
            n_units_in=n_features + n_units_latent,
            n_units_out=1,  # time to event
            n_layers_hidden=generator_n_layers_hidden,
            n_units_hidden=generator_n_units_hidden,
            nonlin=generator_nonlin,
            nonlin_out=generator_nonlin_out,
            n_iter=generator_n_iter,
            batch_norm=generator_batch_norm,
            dropout=generator_dropout,
            loss=generator_loss,
            random_state=random_state,
            lr=generator_lr,
            residual=generator_residual,
            opt_betas=generator_opt_betas,
            device=self.device,
        ).to(self.device)

        self.discriminator = MLP(
            task_type="regression",
            n_units_in=n_features + 1,
            n_units_out=1,  # fake/true
            n_layers_hidden=discriminator_n_layers_hidden,
            n_units_hidden=discriminator_n_units_hidden,
            nonlin=discriminator_nonlin,
            nonlin_out=[("none", 1)],
            n_iter=discriminator_n_iter,
            batch_norm=discriminator_batch_norm,
            dropout=discriminator_dropout,
            loss=discriminator_loss,
            random_state=random_state,
            lr=discriminator_lr,
            opt_betas=discriminator_opt_betas,
            device=self.device,
        ).to(self.device)

        # training
        self.generator_n_iter = generator_n_iter
        self.discriminator_n_iter = discriminator_n_iter
        self.n_iter_print = n_iter_print
        self.n_iter_min = n_iter_min
        self.batch_size = batch_size
        self.clipping_value = clipping_value
        self.patience = patience

        self.random_state = random_state
        enable_reproducible_results(random_state)

    def fit(
        self,
        X: np.ndarray,
        T: np.ndarray,
        E: np.ndarray,
    ) -> "TimeEventGAN":
        Xt = self._check_tensor(X)
        Tt = self._check_tensor(T)
        Et = self._check_tensor(E)

        self._train(
            Xt,
            Tt,
            Et,
        )

        return self

    def generate(self, X: np.ndarray) -> np.ndarray:
        X = self._check_tensor(X).float()

        return self(X).cpu().numpy()

    @validate_arguments(config=dict(arbitrary_types_allowed=True))
    def forward(self, X: torch.Tensor) -> torch.Tensor:
        self.generator.eval()

        fixed_noise = torch.randn(len(X), self.n_units_latent, device=self.device)
        with torch.no_grad():
            return self.generator(torch.hstack([X, fixed_noise])).detach().cpu()

    def dataloader(
        self, X: torch.Tensor, T: torch.Tensor, E: torch.Tensor
    ) -> Tuple[DataLoader, TensorDataset]:
        X_train, X_val, T_train, T_val, E_train, E_val = train_test_split(
            X.cpu(),
            T.cpu(),
            E.cpu(),
            stratify=E.cpu(),
            random_state=self.random_state,
        )
        train_dataset = TensorDataset(
            self._check_tensor(X_train),
            self._check_tensor(T_train),
            self._check_tensor(E_train),
        )
        val_dataset = TensorDataset(
            self._check_tensor(X_val),
            self._check_tensor(T_val),
            self._check_tensor(E_val),
        )

        return DataLoader(
            train_dataset, batch_size=self.batch_size, pin_memory=False
        ), DataLoader(val_dataset, batch_size=len(val_dataset), pin_memory=False)

    def _generate_training_outputs(
        self, X: torch.Tensor, T: torch.Tensor, E: torch.Tensor
    ) -> tuple:
        # Train with non-censored true batch
        Xnc = X[E == 1].to(self.device)
        Tnc = T[E == 1].to(self.device)
        true_features_time = torch.hstack([Xnc, Tnc.reshape(-1, 1)])

        true_output = self.discriminator(true_features_time).squeeze().float()

        # Train with fake batch
        noise = torch.randn(len(X), self.n_units_latent, device=self.device)
        noise = torch.hstack([X, noise])
        fake_T = self.generator(noise)

        fake_features_time = torch.hstack([X, fake_T.reshape(-1, 1)])

        fake_output = self.discriminator(fake_features_time.detach()).squeeze()

        return true_output, fake_output

    def _train_epoch_generator(
        self,
        X: torch.Tensor,
        T: torch.Tensor,
        E: torch.Tensor,
    ) -> float:
        # Update the G network
        self.generator.optimizer.zero_grad()

        # Evaluate noncensored error
        Xnc = X[E == 1].to(self.device)
        Tnc = T[E == 1].to(self.device)

        batch_size = len(Xnc)

        noise = torch.randn(batch_size, self.n_units_latent, device=self.device)
        noncen_input = torch.hstack([Xnc, noise])
        fake_T = self.generator(noncen_input).squeeze()

        errG_noncen = nn.MSELoss()(
            fake_T, Tnc
        )  # fake_T should be == T for noncensored data

        # Evaluate censored error
        Xc = X[E == 0].to(self.device)
        Tc = T[E == 0].to(self.device)

        batch_size = len(Xc)

        noise = torch.randn(batch_size, self.n_units_latent, device=self.device)
        cen_input = torch.hstack([Xc, noise])
        fake_T = self.generator(cen_input)

        errG_cen = torch.mean(
            nn.ReLU()(Tc - fake_T)
        )  # fake_T should be >= T for censored data

        # Discriminator loss
        real_output, fake_output = self._generate_training_outputs(X, T, E)

        errG_discr = 0
        if real_output.dim() > 0 and len(real_output) > 0:
            errG_discr += torch.mean(real_output)

        if fake_output.dim() > 0 and len(fake_output) > 0:
            errG_discr -= torch.mean(fake_output)

        # Calculate G's loss based on this output
        errG = errG_noncen + errG_cen + errG_discr

        if errG.isnan().sum() != 0:
            raise RuntimeError("NaNs detected in the generator loss")

        # Calculate gradients for G
        errG.backward()

        # Update G
        if self.clipping_value > 0:
            torch.nn.utils.clip_grad_norm_(
                self.generator.parameters(), self.clipping_value
            )
        self.generator.optimizer.step()

        # Return loss
        return errG.item()

    def _train_epoch_discriminator(
        self,
        X: torch.Tensor,
        T: torch.Tensor,
        E: torch.Tensor,
    ) -> float:
        # Update the D network
        errors = []

        for epoch in range(self.discriminator_n_iter):
            self.discriminator.zero_grad()

            (
                true_output,
                fake_output,
            ) = self._generate_training_outputs(X, T, E)

            act = nn.Sigmoid()
            errD: torch.Tensor = 0
            if true_output.dim() > 0 and len(true_output) > 0:
                errD -= torch.mean(torch.log(act(true_output)))

            if fake_output.dim() > 0 and len(fake_output) > 0:
                errD -= torch.mean(torch.log(1 - act(fake_output)))

            if errD.isnan().sum() != 0:
                raise RuntimeError("NaNs detected in the discriminator loss")
            errD.backward()

            # Update D
            if self.clipping_value > 0:
                torch.nn.utils.clip_grad_norm_(
                    self.discriminator.parameters(), self.clipping_value
                )
            self.discriminator.optimizer.step()

            errors.append(errD.item())

        return np.mean(errors)

    def _train_epoch(
        self,
        loader: DataLoader,
    ) -> Tuple[float, float]:

        G_losses = []
        D_losses = []

        for i, data in enumerate(loader):
            G_losses.append(
                self._train_epoch_generator(
                    *data,
                )
            )
            D_losses.append(
                self._train_epoch_discriminator(
                    *data,
                )
            )

        return np.mean(G_losses), np.mean(D_losses)

    def _train(
        self,
        X: torch.Tensor,
        T: torch.Tensor,
        E: torch.Tensor,
    ) -> "TimeEventGAN":
        X = self._check_tensor(X).float()
        T = self._check_tensor(T).float()
        E = self._check_tensor(E).long()

        # Load Dataset
        loader, val_loader = self.dataloader(X, T, E)

        best_exp_tte_err = 9999
        patience = 0

        # Train loop
        for i in range(self.generator_n_iter):
            g_loss, d_loss = self._train_epoch(loader)
            # Check how the generator is doing by saving G's output on fixed_noise
            if (i + 1) % self.n_iter_print == 0:
                with torch.no_grad():
                    Xval, Tval, Eval = next(iter(val_loader))
                    Xdf = Xval.cpu().numpy()
                    Tdf = pd.Series(Tval.cpu().numpy())
                    Edf = pd.Series(Eval.cpu().numpy(), index=Tdf.index)

                    Tpred = pd.Series(
                        self.generate(Xdf).squeeze(),
                        index=Tdf.index,
                    )

                    c_index_val = c_index(Tdf, Edf, Tpred)
                    exp_err_val = expected_time_error(Tdf, Edf, Tpred)

                    if best_exp_tte_err > exp_err_val:
                        patience = 0
                        best_exp_tte_err = exp_err_val
                    else:
                        patience += 1

                    if patience > self.patience:
                        log.debug(
                            f"No improvement for {patience} iterations. stopping..."
                        )
                        break

                log.debug(
                    f"[{i}/{self.generator_n_iter}]\tLoss_D: {d_loss}\tLoss_G: {g_loss}\tC-Index val: {c_index_val} Expected time err: {exp_err_val}"
                )

        return self

    def _check_tensor(self, X: torch.Tensor) -> torch.Tensor:
        if isinstance(X, torch.Tensor):
            return X.to(self.device)
        else:
            return torch.from_numpy(np.asarray(X)).to(self.device)

class DATETimeToEvent(TimeToEventPlugin):
    def __init__(self, **kwargs: Any) -> None:
        super().__init__()

        self.kwargs = kwargs

    @validate_arguments(config=dict(arbitrary_types_allowed=True))
    def fit(self, X: pd.DataFrame, T: pd.Series, Y: pd.Series) -> "TimeToEventPlugin":
        "Training logic"
        self._fit_censoring_model(X, T, Y)

        self.model = TimeEventGAN(
            n_features=X.shape[1], n_units_latent=X.shape[1], **self.kwargs
        )

        self.scaler_X = MinMaxScaler()
        enc_X = self.scaler_X.fit_transform(X)

        self.scaler_T = MinMaxScaler()
        enc_T = self.scaler_T.fit_transform(T.values.reshape(-1, 1)).squeeze()

        self.model.fit(enc_X, enc_T, Y)

        return self

    @validate_arguments(config=dict(arbitrary_types_allowed=True))
    def predict(self, X: pd.DataFrame) -> pd.Series:
        "Predict time-to-event"

        enc_X = self.scaler_X.fit_transform(X)

        enc_preds = self.model.generate(enc_X)
        preds = self.scaler_T.inverse_transform(enc_preds).squeeze()

        return pd.Series(preds, index=X.index)

    @validate_arguments(config=dict(arbitrary_types_allowed=True))
    def predict_any(self, X: pd.DataFrame, E: pd.Series) -> pd.Series:
        "Predict time-to-event"

        result = pd.Series([0] * len(X), index=E.index)

        if (E == 1).sum() > 0:
            result[E == 1] = self.predict(X[E == 1])
        if (E == 0).sum() > 0:
            result[E == 0] = self._predict_censoring(X[E == 0])

        return result

    @staticmethod
    def name() -> str:
        return "date"

    @staticmethod
    def hyperparameter_space(**kwargs: Any) -> List[Distribution]:
        return [
            IntegerDistribution(name="generator_n_layers_hidden", low=1, high=5),
            IntegerDistribution(
                name="generator_n_units_hidden", low=100, high=500, step=50
            ),
            CategoricalDistribution(
                name="generator_nonlin", choices=["relu", "leaky_relu"]
            ),
            IntegerDistribution(
                name="generator_n_iter", low=1000, high=3000, step=1000
            ),
            FloatDistribution(name="generator_dropout", low=0, high=0.2),
            CategoricalDistribution(name="generator_lr", choices=[1e-2, 1e-3, 1e-4]),
            IntegerDistribution(name="discriminator_n_layers_hidden", low=1, high=5),
            IntegerDistribution(
                name="discriminator_n_units_hidden", low=100, high=500, step=50
            ),
            CategoricalDistribution(
                name="discriminator_nonlin", choices=["relu", "leaky_relu"]
            ),
            FloatDistribution(name="discriminator_dropout", low=0, high=0.2),
            CategoricalDistribution(
                name="discriminator_lr", choices=[1e-2, 1e-3, 1e-4]
            ),
            CategoricalDistribution(name="batch_size", choices=[100, 250, 500, 1000]),
        ]


import logging
import subprocess
import sys
import time

from typing import Optional

import psutil

from golem.docker.commands.docker import CommandDict, DockerCommandHandler
from golem.docker.config import DOCKER_VM_STATUS_RUNNING

logger = logging.getLogger(__name__)

class DockerForMacCommandHandler(DockerCommandHandler):

    APP = '/Applications/Docker.app'
    PROCESSES = dict(
        app='Docker',
        driver='com.docker.driver',
        hyperkit='com.docker.hyperkit',
        vpnkit='com.docker.vpnkit',
    )

    @classmethod
    def start(cls, *_args, **_kwargs) -> None:
        try:
            subprocess.check_call(['open', '-g', '-a', cls.APP])
            cls.wait_until_started()
        except (FileNotFoundError, subprocess.CalledProcessError):
            logger.error('Docker for Mac: unable to start the app')
            sys.exit(1)

    @classmethod
    def stop(cls) -> None:
        pid = cls.pid()
        if not pid:
            return

        try:
            subprocess.check_call(['kill', str(pid)])
        except subprocess.CalledProcessError:
            logger.error('Docker for Mac: unable to stop the app')
            return

        cls.wait_until_stopped()

    @classmethod
    def pid(cls, name: Optional[str] = None) -> Optional[int]:
        name = name or cls.PROCESSES['app']

        try:
            process = next(p for p in psutil.process_iter() if p.name() == name)
        except StopIteration:
            return None
        return process.pid

    @classmethod
    def status(cls) -> str:
        return DOCKER_VM_STATUS_RUNNING if cls.pid() else ''

    @classmethod
    def wait_until_stopped(cls) -> None:
        started = time.time()

        while any(map(cls.pid, cls.PROCESSES.values())):
            if time.time() - started >= cls.TIMEOUT:
                logger.error('Docker for Mac: VM start timeout')
                return
            time.sleep(0.5)

    # pylint: disable=undefined-variable
    commands: CommandDict = dict(
        start=lambda *_: DockerForMacCommandHandler.start(),
        stop=lambda *_: DockerForMacCommandHandler.stop(),
        status=lambda *_: DockerForMacCommandHandler.status(),
    )

    commands.update(DockerCommandHandler.commands)


# f = open("test.txt", "w", encoding="utf-8")
# f.write("안녕, 스파르타! \n")
#
# for i in [1, 2, 3, 4, 5]:
#     f.write(f"{i}번째 줄이에요\n")
# f.close()
#
# text = ""
#
# with open("test.txt", "r", encoding="utf-8") as f:
#     lines = f.readlines()
#     for line in lines:
#         text += line
#         # print(line, end="")
# print(text)

from wordcloud import WordCloud
from PIL import Image
import numpy as np

text = ''
with open("텍스트파", "r", encoding="utf-8") as f:
    lines = f.readlines()
    for line in lines[5:]:
        if "] [" in line:
            text += line.split('] ')[2].replace('저', '').replace('저도', '').replace('저두', '').replace('ㅋ', '').replace('ㅠ', '').replace('이모티콘\n','').replace('사진\n','').replace('삭제된 메세지입니다.\n','')
# print(text)

# import matplotlib.font_manager일 as fm

# # 이용 가능한 폰트 중 '고딕'만 선별
# for font in fm.fontManager.ttflist:
#     if 'Gothic' in font.name:
#         print(font.name, font.fname)
# /System/Library/Fonts/Supplemental/AppleGothic.ttf

# wc = WordCloud(font_path="/System/Library/Fonts/Supplemental/AppleGothic.ttf", background_color="white", width=600, height=400)
# wc.generate(text)
# wc.to_file("result.png")

mask = np.array(Image.open('cloud.png'))
wc = WordCloud(font_path="/System/Library/Fonts/Supplemental/AppleGothic.ttf", background_color="white", mask=mask)
wc.generate(text)
wc.to_file("result_masked.png")


#!/usr/bin/env python3

import os
import re
import json
import pandas as pd
from typing import List
from typing import Dict
from typing import Union
from typing import BinaryIO

__version = "1.0.0"
__date = "2023-02-07"

class JSONConverter:
    """
    Convert JSON files to different (file) formats.
    Example usage:
        json_file = "data.json"
        converter = JSONConverter()
        converter.load(json_file)
        dataframes = converter.to_dataframes()
        converter.to_csv(prefix = "data")
        dataframes[0].head()
        dataframes[1].head()
    """

    def __init__(self, input: Union[str, BinaryIO] = None) -> None:
        """
        Constructor.
        If 'input' is provided, self.load(input) will be called.
        """
        self.data = None
        if input is not None:
            self.load(input)

    def load(self, input: Union[str, BinaryIO]) -> Dict:
        """
        Load JSON from file or filestream (auto-detect).
        """

        if os.path.isfile(input):
            self.data = self.load_from_file(input)
        else:
            self.data = self.load_from_stream(input)

        return self.data

    def load_from_file(self, json_file: str) -> Dict:
        """
        Load JSON from file.
        """

        with open(json_file, "r", encoding = "utf-8") as f:
            self.data = json.load(f)
            f.close()

        return self.data

    def load_from_stream(self, json_filestream: BinaryIO) -> Dict:
        """
        Load JSON from filestream.
        """

        self.data = json.load(json_filestream)

        return self.data

    def to_csv(self, prefix: str, data: Dict = None) -> List[pd.DataFrame]:
        """
        Export JSON to CSV format.
        """

        if data == None:
            data = self.data

        dataframes = self.to_dataframes(data)
        dataframes[0].to_csv(prefix + "_fragment.csv", index = False)
        dataframes[1].to_csv(prefix + "_spectrum.csv", index = False)

        return dataframes

    def to_excel(self, prefix: str, data: Dict = None) -> List[pd.DataFrame]:
        """
        Export JSON to EXCEL format.
        """

        if data == None:
            data = self.data

        dataframes = self.to_dataframes(data)
        dataframes[0].to_excel(prefix + "_fragment.xlsx")
        dataframes[1].to_excel(prefix + "_spectrum.xlsx")

        return dataframes

    def to_dataframes(self, data: Dict = None) -> List[pd.DataFrame]:
        """
        Re-format JSON to dataframes.
        """

        if data == None:
            data = self.data

        # fragment-centric dataframe structure
        fragment = {"frag_code": [],
                    "frag_seq": [],
                    "frag_type1": [],
                    "frag_type2": [],
                    "position_frag_type1": [],
                    "position_frag_type2": [],
                    "frag_length": [],
                    "frag_charge": [],
                    "frag_intensity": [],
                    "frag_mz": [],
                    "perc_of_total_intensity": [],
                    "prop_intensity_to_base_peak": [],
                    "modification": [],
                    "spectrum_id": [],
                    "ambiguity": []}

        # spectrum-centric dataframe structure
        spectrum = {"perc_internal": [],
                    "perc_terminal": [],
                    "perc_other": [],
                    "total_int_internal": [],
                    "total_int_terminal": [],
                    "total_int_other": [],
                    "top1_internal_ion_code": [],
                    "top1_internal_seq": [],
                    "top2_internal_ion_code": [],
                    "top2_internal_seq": [],
                    "top3_internal_ion_code": [],
                    "top3_internal_seq": [],
                    "intensity_explained_aa": [],
                    "intensity_explained_precursor": [],
                    "spectrum_id": [],
                    "score": [],
                    "peptide_seq": [],
                    "peptide_length": []}

        for entry in data:
            pep_seq = entry["sequence"]
            pep_len = len(pep_seq)

            # Fragment-centric
            for i, code in enumerate(entry["annotation"]["theoretical_code"]):
                # skip non-annonated fragments
                if code is None:
                    fragment["frag_code"].append("n:n@0:0(+0)")
                    fragment["frag_seq"].append("")
                    fragment["frag_type1"].append("n")
                    fragment["frag_type2"].append("n")
                    fragment["position_frag_type1"].append(0)
                    fragment["position_frag_type2"].append(0)
                    fragment["frag_length"].append(0)
                    fragment["frag_charge"].append(0)
                    fragment["frag_intensity"].append(entry["annotation"]["intensity"][i])
                    fragment["frag_mz"].append(entry["annotation"]["mz"][i])
                    total_intensity = sum(entry["annotation"]["intensity"])
                    fragment["perc_of_total_intensity"].append(entry["annotation"]["intensity"][i] / total_intensity)
                    intensity_base_peak = max(entry["annotation"]["intensity"])
                    fragment["prop_intensity_to_base_peak"].append(entry["annotation"]["intensity"][i] / intensity_base_peak)
                    fragment["modification"].append("")
                    fragment["spectrum_id"].append(self.__get_spectrum_id(entry))
                    fragment["ambiguity"].append(self.__get_ambiguity(entry["annotation"], i))
                else:
                    start, end, ion_cap_start, ion_cap_end, charge, formula = self.__parse_fragment_code(code)
                    frag_seq = pep_seq[start - 1:end]
                    fragment["frag_code"].append(code)
                    fragment["frag_seq"].append(frag_seq)
                    fragment["frag_type1"].append(ion_cap_start)
                    fragment["frag_type2"].append(ion_cap_end)
                    fragment["position_frag_type1"].append(start)
                    fragment["position_frag_type2"].append(end)
                    fragment["frag_length"].append(end - start + 1)
                    fragment["frag_charge"].append(charge)
                    fragment["frag_intensity"].append(entry["annotation"]["intensity"][i])
                    fragment["frag_mz"].append(entry["annotation"]["mz"][i])
                    total_intensity = sum(entry["annotation"]["intensity"])
                    fragment["perc_of_total_intensity"].append(entry["annotation"]["intensity"][i] / total_intensity)
                    intensity_base_peak = max(entry["annotation"]["intensity"])
                    fragment["prop_intensity_to_base_peak"].append(entry["annotation"]["intensity"][i] / intensity_base_peak)
                    fragment["modification"].append(self.__parse_modfication(entry["proforma"], start, end))
                    fragment["spectrum_id"].append(self.__get_spectrum_id(entry))
                    fragment["ambiguity"].append(self.__get_ambiguity(entry["annotation"], i))

            # Spectrum-centric
            percentages_and_total_intensities = self.__calculate_internal_terminal_non_annotated_ions(entry["annotation"]["theoretical_code"], entry["annotation"]["intensity"])
            spectrum["perc_internal"].append(percentages_and_total_intensities["internal"])
            spectrum["perc_terminal"].append(percentages_and_total_intensities["terminal"])
            spectrum["perc_other"].append(percentages_and_total_intensities["non_annotated"])
            spectrum["total_int_internal"].append(percentages_and_total_intensities["total_int_internal"])
            spectrum["total_int_terminal"].append(percentages_and_total_intensities["total_int_terminal"])
            spectrum["total_int_other"].append(percentages_and_total_intensities["total_int_non"])
            top_3 = self.__find_top3_most_intense_internal_ions(entry["annotation"]["theoretical_code"],entry["annotation"]["intensity"], pep_seq)
            spectrum["top1_internal_ion_code"].append(top_3[0][0])
            spectrum["top1_internal_seq"].append(top_3[1][0])
            spectrum["top2_internal_ion_code"].append(top_3[0][1])
            spectrum["top2_internal_seq"].append(top_3[1][1])
            spectrum["top3_internal_ion_code"].append(top_3[0][2])
            spectrum["top3_internal_seq"].append(top_3[1][2])
            spectrum["intensity_explained_aa"].append(self.__find_explained_by_aa(entry["annotation"]["theoretical_code"], entry["annotation"]["intensity"]))
            spectrum["intensity_explained_precursor"].append(self.__find_explained_precursor(entry))
            spectrum["spectrum_id"].append(self.__get_spectrum_id(entry))
            spectrum["score"].append(self.__get_identification_score(entry))
            spectrum["peptide_seq"].append(pep_seq)
            spectrum["peptide_length"].append(len(pep_seq))

        return [pd.DataFrame(fragment), pd.DataFrame(spectrum)]

    def __get_spectrum_id(self, entry: Dict) -> Union[int, float, str]:
        """
        Get the spectrum ID if it exists.
        """

        if "spectrum_id" in entry:
            return entry["spectrum_id"]
        else:
            return ""

    def __get_identification_score(self, entry: Dict) -> Union[int, float, str]:
        """
        Get the identification score if it exists.
        """

        if "identification_score" in entry:
            return entry["identification_score"]
        else:
            return 0.0

    def __get_ambiguity(self, entry_annotation: Dict, index: int) -> Union[int, float, str]:
        """
        Get the ambiguity if information is available.
        """

        if "matches_count" in entry_annotation:
            return entry_annotation["matches_count"][index]
        else:
            return -1

    def __find_explained_by_aa(self, fragments: List[str], intensities: List[float]) -> float:
        """
        Calculate the explained intensity by single amino acids.
        """

        intensities_single_aa = 0

        for i, frag in enumerate(fragments):
            if frag is not None and "t" not in frag:
                start, end, ion_cap_start, ion_cap_end, charge, formula = self.__parse_fragment_code(frag)
                if start == end:
                    intensities_single_aa += intensities[i]

        return intensities_single_aa / sum(intensities)

    def __find_explained_precursor(self, entry: Dict) -> Union[int, float]:
        """
        Calculate the explained intensity by the precursor.
        """

        precursor_intensity = 0

        if "precursor_intensity" in entry:
            precursor_intensity = float(entry["precursor_intensity"])

        if precursor_intensity > 0:
            return precursor_intensity / sum(entry["annotation"]["intensity"])

        return -1

    def __find_top3_most_intense_internal_ions(self, fragments: List[str], intensities: List[float], pep_seq: str) -> List[List[str]]:
        """
        Get the top 3 most intense internal ions.
        """

        mapping = dict()
        for i, intensity in enumerate(intensities):
            # Add only the internal ions
            if fragments[i] is not None and "t" not in fragments[i]:
                mapping[intensity] = fragments[i]

        top_3_intensities = sorted(list(mapping.keys()), reverse = True)[:3]
        top_3_codes = [mapping[intensity] for intensity in top_3_intensities]

        top_3_sequences = []

        for code in top_3_codes:
            start, end, ion_cap_start, ion_cap_end, charge, formula = self.__parse_fragment_code(code)
            top_3_sequences.append(pep_seq[start-1:end])

        if len(top_3_codes) < 3:
            if len(top_3_codes) == 0:
                top_3_codes = ["", "", ""]
                top_3_sequences = ["", "", ""]
            if len(top_3_codes) == 1:
                top_3_codes.append("")
                top_3_codes.append("")
                top_3_sequences.append("")
                top_3_sequences.append("")
            else:
                top_3_codes.append("")
                top_3_sequences.append("")

        return [top_3_codes, top_3_sequences]

    def __calculate_internal_terminal_non_annotated_ions(self, fragments: List[str], intensities: List[float]) -> Dict:
        """
        Calculate ion counts and frequencies.
        """

        # Number of different ion types
        internal = 0
        terminal = 0
        non_annotated = 0

        # Total intensities of ion types
        total_int_internal = 0
        total_int_terminal = 0
        total_int_non = 0

        for i,fragment in enumerate(fragments):
            if fragment is not None:
                if "t" in fragment:
                    terminal += 1
                    total_int_terminal += intensities[i]
                else:
                    internal += 1
                    total_int_internal += intensities[i]
            else:
                non_annotated += 1
                total_int_non += intensities[i]

        return {"internal": internal / len(fragments),
                "terminal": terminal / len(fragments),
                "non_annotated": non_annotated / len(fragments),
                "total_int_internal": total_int_internal,
                "total_int_terminal": total_int_terminal,
                "total_int_non": total_int_non}

    def __parse_modfication(self, proforma: str, start: int, end: int) -> str:
        """
        Get modification string.
        """

        # Finds the modifications in the proforma string
        pattern = r"\[([\+?\-?A-Za-z0-9_\.?0-9]+)\]"
        mods = re.findall(pattern, proforma)

        positions = self.__parse_modification_positions(proforma)

        modifications = ""

        # Finds the positions of the modifications
        for i, position in enumerate(positions):
            if position >= start and position <= end:
                modifications += mods[i] + ";"

        return modifications.rstrip(";")

    def __parse_modification_positions(self, seq: str) -> List[int]:
        """
        Get positions of the modifications.
        """

        i = 1
        is_modification = False
        annotation = []
        for aa in seq:
            if aa == "[":
                is_modification = True
                annotation.append(0)
            elif aa == "]":
                is_modification = False
            else:
                if not is_modification:
                    annotation.append(i)
                    i += 1

        positions = []

        for i, anno in enumerate(annotation):
            if anno == 0:
                positions.append(annotation[i-1])

        return positions

    def __parse_fragment_code(self, fragment_code: str):
        """
        Parse the fragment code.
        """

        # test if fragment code format is valid*
        fragment_code_pattern = re.compile(".+(:).+(@)[0-9]+(:)[0-9]+(\()(\+|\-)[0-9](\))(\[(.*?)\])?")
        if bool(fragment_code_pattern.match(fragment_code)) == False:
            raise RuntimeError("Incorrect fragment code format: {0}".format(fragment_code))

        # Parse fragment code
        start, end = [
            int(i) for i in re.search("(?<=\@)(.*?)(?=\()", fragment_code).group(1).split(":")
        ]
        # Get start and end amino acid indexes
        ion_cap_start, ion_cap_end = [
            str(i) for i in re.search("^(.*?)(?=\@)", fragment_code).group(1).split(":")
        ]
        # Get start and end ion caps name
        charge = int(re.search("(?<=\()(.*?)(?=\))", fragment_code).group(1))  # get charge state
        formula = re.search("(?<=\[)(.*?)(?=\])", fragment_code)
        if formula == None:
            formula = ""
        else:
            formula = str(re.search("(?<=\[)(.*?)(?=\])", fragment_code).group(1))

        return start, end, ion_cap_start, ion_cap_end, charge, formula


import cv2
import numpy as np
import os

############## KNN CODE ###############
def distance(v1,v2):
	#Euclidean
	return np.sqrt(((v1-v2)**2).sum())

def knn(train,test,k=5):
	dist = []

	for i in range(train.shape[0]):
		# Get the vector and label`
		# we have used the last column for the labels part
		ix = train[i,:-1]
		iy = train[i,-1] # -1 because we have used the last column for the labels part
		# Compute the distance from the test point
		d = distance(test,ix)
		dist.append([d, iy])
	# Sort based on distance and get top k
	dk = sorted(dist,key=lambda x: x[0])[:k]
	# Retrieve only the labels
	labels = np.array(dk)[:, -1]

	# Get frequencies of each label
	output = np.unique(labels,return_counts=True)
	# Find max frequencyand corresponding label
	index = np.argmax(output[1])
	return output[0][index]
############################################

# Init Camera
cap = cv2.VideoCapture(0)

# Face Detection
face_cascade = cv2.CascadeClassifier("D:/Sublime/FaceRecognitionProject/haarcascade_frontalface_alt.xml")

skip = 0
dataset_path = './FaceData/'

face_data = []  # will contain the X-values ie feature information of data.X-values don't mean the x-coordinate values at all
labels = [] # contains the Y-values ie the indices of the data for algo

class_id = 0 # Labels for the given file
names = {}  # this dictionary Will be used to create a mapping between id and name77.9

# Data Preperation
for fx in os.listdir(dataset_path): # iterate over all the directories of the file
	if fx.endswith('.npy'):
		# Create a mapping btw class_id and name of the file
		names[class_id] = fx[:-4]
		print("Loaded : "+fx)
		data_item = np.load(dataset_path+fx)
		face_data.append(data_item)

		# create labels for the class,the following section of code of three lines ensures that each face in a single data_item or class,contains the same labels for ex., suppose saksham is the first class having class_id=0 , then each face in class saksham will have a label as 0.Similarly each face in class1 let it be of rahul.npy will contain the same label as 1 for each face in it.
		target = class_id*np.ones((data_item.shape[0],))
		class_id += 1
		labels.append(target)

face_dataset = np.concatenate(face_data,axis=0) # axis=0 represents appending or concatenating in row wise,concatenating rows
face_labels = np.concatenate(labels,axis=0).reshape((-1,1)) # whole of this Y-data or the labels are now transformed into a single column

print(face_dataset.shape)
print(face_labels.shape)

# We now need to concatenate both X ie no. rows or datasets and Y ie indexes  in a single training matrix.
# We do this because our KNN algorithm excepts one training matrix in which we should have the X-data and the Y-data combined in single matrix
# Therefore for doing this we first need to reshape our Y-data int a single column as done above in line 60

trainset = np.concatenate((face_dataset,face_labels),axis=1) # axis=1 represents concatenating along the columns
print(trainset.shape)

# Testing

while True:
	ret,frame = cap.read()
	if ret == False:
		continue

	faces = face_cascade.detectMultiScale(frame,1.3,5)

	for face in faces:
		x,y,w,h = face

		# Get the face Region Of Interest(ROI)
		offset = 10
		face_section = frame[y-offset:y+h+offset,x-offset:x+w+offset]
		face_section = cv2.resize(face_section,(100,100))

		# Predicted Label (out)
		out = knn(trainset,face_section.flatten())

		# Display on the screen the name and rectangle around it
		pred_name = names[int(out)]
		cv2.putText(frame,pred_name,(x,y-10),cv2.FONT_HERSHEY_SIMPLEX,1,(255,0,0),2,cv2.LINE_AA)
		cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,255),2)
	cv2.imshow("Faces",frame)

	key = cv2.waitKey(1) & 0xFF
	if key == ord('q'):
		break
cap.release()
cv2.destroyAllWindows()


#!/usr/bin/env python
# SimpBot - Simple IRC Bot
#
# Author: Ismael Lugo <ismaelrlgv@gmail.com>
# GIT: https://github.com/IsmaelRLG/simpbot

try:
    from setuptools import setup, find_packages
except ImportError:
    print("Please install the setuptools package")
    exit(1)

from os import walk
from os.path import join
from os.path import dirname as dir
import simpbot

requirements_file = 'requirements.txt'
currentdir = dir(__file__)
requires = open(join(currentdir, requirements_file), 'r').read().splitlines()

# searching plugins requirements...
for path, dirnames, filenames in walk(join(currentdir, 'simpmods')):
    if requirements_file in filenames:
        for req in open(join(path, requirements_file), 'r').read().splitlines():

            if req in requires:
                continue
            else:
                requires.append(req)

setup(
    name='simpbot',
    version=simpbot.__version__,
    author=simpbot.__author__,
    author_email="ismaelrlgv@gmail.com",
    description="Simple Bot (SimpBot) - IRC (Internet Relay Chat) Bot",
    url="https://github.com/IsmaelRLG/simpbot",
    license='MIT',
    packages=find_packages(exclude=['extra']),
    package_data=dict(simpbot=[join('localedata', '*.dat')]),
    install_requires=requires,
    classifiers=[
        "Development Status :: 3 - Alpha",
        "Environment :: Console",
        "Intended Audience :: Developers",
        "Intended Audience :: End Users/Desktop",
        "License :: OSI Approved :: MIT License",
        "Operating System :: POSIX :: Linux",
        "Operating System :: Microsoft :: Windows",
        "Programming Language :: Python :: 2.7",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.4",
        "Programming Language :: Python :: 3.5",
        "Topic :: Communications :: Chat :: Internet Relay Chat"
    ],
    entry_points=dict(console_scripts=['simpbot = simpbot.cli:main'])
)


import os
import pdb
import argparse
import logging
import torch
import pygame

import numpy as np
import matplotlib.pyplot as plt

from time import sleep, time
from torch import nn

batchsize=25
parser = argparse.ArgumentParser()
parser.add_argument("-f", "--file")
parser.add_argument("-t", "--test", action="store_true")
parser.add_argument("-p", "--plain", action="store_true")
parser.add_argument("-b", "--lbd", type=float, default=1.0)
parser.add_argument("-e", "--exp", type=float, default=1.5)
parser.add_argument("-d", "--decay", type=float, default=0.9995)
parser.add_argument("-r", "--repeat", type=int, default=250000)
args = parser.parse_args()
device = torch.device("cuda:0")
logfile = "logs/autoencoder-{'plain' if args.plain else 'simple'}-{time():.0f}.log"
if not args.test:
  logging.basicConfig(filename=logfile, format="%(message)s", level=logging.INFO)

w, h, n = 80, 80, 5
a, b = w//n, h//n

mean_rewards = torch.zeros((2, n, n), dtype=torch.float32).to(device)
mean_rewards_count = torch.ones((2, n, n), dtype=torch.float32).to(device)

def get_b(poses, k):
  return mean_rewards[k][poses]

def update_b(poses, rewards, k):
  mean_rewards[k][poses] -= (mean_rewards[k][poses] - rewards[:, 0]) / mean_rewards_count[k][poses]
  mean_rewards_count[k][poses] += 1.0

bg_color = (255, 255, 255)
action_space = (0, 1, 2, 3)

color = (0, 0, 0)
circle_center = (0, 0)
circle_radius = min(a//2, b//2)

class GW():
  def __init__(self):
    self.screen = pygame.Surface((w, h))
    self.screen.fill(bg_color)
    self.frames = torch.empty((n, n, 1, w, h), dtype=torch.float32).to(device)

  def initialize(self):
    for idx_a in range(n):
      for idx_b in range(n):
        center = GW.compute_center(idx_a, idx_b)
        pygame.draw.circle(self.screen, color, center, circle_radius)
        self.frames[idx_a, idx_b] = self.get_torch_frame()
        rect = pygame.rect.Rect((center[0] - a//2, center[1] - b//2), (a, b))
        pygame.draw.rect(self.screen, bg_color, rect)

  def visualize(self):
    f, axes = plt.subplots(n, n)
    for i in range(n):
      for j in range(n):
        axes[i][j].imshow(self.frames[i, j].moveaxis(0, 2).cpu().numpy())
    plt.show(block=False)

  @staticmethod
  def visualize_frames(frames, size):
    f, axes = plt.subplots(size[0], size[1])
    k = 0
    for i, j in zip(*[shit.flat for shit in np.mgrid[0:size[0], 0:size[1]]]):
      axes[i][j].imshow(frames[k].moveaxis(0, 2).cpu().numpy())
      k += 1
      if k == len(frames):
        break
    plt.show(block=False)

  def get_torch_frame(self):
    frame = pygame.surfarray.pixels3d(self.screen)
    return GW.to_float_tensor(frame[:, :, :1])

  @staticmethod
  def to_float_tensor(frame):
    frame = torch.from_numpy(np.asarray(frame, dtype=np.float32) / 255.0)
    frame = torch.moveaxis(frame, 2, 0)
    return frame

  @staticmethod
  def compute_center(idx_a, idx_b):
    return (idx_a * a + a//2, idx_b * b + b//2)

  def sample(self):
    sampled_flat_indexes = np.random.permutation(n*n)
    poses = np.unravel_index(sampled_flat_indexes, shape=(n, n))
    frames = self.frames[poses]
    # GW.visualize_frames(frames)
    return frames, poses

  def step(self, poses, actions):
    actions = actions.detach().cpu().numpy()
    actions = (actions[:, 0], actions[:, 1])
    next_poses = tuple([(_poses + _actions + n) % n for _poses, _actions in zip(poses, actions)])
    frames = self.frames[next_poses]
    # GW.visualize_frames(frames)
    return frames, poses

class ConvEncoder(nn.Module):
  def __init__(self):
    super(ConvEncoder, self).__init__()
    self.net = nn.Sequential(
      nn.Conv2d(1, 4, kernel_size=2, stride=2, bias=True),
      nn.LeakyReLU(inplace=True),
      nn.Conv2d(4, 8, kernel_size=2, stride=2, bias=True),
      nn.LeakyReLU(inplace=True),
      nn.Conv2d(8, 16, kernel_size=4, stride=4, bias=True),
      nn.LeakyReLU(inplace=True),
      nn.Conv2d(16, 32, kernel_size=3, stride=2, bias=True),
      nn.LeakyReLU(inplace=True),
      nn.Conv2d(32, 64, kernel_size=2, stride=1, bias=True),
    )

    for l in self.net.modules():
      if isinstance(l, nn.Conv2d):
        nn.init.xavier_uniform_(l.weight, gain=nn.init.calculate_gain("leaky_relu"))

  def forward(self, x):
    return self.net(x)

class ConvDecoder(nn.Module):

  def __init__(self):

    super(ConvDecoder, self).__init__()
    self.net = nn.Sequential(
      nn.ConvTranspose2d(64, 32, kernel_size=2, stride=1, bias=True),
      nn.ReLU(inplace=True),
      nn.ConvTranspose2d(32, 16, kernel_size=3, stride=2, bias=True),
      nn.ReLU(inplace=True),
      nn.ConvTranspose2d(16, 8, kernel_size=4, stride=4, bias=True),
      nn.ReLU(inplace=True),
      nn.ConvTranspose2d(8, 4, kernel_size=2, stride=2, bias=True),
      nn.ReLU(inplace=True),
      nn.ConvTranspose2d(4, 1, kernel_size=2, stride=2, bias=True),
      nn.Sigmoid(),
    )
    for l in self.net.modules():
      if isinstance(l, nn.Conv2d):
        nn.init.xavier_uniform_(l.weight, gain=nn.init.calculate_gain("relu"))

  def forward(self, x):
    return self.net(x)

class VanillaAutoEncoder(nn.Module):

  def __init__(self):
    super(VanillaAutoEncoder, self).__init__()
    self.cv_enc = ConvEncoder()
    self.fc_enc = nn.Sequential(
      nn.Linear(64, 16),
      nn.ReLU(inplace=True),
      nn.Linear(16, 2),
    )
    self.fc_dec = nn.Sequential(
      nn.Linear(2, 16),
      nn.ReLU(inplace=True),
      nn.Linear(16, 64),
      nn.ReLU(inplace=True),
    )
    self.cv_dec = ConvDecoder()

    for l in self.fc_enc.modules():
      if isinstance(l, nn.Linear):
        nn.init.xavier_normal_(l.weight)
        nn.init.zeros_(l.bias)

    for l in self.fc_dec.modules():
      if isinstance(l, nn.Linear):
        nn.init.xavier_normal_(l.weight)
        nn.init.zeros_(l.bias)

  def forward(self, x):
    x = self.cv_enc(x)
    x = torch.flatten(x, start_dim=1)
    h = self.fc_enc(x)
    x = self.fc_dec(h)
    x = x[..., None, None]
    x = self.cv_dec(x)
    return x, h

  def encode(self, x):
    x = self.cv_enc(x)
    x = torch.flatten(x, start_dim=1)
    x = self.fc_enc(x)
    return x

class FeaturePolicy(nn.Module):

  def __init__(self):
    super(FeaturePolicy, self).__init__()
    self.fc = nn.Sequential(
        nn.Linear(1, 4),
    )

  def forward(self, x):
    x = self.fc(x)
    x = torch.softmax(x, dim=1)
    x = (x + 0.001) / (1 + 0.001*4)
    return x
minlr=1e-5
maxlr=1e-4
lbd=args.lbd
vanilla_autoencoder = VanillaAutoEncoder().to(device)
ae_optimizer = torch.optim.Adam(params=vanilla_autoencoder.parameters(), lr=maxlr)
ae_scheduler = torch.optim.lr_scheduler.ExponentialLR(optimizer=ae_optimizer, gamma=args.decay)

policies = [FeaturePolicy().to(device) for _ in range(2)]
pc_optimizers = [torch.optim.Adam(params=policy.parameters(), lr=maxlr) for policy in policies]
pc_schedulers = [torch.optim.lr_scheduler.ExponentialLR(optimizer=pc_optimizer, gamma=args.decay) for pc_optimizer in pc_optimizers]

def init_grid_world():
  grid_world = GW()
  grid_world.initialize()
  return grid_world

def sample_actions(prob_actions):
  c = prob_actions.detach().cpu().numpy().cumsum(axis=1)
  u = np.random.rand(len(c), 1)
  choices = (u < c).argmax(axis=1)
  return torch.from_numpy(choices).to(device)

moves = torch.tensor([
  [-1, 0],
  [0, -1],
  [+1, 0],
  [0, +1],
])

def actions2move(actions, rlossistoobig):
  if rlossistoobig:
    return moves[actions]
  else:
    directions = moves[actions]
    return directions * torch.randint_like(directions, 1, n)

grid_world = init_grid_world()

def train():
  for i in range(args.repeat):
    states, poses = grid_world.sample()
    rstates, _latents = vanilla_autoencoder.forward(states)
    rloss = torch.sum(torch.sum(0.5 * torch.square(rstates - states), dim=1))
    rloss.backward()
    if args.plain:
      ae_optimizer.step()
      ae_optimizer.zero_grad()
    else:
      sloss = [0, 0]
      for k in range(2):
        policies[k].zero_grad()
        latents = vanilla_autoencoder.encode(states.to(device))
        prob_actions = policies[k].forward(latents[:,k:k+1])
        actions = sample_actions(prob_actions)
        lprob_actions = torch.log(prob_actions.take_along_dim(actions[..., None], dim=1))
        _moves = actions2move(actions, float(rloss) > 1600)
        next_states, _ = grid_world.step(poses, _moves)
        next_latents = vanilla_autoencoder.encode(next_states.to(device))
        dlatents = torch.abs(next_latents - latents.detach())
        rewards  = dlatents[:, k:k+1] / torch.sum(dlatents, dim=1, keepdim=True)
        # update_b(poses, rewards.detach(), k)
        # mean_rewards = get_b(poses, k)
        # sloss[k] = torch.sum(-lprob_actions * (rewards - mean_rewards)) * lbd
        if float(rloss) > 1600:
          sloss[k] = torch.sum(-lprob_actions * rewards )
        elif float(rloss) > 800:
          sloss[k] = torch.sum(-lprob_actions * rewards ) * lbd
        elif float(rloss) > 400:
          sloss[k] = torch.sum(-lprob_actions * rewards ) * lbd * args.exp
        elif float(rloss) > 200:
          sloss[k] = torch.sum(-lprob_actions * rewards ) * lbd * (args.exp**2)
        elif float(rloss) > 100:
          sloss[k] = torch.sum(-lprob_actions * rewards ) * lbd * (args.exp**3)
        elif float(rloss) > 50:
          sloss[k] = torch.sum(-lprob_actions * rewards ) * lbd * (args.exp**4)
        elif float(rloss) > 25:
          sloss[k] = torch.sum(-lprob_actions * rewards ) * lbd * (args.exp**5)
        else:
          sloss[k] = torch.sum(-lprob_actions * rewards ) * lbd * (args.exp**6)
        sloss[k].backward()
        if i % 20 == 0:
          print(f"policy loss {k}: {sloss[k]:.3f}")
      pc_optimizers[0].step()
      pc_optimizers[1].step()
      ae_optimizer.step()
      pc_optimizers[0].zero_grad()
      pc_optimizers[1].zero_grad()
      ae_optimizer.zero_grad()
      if ae_scheduler.get_lr()[0] > minlr:
        ae_scheduler.step()
        pc_optimizers[0].step()
        pc_optimizers[1].step()
      logging.info(f"{rloss},{sloss[0]},{sloss[0]}")
    if i % 20 == 0:
      print(f"r_loss: {rloss:.3f}")
      print("---------------------------------------------------------")

    if i % 10000 == 0 :
      filename = os.path.join("checkpoints", f"{'plain' if args.plain else 'simple'}-ae-{time():.0f}-{rloss}-{lbd}-{args.exp:0f}-{args.decay}.pt")
      torch.save(vanilla_autoencoder.state_dict(), filename)

def visualise_latents(latents):
  f, axe = plt.subplots()
  X = latents[:, 0]
  Y = latents[:, 1]
  axe.scatter(X, Y, s=100, color="red")
  axe.set_xlabel("X")
  axe.set_ylabel("Y")
  for i in range(batchsize):
    idx = np.unravel_index(i, (n, n))
    axe.text(X[i], Y[i], f"({idx[0]}, {idx[1]})")
  plt.show(block=False)

def test():
  vanilla_autoencoder.load_state_dict(torch.load("checkpoints/" + args.file))
  frames = grid_world.frames.flatten(start_dim=0, end_dim=1)
  rframes, latents = vanilla_autoencoder(frames)
  grid_world.visualize_frames(frames.detach().cpu(), (n, n))
  grid_world.visualize_frames(rframes.detach().cpu(), (n, n))
  print(latents)
  visualise_latents(latents.detach().cpu().numpy())
  input()

if __name__ == '__main__':
  if args.test:
    test()
  else:
    train()


"""Setup logger."""
import collections.abc
import logging
import os
import typing

import HABApp.config.config
import HABApp.config.logging

import habapp_rules.__version__

LOG_PATH = HABApp.config.config.CONFIG.directories.logging.absolute()

def setup_logger() -> None:
	"""Setup the logger"""
	log_formatter = logging.Formatter("%(asctime)s.%(msecs)03d | %(threadName)20s | %(levelname)8s | %(name)s:%(lineno)d | %(message)s", datefmt="%Y-%m-%d | %H:%M:%S")
	habapp_rules_logger = logging.getLogger("habapp_rules")
	habapp_rules_logger.setLevel(logging.DEBUG)

	console_handler = logging.StreamHandler()
	console_handler.setFormatter(log_formatter)
	console_handler.setLevel(logging.DEBUG)
	habapp_rules_logger.addHandler(console_handler)

	if not LOG_PATH.is_dir():
		os.makedirs(LOG_PATH)

	file_handler = HABApp.config.logging.MidnightRotatingFileHandler(LOG_PATH / "habapp_rules.log", encoding="utf-8")
	file_handler.setFormatter(log_formatter)
	file_handler.setLevel(logging.DEBUG)
	habapp_rules_logger.addHandler(file_handler)

class InstanceLogger(logging.LoggerAdapter):
	"""Logging adapter to add the instance name to the log message."""

	def __init__(self, logger: logging.Logger, instance_name: str) -> None:
		"""Instantiate a logging adapter for multiple instances.

		:param logger: the underlying logger e.g. module logger
		:param instance_name: the name of the instance
		"""
		self._instance_name = instance_name
		logging.LoggerAdapter.__init__(self, logger)

	def process(self, msg: str, kwargs: collections.abc.MutableMapping[str, typing.Any]) -> tuple[str, collections.abc.MutableMapping[str, typing.Any]]:
		"""Add the instance name to log message.

		:param msg: the log message
		:param kwargs: additional keyword arguments.
		:return: tuple of msg with given keyword arguments
		"""
		return f"{self._instance_name} | {msg}", kwargs

setup_logger()
LOGGER = logging.getLogger(__name__)
LOGGER.info(f"Start logging of habapp_rules. Version = {habapp_rules.__version__.__version__}")


import io
import re

import six

from .commands import call_command

def get_current_branch():
    return call_command(["git", "rev-parse", "--abbrev-ref", "HEAD"])

def retrieve_ticket(branch, regex):
    matches = re.match(regex, branch)
    if matches:
        ticket_number = matches.group("ticket")
        return ticket_number

def is_ticket_in_message(contents, ticket):
    for line in contents.splitlines():
        stripped = line.strip().lower()

        if stripped == "" or stripped.startswith("#"):
            continue

        if ticket in stripped:
            return True

def add_ticket_number(filename, regex, format_template):
    branch = get_current_branch()
    ticket_number = retrieve_ticket(branch, regex)

    if ticket_number:
        with io.open(filename, "r+") as fd:
            contents = fd.read()

            if (
                is_ticket_in_message(contents, ticket_number)
                or not contents[:contents.find("\n")]
            ):
                return

            ticket_msg = format_template.format(message=contents, ticket=ticket_number)
            fd.seek(0)
            fd.write(six.text_type(ticket_msg))
            fd.truncate()


import functools
from loguru import logger
import sys

defined_log_levels = ['TRACE', 'DEBUG', 'INFO', 'SUCCESS', 'WARNING', 'ERROR', 'CRITICAL']

def init_logger(level='NOLOG', backtrace=False, diagnose=False, file_log=False, file_log_level="WARNING"):
    logger.remove()
    if level != 'NOLOG':
        logger.add(sys.stderr, level=level, backtrace=backtrace,
                   diagnose=diagnose, colorize=True)
        if file_log:
            logger.add("error_log.log", serialize=True, level=file_log_level, backtrace=backtrace,
                       diagnose=diagnose, rotation="1 day", retention="7 days", compression="zip")

def log_anime_info(anime,msg=""):
    logger.debug(f"{msg} {anime.a_id}, {anime.title}, {anime.slug}, {anime.type}, {anime.episodes_length}")

def logger_wraps(*, entry=True, exit=True, level="TRACE"):
    def wrapper(func):
        name = func.__name__

        @functools.wraps(func)
        def wrapped(*args, **kwargs):
            logger_ = logger.opt(depth=1)
            if entry:
                logger_.log(level, "Entering '{}' (args={}, kwargs={})", name, args, kwargs)
            result = func(*args, **kwargs)
            if exit:
                logger_.log(level, "Exiting '{}' (result={})", name, result)
            return result

        return wrapped

    return wrapper


from django.shortcuts import redirect
from receitas.models.Receitas import Receitas

def atualizar_receita(request):
    if request.method == 'POST':
        receita = Receitas.objects.get(id=request.POST['receita_id'])
        receita.nome_receita = request.POST['nome_receita']
        receita.ingredientes = request.POST['ingredientes']
        receita.modo_preparo = request.POST['modo_preparo']
        receita.tempo_preparo = request.POST['tempo_preparo']
        receita.rendimento = request.POST['rendimento']
        receita.categoria = request.POST['categoria']

        if 'foto_receita' in request.FILES:
            receita.foto_receita = request.FILES['foto_receita']

        receita.save()

        return redirect(to='dashboard')