import pygame
from random import *
from PIL import Image
import time
pygame.init()
pygame.font.init()

WIDTH, HEIGHT = 800, 600
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Blackjack")

# Background
BG = pygame.transform.scale(pygame.image.load("C:\\Users\\Admin\\Desktop\\Deck\\Poker_table.png"), (WIDTH, HEIGHT))

# Deck images
Ace = Image.open("C:\\Users\\Admin\\Desktop\\Deck\\Ace.png").resize((70, 90))
Two = Image.open("C:\\Users\\Admin\\Desktop\\Deck\\2.png").resize((70, 90))
Three = Image.open("C:\\Users\\Admin\\Desktop\\Deck\\3.png").resize((70, 90))
Four = Image.open("C:\\Users\\Admin\\Desktop\\Deck\\4.png").resize((70, 90))
Five = Image.open("C:\\Users\\Admin\\Desktop\\Deck\\5.png").resize((70, 90))
Six = Image.open("C:\\Users\\Admin\\Desktop\\Deck\\6.png").resize((70, 90))
Seven = Image.open("C:\\Users\\Admin\\Desktop\\Deck\\7.png").resize((70, 90))
Eight = Image.open("C:\\Users\\Admin\\Desktop\\Deck\\8.png").resize((70, 90))
Nine = Image.open("C:\\Users\\Admin\\Desktop\\Deck\\9.png").resize((70, 90))
Ten = Image.open("C:\\Users\\Admin\\Desktop\\Deck\\10.png").resize((70, 90))
Jack = Image.open("C:\\Users\\Admin\\Desktop\\Deck\\Jack.jpg").resize((70, 90))
Queen = Image.open("C:\\Users\\Admin\\Desktop\\Deck\\Queen1.jpg").resize((70, 90))
King = Image.open("C:\\Users\\Admin\\Desktop\\Deck\\King.png").resize((70, 90))
Card = Image.open("C:\\Users\\Admin\\Desktop\\Deck\\Card.jpg").resize((70, 90))
Chips = Image.open("C:\\Users\\Admin\\Desktop\\Deck\\Chips.png").resize((80, 80))
Icon = Image.open("C:\\Users\\Admin\\Desktop\\Deck\\blackjack.png").resize((80, 80))
Icon2 = Image.open("C:\\Users\\Admin\\Desktop\\Deck\\baccarat.png").resize((80, 90))

Ace_img = pygame.image.fromstring(Ace.tobytes(), Ace.size, Ace.mode)
Two_img = pygame.image.fromstring(Two.tobytes(), Two.size, Two.mode)
Three_img = pygame.image.fromstring(Three.tobytes(), Three.size, Three.mode)
Four_img = pygame.image.fromstring(Four.tobytes(), Four.size, Four.mode)
Five_img = pygame.image.fromstring(Five.tobytes(), Five.size, Five.mode)
Six_img = pygame.image.fromstring(Six.tobytes(), Six.size, Six.mode)
Seven_img = pygame.image.fromstring(Seven.tobytes(), Seven.size, Seven.mode)
Eight_img = pygame.image.fromstring(Eight.tobytes(), Eight.size, Eight.mode)
Nine_img = pygame.image.fromstring(Nine.tobytes(), Nine.size, Nine.mode)
Ten_img = pygame.image.fromstring(Ten.tobytes(), Ten.size, Ten.mode)
Jack_img = pygame.image.fromstring(Jack.tobytes(), Jack.size, Jack.mode)
Queen_img = pygame.image.fromstring(Queen.tobytes(), Queen.size, Queen.mode)
King_img = pygame.image.fromstring(King.tobytes(), King.size, King.mode)
Card_img = pygame.image.fromstring(Card.tobytes(), Card.size, Card.mode)
Chips_img = pygame.image.fromstring(Chips.tobytes(), Chips.size, Chips.mode)
Icon_img = pygame.image.fromstring(Icon.tobytes(), Icon.size, Icon.mode)
Icons2_img = pygame.image.fromstring(Icon2.tobytes(), Icon2.size, Icon2.mode)

Image_Deck = {"Ace": Ace_img, 2: Two_img, 3: Three_img, 4: Four_img, 5: Five_img, 6:Six_img, 7:Seven_img, 8:Eight_img, 9:Nine_img, 10:Ten_img, 11:Jack_img, 12:Queen_img, 13:King_img, 'Back':Card_img}
Deck = ["Ace", 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

def shuffle_deck():
    shuffle(Deck)

def draw_card():
    shuffle_deck()
    card = Deck[0]
    return card

def card_value(card):
    if card == 'Ace':
        return 1
    elif card > 10:
        return 10
    else:
        return card

class Draw_cards:
    def __init__(self, window):
        self.window = window

    def player(self, images, y_pos=390):
        tot_width = 0
        for items in images:
            tot_width += 70
        tot_width += (len(images) - 1) * 4

        starting_pt = (WIDTH / 2) - (tot_width / 2)
        for item in images:
            self.window.blit(Image_Deck[item], (starting_pt, y_pos))
            starting_pt += 74

    def dealer(self, images, y_pos=120):
        if len(images) == 1:
            self.window.blit(Image_Deck[images[0]], (328, 120))
            self.window.blit(Image_Deck['Back'], (402, 120))
        else:
            self.player(images, y_pos)

# Initial cards:
def player_cards():
    cards = [draw_card()]
    cards.append(draw_card())
    cardsum = 0
    for items in cards:
        cardsum += card_value(items)
    return [cards, cardsum]

def dealer_cards():
    cards = draw_card()
    cardsum = 0
    cardsum = card_value(cards)
    return [[cards], cardsum]

# Get card from deck and return that card and new sum
def hit_func(current_sum):
    new_card = draw_card()
    new_sum = current_sum + card_value(new_card)
    return [new_card, new_sum]

def is_over_limit(sum):
    if sum > 21:
        return True

class Button:
    def __init__(self, color, x, y, width, height):
        self.color = color
        self.x = x
        self.y = y
        self.width = width
        self.height = height

    def draw(self, window, text, fontsize, outline = None):
        if outline:
            pygame.draw.rect(window, outline, (self.x-2, self.y-2, self.width+4, self.height+4), 0)

        pygame.draw.rect(window, self.color, (self.x, self.y, self.width, self.height), 0)

        font = pygame.font.SysFont('comicsans', fontsize)
        text_label = font.render(text, 1, (250,250,250))
        window.blit(text_label, (self.x + (self.width/2 - text_label.get_width()/2), self.y + (self.height/2 - text_label.get_height()/2)))

    def isOver(self, pos):
        if pos[0] > self.x and pos[0] < self.x+ self.width:
            if pos[1] > self.y and pos[1] < self.y + self.height:
                return True
        return False

class Chips:
    def __init__(self, Total):
        self.Total = Total

    def win_bet(self):
        self.Total += 20

    def loose_bet(self):
        self.Total -= 20

def main():
    run = True #False
    FPS = 60
    clock = pygame.time.Clock()
    end = 0
    Player_Sum = 0
    Dealer_Sum = 0
    player_card_imgs = []
    dealer_card_imgs = []
    sum_font = pygame.font.SysFont("comicsans", 30)
    cards_font = pygame.font.SysFont("comicsans", 40)
    title_font = pygame.font.SysFont("comicsans", 47)
    chips_font = pygame.font.SysFont("comicsans", 23)
    lost_font = pygame.font.SysFont('comicsans', 50)
    hit_button = Button((0,0,255), 620, 250, 110, 40)
    stand_button = Button((0,0,255), 620, 300, 110, 40)
    main_menu_button = Button((0,0,0), 30, 30, 200, 40)
    DrawCards = Draw_cards(WIN)
    lost = False
    won = False
    lost_hand = False
    won_hand = False
    count = 0

    def redraw_window():
        WIN.blit(BG, (0, 0))
        WIN.blit(Chips_img, (80, 240))

        # Draw Text
        player_cards_label = cards_font.render("Player Cards", 1, (255, 255, 255))
        dealer_cards_label = cards_font.render("Dealer Cards", 1, (255, 255, 255))
        player_sum_label = sum_font.render(f"Player sum: {Player_Sum}", 1, (255, 255, 255))
        dealer_sum_label = sum_font.render(f"Dealer sum: {Dealer_Sum}", 1, (255, 255, 255))
        title_font_label = title_font.render("Lets play Blackjack!", 1, (255, 255, 255))
        chips_label = chips_font.render(f"Available chips: {chips.Total}", 1, (255, 255, 255))

        WIN.blit(player_sum_label, ((WIDTH/2) - (player_sum_label.get_width()/2), 355))
        WIN.blit(dealer_sum_label, ((WIDTH/2) - (dealer_sum_label.get_width()/2), 230))
        WIN.blit(dealer_cards_label, ((WIDTH / 2) - (dealer_cards_label.get_width() / 2), 80))
        WIN.blit(player_cards_label, ((WIDTH / 2) - (player_cards_label.get_width() / 2), 495))
        WIN.blit(title_font_label, (((WIDTH / 2) - (title_font_label.get_width() / 2) + 5), ((HEIGHT/2) - (title_font_label.get_height()/2))))
        WIN.blit(chips_label, (55, 325))

        hit_button.draw(WIN, "Hit!", 40, (0,0,0))
        stand_button.draw(WIN, "Stand", 40, (0,0,0))
        main_menu_button.draw(WIN, "Back to Main Menu", 25)

        DrawCards.player(player_card_imgs)
        DrawCards.dealer(dealer_card_imgs)

        if lost:
            lost_label = lost_font.render("You lost the hand!", 1, (255,255,255))
            pygame.draw.rect(WIN, (0,0,0), (200, 250, 400, 100), 0)
            WIN.blit(lost_label, ((400 - (lost_label.get_width()/2)), (300 - (lost_label.get_height()/2))))

        if won:
            won_label = lost_font.render("You won the hand!", 1, (255, 255, 255))
            pygame.draw.rect(WIN, (0, 0, 0), (200, 250, 400, 100), 0)
            WIN.blit(won_label, ((400 - (won_label.get_width() / 2)), (300 - (won_label.get_height() / 2))))

        pygame.display.update()

    [player_card_imgs, Player_Sum] = player_cards()
    [dealer_card_imgs, Dealer_Sum] = dealer_cards()
    #chips = Chips()

    while run:
        clock.tick(FPS)
        redraw_window()

        if lost_hand:
             lost = True
             count += 1
        if won_hand:
            won = True
            count += 1
        if lost or won:
            if count <= FPS*2:
                continue
            else:
                lost = False
                won = False
                return "continue"

        lost_hand = False
        won_hand = False

        if chips.Total == 0:
            return "menu"

        for event in pygame.event.get():
            pos = pygame.mouse.get_pos()

            if event.type == pygame.QUIT:
                return "quit"

            if event.type == pygame.MOUSEBUTTONDOWN:
                if main_menu_button.isOver(pos):
                    return "menu"

                if hit_button.isOver(pos):
                    new_card, new_sum = hit_func(Player_Sum)
                    Player_Sum = new_sum
                    player_card_imgs += [new_card]
                    if is_over_limit(Player_Sum):
                        chips.loose_bet()
                        lost_hand = True

                if stand_button.isOver(pos):
                    while True:
                        new_card, new_sum = hit_func(Dealer_Sum)
                        Dealer_Sum = new_sum
                        dealer_card_imgs += [new_card]
                        time.sleep(0.5)
                        redraw_window()
                        if Dealer_Sum > Player_Sum or Dealer_Sum == 21:
                            if is_over_limit(Dealer_Sum) or (Dealer_Sum == Player_Sum):
                                chips.win_bet()
                                won_hand = True
                            else:
                                chips.loose_bet()
                                lost_hand = True
                            break

            if event.type == pygame.MOUSEMOTION:
                if hit_button.isOver(pos):
                    hit_button.color = (204,204,0)
                else:
                    hit_button.color = (0,0,255)

                if stand_button.isOver(pos):
                    stand_button.color = (204,204,0)
                else:
                    stand_button.color = (0,0,255)

                if main_menu_button.isOver(pos):
                    main_menu_button.color = (128,128,128)
                else:
                    main_menu_button.color = (0,0,0)

def instructions():
    title_font = pygame.font.SysFont('comicsans', 40)
    content_font = pygame.font.SysFont('comicsans', 22)
    main_menu_button = Button((0, 0, 0), 30, 30, 200, 40)
    run = True
    while run:
        WIN.blit(BG, (0,0))
        main_menu_button.draw(WIN, "Back to Main Menu", 25)
        title_label = title_font.render("Instructions:", 1, (255,255,255))
        content_label1 = content_font.render("1. Player has 100 chips at the start of the game.", 1, (255,255,255))
        content_label2 = content_font.render("2. Each bet is of 20 chips.", 1, (255, 255, 255))
        content_label3 = content_font.render("3. Sum of cards should be less than or equal to 21.", 1, (255, 255, 255))
        content_label4 = content_font.render("4. Player can either draw a card using Hit or give turn to dealer using Stand.", 1, (255, 255, 255))
        content_label5 = content_font.render("5. After player hits Stand, dealer draws cards till a hand is won/lost.", 1, (255, 255, 255))
        content_label6 = content_font.render("6. If dealer sum is less than 21 and more than player sum, player looses the hand.", 1, (255, 255, 255))
        content_label7 = content_font.render("7. If dealer sum exceeds 21, player wins the hand.", 1, (255, 255, 255))

        WIN.blit(title_label, ((400-(title_label.get_width()/2)), 120))
        WIN.blit(content_label1, (105, 190))
        WIN.blit(content_label2, (105, 210))
        WIN.blit(content_label3, (105, 230))
        WIN.blit(content_label4, (105, 250))
        WIN.blit(content_label5, (105, 270))
        WIN.blit(content_label6, (105, 290))
        WIN.blit(content_label7, (105, 310))

        pygame.display.update()

        for event in pygame.event.get():
            pos = pygame.mouse.get_pos()

            if event.type == pygame.QUIT:
                return "quit"

            if event.type == pygame.MOUSEBUTTONDOWN:
                if main_menu_button.isOver(pos):
                    return "menu"

            if event.type == pygame.MOUSEMOTION:
                if main_menu_button.isOver(pos):
                    main_menu_button.color = (128, 128, 128)
                else:
                    main_menu_button.color = (0, 0, 0)

def main_menu():
    MainMenu = True
    while MainMenu:
        welcome_font = pygame.font.SysFont('comicsans', 70)
        start_button = Button((0, 0, 0), 280, 300, 250, 70)
        instructions_button = Button((0,0,0), 280, 380, 250, 70)
        run = True
        playing = False

        while run:
            WIN.blit(BG, (0, 0))
            WIN.blit(Icon_img, (420, 100))
            WIN.blit(Icons2_img, (300, 100))
            welcome_label = welcome_font.render("Welcome to Blackjack!", 1, (255,255,0))
            WIN.blit(welcome_label, (145, 210))
            start_button.draw(WIN, "Begin Game", 40)
            instructions_button.draw(WIN, "How to play", 40)

            pygame.display.update()

            for event in pygame.event.get():
                pos = pygame.mouse.get_pos()

                if event.type == pygame.QUIT:
                    MainMenu = False
                    run = False

                if event.type == pygame.MOUSEBUTTONDOWN:
                    if start_button.isOver(pos):
                        playing = True
                        run = False
                    if instructions_button.isOver(pos):
                        a = instructions()
                        if a == "quit":
                            MainMenu = False
                            run = False
                        elif a == "menu":
                            run = False

                if event.type == pygame.MOUSEMOTION:
                    if start_button.isOver(pos):
                        start_button.color = (128, 128, 128)
                    else:
                        start_button.color = (0, 0, 0)

                    if instructions_button.isOver(pos):
                        instructions_button.color = (128, 128, 128)
                    else:
                        instructions_button.color = (0, 0, 0)

        global chips
        chips = Chips(100)
        while playing:
            a = main()
            if a == "quit":
                playing = False
                MainMenu = False
            elif a == "menu":
                playing = False
            else:
                continue

    pygame.quit()

if __name__ == '__main__':
    main_menu()


# Definition for a binary tree node.
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

from collections import deque
class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:

        if root is None: return None

        inverted_root = TreeNode(val = root.val)
        inverted_queue = deque([inverted_root])

        queue = deque([root])

        while queue:
            for _ in range(len(queue)):
                curr = queue.popleft()
                inverted_curr = inverted_queue.popleft()

                # right append left, left append right
                if curr.right:
                    queue.append(curr.right)
                    inverted_curr.left = TreeNode(curr.right.val)
                    inverted_queue.append(inverted_curr.left)

                if curr.left:
                    queue.append(curr.left)
                    inverted_curr.right = TreeNode(curr.left.val)
                    inverted_queue.append(inverted_curr.right)

        return inverted_root


# -*- coding: utf-8 -*-
"""
Created on Thu Oct  8 16:17:46 2020

@author: adds0
"""

import torch
import re
import time
import os

from torchvision import utils
from utils.utilities import *

from training.good_G_D import *
from training.wasserstein_GP_256 import *
#from utils.inceptionScore import *
from pathlib import Path
import matplotlib.pyplot as plt
plt.switch_backend('agg')

from utils.data_load import make_data_loader
from utils.utilities import Plane,Diagnoses

def evaluate(train_loader, loading_dir, results_dir,no_of_iterations=3000,starting_case_id=0):
    nz = 128
    save_per_times = 1000
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    load_model('discriminator.pkl', 'generator.pkl', loading_dir)
    d_load = get_infinite_batches(train_loader)

    for i in range(no_of_iterations):
        real_scan = d_load.__next__()
        scan = real_scan.squeeze(0)

        #number of slices is set to 57 if scan has more than 57 slices to prevent a CUDA Out of Memory Exception
        batch_size = scan.shape[0] if scan.shape[0] <= 57 else 57

        testing_result_images_dir = os.path.join(results_dir, 'testing_result_images')
        if not os.path.exists(testing_result_images_dir):
            os.makedirs(testing_result_images_dir)

        z = create_noise(batch_size, nz, device)
        torch.cuda.empty_cache()
        samples = generator(z).cpu().detach()
        samples_numpy = samples.numpy()
        print(samples_numpy.shape)
        case_id = i+starting_case_id
        save_numpy(os.path.join(testing_result_images_dir,'{}.npy'.format(str(case_id).zfill(3))),samples_numpy)

        grid = utils.make_grid(samples)

        if i % save_per_times ==0:
            utils.save_image(grid, os.path.join(testing_result_images_dir, 'img_generatori_iter_{}.png'.format(str(i).zfill(3))))

data_path = Path('D:/OneDrive - University of Glasgow/Documnets/courses/Msc/Project/MRI/MRNet/resources')
train_path = data_path/'train'
valid_path = data_path/'valid'

starting_case_id=1130
# =============================================================================
#                           #ACL
# =============================================================================
loading_dir = 'D:/OneDrive - City, University of London/MSc Data Science City/Individual Project/GANKneeMRI2/src/model_weights/wgan_[1,1,0]'
plane = Plane.Axial.name
daignoses = Diagnoses.ACL
dataset_type = 'train'
axial_data_loader = make_data_loader(data_path, dataset_type, plane= plane, diagnoses_filter =daignoses )
results_dir = 'D:/eval/gan/{}/{}/{}/results_{}'.format( dataset_type,plane,str(daignoses),time.strftime("%Y%m%d-%H%M%S"))
test = evaluate(axial_data_loader, loading_dir, results_dir,starting_case_id=starting_case_id)
 #'augmented_acl_labels',daignoses

# =============================================================================
#                       #meniscus
# =============================================================================
starting_case_id = starting_case_id + 3000

loading_dir = 'D:/OneDrive - City, University of London/MSc Data Science City/Individual Project/GANKneeMRI2/src/model_weights/wgan_[1,0,1]'
plane = Plane.Axial.name
daignoses = Diagnoses.Meniscus
dataset_type = 'train'
axial_data_loader = make_data_loader(data_path, dataset_type, plane= plane, diagnoses_filter =daignoses )
results_dir = 'D:/eval/gan/{}/{}/{}/results_{}'.format( dataset_type,plane,str(daignoses),time.strftime("%Y%m%d-%H%M%S"))
test = evaluate(axial_data_loader, loading_dir, results_dir,starting_case_id=starting_case_id )
#'augmented_meniscus_labels',daignoses

# =============================================================================
#                           #None
# =============================================================================
starting_case_id = starting_case_id + 6000
loading_dir = 'D:/OneDrive - City, University of London/MSc Data Science City/Individual Project/GANKneeMRI2/src/model_weights/wgan_[0,0,0]'
plane = Plane.Axial.name
daignoses = Diagnoses.Normal
dataset_type = 'train'
axial_data_loader = make_data_loader(data_path, dataset_type, plane= plane, diagnoses_filter =daignoses )
results_dir = 'D:/eval/gan/{}/{}/{}/results_{}'.format( dataset_type,plane,str(daignoses),time.strftime("%Y%m%d-%H%M%S"))
test = evaluate(axial_data_loader, loading_dir, results_dir,starting_case_id=starting_case_id )

######CREATE LABELS FOR AUGMENTED DATASET
from glob import glob
def create_labels(dataset_dir,plane,labels_filename):
    with open('{}/{}.csv'.format(dataset_dir,labels_filename), mode='w', newline = '') as csv_file:
        fieldnames = ['case','abnormal','acl','meniscus']
        writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
        writer.writeheader()
        for file in sorted(glob('{}/{}/**/**.npy'.format(dataset_dir,plane),recursive=True)):
            labels = re.sub(r"\[|\]","",file.split('\\')[1]).split(',')
            case_id = os.path.splitext(os.path.basename(file))[0]
            writer.writerow({'case':'{}'.format(str(case_id).zfill(3)),'abnormal':labels[0],'acl':labels[1],'meniscus':labels[2]})

dataset_dir = 'D:/eval/gan/train'
filename='augmented_labels'
plane = 'axial'
create_labels(dataset_dir,plane,filename)


"""Module for modeling the probabilites as opposed to simulating"""

from itertools import combinations
import numpy as np
from scipy import special as spec

def prob_of_crossing_single_set(lengths: np.array, dim: int, C: int, S: int):
    """Calculate the probability of crossing more than some number of
    hyperplanes with a hyperdimensional needle. Assume there is only a
    single set of parallel hyperplanes.

    Args:
        lengths: an array of lengths of the needle
        dim: the dimension of the R^D space that the needle is embedded in
        C: the number of hyperplanes the needle must cross
        S: the spacing between the parallel hyperplanes

    Returns:
        A numpy array the same length as `lengths` with the probability of
        meeting the crossing criteria."""
    if dim <= 1:
        raise ValueError("dim must be greater than 1")
    i_s = lengths < (S * (C - 1))
    i_m = (lengths >= (S * (C - 1))) * (lengths < (S * C))
    i_l = lengths >= (S * C)

    r_s = lengths[i_s]
    r_m = lengths[i_m]
    r_l = lengths[i_l]

    prob_s = np.zeros_like(r_s)
    prob_m = prob_of_crossing_single_set_small_r(r_m, dim, C, S)
    prob_l = prob_of_crossing_single_set_small_r(
        r_l, dim, C, S
    ) - prob_of_crossing_single_set_small_r(r_l, dim, C + 1, S)

    probability = np.concatenate((prob_s, prob_m, prob_l))
    return probability

def prob_of_crossing_single_set_small_r(lengths, dim, C, S):
    """Calculate the probability of crossing more than some number of
    hyperplanes with a hyperdimensional needle. Assume there is only a
    single set of parallel hyperplanes and that the length is less than
    C*S. The lengths need not be actually less than C*S.

    Args:
        lengths: an array of lengths of the needle
        dim: the dimension of the R^D space that the needle is embedded in
        C: the number of hyperplanes the needle must cross
        S: the spacing between the parallel hyperplanes

    Returns:
        A numpy array the same length as `lengths` with the probability of
        meeting the crossing criteria."""
    r = lengths
    gamma = S * (C - 1) / r
    loop_sum = np.sum(
        [
            spec.beta((dim - 2 * i) / 2, 0.5) / (1 - gamma**2) ** i
            for i in range(1, int((dim - 2) / 2) + 1)
        ],
        axis=0,
    )
    if dim % 2 == 0:
        parity_shape = 2 / np.pi * np.arccos(gamma)
    else:
        parity_shape = 1 - gamma
    probability = (
        r
        / S
        * (
            (1 - gamma**2) ** ((dim - 1) / 2)
            / np.pi
            * (spec.beta(dim / 2, 0.5) + gamma**2 * loop_sum)
            - gamma * parity_shape
        )
    )
    return probability

def single_set_peak(lengths: np.array, dim: int, C: int, S: int):
    """Return the length of the needle with the best chance of crossing C hyperplanes
    and the associated probability."""
    pass

def sum_of_combo_reciprocals(S: np.array, num_choose: int):
    """Given an array of array of values, return the sum of the reciprocals of
    the combo products.

    eg. S = [1, 2, 3], num_choose = 2: return 1/(1*2) + 1/(1*3) + 1/(2*3)"""
    reciprocal_sum = 0
    for combos in combinations(S, num_choose):
        reciprocal_sum += 1 / np.prod(combos)
    return reciprocal_sum

def prob_of_crossing_small_r(lengths: np.array, dim: int, c: int, N: int, S: np.array):
    """Return the probability of crossing exactly c hyperplanes.

    Args:
        - lengths: lengths of the line segment to calculate the prob of.
            For now must be <= all S
        - dim: the dimension of the space the needle is embedded in
        - c: the number of hyperplanes
        - N: the number of sets of parallel D-1 dimensional hyperplanes
        - S: the spacing for each of the N hyperplanes. Must have length N.

    Returns:
        The probability that the line segment has at least 1 crossing in all
        sets of hyperplanes."""
    probability = 0
    for idx in range(N - c + 1):
        probability += (
            (-1) ** idx
            * lengths ** (c + idx)
            * spec.gamma(dim / 2)
            / (c + idx + 1)
            / np.pi ** ((c + idx) / 2)
            / spec.beta(c + 1, idx + 1)
            / spec.gamma((dim + c + idx) / 2)
            * sum_of_combo_reciprocals(S, c + idx)
        )
    return probability

def prob_of_crossing_small_r_ge(
    lengths: np.array, dim: int, c: int, N: int, S: np.array
):
    """Return the probability of crossing greater than or equal to c hyperplanes.

    Args:
        - lengths: lengths of the line segment to calculate the prob of.
            For now must be <= all S
        - dim: the dimension of the space the needle is embedded in
        - c: the number of hyperplanes
        - N: the number of sets of parallel D-1 dimensional hyperplanes
        - S: the spacing for each of the N hyperplanes. Must have length N.

    Returns:
        The probability that the line segment has at least 1 crossing in all
        sets of hyperplanes."""
    probability = 0
    combos = list(combinations(S[:N], c))
    for idx in range(1, int(spec.comb(N, c)) + 1):
        for combocombo in combinations(combos, idx):
            combo_list = list(set(sum(combocombo, ())))
            c_list_len = len(combo_list)
            probability += (
                (-1) ** (idx + 1)
                * lengths**c_list_len
                / np.prod(combo_list)
                / np.pi ** (c_list_len / 2)
                * spec.gamma(dim / 2)
                / spec.gamma((dim + c_list_len) / 2)
            )
    return probability

def prob_upper_bound_of_crossing_big_r_ge(
    lengths: np.array, dim: int, c: int, N: int, S: np.array
):
    """Returns an upper bound on the probability of crossing ge c hyperplanes.

    Args:
        - lengths: lengths of the line segment to calculate the prob of.
            For now must be <= all S
        - dim: the dimension of the space the needle is embedded in
        - c: the number of hyperplanes
        - N: the number of sets of parallel D-1 dimensional hyperplanes
        - S: the spacing for each of the N hyperplanes. Must have length N.

    Returns:
        The upper bound probability that the line segment has at least 1 crossing in all
        sets of hyperplanes."""
    probability = 0
    raise NotImplementedError

def prob_of_crossing_vs_dim(
    length: int, dims: np.array, C: int = 0, N: int = 1, S=None
):
    """Calculate the probability of crossing more than some number of
    hyperplanes with a hyperdimensional needle. Lots to do to clean this function up

    Args:
        lengths: the length of the needle
        dims: the dimensions of the R^D space that the needle is embedded in
        C: the number of hyperplanes the needle must cross
        N: the number of orthogonal sets of parallel hyperplanes
        S: the spacing between the parallel hyperplanes of any given set (can
            be different for each set)

    Returns:
        A numpy array the same length as `lengths` with the probability of
        meeting the crossing criteria."""
    raise (NotImplementedError)


try:
	import cPickle as pickle
except:
	import pickle

import os

def load_pickle(dir = "data.pkl"):
      if os.path.exists(dir):
            pkl_file = open(dir, 'rb')
            data = pickle.load(pkl_file)
            pkl_file.close()
      return data

def save_pickle(data , name = "data.pkl"):
      output = open( name, 'wb')
      pickle.dump(data, output)
      output.close()


def get_demog(data_points):

    demog = {}

    for k,v in data_points.items():
        val = input(f"Enter the subject's {k}> ")

        # If v is a type, then compare input value type
        if not isinstance(v,tuple):
            while True:
                try:
                    val = v(val)
                    break
                except:
                    val = input(f"{val} is not an {v}, enter age as an integer> ")

        demog[v]=val

    return demog

demog_values = get_demog({"id":str,"age":int,"sex":('M','F'),"weight":float})
print(demog_values)


from utils import AttributeDict
import os
import numpy as np
from scipy.io import loadmat, savemat
import matplotlib.image as mpimg
from PIL import Image
from copy import deepcopy

import matplotlib
import matplotlib.pyplot as plt
import matplotlib.cm as cm

class SeqSLAM():
    params = None

    def __init__(self, params):
        self.params = params

    def run(self):
        # begin with preprocessing of the images
        if self.params.DO_PREPROCESSING:
            results = self.doPreprocessing()

        # image difference matrix
        if self.params.DO_DIFF_MATRIX:
            results = self.doDifferenceMatrix(results)

        # contrast enhancement
        if self.params.DO_CONTRAST_ENHANCEMENT:
            results = self.doContrastEnhancement(results)
        else:
            if self.params.DO_DIFF_MATRIX:
                results.DD = results.D

        # find the matches
        if self.params.DO_FIND_MATCHES:
            results = self.doFindMatches(results)
        return results

    def doPreprocessing(self):
        results = AttributeDict()
        results.dataset = []
        for i in range(len(self.params.dataset)):
            # shall we just load it?
            filename = '%s/preprocessing-%s%s.mat' % (self.params.dataset[i].savePath, self.params.dataset[i].saveFile, self.params.saveSuffix)
            if self.params.dataset[i].preprocessing.load and os.path.isfile(filename):
                r = loadmat(filename)
                print('Loading file %s ...' % filename)
                results.dataset[i].preprocessing = r.results_preprocessing
            else:
                # or shall we actually calculate it?
                p = deepcopy(self.params)
                p.dataset = self.params.dataset[i]
                d = AttributeDict()
                d.preprocessing = np.copy(SeqSLAM.preprocessing(p))
                results.dataset.append(d)

                if self.params.dataset[i].preprocessing.save:
                    results_preprocessing = results.dataset[i].preprocessing
                    savemat(filename, {'results_preprocessing': results_preprocessing})

        return results

    @staticmethod
    def rgb2gray(rgb):
        r, g, b = rgb[:,:,0], rgb[:,:,1], rgb[:,:,2]
        gray = 0.2989 * r + 0.5870 * g + 0.1140 * b
        return gray

    @staticmethod
    def preprocessing(params):
        print('Preprocessing dataset %s, indices %d - %d ...' % (params.dataset.name, params.dataset.imageIndices[0], params.dataset.imageIndices[-1]))
        # allocate memory for all the processed images
        n = len(params.dataset.imageIndices)
        m = params.downsample.size[0]*params.downsample.size[1]

        if len(params.dataset.crop) > 0:
            c = params.dataset.crop
            m = (c[2]-c[0]+1) * (c[3]-c[1]+1)

        images = np.zeros((m,n), 'uint8')
        j=0

        # for every image ....
        for i in (params.dataset.imageIndices):
            filename = '%s/%s%05d%s%s' % (params.dataset.imagePath, \
                params.dataset.prefix, \
                i, \
                params.dataset.suffix, \
                params.dataset.extension)

            img = Image.open(filename)

            # convert to grayscale
            if params.DO_GRAYLEVEL:
                #img = img.convert('L') #LA to include alpha
                img = SeqSLAM.rgb2gray(np.asarray(img))

            # resize the image
            if params.DO_RESIZE:
                img = img.resize(params.downsample.size, params.downsample.method)

            img = np.copy(np.asarray(img))
            #img.flags.writeable = True

            # crop the image if necessary
            if len(params.dataset.crop) > 0:
                img = img[params.dataset.crop[1]:params.dataset.crop[3], params.dataset.crop[0]:params.dataset.crop[2]]

            # do patch normalization
            if params.DO_PATCHNORMALIZATION:
                img = SeqSLAM.patchNormalize(img, params)

            # shall we save the result?
            if params.DO_SAVE_PREPROCESSED_IMG:
                pass

            images[:,j] = img.flatten(0)
            j += 1

        return images

    @staticmethod
    def patchNormalize(img, params):
        s = params.normalization.sideLength

        n = range(0, img.shape[0]+2, s)
        m = range(0, img.shape[1]+2, s)

        for i in range(len(n)-1):
            for j in range(len(m)-1):
                p = img[n[i]:n[i+1], m[j]:m[j+1]]

                pp=np.copy(p.flatten(1))

                if params.normalization.mode != 0:
                    pp=pp.astype(float)
                    img[n[i]:n[i+1], m[j]:m[j+1]] = 127+np.reshape(np.round((pp-np.mean(pp))/np.std(pp, ddof=1)), (s, s))
                else:
                    f = 255.0/np.max((1, np.max(pp) - np.min(pp)))
                    img[n[i]:n[i+1], m[j]:m[j+1]] = np.round(f * (p-np.min(pp)))

                #print str((n[i], n[i+1], m[j], m[j+1]))
        return img

    def getDifferenceMatrix(self, data0preproc, data1preproc):
        # TODO parallelize
        n = data0preproc.shape[1]
        m = data1preproc.shape[1]
        D = np.zeros((n, m))

        #parfor?
        for i in range(n):
            d = data1preproc - np.tile(data0preproc[:,i],(m, 1)).T
            D[i,:] = np.sum(np.abs(d), 0)/n

        return D

    def doDifferenceMatrix(self, results):
        filename = '%s/difference-%s-%s%s.mat' % (self.params.savePath, self.params.dataset[0].saveFile, self.params.dataset[1].saveFile, self.params.saveSuffix)

        if self.params.differenceMatrix.load and os.path.isfile(filename):
            print('Loading image difference matrix from file %s ...' % filename)

            d = loadmat(filename)
            results.D = d.D
        else:
            if len(results.dataset)<2:
                print('Error: Cannot calculate difference matrix with less than 2 datasets.')
                return None

            print('Calculating image difference matrix ...')

            results.D=self.getDifferenceMatrix(results.dataset[0].preprocessing, results.dataset[1].preprocessing)

            # save it
            if self.params.differenceMatrix.save:
                savemat(filename, {'D':results.D})

        return results

    def enhanceContrast(self, D):
        # TODO parallelize
        DD = np.zeros(D.shape)

        #parfor?
        for i in range(D.shape[0]):
            a=np.max((0, i-self.params.contrastEnhancement.R/2))
            b=np.min((D.shape[0], i+self.params.contrastEnhancement.R/2+1))
            v = D[a:b, :]
            DD[i,:] = (D[i,:] - np.mean(v, 0)) / np.std(v, 0, ddof=1)

        return DD-np.min(np.min(DD))

    def doContrastEnhancement(self, results):

        filename = '%s/differenceEnhanced-%s-%s%s.mat' % (self.params.savePath, self.params.dataset[0].saveFile, self.params.dataset[1].saveFile, self.params.saveSuffix)

        if self.params.contrastEnhanced.load and os.path.isfile(filename):
            print('Loading contrast-enhanced image distance matrix from file %s ...' % filename)
            dd = loadmat(filename)
            results.DD = dd.DD
        else:
            print('Performing local contrast enhancement on difference matrix ...')

            # let the minimum distance be 0
            results.DD = self.enhanceContrast(results.D)

            # save it?
            if self.params.contrastEnhanced.save:
                DD = results.DD
                savemat(filename, {'DD':DD})

        return results

    def doFindMatches(self, results):

        filename = '%s/matches-%s-%s%s.mat' % (self.params.savePath, self.params.dataset[0].saveFile, self.params.dataset[1].saveFile, self.params.saveSuffix)

        if self.params.matching.load and os.path.isfile(filename):
            print('Loading matchings from file %s ...' % filename)
            m = loadmat(filename)
            results.matches = m.matches
        else:

            print('Searching for matching images ...')

            # make sure ds is dividable by two
            self.params.matching.ds = self.params.matching.ds + np.mod(self.params.matching.ds,2)

            matches = self.getMatches(results.DD)

            # save it
            if self.params.matching.save:
                savemat(filename, {'matches':matches})

            results.matches = matches

        return results

    def getMatches(self, DD):
        # TODO parallelize
        matches = np.nan*np.ones((DD.shape[1],2))
        # parfor?
        for N in range(self.params.matching.ds/2, DD.shape[1]-self.params.matching.ds/2):
            # find a single match

            # We shall search for matches using velocities between
            # params.matching.vmin and params.matching.vmax.
            # However, not every vskip may be neccessary to check. So we first find
            # out, which v leads to different trajectories:

            move_min = self.params.matching.vmin * self.params.matching.ds
            move_max = self.params.matching.vmax * self.params.matching.ds

            move = np.arange(int(move_min), int(move_max)+1)
            v = move.astype(float) / self.params.matching.ds

            idx_add = np.tile(np.arange(0, self.params.matching.ds+1), (len(v),1))
            idx_add = np.floor(idx_add * np.tile(v, (idx_add.shape[1], 1)).T)

            # this is where our trajectory starts
            n_start = N + 1 - self.params.matching.ds/2
            x= np.tile(np.arange(n_start , n_start+self.params.matching.ds+1), (len(v), 1))

            #TODO idx_add and x now equivalent to MATLAB, dh 1 indexing
            score = np.zeros(DD.shape[0])

            # add a line of inf costs so that we penalize running out of data
            DD=np.vstack((DD, np.infty*np.ones((1,DD.shape[1]))))

            y_max = DD.shape[0]
            xx = (x-1) * y_max

            flatDD = DD.flatten(1)
            for s in range(1, DD.shape[0]):
                y = np.copy(idx_add+s)
                y[y>y_max]=y_max
                idx = (xx + y).astype(int)
                ds = np.sum(flatDD[idx-1],1)
                score[s-1] = np.min(ds)

            # find min score and 2nd smallest score outside of a window
            # around the minimum

            min_idx = np.argmin(score)
            min_value=score[min_idx]
            window = np.arange(np.max((0, min_idx-self.params.matching.Rwindow/2)), np.min((len(score), min_idx+self.params.matching.Rwindow/2)))
            not_window = list(set(range(len(score))).symmetric_difference(set(window))) #xor
            min_value_2nd = np.min(score[not_window])

            match = [min_idx + self.params.matching.ds/2, min_value / min_value_2nd]
            matches[N,:] = match

        return matches


# the configuration of trainng
gpu_device = 0
epochs = 100
batch_size = 128

# the mode of training methods, inlcuding DARL, MAML, DARL_CNN_CLASSIC, DARL_CNN_TRANSITION, DARL_CNN_FEW_SHOT
mode = 'DARL'

# the configuration of Generator
n_hidden = 256
n_embed = 300

# source domains
sources = ['beauty', 'pet', 'toys', 'baby', 'food']

# target domain
target = 'phone'

# the configuration of few shot learning
# size of target samples
shot = 5
# query dateset size of
Q = 32
# suport dateset size
S = shot

# the configuration of MAML
# the meta lr
meta_lr = 0.003
# the inner lr
inner_lr = 0.003
# the test lr
test_lr = 0.003

# the configuration of DARL
# the pre-traing lr of generator
pre_train_lr = 0.0001
# the traing lr of generator
lr = 0.001
# pre-traing lr of discriminator
pre_cls_lr = 1e-4
# epochs of discriminator pre-training
pre_cls_epochs = 10000
# number of Monte Carlo search
sample_num = 16
# the ratio of RL training and MLE training
R = 0.5

# the configuration of DARL with CNN discriminator
# d-steps of discriminator training
d = 1
# epochs in each discriminator training
k = 1
# the meta lr of discriminator trained by classic or transition
cls_lr = 1e-3
# the meta lr of discriminator trained by few-shot learning
cls_meta_lr= 0.001
# the inner lr of discriminator trained by few-shot learning
cls_inner_lr = 0.01


import re
from bs4 import BeautifulSoup
import notes_html
import pandas as pd

html = notes_html.return_html()
HTML_PARSER_CONSTANT = 'html.parser'

def text_formatter(text):
    # Check if length is greater than 0
    if len(text) > 0:
        for index, char in enumerate(text):
            if char.isalpha() or char in ['""','?',"@","#","$","''"]:
                return text[index:]
        return ""
    else:
        return ""

# Remove the empty spaces from the html
html = re.sub(r'\s+',' ',html)
# replace the empty

 tag in the html
html = re.sub(r'
<\/p>',' ',html)
#remove the button part as well
html = re.sub(r'<button class.+?<\/button>',' ',html)
#2 more clean up patterns
html = re.sub(r'

',' ',html)
# html = re.sub(r'
.+?<span.+?style.+?font.+?large.+?<\/span>.+?<\/p>',' ',html)
pattern = r'
.+?<ol.+?<\/ol>.+?<div.+?<\/p>\s*<\/div>'
# with open('test_html_1.txt', 'w') as f:
#     f.write(html)

# Create a new df and assign column names as well:
df = pd.DataFrame(columns=['Question','option1','option2','option3','option4','option5','option6','answer','last_checked_option'])

html_list = re.finditer(pattern, html)
for index, pattern_text in enumerate(html_list):
    dictionary = {'Question':"",
'option1':"",
'option2':"",
'option3':"",
'option4':"",
'option5':"",
'option6':"",
'answer':"",
'last_checked_option':""}

    # print(pattern_text.group(0))
    # find all the
 tags before the
 tag in the each pattern
    p_tag_arrays = re.finditer(r'
.+?<ol', pattern_text.group(0))
    print(f'Question {index}:')
    final_question_string = ""
    for p_tag in p_tag_arrays:
        soup = BeautifulSoup(p_tag.group(0),features=HTML_PARSER_CONSTANT)
        for i,para in enumerate(soup.find_all("p")):
            if i == 0:
                final_question_string = text_formatter(para.text)
            else:
                final_question_string += "\n{}".format(para.text)
    dictionary['Question'] = final_question_string
    print(final_question_string)

    li_tag_array =  re.findall(r'<ol.+?<\/ol>', pattern_text.group(0))
    print("Answer option:")
    soup = BeautifulSoup(li_tag_array[0],features=HTML_PARSER_CONSTANT)
    for index,li in enumerate(soup.find_all("li")):
        dictionary["option{}".format(index + 1)] = li.text
        print(text_formatter(li.text))
    # Lets find the actual answer now
    soup =  BeautifulSoup(pattern_text.group(0), features=HTML_PARSER_CONSTANT)
    answer_string = soup.find('div',class_= "mcq").find_all('p')[0].text
    # Remove the Answer and number part
    remove_answer_text = re.sub(r'A.+?.\)', '', answer_string)
    dictionary["answer"] = remove_answer_text
    #pushing the data in the frame
    df_dictionary = pd.DataFrame([dictionary])
    df = pd.concat([df, df_dictionary], ignore_index=True)
    # print(f"Answer:{remove_answer_text}") #.replace(' ','')
df = df.applymap(lambda x: x.encode('unicode_escape').decode('utf-8') if isinstance(x, str) else x)
df.to_excel('test.xlsx',index=False)


# train
from func.load_dataset import airway_dataset
# from func.unet_3d_basic import UNet3D_basic
from func.model_arch import SegAirwayModel
from func.loss_func import dice_loss_weights, dice_accuracy, dice_loss_power_weights, dice_loss, dice_loss_power
from func.ulti import load_obj

import numpy as np
import torch
from torch.utils.data import DataLoader, RandomSampler
import os
import time
import gc

# settings
# ----------
save_path = 'checkpoint/checkpoint_sample.pkl'
need_resume = True
load_path = "" #'checkpoint/checkpoint.pkl'
path_dataset_info_more_focus_on_airways_of_low_generation = \
    "dataset_info/train_dataset_info_EXACT09_LIDC_IDRI_crops_128_extended_more_low_generation_10"
path_dataset_info_more_focus_on_airways_of_high_generation = \
    "dataset_info/train_dataset_info_EXACT09_LIDC_IDRI_crops_128_extended_more_high_generation_1"
learning_rate = 1e-5
max_epoch = 50
freq_switch_of_train_mode_high_low_generation = 1
num_samples_of_each_epoch = 2000
batch_size = 4
train_file_format = '.npy'
crop_size = (32, 128, 128)
windowMin_CT_img_HU = -1000 # min of CT image HU value
windowMax_CT_img_HU = 600 # max of CT image HU value
model_save_freq = 1
num_workers = 4
# ----------

# init model
model=SegAirwayModel(in_channels=1, out_channels=2)
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
model.to(device)

if need_resume and os.path.exists(load_path):
    print("resume model from "+str(load_path))
    checkpoint = torch.load(load_path)
    model.load_state_dict(checkpoint['model_state_dict'], strict=False)

# optimizer
optimizer=torch.optim.Adam(model.parameters(), lr=learning_rate)

# dataset
dataset_info_more_focus_on_airways_of_low_generation = load_obj(path_dataset_info_more_focus_on_airways_of_low_generation)
train_dataset_more_focus_on_airways_of_low_generation = airway_dataset(dataset_info_more_focus_on_airways_of_low_generation)
train_dataset_more_focus_on_airways_of_low_generation.set_para(file_format=train_file_format, crop_size=crop_size,\
    windowMin=windowMin_CT_img_HU, windowMax=windowMax_CT_img_HU, need_tensor_output=True, need_transform=True)

dataset_info_more_focus_on_airways_of_high_generation = load_obj(path_dataset_info_more_focus_on_airways_of_high_generation)
train_dataset_more_focus_on_airways_of_high_generation = airway_dataset(dataset_info_more_focus_on_airways_of_high_generation)
train_dataset_more_focus_on_airways_of_high_generation.set_para(file_format=train_file_format, crop_size=crop_size,\
    windowMin=windowMin_CT_img_HU, windowMax=windowMax_CT_img_HU, need_tensor_output=True, need_transform=True)

print('total epoch: '+str(max_epoch))

start_time = time.time()

for ith_epoch in range(0, max_epoch):

    if np.floor(ith_epoch/freq_switch_of_train_mode_high_low_generation)%2==0 or \
        ith_epoch>=(max_epoch-freq_switch_of_train_mode_high_low_generation):
        print("train_more_focus_on_airways_of_low_generation")
        sampler_of_airways_of_low_generation = RandomSampler(train_dataset_more_focus_on_airways_of_low_generation,\
            num_samples = min(num_samples_of_each_epoch, len(dataset_info_more_focus_on_airways_of_low_generation)), replacement = True)
        dataset_loader = DataLoader(train_dataset_more_focus_on_airways_of_low_generation,\
            batch_size=batch_size, sampler = sampler_of_airways_of_low_generation, num_workers=num_workers,\
                pin_memory=True, persistent_workers=(num_workers > 1))

    else:
        print("train_more_focus_on_airways_of_high_generation")
        sampler_of_airways_of_high_generation = RandomSampler(train_dataset_more_focus_on_airways_of_high_generation,\
            num_samples = min(num_samples_of_each_epoch, len(dataset_info_more_focus_on_airways_of_high_generation)), replacement = True)
        dataset_loader = DataLoader(train_dataset_more_focus_on_airways_of_high_generation,\
            batch_size=batch_size, sampler = sampler_of_airways_of_high_generation, num_workers=num_workers,\
                pin_memory=True, persistent_workers=(num_workers > 1))

    len_dataset_loader = len(dataset_loader)

    for ith_batch, batch in enumerate(dataset_loader):
        img_input=batch['image'].float().to(device)

        groundtruth_foreground=batch['label'].float().to(device)
        groundtruth_background=1-groundtruth_foreground

        fore_pix_num = torch.sum(groundtruth_foreground)
        back_pix_num = torch.sum(groundtruth_background)
        fore_pix_per = fore_pix_num/(fore_pix_num+back_pix_num)
        back_pix_per = back_pix_num/(fore_pix_num+back_pix_num)
        weights = (torch.exp(back_pix_per)/(torch.exp(fore_pix_per)+torch.exp(back_pix_per))*torch.eq(groundtruth_foreground,1).float()+\
            torch.exp(fore_pix_per)/(torch.exp(fore_pix_per)+torch.exp(back_pix_per))*torch.eq(groundtruth_foreground,0).float()).to(device)

        img_output=model(img_input)

        loss=dice_loss_weights(img_output[:,0,:,:,:], groundtruth_background, weights)+\
            dice_loss_power_weights(img_output[:,1,:,:,:], groundtruth_foreground, weights, alpha=2)
        accuracy=dice_accuracy(img_output[:,1,:,:,:], groundtruth_foreground)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        time_consumption = time.time() - start_time

        print(
            "epoch [{0}/{1}]\t"
            "batch [{2}/{3}]\t"
            "time(sec) {time:.2f}\t"
            "loss {loss:.4f}\t"
            "acc {acc:.2f}%\t"
            "fore pix {fore_pix_percentage:.2f}%\t"
            "back pix {back_pix_percentage:.2f}%\t".format(
                ith_epoch + 1,
                max_epoch,
                ith_batch,
                len_dataset_loader,
                time = time_consumption,
                loss = loss.item(),
                acc = accuracy.item()*100,
                fore_pix_percentage = fore_pix_per*100,
                back_pix_percentage = back_pix_per*100))

    del dataset_loader
    gc.collect()

    if (ith_epoch+1)%model_save_freq==0:
        print('epoch: '+str(ith_epoch+1)+' save model')
        model.to(torch.device('cpu'))
        torch.save({'model_state_dict': model.state_dict()}, save_path)
        model.to(device)


import logging
import os

loggers = {}

def get_logger(_dir, name, console_level):
    global loggers

    if loggers.get(name):
        return loggers.get(name)
    else:
        _dir = os.path.join('log', _dir)
        try:
            os.makedirs(_dir)
        except FileExistsError:  # safe to ignore exist
            pass
        logger = logging.getLogger(name)
        logger.setLevel(logging.DEBUG)

        # create console handler and set level to INFO
        ch = logging.StreamHandler()
        ch.setLevel(console_level)
        # create formatter
        formatter = logging.Formatter('[%(asctime)s - %(name)s - %(levelname)s]: %(message)s')
        # add formatter to ch
        ch.setFormatter(formatter)
        # add ch to logger
        logger.addHandler(ch)
        # file version of console output
        chf = logging.FileHandler(os.path.join(_dir, 'console.log'))
        chf.setLevel(console_level)
        chf.setFormatter(formatter)
        logger.addHandler(chf)
        loggers.update(name=logger)

        # create error file handler and set level to WARNING
        eh = logging.FileHandler(os.path.join(_dir, 'error.log'))
        eh.setLevel(logging.WARNING)
        eh.setFormatter(formatter)
        logger.addHandler(eh)

        # create debug file handler and set level to DEBUG
        dh = logging.FileHandler(os.path.join(_dir, 'debug.log'))
        dh.setLevel(logging.DEBUG)
        dh.setFormatter(formatter)
        logger.addHandler(dh)

    return logger


# -*- coding: utf-8 -*-
"""
Created on Thu May 23 10:23:37 2019

@author: Plamen
"""
import numpy as np
import scipy
from collections import Counter

def autocorr(x):
    """
    Calculate Autoregressive coefs.
    """
    result = np.correlate(x, x, mode='full')
    return list(result[len(result)//2:])

def calculate_mean_vars(data):

    mean_vars = []
    for sig in data:
        var = np.var(sig, axis=0).mean()
        mean_vars.append(var)
    return np.array(mean_vars)

def calculate_entropy(list_values):
    counter_values = Counter(list_values).most_common()
    probabilities = [elem[1]/len(list_values) for elem in counter_values]
    entropy=scipy.stats.entropy(probabilities)
    return entropy

def calculate_statistics(values):
    n5 = np.nanpercentile(values, 5)
    n25 = np.nanpercentile(values, 25)
    n75 = np.nanpercentile(values, 75)
    n95 = np.nanpercentile(values, 95)
    median = np.nanpercentile(values, 50)
    mean = np.nanmean(values)
    std = np.nanstd(values)
    var = np.nanvar(values)
    rms = np.nanmean(np.sqrt(values**2))
    skew = scipy.stats.skew(values,axis=0)
    return [n5, n25, n75, n95, median, mean, std, var, rms, skew]

def calculate_crossings_per_hz(values, freq):

    mean_val = np.mean(values)
    crossings = (((values[:-1]-mean_val) * (values[1:]-mean_val)) < 0).sum()
    mean_crossings = crossings*(freq/values.shape[0])
    return [mean_crossings]

def get_chanel_features(values, freq):
    entropy = calculate_entropy(values)
    crossings = calculate_crossings_per_hz(values, freq)
    statistics = calculate_statistics(values)
    autocorr_cfs =  autocorr(values)[:16]
    return np.array([entropy] + crossings + statistics+autocorr_cfs)

def make_fets(data, freq):
    """
    Itarate over the data and for each segment
    calculate statsitstical proparties
    """
    result = []
    for sig in data:
        _, n_ch = sig.shape

        all_chanels_feats = []
        for ch_idx  in range(n_ch):
            ch_data = sig[:,ch_idx]
            chanel_features = get_chanel_features(ch_data, freq)
            all_chanels_feats.append(chanel_features)
        result.append(np.array(all_chanels_feats).T)
    return np.array(result)


from unittest import TestCase, main

from icypaw.topic import DeviceTopic

class TopicTest(TestCase):
    def test_match(self):
        dt = DeviceTopic("spBv1.0", "+", "DBIRTH", "+", "+")
        self.assertTrue(dt.match("spBv1.0/qscout/DBIRTH/plogger/DLpro_029201"))

if __name__ == "__main__":
    main()


# Complete the minimumBribes function below.
def minimumBribes(q):
    totalMoves = 0

    q = [p-1 for p in q]

    for i, num in enumerate(q):

        if num-i > 2:
            print('Too chaotic')
            return

        for y in range(max(num-1, 0),i):
            if q[y]> q[i]:
                totalMoves += 1

    print(totalMoves)

minimumBribes([2, 1, 5, 3, 4])
minimumBribes([2, 5, 1, 3, 4])


import os
from tools.utils import get_logger, replace_nan
from tools.seg_lung import segment_a_lung, get_roi, get_cardiac_roi_mask
from tools.apply_mask import apply_mask
import nibabel as nib
import numpy as np

logger = get_logger('CAC preprocessing')

SRC_ROOT = os.path.dirname(os.path.realpath(__file__)) + '/../..'
c3d_path = os.path.join(SRC_ROOT, 'packages/c3d/c3d')
reg_resample_path = os.path.join(SRC_ROOT, 'packages/niftyreg/reg_resample')

class CACPreprocess:
    def __init__(self):
        pass

    @staticmethod
    def _step_resample(in_image_path, out_image_path, spacing):
        cmd_str = f'{c3d_path} {in_image_path} -resample-mm {spacing}x{spacing}x{spacing}mm -o {out_image_path}'
        logger.info('Resample image')
        logger.info(f'Run command: {cmd_str}')
        os.system(cmd_str)

    @staticmethod
    def _step_lung_mask(in_image_path, out_seg_path):
        logger.info(f'Get lung segmentation of {in_image_path}, save to {out_seg_path}')
        segment_a_lung(in_image_path, out_seg_path)

    @staticmethod
    def _step_get_lung_mask_bb(in_seg_path, out_bb_path):
        logger.info(f'Get the bb of {in_seg_path}, save to {out_bb_path}')
        get_roi(in_seg_path, out_bb_path)

    @staticmethod
    def _step_get_trimmed_bb(in_bb_path, out_trimmed_path):
        logger.info('Trim bounding box mask')
        cmd_str = f'{c3d_path} {in_bb_path} -trim 0vox -o {out_trimmed_path}'
        logger.info(f'Run command: {cmd_str}')
        os.system(cmd_str)

    @staticmethod
    def _step_roi_crop(in_ori_image_path, in_ref_path, out_roi_crop_path):
        logger.info('ROI crop')
        cmd_str = f'{reg_resample_path} -flo {in_ori_image_path} -ref {in_ref_path} -res {out_roi_crop_path} -inter 3'
        # cmd_str = f'{c3d_path} {in_ref_path} {in_ori_image_path} -mbb -o {out_roi_crop_path}'
        logger.info(f'Run command: {cmd_str}')
        os.system(cmd_str)

    @staticmethod
    def _step_roi_mask(in_lung_mask, out_roi_mask, kaggle_format=True):
        logger.info(f'Create CAC ROI mask using {in_lung_mask}, save to {out_roi_mask}')
        get_cardiac_roi_mask(in_lung_mask, out_roi_mask, kaggle_format)

    @staticmethod
    def _step_apply_mask(in_ori_image_path, mask_path, out_apply_mask_path, ambient):
        logger.info(f'Apply mask {mask_path} to {in_ori_image_path} with ambient {ambient}')
        logger.info(f'Save to {out_apply_mask_path}')
        apply_mask(in_ori_image_path, mask_path, ambient, out_apply_mask_path)

    @staticmethod
    def _step_apply_window(in_ori_image_path, window_lower, window_upper, out_image_path):
        logger.info(f'Apply window [{window_lower}, {window_upper}]')
        cmd_str = f'{c3d_path} {in_ori_image_path} -clip {window_lower} {window_upper} -o {out_image_path}'
        logger.info(f'Run command: {cmd_str}')
        os.system(cmd_str)

    @staticmethod
    def _step_calcium_mask(in_ori_image_path, thres_val, out_mask_path):
        logger.info(f'Get calcium mask of {in_ori_image_path} with thres_val {thres_val}, save to {out_mask_path}')
        cmd_str = f'{c3d_path} {in_ori_image_path} -threshold {thres_val} inf 1 0 -o {out_mask_path}'
        logger.info(f'Run command: {cmd_str}')
        os.system(cmd_str)

    @staticmethod
    def _step_resample_final(in_ori_image_path, out_image_path, interp_order=3):
        cmd_str = f'{c3d_path} -int {interp_order} {in_ori_image_path} -resample 192x128x64 -o {out_image_path}'
        logger.info(f'Run command: {cmd_str}')
        os.system(cmd_str)

    @staticmethod
    def _step_replace_nan(in_image_path, out_image_path, impute_value=0):
        replace_nan(in_image_path, out_image_path, impute_value)

    @staticmethod
    def _step_merge_jac_calcium(in_jac_path, in_calcium_path, out_calcium_w_vol_path):
        logger.info(f'Merge jac {in_jac_path} and calcium {in_calcium_path}')
        jac_data = nib.load(in_jac_path)
        jac_img = jac_data.get_data()
        cal_img = nib.load(in_calcium_path).get_data()
        cal_img[cal_img < 0.5] = 0

        jac_no_log_img = np.power(10, jac_img)
        out_cal_w_vol = np.multiply(cal_img, jac_no_log_img)
        logger.info(f'Save cal_w_vol to {out_calcium_w_vol_path}')
        out_obj = nib.Nifti1Image(out_cal_w_vol, affine=jac_data.affine, header=jac_data.header)
        nib.save(out_obj, out_calcium_w_vol_path)

    @staticmethod
    def _step_unlog(in_jac_path, out_unlog_jac_path):
        logger.info(f'Unlog {in_jac_path}, save to {out_unlog_jac_path}')
        jac_data = nib.load(in_jac_path)
        jac_img = jac_data.get_data()
        print(f'{np.min(jac_img)}, {np.max(jac_img)}')
        jac_img = np.clip(jac_img, -2, 2)
        print(f'{np.min(jac_img)}, {np.max(jac_img)}')
        # jac_img = np.power(np.pi, jac_img)
        jac_img = np.exp(jac_img)
        print(f'{np.min(jac_img)}, {np.max(jac_img)}')
        out_jac_obj = nib.Nifti1Image(jac_img, affine=jac_data.affine, header=jac_data.header)
        nib.save(out_jac_obj, out_unlog_jac_path)


from css import img_style
from os import mkdir, name
from socket import timeout
import sys
import time
import datetime

from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtWidgets import *
from PyQt5.QtCore import pyqtSlot

from functools import partial
from client2 import My_Client
import concurrent.futures
from threading import Thread
import urllib.request
import os

threads = []

class Chat_ui(QtWidgets.QWidget):
    signal_send = QtCore.pyqtSignal(str)
    switch_window = QtCore.pyqtSignal()
    curr_img = ""
    def __init__(self, name: str = "", phone : str = ""):
        print("in init")
        self.name = name
        QtWidgets.QWidget.__init__(self)
        self.window = QtWidgets.QMainWindow()
        self.window.setObjectName("Window")
        self.window.setWindowTitle("Chat")
        self.window.resize(700,300)

        self.main_widget = QtWidgets.QWidget(self.window)
        self.main_widget.setObjectName("main_widget")
        # main vertical layout:
        self.top_layer = QtWidgets.QVBoxLayout(self.main_widget)
        self.top_layer.setObjectName("top_layer")
        # scroll area where messages are shown:
        self.scroll = QtWidgets.QScrollArea(self.main_widget)
        self.scroll.setWidgetResizable(True)
        self.scroll.setObjectName("scroll")
        self.scroll.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.scroll.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.scroll_content = QtWidgets.QWidget()
        self.scroll_content.setObjectName("scroll_content")
        self.scroll_content.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum))
        self.scroll.setWidget(self.scroll_content)
        self.top_layer.addWidget(self.scroll)
        # vertical layout for the msg area:
        self.msgVLayout = QtWidgets.QVBoxLayout(self.scroll_content)
        self.chat_Greet = QtWidgets.QTextEdit()
        font = QtGui.QFont()
        font.setFamily("MS Serif")
        font.setPointSize(14)
        self.chat_Greet.setCurrentFont(font)
        self.chat_Greet.append("Welcome to the server {}!".format(name).title())
        self.chat_Greet.setFocusPolicy(QtCore.Qt.NoFocus)
        self.chat_Greet.setMaximumHeight(int(self.window.size().height() / 12))
        self.chat_Greet.setReadOnly(True)
        self.msgVLayout.addWidget(self.chat_Greet)
        # horizontal layout for input widgets:
        self.inputHLayout = QtWidgets.QHBoxLayout()
        self.inputHLayout.setObjectName("inputHLayout")
        # text msg input:

        # self.msgInput = QtWidgets.QTextEdit(self.centralwidget)
        self.msgInput = QtWidgets.QLineEdit(self.main_widget)
        self.msgInput.setObjectName("msgInput")
        self.msgInput.setMaximumHeight(int(self.window.size().height() / 2))
        self.msgInput.returnPressed.connect(self.write_msg)
        self.inputHLayout.addWidget(self.msgInput)
        # send-message button:
        self.sendButton = QtWidgets.QPushButton(self.main_widget)
        self.sendButton.setObjectName("sendButton")
        self.sendButton.setText("Send")
        self.sendButton.clicked.connect(self.write_msg)
        self.sendButton.setCursor(QtCore.Qt.PointingHandCursor)
        self.inputHLayout.addWidget(self.sendButton, 0, QtCore.Qt.AlignBottom)

        self.top_layer.addLayout(self.inputHLayout)
        self.window.setCentralWidget(self.main_widget)
        self.main_widget.show()
        self.window.resizeEvent = self.resize_event

        self.style()
        QtCore.QMetaObject.connectSlotsByName(self.window)
        self.window.show()

    def write_msg(self):
        now = datetime.datetime.now().time()
        print("in write msg")
        temp_QTextedit = QtWidgets.QTextEdit(f"[{now}] " + self.msgInput.text())
        # temp_QTextedit.setTextBackgroundColor(QtGui.QColor(0, 255, 0))
        from css import write_Qtext
        temp_QTextedit.setStyleSheet(write_Qtext())
        temp_QTextedit.setReadOnly(True)
        temp_QTextedit.setMinimumHeight(int(self.window.size().height() / 6))
        temp_QTextedit.setMaximumHeight(int(self.window.size().height() / 4))
        self.msgVLayout.addWidget(temp_QTextedit, 0, QtCore.Qt.AlignRight)
        self.signal_send.emit(self.msgInput.text())
        self.msgInput.clear()
        self.msgInput.setReadOnly(False)

    def add_msg(self, msg : str = ""):
        if "/help" in msg:
            print("in add msg /help")
            temp_QTextedit = QtWidgets.QTextEdit(msg)
            from css import help_style
            temp_QTextedit.setHtml(help_style())
            from css import write_Qtext
            # temp_QTextedit.setStyleSheet("QtWidgets.QTextEdit{border-radius: 15px 50px 30px 5px; }")
            temp_QTextedit.setStyleSheet(write_Qtext())
            temp_QTextedit.setReadOnly(True)
            temp_QTextedit.setMinimumHeight(int(self.window.size().height() / 3))
            temp_QTextedit.setMaximumHeight(int(self.window.size().height()))
            self.msgVLayout.addWidget(temp_QTextedit, 0, QtCore.Qt.AlignLeft)
        # elif msg.startswith("/img"):
        #     # msg should be the link itself here (only with "/img before"), cleaning the str should be before the function
        #     print("in add msg /img")
        #     msg = msg.replace("/msg", "")
        #     temp_QTextedit = QtWidgets.QTextEdit()
        #     from css import img_style
        #     # temp_QTextedit.setHtml(img_style(msg.split(":")[1]).replace(" ", ""))
        #     temp_QTextedit.setStyleSheet(img_style(msg))
        #     temp_QTextedit.setReadOnly(True)
        #     self.msgVLayout.addWidget(temp_QTextedit, 0, QtCore.Qt.AlignCenter)
        elif msg.startswith("/img") or msg.startswith("//serverimg") or ( "[" in msg and "]" in msg and "sends:" in msg and ("//serverimg" in msg or "/img" in msg) ) :
            if msg.startswith("//serverimg"):
                msg_list = msg.split("---")
                msg_to_be = msg_list[1][1:]
                print(f"\nmsg to be is: {msg_to_be} \n")
            elif msg.startswith("["):
                sender = msg.split("/img")[0]
                msg = msg.replace(sender, "")
                temp_QTextedit = QtWidgets.QTextEdit(sender)
                temp_QTextedit.setStyleSheet("QtWidgets.QTextEdit{border-radius: 15px 50px 30px 5px; height: 10px;  }")
                self.msgVLayout.addWidget(temp_QTextedit, 0, QtCore.Qt.AlignLeft)
            print("in add msg /img")
            msg = msg.replace("/img", "")
            msg = msg.replace("//serverimg", "")
            print(f"/img url link: {msg}")
            try:
                self.dl_jpg_url(msg)
                temp = QtWidgets.QLabel()
                pixmap = QtGui.QPixmap(self.curr_img)
                temp.setPixmap(pixmap)
                self.resize(pixmap.width(), pixmap.height())
                self.msgVLayout.addWidget(temp, 0, QtCore.Qt.AlignLeft)
            except:
                e = sys.exc_info()
                print("exception in uploading img: ", str(e))
        else:
            print("in add msg with: ", msg)
            temp_QTextedit = QtWidgets.QTextEdit(msg)
            temp_QTextedit.setStyleSheet("QtWidgets.QTextEdit{border-radius: 15px 50px 30px 5px; height: 10px;  }")
            # temp_QTextedit.setTextBackgroundColor(QtGui.QColor.fromRgb(0, 255, 0))
            # temp_QTextedit.setTextBackgroundColor(QtGui.QColor(0, 255, 0))
            temp_QTextedit.setReadOnly(True)
            if msg == "Welcome to the server, pls send us your name":
                temp_QTextedit.setMaximumHeight(int(self.window.size().height() / 8))
            self.msgVLayout.addWidget(temp_QTextedit, 0, QtCore.Qt.AlignLeft)

    def dl_jpg_url(self, url: str):
        try:
            if not os.path.exists("images"):
                os.mkdir("images")
            PATH = "images/img"
            i = 0
            while True:
                if not os.path.exists("images/img{}.jpg".format(i)):
                    urllib.request.urlretrieve(url, "images/img{}.jpg".format(i))
                    self.curr_img = "images/img{}.jpg".format(i)
                    break
                i += 1
        except:
            e = sys.exc_info()
            print("exception in urlretrieve", str(e))

    def style(self):
        from css import scrollbar_style
        scrollbar_style = scrollbar_style()
        self.main_widget.setStyleSheet(scrollbar_style)

    def resize_event(self, event):
        self.msgInput.setMaximumHeight(int(event.size().height() / 2))
        # self.msgInput.adjustHeight()

class Login(QtWidgets.QWidget):
    switch_sign_up = QtCore.pyqtSignal()
    switch_window_main = QtCore.pyqtSignal(str, str)
    start_socket = QtCore.pyqtSignal(str, str, str)

    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        self.start_socket = self.start_socket
        self.window = QtWidgets.QMainWindow()
        self.window.setObjectName("Window")
        self.window.setWindowTitle("Login")
        # self.window.resize(400,200)

        self.main_widget = QtWidgets.QWidget(self.window)
        self.main_widget.setObjectName("main_widget")

        self.top_layer = QtWidgets.QVBoxLayout(self.main_widget)
        self.top_layer.setObjectName("top_layer")

        self.Ylayout = QtWidgets.QVBoxLayout()
        self.top_layer.addLayout(self.Ylayout)
        self.Xlayout = QtWidgets.QHBoxLayout()
        self.Xlayout2 = QtWidgets.QHBoxLayout()

        self.label = QtWidgets.QLabel("Enter your name: ")
        font = QtGui.QFont()
        font.setFamily("MS Serif")
        font.setPointSize(16)
        self.label.setFont(font)
        self.Xlayout.addWidget(self.label)
        self.lineEdit = QtWidgets.QLineEdit()
        # self.lineEdit.returnPressed.connect(self.start_socket_connection)
        self.lineEdit.returnPressed.connect(self.switch_and_start)
        self.Xlayout.addWidget(self.lineEdit)
        self.Ylayout.addLayout(self.Xlayout)

        self.label2 = QtWidgets.QLabel("Enter your phone number: ")
        font = QtGui.QFont()
        font.setFamily("MS Serif")
        font.setPointSize(16)
        self.label2.setFont(font)
        self.Xlayout2.addWidget(self.label2)
        self.lineEdit2 = QtWidgets.QLineEdit()
        self.lineEdit2.returnPressed.connect(self.switch_and_start)
        self.Xlayout2.addWidget(self.lineEdit2)
        self.Ylayout.addLayout(self.Xlayout2)

        self.pushButton = QtWidgets.QPushButton("Confirm name")
        # self.pushButton.clicked.connect(self.start_socket_connection)
        self.pushButton.clicked.connect(self.switch_and_start)
        self.Ylayout.addWidget(self.pushButton)

        self.pushButton2 = QtWidgets.QPushButton("Sign Up")
        # self.pushButton.clicked.connect(self.start_socket_connection)
        self.pushButton2.clicked.connect(self.switch_to_sign_up)
        self.Ylayout.addWidget(self.pushButton2)

        self.window.setCentralWidget(self.main_widget)
        self.main_widget.show()
        QtCore.QMetaObject.connectSlotsByName(self.window)
        # self.setLayout(self.Ylayout)

    def switch_to_sign_up(self):
        self.switch_sign_up.emit()

    def switch_main(self):
        self.switch_window_main.emit(self.lineEdit.text(), self.lineEdit2.text())

    def switch_and_start(self):
        # self.switch_window_main.emit(self.lineEdit.text(), self.lineEdit2.text())
        self.start_socket.emit(self.lineEdit.text(), self.lineEdit2.text(), "/login")
        self.close()

class Sign_up(QtWidgets.QWidget):
    switch_Log_in = QtCore.pyqtSignal()
    switch_window_main = QtCore.pyqtSignal(str, str)
    start_socket = QtCore.pyqtSignal(str, str, str)

    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        self.window = QtWidgets.QMainWindow()
        self.window.setObjectName("Window")
        self.window.setWindowTitle("SignUp")

        self.main_widget = QtWidgets.QWidget(self.window)
        self.main_widget.setObjectName("main_widget")

        self.top_layer = QtWidgets.QVBoxLayout(self.main_widget)
        self.top_layer.setObjectName("top_layer")

        self.Ylayout = QtWidgets.QVBoxLayout()
        self.top_layer.addLayout(self.Ylayout)
        self.Xlayout = QtWidgets.QHBoxLayout()
        self.Xlayout2 = QtWidgets.QHBoxLayout()

        self.label = QtWidgets.QLabel("Enter your name: ")
        font = QtGui.QFont()
        font.setFamily("MS Serif")
        font.setPointSize(16)
        self.label.setFont(font)
        self.Xlayout.addWidget(self.label)

        self.lineEdit = QtWidgets.QLineEdit()
        self.Xlayout.addWidget(self.lineEdit)

        self.label2 = QtWidgets.QLabel("Enter your phone number: ")
        font = QtGui.QFont()
        font.setFamily("MS Serif")
        font.setPointSize(16)
        self.label2.setFont(font)
        self.Xlayout2.addWidget(self.label2)

        self.lineEdit2 = QtWidgets.QLineEdit()
        self.lineEdit2.returnPressed.connect(self.switch_and_start)
        self.Xlayout2.addWidget(self.lineEdit2)

        self.Ylayout.addLayout(self.Xlayout)
        self.Ylayout.addLayout(self.Xlayout2)

        self.pushButton = QtWidgets.QPushButton("Confirm")
        self.pushButton.clicked.connect(self.switch_and_start)
        self.Ylayout.addWidget(self.pushButton)

        self.pushButton2 = QtWidgets.QPushButton("Log in")
        # self.pushButton.clicked.connect(self.start_socket_connection)
        self.pushButton2.clicked.connect(self.switch_Log_in)
        self.Ylayout.addWidget(self.pushButton2)

        # self.setLayout(self.Ylayout)
        self.window.setCentralWidget(self.main_widget)
        self.main_widget.show()
        QtCore.QMetaObject.connectSlotsByName(self.window)

    def switch_to_login(self):
        self.switch_Log_in.emit()

    def switch_and_start(self):
        self.start_socket.emit(self.lineEdit.text(), self.lineEdit2.text(), "/signup")
        # self.switch_window_main.emit(self.lineEdit.text(), self.lineEdit2.text())
        # self.close()

class Pop_Up1(QtWidgets.QWidget):
    signal_send = QtCore.pyqtSignal()
    signal_end = QtCore.pyqtSignal()

    def __init__(self, name : str, boolean : bool, mode : str = "", phone : str = ""):
        QtWidgets.QWidget.__init__(self)
        self.setWindowTitle('Prompt')

        layout = QtWidgets.QGridLayout()
        if boolean:
            self.label = QtWidgets.QLabel("hello {} pls send if you want to send a message, if not just the close the window".format(name))
            layout.addWidget(self.label)
        else:
            if mode == "/signup":
                self.label = QtWidgets.QLabel("we are sorry, {} the name is alerady taken. \nPlease choose another".format(name))
            elif mode == "/login":
                self.label = QtWidgets.QLabel(f"we are sorry, {name},We cant find a phone number matching that name, or the opposite")
            else: self.label = QtWidgets.QLabel("we are sorry, {name}, we have some unresolved error, please try again")
            layout.addWidget(self.label)

        if boolean and mode != "restart":
            self.button = QtWidgets.QPushButton('Send and Close')
            self.button.clicked.connect(self.doube_emit)
            layout.addWidget(self.button)

        self.button2 = QtWidgets.QPushButton('Close')
        self.button2.clicked.connect(self.signal_end.emit)
        layout.addWidget(self.button2)

        self.setLayout(layout)
    def doube_emit(self) -> None:
        self.signal_send.emit()
        self.signal_end.emit()

class MyThread(QtCore.QThread):
    def __init__(self, func = None, parent = None) -> None:
        super(MyThread, self).__init__(parent)
        self.func = func
    def run(self) -> None:
        self.func()

class Controller(QtWidgets.QWidget):

    signal_add_msg = QtCore.pyqtSignal(str)
    move_main = QtCore.pyqtSignal(str, str)
    new_popup = QtCore.pyqtSignal(bool, str, str, str)
    restart = QtCore.pyqtSignal()
    login_close = QtCore.pyqtSignal()
    signup_close = QtCore.pyqtSignal()

    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        self.client = My_Client()
        self.show_login()
        self.img = ""
        self.taking_img = False
        self.move_main.connect(self.show_main)
        self.new_popup.connect(self.show_PopUp1)
        # self.restart.connect(self.__init__)
        self.restart.connect(self.show_login)
        self.login_close.connect(self.close_login)
        self.signup_close.connect(self.close_signup)

    def close_login(self):
        self.login.window.close()
    def close_signup(self):
        try:
            print("trying to close signup ")
            self.sign_up.window.close()
        except:
            e = sys.exc_info()
            print("exception close_signup", str(e))
    def restart_F(self):
        self.new_popup.emit(False, "restart", "", "")
        self.client.close()
        self.restart.emit()

    def restart2(self):
        self.restart.emit()
        self.new_popup.emit(False, "restart", "", "")

    def show_login(self):
        self.login = Login()
        try:
            self.login.start_socket.connect(self.start_socket1)
            self.login.switch_window_main.connect(self.show_main)
            self.login.switch_sign_up.connect(lambda : [self.show_sign_up(), self.login.window.close()])
            print("trying to show")
            self.login.window.show()
            print("should show login")
        except:
            e = sys.exc_info()
            print("exception in login", str(e))

    def show_sign_up(self):
        self.sign_up = Sign_up()
        self.sign_up.switch_Log_in.connect(lambda : [self.show_login(), self.sign_up.window.close()])
        # self.sign_up.switch_window_main.connect(lambda : [self.show_main(), self.sign_up.close()])
        self.sign_up.switch_window_main.connect(self.sign_up.window.close)
        self.sign_up.start_socket.connect(self.start_socket1)

        self.sign_up.window.show()

    def show_main(self, name : str = "", phone : str = ""):
        if name == "" or phone == "":
            print("show main: one of the params (or more) did not arrive")
        print("in show_main")
        try:
            self.main = Chat_ui(name, phone)
            print("managed to make main")
            self.signal_add_msg.connect(self.main.add_msg)
            self.main.signal_send.connect(self.send_Socket)
            self.main.window.show()
            print("should show main")
        except:
            e = sys.exc_info()
            print("exception in show_main", str(e))

    def show_PopUp1(self, boolean: bool, mode : str = "", name : str = "", phone : str = "") -> None:
        self.pop_up = Pop_Up1(name, boolean, mode, phone)
        self.pop_up.signal_send.connect(lambda: self.send_Socket(name, phone, mode))
        close = lambda  : self.pop_up.close()
        self.pop_up.signal_end.connect(close)
        self.pop_up.show()

    def start_socket1(self, name : str = "", phone : str = "", mode :str = "") -> None:
        if name == "" or phone == "" or mode == "":
            print("start_socket: one of the params (or more) did not arrive")
        # self.read_from_socket = Thread(target=self.socket_Read, args=())
        # self.read_from_socket.start()
        global threads
        for thread in threads:
            try:
                thread.terminate()
            except:
                e = sys.exc_info()
                print("exception thread termintaion", str(e))
        threads = []
        self.read_thread = MyThread(self.socket_Read)
        threads.append(self.read_thread)
        self.read_thread.start()
        print("start_socket: started threading to read socket")
        self.show_PopUp1(True, mode, name, phone)

    def socket_Read(self):
        try:
            self.data = ""
            self.data = self.client.current_socket.recv(1024).decode()
            if self.data != "" and len(self.data) >= 1:
                print("read successfully: ", self.data)
                # if not self.taking_img:
                if self.taking_img != None and self.taking_img == False:
                    if self.data.startswith("/img") or "//serverimg" in self.data:
                        print("starting to read img")
                        if self.data[::-1].startswith("//ServerEnd") or "//ServerEnd" in self.data or self.data[::-1].startswith("dnErevreS//"):
                            self.data = self.data.replace("//ServerEnd", "")
                            data101 = self.data.split("---")[0].split("//")[0] + "/img" + self.data.split("---")[1][1:]
                            print(f"data 101: {data101}")
                            # self.data = self.data.split("---")[1][1:]
                            # self.data = "/img" + self.data
                            # self.img=self.data
                            print("emiting img: ", data101)
                            self.signal_add_msg.emit(data101)
                            self.img = ""
                        else:
                            self.img+= self.img
                            self.taking_img = True
                    elif self.data.startswith("/login ok, name was verified for:"):
                        param_list = self.data.split(":")
                        print(f"1trying to pass to main: {param_list[1]}, {param_list[2]}")
                        try:
                            self.move_main.emit(param_list[1], param_list[2])
                            print("emitted to open main")
                            self.login_close.emit()
                            print("closed login window")
                        except:
                            e = sys.exc_info()
                            print("exception in .login verified", str(e))
                    elif self.data.startswith("/signup ok, verified for:"):
                        param_list = self.data.split(":")
                        print(f"2trying to pass to main: {param_list[1]}, {param_list[2]}")
                        try:
                            self.move_main.emit(param_list[1], param_list[2])
                            self.signup_close.emit()
                            print("closed /signup window")
                        except:
                            e = sys.exc_info()
                            print("exception in /signup verified", str(e))
                    elif self.data.startswith("That name already exists, pls send us another name"):
                        # self.show_PopUp1(False, "", name)
                        # self.show_login()
                        try:
                            self.login = None
                            self.restart.emit()
                            self.new_popup.emit(False, "restart", "", "")
                            print("tried to reopen all")
                        except:
                            e = sys.exc_info()
                            print("exception in restart", str(e))
                    elif self.data.startswith("We cant find a phone number matching that name, or the opposite\nplease try again"):
                        print("trying to restart")
                        try:
                            self.login = None
                            self.restart.emit()
                            self.new_popup.emit(False, "restart", "", "")
                            print("tried to reopen all")
                        except:
                            e = sys.exc_info()
                            print("exception in restart", str(e))
                    else:
                        self.signal_add_msg.emit(self.data)
                        print("signaled to to add msg")
                else:
                    # if self.data[::-1].startswith("//ServerEnd"):
                    if self.data[::-1].startswith("//ServerEnd") or "//ServerEnd" in self.data or self.data[::-1].startswith("dnErevreS//"):
                        print(f"got img when taking img was true. got: {self.data}")
                        self.img+=self.data.replace("//ServerEnd", "")
                        self.signal_add_msg.emit(self.img)
                        self.img = ""
                        self.taking_img = False
                    else:
                        self.taking_img = True
                        self.img+= self.img

            time.sleep(0.2)
            self.socket_Read()
        except timeout as e:
            # print("Got timed out?: {}".format(e))
            self.socket_Read()
            time.sleep(0.2)
        except RecursionError as e:
            print("Got RecursionError: {}".format(e))
        except:
            e = sys.exc_info()
            print("exception", str(e))

    def send_Socket(self, param : str, phone : str = "", mode : str = ""):
        try:
            # if mode and phone != "":
            if mode and phone != "":
                print(f"in mode send: {mode}-{param}-{phone}")
                self.client.current_socket.send(f"{mode}-{param}-{phone}".encode())
            else:
                if param.startswith("/img"):
                    param += "//ServerEnd"
                    param = param.replace("/img", "//serverimg{}---".format( len(param) + len("//serverimg---") + len(str(len(param) + len("//serverimg---")))   )  )
                    self.client.current_socket.send(param.encode())
                    print("sending image:  {}".format(param))
                else:
                    print("in send, param is {}".format(param))
                    self.client.current_socket.send(str(param).encode())
        except:
            e = sys.exc_info()
            print("exception in send_Socket: ", str(e))

def main():
    app = QtWidgets.QApplication(sys.argv)
    controller = Controller()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()


import face_recognition
import cv2
import numpy as np
from tkinter import *

def register(img,cav,e1):

    # cap = cv2.VideoCapture(0)
    name = str(e1.get())
    # name = input("Enter your name : ")
    encoding = open("known_face.txt","a")
    # encoding.write("\n")
    encoding.write(str(name))

    print("Updated")
    encoding.close()

    frame = img
    cv2.imshow("Register",frame)
    cv2.waitKey(100)

    cv2.imwrite("dataset\\"+str(name)+".jpeg",frame)
    cv2.waitKey(100)

    # cv2.destroyAllWindows()
        # return name,frame
    print("Done")

    # while(True):
    #     _,frame = cap.read()
    #     cv2.imshow("Register",frame)
    #     cv2.waitKey(10)
    #     if cv2.waitKey(50) == ord('q'):
    #         cv2.imwrite("dataset\\"+str(name)+".jpeg",frame)
    #         cv2.waitKey(100)
    #
    #         cv2.destroyAllWindows()
    #         # return name,frame
    #         print("Done")
    #         break

    jatin_image = face_recognition.load_image_file(".\\dataset\\"+str(name)+".jpeg")
    print(jatin_image)
    jatin_face_encoding = face_recognition.face_encodings(jatin_image)[0]
    np.savetxt("code\\"+str(name)+".txt",jatin_face_encoding,fmt='%f')
    #np.savetxt("code\\"+str(name)+".txt", jatin_face_encoding)
###################################################################################################
    # encoding = open("abc.npy","a")
    # encoding.write(jatin_face_encoding)
    # encoding.close()
    # np.save("abc.npy",jatin_face_encoding)
    # encoding.write(str(jatin_face_encoding))
    # encoding.write(",")
    # with open("encoding.txt", "ab") as f:
    #     numpy.savetxt(f, jatin_face_encoding,delimiter='\n\n')

    # z = open("encoding.txt","a")
    # # z.write("\n\n")
    # z.write(str(jatin_face_encoding))
    print("Done")
    # z.close()
    # encoding = open("known_face.txt","a")
    #
    # encoding.write(str(name))
    # encoding.write("\n")
    # print("Updated")

# register()

# jatin_image = face_recognition.load_image_file("dataset\\"+str(name)+".jpg")
# jatin_face_encoding = face_recognition.face_encodings(jatin_image)[0]
#
# encoding = open("encoding.txt","a")
#
# encoding.write(jatin_face_encoding)
# # encoding.write("\n")
# import numpy as np
#
# # known_face_encodings = np.loadtxt("known_face.txt", delimiter="\n",dtype="str")
# known_face_encodings = np.loadtxt("encoding.txt", delimiter=",",dtype="float32")
# # str(known_face_encodings).replace("'", "")
#
# print(known_face_encodings)


from flask import request, Flask, make_response, json
from services import flights, edit_flight, create_flight, get_flight
from flask_cors import CORS, cross_origin

#import json

app = Flask(__name__)
cors = CORS(app)
app.config['CORS_HEADERS'] = 'Content-Type'

@app.route('/')
def hello():
    return 'Hello, World!'

@app.route('/flights')
@cross_origin()
def get_flights():
    flt = flights()
    response = app.response_class(
        response = json.dumps(flt),
        status=200,
        mimetype='application/json'
    )
    return response

@app.route('/flight/<string:op_nb>', methods=["GET", "POST", "DELETE", "PUT"])
def flight(op_nb):

    if request.method == "GET":
        # Get The flight
        print(op_nb)
        flt = get_flight(op_nb);
        response = app.response_class(
            response = json.dumps(flt),
            status=200,
            mimetype='application/json'
        )
        return response

    if request.method == "POST":
        # Create the flight
        data = request.get_json();
        print(op_nb)
        print(data['ori'])
        flt = create_flight(data['op_nb'], data['ori'], data['dst'])
        response = app.response_class(
            response = json.dumps(
                {
                    "data": "OK"
                }),
            status=200,
            mimetype='application/json'
        )
        return response

    if request.method == "PUT":
        # Edit flight
        data = request.get_json();
        print(op_nb)
        print(data['ori'])
        edit_flight(data['op_nb'], data['ori'], data['dst'])
        response = app.response_class(
            response = json.dumps(
                {
                    "data": "OK"
                }),
            status=200,
            mimetype='application/json'
        )
        return response

if __name__ == "__main__":
    app.run(port=7777)
    pass


import argparse
import json
import os
import shutil
import subprocess

import yaml
from ultralytics import YOLO

ROOT_PATH = "/opt/ml/dataset"
IMAGE_PATH = os.path.join(ROOT_PATH, "images")
LABEL_PATH = os.path.join(ROOT_PATH, "labels")
CONFIG_PATH = "/opt/ml/baseline/ultralytics/ultralytics/yolo/cfg/zconfigs"

if __name__ == "__main__":
    # argparse 모듈을 사용하여 스크립트 실행 시 사용자로부터 입력받은 인자들을 파싱
    parser = argparse.ArgumentParser(description="YOLO v8 학습 코드")

    parser.add_argument("--yaml_file", help="학습 파라미터를 저장하는 yaml 파일의 이름", required=True)
    args = parser.parse_args()
    with open(os.path.join(CONFIG_PATH, args.yaml_file), "r") as config_yaml_file:
        config = yaml.load(config_yaml_file, Loader=yaml.FullLoader)

    parser.add_argument("--train_json_path", default=config["train_json_path"], help="학습 json파일 경로")
    parser.add_argument("--valid_json_path", default=config["valid_json_path"], help="검증 json파일 경로")
    args = parser.parse_args()

    del config["train_json_path"], config["valid_json_path"]

    # ---------------------------------------- DATA SPLIT ----------------------------------------

    print("-" * 10 + "| 데이터 split |" + "-" * 10)

    # 학습 데이터와 검증 데이터를 json 파일로부터 읽어와서 이미지 파일 경로를 추출
    with open(args.train_json_path, "r") as train_json_file:
        train_data = json.load(train_json_file)
    with open(args.valid_json_path, "r") as valid_json_file:
        valid_data = json.load(valid_json_file)

    train_image_paths = [image["file_name"] for image in train_data["images"]]
    valid_image_paths = [image["file_name"] for image in valid_data["images"]]

    len_train_data = len(train_image_paths)
    len_valid_data = len(valid_image_paths)

    # 분할된 데이터 수 출력
    print("split된 파일 갯수")
    print(f"train: {len_train_data}")
    print(f"valid: {len_valid_data}\n")

    os.makedirs(IMAGE_PATH, exist_ok=True)
    os.makedirs(os.path.join(IMAGE_PATH, "train"), exist_ok=True)
    os.makedirs(os.path.join(IMAGE_PATH, "valid"), exist_ok=True)

    os.makedirs(LABEL_PATH, exist_ok=True)
    os.makedirs(os.path.join(LABEL_PATH, "train"), exist_ok=True)
    os.makedirs(os.path.join(LABEL_PATH, "valid"), exist_ok=True)

    # train 폴더와 valid 폴더로 분리하여 복사
    for train_image_path in train_image_paths:
        origin_path = os.path.join(ROOT_PATH, train_image_path)
        moved_path = os.path.join(IMAGE_PATH, "train")
        shutil.copy2(origin_path, moved_path)
    for valid_image_path in valid_image_paths:
        origin_path = os.path.join(ROOT_PATH, valid_image_path)
        moved_path = os.path.join(IMAGE_PATH, "valid")
        shutil.copy2(origin_path, moved_path)

    len_train_files = len(os.listdir(os.path.join(IMAGE_PATH, "train")))
    len_valid_files = len(os.listdir(os.path.join(IMAGE_PATH, "valid")))

    # train/valid 폴더 내 이미지 파일 수 출력
    print("폴더 내 파일 갯수")
    print(f"train: {len_train_files}")
    print(f"valid: {len_valid_files}\n")

    # 분할된 데이터와 train/valid 폴더 내 이미지 파일 수가 일치하는지 검사
    assert len_train_data == len_train_files and len_valid_data == len_valid_files, "데이터 유효성 검사 실패"
    print("데이터 유효성 검사 성공\n")
    print("split된 데이터를 기반으로 COCO 포맷에서 YOLO 포맷으로 label을 변환합니다")
    print("coco2yolo 실행\n")

    train_command = [
        "conda",
        "run",
        "-n",
        "detection",
        "python3",
        "/opt/ml/baseline/ultralytics/coco2yolo.py",
        "-j",
        args.train_json_path,
        "-o",
        os.path.join(LABEL_PATH, "train"),
    ]
    valid_command = [
        "conda",
        "run",
        "-n",
        "detection",
        "python3",
        "/opt/ml/baseline/ultralytics/coco2yolo.py",
        "-j",
        args.valid_json_path,
        "-o",
        os.path.join(LABEL_PATH, "valid"),
    ]
    subprocess.run(train_command, check=True)
    subprocess.run(valid_command, check=True)

    # ---------------------------------------- MODEL ----------------------------------------

    os.chdir("/opt/ml/baseline/ultralytics")
    model = YOLO(config["model"])

    del config["model"]
    config["name"] = args.yaml_file[:-5]

    model.train(**config)


# -*- coding: utf-8 -*-
"""
Created on Thu Oct 27 12:48:05 2016

@author: wattai
"""
import numpy as np
import matplotlib.pyplot as plt

def gauss_ludgendle(N_iter):
    a0 = 1. / np.sqrt(2)
    b0 = 1.
    s0 = 1.
    t0 = 4.
    pis = []

    for i in range(N_iter):
        a1 = np.sqrt(a0*b0)
        b1 = (a0 + b0) / 2.
        s1 = s0 - t0 * (b1 - b0)**2
        t1 = 2. * t0

        a0 = a1
        b0 = b1
        s0 = s1
        t0 = t1

        pi = ((a0 + b0)**2) / s0
        pis.append(pi)

    return np.array(pis)

def borwein_4d(N_iter):
    a0 = 6. - 4. * np.sqrt(2)
    y0 = np.sqrt(2) - 1.
    pis = []

    for i in range(N_iter):
        y1 = ( 1 - ( 1 - y0**4 )**(1/4) ) / ( 1 + ( 1 - y0**4 )**(1/4) )
        a1 = a0 * (1. + y1)**4 -( 2.**(i+3.) * y1 * (1. + y1 + y1**2) )

        y0 = y1
        a0 = a1

        pi = 1 / a0
        pis.append(pi)

    return np.array(pis)

if __name__ == "__main__":

    N_iter = 5
    pis_gauss = gauss_ludgendle(N_iter)
    pis_bor = borwein_4d(N_iter)
    print("gauss pi: " +str(pis_gauss))
    print("borwein pi: " +str(pis_bor))
    print("true pi: " +str(np.pi))
    print("error: " +str(abs(np.pi-pis_gauss[N_iter-1])))
    print("error: " +str(abs(np.pi-pis_bor[N_iter-1])))

    n = np.arange(N_iter)
    plt.figure()
    plt.plot(n, (np.pi - pis_gauss), color="red")
    plt.plot(n, (np.pi - pis_bor), color="blue")


"""
this file contains tooltips messages values
"""

name = '''REQUIRED. Name of the dataset.'''

bids_version = '''REQUIRED. The version of the BIDS standard that was used.'''

dataset_type =\
    '''RECOMMENDED. The interpretaton of the dataset. MUST be one of "raw"
or "derivative". For backwards compatibility, the default value is "raw".'''

dataset_license =\
    '''RECOMMENDED. The license for the dataset. The use of license name
abbreviations is RECOMMENDED for specifying a license (see Appendix II).
The corresponding full license text MAY be specified in an additional
LICENSE file.'''

license_pd =\
    '''Public Domain: No license required for any purpose;
the work is not subject to copyright in any jurisdiction.'''

license_pddl =\
    '''Open Data Commons Public Domain Dedication and License:
License to assign public domain like permissions without giving up the
copyright: http://opendatacommons.org/licenses/pddl/'''

license_cc0 =\
    '''Creative Commons Zero 1.0 Universal.:
use this if you are a holder of copyright or database rights, and you wish
to waive all your interests in your work worldwide:
http://opendatacommons.org/licenses/cc0/'''

authors =\
    '''OPTIONAL. List of individuals who contributed to the creation/curation of
the dataset.'''

acknowledgements =\
    '''OPTIONAL. Text acknowledging contributions of individuals or
institutions beyond those listed in Authors or Funding.'''

how_to_ack =\
    '''OPTIONAL. Text containing instructions on how researchers using this
dataset should acknowledge the original authors. This field can also be used
to define a publication that should be cited in publications that use the
dataset.'''

funding = '''OPTIONAL. List of sources of funding (grant numbers).'''

ethics_approval =\
    '''OPTIONAL. List of ethics committee approvals of the research protocols
and/or protocol identifiers.'''

ref_and_links =\
    '''OPTIONAL. List of references to publication that contain information on
the dataset, or links.'''

dataset_doi =\
    '''OPTIONAL. The Document Object Identifier of the dataset
(not the corresponding paper).'''

generated_by =\
    '''REQUIRED. List of [objects][object] with at least one element.'''

gen_name =\
    '''REQUIRED. Name of the pipeline or process that generated the outputs.
Use "Manual" to indicate the derivatives were generated by hand, or adjusted
manually after an initial run of an automated pipeline.'''

gen_version = '''RECOMMENDED. Version of the pipeline.'''

gen_description = \
    '''OPTIONAL. Plain-text description of the pipeline or process that
generated the outputs. RECOMMENDED if Name is "Manual".'''

gen_code_url = \
    '''OPTIONAL. URL where the code used to generate the derivatives
may be found.'''

gen_container = \
    '''OPTIONAL. [Object][object] specifying the location and relevant
attributes of software container image used to produce the derivative.
Valid fields in this object include Type, Tag and URI.'''

sources_datasets = \
    '''RECOMMENDED. A list of [objects][object] specifying the locations and
relevant attributes of all source datasets. Valid fields in each object
include URL, DOI, and Version.'''