import pygame as pg
import os
from random import randint

import pygame.mixer

from MAPS.world import *
from MENU.menu import *
from PLAYER.player import *

#TODO: Retocar las animaciones de jump off y slide

pg.font.init()

# CONSTANTS, IMAGES AND GAME VARIABLES

# screen specs for menu

SCREEN_WIDTH, SCREEN_HEIGHT = 1280, 720
SCREEN = pg.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pg.display.set_caption("GUNS & BOOM")

CLOCK = pg.time.Clock()

SELECTION_FONT = pg.font.SysFont('comicsans', 45)
ITEMS_FONT = pg.font.SysFont('comicsans', 120)
LIFE_FONT = pg.font.SysFont('comicsans', 60)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

# MENU IMAGES
INITIAL_INTERFACE = pg.image.load(os.path.join('SPRITES-INTERFACES-EFFECTS/INTERFACES/initial.png'))
MENU_INTERFACE = pg.image.load(os.path.join('SPRITES-INTERFACES-EFFECTS/INTERFACES/menu.png'))
CHOOSE_CHARACTER_INTERFACE = pg.image.load(os.path.join('SPRITES-INTERFACES-EFFECTS/INTERFACES/choose-character.png'))
CHOOSE_MAP_INTERFACE = pg.image.load(os.path.join('SPRITES-INTERFACES-EFFECTS/INTERFACES/choose-map.png'))
HELP_INTERFACE = pg.image.load(os.path.join('SPRITES-INTERFACES-EFFECTS/INTERFACES/help.png'))
CHOOSE_ITEMS_INTERFACE = pg.image.load(os.path.join('SPRITES-INTERFACES-EFFECTS/INTERFACES/choose_items.png'))
PAUSED_GAME_INTERFACE = pg.image.load(os.path.join('SPRITES-INTERFACES-EFFECTS/INTERFACES/gamePaused.png'))

# MAPS IMAGES
FOREST_WORLD_BACKGROUND = pg.image.load(os.path.join('SPRITES-INTERFACES-EFFECTS/MAPAS/MAPA #1/Map#1.png'))
ICE_WORLD_BACKGROUND = pg.image.load(os.path.join('SPRITES-INTERFACES-EFFECTS/MAPAS/MAPA #2/Map#2.png'))

#WIN IMAGES
PLAYER1_WINS = pg.image.load(os.path.join('SPRITES-INTERFACES-EFFECTS/INTERFACES/player1-win.png'))
PLAYER2_WINS = pg.image.load(os.path.join('SPRITES-INTERFACES-EFFECTS/INTERFACES/player2-win.png'))
BOTH_DIED = pg.image.load(os.path.join('SPRITES-INTERFACES-EFFECTS/INTERFACES/draw-win.png'))

#SOUND
controler = randint(0,2)
if controler == 0:
    MAP_SOUND = pygame.mixer.Sound( f'SPRITES-INTERFACES-EFFECTS/SOUND EFFECTS/Boss-Fight.wav' )
elif controler == 1:
    MAP_SOUND = pygame.mixer.Sound( f'SPRITES-INTERFACES-EFFECTS/SOUND EFFECTS/Common-Fight.wav' )
elif controler == 2:
    MAP_SOUND = pygame.mixer.Sound( f'SPRITES-INTERFACES-EFFECTS/SOUND EFFECTS/New-Hope.wav' )

# - FPS
FPS = 60

# PLAYERS, MAP
# CHOSEN PLAYERS
# [P1,P2]
CHOSEN_PLAYERS = [None, None]
MAP = [None, None]
POTIONS = [None, None]

# ------------------------------------------------------------------------------------------------------------------------
# Functions

def drawPlayerChoose(characterSelected, playerSelectionCounter):
    draw_text = SELECTION_FONT.render("PLAYER " + str(playerSelectionCounter), 1, WHITE)

    if characterSelected == "NINJA-MALE":
        SCREEN.blit(draw_text, (64, 558))
    elif characterSelected == "NINJA-FEMALE":
        SCREEN.blit(draw_text, (380, 555))
    elif characterSelected == "ROBOT":
        SCREEN.blit(draw_text, (692, 558))
    elif characterSelected == "ZOMBIE-FEMALE":
        SCREEN.blit(draw_text, (991, 553))

    pg.display.update()

def drawMapChoose(menuObject):
    menuObject.drawChooseMapInterface(SCREEN)
    mapName = ""
    coordinates = ()
    if MAP[1] == "FOREST":
        mapName = "FOREST"
        coordinates = (185, 509)
    elif MAP[1] == "ICE":
        mapName = "ICE"
        coordinates = (821, 509)
    draw_text = SELECTION_FONT.render(mapName, 1, WHITE)
    SCREEN.blit(draw_text, coordinates)

def drawItemChoose(option):
    global SCREEN

    coordinates = ()

    if option == "DAMAGE":
        coordinates = (254, 274)
    elif option == "LIFE":
        coordinates = (752, 274)

    draw_text_damage_potion = ITEMS_FONT.render('X', 1, BLACK)
    SCREEN.blit(draw_text_damage_potion, coordinates)

def confirmCharacterSelection(characterSelected, selectionsCounter, keys_pressed):
    if keys_pressed[0] and selectionsCounter == 1:  # Player 1 confirms its selection
        CHOSEN_PLAYERS[selectionsCounter - 1] = characterSelected
        return True
    if keys_pressed[1] and selectionsCounter == 2:  # Player 2 confirms its selection
        CHOSEN_PLAYERS[selectionsCounter - 1] = characterSelected
        return True

    return False

def isContinueButtonPressed(coordinate_x, coordinate_y):
    if 970 <= coordinate_x <= 1258 and 631 <= coordinate_y <= 700:
        print("CONTINUAR")
        return True
    else:
        return False

def isPressedGoBackButton(coordinates_x, coordinates_y):
    if 41 <= coordinates_x <= 158 and 34 <= coordinates_y <= 147:
        print("DEVOLVERSE")
        return True
    else:
        return False

def isGamePaused(coordinate_x, coordinate_y, world):
    if world == "FOREST":
        return True if 12 <= coordinate_x <= 71 and 12 <= coordinate_y <= 61 else False
    elif world == "ICE":
        return True if 6 <= coordinate_x <= 69 and 9 <= coordinate_y <= 63 else False

def handlePausedGame():
    global SCREEN
    run = True

    while run:
        SCREEN.blit(PAUSED_GAME_INTERFACE, (SCREEN_WIDTH/2-423, 100))
        pg.display.update()
        for event in pg.event.get():
            if event.type == pg.KEYDOWN:
                if event.key == pg.K_y:
                    return False
                elif event.key == pg.K_n:
                    return True

def managePlaySection(menuObject):
    global CHOSEN_PLAYERS
    print("-SELECCIONAR PERSONAJE")
    menuObject.drawChooseCharacterInterface(SCREEN)
    run = True
    selectionsCounter = 1
    characterSelected = 0
    keys_pressed = []
    pageDirection = ""
    while run:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                run = False
                pg.quit()
            if event.type == pg.MOUSEBUTTONDOWN:
                coordinate_x, coordinate_y = event.pos
                if isPressedGoBackButton(coordinate_x, coordinate_y):
                    pageDirection = "MENU"
                    run = False
                else:
                    if isContinueButtonPressed(coordinate_x, coordinate_y):
                        if CHOSEN_PLAYERS[0] is not None and CHOSEN_PLAYERS[1] is not None:
                            pageDirection = "MAP"
                            run = False
                            print("Ya hay personajes seleccionados")
                        else:
                            print("No hay personajes seleccionados")
                        # else que indique que seleccione personaje
                    elif 36 <= coordinate_x <= 1248 and 215 <= coordinate_y <= 592:
                        if selectionsCounter <= 2:
                            # MALE-NINJA CHOSEN
                            if 54 <= coordinate_x <= 310 and 234 <= coordinate_y <= 580:
                                characterSelected = "NINJA-MALE"
                                # FEMALE-NINJA CHOSEN
                            elif 367 <= coordinate_x <= 624 and 238 <= coordinate_y <= 567:
                                characterSelected = "NINJA-FEMALE"
                                # ROBOT CHOSEN
                            elif 685 <= coordinate_x <= 920 and 241 <= coordinate_y <= 571:
                                characterSelected = "ROBOT"
                                # FEMALE-ZOMBIE CHOSEN
                            elif 981 <= coordinate_x <= 1222 and 237 <= coordinate_y <= 575:
                                characterSelected = "ZOMBIE-FEMALE"
            if event.type == pg.KEYDOWN:
                keys_pressed.append(pg.key.get_pressed()[pg.K_LALT])
                keys_pressed.append(pg.key.get_pressed()[pg.K_RALT])
                print(confirmCharacterSelection(characterSelected, selectionsCounter, keys_pressed), selectionsCounter)
                # TODO: Mejorar la forma de sleección,
                # Si presiona nuevamente una tecla cuando ya hay jugadores seleccionados, determinar la tecla presionada y cambiar según la selección
                if confirmCharacterSelection(characterSelected, selectionsCounter, keys_pressed):
                    drawPlayerChoose(characterSelected, selectionsCounter)  # Indica la selección ya confirmada
                    selectionsCounter += 1
                    characterSelected = 0
            keys_pressed = []
        pg.display.update()
    if pageDirection == "MENU":
        manageMenu(menuObject)
    elif pageDirection == "MAP":
        print("CHOSEN_PLAYERS -> ",CHOSEN_PLAYERS)
        manageMapSelection(menuObject)

def manageMapSelection(menuObject):
    global SCREEN,MAP
    print("-SELECCIONAR MAPA")
    menuObject.drawChooseMapInterface(SCREEN)
    run = True
    pageDirection = ""
    while run:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                run = False
                pg.quit()
            if event.type == pg.MOUSEBUTTONDOWN:
                coordinate_x, coordinate_y = event.pos
                if isPressedGoBackButton(coordinate_x, coordinate_y):
                    pageDirection = "CHARACTER"
                    run = False
                else:
                    if isContinueButtonPressed(coordinate_x, coordinate_y):
                        if MAP[0] is not None:
                            pageDirection = "ITEMS"
                            run = False
                        # else que indique que seleccione personaje
                    elif 40 <= coordinate_x <= 1230 and 220 <= coordinate_y <= 547:
                        # FOREST
                        if 40 <= coordinate_x <= 606 and 220 <= coordinate_y <= 547:
                            MAP = [FOREST_WORLD_BACKGROUND, "FOREST"]
                        # ICE
                        elif 664 <= coordinate_x <= 1230 and 220 <= coordinate_y <= 547:
                            MAP = [ICE_WORLD_BACKGROUND, "ICE"]
            if event.type == pg.KEYDOWN:
                if event.key == pg.K_RSHIFT and MAP is not None:
                    print("mapa seleccionado")
                    drawMapChoose(menuObject)
        pg.display.update()
    if pageDirection == "ITEMS":
        print("MAP -> ",MAP)
        manageItemsSelection(menuObject)
    elif pageDirection == "CHARACTER":
        managePlaySection(menuObject)

def manageItemsSelection(menuObject):
    global SCREEN, POTIONS
    print("-SELECCIONAR ITEMS")
    menuObject.drawItemsInterface(SCREEN)
    run = True
    pageDirection = ""
    option = ""
    while run:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                run = False
                pg.quit()
            if event.type == pg.MOUSEBUTTONDOWN:
                coordinate_x, coordinate_y = event.pos
                if isPressedGoBackButton(coordinate_x, coordinate_y):
                    pageDirection = "MAPAS"
                    run = False
                else:
                    if isContinueButtonPressed(coordinate_x, coordinate_y):
                        # if POTIONS[0] is not None or POTIONS[1] is not None:
                        print(POTIONS)
                        pageDirection = "PLAY"
                        run = False
                        print("Puede o no haber items seleccionados")
                    else:
                        # DANO
                        if 256 <= coordinate_x <= 489 and 523 <= coordinate_y <= 582:
                            POTIONS[0] = 1
                            option = "DAMAGE"
                        # VIDA
                        elif 749 <= coordinate_x <= 982 and 523 <= coordinate_y <= 582:
                            POTIONS[1] = 1
                            option = "LIFE"
                        # reset
                        elif 521 <= coordinate_x <= 700 and 347 <= coordinate_y <= 406:
                            POTIONS = [None, None]
                            menuObject.drawItemsInterface(SCREEN)
            if event.type == pg.KEYDOWN:
                if event.key == pg.K_RSHIFT and MAP is not None:
                    print(f"POCION DE {option} SELECCIONADA")
                    drawItemChoose(option)
        pg.display.update()
    if pageDirection == "MAPAS":
        manageMapSelection(menuObject)
    elif pageDirection == "PLAY":
        print("POTIONS -> ",POTIONS)
        launchGame(menuObject)

def winnerExists(player1, player2):
    if player1.getLife() == 0 and player2.getLife() > 0:
        return (True, PLAYER2_WINS)
    elif player1.getLife() > 0  and player2.getLife() == 0:
        return (True, PLAYER1_WINS)
    elif player1.getLife() == 0 and player2.getLife() == 0:
        return (True, BOTH_DIED)
    else:
        return (False, 0)

def drawWinner(winner_image):

    global SCREEN
    run = True

    while run:
        SCREEN.blit(winner_image, (SCREEN_WIDTH / 2 - 423, 100))
        pg.display.update()
        for event in pg.event.get():
            if event.type == pg.KEYDOWN:
                if event.key == pg.K_y:
                    return False

def launchGame(menuObject):
    global SCREEN, SCREEN_WIDTH, SCREEN_HEIGHT, CHOSEN_PLAYERS, MAP, POTIONS

    print("-CARGANDO PARTIDA")

    # creating player

    player1 = Player(0, 360, CHOSEN_PLAYERS[0], "WASD")
    player2 = Player(1200, 360, CHOSEN_PLAYERS[1], "ULDR")  # Up, Left,Down,Right

    # Creating worlds
    print(MAP)
    chosen_map = World(MAP[0], MAP[1])

    # test
    # forest_world = World(FOREST_WORLD_BACKGROUND,"FOREST")
    # ice_world = World(ICE_WORLD_BACKGROUND,"ICE")

    run = True
    wantGoMenu = False
    pygame.mixer.Sound.play(MAP_SOUND)
    while run:
        CLOCK.tick(FPS)
        chosen_map.drawBackground(SCREEN)
        chosen_map.draw_collision_objects(SCREEN, chosen_map.getWorldName())
        # player1.update(SCREEN, SCREEN_WIDTH,SCREEN_HEIGHT, chosen_map.getCollisionsObjects(), chosen_map.getWorldName(), player2.getPlayerRectangle(), player2.getCharacter())
        # player2.update(SCREEN,SCREEN_WIDTH,SCREEN_HEIGHT , chosen_map.getCollisionsObjects(), chosen_map.getWorldName(), player1.getPlayerRectangle(), player1.getCharacter())
        player1.update(SCREEN, SCREEN_WIDTH, SCREEN_HEIGHT, chosen_map.getCollisionsObjects(),
                       chosen_map.getWorldName(), player2)
        player2.update(SCREEN, SCREEN_WIDTH, SCREEN_HEIGHT, chosen_map.getCollisionsObjects(),
                       chosen_map.getWorldName(), player1)
        player1.drawLife(SCREEN, LIFE_FONT, WHITE)
        player2.drawLife(SCREEN, LIFE_FONT, WHITE)

        # test
        # forest_world.drawBackground(SCREEN)
        # forest_world.draw_collision_objects(SCREEN, "FOREST")
        # ice_world.drawBackground(SCREEN)
        # ice_world.draw_collision_objects(SCREEN, "ICE")

        for event in pg.event.get():
            if event.type == pg.QUIT:
                run = False
                pg.quit()
            if event.type == pg.MOUSEBUTTONDOWN:
                coordinate_x, coordinate_y = event.pos
                if isGamePaused(coordinate_x, coordinate_y, chosen_map.getWorldName()):
                    print("LA PARTIDA SE HA PAUSADO")
                    run = handlePausedGame()
                    wantGoMenu = not run

        winner = winnerExists(player1, player2)
        if winner[0]:
            run = drawWinner(winner[1])
            wantGoMenu = not run

        pg.display.set_caption(str(int(CLOCK.get_fps())))
        pg.display.update()

        # drawWinner(player1,player2)

    if wantGoMenu:
        POTIONS = [None,None]
        CHOSEN_PLAYERS = [None, None]
        MAP = [None,None]
        pygame.mixer.Sound.stop(MAP_SOUND)
        manageMenu(menuObject)

def manageHelp(menuObject):
    print("AYUDA")
    menuObject.drawHelpInterface(SCREEN)
    run = True
    while run:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                run = False
                pg.quit()
            if event.type == pg.MOUSEBUTTONDOWN:
                coordinate_x, coordinate_y = event.pos
                if isPressedGoBackButton(coordinate_x, coordinate_y):
                    menu.drawMenuInterface(SCREEN)
                    run = False
        pg.display.update()

def manageMenu(menuObject):
    menuObject.drawMenuInterface(SCREEN)
    run = True
    while run:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                run = False
                pg.quit()
            elif event.type == pg.MOUSEBUTTONDOWN:
                coordinate_x, coordinate_y = event.pos
                if 55 <= coordinate_x <= 387 and 176 <= coordinate_y <= 359:
                    print("SELECCIONAR PERSONAJE y MAPA")
                    managePlaySection(menuObject)
                elif 474 <= coordinate_x <= 808 and 303 <= coordinate_y <= 488:
                    manageHelp(menuObject)
                elif 879 <= coordinate_x <= 1204 and 494 <= coordinate_y <= 667:
                    print("SALIENDO")
                    exit()
        pg.display.update()

# ------------------------------------------------------------------------------------------------------------------------

if __name__ == '__main__':

    menu = Menu(INITIAL_INTERFACE, MENU_INTERFACE, CHOOSE_CHARACTER_INTERFACE, CHOOSE_MAP_INTERFACE,
                CHOOSE_ITEMS_INTERFACE, HELP_INTERFACE)
    run = True

    menu.drawInitialInterface(SCREEN)
    menu.drawMenuInterface(SCREEN)

    while run:

        for event in pg.event.get():
            if event.type == pg.QUIT:
                run = False
                pg.quit()
            manageMenu(menu)
            # launchGame(menu)

        pg.display.update()


"""
Contains a representation of GitHub users.
"""
from typing import Optional

from IGitt.GitHub import GitHubMixin
from IGitt.GitHub import GitHubToken
from IGitt.GitHub import GitHubInstallationToken
from IGitt.Interfaces import get
from IGitt.Interfaces.User import User

PREVIEW_HEADER = {'Accept': 'application/vnd.github.machine-man-preview+json'}

class GitHubUser(GitHubMixin, User):
    """
    A GitHub user, e.g. sils :)
    """
    def __init__(self, token: GitHubToken, username: Optional[str]=None):
        """
        Creates a GitHubUser with the given credentials.

        :param token:       The Oauth token.
        :param username:    The username of github user.
                            Takes None, if it's the associated user's token.
        """
        self._token = token
        self._url = '/users/' + username if username else '/user'
        self._username = username

    @property
    def username(self) -> str:
        """
        Retrieves the login for the user.
        """
        return self._username or self.data['login']

    @property
    def identifier(self) -> int:
        """
        Gets a unique id for the user that never changes.
        """
        return self.data['id']

    def installed_repositories(self, installation_id: int):
        """
        List repositories that are accessible to the authenticated user for an
        installation.
        """
        # Don't move to module code, causes circular dependencies
        from IGitt.GitHub.GitHubRepository import GitHubRepository

        repos = get(self._token,
                    self.absolute_url(
                        '/user/installations/{}/repositories'.format(
                            installation_id
                        )
                    ),
                    headers=PREVIEW_HEADER)['repositories']
        return {GitHubRepository.from_data(repo, self._token, repo['id'])
                for repo in repos}

    def get_installations(self, jwt):
        """
        Gets the installations this user has access to.

        :param jwt: The GitHubJsonWebToken required to fetch data.
        """
        # Don't move to module code, causes circular dependencies
        from IGitt.GitHub.GitHubInstallation import GitHubInstallation

        resp = get(self._token, self.absolute_url('/user/installations'),
                   headers=PREVIEW_HEADER)
        return {
            GitHubInstallation.from_data(
                i, GitHubInstallationToken(i['id'], jwt), i['id'])
            for i in resp['installations']
        }


#!/usr/bin/python3

import lxml.etree

def test():
	tree = lxml.etree.parse('/home/msr/src/opengovernment/raw/usc18@113-21.xml')
	for section in tree.xpath('//a:section', namespaces={'a': 'http://xml.house.gov/schemas/uslm/1.0'}):
		traverse(section)

def traverse(node):
	for subnode in node.xpath('./a:content|./a:subsection', namespaces={'a': 'http://xml.house.gov/schemas/uslm/1.0'}):
		if subnode.tag == '{http://xml.house.gov/schemas/uslm/1.0}content':
			for p in subnode.iterfind('{http://xml.house.gov/schemas/uslm/1.0}p'):
				print(lxml.etree.tostring(p.text,encoding=str))
		elif subnode.tag == '{http://xml.house.gov/schemas/uslm/1.0}subsection':
			traverse(subnode)

def main():
	test()

if __name__ == '__main__':
	main()


# stdlib, alphabetical
import json
import logging
from lxml import etree
import os
import shutil
import subprocess
import tempfile

# Core Django, alphabetical
from django.db import models

# Third party dependencies, alphabetical
import bagit
import jsonfield
from django_extensions.db.fields import UUIDField

# This project, alphabetical
from common import utils

# This module, alphabetical
from . import StorageException
from location import Location
from space import Space

__all__ = ('Package', )

LOGGER = logging.getLogger(__name__)

class Package(models.Model):
    """ A package stored in a specific location. """
    uuid = UUIDField(editable=False, unique=True, version=4,
        help_text="Unique identifier")
    description = models.CharField(max_length=256, default=None,
        null=True, blank=True, help_text="Human-readable description.")
    origin_pipeline = models.ForeignKey('Pipeline', to_field='uuid', null=True, blank=True)
    current_location = models.ForeignKey(Location, to_field='uuid')
    current_path = models.TextField()
    pointer_file_location = models.ForeignKey(Location, to_field='uuid', related_name='+', null=True, blank=True)
    pointer_file_path = models.TextField(null=True, blank=True)
    size = models.IntegerField(default=0, help_text='Size in bytes of the package')

    AIP = "AIP"
    AIC = "AIC"
    SIP = "SIP"
    DIP = "DIP"
    TRANSFER = "transfer"
    FILE = 'file'
    DEPOSIT = 'deposit'
    PACKAGE_TYPE_CHOICES = (
        (AIP, 'AIP'),
        (AIC, 'AIC'),
        (SIP, 'SIP'),
        (DIP, 'DIP'),
        (TRANSFER, 'Transfer'),
        (FILE, 'Single File'),
        (DEPOSIT, 'FEDORA Deposit')
    )
    package_type = models.CharField(max_length=8, choices=PACKAGE_TYPE_CHOICES)

    PENDING = 'PENDING'
    STAGING = 'STAGING'
    UPLOADED = 'UPLOADED'
    VERIFIED = 'VERIFIED'
    DEL_REQ = 'DEL_REQ'
    DELETED = 'DELETED'
    FAIL = 'FAIL'
    FINALIZED = 'FINALIZE'
    STATUS_CHOICES = (
        (PENDING, "Upload Pending"),  # Still on Archivematica
        (STAGING, "Staged on Storage Service"),  # In Storage Service staging dir
        (UPLOADED, "Uploaded"),  # In final storage location
        (VERIFIED, "Verified"),  # Verified to be in final storage location
        (FAIL, "Failed"),  # Error occured - may or may not be at final location
        (DEL_REQ, "Delete requested"),
        (DELETED, "Deleted"),
        (FINALIZED, "Deposit Finalized")
    )
    status = models.CharField(max_length=8, choices=STATUS_CHOICES,
        default=FAIL,
        help_text="Status of the package in the storage service.")
    # NOTE Do not put anything important here because you cannot easily query
    # JSONFields! Add a new column if you need to query it
    misc_attributes = jsonfield.JSONField(blank=True, null=True, default={},
        help_text='For storing flexible, often Space-specific, attributes')

    # Temporary attributes to track path on locally accessible filesystem
    local_path = None
    local_path_location = None

    PACKAGE_TYPE_CAN_DELETE = (AIP, AIC, TRANSFER)
    PACKAGE_TYPE_CAN_EXTRACT = (AIP, AIC)

    # Compression options
    COMPRESSION_7Z_BZIP = '7z with bzip'
    COMPRESSION_7Z_LZMA = '7z with lzma'
    COMPRESSION_TAR = 'tar'
    COMPRESSION_TAR_BZIP2 = 'tar bz2'
    COMPRESSION_ALGORITHMS = (
        COMPRESSION_7Z_BZIP,
        COMPRESSION_7Z_LZMA,
        COMPRESSION_TAR,
        COMPRESSION_TAR_BZIP2,
    )

    class Meta:
        verbose_name = "Package"
        app_label = 'locations'

    def __unicode__(self):
        return u"{uuid}: {path}".format(
            uuid=self.uuid,
            path=self.full_path,
        )
        # return "File: {}".format(self.uuid)

    # Attributes
    @property
    def full_path(self):
        """ Return the full path of the package's current location.

        Includes the space, location, and package paths joined. """
        return os.path.normpath(
            os.path.join(self.current_location.full_path, self.current_path))

    @property
    def full_pointer_file_path(self):
        """ Return the full path of the AIP's pointer file, None if not an AIP.

        Includes the space, location and package paths joined."""
        if not self.pointer_file_location:
            return None
        else:
            return os.path.join(self.pointer_file_location.full_path,
                self.pointer_file_path)

    @property
    def is_compressed(self):
        """ Determines whether or not the package is a compressed file. """
        full_path = self.fetch_local_path()
        if os.path.isdir(full_path):
            return False
        elif os.path.isfile(full_path):
            return True
        else:
            if not os.path.exists(full_path):
                message = "Package {} (located at {}) does not exist".format(self.uuid, full_path)
            else:
                message = "{} is neither a file nor a directory".format(full_path)
            raise StorageException(message)

    def get_download_path(self, lockss_au_number=None):
        full_path = self.fetch_local_path()
        if lockss_au_number is None:
            if not self.is_compressed:
                raise StorageException("Cannot return a download path for an uncompressed package")
            path = full_path
        elif self.current_location.space.access_protocol == Space.LOM:
            # Only LOCKSS breaks files into AUs
            # TODO Get path from pointer file
            # self.pointer_root.find("mets:structMap/*/mets:div[@ORDER='{}']".format(lockss_au_number), namespaces=NSMAP)
            path = os.path.splitext(full_path)[0] + '.tar-' + str(lockss_au_number)
        else:  # LOCKSS AU number specified, but not a LOCKSS package
            LOGGER.warning('Trying to download LOCKSS chunk for a non-LOCKSS package.')
            path = full_path
        return path

    def get_local_path(self):
        """
        Return a locally accessible path to this Package if available.

        If a cached copy of the local path is available (possibly from
        fetch_local_path), return that. If the package is available locally,
        return self.full_path. Otherwise, local_path is None.

        :returns: Local path to this package or None
        """
        # Return cached copy
        if self.local_path is not None and os.path.exists(self.local_path):
            return self.local_path
        # Package is locally accessible
        if os.path.exists(self.full_path):
            # TODO use Space protocol to determine if this is possible?
            self.local_path = self.full_path
            return self.local_path
        return None

    def fetch_local_path(self):
        """
        Fetches a local copy of the package.

        Returns local path if package is already available locally. Otherwise,
        copy to SS Internal Location, and return that path.

        :returns: Local path to this package.
        """
        local_path = self.get_local_path()
        if local_path:
            return local_path
        # Not locally accessible, so copy to SS internal temp dir
        ss_internal = Location.objects.get(purpose=Location.STORAGE_SERVICE_INTERNAL)
        temp_dir = tempfile.mkdtemp(dir=ss_internal.full_path)
        int_path = os.path.join(temp_dir, self.current_path)
        self.current_location.space.move_to_storage_service(
            source_path=os.path.join(self.current_location.relative_path, self.current_path),
            destination_path=self.current_path,
            destination_space=ss_internal.space,
        )
        relative_path = int_path.replace(ss_internal.space.path, '', 1).lstrip('/')
        ss_internal.space.move_from_storage_service(
            source_path=self.current_path,
            destination_path=relative_path,
        )
        self.local_path_location = ss_internal
        self.local_path = int_path
        return self.local_path

    def get_base_directory(self):
        """
        Returns the base directory of a package. This is the directory in
        which all of the contents of the package are nested. For example,
        given the following bag:

        .
        |-- package-00000000-0000-0000-0000-000000000000
            |-- bagit.txt
            |-- manifest-sha512.txt
            ...

        The string "package-00000000-0000-0000-0000-000000000000" would be
        returned.

        Note that this currently only supports locally-available packages.
        If the package is stored externally, raises NotImplementedError.
        """
        full_path = self.get_local_path()
        if full_path is None:
            raise NotImplementedError("This method currently only retrieves base directories for locally-available AIPs.")

        if self.is_compressed:
            # Use lsar's JSON output to determine the directories in a
            # compressed file. Since the index of the base directory may
            # not be consistent, determine it by filtering all entries
            # for directories, then determine the directory with the
            # shortest name. (e.g. foo is the parent of foo/bar)
            # NOTE: lsar's JSON output is broken in certain circumstances in
            #       all released versions; make sure to use a patched version
            #       for this to work.
            command = ['lsar', '-ja', full_path]
            output = json.loads(subprocess.check_output(command))
            directories = [d['XADFileName'] for d in output['lsarContents'] if d.get('XADIsDirectory', False)]
            directories = sorted(directories, key=len)
            return directories[0]
        else:
            return os.path.basename(full_path)

    def _check_quotas(self, dest_space, dest_location):
        """
        Verify that there is enough storage space on dest_space and dest_location for this package.  All sizes in bytes.
        """
        # Check if enough space on the space and location
        # All sizes expected to be in bytes
        if dest_space.size is not None and dest_space.used + self.size > dest_space.size:
            raise StorageException(
                "Not enough space for AIP on storage device {space}; Used: {used}; Size: {size}; AIP size: {aip_size}".format(
                    space=dest_space, used=dest_space.used, size=dest_space.size,
                    aip_size=self.size))
        if (dest_location.quota is not None and
                dest_location.used + self.size > dest_location.quota):
            raise StorageException(
                "AIP too big for quota on {location}; Used: {used}; Quota: {quota}; AIP size: {aip_size}".format(
                    location=dest_location,
                    used=dest_location.used,
                    quota=dest_location.quota,
                    aip_size=self.size)
            )

    def _update_quotas(self, space, location):
        """
        Add this package's size to the space and location.
        """
        space.used += self.size
        space.save()
        location.used += self.size
        location.save()

    def store_aip(self, origin_location, origin_path):
        """ Stores an AIP in the correct Location.

        Invokes different transfer mechanisms depending on what the source and
        destination Spaces are.  Checks if there is space in the Space and
        Location for the AIP, and raises a StorageException if not.  All sizes
        expected to be in bytes.
        """
        self.origin_location = origin_location
        self.origin_path = origin_path
        # TODO Move some of the procesing in archivematica
        # clientScripts/storeAIP to here?

        # Check if enough space on the space and location
        # All sizes expected to be in bytes
        src_space = self.origin_location.space
        dest_space = self.current_location.space
        self._check_quotas(dest_space, self.current_location)

        # Store AIP at
        # destination_location/uuid/split/into/chunks/destination_path
        uuid_path = utils.uuid_to_path(self.uuid)
        self.current_path = os.path.join(uuid_path, self.current_path)
        self.save()

        # Store AIP Pointer File at
        # internal_usage_location/uuid/split/into/chunks/pointer.uuid.xml
        if self.package_type in (Package.AIP, Package.AIC):
            self.pointer_file_location = Location.active.get(purpose=Location.STORAGE_SERVICE_INTERNAL)
            self.pointer_file_path = os.path.join(uuid_path, 'pointer.{}.xml'.format(self.uuid))
            pointer_file_src = os.path.join(self.origin_location.relative_path, os.path.dirname(self.origin_path), 'pointer.xml')
            pointer_file_dst = os.path.join(self.pointer_file_location.relative_path, self.pointer_file_path)

        self.status = Package.PENDING
        self.save()

        # Move pointer file
        if self.package_type in (Package.AIP, Package.AIC):
            try:
                src_space.move_to_storage_service(pointer_file_src, self.pointer_file_path, self.pointer_file_location.space)
                self.pointer_file_location.space.move_from_storage_service(self.pointer_file_path, pointer_file_dst)
            except:
                LOGGER.warning("No pointer file found")
                self.pointer_file_location = None
                self.pointer_file_path = None
                self.save()

        # Move AIP
        src_space.move_to_storage_service(
            source_path=os.path.join(self.origin_location.relative_path, self.origin_path),
            destination_path=self.current_path,  # This should include Location.path
            destination_space=dest_space)
        src_space.post_move_to_storage_service()
        dest_space.move_from_storage_service(
            source_path=self.current_path,  # This should include Location.path
            destination_path=os.path.join(self.current_location.relative_path, self.current_path),
        )
        dest_space.post_move_from_storage_service(
            staging_path=self.current_path,
            destination_path=os.path.join(self.current_location.relative_path, self.current_path),
            package=self)

        # Save new space/location usage, package status
        self._update_quotas(dest_space, self.current_location)
        if dest_space.access_protocol == Space.LOM:
            self.status = Package.STAGING
        else:
            self.status = Package.UPLOADED
        self.save()

        # Update pointer file's location information
        if self.pointer_file_path and self.package_type in (Package.AIP, Package.AIC):
            pointer_absolute_path = self.full_pointer_file_path
            root = etree.parse(pointer_absolute_path)
            element = root.find('.//mets:file', namespaces=utils.NSMAP)
            flocat = element.find('mets:FLocat', namespaces=utils.NSMAP)
            if self.uuid in element.get('ID', '') and flocat is not None:
                flocat.set('{{{ns}}}href'.format(ns=utils.NSMAP['xlink']), self.full_path)
            # Add USE="Archival Information Package" to fileGrp.  Required for
            # LOCKSS, and not provided in Archivematica <=1.1
            if root.find('.//mets:fileGrp[@USE="Archival Information Package"]', namespaces=utils.NSMAP) is not None:
                root.find('.//mets:fileGrp', namespaces=utils.NSMAP).set('USE', 'Archival Information Package')

            with open(pointer_absolute_path, 'w') as f:
                f.write(etree.tostring(root, pretty_print=True))

    def extract_file(self, relative_path='', extract_path=None):
        """
        Attempts to extract this package.

        If `relative_path` is provided, will extract only that file.  Otherwise,
        will extract entire package.
        If `extract_path` is provided, will extract there, otherwise to a temp
        directory in the SS internal location.
        If extracting the whole package, will set local_path to the extracted path.
        Fetches the file from remote storage before extracting, if necessary.

        Returns path to the extracted file and a temp dir that needs to be
        deleted.
        """
        if extract_path is None:
            ss_internal = Location.objects.get(purpose=Location.STORAGE_SERVICE_INTERNAL)
            extract_path = tempfile.mkdtemp(dir=ss_internal.full_path)
        full_path = self.fetch_local_path()

        # The basename is the base directory containing a package
        # like an AIP inside the compressed file.
        basename = self.get_base_directory()

        if relative_path:
            output_path = os.path.join(extract_path, relative_path)
        else:
            output_path = os.path.join(extract_path, basename)

        if self.is_compressed:
            command = ['unar', '-force-overwrite', '-o', extract_path, full_path]
            if relative_path:
                command.append(relative_path)

            LOGGER.info('Extracting file with: %s to %s', command, output_path)
            rc = subprocess.call(command)
            LOGGER.debug('Extract file RC: %s', rc)
        else:
            aip_path = os.path.join(full_path, basename)
            LOGGER.info('Copying AIP from: %s to %s', aip_path, output_path)
            shutil.copytree(aip_path, output_path)

        if not relative_path:
            self.local_path_location = ss_internal
            self.local_path = output_path

        return (output_path, extract_path)

    def compress_package(self, algorithm, extract_path=None):
        """
        Produces a compressed copy of the package.

        :param algorithm: Compression algorithm to use. Should be one of
            :const:`Package.COMPRESSION_ALGORITHMS`
        :param str extract_path: Path to compress to. If not provided, will
            compress to a temp directory in the SS internal location.
        :return: Tuple with (path to the compressed file, parent directory of
            compressed file)  Given that compressed packages are likely to
            be large, this should generally be deleted after use if a temporary
            directory was used.
        """

        if extract_path is None:
            ss_internal = Location.objects.get(purpose=Location.STORAGE_SERVICE_INTERNAL)
            extract_path = tempfile.mkdtemp(dir=ss_internal.full_path)
        if algorithm not in self.COMPRESSION_ALGORITHMS:
            raise ValueError('Algorithm %s not in %s' % algorithm, self.COMPRESSION_ALGORITHMS)

        full_path = self.fetch_local_path()

        if os.path.isfile(full_path):
            basename = os.path.splitext(os.path.basename(full_path))[0]
        else:
            basename = os.path.basename(full_path)

        if algorithm in (self.COMPRESSION_TAR, self.COMPRESSION_TAR_BZIP2):
            compressed_filename = os.path.join(extract_path, basename + '.tar')
            relative_path = os.path.dirname(full_path)
            algo = ''
            if algorithm == self.COMPRESSION_TAR_BZIP2:
                algo = '-j'  # Compress with bzip2
                compressed_filename += '.bz2'
            command = [
                'tar', 'c',  # Create tar
                algo,  # Optional compression flag
                '-C', relative_path,  # Work in this directory
                '-f', compressed_filename,  # Output file
                os.path.basename(full_path),   # Relative path to source files
            ]
        elif algorithm in (self.COMPRESSION_7Z_BZIP, self.COMPRESSION_7Z_LZMA):
            compressed_filename = os.path.join(extract_path, basename + '.7z')
            if algorithm == self.COMPRESSION_7Z_BZIP:
                algo = 'bzip2'
            elif algorithm == self.COMPRESSION_7Z_LZMA:
                algo = 'lzma'
            command = [
                '7z', 'a',  # Add
                '-bd',  # Disable percentage indicator
                '-t7z',  # Type of archive
                '-y',  # Assume Yes on all queries
                '-m0=' + algo,  # Compression method
                '-mtc=on', '-mtm=on', '-mta=on',  # Keep timestamps (create, mod, access)
                '-mmt=on',  # Multithreaded
                compressed_filename,  # Destination
                full_path,  # Source
            ]
        else:
            raise NotImplementedError('Algorithm %s not implemented' % algorithm)

        LOGGER.info('Compressing package with: %s to %s', command, compressed_filename)
        rc = subprocess.call(command)
        LOGGER.debug('Extract file RC: %s', rc)

        return (compressed_filename, extract_path)

    def backlog_transfer(self, origin_location, origin_path):
        """
        Stores a package in backlog.

        Invokes different transfer mechanisms depending on what the source and
        destination Spaces are.  Checks if there is space in the Space and
        Location for the AIP, and raises a StorageException if not.  All sizes
        expected to be in bytes.
        """
        self.origin_location = origin_location
        self.origin_path = origin_path

        # Check if enough space on the space and location
        # All sizes expected to be in bytes
        src_space = self.origin_location.space
        dest_space = self.current_location.space
        self._check_quotas(dest_space, self.current_location)

        # No pointer file
        self.pointer_file_location = None
        self.pointer_file_path = None

        self.status = Package.PENDING
        self.save()

        # Move transfer
        src_space.move_to_storage_service(
            source_path=os.path.join(self.origin_location.relative_path, self.origin_path),
            destination_path=self.current_path,  # This should include Location.path
            destination_space=dest_space)
        dest_space.move_from_storage_service(
            source_path=self.current_path,  # This should include Location.path
            destination_path=os.path.join(self.current_location.relative_path, self.current_path),
        )

        # Save new space/location usage, package status
        self._update_quotas(dest_space, self.current_location)
        self.status = Package.UPLOADED
        self.save()

    def check_fixity(self, delete_after=True):
        """ Scans the package to verify its checksums.

        This is implemented using bagit-python module, using the checksums from the
        bag's manifest. Note that this does not support packages which are not bags.

        Returns a tuple containing (success, [errors], message).
        Success will be True or False if the verification succeeds or fails, and
        None if the scan could not start (for instance, if this package is not
        a bag).

        [errors] will be a list of zero or more classes representing different
        classes of errors.

        message will be a human-readable string explaining the report;
        it will be empty for successful scans.

        Note that if the package is not compressed, the fixity scan will occur
        in-place. If fixity scans will happen periodically, if packages are very
        large, or if scans are otherwise expected to contribute to heavy disk load,
        it is recommended to store packages uncompressed. """

        if self.package_type not in (self.AIC, self.AIP):
            return (None, [], "Unable to scan; package is not a bag (AIP or AIC)")

        if self.is_compressed:
            # bagit can't deal with compressed files, so extract before
            # starting the fixity check.
            path, temp_dir = self.extract_file()
        else:
            path = self.fetch_local_path()
            temp_dir = None

        bag = bagit.Bag(path)
        try:
            success = bag.validate()
            failures = []
            message = ""
        except bagit.BagValidationError as failure:
            success = False
            failures = failure.details
            message = failure.message

        if temp_dir and delete_after and (self.local_path_location != self.current_location or self.local_path != self.full_path):
            shutil.rmtree(temp_dir)

        return (success, failures, message)

    def delete_from_storage(self):
        """ Deletes the package from filesystem and updates metadata.

        Returns (True, None) on success, and (False, error_msg) on failure. """
        error = None
        # LOCKSS must notify LOM before deleting
        if self.current_location.space.access_protocol == Space.LOM:
            # Notify LOM that files will be deleted
            if 'num_files' in self.misc_attributes:
                lom = self.current_location.space.get_child_space()
                lom.update_service_document()
                delete_lom_ids = [lom._download_url(self.uuid, idx + 1) for idx in range(self.misc_attributes['num_files'])]
                error = lom._delete_update_lom(self, delete_lom_ids)

        try:
            self.current_location.space.delete_path(self.full_path)
        except Exception as e:
            error = e.message

        # Remove pointer file, and the UUID quad directories if they're empty
        pointer_path = self.full_pointer_file_path
        if pointer_path:
            try:
                os.remove(pointer_path)
            except OSError as e:
                LOGGER.info("Error deleting pointer file %s for package %s", pointer_path, self.uuid, exc_info=True)
            utils.removedirs(os.path.dirname(self.pointer_file_path),
                base=self.pointer_file_location.full_path)

        self.status = self.DELETED
        self.save()
        return True, error

    # SWORD-related methods
    def has_been_submitted_for_processing(self):
        return 'deposit_completion_time' in self.misc_attributes


'''
Created on 2019年6月4日

@author: wukai
'''
import os
import numpy as np
import scipy.io as sio
import matplotlib.pyplot as plt
from calcu import *

print('Loading data ...........')
os.chdir(os.path.split(os.path.abspath(__file__))[0])
data = sio.loadmat('ex3data1.mat')
m, n = data['X'].shape
y = data['y']
input_layer_size = n     # Input feature nums
hidden_layer_size = 25   # 25 hidden unit
num_labels = 10          # Label nums
X = np.column_stack((np.ones(m), data['X']))

print('Loading Saved Neural Network Parameters')
params = sio.loadmat('ex3weights.mat')
print(params)

y_pr = nnPredict(params['Theta1'], params['Theta2'], X)
py = (y.flatten() == y_pr)
acc = len(py[(py == True)]) * 100.0 / len(y)
print('Accuracy = {}'.format(acc))


import pygame, sys
from settings import *
from player import Player
from car import Car

class AllSprites(pygame.sprite.Group):
    def __init__(self):
        super().__init__()

    def customize_draw(self):
        for sprite in self.sprites():
            screen.blit(sprite.image, sprite.rect)

pygame.init()

screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption("Frogger")
clock = pygame.time.Clock()

# groups
all_sprites = AllSprites()

# classes
player = Player(all_sprites, (200, 300))
car = Car(all_sprites, (700, 400))

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

        # keyboard alternative
        # if event.type == pygame.KEYDOWN:
        #     if event.key == pygame.K_w:
        #         print("w")

    dt = clock.tick() / 1000

    screen.fill("black")

    all_sprites.update(dt)

    all_sprites.draw(screen)

    pygame.display.update()


from __future__ import absolute_import
from __future__ import unicode_literals

import six
import yaml

from compose.config import types
from compose.const import COMPOSEFILE_V1 as V1
from compose.const import COMPOSEFILE_V2_1 as V2_1
from compose.const import COMPOSEFILE_V2_2 as V2_2
from compose.const import COMPOSEFILE_V3_1 as V3_1
from compose.const import COMPOSEFILE_V3_2 as V3_2

def serialize_config_type(dumper, data):
    representer = dumper.represent_str if six.PY3 else dumper.represent_unicode
    return representer(data.repr())

def serialize_dict_type(dumper, data):
    return dumper.represent_dict(data.repr())

yaml.SafeDumper.add_representer(types.VolumeFromSpec, serialize_config_type)
yaml.SafeDumper.add_representer(types.VolumeSpec, serialize_config_type)
yaml.SafeDumper.add_representer(types.ServiceSecret, serialize_dict_type)
yaml.SafeDumper.add_representer(types.ServicePort, serialize_dict_type)

def denormalize_config(config, image_digests=None):
    result = {'version': V2_1 if config.version == V1 else config.version}
    denormalized_services = [
        denormalize_service_dict(
            service_dict,
            config.version,
            image_digests[service_dict['name']] if image_digests else None)
        for service_dict in config.services
    ]
    result['services'] = {
        service_dict.pop('name'): service_dict
        for service_dict in denormalized_services
    }
    result['networks'] = config.networks.copy()
    for net_name, net_conf in result['networks'].items():
        if 'external_name' in net_conf:
            del net_conf['external_name']

    result['volumes'] = config.volumes.copy()
    for vol_name, vol_conf in result['volumes'].items():
        if 'external_name' in vol_conf:
            del vol_conf['external_name']

    if config.version in (V3_1, V3_2):
        result['secrets'] = config.secrets
    return result

def serialize_config(config, image_digests=None):
    return yaml.safe_dump(
        denormalize_config(config, image_digests),
        default_flow_style=False,
        indent=2,
        width=80)

def serialize_ns_time_value(value):
    result = (value, 'ns')
    table = [
        (1000., 'us'),
        (1000., 'ms'),
        (1000., 's'),
        (60., 'm'),
        (60., 'h')
    ]
    for stage in table:
        tmp = value / stage[0]
        if tmp == int(value / stage[0]):
            value = tmp
            result = (int(value), stage[1])
        else:
            break
    return '{0}{1}'.format(*result)

def denormalize_service_dict(service_dict, version, image_digest=None):
    service_dict = service_dict.copy()

    if image_digest:
        service_dict['image'] = image_digest

    if 'restart' in service_dict:
        service_dict['restart'] = types.serialize_restart_spec(
            service_dict['restart']
        )

    if version == V1 and 'network_mode' not in service_dict:
        service_dict['network_mode'] = 'bridge'

    if 'depends_on' in service_dict and version not in (V2_1, V2_2):
        service_dict['depends_on'] = sorted([
            svc for svc in service_dict['depends_on'].keys()
        ])

    if 'healthcheck' in service_dict:
        if 'interval' in service_dict['healthcheck']:
            service_dict['healthcheck']['interval'] = serialize_ns_time_value(
                service_dict['healthcheck']['interval']
            )
        if 'timeout' in service_dict['healthcheck']:
            service_dict['healthcheck']['timeout'] = serialize_ns_time_value(
                service_dict['healthcheck']['timeout']
            )

    if 'ports' in service_dict and version not in (V3_2,):
        service_dict['ports'] = [
            p.legacy_repr() if isinstance(p, types.ServicePort) else p
            for p in service_dict['ports']
        ]

    return service_dict


import os
import pandas as pd
import numpy as np

from  sdg_utils import Positive, Binary

import openpyxl

from sklearn.preprocessing import OneHotEncoder

from typing import Tuple, List

def prepare_ALZ_BALEA(dataset_path : str = "", filename : str = "") ->  Tuple[pd.DataFrame,
                                                        pd.DataFrame, pd.DataFrame, List, str] :
    """Read the Alzheimer-Balea dataset from a .xlsx file and suit it to be processed
    as a pd.DataFrame. It returns tha dataset dataframe and strings associated to
    it to easy its management.

    Args:
    -----
            dataset_path: path where ALZ-BALEA dataset is stored. Set by default.
            filename : file name of the .csv containing the dataset. Set by default.

    Returns:
    --------
            data: dataframe containing the whole dataset
            X : dataframe containing the dataset features
            Y : dataframe containing only the target variable
            cols_names: list of strings containing feature names.
            y_tag: string containing target variable name.
    """

    # Go to dataset path
    os.chdir(dataset_path)

    # Open the Excel file
    bd = openpyxl.load_workbook(filename)

    # Load the useful information of the Excel file
    sheet = bd['Tesis definitiva']

    # Convert sheet into DataFrame
    data = pd.DataFrame(sheet.values)

    # Fix data properly in the dataframe
    tags = data.iloc[0]
    data.columns = tags

    # Drop useless rows and columns
    data = data.drop(index = [0,86,87,88,89,90])
    data.reset_index(drop=True, inplace=True)
    data = data.drop(['Grupo','ID','Pfeiffer','Comentario', 'HiperEspectMIC', 'HiperEspectMAC'], axis=1)

    # Replace "NULL" values by a integer to be handled later
    data = data.replace(to_replace = "#NULL!", value = 99999)

    # Store features' and target variable's names
    cols_names_prev = data.columns
    y_tag = cols_names_prev[len(cols_names_prev)-1]
    cols_names = cols_names_prev[0:cols_names_prev.size]

    # Substitute value of 6 (non-existant) in AntNeurol by 99999, as if it was "NULL"
    data['AntNeurolog'][61] = 99999

    # Drop those rows which has the output 'TNeurolog' equals to 99999 (NULL)
    data = data[data['TNeurocog'] < 2]

    # Save X, Y, feature names and Y name
    y_tag = cols_names[len(cols_names)-1]
    cols_names = cols_names[0:len(cols_names)-1]
    X = data[cols_names]
    Y = data[y_tag]

    return data, X, Y, cols_names, y_tag

def numerical_conversion(data : np.array, features : str, y_col : str) -> Tuple[pd.DataFrame,
                                            pd.DataFrame, pd.DataFrame]:
    """Fix all Alzheimer-Balea database features data types to its original type after
    KNNImputer is used, since this functions returns only a floating points ndarray.
    For more, check sklearn documentation of this function at
    https://scikit-learn.org/stable/modules/generated/sklearn.impute.KNNImputer.html. After
    fixing datatypes, an ndarray to pd.DataFrame conversion is performed. Notice that this
    operation is only done in the fields that were not originally floats.

    Args:
    -----
            data: data returned by KNN Imputer (float data type).
            features: list of strings containing the feature names of the dataset.
            y_col: target variable (i.e., Y) name

    Returns:
    --------
            data: dataframe containing the whole dataset after imputation
            X : dataframe containing the dataset features after imputation
            y : dataframe containing only the target variable after imputation
    """
    # From ndarray to pd.DataFrame
    names = features.insert(len(features), y_col)
    data = pd.DataFrame(data, columns = names)

    # Fixing necessary datatypes to int (including categorical variables)
    data['Edad'] = data['Edad'].astype(int)
    data['Sexo'] = data['Sexo'].astype(int)
    data['EstCivil'] = data['EstCivil'].astype(int)
    data['ActLaboral'] = data['ActLaboral'].astype(int)
    data['FormatConvivencia'] = data['FormatConvivencia'].astype(int)
    data['NivelEducativo'] = data['NivelEducativo'].astype(int)
    data['ActIntelectual'] = data['ActIntelectual'].astype(int)
    data['RelSociales'] = data['RelSociales'].astype(int)
    data['AntPsiquia'] = data['AntPsiquia'].astype(int)
    data['AntCardiologi'] = data['AntCardiologi'].astype(int)
    data['AntNeurolog'] = data['AntNeurolog'].astype(int)
    data['AntRenal'] = data['AntRenal'].astype(int)
    data['AntPulmonar'] = data['AntPulmonar'].astype(int)
    data['AntDemencia'] = data['AntDemencia'].astype(int)
    data['Tabaco'] = data['Tabaco'].astype(int)
    data['Alcohol'] = data['Alcohol'].astype(int)
    data['HTAanterior'] = data['HTAanterior'].astype(int)
    data['TAS'] = data['TAS'].astype(int)
    data['TAD'] = data['TAD'].astype(int)
    data['DM'] = data['DM'].astype(int)
    data['Barthel'] = data['Barthel'].astype(int)
    data['Hb'] = data['Hb'].astype(float)
    data['VCM'] = data['VCM'].astype(float)
    data['HCM'] = data['HCM'].astype(float)
    data['Plaquetas'] = data['Plaquetas'].astype(int)
    data['Leucocitos'] = data['Leucocitos'].astype(float)
    data['VCM'] = data['VCM'].astype(float)
    data['Neutrófilos'] = data['Neutrófilos'].astype(float)
    data['Linfocitos'] = data['Linfocitos'].astype(float)
    data['Monocitos'] = data['Monocitos'].astype(float)
    data['Glucosa'] = data['Glucosa'].astype(int)
    data['Creatinina'] = data['Creatinina'].astype(float)
    data['FG'] = data['FG'].astype(float)
    data['Na'] = data['Na'].astype(int)
    data['K'] = data['K'].astype(float)
    data['ALT'] = data['ALT'].astype(float)
    data['Colesterol'] = data['Colesterol'].astype(int)
    data['LDL'] = data['LDL'].astype(int)
    data['TNeurocog'] = data['TNeurocog'].astype(int)

    # Separate X and Y
    X = data[features]
    y = data[[y_col]]

    return data, X, y

def general_conversion (data : pd.DataFrame) -> pd.DataFrame :
    """Fix all Alzheimer-Balea database features data types to its original type.
    Categorical variables are set as "object" type. A DataFrame with the original
    datatypes of this database is returned.

    Args:
    -----
            data: dataset with datatypes not corresponding to the original ones.
            features: list of strings containing the feature names of the dataset.
            y_col: target variable (i.e., Y) name

    Returns:
    --------
            data: dataframe with the original datatypes
    """
    data['Edad'] = data['Edad'].astype(int)
    data['Sexo'] = data['Sexo'].astype('object')
    data['EstCivil'] = data['EstCivil'].astype('object')
    data['ActLaboral'] = data['ActLaboral'].astype('object')
    data['FormatConvivencia'] = data['FormatConvivencia'].astype('object')
    data['NivelEducativo'] = data['NivelEducativo'].astype('object')
    data['ActIntelectual'] = data['ActIntelectual'].astype('object')
    data['RelSociales'] = data['RelSociales'].astype('object')
    data['AntPsiquia'] = data['AntPsiquia'].astype('object')
    data['AntNeurolog'] = data['AntNeurolog'].astype('object')
    data['AntRenal'] = data['AntRenal'].astype('object')
    data['AntPulmonar'] = data['AntPulmonar'].astype('object')
    data['AntDemencia'] = data['AntDemencia'].astype('object')
    data['Tabaco'] = data['Tabaco'].astype('object')
    data['Alcohol'] = data['Alcohol'].astype('object')
    data['AntPsiquia'] = data['AntPsiquia'].astype('object')
    data['AntCardiologi'] = data['AntCardiologi'].astype('object')
    data['HTAanterior'] = data['HTAanterior'].astype(int)
    data['TAS'] = data['TAS'].astype(int)
    data['TAD'] = data['TAD'].astype(int)
    data['DM'] = data['DM'].astype(int)
    data['Barthel'] = data['Barthel'].astype(int)
    data['Hb'] = data['Hb'].astype(float)
    data['VCM'] = data['VCM'].astype(float)
    data['HCM'] = data['HCM'].astype(float)
    data['Plaquetas'] = data['Plaquetas'].astype(int)
    data['Leucocitos'] = data['Leucocitos'].astype(float)
    data['VCM'] = data['VCM'].astype(float)
    data['Neutrófilos'] = data['Neutrófilos'].astype(float)
    data['Linfocitos'] = data['Linfocitos'].astype(float)
    data['Monocitos'] = data['Monocitos'].astype(float)
    data['Glucosa'] = data['Glucosa'].astype(int)
    data['Creatinina'] = data['Creatinina'].astype(float)
    data['FG'] = data['FG'].astype(float)
    data['Na'] = data['Na'].astype(int)
    data['K'] = data['K'].astype(float)
    data['ALT'] = data['ALT'].astype(float)
    data['Colesterol'] = data['Colesterol'].astype(int)
    data['LDL'] = data['LDL'].astype(int)
    data['TNeurocog'] = data['TNeurocog'].astype(int)

    return data

def replacement(data : pd.DataFrame) -> pd.DataFrame :
    """This function replaces the numerical values corresponding to categories in
    the Alzheimer-Balea database by its correspondant category. It returns a DataFrame
    after this replacement.

    Args:
    -----
            data: dataset with categories represented by numbers.

    Returns:
    --------
            data: dataframe with the categories represented by their correspondant string
    """
    data['Sexo']  = data['Sexo'].replace([1,2],['Varon', 'Mujer'])
    data['EstCivil']  = data['EstCivil'].replace([1,2,3,4],['Solteria', 'Matrimonio',
                                                                        'Viudedad', 'Divorcio'])
    data['ActLaboral']  = data['ActLaboral'].replace([1,2,3,4],['Cualificado', 'No cualificado',
                                                                        'Empresario', 'Ama de casa'])
    data['FormatConvivencia']  = data['FormatConvivencia'].replace([1,2,3,4],['Convivencia Conyuge', 'Convivencia Solo',
                                                                        'Convivencia Hijos_Familiares', 'Convivencia Residencia'])
    data['NivelEducativo']  = data['NivelEducativo'].replace([1,2,3,4],['Sin estudios', 'Estudios primarios',
                                                                        'Estudios medios', 'Estudios universitarios'])
    data['ActIntelectual']  = data['ActIntelectual'].replace([1,2,3],['+10 libros/año', '5-10 libros/año',
                                                                        'Lectura escasa'])
    data['RelSociales']  = data['RelSociales'].replace([1,2,3],['Relsociales Buenas', 'Relsociales Normales',
                                                                             'Relsociales Inexistentes'])
    data['AntPsiquia']  = data['AntPsiquia'].replace([1,2,3],['Psiquia Depresion', 'Psiquia Otros antecedentes', 'Psiquia Sin antecedentes'])
    data['AntCardiologi']  = data['AntCardiologi'].replace([1,2,3,4],['Cardio Isquemica', 'Cardio FA',
                                                                            'Cardio otras','Cardio Sin antecedentes'])
    data['AntNeurolog'] = data['AntNeurolog'].replace([1,2,3,4,5],['Neuro Ictus', 'Neuro Cefalea', 'Neuro Traumatismo',
                                                                            'Neuro Epilepsia','Neuro Sin antecedentes'])
    data['AntRenal'] = data['AntRenal'].replace([1,2,3],['Renal ERC', 'Renal Otras', 'Renal Sin Patologias'])
    data['AntPulmonar'] = data['AntPulmonar'].replace([1,2,3,4],['Pulmonar EPOC', 'Pulmonar Cancer',
                                                                             'Pulmonar Otras','Pulmonar Sin Patologias'])
    data['AntDemencia'] = data['AntDemencia'].replace([1,2,3],['Demencia Padres', 'Demencia otros',
                                                                             'Demencia Sin Antecedentes'])
    data['Tabaco'] = data['Tabaco'].replace([1,2],['Ex/Fumador', 'No Fumador'])
    data['Alcohol'] = data['Alcohol'].replace([1,2,3,4],['Alcohol Elevado', 'Alcohol Moderado',
                                                                           'Alcohol leve', 'Alcohol nunca'])
    data['HTAanterior'] = data['HTAanterior'].replace([1,2],[1,0])
    data['DM'] = data['DM'].replace([1,2],[1,0])

    return data

def one_hot_enc(data : pd.DataFrame) -> pd.DataFrame :
    """This function performs One-Hot Encoding in the Alzheimer-Balea database. Since this
    database is really small, validation and train sets are even smaller. Hence, sometimes
    columns full of 0s must be manually added, because a certain value of a feature does not
    appear in the dataset subset. This is the case of category 'Empresarios' of feature "ActLaboral".

    Args:
    -----
            data: dataset with categories represented by numbers.

    Returns:
    --------
            data: dataframe with the categories represented by their correspondant string
    """

    # One-hot Encoder declaration
    enc = OneHotEncoder(handle_unknown='ignore')
    # Sexo
    cats = ['Varon', 'Mujer']
    data[['Sexo']] = data[['Sexo']].astype('category')
    sexo = pd.DataFrame(enc.fit_transform(data[['Sexo']]).toarray())
    sexo.columns = enc.categories_
    for name in cats:
        if name not in sexo:
            sexo[name] = 0
    sexo = sexo[['Varon', 'Mujer']]
    sexo.reset_index(drop=True, inplace=True)
    # Estado Civil
    cats = ['Solteria', 'Matrimonio', 'Viudedad', 'Divorcio']
    data[['EstCivil']] = data[['EstCivil']].astype('category')
    civil = pd.DataFrame(enc.fit_transform(data[['EstCivil']]).toarray())
    civil.columns = enc.categories_
    for name in cats:
        if name not in civil:
            civil[name] = 0
    civil = civil[['Solteria', 'Matrimonio', 'Viudedad', 'Divorcio']]
    civil.reset_index(drop=True, inplace=True)
    # Actividad laboral
    cats = ['Cualificado', 'No cualificado','Empresario', 'Ama de casa']
    data[['ActLaboral']] = data[['ActLaboral']].astype('category')
    laboral = pd.DataFrame(enc.fit_transform(data[['ActLaboral']]).toarray())
    laboral.columns = enc.categories_
    for name in cats:
        if name not in laboral:
            laboral[name] = 0
    laboral = laboral[['Cualificado', 'No cualificado','Empresario', 'Ama de casa']]
    laboral.reset_index(drop=True, inplace=True)
    # Formato Convivencia
    cats = ['Convivencia Conyuge', 'Convivencia Solo','Convivencia Hijos_Familiares',
            'Convivencia Residencia']
    data[['FormatConvivencia']] = data[['FormatConvivencia']].astype('category')
    convi = pd.DataFrame(enc.fit_transform(data[['FormatConvivencia']]).toarray())
    convi.columns = enc.categories_
    for name in cats:
        if name not in convi:
            convi[name] = 0
    convi = convi[['Convivencia Conyuge', 'Convivencia Solo','Convivencia Hijos_Familiares',
            'Convivencia Residencia']]
    convi.reset_index(drop=True, inplace=True)
    # Nivel educativo
    cats = ['Sin estudios', 'Estudios primarios','Estudios medios', 'Estudios universitarios']
    data[['NivelEducativo']] = data[['NivelEducativo']].astype('category')
    educ = pd.DataFrame(enc.fit_transform(data[['NivelEducativo']]).toarray())
    educ.columns = enc.categories_
    for name in cats:
        if name not in educ:
            educ[name] = 0
    educ = educ[['Sin estudios', 'Estudios primarios','Estudios medios', 'Estudios universitarios']]
    educ.reset_index(drop=True, inplace=True)
    # Acitividad intelectual
    cats = ['+10 libros/año', '5-10 libros/año', 'Lectura escasa']
    data[['ActIntelectual']] = data[['ActIntelectual']].astype('category')
    intec = pd.DataFrame(enc.fit_transform(data[['ActIntelectual']]).toarray())
    intec.columns = enc.categories_
    for name in cats:
        if name not in intec:
            intec[name] = 0
    intec = intec[['+10 libros/año', '5-10 libros/año', 'Lectura escasa']]
    intec.reset_index(drop=True, inplace=True)
    # Relaciones sociales
    cats = ['Relsociales Buenas', 'Relsociales Normales','Relsociales Inexistentes']
    data[['RelSociales']] = data[['RelSociales']].astype('category')
    rels = pd.DataFrame(enc.fit_transform(data[['RelSociales']]).toarray())
    rels.columns = enc.categories_
    for name in cats:
        if name not in rels:
            rels[name] = 0
    rels = rels[['Relsociales Buenas', 'Relsociales Normales','Relsociales Inexistentes']]
    rels.reset_index(drop=True, inplace=True)
    # Psiquiatria
    cats = ['Psiquia Depresion', 'Psiquia Otros antecedentes', 'Psiquia Sin antecedentes']
    data[['AntPsiquia']] = data[['AntPsiquia']].astype('category')
    psiq = pd.DataFrame(enc.fit_transform(data[['AntPsiquia']]).toarray())
    psiq.columns = enc.categories_
    for name in cats:
        if name not in psiq:
            psiq[name] = 0
    psiq = psiq[['Psiquia Depresion', 'Psiquia Otros antecedentes', 'Psiquia Sin antecedentes']]
    psiq.reset_index(drop=True, inplace=True)
    # Cardiologia
    cats = ['Cardio Isquemica', 'Cardio FA','Cardio otras','Cardio Sin antecedentes']
    data[['AntCardiologi']] = data[['AntCardiologi']].astype('category')
    card = pd.DataFrame(enc.fit_transform(data[['AntCardiologi']]).toarray())
    card.columns = enc.categories_
    for name in cats:
        if name not in card:
            card[name] = 0
    card = card[['Cardio Isquemica', 'Cardio FA','Cardio otras','Cardio Sin antecedentes']]
    card.reset_index(drop=True, inplace=True)
    # Neurologia
    cats = ['Neuro Ictus', 'Neuro Cefalea', 'Neuro Traumatismo','Neuro Epilepsia','Neuro Sin antecedentes']
    data[['AntNeurolog']] = data[['AntNeurolog']].astype('category')
    neur = pd.DataFrame(enc.fit_transform(data[['AntNeurolog']]).toarray())
    neur.columns = enc.categories_
    for name in cats:
        if name not in neur:
            neur[name] = 0
    neur = neur[['Neuro Ictus', 'Neuro Cefalea', 'Neuro Traumatismo','Neuro Epilepsia',
                 'Neuro Sin antecedentes']]
    neur.reset_index(drop=True, inplace=True)
    # Renal
    cats = ['Renal ERC', 'Renal Otras', 'Renal Sin Patologias']
    data[['AntRenal']] = data[['AntRenal']].astype('category')
    ren = pd.DataFrame(enc.fit_transform(data[['AntRenal']]).toarray())
    ren.columns = enc.categories_
    for name in cats:
        if name not in ren:
            ren[name] = 0
    ren = ren[['Renal ERC', 'Renal Otras', 'Renal Sin Patologias']]
    ren.reset_index(drop=True, inplace=True)
    # Pulmonar
    cats = ['Pulmonar EPOC', 'Pulmonar Cancer','Pulmonar Otras','Pulmonar Sin Patologias']
    data[['AntRenal']] = data[['AntRenal']].astype('category')
    pulm = pd.DataFrame(enc.fit_transform(data[['AntPulmonar']]).toarray())
    pulm.columns = enc.categories_
    for name in cats:
        if name not in pulm:
            pulm[name] = 0
    pulm = pulm[['Pulmonar EPOC', 'Pulmonar Cancer','Pulmonar Otras','Pulmonar Sin Patologias']]
    pulm.reset_index(drop=True, inplace=True)
    # Demencia
    cats = ['Demencia Padres', 'Demencia otros', 'Demencia Sin Antecedentes']
    data[['AntDemencia']] = data[['AntDemencia']].astype('category')
    dem = pd.DataFrame(enc.fit_transform(data[['AntDemencia']]).toarray())
    dem.columns = enc.categories_
    for name in cats:
        if name not in dem:
            dem[name] = 0
    dem = dem[['Demencia Padres', 'Demencia otros', 'Demencia Sin Antecedentes']]
    dem.reset_index(drop=True, inplace=True)
    # Tabaco
    cats = ['Ex/Fumador', 'No Fumador']
    data[['Tabaco']] = data[['Tabaco']].astype('category')
    tab = pd.DataFrame(enc.fit_transform(data[['Tabaco']]).toarray())
    tab.columns = enc.categories_
    for name in cats:
        if name not in tab:
            tab[name] = 0
    tab = tab[['Ex/Fumador', 'No Fumador']]
    tab.reset_index(drop=True, inplace=True)
    # Alcohol
    cats = ['Alcohol Elevado', 'Alcohol Moderado','Alcohol leve', 'Alcohol nunca']
    data[['Alcohol']] = data[['Alcohol']].astype('category')
    alc = pd.DataFrame(enc.fit_transform(data[['Alcohol']]).toarray())
    alc.columns = enc.categories_
    for name in cats:
        if name not in alc:
            alc[name] = 0
    alc = alc[['Alcohol Elevado', 'Alcohol Moderado','Alcohol leve', 'Alcohol nunca']]
    alc.reset_index(drop=True, inplace=True)

    # Drop column to add it at the end
    affected = data[['TNeurocog']]
    affected.reset_index(drop=True, inplace=True)

    # Drop original categorical columns
    data = data.drop(['Sexo', 'EstCivil', 'ActLaboral','FormatConvivencia',
                                'NivelEducativo', 'ActIntelectual', 'RelSociales','AntPsiquia',
                                'AntCardiologi','AntNeurolog','AntRenal','AntPulmonar',
                                'AntDemencia','Tabaco','Alcohol','TNeurocog'], axis=1)
    data.reset_index(drop=True, inplace=True)

    data = pd.concat([data, sexo, civil, laboral,
                                  convi, educ, intec,
                                  rels, psiq, card, neur, ren,
                                  pulm, dem, tab, alc,
                                  affected],axis=1)
    return data

# Dictionary to specify fields of synthetic data for Alzheimer-Balea database
alz_fields = {
    'Edad' : {
        'type' : 'numerical',
        'subtype' : 'integer'
    },
    'Sexo' : {
        'type' : 'categorical'
    },
    'EstCivil' : {
        'type' : 'categorical'
    },
    'ActLaboral' : {
        'type' : 'categorical'
    },
    'FormatConvivencia' : {
        'type' : 'categorical'
    },
    'NivelEducativo' : {
        'type' : 'categorical'
    },
    'ActIntelectual' : {
        'type' : 'categorical'
    },
    'RelSociales' : {
        'type' : 'categorical'
    },
    'AntPsiquia' : {
        'type' : 'categorical'
    },
    'AntCardiologi' : {
        'type' : 'categorical'
    },
    'AntNeurolog' : {
        'type' : 'categorical'
    },
    'AntRenal' : {
        'type' : 'categorical'
    },
    'AntPulmonar' : {
        'type' : 'categorical'
    },
    'AntDemencia' : {
        'type' : 'categorical'
    },
    'Tabaco' : {
        'type' : 'categorical'
    },
    'Alcohol' : {
        'type' : 'categorical'
    },
    'HTAanterior' : {
        'type' : 'numerical',
        'subtype' : 'integer'
    },
    'TAS' : {
        'type' : 'numerical',
        'subtype' : 'integer'
    },
    'TAD' : {
        'type' : 'numerical',
        'subtype' : 'integer'
    },
    'DM' : {
        'type' : 'numerical',
        'subtype' : 'integer'
    },
    'Barthel' : {
        'type' : 'numerical',
        'subtype' : 'integer'
    },
    'Hb' : {
        'type' : 'numerical',
        'subtype' : 'float'
    },
    'VCM' : {
        'type' : 'numerical',
        'subtype' : 'float'
    },
    'HCM' : {
        'type' : 'numerical',
        'subtype' : 'float'
    },
    'Plaquetas' : {
        'type' : 'numerical',
        'subtype' : 'float'
    },
    'Leucocitos' : {
        'type' : 'numerical',
        'subtype' : 'float'
    },
    'Neutrófilos' : {
        'type' : 'numerical',
        'subtype' : 'float'
    },
    'Linfocitos' : {
        'type' : 'numerical',
        'subtype' : 'float'
    },
    'Monocitos' : {
        'type' : 'numerical',
        'subtype' : 'float'
    },
    'Glucosa' : {
        'type' : 'numerical',
        'subtype' : 'float'
    },
    'Creatinina' : {
        'type' : 'numerical',
        'subtype' : 'float'
    },
    'FG' : {
        'type' : 'numerical',
        'subtype' : 'float'
    },
    'Na' : {
        'type' : 'numerical',
        'subtype' : 'float'
    },
    'K' : {
        'type' : 'numerical',
        'subtype' : 'float'
    },
    'ALT' : {
        'type' : 'numerical',
        'subtype' : 'float'
    },
    'LDL' : {
        'type' : 'numerical',
        'subtype' : 'float'
    },
    'TNeurocog' : {
        'type' : 'numerical',
        'subtype' : 'integer'
    },
 }

# Custom variable constraints to generate synthetic data
constraints = [
                #Positive('Edad',handling_strategy='reject_sampling'),
                #Binary('HTAanterior',handling_strategy='reject_sampling'),
                #Positive('TAS',handling_strategy='reject_sampling'),
                #Positive('TAD',handling_strategy='reject_sampling'),
                #Binary('DM',handling_strategy='reject_sampling'),
                # Positive('Barthel',handling_strategy='reject_sampling'),
                # Positive('Hb',handling_strategy='reject_sampling'),
                # Positive('VCM',handling_strategy='reject_sampling'),
                # Positive('HCM',handling_strategy='reject_sampling'),
                # Positive('Plaquetas',handling_strategy='reject_sampling'),
                # Positive('Leucocitos',handling_strategy='reject_sampling'),
                # Positive('Neutrófilos',handling_strategy='reject_sampling'),
                # Positive('Linfocitos',handling_strategy='reject_sampling'),
                # Positive('Monocitos',handling_strategy='reject_sampling'),
                # Positive('Glucosa',handling_strategy='reject_sampling'),
                # Positive('Creatinina',handling_strategy='reject_sampling'),
                # Positive('FG',handling_strategy='reject_sampling'),
                # Positive('Na',handling_strategy='reject_sampling'),
                # Positive('K',handling_strategy='reject_sampling'),
                # Positive('ALT',handling_strategy='reject_sampling'),
                # Positive('Colesterol',handling_strategy='reject_sampling'),
                # Positive('LDL',handling_strategy='reject_sampling'),
                #Binary('TNeurocog',handling_strategy='reject_sampling'),
                ]

# Distributions for each field (all set to univariate)
alz_distributions = {
    'Grupo' : 'univariate',
    'Edad' : 'univariate',
    'EstCivil' : 'univariate',
    'Actlaboral' : 'univariate',
    'FormatConvivencia' : 'univariate',
    'NivelEducativo' : 'univariate',
    'ActIntelectual' : 'univariate',
    'RelSociales' : 'univariate',
    'AntCardiologi' : 'univariate',
    'AntNeurolog' : 'univariate',
    'AntRenal' : 'univariate',
    'AntPulmonar' : 'univariate',
    'AntDemencia' : 'univariate',
    'Tabaco' : 'univariate',
    'Alcohol' : 'univariate',
    'HTAanterior' : 'univariate',
    'TAS' : 'univariate',
    'TAD' : 'univariate',
    'DM' : 'univariate',
    'Barthel' : 'univariate',
    'Hb' : 'univariate',
    'VCM' : 'univariate',
    'HCM' : 'univariate',
    'Plaquetas' : 'univariate',
    'Leucocitos' : 'univariate',
    'Neutrófilos' : 'univariate',
    'Linfocitos' : 'univariate',
    'Monocitos' : 'univariate',
    'Glucosa' : 'univariate',
    'Creatinina' : 'univariate',
    'FG' : 'univariate',
    'Na' : 'univariate',
    'K' : 'univariate',
    'ALT' : 'univariate',
    'Colesterol' : 'univariate',
    'LDL' : 'univariate',
    'TNeurocog' : 'univariate',
    }

################################################################################
#              CONSTANTS TO HANDLE/STORE/VISUALIZE OBTAINED RESULTS            #
################################################################################

# Path where directories are stored
DICT_PATH = r"C:\Users\aralmeida\OneDrive - Universidad de Las Palmas de Gran Canaria\Doctorado\codigo\synthetic_data_generation_framework\AlzheimerBALEA\results"

# Dataset name
dataset_name = 'ALZ-BALEA'

# Variables needed to handle dictionaries corresponding to the number of generated data samples
sizes_keys = ["quarter", "half", "unit", "double", "quadruple", "only-synth"]

# Balancing Methods
balance1 = "NC"
balance2 = "Borderline"

# Augmentation methods
augmen1 = "CTGAN"
augmen2 = "GC"

# Best and worst combinations
best_worst = ['Borderline + Sep. + GC', 'NC + CTGAN'] # might be wrong

# Best combination
best_method = 'Borderline + Sep. + GC' # might be wrong

# Name of the used Machine Learning models and associated colors
models = ['SVM','RF', 'XGB', 'KNN']
model_colors = ['b','r','k','g']

# Studied metrics
mets = ["PCD","MMD","KLD"]

# Strings containing combinations of SDG (Synthetic Data Generators)
comb1 = ("%s + %s") % (balance1, augmen1)
comb2 = ("%s + %s") % (balance1, augmen2)
comb3 = ("%s + %s") % (balance2, augmen1)
comb4 = ("%s + %s") % (balance2, augmen2)
comb5 = ("%s + Sep. + %s") % (balance1, augmen1)
comb6 = ("%s + Sep. + %s") % (balance1, augmen2)
comb7 = ("%s + Sep. + %s") % (balance2, augmen1)
comb8 = ("%s + Sep. + %s") % (balance2, augmen2)
comb9 = "%s" % (augmen1)
comb10 = "Sep. + %s" % (augmen1)

# Split CTGAN and Gaussian Copula methods to plot them separately
ctgan_combinations = [comb1, comb3, comb5, comb7]
gc_combinations = [comb2, comb4, comb6, comb8]

# Chosen colors for each synthetic data generation combinations
ctgan_colors = ["k","r","g","b"]
gc_colors = ["c","m","y","orange"]

################################################################################
#              CONSTANTS TO HANDLE/STORE/VISUALIZE OBTAINED RESULTS            #
################################################################################


import sys
import os
newPath = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir, os.path.pardir))
sys.path.append(newPath)

from datetime import datetime, timedelta
import unittest
from app import create_app, db
from app.models import User, Post
from config import Config

class TestConfig(Config):
    TESTING = True
    SQLALCHEMY_DATABASE_URI = 'sqlite://'
    ELASTICSEARCH_URL = None

class EditPostTestCase(unittest.TestCase):
    def setUp(self):
        self.app = create_app(TestConfig)
        self.client = self.app.test_client()
        self.app_context = self.app.app_context()
        self.app_context.push()
        db.create_all()

    def tearDown(self):
        db.session.remove()
        db.drop_all()
        self.app_context.pop()

    def test_edit_post(self):
        u = User(username='manraj')
        db.session.add(u)

        now = datetime.utcnow()
        p1 = Post(body="post from manraj", author=u,
                  timestamp=now + timedelta(seconds=1))
        db.session.add(p1)
        db.session.commit()

        p2 = Post(body="post from manraj but different", author=u,
                  timestamp=now + timedelta(seconds=1))
        p1 = p2
        db.session.add(p1)
        db.session.commit()

        self.assertEqual(p1, p2)

if __name__ == '__main__':
    unittest.main()


import sys
from PyQt5.QtWidgets import QDialog, QApplication
from messung1 import *

class MyMessungQT(QDialog):
    def __init__(self):
        super().__init__()
        self.ui=Ui_Messung()
        self.ui.setupUi(self)
        self.ui.Mstarten.clicked.connect(self.startMessung)
        self.ui.Mstoppen.clicked.connect(self.stopMessung)
        self.show()

    def startMessung(self):
        self.ui.Mstoppen.setEnabled(True)
        self.ui.Mstarten.setEnabled(False)

    def stopMessung(self):
        self.ui.Mstoppen.setEnabled(False)
        self.ui.Mstarten.setEnabled(True)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MyMessungQT()
    w.show()
    sys.exit(app.exec_())


from pyfirmata2 import Arduino
from time import sleep
import matplotlib.pyplot as plt

signal = []

def my_cb(data):
    # print(data)
    signal.append(data)
    #pass

board = Arduino(Arduino.AUTODETECT)

board.samplingOn(10)  # ms

board.analog[0].register_callback(my_cb)
board.analog[0].enable_reporting()

lenPin = board.get_pin('d:3:p')

lum = 0
delta_lum = 0.05;

for t in range(50):
    sleep(0.5)
    if lum > 1.0 or lum < 0:
        delta_lum = -delta_lum
    lum += delta_lum
    lenPin.write(lum)

lenPin.write(0)

plt.plot(signal)
plt.show()

board.exit()


"""

Authors: Shubham Ugare.

Copyright:
Copyright (c) 2020 Microsoft Research
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

"""

import numpy.random
import numpy as np
import common
import os, sys
import onnx
from onnx import helper
import math
from onnx import numpy_helper

def main():
    if len(sys.argv) < 3:
        print("Model file or scaling factor unspecified.", file=sys.stderr)
        exit(1)

    file_name = sys.argv[1]
    scaling_factor = int(sys.argv[2])
    file_path = "models/" + file_name
    model_name = file_name[:-5]  # name without the '.onnx' extension
    model = onnx.load(file_path)
    graph_def = model.graph

    # Generating input
    input_dims = common.proto_val_to_dimension_tuple(model.graph.input[0])
    input_array = numpy.random.random(input_dims)
    # input_array = numpy.ones(input_dims, dtype=float)
    print("Generated random input of dimension " + str(input_dims))
    np.save("debug/" + model_name + "/" + model_name + "_input", input_array)

    (chunk, cnt) = common.numpy_float_array_to_fixed_point_val_str(
        input_array, scaling_factor
    )
    f = open("debug/" + model_name + "/" + model_name + "_input.inp", "w")
    f.write(chunk)
    f.close()

    model_name_to_val_dict = {
        init_vals.name: numpy_helper.to_array(init_vals).tolist()
        for init_vals in model.graph.initializer
    }

    preprocess_batch_normalization(graph_def, model_name_to_val_dict)

    chunk_n = ""
    cnt_n = 0
    for init_vals in model.graph.initializer:
        (chunk_1, cnt_1) = common.numpy_float_array_to_fixed_point_val_str(
            np.asarray(model_name_to_val_dict[init_vals.name], dtype=np.float32),
            scaling_factor,
        )
        chunk_n += chunk_1
        cnt_n += cnt_1

    f = open("debug/" + model_name + "/" + model_name + "_weights.inp", "w")
    f.write(chunk_n)
    f.close()

    f = open(
        "debug/" + model_name + "/" + model_name + "_combined_input_weights.inp", "w"
    )
    f.write(chunk + chunk_n)
    f.close()

    print(
        "Total "
        + str(cnt + cnt_n)
        + " integers were written in "
        + model_name
        + "_combined_input_weights.inp"
    )

def preprocess_batch_normalization(graph_def, model_name_to_val_dict):
    # set names to graph nodes if not present
    for node in graph_def.node:
        node.name = node.output[0]
        # Update the batch normalization scale and B
        # so that mean and var are not required
        if node.op_type == "BatchNormalization":
            # scale
            gamma = model_name_to_val_dict[node.input[1]]
            # B
            beta = model_name_to_val_dict[node.input[2]]
            mean = model_name_to_val_dict[node.input[3]]
            var = model_name_to_val_dict[node.input[4]]
            for i in range(len(gamma)):
                rsigma = 1 / math.sqrt(var[i] + 1e-5)
                gamma[i] = gamma[i] * rsigma
                beta[i] = beta[i] - gamma[i] * mean[i]
                mean[i] = 0
                var[i] = 1 - 1e-5

    # Just testing if the correct values are put
    model_name_to_val_dict2 = {}
    for init_vals in graph_def.initializer:
        # TODO: Remove float_data
        model_name_to_val_dict2[init_vals.name] = init_vals.float_data
    for node in graph_def.node:
        node.name = node.output[0]
        if node.op_type == "BatchNormalization":
            mean = model_name_to_val_dict[node.input[3]]
            for val in mean:
                assert val == 0

if __name__ == "__main__":
    main()


import cv2

face_cascade = cv2.CascadeClassifier("user/haarcascade_frontalface_default.xml")
src = cv2.imread('user/2020-11-30_16h13_39.png')
#http://localhost/fs/pub/533a250b/2020-11-30_12h54_46.png
#http://localhost/fs/pub/533a250b/2020-11-30_16h13_39.png
src_gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)

faces = face_cascade.detectMultiScale(src_gray)

for x, y, w, h in faces:
    cv2.rectangle(src, (x, y), (x + w, y + h), (255, 0, 0), 2)
    face = src[y: y + h, x: x + w]
    face_gray = src_gray[y: y + h, x: x + w]
    #eyes = eye_cascade.detectMultiScale(face_gray)
    #for ex, ey, ew, eh in eyes:
    #    cv2.rectangle(face, (ex, ey), (ex + ew, ey + eh), (0, 255, 0), 2)
cv2.imshow("face", src)


import json
from typing import Any
from typing import Dict

from src.code.logger import create_logger
from src.code.model.custom_enums import MessageGroup
from src.code.model.custom_enums import MessageType
from src.code.model.request import Request

logger = create_logger(__name__)

class SlackEventType:
    def __init__(self, event: Dict):
        self._event: Dict = event

    def get_event_type(self) -> MessageType:
        if self._event.get("type") == "message":
            # Test for new main message
            if self._event.get("subtype") is None:
                if self._event.get("thread_ts") is not None:
                    logger.info("Message type is: %s", MessageType.THREAD_NEW.value)
                    return MessageType.THREAD_NEW
                else:
                    logger.info("Message type is: %s", MessageType.MAIN_NEW.value)
                    return MessageType.MAIN_NEW

            # Test for new main file share
            if self._event.get("subtype") == "file_share":
                if self._event.get("thread_ts") is not None:
                    logger.info("Message type is: %s", MessageType.THREAD_NEW_FILE.value)
                    return MessageType.THREAD_NEW_FILE
                else:
                    logger.info("Message type is: %s", MessageType.MAIN_NEW.value)
                return MessageType.MAIN_NEW_FILE

            # Test for editing message - if true the main message exists
            if self._event.get("subtype") == "message_changed":
                record = Request().get_request(channel_id=self._event["channel"], event_ts=self._event["message"]["ts"])
                if record is not None:
                    if self._event["message"]["text"] == "This message was deleted.":
                        logger.info("Message type is: %s", MessageType.MAIN_REMOVE.value)
                        return MessageType.MAIN_REMOVE

                    else:
                        logger.info("Message type is: %s", MessageType.MAIN_EDIT.value)
                        return MessageType.MAIN_EDIT
                else:
                    logger.info("Message type is: %s", MessageType.THREAD_EDIT.value)
                    return MessageType.THREAD_EDIT
        elif self._event.get("type") == "reaction_added":
            logger.info("Message type is: %s", MessageType.REACTION_ADD.value)
            return MessageType.REACTION_ADD
        elif self._event.get("type") == "reaction_removed":
            logger.info("Message type is: %s", MessageType.REACTION_REMOVE.value)
            return MessageType.REACTION_REMOVE
        raise ValueError("Failed to find event type on event %s", json.dumps(self._event))

    def get_event_group(self) -> Any:
        if self._event.get("subtype") == "message_changed":
            return MessageGroup.EDIT.value
        return MessageGroup.NEW.value


""" Patch plone.app.layout ver 2.2.7, due to #9518
"""
from plone.app.layout.navigation import root as nav_root
from Products.CMFCore.utils import getToolByName
from zope.component.hooks import getSite

def getNavigationRootObject(context, portal):
    """ Patched getNavigationRootObject in order to return site root
    """
    if context is None:
        return None

    ### patch #9518 return root + context language as navigationRootObject
    # #16662 define portal as it might be an empty parameter when using a
    # dexterity object
    portal = portal or getSite()
    portal_url = '/'.join(portal.getPhysicalPath())
    if portal_url[-1] != '/':
        portal_url += '/'
    lang = context.Language()
    # check if portal_url is /www as this code could be reached from tests
    # where we don't have SITE
    if portal_url != '/www/':
        return portal
    if lang:
        # use  same logic for getting the navigationRootObject like the
        # one used and explained in getNavigationRoot
        context_path_root = context.getPhysicalPath()
        context_path_root = context_path_root[2] if \
                    len(context_path_root) > 2 else context_path_root[-1]
        lang = lang if lang != 'en' else 'SITE'
        if context_path_root != lang:
            return portal.get(context_path_root)
        return portal.get(lang)
    return portal
    ### end patch

def getNavigationRoot(context, relativeRoot=None):
    """Get the path to the root of the navigation tree.

    If a relativeRoot argument is provided, navigation root is computed from
    portal path and this relativeRoot.

    If no relativeRoot argument is provided, and there is a root value set in
    portal_properties, navigation root path is computed from
    portal path and this root value.

    IMPORTANT !!!
    Previous paragraphs imply relativeRoot is relative to the Plone portal.

    Else, a root must be computed : loop from the context to the portal,
    through parents, looking for an object implementing INavigationRoot.
    Return the path of that root.
    """
    portal_url = getToolByName(context, 'portal_url')

    if relativeRoot is None:
        # fetch from portal_properties
        portal_properties = getToolByName(context, 'portal_properties')
        navtree_properties = getattr(portal_properties, 'navtree_properties')
        relativeRoot = navtree_properties.getProperty('root', None)

    ### Original code:

    ## if relativeRoot has a meaningful value,
    #if relativeRoot and relativeRoot != '/':
    #    # use it
    #
    #    # while taking care of case where
    #    # relativeRoot is not starting with a '/'
    #    if relativeRoot[0] != '/':
    #        relativeRoot = '/' + relativeRoot

    #    portalPath = portal_url.getPortalPath()
    #    return portalPath + relativeRoot

    ### Start patch

    if relativeRoot:
        if relativeRoot[0] != '/':
            relativeRoot = '/' + relativeRoot

        portalPath = portal_url.getPortalPath()
        # return old logic if portalPath isn't /www
        if portalPath != '/www':
            return portalPath + relativeRoot
        lang = context.Language()
        portal = portal_url.getPortalObject()
        if lang:
            lang = lang if lang != 'en' else 'SITE'
            context_path_root = context.getPhysicalPath()
            # check if length of physicalPath is greater than 2 as we might
            # get a result where we are on the root path and it results in
            # ('', 'www')
            context_path_root = context_path_root[2] if \
                    len(context_path_root) > 2 else context_path_root[-1]
            # context_path_root will return the path after www, from the
            # context, if it is not equal to lang then it means that the
            # context is of different language from the root of the context
            # but we should use that context_path_root in order to preserve
            # correct listing ex: /www/SITE/tests/romanian-page should return
            # /www/SITE as the navigationRoot and not /www/ro even thou the
            # page is romanian since it is created in the /www/SITE english
            # folder
            if context_path_root != lang:
                return portalPath + '/' + context_path_root
            return portalPath + '/' + lang
        return portalPath + relativeRoot
    ### End patch

    else:
        # compute the root
        portal = portal_url.getPortalObject()
        root = getNavigationRootObject(context, portal)
        return '/'.join(root.getPhysicalPath())

nav_root.getNavigationRoot = getNavigationRoot
nav_root.getNavigationRootObject = getNavigationRootObject