import pygame
import os
from subprocess import call

pygame.init()
class Door:
    def __init__(self, surface, subject, file):
        self.door_sprite = pygame.image.load(os.path.join("assets", "door_sprite.png"))
        self.subject = subject
        self.text = subject
        self.display_surface = surface
        self.file = file
        self.i = 0

    def draw_door(self, x, y):
        font = pygame.font.SysFont("comicsans", 18)
        text = font.render(self.text, 1, (0,0,0))
        textRect = text.get_rect()
        textRect.center = (x + 50, y - 25)

        picture = pygame.transform.scale(self.door_sprite, (100, 150))
        self.display_surface.blit(picture, (x, y))
        self.display_surface.blit(text, textRect)

    def handle_file(self):
        # for ev in pygame.event.get():
        #     if ev.type == pygame.key:
        #         print('keydown')
        #         if ev.key == pygame.K_e:
        #             call(['python', self.file])

        keys = pygame.key.get_pressed()
        if keys[pygame.K_e] and self.i <= 0:
            call(['python', self.file])
            self.i+=1

    def collide(self, player, x, y):
        doorRect = pygame.Rect(x, y, self.door_sprite.get_width(), self.door_sprite.get_height())
        if doorRect.colliderect(player):
            self.text = "Vajutage E nuppu"
            self.handle_file()
        else:
            self.text = self.subject

    def run(self, x, y, player):
        self.draw_door(x,y)
        self.collide(player, x, y)


from datetime import date

from src.lib.parser import MeetupEvent, get_event
from telegram import Bot, ChatAction, Message, ParseMode

DATE_FORMAT = "%A, %-d %B %Y %-I:%M %p"  # e.g. Monday, 7 March 2022 7:00 PM

REMINDER_TEMPLATE = """
Please RSVP to the following event:

Event: {title}
Date: {date}

This has been a \U00002728 public service announcement \U00002728
"""

class MeetupReminderBot:
    def __init__(self, token: str, chat_id: str):
        self.bot = Bot(token=token)
        self.chat_id = chat_id

    @staticmethod
    def craft_reminder(event: MeetupEvent) -> str:
        """Populates `REMINDER_TEMPLATE` with metadata from `event`.

        Parameters
        ----------
        event : MeetupEvent
            Meetup event metadata to populate `REMINDER_TEMPLATE` with

        Returns
        -------
        reminder : str
            The reminder message to be sent
        """
        return REMINDER_TEMPLATE.format(
            url=event.url, title=event.title, date=event.date.strftime(DATE_FORMAT)
        )

    def send_reminder(
        self, group_name: str, event_date: date, event_regex: str = ".*"
    ) -> Message:
        """Sends reminder to RSVP to Meetup events.

        Parameters
        ----------
        group_name : str
            Meetup group name, used to find out the next event to RSVP to
        event_date : date
            Date for the next event to RSVP to
        event_regex : str, optional
            Regular expression to optionally filter events by
            Defaults to ".*" (matches all events)

        Returns
        -------
        message : Message
            Telegram message metadata
        """
        event = get_event(group_name, event_date, event_regex=event_regex)
        reminder = MeetupReminderBot.craft_reminder(event)

        self.bot.send_chat_action(chat_id=self.chat_id, action=ChatAction.TYPING)

        return self.bot.send_message(
            chat_id=self.chat_id, text=reminder, parse_mode=ParseMode.HTML
        )


from models.GridEval import GridEval
from sklearn import tree
class DecisionTree(GridEval):
    """run the Decision Tree model
    """

    def decisionRunGrid(self, classWeight = None):
        """Set the parameters to select from for Random Grid Search
        Output:
        the best model returned by random grid search
        """
        print("\n"+"DECISION TREE"+"\n")
        max_features = ['auto']
        criterion = ['gini']
        max_depth = [x for x in range(1,50,15)]
        dec_param= {    'max_features': max_features,
                        'max_depth': max_depth,
                        'criterion': criterion,
                        'random_state': [42],
                        'class_weight': [classWeight]
                    }
        dectree = tree.DecisionTreeClassifier()
        return(self.randomGrid(dectree,dec_param,5))

    def decisionBest(self):
        """define the best performing decision tree model for application_train.csv
        """
        print("\n"+"DECISION TREE"+"\n")
        self.model = tree.DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=46,
                       max_features='auto', max_leaf_nodes=None,
                       min_impurity_decrease=0.0, min_impurity_split=None,
                       min_samples_leaf=1, min_samples_split=2,
                       min_weight_fraction_leaf=0.0, presort=False,
                       random_state=42, splitter='best')
        self.evaluate()


"""
A confederação de natação precisa de um programa que leia o ano de nascimento e mostre a categoria
ate 9 anos Mirim
até 14 anos Infantil
até 19 anos Junior
ate 20 anos Senior
acima Master
"""
import datetime
nascimento = int(input('Ano de nascimento:'))
ano_atual = datetime.date.today().year
idade = ano_atual - nascimento

if idade < 9:
    print('O nadador está na categoria MIRIM.')
elif 9 < idade < 14:
    print('O nadador está na categoria INFANTIL.')
elif 14 < idade < 19:
    print('O nadador está na categoria JUNIOR.')
elif 19 < idade < 20:
    print('O nadador está na categoria SENIOR.')
else:
    print('O nadador já se enquadra na categoria MASTER.')
print('O Atleta possui {} anos nesse momento.'.format(idade))


from pymongo import MongoClient
from bson.objectid import ObjectId
import logger2
import random

c = MongoClient()
db = c['alkows']

# === ADDING === #
def add_creature_species(sp):
    logger2.logger.debug("add_creature_species")
    db.bestiary.insert_one(sp)

def add_flora_species(fsp):
    logger2.logger.debug("add_flora_species")
    db.herbarium.insert_one(fsp)

def add_creature(cret):
    logger2.logger.debug("add_creature")
    db.population.insert_one(cret)

def add_test_creature(cret):
    logger2.logger.debug("add_creature")
    x = db.population.insert_one(cret)
    return x

def add_flora(flora):
    logger2.logger.debug("add_flora")
    db.flora_pop.insert_one(flora)

# === REMOVING === #
def remove_test_crets():
    logger2.logger.error("remove_test_crets")
    query = { "species_type" : {'$regex':'^testcreature'}}
    db.population.delete_many(query)

def remove_test_species():
    query = { "species_type" : {'$regex':'^testcreature'}}
    db.bestiary.delete_many(query)

def remove_individual_byid(id):
    logger2.logger.info("remove_individual_byid")
    db.population.delete_one( { "_id" : id } )

def clear_db():
    logger2.logger.debug("clear_db")
    db.bestiary.drop()
    db.population.drop()
    db.herbarium.drop()
    db.flora_pop.drop()
    db.history.drop()

def full_extinction_event(collection):
    msg = collection, "full extinction event has been implemented"
    logger2.logger.info(msg)
    if collection == "bestiary":
        db.bestiary.drop()
    elif collection == "population":
        db.population.drop()
    elif collection == "herbarium":
        db.herbarium.drop()
    elif collection == "flora_pop":
        db.flora_pop.drop()

# percent is very approximate, random choice from list may choose the same unit twice.
# actual percentage may be lower
def mass_extinction_event(collection, percent):
    msg = collection, "mass extinction event has been implemented"
    logger2.logger.info(msg)

    if collection == "bestiary":
        all = db.bestiary.find()

        all_lst = []
        for i in all:
            all_lst.append(i['species_type'])

        lenlist = len(all_lst)
        ct_for_removal = round(lenlist * percent/100)
        print(ct_for_removal)
        for j in range(1, ct_for_removal+1):
            x = random.choice(all_lst)
            db.bestiary.delete_one( { "species_type": x})

    if collection == "population":
        all = db.population.find()

        all_lst = []
        for i in all:
            all_lst.append(i['_id'])

        lenlist = len(all_lst)
        ct_for_removal = round(lenlist * percent/100)
        print(ct_for_removal)
        for j in range(1, ct_for_removal+1):
            x = random.choice(all_lst)
            db.population.delete_one( { "_id" : x } )

    if collection == "herbarium":
        all = db.herbarium.find()

        all_lst = []
        for i in all:
            all_lst.append(i['flora_species_type'])

        lenlist = len(all_lst)
        ct_for_removal = round(lenlist * percent/100)
        print(ct_for_removal)
        for j in range(1, ct_for_removal+1):
            x = random.choice(all_lst)
            db.herbarium.delete_one( { 'flora_species_type' : x } )

    if collection == "flora_pop":
        all = db.flora_pop.find()

        all_lst = []
        for i in all:
            all_lst.append(i['_id'])

        lenlist = len(all_lst)
        ct_for_removal = round(lenlist * percent/100)
        print("should be 75%", ct_for_removal)
        for j in range(1, ct_for_removal+1):
            x = random.choice(all_lst)
            db.flora_pop.delete_one( { "_id" : x } )

# === READING === #

def get_rand_pop():
    logger2.logger.info("get_rand_pop")
    cursor = db.population.aggregate([{"$sample" : {'size': 4}}])
    return cursor

def find_latest_addition():
    logger2.logger.debug("find_latest_addition")
    x = db.population.find().sort("_id",-1).limit(1)
    return x

def list_beasts():
    logger2.logger.debug("list_beasts")
    beasts = db.bestiary.find()
    beast_list = []
    for i in beasts:
        beast_list.append(i['species_type'])
    return beast_list

def list_flora():
    logger2.logger.debug("list_flora")
    flora = db.herbarium.find()
    flora_list = []
    for i in flora:
        flora_list.append(i['flora_species_type'])
    return flora_list

def get_bestiary():
    logger2.logger.debug("get_bestiary")
    beasts = db.bestiary.find()
    bestiary = {}
    for i in beasts:
        bestiary.update({i['species_type']:i})
    logger2.logger.debug(bestiary)
    return bestiary

def get_herbarium():
    logger2.logger.debug("get_herbarium")
    flora = db.herbarium.find()
    herbarium = {}
    for i in flora:
        herbarium.update({i['flora_species_type']:i})
    logger2.logger.debug(herbarium)
    return herbarium

def get_cret_census():
    logger2.logger.debug("get_census")
    cret_collection = db.population.find()
    cret_dict = {}
    for i in cret_collection:
        cret_dict.update({i['_id']:i})
    return cret_dict

def get_flora_census():
    logger2.logger.debug("get_flora_census")
    flora_collection = db.flora_pop.find()
    flora_dict = {}
    for i in flora_collection:
        flora_dict.update({i['_id']:i})
    return flora_dict

def get_collection(collection_name):
    cursor = db.collection_name.find()
    census_dict = {}
    for i in cursor:
        census_dict.update({i['_id']:i})
    return census_dict

# for c_bestiary
def get_bestiary():
    full_bestiary = []
    for x in  db.bestiary.find({},{"species_type": 1 , "phylum": 1, "size": 1, "exoskeleton_color": 1, "eyes": 1, "legs": 1}):
        full_bestiary.append(x)
    return full_bestiary

def get_population():
    logger2.logger.debug("get_population")
    # get _ids
    population = db.population.find()
    actors_list = []
    for i in population:
        actors_list.append(i['_id'])
    return actors_list

def get_flora_population():
    logger2.logger.debug("get_flora_population")
    # get _ids
    flora_pop = db.flora_pop.find()
    flora_list = []
    for i in flora_pop:
        flora_list.append(i['_id'])
    return flora_list

def read_creature_species(a , b):
    logger2.logger.debug("read_species")
    cursor = db.bestiary.find({ a : b })
    return cursor

def read_creature_species_du(a , b):
    logger2.logger.debug("read_species")
    species_dict = db.bestiary.find_one({ a : b })
    return species_dict

def read_flora_species(a,b):
    logger2.logger.debug("read flora species")
    cursor = db.herbarium.find({a:b})
    return cursor

def read_flora_species_du(a,b):
    logger2.logger.info("read flora species")
    cursor = db.herbarium.find_one({a:b})
    return cursor

def read_population(a,b):
    logger2.logger.debug("read_population")
    cursor = db.population.find({ a : b })
    return cursor

def read_creature_parent(id):    # REPLACE THIS WITH 3RD
    logger2.logger.debug("read_creature_parent")
    parent_dict = db.population.find_one({"_id" : id})
    return parent_dict

# findone returns a dict rather than a cursor
def read_ind_by_id(id):    # REPLACE OTHER TWO WITH THIS ONE
    logger2.logger.debug("read_creature_parent")
    ind_dict = db.population.find_one({"_id" : ObjectId(id)})
    return ind_dict

# used in testing - see test_division
def read_ind_by_name(name):
    logger2.logger.info("read_ind_by_name")
    ind_dict = db.population.find_one({"species_type" : name})
    return ind_dict

##############################################################

def read_flora_ind_byid(id):
    logger2.logger.debug("read_flora_ind_byid")
    cursor = db.flora_pop.find({"_id" : ObjectId(id)})
    return cursor

# returns a list of tuples (creature id, species type, active_task)
def get_locals(x,y,fov):
    logger2.logger.debug("get_locals")

    # compass equivalent {"and": [{"x": {"$gt": 200}}, {"x": {"$lt": 300}}]}
    x = db.population.find({"$and": [{"x": {"$gt": x - fov}},
                                     {"x": {"$lt": x + fov}},
                                     {"y": {"$gt": y - fov}},
                                      {"y": {"$lt": y + fov}}
                                    ]})

    local_crets = []
    for i in x:
        local_crets.append((i['_id'], i['species_type'], i['active_task']))

    # list of tuples (cret id, species type, active_task)
    return local_crets

# update = {"x": 500, "y": 590}
# update_cret_byid("6400b0b89089706e43621b46", update)
def update_cret_byid(id, update):
    logger2.logger.debug("update_cret_byid")

    id = {"_id" : ObjectId(id)}
    #logger2.logger.info(str(id))

    new_vals = { "$set" : update }
    #logger2.logger.info(str(new_vals))

    db.population.update_one(id, new_vals)

def update_flora_byid(id, update):
    logger2.logger.debug("update_flora_byid")

    id = {"_id" : ObjectId(id)}
    #logger2.logger.debug(str(id))

    new_vals = { "$set" : update }
    #logger2.logger.debug(str(new_vals))

    db.flora_pop.update_one(id, new_vals)

def update_species_by_name(name, update):
    logger2.logger.debug("update_species_by_name")
    by_name = {"species_type": name}
    x = db.bestiary.update_one(by_name, update)
    print(x.modified_count)

def add_to_mortuary(unit):
    logger2.logger.debug("add_to_mortuary")
    try:
        db.mortuary.insert_one(unit)
    except Exception as e:
        msg = "send to log file: ", e

def check_for_dup(species,x,y):
    logger2.logger.debug("check_for_dup")
    cursor = db.flora_pop.find({ "flora_species_type" : species })
    return cursor

# ===== WORLD =====
def get_world_data(world_name):
    logger2.logger.debug("get_world_data")
    cursor = db.world.find({ "world_name" : world_name })
    return cursor

def update_world(world_name, update):
    logger2.logger.debug("update_world_data")

    name = {"world_name" : world_name }
    new_vals = { "$set" : update }
    db.world.update_one(name, new_vals)

# === HISTORICAL === #
def get_hist_data(id):
    logger2.logger.debug("get_hist_data")
    cursor = db.history.find_one({"_id" : id })
    return cursor

def add_history(h):
    logger2.logger.debug("add_history_byid")
    db.history.insert_one(h)

def update_history_byid(id, update):
    logger2.logger.debug("update_cret_byid")

    id = {"_id" : ObjectId(id)}
    #logger2.logger.info(str(id))

    new_vals = { "$set" : update }
    #logger2.logger.info(str(new_vals))

    db.history.update_one(id, new_vals)


#!/usr/bin/env python

import atexit
import csv
import inspect
import json
import logging
import os
import signal
import sys
import time
import click
import panapi
from panapi.config import \
    iam, \
    security, \
    identity, \
    objects, \
    network, \
    subscription, \
    tenancy, \
    mobile

__author__ = "Palo Alto Networks"
__copyright__ = "Copyright 2023, Palo Alto Networks"
__credits__ = ["Robert Hagen", "Anton Coleman"]
__license__ = "MIT"
__version__ = ".2"
__maintainer__ = "Anton Coleman"
__email__ = "acoleman@paloaltonetworks.com"
__status__ = "Community"

# TODO Add Exception Handling

def setup_logger(logger_name, log_file, file_level=logging.DEBUG, stream_level=logging.INFO):
    l = logging.getLogger(logger_name)
    formatter = logging.Formatter('%(asctime)s : %(levelname)s : %(name)s : %(message)s')
    fileHandler = logging.FileHandler(log_file, mode='w')
    fileHandler.setLevel(file_level)
    fileHandler.setFormatter(formatter)
    streamHandler = logging.StreamHandler()
    streamHandler.setLevel(stream_level)
    streamHandler.setFormatter(formatter)
    l.setLevel(logging.DEBUG)
    l.addHandler(fileHandler)
    l.addHandler(streamHandler)
    return l

logger = setup_logger('config_logger', '/app/resources/log/config_exporter.log', file_level=logging.DEBUG,
                      stream_level=logging.INFO)

def create_session():
    """

    Returns: Session Object

    """
    try:
        logger.info(f'Generating new session')
        session = panapi.PanApiSession()
        session.authenticate()
        logger.info(f'Session Generated')
        time.sleep(1)
        return session
    except Exception as e:
        logger.critical(f'Failed with exception: {e}')
        return f'Failed with exception: {e}'

###############################################################
# Extract all available configuration from Prisma Access Tenant
###############################################################
@click.command()
@click.option('--folders', multiple=True, default=["Shared,Service Connections,Mobile Users,"
                                                   "Mobile Users Explicit Proxy,Remote Networks"])
@click.option('--filename', default='config.json')
@click.option('--docker', default=True)
def get_configuration(folders, filename, docker):
    """

    Args:
        filename: Filename of the exported JSON configuration
        folders: Prisma Access Folders to utilize for queries
        session: SASE Authentication Token
    Returns:

    """
    session = create_session()
    excluded_objects = ["Application", "Certificate"]
    inspect_objects = [mobile, iam, objects, network, security, identity, subscription, tenancy]
    config = {'predefined': {}}

    if docker:
        filename = f'/app/resources/config/{filename}'

    def get_items(session, folder, key, obj):
        """Get the items from the API endpoint.

        Args:
            session (PanApiSession): The authenticated API session.
            folder (str): The folder to retrieve the items from.
            obj (object): The object that represents the endpoint.

        Returns:
            list: A list of items or "Not Found" if no items are found.
        """
        predefined = []
        shared = []

        def unpack_items(items, rule=False, sc=False, ba=False, mu=False):
            """Unpack the items from the API response.

            Args:
                items (list): The list of items to unpack.

            Returns:
                list: A list of unpacked items.
            """
            if items is not None:
                unpacked = []
                for item in items:
                    logger.debug(f'Checking if {item} has a payload attribute')
                    if hasattr(item, "payload"):
                        if hasattr(item, "_headers"):
                            delattr(item, '_headers')
                        logger.debug(f'Checking if {item} has a folder attribute')
                        if hasattr(item, 'folder'):
                            logger.debug(f'Checking if {item} folder is predefined')
                            if item.folder in ["All", "Prisma Access", "predefined"]:
                                logger.debug(f'Determined {item} is predefined because {item.folder} matches')
                                if rule:
                                    logger.debug(
                                        f'Determined {item} is predefined default rule because {item.folder} matches')
                                else:
                                    predefined.append(item.payload)
                            elif item.folder == 'Shared':
                                logger.debug(f'Determined {item} is shared because {item.folder} matches')
                                shared.append(item.payload)
                            else:
                                logger.debug(f'Determined {item} matches folder {folder}')
                                unpacked.append(item.payload)
                        else:
                            logger.debug(f'Determined {item} does not have a folder')
                            unpacked.append(item.payload)

                if len(unpacked) > 0:
                    logger.debug(f'Returning list of items for {items} that are NOT predefined')
                    if sc:
                        return {'Service Connections': unpacked}
                    elif ba:
                        return {'Remote Networks': unpacked}
                    elif mu:
                        return {'Mobile Users': unpacked}
                    else:
                        # logger.debug(f'Returning list of items for {items} that ARE Shared')
                        # return {'Shared': unpacked}
                        return {folder: unpacked}
                if len(predefined) > 0:
                    logger.debug(f'Returning list of items for {items} that ARE predefined')
                    return {'predefined': predefined}
                if len(shared) > 0:
                    logger.debug(f'Returning list of items for {items} that ARE Shared')
                    return {'Shared': shared}

        if hasattr(obj, '_position'):
            unpacked_dict = {}
            for idx, position in enumerate(obj._position):
                logger.debug(f'Iterating for {key} at position: {position} in folder: {folder}')
                items = obj(folder=folder, position=position)
                item_list = items.list(session)
                if item_list is not None:
                    logger.debug(f'Unpacking items for {key} at position: {position}')
                    unpacked = unpack_items(item_list, rule=True)
                    logger.debug(f'Unpacked items for {key} at position: {position}')
                    if folder == list(unpacked.keys())[0]:
                        if folder in unpacked_dict:
                            unpacked_dict[folder][position] = unpacked[folder]
                        else:
                            unpacked_dict[folder] = {position: unpacked[folder]}
                else:
                    logger.debug(f'Nothing to retrieve for {key} at position: {position}')
            return unpacked_dict
        if hasattr(obj, '_no_folder'):
            items = obj(no_folder=True)
            item_list = items.list(session)
            if item_list is not None:
                unpacked = unpack_items(item_list)
                return unpacked
            else:
                logger.debug(f'Nothing to retrieve for {key} object passed with no folder')
                return "Not Found"
        else:
            mu_pinning = ["global_settings", "infrastructure_settings", "locations"]
            items = obj(folder=folder)
            item_list = items.list(session)
            if item_list is not None:
                if key == "service_connections":
                    unpacked = unpack_items(item_list, sc=True)
                    return unpacked
                elif key == "remote_networks":
                    unpacked = unpack_items(item_list, ba=True)
                    return unpacked
                elif key in mu_pinning:
                    unpacked = unpack_items(item_list, mu=True)
                    return unpacked
                else:
                    unpacked = unpack_items(item_list)
                    return unpacked
            else:
                logger.debug(f'Nothing to retrieve for {key} object passed')
                return "Not Found"

    def match_folder(folder, items={}):
        if items:
            if folder in items:
                if len(items[folder]) > 0:
                    return True
                else:
                    return False
            else:
                return False
        else:
            return False

    try:
        if not isinstance(folders, list):

            folders = (''.join(map(str, folders))).split(",")
            logger.debug(f'Convert click option to list: {folders}')

        for folder in folders:
            logger.info(f'Updating configuration for folder: {folder}')
            config.update({folder: {}})
            for inspected_obj in inspect_objects:
                section = str(inspected_obj.__name__).split('panapi.config.')[1]
                config[folder].update({section: {}})
                if section not in config['predefined']:
                    config['predefined'].update({section: {}})
                for name, obj in inspect.getmembers(inspected_obj):
                    if name in excluded_objects:
                        # SKIP Endpoint
                        continue
                    else:
                        if hasattr(obj, '_endpoint'):
                            endpoint = str(obj._endpoint)
                            logger.info(f'Acquired endpoint: {endpoint}')
                            key_name = (endpoint.rsplit("/", 1)[1]).replace("-", "_")
                            if hasattr(obj, '_required'):
                                if folder in obj._required:
                                    logger.info(f'Getting required items for: {key_name} for folder: {folder}')
                                    items = get_items(session, folder, key_name, obj)
                                    if match_folder(folder, items):
                                        config[folder][section].update({key_name: items[folder]})
                                    elif match_folder('predefined', items):
                                        if key_name not in config['predefined'][section]:
                                            config['predefined'][section].update({key_name: items['predefined']})
                                        else:
                                            continue
                                    elif match_folder('Shared', items):
                                        if key_name not in config['Shared'][section] and items is not None:
                                            config['Shared'][section].update({key_name: items['Shared']})
                                        else:
                                            continue
                                    else:
                                        continue
                            else:
                                logger.info(f'Getting non required items for: {key_name}')
                                items = get_items(session, folder, key_name, obj)
                                if match_folder(folder, items):
                                    config[folder][section].update({key_name: items[folder]})
                                else:
                                    if match_folder('predefined', items):
                                        if key_name not in config['predefined'][section]:
                                            config['predefined'][section].update({key_name: items['predefined']})
                                        else:
                                            continue
        # Remove empty keys
        empty_keys = [k for k, v in config.items() if not v]
        for k in empty_keys:
            logger.debug(f'Removing empty key: {k}')
            del config[k]
        # Cleanup empty dicts
        config = {key: {inner_key: inner_value for inner_key, inner_value in value.items()
                        if bool(inner_value)} for key, value in config.items()}
        # return config
        generate_json_file(filename, config)

    except Exception as e:
        logger.critical(f'Failed to acquire configuration with error: {e}')
        print(e)

###############################
# Generates a JSON file output.
###############################
def generate_json_file(filename, rules):
    """
        Args:
            filename: the actual filename to generate for json
            rules: Dictionary of rules generated from the get_rules() function
    """
    logger.info('Saving configuration as json....')
    try:
        with open(filename, 'w') as f:
            # Convert dictionary to JSON
            json.dump(rules, f, indent=4)
        logger.info('Finished exporting to json')
    except Exception as e:
        logger.error(f'Failed to save the json file with error: {e}')
        raise e

###############################
# Generates a CSV file output.
###############################
def generate_csv_rules(folders, rules_dict, type, suffix):
    """

    Args:
        suffix: Append string suffix to csv file
        folders: List of Prisma Access folders to cycle through
        rules_dict: Dictionary of rules generated from the get_rules() function
        type: # Str value for the rule type to modify csv filename

    Returns:

    """
    try:
        for folder in folders:
            for position in ['pre', 'post']:
                if position in rules_dict[folder]:
                    if len(rules_dict[folder][position]) > 0:
                        folder_data = rules_dict[folder][position]
                        new_csv = open(f'{folder.lower()}_{type.lower()}_{position}_{suffix}.csv',
                                       'w', newline='', encoding='utf-8')
                        csv_writer = csv.writer(new_csv)
                        count = 0

                        for item in folder_data:
                            if count == 0:
                                # Writing headers of CSV file
                                header = item.keys()
                                csv_writer.writerow(header)
                                count += 1

                            # Writing data of CSV file
                            csv_writer.writerow(item.values())
                        new_csv.close()
    except Exception as e:
        raise e

def cleanup():
    os.kill(os.getpid(), signal.SIGINT)

if __name__ == '__main__':
    try:
        get_configuration()
        atexit.register(cleanup)
    except Exception as e:
        print(e)
        sys.exit(1)


from django.conf.urls import url
from . import views

urlpatterns = [
	url(r'^$', views.index, name='index'),
	url(r'^step/', views.physics_step, name='physics_step'),
	url(r'^engine/', views.fire_engine, name='fire_engine'),
	url(r'^thruster/', views.fire_thruster, name='fire_thruster'),
	url(r'^ship/', views.ship_view, name ='ship_view'),
	url(r'^teleport/', views.teleport, name='teleport'),
]


from django.contrib.auth.models import AbstractUser
from django.db import models

from .enums import Role

class User(AbstractUser):
    REQUIRED_FIELDS = ('first_name', 'last_name', 'username',)
    USERNAME_FIELD = 'email'
    ROLES = [
        ('user', Role.USER),
        ('admin', Role.ADMIN),
    ]

    email = models.EmailField(
        max_length=254, unique=True, blank=False,
        verbose_name='Электронная почта',
    )
    role = models.CharField(
        max_length=20, choices=ROLES,
        default='user', verbose_name='Право достапа',
    )
    bio = models.TextField(
        blank=True, verbose_name='Биография',
    )
    confirmation_code = models.CharField(
        max_length=255, blank=True, null=True,
        verbose_name='Код подтверждения',
    )

    @property
    def is_admin(self):
        return self.role == self.ADMIN or self.is_superuser

    class Meta:
        verbose_name = 'Пользователь'
        verbose_name_plural = 'Пользователи'
        ordering = ('username',)

    def __str__(self):
        return self.username


from enum import Enum
from os import getcwd
from os.path import expanduser
from typing import Union, List, Iterable

try:
    # noinspection PyPackageRequirements
    import wx
    # noinspection PyPackageRequirements
    from wx.lib.agw import multidirdialog as mdd
except ImportError:
    wx, mdd = None, None
    raise ImportError('install wx to use wx ui functions')

# noinspection PyArgumentList
DialogStyle = Enum('DialogStyle', 'open save multiple')
Filter = Union[str, List[str]]

_file_dialog_style = {DialogStyle.open: wx.FD_OPEN | wx.FD_FILE_MUST_EXIST,
                      DialogStyle.save: wx.FD_SAVE,
                      DialogStyle.multiple: wx.FD_OPEN | wx.FD_MULTIPLE | wx.FD_FILE_MUST_EXIST}

def _select_item(dialog, style: DialogStyle) -> Union[str, List[str]]:
    dialog.SetSize(0, 0, 200, 50)
    result = dialog.ShowModal()
    if result == wx.ID_CANCEL:
        raise KeyboardInterrupt
    if style == DialogStyle.multiple:
        chosen_path = dialog.GetPaths()
    else:
        chosen_path = dialog.GetPath() if hasattr(dialog, 'GetPath') else dialog.GetPaths()[0]
    dialog.Destroy()
    return chosen_path

def file_to_open(ext: Filter="", default_dir: str=getcwd(),
                 style: DialogStyle=DialogStyle.open) -> Union[str, List[str]]:
    if isinstance(ext, str):
        wildcard = "{0}|*{1}".format(ext[1:], ext)  # no space between pipe and wildcard
    elif isinstance(ext, list) or isinstance(ext, tuple):  # Default (*) | * would not give anything
        wildcard = "{0}|{1}".format(ext[0][1:], ';'.join('*' + x for x in ext))
    else:
        raise ValueError('file filter error: ' + str(ext))
    _ = wx.App()
    open_file_dialog = wx.FileDialog(None, "Select File", defaultDir=default_dir, wildcard=wildcard,
                                     style=_file_dialog_style[style])
    return _select_item(open_file_dialog, style)

def files_to_open(ext: Filter="", default_dir: str=getcwd()) -> List[str]:
    return file_to_open(ext, default_dir, DialogStyle.multiple)

def file_to_save(ext: Filter="", default_dir: str=getcwd()) -> str:
    return file_to_open(ext, default_dir, DialogStyle.save)

_folder_dialog_style = {DialogStyle.open: mdd.DD_DIR_MUST_EXIST,
                        DialogStyle.save: mdd.DD_NEW_DIR_BUTTON,
                        DialogStyle.multiple: mdd.DD_DIR_MUST_EXIST | mdd.DD_MULTIPLE}

def _folder_dialog_filter(folder: str) -> str:
    return expanduser('~' + folder[14:]) if folder.startswith('Home directory') else folder

def folder_to_open(default_dir: str=getcwd(), style: DialogStyle=DialogStyle.open) -> Union[str, Iterable[str]]:
    _ = wx.App()
    open_folder_dialog = wx.lib.agw.multidirdialog.MultiDirDialog(
        None, "Select Folder", defaultPath=default_dir, agwStyle=_folder_dialog_style[style])
    selection = _select_item(open_folder_dialog, style)
    if isinstance(selection, str):
        return _folder_dialog_filter(selection)
    elif isinstance(selection, Iterable):
        return (_folder_dialog_filter(x) for x in selection)

def folders_to_open(default_dir: str=getcwd()) -> Iterable[str]:
    return folder_to_open(default_dir, style=DialogStyle.multiple)

def folder_to_save(default_dir: str=getcwd()) -> str:
    return folder_to_open(default_dir, style=DialogStyle.save)


__all__ = ['ANTsImage',
           'LabelImage',
           'copy_image_info',
           'set_origin',
           'get_origin',
           'set_direction',
           'get_direction',
           'set_spacing',
           'get_spacing',
           'image_physical_space_consistency',
           'image_type_cast',
           'allclose']

import os

import numpy as np
import pandas as pd

try:
    from functools import partialmethod
    HAS_PY3 = True
except:
    HAS_PY3 = False

import inspect

from .. import registration, segmentation, utils, viz
from . import ants_image_io as iio2

_supported_ptypes = {'unsigned char', 'unsigned int', 'float', 'double'}
_supported_dtypes = {'uint8', 'uint32', 'float32', 'float64'}
_itk_to_npy_map = {
    'unsigned char': 'uint8',
    'unsigned int': 'uint32',
    'float': 'float32',
    'double': 'float64'}
_npy_to_itk_map = {
    'uint8': 'unsigned char',
    'uint32':'unsigned int',
    'float32': 'float',
    'float64': 'double'}

class ANTsImage(object):

    def __init__(self, pixeltype='float', dimension=3, components=1, pointer=None, is_rgb=False, label_image=None):
        """
        Initialize an ANTsImage

        Arguments
        ---------
        pixeltype : string
            ITK pixeltype of image

        dimension : integer
            number of image dimension. Does NOT include components dimension

        components : integer
            number of pixel components in the image

        pointer : py::capsule (optional)
            pybind11 capsule holding the pointer to the underlying ITK image object

        label_image : LabelImage
            a discrete label image for mapping locations to atlas regions

        """
        ## Attributes which cant change without creating a new ANTsImage object
        self.pointer = pointer
        self.pixeltype = pixeltype
        self.dimension = dimension
        self.components = components
        self.has_components = self.components > 1
        self.dtype = _itk_to_npy_map[self.pixeltype]
        self.is_rgb = is_rgb

        self._pixelclass = 'vector' if self.has_components else 'scalar'
        self._shortpclass = 'V' if self._pixelclass == 'vector' else ''
        if is_rgb:
            self._pixelclass = 'rgb'
            self._shortpclass = 'RGB'

        self._libsuffix = '%s%s%i' % (self._shortpclass, utils.short_ptype(self.pixeltype), self.dimension)

        self.shape = utils.get_lib_fn('getShape%s'%self._libsuffix)(self.pointer)
        self.physical_shape = tuple([round(sh*sp,3) for sh,sp in zip(self.shape, self.spacing)])

        if label_image is not None:
            if not isinstance(label_image, LabelImage):
                raise ValueError('label_image argument must be a LabelImage type')
            self.label_image = label_image

        self._array = None

    @property
    def spacing(self):
        """
        Get image spacing

        Returns
        -------
        tuple
        """
        libfn = utils.get_lib_fn('getSpacing%s'%self._libsuffix)
        return libfn(self.pointer)

    def set_spacing(self, new_spacing):
        """
        Set image spacing

        Arguments
        ---------
        new_spacing : tuple or list
            updated spacing for the image.
            should have one value for each dimension

        Returns
        -------
        None
        """
        if not isinstance(new_spacing, (tuple, list)):
            raise ValueError('arg must be tuple or list')
        if len(new_spacing) != self.dimension:
            raise ValueError('must give a spacing value for each dimension (%i)' % self.dimension)

        libfn = utils.get_lib_fn('setSpacing%s'%self._libsuffix)
        libfn(self.pointer, new_spacing)

    @property
    def origin(self):
        """
        Get image origin

        Returns
        -------
        tuple
        """
        libfn = utils.get_lib_fn('getOrigin%s'%self._libsuffix)
        return libfn(self.pointer)

    def set_origin(self, new_origin):
        """
        Set image origin

        Arguments
        ---------
        new_origin : tuple or list
            updated origin for the image.
            should have one value for each dimension

        Returns
        -------
        None
        """
        if not isinstance(new_origin, (tuple, list)):
            raise ValueError('arg must be tuple or list')
        if len(new_origin) != self.dimension:
            raise ValueError('must give a origin value for each dimension (%i)' % self.dimension)

        libfn = utils.get_lib_fn('setOrigin%s'%self._libsuffix)
        libfn(self.pointer, new_origin)

    @property
    def direction(self):
        """
        Get image direction

        Returns
        -------
        tuple
        """
        libfn = utils.get_lib_fn('getDirection%s'%self._libsuffix)
        return libfn(self.pointer)

    def set_direction(self, new_direction):
        """
        Set image direction

        Arguments
        ---------
        new_direction : numpy.ndarray or tuple or list
            updated direction for the image.
            should have one value for each dimension

        Returns
        -------
        None
        """
        if isinstance(new_direction, (tuple,list)):
            new_direction = np.asarray(new_direction)

        if not isinstance(new_direction, np.ndarray):
            raise ValueError('arg must be np.ndarray or tuple or list')
        if len(new_direction) != self.dimension:
            raise ValueError('must give a origin value for each dimension (%i)' % self.dimension)

        libfn = utils.get_lib_fn('setDirection%s'%self._libsuffix)
        libfn(self.pointer, new_direction)

    @property
    def orientation(self):
        if self.dimension == 3:
            return self.get_orientation()
        else:
            return None

    def view(self, single_components=False):
        """
        Geet a numpy array providing direct, shared access to the image data.
        IMPORTANT: If you alter the view, then the underlying image data
        will also be altered.

        Arguments
        ---------
        single_components : boolean (default is False)
            if True, keep the extra component dimension in returned array even
            if image only has one component (i.e. self.has_components == False)

        Returns
        -------
        ndarray
        """
        if self.is_rgb:
            img = self.rgb_to_vector()
        else:
            img = self
        dtype = img.dtype
        shape = img.shape[::-1]
        if img.has_components or (single_components == True):
            shape = list(shape) + [img.components]
        libfn = utils.get_lib_fn('toNumpy%s'%img._libsuffix)
        memview = libfn(img.pointer)
        return np.asarray(memview).view(dtype = dtype).reshape(shape).view(np.ndarray).T

    def numpy(self, single_components=False):
        """
        Get a numpy array copy representing the underlying image data. Altering
        this ndarray will have NO effect on the underlying image data.

        Arguments
        ---------
        single_components : boolean (default is False)
            if True, keep the extra component dimension in returned array even
            if image only has one component (i.e. self.has_components == False)

        Returns
        -------
        ndarray
        """
        array = np.array(self.view(single_components=single_components), copy=True, dtype=self.dtype)
        if self.has_components or (single_components == True):
            array = np.rollaxis(array, 0, self.dimension+1)
        return array

    def clone(self, pixeltype=None):
        """
        Create a copy of the given ANTsImage with the same data and info, possibly with
        a different data type for the image data. Only supports casting to
        uint8 (unsigned char), uint32 (unsigned int), float32 (float), and float64 (double)

        Arguments
        ---------
        dtype: string (optional)
            if None, the dtype will be the same as the cloned ANTsImage. Otherwise,
            the data will be cast to this type. This can be a numpy type or an ITK
            type.
            Options:
                'unsigned char' or 'uint8',
                'unsigned int' or 'uint32',
                'float' or 'float32',
                'double' or 'float64'

        Returns
        -------
        ANTsImage
        """
        if pixeltype is None:
            pixeltype = self.pixeltype

        if pixeltype not in _supported_ptypes:
            raise ValueError('Pixeltype %s not supported. Supported types are %s' % (pixeltype, _supported_ptypes))

        if self.has_components and (not self.is_rgb):
            comp_imgs = utils.split_channels(self)
            comp_imgs_cloned = [comp_img.clone(pixeltype) for comp_img in comp_imgs]
            return utils.merge_channels(comp_imgs_cloned)
        else:
            p1_short = utils.short_ptype(self.pixeltype)
            p2_short = utils.short_ptype(pixeltype)
            ndim = self.dimension
            fn_suffix = '%s%i%s%i' % (p1_short,ndim,p2_short,ndim)
            libfn = utils.get_lib_fn('antsImageClone%s'%fn_suffix)
            pointer_cloned = libfn(self.pointer)
            return ANTsImage(pixeltype=pixeltype,
                            dimension=self.dimension,
                            components=self.components,
                            is_rgb=self.is_rgb,
                            pointer=pointer_cloned)

    # pythonic alias for `clone` is `copy`
    copy = clone

    def astype(self, dtype):
        """
        Cast & clone an ANTsImage to a given numpy datatype.

        Map:
            uint8   : unsigned char
            uint32  : unsigned int
            float32 : float
            float64 : double
        """
        if dtype not in _supported_dtypes:
            raise ValueError('Datatype %s not supported. Supported types are %s' % (dtype, _supported_dtypes))

        pixeltype = _npy_to_itk_map[dtype]
        return self.clone(pixeltype)

    def new_image_like(self, data):
        """
        Create a new ANTsImage with the same header information, but with
        a new image array.

        Arguments
        ---------
        data : ndarray or py::capsule
            New array or pointer for the image.
            It must have the same shape as the current
            image data.

        Returns
        -------
        ANTsImage
        """
        if not isinstance(data, np.ndarray):
            raise ValueError('data must be a numpy array')
        if not self.has_components:
            if data.shape != self.shape:
                raise ValueError('given array shape (%s) and image array shape (%s) do not match' % (data.shape, self.shape))
        else:
            if (data.shape[-1] != self.components) or (data.shape[:-1] != self.shape):
                raise ValueError('given array shape (%s) and image array shape (%s) do not match' % (data.shape[1:], self.shape))

        return iio2.from_numpy(data, origin=self.origin,
            spacing=self.spacing, direction=self.direction,
            has_components=self.has_components)

    def to_file(self, filename):
        """
        Write the ANTsImage to file

        Args
        ----
        filename : string
            filepath to which the image will be written
        """
        filename = os.path.expanduser(filename)
        libfn = utils.get_lib_fn('toFile%s'%self._libsuffix)
        libfn(self.pointer, filename)
    to_filename = to_file

    def apply(self, fn):
        """
        Apply an arbitrary function to ANTsImage.

        Args
        ----
        fn : python function or lambda
            function to apply to ENTIRE image at once

        Returns
        -------
        ANTsImage
            image with function applied to it
        """
        this_array = self.numpy()
        new_array = fn(this_array)
        return self.new_image_like(new_array)

    def as_label_image(self, label_info=None):
        return LabelImage(image=self, label_info=label_info)

    ## NUMPY FUNCTIONS ##
    def abs(self, axis=None):
        """ Return absolute value of image """
        return np.abs(self.numpy())
    def mean(self, axis=None):
        """ Return mean along specified axis """
        return self.numpy().mean(axis=axis)
    def median(self, axis=None):
        """ Return median along specified axis """
        return np.median(self.numpy(), axis=axis)
    def std(self, axis=None):
        """ Return std along specified axis """
        return self.numpy().std(axis=axis)
    def sum(self, axis=None, keepdims=False):
        """ Return sum along specified axis """
        return self.numpy().sum(axis=axis, keepdims=keepdims)
    def min(self, axis=None):
        """ Return min along specified axis """
        return self.numpy().min(axis=axis)
    def max(self, axis=None):
        """ Return max along specified axis """
        return self.numpy().max(axis=axis)
    def range(self, axis=None):
        """ Return range tuple along specified axis """
        return (self.min(axis=axis), self.max(axis=axis))
    def argmin(self, axis=None):
        """ Return argmin along specified axis """
        return self.numpy().argmin(axis=axis)
    def argmax(self, axis=None):
        """ Return argmax along specified axis """
        return self.numpy().argmax(axis=axis)
    def argrange(self, axis=None):
        """ Return argrange along specified axis """
        amin = self.argmin(axis=axis)
        amax = self.argmax(axis=axis)
        if axis is None:
            return (amin, amax)
        else:
            return np.stack([amin, amax]).T
    def flatten(self):
        """ Flatten image data """
        return self.numpy().flatten()
    def nonzero(self):
        """ Return non-zero indices of image """
        return self.numpy().nonzero()
    def unique(self, sort=False):
        """ Return unique set of values in image """
        unique_vals = np.unique(self.numpy())
        if sort:
            unique_vals = np.sort(unique_vals)
        return unique_vals

    ## OVERLOADED OPERATORS ##
    def __add__(self, other):
        this_array = self.numpy()

        if isinstance(other, ANTsImage):
            if not image_physical_space_consistency(self, other):
                raise ValueError('images do not occupy same physical space')
            other = other.numpy()

        new_array = this_array + other
        return self.new_image_like(new_array)

    def __sub__(self, other):
        this_array = self.numpy()

        if isinstance(other, ANTsImage):
            if not image_physical_space_consistency(self, other):
                raise ValueError('images do not occupy same physical space')
            other = other.numpy()

        new_array = this_array - other
        return self.new_image_like(new_array)

    def __mul__(self, other):
        this_array = self.numpy()

        if isinstance(other, ANTsImage):
            if not image_physical_space_consistency(self, other):
                raise ValueError('images do not occupy same physical space')
            other = other.numpy()

        new_array = this_array * other
        return self.new_image_like(new_array)

    def __truediv__(self, other):
        this_array = self.numpy()

        if isinstance(other, ANTsImage):
            if not image_physical_space_consistency(self, other):
                raise ValueError('images do not occupy same physical space')
            other = other.numpy()

        new_array = this_array / other
        return self.new_image_like(new_array)

    def __pow__(self, other):
        this_array = self.numpy()

        if isinstance(other, ANTsImage):
            if not image_physical_space_consistency(self, other):
                raise ValueError('images do not occupy same physical space')
            other = other.numpy()

        new_array = this_array ** other
        return self.new_image_like(new_array)

    def __gt__(self, other):
        this_array = self.numpy()

        if isinstance(other, ANTsImage):
            if not image_physical_space_consistency(self, other):
                raise ValueError('images do not occupy same physical space')
            other = other.numpy()

        new_array = this_array > other
        return self.new_image_like(new_array.astype('uint8'))

    def __ge__(self, other):
        this_array = self.numpy()

        if isinstance(other, ANTsImage):
            if not image_physical_space_consistency(self, other):
                raise ValueError('images do not occupy same physical space')
            other = other.numpy()

        new_array = this_array >= other
        return self.new_image_like(new_array.astype('uint8'))

    def __lt__(self, other):
        this_array = self.numpy()

        if isinstance(other, ANTsImage):
            if not image_physical_space_consistency(self, other):
                raise ValueError('images do not occupy same physical space')
            other = other.numpy()

        new_array = this_array < other
        return self.new_image_like(new_array.astype('uint8'))

    def __le__(self, other):
        this_array = self.numpy()

        if isinstance(other, ANTsImage):
            if not image_physical_space_consistency(self, other):
                raise ValueError('images do not occupy same physical space')
            other = other.numpy()

        new_array = this_array <= other
        return self.new_image_like(new_array.astype('uint8'))

    def __eq__(self, other):
        this_array = self.numpy()

        if isinstance(other, ANTsImage):
            if not image_physical_space_consistency(self, other):
                raise ValueError('images do not occupy same physical space')
            other = other.numpy()

        new_array = this_array == other
        return self.new_image_like(new_array.astype('uint8'))

    def __ne__(self, other):
        this_array = self.numpy()

        if isinstance(other, ANTsImage):
            if not image_physical_space_consistency(self, other):
                raise ValueError('images do not occupy same physical space')
            other = other.numpy()

        new_array = this_array != other
        return self.new_image_like(new_array.astype('uint8'))

    def __getitem__(self, idx):
        if self._array is None:
            self._array = self.numpy()

        if isinstance(idx, ANTsImage):
            if not image_physical_space_consistency(self, idx):
                raise ValueError('images do not occupy same physical space')
            return self._array.__getitem__(idx.numpy().astype('bool'))
        else:
            return self._array.__getitem__(idx)

    def __setitem__(self, idx, value):
        arr = self.view()
        if isinstance(idx, ANTsImage):
            if not image_physical_space_consistency(self, idx):
                raise ValueError('images do not occupy same physical space')
            arr.__setitem__(idx.numpy().astype('bool'), value)
        else:
            arr.__setitem__(idx, value)

    def __repr__(self):
        if self.dimension == 3:
            s = 'ANTsImage ({})\n'.format(self.orientation)
        else:
            s = 'ANTsImage\n'
        s = s +\
            '\t {:<10} : {} ({})\n'.format('Pixel Type', self.pixeltype, self.dtype)+\
            '\t {:<10} : {}{}\n'.format('Components', self.components, ' (RGB)' if 'RGB' in self._libsuffix else '')+\
            '\t {:<10} : {}\n'.format('Dimensions', self.shape)+\
            '\t {:<10} : {}\n'.format('Spacing', tuple([round(s,4) for s in self.spacing]))+\
            '\t {:<10} : {}\n'.format('Origin', tuple([round(o,4) for o in self.origin]))+\
            '\t {:<10} : {}\n'.format('Direction', np.round(self.direction.flatten(),4))
        return s

if HAS_PY3:
    # Set partial class methods for any functions which take an ANTsImage as the first argument
    for k, v in utils.__dict__.items():
        if callable(v):
            args = inspect.getfullargspec(getattr(utils,k)).args
            if (len(args) > 0) and (args[0] in {'img','image'}):
                setattr(ANTsImage, k, partialmethod(v))

    for k, v in registration.__dict__.items():
        if callable(v):
            args = inspect.getfullargspec(getattr(registration,k)).args
            if (len(args) > 0) and (args[0] in {'img','image'}):
                setattr(ANTsImage, k, partialmethod(v))

    for k, v in segmentation.__dict__.items():
        if callable(v):
            args = inspect.getfullargspec(getattr(segmentation,k)).args
            if (len(args) > 0) and (args[0] in {'img','image'}):
                setattr(ANTsImage, k, partialmethod(v))

    for k, v in viz.__dict__.items():
        if callable(v):
            args = inspect.getfullargspec(getattr(viz,k)).args
            if (len(args) > 0) and (args[0] in {'img','image'}):
                setattr(ANTsImage, k, partialmethod(v))

class Dictlist(dict):
    def __setitem__(self, key, value):
        try:
            self[key]
        except KeyError:
            super(Dictlist, self).__setitem__(key, [])
        self[key].append(value)

class LabelImage(ANTsImage):
    """
    A LabelImage is a special class of ANTsImage which has discrete values
    and string labels or other metadata (e.g. another string label such as the
    "lobe" of the region) associated with each of the discrete values.
    A canonical example of a LabelImage is a brain label_image or parcellation.

    This class provides convenient functionality for manipulating and visualizing
    images where you have real values associated with aggregated image regions (e.g.
    if you have cortical thickness values associated with brain regions)

    Commonly-used functionality for LabelImage types:
        - create publication-quality figures of an label_image

    Nomenclature
    ------------
    - key : a string representing the name of the associated index in the atlas image
        - e.g. if the index is 1001 and the key may be InferiorTemporalGyrus`
    - value : an integer value in the atlas image
    - metakey : a string representing one of the possible sets of label key
        - e.g. 'Lobes' or 'Regions'
    Notes
    -----
    - indexing works by creating a separate dict for each metakey, where
    """
    def __init__(self, label_image, label_info=None, template=None):
        """
        Initialize a LabelImage

        ANTsR function: N/A

        Arguments
        ---------
        label_image : ANTsImage
            discrete (integer) image as label_image

        label_info : dict or pandas.DataFrame
            mapping between discrete values in `image` and string names
            - if dict, the keys should be the discrete integer label values
              and the values should be the label names or another dict with
              any metadata
            - if pd.DataFrame, the index (df.index) should be the discrete integer
              label values and the other column(s) should be the label names and
              any metadata

        template : ANTsImage
            default real-valued image to use for plotting or creating new images.
            This image should be in the same space as the `label_image` image and the
            two should be aligned.

        Example
        -------
        >>> import ants
        >>> square = np.zeros((20,20))
        >>> square[:10,:10] = 0
        >>> square[:10,10:] = 1
        >>> square[10:,:10] = 2
        >>> square[10:,10:] = 3
        >>> img = ants.from_numpy(square).astype('uint8')
        >>> label_image = ants.LabelImage(label_image=img, label_info=label_dict)
        """
        if label_image.pixeltype not in {'unsigned char', 'unsigned int'}:
            raise ValueError('Label images must have discrete pixeltype - got %s' % label_image.pixeltype)
        if label_image.components > 1:
            raise ValueError('Label images must have only one component - got %i' % label_image.components)

        if label_info is None:
            label_info = {k:'Label%i'%k for k in range(len(label_image.unique()))}

        if isinstance(label_info, pd.DataFrame):
            pass
        elif isinstance(label_info, dict):
            if isinstance(label_info[list(label_info.keys())[0]], dict):
                label_info = pd.DataFrame(label_info).T.to_dict()
            else:
                label_info = pd.DataFrame(label_info, index=np.arange(len(label_info))).T.to_dict()
        else:
            raise ValueError('label_label_info argument must be pd.DataFrame')

        self.label_info = label_info
        self.label_image = label_image
        self.template = template
        self.generate_data()

        super(LabelImage, self).__init__(pixeltype=label_image.pixeltype, dimension=label_image.dimension,
            components=label_image.components, pointer=label_image.pointer)

    def generate_data(self):
        self._metakeys = list(self.label_info.columns)
        self._uniquekeys = {mk:list(np.unique(self.label_info[mk])) for mk in self._metakeys}
        self._keys = {mk:list(self.label_info[mk]) for mk in self._metakeys}
        self._values = list(self.label_info.index)
        self._n_values = len(self._values)

        items = {}
        for mk in self._metakeys:
            items[mk] = {}
            for k, v in zip(self.keys(mk), self.values()):
                if k in items[mk]:
                    if isinstance(items[mk][k], list):
                        items[mk][k].append(v)
                    else:
                        items[mk][k] = [items[mk][k]] + [v]
                else:
                    items[mk][k] = v
        self._items = items

    def uniquekeys(self, metakey=None):
        """
        Get keys for a given metakey
        """
        if metakey is None:
            return self._uniquekeys
        else:
            if metakey not in self.metakeys():
                raise ValueError('metakey %s does not exist' % metakey)
            return self._uniquekeys[metakey]

    def keys(self, metakey=None):
        if metakey is None:
            return self._keys
        else:
            if metakey not in self.metakeys():
                raise ValueError('metakey %s does not exist' % metakey)
            return self._keys[metakey]

    def metakeys(self):
        return self._metakeys

    def parentkey(self, key):
        parent = None
        for mk in self.metakeys():
            if key in self.keys(mk):
                parent = mk
        if parent is None:
            raise ValueError('key does not have a parent')
        return parent

    def values(self):
        return self._values

    def items(self, metakey):
        if metakey not in self.metakeys():
            raise ValueError('metakey %s does not exist' % metakey)
        return self._items[metakey]

    def n_values(self):
        return self._n_values

    def __getitem__(self, key):
        # get metakey of key
        metakey = self.parentkey(key)
        # get key,value pairs for metakey
        items = self.items(metakey)
        # return value at the given key
        return items[key]

    def __setitem__(self, key, value):
        label_value = self.__getitem__(key)
        if isinstance(label_value, list):
            if isinstance(value, list):
                if len(value) != len(label_value):
                    raise ValueError('must give either single value or one value '+\
                                     'for each index (got %i, expected %i)' % (len(value), len(label_value)))
                    for old_val, new_val in zip(label_value, value):
                        self.label_image[self.label_image==old_val] = new_val
                else:
                    for lv in label_value:
                        self.label_image[self.label_image==lv] = value
        else:
            self.label_image[self.label_image==label_value] = value

    def __repr__(self):
        s = 'LabelImage\n' +\
            '\t {:<10} : {} ({})\n'.format('Pixel Type', self.pixeltype, self.dtype)+\
            '\t {:<10} : {}\n'.format('Components', self.components)+\
            '\t {:<10} : {}\n'.format('Dimensions', self.shape)+\
            '\t {:<10} : {}\n'.format('Spacing', self.spacing)+\
            '\t {:<10} : {}\n'.format('Origin', self.origin)+\
            '\t {:<10} : {}\n'.format('Direction', self.direction.flatten())+\
            '\t {:<10} : {}\n'.format('Num Values', self.n_values())
        return s

def copy_image_info(reference, target):
    """
    Copy origin, direction, and spacing from one antsImage to another

    ANTsR function: `antsCopyImageInfo`

    Arguments
    ---------
    reference : ANTsImage
        Image to get values from.
    target  : ANTsImAGE
        Image to copy values to

    Returns
    -------
    ANTsImage
        Target image with reference header information
    """
    target.set_origin(reference.origin)
    target.set_direction(reference.direction)
    target.set_spacing(reference.spacing)
    return target

def set_origin(image, origin):
    """
    Set origin of ANTsImage

    ANTsR function: `antsSetOrigin`
    """
    image.set_origin(origin)

def get_origin(image):
    """
    Get origin of ANTsImage

    ANTsR function: `antsGetOrigin`
    """

    return image.origin

def set_direction(image, direction):
    """
    Set direction of ANTsImage

    ANTsR function: `antsSetDirection`
    """
    image.set_direction(direction)

def get_direction(image):
    """
    Get direction of ANTsImage

    ANTsR function: `antsGetDirection`
    """
    return image.direction

def set_spacing(image, spacing):
    """
    Set spacing of ANTsImage

    ANTsR function: `antsSetSpacing`
    """
    image.set_spacing(spacing)

def get_spacing(image):
    """
    Get spacing of ANTsImage

    ANTsR function: `antsGetSpacing`
    """
    return image.spacing

def image_physical_space_consistency(image1, image2, tolerance=1e-2, datatype=False):
    """
    Check if two or more ANTsImage objects occupy the same physical space

    ANTsR function: `antsImagePhysicalSpaceConsistency`

    Arguments
    ---------
    *images : ANTsImages
        images to compare

    tolerance : float
        tolerance when checking origin and spacing

    data_type : boolean
        If true, also check that the image data types are the same

    Returns
    -------
    boolean
        true if images share same physical space, false otherwise
    """
    images = [image1, image2]

    img1 = images[0]
    for img2 in images[1:]:
        if (not isinstance(img1, ANTsImage)) or (not isinstance(img2, ANTsImage)):
            raise ValueError('Both images must be of class `AntsImage`')

        # image dimension check
        if img1.dimension != img2.dimension:
            return False

        # image spacing check
        space_diffs = sum([abs(s1-s2)>tolerance for s1, s2 in zip(img1.spacing, img2.spacing)])
        if space_diffs > 0:
            return False

        # image origin check
        origin_diffs = sum([abs(s1-s2)>tolerance for s1, s2 in zip(img1.origin, img2.origin)])
        if origin_diffs > 0:
            return False

        # image direction check
        origin_diff = np.allclose(img1.direction, img2.direction, atol=tolerance)
        if not origin_diff:
            return False

        # data type
        if datatype == True:
            if img1.pixeltype != img2.pixeltype:
                return False

            if img1.components != img2.components:
                return False

    return True

def image_type_cast(image_list, pixeltype=None):
    """
    Cast a list of images to the highest pixeltype present in the list
    or all to a specified type

    ANTsR function: `antsImageTypeCast`

    Arguments
    ---------
    image_list : list/tuple
        images to cast

    pixeltype : string (optional)
        pixeltype to cast to. If None, images will be cast to the highest
        precision pixeltype found in image_list

    Returns
    -------
    list of ANTsImages
        given images casted to new type
    """
    if not isinstance(image_list, (list,tuple)):
        raise ValueError('image_list must be list of ANTsImage types')

    pixtypes = []
    for img in image_list:
        pixtypes.append(img.pixeltype)

    if pixeltype is None:
        pixeltype = 'unsigned char'
        for p in pixtypes:
            if p == 'double':
                pixeltype = 'double'
            elif (p=='float') and (pixeltype!='double'):
                pixeltype = 'float'
            elif (p=='unsigned int') and (pixeltype!='float') and (pixeltype!='double'):
                pixeltype = 'unsigned int'

    out_images = []
    for img in image_list:
        if img.pixeltype == pixeltype:
            out_images.append(img)
        else:
            out_images.append(img.clone(pixeltype))

    return out_images

def allclose(image1, image2):
    """
    Check if two images have the same array values
    """
    return np.allclose(image1.numpy(), image2.numpy())


from collections import deque

n, m, v = map(int, input().split())
graph = [[] for _ in range(n)]
v = v - 1
for _ in range(m):
    a, b = map(int, input().split())
    graph[a - 1].append(b - 1)
    graph[b - 1].append(a - 1)

for _ in range(n):
    graph[_].sort()

def bfs(v):
    visited = [0] * n
    result = []
    queue = deque()
    queue.append(v)
    result.append(v)
    visited[v] = True
    while queue:
        pt = queue.popleft()
        for i in graph[pt]:
            if not visited[i]:
                visited[i] = True
                queue.append(i)
                result.append(i)
    return result

visited = [0] * n
result = []

def dfs(v):
    visited[v] = True
    result.append(v)
    for i in graph[v]:
        if not visited[i]:
            dfs(i)

dfs(v)
for i in range(len(result)):
     result[i] += 1
print(*result, sep=' ')
result = bfs(v)
for i in range(len(result)):
     result[i] += 1
print(*result, sep=' ')


import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-s", "--solvers",
                metavar="solvers[latest solver, earlier solver1,...]",
                action="store",
                # type = str,
                dest="solvers",
                default=[],
                nargs='+',
                help="The target SMT Solvers for SPRFinder.py.",
                required=True
)
parser.add_argument("-t", "--type",
                metavar="z3seq, z3str3 or cvc4",
                action="store",
                type = str,
                dest='type',
                default='',
                # nargs=1,
                help="The type of the solver.",
                required=True
)

parser.add_argument('-l', '--string_length',
                    metavar="-l length_of_string",
                    action="store",
                    type = int,
                    dest="length",
                    default=10,
                    help="The init max string length"
                    )

parser.add_argument('-v', '--var_num',
                    metavar="variable_number",
                    action="store",
                    type = int,
                    dest="var_num",
                    default=3,
                    help="The init max variable number"
                    )
parser.add_argument('-a', '--assert_num',
                    metavar="number_of_assertion",
                    action="store",
                    type = int,
                    dest="assert_num",
                    default=4,
                    help="The init max assert number"
                    )
parser.add_argument('-d', '--max_depth',
                    metavar="init_depth",
                    action="store",
                    type = int,
                    dest="depth",
                    default=3,
                    help="The init max depth"
                    )

parser.add_argument('-T', '--time_out',
                    metavar='time',
                    action='store',
                    dest='timeout',
                    default=20,
                    help='The timeout setting'
                    )
# parser.add_argument()
args = parser.parse_args()


import moment
from sqlalchemy.engine import Engine
from sqlalchemy.orm import Session
from sqlalchemy import insert
from model.db.db_orm import (
    ContasTipo,
    Categorias,
    Contas,
    Lancamentos,
    association_lanc_categ,
)

class DataLoader:
    def __init__(self, engine: Engine) -> None:
        self.engine = engine

    def insert_all(self):
        self.__insert_contas_tipo()
        self.__insert_categorias()

    def __insert_contas_tipo(self):
        session = Session(self.engine)
        session.execute(
            insert(ContasTipo),
            [
                {"descricao": "Conta Corrente"},
                {"descricao": "Poupança"},
                {"descricao": "Cartão Crédito"},
            ]
        )
        session.commit()

    def __insert_categorias(self):

        session = Session(self.engine)
        session.execute(
            insert(Categorias),
            [
                {"nm_categoria": "Almoço"},
                {"nm_categoria": "Aluguel"},
                {"nm_categoria": "Água"},
                {"nm_categoria": "Banco"},
                {"nm_categoria": "Carro"},
                {"nm_categoria": "Cartão Crédito"},
                {"nm_categoria": "Combo TV+Internet"},
                {"nm_categoria": "Comida fora"},
                {"nm_categoria": "Compras"},
                {"nm_categoria": "Entretenimento"},
                {"nm_categoria": "Escola"},
                {"nm_categoria": "Imposto"},
                {"nm_categoria": "Luz"},
                {"nm_categoria": "Multa"},
                {"nm_categoria": "Poupança"},
                {"nm_categoria": "Salário"},
                {"nm_categoria": "Saque"},
                {"nm_categoria": "Segurança Social"},
                {"nm_categoria": "Seguro"},
                {"nm_categoria": "Supermercado"},
                {"nm_categoria": "Transferência"},
                {"nm_categoria": "Transporte"},
            ]
        )
        session.commit()

    def insert_sample_db(self):
        self.__insert_contas()
        self.__insert_lancamentos()
        self.__insert_lanc_categoria()

    def __insert_contas(self):

        session = Session(self.engine)
        session.execute(
            insert(Contas),
            [
                {
                    "descricao": "Itaú-CC",
                    "numero": "0516-145589",
                    "moeda": "BRL",
                    "tipo_id": 1,
                },
                {
                    "descricao": "ActivoBank-CC",
                    "numero": "PT144684831",
                    "moeda": "BRL",
                    "tipo_id": 1,
                },
                {
                    "descricao": "ActivoBank-CRD",
                    "numero": "PT144684831",
                    "moeda": "BRL",
                    "tipo_id": 3,
                },
                {
                    "descricao": "BPI-CC",
                    "numero": "4477889-888555",
                    "moeda": "BRL",
                    "tipo_id": 1,
                },
            ],
        )
        session.commit()

    def __insert_lancamentos(self):

        session = Session(self.engine)
        session.execute(
            insert(Lancamentos),
            [
                {
                    "conta_id": 1,
                    "seq_ordem_linha": 1,
                    "nr_referencia": "334562",
                    "descricao": "Transf China",
                    "data": moment.date("2019-11-30").date,
                    "valor": -2200,
                },
                {
                    "conta_id": 1,
                    "seq_ordem_linha": 2,
                    "nr_referencia": "334563",
                    "descricao": "Transf Port.",
                    "data": moment.date("2019-11-30").date,
                    "valor": -120,
                },
                {
                    "conta_id": 2,
                    "seq_ordem_linha": 1,
                    "nr_referencia": "334562",
                    "descricao": "Salário",
                    "data": moment.date("2019-11-30").date,
                    "valor": 500000,
                },
                {
                    "conta_id": 2,
                    "seq_ordem_linha": 2,
                    "nr_referencia": "334563",
                    "descricao": "Compra bala",
                    "descricao_user": "Mercadinho da Esquina",
                    "data": moment.date("2019-11-30").date,
                    "valor": -10000,
                },
                {
                    "conta_id": 2,
                    "seq_ordem_linha": 3,
                    "nr_referencia": "334564",
                    "descricao": "Comprar chiclete",
                    "data": moment.date("2019-11-30").date,
                    "valor": -12000,
                },
                {
                    "conta_id": 2,
                    "seq_ordem_linha": 1,
                    "nr_referencia": "334565",
                    "descricao": "Aluguel",
                    "data": moment.date("2019-12-01").date,
                    "valor": -65050,
                },
                {
                    "conta_id": 2,
                    "seq_ordem_linha": 1,
                    "nr_referencia": "334566",
                    "descricao": "Carro",
                    "data": moment.date("2019-12-02").date,
                    "valor": -36050,
                },
            ]
        )
        session.commit()

    def __insert_lanc_categoria(self):
        session = Session(self.engine)
        session.execute(
            insert(association_lanc_categ),
            [
                {"lancamento_id": 1, "categoria_id": 1},
                {"lancamento_id": 2, "categoria_id": 1},
            ]
        )
        session.commit()


import numpy as np
import torch.nn as nn
from mmcv.cnn import normal_init

from .anchor_head import AnchorHead
from ..registry import HEADS
from ..utils import bias_init_with_prob

@HEADS.register_module
class RetinaHead(AnchorHead):

    def __init__(self,
                 num_classes,
                 in_channels,
                 num_images_3dce=1,
                 stacked_convs=4,
                 octave_base_scale=4,
                 scales_per_octave=3,
                 bn_to_head=False,
                 **kwargs):
        self.num_images_3dce = num_images_3dce
        self.stacked_convs = stacked_convs
        self.octave_base_scale = octave_base_scale
        self.scales_per_octave = scales_per_octave
        self.bn_to_head = bn_to_head
        octave_scales = np.array(
            [2**(i / scales_per_octave) for i in range(scales_per_octave)])
        anchor_scales = octave_scales * octave_base_scale
        super(RetinaHead, self).__init__(
            num_classes,
            in_channels,
            anchor_scales=anchor_scales,
            use_sigmoid_cls=True,
            use_focal_loss=True,
            **kwargs)

    def _init_layers(self):
        self.relu = nn.ReLU(inplace=True)
        self.cls_convs = nn.ModuleList()
        self.reg_convs = nn.ModuleList()

        if self.bn_to_head:
            for i in range(self.stacked_convs):
                chn = self.in_channels if i == 0 else self.feat_channels
                self.cls_convs.append(nn.Sequential(
                    nn.Conv2d(chn, self.feat_channels, 3, stride=1, padding=1),
                    nn.BatchNorm2d(self.feat_channels),
                    nn.ReLU(inplace=True)
                ))
                self.reg_convs.append(nn.Sequential(
                    nn.Conv2d(chn, self.feat_channels, 3, stride=1, padding=1),
                    nn.BatchNorm2d(self.feat_channels),
                    nn.ReLU(inplace=True)
                ))
        else:
            for i in range(self.stacked_convs):
                chn = self.in_channels if i == 0 else self.feat_channels
                self.cls_convs.append(
                    nn.Conv2d(chn, self.feat_channels, 3, stride=1, padding=1))
                self.reg_convs.append(
                    nn.Conv2d(chn, self.feat_channels, 3, stride=1, padding=1))

        self.retina_cls = nn.Conv2d(
            self.feat_channels,
            self.num_anchors * self.cls_out_channels,
            3,
            padding=1)
        self.retina_reg = nn.Conv2d(
            self.feat_channels, self.num_anchors * 4, 3, padding=1)

    def init_weights(self):
        for m in self.cls_convs:
            if isinstance(m, nn.Conv2d):
                normal_init(m, std=0.01)
        for m in self.reg_convs:
            if isinstance(m, nn.Conv2d):
                normal_init(m, std=0.01)
        bias_cls = bias_init_with_prob(0.01)
        normal_init(self.retina_cls, std=0.01, bias=bias_cls)
        normal_init(self.retina_reg, std=0.01)

    def forward_single(self, x):
        cls_feat = x
        reg_feat = x

        if not self.bn_to_head:
            for cls_conv in self.cls_convs:
                cls_feat = self.relu(cls_conv(cls_feat))
            for reg_conv in self.reg_convs:
                reg_feat = self.relu(reg_conv(reg_feat))
        else:
            for cls_conv in self.cls_convs:
                cls_feat = cls_conv(cls_feat)
            for reg_conv in self.reg_convs:
                reg_feat = reg_conv(reg_feat)

        # for 3dce
        if self.num_images_3dce != 1:
            bs, c, w, h = cls_feat.size()
            imgs_per_gpu = int(bs / self.num_images_3dce)
            cls_feat = cls_feat.view(imgs_per_gpu, -1, w, h)
            reg_feat = reg_feat.view(imgs_per_gpu, -1, w, h)

        cls_score = self.retina_cls(cls_feat)
        bbox_pred = self.retina_reg(reg_feat)
        return cls_score, bbox_pred


from setuptools import setup
from setuptools import find_packages
import sys

with open("README.md", "r") as fh:
  long_description = fh.read()

exec(open("openSAP32/_version.py").read())
setup(
  name = 'openSAP32',
  packages = find_packages(),
  version = __version__,
  license='New BSD',
  description = 'openSAP32 is open source software for modeling and perform structural analysis.',
  long_description=long_description,
  long_description_content_type = 'text/markdown',
  author = 'Duken Marga',
  author_email = 'dukenmarga@gmail.com',
  url = 'https://github.com/dukenmarga/openSAP32',
  #download_url = 'https://github.com/dukenmarga/openSAP32/',
  keywords = ['structural', 'analysis', 'civil','engineering','frame','fem', 'finite element'],
  install_requires=[
     'numpy>=1.16',
  ],
  classifiers=[
    'Development Status :: 3 - Alpha',      # Chose either "3 - Alpha", "4 - Beta" or "5 - Production/Stable" as the current state of your package
    'Intended Audience :: Developers',
    'Intended Audience :: End Users/Desktop',
    'Topic :: Software Development :: Build Tools',
    'License :: OSI Approved :: BSD License',
    'Programming Language :: Python :: 3',
    'Programming Language :: Python :: 3.6',
    'Operating System :: OS Independent',
  ],
  python_requires='>=3.6',
)


import re
import pickle
import io
import os.path
import base64
from PIL import Image
from io import BytesIO
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

class Encoder(tf.keras.Model):
    def __init__(self, embed_dim):
        super(Encoder, self).__init__()
        self.den = tf.keras.layers.Dense(embed_dim)

    def call(self, x):
        x = self.den(x)
        x = tf.nn.relu(x)
        return x

class Attend(tf.keras.Model):
    def __init__(self, units):
        super(Attend, self).__init__()
        self.W1 = tf.keras.layers.Dense(units)
        self.W2 = tf.keras.layers.Dense(units)
        self.V = tf.keras.layers.Dense(1)

    def call(self, feat, hidden):
        hidden_ = tf.expand_dims(hidden, axis=1)
        score = tf.nn.tanh(self.W1(feat) + self.W2(hidden_))
        att_wt = tf.nn.softmax(self.V(score), axis=1)
        context = att_wt * feat
        context = tf.reduce_sum(context, axis=1)

        return context, att_wt

class Decoder(tf.keras.Model):
    def __init__(self, units, embed_M, sentence_length):
        super(Decoder, self).__init__()
        self.units = units
        self.embed = tf.keras.layers.Embedding(input_dim=embed_M.shape[0], output_dim=embed_M.shape[1],
                                               weights=[embed_M], input_length=sentence_length, trainable=False)
        self.lstm = tf.keras.layers.LSTM(units=units, return_sequences=True, return_state=True)
        self.den1 = tf.keras.layers.Dense(units)
        self.den2 = tf.keras.layers.Dense(embed_M.shape[0])
        self.attend = Attend(units)

    def call(self, tok, feat, hidden):
        context, att_wt = self.attend(feat, hidden)
        x = self.embed(tok)
        context_ = tf.expand_dims(context, 1)
        x = tf.concat([context_, x], axis=2)
        output, state, _ = self.lstm(x)
        x = self.den1(output)
        x = tf.reshape(x, (-1, x.shape[2]))
        x = self.den2(x)
        return x, state, att_wt

    def reset_state(self, batch_size):
        return tf.zeros((batch_size, self.units))

class ImageCaptioning:
    def __init__(self, model_dir):
        self.model_dir = model_dir
        self.embed_dim = 300
        self.units = 512
        self.max_length = 80
        self.min_words = 3  # Minimum number of words in the result
        self.max_words = 10  # Maximum number of words in the result
        self.word_ind_map = {}
        self.ind_word_map = {}
        self.IV3_feat = None
        self.enc = None
        self.dec = None

    def load_models(self):
        M = np.load(os.path.join(self.model_dir, 'embedB.npy'))
        cap_seq = np.load(os.path.join(self.model_dir, 'caption_vec.npy'))

        with open(os.path.join(self.model_dir, 'word_ind_map.pkl'), 'rb') as f:
            self.word_ind_map = pickle.load(f)

        with open(os.path.join(self.model_dir, 'ind_word_map.pkl'), 'rb') as f:
            self.ind_word_map = pickle.load(f)

        self.IV3_feat = tf.keras.models.load_model(os.path.join(self.model_dir, 'IV3_feat.h5'))

        self.enc = Encoder(self.embed_dim)
        self.dec = Decoder(self.units, M, self.max_length)
        self.enc.load_weights(os.path.join(self.model_dir, 'encoder/'))
        self.dec.load_weights(os.path.join(self.model_dir, 'decoder/'))

    def evaluate(self, file):
        while True:
            attention_plot = np.zeros((self.max_length, 64))
            hidden = self.dec.reset_state(batch_size=1)
            temp_input = tf.expand_dims(self.load_image(file)[0], 0)
            img_tensor_val = self.IV3_feat(temp_input)
            img_tensor_val = tf.reshape(img_tensor_val, (img_tensor_val.shape[0], -1, img_tensor_val.shape[3]))

            features = self.enc(img_tensor_val)

            dec_input = tf.expand_dims([self.word_ind_map['<start>']], 0)
            result = []

            for i in range(self.max_length):
                predictions, hidden, attention_weights = self.dec(dec_input, features, hidden)

                attention_plot[i] = tf.reshape(attention_weights, (-1,)).numpy()

                predicted_id = tf.random.categorical(predictions, 1)[0][0].numpy()
                result.append(self.ind_word_map[predicted_id])

                if self.ind_word_map[predicted_id] == '<end>':
                    if self.min_words <= len(result) <= self.max_words:
                        attention_plot = attention_plot[:len(result), :]
                        return result, attention_plot
                    else:
                        break

                dec_input = tf.expand_dims([predicted_id], 0)

    def measure_caption_accuracy(self, result):
        # Measure the accuracy of the caption based on your criteria
        # You can implement your own scoring mechanism here
        # Return a score between 0 and 1, where 1 indicates a perfect caption

        # Example scoring mechanism: Calculate the ratio of known words in the caption
        known_words = sum(word in self.word_ind_map for word in result)
        accuracy = known_words / len(result) if len(result) > 0 else 0.0
        return accuracy

    def predict(self, file):
        result, attention_plot = self.evaluate(file)
        accuracy = self.measure_caption_accuracy(result)

        if accuracy < 0.8:
            result, attention_plot = self.evaluate(file)  # Rerun evaluation for low accuracy captions

        heatmap_base64 = self.plot_attention(file, result, attention_plot)

        text = " ".join(result)
        text = re.sub(r"<end>", "", text).strip()
        return text, heatmap_base64

    @staticmethod
    def load_image(arg):
        img = tf.convert_to_tensor(arg)
        img = tf.image.decode_jpeg(img, channels=3)
        img = tf.image.resize(img, (299, 299))
        img = tf.keras.applications.inception_v3.preprocess_input(img)
        return img, arg

    @staticmethod
    def read_image_file(file):
        # Load the image using PIL
        pil_image = Image.open(BytesIO(file))
        # Convert PIL image to numpy array
        return np.array(pil_image)

    @staticmethod
    def plot_attention(file, result, attention_plot):
        image = ImageCaptioning.read_image_file(file)
        len_result = len(result)
        num_rows = (len_result + 1) // 2
        num_cols = min(len_result, 2)

        fig = plt.figure(figsize=(10, 10), dpi=200)

        for l in range(len_result):
            temp_att = np.resize(attention_plot[l], (8, 8))
            ax = fig.add_subplot(num_rows, num_cols, l + 1)
            ax.set_title(result[l])
            img = ax.imshow(image)
            ax.imshow(temp_att, cmap='gray', alpha=0.6, extent=img.get_extent())

        plt.tight_layout()

        # Capture the plot image as bytes
        buf = io.BytesIO()
        plt.savefig(buf, format='png')
        buf.seek(0)
        image_bytes = buf.getvalue()
        buf.close()

        # Encode the image bytes as a base64 string
        image_base64 = base64.b64encode(image_bytes).decode("utf-8")

        # Return the plot image base64 string
        return image_base64


import pygame
import time
# import pygame_functions
WIDTH = 1000
HEIGHT = 1000

pygame.init()
screenRefresh = True
background_image = pygame.image.load("plain_bg.jpg")
back_pos = [0,0]

screen = pygame.display.set_mode((WIDTH,HEIGHT))
done = False

class Button(pygame.sprite.Sprite):
    def __init__(self,loc):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("blue_button-1-1.png.png")
        self.loc = loc
        self.is_visible = True
    def blitme(self):
        if self.is_visible == True:
            screen.blit(self.image,self.loc)
    def move_y(self):
        self.loc[1] = self.loc[1]+5

class Blank(pygame.sprite.Sprite):
    def __init__(self,loc):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("blank.png")
        self.loc = loc
        self.is_visible = True
    def blitme(self):
        if self.is_visible == True:
            screen.blit(self.image,self.loc)
    def move_y(self):
        self.loc[1] = self.loc[1]+5

class Target():
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("target-1.png")

#CREATES INITIAL COLUMNS OF FALLING BUTTONS

column_a = ['-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','x','-','-','-','-','-','-','-','x','-','-','-','-','-','-','-','-','x','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','x']
column_s = ['-','x','x','-','-','-','-','-','-','-','-','-','-','x','x','-','-','-','-','-','-','x','x','-','-','-','-','-','-','-','x','x','-','-','x','x','-','-','-','-','-','-','-','-','-','-','x','x','-']
column_d = ['-','-','-','x','x','-','-','x','-','-','-','x','x','-','-','-','-','-','-','x','x','-','-','-','-','-','-','-','x','x','-','-','-','-','-','-','x','x','-','-','x','-','-','-','x','x','-','-','-']
column_f = ['-','-','-','-','-','x','x','-','-','x','x','-','-','-','-','-','-','x','x','-','-','-','-','-','-','x','x','-','-','-','-','-','-','-','-','-','-','-','x','x','-','-','x','x','-','-','-','-','-']
# time_a = ['8.00','11.2','14.40','20.8']
# time_s = ['2.3','2.6','7.20','7.60','10.4','10.8''13.60','14.0','15.2','15.6','20','20.4']
# time_d = ['2.90','3.3','4.43''6.40','6.80','9.60','10.0''12.80','13.20','16','16.4','17.6''19.2','19.6']
# time_f = ['3.66','4.04','5.10','5.5','8.80','9.2','12.0','12.40''16.8','17.2','18.4','18.8']
note_a = ['c','d','d','c']
note_s = ['c','c','d','d','e','e','e','e','c','c','d','d']
note_d = ['g','g','g','e','e','f','f','f','f','g','g','g','e','e']
note_f = ['a','a','f','f','g','g','g','g','a','a','f','f']

def beatmap():
    buttons_a = []
    buttons_s = []
    buttons_d = []
    buttons_f = []
    row = 0
    spacing = 130
    for space_a,space_s,space_d,space_f in zip(column_a,column_s,column_d,column_f):

        if space_a == "-":
            blank_a = Blank([400,10 - row * spacing])

            buttons_a.append(blank_a)

        if space_a == "x":
            butt_a = Button([400,10 - row * spacing])

            buttons_a.append(butt_a)

        if space_s == "-":
            blank_s = Blank([450,10- row * spacing])

            buttons_s.append(blank_s)

        if space_s == "x":
            butt_s = Button([450,10- row * spacing])

            buttons_s.append(butt_s)

        if space_d == "-":
            blank_d = Blank([500,10- row * spacing])

            buttons_d.append(blank_d)

        if space_d == "x":
            butt_d = Button([500,10- row * spacing])

            buttons_d.append(butt_d)

        if space_f == "-":
            blank_f = Blank([550,10- row * spacing])

            buttons_f.append(blank_f)

        if space_f == "x":
            butt_f = Button([550,10- row * spacing])

            buttons_f.append(butt_f)

        row += 1

    return [buttons_a,buttons_s,buttons_d,buttons_f]
bm = beatmap()
def show_buttons(bm):

    for ele in bm[0]:

        ele.blitme()
        ele.move_y()

    for ele in bm[1]:

        ele.blitme()
        ele.move_y()
    for ele in bm[2]:

        ele.blitme()
        ele.move_y()
    for ele in bm[3]:

        ele.blitme()
        ele.move_y()

# pygame.mixer.init()
# first_song = pygame.mixer.music.load("tt_lit.ogg")
# pygame.mixer.music.play()
# pygame.event.wait()
# start = time.time()
score_range = 100
while not done:
    # end = time.time()
    # elapsed = end-start
    # presstime_a = abs(elapsed-float(time_a[0])-.18)
    # presstime_s = abs(elapsed-float(time_s[0])-.18)
    # presstime_d = abs(elapsed-float(time_d[0])-.18)
    # presstime_f = abs(elapsed-float(time_f[0])-.18)
    # window_a = abs(bm[0][0].loc[1]- 700)
    # window_s = abs(bm[1][0].loc[1]- 700)
    # window_d = abs(bm[2][0].loc[1]- 700)
    # window_f = abs(bm[3][0].loc[1]- 700)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_a:
                if not(len(bm[0]) == 0):
                    while not type(bm[0][0]) == Button:
                        bm[0] = bm[0][1:]
                    window_a = abs(bm[0][0].loc[1]- 700)
                    if window_a < score_range:
                        print('yes')
                        a.play()
                    else:
                        pass
                        #play wrong note
                    bm[0][0].is_visible = False
                    bm[0] = bm[0][1:]

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_s:
                if not(len(bm[1]) == 0):
                    while not type(bm[1][0]) == Button:
                        bm[1]=bm[1][1:]
                    window_s = abs(bm[1][0].loc[1]- 700)
                    if window_s < score_range:
                        print('yes')
                        #play music
                    else:
                        pass
                        #play wrong note
                    bm[1][0].is_visible = False
                    bm[1]=bm[1][1:]

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_d:
                if not(len(bm[2]) == 0):
                    while not type(bm[2][0]) == Button:
                        bm[2] = bm[2][1:]
                    window_d = abs(bm[2][0].loc[1]- 700)
                    if window_d < score_range:
                        print('yes')
                    bm[2][0].is_visible = False
                    bm[2] = bm[2][1:]

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_f:
                if not(len(bm[3]) == 0):
                    while not type(bm[3][0]) == Button:
                        bm[3] = bm[3][1:]
                    window_f = abs(bm[3][0].loc[1]- 700)
                    if window_s < score_range:
                        print('yes')
                    bm[3][0].is_visible = False
                    bm[3] = bm[3][1:]

    screen.blit(background_image,back_pos )

    t=Target()
    screen.blit(t.image,(375,700))

    show_buttons(bm)

    pygame.display.flip()