import cv2 as cv
import matplotlib
import numpy as np
import random

matplotlib.use('Agg')

from itertools import cycle
from matplotlib import colors as mcolors
from matplotlib import pyplot as plt
from pls_classifier import PLSClassifier
from sklearn.metrics import auc
from sklearn.metrics import average_precision_score, precision_recall_curve
from sklearn.metrics import roc_curve, roc_auc_score
from sklearn.svm import SVC
from sklearn.svm import SVR

def load_txt_file(file_name):
    this_file = open(file_name, 'r')
    this_list = []
    for line in this_file:
        line = line.rstrip()
        components = line.split()
        this_list.append(components)
    return this_list

def read_fold_file(file_name):
    with open(file_name) as file_input:
        neg_folds = []
        pos_folds = []

        file_list = file_input.readlines()
        for index in range(len(file_list)):
            file_list[index] = file_list[index].replace(' ', '_').strip().split('\t')

        index = 0;
        while str(file_list[index][0]).startswith('#'):
            index += 1
        num_folds = int(file_list[index][0])
        index += 1

        while index < len(file_list):
            if not str(file_list[index][0]).startswith('#'):
                num_pos = int(file_list[index][0])
                num_neg = int(file_list[index][1])
                index += 1

                pos_list = []
                for inner in range(index, num_pos + index):
                    if len(file_list[inner]) == 3:
                        file_list[inner].insert(2, file_list[inner][0])
                    pos_list.append(tuple(file_list[inner]))
                    index += 1

                neg_list = []
                for inner in range(index, num_neg + index):
                    neg_list.append(tuple(file_list[inner]))
                    index += 1

                pos_folds.append(pos_list)
                neg_folds.append(neg_list)
            else:
                index += 1

        return pos_folds, neg_folds

def split_known_unknown_sets(complete_tuple_list, known_set_size=0.5):
    label_set = set()
    for (path, label) in complete_tuple_list:
        label_set.add(label)

    known_set = set(random.sample(label_set, int(known_set_size * len(label_set))))
    unknown_set = label_set - known_set

    known_tuple = [(path, label) for (path, label) in complete_tuple_list if label in known_set]
    unknown_tuple = [(path, label) for (path, label) in complete_tuple_list if label in unknown_set]

    return known_tuple, unknown_tuple

def split_train_test_samples(complete_tuple_list, train_set_samples=4):
    to_shuffle = [item for item in complete_tuple_list]
    np.random.shuffle(to_shuffle)

    tuple_dict = dict()
    for (path, label) in to_shuffle:
        if tuple_dict.has_key(label):
            tuple_dict[label].append(path)
        else:
            tuple_dict[label] = [path]

    # for tuple in tuple_dict.iteritems():
    #     assert len(tuple[1]) > train_set_samples

    test_set = []
    train_set = []
    for (label, paths) in tuple_dict.iteritems():
        for path in paths[0:train_set_samples]:
            train_set.append((path, label))
        for path in paths[train_set_samples:len(paths)]:
            test_set.append((path, label))

    return train_set, test_set

def split_train_test_sets(complete_tuple_list, train_set_size=0.5):
    label_set = {label for (path, label) in complete_tuple_list}
    train_tuple = list()
    test_tuple = list()
    for label in label_set:
        # Sample images to compose train_set
        path_set = {path for (path, target) in complete_tuple_list if label == target}
        train_set = set(random.sample(path_set, int(train_set_size * len(path_set))))
        test_set = path_set - train_set
        # Put together labels and paths
        train_tuple.extend([(path, label) for path in train_set])
        test_tuple.extend([(path, label) for path in test_set])
    return train_tuple, test_tuple

def load_images(path, image_list, display=False):
    for name in image_list:
        image = cv.imread(path + '/' + name, cv.IMREAD_COLOR)
        if display:
            cv.imshow('img', image)
            cv.waitKey(20)
    if display:
        cv.destroyAllWindows()

def augment_gallery_set(image_sample):
    image_samples = []
    image_samples.append(image_sample)
    image_samples.append(cv.flip(image_sample, 1)) # vertical-axis flip
    rows,cols,dep = image_sample.shape
    for angle in range(-5,6,10):
        rot_matrix = cv.getRotationMatrix2D((rows/2, cols/2), angle, 1.1)
        image_samples.append(cv.warpAffine(image_sample, rot_matrix,(cols, rows)))
    return image_samples

def sliding_window(image, window_size, step_size):
    for y in xrange(0, image.shape[0], step_size):
        for x in xrange(0, image.shape[1], step_size):
            yield (x, y, image[y:y + window_size[1], x:x + window_size[0]])

def generate_pos_neg_dict(labels):
    to_shuffle = [item for item in labels]
    np.random.shuffle(to_shuffle)
    neg_set = map(lambda neg: (neg, -1), to_shuffle[0:(len(labels) / 2)])
    pos_set = map(lambda pos: (pos, +1), to_shuffle[(len(labels) / 2):len(labels)])
    full_set = neg_set + pos_set
    full_dict = dict((key, val) for key, val in full_set)
    return full_dict

def mount_tuple(tuple, dataset='lfw'):
    if dataset == 'lfw':
        sample_a = tuple[0] + '/' + tuple[0] + '_' + format(int(tuple[1]),'04d') + '.jpg'
        sample_b = tuple[2] + '/' + tuple[2] + '_' + format(int(tuple[3]),'04d') + '.jpg'
    elif dataset == 'pubfig':
        sample_a = tuple[0] + '/' + tuple[1] + '.jpg'
        sample_b = tuple[2] + '/' + tuple[3] + '.jpg'
    else:
        exit(0)
    return sample_a, sample_b

def split_into_chunks(full_tuple, num_models=100, num_subjects=100):
    neg_split = []
    pos_split = []

    tuple_dict = dict()
    for (path, label) in full_tuple:
        if tuple_dict.has_key(label):
            tuple_dict[label].append(path)
        else:
            tuple_dict[label] = [path]

    individuals = []
    while len(individuals) < num_subjects:
        individuals.extend(tuple_dict.keys())

    for index in range(num_models):
        neg_list = []
        pos_list = []
        for pos in random.sample(individuals, num_subjects):
            candidates = tuple(random.sample(tuple_dict[pos], 2))
            pos_list.append(candidates)
        for neg_index in range(num_subjects):
            chosen = random.sample(tuple_dict.keys(), 2)
            candidate_a = random.sample(tuple_dict[chosen[0]], 1)
            candidate_b = random.sample(tuple_dict[chosen[1]], 1)
            neg_list.append((candidate_a[0], candidate_b[0]))

        pos_split.append(pos_list)
        neg_split.append(neg_list)

    return pos_split, neg_split

def getModel(input_shape, nclasses=2):
    import keras
    from keras.datasets import mnist
    from keras.layers import Dense, Dropout
    from keras.models import Sequential
    from keras.optimizers import RMSprop
    from keras import callbacks

    model = Sequential()
    model.add(Dense(64, activation='relu', input_shape=input_shape))
    model.add(Dropout(0.2))
    model.add(Dense(nclasses, activation='softmax'))
    #model.summary()
    model.compile(loss='categorical_crossentropy', optimizer='adadelta', metrics=['accuracy'])#RMSprop()

    return model

def learn_fcn_model(X, Y, split):
    import keras
    from keras.utils import np_utils
    from keras import callbacks

    boolean_label = [(split[key]+1)/2 for key in Y]
    y_train = np_utils.to_categorical(boolean_label, 2)

    model = getModel(input_shape=X[0].shape)
    model.fit(X, y_train, batch_size=40, nb_epoch=100, verbose=0)
    return (model, split)

def learn_pls_model(matrix_x, matrix_y):
    classifier = PLSClassifier()
    model = classifier.fit(np.array(matrix_x), np.array(matrix_y))
    return model

def learn_plsh_model(matrix_x, matrix_y, split):
    classifier = PLSClassifier()
    boolean_label = [split[key] for key in matrix_y]
    model = classifier.fit(np.array(matrix_x), np.array(boolean_label))
    return (model, split)

def learn_plsh_v_model(pos_split, neg_split):
    neg_label = np.zeros(len(neg_split))
    pos_label = np.ones(len(pos_split))
    labels = np.concatenate([neg_label, pos_label])
    splits = neg_split + pos_split

    classifier = PLSClassifier()
    model = classifier.fit(np.array(splits), np.array(labels))
    return model

def learn_svmh_v_model(pos_split, neg_split):
    neg_label = np.zeros(len(neg_split))
    pos_label = np.ones(len(pos_split))
    labels = np.concatenate([neg_label, pos_label])
    splits = neg_split + pos_split

    classifier = SVR(C=1.0,kernel='linear')
    model = classifier.fit(np.array(splits), np.array(labels))
    return model

def learn_plsh_cv_model(features, dictionary, pos_split, neg_split):
    matrix_x = []
    matrix_y = []

    for pos in pos_split:
        index_a = dictionary[pos[0]]
        index_b = dictionary[pos[1]]
        diff_feat = np.absolute(np.subtract(features[index_a], features[index_b]))
        matrix_x.append(diff_feat)
        matrix_y.append(1)

    for neg in neg_split:
        index_a = dictionary[neg[0]]
        index_b = dictionary[neg[1]]
        diff_feat = np.absolute(np.subtract(features[index_a], features[index_b]))
        matrix_x.append(diff_feat)
        matrix_y.append(0)

    classifier = PLSClassifier()
    model = classifier.fit(np.array(matrix_x), np.array(matrix_y))
    return (model, (pos_split, neg_split))

def learn_svmh_cv_model(features, dictionary, pos_split, neg_split):
    matrix_x = []
    matrix_y = []

    for pos in pos_split:
        index_a = dictionary[pos[0]]
        index_b = dictionary[pos[1]]
        diff_feat = np.absolute(np.subtract(features[index_a], features[index_b]))
        matrix_x.append(diff_feat)
        matrix_y.append(1)

    for neg in neg_split:
        index_a = dictionary[neg[0]]
        index_b = dictionary[neg[1]]
        diff_feat = np.absolute(np.subtract(features[index_a], features[index_b]))
        matrix_x.append(diff_feat)
        matrix_y.append(0)

    classifier = SVR(C=1.0,kernel='linear')
    model = classifier.fit(np.array(matrix_x), np.array(matrix_y))
    return (model, (pos_split, neg_split))

def generate_probe_histogram(individuals, values, extra_name):
    plt.clf()
    plt.bar(range(len(individuals)), values)
    if sample_name == result[0][0]:
        plt.savefig('plots/' + extra_name + '_' + str(NUM_HASH) + '_' + str(counter) + '_' + sample_name + '_' + result[0][0])
    else:
        plt.savefig('plots/' + extra_name + '_' + str(NUM_HASH) + '_' + str(counter) + '_' + sample_name + '_' + result[0][0] + '_ERROR')

def generate_precision_recall(y_label_list, y_score_list):
    """
    A system with high recall but low precision returns many results, but most of its predicted labels are incorrect when compared to the training labels.
    A system with high precision but low recall is just the opposite, returning very few results, but most of its predicted labels are correct when compared to the training labels.
    An ideal system with high precision and high recall will return many results, with all results labeled correctly.
    """
    # Prepare input data
    label_list = [line[1] for line in y_label_list]
    score_list = [line[1] for line in y_score_list]
    label_array = np.array(label_list)
    score_array = np.array(score_list)

    # Compute micro-average ROC curve and ROC area
    pr = dict()
    pr['precision'], pr['recall'], pr['thresh'] = precision_recall_curve(label_array.ravel(), score_array.ravel())
    pr['avg_precision'] = average_precision_score(label_array, score_array, average="micro")
    return pr

def generate_roc_curve(y_label_list, y_score_list):
    """
    ROC curves typically feature true positive rate on the Y axis, and false positive rate on the X axis.
    This means that the top left corner of the plot is the ideal point - a false positive rate of zero, and a true positive rate of one.
    This is not very realistic, but it does mean that a larger area under the curve (AUC) is usually better.
    """
    # Prepare input data
    label_list = [line[1] for line in y_label_list]
    score_list = [line[1] for line in y_score_list]
    label_array = np.array(label_list)
    score_array = np.array(score_list)

    # Compute micro-average ROC curve and ROC area
    roc = dict()
    roc['fpr'], roc['tpr'], roc['thresh'] = roc_curve(label_array.ravel(), score_array.ravel())
    roc['auc']  = auc(roc['fpr'], roc['tpr'])
    return roc

def plot_cmc_curve(cmc_scores, extra_name):
    """
    The CMC shows how often the biometric subject template appears in the ranks (1, 5, 10, 100, etc.), based on the match rate.
    It is a method of showing measured accuracy performance of a biometric system operating in the closed-set identification task.
    Templates are compared and ranked based on their similarity.
    """
    # Setup plot details
    color_dict = dict(mcolors.BASE_COLORS, **mcolors.CSS4_COLORS)
    color_names = [name for name, color in color_dict.items()]
    colors = cycle(color_names)
    lw = 2

    # Plot Cumulative Matching Characteristic curve
    plt.clf()
    counter = 1
    for score, color in zip(cmc_scores, colors):
        x_axis = range(len(score))
        y_axis = score
        area = auc(x_axis, y_axis)/len(score)
        rank1 = score[0]
        plt.plot(x_axis, y_axis, lw=lw, color=color, label='CMC curve %d (area = %0.2f, rank-1 = %0.2f)' % (counter, area, rank1))
        counter += 1

    plt.xlim([0, len(score)])
    plt.ylim([0.0, 1.05])
    plt.xlabel('Rank')
    plt.ylabel('Accuracy Rate')
    plt.title('Cumulative Matching Characteristic')
    plt.legend(loc="lower right")
    plt.grid()
    if extra_name == None:
        plt.show()
    else:
        plt.savefig('./plots/CMC_' + extra_name + '.pdf')
    plt.close()

def plot_precision_recall(prs, extra_name=None):
    # Setup plot details
    aucs = [pr['avg_precision'] for pr in prs]
    color_dict = dict(mcolors.BASE_COLORS, **mcolors.CSS4_COLORS)
    color_names = [name for name, color in color_dict.items()]
    colors = cycle(color_names)
    lw = 2

    # Plot Precision-Recall curve
    plt.clf()
    for index, color in zip(range(len(prs)), colors):
        pr = prs[index]
        plt.plot(pr['recall'], pr['precision'], lw=lw, color=color, label='PR curve %d (area = %0.2f)' % (index+1, pr['avg_precision']))
    plt.xlabel('Recall')
    plt.ylabel('Precision')
    plt.ylim([0.0, 1.05])
    plt.xlim([0.0, 1.0])
    plt.title('Precision-Recall Curve (%0.3f - %0.3f)' % (np.mean(aucs),np.std(aucs)))
    plt.legend(loc="lower left")
    plt.grid()
    if extra_name == None:
        plt.show()
    else:
        plt.savefig('./plots/PR_' + extra_name + '.pdf')
    plt.close()

def plot_roc_curve(rocs, extra_name=None):
    # Setup plot details
    aucs = [roc['auc'] for roc in rocs]
    color_dict = dict(mcolors.BASE_COLORS, **mcolors.CSS4_COLORS)
    color_names = [name for name, color in color_dict.items()]
    colors = cycle(color_names)
    lw = 2

    # Plot Receiver Operating Characteristic curve
    plt.clf()
    for index, color in zip(range(len(rocs)), colors):
        roc = rocs[index]
        plt.plot(roc['fpr'], roc['tpr'], color=color, lw=lw, label='ROC curve %d (area = %0.2f)' % (index+1, roc['auc']))
    plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
    plt.xlim([0.0, 1.0])
    plt.ylim([0.0, 1.05])
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')
    plt.title('Receiver Operating Characteristic (%0.3f - %0.3f)' % (np.mean(aucs),np.std(aucs)))
    plt.legend(loc="lower right")
    plt.grid()
    if extra_name == None:
        plt.show()
    else:
        plt.savefig('./plots/ROC_' + extra_name + '.pdf')
    plt.close()

def iteration_to_fold(prs, rocs):
    fold_prs = {}
    fold_rocs = {}

    # prs_avg = []
    # prs_pre = []
    # prs_rec = []
    # prs_thr = []
    # avg_prs = {}
    for row in prs:
        for col in range(len(row)):
            if fold_prs.has_key(col):
                fold_prs[col].append(row[col])
            else:
                fold_prs[col] = [row[col]]
    # for fold in fold_prs.values():
    #     for item in fold:
    #         prs_avg.append(item['avg_precision'])
    #         prs_pre.append(item['precision'])
    #         prs_rec.append(item['recall'])
    #         prs_thr.append(item['thresh'])
    #     avg_prs['avg_precision'] = np.mean(prs_avg, axis=0)
    #     avg_prs['precision'] = np.mean(prs_pre, axis=0)
    #     avg_prs['recall'] = np.mean(prs_rec, axis=0)
    #     avg_prs['thresh'] = np.mean(prs_thr, axis=0)

    # rocs_auc = []
    # rocs_fpr = []
    # rocs_thr = []
    # rocs_tpr = []
    # avg_rocs = {}
    for row in rocs:
        for col in range(len(row)):
            if fold_rocs.has_key(col):
                fold_rocs[col].append(row[col])
            else:
                fold_rocs[col] = [row[col]]
    # for fold in fold_rocs.values():
    #     for item in fold:
    #         rocs_auc.append(item['auc'])
    #         rocs_fpr.append(item['fpr'])
    #         rocs_thr.append(item['thresh'])
    #         rocs_tpr.append(item['tpr'])
    #     avg_rocs['auc'] = np.mean(rocs_auc, axis=0)
    #     avg_rocs['fpr'] = np.mean(rocs_fpr, axis=0)
    #     avg_rocs['thresh'] = np.mean(rocs_thr, axis=0)
    #     avg_rocs['tpr'] = np.mean(rocs_tpr, axis=0)

    return fold_prs, fold_rocs


"""Functions to use inside of tests.

Contains functions for easily returning wanted values on service.
Also contains functions for validating values on a service.
"""

from typing import Any, Dict, Optional, cast

from emulation_system.compose_file_creator import BuildItem, Service
from emulation_system.compose_file_creator.images import (
    HeaterShakerModuleImages,
    MagneticModuleImages,
    RobotServerImage,
    TemperatureModuleImages,
    ThermocyclerModuleImages,
)
from tests.conftest import (
    HEATER_SHAKER_MODULE_ID,
    MAGNETIC_MODULE_ID,
    OT2_ID,
    TEMPERATURE_MODULE_ID,
    THERMOCYCLER_MODULE_ID,
)

CONTAINER_NAME_TO_IMAGE = {
    OT2_ID: RobotServerImage().image_name,
    f"{THERMOCYCLER_MODULE_ID}-1": ThermocyclerModuleImages().hardware_image_name,
    f"{HEATER_SHAKER_MODULE_ID}-1": HeaterShakerModuleImages().hardware_image_name,
    f"{TEMPERATURE_MODULE_ID}-1": TemperatureModuleImages().firmware_image_name,
    f"{MAGNETIC_MODULE_ID}-1": MagneticModuleImages().firmware_image_name,
}
SERVICE_NAMES = [
    OT2_ID,
    f"{THERMOCYCLER_MODULE_ID}-1",
    f"{HEATER_SHAKER_MODULE_ID}-1",
    f"{TEMPERATURE_MODULE_ID}-1",
    f"{MAGNETIC_MODULE_ID}-1",
]
EXTRA_MOUNT_PATH = "/var/log/log_files"

def partial_string_in_mount(string: str, service: Service) -> bool:
    """Check if the partial string exists in any of the Service's mounts."""
    volumes = service.volumes
    assert volumes is not None
    return any([string in volume for volume in volumes])

def mount_string_is(string: str, service: Service) -> bool:
    """Confirm that mount string exists in volumes."""
    volumes = service.volumes
    assert volumes is not None
    return any([string == volume for volume in volumes])

def check_correct_number_of_volumes(container: Service, expected_number: int) -> None:
    """Confirm container has correct number of volumes."""
    volumes = container.volumes
    if expected_number == 0:
        assert (
            volumes is None
        ), f'Correct number of volumes is 0, you have "{len(volumes)}'
    else:
        assert volumes is not None
        assert (
            len(volumes) == expected_number
        ), f'Correct number of volumes is {expected_number}, you have "{len(volumes)}"'

def get_source_code_build_args(service: Service) -> Optional[Dict[str, str]]:
    """Get build args for service."""
    build = service.build
    assert build is not None
    assert isinstance(build, BuildItem)
    if build.args is None:
        return None
    else:
        return cast(Dict[str, str], build.args.__root__)

def build_args_are_none(service: Service) -> bool:
    """Whether or not build args are None. With annoying typing stuff."""
    build = service.build
    assert build is not None
    assert isinstance(build, BuildItem)
    return build.args is None

def get_env(container: Service) -> Dict[str, Any] | None:
    """Get environment variables for container."""
    return (
        None
        if container.environment is None
        else cast(Dict[str, Any], container.environment.__root__)
    )


'''
    # RPC Cliente #
    # Autores: Henrique Moura Bini e Vinicius Henrique Soares
    # Data de criação: 15/11/2021
    # Data de modificação: 18/11/2021
    # Descrição: Implementação de um serviço de gerenciamento de notas que deve enviar informações via gRPC:
            - LISTAR_ALUNOS (1): Tenta listar os alunos de uma disciplina com base no código da disciplina, ano e semestre.
            - ALTERAR_NOTA (2): Tenta alterar a nota de um aluno em uma disciplina com base no código do aluno, código da disciplina, ano e semestre.
            - ALTERAR_FALTAS (3): Tenta alterar a quantidade de faltas de um aluno com base no código do aluno, código da disciplina, ano e semestre.
            - LISTAR_DISCIPLINAS_CURSO (4): Tenta listar as disciplinas de um curso com base no código do curso.
            - LISTAR_DISCIPLINAS_ALUNO (5): Tenta listar os alunos de uma disciplina com base no ra, ano e semestre.
            - INSERIR_MATRICULA (6): Tenta inserir uma nova matrícula de um aluno em uma disciplina.

'''

import grpc

import gerenciamentoNotas_pb2_grpc
import gerenciamentoNotas_pb2

channel = grpc.insecure_channel('localhost:7778')
stub = gerenciamentoNotas_pb2_grpc.GerenciadorDeNotasStub(channel)

# Constantes para o tipo de requisição
LISTAR_ALUNOS = "1"
ALTERAR_NOTA = "2"
ALTERAR_FALTAS = "3"
LISTAR_DISCIPLINAS_CURSO = "4"
LISTAR_DISCIPLINAS_ALUNO = "5"
INSERIR_MATRICULA = "6"

# Função para receber os dados da requisição do cliente e enviá los para o servidor
def dadosRequisicao(opcao):
    if opcao == LISTAR_ALUNOS:
        # Variável para armazenar os dados da requisição
        request = gerenciamentoNotas_pb2.ListarAlunosRequest()
        # Recebe os dados da requisição
        codigoDisciplina = (input("Digite o código da disciplina: "))
        ano = input("Digite o ano: ")
        semestre = input("Digite o semestre: ")
        # Verifica se os dados da requisição são válidos
        if ano.isdigit() and semestre.isdigit() and codigoDisciplina != "" and ano != "" and semestre != "":
            request.codigoDisciplina = codigoDisciplina
            request.ano = int(ano)
            request.semestre = int(semestre)
            # Envia os dados da requisição para o servidor e recebe a resposta
            response = stub.ListarAlunos(request)
            # Verifica se a requisição foi bem sucedida
            if response.mensagem != "":
                # Imprime os dados da resposta
                print(response.mensagem)
            else:
                # Imprime os dados da resposta
                for aluno in response.alunos:
                    print(aluno, end="")
                    print("===========================")
        else:
            print("Algum dos campos não foi preenchido corretamente")

    elif opcao == ALTERAR_NOTA:
        # Variável para armazenar os dados da requisição
        request = gerenciamentoNotas_pb2.AlterarNotaRequest()
        # Recebe os dados da requisição
        ra = input("Digite o RA do aluno: ")
        codigoDisciplina = input("Digite o código da disciplina: ")
        ano = input("Digite o ano da disciplina: ")
        semestre = input("Digite o semestre da disciplina: ")
        nota = input("Digite a nota do aluno: ")
        # Verifica se os dados da requisição são válidos
        if ra.isdigit() and ano.isdigit() and semestre.isdigit() and nota.isdigit() and codigoDisciplina != "" and ano != "" and semestre != "" and nota != "" and ra != "":
            request.ra = int(ra)
            request.codigoDisciplina = codigoDisciplina
            request.ano = int(ano)
            request.semestre = int(semestre)
            request.nota = float(nota)
            # Envia os dados da requisição para o servidor e recebe a resposta
            response = stub.AlterarNota(request)
            # Verifica se a requisição foi bem sucedida
            if response.mensagem != "":
                # Imprime os dados da resposta
                print(response.mensagem)
            else:
                # Imprime os dados da resposta
                print("Ra: " + str(response.ra) + "\nCodigo da Disciplina:" + str(response.codigoDisciplina) + "\nAno: " + str(response.ano) + "\nSemestre: " + str(response.semestre) + "\nNota: " + str(response.nota))
        else:
            print("Algum dos campos não foi preenchido corretamente")

    elif opcao == ALTERAR_FALTAS:
        # Variável para armazenar os dados da requisição
        request = gerenciamentoNotas_pb2.AlterarFaltasRequest()
        # Recebe os dados da requisição
        ra = input("Digite o RA do aluno: ")
        codigoDisciplina = input("Digite o código da disciplina: ")
        ano = input("Digite o ano da disciplina: ")
        semestre = input("Digite o semestre da disciplina: ")
        faltas = input("Digite a quantidade de faltas do aluno: ")
        # Verifica se os dados da requisição são válidos
        if ra != '' and codigoDisciplina != '' and ano != '' and semestre != '' and faltas != '' and ra.isdigit() and ano.isdigit() and semestre.isdigit() and faltas.isdigit():
            request.ra = int(ra)
            request.codigoDisciplina = codigoDisciplina
            request.ano = int(ano)
            request.semestre = int(semestre)
            request.faltas = int(faltas)
            # Envia os dados da requisição para o servidor e recebe a resposta
            response = stub.AlterarFaltas(request)
            # Verifica se a requisição foi bem sucedida
            if response.mensagem != "":
                print(response.mensagem)
            else:
                print("Ra: " + str(response.ra) + "\nCodigo da Disciplina:" + str(response.codigoDisciplina) + "\nAno: " + str(response.ano) + "\nSemestre: " + str(response.semestre) + "\nFaltas: " + str(response.faltas))
        else:
            print("Algum dos campos não foi preenchido corretamente")

    elif opcao == LISTAR_DISCIPLINAS_CURSO:
        # Variável para armazenar os dados da requisição
        request = gerenciamentoNotas_pb2.ListarDisciplinasCursoRequest()
        # Recebe os dados da requisição
        codigoCurso = input("Digite o código do curso: ")
        # Verifica se os dados da requisição são válidos
        if codigoCurso.isdigit() and codigoCurso != "":
            request.codigoCurso = int(codigoCurso)
            # Envia os dados da requisição para o servidor e recebe a resposta
            response = stub.ListarDisciplinasCurso(request)
            # Verifica se a requisição foi bem sucedida
            if response.mensagem != "":
                print(response.mensagem)
            else:
                # Imprime os dados da resposta
                for i in range(len(response.disciplinas)):
                    print("Código da Disciplina: " + str(response.disciplinas[i].codigoDisciplina) + "\nNome: " + str(response.disciplinas[i].nome) + "\nProfessor: " + str(response.disciplinas[i].professor))
                    print("===========================")
        else:
            print("Algum dos campos não foi preenchido corretamente")

    elif opcao == LISTAR_DISCIPLINAS_ALUNO:
        # Variável para armazenar os dados da requisição
        request = gerenciamentoNotas_pb2.ListarDisciplinasAlunoRequest()
        # Recebe os dados da requisição
        ra = input("Digite o RA do aluno: ")
        ano = input("Digite o ano: ")
        semestre = input("Digite o semestre: ")
        # Verifica se os dados da requisição são válidos
        if ra.isdigit() and ano.isdigit() and semestre.isdigit() and ra != '' and ano != '' and semestre != '':
            request.ra = int(ra)
            request.ano = int(ano)
            request.semestre = int(semestre)
            # Envia os dados da requisição para o servidor e recebe a resposta
            response = stub.ListarDisciplinasAluno(request)
            # Verifica se a requisição foi bem sucedida
            if response.mensagem != "":
                print(response.mensagem)
            else:
                # Imprime os dados da resposta
                for i in range(len(response.disciplinas)):
                        print("Ra: " + str(response.disciplinas[i].ra) + "\nCódigo da Disciplina: " + str(response.disciplinas[i].codigoDisciplina) + "\nNota: " + str(response.disciplinas[i].nota) + "\nFaltas: " + str(response.disciplinas[i].faltas))
                        print("===========================")
        else:
            print("Algum dos campos não foi preenchido corretamente")

    elif opcao == INSERIR_MATRICULA:
        # Variável para armazenar os dados da requisição
        request = gerenciamentoNotas_pb2.InserirMatriculaRequest()
        # Recebe os dados da requisição
        ra = input("Digite o código do aluno: ")
        codigoDisciplina = input("Digite o código da disciplina: ")
        ano = input("Digite o ano da disciplina: ")
        semestre = input("Digite o semestre da disciplina: ")
        # Verifica se os dados da requisição são válidos
        if ra.isdigit() and ano.isdigit() and semestre.isdigit() and codigoDisciplina != "" and ano != "" and semestre != "" and ra != "":
            request.matricula.ra = int(ra)
            request.matricula.codigoDisciplina = codigoDisciplina
            request.matricula.ano = int(ano)
            request.matricula.semestre = int(semestre)
            # Envia os dados da requisição para o servidor e recebe a resposta
            response = stub.InserirMatricula(request)
            # Verifica se a requisição foi bem sucedida
            if response.mensagem != "":
                print(response.mensagem)
            else:
                print("Ra: " + str(response.matricula.ra) + "\nCodigo da Disciplina:" + str(response.matricula.codigoDisciplina) + "\nAno: " + str(response.matricula.ano) + "\nSemestre: " + str(response.matricula.semestre))
        else:
            print("Algum dos campos não foi preenchido corretamente")
    else:
        print("Opção inválida")

def main():

    print("1 - Listar Alunos")
    print("2 - Alterar Nota")
    print("3 - Alterar Faltas")
    print("4 - Listar Disciplinas do Curso")
    print("5 - Listar Disciplinas do Aluno")
    print("6 - Inserir Matricula")
    # Recebe a opção do usuário
    while True:
        opcao = input("Digite a opção desejada: ")
        # Verifica se a opção é válida
        if(opcao.isdigit()):
            dadosRequisicao(opcao)
        else:
            print("Opção inválida")

main()


import matplotlib as mpl
from matplotlib.colors import LightSource
from matplotlib.collections import PolyCollection
import matplotlib.gridspec as gridspec
import matplotlib.patches as patches
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
import pandas as pd

from .tnautoregression import TNToolsAutoregression
from .tninference import TNToolsSimilarities

new_rc_params = {'text.usetex': False,
                 'svg.fonttype': 'none',
                 'lines.linewidth': 1}

mpl.rcParams.update(new_rc_params)

class TNToolsPlot:
    """
    This class is part of the toolset for usage of Twin Network (TN)
    on evaluation purposes.
    This part of the toolset is used to plot embedding similarities.
    """

    def __init__(self):
        self.plot_cmap = mpl.cm.get_cmap('viridis')
        self.plot_line_alpha_fg = 1
        self.plot_line_colors = ["#fde725",
                                 "#35b779",
                                 "#31688e",
                                 "#1f4696",
                                 "#ed1c24",
                                 '#6abd45'
                                 ]
        self.plot_line_colors_difference = ["#25858e",
                                            "#482173"]
        self.plot_line_width = 1

        self.plot_fig_dpi = 300
        self.plot_fig_size = (5, 3)
        self.plot_fig_size_square = (4, 4)

        self.plot_fontsize_large = 8
        self.plot_fontsize_small = 6

        self.plot_marker_size = self.plot_line_width * 5
        self.plot_marker_size_mean = self.plot_line_width * 8

        self.plot_text_weight = 'ultralight'

        self.tools_autoregression = TNToolsAutoregression()
        self.tools_similarities = TNToolsSimilarities()

    def fn_similarity_self_cmap_custom(self, **kwargs):
        """
        Creates a colormap based on predefined
        'matplotlib' colormaps. Colors are adjusted
        such that color changes occur mainly in
        upper range of values.
        """
        samples = self.fn_similarity_self_cmap_custom_samples_exponential(
            **kwargs)
        list_colors = [self.plot_cmap(s) for s in samples]
        lscmap = mpl.colors.LinearSegmentedColormap.from_list("cmap_custom",
                                                              list_colors)
        return lscmap

    @staticmethod
    def fn_similarity_self_cmap_custom_samples_exponential(lamb=0.2,
                                                           **kwargs):
        """
        Generates 100 samples based on a
        decaying exponential distribution.
        """
        n_samples = 100
        xs = np.linspace(0, n_samples, n_samples)
        ys = np.exp(lamb * xs)
        ys = (ys - np.min(ys)) / (np.max(ys) - np.min(ys))

        grads = np.gradient(ys)
        tp_grad = next(grad for grad in grads if grad >= 1 / n_samples)
        x_tp_grad = np.where(np.isclose(grads, tp_grad))

        if kwargs.get("verbose", False):
            print(f"Index of change: {x_tp_grad[0] / n_samples}")

        return ys

    def plot_distribution_similarities(self,
                                       values_similarities,
                                       colors,
                                       labels,
                                       **kwargs):
        """Plot count of similarities as histogram."""
        bins = np.linspace(0, 1, 1000)
        plot_x_mins = list()
        plot_y_maxs = list()

        fig, axs = plt.subplots(dpi=self.plot_fig_dpi,
                                figsize=self.plot_fig_size)

        for i in range(len(values_similarities)):
            b = axs.hist(values_similarities[i],
                         bins=bins,
                         color=colors[i],
                         label=labels[i])
            # Append x position of the lowest bin to list
            for val_y in b[0]:
                if val_y != .0:
                    ind_x_min = list(b[0]).index(val_y)
                    break
            plot_x_mins.append(b[1][ind_x_min])
            # Append max. y-values to list
            plot_y_maxs.append(max(b[0]))

        plt.tick_params(axis='both',
                        which='both',
                        labelsize=self.plot_fontsize_small)

        plt.xlabel('Similarity values',
                   fontsize=self.plot_fontsize_large)
        plt.xlim(left=np.min(plot_x_mins) * 0.9,
                 right=1.01)

        plt.ylim(bottom=0,
                 top=np.max(plot_y_maxs) * 1.1)
        axs.set_xlabel('Similarity values',
                       fontsize=self.plot_fontsize_large)
        axs.set_ylabel('Density',
                       fontsize=self.plot_fontsize_large)
        plt.legend(fontsize=self.plot_fontsize_small)

        if 'path_save' in kwargs:
            plt.savefig(kwargs['path_save'])
        plt.show()
        plt.close(fig)

    def plot_distribution_similarities_multiple(self,
                                                similarities,
                                                **kwargs):
        """
        Plot the distributions of the similarities at multiple indices
        of test image series.
        """
        # We have to un-nest the similarities for each timepoint first, as
        # the similarities are stored separately
        similarities_mean = [np.mean(_v_sim) for _v_sim in
                             similarities.values()]
        similarities_widths = [max(_v_sim) - min(_v_sim) for _v_sim in
                               similarities.values()]

        num_timepoints_reference = len(similarities_mean)

        plot_atp_min_correction = int(kwargs.get('intervals', 4))
        plot_colors = ["#431c53", '#1f4497']

        plot_x_ticks = list(range(0, num_timepoints_reference, 50))

        fig, axs = plt.subplots(1,
                                dpi=self.plot_fig_dpi,
                                figsize=self.plot_fig_size)
        axs.plot(range(len(similarities_mean)),
                 similarities_mean,
                 color=plot_colors[0],
                 linewidth=self.plot_line_width,
                 label="Similarity mean")
        axs.set_ylabel('Average cosine similarity φ',
                       fontsize=self.plot_fontsize_large)
        axs.set_xlabel('Acquisition time (min)',
                       fontsize=self.plot_fontsize_large)
        axs.tick_params(axis='both',
                        which='both',
                        labelsize=self.plot_fontsize_small)
        axs.set_xlim(left=0,
                     right=num_timepoints_reference)
        axs.set_xticks(plot_x_ticks,
                       [str(x * plot_atp_min_correction)
                        for x in plot_x_ticks],
                       fontsize=self.plot_fontsize_small)

        axs2 = plt.twinx()
        axs2.plot(range(len(similarities_mean)),
                  similarities_widths,
                  color=plot_colors[1],
                  linewidth=self.plot_line_width,
                  label='Similarity range')
        axs2.grid(False)
        axs2.tick_params(axis='both',
                         which='both',
                         labelsize=self.plot_fontsize_small)
        axs2.set_ylabel('Similarity distribution range',
                        fontsize=self.plot_fontsize_large)
        if 'path_save' in kwargs:
            plt.savefig(kwargs['path_save'])
        plt.show()
        plt.close()

    def plot_distribution_stages_dev_fractions(self,
                                               values_histograms,
                                               num_timepoints_reference,
                                               colors,
                                               labels,
                                               **kwargs):
        """
        Plot a histogram to show where the
        predictions for an acquisition timepoint lie.
        """
        plot_atp_min_correction = int(kwargs.get('intervals', 4))
        plot_x_ticks = list(range(0, num_timepoints_reference, 50))
        bins = list(range(0, num_timepoints_reference))

        fig, ax_hist = plt.subplots(dpi=self.plot_fig_dpi,
                                    figsize=self.plot_fig_size)
        for i in range(len(values_histograms)):
            alpha = np.sqrt(self.plot_line_alpha_fg / len(values_histograms))
            counts, bins = np.histogram(values_histograms[i], bins=bins)
            plt.hist(bins[:-1], bins,
                     alpha=self.plot_line_alpha_fg,
                     color=colors[i] + (alpha,),
                     label=labels[i],
                     weights=[c / sum(counts) * 100 for c in counts])

        ax_hist.set_ylabel('Percentage of predictions',
                           fontsize=self.plot_fontsize_large)
        ax_hist.set_xlabel('Predicted reference developmental time (min)',
                           fontsize=self.plot_fontsize_large)
        ax_hist.tick_params(axis='both',
                            which='both',
                            labelsize=self.plot_fontsize_small)
        ax_hist.set_xlim(left=0, right=num_timepoints_reference)
        ax_hist.set_xticks(plot_x_ticks,
                           [str(x * plot_atp_min_correction)
                            for x in plot_x_ticks],
                           fontsize=self.plot_fontsize_small)
        plt.legend()
        if 'path_save' in kwargs:
            plt.savefig(kwargs['path_save'])
        plt.show()

        plt.close()

    def plot_similarity_self_2d(self, similarities, **kwargs):
        """
        Plot similarities of images from a time-series image sequence
        of an embryo to earlier images from the same series as
        two-dimensional matrix.

        Parameters
        ----------
        similarities: list
            List of lists with similarity values. Each sublist contains
            similarity values between one test image and all earlier
            images in the test sequence. Thus, the number of similarities
            must be number of time points in the acquisition - 1.
        **kwargs: Variable keyword arguments
            See below.

        Keyword Arguments
        -----------------
        intervals: int/float
            Time intervals (min), at which test embryo images
            were acquired. Default is 4 minutes. Use this
            to adjust axis labels to be labelled with minutes.
        """
        num_imgs_test = len(similarities) + 1
        plot_atp_min_correction = int(kwargs.get('intervals', 4))
        plot_xy_ticks = list(range(0, num_imgs_test, 50))

        if kwargs.get("color_adjust", False):
            plot_colors_hlf = self.fn_similarity_self_cmap_custom(**kwargs)
        else:
            plot_colors_hlf = self.plot_cmap

        xs_grid, ys_grid, zs_grid_plot = self.tools_autoregression.\
            fn_2d_sims_to_arrays(
                similarities,
                num_imgs_test,
                square=True
            )

        # Figure
        f, ax = plt.subplots(dpi=self.plot_fig_dpi,
                             figsize=self.plot_fig_size_square)
        f.tight_layout(rect=[0.0, 0.00, 0.8, 1.0])

        # Plot
        ax.imshow(zs_grid_plot,
                  cmap=plot_colors_hlf)

        # Labels and titles
        ax.tick_params(axis='both',
                       which='both',
                       labelsize=self.plot_fontsize_small)
        ax.set_xlabel('Time (min)',
                      fontsize=self.plot_fontsize_large)
        ax.set_ylabel('Time (min)',
                      fontsize=self.plot_fontsize_large)
        ax.set_xlim(left=0,
                    right=len(similarities))
        ax.set_ylim(bottom=0,
                    top=len(similarities))
        ax.set_xticks(plot_xy_ticks,
                      [str(a * plot_atp_min_correction)
                       for a in plot_xy_ticks],
                      fontsize=self.plot_fontsize_small)
        ax.set_yticks(plot_xy_ticks,
                      [str(a * plot_atp_min_correction)
                       for a in plot_xy_ticks],
                      fontsize=self.plot_fontsize_small)

        divider = make_axes_locatable(ax)
        sm = plt.cm.ScalarMappable(cmap=plot_colors_hlf)
        cax = divider.append_axes("right",
                                  size="5%",
                                  pad=0.05)
        cax.tick_params(axis='both',
                        which='both',
                        labelsize=self.plot_fontsize_small)
        cbar = f.colorbar(sm,
                          cmap=plot_colors_hlf,
                          cax=cax)
        cbar.ax.set_ylabel('Cosine similarity ϕ',
                           fontsize=self.plot_fontsize_large)

        if 'path_save' in kwargs:
            plt.savefig(kwargs['path_save'])
        else:
            plt.show()
        plt.close()

    def plot_similarity_self_3d(self,
                                similarities,
                                **kwargs):
        """
        Plot similarities of images from a time-series image sequence
        of an embryo to earlier images from the same series as
        three-dimensional surface plot.

        Parameters
        ----------
        similarities: list
            List of lists with similarity values. Each sublist contains
            similarity values between one test image and all earlier
            images in the test sequence. Thus, the number of similarities
            must be number of time points in the acquisition - 1.
        **kwargs: Variable keyword arguments
            See below.

        Keyword Arguments
        -----------------
        intervals: int/float
            Time intervals (min), at which test embryos
            were acquired. Default is 4 minutes. Use this
            to adjust axis labels to minute.
        plot_index: int
            Index of the last image that should be included in the plot.
            We assume 1-based indexing for indexing of the images. Thus,
            the lowest image index that can be given is 2, as the first
            comparison between two images is between images at indices
            2 and 1.
        rotation_angle: int
            Rotation of plot along z-axis.
        """
        # Number of images in the dataset is by 1 lager
        # than number of similarities
        num_imgs_test = len(similarities) + 1
        # This is the index of the image until which similarities
        # should be plotted.
        plot_index = kwargs.get("plot_index", len(similarities))

        print(f"[INFO] Number of similarity lists: {len(similarities)}")

        assert num_imgs_test >= plot_index >= 2, \
            f"Plot index is wrong." \
            f"\nLowest plot index is 2, " \
            f"as first comparison is image nr. 2 vs. image nr. 1. " \
            f"\nHighest plot index is {num_imgs_test}, " \
            f"as this is the number of images in the dataset."

        # Plot parameters
        plot_alpha_polygon = 0.5
        plot_atp_min_correction = int(kwargs.get('intervals', 4))
        plot_bottom = 0.0
        plot_color_line_marker = self.plot_line_colors[5]
        plot_color_polygon = plot_color_line_marker
        plot_grid_linewidth = 0.5
        plot_tick_pad = -2
        plot_xy_ticks = list(range(0, num_imgs_test, 50))

        mpl.rcParams.update({'axes.linewidth': plot_grid_linewidth,
                             'grid.linewidth': plot_grid_linewidth,
                             'xtick.major.width': plot_grid_linewidth,
                             'xtick.major.pad': plot_tick_pad,
                             'ytick.major.width': plot_grid_linewidth,
                             'ytick.major.pad': plot_tick_pad})

        # We used 1-indexing for the image indices and the number of
        # similarities is supposed to be 1 smaller than the number of
        # images. Thus, we can slice the array of similarities until
        # plot_index - 1 (will be excluded from slice). As a result,
        # the last list of similarities shown here corresponds to
        # similarities[plot_index - 2], which can be used to plot a
        # line at the edge.
        xs_grid, ys_grid, zs_grid_plot, zs_grid_colors = \
            self.tools_autoregression.fn_3d_sims_to_arrays(
                similarities[:plot_index - 1],
                num_imgs_test
            )

        # Figure
        fig = plt.figure(dpi=self.plot_fig_dpi,
                         figsize=self.plot_fig_size)
        spec = gridspec.GridSpec(figure=fig,
                                 ncols=2,
                                 nrows=1,
                                 width_ratios=[1, 0.05])
        ax = fig.add_subplot(spec[0, 0],
                             projection='3d')
        cax = fig.add_subplot(spec[0, 1])

        scatter = ax.plot_surface(xs_grid, ys_grid, zs_grid_plot,
                                  cmap=self.plot_cmap,
                                  edgecolors=(1., 1., 1., 1.),
                                  alpha=1.0,
                                  linewidth=0,
                                  antialiased=False,
                                  shade=False)

        # Set axis range
        xlim_max = ax.get_xlim()[1]
        ylim_min = ax.get_ylim()[0]
        zlim_min = -0.017

        if kwargs.get("plot_line", False):
            line_x, line_y, line_z = \
                self.tools_autoregression.fn_3d_sims_line_plot(
                    similarities,
                    plot_index
                )

            # Line plots
            ax.plot(line_x, line_y, line_z,
                    color=plot_color_line_marker,
                    linewidth=self.plot_line_width,
                    zorder=10)

            vertices = [self.tools_autoregression.fn_polygon_under_graph(
                line_y,
                line_z,
                zlim_min
            )]

            poly = PolyCollection(
                vertices,
                facecolors=[plot_color_polygon]*len(vertices),
                alpha=plot_alpha_polygon
            )

            ax.add_collection3d(poly,
                                zs=[plot_index],
                                zdir='x')

            # Line orthogonal to x-axis
            ax.plot([plot_index, plot_index],
                    [ylim_min, plot_index],
                    [zlim_min, zlim_min],
                    color=plot_color_line_marker,
                    linewidth=self.plot_line_width)
            # Line orthogonal to y-axis
            ax.plot([plot_index, xlim_max],
                    [plot_index, plot_index],
                    [zlim_min, zlim_min],
                    color=plot_color_line_marker,
                    linewidth=self.plot_line_width)
            # Line parallel to z-axis
            ax.plot([plot_index, plot_index],
                    [plot_index, plot_index],
                    [zlim_min, similarities[plot_index - 2][-1]],
                    color=plot_color_line_marker,
                    linewidth=self.plot_line_width)

        # Labels and titles
        ax.tick_params(axis='both',
                       which='both',
                       labelsize=self.plot_fontsize_small)
        ax.set_xlabel('Time (min)',
                      fontsize=self.plot_fontsize_large)
        ax.set_ylabel('Time (min)',
                      fontsize=self.plot_fontsize_large)
        ax.set_zlabel('Cosine similarity ϕ',
                      fontsize=self.plot_fontsize_large)
        ax.set_xlim3d(left=0,
                      right=len(similarities))
        ax.set_xticks(plot_xy_ticks,
                      [str(a * plot_atp_min_correction)
                       for a in plot_xy_ticks],
                      fontsize=self.plot_fontsize_small)
        ax.set_yticks(plot_xy_ticks,
                      [str(a * plot_atp_min_correction)
                       for a in plot_xy_ticks],
                      fontsize=self.plot_fontsize_small)
        ax.set_ylim3d(bottom=0,
                      top=len(similarities))
        ax.set_zlim3d(bottom=plot_bottom,
                      top=1.0)

        # Colorbar
        scatter.set_clim(0.0, 1.0)
        cax.set_ylim(bottom=0.0, top=1.0)
        cax.set_yticks(list(np.arange(0, 1, 0.1)),
                       list(np.arange(0, 1, 0.1)),
                       fontsize=self.plot_fontsize_small)
        cax.tick_params(pad=-plot_tick_pad)
        cbar = plt.colorbar(scatter,
                            cax=cax,
                            format='%.1f',
                            fraction=0.05,
                            )
        cbar.set_label(label="Cosine similarity ϕ",
                       size=self.plot_fontsize_large,)
        cax.set_aspect(10)

        if isinstance(kwargs.get('rotation_angle', None), int):
            ax.view_init(
                25,
                int(kwargs.get('rotation_angle', -60))
            )

        if 'path_save' in kwargs:
            plt.savefig(kwargs['path_save'])
        else:
            plt.show()
        plt.close()

    def plot_similarity_curve(self, path_df, path_save=None, **kwargs):
        """
        Plot mean of calculated similarities of images
        from dataframe.
        """
        # Dataframe
        if isinstance(path_df, str):
            path_df = pd.read_csv(path_df)
        df = path_df
        df_mean = df.mean(axis=1)
        df_similarity_high = df.loc[df['Anch_sim_1'] > 0.8]
        num_timepoints_reference = len(df)

        # Plot parameters
        plot_atp_min_correction = int(kwargs.get('intervals', 4))
        plot_label_x = f'Time (min)'
        plot_label_y = "Cosine similarity φ"
        plot_xs = range(1, num_timepoints_reference + 1)
        plot_x_ticks = list(range(0, num_timepoints_reference, 50))

        # Figure
        fig, (ax_hist, ax_box) = plt.subplots(
            2,
            dpi=self.plot_fig_dpi,
            figsize=self.plot_fig_size,
            gridspec_kw={"height_ratios": (.85, .15)},
            sharex=True
        )

        # Plot similarities
        ax_hist.scatter(plot_xs,
                        df_mean,
                        alpha=self.plot_line_alpha_fg,
                        c=self.plot_line_colors[2],
                        label='Mean',
                        marker='o',
                        linewidth=0,
                        s=self.plot_marker_size)

        ax_hist.set_xlim(left=0,
                         right=num_timepoints_reference)
        ax_hist.set_ylabel(plot_label_y,
                           fontsize=self.plot_fontsize_large,
                           weight=self.plot_text_weight)
        ax_hist.set_ylim(0, 1)
        ax_hist.tick_params(axis='both',
                            labelsize=self.plot_fontsize_small)
        ax_hist.set_xticks(plot_x_ticks,
                           [str(x * plot_atp_min_correction)
                            for x in plot_x_ticks],
                           fontsize=self.plot_fontsize_small)

        ax_hist.tick_params(axis='x',
                            which='both',
                            bottom=False,
                            top=False,
                            labelbottom=False)
        plt.setp(ax_hist.get_xticklabels(), visible=False)

        # Plot boxplot
        ax_box.scatter(df_similarity_high['Anch_sim_1'].idxmax(),
                       [0],  # y-value for plot in boxplot axis
                       c='r',
                       s=self.plot_marker_size_mean)
        ax_box.set_xlabel(plot_label_x,
                          fontsize=self.plot_fontsize_large,
                          weight=self.plot_text_weight)
        boxplot = ax_box.boxplot(
            x=df_similarity_high.index.values,
            boxprops={'facecolor': self.plot_line_colors[2],
                      'linewidth': self.plot_line_width},
            capprops={'linewidth': self.plot_line_width},
            flierprops={'marker': '.',
                        'markersize': self.plot_marker_size},
            medianprops={'color': (0, 0, 0),
                         'linewidth': self.plot_line_width},
            patch_artist=True,
            positions=[0],
            vert=False,
            widths=0.5,
            whiskerprops={'linewidth': self.plot_line_width},
            zorder=0)
        ax_box.tick_params(axis='both', labelsize=self.plot_fontsize_small)
        ax_box.set_yticks([])
        ax_box.linewidth = 0.1

        # Quartile highlight
        q25_mean = boxplot["whiskers"][0].get_path().get_extents().x1
        median_mean = boxplot["medians"][0].get_path().get_extents().x1
        q75_mean = boxplot["whiskers"][1].get_path().get_extents().x0

        ax_hist.add_patch(
            patches.Rectangle((q25_mean, 0),
                              q75_mean - q25_mean,
                              1,
                              facecolor=self.plot_line_colors[2],
                              alpha=0.1))
        ax_hist.plot([median_mean, median_mean],
                     [0, 1],
                     color=self.plot_line_colors[2],
                     linewidth=self.plot_line_width,
                     alpha=0.4)

        ax_box.add_patch(
            patches.Rectangle((q25_mean, -0.5),
                              q75_mean - q25_mean,
                              1,
                              facecolor=self.plot_line_colors[2],
                              alpha=0.1))
        ax_box.plot([median_mean, median_mean],
                    [-0.5, 0.5],
                    color=self.plot_line_colors[2],
                    linewidth=self.plot_line_width,
                    alpha=0.4)

        # Formatting
        plt.subplots_adjust(hspace=0)

        if path_save is not None:
            plt.savefig(path_save, dpi=fig.dpi)
        plt.show()
        plt.close(fig)

    def plot_similarity_maxima(self, df_sims, **kwargs):
        """
        Plot maxima of similarity sequence.

        Parameters
        ----------
        df_sims: pandas.core.frame.DataFrame
        **kwargs: See below

        Keyword Arguments
        -----------------
        intervals_x: int
            Time intervals (min), at which reference embryos
            were acquired. Default is 4 minutes.
        intervals_y: int
            Time intervals (min), at which reference embryos
            were acquired. Default, corresponding to default
            set of reference embryos, is 4 minutes.
        """

        num_timepoints_query = df_sims.shape[0]
        num_timepoints_reference = df_sims.shape[1]

        plot_atp_min_correction_x = int(kwargs.get('intervals_x', 4))
        plot_atp_min_correction_y = int(kwargs.get('intervals_y', 4))
        plot_axis = 1
        plot_label_x = "Query embryo time (min)"
        plot_label_y = "Reference embryo time (min)"

        # Make axes equal length
        # Calculate durations of data sets
        duration_query = num_timepoints_query * \
                         plot_atp_min_correction_x
        duration_reference = num_timepoints_reference * \
                             plot_atp_min_correction_y
        # Get longer duration
        plot_range = max(duration_query, duration_reference)

        # Make tick labels based on timepoints
        plot_tick_labels = [int(i) for i in list(range(0, plot_range, 200))]

        # Divide timepoints by acquisition time intervals
        # to get indices for plotting
        plot_xs = range(1, num_timepoints_query + 1)
        plot_x_ticks = [plot_tick_label / plot_atp_min_correction_x
                        for plot_tick_label in plot_tick_labels]
        plot_y_ticks = [plot_tick_label / plot_atp_min_correction_y
                        for plot_tick_label in plot_tick_labels]

        plot_maxima = df_sims.idxmax(axis=plot_axis)
        plot_true_values = kwargs.get("true_values", [])

        # Plot
        fig, axs = plt.subplots(dpi=self.plot_fig_dpi,
                                figsize=self.plot_fig_size_square)

        axs.scatter(plot_xs,
                    plot_maxima,
                    alpha=self.plot_line_alpha_fg,
                    c=self.plot_line_colors[3],
                    label='Mean',
                    marker='o',
                    linewidth=0,
                    s=self.plot_marker_size)
        axs.plot(plot_true_values,
                 c=self.plot_line_colors[4],
                 label='Theoretical true value',
                 lw=self.plot_line_width)

        axs.set_xlabel(plot_label_x,
                       fontsize=self.plot_fontsize_large)
        axs.set_xlim(0, int(plot_range / plot_atp_min_correction_x))
        axs.set_xticks(plot_x_ticks,
                       plot_tick_labels,
                       fontsize=self.plot_fontsize_small)

        axs.set_ylabel(plot_label_y,
                       fontsize=self.plot_fontsize_large)
        axs.set_ylim(0, int(plot_range / plot_atp_min_correction_y))
        axs.set_yticks(plot_y_ticks,
                       plot_tick_labels,
                       fontsize=self.plot_fontsize_small)

        if 'path_save' in kwargs:
            plt.savefig(kwargs['path_save'], dpi=self.plot_fig_dpi)
        plt.show()
        plt.close(fig)

    def plot_similarity_differences(self, df_earlier, df_later, **kwargs):
        """
        Plot differences in calculated similarities
        of two subsequently acquired images.
        """
        # Calculate similarity differences
        df_earlier_mean, df_later_mean, df_diff = \
            self.tools_similarities.fn_calculate_similarity_differences(
                df_earlier, df_later
            )

        num_timepoints_reference = len(df_earlier_mean)
        plot_atp_min_correction = int(kwargs.get('intervals', 4))
        plot_xs = list(range(1, num_timepoints_reference + 1))
        plot_x_ticks = list(range(0, num_timepoints_reference, 50))

        fig, ax_hist = plt.subplots(1,
                                    dpi=self.plot_fig_dpi,
                                    figsize=self.plot_fig_size)

        ax_hist.scatter(plot_xs,
                        df_earlier_mean,
                        alpha=self.plot_line_alpha_fg,
                        c=self.plot_line_colors_difference[0],
                        label='Earlier',
                        marker='o',
                        linewidth=0,
                        s=self.plot_marker_size)
        ax_hist.scatter(plot_xs,
                        df_later_mean,
                        alpha=self.plot_line_alpha_fg,
                        c=self.plot_line_colors_difference[1],
                        label='Later',
                        marker='o',
                        linewidth=0,
                        s=self.plot_marker_size)
        ax_hist.scatter(plot_xs,
                        df_diff,
                        alpha=self.plot_line_alpha_fg,
                        c=self.plot_line_colors[3],
                        label='Difference',
                        marker='o',
                        linewidth=0,
                        s=self.plot_marker_size)
        ax_hist.set_ylabel('Cosine similarity φ',
                           fontsize=self.plot_fontsize_large)
        ax_hist.set_xlabel('Reference time (min)',
                           fontsize=self.plot_fontsize_large)
        ax_hist.tick_params(axis='both', which='both',
                            labelsize=self.plot_fontsize_small)
        ax_hist.set_xlim(left=0, right=num_timepoints_reference)
        ax_hist.set_xticks(plot_x_ticks,
                           [str(x * plot_atp_min_correction)
                            for x in plot_x_ticks],
                           fontsize=self.plot_fontsize_small)
        ax_hist.set_ylim(-0.2, 1)

        ax_hist.spines['left'].set_position('zero')
        ax_hist.spines['bottom'].set_position('zero')
        ax_hist.xaxis.set_ticks_position('bottom')
        ax_hist.yaxis.set_ticks_position('left')

        lgnd = ax_hist.legend()
        for lgndHandle in lgnd.legendHandles:
            lgndHandle._sizes = [30]

        if kwargs.get("path_save", None) is not None:
            plt.savefig(kwargs["path_save"], dpi=self.plot_fig_dpi)
        plt.show()
        plt.close(fig)

    def plot_similarity_zscores_inbatch(self, similarities, **kwargs):
        """
        Plot calculated similarities of multiple embryos in one batch
        for multiple image indices of these embryos.

        Parameters
        ----------
        similarities: pandas.core.frame.DataFrame
            A pandas DataFrame containing similarity values
            or zscores. Values should be sorted by embryo
            names (column names) and image indices (row indices).
        **kwargs: Variable keyword arguments
            See below.

        Keyword Arguments
        -----------------
        intervals_x: int/float
            Time intervals (min), at which test embryo
            images were acquired. Default is 4 minutes.
        """
        columns_embryos = list(similarities.columns)
        num_embryos = len(columns_embryos)
        num_indices = len(similarities.index)

        plot_atp_min_correction = kwargs.get("intervals_x", 2)
        plot_xs = list(range(1, num_indices + 1))
        plot_x_ticks = list(range(0, num_indices, 50))

        fig, ax = plt.subplots(1,
                               dpi=self.plot_fig_dpi,
                               figsize=self.plot_fig_size)

        for column_embryo in columns_embryos:
            color = self.plot_cmap(
                columns_embryos.index(column_embryo) / num_embryos)

            ax.scatter(plot_xs,
                       similarities[column_embryo],
                       alpha=self.plot_line_alpha_fg,
                       c=[color] * len(plot_xs),
                       label=column_embryo,
                       linewidth=self.plot_line_width,
                       marker='o',
                       s=self.plot_line_width
                       )

        ax.set_xlabel('Time (min)',
                      fontsize=self.plot_fontsize_large)
        ax.set_xticks(plot_x_ticks,
                      [str(x * plot_atp_min_correction)
                       for x in plot_x_ticks],
                      fontsize=self.plot_fontsize_small)
        ax.set_xlim(left=0,
                    right=num_indices)
        ax.set_ylabel('Cumulative z-score',
                      fontsize=self.plot_fontsize_large)
        ax.tick_params(axis='both',
                       which='both',
                       labelsize=self.plot_fontsize_small)
        ax.legend(fontsize=self.plot_fontsize_small,
                  ncol=2)
        if kwargs.get('path_save', None) is not None:
            _ = plt.savefig(kwargs['path_save'],
                            dpi=300)
        plt.show()
        plt.close(fig)


import requests
import json
import os
from dotenv import load_dotenv
import time
import datetime
import pytz

# start timer to see how long it takes
start_time = time.time()

# Convert timestamp to human-readable format and Seattle timezone
seattle_tz = pytz.timezone('America/Los_Angeles')
start_dt = datetime.datetime.fromtimestamp(start_time, tz=seattle_tz).isoformat()

print(f"Script started at: {start_dt}")

# Load environment variables from .env file
load_dotenv()

directline_secret = os.getenv("AZURE_DIRECT_LINE_SECRET")
directline_url = os.getenv("AZURE_DIRECT_LINE_URL")
headers = {
    'Authorization': 'Bearer ' + directline_secret,
}

message_receive_time = None
try:
    print("Starting a conversation with Azure...")
    # Start a conversation
    response_start_time = time.time()
    response = requests.post(directline_url, headers=headers)
    response.raise_for_status() # raise exception if invalid response
    conversation_time = time.time() - response_start_time
    convo = response.json()

    if 'conversationId' in convo and 'token' in convo:
        conversation_id = convo['conversationId']
        token = convo['token']
    else:
        print("Invalid JSON response: ", convo)
        exit(1)

    # Timer for URL building
    print("Building the URL for the message...")
    url_start_time = time.time()
    message_url = f'{directline_url}/{conversation_id}/activities'
    url_end_time = time.time()
    url_building_time = url_end_time - url_start_time

    headers['Authorization'] = 'Bearer ' + token
    message = {
        'type': 'message',
        'from': {
            'id': 'not a computer man',
            'role': 'user'
        },
        'text': 'Hello, bot! tell me a story about seattle.',
        'locale': 'en-US'
    }
    # Print the request payload
    print("Sending message to Azure...")
    print("Request Payload: ")
    print(json.dumps(message, indent=4))
    # Send the message
    message_send_time = time.time()
    response = requests.post(message_url, headers=headers, json=message)
    response.raise_for_status() # raise exception if invalid response
    # Get the bot's response
    print("Getting response from Azure...")
    response = requests.get(message_url, headers=headers)
    response.raise_for_status() # raise exception if invalid response
    message_receive_time = time.time()
    azure_processing_time = message_receive_time - message_send_time
    # Print out the response
    print("Response Payload: ")
    print(json.dumps(response.json(), indent=4))
except requests.exceptions.HTTPError as errh:
    print ("Http Error:",errh)
except requests.exceptions.ConnectionError as errc:
    print ("Error Connecting:",errc)
except requests.exceptions.Timeout as errt:
    print ("Timeout Error:",errt)
except requests.exceptions.RequestException as err:
    print ("Oops: Something Else",err)

# end total script timing
end_time = time.time()
end_dt = datetime.datetime.fromtimestamp(end_time, tz=seattle_tz).isoformat()
total_time_elapsed = end_time - start_time

if message_receive_time:
    print(f"\nTransaction finished!")
    print(f"Script started at: {start_dt}")
    print(f"Time to build the URL: {url_building_time:.9f} seconds.")
    print(f"Sent to Azure at: {datetime.datetime.fromtimestamp(message_send_time, tz=seattle_tz).isoformat()}")
    print(f"Received a response from Azure at: {datetime.datetime.fromtimestamp(message_receive_time, tz=seattle_tz).isoformat()}")
    print(f"Total Azure processing time: {azure_processing_time:.9f} seconds")
print(f"Script finished at: {end_dt}")
print(f"Total script time to run: {total_time_elapsed:.9f} seconds.")
print("\n*******************\nWHAT JUST HAPPENED: \n"
      "1. The script started and we loaded Direct Line API credentials from the environment. \n"
      "2. A new conversation with the Azure Bot was started. \n"
      "3. A URL was built for a new message to be sent to the bot. \n"
      "4. A message was sent to the Azure Bot asking to tell a story about Seattle. \n"
      "5. We waited for a response from Azure Bot. \n"
      "6. Once the message was received, we pretty printed the response. \n"
      "7. Throughout the process, timestamps were captured at each key stage and total times taken for key interactions were calculated.")


# There should be a readme.md file bundled with this script.  Please refer to it if you have any questions.
import math
import psycopg2
import time

from multiprocessing import Pool
from os import environ
from threading import Lock

# DEFINE THIS ENVIRONMENT VARIABLE BEFORE RUNNING!
# Obvs, this is the connection string to the database.
CONNECTION_STRING = environ["DATABASE_URL"]

MULTIPROCESSING_POOLS = 4  # This was chosen after much fine tuning.  Adding more might slow things down.
CHUNK_SIZE = 50000
TEMPORARY_TABLE_NAME = "temp_awards_ops494"

# Unlogged prevents updates to the log file.  This should be safe even in
# replication environments because we don't want this table replicated, only
# the final updates to the Awards tables.  But testing is your friend...
CREATE_TABLE = (
    """
    create unlogged table "%s" (
        id bigint,
        fpds_agency_id text,
        fpds_parent_agency_id text,
        base_exercised_options_val numeric(23, 2)
    )
"""
    % TEMPORARY_TABLE_NAME
)

POPULATE_TABLE = (
    """
    insert into
        "%s"
    select
        tx.award_id,
        max(case when f.transaction_id = a.latest_transaction_id then f.agency_id end)
            agency_id,
        max(case when f.transaction_id = a.latest_transaction_id then f.referenced_idv_agency_iden end)
            referenced_idv_agency_iden,
        sum(cast(f.base_exercised_options_val as numeric))
            base_exercised_options_val
    from
        vw_awards a
        inner join vw_transaction_normalized as tx on tx.award_id = a.id
        inner join vw_transaction_fpds as f on f.transaction_id = tx.id
    group by
        tx.award_id
"""
    % TEMPORARY_TABLE_NAME
)

ADD_PRIMARY_KEY = 'alter table "%s" add primary key (id)' % TEMPORARY_TABLE_NAME

GET_MIN_MAX_SQL = "select min(id), max(id) from vw_awards"

UPDATE_SQL = (
    """
    update
        award_search
    set
        fpds_agency_id = t.fpds_agency_id,
        fpds_parent_agency_id = t.fpds_parent_agency_id,
        base_exercised_options_val = t.base_exercised_options_val
    from
        "%s" t
    where
        t.id = awards.id and awards.id between {minid} and {maxid}
"""
    % TEMPORARY_TABLE_NAME
)

DROP_TABLE = 'drop table if exists "%s"' % TEMPORARY_TABLE_NAME

TABLE_EXISTS = (
    """
    select
        table_name
    from
        information_schema.tables
    where
        table_name = '%s' and table_schema = 'public'
"""
    % TEMPORARY_TABLE_NAME
)

class Counter(object):
    def __init__(self):
        self.value = 0
        self.lock = Lock()

    def increment(self, arg):
        with self.lock:
            self.value += 1

class Timer:
    def __enter__(self):
        self.start = time.perf_counter()
        return self

    def __exit__(self, *args, **kwargs):
        self.end = time.perf_counter()
        self.elapsed = self.end - self.start
        self.elapsed_as_string = self.pretty_print(self.elapsed)

    def snapshot(self):
        end = time.perf_counter()
        return self.pretty_print(end - self.start)

    def estimated_total_runtime(self, ratio):
        end = time.perf_counter()
        elapsed = end - self.start
        est = elapsed / ratio
        return self.pretty_print(est)

    def estimated_remaining_runtime(self, ratio):
        end = time.perf_counter()
        elapsed = end - self.start
        est = max((elapsed / ratio) - elapsed, 0.0)
        return self.pretty_print(est)

    @staticmethod
    def pretty_print(elapsed):
        f, s = math.modf(elapsed)
        m, s = divmod(s, 60)
        h, m = divmod(m, 60)
        return "%d:%02d:%02d.%04d" % (h, m, s, f * 10000)

def execute_chunk(max_id, _min, _max, timer):
    try:
        with psycopg2.connect(dsn=CONNECTION_STRING) as connection:
            connection.autocommit = True  # We are not concerned with transactions.
            with connection.cursor() as cursor:
                with Timer() as t:
                    cursor.execute(UPDATE_SQL.format(minid=_min, maxid=_max))
                row_count = cursor.rowcount
                print(
                    "[{:.2%}] {:,} => {:,}: {:,} updated in {} with an estimated remaining run time of {}".format(
                        _max / max_id,
                        _min,
                        _max,
                        row_count,
                        t.elapsed_as_string,
                        timer.estimated_remaining_runtime(_max / max_id),
                    ),
                    flush=True,
                )
    except Exception as e:
        print("Exception {:,} => {:,}: {}".format(_min, _max, e))
        raise

failure_count = Counter()

with Timer() as overall_timer:

    with psycopg2.connect(dsn=CONNECTION_STRING) as connection:
        connection.autocommit = True  # We are not concerned with transactions.

        with connection.cursor() as cursor:
            print("Checking for temp table...")
            cursor.execute(TABLE_EXISTS)
            if cursor.rowcount > 0:
                print("Temp table found.  Not creating.")
            else:
                print("Temp table not found.  Creating.")
                cursor.execute(CREATE_TABLE)

                print("Populating temp table...", flush=True)
                with Timer() as t2:
                    cursor.execute(POPULATE_TABLE)
                print("Populated temp table in %s" % t2.elapsed_as_string)

                print("Adding primary key to temp table.", flush=True)
                with Timer() as t2:
                    cursor.execute(ADD_PRIMARY_KEY)
                print("Created primary key in %s" % t2.elapsed_as_string)

            print("Finding min/max IDs...")
            cursor.execute(GET_MIN_MAX_SQL)
            results = cursor.fetchall()
            min_id, max_id = results[0]

            print("Min ID: {:,}".format(min_id))
            print("Max ID: {:,}".format(max_id), flush=True)

        pool = Pool(MULTIPROCESSING_POOLS)

        with Timer() as chunk_timer:
            _min = min_id
            while _min <= max_id:
                _max = min(_min + CHUNK_SIZE - 1, max_id)
                pool.apply_async(
                    execute_chunk, (max_id, _min, _max, chunk_timer), error_callback=failure_count.increment
                )
                _min = _max + 1

        pool.close()
        pool.join()

        with connection.cursor() as cursor:
            print("Dropping temp table...")
            cursor.execute(DROP_TABLE)

print("Finished.  Overall run time: %s" % overall_timer.elapsed_as_string)

if failure_count.value > 0:
    print("{:,} queries failed".format(failure_count.value))
    exit(1)


import html
import os
import base64
from telethon.tl.functions.messages import ImportChatInviteRequest as Get
from telethon.tl.types import MessageEntityMentionName
from requests import get
from telethon.tl.functions.photos import GetUserPhotosRequest
from telethon.tl.functions.users import GetFullUserRequest
from Arab import iqthon
from Arab.core.logger import logging
from ..Config import Config
from ..core.managers import edit_or_reply, edit_delete
from ..helpers import reply_id
from ..sql_helper.globals import gvarstatus
from . import spamwatch
plugin_category = "@iqthon"
LOGS = logging.getLogger(__name__)
iqthon_TEXT = gvarstatus("CUSTOM_ALIVE_TEXT") or "╮•• مـعلومات الـشخص من بوت تليثون العرب"
iqthonM = gvarstatus("CUSTOM_ALIVE_EMOJI") or "✦"
iqthonF = gvarstatus("CUSTOM_ALIVE_FONT") or "★•┉ ┉ ┉ ┉ ┉ ┉  ┉ ┉ ┉ ┉•★"

async def get_user_from_event(event):
    if event.reply_to_msg_id:
        previous_message = await event.get_reply_message()
        user_object = await event.client.get_entity(previous_message.sender_id)
    else:
        user = event.pattern_match.group(1)
        if user.isnumeric():
            user = int(user)
        if not user:
            self_user = await event.client.get_me()
            user = self_user.id
        if event.message.entities:
            probable_user_mention_entity = event.message.entities[0]
            if isinstance(probable_user_mention_entity, MessageEntityMentionName):
                user_id = probable_user_mention_entity.user_id
                user_obj = await event.client.get_entity(user_id)
                return user_obj
        if isinstance(user, int) or user.startswith("@"):
            user_obj = await event.client.get_entity(user)
            return user_obj
        try:
            user_object = await event.client.get_entity(user)
        except (TypeError, ValueError) as err:
            await event.edit(str(err))
            return None
    return user_object

async def fetch_info(replied_user, event):
    """Get details from the User object."""
    FullUser = (await event.client(GetFullUserRequest(replied_user.id))).full_user
    replied_user_profile_photos = await event.client(
        GetUserPhotosRequest(user_id=replied_user.id, offset=42, max_id=0, limit=80)    )
    replied_user_profile_photos_count = "لايـوجـد بروفـايـل"
    dc_id = "Can't get dc id"
    try:
        replied_user_profile_photos_count = replied_user_profile_photos.count
        dc_id = replied_user.photo.dc_id
    except AttributeError:
        pass
    user_id = replied_user.id
    first_name = replied_user.first_name
    full_name = FullUser.private_forward_name
    common_chat = FullUser.common_chats_count
    username = replied_user.username
    user_bio = FullUser.about
    is_bot = replied_user.bot
    restricted = replied_user.restricted
    verified = replied_user.verified
    photo = await event.client.download_profile_photo(     user_id,     Config.TMP_DOWNLOAD_DIRECTORY + str(user_id) + ".jpg",    download_big=True  )
    first_name = (      first_name.replace("\u2060", "")
        if first_name
        else ("هذا المستخدم ليس له اسم أول")  )
    full_name = full_name or first_name
    username = "@{}".format(username) if username else ("لايـوجـد معـرف")
    user_bio = "لاتـوجـد نبـذة" if not user_bio else user_bio
    rotbat = "⌁ من مطورين السورس 𓄂𓆃 ⌁" if user_id == 1226408155 else ("⌁ العضـو 𓅫 ⌁")
    rotbat = "⌁ مـالك الحساب 𓀫 ⌁" if user_id == (await event.client.get_me()).id and user_id != 1226408155  else rotbat
    caption = f" {iqthon_TEXT} \n"
    caption += f"ٴ{iqthonF} \n"
    caption += f" {iqthonM}╎الاسـم    ⇠  {full_name}\n"
    caption += f" {iqthonM}╎المعـرف  ⇠  {username}\n"
    caption += f" {iqthonM}╎الايـدي   ⇠  {user_id}\n"
    caption += f" {iqthonM}╎الرتبـــه  ⇠ {rotbat} \n"
    caption += f" {iqthonM}╎الصـور   ⇠  {replied_user_profile_photos_count}\n"
    caption += f" {iqthonM}╎الحساب ⇠  "
    caption += f'{first_name}'
    caption += f"\n {iqthonM}╎البايـو    ⇠  {user_bio} \n"
    caption += f"ٴ{iqthonF} "
    return photo, caption

@iqthon.iq_cmd(pattern="ايدي(?: |$)(.*)",
    command=("ايدي", plugin_category),
    info={
        "header": "لـ عـرض معلومـات الشخـص",
        "الاستـخـدام": " {tr}ايدي بالـرد او {tr}ايدي + معـرف/ايـدي الشخص",
    },
)
async def who(event):
    "Gets info of an user"
    iqthon = await edit_or_reply(event, "⇆")
    if not os.path.isdir(Config.TMP_DOWNLOAD_DIRECTORY):
        os.makedirs(Config.TMP_DOWNLOAD_DIRECTORY)
    replied_user = await get_user_from_event(event)
    try:
        photo, caption = await fetch_info(replied_user, event)
    except AttributeError:
        return await edit_or_reply(iqthon, "**- لـم استطـع العثــور ع الشخــص**")
    message_id_to_reply = event.message.reply_to_msg_id
    if not message_id_to_reply:
        message_id_to_reply = None
    try:
        await event.client.send_file(            event.chat_id,            photo,            caption=caption,            link_preview=False,            force_document=False,            reply_to=message_id_to_reply,            parse_mode="html",        )
        if not photo.startswith("http"):
            os.remove(photo)
        await iqthon.delete()
    except TypeError:
        await iqthon.edit(caption, parse_mode="html")


import pika
import time
from pymongo import MongoClient

print('Start')
time.sleep(10)

connection = pika.BlockingConnection(pika.ConnectionParameters(host='rabbit', port=5672))
channel = connection.channel()
channel.queue_declare(queue='hello')

client = MongoClient(host='database', port=27017)
db = client.mydb
collection = db.mycoll

print('Wait')
def callback(ch, method, properties, body):
    collection.save({"massage":body})

channel.basic_consume(callback, queue='hello', no_ack=True)

channel.start_consuming()
print('End')


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

# You can run the script with a CSV filename as an argument.
#
# python post-ocr.py IMG_20170602_120428.jpg.csv

from __future__ import print_function
import sys
import re, csv, datetime, os
import pdb

# print errors
def eprint(*args, **kwargs):
  print(*args, file=sys.stderr, **kwargs)

def remove_empty_lines(rows, **kwargs):
  # second column defines name, which is defined in all valid rows
  for row in rows:
    if not row[2]: eprint('Removing potentially empty line: '+",".join(row))
  return [row for row in rows if row[2]]

# remove the header line that is printed on photographed pages
def remove_header_line(rows, **kwargs):
#  if 'VIERAILIJAN NIMI' in rows[0][1]: del rows[0]
#  return rows
  return [row for row in rows if not 'VIERAILIJAN NIMI' in row[2]]

# in beginning, string with name actually starts with card number - this column
# to be split
def add_card_number(rows, **kwargs):
  for row in rows:
    # if string starts with number or Xs, then it's a card number
    st = re.search('([0-9]+|[xX]+) (.*)', row[2])
    if st:
      card_number = st.group(1)
      row[2] = st.group(2)
    else:
      card_number = ''
    # add card_number as last element in list
    row.append(card_number)
  return rows

def add_group_id(rows, **kwargs):
  current_host_name = ''
  current_group_count = 0
  # default group id
  current_group_id = rows[0][0] + '-' + str(current_group_count)
  for row in rows:
    if row[3] and row[3] != current_host_name:
      current_host_name = row[3]
      current_group_count += 1
      current_group_id = row[0] + '-' + str(current_group_count)
    # add group_id as last element in list
    row.append(current_group_id)
  return rows

def add_index(rows, **kwargs):
  index = 0
  for row in rows:
    row.insert(0, row[0] + '-' + str(index))
    index += 1
  return rows

# time is often garbled, let's try to convert it into standard format HH:MM
def fix_time(rows, **kwargs):
  for row in rows:
    orig_time = row[2]
    hour = ''
    if row[2]:
      st = re.search('(\d{1,2})[^\d](\d{2})', row[2])
      if st:
        hour = st.group(1)
        minute = st.group(2)
      if re.search('\d{4}', row[2]):
        hour = row[2][:2]
        minute = row[2][2:4]
      elif re.search('\d{3}', row[2]):
        hour = row[2][:1]
        minute = row[2][1:3]
    if hour:
      row[2] = hour+':'+minute
    row.append(orig_time)
  return rows

# fill in time on rows where it's undefined, check time and date format
def fill_time(rows, **kwargs):
  dt = datetime.datetime.strptime(kwargs['date'], '%Y-%m-%d')
  # default time
  current_time = dt.strftime('%Y-%m-%d %H:%M')
  for row in rows:
    if row[2]:
      if re.search('\d{1,2}:\d{1,2}', row[2]):
        date_string = '{} {}'.format(kwargs['date'], row[2])
        try:
          dt = datetime.datetime.strptime(date_string, '%Y-%m-%d %H:%M')
          current_time = dt.strftime('%Y-%m-%d %H:%M')
        except:
          # current_time remains previously set value
          eprint('Invalid time format encountered: '+",".join(row))
    # overwrite column
    row[2] = current_time
  return rows

# fill in host information
def fill_host(rows, **kwargs):
  current_host = ''
  for row in rows:
    if row[4]: current_host = row[4]
    row[4] = current_host
  return rows

def fill_additional_info(rows, **kwargs):
  current_info = ''
  for row in rows:
    if row[5]: current_info = row[5]
    row[5] = current_info
  return rows

def add_affiliation(rows, **kwargs):
  for row in rows:
    # some text separated with either "/ or ","
    st = re.search('(.*?) ?[,\/] ?(.*)', row[3])
    if st:
      row[3] = st.group(1)
      row.append(st.group(2))
    else:
      row.append('')
  return rows

def add_contextual_columns(rows, **kwargs):
  for row in rows:
    row.append(kwargs['notified'])
    row.append(kwargs['location_id'])
  return rows

def add_header(rows, **kwargs):
  header = ['id','page_id','time','visitor name','host name','additional information','card number','group id','original time','affiliation','notified','location id']
  return [header] + rows

def get_filename_args(filename):
  fn = os.path.basename(filename)
  fn = fn.split('#')
  location_id = fn[0]
  date = fn[1]
  notified = fn[2]
  notified = notified.split('.')[0]
  return {'location_id': location_id, 'date': date, 'notified': notified}

def process_ocr_output(rows, **kwargs):
  functions = [remove_empty_lines, remove_header_line, add_card_number,
          add_group_id, add_index, fix_time, fill_time, fill_host, fill_additional_info,
          add_affiliation, add_contextual_columns, add_header]
  for fn in functions:
    rows = fn(rows, date=kwargs['date'], notified=kwargs['notified'], location_id=kwargs['location_id'])
  return rows

# this gets called if you run the script (as opposed to e.g. importing)
if __name__ == '__main__':
  file = sys.argv[1]
  with open(file, 'rb') as csvfile:
    args = get_filename_args(csvfile.name)
    rs = csv.reader(csvfile, delimiter=',')
    rows = process_ocr_output(list(rs), date=args['date'], notified=args['notified'], location_id=args['location_id'])
#  with open('csv.csv', 'a') as f:
#   writer = csv.writer(f)
  writer = csv.writer(sys.stdout)
  for row in rows:
    writer.writerow(row)


from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import MovieViewSet, MovieSearchView, WatchlistDeleteView, CastViewSet, ReviewsViewSet, MovieByGenre, GenreViewSet, GetCastByMovie, WatchlistCreateView, GetReviewByMovie, RandomizeRatings, WatchlistDetailView, WatchlistShareView
router = DefaultRouter()
router.register(r'movies', MovieViewSet)
router.register(r'casts', CastViewSet)
router.register(r'reviews', ReviewsViewSet)
router.register(r'movies/genre', MovieByGenre)
router.register(r'genre', GenreViewSet)
urlpatterns = [
    # Your other URL patterns
    path('', include(router.urls)),
    path('movies/search', MovieSearchView.as_view(), name='movie-search'),
    path('cast/movie/<int:movie_id>/',
         GetCastByMovie.as_view(), name='get-cast-by-movie'),
    path('review/movie/<int:movie_id>/',
         GetReviewByMovie.as_view(), name='get-cast-by-movie'),
    path('randomize_ratings/', RandomizeRatings.as_view(),
         name='randomize-ratings'),
    path('add/movie/watchlist/', WatchlistCreateView.as_view(),
         name='create-watchlist'),
    path('get/movies/watchlist/<int:userId>/',
         WatchlistDetailView.as_view(), name='watchlist-detail'),
    path('share/watchlist/', WatchlistShareView.as_view(), name='create-watchlist'),
    path('watchlist/delete/<int:watchlist_id>/',
         WatchlistDeleteView.as_view(), name='watchlist-delete'),

]


from typing import TYPE_CHECKING

from ...file_utils import (
    _BaseLazyModule,
    is_tokenizers_available,
    is_torch_available,
)

_import_structure = {
    "configuration_dkplm": ["DkplmConfig"],
    "tokenization_dkplm": ["BasicTokenizer", "DkplmTokenizer", "WordpieceTokenizer"],
}

if is_tokenizers_available():
    _import_structure["tokenization_dkplm_fast"] = ["DkplmTokenizerFast"]

if is_torch_available():
    _import_structure["modeling_dkplm"] = [
        "DKPLM_PRETRAINED_MODEL_ARCHIVE_LIST",
        "DkplmForMaskedLM",
        "DkplmForMultipleChoice",
        "DkplmForNextSentencePrediction",
        "DkplmForPreTraining",
        "DkplmForQuestionAnswering",
        "DkplmForSequenceClassification",
        "DkplmForTokenClassification",
        "DkplmLayer",
        "DkplmLMHeadModel",
        "DkplmModel",
        "DkplmPreTrainedModel",
        # "load_tf_weights_in_dkplm",
    ]
if TYPE_CHECKING:
    # from .configuration_dkplm import DKPLM_PRETRAINED_CONFIG_ARCHIVE_MAP, DkplmConfig
    from .configuration_dkplm import DkplmConfig
    from .tokenization_dkplm import BasicTokenizer, DkplmTokenizer, WordpieceTokenizer

    if is_tokenizers_available():
        from .tokenization_dkplm_fast import DkplmTokenizerFast

    if is_torch_available():
        from .modeling_dkplm import (
            # DKPLM_PRETRAINED_MODEL_ARCHIVE_LIST,
            DkplmForMaskedLM,
            DkplmForMultipleChoice,
            DkplmForNextSentencePrediction,
            DkplmForPreTraining,
            DkplmForQuestionAnswering,
            DkplmForSequenceClassification,
            DkplmForTokenClassification,
            DkplmLayer,
            DkplmLMHeadModel,
            DkplmModel,
            DkplmPreTrainedModel,
            # load_tf_weights_in_dkplm,
        )
else:
    import importlib
    import os
    import sys

    class _LazyModule(_BaseLazyModule):
        """
        Module class that surfaces all objects but only performs associated imports when the objects are requested.
        """

        __file__ = globals()["__file__"]
        __path__ = [os.path.dirname(__file__)]

        def _get_module(self, module_name: str):
            return importlib.import_module("." + module_name, self.__name__)

    sys.modules[__name__] = _LazyModule(__name__, _import_structure)


from PyQt6.QtCore import QTimer
from PyQt6.QtGui import QDoubleValidator
from PyQt6.QtWidgets import QWidget, QLabel, QVBoxLayout, QPushButton, QGridLayout, QMessageBox, QLineEdit, QHBoxLayout

from widgets.color import Color

class LandingGearFrame(QWidget):
    def __init__(self):
        super(LandingGearFrame, self).__init__()
        self.data_values = {}

        layout = QVBoxLayout()

        # Create a horizontal layout for the label and buttons
        header_layout = QHBoxLayout()

        header_layout.addWidget(QLabel("Add Landing Gear"))

        # Add buttons for appending and deleting data
        append_button = QPushButton("Append Data", self)
        delete_button = QPushButton("Delete Data", self)

        append_button.clicked.connect(self.append_data)
        delete_button.clicked.connect(self.delete_data)

        header_layout.addWidget(append_button)
        header_layout.addWidget(delete_button)

        layout.addLayout(header_layout)
        layout.addWidget(Color("lightblue"))

        # Create a grid layout with 3 columns
        grid_layout = QGridLayout()

        # List of data labels
        data_labels = landing_gear_names = [
            "Main Tire Diameter",
            "Nose Tire Diameter",
            "Main Strut Length",
            "Nose Strut Length",
            "Main Units",
            "Nose Units",
            "Main Wheels",
            "Nose Wheels"
        ]

        # Create QLineEdit frames with QDoubleValidator for numerical input
        for index, label in enumerate(data_labels):
            row, col = divmod(index, 3)
            line_edit = QLineEdit(self)
            line_edit.setValidator(QDoubleValidator())

            # Set the width of the line edit
            line_edit.setFixedWidth(100)  # Adjust the width as needed

            grid_layout.addWidget(QLabel(label + ":"), row, col * 3)
            grid_layout.addWidget(line_edit, row, col * 3 + 1, 1, 2)

            # Store a reference to the QLineEdit in the dictionary
            self.data_values[label] = line_edit

        # Add the grid layout to the home layout
        layout.addLayout(grid_layout)

        self.setLayout(layout)

    def append_data(self):
        """Append the entered data to a list or perform any other action."""
        entered_data = self.get_data_values()
        # Implement appending logic here, e.g., append to a list
        print("Appending Data:", entered_data)
        self.show_popup("Data Saved!", self)

    def delete_data(self):
        """Delete the entered data or perform any other action."""
        entered_data = self.get_data_values()
        # Implement deletion logic here, e.g., clear the entries
        print("Deleting Data:", entered_data)
        for line_edit in self.data_values.values():
            line_edit.clear()
        self.show_popup("Data Erased!", self)

    def get_data_values(self):
        """Retrieve the entered data values from the dictionary."""
        return {label: float(line_edit.text()) if line_edit.text() else 0.0
                for label, line_edit in self.data_values.items()}

    def show_popup(self, message, parent):
        """Display a pop-up message for 2 seconds."""
        popup = QMessageBox(parent)
        popup.setWindowTitle("Info")
        popup.setText(message)
        # This line seemed to make it impossible to close the popup
        # popup.setStandardButtons(QMessageBox.StandardButton.NoButton)
        popup.setStyleSheet("QLabel{min-width: 300px;}")
        popup.show()
        #
        # # Use QTimer to close the popup after 2 seconds
        timer = QTimer(popup)
        timer.setSingleShot(True)
        timer.timeout.connect(popup.close)
        timer.start(2000)  # 2000 milliseconds (2 seconds)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Nov 24 14:24:04 2018
content similarity
@author: wentingyang
"""

import pandas as pd
import numpy as np

Dbase=pd.read_csv('Master_Data.csv',sep=',')

list_content=list(Dbase['Review'])

import gensim
print(dir(gensim))
raw_documents = list_content
print("Number of documents:",len(raw_documents))

#import nltk
#nltk.download('punkt')
from nltk.tokenize import word_tokenize
gen_docs = [[w.lower() for w in word_tokenize(text)]
            for text in raw_documents]
print(gen_docs)

dictionary = gensim.corpora.Dictionary(gen_docs)

print("Number of words in dictionary:",len(dictionary))
for i in range(len(dictionary)):
    print(i, dictionary[i])

corpus = [dictionary.doc2bow(gen_doc) for gen_doc in gen_docs]
print(corpus)

tf_idf = gensim.models.TfidfModel(corpus)
print(tf_idf)
s = 0
for i in corpus:
    s += len(i)
print(s)

sims = gensim.similarities.Similarity('/Users/wentingyang/Downloads',tf_idf[corpus],
                                      num_features=len(dictionary))
print(sims)
print(type(sims))

label=[]
for text_content in list_content:
    query_doc = [w.lower() for w in word_tokenize(text_content)]
    #print(query_doc)
    query_doc_bow = dictionary.doc2bow(query_doc)
    #print(query_doc_bow)
    query_doc_tf_idf = tf_idf[query_doc_bow]
    #print(query_doc_tf_idf)

    sims[query_doc_tf_idf]
    #max(sims[query_doc_tf_idf])
    test=list(enumerate(sims[query_doc_tf_idf]))
    max_test=sorted(test,key=lambda tup:tup[1],reverse=True)[1][1]
    #max_test=max_test[1]
    if max_test<.5:
        Label_score=True
    else:
        Label_score=False
    label.append(Label_score)

sentiment=pd.read_csv("results_joined_sentiment.csv")
sentiment['SIM_label']=label

sentiment['Overall_label']=True

for i in range(sentiment.shape[0]):
    sentiment.iat[i,-1]=sentiment.iat[i,-2] and sentiment.iat[i,-3]

from datetime import datetime

def try_parsing_date(text):
    for fmt in ('%d-%b-%y','%B %d, %Y'):
        try:
            return datetime.strptime(text.strip(),fmt)
        except ValueError:
            pass
    raise ValueError('no valid date format found')

sentiment.iat[1021,2]='October 28, 2018'
sentiment['Review Date']=sentiment['Review Date'].apply(lambda x:try_parsing_date(x))

#sentiment.drop(['Review Date_corrected'],axis=1)

sentiment.to_csv('FinalData.csv',header=True)

detect the fake reviews/Data Cleaning Codes/ContentSimilarity.py