from collections import defaultdict
import glob
import numpy as np
import re, string, unicodedata
import os
import nltk
from nltk import tokenize, word_tokenize, sent_tokenize
from nltk.corpus import stopwords
from nltk.stem import PorterStemmer
#import contractions
#import inflect
from bs4 import BeautifulSoup

from mimetypes import init

class Boolean_Model(object):
    def __init__(self, Corpus):
        self.Corpus = Corpus # path to the documents

        self.documents = dict()

        self.Terms = []
        #self.Stemmer = PorterStemmer()

        self.inverted_matix = defaultdict(list)

        self._preprocesing_corpus()

    def _strip_htlm(self,text):
        soup = BeautifulSoup(text,"html.parser")
        return soup.get_text()

    def _remove_between_square_brackets(self,text):
        return re.sub('\[[^]]*\]','',text)

    def _denoise_text(self,text):
        text = self._strip_htlm(text)
        text = self._remove_between_square_brackets(text)
        return text

    def _denoise(self,text):
        return re.sub(r'<[^>]*?>','', text)

    def _preprocesing_corpus(self):
        index = 1
        for filename in glob.glob(self.Corpus) :
            with open(filename,"r") as file :
                text = file.read()
            text = self._denoise(text)
            text = self._remove_unnecesary_characters(text)
            text = self._remove_digits(text)

            #tokenization
            words = tokenize.word_tokenize(text)

            #Remove stopwords
            words = [word.lower() for word in words if word not in stopwords.words('english')]

           # words = [self.Stemmer.stem(word) for word in words]

            terms = list(set(words)) # eliminar palabras repetidas
            for term in terms:
                self.inverted_matix[term].append(index)
                self.Terms.append(term)
            self.documents[index] = os.path.basename(filename)
            index +=1

    def _tokenizer(self,expression):
            tokens = []
            for item in expression.split():
                tokens.append(item)
            return tokens

    # E -> BX
    # X -> OR BX | epsilon
    # B -> AND CY
    # Y -> AND CY |epsilon
    # C -> D | not D
    # D -> term | (A)

    def proces_query(self, query):
        query_tokens = self._tokenizer(query) #mejorar el tokenizer
        vector = self._evaluate_query(query_tokens)
        relevant_docs = dict()
        for i in  range(len(self.documents)):
            if vector[i] == True:
                relevant_docs[i+1] = self.documents[i+1]
        print(vector)

        return relevant_docs

    def _evaluate_query(self,query_tokens):
        i, vector= self._parse_expression(query_tokens,0)
        if i!=len(query_tokens):
            print("La expresion no es correcta")
            return np.zeros(len(self.documents), dtype=bool)
        return vector

    def _parse_expression(self,tokens,i):
        i,term = self._parse_B(tokens,i)
        return self._parse_X(tokens,i,term)

    def _parse_X(self,tokens,i,value):
        if i < len(tokens):
            if tokens[i] == 'OR':
                i,term2 = self._parse_B(tokens,i+1)
                value = value | term2
                return self._parse_X(tokens,i,value)
        return i,value

    def _parse_B(self,tokens,i):
        i,factor = self._parse_C(tokens,i)
        return self._parse_Y(tokens,i,factor)

    def _parse_Y(self,tokens,i,value):
        if i<len(tokens):
            if tokens[i] == 'AND':
                i,factor2 = self._parse_C(tokens,i+1)
                value = value & factor2
                return self._parse_Y(tokens,i,value)
        return i,value

    def _parse_C(self,tokens,i) :
        if i < len(tokens):
            if tokens [i] == 'not':
                i, vector = self._parse_C(tokens,i+1)
                return i, ~vector
            elif self._is_term(tokens[i]):
                vector = self._vector(tokens[i])
                return i + 1, vector
            elif tokens[i] == '(':
                i, vector = self._parse_expression(tokens,i+1)
                if tokens[i] != ')':
                  print ("Expresion mal formada")
                return i + 1,vector
            else:
                print("Expresion mal formada")
                return -1,np.zeros(len(self.documents),dtype = bool)
        else:
            print("Expresion mal formada")
            return -1,np.zeros(len(self.documents),dtype = bool)

    def _is_term(self,token):
        if token == 'AND' or token == 'OR' or token == '(' or token ==')' or token == 'not':
            return False
        return True

    def _vector(self,term):
        docs_count = len(self.documents)
        if term in self.Terms:
            vector = np.zeros(docs_count,dtype=bool)

            postings = self.inverted_matix[term]
            for doc_id in postings:
                vector[doc_id-1] = True
            return vector
        else:
            print("The term"+ term + " Was not found in the corpus")
            return np.zeros(docs_count,dtype=bool)

    def Rank(query_vector, documents): raise NotImplementedError

    def _remove_unnecesary_characters(self,text):
        regex = re.compile(r"[^a-zA-Z0-9\s]")

        # Replace and return
        return re.sub(regex, "", text)

    def _remove_digits(self, text):
        """Removes digits from a blob of text"""

         # Regex pattern for a word
        regex = re.compile(r"\d")

        # Replace and return
        return re.sub(regex, "", text)


#coding=gbk
import warnings
warnings.simplefilter("ignore", UserWarning)
import os
import argparse
import matplotlib as mpl
mpl.use('Agg')
import matplotlib.pyplot as plt
from tqdm import tqdm
import torch
import torch.nn as nn
from torch.optim import Adam,lr_scheduler
from torch.utils.data import DataLoader
from torchvision.utils import save_image
import torchvision.transforms as transforms
from dataset import PreprocessDataset, denorm
import torch.multiprocessing as mp
from model import Model
import datetime

def weight_init(m):
    if type(m)==nn.Conv2d:
        nn.init.normal(m.weight,mean=0,std=0.5)

def main():
    time_start = datetime.datetime.now()
    parser = argparse.ArgumentParser(description='Hiding information based on NST by Pytorch')
    parser.add_argument('--batch_size', '-b', type=int, default=2,
                        help='Number of images in each mini-batch')
    parser.add_argument('--epoch', '-e', type=int, default=100,
                        help='Number of sweeps over the dataset to train')
    parser.add_argument('--gpu', '-g', type=int, default=0,
                        help='GPU ID(nagative value indicate CPU)')
    parser.add_argument('--learning_rate', '-lr', type=int, default=5e-5,
                        help='learning rate for Adam')
    parser.add_argument('--snapshot_interval', type=int, default=1000,
                        help='Interval of snapshot to generate image')
    parser.add_argument('--train_content_dir', type=str, default='content',
                        help='content images directory for train')
    parser.add_argument('--train_style_dir', type=str, default='style',
                        help='style images directory for train')
    parser.add_argument('--train_secret_dir', type=str, default='secret',
                        help='secret images directory for train')

    parser.add_argument('--test_content_dir', type=str, default='content',
                        help='content images directory for test')
    parser.add_argument('--test_style_dir', type=str, default='style',
                        help='style images directory for test')
    parser.add_argument('--test_secret_dir', type=str, default='secret',
                        help='secret images directory for test')
    parser.add_argument('--save_dir', type=str, default='ckpt2',
                        help='save directory for result and loss')
    parser.add_argument('--reuse', default=None,
                        help='model state path to load for reuse')
    args = parser.parse_args()

    # create directory to save
    if not os.path.exists(args.save_dir):
        os.mkdir(args.save_dir)

    loss_dir = f'{args.save_dir}/loss'
    model_state_dir = f'{args.save_dir}/model_state'
    image_dir = f'{args.save_dir}/image'

    if not os.path.exists(loss_dir):
        os.mkdir(loss_dir)
        os.mkdir(model_state_dir)
        os.mkdir(image_dir)

    # set device on GPU if available, else CPU
    if torch.cuda.is_available() and args.gpu >= 0:
        device = torch.device(f'cuda:{args.gpu}')
        print(f'# CUDA available: {torch.cuda.get_device_name(0)}')
    else:
        device = 'cpu'

    print(f'# Minibatch-size: {args.batch_size}')
    print(f'# epoch: {args.epoch}')
    print('')

    # train_data_transforms=transforms.Compose([
    #     transforms.CenterCrop(256),
    #     transforms.ToTensor(),
    #     transforms.Normalize([0.471, 0.448, 0.408],
    #                         [0.234, 0.239, 0.242])
    # ])
    # prepare dataset and dataLoader
    train_dataset = PreprocessDataset(args.train_content_dir, args.train_style_dir,args.train_secret_dir)
    test_dataset = PreprocessDataset(args.test_content_dir, args.test_style_dir,args.test_secret_dir)
    iters = len(train_dataset)
    print(f'Length of train image pairs: {iters}')

    train_loader = DataLoader(train_dataset, batch_size=args.batch_size, shuffle=False,num_workers=2)
    test_loader = DataLoader(test_dataset, batch_size=args.batch_size, shuffle=False,num_workers=2)
    test_iter = iter(test_loader)

    # set model and optimizer2063
    model = Model().to(device)
    #model.apply(weight_init)
    if args.reuse is not None:
        model.load_state_dict(torch.load(args.reuse))
    optimizer_decder = Adam(model.decoder.parameters(), lr=args.learning_rate)
    #lr_sch =lr_scheduler.StepLR(optimizer=optimizer_decder,step_size=100,gamma=0.3)
    optimizer_sec_fea = Adam(model.sec_fea_ext.parameters(), lr=args.learning_rate)
    optimizer_extra = Adam(model.extract.parameters(), lr=1e-3)

    # start training
    loss_list = []
    loss_secret_list = []

    for e in range(1, args.epoch + 1):
        print(f'Start {e} epoch')
        for i, (content, style,secret) in tqdm(enumerate(train_loader, 1)):
            content = content.to(device)
            style = style.to(device)
            secret = secret.to(device)
            loss,loss_secret = model(content, style,secret)
            loss_list.append(loss.item())
            loss_secret_list.append(loss_secret.item())

            if i % 2 == 0:
                optimizer_decder.zero_grad()
                optimizer_sec_fea.zero_grad()
                loss.backward(retain_graph=True)
                optimizer_decder.step()
                optimizer_sec_fea.step()
                #lr_sch.step()
                #print("µÚ%d¸öepochµÄÑ§Ï°ÂÊ:%f" %(e,optimizer_extra.param_groups[0]['lr']))

            else:
                optimizer_extra.zero_grad()
                loss_secret.backward()
                optimizer_extra.step()
                #optimizer_D.zero_grad()
                # d_loss.backward()
                # optimizer_D.step()

            if args.epoch %10 ==0:
                print(f'[{e}/total {args.epoch} epoch],[{i} /'
                  f'total {round(iters/args.batch_size)} iteration]: {loss.item()}, {loss_secret.item()},') #{d_loss.item()}

            if i % args.snapshot_interval == 0:
                content, style, secret = next(test_iter)
                content = content.to(device)
                style = style.to(device)
                secret = secret.to(device)
                with torch.no_grad():
                    out = model.generate(content, style, secret)
                    out_secret = model.extractor_model(out)

                content = denorm(content, device)
                style = denorm(style, device)
                secret = denorm(secret,device)
                out = denorm(out, device)
                out_secret = denorm(out_secret,device)
                res = torch.cat([content, style, out, secret, out_secret], dim=0)
                res = res.to('cpu')
                save_image(res, f'{image_dir}/{e}_epoch_{i}_iteration.png', nrow=args.batch_size)
        torch.save(model.state_dict(), f'{model_state_dir}/{e}_epoch.pth')
    plt.plot(range(len(loss_list)), loss_list)
    plt.xlabel('iteration')
    plt.ylabel('loss')
    plt.title('train loss')
    plt.savefig(f'{loss_dir}/train_loss.png')

    plt.plot(range(len(loss_secret_list)), loss_secret_list)
    plt.xlabel('iteration')
    plt.ylabel('loss')
    plt.title('secret loss')
    plt.savefig(f'{loss_dir}/serect_loss.png')

    with open(f'{loss_dir}/loss_log.txt', 'w') as f:
        for l in loss_list:
            f.write(f'{l}\n')
    print(f'Loss saved in {loss_dir}')

    with open(f'{loss_dir}/loss_secret_log.txt', 'w') as f:
        for l in loss_secret_list:
            f.write(f'{l}\n')
    print(f'Loss_secret saved in {loss_dir}')

if __name__ == '__main__':
    ngpus_per_node = torch.cuda.device_count()
    multiprocessing_distributed = False
    gpu = 0
    world_size = 1
    if ngpus_per_node > 1:
        multiprocessing_distributed = True

    if multiprocessing_distributed:
        # Since we have ngpus_per_node processes per node, the total world_size
        # needs to be adjusted accordingly
        world_size = ngpus_per_node * world_size
        # Use torch.multiprocessing.spawn to launch distributed processes: the
        # main_worker process function
        mp.spawn(main, nprocs=ngpus_per_node, args=(ngpus_per_node, world_size, multiprocessing_distributed))
    else:
        main()


import json

def filter_job_traces():
    f = open("trace-data/cluster_job_log")
    data = json.load(f)

    filtered_traces = [x for x in data if x['status'] == 'Pass' and len(x['attempts']) == 1]

    json_string = []
    for d in filtered_traces:
        #print(d)
        print("attempts!", d['attempts'][0])
        trace = {
            "jobid": d['jobid'],
            "start_time": d['attempts'][0]['start_time'],
            "end_time": d['attempts'][0]['end_time'],
            "submitted_time": d['submitted_time'],
            "user": d['user']
        }
        gpus = []
        for req in d['attempts'][0]['detail']:
            gpus += req['gpus']
            #gpus.concat(req['gpus'])
        trace['gpus'] = gpus
        json_string.append(trace)

    with open('filtered_traces/cluster_job_log', 'w') as outfile:
        json.dump(json_string, outfile)

filter_job_traces()


import random
from selenium.webdriver.common.keys import Keys
from locators.practice_form_locators import PracticeFormPageLocators
from pages.base_page import BasePage
from selenium.webdriver.common.by import By
from generator.generator import generated_person, generated_file, generate_subject
import os

class PracticeFormPage(BasePage):

    def fill_all_fields(self):
        personal = next(generated_person())
        file_name, path = generated_file()
        firstname = personal.firstname
        lastname = personal.lastname
        email = personal.email
        age = personal.age
        salary = personal.salary
        department = personal.department
        self.element_is_visible(WebTablePageLocators.ADD_BUTTON).click()
        self.element_is_visible(WebTablePageLocators.FIRSTNAME_INPUT).send_keys(firstname)
        self.element_is_visible(WebTablePageLocators.LASTNAME_INPUT).send_keys(lastname)
        self.element_is_visible(WebTablePageLocators.EMAIL_INPUT).send_keys(email)
        self.element_is_visible(WebTablePageLocators.AGE_INPUT).send_keys(age)
        self.element_is_visible(WebTablePageLocators.SALARY_INPUT).send_keys(salary)
        self.element_is_visible(WebTablePageLocators.DEPARTMENT_INPUT).send_keys(department)
        self.element_is_visible(WebTablePageLocators.SUBMIT_BUTTON).click()

        return [firstname, lastname, str(age), email, str(salary), department]

    def fill_form_fields(self):
        person = next(generated_person())
        file_name, path = generated_file()
        subject = generate_subject()
        self.element_is_visible(PracticeFormPageLocators.FIRST_NAME_INPUT).send_keys(person.firstname)
        self.element_is_visible(PracticeFormPageLocators.LAST_NAME_INPUT).send_keys(person.lastname)
        self.element_is_visible(PracticeFormPageLocators.EMAIL_NAME_INPUT).send_keys(person.email)

        gender_radio = self.element_is_present(PracticeFormPageLocators.GENDER_RADIO_BUTTONS)
        gender_radio.click()
        gender_name = gender_radio.find_element("xpath", PracticeFormPageLocators.GENDER_TEXT)

        date_of_birth = self.element_is_visible(PracticeFormPageLocators.DATA_OF_BIRTH_INPUT).get_attribute("value")

        self.element_is_visible(PracticeFormPageLocators.MOBILE_INPUT).send_keys(person.mobile)

        subject_name = subject[random.randint(0, 13)]
        self.element_is_visible(PracticeFormPageLocators.SUBJECT).send_keys(subject_name)
        self.element_is_visible(PracticeFormPageLocators.SUBJECT).send_keys(Keys.RETURN)

        hobbies_check_box = self.element_is_visible(PracticeFormPageLocators.HOBBIES_CHECK_BOXES)
        hobbies_check_box.click()
        hobbies_text = hobbies_check_box.find_element("xpath", PracticeFormPageLocators.HOBBIES_TEXT)

        self.element_is_present(PracticeFormPageLocators.UPLOAD_FILE_INPUT).send_keys(path)
        os.remove(path)

        self.element_is_visible(PracticeFormPageLocators.CURRENT_ADDRESS_INPUT).send_keys(person.current_address.split('\n'))

        self.go_to_element(self.element_is_present(PracticeFormPageLocators.STATE_DROP_DOWN))
        self.element_is_visible(PracticeFormPageLocators.STATE_DROP_DOWN).click()
        self.element_is_visible(PracticeFormPageLocators.STATE_INPUT).send_keys(Keys.RETURN)
        state_text = self.element_is_visible(PracticeFormPageLocators.STATE_DROP_DOWN)

        self.element_is_visible(PracticeFormPageLocators.CITY_DROP_DOWN).click()
        self.element_is_visible(PracticeFormPageLocators.CITY_INPUT).send_keys(Keys.RETURN)
        city_text = self.element_is_visible(PracticeFormPageLocators.CITY_DROP_DOWN)

        self.go_to_element(self.element_is_present(PracticeFormPageLocators.SUBMIT_BUTTON))
        self.element_is_visible(PracticeFormPageLocators.SUBMIT_BUTTON).click()

        return person, gender_name.text, hobbies_text.text, date_of_birth, file_name.split('\\')[-1], subject_name,\
            state_text.text, city_text.text

    def get_form_result(self):
        result_list = self.elements_are_present(PracticeFormPageLocators.RESULT_TABLE)
        data = []
        for item in result_list:
            data.append(item.text)
        return data


from tensorflow.examples.tutorials.mnist import input_data
from scipy import misc
import PIL
from PIL import Image

import tensorflow as tf

# mnist = input_data.read_data_sets("MNIST_data", one_hot=True)

# pre-process data if necessary

flags = tf.app.flags
FLAGS = flags.FLAGS
flags.DEFINE_string("image_path", "../num4_1.jpg", "Path to your input digit image.")

img = Image.open(FLAGS.image_path)
print("Orignial image size is: ")
print(img.size)
img = img.resize((28, 28), PIL.Image.ANTIALIAS)
img.save("../tmp_image.jpg")
print("Resized image size is: ")
print(img.size)

import tensorflow as tf
sess = tf.Session()

x = tf.placeholder(tf.float32, shape=[None, 784])
y_ = tf.placeholder(tf.float32, shape=[None, 10])

W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))

def weight_variable(shape):
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)

def bias_variable(shape):
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial)

def conv2d(x, W):
    return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

def max_pool_2x2(x):
    return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])

x_image = tf.reshape(x, [-1, 28, 28, 1])

h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)

W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])

h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)

W_fc1 = weight_variable([7*7*64, 1024])
b_fc1 = bias_variable([1024])

h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)

keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])

y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

# Your own data
img = misc.imread("../tmp_image.jpg")
img.shape=(1, 784)

cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y_conv), reduction_indices=[1]))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
sess.run(tf.global_variables_initializer())

saver = tf.train.Saver()
saver.restore(sess, "../model_simple.ckpt")
print("model restored.")

result = sess.run(y_conv, feed_dict={x: img, keep_prob: 1.0})
print("The output of the network is: ")
print(result)
print("Prediction is (output one-hot digit from 0 to 9):")
print(sess.run(tf.argmax(result, 1)))
# print("test accuracy %g"%sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))


import numpy as np
import cv2
import pywt

def DWT(coverImage, waterMarkImage):

    # Đọc và thay đổi kích thước ảnh
    coverImage = cv2.resize(coverImage, (300,300))
    cv2.imshow('coverImage', coverImage)
    waterMarkImage = cv2.resize(waterMarkImage, (150,150))
    cv2.imshow('waterMarkImage', waterMarkImage)

    # Thực hiện DWT trên ảnh cover
    coverImage = np.float32(coverImage)
    coverImage /= 255
    coeffC = pywt.dwt2(coverImage, 'haar')
    cA, (cH, cV, cD) = coeffC

    waterMarkImage = np.float32(waterMarkImage)
    waterMarkImage /= 255

    # Nhúng
    apha_c = 1
    apha_w = 0.05
    coeffW = (apha_c * cA + apha_w * waterMarkImage, (cH, cV, cD))
    waterMarkImage = pywt.idwt2(coeffW, 'haar')
    cv2.imshow('waterMarkImage', waterMarkImage)
    cv2.imwrite('WaterMarkImage.png', waterMarkImage)

    # Rút trích
    coeffWM = pywt.dwt2(waterMarkImage, 'haar')
    hA, (hH, hV, hD) = coeffWM
    extracted = (hA - apha_c * cA) / apha_w
    extracted *= 255
    extracted = np.uint8(extracted )
    extracted = cv2.resize(extracted, (300,300))
    cv2.imshow('extracted', extracted)

coverImage = cv2.imread('abc.png',0)
watermarkImage = cv2.imread('abcd.png',0)

DWT(coverImage, watermarkImage)
cv2.waitKey(0)
cv2.destroyAllWindows()


import torch
from omegaconf import OmegaConf
import os
import time
import argparse
from ot_local.ot_plugin import OTPlugin
from data_handler.config import DatasetConfig
from data_handler.data_common import get_data
from recommendation_method.common.common import train
from recommendation_method.cne.model import IdentityModel

def get_ot_param_dict(args, train_loader, user_num, item_num):
	ot_plugin = OTPlugin(user_num, item_num, args.sinkhorn_gamma, args.sinkhorn_maxiter)
	if args.use_ot == 1:
		ot_param_dict = {"ot_plugin": ot_plugin, "lambda_p": args.lambda_p, 'train_dataset': train_loader.dataset, 'ot_method': args.ot_method}
	else:
		ot_param_dict = {"ot_plugin": ot_plugin, "lambda_p": args.lambda_p, 'train_dataset': train_loader.dataset}
	return ot_param_dict, ot_plugin

parser = argparse.ArgumentParser()
parser.add_argument("--path_to_config",
	type=str,
	default='recommendation_method/cne/config.yml',
	help="config path, parameters learning_rate, weight_decay, and dim are reinitialized using arguments in this file")
parser.add_argument("--base_path_to_config",
	type=str,
	default='recommendation_method/cne/config.yml',
	help="base config path, not used")

parser.add_argument("--batch_size",
	type=int,
	default=4096,
	help="batch size for training")
parser.add_argument("--base_batch_size",
	type=int,
	default=4096,
	help="base batch size for training")

parser.add_argument("--min_epochs",
	type=int,
	default=0,
	help="training epoches")
parser.add_argument("--epochs",
	type=int,
	default=40000,
	help="training epoches")
parser.add_argument("--base_epochs",
	type=int,
	default=40000,
	help="base training epoches")
parser.add_argument("--base_training_repeat",
	type=int,
	default=0,
	help="not used")
parser.add_argument("--base_monitor",
	type=str,
	default='valid_loss',
	help="valid_loss, valid_auc")

parser.add_argument("--num_ng",
	type=int,
	default=4,
	help="sample negative items for training")
parser.add_argument("--out",
	type=int,
	default=1,
	help="save model or not")
parser.add_argument("--gpu",
	type=str,
	default="0",
	help="gpu card ID")
parser.add_argument("--device",
	type=str,
	default="gpu",
	help="cpu/gpu")
parser.add_argument("--use_ot",
	type=int,
	default=0,
	help="0 or 1")
parser.add_argument("--lambda_p",
	type=float,
	default=0.005,
	help="regularization weight")
parser.add_argument("--sinkhorn_gamma",
	type=float,
	default=10.0,
	help="sinkhorn gamma")
parser.add_argument("--sinkhorn_maxiter",
	type=int,
	default=5,
	help="sinkhorn max iterations")
parser.add_argument("--dataset",
	type=str,
	default='career_builder_small',
	help="")
parser.add_argument("--main_path",
	type=str,
	default='Data/',
	help="main path for data")
parser.add_argument("--model_path",
	type=str,
	default='models/',
	help="model path to save/load")
parser.add_argument("--figures_path",
	type=str,
	default='figures/',
	help="not used")
parser.add_argument("--use_pretrained",
	type=int,
	default=0,
	help="not used")
parser.add_argument("--early_stop",
	type=int,
	default=1,
	help="do early stopping?")

parser.add_argument("--patience",
	type=int,
	default=5,
	help="patience in early stopping")
parser.add_argument("--base_patience",
	type=int,
	default=5,
	help="base patience in early stopping")

parser.add_argument("--monitor",
	type=str,
	default='valid_loss',
	help="valid_loss, valid_auc")

parser.add_argument("--mode",
	type=str,
	default='min',
	help="min or max")
parser.add_argument("--ot_method",
	type=str,
	default='all',
	help="")

parser.add_argument("--popularity",
	type=int,
	default=1,
	help="whether to add popularity model or not")
parser.add_argument("--gradient_clipping",
	type=float,
	default=0,
	help="gradient clipping")
parser.add_argument("--precision",
	type=int,
	default=32,
	help="mixed precision")

	# cne configs
parser.add_argument("--dim",
	type=int,
	default=8,
	help="embedding_dimension")
parser.add_argument("--learning_rate",
	type=float,
	default=0.01,
	help="learning_rate")
parser.add_argument("--weight_decay",
	type=float,
	default=0.01,
	help="weight_decay")

parser.add_argument("--max_time",
	type=float,
	default=-1,
	help="max training time in hours. If < 0, does not set a limit")

if __name__ == "__main__":
	args = parser.parse_args()
	print(args)
	config = DatasetConfig('cne', args.model_path, args.main_path, args.dataset)

	os.environ["CUDA_VISIBLE_DEVICES"] = args.gpu

	user_num,item_num,top_k_list_for_rec_performance,top_k_list,train_loader,test_loader_classification, test_loader_ranking, val_loader = get_data(args, config)
	print(user_num)
	print(item_num)

	print("load config")
	cne_config = OmegaConf.load(args.path_to_config)
	base_cne_config = OmegaConf.load(args.base_path_to_config)

	cne_config.interaction.parameters.dim = args.dim
	cne_config.interaction.parameters.learning_rate = args.learning_rate
	cne_config.interaction.parameters.weight_decay = args.weight_decay

	popularity_epochs = min(50, args.epochs)
	popularity_patience = 5
	popularity_model_file_path = '{}popularity_{}.pth'.format(args.model_path, args.dataset)
	base_model_file_path = '{}cne_{}_{}.pth'.format(args.model_path, 0, args.dataset)
	model_file_path = '{}cne_{}_{}.pth'.format(args.model_path, args.use_ot, args.dataset)

	if args.popularity:
		popularity_model = IdentityModel(user_num ,item_num, None, cne_config.popularity.parameters)
		if torch.cuda.is_available():
			popularity_model = popularity_model.cuda()

		########################### CREATE MODEL POPULARITY #################################
		if not os.path.exists(popularity_model_file_path):
			print("popularity model not found")
			popularity_model = train(args, config, popularity_model, IdentityModel, model_name='popularity', model_file_path=model_file_path, epochs=popularity_epochs, patience=popularity_patience, monitor=args.base_monitor, ot_method='all')
			if args.out:
				if not os.path.exists(args.model_path):
					os.mkdir(args.model_path)
				popularity_model.zero_grad()
				torch.save(popularity_model.state_dict(),
					popularity_model_file_path)

		else:
			print("popularity model found")
			if torch.cuda.is_available():
				state = torch.load(popularity_model_file_path)
			else:
				state = torch.load(popularity_model_file_path, map_location=torch.device('cpu'))
			popularity_model.load_state_dict(state)

	class_ = IdentityModel
	if args.popularity:
		if torch.cuda.is_available():
			popularity_model.cuda()
		d = {'embeddings': {'emb_u': popularity_model.emb_u.weight.detach(), 'emb_i': popularity_model.emb_i.weight.detach()},
		'emb_operator': popularity_model._emb_operator}
		dependent_models = {'popularity': d}
	else:
		dependent_models = dict()
	cne_model = class_(user_num ,item_num, dependent_models, cne_config.interaction.parameters, ot_param_dict=dict(), use_ot=args.use_ot)
	if torch.cuda.is_available():
		cne_model.cuda()

	ot_param_dict, ot_plugin = get_ot_param_dict(args, train_loader, user_num, item_num)

	if not os.path.exists(model_file_path):
		print("model not found")

		########################### CREATE MODEL CNE #################################
		start_time = time.time()
		cne_model = class_(user_num ,item_num, dependent_models, cne_config.interaction.parameters, use_ot=args.use_ot, ot_param_dict=ot_param_dict)
		if torch.cuda.is_available():
			cne_model = cne_model.cuda()

		########################### TRAINING CNE #####################################
		cne_model = train(args, config, cne_model, class_, model_name='cne', ot_param_dict=ot_param_dict, dependent_models=dependent_models, model_file_path=model_file_path, epochs=args.epochs, patience=args.patience, monitor=args.monitor)
		if torch.cuda.is_available():
			cne_model = cne_model.cuda()
		end_time = time.time()
		total_time = end_time - start_time
		print("The total time is: " +
			time.strftime("%H: %M: %S", time.gmtime(total_time)))

		if args.out:
			if not os.path.exists(args.model_path):
				os.mkdir(args.model_path)
			cne_model.zero_grad()
			torch.save(cne_model.state_dict(),
				model_file_path)

	else:
		print("model found")
		if torch.cuda.is_available():
			state = torch.load(model_file_path)
		else:
			state = torch.load(model_file_path, map_location=torch.device('cpu'))
		cne_model.load_state_dict(state)
		cne_model.init_part2(args.use_ot, ot_param_dict, dependent_models, user_num, item_num)
		if torch.cuda.is_available():
			cne_model.cuda()


""" Recipe repository. """

from typing import List
from sqlalchemy import select, func, and_, or_, not_
from sqlalchemy.orm import joinedload, join
from core.db import session
from core.db.models import (
    Recipe,
    Tag,
    Ingredient,
    RecipeIngredient,
    RecipeTag,
    RecipeJudgement,
    User,
    UserTag,
)
from core.repository.base import BaseRepo

WANTED_TAG_TYPES = ["Keuken", "Dieet"]
UNWANTED_TAG_TYPES = ["Allergieën"]

class RecipeRepository(BaseRepo):
    """Recipe repository.

    Attributes
    ----------
    session : Session
        The database session.

    Methods
    -------
    get()
        Get a list of recipes.
    get_by_id(recipe_id)
        Get a recipe by id.
    get_by_tags(tags)
        Get a list of recipes by tags.
    get_by_ingredients(ingredients)
        Get a list of recipes by ingredients.
    get_judgment(recipe_id, user_id)
        Get a recipe judgement by recipe id and user id.
    """

    def __init__(self):
        super().__init__(Recipe)

    def query_options(self, query):
        return query.options(
            joinedload(Recipe.tags).joinedload(RecipeTag.tag),
            joinedload(Recipe.ingredients).joinedload(RecipeIngredient.ingredient),
            joinedload(Recipe.creator).joinedload(User.account_auth),
            joinedload(Recipe.creator).joinedload(User.image),
            joinedload(Recipe.judgements),
            joinedload(Recipe.image),
        )

    def get_no_dieet_filter_queries(self, user_id, user_tags):
        del user_tags

        query = (
            select(Recipe)
            .join(RecipeTag)
            .join(Tag)
            .join(UserTag, isouter=True)
            .where(
                Recipe.id.not_in(
                    select(Recipe.id)
                    .select_from(
                        join(Recipe, RecipeTag, Recipe.id == RecipeTag.recipe_id)
                        .join(Tag, Tag.id == RecipeTag.tag_id)
                        .join(UserTag, UserTag.tag_id == Tag.id)
                    )
                    .where(UserTag.user_id == user_id, Tag.tag_type == "Allergieën")
                )
            )
            .where((UserTag.user_id.is_(None)) | (UserTag.user_id == user_id))
            .order_by(Recipe.id)
        )
        count_query = (
            select(func.count(Recipe.id))
            .join(RecipeTag)
            .join(Tag)
            .join(UserTag, isouter=True)
            .where(
                Recipe.id.not_in(
                    select(Recipe.id)
                    .select_from(
                        join(Recipe, RecipeTag, Recipe.id == RecipeTag.recipe_id)
                        .join(Tag, Tag.id == RecipeTag.tag_id)
                        .join(UserTag, UserTag.tag_id == Tag.id)
                    )
                    .where(UserTag.user_id == user_id, Tag.tag_type == "Allergieën")
                )
            )
            .where((UserTag.user_id.is_(None)) | (UserTag.user_id == user_id))
        )
        return query, count_query

    def get_vegan_filter_queries(self, user_id, user_tags):
        del user_tags

        query = (
            select(Recipe)
            .join(RecipeTag)
            .join(Tag)
            .where(
                Recipe.id.not_in(
                    select(Recipe.id)
                    .select_from(
                        join(Recipe, RecipeTag, Recipe.id == RecipeTag.recipe_id)
                        .join(Tag, Tag.id == RecipeTag.tag_id)
                        .join(UserTag, UserTag.tag_id == Tag.id)
                    )
                    .where(UserTag.user_id == user_id, Tag.tag_type == "Allergieën")
                )
            )
            .where(Tag.name == "Veganistisch")
            .order_by(Recipe.id)
        )
        count_query = (
            select(func.count(Recipe.id))
            .join(RecipeTag)
            .join(Tag)
            .where(
                Recipe.id.not_in(
                    select(Recipe.id)
                    .select_from(
                        join(Recipe, RecipeTag, Recipe.id == RecipeTag.recipe_id)
                        .join(Tag, Tag.id == RecipeTag.tag_id)
                        .join(UserTag, UserTag.tag_id == Tag.id)
                    )
                    .where(UserTag.user_id == user_id, Tag.tag_type == "Allergieën")
                )
            )
            .where(Tag.name == "Veganistisch")
        )
        return query, count_query

    def get_vegetarian_filter_queries(self, user_id, user_tags):
        del user_tags

        query = (
            select(Recipe)
            .join(RecipeTag)
            .join(Tag)
            .where(
                Recipe.id.not_in(
                    select(Recipe.id)
                    .select_from(
                        join(Recipe, RecipeTag, Recipe.id == RecipeTag.recipe_id)
                        .join(Tag, Tag.id == RecipeTag.tag_id)
                        .join(UserTag, UserTag.tag_id == Tag.id)
                    )
                    .where(UserTag.user_id == user_id, Tag.tag_type == "Allergieën")
                )
            )
            .where((Tag.name == "Veganistisch") | (Tag.name == "Vegetarisch"))
            .order_by(Recipe.id)
        )
        count_query = (
            select(func.count(Recipe.id))
            .join(RecipeTag)
            .join(Tag)
            .where(
                Recipe.id.not_in(
                    select(Recipe.id)
                    .select_from(
                        join(Recipe, RecipeTag, Recipe.id == RecipeTag.recipe_id)
                        .join(Tag, Tag.id == RecipeTag.tag_id)
                        .join(UserTag, UserTag.tag_id == Tag.id)
                    )
                    .where(UserTag.user_id == user_id, Tag.tag_type == "Allergieën")
                )
            )
            .where((Tag.name == "Veganistisch") | (Tag.name == "Vegetarisch"))
        )
        return query, count_query

    async def get(self, limit: int = None, offset: int = None):
        query = select(Recipe)
        if limit:
            query = query.limit(limit)
        if offset:
            query = query.offset(offset)
        query = self.query_options(query)

        result = await session.execute(query)
        return result.scalars().unique().all()

    async def get_custom_filtered(
        self, tags: list[Tag], limit: int, offset: int
    ) -> list[Recipe]:
        recipes = await self.get()

        result = []

        if "Veganistisch" in [tag.name for tag in tags]:
            for recipe in recipes:
                if ("Veganistisch" in [tag.tag.name for tag in recipe.tags] or
                    "Vegetarisch" in [tag.tag.name for tag in recipe.tags]):
                    result.append(recipe)

        elif "Vegetarisch" in [tag.name for tag in tags]:
            for recipe in recipes:
                if "Vegetarisch" in [tag.tag.name for tag in recipe.tags]:
                    result.append(recipe)

        else:
            result = recipes

        if offset:
            result = result[offset:]

        if limit:
            result = result[:limit]

        return result

    async def get_filtered(
        self, limit: int, offset: int, user_id: int = None
    ) -> List[Recipe]:
        """Get a list of recipes.

        Returns
        -------
        List[Recipe]
            A list of recipes.
        """
        if user_id:
            user_tags = await self.get_user_tags(user_id)
            if not user_tags:
                query = select(Recipe)
                count_query = select(func.count()).select_from(Recipe)
            else:
                # apply filters
                if "Veganistisch" in [tag.name for tag in user_tags]:
                    ## apply vegan filter
                    query, count_query = self.get_vegan_filter_queries(
                        user_id, user_tags
                    )
                elif "Vegetarisch" in [tag.name for tag in user_tags]:
                    ## apply vegetarian filter
                    query, count_query = self.get_vegetarian_filter_queries(
                        user_id, user_tags
                    )
                else:
                    ## apply no dieet filters
                    query, count_query = self.get_no_dieet_filter_queries(
                        user_id, user_tags
                    )

        else:
            query = select(Recipe)
            count_query = select(func.count()).select_from(Recipe)
        # eager load all relationships
        query = self.query_options(query)
        # apply limit and offset
        query = query.limit(limit).offset(offset)
        result = await session.execute(query)
        # get count of all recipes in database
        result_count = await session.execute(count_query)
        recipes = result.unique().scalars().all()
        count = result_count.scalar()
        # return recipes and count
        return recipes, count

    async def get_user_tags(self, user_id: int):
        query = select(Tag).join(UserTag).where(UserTag.user_id == user_id)
        result = await session.execute(query)
        return result.scalars().all()

    async def get_by_id(self, model_id) -> Recipe:
        """Get a recipe by id.

        Parameters
        ----------
        recipe_id : int
            The id of the recipe to get.

        Returns
        -------
        Recipe
            The recipe with the given id.
        """
        query = select(Recipe).where(Recipe.id == model_id)
        query = self.query_options(query)
        result = await session.execute(query)
        return result.scalars().first()

    async def get_by_tags(self, tags: List[str]) -> List[Recipe]:
        """Get a list of recipes by tags.

        Parameters
        ----------
        tags : List[str]
            A list of tags to filter recipes by.

        Returns
        -------
        List[Recipe]
            A list of recipes filtered by the given tags.
        """
        query = select(Recipe).join(Recipe.tags).where(Tag.name.in_(tags))
        query = self.query_options(query)
        result = await session.execute(query)
        return result.scalars().all()

    async def get_by_ingredients(self, ingredients: List[str]) -> List[Recipe]:
        """Get a list of recipes by ingredients.

        Parameters
        ----------
        ingredients : List[str]
            A list of ingredients to filter recipes by.

        Returns
        -------
        List[Recipe]
            A list of recipes filtered by the given ingredients.
        """
        query = (
            select(Recipe)
            .join(Recipe.ingredients)
            .where(Ingredient.name.in_(ingredients))
        )
        query = self.query_options(query)
        result = await session.execute(query)
        return result.scalars().all()

    async def get_jugment(self, recipe_id: int, user_id: int) -> RecipeJudgement:
        """Get a recipe judgement.

        Parameters
        ----------
        recipe_id : int
            The id of the recipe to get the judgement for.
        user_id : int
            The id of the user to get the judgement for.

        Returns
        -------
        RecipeJudgement
            The recipe judgement.
        """

        query = select(RecipeJudgement).where(
            (RecipeJudgement.recipe_id == recipe_id)
            & (RecipeJudgement.user_id == user_id)
        )
        result = await session.execute(query)
        return result.scalars().first()

    async def judge(self, recipe_id: int, user_id: int, like: bool) -> None:
        """Like a recipe.

        Parameters
        ----------
        recipe_id : int
            The id of the recipe to like.
        user_id : int
            The id of the user who likes the recipe.
        like : bool
            True if the user likes the recipe, False if the user dislikes the recipe.
        """
        judgement = await self.get_jugment(recipe_id, user_id)
        if judgement:
            judgement.like = like
        else:
            session.add(
                RecipeJudgement(recipe_id=recipe_id, user_id=user_id, like=like)
            )

    # async def update_recipe(self, recipe: Recipe) -> Recipe:
    #     """Update a recipe.

    #     Parameters
    #     ----------
    #     recipe : Recipe
    #         The recipe to update.

    #     Returns
    #     -------
    #     Recipe
    #         The updated recipe.
    #     """
    #     await session.flush()
    #     return recipe


# COSC 482 Homework #3 - 3
#
# The eyes will follow the mouse pointer around the window.
#
# Kalyn Howes
# 3/9/22

from OpenGL.GL import *
from OpenGL.GL.shaders import *
from Shader import *
import numpy as np
import ctypes
from PIL import Image
from Polygon import *
import random
import pygame
import time
import glm
from PolygonAttr import *
from Polygon import *

class GraphicsEngine():
    # "Addresses" for OpenGL constructs.
    VAO = 0
    Buffer = 0
    vPosition = 0
    vColor = 1
    mode = GL_FILL
    shaderProgram = -1
    screenBounds = [-1, 1, -1, 1]

    # Constructor
    def __init__(self):
        # Load shaders and compile shader programs.
        try:
            shader = Shader()
            self.shaderProgram = shader.loadShadersFromFile("AspectRatioAndTransformVert.glsl", "PassThroughFrag.glsl")
        except Exception as err:
            for i in range(len(err.args)):
                print(err.args[i])
            raise Exception(err)

        # Turn on program, get the location of the projection and model matrices in the shader.
        glUseProgram(self.shaderProgram)
        self.projLoc = glGetUniformLocation(self.shaderProgram, "Projection")
        self.modelLoc = glGetUniformLocation(self.shaderProgram, "Model")
        self.setProjectionMatrix(pygame.display.get_surface().get_size())

        # Set clear/background color to black.
        glClearColor(0, 0, 0, 1)

        # self.eyes = []
        # self.pupils = []
        # self.pupilAttr = []

        self.circles = [] # first 2 will be whites of eyes, then pupils
        self.circleAttr = []

        # eyes
        self.circles.append(Polygon(0.4, 0, 50, 0.2))
        self.circles[len(self.circles) - 1].setColor([1, 1, 1, 0])
        self.circles.append(Polygon(-0.4, 0, 50, 0.2))
        self.circles[len(self.circles) - 1].setColor([1, 1, 1, 0])
        # pupils
        self.circles.append(Polygon(0.4, 0, 50, 0.08))
        self.circles[len(self.circles) - 1].setColor([0, 0, 0, 0])
        self.circles.append(Polygon(-0.4, 0, 50, 0.08))  # centerX, centerY, numSides, radius
        self.circles[len(self.circles) - 1].setColor([0, 0, 0, 0])

        velocity = [random.uniform(-0.01, 0.01), random.uniform(-0.01, 0.01)]

        # eyes attrs
        self.circleAttr.append(PolygonAttr(0, 0, 0.2, 0, 0))
        self.circleAttr.append(PolygonAttr(0, 0, 0.2, 0, 0))
        # pupils attrs
        self.circleAttr.append(PolygonAttr(0, 0, 0.08, velocity[0], velocity[1]))
        self.circleAttr.append(PolygonAttr(0, 0, 0.08, velocity[0], velocity[1]))

        # Get the start time of the program.
        self.start_time = time.time()

    # Turn on shader, clear screen, draw, swap display buffers.
    def update(self):
        glUseProgram(self.shaderProgram)
        glClear(GL_COLOR_BUFFER_BIT)
        glPolygonMode(GL_FRONT_AND_BACK, self.mode)

        for i in range(len(self.circles)):

            ModelMatrix = glm.mat4(1.0) # identity matrix
            ModelMatrix = glm.translate(ModelMatrix, glm.vec3(self.circleAttr[i].cx, self.circleAttr[i].cy, -1))
            glUniformMatrix4fv(self.modelLoc, 1, GL_FALSE, glm.value_ptr(ModelMatrix))

            self.circles[i].draw()

        self.printOpenGLErrors()

    # Set mode to fill.
    def setFill(self):
        self.mode = GL_FILL

    # Set mode to line.
    def setLine(self):
        self.mode = GL_LINE

    # Set mode to point.
    def setPoint(self):
        self.mode = GL_POINT

    # Get the real world screen bounds.
    def getScreenBounds(self):
        return self.screenBounds

    # Get the current viewport dimensions.
    def getViewport(self):
        return glGetIntegerv(GL_VIEWPORT)

    # Dump screen buffer data to raw pixels and convert to PIL Image object.
    def getScreenImage(self):
        viewport = glGetIntegerv(GL_VIEWPORT)
        glReadBuffer(GL_FRONT)
        pixels = glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3], GL_RGB, GL_UNSIGNED_BYTE)
        image = Image.frombytes("RGB", (viewport[2], viewport[3]), pixels)
        image = image.transpose(Image.FLIP_TOP_BOTTOM)
        return image

    # Set and load the projection matrix to the graphics card.
    def setProjectionMatrix(self, size):
        w, h = size

        # if width > height create a matrix to map scene to [-a, a] X [-1, 1]
        # if height > width create a matrix to map scene to [-1, 1] X [-a, a]
        if w > h:
            aspratio = w / h
            ProjectionMatrix = glm.ortho(-aspratio, aspratio, -1, 1) # glm.ortho creates the scaling matrix
            self.screenBounds = [-aspratio, aspratio, -1, 1]
        else:
            aspratio = h / w
            ProjectionMatrix = glm.ortho(-1, 1, -aspratio, aspratio) # glm.ortho creates the scaling matrix
            self.screenBounds = [-1, 1, -aspratio, aspratio]

        # Load Projection Matrix to the projection matrix in the shader.
        glUniformMatrix4fv(self.projLoc, 1, GL_FALSE, glm.value_ptr(ProjectionMatrix))

    # Print out any errors in the OpenGL error queue.
    def printOpenGLErrors(self):
        errCode = glGetError()
        while errCode != GL_NO_ERROR:
            errString = gluErrorString(errCode)
            print("OpenGL Error: ", errString, "\n")
            errCode = glGetError()


import logging
import os
import errno

def file_exists(data_file, must_exist=False):
    '''
    |
    | Function that test if a file exists
    |
    |
    |  Parameters
    |  ----------
    |  data_file : Path to the file
    |  must_exist : A boolean (default False), if True the code will stop
    |
    |  Returns
    |  -------
    |  boolean: True if the file exists
    |
    '''
    is_dir = False
    if os.path.exists(data_file):
        if not os.path.isdir(data_file):
            return True
        is_dir = True

    if must_exist:
        if is_dir:
            logging.error('%s is a directory!', data_file)
        else:
            logging.error('File %s does not exist!', data_file)
        exit(errno.ENOENT)
    else:
        return False

def directory_exists(path, must_exist=False):
    '''
    |
    | Function that test if a file exists
    |
    |
    |  Parameters
    |  ----------
    |  data_file : Path to the file
    |  must_exist : A boolean (default False), if True the code will stop
    |
    |  Returns
    |  -------
    |  boolean: True if the file exists
    |
    '''
    not_dir = False
    if os.path.exists(path):
        if os.path.isdir(path):
            return True
        not_dir = True

    if must_exist:
        if not_dir:
            logging.error('%s is not a directory!', path)
        else:
            logging.error('Directory %s does not exist!', path)
        exit(errno.ENOENT)
    else:
        return False

def get_cmri_logger():
    log_formatter = logging.Formatter('CMRI Bioinformatics %(levelname)s [%(asctime)s] | %(message)s')
    root_logger = logging.getLogger()
    root_logger.setLevel(logging.INFO)
    return root_logger, log_formatter

epilog_text = "Children's Medical Research Institute - Bioinformatics team "

def print_cmri_welcome(name):
    logging.info("-----------------------------------------------")
    logging.info("   ______     __    __     ______     __       ")
    logging.info('  /\  ___\   /\ "-./  \   /\  == \   /\ \      ')
    logging.info("  \ \ \____  \ \ \-./\ \  \ \  __<   \ \ \     ")
    logging.info("   \ \_____\  \ \_\ \ \_\  \ \_\ \_\  \ \_\    ")
    logging.info("    \/_____/   \/_/  \/_/   \/_/ /_/   \/_/    ")
    logging.info("")
    logging.info("---- Children’s Medical Research Institute ----")
    logging.info(" Finding cures for childhood genetic diseases  ")
    logging.info("")
    logging.info(" ==============================================")
    logging.info(" " + name)
    logging.info(" Author: Pablo Galaviz             ")
    logging.info(" pgalaviz@cmri.org.au              ")
    logging.info(" ==============================================")
    logging.info("")

def find_files(input_path, ext, compressed=False, path_list=None ):
    if path_list is None:
        path_list = list()
    file_name_list=os.path.basename(input_path).split(".")
    if os.path.isdir(input_path):
        for p in os.listdir(input_path):
            find_files(os.path.join(input_path, p), ext, compressed, path_list)
    elif compressed and len(file_name_list) ==3:
        if ".".join(file_name_list[1:]) == ext:
            path_list.append(input_path)
    elif file_name_list[-1] == ext:
        path_list.append(input_path)

    return path_list


## 백준 : 5430
from collections import deque
import sys
input = sys.stdin.readline

for _ in range(int(input())):
    p = input().rstrip()
    n = int(input())
    que = deque(input().rstrip()[1:-1].split(","))  ##',' 기준으로 나누기

    if n == 0:      ## 빈 배열 입력시, 다시 초기화 해줘야함.
        que = []

    flag = 0    ## 뒤집은 여부
    for ac in p:
        if ac == 'R':
            flag += 1

        elif ac == 'D':
            if que:
                if flag%2 == 0:      # 'R'이 짝수면 앞에서 제거
                    que.popleft()
                else:           ## 홀수면 뒤에서 제거
                    que.pop()

            else: ## 빈 배열이면 error 출력 뒤 break
                print('error')
                break

    else:
        if flag%2 == 0:
            print('['+','.join(que)+']')
        else:
            que.reverse()       ## reverse()는 최종적으로 한 번만
            print('['+','.join(que)+']')

백준/자료구조(stack, queue, heap, hash)/5430.py


import pathlib
import platform
import re
import warnings
from os import environ
from pathlib import Path

def ansys_version_from_inst_dir(installation_directory: pathlib.Path) -> str:
    """Get version from installation directory"""
    installation_directory = pathlib.Path(installation_directory)
    p = re.compile('v[0-9][0-9][0-9]')

    for part in installation_directory.parts:
        if p.match(part) is not None:
            return f'{part[1:3]}.{part[-1]}'

class CFXInstallation:
    """CFX Installation class"""

    def __init__(self, installation_directory: pathlib.Path = None,
                 paths=None):

        self.paths = paths
        if self.paths is None:
            self.paths = dict(cfx5pre=environ.get("cfx5pre"),
                              cfx5solve=environ.get("cfx5solve"),
                              cfx5post=environ.get("cfx5post"),
                              cfx5cmds=environ.get("cfx5cmds"))

        if installation_directory is None:
            if pathlib.Path(self.paths['cfx5pre']).exists():
                self.installation_directory = pathlib.Path(self.paths['cfx5pre']).parent
        else:
            self.installation_directory = pathlib.Path(installation_directory)

        if 'win' in platform.system().lower():
            self.paths = dict(cfx5pre=self.installation_directory / "cfx5pre.exe",
                              cfx5solve=self.installation_directory / "cfx5solve.exe",
                              cfx5post=self.installation_directory / "cfx5post.exe",
                              cfx5cmds=self.installation_directory / "cfx5cmds.exe")
        else:
            self.paths = dict(cfx5pre=self.installation_directory / "cfx5pre",
                              cfx5solve=self.installation_directory / "cfx5solve",
                              cfx5post=self.installation_directory / "cfx5post",
                              cfx5cmds=self.installation_directory / "cfx5cmds")

    def __repr__(self) -> str:
        return f'<{self.__class__.__name__} "{self.directory}">'

    @property
    def directory(self) -> pathlib.Path:
        """Installation dir"""
        return self.pre.parent

    @property
    def version(self) -> str:
        """Ansys version"""
        return ansys_version_from_inst_dir(self.directory)

    @property
    def pre(self) -> pathlib.Path:
        """Path to cfx5pre exe"""
        return pathlib.Path(self.paths["cfx5pre"])

    @property
    def solve(self) -> pathlib.Path:
        """Path to cfx5solve exe"""
        return pathlib.Path(self.paths["cfx5solve"])

    @property
    def post(self) -> pathlib.Path:
        """Path to cfx5post exe"""
        return pathlib.Path(self.paths["cfx5post"])

    @property
    def cmds(self) -> pathlib.Path:
        """Path to cfx5cmds exe"""
        return pathlib.Path(self.paths["cfx5cmds"])

    def is_valid(self) -> bool:
        """Check if exe exist"""
        for exe_name, exe_path in (('cfx5solve', self.solve),
                                   ('cfx5pre', self.pre),
                                   ('cfx5post', self.post),
                                   ('cfx5cmds', self.cmds)):
            if exe_path is None:
                warnings.warn(f'{exe_name} not found in environment variables!')
                return False
            else:
                if not Path(exe_path).exists():
                    warnings.warn(f'cfx5solve not found: "{Path(exe_path).resolve()}"')
                    return False
        return True


import sys
from PyQt5.QtWidgets import QApplication
import service_browser
import service_add
import service_edit
import shipment_browser
import shipment_edit
import shipment_add
import customer_browser
import customer_edit
import customer_add
import connect

def customerE_click1():
    b=customerB.label_id1.text()
    return b
def customerE_click2():
    b=customerB.label_id2.text()
    return b
def customerE_click3():
    b=customerB.label_id3.text()
    return b
def customerE_click4():
    b=customerB.label_id4.text()
    return b
def customerE_click5():
    b=customerB.label_id5.text()
    return b
def customerE_click6():
    b=customerB.label_id6.text()
    return b
def customerE_click7():
    b=customerB.label_id7.text()
    return b
def customerE_click8():
    b=customerB.label_id8.text()
    return b
def customerE_click9():
    b=customerB.label_id9.text()
    return b
def customerE_click10():
    b=customerB.label_id10.text()
    return b

def serviceE_click1():
    b=serviceB.label_id1.text()
    return b
def serviceE_click2():
    b=serviceB.label_id2.text()
    return b
def serviceE_click3():
    b=serviceB.label_id3.text()
    return b
def serviceE_click4():
    b=serviceB.label_id4.text()
    return b
def serviceE_click5():
    b=serviceB.label_id5.text()
    return b
def serviceE_click6():
    b=serviceB.label_id6.text()
    return b
def serviceE_click7():
    b=serviceB.label_id7.text()
    return b
def serviceE_click8():
    b=serviceB.label_id8.text()
    return b
def serviceE_click9():
    b=serviceB.label_id9.text()
    return b
def serviceE_click10():
    b=serviceB.label_id10.text()
    return b

def shipmentE_click1():
    b=shipmentB.label_id1.text()
    return b
def shipmentE_click2():
    b=shipmentB.label_id2.text()
    return b
def shipmentE_click3():
    b=shipmentB.label_id3.text()
    return b
def shipmentE_click4():
    b=shipmentB.label_id4.text()
    return b
def shipmentE_click5():
    b=shipmentB.label_id5.text()
    return b
def shipmentE_click6():
    b=shipmentB.label_id6.text()
    return b
def shipmentE_click7():
    b=shipmentB.label_id7.text()
    return b
def shipmentE_click8():
    b=shipmentB.label_id8.text()
    return b
def shipmentE_click9():
    b=shipmentB.label_id9.text()
    return b
def shipmentE_click10():
    b=shipmentB.label_id10.text()
    return b

if __name__=='__main__':
    app=QApplication(sys.argv) #格式

### 引入3个brower页面
    customerB = customer_browser.MyForm()
    shipmentB = shipment_browser.MyForm()
    serviceB = service_browser.MyForm()
    sync=connect.MyForm() #数据同步页面

    customerB.pageDisplay(0,1) #默认显示第1页
    shipmentB.pageDisplay(0,1) #默认显示第1页
    serviceB.pageDisplay(0,1) #默认显示第1页
    shipmentB.show()  #默认显示产品出货页面

### 引入3个edit页面
    shipmentE = shipment_edit.MyForm()
    serviceE = service_edit.MyForm()
    customerE = customer_edit.MyDialog()

### 引入3个add页面
    shipmentA = shipment_add.MyForm()
    serviceA = service_add.MyForm()
    customerA = customer_add.MyForm()

# browser页面点击切换不同窗口：产品出货/售后服务/客户信息
    customerB.pushButton_SwitchShipment.clicked.connect(shipmentB.show)
    customerB.pushButton_SwitchShipment.clicked.connect(customerB.hide)
    serviceB.pushButton_SwitchShipment.clicked.connect(shipmentB.show)
    serviceB.pushButton_SwitchShipment.clicked.connect(serviceB.hide)
    shipmentB.pushButton_SwitchCustomer.clicked.connect(customerB.show)
    shipmentB.pushButton_SwitchCustomer.clicked.connect(shipmentB.hide)

    serviceB.pushButton_SwitchCustomer.clicked.connect(customerB.show)
    serviceB.pushButton_SwitchCustomer.clicked.connect(serviceB.hide)
    shipmentB.pushButton_SwitchService.clicked.connect(serviceB.show)
    shipmentB.pushButton_SwitchService.clicked.connect(shipmentB.hide)
    customerB.pushButton_SwitchService.clicked.connect(serviceB.show)
    customerB.pushButton_SwitchService.clicked.connect(customerB.hide)

# browser页面点击“编辑”弹出编辑窗口
    customerB.pushButton_edit1.clicked.connect(lambda:customerE.handle_click1(customerE_click1()))
    customerB.pushButton_edit2.clicked.connect(lambda:customerE.handle_click2(customerE_click2()))
    customerB.pushButton_edit3.clicked.connect(lambda:customerE.handle_click3(customerE_click3()))
    customerB.pushButton_edit4.clicked.connect(lambda:customerE.handle_click4(customerE_click4()))
    customerB.pushButton_edit5.clicked.connect(lambda:customerE.handle_click5(customerE_click5()))
    customerB.pushButton_edit6.clicked.connect(lambda:customerE.handle_click6(customerE_click6()))
    customerB.pushButton_edit7.clicked.connect(lambda:customerE.handle_click7(customerE_click7()))
    customerB.pushButton_edit8.clicked.connect(lambda:customerE.handle_click8(customerE_click8()))
    customerB.pushButton_edit9.clicked.connect(lambda:customerE.handle_click9(customerE_click9()))
    customerB.pushButton_edit10.clicked.connect(lambda:customerE.handle_click10(customerE_click10()))

    serviceB.pushButton_edit1.clicked.connect(lambda:serviceE.handle_click1(serviceE_click1()))
    serviceB.pushButton_edit2.clicked.connect(lambda:serviceE.handle_click2(serviceE_click2()))
    serviceB.pushButton_edit3.clicked.connect(lambda:serviceE.handle_click3(serviceE_click3()))
    serviceB.pushButton_edit4.clicked.connect(lambda:serviceE.handle_click4(serviceE_click4()))
    serviceB.pushButton_edit5.clicked.connect(lambda:serviceE.handle_click5(serviceE_click5()))
    serviceB.pushButton_edit6.clicked.connect(lambda:serviceE.handle_click6(serviceE_click6()))
    serviceB.pushButton_edit7.clicked.connect(lambda:serviceE.handle_click7(serviceE_click7()))
    serviceB.pushButton_edit8.clicked.connect(lambda:serviceE.handle_click8(serviceE_click8()))
    serviceB.pushButton_edit9.clicked.connect(lambda:serviceE.handle_click9(serviceE_click9()))
    serviceB.pushButton_edit10.clicked.connect(lambda:serviceE.handle_click10(serviceE_click10()))

    shipmentB.pushButton_edit1.clicked.connect(lambda:shipmentE.handle_click1(shipmentE_click1()))
    shipmentB.pushButton_edit2.clicked.connect(lambda:shipmentE.handle_click2(shipmentE_click2()))
    shipmentB.pushButton_edit3.clicked.connect(lambda:shipmentE.handle_click3(shipmentE_click3()))
    shipmentB.pushButton_edit4.clicked.connect(lambda:shipmentE.handle_click4(shipmentE_click4()))
    shipmentB.pushButton_edit5.clicked.connect(lambda:shipmentE.handle_click5(shipmentE_click5()))
    shipmentB.pushButton_edit6.clicked.connect(lambda:shipmentE.handle_click6(shipmentE_click6()))
    shipmentB.pushButton_edit7.clicked.connect(lambda:shipmentE.handle_click7(shipmentE_click7()))
    shipmentB.pushButton_edit8.clicked.connect(lambda:shipmentE.handle_click8(shipmentE_click8()))
    shipmentB.pushButton_edit9.clicked.connect(lambda:shipmentE.handle_click9(shipmentE_click9()))
    shipmentB.pushButton_edit10.clicked.connect(lambda:shipmentE.handle_click10(shipmentE_click10()))

# browser页面点击“新增”弹出新增窗口
    customerB.pushButton_new.clicked.connect(customerA.handle_click)
    serviceB.pushButton_new.clicked.connect(serviceA.handle_click)
    shipmentB.pushButton_new.clicked.connect(shipmentA.handle_click)

# shipment_browser页面点击“数据同步”连接数据库
    shipmentB.toolButton.clicked.connect(sync.handle_click)

# edit编辑或add新增信息后，刷新browser窗口
    customerE.pushButton_save.clicked.connect(customerB.reload)
    customerA.pushButton_save.clicked.connect(customerB.reload)
    serviceE.pushButton_save.clicked.connect(serviceB.reload)
    serviceA.pushButton_save.clicked.connect(serviceB.reload)
    shipmentE.pushButton_save.clicked.connect(shipmentB.reload)
    shipmentA.pushButton_save.clicked.connect(shipmentB.reload)

    app.exec_() #格式


# Boorger. Downloads images and videos from Gelbooru, Danbooru, Konachan
# and iibooru.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>

import sys
import argparse

# local import:
from boorger.startburger import Boorger

def main():
    """If user pass no arguments - return help message. Otherwise start
    the programm."""
    if len(sys.argv) > 1:
        start()
    else:
        sys.argv.append("--help")
        start()

def start():
    """https://docs.python.org/3/library/argparse.html"""

    parser = argparse.ArgumentParser(
        usage="""boorger url [optional arguments]""",
        description="""Downloads images and videos from Gelbooru, Danbooru,
        Konachan and iibooru.""")
    parser.add_argument(
        "url", nargs='?', help="""Valid url. For example:
        'https://gelbooru.com/index.php?page=post&s=list&tags=suigintou'""")
    parser.add_argument(
        "-d", "--directory", type=str, default=None,
        help="""Directory to store downloaded images. Must contain full path.
        For example: '/home/user/Pictures/' If not given, images vill
        downloaded to /booru_images/ in current working directory.""")
    parser.add_argument(
        "-p", "--pages", type=int, default=1,
        help="""Number of pages you want to download.""")
    parser.add_argument(
        "-r", "--reverse", action="store_true",
        help="""If selected, pages will be loaded in descending order.""")
    parser.add_argument(
        "-l", "--license", action="store_true",
        help="""Print the license of boorger.""")

    args = parser.parse_args()
    url = args.url
    directory = args.directory
    pages = args.pages
    if args.reverse:
        reverse = True
    else:
        reverse = False
    if args.license:
        gpl = __file__.rsplit("/", 1)[0] + "/LICENSE"
        with open(gpl) as f:
            my_license = f.read()
            print(my_license)
    elif not args.url:
        print("You need to pass valid url.")
    else:
        # Start "startburger.py" from command line.
        download = Boorger(url, directory, reverse)
        download.main(pages)


import bs4
import urllib.request as request
from urllib import parse

from italian_dictionary import exceptions

URL = "https://www.dizionario-italiano.it/dizionario-italiano.php?parola={}100"

def build_url(base_url):
    scheme, netloc, path, query, fragment = parse.urlsplit(base_url)
    query = parse.quote(query, safe="?=/")
    return parse.urlunsplit((scheme, netloc, path, query, fragment))  # replacing special characters

def get_soup(url):
    sauce = request.urlopen(url).read()
    soup = bs4.BeautifulSoup(sauce, 'html.parser')
    return soup

def get_lemma(soup):
    lemma = soup.find('span', class_='lemma')
    if lemma is not None:
        return lemma.find(text=True, recursive=False).rstrip() # Getting only span text + removing white spaces at the end

def get_sillabe(soup, word):
    lemma = soup.find(class_='lemma')
    small_list = lemma.find_all_next('small')
    for el in small_list:
        if el.parent not in lemma.children:
            try:
                sillabe = el.span.find(text=True, recursive=False)
            except AttributeError:  # Word has no syllable division
                return [word]
            break

    split_indexes = [pos for pos, char in enumerate(sillabe) if char == "|"]
    # necessario perchè le sillabazioni contengono gli accenti di pronuncia
    tmp = list(word)
    for i in split_indexes:
        tmp = tmp[0:i] + ["|"] + tmp[i:]
        sillabe = ''.join(tmp).split("|")
    return sillabe

def get_pronuncia(soup):
    pronuncia = soup.find('span', class_="paradigma")
    return pronuncia.text[10:]

def get_grammatica(soup):
    gram = soup.find_all('span', class_="grammatica")
    return [x.text for x in gram]

def get_locuzioni(soup):
    bad_loc = soup.find_all('span', class_='cit_ita_1')
    loc = [x.text for x in bad_loc]
    return loc

def get_defs(soup):
    defs = []
    for definitions in soup.find_all('span', class_='italiano'):
        children_content = ''
        for children in definitions.findChildren():
            if children.string is None:
                continue
            try:
                if children.attrs['class'][0] in ('esempi', 'autore'):
                    continue
                else:
                    children_content += children.text
                    children_content += ' '
                    children.decompose()
            except KeyError:
                continue
        if children_content != '':
            defs.append(f"{children_content.upper()} -- {definitions.text.replace('()', '')}")
        else:
            defs.append(definitions.text)
    if len(defs) == 0:
        raise exceptions.WordNotFoundError()
    return defs

def get_data(word, all_data=True):
    url = build_url(URL.format(word))
    soup = get_soup(url)
    if all_data is False:
        return get_defs(soup)

    data = {'definizione': get_defs(soup), 'sillabe': get_sillabe(soup, word), 'lemma': get_lemma(soup),
            'pronuncia': get_pronuncia(soup), 'grammatica': get_grammatica(soup), 'locuzioni': get_locuzioni(soup),
            'url': url}
    return data


"""
Requirement:
    https://leetcode.com/problems/rotate-array/

    Given an array, rotate the array to the right by k steps, where k is non-negative.

    Example 1:

    Input: [1,2,3,4,5,6,7] and k = 3
    Output: [5,6,7,1,2,3,4]
    Explanation:
    rotate 1 steps to the right: [7,1,2,3,4,5,6]
    rotate 2 steps to the right: [6,7,1,2,3,4,5]
    rotate 3 steps to the right: [5,6,7,1,2,3,4]
    Example 2:

    Input: [-1,-100,3,99] and k = 2
    Output: [3,99,-1,-100]
    Explanation:
    rotate 1 steps to the right: [99,-1,-100,3]
    rotate 2 steps to the right: [3,99,-1,-100]
    Note:

    Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem.
    Could you do it in-place with O(1) extra space?
"""

"""
Solution:
    [1, 2, 3, 4, 5, 6, 7, 8]
            [1, 2, 3, 4, 5     => nums[0, 8 - 3]
    6, 7, 8]                    => nums[8 - 3, 8]
"""

from typing import List
class Solution:
    def rotate(self, nums: List[int], k: int):
        """Do not return anything, modify nums in-place instead"""
        length = len(nums)
        scope = length - k

        # https://stackoverflow.com/questions/22054698/python-modifying-list-inside-a-function
        # If you assign something to the variable list_arg, it will from then on
        # point to the new value. The value it pointed to before that assignment
        # (your original list) will stay unchanged.
        #
        # If you, instead, assign something to elements of that list, this will
        # change the original list:
        #
        # list_arg[:] = list(a)
        print(nums[scope:length])
        print(nums[0:scope])
        nums[:] = nums[scope:length] + nums[0:scope]
        print(nums)

nums = [1, 2, 3, 4, 5, 6, 7, 8]
Solution().rotate(nums, 3)

nums = [1, 2]
Solution().rotate(nums, 1)


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

# In[11]:

####################################################################################################################
##ver002

#001 : score+angle , 같은구도의 사진이 너무 많이 출력됨.
#002 : score, angle도 score화 하여 angle값이 0에 가까울수록 좋은사진이라고 판별하고 저장, 같은구도는 생략하도록 코드수정

####################################################################################################################
##사용모듈

import cv2
import numpy as np
import mediapipe as mp
import pandas as pd
from tqdm.notebook import tqdm
from sklearn.model_selection import train_test_split
import time
from collections import deque
import tensorflow as tf

####################################################################################################################
##사용함수
def cal_d(p,n):
    d = (p[0]-n[0])**2 + (p[1]-n[1])**2
    return d**(1/2)

def cal_p(x,y):
    return (x-y)

def get_score(data):
    score = score_model.predict(data)[0][0]
    score = int(score*10000)
    score = float(score)/100
    return score

def get_angle(data):
    p = angle_model.predict(data)[0][0]
    return p-90

def cor_histogram(correl_imagelist):
    hists = []
    co01 = []
    co09 = []
    for file in correl_imagelist:
        nowimg = file[0]
        #// BGR 이미지를 HSV 이미지로 변환
        hsv = cv2.cvtColor(nowimg, cv2.COLOR_BGR2HSV)
        #// 히스토그램 연산(파라미터 순서 : 이미지, 채널, Mask, 크기, 범위)
        hist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
        #// 정규화(파라미터 순서 : 정규화 전 데이터, 정규화 후 데이터, 시작 범위, 끝 범위, 정규화 알고리즘)
        cv2.normalize(hist, hist, 0, 1, cv2.NORM_MINMAX)
       # // hists 리스트에 저장
        hists.append(hist)

    #// 1번째 이미지를 원본으로 지정
    if hists:
        query = hists[-1]

        #// 비교 알고리즘의 이름들을 리스트에 저장
        methods = ['CORREL']#, 'CHISQR', 'INTERSECT', 'BHATTACHARYYA', 'EMD']
        compare_hists = []
        for i, histogram in enumerate(hists):
            ret = cv2.compareHist(query, histogram, 0)
            if ret<0.9:
                co01.append(correl_imagelist[i])
            else:
                co09.append(correl_imagelist[i])

        co09 = sorted(co09, key = lambda x : x[1])

        while len(co09) > correl_save_number:
            del co09[0]

        correl_imagelist = co01 + co09
        correl_imagelist = sorted(correl_imagelist, key=lambda x : x[1])

        while len(correl_imagelist)> picture_save_number:
            del correl_imagelist[0]

    return correl_imagelist

####################################################################################################################
#pretrained model
score_model = tf.keras.models.load_model('./flp/model/flp_score_predict001.h5')
angle_model = tf.keras.models.load_model('./flp/model/flp_horizon_correction003.h5')

####################################################################################################################
#main code

mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_holistic = mp.solutions.holistic
count=0
BG_COLOR = (0, 0, 0) # gray
MASK_COLOR = (1, 1, 1) # white

cap = cv2.VideoCapture('./test02.mp4')

prev_time = 0
FPS = 10
prescore=0
idx=0
datacompare = 0

picture_save_number = 30
correl_save_number = 5

imagelist = []
correl_imagelist = []

with mp_holistic.Holistic(
    min_detection_confidence=0.5,
    min_tracking_confidence=0.5) as holistic:
    while cap.isOpened():
        idx+=1
        success, image = cap.read()
        if not success:
            print("Ignoring empty camera frame.")
    # If loading a video, use 'break' instead of 'continue'.
            break

    # To improve performance, optionally mark the image as not writeable to
    # pass by reference.
        image.flags.writeable = False
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        results = holistic.process(image)

        n=[]
        visibility =[]
        if results.pose_landmarks:
            for data_point in results.pose_landmarks.landmark:
                n.append(data_point.x)
                n.append(data_point.y)
                n.append(data_point.z)
                visibility.append(data_point.visibility)
        else:
            for _ in range(99):
                n.append(0)

        nowdata = [n]

        if datacompare ==0:
            predata = [[0 for _ in range(99)]]

        datacompare +=1

        #프레임간 좌표이동값
        xyzd = 0
        for i in range(99):
            xyzd += (nowdata[0][i]-predata[0][i])**2

        lifescore = get_score(nowdata)
        lifeangle = get_angle(nowdata)

#         allscore = (lifescore+(100-abs(lifeangle)))/2
        allscore = lifescore
        predata = nowdata

        text1 = "score : {}".format(round(lifescore,2))
        text2 = "angle : {}".format(round(lifeangle,2))
        org1 = (30,30)
        org2 = (30,60)
        font=cv2.FONT_HERSHEY_SIMPLEX

    # Draw landmark annotation on the image.
        image.flags.writeable = True
        image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
        save_image = image.copy()

        mp_drawing.draw_landmarks(
            image,
            results.pose_landmarks,
            mp_holistic.POSE_CONNECTIONS,
            landmark_drawing_spec=mp_drawing_styles.get_default_pose_landmarks_style())

        #이상한사진 감지 후 image추가
        if xyzd<0.002 and abs(lifeangle)<10:
            correl_imagelist.append([save_image, allscore])

        correl_imagelist = cor_histogram(correl_imagelist)

        prescore= lifescore
        cv2.putText(image, text1, org1, font, 1, (255,0,0) ,2)
        cv2.putText(image, text2, org2, font, 1, (255,0,0) ,2)

    # Flip the image horizontally for a selfie-view display.
        cv2.imshow('MediaPipe Holistic', image)
        if cv2.waitKey(1) & 0xFF == 27:
            break

cv2.destroyAllWindows()
cap.release()

##bestcut 저장
count2=0
for bestpicture in correl_imagelist:
    count2 += 1
    cv2.imwrite('./flp/test002/best_image{:0>4}_s{}'.format(count2, int(bestpicture[1]))+'.png', bestpicture[0])


# Create your views here.
import requests
from django.contrib.auth import login as auth_login
from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from django.contrib.auth import logout as auth_logout
from exp_rest.api.v1.serializers import AuthSerializer

BASE_URL = 'https://gis-api.aiesec.org/v2/'
API_REQUESTS = {
    'GET': requests.get,
    'POST': requests.post,
    'PUT': requests.put,
    'DELETE': requests.delete,
    'PATCH': requests.patch,
}

@api_view(['POST'])
def login(request):
    if not request.user.is_anonymous():
        auth_logout(request)
    serial = AuthSerializer(data=request.data)
    if serial.is_valid():
        token = serial.login()
        if not token:
            return Response({'detail': 'Failed to login; incorrect email or password'}, status.HTTP_400_BAD_REQUEST)
        # auth_login(request, request.user)
        return Response({'token': token}, status.HTTP_200_OK)
    return Response({'detail': 'Invalid login data'}, status.HTTP_400_BAD_REQUEST)

"""
EXP logout doesn't work correctly. I can use two tokens at same time
and one of them was used to sign_out from experience.org
"""

@api_view(['POST'])
def logout(request):
    detail = {
        'detail': 'Successfully logged out',
    }
    response = Response(detail, status.HTTP_200_OK)
    if request.user.is_anonymous():
        return response
    # auth_logout(request)
    return response

def get_api_request_result(url, data, method):
    headers = {}
    if method != 'GET':
        headers['Content-type'] = 'application/json'
    response = API_REQUESTS[method](BASE_URL + url, data=data, headers=headers)
    if response.status_code >= 400:
        return [None, response.status_code, response.content]
    result = response.json()
    return [result]

@api_view(['GET'])
# @permission_classes((IsAuthenticated,))
def get_eps(request, token):
    if not token:
        return Response({'detail': 'No access to do this'}, status.HTTP_401_UNAUTHORIZED)
    result = get_api_request_result('people', {'access_token': token}, 'GET')
    if len(result) > 1:
        return Response({'detail': result[2]}, status=result[1])
    return Response(result[0], status.HTTP_200_OK)

@api_view(['GET'])
# @permission_classes((IsAuthenticated,))
def get_my_eps(request, token):
    if not token:
        return Response({'detail': 'No access to do this'}, status.HTTP_401_UNAUTHORIZED)
    result = get_api_request_result('people/my', {'access_token': token}, 'GET')
    if len(result) > 1:
        return Response({'detail': result[2]}, status=result[1])
    return Response(result[0], status.HTTP_200_OK)

@api_view(['GET'])
def get_ep(request, id, token):
    if not token:
        return Response({'detail': 'No access to do this'}, status.HTTP_401_UNAUTHORIZED)
    result = get_api_request_result('people/' + id, {'access_token': token}, 'GET')
    if len(result) > 1:
        return Response({'detail': result[2]}, status=result[1])
    return Response(result[0], status.HTTP_200_OK)

@api_view(['GET'])
def get_opportunities(request, token):
    if not token:
        return Response({'detail': 'No access to do this'}, status.HTTP_401_UNAUTHORIZED)
    result = get_api_request_result('opportunities', {'access_token': token}, 'GET')
    if len(result) > 1:
        return Response({'detail': result[2]}, status=result[1])
    return Response(result[0], status.HTTP_200_OK)

@api_view(['GET'])
def get_opportunity(request, id, token):
    if not token:
        return Response({'detail': 'No access to do this'}, status.HTTP_401_UNAUTHORIZED)
    result = get_api_request_result('opportunities/' + id, {'access_token': token}, 'GET')
    if len(result) > 1:
        return Response({'detail': result[2]}, status=result[1])
    return Response(result[0], status.HTTP_200_OK)


import typing
from abc import abstractmethod

import numpy as np
import torch
from PyQt5.QtGui import QValidator, QDoubleValidator, QIntValidator
from PyQt5.QtWidgets import QLineEdit

from dipter.gui.widgets.node_input.io_module import Input
from dipter.node_graph.data_type import DataType

Number = typing.Union[int, float]

INT_MIN = np.iinfo(np.int32).min
INT_MAX = np.iinfo(np.int32).max
FLOAT_MIN = np.finfo(np.float32).min
FLOAT_MAX = np.finfo(np.float32).max

class NumberValidator:
    MALFORMED_NUMBER = 0
    TOO_LARGE = 1
    TOO_SMALL = 2

    def __init__(self, bottom, top):
        """Subclasses must pass a function used to convert the string to be validated into the correct data type."""
        self._reason_for_invalid = None
        self.bottom = bottom
        self.top = top

    def validate(self, input_: str, cursor_pos: int) -> (int, str, int):
        input_ = input_.strip()

        if input_ == "" or input_ == "-" or input_ == "+":
            return QValidator.Intermediate, input_, cursor_pos

        if input_ == "-" or input_ == "+":
            return QValidator.Intermediate, input_, cursor_pos

        try:
            as_number = self.validate_intermediate(input_)

            ltt = as_number <= self.top
            gtb = as_number >= self.bottom

            if ltt:
                if gtb:
                    self._reason_for_invalid = None
                    return QValidator.Acceptable, input_, cursor_pos
                else:
                    self._reason_for_invalid = self.TOO_SMALL
                    return QValidator.Intermediate, input_, cursor_pos
            else:
                self._reason_for_invalid = self.TOO_LARGE
                return QValidator.Invalid, input_, cursor_pos

        except ValueError:
            self._reason_for_invalid = self.MALFORMED_NUMBER
            return QValidator.Invalid, input_, cursor_pos

    @abstractmethod
    def validate_intermediate(self, intermediate_input: str) -> Number:
        """Validate the intermediate input. This is called after the string has been cleaned and checked if its empty (including '+' or '-').

        This function should raise a ValueError if the string does not follow the formatting of the wanted number type. This includes converting a
        valid float with decimals to an integer (as integers should not contain decimals). This enables fixup() to clean the string properly.

        :return: The string input converted to a number.
        """
        pass

class FloatValidator(NumberValidator, QDoubleValidator):

    def __init__(self, bottom: float, top: float, decimals: int):
        """
        Creates a new DoubleValidator with fixup (attempts to correct an invalid string)
        """
        NumberValidator.__init__(self, bottom, top)
        QDoubleValidator.__init__(self, bottom, top, decimals)

    def validate_intermediate(self, intermediate_input: str) -> Number:
        # TODO Check for number of decimals to display!
        return float(intermediate_input)

    def fixup(self, input_: str) -> str:
        """Attempts to return a corrected version of the invalid widgets string."""

        corrected = input_

        if self._reason_for_invalid == self.MALFORMED_NUMBER:
            corrected = corrected.replace(',', '.')  # replace commas with full stops
            corrected = corrected.replace('\D', '')  # Remove any non-digits
        elif self._reason_for_invalid == self.TOO_SMALL:
            corrected = str(self._bottom())
        elif self._reason_for_invalid == self.TOO_LARGE:
            corrected = str(self._top())

        return corrected

class IntValidator(NumberValidator, QIntValidator):

    def __init__(self, bottom: int, top: int):
        """
        Creates a new IntValidator with fixup (attempts to correct an invalid string)
        """
        NumberValidator.__init__(self, bottom, top)
        QIntValidator.__init__(self, bottom, top)

    def validate_intermediate(self, intermediate_input: str) -> Number:
        if ',' in intermediate_input or '.' in intermediate_input:
            raise ValueError("Decimal symbol in integer input is invalid!")

        return int(intermediate_input)

    def fixup(self, input_: str) -> str:
        """Attempts to return a corrected version of the invalid widgets string."""

        corrected = input_

        if self._reason_for_invalid == self.MALFORMED_NUMBER:
            corrected = corrected.replace(',', '.')  # replace commas with full stops
            corrected = corrected.replace('\D', '')  # Remove any non-digits
            try:
                corrected = int(corrected)  # Attempt to remove decimals
            except ValueError:
                pass
        elif self._reason_for_invalid == self.TOO_SMALL:
            corrected = str(self.bottom())
        elif self._reason_for_invalid == self.TOO_LARGE:
            corrected = str(self.top())

        return corrected

class MultipleNumberValidator(QValidator):

    def __init__(self, validate: typing.Callable, fixup: typing.Callable):
        super().__init__()
        self.func_validate = validate
        self.func_fixup = fixup

    def validate(self, input_: str, cursor_pos: int) -> (int, str, int):
        numbers = input_.split(",")
        total_res = self.Acceptable
        for num in numbers:
            res, _, _ = self.func_validate(num, cursor_pos)

            if res == self.Intermediate:
                total_res = self.Intermediate
            elif res == self.Invalid:
                return self.Invalid, input_, cursor_pos

        return total_res, input_, cursor_pos

    def fixup(self, input_: str) -> str:
        numbers = input_.split(",")
        for i, num in enumerate(numbers):
            corrected = self.func_fixup(num)
            numbers[i] = corrected

        return ", ".join(numbers)

class MultipleFloatValidator(MultipleNumberValidator):
    def __init__(self, bottom: float, top: float, decimals: int):
        validator = FloatValidator(bottom, top, decimals)
        super().__init__(validate=validator.validate, fixup=validator.fixup)

class MultipleIntValidator(IntValidator):

    def __init__(self, bottom: int, top: int):
        super().__init__(bottom, top)

    def validate(self, input_: str, cursor_pos: int) -> (int, str, int):
        numbers = input_.split(",")
        total_res = self.Acceptable
        for num in numbers:
            res, _, _ = super().validate(num, cursor_pos)

            if res == self.Intermediate:
                total_res = self.Intermediate
            elif res == self.Invalid:
                return self.Invalid, input_, cursor_pos

        return total_res, input_, cursor_pos

    def fixup(self, input_: str) -> str:
        numbers = input_.split(",")
        for i, num in enumerate(numbers):
            corrected = super().fixup(num)
            numbers[i] = corrected

        return ", ".join(numbers)

class LineInput(QLineEdit, Input):

    @abstractmethod
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._old_text = ""
        self.editingFinished.connect(self._handle_change)
        self.textChanged.connect(self._handle_change)
        self.setMaximumWidth(80)

    def _handle_change(self):
        if self.text() != self._old_text:
            self.input_changed.emit()
            self._old_text = self.text()

    def get_value(self) -> str:
        return self.text()

class FloatInput(LineInput):

    def __init__(self, min_: float = FLOAT_MIN, max_: float = FLOAT_MAX, dtype=DataType.Float):
        assert min_ <= max_, "Minimum value must be less than or equal to maximum value!"
        super().__init__(dtype=dtype)

        self.min_ = min_
        self.max_ = max_
        self.setValidator(FloatValidator(bottom=self.min_, top=self.max_, decimals=5))

    def set_value(self, value: typing.Any):
        assert isinstance(value, (float, int, np.int, np.float32, torch.FloatTensor, torch.cuda.FloatTensor)), \
            "Incompatible type ({}) of value for FloatInput!".format(type(value))

        self.setText(str(float(value)))

    def get_gl_value(self) -> typing.Any:
        text = self.text().strip()
        if text == "+" or text == "-" or text == "":
            return np.float32(0.0)

        return np.float32(float(self.text()))

class IntInput(LineInput):

    def __init__(self, min_: int = INT_MIN, max_: int = INT_MAX, dtype=DataType.Int):
        assert min_ <= max_, "Minimum value must be less than or equal to maximum value!"
        super().__init__(dtype=dtype)

        self.min_ = min_
        self.max_ = max_
        self.setValidator(IntValidator(bottom=self.min_, top=self.max_))

    def set_value(self, value: typing.Any):
        if isinstance(value, (float, np.float)):
            value = int(value)
        elif isinstance(value, torch.Tensor):
            value = int(value.detach().cpu().numpy())

        assert isinstance(value, (int, np.int)), "Incompatible type of default value for FloatInput!"

        self.setText(str(value))

    def get_gl_value(self) -> int:
        text = self.text().strip()
        if text == "+" or text == "-" or text == "":
            return np.int(0)

        return int(self.text())

class MultipleIntInput(LineInput):

    def __init__(self, min_: int = INT_MIN, max_: int = INT_MAX, dtype=DataType.Int):
        assert min_ <= max_, "Minimum value must be less than or equal to maximum value!"
        super().__init__(dtype=dtype)

        self.min_ = min_
        self.max_ = max_
        self.setValidator(MultipleIntValidator(bottom=self.min_, top=self.max_))

    def set_value(self, values: typing.Iterable):
        list_values = []
        for value in values:
            if isinstance(value, (float, np.float)):
                value = int(value)
            elif isinstance(value, torch.Tensor):
                value = int(value.detach().cpu().numpy())

            list_values.append(value)
            assert isinstance(value, (int, np.int)), "Incompatible type of default value for FloatInput!"

        self.setText(", ".join([str(i) for i in list_values]))

    def get_gl_value(self) -> typing.List[int]:
        text = self.text().strip()
        if len(text) == 0:
            return []
        nums = text.split(",")

        return [int(num) for num in nums]

class MultipleFloatInput(LineInput):

    def __init__(self, min_: float = FLOAT_MIN, max_: float = FLOAT_MAX, dtype=DataType.Int):
        assert min_ <= max_, "Minimum value must be less than or equal to maximum value!"
        super().__init__(dtype=dtype)

        self.min_ = min_
        self.max_ = max_
        self.setValidator(MultipleFloatValidator(bottom=self.min_, top=self.max_, decimals=5))

    def set_value(self, values: typing.Iterable):
        list_values = []
        for value in values:
            if isinstance(value, (float, np.float)):
                value = float(value)
            elif isinstance(value, torch.Tensor):
                value = float(value.detach().cpu().numpy())

            list_values.append(value)
            assert isinstance(value, (float, np.float32)), "Incompatible type of default value for FloatInput!"

        self.setText(", ".join([str(i) for i in list_values]))

    def get_gl_value(self) -> typing.List[float]:
        text = self.text().strip()
        if len(text) == 0:
            return []
        nums = text.split(",")

        return [float(num) for num in nums]

class StringInput(LineInput, Input):

    def __init__(self):
        super().__init__(dtype=DataType.String)

    def get_gl_value(self) -> typing.Any:
        return self.get_value()

    def set_value(self, value: typing.Any):
        self.setText(value)