import socket
import threading
import queue
import json
import os

IP = ''
PORT_CHAT = 50007
PORT_FILE = 50008
PORT_IMG = 50009
que = queue.Queue()  # 用于存放客户端发送的信息的队列
user_list = []  # 用于存放在线用户的信息  [conn, user, addr]
lock = threading.Lock()  # 创建锁, 防止多个线程写入数据的顺序打乱
# 获取服务端图片缓存文件夹的绝对路径
p = os.getcwd().split('\\')
for i in range(len(p)):
    if p[i] == 'myproject':
        break
server_cache = ('\\'.join(p[:i+1])) + '\\imgcache_server'
# 如果文件夹不存在则创建一个
if not os.path.exists(server_cache):
    os.mkdir(server_cache)
# print(server_cache)

################################################################################################################################
class Chat_Server(threading.Thread):
    global user_list, lock, que

    def __init__(self, ip, port):
        threading.Thread.__init__(self)
        self.ADDR = (ip, port)
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    def run(self):
        self.s.bind(self.ADDR)
        self.s.listen(5)
        print('聊天服务器运行中...')
        q = threading.Thread(target=self.send_message)
        q.start()
        while True:
            conn, addr = self.s.accept()
            t = threading.Thread(target=self.chat_connect, args=(conn, addr))
            t.start()
        self.s.close()

    # 将接收到的信息存入que
    def enter_que(self, addr, data):
        lock.acquire()
        try:
            que.put((addr, data))
        finally:
            lock.release()

    # 将离线用户移出user_list
    def del_user(self, conn, addr):
        for i in range(len(user_list)):
            if user_list[i][0] == conn:
                user_list.pop(i)
                # 显示当前在线用户
                online_user_list = [user_list[i][1] for i in range(len(user_list))]
                self.enter_que(addr, online_user_list)
                print('剩余在线用户：', online_user_list)
                break

    # 用于接收所有客户端发送信息的函数
    def chat_connect(self, conn, addr):
        print('*****聊天服务器已连接: ', addr)
        # 连接后将用户信息添加到user_list
        user = conn.recv(1024).decode()  # 接收用户名
        if user == 'no':
            user = addr[0] + ':' + str(addr[1])
        else:
            # 防止重名
            user = user + '[' + str(addr[1]) + ']'
        user_list.append((conn, user, addr))
        # print(user_list)
        online_user_list = [user_list[i][1] for i in range(len(user_list))]
        self.enter_que(addr, online_user_list)
        try:
            while True:
                data = conn.recv(1024)
                data = data.decode()
                self.enter_que(addr, data)  # 保存信息到队列
            conn.close()
        except:
            print('*****聊天服务器断开连接: ', addr)
            self.del_user(conn, addr)  # 将断开用户移出users
            conn.close()

    # 将队列que中的消息发送给所有连接到的用户
    def send_message(self):
        while True:
            if not que.empty():
                data = ''
                message = que.get()  # 取出队列第一个元素
                # print('-------------', message)
                # 如果是字符串，说明是消息
                if isinstance(message[1], str):
                    for i in range(len(user_list)):
                        for j in range(len(user_list)):
                            if message[0] == user_list[j][2]:
                                data = message[1]
                                # print(message[1])
                                break
                        user_list[i][0].send(data.encode())
                # print(data)
                data = data.split('$&')[0]
                # print(data)
                # 如果是列表，说明是用户列表
                if isinstance(message[1], list):
                    data = json.dumps(message[1])
                    for i in range(len(user_list)):
                        user_list[i][0].send(data.encode())

 ################################################################################################################################
class File_Server(threading.Thread):
    def __init__(self, ip, port):
        threading.Thread.__init__(self)
        self.ADDR = (ip, port)
        self.upload = './filerecv'
        if not os.path.exists(self.upload):
            os.mkdir(self.upload)
        os.chdir(self.upload)  # 将filerecv作为文件上传默认路径
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    def run(self):
        self.s.bind(self.ADDR)
        self.s.listen(5)
        print('文件服务器运行中...')
        while True:
            conn, addr = self.s.accept()
            t = threading.Thread(target=self.file_connect, args=(conn, addr))
            t.start()
        self.s.close()

    # 传输当前目录列表
    def send_current_dirlist(self, conn):
        current_dir = os.listdir(os.getcwd())
        current_dir = json.dumps(current_dir)
        conn.sendall(current_dir.encode())

    # 客户端上传文件
    def upload_file(self, path, conn):
        file_path = './' + path
        with open(file_path, 'wb') as f:
            while True:
                line = conn.recv(1024)
                if 'EOF'.encode() in line:
                    f.write(line[:-3])
                    break
                f.write(line)
            # 发送同步消息
            conn.send('ok'.encode())
            print('文件上传完成', file_path)

    # 客户端下载文件
    def download_file(self, path, conn):
        file_path = './' + path
        with open(file_path, 'rb') as f:
            lines = f.read()
            conn.sendall(lines)
        conn.send('EOF'.encode())
        # 接收同步消息
        y = conn.recv(1024).decode()
        if y == 'ok':
            print('文件下载完成', file_path)

    # 切换目录
    def cd(self, item, conn):
        # 如果是新连接或者下载上传文件后的发送则不切换,只发送当前工作目录
        if item != 'same':
            f = './' + item
            os.chdir(f)
        path_list = os.getcwd().split('\\')  # 当前工作目录
        # print('===============', path_list)
        for i in range(len(path_list)):
            if path_list[i] == 'filerecv':
                break
        path = ''
        for j in range(i, len(path_list)):
            path = path + path_list[j] + ' '
        path = '\\'.join(path.split())
        # print('+++++++++', path)
        # 如果切换目录超出范围则退回切换根目录
        if not 'filerecv' in path_list:
            f = './filerecv'
            os.chdir(f)
            path = 'filerecv'
        conn.send(path.encode())

    def file_connect(self, conn, addr):
        print('*****文件服务器已连接: ', addr)
        while True:
            # 获取客户端请求
            request = conn.recv(1024).decode()
            # 打印客户端请求
            print('客户端请求：', ' '.join(request.split('!@')))
            # if request == 'quit':
            #     print('*****文件服务器断开连接: ', addr)
            #     break
            # 获取客户端传来的操作命令
            command = request.split('!@')[0]
            # 获取客户端传来的目标路径
            path = request.split('!@')[1]
            if command == 'quit':
                print('*****文件服务器断开连接: ', addr)
                break
            elif command == 'upload':
                self.upload_file(path, conn)
            elif command == 'download':
                self.download_file(path, conn)
            elif command == 'show':
                self.send_current_dirlist(conn)
            elif command == 'cd':
                self.cd(path, conn)
        conn.close()

################################################################################################################################
class Img_Server(threading.Thread):
    global server_cache
    def __init__(self, ip, port):
        threading.Thread.__init__(self)
        self.ADDR = (ip, port)
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    def run(self):
        self.s.bind(self.ADDR)
        self.s.listen(5)
        print('图片服务器运行中...')
        while True:
            conn, addr = self.s.accept()
            t = threading.Thread(target=self.img_connect, args=(conn, addr))
            t.start()
        self.s.close()

    def upload_img(self, name, conn):
        img_path = server_cache + '\\' + name
        self.server_img = []
        for _, _, namelist in os.walk(server_cache):
            for n in namelist:
                self.server_img.append(n)
        # print(self.server_img)
        if name not in self.server_img:
            self.server_img.append(name)
            conn.send('permit'.encode())
            with open(img_path, 'wb') as f:
                while True:
                    line = conn.recv(1024)
                    if 'EOF'.encode() in line:
                        f.write(line[:-3])
                        break
                    f.write(line)
            # 发送同步消息
            conn.send('ok'.encode())
            print('图片上传完成', img_path)
        else:
            conn.send('deny'.encode())
            print('图片已存在')

    def download_img(self, name, conn):
        img_path = server_cache + '\\' + name
        with open(img_path, 'rb') as f:
            lines = f.read()
            conn.sendall(lines)
        conn.send('EOF'.encode())
        # 接收同步消息
        x = conn.recv(1024).decode()
        if x == 'ok':
            print('图片下载完成', img_path)

    def img_connect(self, conn, addr):
        print('*****图片服务器已连接: ', addr)
        while True:
            # 接收客户端传来的请求
            request = conn.recv(1024).decode()
            # 打印客户端请求
            print('客户端请求：', ' '.join(request.split('!@')))
            # 获取客户端传来的操作命令
            command = request.split('!@')[0]
            # 获取客户端传来的图片名
            name = request.split('!@')[1]
            # 将图片上传至服务器缓存文件夹
            if command == 'upload':
                self.upload_img(name, conn)
            # 下载图片到客户端缓存文件夹
            elif command == 'download':
                self.download_img(name, conn)
        conn.close()

################################################################################################################################
if __name__ == '__main__':
    chat_server = Chat_Server(IP, PORT_CHAT)
    chat_server.start()
    file_server = File_Server(IP, PORT_FILE)
    file_server.start()
    img_server = Img_Server(IP, PORT_IMG)
    img_server.start()


import gzip
import json
import re
import StringIO
import urllib2

from autopkglib import Processor, ProcessorError

__all__ = ["GoToMeetingURLProvider"]

BASE_URL = "https://p5.osdimg.com/g2mupdater/live/config.json"

class GoToMeetingURLProvider(Processor):

    """Provides a download URL for the latest GoToMeeting release."""
    input_variables = {
        "base_url": {
            "required": False,
            "description": "Default is %s" % BASE_URL
        }
    }
    output_variables = {
        "url": {
            "description": "URL to the latest GoToMeeting release."
        },
        "build": {
            "description": "Build number of the latest GoToMeeting release."
        }
    }
    description = __doc__

    def get_g2m_json(self, base_url):
        request = urllib2.Request(base_url)
        request.add_header("Accept-Encoding", "gzip")
        opener = urllib2.build_opener()
        response = opener.open(request)

        # Sometimes the base URL is compressed as gzip, sometimes it's not.
        if response.info().get("Content-Encoding") == "gzip":
            self.output("Encoding: gzip")
            gzipData = StringIO.StringIO(response.read())
            jsonData = json.loads(gzip.GzipFile(fileobj=gzipData).read())
        else:
            self.output("Encoding: plaintext")
            jsonData = json.loads(response.read())

        return jsonData

    def get_g2m_url(self, jsonData):
        return jsonData["activeBuilds"][
            len(jsonData["activeBuilds"]) - 1]["macDownloadUrl"]

    def get_g2m_build(self, jsonData):
        return str(jsonData["activeBuilds"][
            len(jsonData["activeBuilds"]) - 1]["buildNumber"])

    def main(self):
        """Find and return a download URL"""
        base_url = self.env.get("base_url", BASE_URL)
        jsonData = self.get_g2m_json(base_url)
        self.env["url"] = self.get_g2m_url(jsonData)
        self.output("Found URL: %s" % self.env["url"])
        self.env["build"] = self.get_g2m_build(jsonData)
        self.output("Build number: %s" % self.env["build"])

if __name__ == "__main__":
    processor = GoToMeetingURLProvider()
    processor.execute_shell()


import math
import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
from utils import core
from agents.ppo_aux_plan.core import composite_reward

class FeatureExtractor(nn.Module):
    def __init__(self, args):
        super(FeatureExtractor, self).__init__()
        self.n_features = args.n_features
        self.n_handcrafted_features = args.n_handcrafted_features
        self.use_handcraft = args.use_handcraft
        self.n_hidden = args.n_hidden
        self.n_layers = args.n_rnn_layers
        self.bidirectional = args.bidirectional
        self.directions = args.rnn_directions
        self.LSTM = nn.LSTM(input_size=self.n_features, hidden_size=self.n_hidden, num_layers=self.n_layers,
                            batch_first=True, bidirectional=self.bidirectional)  # (seq_len, batch, input_size)

    def forward(self, s, feat, mode):
        if mode == 'batch':
            output, (hid, cell) = self.LSTM(s)
            lstm_output = hid.view(hid.size(1), -1)  # => batch , layers * hid
            feat = feat.squeeze(1)
        else:
            s = s.unsqueeze(0)  # add batch dimension
            output, (hid, cell) = self.LSTM(s)  # hid = layers * dir, batch, hidden
            lstm_output = hid.squeeze(1)  # remove batch dimension
            lstm_output = torch.flatten(lstm_output)  # hid = layers * hidden_size

        if self.use_handcraft == 1:  # concat_features = torch.cat((lstm_output, feat), dim=1)
            if mode == 'batch':
                extract_states = torch.cat((lstm_output, feat), dim=1)  # ==>torch.size[256 + 5]
            else:
                extract_states = torch.cat((lstm_output, feat), dim=0)
        else:
            extract_states = lstm_output
        return extract_states, lstm_output

class GlucoseModel(nn.Module):
    def __init__(self, args, device):
        super(GlucoseModel, self).__init__()
        self.n_features = args.n_features
        self.device = device
        self.n_handcrafted_features = args.n_handcrafted_features
        self.use_handcraft = args.use_handcraft
        self.output = args.n_action
        self.n_hidden = args.n_hidden
        self.n_layers = args.n_rnn_layers
        self.bidirectional = args.bidirectional
        self.directions = args.rnn_directions
        # self.feature_extractor = self.n_hidden * self.n_layers * self.directions + \
        #                          (self.n_handcrafted_features * self.use_handcraft)
        self.feature_extractor = self.n_hidden * self.n_layers * self.directions
        self.last_hidden = self.feature_extractor #* 2
        self.fc_layer1 = nn.Linear(self.feature_extractor + self.output, self.last_hidden)
        # self.fc_layer2 = nn.Linear(self.last_hidden, self.last_hidden)
        # self.fc_layer3 = nn.Linear(self.last_hidden, self.last_hidden)
        self.cgm_mu = NormedLinear(self.last_hidden, self.output, scale=0.1)
        self.cgm_sigma = NormedLinear(self.last_hidden, self.output, scale=0.1)
        self.normal = torch.distributions.Normal(0, 1)

    def forward(self, extract_state, action, mode):
        concat_dim = 1 if (mode == 'batch') else 0
        concat_state_action = torch.cat((extract_state, action), dim=concat_dim)
        fc_output1 = F.relu(self.fc_layer1(concat_state_action))
        fc_output = fc_output1
        # fc_output2 = F.relu(self.fc_layer2(fc_output1))
        # fc_output = F.relu(self.fc_layer3(fc_output2))
        cgm_mu = F.tanh(self.cgm_mu(fc_output))
        # deterministic
        # cgm_sigma = torch.zeros(1, device=self.device, dtype=torch.float32)
        # cgm = cgm_mu
        # probabilistic
        cgm_sigma = F.softplus(self.cgm_sigma(fc_output) + 1e-5)
        z = self.normal.sample()
        cgm = cgm_mu + cgm_sigma * z
        cgm = torch.clamp(cgm, -1, 1)
        return cgm_mu, cgm_sigma, cgm

class ActionModule(nn.Module):
    def __init__(self, args, device):
        super(ActionModule, self).__init__()
        self.device = device
        self.args = args
        self.n_handcrafted_features = args.n_handcrafted_features
        self.use_handcraft = args.use_handcraft
        self.output = args.n_action
        self.n_hidden = args.n_hidden
        self.n_layers = args.n_rnn_layers
        self.directions = args.rnn_directions
        self.feature_extractor = self.n_hidden * self.n_layers * self.directions + \
                                 (self.n_handcrafted_features * self.use_handcraft)
        self.last_hidden = self.feature_extractor * 2
        self.fc_layer1 = nn.Linear(self.feature_extractor, self.last_hidden)
        self.fc_layer2 = nn.Linear(self.last_hidden, self.last_hidden)
        self.fc_layer3 = nn.Linear(self.last_hidden, self.last_hidden)
        self.mu = NormedLinear(self.last_hidden, self.output, scale=0.1)
        self.sigma = NormedLinear(self.last_hidden, self.output, scale=0.1)
        self.normalDistribution = torch.distributions.Normal

    def forward(self, extract_states, action_type='N'):
        fc_output1 = F.relu(self.fc_layer1(extract_states))
        fc_output2 = F.relu(self.fc_layer2(fc_output1))
        fc_output = F.relu(self.fc_layer3(fc_output2))
        mu = F.tanh(self.mu(fc_output))
        sigma = F.sigmoid(self.sigma(fc_output) + 1e-5)
        z = self.normalDistribution(0, 1).sample()
        action = mu + sigma * z
        action = torch.clamp(action, -1, 1)
        try:
            dst = self.normalDistribution(mu, sigma)
            log_prob = dst.log_prob(action[0])
        except ValueError:
            print('\nCurrent mu: {}, sigma: {}'.format(mu, sigma))
            print('shape: {}. {}'.format(mu.shape, sigma.shape))
            print(extract_states.shape)
            print(extract_states)
            log_prob = torch.ones(2, 1, device=self.device, dtype=torch.float32) * self.glucose_target
        # log_prob = dst.log_prob(action[0])
        # sigma = torch.ones(1, device=self.device, dtype=torch.float32) * 0.01
        # clamp the sigma
        # sigma = F.softplus(self.sigma(fc_output) + 1e-5)
        # sigma = torch.clamp(sigma, 1e-5, 0.33)
        return mu, sigma, action, log_prob

class ValueModule(nn.Module):
    def __init__(self, args, device):
        super(ValueModule, self).__init__()
        self.device = device
        self.output = args.n_action
        self.n_handcrafted_features = args.n_handcrafted_features
        self.use_handcraft = args.use_handcraft
        self.n_hidden = args.n_hidden
        self.n_layers = args.n_rnn_layers
        self.directions = args.rnn_directions
        self.feature_extractor = self.n_hidden * self.n_layers * self.directions + \
                                 (self.n_handcrafted_features * self.use_handcraft)
        self.last_hidden = self.feature_extractor * 2
        self.fc_layer1 = nn.Linear(self.feature_extractor, self.last_hidden)
        self.fc_layer2 = nn.Linear(self.last_hidden, self.last_hidden)
        self.fc_layer3 = nn.Linear(self.last_hidden, self.last_hidden)
        self.value = NormedLinear(self.last_hidden, self.output, scale=0.1)

    def forward(self, extract_states):
        fc_output1 = F.relu(self.fc_layer1(extract_states))
        fc_output2 = F.relu(self.fc_layer2(fc_output1))
        fc_output = F.relu(self.fc_layer3(fc_output2))
        value = (self.value(fc_output))
        return value

class ActorNetwork(nn.Module):
    def __init__(self, args, device):
        super(ActorNetwork, self).__init__()
        self.device = device
        self.args = args
        self.FeatureExtractor = FeatureExtractor(args)
        self.GlucoseModel = GlucoseModel(args, self.device)
        self.ActionModule = ActionModule(args, self.device)
        self.distribution = torch.distributions.Normal
        self.planning_n_step = args.planning_n_step
        self.n_planning_simulations = args.n_planning_simulations
        self.glucose_target = core.linear_scaling(x=112.5, x_min=self.args.glucose_min, x_max=self.args.glucose_max)
        self.t_to_meal = core.linear_scaling(x=0, x_min=0, x_max=self.args.t_meal)

    def forward(self, s, feat, old_action, mode, is_training=False):
        extract_states, lstmOut = self.FeatureExtractor.forward(s, feat, mode)
        mu, sigma, action, log_prob = self.ActionModule.forward(extract_states)
        if mode == 'forward':
            cgm_mu, cgm_sigma, cgm = self.GlucoseModel.forward(lstmOut, action.detach(), mode)
        else:
            cgm_mu, cgm_sigma, cgm = self.GlucoseModel.forward(lstmOut, old_action.detach(), mode)
        return mu, sigma, action, log_prob, cgm_mu, cgm_sigma, cgm

    def update_state(self, s, cgm_pred, action, batch_size):
        if batch_size == 1:
            if self.args.n_features == 2:
                s_new = torch.cat((cgm_pred, action), dim=0)
            if self.args.n_features == 3:
                s_new = torch.cat((cgm_pred, action, self.t_to_meal * torch.ones(1, device=self.device)), dim=0)
            s_new = s_new.unsqueeze(0)
            s = torch.cat((s[1:self.args.feature_history, :], s_new), dim=0)
        else:
            if self.args.n_features == 3:
                s_new = torch.cat((cgm_pred, action, self.t_to_meal * torch.ones(batch_size, 1, device=self.device)), dim=1)
            if self.args.n_features == 2:
                s_new = torch.cat((cgm_pred, action), dim=1)
            s_new = s_new.unsqueeze(1)
            s = torch.cat((s[:, 1:self.args.feature_history, :], s_new), dim=1)
        return s

    def expert_search(self, s, feat, rew_norm_var, mode):
        pi, mu, sigma, s_e, f_e, r = self.expert_MCTS_rollout(s, feat, mode, rew_norm_var)
        return pi, mu, sigma, s_e, f_e, r

    def expert_MCTS_rollout(self, s, feat, mode, rew_norm_var=1):
        batch_size = s.shape[0]
        first_action, first_mu, first_sigma, cum_reward, mu, sigma = 0, 0, 0, 0, 0, 0
        for i in range(self.planning_n_step):
            extract_states, lstmOut = self.FeatureExtractor.forward(s, feat, mode) #.detach()# todo: fix handcraft features
            extract_states, lstmOut = extract_states.detach(), lstmOut.detach()
            mu, sigma, action, log_prob = self.ActionModule.forward(extract_states)
            if i == 0:
                first_action = action
                first_mu = mu
                first_sigma = sigma
            _, _, cgm_pred = self.GlucoseModel.forward(lstmOut, action, mode)
            bg = core.inverse_linear_scaling(y=cgm_pred.detach().cpu().numpy(), x_min=self.args.glucose_min, x_max=self.args.glucose_max)
            reward = np.array([[composite_reward(self.args, state=xi, reward=None)] for xi in bg])
            reward = reward / (math.sqrt(rew_norm_var + 1e-8))
            reward = np.clip(reward, 10, 10)
            discount = (self.args.gamma ** i)
            cum_reward += (reward * discount)

            # todo: fix - this is a hardcoded to pump action exponential!!!
            action = action.detach()
            cgm_pred = cgm_pred.detach()
            pump_action = self.args.action_scale * (torch.exp((action - 1) * 4))
            action = core.linear_scaling(x=pump_action, x_min=self.args.insulin_min, x_max=self.args.insulin_max)
            ### #todo

            s = self.update_state(s, cgm_pred, action, batch_size)
            feat[0] += 1  #todo: quick fix for integrating the 'n', wont work other handcraft feat
        cum_reward = torch.as_tensor(cum_reward, dtype=torch.float32, device=self.device)
        return first_action, first_mu, first_sigma, s, feat, cum_reward

    def horizon_error(self, s, feat, actions, real_glucose, mode):
        horizon_error = 0
        s = torch.as_tensor(s, dtype=torch.float32, device=self.device)
        feat = torch.as_tensor(feat, dtype=torch.float32, device=self.device)
        for i in range(0, len(actions)):
            cur_action = torch.as_tensor(actions[i], dtype=torch.float32, device=self.device).reshape(1)
            extract_states, lstmOut = self.FeatureExtractor.forward(s, feat, mode) #.detach()
            extract_states, lstmOut = extract_states.detach(), lstmOut.detach()

            cgm_mu, cgm_sigma, cgm_pred = self.GlucoseModel.forward(lstmOut, cur_action, mode)
            pred = core.inverse_linear_scaling(y=cgm_pred.detach().cpu().numpy(), x_min=self.args.glucose_min,
                                               x_max=self.args.glucose_max)
            horizon_error += ((pred - real_glucose[i])**2)
            s = self.update_state(s, cgm_pred, cur_action, batch_size=1)
        return horizon_error / len(actions)

class CriticNetwork(nn.Module):
    def __init__(self, args, device):
        super(CriticNetwork, self).__init__()
        self.FeatureExtractor = FeatureExtractor(args)
        self.ValueModule = ValueModule(args, device)
        self.aux_mode = args.aux_mode
        self.GlucoseModel = GlucoseModel(args, device)
    def forward(self, s, feat, action, cgm_pred=True, mode='forward'):
        extract_states, lstmOut = self.FeatureExtractor.forward(s, feat, mode)
        value = self.ValueModule.forward(extract_states)
        cgm_mu, cgm_sigma, cgm = self.GlucoseModel.forward(lstmOut, action.detach(), mode) if cgm_pred else (None, None, None)
        return value, cgm_mu, cgm_sigma, cgm

class ActorCritic(nn.Module):
    def __init__(self, args, load, actor_path, critic_path, device):
        super(ActorCritic, self).__init__()
        self.device = device
        self.experiment_dir = args.experiment_dir
        self.Actor = ActorNetwork(args, device)
        self.Critic = CriticNetwork(args, device)
        if load:
            self.Actor = torch.load(actor_path, map_location=device)
            self.Critic = torch.load(critic_path, map_location=device)
        self.distribution = torch.distributions.Normal
        self.is_testing_worker = False

    def predict(self, s, feat):
        s = torch.as_tensor(s, dtype=torch.float32, device=self.device)
        feat = torch.as_tensor(feat, dtype=torch.float32, device=self.device)
        mean, std, action, log_prob, a_cgm_mu, a_cgm_sigma, a_cgm = self.Actor(s, feat, None, mode='forward',
                                                                               is_training=self.is_testing_worker)
        state_value, c_cgm_mu,  c_cgm_sigma, c_cgm = self.Critic(s, feat, action, cgm_pred=True, mode='forward' )
        return (mean, std, action, log_prob, a_cgm_mu, a_cgm_sigma, a_cgm), (state_value, c_cgm_mu,  c_cgm_sigma, c_cgm)

    def get_action(self, s, feat):
        (mu, std, act, log_prob, a_cgm_mu, a_cgm_sig, a_cgm), (s_val, c_cgm_mu, c_cgm_sig, c_cgm) = self.predict(s, feat)
        data = dict(mu=mu, std=std, action=act, log_prob=log_prob, state_value=s_val, a_cgm_mu=a_cgm_mu,
                    a_cgm_sigma=a_cgm_sig, c_cgm_mu=c_cgm_mu, c_cgm_sigma=c_cgm_sig, a_cgm=a_cgm, c_cgm=c_cgm)
        return {k: v.detach().cpu().numpy() for k, v in data.items()}

    def get_final_value(self, s, feat):
        s = torch.as_tensor(s, dtype=torch.float32, device=self.device)
        feat = torch.as_tensor(feat, dtype=torch.float32, device=self.device)
        state_value, _,  _, _ = self.Critic(s, feat, action=None, cgm_pred=False, mode='forward' )
        return state_value.detach().cpu().numpy()

    def evaluate_actor(self, state, action, feat):  # evaluate batch
        action_mean, action_std, _, _, a_cgm_mu, a_cgm_sigma, _ = self.Actor(state, feat, action, mode='batch')
        dist = self.distribution(action_mean, action_std)
        action_logprobs = dist.log_prob(action)
        dist_entropy = dist.entropy()
        return action_logprobs, dist_entropy, a_cgm_mu, a_cgm_sigma

    def evaluate_critic(self, state, feat, action, cgm_pred):  # evaluate batch
        state_value, c_cgm_mu,  c_cgm_sigma, _ = self.Critic(state, feat, action, cgm_pred, mode='batch')
        return torch.squeeze(state_value), c_cgm_mu,  c_cgm_sigma

    def save(self, episode):
        actor_path = self.experiment_dir + '/checkpoints/episode_' + str(episode) + '_Actor.pth'
        critic_path = self.experiment_dir + '/checkpoints/episode_' + str(episode) + '_Critic.pth'
        torch.save(self.Actor, actor_path)
        torch.save(self.Critic, critic_path)

def NormedLinear(*args, scale=1.0):
    out = nn.Linear(*args)
    out.weight.data *= scale / out.weight.norm(dim=1, p=2, keepdim=True)
    return out


from flask import Blueprint,render_template, url_for,request, current_app, session
#import jinja2
# from code import InteractiveConsole
import subprocess

terminal=Blueprint("terminal",__name__,static_folder="static",template_folder="templates")
#my_loader=jinja2.ChoiceLoader([terminal.jinja_loader,jinja2.FileSystemLoader

# load an interactive console and a call stack
# note: this is currently not attached to user context but shared over global context
# interactive_terminal=InteractiveConsole()
call_stack=[]
out_stack=[""]

@terminal.route("/",methods=["GET","POST"])
@terminal.route("/home",methods=["GET","POST"])
def index():
    """Allows to execute terminal commands on the RPi

    Returns:
        rendered html: Containing Output of Terminal STDOut
    """
    global out_stack
    global call_stack
    if request.method=="POST":
        call_stack.append(str(request.form["terminal_input"]))
        # with Capturing(out_stack) as out_stack:
        #     interactive_terminal.runcode(str(request.form["terminal_input"]))
        try:
            out_stack.append(subprocess.getoutput(str(request.form["terminal_input"])))
        except Exception as e:
            out_stack.append(f"Error {e} occured in subprocess call")

    print(out_stack)

    return render_template("terminal.html",title="Terminal",terminal_output=out_stack[-1],bg_img_path=url_for('terminal.static',filename="backgroundimg.png"))

# class for capturing print statement
# from io import StringIO
# import sys
# class Capturing(list):
#     def __enter__(self):
#         self._stdout = sys.stdout
#         self._sterr = sys.stderr
#         sys.stderr = sys.stdout = self._stringio = StringIO()
#         return self
#     def __exit__(self, *args):
#         if not self._stringio.getvalue().splitlines():
#             self.extend(["Your input required no answer"])
#         else:
#             self.extend(self._stringio.getvalue().splitlines())
#         del self._stringio
#         sys.stdout = self._stdout
#         sys.stderr = self._sterr


#!/usr/bin/env python
import tf.transformations as tf
import numpy as np
import rospy
import threading
from nav_msgs.msg import Odometry
from geometry_msgs.msg import PoseWithCovarianceStamped, Vector3, Pose

class ringTranslator():
    def __init__(self):
        rospy.init_node("ring_translator")

        self.pose_sub = rospy.Subscriber("/ground_truth/state", Odometry,
                                         self.simCallback, queue_size=1)

        self.rob_sub = rospy.Subscriber("robot_pos_ls", Pose, self.rob_callback, queue_size=1)

        self.ring_sub = rospy.Subscriber("ring_pos",
                                         Pose,
                                         self.pos_callback,
                                         queue_size=1)

        self.ring_pub = rospy.Publisher("ringWorld",
                                         Pose,
                                         queue_size=1)

        self.euler = np.zeros(3)
        self.pos = np.zeros(3)
        self.ring_abs = np.zeros(3)
        self.ring_rel = np.zeros(3)

    def simCallback(self, msg):
        orient = msg.pose.pose.orientation
        quat = np.array([orient.x, orient.y, orient.z, orient.w])
        self.euler = tf.euler_from_quaternion(quat, axes='sxyz')

    def rob_callback(self, msg):
        pos = msg.position
        self.pos = np.array([pos.x, pos.y, pos.z])

    def pos_callback(self, msg):
        pos = msg.position
        self.ring_rel = np.array([-pos.x, pos.y, -pos.z])-\
                        np.array([0.0, -0.1, -0.1])
        self.transform()

    def transform(self):
        # R = tf.euler_matrix(-self.euler[0], -self.euler[1], -self.euler[2], 'sxyz')
        # print(self.euler)
        yaw = -(self.euler[2]-np.pi/2)
        R = np.array([[np.cos(yaw), -np.sin(yaw), 0],
                      [np.sin(yaw),  np.cos(yaw), 0],
                      [0, 0, 1]])
        ring_rel_tank = np.matmul(R, self.ring_rel)
        self.ring_abs = ring_rel_tank + self.pos #- \
           # np.array([0.2, -0.25, 0.2])
        # print(self.ring_abs)
        # print(ring_rel_tank, self.ring_rel)
        self.publish()

    def publish(self):
        msg = Pose()
        msg.position.x = self.ring_abs[0]
        msg.position.y = self.ring_abs[1]
        msg.position.z = self.ring_abs[2]
        self.ring_pub.publish(msg)

    def run(self):
        rospy.spin()

def main():
    node = ringTranslator()
    node.run()

if __name__ == '__main__':
    main()


#! /usr/bin/env python3

import rospy
import numpy as np
from nav_msgs.msg import OccupancyGrid
import math
from tf.transformations import quaternion_from_euler

def load_param(name, value=None):
    if value is None:
        assert rospy.has_param(name), f'Missing parameter "{name}"'
    return rospy.get_param(name, value)

class GridMapInterface(object):
    _gridmap_msg = None
    _gridmap_sub = None
    _map_topic = None
    _gridmap = None

    def __init__(self):
        self._map_topic = load_param('~map_topic', '/map')

    def init_ros_subscribers(self):
        self._gridmap_sub = rospy.Subscriber(self._map_topic, OccupancyGrid, self._gridmap_cb, queue_size=1)

    def _gridmap_cb(self, msg):
        self._gridmap_msg = OccupancyGrid(msg.header, msg.info, msg.data)

    def _get_delta(self):
        if self._gridmap_msg  is not None:
            return [self._gridmap_msg.info.resolution, self._gridmap_msg.info.resolution]

    def _get_limits(self):
        if self._gridmap_msg is not None:
            return [[0, self._gridmap_msg.info.width * self._gridmap_msg.info.resolution], [0, self._gridmap_msg.info.height * self._gridmap_msg.info.resolution]]

    def _get_obstacles(self):
        if self._gridmap_msg  is not None:
            gridmap = np.array(self._gridmap_msg.data).reshape((self._gridmap_msg.info.height, self._gridmap_msg.info.width)).T * 0.01
            # Cell values are changed to -0.01 (unknown), 0 (free), 1 (obstacle)
            obstacles = []
            for (x, y), cell in np.ndenumerate(gridmap):
                #!! Strong assumption: unknown cells are considered as obstacles
                if cell < 0 or cell == 1:
                    obstacles.append([x, y, self._gridmap_msg.info.resolution])
            return obstacles

    def get_planner_world(self):
        while self._gridmap_msg is None:
            continue
        return self._get_delta(), self._get_limits(), self._get_obstacles()

    def publish_map_internal_representation(self):
        obstacles = []
        delta, limits, obs = self.get_planner_world()

        rows_int = int(np.round(limits[0][1] / delta[0]))
        cols_int = int(np.round(limits[1][1] / delta[1]))
        data = np.zeros(rows_int * cols_int).reshape(rows_int, cols_int)
        [obstacles.append(tup[0:2]) for tup in obs]
        obs_np = np.asarray(obstacles)
        data[obs_np[:, 0], obs_np[:, 1]] = 100

        map_pub = rospy.Publisher('/map_from_grid', OccupancyGrid, latch=True, queue_size=1)
        map_msg = OccupancyGrid()
        map_msg.data = [item for sublist in np.array(data, dtype=int).tolist() for item in sublist]
        map_msg.header.frame_id = 'map'
        map_msg.header.stamp = rospy.Time.now()
        map_msg.info.resolution = delta[1]
        map_msg.info.width = cols_int
        map_msg.info.height = rows_int
        quat = quaternion_from_euler(0, math.pi , -math.pi / 2)
        map_msg.info.origin.orientation.x = quat[0]
        map_msg.info.origin.orientation.y = quat[1]
        map_msg.info.origin.orientation.z = quat[2]
        map_msg.info.origin.orientation.w = quat[3]

        print('Publishing map...')
        map_pub.publish(map_msg)


import requests, json
from tkinter import *
from datetime import datetime
from pygame import mixer

def internet_on():
    try:
        requests.get('http://216.58.192.142', timeout=5)
        return True
    except requests.ConnectionError:
        return False

#import winsound
#winsound.PlaySound("SystemExit", winsound.SND_ALIAS)

def select_place(user, coach, coaches):
    print(coach)
    key = ""
    for value in coach['value']['places']:
        key = value
        break
    places = {0: {
        'ord': 0,
        'charline': "А",
        'wagon_num': coaches["coaches"][0]["num"],
        'wagon_class': coaches["coaches"][0]["coach_class"],
        'wagon_type': coaches["coaches"][0]["type"],
        'firstname': user.f_name,
        'lastname': user.l_name,
        'child': "",
        'stud': "",
        'bedding': 0,
        'place_num': coach['value']['places'][key][0]
    }}
    coach = {
        'from': user.st_from_id,
        'to': user.st_till_id,
        'train': user.my_train['num'],
        'date': user.dep_date.strftime('%Y-%m-%d'),
        'round_trip': 0,
        'places': places
    }
    r = requests.post('http://booking.uz.gov.ua/cart/add/', data=coach)
    print(r.status_code)
    print(r.text)
    print(requests.utils.dict_from_cookiejar(r.cookies))

def find_coach(user, coaches):
    data = {
        'station_id_from': user.st_from_id,
        'station_id_till': user.st_till_id,
        'train': user.my_train['num'],
        'coach_num': coaches['coaches'][0]['num'],
        'coach_class': coaches['coaches'][0]["coach_class"],
        'coach_type_id': coaches['coaches'][0]["coach_type_id"],
        'date_dep': user.my_train['from']['date'],
        'scheme_id': 0
    }
    r = requests.post('http://booking.uz.gov.ua/purchase/coach/', data=data)
    print(r.status_code)
    select_place(user, json.loads(r.text), coaches)

def find_coaches(user):
    data = {
        'station_id_from' : user.st_from_id,
        'station_id_till' : user.st_till_id,
        'train' : user.my_train['num'],
        'coach_type' : user.place_type,
        'model': user.my_train['model'],
        'date_dep': user.my_train['from']['date'],
        'round_trip': 0,
        'another_ec': 0
    }
    r = requests.post('http://booking.uz.gov.ua/purchase/coaches/', data=data)
    print(r.status_code)
    find_coach(user, json.loads(r.text))

def compare_place_type(all_trains_val, search_place, user):
    if search_place:
        for element in all_trains_val:
            for types in element['types']:
                if types['id'] == search_place and element['num'] == '063О':
                    print(types)
                    user.my_train = element
                    return True
    else:
        print(all_trains_val)
        return True
    return False

def find_place(user, all_trains):
    print("Шукаю " + user.place_type + " Осання перевірка - " + datetime.now().strftime("%H:%M:%S"))
    print(all_trains)
    if isinstance(all_trains['value'], str):
        print(all_trains['value'])
        return True
    else:
        if compare_place_type(all_trains['value'], user.place_type, user):
            mixer.init()
            mixer.music.load('vopli_vidopljasova_-_strivaj__parovoze_bonus_(zvukoff.ru).mp3')
            mixer.music.play()
            if user.f_name and user.l_name:
                find_coaches(user)
            return False
        else:
            return True

def get_all_places(user):
    print("=============Шукаю вльні місця============")
    data = {
        'station_id_from': user.st_from_id,
        'station_id_till': user.st_till_id,
        'station_from': user.st_from,
        'station_till': user.st_till,
        'date_dep': user.dep_date.strftime('%d.%m.%Y'),
        'time_dep': user.dep_date.strftime('%H:%M'),
        'time_dep_till': '',
        'another_ec': '',
        'search': ''
    }
    r = requests.post('http://booking.uz.gov.ua/purchase/search/', data=data)
    print(r.status_code)
    return find_place(user, json.loads(r.text))

def get_station_id(name):
    r = requests.get('http://booking.uz.gov.ua/purchase/station/', params={'term': name})
    print(r.status_code)
    print(r.text)
    obj = json.loads(r.text)
    print(obj[0]['value'])
    return obj[0]['value']

def try_find_ticket(my_fild):
    if my_fild.simple_not_empty() == False:
        print("Заповніть пусті рядки")
        return False
    else:
        user = Pasenger(my_fild.station_from.get(), my_fild.station_till.get(), my_fild.dep_date.get(),
                        my_fild.place_type.get())
        user.f_name = my_fild.first_name.get()
        user.l_name = my_fild.last_name.get()
        if get_all_places(user):
            root.after(int(60000 * float(my_fild.r_time.get())), try_find_ticket, my_fild)

class EntryFild:
    def __init__(self):
        self.label = Label(root, text="New Label", font="Arial 48", bg="green")
        self.label.place(relx=0.5, rely=0.5, anchor="center")
        self.r_time = Entry(root, width="5")
        self.r_time.insert(END, 2)
        self.r_time.pack()
        self.station_from = Entry(root, width="40")
        self.station_from.insert(END, "Тернопіль")
        self.station_from.pack()
        self.station_till = Entry(root, width="40")
        self.station_till.insert(END, "Київ")
        self.station_till.pack()
        self.dep_date = Entry(root, width="15")
        self.dep_date.insert(END, datetime.now().strftime("%d.%m.%Y %H:%M"))
        self.dep_date.pack()
        self.place_type = Entry(root, width="5")
        self.place_type.insert(END, "П")
        self.place_type.pack()
        self.first_name = Entry(root, width="40")
        self.first_name.pack()
        self.last_name = Entry(root, width="40")
        self.last_name.pack()
    def simple_not_empty(self):
        if self.station_from.get() and self.station_till.get() and self.dep_date.get():
            return True
        else:
            return False

class FindButton:
    def __init__(self):
        self.but = Button(root)
        self.but['text'] = "Шукати"
        self.but.pack()
        self.but.bind("<Button-1>", self.action_find)
        self.but.bind('<Return>', self.action_find)
    def action_find(self, event):
        try_find_ticket(my_fild)

class Pasenger :
    def __init__(self, st_from, st_till, dep_date, place_type):
        self.st_from_id = get_station_id(st_from)
        self.st_from = st_from
        self.st_till_id = get_station_id(st_till)
        self.st_till = st_till
        self.dep_date = datetime.strptime(dep_date, '%d.%m.%Y %H:%M')
        self.place_type = place_type
        self.f_name = ""
        self.l_name = ""
        self.my_train = {}

s = requests.Session()

root = Tk()
my_fild = EntryFild()
if internet_on():
    my_button = FindButton()
else:
    print('"Інернет си скінчив))"')
root.mainloop()


#!/usr/bin/python2
# -*- coding: utf-8 -*-
import xlrd
import sys
import os
import re
reload(sys)
sys.setdefaultencoding('utf8')

#region FIELDS
ROOT_DIR = os.getcwd()
LUAOUT_DIR = os.path.join(ROOT_DIR,"Test")
EXCEL_DIR = os.path.join(ROOT_DIR,"xlsx_origin")
FILETYPE = ".xlsx"
LUAFILETYPE = ".lua"
TBASE = {"int":True, "string":True, "float":True}
TBASESWITCH = {
    "int": lambda ds,f,v: save_int_value(ds,f,v),
    "float": lambda ds,f,v: save_float_value(ds,f,v),
    "string": lambda ds,f,v: save_string_vale(ds,f,v),
}
TBASESAPPENDWITCH = {
    "int": lambda ds,f,v: append_int_value(ds,f,v),
    "float": lambda ds,f,v: append_float_value(ds,f,v),
    "string": lambda ds,f,v: append_string_vale(ds,f,v),
}
#endregion

#out lua path
lua_path = "LuaOutPath"
#region COMMON

def value_is_none(value):
    return value == ''

def get_int_value(v):
    return 0 if value_is_none(v) else int(v)

def get_float_value(v):
    return 0.0 if value_is_none(v) else float(v)

def get_string_value(v):
    return '' if value_is_none(v) else str(v)

TBASESGETWITCH = {
    "int": get_int_value,
    "float": get_float_value,
    "string": get_string_value,
}
def save_int_value(ds,f,v):
    ds[f] = get_int_value(v)

def save_float_value(ds,f,v):
    ds[f] = get_float_value(v)

def save_string_vale(ds,f,v):
    ds[f] = get_string_value(v)

def append_int_value(ds,f,v):
    ds.append(get_int_value(v))

def append_float_value(ds,f,v):
    ds.append(get_float_value(v))

def append_string_vale(ds,f,v):
    ds.append(get_string_value(v))

def save_list_vale(ds,f,v,tp):
    data = []
    ds[f] = data
    #处理只填了一个值
    if type(v) == int or type(v) == float:
        TBASESAPPENDWITCH[tp](data,0,v)
    else:
        sl = v.split(';')
        for i, v in enumerate(sl):
            TBASESAPPENDWITCH[tp](data,i,v)

def save_dictionary_vale(ds,f,v,tp1,tp2,dm):
    data = {}
    ds[f] = data
    sdi = v.split(';')
    for i, di in enumerate(sdi):
        if not value_is_none(di):
            skv = di.split(',')
            if len(skv) != 2:raise Exception("Error Dictionary ")
            dkey = TBASESGETWITCH[tp1](skv[0])
            TBASESWITCH[tp2](data,dkey,skv[1])
#endregion

#region FUNCTIONS
def check_types(record,types):
    col_idx = 0
    for value in record:
        if col_idx > 0:
            if not value: raise Exception("第 %d 列没填类型"%(col_idx))
            if col_idx == 1 and value != 'int': raise Exception("first type isnot int")
            elif value in TBASE:
                types.append(str(value.strip()))
            elif value.find('List') != -1:
                tb = re.findall(re.compile(r"<(.*?)>",re.S),value)
                if tb[0] in TBASE:
                    types.append(str(value.strip()))
                else:
                    raise Exception("暂不支持该类型List:%s"%(str(value)))
            elif value.find('Dictionary') != -1:
                tb = re.findall(re.compile(r"<(.*?),(.*?)>",re.S),value)
                for tp in tb[0]:
                    if not tp in TBASE:
                        raise Exception("暂不支持该类型Dictionary:%s"%(str(value)))
                types.append(str(value.strip()))
            else:
                raise Exception("暂不支持该类型:%s"%(str(value)))
        col_idx += 1

def check_fields(record,types,fields):
    col_idx = 0
    for value in record:
        if col_idx > 0:
            if value_is_none(value): raise Exception("第 %d 列字段名为空"%(col_idx))
            if col_idx == 1 and value != 'Id': raise Exception("first Key not Id")
            if value in fields:
                raise Exception("重复的字段名:%s"%(str(value.strip())))
            fields.append(str(value.strip()))
        col_idx += 1

def make_data(record,types,fields,datas):
    data = {}
    if record[1] == '': return
    datas[int(record[1])] = data
    for i, tp in enumerate(types):
        if not tp: continue
        if tp in TBASE:
            TBASESWITCH[tp](data,fields[i],record[i + 1])
        elif tp.find('List') != -1:
            tb = re.findall(re.compile(r"<(.*?)>",re.S),tp)
            save_list_vale(data,fields[i],record[i + 1],tb[0])
        elif tp.find('Dictionary') != -1:
            tb = re.findall(re.compile(r"<(.*?),(.*?)>",re.S),tp)
            save_dictionary_vale(data,fields[i],record[i + 1],tb[0][0],tb[0][1],datas)
        else:
            raise Exception("暂不支持该类型:%s"%(tp))

def make_defalue_value(datas,defalut_values,fields):
    value_refs = {}
    for id,data in datas.items():
        for key,value in data.items():
            if not key in value_refs:
                value_refs[key] = {}
            value2str = str(value)
            if not value2str in value_refs[key]:
                value_refs[key][value2str] = {}
                value_refs[key][value2str]['cnt'] = 1
                value_refs[key][value2str]['value'] = value
            else:
                value_refs[key][value2str]['cnt'] += 1
    for key,vl in value_refs.items():
        if not key in defalut_values:
            defalut_values[key] = {}
            defalut_values[key]['cnt'] = 0
        for _,vi in vl.items():
            curr_cnt = defalut_values[key]['cnt']
            if curr_cnt < vi['cnt']:
                defalut_values[key]['value'] = vi['value']
                defalut_values[key]['cnt'] = vi['cnt']

def handle_one_file(dirname, filename):
    basename = filename.replace(FILETYPE,"")
    rpath = os.path.join(dirname,filename)

    print("process>>>>>>>>>    " + basename)
    excel = xlrd.open_workbook(rpath)
    tables = excel.sheets()

    if len(tables) == 0:
        raise Exception("file is empty" + basename)

    for table in tables:
        rows = table.nrows
        if rows < 4:
            raise Exception(basename + "    content error")
        types,fields = [],[]
        datas,defalut_values = {},{}
        #跳过服务器表
        if table.cell(0, 2).value == "server":
            print("break server cfg >",filename)
            return
        for row_idx in range(rows):
            record = table.row_values(row_idx)
            if row_idx == 1:
                check_types(record,types)
            if row_idx == 2:
                check_fields(record,types,fields)
            if row_idx >3:
                make_data(record,types,fields,datas)
        make_defalue_value(datas,defalut_values,fields)
        #TODO 只读第一个table
        break

    gen_lua_file(basename,datas,fields,defalut_values)

def gen_lua_file(baseName,datas,fields,default_value):
    if not os.path.isdir(LUAOUT_DIR):
        os.makedirs(LUAOUT_DIR)

    outfilepath = os.path.join(LUAOUT_DIR,baseName + LUAFILETYPE)
    outfp = open(outfilepath, "w")
    outfp.write('local keys = {')
    for idx,keyn in enumerate(fields):
        outfp.write('%s = %d,'%(keyn,idx + 1))
    outfp.write('}\n')
    outfp.write('local d = \"__default_value__\"\n')
    outfp.write('local data = { \n')
    for key,value in datas.items():
        outfp.write('\t[%d] = {'%(key))
        for idx,keyn in enumerate(fields):
            dlv = value[keyn]
            if dlv == default_value[keyn]['value']:
                outfp.write('d,')
            else:
                if type(dlv) == int:
                    outfp.write('%d,'%(dlv))
                elif type(dlv) == float:
                    outfp.write('%f,'%(dlv))
                elif type(dlv) == str:
                    outfp.write('\"%s\",'%(dlv))
                elif type(dlv) == list:
                    outfp.write('{')
                    for idx,lv in enumerate(dlv):
                        if type(lv) == str:
                            outfp.write('\"%s\",'%(str(lv)))
                        else:
                            outfp.write('%s,'%(str(lv)))
                    outfp.write('},')
                elif type(dlv) == dict:
                    outfp.write('{')
                    for dk,dv in dlv.items():
                        if type(dv) == str:
                            outfp.write('[\"%s\"] = '%(dk) + "\"" + str(dv) + '\",')
                        else:
                            outfp.write('[\"%s\"] = '%(dk) + str(dv) + ',')
                    outfp.write('},')
        outfp.write('},\n')

    outfp.write('}\n')
    outfp.write('local default_value = {\n')
    for k,v in default_value.items():
        outfp.write('\t%s = '%(k))
        dv = v['value']
        if type(dv) == int:
            outfp.write('%d,\n'%(dv))
        elif type(dv) == float:
            outfp.write('%f,\n'%(dv))
        elif type(dv) == str:
            outfp.write('\"%s\",\n'%(dv))
        elif type(dv) == list:
            outfp.write('{')
            for idx,lv in enumerate(dv):
                if type(lv) == str:
                    outfp.write('\"%s\",'%(str(lv)))
                else:
                    outfp.write('%s,'%(str(lv)))
            outfp.write('},\n')
        elif type(dv) == dict:
            outfp.write('{')
            for dk,dv in dv.items():
                if type(dv) == str:
                    outfp.write('[\"%s\"] = '%(dk) + "\"" + str(dv) + '\",')
                else:
                    outfp.write('[\"%s\"] = '%(dk) + str(dv) + ',')
            outfp.write('},\n')
    outfp.write('}\n')

    outfp.write('local mt = {}\n')
    outfp.write('mt.__index = function(t,k)\n')
    outfp.write('\t local key = keys[k]\n')
    outfp.write('\t local value = rawget(t,key)\n')
    outfp.write('\tif value == d then return default_value[k] end\n')
    outfp.write('\treturn value')
    outfp.write('\nend')

    outfp.write('\nmt.__newindex = function(t,k)')
    outfp.write('\t error( \' do not edit config \') end')

    outfp.write('\nmt.metatable = false')

    outfp.write('\nfor _,v in pairs(data) do')
    outfp.write('\n\tsetmetatable(v,mt)')
    outfp.write('\nend')

    outfp.write('\nreturn data')

    outfp.close()

#endregion

def main():
    for parent, dirnames, filenames in os.walk(EXCEL_DIR):
        for filename in filenames:
            if filename.endswith(FILETYPE):
                handle_one_file(parent, filename)
    print("tolua datatable done")
    # handle_one_file(EXCEL_DIR, "itemsBuy.xlsx")

if __name__ == '__main__':
    main()


import hashlib
import os
import re
import subprocess

# try to auto-detect the maximum number of available CPUs
def get_cpus():
  try:
    import multiprocessing
    n_cpus = multiprocessing.cpu_count()
  except:
    n_cpus = 1
  return n_cpus

# expand to full path name
# process leading '~' or relative path

def fullpath(path):
  return os.path.abspath(os.path.expanduser(path))

def which(program):
  def is_exe(fpath):
    return os.path.isfile(fpath) and os.access(fpath, os.X_OK)

  fpath, fname = os.path.split(program)
  if fpath:
    if is_exe(program):
      return program
  else:
    for path in os.environ["PATH"].split(os.pathsep):
      path = path.strip('"')
      exe_file = os.path.join(path, program)
      if is_exe(exe_file):
        return exe_file

  return None

def geturl(url, fname):
  success = False

  if which('curl') != None:
    cmd = 'curl -L -o "%s" %s' % (fname, url)
    try:
      subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
      success = True
    except subprocess.CalledProcessError as e:
      print("Calling curl failed with: %s" % e.output.decode('UTF-8'))

  if not success and which('wget') != None:
    cmd = 'wget -O "%s" %s' % (fname, url)
    try:
      subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
      success = True
    except subprocess.CalledProcessError as e:
      print("Calling wget failed with: %s" % e.output.decode('UTF-8'))

  if not success:
    raise Exception("Failed to download source code with 'curl' or 'wget' from " + url)
  return

def checkmd5sum(md5sum, fname):
    with open(fname, 'rb') as fh:
        m = hashlib.md5()
        while True:
            data = fh.read(81920)
            if not data:
                break
            m.update(data)
    fh.close()
    return m.hexdigest() == md5sum

def getfallback(lib, url):
  archive = re.sub(r'^https://.*/([^/]+gz)', r'-\1', url)
  return 'https://download.lammps.org/thirdparty/' + lib + archive


import json
import subprocess
import sys
import time

from selenium import webdriver
from selenium.webdriver.common.by import By

def navigate_to_next_page(driver):
    """
    Navigate to the next wish page
    :param driver: the driver
    :rtype: str
    """
    selector = "to-next"
    element = driver.find_element(By.CLASS_NAME, selector)
    element.click()
    time.sleep(1.5)
    return get_current_page_number(driver)

def get_current_page_number(driver):
    navigation_buttons = driver.find_elements(By.CLASS_NAME, "page-item")
    assert len(navigation_buttons) == 3
    page_number = navigation_buttons[1].text
    return page_number

def get_table(driver):
    """
    Get wishes in the table
    :param Webdriver driver:
    :return:
    """
    selector = "log-item-row"
    wish_rows = driver.find_elements(By.CLASS_NAME, selector)

    res = []
    for row in wish_rows:
        res.append(
            {
                "item_type": row.find_element(By.CLASS_NAME, "type").text,
                "wish_item_name": row.find_element(By.CLASS_NAME, "name").text,
                "wish_type": row.find_element(By.CLASS_NAME, "wish").text,
                "time_receive": row.find_element(By.CLASS_NAME, "time").text
            },
        )
    return res

def switch_banner_page(driver, banner):
    options = {
        "event": 301,
        "weapon": 302
    }
    if banner not in options:
        raise Exception("Unrecognized banner")
    banner_id = options[banner]
    dropdown = driver.find_element(By.CLASS_NAME, "selected-val")
    dropdown.click()
    time.sleep(0.5)

    driver.find_element(By.CLASS_NAME, f"item[data-id='{banner_id}']").click()
    time.sleep(0.5)

def get_wishes(wish_url, banner="character"):
    options = webdriver.ChromeOptions()
    options.add_argument("--log-level=3")
    driver = webdriver.Chrome(options=options)
    driver.minimize_window()
    driver.get(wish_url)
    time.sleep(4)
    current_page_number = get_current_page_number(driver)
    last_page_number = ""

    if banner != "character":
        switch_banner_page(driver, banner)

    wish_list = []
    while current_page_number != last_page_number:
        if int(current_page_number) % 5 == 0:
            print("parsing page: " + current_page_number)
        page_wishes = get_table(driver)
        wish_list.extend(page_wishes)
        last_page_number, current_page_number = current_page_number, navigate_to_next_page(driver)
        time.sleep(1)
    driver.close()
    return wish_list

def get_five_star_weapon_list():
    driver = get_driver()
    URL = "https://genshin-impact.fandom.com/wiki/Category:5-Star_Weapons"
    driver.get(URL)

    elements = driver.find_elements(By.CLASS_NAME, "category-page__member")

    weapon_list = []
    for element in elements:
        weapon_name = element.text
        weapon_list.append(weapon_name)
    driver.close()
    return weapon_list

def parse_wish_json(json_data):
    FIVE_STAR_WEAPON_PREFIXES = get_five_star_weapon_list()
    total_rolls = 0
    five_star_count = 0
    for wish in reversed(json_data):
        five_star_count += 1
        total_rolls += 1
        item_type = wish['item_type']
        item_name = wish['wish_item_name'].split("(")[0].strip()
        if item_type == "Character":
            if "5" in item_name:
                print(item_name, ":", five_star_count, "rolls")
                five_star_count = 0
        elif item_type == "Weapon":
            if "5" in item_name or item_name in FIVE_STAR_WEAPON_PREFIXES:
                print(item_name, ":", five_star_count, "rolls")
                five_star_count = 0

    print("Pity count", ":", five_star_count)
    print("Total rolls in history", ":", total_rolls)

def get_driver():
    options = webdriver.ChromeOptions()
    options.headless = True
    options.add_argument("--log-level=3")
    driver = webdriver.Chrome(options=options)
    driver.minimize_window()

    return driver

if __name__ == '__main__':
    wish_json_data = ""

    if len(sys.argv) >= 2:
        command = sys.argv[1]
        if len(sys.argv) == 2:
            if command == "PARSE_JSON":
                with open("wish_data.json", 'r') as f:
                    data = json.load(f)
                    parse_wish_json(data)
        elif len(sys.argv) >= 3:
            arg = sys.argv[2]
            if command == "PARSE_URL":
                wish_json_data = get_wishes(arg)
                parse_wish_json(wish_json_data)
            elif command == "BANNER":
                raw_output = subprocess.check_output('powershell.exe -ExecutionPolicy Bypass -File ./get_wish_link.ps1')
                url = raw_output.decode()
                wish_json_data = get_wishes(url, banner=arg)
                parse_wish_json(wish_json_data)

    elif len(sys.argv) == 1:
        raw_output = subprocess.check_output('powershell.exe -ExecutionPolicy Bypass -File ./get_wish_link.ps1')
        url = raw_output.decode()
        wish_json_data = get_wishes(url)
        parse_wish_json(wish_json_data)

    if wish_json_data:
        with open("wish_data.json", "w") as f:
            json.dump(wish_json_data, f, indent=4)


import pandas as pd
import numpy as np
from sklearn.cluster import KMeans, SpectralClustering, DBSCAN
import matplotlib.pyplot as plt
import scanpy as sc
from sklearn.preprocessing import normalize
import anndata
import seaborn as sb
from sklearn.neighbors import kneighbors_graph, DistanceMetric
from sklearn.metrics import silhouette_score

def add_neighbors_and_umapCoords(adata, n_neighs, metric_name, min_d):
    ad1 = sc.AnnData(X=adata.X, var=adata.var, obs=adata.obs)

    sc.pp.neighbors(ad1, n_neighbors=n_neighs, use_rep="X", metric=metric_name)
    sc.tl.umap(ad1, min_dist=min_d, n_components=2)

    return ad1, metric_name

def cluster(ad, algorithm, n_cls, metricName):
    labels = []
    if algorithm.lower() == 'kmeans':
        clustering = KMeans(n_clusters=n_cls).fit(ad.X)
        labels = clustering.labels_
    elif algorithm.lower() == 'spectral':
        ds = ad.obsp["distances"]
        ds = pd.DataFrame.sparse.from_spmatrix(ds)
        ds_s = (ds + ds.T)/2
        clustering = SpectralClustering(n_clusters=n_cls, affinity='precomputed').fit(ds_s)
        labels = clustering.labels_
    y = pd.Series(labels)
    labeling(y, ad, metricName)

def labeling(y, ad, metricName):
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20,4))
    fig.suptitle(metricName)

    colors1 = []
    colors2 = []
    exacts = []
    expected = []

    for index, value in y.items():
        if value == 0:
            colors1.append('cl1')
        elif value == 1:
            colors1.append('cl2')
        elif value == 2:
            colors1.append('cl3')
        elif value == 3:
            colors1.append('cl4')
        elif value == 4:
            colors1.append('cl5')
        elif value == 5:
            colors1.append('cl6')
        elif value == 6:
            colors1.append('cl7')
        elif value == 7:
            colors1.append('cl8')
        elif value == 8:
            colors1.append('cl9')
        elif value == 9:
            colors1.append('cl10')
        elif value == 10:
            colors1.append('cl11')
        elif value == 11:
            colors1.append('cl12')
        elif value == 12:
            colors1.append('cl13')
        elif value == 13:
            colors1.append('cl14')
        elif value == 14:
            colors1.append('cl15')

    for i in range(1786):
        exacts.append('B')

    for i in range(2445):
        exacts.append('MDC')

    for i in range(856):
        exacts.append('MC')

    for i in range(309):
        exacts.append('NK')

    for i in range(325):
        exacts.append('iNKT')

    for i in range(382):
        exacts.append('MaiT')

    for i in range(4486):
        exacts.append('P5T')

    for i in range(1247):
        exacts.append('T4_1')

    for i in range(222):
        exacts.append('T4_2')

    for i in range(965):
        exacts.append('T4_3')

    for i in range(435):
        exacts.append('T4_4')

    for i in range(310):
        exacts.append('T8')

    for i in range(4753):
        exacts.append('T8_metha')

    for i in range(284):
        exacts.append('Vd1')

    for i in range(204):
        exacts.append('Vd2')

    exacts = pd.Series(exacts)

    names = pd.Series(ad1.obs_names)
    names_connect = pd.concat((names, y, exacts),axis=1)
    names_connect = names_connect.rename({0:'Cells', 1:'Cluster', 2:'Names'},axis=1)
    sort_cells = names_connect.sort_values(['Names'])

    for i, v in sort_cells.iterrows():
        if v['Names'] == 'B':
            colors2.append('B')
        elif v['Names'] == 'MDC':
            colors2.append('MDC')
        elif v['Names'] == 'MC':
            colors2.append('MC')
        elif v['Names'] == 'NK':
            colors2.append('NK')
        elif v['Names'] == 'iNKT':
            colors2.append('T1')
        elif v['Names'] == 'MaiT':
            colors2.append('T23')
        elif v['Names'] == 'P5T':
            colors2.append('T23')
        elif v['Names'] == 'T4_1':
            colors2.append('T4')
        elif v['Names'] == 'T4_2':
            colors2.append('T5678')
        elif v['Names'] == 'T4_3':
            colors2.append('T5678')
        elif v['Names'] == 'T4_4':
            colors2.append('T5678')
        elif v['Names'] == 'T8':
            colors2.append('T5678')
        elif v['Names'] == 'T8_metha':
            colors2.append('T9_10')
        elif v['Names'] == 'Vd1':
            colors2.append('T9_10')
        elif v['Names'] == 'Vd2':
            colors2.append('T11')

    s = silhouette_score(ad.X, y)
    print(s)

    ad.obs['ClassFound'] = colors1
    found = sc.pl.umap(ad, color="ClassFound", ax = ax1, show=False)

    ad.obs['ClassReal'] = colors2

    real = sc.pl.umap(ad, color="ClassReal", ax = ax2, show=False)

#specify the path
adata = sc.read_csv('C:\\Users\\User\Desktop\seminarski.ip2\GEO\\klaster\\Sve.csv')

#example
ad1, metric = add_neighbors_and_umapCoords(adata, 110, 'cosine', 0.1)
cluster(ad1, 'kmeans', 6, metric)


import logging
import time

from nats.aio.client import Client

from metropolis.core.utils import InterruptBumper

WORKER_STATE_CONNECTED = 'connected'
WORKER_STATE_DISCONNECTED = 'connected'
WORKER_STATE_ERROR = 'error'
WORKER_STATE_CLOSED = 'closed'

class NatsDriver(object):
    nats = None
    serializer = None
    state = None

    def __init__(self, urls, serializer):
        self.urls = urls
        self.serializer = serializer

    async def get_connection(self, loop):
        self.nats = Client()

        await self.nats.connect(
            servers=self.urls,
            loop=loop,
            io_loop=loop,
            error_cb=self.get_error_cb(),
            disconnected_cb=self.get_disconnected_cb(),
            closed_cb=self.get_closed_cb(),
            reconnected_cb=self.get_reconnected_cb()
        )

        self.state = WORKER_STATE_CONNECTED

        return self.nats

    def get_error_cb(self):
        async def on_error(exception):
            self.state = WORKER_STATE_ERROR
            logging.error(f'{exception} {self.urls}')

        return on_error

    def get_disconnected_cb(self):
        async def on_disconnected():
            self.state = WORKER_STATE_DISCONNECTED
            logging.info(f'disconnected')

        return on_disconnected

    def get_closed_cb(self):
        async def on_closed():
            self.state = WORKER_STATE_DISCONNECTED
            logging.info(f'closed')

        return on_closed

    def get_reconnected_cb(self):
        async def on_reconnected():
            self.state = WORKER_STATE_CONNECTED
            logging.info(f'reconnected')

        return on_reconnected

    async def execute(self, task_fn, msg):
        logging.info((
            'Received message. '
            f'[subject={msg.subject}][fn={task_fn.__name__}]'
            f'[from={msg.reply}]'
        ))

        now = time.perf_counter()
        data = self.serializer.deserialize(msg.data)

        try:
            ret = task_fn(**data)
            code = 200

        except Exception as e:
            ret = str(e)
            code = 500

        if msg.reply:
            response_data = self.serializer.serialize({
                'code': code,
                'data': ret
            })

            await self.nats.publish(msg.reply, response_data)

        elapsed = (time.perf_counter() - now) * 1000

        logging.info((
            'Task finished. '
            f'[subject={msg.subject}][fn={task_fn.__name__}]'
            f'[elapsed={elapsed:.3f}ms]'
        ))

    def create_task_simple(self, task_fn):
        logging.debug(f'Create task [task_fn={task_fn.__name__}]')

        async def run_task(msg):
            await self.execute(task_fn, msg)

        return run_task

    def create_task(self, task_fn):
        logging.debug(f'Create task [task_fn={task_fn.__name__}]')

        async def run_task(msg):
            if self.nats.is_draining:
                logging.debug('Connection is draining')
                raise Exception('draining')

            try:
                with InterruptBumper(attempts=3):
                    self.execute(task_fn, msg)

            except KeyboardInterrupt:
                await self.nats.publish(
                    msg.reply, 'KeyboardInterrupt'.encode())
                raise

        return run_task

    async def close(self):
        logging.debug('Drain subscriptions')

        await self.nats.flush()
        logging.debug('Flushed')

        await self.nats.drain()
        logging.debug('Drained')

        await self.nats.close()
        logging.debug('Closed')


# B. Tech Project
# HANDWRITTEN FORMULAE DETECTION
# Semester 7
# December 2020
# Dr. Gaurav Harit
# Shashwat Kathuria - B17CS050
# Satya Prakash Sharma - B17CS048

# Importing required libraries
import os, random, time
from tkinter import *
from PIL import Image, ImageDraw, ImageTk
from collections import defaultdict

# Defining constants required
# Temp and output directories
TEMP_POSTSCRIPT_IMAGE_DIRECTORY = 'Modified_Text_PDF_Images/'
TEXT_ANNOTATIONS_DIRECTORY = 'Handwritten_Images_Text_Annotations/'
FORMULA_ANNOTATIONS_DIRECTORY = 'Handwritten_Images_Formula_Annotations/'
IMAGES_DIRECTORY = 'Handwritten_Images/'

# Input directories
FORMULAS_DIRECTORY = 'Handwritten_Formula_Images/'
TEXT_DIRECTORY = 'Handwritten_Sentences/'

# Some constants for output images
LEFT_MARGIN = 20
RIGHT_MARGIN = 20
BOTTOM_MARGIN = 40
PDF_HEIGHT = 1000
PDF_WIDTH = 700
PARA_GAP = 90
FORMULA_GAP = 45
LINE_GAP = 13

def main():
    '''Main function.'''

    # Calling function to create output and temp directories
    createDirectories()

    # Calling function to get input formula images
    formulasArray = getInputFormulaImages()

    # Calling function to get input text images
    textImagesDict = getInputTextImages()

    root = Tk()

    # Initializing empty white canvas with specififed width and height
    cv = Canvas(root, width = PDF_WIDTH, height = PDF_HEIGHT, bg = 'white')

    # Converting all formula images in list to tkinter PhotoImage object
    # Initializing temp list
    tempFormulasArray = []
    # Looping through array
    for formulaImage in formulasArray:
        # Converting to PhotoImage object
        tkImg = ImageTk.PhotoImage(formulaImage)
        # Appending PhotoImage object and image size to array
        tempFormulasArray.append([tkImg, formulaImage.size])
    formulasArray = tempFormulasArray

    # Generating synthetic pdf images with text and formula

    # Looping through keyed common handwritings
    for key in textImagesDict:
        # 50 images per handwriting
        for pageNo in range(50):
            # Random seed
            random.seed(time.time())

            # Initializing text and formula annotation file to write
            textAnnotationFile = open(TEXT_ANNOTATIONS_DIRECTORY + key + str(pageNo) + '.txt', 'w')
            formulaAnnotationFile = open(FORMULA_ANNOTATIONS_DIRECTORY + key + str(pageNo) + '.txt', 'w')

            # Converting all text images in list to tkinter PhotoImage object
            # Initializing temp list
            textImagesArray = []
            # Looping through array
            for image in textImagesDict[key]:
                # Converting to PhotoImage object
                tkImg = ImageTk.PhotoImage(image)
                # Appending PhotoImage object and image size to array
                textImagesArray.append([tkImg, image.size])

            # Shuffling array
            random.shuffle(textImagesArray)

            # Initializing variables required
            paraCount = 1
            numberOfParas = random.randint(4, 6)

            # Initial height, and x1 and y1(=height)
            height = 20
            x1 = LEFT_MARGIN
            y1 = height

            # Add text and formulas until the page is not completely filled
            while height < PDF_HEIGHT - BOTTOM_MARGIN:
                # Random seed
                random.seed(time.time())

                # Randomly shuffling arrays
                random.shuffle(textImagesArray)
                random.shuffle(formulasArray)

                # Initializing variables required
                # Sentence starts from LEFT_MARGIN
                width = LEFT_MARGIN
                # Variable for maxHeight of whole sentence
                maxHeight = textImagesArray[0][1][1]
                # Keeping track of number of images added
                counter = 0

                # Looping through textImagesArray to add text and formulas
                for element in textImagesArray:

                    # Randomly adding formula to sentence
                    if random.random() > 0.99:
                        isFormula = True
                        imageElement = random.sample(formulasArray, 1)[0]
                        imggg = imageElement[0]
                        imgggSize = imageElement[1]
                    # Else adding plain text
                    else:
                        isFormula = False
                        imggg = element[0]
                        imgggSize = element[1]

                    # If element goes out of page width, skip and go on to next one
                    if width + imgggSize[0] > PDF_WIDTH - RIGHT_MARGIN:
                        continue
                    # If element goes out of page height, skip and go on to next one
                    if height + imgggSize[1] > PDF_HEIGHT - BOTTOM_MARGIN:
                        continue
                    # Incrementing counter as now image will be added
                    counter += 1
                    # Adding image to canvas
                    cv.create_image(width, height, anchor = NW, image = imggg)

                    # If a formula, add annotation also
                    if isFormula:
                        # Formula bounding box annotation
                        formulaX1 = width
                        formulaX2 = width + imgggSize[0]
                        formulaY1 = height
                        formulaY2 = height + imgggSize[1]

                        # Adding annotation to file
                        formulaAnnotationFile.write(str(formulaX1) + ' ' + str(formulaY1) + ' ' + str(formulaX2) + ' ' + str(formulaY2) + '\n')

                        # Uncomment below line to see the annotations in action in tkinter canvas
                        # cv.create_line(formulaX1, formulaY1, formulaX2, formulaY2, fill="blue")

                    # Incrementing width and max height of sentence elements accordingly
                    width += imgggSize[0]
                    maxHeight = max(maxHeight, imgggSize[1])

                # If images added, add max height and line gap
                if counter > 0:
                    height += maxHeight + LINE_GAP
                # If no image added, add line gap
                else:
                    height += LINE_GAP

                # Randomly adding paragraph breaks in text with maximum as numberOfParas
                if random.random() > 0.8 and paraCount < numberOfParas:

                    # Adding text annotation as para ends here
                    x2 = PDF_WIDTH - RIGHT_MARGIN
                    y2 = height
                    # Adding annotation to file
                    textAnnotationFile.write(str(x1) + ' ' + str(y1) + ' ' + str(x2) + ' ' + str(y2) + '\n')
                    # Uncomment below line to see the annotations in action in tkinter canvas
                    # cv.create_line(x1, y1, x2, y2, fill = "red")

                    # Initializing variables required
                    height += FORMULA_GAP
                    numberOfFormulas = random.randint(1, 3)

                    # Add horizontal formula alignment randomly if even number of formulas
                    if random.random() > 0.3 and numberOfFormulas == 2:

                        # Initializing variable required
                        maxHeight = 0
                        factor = int((PDF_WIDTH - LEFT_MARGIN - RIGHT_MARGIN) / 4)
                        counter = 0

                        # Looping
                        for i in [1, 3]:
                            # Randomly chosse a formula from list
                            formula = random.sample(formulasArray, 1)[0]
                            formulaImage = formula[0]
                            formulaImageSize = formula[1]

                            # If element goes out of page width, skip and go on to next one
                            if LEFT_MARGIN + formulaImageSize[0] > PDF_WIDTH - RIGHT_MARGIN:
                                continue
                            # If element goes out of page height, skip and go on to next one
                            if height + formulaImageSize[1] > PDF_HEIGHT - BOTTOM_MARGIN:
                                continue

                            # Incrementing counter as now image will be added
                            counter += 1

                            # Adding bounding box coordinates accordingly
                            initialWidth = int( (factor * i) - (formulaImageSize[0] / 2) )
                            formulaX1 = initialWidth
                            formulaX2 = initialWidth + formulaImageSize[0]
                            formulaY1 = height
                            formulaY2 = height + formulaImageSize[1]
                            # Adding annotation to file
                            formulaAnnotationFile.write(str(formulaX1) + ' ' + str(formulaY1) + ' ' + str(formulaX2) + ' ' + str(formulaY2) + '\n')
                            # Adding image to canvas
                            cv.create_image(initialWidth, height, anchor = NW, image = formulaImage)

                            # Uncomment below line to see the annotations in action in tkinter canvas
                            # cv.create_line(formulaX1, formulaY1, formulaX2, formulaY2, fill="blue")

                            # Updating formula line max height
                            maxHeight = max(maxHeight, formulaImageSize[1])

                        # If images added, add max height and line gap
                        if counter > 0:
                            height += maxHeight + PARA_GAP
                        # If images added, add line gap
                        else:
                            height += PARA_GAP
                    # Vertical formula alignment
                    else:

                        # Looping through number of formulas to be added
                        for i in range(numberOfFormulas):
                            # Randomly chosse a formula from list
                            formula = random.sample(formulasArray, 1)[0]
                            formulaImage = formula[0]
                            formulaImageSize = formula[1]

                            # If element goes out of page width, skip and go on to next one
                            if LEFT_MARGIN + formulaImageSize[0] > PDF_WIDTH - RIGHT_MARGIN:
                                continue
                            # If element goes out of page height, skip and go on to next one
                            if height + formulaImageSize[1] > PDF_HEIGHT - BOTTOM_MARGIN:
                                continue

                            # Adding bounding box coordinates accordingly
                            initialWidth = int( (PDF_WIDTH - LEFT_MARGIN - RIGHT_MARGIN - formulaImageSize[0]) / 2)
                            formulaX1 = initialWidth
                            formulaX2 = initialWidth + formulaImageSize[0]
                            formulaY1 = height
                            formulaY2 = height + formulaImageSize[1]

                            # Adding annotation to file
                            formulaAnnotationFile.write(str(formulaX1) + ' ' + str(formulaY1) + ' ' + str(formulaX2) + ' ' + str(formulaY2) + '\n')

                            # Adding image to canvas
                            cv.create_image(initialWidth, height, anchor = NW, image = formulaImage)

                            # Uncomment below line to see the annotations in action in tkinter canvas
                            # cv.create_line(formulaX1, formulaY1, formulaX2, formulaY2, fill="blue")

                            # Updating height
                            height += formulaImageSize[1] + 20

                    # Uncomment below line to see the annotations in action in tkinter canvas
                    # cv.create_line(0,height,PDF_WIDTH,height, fill="blue")

                    # New para starts, updating values of x1 and y1
                    paraCount += 1
                    x1 = LEFT_MARGIN
                    y1 = height

            # End of text para, updating values
            x2 = PDF_WIDTH - RIGHT_MARGIN
            y2 = height
            # cv.create_line(x1, y1, x2, y2, fill="red")

            cv.pack()
            cv.update()
            # Adding postscript output to file
            cv.postscript(colormode = 'color', file = TEMP_POSTSCRIPT_IMAGE_DIRECTORY + key + str(pageNo) + '.eps', pagewidth=PDF_WIDTH -1, pageheight=PDF_HEIGHT-1)
            # Generating image object from above postscript output
            img = Image.open(TEMP_POSTSCRIPT_IMAGE_DIRECTORY + key + str(pageNo) + '.eps')
            # Saving generated image as png
            img.save(IMAGES_DIRECTORY + key + str(pageNo) + '.png', 'png')
            # Clearing canvas for next page generation
            cv.delete('all')

    # Root mainloop
    root.mainloop()

def getInputTextImages():
    '''Function to get processed text images dict keyed according to common handwritings.'''

    # Initializing dict (keyed according to common handwritings) and scaling factor
    # Default element in textImagesDict is an empty list
    textImagesDict = defaultdict(list)
    scalingFactor = 3.25

    # Looping through all the text images
    for index, filename in enumerate(sorted(os.listdir(TEXT_DIRECTORY))[:3000]):
        # Initializing image object
        img = Image.open(TEXT_DIRECTORY + filename)
        # Resizing according to scaling factor
        img = img.resize((int(img.size[0] / scalingFactor), int(img.size[1] / scalingFactor)), Image.ANTIALIAS)
        if filename[:3] not in ['b06', 'c03', 'c06', 'g06', 'd06']: # 'do6'
            # Appending to array of keyed element in dict
            textImagesDict[filename[:3]].append(img)

    # Returning dict
    return textImagesDict

def getInputFormulaImages():
    '''Function to get processed formula images array.'''

    # Initializing list and scaling factor
    formulasArray = []
    scalingFactor = 4.25

    # Looping through all the formulas images
    for index, filename in enumerate(sorted(os.listdir(FORMULAS_DIRECTORY))):
        # Initializing image object
        img = Image.open(FORMULAS_DIRECTORY + filename)
        if img.size[0] == 523:
            if img.size[1] > 120 and img.size[1] < 200:
                # Resizing according to scaling factor
                img = img.resize((int(img.size[0] / scalingFactor), int(img.size[1] / scalingFactor)), Image.ANTIALIAS)
                # Appending to array
                formulasArray.append(img)

    # Returning array
    return formulasArray

def createDirectories():
    '''Function to create directories required. Ignoring if already created.'''

    # Initializing directories to be created
    directoriesToCreate = [
        TEMP_POSTSCRIPT_IMAGE_DIRECTORY,
        IMAGES_DIRECTORY,
        TEXT_ANNOTATIONS_DIRECTORY,
        FORMULA_ANNOTATIONS_DIRECTORY
    ]

    # Looping through list
    for directoryName in directoriesToCreate:
        # Create directory
        try:
            os.mkdir(directoryName)
        # Ignore if already exists
        except FileExistsError:
            pass

# Calling main function
if __name__ == "__main__":
    main()


from transformers import AutoProcessor, BlipForConditionalGeneration
from torch.utils.data import DataLoader

import csv
from PIL import Image
from torchvision import transforms
import torch
from torch.utils.data import Dataset, DataLoader
from image_caption_dataset import ImageCaptioningDataset

# Initialize processor and model
processor = AutoProcessor.from_pretrained("Salesforce/blip-image-captioning-base")
model = BlipForConditionalGeneration.from_pretrained("Salesforce/blip-image-captioning-base")

# Assuming 'dataset' is already defined or loaded
# Create an instance of your custom dataset
csv_file_path = "/Users/nero/Desktop/CaptionThis/data_sets/downloaded_images.csv"
transform = transforms.Compose([
    transforms.Resize((300, 300)),
    transforms.ToTensor(),
])
train_dataset = ImageCaptioningDataset(csv_file_path, transform, processor)

# Create a DataLoader for the training dataset
train_dataloader = DataLoader(train_dataset, shuffle=True, batch_size=2)

# Training setup (optimizer, device setup)
optimizer = torch.optim.AdamW(model.parameters(), lr=5e-5)
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)  # Optional, if you want to use a scheduler

device = "cuda" if torch.cuda.is_available() else "cpu"
model.to(device)

# Training loop
TOTAL_EPOCHS = 10
for epoch in range(TOTAL_EPOCHS):
    print("Epoch:", epoch)
    model.train()

    total_loss = 0.0
    for idx, batch in enumerate(train_dataloader):
        optimizer.zero_grad()  # Reset gradients

        input_ids = batch["input_ids"].to(device)
        pixel_values = batch["pixel_values"].to(device)

        outputs = model(input_ids=input_ids, pixel_values=pixel_values, labels=input_ids)
        loss = outputs.loss

        if loss is not None:
            loss.backward()
            optimizer.step()

            total_loss += loss.item()
            print(f"Batch {idx} Loss: {loss.item()}")
        else:
            print(f"Batch {idx} Loss: None")

    scheduler.step()  # Adjust the learning rate

    # Save the model after each epoch (optional but recommended)
    torch.save(model.state_dict(), f'model_epoch_{epoch}.pth')

    # Print average loss
    avg_loss = total_loss / len(train_dataloader)
    print(f"Average Loss for Epoch {epoch}: {avg_loss}")