# %%
import pandas as pd
import numpy as np
import cv2
import os
from PIL import Image
import os

class ImagesHandle:

    def __init__(self,path_dirty,path_clean,size=256) -> None:
        self.size       = size
        self.path_dirty = path_dirty
        self.path_clean = path_clean
        self.names      = self.get_list_of_images_names(path_dirty)
        self.start_resize()
        pass

    def start_resize(self):
        i = 0
        for _ in self.names:
            print(i)
            i += 1
            new_im = self.resize_image(self.size, Image.open(self.path_dirty+_))
            new_im.save(self.path_clean+_)

    def resize_image(self,final_size, im):
        size = im.size
        ratio = float(final_size) / max(size)
        new_image_size = tuple([int(x*ratio) for x in size])
        im = im.resize(new_image_size, Image.ANTIALIAS)
        new_im = Image.new("RGB", (final_size, final_size))
        new_im.paste(im, ((final_size-new_image_size[0])//2, (final_size-new_image_size[1])//2))
        return new_im

    def get_list_of_images_names(self,path):
        self.names = os.listdir(path)
#        print(self.names)
        for _ in self.names:
            if not('.jpg' in _):
                self.names.remove(_)
        return self.names

    def get_list_of_images_size(self,path):
        width   = []
        height  = []
        channel = []
        i = 0
        for _ in self.names:
            print(i)
            i += 1
            raw = cv2.imread(path+_).shape
            width.  append(raw[0])
            height. append(raw[1])
            channel.append(raw[2])
        frame_size = pd.DataFrame({'width':width,'height':height,'channel':channel,})
        return frame_size

if __name__ == '__main__':
    path_dirty = 'C:/Users/Danila/Documents/GitHub/facebook-marketplaces-recommendation-ranking-system/images_fb/images/'
    path_clean = 'C:/Users/Danila/Documents/GitHub/facebook-marketplaces-recommendation-ranking-system/images_fb/clean_images_224/'
    ih = ImagesHandle(path_dirty,path_clean)
#    ih.get_list_of_images_names(path_dirty)
 #   df_size = ih.get_list_of_images_size(path_dirty)
    pass
#'''

  #  dirs = os.listdir(path)
 #   final_size = 512
   # for n, item in enumerate(dirs[:5], 1):
    #    im = Image.open('images/' + item)
     #   new_im = resize_image(final_size, im)
      #  new_im.save(f'{n}_resized.jpg')

# %%


# Auto-Split-Editor
# Nick Furlo aka earllgray
# August 2021
# The GNU General Public License v3.0
import os
import shutil

# Start menu, might add more functionality later.
def start():
    if not os.path.exists('images'):
        print("images folder does not exist, creating one...")
        os.makedirs('images')
    print("Make sure split images from your autos-plitter have been copied to the 'images' folder.")
    choice = input("What would you like to do? \n1. Change Thresholds\n")
    if int(choice) == 1:
        changeThresholds()
    else:
        print("nope")
        start()

# Given a filename and new threshold, this function will generate a filename with the new threshold value.
def generateThreshold(filename, threshold):
    if int(threshold) >= 100:
        print("Enter an integer less than 100")
        return 1
    # gets index values for #s after the decimal place. These indexes are used to replace that portion of text with the new threshold.
    lindex = filename.find("(") + 3
    rindex = filename.find(")") - 1
    newFilename = filename[0:lindex] + threshold + filename[rindex + 1:]
    return newFilename

# Started by start selection. This function gets input from the user and calls generateThreshold. It then use shutil to rename the file. It iterates through all files in the images folder.
def changeThresholds():
    print("\nEnter threshold values as integers, s to skip, or q to quit. Ex: 80% = 80")
    for filename in os.listdir("images"):
        fullPath = os.path.join("images", filename)
        if os.path.isfile(fullPath):
            print("What threshold do you want for this image?\n" + fullPath[7:])
            threshold = input()
            if threshold.lower() == "s":
                print("Skipped.\n")
            elif threshold.lower() == "q":
                return print("Quitting!")
            else:
                newFilename = generateThreshold(filename, threshold)
                if isinstance(newFilename, int):
                    return print("error generating filename.")
                print("New Filename: " + newFilename + "\n")
                newFull = fullPath[0:7] + newFilename
                shutil.move(fullPath, newFull)

start()


# AlphaFir (Alpha Four In Row)
# Made by Airil/Ainhoa and IA based on AlphaZero algorithm

import random
import tensorflow as tf
from tensorflow import keras
import numpy as np
import os

partida = 1

tablero_base = [[0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0]]

def save_network(network, filename):
    script_dir = os.path.dirname(os.path.abspath(__file__))

    save_path = os.path.join(script_dir, 'networks')
    if not os.path.exists(save_path):
        os.makedirs(save_path)

    network.save(os.path.join(save_path, filename))
    print("[+] Saved network")

def place_a_tile(tablero, column, player):
    numerajo_mas_bajo = 0 # el numerajo mas bajo es el numero del bichajo
    unajo = 1

    for i in range(len(tablero)):
        if tablero[i][column] == 0:
            numerajo_mas_bajo = i
        else:
            break

    # ya ta encontrado el numerajo mas bajo uwu
    # si, estoy programando a las 5am una ia que juega al 4 en ralla mientras veo un bollodrama, porfi no me juzguen

    tablero[numerajo_mas_bajo][column] = player # player son 1 o 2, porque ese es el numero de neuronas que tengo :)

    return tablero

def check_cuatrejo_en_rallejo(board, player, last_column):
    rallitas, columnitas = len(board), len(board[0])

    # ladajo
    for row in range(rallitas):
        for col in range(max(0, last_column - 3), min(columnitas - 3, last_column + 1)):
            if all(board[row][col + i] == player for i in range(4)):
                return True

    # arribajo
    for row in range(rallitas - 3):
        if all(board[row + i][last_column] == player for i in range(4)):
            return True

    # diagonal bajorriba
    for row in range(3, rallitas):
        for col in range(max(0, last_column - 3), min(columnitas - 3, last_column + 1)):
            if all(board[row - i][col + i] == player for i in range(4)):
                return True

    # diagonal arribajo
    for row in range(rallitas - 3):
        for col in range(max(0, last_column - 3), min(columnitas - 3, last_column + 1)):
            if all(board[row + i][col + i] == player for i in range(4)):
                return True

    return False

# AHORA TOCA LA IA BAILONGA, AlphaFisting, osea, quiero decir, AlphaFir jajaja

# PRIMERO EL ARBOL DE PROBABILIDADES PARA EL HACER UN DATASET DE LA MEJOR JUGADA PARA CADA CASO

class Node: # un nodo del arbol de probabilidades
    def __init__(self, board, player, parent=None):
        self.board = board.copy()
        self.player = player
        self.parent = parent
        self.children = []
        self.visits = 0
        self.value = 0
        self.expanded = False

    def expand(self):
        valid_moves = False
        for col in range(len(self.board[0])):
            if self.board[0][col] == 0:
                valid_moves = True
                new_board = place_a_tile(self.board, col, self.player)
                child_node = Node(new_board, 3 - self.player, self)
                self.children.append(child_node)
        if not valid_moves:
            self.expanded = True
            return False
        self.expanded = True
        return True

    def best_child(self, exploration_weight=1.):
        if not self.children:
            return None

        scores = [(child.value / (child.visits + 1e-7)) + exploration_weight * np.sqrt(np.log(self.visits + 1) / (child.visits + 1e-7)) for child in self.children]
        return self.children[np.argmax(scores)]

training_data = []

def MCTS(root, simulations=1000):
    for i in range(simulations):
        node = root

        while node.expanded and node.children:
            node = node.best_child()

        if not node.expanded:
            node.expand()

        outcome = random_simulation(node.board, node.player)

        while node:
            node.visits += 1
            node.value += outcome
            training_data.append((node.board, best_move(node)))
            node = node.parent

def empate(board):
    for columna in board:
        if 0 in columna:
            return False
    return True

def random_simulation(board, player):
    while True:
        if empate(board):
            return 0
        col = random.choice(range(len(board[0])))
        if board[0][col] == 0:
            board = place_a_tile(board, col, player)
            if check_cuatrejo_en_rallejo(board, player, col):
                return 1 if player == 1 else -1
            player = 3 - player
        else:
            continue

def best_move(root):
    child = root.best_child(exploration_weight=0)
    if child is None:
        return None
    return root.children.index(child)

# Y AHORA UN MODELO QUE APRENDE CON ESE DATASET A PREDECIR LA MEJOR JUGADA (no se hace un dataset entero sino que varios pequeños con los que se va entrenando poquito a poquito)

model = keras.models.Sequential([
    keras.layers.InputLayer(input_shape=(6, 7, 1)),

    keras.layers.Conv2D(32, (3, 3), padding="same", activation="relu"),
    keras.layers.Dropout(0.25),
    keras.layers.Conv2D(64, (3, 3), padding="same", activation="relu"),
    keras.layers.Dropout(0.25),
    keras.layers.Conv2D(64, (3, 3), padding="same", activation="relu"),
    keras.layers.Dropout(0.25),
    keras.layers.Conv2D(64, (3, 3), padding="same", activation="relu"),
    keras.layers.Dropout(0.25),
    keras.layers.Conv2D(128, (3, 3), padding="same", activation="relu"),
    keras.layers.Dropout(0.25),
    keras.layers.Conv2D(128, (3, 3), padding="same", activation="relu"),

    keras.layers.Flatten(),
    keras.layers.Dense(128, activation="relu"),
    keras.layers.Dropout(0.25),
    keras.layers.Dense(300, activation="relu"),
    keras.layers.Dropout(0.25),
    keras.layers.Dense(400, activation="relu"),
    keras.layers.Dropout(0.25),
    keras.layers.Dense(600, activation="relu"),
    keras.layers.Dropout(0.25),
    keras.layers.Dense(600, activation="relu"),
    keras.layers.Dropout(0.25),
    keras.layers.Dense(600, activation="relu"),
    keras.layers.Dropout(0.25),
    keras.layers.Dense(600, activation="relu"),
    keras.layers.Dropout(0.25),
    keras.layers.Dense(600, activation="relu"),
    keras.layers.Dropout(0.25),
    keras.layers.Dense(400, activation="relu"),
    keras.layers.Dropout(0.25),
    keras.layers.Dense(300, activation="relu"),
    keras.layers.Dropout(0.25),
    keras.layers.Dense(128, activation="relu"),

    keras.layers.Dense(7, activation="softmax")
])

model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

while True:
    movimiento = 1
    board = tablero_base.copy()
    column = 0
    root = Node(board, 1)

    while True: # comienza la partida: ave cesar, gallina tu madre
        print("\n[+] Partida: " + str(partida))

        if movimiento % 2 == 0:
            player = 2
        else:
            player = 1

        if player == 1:
            print("\n[!] MCTS start")
            MCTS(root, simulations=1000)
            print("[!] MCTS finished")
            column = best_move(root)

            if column is None:
                print("No valid moves available!")
                partida += 1
                break
            else:
                board = place_a_tile(board, column, player)

        else:
            column = random.choice(range(7))
            undescartau = [0, 1, 2, 3, 4, 5, 6]
            while True:
                column = random.choice(undescartau)
                undescartau.remove(column)

                if board[0][column] == 0 or undescartau == []:
                    break

            board = place_a_tile(board, column, player)

        if movimiento > 6: # ckeckea si hay 4 en ralla (los primeros 6 movimientos no porque es imposible y asi es un poquito mas eficiente)
            if check_cuatrejo_en_rallejo(board, player, column):
                partida += 1
                break

        movimiento += 1

    if partida % 1000 == 0:
        if any(move is not None for _, move in training_data):
            boards, moves = zip(*[(board, move) for board, move in training_data if move is not None])
            boards_np = np.array(boards).reshape(-1, 6, 7, 1)
            moves_np = keras.utils.to_categorical(moves, 7)

            model.fit(boards_np, moves_np, epochs=40, batch_size=32)
            training_data.clear()

            save_network(model, "AlphaFir")


'''
Accept N numbers from user and accept Range, Display all elements from
that range
Input : N : 6
Start: 60
End : 90
Elements : 85 66 3 76 93 88
Output : 85 66 76 88
Input : N : 6
Start: 30
End : 50
Elements : 85 66 3 76 93 88
Output :
'''

def AcceptElements(arr,size):
    print("Enter the elements:");
    for i in range(0,size):
        arr.append(int(input()));

def DisplayElements(arr):
    for i in arr:
        print(i);

def DisplayElementsInRange(arr,iStart,iEnd):
    for i in range(0,len(arr)):
        if((arr[i] > iStart) and (arr[i] < iEnd)):
            print(arr[i]);

def main():
    size = int(input("Enter number of elements: "));
    arr = [];
    AcceptElements(arr,size);
    print("Entered elements are:");
    DisplayElements(arr);
    iStart = int(input("Enter start range:"));
    iEnd = int(input("Enter end range:"));
    DisplayElementsInRange(arr,iStart,iEnd);

if __name__ == "__main__":
    main();

4 Python_Programs/5 Problems on N numbers/13_DisplayNumbers_InSpecifiedRange/Demo.py


from src.basehandler import BaseHandler
import json
import redis

__author__ = 'alay'

class VoteHandler(BaseHandler):

    @staticmethod
    def vote_counter(data, pipe):
        voter = 'voter:' + data['counter']
        pipe.hset(voter, 'enroll', data['login']['enroll'])
        pipe.set(data['login']['enroll'], data['counter'])
        for data_category in data['form']:
            if isinstance(data['form'][data_category], dict):
                for gender in data['form'][data_category]:
                    category = data_category
                    value = data['form'][data_category][gender]
                    category = category + ':' + gender
                    pipe.hset(voter, category, value)
                    pipe.hincrby(category, value)
            else:
                category = data_category
                value = data['form'][data_category]
                pipe.hincrby(category, value)
                pipe.hset(voter, category, value)
        pipe.save()
        return

    def options(self, *args, **kwargs):
        self.send_error(200)

    def post(self, *args, **kwargs):
        data = json.loads(self.request.body.decode('utf-8'))
        login = data['login']

        if BaseHandler.check_credentials(login['enroll'], login['key']):

            flag = self.client.get(login['enroll'])

            if flag:
                self.response['ok'] = False
                self.response['error'] = []
                self.response['error'].append('voted')
            else:
                with self.client.pipeline() as pipe:
                    while 1:
                        try:
                            counter = self.client.get('counter')
                            data['counter'] = str(counter.decode('utf-8'))
                            pipe.watch('counter')
                            pipe.multi()
                            VoteHandler.vote_counter(data, pipe)
                            pipe.incr('counter')
                            pipe.execute()
                            break
                        except redis.WatchError as error:
                            continue

                self.response['ok'] = True
        else:
            self.response['ok'] = False
            self.response['error'] = []
            self.response['error'].append('credentials')

        self.send_error(200)
        return

    def __del__(self):
        del self.client


import os
import time

import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim

import config
from model import Generator, Discriminator
from train_utils import user_friendly_time, time_since, progress_bar, eta, outputids2words

class Trainer(object):
    def __init__(self, embedding, data_loaders):
        if len(data_loaders) == 2:
            self.train_loader, self.dev_loader = data_loaders
            self.is_train = True
            self.g_optim = None
            self.d_optim = None
        else:
            self.test_loader = data_loaders[0]
            self.is_train = False
        self.vocab_size = embedding.shape[0]
        self.embedding = torch.FloatTensor(embedding).to(config.device)

    def train(self):
        generator = Generator(self.embedding, self.vocab_size, config.att_embedding_size, 2, config.ber_prob)
        generator = generator.to(config.device)
        discriminator = Discriminator(2, config.dec_hidden_size, config.enc_hidden_size)
        discriminator = discriminator.to(config.device)
        self.g_optim = optim.Adam(params=generator.parameters(), lr=config.g_lr)
        self.d_optim = optim.Adam(params=discriminator.parameters(), lr=config.d_lr)
        criterion = nn.CrossEntropyLoss(ignore_index=0)

        num_step = 0
        best_loss = 1e10
        batch_nb = len(self.train_loader)
        for epoch in range(1, config.num_epochs + 1):
            start = time.time()
            for i, train_data in enumerate(self.train_loader):
                batch_idx = i + 1
                num_step += 1
                recon_loss, errG, errD = self.step(generator, discriminator, criterion, train_data)

                generator_loss = recon_loss + errG * config.loss_lambda
                # generator_loss = recon_loss
                msg = "{}/{} {} - ETA : {} - recon : {:.4f}, loss G: {:.4f}, loss D: {:.4f}".format(
                    batch_idx, batch_nb,
                    progress_bar(batch_idx, batch_nb),
                    eta(start, batch_idx, batch_nb),
                    recon_loss, errG, errD)
                print(msg)
            # only see reconstruction loss
            dev_loss = self.evaluate(generator)
            msg = "Epoch {} took {} - final loss : {:.4f} - validation loss : {:.4f}" \
                .format(epoch, user_friendly_time(time_since(start)), generator_loss, dev_loss)
            print(msg)
            if dev_loss < best_loss:
                best_loss = dev_loss
                generator.save(config.save_dir, epoch, num_step)

    def step(self, generator, discriminator, recon_criterion, train_data):
        x, x_len, l_src = train_data
        x = x.to(config.device)
        l_src = l_src.to(config.device)
        l_trg = torch.ones_like(l_src, device=config.device) - l_src
        l_trg = l_trg.to(config.device)

        # forward pass
        recon_logits, hiddens_x, hiddens_y, trg_len = generator(x, x_len, l_src, l_trg)

        # backward pass and update Discriminator
        gan_loss = nn.BCEWithLogitsLoss()
        batch_size = x.size(0)

        # FIXME: detach either hiddens_x or hiddens_y or both?
        self.d_optim.zero_grad()
        real_logits = discriminator(hiddens_x.detach(), x_len, l_src)
        fake_logits_x = discriminator(hiddens_x.detach(), x_len, l_trg)
        fake_logits_y = discriminator(hiddens_y.detach(), trg_len, l_trg, sorting=True)

        real_label = torch.full((batch_size,), 1, device=config.device)
        fake_label = torch.full((batch_size,), 0, device=config.device)
        # 2logD(h_x, l)
        errD_real = 2 * gan_loss(real_logits, real_label)

        # log(1 - D(h_y, l')) + log(1 - D(h_x, l'))
        errD_fake_x = gan_loss(fake_logits_x, fake_label)
        errD_fake_y = gan_loss(fake_logits_y, fake_label)
        errD = errD_real + errD_fake_x + errD_fake_y
        errD.backward()
        self.d_optim.step()

        # backward pass of Generator
        self.g_optim.zero_grad()
        targets = x.view(-1)
        recon_loss = recon_criterion(recon_logits, targets)

        fake_logits_y = discriminator(hiddens_y, trg_len, l_trg, sorting=True)
        errG = 2 * gan_loss(fake_logits_y, real_label)
        generator_loss = recon_loss + config.loss_lambda * errG
        generator_loss.backward()
        self.g_optim.step()

        return recon_loss, errG, errD

    def evaluate(self, generator):
        criterion = nn.CrossEntropyLoss(ignore_index=0)
        losses = []
        for i, eval_data in enumerate(self.dev_loader):
            with torch.no_grad():
                x, x_len, l_src = eval_data
                x = x.to(config.device)
                l_src = l_src.to(config.device)
                l_trg = torch.ones_like(l_src, device=config.device) - l_src
                recon_logits, _, _, _ = generator(x, x_len, l_src, l_trg)
                target = x.view(-1)
                loss = criterion(recon_logits, target)
                losses.append(loss.item())

        return np.mean(losses)

    def inference(self, model_path, output_dir, idx2word):
        model = Generator(self.embedding, self.vocab_size, config.att_embedding_size, 2, config.ber_prob)
        model.load_state_dict(torch.load(model_path))
        model = model.to(config.device)
        total_decoded_sents = []
        original_sents = []

        for test_data in self.test_loader:
            x, x_len, l_src = test_data
            x = x.to(config.device)
            l_trg = torch.zeros_like(l_src, device=config.device)
            decoded = model.decode(x, x_len, l_trg, config.max_decode_step)

            origin_sent = [outputids2words(sent, idx2word) for sent in x.detach()]
            original_sents.extend(origin_sent)

            decoded_sents = [outputids2words(sent, idx2word) for sent in decoded.detach()]
            total_decoded_sents.extend(decoded_sents)

        # write the results into text file
        path = os.path.join(output_dir, "decoded.txt")

        with open(path, "w", encoding="utf-8") as f:
            for original_sent, decoded_sent in zip(original_sents, total_decoded_sents):
                f.write(original_sent + " -> " + decoded_sent + "\n")

        idx = np.random.randint(0, 100)
        decoded_sent = total_decoded_sents[idx]
        original_sent = original_sents[idx]
        print(original_sent, "->", decoded_sent)


from tkinter import *
import random

root = Tk()
root.title("Rock--Paper--Scissor")

e = Entry(root, width = 35, borderwidth = 5,textvariable = "Whats your choice? 'r' for rock, 'p' for paper, 's' for scissors:----")
e.grid(row = 0, column = 0, columnspan = 3, padx = 10, pady = 10)

def play(choice):
    user = choice
    computer = random.choice(['r', 'p', 's'])

    if user == computer:
        return " It\'s a Tie"
    if is_win(user, computer):
        return "You Won"

    return "You Lost"

def is_win(player,opponent):
    if (player == "r" and opponent == "s") or (player == "s" and opponent == "p") or (player == "p" and opponent == "r"):
        return True

button_rock = Button(root, text = "Rock", padx = 40, pady = 20, command = lambda: play(1)).grid(row = 3, column = 0)
button_paper = Button(root, text = "Paper", padx = 40, pady = 20, command = lambda: play(2)).grid(row = 3, column = 1)
button_scissor = Button(root, text = "Scissor", padx = 40, pady = 20, command = lambda: play(3)).grid(row = 3, column = 2)

root.mainloop()


def cond1(n):
    res = '%s : ' % n
    if (n >= 0):
            res += 'positive '
            if n % 2 == 0:
                res += 'divisible by 2 '
            elif n % 3 == 0:
                res += 'divisible by 3 '

            elif n % 5 == 0:
                res += 'divisible by 5 '
            else:
                res += 'funny '
    else:
        # negative
        res += 'negative '
    return res + 'number'

def test_if_elif_else():
    assert cond1(27) == '27 : positive divisible by 3 number'

def test_if_else_expr():
    assert 8 + (2 if 1 else 3) == 10
    assert 8 + (2 if 0 else 3) == 11

def test_all():
    test_if_else_expr()
    test_if_elif_else()

if __name__ == '__main__':
    test_all()


import torch
import torch.nn as nn
import torch.nn.init as init
import torch.nn.functional as F
from torch.autograd import Variable
from lib.utils import init_kernel_AR, warp, conv2
import numpy as np

class Blend(nn.Module):
    def __init__(self):
        super(Blend, self).__init__()
        self.c = 1
        self.numb = 4
        self.k_size = 3
        self.relu = nn.LeakyReLU(negative_slope=0.2, inplace=True)

        # Init FeatureExtractor
        self.FE = dict()
        for i in range(self.numb):
            self.FeatureExtract(i)

        # Init Refine Network
        self.RF = dict()
        self.RefineNet()

        self.Pr = nn.Parameter(torch.from_numpy(init_kernel_AR()).cuda())

        self._initialize_weights()
        self._get_params()

    def forward(self, x, v, flows):
        inputs = x
        # Extract Feature
        x = self.FE_forward(x)
        warped = []
        inputs_ = []
        for i in range(self.numb):
            if v == 1:
              if i > 1:
                warped.append(x[i])
                inputs_.append(inputs[i])
              else:
                warped.append(warp(x[i], flows[i]))
                inputs_.append(warp(inputs[i], flows[i]))
            elif v == 2:
              if (i == 1 or i == 3):
                warped.append(x[i])
                inputs_.append(inputs[i])
              else:
                warped.append(warp(x[i], flows[i]))
                inputs_.append(warp(inputs[i], flows[i]))
            else:
                warped.append(warp(x[i], flows[i]))
                inputs_.append(warp(inputs[i], flows[i]))

        x = torch.cat(warped, 1)
        inputs = torch.cat(inputs_, 1)
        b, c, h, w = inputs.shape

        pruning_kernel = self.Pr[v]
        weights = pruning_kernel.view(32*4, 32*4, 1, 1)
        x = F.conv2d(x, weights)
        # Refined(Mix) Feature & Get outputs
        ex = self.RefineNet_forward(x)

        x = F.pad(inputs, (self.k_size//2, self.k_size//2, self.k_size//2, self.k_size//2))
        patches = x.unfold(2, self.k_size, 1).unfold(3, self.k_size, 1)
        patches = patches.permute(0, 1, 4, 5, 2, 3).reshape(b, -1, h, w)
        output = patches.view(b, 1, c*(self.k_size**2), h, w)\
                     * ex.view(b, self.c, c*(self.k_size**2), h, w)
        return output.sum(2)

    def _initialize_weights(self):
        for name in self.FE:
            init.orthogonal_(self.FE[name].weight, init.calculate_gain('leaky_relu'))

        for name in self.RF:
            if name in 'output':
                init.orthogonal_(self.RF[name].weight)
            else:
                init.orthogonal_(self.RF[name].weight, init.calculate_gain('leaky_relu'))

    def _get_params(self):
        self.params = []
        for name in self.FE:
            self.params += list(self.FE[name].parameters())
        for name in self.RF:
            self.params += list(self.RF[name].parameters())
        #for name in self.SU_:
        self.params += list([self.Pr])

    def FeatureExtract(self, iter):
        self.FE['%d_conv1' % iter] = conv2(self.c, 32)
        self.FE['%d_conv2' % iter] = conv2(32, 32)

    def RefineNet(self):
        def RDB(name, iter):
            name = name + '_%d'
            for i in range(2):
                self.RF[name % i + '_conv1'] = conv2(64*(1+i+iter), 64)
            self.RF[name % i + '_conv'] = conv2(64*(2+i+iter), 64, kernel=1)

        self.RF['concat1'] = conv2(32*self.numb, 32*(int(self.numb**0.5)))
        self.RF['concat2'] = conv2(32*(int(self.numb**0.5)), 64)

        for i in range(2):
            RDB('RDN%d'%i, i)

        self.RF['concat3'] = conv2(192, 64, kernel=1)
        self.RF['conv1'] = conv2(64, 64)
        self.RF['conv2'] = conv2(64, 64, kernel=1)
        self.RF['conv3'] = conv2(64, 64)
        self.RF['output'] = conv2(64, self.c*(self.c*4)*9, kernel=1)

    def FE_forward(self, x):
        y = []
        for i in range(self.numb):
            x_ = x[i]
            for j in range(2):
                j += 1
                x_ = self.relu(self.FE['%d_conv%d' % (i, j)](x_))
            y.append(x_)
        return y#torch.cat(y, 1)

    def RefineNet_forward(self, x):
        def RDB(x, name):
            name = name + '_%d'
            res = x
            for i in range(2):
                x = self.relu(self.RF[name % i + '_conv1'](res))
                res = torch.cat((res, x), 1)
            x = self.relu(self.RF[name % i + '_conv'](res))
            return x

        for i in range(2):
            i += 1
            x = self.relu(self.RF['concat%d'%i](x))
        res = x
        for i in range(2):
            x = RDB(res, 'RDN%d'%i)
            res = torch.cat((res, x), 1)
        x = self.relu(self.RF['concat3'](res))
        for i in range(2):
            i += 1
            x = self.relu(self.RF['conv%d'%i](x))

        x = self.relu(self.RF['conv3'](x))
        return self.RF['output'](x)


import cv2 as cv
import numpy as np
from matplotlib.patches import Rectangle
from matplotlib.patches import Circle
from matplotlib import pyplot as plt
import matplotlib.pyplot as plt
import matplotlib.lines as mlines
from mtcnn.mtcnn import MTCNN
import math
import pandas as pd
import os

from PyQt5.QtGui import QImage
from PyQt5 import QtCore, QtGui, QtWidgets
dir_path = 's12/'
dir_path2 = 'pic/'
res = []
res2 = []
for path in os.listdir(dir_path):
    # check if current path is a file
    if os.path.isfile(os.path.join(dir_path, path)):
        res.append(dir_path + path)

for path2 in os.listdir(dir_path2):
    # check if current path is a file
    if os.path.isfile(os.path.join(dir_path2, path2)):
        res2.append(dir_path2 + path2)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(970, 841)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.comboBox = QtWidgets.QComboBox(self.centralwidget)
        self.comboBox.setGeometry(QtCore.QRect(550, 590, 161, 21))
        self.comboBox.setObjectName("comboBox")
        self.Template_but = QtWidgets.QPushButton(self.centralwidget)
        self.Template_but.setGeometry(QtCore.QRect(30, 650, 281, 51))
        self.Template_but.setStyleSheet("font: 16pt \"Lucida Console\";\n"
"background-color: rgb(0, 170, 0);")
        self.Template_but.setObjectName("Template_but")
        self.comboBox_2 = QtWidgets.QComboBox(self.centralwidget)
        self.comboBox_2.setGeometry(QtCore.QRect(170, 590, 151, 21))
        self.comboBox_2.setObjectName("comboBox_2")
        self.result = QtWidgets.QLabel(self.centralwidget)
        self.result.setGeometry(QtCore.QRect(40, 280, 741, 281))
        self.result.setObjectName("result")
        self.tmplate = QtWidgets.QLabel(self.centralwidget)
        self.tmplate.setGeometry(QtCore.QRect(10, 40, 241, 221))
        self.tmplate.setObjectName("tmplate")
        self.pictures = QtWidgets.QLabel(self.centralwidget)
        self.pictures.setGeometry(QtCore.QRect(340, 30, 361, 221))
        self.pictures.setObjectName("pictures")
        self.label_4 = QtWidgets.QLabel(self.centralwidget)
        self.label_4.setGeometry(QtCore.QRect(300, 230, 101, 21))
        font = QtGui.QFont()
        font.setPointSize(11)
        font.setBold(True)
        font.setWeight(75)
        self.label_4.setFont(font)
        self.label_4.setStyleSheet("\n"
"background-color: rgb(85, 170, 255);")
        self.label_4.setFrameShape(QtWidgets.QFrame.Box)
        self.label_4.setLineWidth(-1)
        self.label_4.setObjectName("label_4")
        self.label_5 = QtWidgets.QLabel(self.centralwidget)
        self.label_5.setGeometry(QtCore.QRect(20, 10, 101, 21))
        font = QtGui.QFont()
        font.setPointSize(11)
        font.setBold(True)
        font.setWeight(75)
        self.label_5.setFont(font)
        self.label_5.setStyleSheet("\n"
"background-color: rgb(85, 170, 255);")
        self.label_5.setFrameShape(QtWidgets.QFrame.Box)
        self.label_5.setLineWidth(-1)
        self.label_5.setObjectName("label_5")
        self.label_6 = QtWidgets.QLabel(self.centralwidget)
        self.label_6.setGeometry(QtCore.QRect(350, 10, 101, 21))
        font = QtGui.QFont()
        font.setPointSize(11)
        font.setBold(True)
        font.setWeight(75)
        self.label_6.setFont(font)
        self.label_6.setStyleSheet("\n"
"background-color: rgb(85, 170, 255);")
        self.label_6.setFrameShape(QtWidgets.QFrame.Box)
        self.label_6.setLineWidth(-1)
        self.label_6.setObjectName("label_6")
        self.label_7 = QtWidgets.QLabel(self.centralwidget)
        self.label_7.setGeometry(QtCore.QRect(160, 550, 181, 21))
        font = QtGui.QFont()
        font.setPointSize(11)
        font.setBold(True)
        font.setWeight(75)
        self.label_7.setFont(font)
        self.label_7.setStyleSheet("\n"
"background-color: rgb(85, 170, 255);")
        self.label_7.setFrameShape(QtWidgets.QFrame.Box)
        self.label_7.setLineWidth(-1)
        self.label_7.setObjectName("label_7")
        self.label_8 = QtWidgets.QLabel(self.centralwidget)
        self.label_8.setGeometry(QtCore.QRect(550, 550, 181, 21))
        font = QtGui.QFont()
        font.setPointSize(11)
        font.setBold(True)
        font.setWeight(75)
        self.label_8.setFont(font)
        self.label_8.setStyleSheet("\n"
"background-color: rgb(85, 170, 255);")
        self.label_8.setFrameShape(QtWidgets.QFrame.Box)
        self.label_8.setLineWidth(-1)
        self.label_8.setObjectName("label_8")
        self.Viola_but = QtWidgets.QPushButton(self.centralwidget)
        self.Viola_but.setGeometry(QtCore.QRect(340, 650, 281, 51))
        self.Viola_but.setStyleSheet("font: 16pt \"Lucida Console\";\n"
"background-color: rgb(0, 170, 0);")
        self.Viola_but.setObjectName("Viola_but")
        self.Sim_but = QtWidgets.QPushButton(self.centralwidget)
        self.Sim_but.setGeometry(QtCore.QRect(670, 650, 281, 51))
        self.Sim_but.setStyleSheet("font: 16pt \"Lucida Console\";\n"
"background-color: rgb(0, 170, 0);")
        self.Sim_but.setObjectName("Sim_but")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 970, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        ##кнопка для темплейт метода
        self.Template_but.clicked.connect(self.showPicts)

        ##кнопка для виола  метода
        self.Viola_but.clicked.connect(self.showViola)

        ##кнопка для вывода симметрии
        self.Sim_but.clicked.connect(self.showSim)
        ##add items
        self.comboBox_2.addItems(res)

        ##add items
        self.comboBox.addItems(res2)
        ##Вывод изображение из выпадающего окна
        pixmap = QtGui.QPixmap(self.comboBox.currentText())
        pixmap2 = pixmap.scaled(256, 256, QtCore.Qt.KeepAspectRatio)
        self.tmplate.setPixmap(pixmap2)
        ##Вывод изображение из выпадающего окна
        self.pictures.setPixmap(QtGui.QPixmap(self.comboBox_2.currentText()))

        ##Вывод изображение из выпадающего окна
        self.comboBox.currentIndexChanged.connect(self.on_combobox_changed)
    def on_combobox_changed(self):
        pixmap = QtGui.QPixmap(self.comboBox.currentText())
        pixmap2 = pixmap.scaled(256, 256, QtCore.Qt.KeepAspectRatio)
        self.pictures.setPixmap(pixmap2)

        ##Вывод изображение из выпадающего окна
        self.comboBox_2.currentIndexChanged.connect(self.on_combobox_changed_2)
    def on_combobox_changed_2(self):
        pixmap = QtGui.QPixmap(self.comboBox_2.currentText())
        pixmap2 = pixmap.scaled(256, 256, QtCore.Qt.KeepAspectRatio)
        self.tmplate.setPixmap(pixmap2)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.Template_but.setText(_translate("MainWindow", "Template метод"))
        self.result.setText(_translate("MainWindow", "Result"))
        self.tmplate.setText(_translate("MainWindow", "template"))
        self.pictures.setText(_translate("MainWindow", "pictures"))
        self.label_4.setText(_translate("MainWindow", "результат"))
        self.label_5.setText(_translate("MainWindow", "Шаблон"))
        self.label_6.setText(_translate("MainWindow", "Картинка"))
        self.label_7.setText(_translate("MainWindow", "Выбрать картинку 1"))
        self.label_8.setText(_translate("MainWindow", "Выбрать картинку 2"))
        self.Viola_but.setText(_translate("MainWindow", "Метод Виолы-Джонса"))
        self.Sim_but.setText(_translate("MainWindow", "Линии симметрии"))
    ##Показать темлейт метод
    def showPicts(self):
        self.template(self.comboBox_2.currentText(),self.comboBox.currentText())

    ##Показать  метод виолы джонсон
    def showViola(self):
        self.Viola_J(self.comboBox_2.currentText())

    def showSim(self):
        self.sim(self.comboBox_2.currentText())
    def template(self,temp,pic):
        img_rgb = cv.imread(pic)
        img_gray = cv.cvtColor(img_rgb, cv.COLOR_BGR2GRAY)
        template = cv.imread(temp,0)
        # crop_img = template[40:95,10:80]
        w, h = template.shape[::-1]
        res = cv.matchTemplate(img_gray,template,cv.TM_CCOEFF_NORMED)
        threshold = 0.7
        loc = np.where( res >= threshold)
        for pt in zip(*loc[::-1]):
            cv.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)
        # cv.imwrite('res.png',img_rgb)
        frame = cv.cvtColor(img_rgb, cv.COLOR_BGR2RGB)
        image = QImage(frame, frame.shape[1], frame.shape[0], frame.strides[0], QImage.Format_RGB888)
        pixmap = QtGui.QPixmap(image)
        pixmap2 = pixmap.scaled(256, 256, QtCore.Qt.KeepAspectRatio)
        self.result.setPixmap(pixmap2)

    def Viola_J(self, temp):

        face_cascade = cv.CascadeClassifier('cascade/haarcascade_frontalface_default.xml')
        eyes_cascade = cv.CascadeClassifier('cascade/haarcascade_eye.xml')
        smile_cascade = cv.CascadeClassifier('cascade/haarcascade_smile.xml')
        glass_cascade = cv.CascadeClassifier('cascade/haarcascade_eye_tree_eyeglasses.xml')
        img_rgb = cv.imread(temp)
        img_gray = cv.cvtColor(img_rgb, cv.COLOR_BGR2GRAY)
        faces = face_cascade.detectMultiScale(img_gray, 1.3, 5)
        eyes = eyes_cascade.detectMultiScale(img_gray, 1.3, 5)
        smile = smile_cascade.detectMultiScale(img_gray, 1.3, 5)
        glass = glass_cascade.detectMultiScale(img_gray, 1.3, 5)
        for (x, y, w, h) in faces:
            cv.rectangle(img_rgb, (x, y), (x+w, y+h), (255, 0, 0), 2)
        # for (ex, ey, ew, eh) in eyes:
        #     cv.rectangle(img_rgb, (ex, ey), (ex + ew, ey + eh), (255, 0, 0), 2)
        for (ex, ey, ew, eh) in smile:
            cv.rectangle(img_rgb,(ex,ey),(ex+ew,ey+eh), (255,0,0),2)
        for (ex, ey, ew, eh) in glass:
            cv.rectangle(img_rgb,(ex,ey),(ex+ew,ey+eh), (255,0,0),2)
        frame = cv.cvtColor(img_rgb, cv.COLOR_BGR2RGB)
        image = QImage(frame, frame.shape[1], frame.shape[0], frame.strides[0], QImage.Format_RGB888)
        pixmap = QtGui.QPixmap(image)
        pixmap2 = pixmap.scaled(256, 256, QtCore.Qt.KeepAspectRatio)
        self.result.setPixmap(pixmap2)

        ##Линии симметрии

    def sim(self,filename):
        test = []
        img_rgb = cv.imread(filename)
        detector = MTCNN()
        faces = detector.detect_faces(img_rgb)
        data = plt.imread(filename)
        plt.imshow(data)
        for result in faces:
            for key, value in result['keypoints'].items():
                if key == 'left_eye':
                    test.append(value)
                if key == 'right_eye':
                    test.append(value)
        x, y, width, height = result['box']
        rect = Rectangle((x, y), width, height, fill=False, color='red')
        new_array = [n for tup in test for n in tup]
        mid_x = (new_array[0] + new_array[2]) / 2
        mid_y = (new_array[1] + new_array[3]) / 2
        dist_x = math.sqrt((new_array[0] - mid_x)**2+(new_array[1] - mid_y)**2)
        ax = plt.gca()
        # горизонтальная
        l = ax.axline([new_array[0], new_array[1]], [new_array[2], new_array[3]])
        ax.add_patch(rect)
        # ##основная симметричная
        l2 = ax.axline([x + width/2,y + height], [mid_x, mid_y])
        # ##дополнительная симметричная
        # l3 = ax.axvline(new_nose[0] + dist_x)
        # l4 = ax.axvline(new_nose[0] - dist_x)
        l3 = ax.axline([new_array[0], new_array[1]],[x + width/2- dist_x,y + height])
        l4 = ax.axline([new_array[2], new_array[3]], [x + width / 2 + dist_x, y + height])
        ###prochee
        # l2 = ax.axline([new_nose[0], new_nose[1]], [mid_x, mid_y])
        # l2 = mlines.Line2D([new_nose[0], mid_x ], [new_nose[1], mid_y])
        ax.add_line(l)
        ax.add_line(l2)
        ax.add_line(l3)
        ax.add_line(l4)
        plt.show()


from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
    QMetaObject, QObject, QPoint, QRect,
    QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
    QFont, QFontDatabase, QGradient, QIcon,
    QImage, QKeySequence, QLinearGradient, QPainter,
    QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QAbstractButton, QApplication, QDialog, QDialogButtonBox,
    QLabel, QSizePolicy, QSpacerItem, QVBoxLayout,
    QWidget)

class Ui_Dialog(object):
    def setupUi(self, Dialog):
        if not Dialog.objectName():
            Dialog.setObjectName(u"Dialog")
        Dialog.resize(400, 307)
        self.root_layout = QVBoxLayout(Dialog)
        self.root_layout.setObjectName(u"root_layout")
        self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)

        self.root_layout.addItem(self.verticalSpacer)

        self.warning_label = QLabel(Dialog)
        self.warning_label.setObjectName(u"warning_label")
        self.warning_label.setStyleSheet(u"QLabel  { color : red; }")

        self.root_layout.addWidget(self.warning_label)

        self.button_box = QDialogButtonBox(Dialog)
        self.button_box.setObjectName(u"button_box")
        self.button_box.setOrientation(Qt.Horizontal)
        self.button_box.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok)

        self.root_layout.addWidget(self.button_box)

        self.retranslateUi(Dialog)
        self.button_box.accepted.connect(Dialog.accept)
        self.button_box.rejected.connect(Dialog.reject)

        QMetaObject.connectSlotsByName(Dialog)
    # setupUi

    def retranslateUi(self, Dialog):
        Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"Dialog", None))
        self.warning_label.setText("")
    # retranslateUi


from PVG          import *

canvas = Canvas()

paths  = svgPaths("flower.svg")
silhouettes = [path.silhouette() for path in paths]
for (silhouette,ccolor) in lzip(silhouettes,[Color.green(0.5),Color.red(0.5),Color.yellow(0.5)]):
    canvas.draw(silhouette.polygon(),ccolor)
    canvas.draw([Circle(p,10.0) for p in silhouette.polygon().points(100)],ccolor.a(1.0))

canvas.save("main_curvepoints.png")


import os
import numpy as np
import math
import re
import scipy.linalg as spla
from scipy import interpolate
from scipy import linalg

######################################################
######################################################
### generate infile for solve_general_EV
######################################################
######################################################
def generate_ccm_in_file(file_path,vec_input,particle_num,matter_type,density,nmax,cal_type):
    with open(file_path,'w') as f_1:
        f_1.write('!Chiral order for Deltas(LO = 0,NLO=2,NNLO=3,N3LO=4) and cutoff'+'\n')
        f_1.write('3, 450\n')
        f_1.write('! cE and cD 3nf parameters:'+'\n' )
        f_1.write('%.12f, %.12f\n' % (vec_input[0],vec_input[1]))
        f_1.write('! LEC ci \n')
        f_1.write('%.12f, %.12f, %.12f, %.12f \n' % (vec_input[2],vec_input[3],vec_input[4],vec_input[5]))
        f_1.write('!c1s0 & c3s1 \n')
        f_1.write('%.12f, %.12f, %.12f, %.12f, %.12f, %.12f \n' % (vec_input[6],vec_input[7],vec_input[8],vec_input[9],vec_input[9],vec_input[9]))
        f_1.write('! cnlo(7) \n')
        f_1.write('%.12f, %.12f, %.12f, %.12f, %.12f, %.12f, %.12f \n' % (vec_input[10],vec_input[11],vec_input[12],vec_input[13],vec_input[14],vec_input[15],vec_input[16]))
        f_1.write('! number of particles'+'\n')
        f_1.write('%d\n' % (particle_num) )
        f_1.write('! specify: pnm/snm, input type: density/kfermi'+'\n')
        f_1.write(matter_type+', density'+'\n')
        f_1.write('! specify boundary conditions (PBC/TABC/TABCsp/subspace_cal/subspace_cal_dens/solve_general_EV)'+'\n')
        f_1.write('%s\n' %(cal_type) )
        f_1.write('! dens/kf, ntwist,  nmax'+'\n')
        f_1.write('%.12f, 1, %d\n' % (density, nmax))
        f_1.write('! specify cluster approximation: CCD, CCDT'+'\n')
        f_1.write('CCD(T)'+'\n')
        f_1.write('! tnf switch (T/F) and specify 3nf approximation: 0=tnf0b, 1=tnf1b, 2=tnf2b'+'\n')
        f_1.write('T, 3'+'\n')
        f_1.write('! 3nf cutoff(MeV),non-local reg. exp'+'\n')
        f_1.write('450, 3'+'\n')

######################################################
######################################################
### read LECs set from file
######################################################
######################################################
def read_LEC_1(LEC_num,file_path):
    LEC = np.zeros(LEC_num)
    with open(file_path,'r') as f_1:
        count = len(open(file_path,'rU').readlines())
        data = f_1.readlines()
        wtf = re.match('#', 'abc',flags=0)
        for loop1 in range(0,count):
            if ( re.search('cE and cD', data[loop1],flags=0) != wtf):
                temp_1 = re.findall(r"[-+]?\d+\.?\d*",data[loop1+1])
                LEC[0] = float(temp_1[0])
                LEC[1] = float(temp_1[1])
            if ( re.search('LEC ci', data[loop1],flags=0) != wtf):
                temp_1 = re.findall(r"[-+]?\d+\.?\d*",data[loop1+1])
                LEC[2] = float(temp_1[0])
                LEC[3] = float(temp_1[1])
                LEC[4] = float(temp_1[2])
                LEC[5] = float(temp_1[3])
            if ( re.search('c1s0 & c3s1', data[loop1],flags=0) != wtf):
                temp_1 = re.findall(r"[-+]?\d+\.?\d*",data[loop1+1])
                LEC[6] = float(temp_1[0])
                LEC[7] = float(temp_1[1])
                LEC[8] = float(temp_1[2])
                LEC[9] = float(temp_1[3])
            if ( re.search('cnlo', data[loop1],flags=0) != wtf):
                temp_1 = re.findall(r"[-+]?\d+\.?\d*",data[loop1+1])
                LEC[10] = float(temp_1[0])
                LEC[11] = float(temp_1[1])
                LEC[12] = float(temp_1[2])
                LEC[13] = float(temp_1[3])
                LEC[14] = float(temp_1[4])
                LEC[15] = float(temp_1[5])
                LEC[16] = float(temp_1[6])
    return LEC

def read_LEC_2(file_path):
    LEC = np.zeros(LEC_num)
    with open(file_path,'r') as f_1:
        count = len(open(file_path,'rU').readlines())
        data = f_1.readlines()
        wtf = re.match('#', 'abc',flags=0)
        for loop1 in range(0,count):
            if ( re.search('cD,cE', data[loop1],flags=0) != wtf):
                temp_1 = re.findall(r"[-+]?\d+\.?\d*",data[loop1])
                LEC[0] = float(temp_1[0])
                LEC[1] = float(temp_1[1])
            if ( re.search('LEC=', data[loop1],flags=0) != wtf):
                temp_1 = re.findall(r"[-+]?\d+\.?\d*",data[loop1])
                LEC[2] = float(temp_1[0])
                LEC[3] = float(temp_1[1])
                LEC[4] = float(temp_1[2])
                LEC[5] = float(temp_1[3])
            if ( re.search('c1s0, c3s1', data[loop1],flags=0) != wtf):
                temp_1 = re.findall(r"[-+]?\d+\.?\d*",data[loop1])
                LEC[6] = float(temp_1[4])
                LEC[7] = float(temp_1[5])
                LEC[8] = float(temp_1[6])
                LEC[9] = float(temp_1[7])
            if ( re.search('cnlo_pw', data[loop1],flags=0) != wtf):
                temp_1 = re.findall(r"[-+]?\d+\.?\d*",data[loop1])
                LEC[10] = float(temp_1[2])
                LEC[11] = float(temp_1[3])
                LEC[12] = float(temp_1[4])
                LEC[13] = float(temp_1[5])
                LEC[14] = float(temp_1[6])
                LEC[15] = float(temp_1[7])
                LEC[16] = float(temp_1[8])
    return LEC

######################################################
######################################################
### read sm output wave function
######################################################
######################################################
def read_sm_vec(vec_num,vec_dimension,sm_vec,database_dir):
    for loop1 in range(vec_num):
        file_path = database_dir + str(loop1+1)+"_sm.txt"
        with open(file_path,'r') as f_1:
           count = len(open(file_path,'rU').readlines())
           data = f_1.readlines()
           wtf = re.match('#', 'abc',flags=0)
           for loop2 in range(0,vec_dimension):
               temp_1 = re.findall(r"[-+]?\d+\.?\d*",data[loop2])
               sm_vec[loop1][loop2] = float(temp_1[0])

######################################################
######################################################
### read ccm_nuclear_matter output (CCD energy)
######################################################
######################################################
def read_nucl_matt_out(file_path):  # converge: flag = 1    converge: flag =0
    with open(file_path,'r') as f_1:
        converge_flag = int (1)
        count = len(open(file_path,'rU').readlines())
        #if ( count > 1500 ):
        #    converge_flag =int (0)
        data =  f_1.readlines()
        wtf = re.match('#', 'abc',flags=0)
        ccd = 0
        for loop1 in range(0,count):
            if ( re.search('CCD energy', data[loop1],flags=0) != wtf):
                temp_1 = re.findall(r"[-+]?\d+\.?\d*",data[loop1])
                ccd = float(temp_1[0])
        return ccd   #,converge_flag
        #print ('No "E/A" found in the file:'+file_path)
        #return float('nan')

######################################################
######################################################
### call CCM_nuclear_matter
######################################################
######################################################
def nuclear_matter(vec_input):
    neutron_num  = 14
    particle_num = 28
    density      = 0.16
    density_min  = 0.14
    density_max  = 0.22
    nmax         = 2
    #snm_dens    = np.zeros(5)
    #snm_energy_per_nucleon = np.zeros(5)
    #snm_dens_new = np.zeros(interpolation_count)
    #snm_energy_per_nucleon_new = np.zeros(interpolation_count)

    nucl_matt_in_dir   = './ccm_in_pnm_%.2f' % (density)
    nucl_matt_out_dir  = './pnm_rho_%.2f.out' % (density)

    generate_ccm_in_file(nucl_matt_in_dir,vec_input,neutron_num,'pnm',density,nmax,"PBC")
    os.system('./'+nucl_matt_exe+' '+nucl_matt_in_dir+' > '+nucl_matt_out_dir)
    ccd = read_nucl_matt_out(nucl_matt_out_dir)
    print ("ccd energy from real CC calculation: "+str(ccd))
    return ccd

def test_2():
    print("wtf")


# !/usr/bin/env python
from baselines.common import set_global_seeds, tf_util as U
import gym, logging
from baselines import logger
from half_cheetah import *

def train(env_id, num_timesteps, seed, num_options,app, saves ,wsaves, epoch,dc,plots,w_intfc,switch,mainlr,intlr,piolr,fewshot,k):
    from baselines.ppoc_int import mlp_policy, pposgd_simple
    U.make_session(num_cpu=1).__enter__()
    set_global_seeds(seed)

    if env_id=="TMaze":
        from twod_tmaze import TMaze
        env=TMaze()
        env.seed(seed)
    else:
        env = gym.make(env_id)
        env._seed(seed)

    def policy_fn(name, ob_space, ac_space):
        return mlp_policy.MlpPolicy(name=name, ob_space=ob_space, ac_space=ac_space,
            hid_size=64, num_hid_layers=2, num_options=num_options, dc=dc, w_intfc=w_intfc,k=k)

    gym.logger.setLevel(logging.WARN)

    if num_options ==1:
        optimsize=64
    elif num_options ==2:
        optimsize=32
    else:
        optimsize=int(64/num_options)

    num_timesteps = num_timesteps #if env_id!="TMaze" else 5e5
    tperbatch = 2048 if not epoch else int(1e4)
    pposgd_simple.learn(env, policy_fn,
            max_timesteps=num_timesteps,
            timesteps_per_batch=tperbatch,
            clip_param=0.2, entcoeff=0.0,
            optim_epochs=10, optim_stepsize=mainlr, optim_batchsize=optimsize,
            gamma=0.99, lam=0.95, schedule='constant', num_options=num_options,
            app=app, saves=saves, wsaves=wsaves, epoch=epoch, seed=seed,dc=dc,plots=plots,
            w_intfc=w_intfc,switch=switch,intlr=intlr,piolr=piolr,fewshot=fewshot,k=k
        )
    env.close()

def main():
    import argparse
    parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('--env', help='environment ID', default='TMaze')
    parser.add_argument('--timesteps', help='number of timesteps', type=int, default=1e6)
    parser.add_argument('--seed', help='RNG seed', type=int, default=1)
    parser.add_argument('--opt', help='number of options', type=int, default=2)
    parser.add_argument('--app', help='Append to folder name', type=str, default='')
    parser.add_argument('--saves', help='Save the returns at each iteration', dest='saves', action='store_true', default=False)
    parser.add_argument('--wsaves', help='Save the weights',dest='wsaves', action='store_true', default=False)
    parser.add_argument('--plots',  help='Plot some visualization', dest='plots', action='store_true', default=False)
    parser.add_argument('--switch', help='Switch task after 150 iterations', dest='switch', action='store_true', default=False)
    parser.add_argument('--fewshot', help='Value learning after 150 iterations', dest='fewshot', action='store_true', default=False)
    parser.add_argument('--nointfc', help='Disables interet functions', dest='w_intfc', action='store_false', default=True)
    parser.add_argument('--epoch', help='Load weights from a certain epoch', type=int, default=0)
    parser.add_argument('--dc', help='Deliberation cost  (not used)', type=float, default=0.)
    parser.add_argument('--mainlr', type=float, default=3e-4)
    parser.add_argument('--intlr', type=float, default=1e-4)
    parser.add_argument('--piolr', type=float, default=1e-4)
    parser.add_argument('--k', type=float, default=0., help='threshold for interest function')

    args = parser.parse_args()

    train(args.env, num_timesteps=args.timesteps, seed=args.seed, num_options=args.opt, app=args.app,
     saves=args.saves, wsaves=args.wsaves, epoch=args.epoch,dc=args.dc,plots=args.plots,
     w_intfc=args.w_intfc,switch=args.switch,mainlr=args.mainlr,intlr=args.intlr,piolr=args.piolr,fewshot=args.fewshot,k=args.k)

if __name__ == '__main__':
    main()


import numpy as np
import sklearn

def hueristic_value_fscore(feature_num, dataset, targets):
    roads_E = np.zeros(feature_num*feature_num*4, dtype="float64").reshape(4, feature_num, feature_num)

#     arr = np.corrcoef(dataset)
#     R = abs(arr)

    ## F-score :
    classes = np.unique(targets)
    class_num = len(classes)
    total_mean_f = dataset.mean(0)
    nominator = 0
    denominator = 0

#     nominator = np.zeros(feature_num, dtype="int64")
#     denominator = np.zeros(feature_num, dtype="int64")

    sample_num_of_this_tag = np.zeros(class_num, dtype="int64")
    for i in range(0, class_num):
        tags = np.zeros((len(targets)), dtype="int64")
        bool_arr = np.equal(targets, classes[i])
        tags[bool_arr] = 1
        sample_num_of_this_tag[i] = np.sum(tags)
        dataset_only_class = dataset[bool_arr, :]
        class_mean_f = dataset_only_class.mean(0)
        class_mean_f = np.round(class_mean_f, decimals=4)

        nominator = nominator + np.power(np.subtract(class_mean_f, total_mean_f), 2)
        denominator = denominator + sum(np.power(np.subtract(dataset_only_class, np.matlib.repmat(total_mean_f, dataset_only_class.shape[0],1)), 2)) / (sample_num_of_this_tag[i]-1)

    F_score = np.divide(nominator, denominator)

    roads_E[0, :, :] = (0.5/feature_num) * sum(F_score)
    roads_E[1, :, :] = np.matlib.repmat(F_score, feature_num, 1)

    roads_E[2, :, :] = (0.5/feature_num) * sum(F_score)
    roads_E[3, :, :] = np.matlib.repmat(F_score, feature_num, 1)

    return roads_E

def heuristic_value_min_redundency(feature_num, dataset):
    roads_E = np.zeros(feature_num*feature_num*4, dtype="float64").reshape(4, feature_num, feature_num)
    arr = np.corrcoef(dataset.T)
    R = abs(arr)

    roads_E[0, :, :] = R
    roads_E[1, :, :] = 1 - R

    roads_E[2, :, :] = R
    roads_E[3, :, :] = 1 - R
    return roads_E

def heuristic_value_min_redundency_max_relevence(feature_num, dataset):
    roads_E = np.zeros(feature_num*feature_num*4, dtype="float64").reshape(4, feature_num, feature_num)
    class_corrs = np.zeros(feature_num, dtype="float64")
    arr = np.corrcoef(dataset.T)
    R = abs(arr)

    for i in range(0, feature_num):
        class_corrs[i] = abs(np.corrcoef(dataset.T[i, :], targets)[0, 1])

    class_corr_sel = np.matlib.repmat(class_corrs, feature_num, 1)
    class_corr_desel = np.matlib.repmat(1-class_corrs, feature_num, 1)

    roads_E[0, :, :] = np.sqrt(np.multiply(R, class_corr_desel))
    roads_E[1, :, :] = np.sqrt(np.multiply(1-R, class_corr_sel))

    roads_E[2, :, :] = np.sqrt(np.multiply(R, class_corr_desel))
    roads_E[3, :, :] = np.sqrt(np.multiply(1-R, class_corr_sel))
    return roads_E

def heuristic_value_method_4(feature_num, dataset):
    roads_E = np.zeros(feature_num*feature_num*4, dtype="float64").reshape(4, feature_num, feature_num)
    class_corrs = np.zeros(feature_num, dtype="float64")
    arr = np.corrcoef(dataset.T)
    R = abs(arr)

    # has problem (i don know MI and it's getting values bigger than 1 ...)
    for i in range(0, feature_num):
        class_corrs[i] = abs(np.corrcoef(dataset.T[i, :], targets)[0, 1])

    class_corr_sel = np.matlib.repmat(class_corrs, feature_num, 1)
    class_corr_desel = np.matlib.repmat(1-class_corrs, feature_num, 1)

    roads_E[0, :, :] = class_corr_desel
    roads_E[1, :, :] = class_corr_sel

    roads_E[2, :, :] = R
    roads_E[3, :, :] = 1 - R

    return roads_E

def heuristic_value_mutual_info(feature_num, dataset):
    roads_E = np.zeros(feature_num*feature_num*4, dtype="float64").reshape(4, feature_num, feature_num)
    mutual_f_f = np.zeros(feature_num*feature_num, dtype="float64").reshape(feature_num, feature_num)

    for i in range(0, feature_num):
        for j in range(0, feature_num):
            if(i == j):
                mutual_f_f[i, j] = 1
            else:
                mutual_f_f[i, j] = sklearn.metrics.normalized_mutual_info_score(dataset[:, i], dataset[:, j])

#     print(mutual_f_f)
    roads_E[0, :, :] = mutual_f_f
    roads_E[1, :, :] = 1 - mutual_f_f

    roads_E[2, :, :] = mutual_f_f
    roads_E[3, :, :] = 1 - mutual_f_f

    return roads_E


from fastapi import FastAPI, Depends
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession

from app import schemas, service, models, exeptions

app = FastAPI()

@app.get("/clients", response_model=list[schemas.Client])
async def get_cities(session: AsyncSession = Depends(models.get_session)):
    clients = await service.get_clients(session)
    return [schemas.Client(id=c.id) for c in clients]

@app.post("/clients")
async def add_city(session: AsyncSession = Depends(models.get_session)):
    client = service.add_client(session)
    try:
        await session.commit()
        return client
    except IntegrityError:
        await session.rollback()
        raise exeptions.DuplicatedEntryError("The client is already stored")

if __name__ == '__main__':
    import uvicorn

    uvicorn.run(app)


# Python imports
import os
import sys
# Flask
from flask import jsonify, make_response, send_from_directory
from flask_graphql import GraphQLView
from flask_cors import CORS
# Local
from modules import logger
from modules.app import create_app
from modules.app.database import db_session, init_db
from modules.app.schema import schema

app = create_app()
app.debug = True

default_query = '''
{
  Users {
    edges {
      node {
        id,
        username,
        email,
        password
        blog {
          id,
          title,
          text
        },
        role {
          id,
          name
        }
      }
    }
  }
}
'''.strip()

"""
:ROOT_PATH : Set root path
:PUBLIC_PATH : Always for joining react public index.html to ROOT_PATH
"""
ROOT_PATH = os.path.dirname(os.path.realpath(__file__))
os.environ.update({'ROOT_PATH': ROOT_PATH})
PUBLIC_PATH = os.path.join(ROOT_PATH, 'modules', 'client', 'public')

''' Set the view for Graphiql '''
view_func = GraphQLView.as_view(
    'graphql', schema=schema, graphiql=True)

""" logger object to output info and debug information """
LOG = logger.get_root_logger(os.environ.get(
    'ROOT_LOGGER', 'root'), filename=os.path.join(ROOT_PATH, 'output.log'))

PORT = os.environ.get('PORT')

app.add_url_rule('/graphql', view_func=view_func)

""" Sets routes for Flask """
@app.errorhandler(404)
def not_found(error):
    """ error handler """
    LOG.error(error)
    return make_response(jsonify({'error': 'Not Found'}), 404)

@app.route('/')
def index():
    """ serve index.html """
    return send_from_directory(PUBLIC_PATH, 'index.html')

@app.route('/login')
def login():
    """ serve index.html """
    return send_from_directory(PUBLIC_PATH, 'index.html')

@app.route('/register')
def register():
    """ serve route to register to index.html """
    return send_from_directory(PUBLIC_PATH, 'index.html')

@app.route('/<path:path>')
def static_proxy(path):
    """
    static folder serve
    :param path: to load all static files in `public`
    :return: the directory `public` with filename i.e. 404.html
    """
    file_name = path.split('/')[-1]
    dir_name = os.path.join(PUBLIC_PATH, '/'.join(path.split('/')[:-1]))
    return send_from_directory(dir_name, file_name)

@app.teardown_appcontext
def shutdown_session(exception=None):
    db_session.remove()

if __name__ == "__main__":
    init_db()
    CORS(app, resources={r'/graphql': {'origins': '*'}})
    LOG.info('running environment: {}'.format(os.environ.get('ENV')))
    app.config['DEBUG'] = os.environ.get('ENV') == 'development'
    app.run(host='0.0.0.0', port=int(PORT))


# -*- coding: utf-8 -*-
"""
This script runs GLM for conductiong RSA.
The most important difference is that predictor definition is based on the RSA interest.
Each condition for calculating the RDM is modeled as a single predictor
Another important difference is that no spatial smoothing is applied, because RSA wants to look at activation patterns.
If smoothing is added, the voxel pattern correlation between conditions is very high

Computing RDM from ROIs is added at the end of the pipeline,
but could be treated as a separate step.

"""
import os
import pandas as pd
import numpy as np
#%%
base_root = '/home/rj299/scratch60/mdm_analysis/'
data_root = '/home/rj299/scratch60/mdm_analysis/data_rename'
out_root = '/home/rj299/scratch60/mdm_analysis/output'

# base_root = 'D:\Ruonan\Projects in the lab\MDM Project\Medical Decision Making Imaging\MDM_imaging\Imaging Analysis\RA_PTSD_SPM'
# data_root = 'D:\Ruonan\Projects in the lab\MDM Project\Medical Decision Making Imaging\MDM_imaging\Imaging Analysis\data_rename'
# out_root = 'D:\Ruonan\Projects in the lab\MDM Project\Medical Decision Making Imaging\MDM_imaging\Imaging Analysis\output'

#%%
from nipype.interfaces import spm

import nipype.interfaces.io as nio  # Data i/o
import nipype.interfaces.utility as util  # utility
import nipype.pipeline.engine as pe  # pypeline engine
#import nipype.algorithms.rapidart as ra  # artifact detection
import nipype.algorithms.modelgen as model  # model specification
#from nipype.algorithms.rapidart import ArtifactDetect
# from nipype.algorithms.misc import Gunzip
from nipype import Node, Workflow, MapNode
from nipype.interfaces import fsl

from nipype.interfaces.matlab import MatlabCommand

import nibabel as nib
from nilearn.input_data import NiftiMasker

#%%
MatlabCommand.set_default_paths('/home/rj299/project/MATLAB/toolbox/spm12/') # set default SPM12 path in my computer.
fsl.FSLCommand.set_default_output_type('NIFTI_GZ')

data_dir = data_root
output_dir = os.path.join(out_root, 'imaging')
work_dir = os.path.join(base_root, 'work') # intermediate products

#subject_list = [2073, 2550, 2582, 2583, 2584, 2585, 2588, 2592, 2593, 2594,
#           2596, 2597, 2598, 2599, 2600, 2624, 2650, 2651, 2652, 2653,
#           2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661, 2662, 2663,
#           2664, 2665, 2666]

#subject_list = [2073, 2550, 2582, 2583, 2584, 2585, 2588]
#subject_list = [2592, 2593, 2594, 2596, 2597, 2598, 2599, 2600, 2624, 2650, 2651, 2652, 2653, 2654, 2655, 2656]
subject_list = [2657, 2658, 2659, 2660, 2661, 2662, 2663, 2664, 2665, 2666]

# task_id = [1,2]

tr = 1
# first sevetal scans to delete
del_scan = 10

# Map field names to individual subject runs.
# infosource = pe.Node(util.IdentityInterface(fields=['subject_id', 'task_id'],),
#                   name="infosource")

# infosource.iterables = [('subject_id', subject_list),
#                         ('task_id', task_list)]

infosource = pe.Node(util.IdentityInterface(fields=['subject_id'],),
                  name="infosource")

infosource.iterables = [('subject_id', subject_list)]

#%%

#in_file = '/home/rj299/project/mdm_analysis/data_rename/sub-2073/ses-1/func/sub-2073_ses-1_task-3_space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz'
#events_file = '/home/rj299/project/mdm_analysis/output/event_files/sub-2073_task-3_cond.csv'
#regressors_file = '/home/rj299/project/mdm_analysis/data_rename/sub-2073/ses-1/func/sub-2073_ses-1_task-3_desc-confounds_regressors.tsv'

def _bids2nipypeinfo(in_file, events_file, regressors_file,
                     regressors_names=None,
                     motion_columns=None,
                     decimals=3, amplitude=1.0, del_scan=10):
    from pathlib import Path
    import numpy as np
    import pandas as pd
    from nipype.interfaces.base.support import Bunch

    # Process the events file
    events = pd.read_csv(events_file, sep=r'\s+')

    bunch_fields = ['onsets', 'durations', 'amplitudes']

    if not motion_columns:
        from itertools import product
        motion_columns = ['_'.join(v) for v in product(('trans', 'rot'), 'xyz')]

    out_motion = Path('motion.par').resolve()

    regress_data = pd.read_csv(regressors_file, sep=r'\s+')
    np.savetxt(out_motion, regress_data[motion_columns].fillna(0.0).values[del_scan:,], '%g')
#     np.savetxt(out_motion, regress_data[motion_columns].fillna(0.0).values, '%g')

    if regressors_names is None:
        regressors_names = sorted(set(regress_data.columns) - set(motion_columns))

    if regressors_names:
        bunch_fields += ['regressor_names']
        bunch_fields += ['regressors']

    domain = list(set(events.condition.values))[0] # domain of this task run, should be only one, 'Mon' or 'Med'
    trial_types = list(set(events.trial_type.values))
#    outcome_levels = list(set(events.vals.values))
    outcome_levels = {'0': 5, '1': 8, '2': 12, '3': 25}
    conds = [domain + '_' + trial_type for trial_type in trial_types] # e.g. ['Med_risk', 'Med_ambig']
    conditions = []
    for cond in conds:
        for outcome_level in list(outcome_levels.keys()):
            conditions.append(cond + '_' + outcome_level)

    runinfo = Bunch(
        scans=in_file,
        conditions=conditions, # should be 8 conditions (2 x 4)
        # conditions = ['Med_amb', 'Med_risk', 'Mon_amb', 'Mon_risk'],
        **{k: [] for k in bunch_fields})

    for condition in runinfo.conditions:

        event = events[(events.trial_type.str.match(condition[4:len(condition)-2])) & (events.vals == outcome_levels[condition[-1:]])]
        runinfo.onsets.append(np.round(event.onset.values - del_scan + 1, 3).tolist()) # take out the first several deleted scans
        runinfo.durations.append(np.round(event.duration.values, 3).tolist())
        if 'amplitudes' in events.columns:
            runinfo.amplitudes.append(np.round(event.amplitudes.values, 3).tolist())
        else:
            runinfo.amplitudes.append([amplitude] * len(event))

        # if domain == condition[:3]:
        #     event = events[events.trial_type.str.match(condition[4:])]
        #     runinfo.onsets.append(np.round(event.onset.values - del_scan + 1, 3).tolist()) # take out the first several deleted scans
        #     runinfo.durations.append(np.round(event.duration.values, 3).tolist())
        #     if 'amplitudes' in events.columns:
        #         runinfo.amplitudes.append(np.round(event.amplitudes.values, 3).tolist())
        #     else:
        #         runinfo.amplitudes.append([amplitude] * len(event))

        # else: # empty conditions
        #     runinfo.onsets.append([])
        #     runinfo.durations.append([])
        #     runinfo.amplitudes.append([])

    # delete empty condition, if any
    cond_idx = 0
    while cond_idx < len(runinfo.conditions):
        if not runinfo.onsets[cond_idx]:
            runinfo.conditions.pop(cond_idx)
            runinfo.onsets.pop(cond_idx)
            runinfo.durations.pop(cond_idx)
            runinfo.amplitudes.pop(cond_idx)
        else:
            cond_idx += 1

    # response predictor regardless of condition
    runinfo.conditions.append('Resp')

    # response predictor when there is a button press
    resp_mask = events.resp != 2
    resp_onset= np.round(events.resp_onset.values[resp_mask] - del_scan + 1, 3).tolist()
    runinfo.onsets.append(resp_onset)
    runinfo.durations.append([0] * len(resp_onset))
    runinfo.amplitudes.append([amplitude] * len(resp_onset))

    if 'regressor_names' in bunch_fields:
        runinfo.regressor_names = regressors_names
        runinfo.regressors = regress_data[regressors_names].fillna(0.0).values[del_scan:,].T.tolist()

    return runinfo, str(out_motion)

#r_temp, o_temp = _bids2nipypeinfo(in_file, events_file, regressors_file,
#                     regressors_names=None,
#                     motion_columns=None,
#                     decimals=3, amplitude=1.0, del_scan=10)
#%%
templates = {'func': os.path.join(data_root, 'sub-{subject_id}', 'ses-1', 'func', 'sub-{subject_id}_ses-1_task-{task_id}_space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz'),
             'mask': os.path.join(data_root, 'sub-{subject_id}', 'ses-1', 'func', 'sub-{subject_id}_ses-1_task-{task_id}_space-MNI152NLin2009cAsym_desc-brain_mask.nii.gz'),
             'regressors': os.path.join(data_root, 'sub-{subject_id}', 'ses-1', 'func', 'sub-{subject_id}_ses-1_task-{task_id}_desc-confounds_regressors.tsv'),
             'events': os.path.join(out_root, 'event_files', 'sub-{subject_id}_task-{task_id}_cond_v3.csv')}

# Flexibly collect data from disk to feed into workflows.
selectfiles = pe.Node(nio.SelectFiles(templates,
                      base_directory=data_root),
                      name="selectfiles")

selectfiles.inputs.task_id = [1,2,3,4,5,6,7,8]

# Extract motion parameters from regressors file
runinfo = MapNode(util.Function(
    input_names=['in_file', 'events_file', 'regressors_file', 'regressors_names', 'motion_columns'],
    function=_bids2nipypeinfo, output_names=['info', 'realign_file']),
    name='runinfo',
    iterfield = ['in_file', 'events_file', 'regressors_file'])

# Set the column names to be used from the confounds file
# reference a paper from podlrack lab
runinfo.inputs.regressors_names = ['std_dvars', 'framewise_displacement'] + \
                                  ['a_comp_cor_%02d' % i for i in range(6)]

runinfo.inputs.motion_columns   = ['trans_x', 'trans_x_derivative1', 'trans_x_derivative1_power2', 'trans_x_power2'] + \
                                  ['trans_y', 'trans_y_derivative1', 'trans_y_derivative1_power2', 'trans_y_power2'] + \
                                  ['trans_z', 'trans_z_derivative1', 'trans_z_derivative1_power2', 'trans_z_power2'] + \
                                  ['rot_x', 'rot_x_derivative1', 'rot_x_derivative1_power2', 'rot_x_power2'] + \
                                  ['rot_y', 'rot_y_derivative1', 'rot_y_derivative1_power2', 'rot_y_power2'] + \
                                  ['rot_z', 'rot_z_derivative1', 'rot_z_derivative1_power2', 'rot_z_power2']

#%%
# gunzip = MapNode(Gunzip(), name='gunzip', iterfield=['in_file'])

# delete first several scans
# def extract_all(in_files):
#     from nipype.interfaces import fsl
#     roi_files = []
#     for in_file in in_files:
#         roi_file = fsl.ExtractROI(in_file = in_file, t_min = 10, t_size = -1, output_type = 'NIFTI')
#         roi_files.append(roi_file)
#     return roi_files

# extract = pe.Node(util.Function(
#         input_names = ['in_files'],
#         function = extract_all, output_names = ['roi_files']),
#         name = 'extract')

extract = pe.MapNode(fsl.ExtractROI(), name="extract", iterfield = ['in_file'])
extract.inputs.t_min = del_scan
extract.inputs.t_size = -1
extract.inputs.output_type='NIFTI'

# set contrasts, depend on the condition
contrasts = []
all_conditions = ['Med_amb_0', 'Med_amb_1', 'Med_amb_2', 'Med_amb_3',
          'Med_risk_0', 'Med_risk_1', 'Med_risk_2', 'Med_risk_3',
          'Mon_amb_0', 'Mon_amb_1', 'Mon_amb_2', 'Mon_amb_3',
          'Mon_risk_0', 'Mon_risk_1', 'Mon_risk_2', 'Mon_risk_3']

for (cond_idx, single_condition) in enumerate(all_conditions):
    contrast_vector = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    contrast_vector[cond_idx] = 1
    contrasts.append([single_condition, 'T',
                      all_conditions,
                      contrast_vector])

# no need to include the response contrast because it is not interest of analysis
# if included, the compute_roi_rdm needs to be adjusted, becasue it now takes all
# contrasts passed from contrast estimate and iterate through. Reponse contrast should bot be included
#contrasts.append(['Response','T', ['Resp'], [1]])

# e.g. a single contrast should be:
#cont1 = ['Med_amb_0', 'T',
#         ['Med_amb_0', 'Med_amb_1', 'Med_amb_2', 'Med_amb_3',
#          'Med_risk_0', 'Med_risk_1', 'Med_risk_2', 'Med_risk_3',
#          'Mon_amb_0', 'Mon_amb_1', 'Mon_amb_2', 'Mon_amb_3',
#          'Mon_risk_0', 'Mon_risk_1', 'Mon_risk_2', 'Mon_risk_3'],
#         [1, 0, 0, 0,
#          0, 0, 0, 0,
#          0, 0, 0, 0,
#          0, 0, 0, 0]]

#%%

modelspec = Node(interface=model.SpecifySPMModel(), name="modelspec")
modelspec.inputs.concatenate_runs = False
modelspec.inputs.input_units = 'scans' # supposedly it means tr
modelspec.inputs.output_units = 'scans'
#modelspec.inputs.outlier_files = '/media/Data/R_A_PTSD/preproccess_data/sub-1063_ses-01_task-3_bold_outliers.txt'
modelspec.inputs.time_repetition = 1.  # make sure its with a dot
modelspec.inputs.high_pass_filter_cutoff = 128.

level1design = pe.Node(interface=spm.Level1Design(), name="level1design") #, base_dir = '/media/Data/work')
level1design.inputs.timing_units = modelspec.inputs.output_units
level1design.inputs.interscan_interval = 1.
level1design.inputs.bases = {'hrf': {'derivs': [0, 0]}}
level1design.inputs.model_serial_correlations = 'AR(1)'

# create workflow
wfSPM_rsa = Workflow(name="l1spm_resp_rsa_nosmooth", base_dir=work_dir)
wfSPM_rsa.connect([
        (infosource, selectfiles, [('subject_id', 'subject_id')]),
        (selectfiles, runinfo, [('events','events_file'),('regressors','regressors_file')]),
        (selectfiles, extract, [('func','in_file')]),
        (extract, runinfo, [('roi_file','in_file')]),
        (extract, modelspec, [('roi_file', 'functional_runs')]),
        (runinfo, modelspec, [('info', 'subject_info'), ('realign_file', 'realignment_parameters')]),

        ])
wfSPM_rsa.connect([(modelspec, level1design, [("session_info", "session_info")])])

#%%
level1estimate = pe.Node(interface=spm.EstimateModel(), name="level1estimate")
level1estimate.inputs.estimation_method = {'Classical': 1}

contrastestimate = pe.Node(
    interface=spm.EstimateContrast(), name="contrastestimate")
#contrastestimate.inputs.contrasts = contrasts
contrastestimate.overwrite = True
contrastestimate.config = {'execution': {'remove_unnecessary_outputs': False}}
contrastestimate.inputs.contrasts = contrasts

wfSPM_rsa.connect([
         (level1design, level1estimate, [('spm_mat_file','spm_mat_file')]),
         (level1estimate, contrastestimate,
            [('spm_mat_file', 'spm_mat_file'), ('beta_images', 'beta_images'),
            ('residual_image', 'residual_image')]),
    ])

#%% Adding data sink
########################################################################
# Datasink
datasink = Node(nio.DataSink(base_directory=os.path.join(output_dir, 'Sink_resp_rsa_nosmooth')),
                                         name="datasink")

wfSPM_rsa.connect([
        (level1estimate, datasink, [('beta_images',  '1stLevel.@betas.@beta_images'),
                                    ('residual_image', '1stLevel.@betas.@residual_image'),
                                    ('residual_images', '1stLevel.@betas.@residual_images'),
                                    ('SDerror', '1stLevel.@betas.@SDerror'),
                                    ('SDbetas', '1stLevel.@betas.@SDbetas'),
                ])
        ])

wfSPM_rsa.connect([
       # here we take only the contrast ad spm.mat files of each subject and put it in different folder. It is more convenient like that.
       (contrastestimate, datasink, [('spm_mat_file', '1stLevel.@spm_mat'),
                                              ('spmT_images', '1stLevel.@T'),
                                              ('con_images', '1stLevel.@con'),
                                              ('spmF_images', '1stLevel.@F'),
                                              ('ess_images', '1stLevel.@ess'),
                                              ])
        ])

#%% Compute ROI RDM

def compute_roi_rdm(in_file,
                    stims,
                    all_masks):

    from pathlib import Path
    from nilearn.input_data import NiftiMasker
    import numpy as np
    import nibabel as nib

    rdm_out = Path('roi_rdm.npy').resolve()
    stim_num = len(stims)

    # dictionary to store rdms for all rois
    rdm_dict = {}

    # loop over all rois
    for mask_name in all_masks.keys():
        mask = all_masks[mask_name]
        masker = NiftiMasker(mask_img=mask)

        # initiate matrix
        spmt_allstims_roi= np.zeros((stim_num, np.sum(mask.get_data())))

        for (stim_idx, spmt_file) in enumerate(in_file):
            spmt = nib.load(spmt_file)

            # get each condition's beta
            spmt_roi = masker.fit_transform(spmt)
            spmt_allstims_roi[stim_idx, :] = spmt_roi

        # create rdm
        rdm_roi = 1 - np.corrcoef(spmt_allstims_roi)

        rdm_dict[mask_name] = rdm_roi

    # save
    np.save(rdm_out, rdm_dict)

    return str(rdm_out)

get_roi_rdm = Node(util.Function(
    input_names=['in_file', 'stims', 'all_masks'],
    function=compute_roi_rdm,
    output_names=['rdm_out']),
    name='get_roi_rdm',
    )

get_roi_rdm.inputs.stims = {'01': 'Med_amb_0', '02': 'Med_amb_1', '03': 'Med_amb_2', '04': 'Med_amb_3',
                            '05': 'Med_risk_0', '06': 'Med_risk_1', '07': 'Med_risk_2', '08': 'Med_risk_3',
                            '09': 'Mon_amb_0', '10': 'Mon_amb_1', '11': 'Mon_amb_2', '12': 'Mon_amb_3',
                            '13': 'Mon_risk_0', '14': 'Mon_risk_1', '15': 'Mon_risk_2', '16': 'Mon_risk_3'}

# Masker files
maskfile_vmpfc = os.path.join(output_dir, 'binConjunc_PvNxDECxRECxMONxPRI_vmpfc.nii.gz')
maskfile_vstr = os.path.join(output_dir, 'binConjunc_PvNxDECxRECxMONxPRI_striatum.nii.gz')
maskfile_roi1 = os.path.join(output_dir, 'none_glm_Med_Mon_TFCE_p005_roi1.nii.gz')
maskfile_roi2 = os.path.join(output_dir, 'none_glm_Med_Mon_TFCE_p005_roi2.nii.gz')
maskfile_roi3 = os.path.join(output_dir, 'none_glm_Med_Mon_TFCE_p005_roi3.nii.gz')

maskfiles = {'vmpfc': maskfile_vmpfc,
             'vstr': maskfile_vstr,
             'med_mon_1': maskfile_roi1,
             'med_mon_2': maskfile_roi2,
             'med_mon_3': maskfile_roi3}

# roi inputs are loaded images
get_roi_rdm.inputs.all_masks = {key_name: nib.load(maskfiles[key_name]) for key_name in maskfiles.keys()}

wfSPM_rsa.connect([
        (contrastestimate, get_roi_rdm, [('spmT_images', 'in_file')]),
        ])

#%% data sink rdm
# Datasink
datasink_rdm = Node(nio.DataSink(base_directory=os.path.join(output_dir, 'Sink_resp_rsa_nosmooth')),
                                         name="datasink_rdm")

wfSPM_rsa.connect([
        (get_roi_rdm, datasink_rdm, [('rdm_out', 'rdm.@rdm')]),
        ])

#%%
wfSPM_rsa.write_graph(graph2use = 'flat')

# # wfSPM.write_graph("workflow_graph.dot", graph2use='colored', format='png', simple_form=True)
# # wfSPM.write_graph(graph2use='orig', dotfilename='./graph_orig.dot')
# %matplotlib inline
# from IPython.display import Image
# %matplotlib qt
# Image(filename = '/home/rj299/project/mdm_analysis/work/l1spm/graph.png')

#%% run
wfSPM_rsa.run('MultiProc', plugin_args={'n_procs': 4})
#wfSPM_rsa.run(plugin='Linear', plugin_args={'n_procs': 1})


"""Copy new images from google images to original dataset"""
from pathlib import Path
from shutil import copy

cwd = Path.cwd()
data_dir = cwd.parent / 'data' / 'stanford-car-dataset-by-classes-folder'
original_train_dir = data_dir / 'car_data' / 'train'
original_test_dir = data_dir / 'car_data' / 'test'
new_data_dir = data_dir / 'car_data' / 'new_data_cleaned'
new_train_dir = data_dir / 'car_data_new_data_in_train' / 'train'
new_test_dir = data_dir / 'car_data_new_data_in_train' / 'test'

if __name__ == '__main__':
    for folder in new_data_dir.iterdir():
        if folder.is_dir():
            for image in folder.glob('*.jpg'):
                copy(str(image), str(new_train_dir / folder.stem / image.name))


# -*- coding: utf-8 -*-
from numpy import sqrt as npSqrt
from .wma import wma
from pandas_ta.utils import get_offset, verify_series

def hma(close, length=None, offset=None, **kwargs):
    """Indicator: Hull Moving Average (HMA)"""
    # Validate Arguments
    length = int(length) if length and length > 0 else 10
    close = verify_series(close, length)
    offset = get_offset(offset)

    if close is None: return

    # Calculate Result
    half_length = int(length / 2)
    sqrt_length = int(npSqrt(length))

    wmaf = wma(close=close, length=half_length)
    wmas = wma(close=close, length=length)
    hma = wma(close=2 * wmaf - wmas, length=sqrt_length)

    # Offset
    if offset != 0:
        hma = hma.shift(offset)

    # Handle fills
    if "fillna" in kwargs:
        hma.fillna(kwargs["fillna"], inplace=True)
    if "fill_method" in kwargs:
        hma.fillna(method=kwargs["fill_method"], inplace=True)

    # Name & Category
    hma.name = f"HMA_{length}"
    hma.category = "overlap"

    return hma

hma.__doc__ = \
"""Hull Moving Average (HMA)

The Hull Exponential Moving Average attempts to reduce or remove lag in moving
averages.

Sources:
    https://alanhull.com/hull-moving-average

Calculation:
    Default Inputs:
        length=10
    WMA = Weighted Moving Average
    half_length = int(0.5 * length)
    sqrt_length = int(sqrt(length))

    wmaf = WMA(close, half_length)
    wmas = WMA(close, length)
    HMA = WMA(2 * wmaf - wmas, sqrt_length)

Args:
    close (pd.Series): Series of 'close's
    length (int): It's period. Default: 10
    offset (int): How many periods to offset the result. Default: 0

Kwargs:
    fillna (value, optional): pd.DataFrame.fillna(value)
    fill_method (value, optional): Type of fill method

Returns:
    pd.Series: New feature generated.
"""


import fnmatch
import logging
import os

from . import armbian_utils as armbian_utils

log: logging.Logger = logging.getLogger("aggregation_utils")

AGGREGATION_SEARCH_ROOT_ABSOLUTE_DIRS = []
DEBOOTSTRAP_SEARCH_RELATIVE_DIRS = []
CLI_SEARCH_RELATIVE_DIRS = []
DESKTOP_ENVIRONMENTS_SEARCH_RELATIVE_DIRS = []
DESKTOP_APPGROUPS_SEARCH_RELATIVE_DIRS = []
SELECTED_CONFIGURATION = None
DESKTOP_APPGROUPS_SELECTED = []
SRC = None

# Hack: this shouldn't be a global.
ALL_POTENTIAL_PATHS_PACKAGES = []

def calculate_potential_paths(root_dirs, relative_dirs, sub_dirs, artifact_file, initial_paths=None):
	if initial_paths is None:
		potential_paths = {"paths": []}
	else:
		potential_paths = initial_paths
	for root_dir in root_dirs:
		for rel_dir in relative_dirs:
			for sub_dir in sub_dirs:
				looked_for_file = f"{root_dir}/{rel_dir}/{sub_dir}/{artifact_file}"
				# simplify the path, removing any /./ or /../
				potential_paths["paths"].append(os.path.normpath(looked_for_file))
	# print(f"DEBUG Potential paths: {potential_paths['paths']}")
	return potential_paths

def process_common_path_for_potentials(potential_paths):
	# find the common prefix across potential_paths, and remove it from all paths.
	potential_paths["common_path"] = SRC + "/"  # os.path.commonprefix(potential_paths["paths"])
	potential_paths["paths"] = [path[len(potential_paths["common_path"]):] for path in potential_paths["paths"]]
	return potential_paths

def get_all_potential_paths_packages():
	# return ALL_POTENTIAL_PATHS_PACKAGES sorted alphabetically
	return sorted(ALL_POTENTIAL_PATHS_PACKAGES)

def aggregate_packages_from_potential(potential_paths):
	aggregation_results = {}  # {"potential_paths": potential_paths}
	for path in potential_paths["paths"]:
		# Add to global, for listing all potential paths for packages:
		ALL_POTENTIAL_PATHS_PACKAGES.append(path)

		full_path = potential_paths["common_path"] + path
		if not os.path.isfile(full_path):
			# print(f"Skipping {path}, not a file")
			continue

		# Resolve the real path of the file, eliminating symlinks; remove the common prefix again.
		resolved_path = os.path.realpath(full_path)[len(potential_paths["common_path"]):]
		# the path in the debugging information is either just the path, or the symlink indication.
		symlink_to = None if resolved_path == path else resolved_path
		# print(f"Reading {path}")
		with open(full_path, "r") as f:
			line_counter = 0
			for line in f:
				line_counter += 1
				line = line.strip()
				if line == "" or line.startswith("#"):
					continue
				if line not in aggregation_results:
					aggregation_results[line] = {"content": line, "refs": []}
				aggregation_results[line]["refs"].append(
					{"path": path, "line": line_counter, "symlink_to": symlink_to})
	return aggregation_results

def aggregate_simple_contents_potential(potential_paths):
	aggregation_results = {}  # {"potential_paths": potential_paths}
	for path in potential_paths["paths"]:
		full_path = potential_paths["common_path"] + path
		if not os.path.isfile(full_path):
			continue

		# Resolve the real path of the file, eliminating symlinks; remove the common prefix again.
		resolved_path = os.path.realpath(full_path)[len(potential_paths["common_path"]):]
		# the path in the debugging information is either just the path, or the symlink indication.
		symlink_to = None if resolved_path == path else resolved_path

		# Read the full contents of the file full_path as a string
		with open(full_path, "r") as f:
			contents = f.read()
		aggregation_results[path] = {"contents": contents, "refs": []}
		aggregation_results[path]["refs"].append({"path": path, "symlink_to": symlink_to})
	return aggregation_results

def find_files_in_directory(directory, glob_pattern):
	files = []
	for root, dir_names, filenames in os.walk(directory):
		for filename in fnmatch.filter(filenames, glob_pattern):
			files.append(os.path.join(root, filename))
	return files

def aggregate_apt_sources(potential_paths):
	aggregation_results = {}  # {"potential_paths": potential_paths}
	for path in potential_paths["paths"]:
		full_path = potential_paths["common_path"] + path
		if not os.path.isdir(full_path):
			continue
		# Resolve the real path of the file, eliminating symlinks; remove the common prefix again.
		resolved_path = os.path.realpath(full_path)[len(potential_paths["common_path"]):]
		# the path in the debugging information is either just the path, or the symlink indication.
		symlink_to = None if resolved_path == path else resolved_path

		# find *.source in the directory
		files = find_files_in_directory(full_path, "*.source")
		for full_filename in files:
			source_name = os.path.basename(full_filename)[:-7]
			base_path = os.path.relpath(full_filename[:-len(".source")], SRC)
			if source_name not in aggregation_results:
				aggregation_results[source_name] = {"content": base_path, "refs": []}
			aggregation_results[source_name]["refs"].append({"path": path, "symlink_to": symlink_to})
	return aggregation_results

def remove_common_path_from_refs(merged):
	all_paths = []
	for item in merged:
		for ref in merged[item]["refs"]:
			if ref["path"].startswith("/"):
				all_paths.append(ref["path"])
	common_path = os.path.commonprefix(all_paths)
	for item in merged:
		for ref in merged[item]["refs"]:
			if ref["path"].startswith("/"):
				# remove the prefix
				ref["path"] = ref["path"][len(common_path):]
	return merged

# Let's produce a list from the environment variables, complete with the references.
def parse_env_for_list(env_name, fixed_ref=None):
	env_list = armbian_utils.parse_env_for_tokens(env_name)
	if fixed_ref is None:
		refs = armbian_utils.parse_env_for_tokens(env_name + "_REFS")
		# Sanity check: the number of refs should be the same as the number of items in the list.
		if len(env_list) != len(refs):
			raise Exception(f"Expected {len(env_list)} refs for {env_name}, got {len(refs)}")
		# Let's parse the refs; they are in the form of "function:path:line"
		parsed_refs = []
		for ref in refs:
			split = ref.split(":")
			# sanity check, make sure we have 3 parts
			if len(split) != 3:
				raise Exception(f"Expected 3 parts in ref {ref}, got {len(split)}")
			parsed_refs.append({"function": split[0], "path": split[1], "line": split[2]})
	else:
		parsed_refs = [fixed_ref] * len(env_list)
	# Now create a dict; duplicates should be eliminated, and their refs merged.
	merged = {}
	for i in range(len(env_list)):
		item = env_list[i]
		if item in merged:
			merged[item]["refs"].append(parsed_refs[i])
		else:
			merged[item] = {"content": item, "refs": [parsed_refs[i]]}
	return remove_common_path_from_refs(merged)

def merge_lists(base, extra, optype="add"):
	merged = {}
	for item in base:
		merged[item] = base[item]
		if "status" not in merged[item]:
			merged[item]["status"] = "added"
		# loop over the refs, and mark them as "initial"
		for ref in merged[item]["refs"]:
			# if the key 'status' is not present, add it
			if "operation" not in ref:
				ref["operation"] = "initial"
	for item in extra:
		for ref in extra[item]["refs"]:
			# if the key 'status' is not present, add it
			if "operation" not in ref:
				ref["operation"] = optype
		if item in merged:
			resulting = base[item]
			resulting["refs"] += extra[item]["refs"]
			merged[item] = resulting
		else:
			merged[item] = extra[item]
		merged[item]["status"] = optype
	return merged

def aggregate_all_debootstrap(artifact, aggregation_function=aggregate_packages_from_potential):
	potential_paths = calculate_potential_paths(
		AGGREGATION_SEARCH_ROOT_ABSOLUTE_DIRS, DEBOOTSTRAP_SEARCH_RELATIVE_DIRS,
		[".", f"config_{SELECTED_CONFIGURATION}"], artifact)
	return aggregation_function(process_common_path_for_potentials(potential_paths))

def aggregate_all_cli(artifact, aggregation_function=aggregate_packages_from_potential):
	potential_paths = calculate_potential_paths(
		AGGREGATION_SEARCH_ROOT_ABSOLUTE_DIRS, CLI_SEARCH_RELATIVE_DIRS,
		[".", f"config_{SELECTED_CONFIGURATION}"], artifact)
	return aggregation_function(process_common_path_for_potentials(potential_paths))

def aggregate_all_desktop(artifact, aggregation_function=aggregate_packages_from_potential):
	potential_paths = calculate_potential_paths(
		AGGREGATION_SEARCH_ROOT_ABSOLUTE_DIRS, DESKTOP_ENVIRONMENTS_SEARCH_RELATIVE_DIRS, ["."], artifact)
	potential_paths = calculate_potential_paths(
		AGGREGATION_SEARCH_ROOT_ABSOLUTE_DIRS, DESKTOP_APPGROUPS_SEARCH_RELATIVE_DIRS,
		DESKTOP_APPGROUPS_SELECTED, artifact, potential_paths)
	return aggregation_function(process_common_path_for_potentials(potential_paths))

def join_refs_for_bash_single_string(refs):
	single_line_refs = []
	for ref in refs:
		if "operation" in ref and "line" in ref:
			one_line = ref["operation"] + ":" + ref["path"] + ":" + str(ref["line"])
		else:
			one_line = ref["path"]
		if "symlink_to" in ref:
			if ref["symlink_to"] is not None:
				one_line += ":symlink->" + ref["symlink_to"]
		single_line_refs.append(one_line)
	return " ".join(single_line_refs)

# @TODO this is shit make it less shit urgently
def join_refs_for_markdown_single_string(refs):
	single_line_refs = []
	for ref in refs:
		one_line = f"  - `"
		if "operation" in ref and "line" in ref:
			one_line += ref["operation"] + ":" + ref["path"] + ":" + str(ref["line"])
		else:
			one_line += ref["path"]
		if "symlink_to" in ref:
			if ref["symlink_to"] is not None:
				one_line += ":symlink->" + ref["symlink_to"]
		one_line += "`\n"
		single_line_refs.append(one_line)
	return "".join(single_line_refs)

def only_names_not_removed(merged_list):
	return [key for key in merged_list if merged_list[key]["status"] != "remove"]

def prepare_bash_output_array_for_list(
	bash_writer, md_writer, output_array_name, merged_list, extra_dict_function=None):
	md_writer.write(f"### `{output_array_name}`\n")

	values_list = []
	explain_dict = {}
	extra_dict = {}
	for key in merged_list:
		value = merged_list[key]
		# print(f"key: {key}, value: {value}")
		refs = value["refs"]
		md_writer.write(f"- `{key}`: *{value['status']}*\n" + join_refs_for_markdown_single_string(refs))
		refs_str = join_refs_for_bash_single_string(refs)  # join the refs with a comma
		explain_dict[key] = refs_str
		if value["status"] != "remove":
			values_list.append(key)
			if extra_dict_function is not None:
				extra_dict[key] = extra_dict_function(value["content"])

	# prepare the values as a bash array definition.
	# escape each value with double quotes, and join them with a space.
	values_list_bash = "\n".join([f"\t'{value}'" for value in values_list])
	actual_var = f"declare -r -g -a {output_array_name}=(\n{values_list_bash}\n)\n"

	# Some utilities (like debootstrap) want a list that is comma separated.
	# Since that subject to infernal life in bash, let's do it here.
	values_list_comma = ",".join(values_list)
	comma_var = f"declare -r -g -a {output_array_name}_COMMA='{values_list_comma}'\n"

	explain_list_bash = "\n".join([f"\t['{value}']='{explain_dict[value]}'" for value in explain_dict.keys()])
	explain_var = f"declare -r -g -A {output_array_name}_EXPLAIN=(\n{explain_list_bash}\n)\n"

	# @TODO also an array with all the elements in explain; so we can do a for loop over it.
	extra_dict_decl = ""
	if len(extra_dict) > 0:
		extra_list_bash = "\n".join([f"\t['{value}']='{extra_dict[value]}'" for value in extra_dict.keys()])
		extra_dict_decl = f"declare -r -g -A {output_array_name}_DICT=(\n{extra_list_bash}\n)\n"

	final_value = actual_var + "\n" + extra_dict_decl + "\n" + comma_var + "\n" + explain_var
	bash_writer.write(final_value)

	# return some statistics for the summary
	return {"number_items": len(values_list)}

def prepare_bash_output_single_string(output_array_name, merged_list):
	values_list = []
	for key in merged_list:
		value = merged_list[key]
		refs_str = join_refs_for_bash_single_string(value["refs"])
		# print(f"key: {key}, value: {value}")
		values_list.append("### START Source: " + refs_str + "\n" + value[
			"contents"] + "\n" + "### END Source: " + refs_str + "\n\n")

	values_list_bash = "\n".join(values_list)
	if (len(values_list_bash) == 0):
		values_list_bash = "### NO sources found during aggregation.\n"
	return bash_string_multiline(output_array_name, values_list_bash)

def bash_string_multiline(var_name, contents):
	return f"declare -g {var_name}\n{var_name}=\"$(cat <<-'EOD_{var_name}_EOD'\n{contents}\nEOD_{var_name}_EOD\n)\"\n\n"

def encode_source_base_path_extra(contents_dict):
	return contents_dict