""" rearch...
NEXT NEED more TESTS!  + split to modules and... and next function for new field  ! MAP_ALL
lines 91, 1307,

-help for each command (from docstrings?)
-split to modules
-add e-mail commands
-add block in phone and mail commands
-add detail and related... commands
-Cweb2 + video
-описати абстрактний базовий клас для представлень користувача і конкретні реалізації, які наслідують базовий клас і реалізують консольний інтерфейс.

"""
from collections import UserDict
from datetime import datetime, timedelta
import os
import pickle
import re
import sys
from typing import List, NoReturn, Union

AMBUSH = 'AMBUSH!'
TO_NEXT_FILE_NAME = 'new_one_'
DEFAULT_FILE_ADDRESS_BOOK = 'ABook.data'
LIMIT_RECORDS_TO_DISPLAY = 10

PREFORMATING_PHONE = r'^\+[0-9)(-]{12,16}$'
PREFORMATING_EMAIL1 = r'\b[a-zA-z][\w_.]+@[a-zA-z]+\.[a-zA-z]{2,}[ ]'
PREFORMATING_EMAIL2 = r'\b[a-zA-z][\w_.]+@[a-zA-z]+\.[a-zA-z]+\.[a-zA-z]{2,}'

ERROR_MESSAGE = {
    'UnpicklingError':['The File',' is corrupted, my apologies.',],
    'UnpicklingOthers':['Is the File',' corrupted? ',],
    'OpenFile':['No access to File',', system error: ',],
    'WriteFile':['No access to write File',', error: ',],
    'PicklingError':['Can\'t save object in file',', my apologies.',],
    'PicklingOthers':['Something was wrong. File',' is not updated. ',],
    'UnknownCommand':['Unknown command ...',],
    'UnpredictableError':['Unpredictable error: No contact record available?...',],
    'UnexpectedError':['Unexpected error!: ',],
    '':['',],
    '':['',],
    '':['',],}

WARNING_MESSAGE = {
    'name':'At the beginning there can be only a Latin letter!',
    'birthday':'Incorrect or nonexistent date, entry must be in year-month-day format (YYYY-MM-DD).',
    'phone':'The number is obviously incorrect, the value should start with \"+\" and have 12 digits.',
    'email':'The e-mail is obviously incorrect.',
    'main':'Something happened. Will you try again?',
    'name is omitted':'Give me name OR name and phone please.\n',
    'the contact exists':'Such an entry is already in the book. Add or change a number.',
    'invalid name':'A name cannot begin with a number and can only begin with Latin characters!\n',
    'invalid phone':'There are no valid phone numbers.\nThe number must be in the following format with 12 digits(d): +dd(ddd)ddd-dddd .\n',
    'empty record to add':'There were no new entries to add.\n',
    'unsuccessful save':'Failed to save file.',
    'name and phone omitted':'Give me name and new phone(s) please.\n',
    'unknown name':'The user is unknown. There are no records for this name yet. Create it first.',
    'no address book':'No contact records available.\n',
    'name and birthday omitted':'Give me a name and birthday, please.\n',
    'invalid birthday entry':'The year of birth is not correct! A person too old or too young.\n',
    'invalid birthday':'The calendar date is not possible!\n',
    'name and 2 phones omitted':'Give me name and 2 phones please (current and new)\n',
    'no search query':'There is no search query\n',
    'name is missing':'Give me a name too, please.\n',
    '':'',
    '':'',}

OTHER_MESSAGE = {
    'Record': ['\n\nRecord(Name: ', '; Phones: ', '; Birthday: ', ';\n\te-mail: ', ';\n\t details: ', ':\n\t related information: ',],
    'RBirthday':['Birthday already recorded for ','. You can change it.','Birthday not specified for ','. You can add it.',],
    'RPhone':[' already recorded for ','No phone(s) entry in record ',' not specified in the contact ',],
    'ABook':['AddressBook(Records:',],
    'next_page':['Press Enter for next Volume... ',],
    'Bye':['Good bye!',],
    'START':['Can I help you?\n',],
    'Unknown':['It is unclear. Unknown command...',],
    'Hello':['Hello! So...\n',],
    'successful addition':['A record(s) have been added.\n',],
    'update successful':['A record have been added. Address book file has been saved.',],
    'no changes':['No changes have been made.\n',],
    'deleting successful':['Record successfully deleted. Results saved.',],
    'deleting field':['Field record deleted successfully. Results saved.',],
    'no new entries':['There were no entries to add.\n',],
    'found':['Entries found in your contact book:',', birthday: ','(days to next birthday: ','. Will be ',' yrs. old)\n-> phone(s): ',', birthday: unknown\n-> phone(s): ','','',],
    'all list':['Entries in your contact book:',],
    'all commands list':['All commands in current version Personal Virtual Assistant:\n', 'Detailed for each command: \"-h\" after them.\n'],  #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    '':['',],
    '':['',],}

class AddressBook(UserDict):
    """A class of Address book."""

    def __str__(self) -> str:
        ABOOK0 = OTHER_MESSAGE.get('ABook', [AMBUSH])[0]
        return f'{ABOOK0}{self.data})'

    def add_record(self, record) -> None:  # record: Record
        """Adds a new record to the address book dictionary."""
        self.data[record.name.value] = record

    def iterator(self, n_count: int) -> list:
        """Return(yield) of n_count records of all AddressBook."""
        current_value = 0
        dictionary_iterator = iter(self.data)

        while current_value < len(self.data):
            volume = []

            for i in range(n_count):

                try:
                    volume.append(self.data[next(dictionary_iterator)])

                except StopIteration:
                    current_value = len(self.data)

            yield volume

            current_value += n_count

    def remove_record(self, name: str) -> None:
        """Remove a record from the address book dictionary."""
        self.data.pop(name)

class Field:  # superclass for all base fields
    """A base class with a simple field."""

    def __init__(self):
        self.__value = None
        self.__bloke = None

    def __str__(self):
        return f'{self.value}'

    @property
    def value(self):
        return self.__value

    @value.setter
    def value(self, new_value: str):
        self.__value = new_value

    @property
    def bloke(self):
        return self.__bloke

    @bloke.setter
    def bloke(self, new_bloke: str):
        self.__bloke = new_bloke

class Name(Field):
    """Class of user name."""
    @Field.value.setter
    def value(self, new_value: str):

        if new_value[0].isalpha():  # not in 'ьъыЫЬЪ\'"[]_0123456789!@$%^&*()-+?<>~`|\\/'
            self._Field__value = new_value

        else:
            print(WARNING_MESSAGE.get('name', AMBUSH))

class Birthday(Field):
    """Class of Birthday data."""
    @Field.value.setter
    def value(self, new_value: str):
        birthday_data = datetime.strptime(new_value, '%Y-%m-%d')

        if birthday_data:
            self._Field__value = birthday_data

        else:
            print(WARNING_MESSAGE.get('birthday', AMBUSH))

    def __str__(self) -> str:
        return f'{self.value.date()}'

class Phone(Field):
    """Class of phone number."""
    @Field.value.setter
    def value(self, new_value: str):

        if re.search(PREFORMATING_PHONE, new_value):
            self._Field__value = self.__preformating(new_value)

        else:
            print(WARNING_MESSAGE.get('phone', AMBUSH))

    @Field.bloke.setter
    def bloke(self, new_bloke: str):
        self._Field__bloke = new_bloke

    @staticmethod
    def __preformating(value: str) -> str:
        """Preformating of phone string into the form +dd(ddd)ddddddd."""
        value = value.replace('-', '').replace('(', '').replace(')', '')

        value = '('.join((value[: 3], value[3:]))
        value = ')'.join((value[: 7], value[7:]))

        return value

class Details(Field):
    """Details information of user."""
    @Field.value.setter
    def value(self, new_value: str):
        self._Field__value = new_value

    @Field.bloke.setter
    def bloke(self, new_bloke: str):
        self._Field__bloke = new_bloke

class Email(Field):
    """Class of user Email."""
    @Field.value.setter
    def value(self, new_value: str):

        if re.search(PREFORMATING_EMAIL1, new_value) or\
             re.search(PREFORMATING_EMAIL2, new_value):
            self._Field__value = self.new_value.strip()

        else:
            print(WARNING_MESSAGE.get('email', AMBUSH))

    @Field.bloke.setter
    def bloke(self, new_bloke: str):
        self._Field__bloke = new_bloke

class RelatedInformation(Field):
    """Related information of user."""
    @Field.value.setter
    def value(self, new_value: str):
        self._Field__value = new_value

    @Field.bloke.setter
    def bloke(self, new_bloke: str):
        self._Field__bloke = new_bloke

class Record:
    """Record class of users information."""

    def __init__(self, name: str, *phones: str):
        self.name = Name()
        self.name.value = name
        self.phones = []
        self.birthday = None
        self.emails = []
        self.details = None
        self.related_info = None

        if phones:

            for phone in phones:
                self.add_phone(phone)

    def __str__(self) -> str:
        NAME = OTHER_MESSAGE.get('Record', [AMBUSH])[0]
        PHONES = OTHER_MESSAGE.get('Record', [AMBUSH]*2)[1]
        BIRTHDAY = OTHER_MESSAGE.get('Record', [AMBUSH]*3)[2]
        EMAIL = OTHER_MESSAGE.get('Record', [AMBUSH]*4)[3]
        DETAILS = OTHER_MESSAGE.get('Record', [AMBUSH]*5)[4]
        RELATED = OTHER_MESSAGE.get('Record', [AMBUSH]*6)[5]

        return f'{NAME}{self.name}{PHONES}{self.phones}{BIRTHDAY}'\
            f'{self.birthday}{EMAIL}{self.emails}{DETAILS}{self.details}'\
            f'{RELATED}{self.related_info})'

    def add_birthday(self, birthday: str) -> tuple:
        """Adds a new entry for the user's birthday to the address book."""
        if not self.birthday:

            self.birthday = Birthday()
            self.birthday.value = birthday

            return True,

        else:
            BIRTHDAY0 = OTHER_MESSAGE.get('RBirthday', [AMBUSH])[0]
            BIRTHDAY1 = OTHER_MESSAGE.get('RBirthday', [AMBUSH]*2)[1]
            return False, f'{BIRTHDAY0}\"{self.name.value}\"{BIRTHDAY1}'

    def add_phone(self, phone_new: str) -> bool:
        """Adds a new entry for the user's phone to the address book."""
        phone_new1 = Phone()
        phone_new1.value = phone_new

        for phone in self.phones:

            if phone_new1 == phone.value:

                PHONE0 = OTHER_MESSAGE.get('RPhone', [AMBUSH])[0]
                print(f'\"{phone_new1}\"{PHONE0}\"{self.name.value}\"')

                return False

        self.phones.append(phone_new1)

        return True

    def change_birthday(self, birthday: str) -> tuple:
        """Modify an existing user's birthday entry in the address book."""
        if not self.birthday:

            BIRTHDAY2 = OTHER_MESSAGE.get('RBirthday', [AMBUSH]*3)[2]
            BIRTHDAY3 = OTHER_MESSAGE.get('RBirthday', [AMBUSH]*4)[3]
            return False, f'{BIRTHDAY2}\"{self.name.value}\"{BIRTHDAY3}'

        else:

            self.birthday = Birthday()
            self.birthday.value = birthday

            return True,

    def change_phone(self, phone_to_change: str, phone_new: str) -> tuple:
        """Modify an existing user's phone entry in the address book."""
        phone_to_change = Phone._Phone__preformating(phone_to_change)
        phone_new = Phone._Phone__preformating(phone_new)
        verdict = False

        for phone in self.phones:

            if phone.value == phone_new:  # new number already in record
                PHONE0 = OTHER_MESSAGE.get('RPhone', [AMBUSH])[0]
                return False, f'\"{phone_new}\"{PHONE0}\"{self.name.value}\"'

            if phone.value == phone_to_change:  # old number not exist in record
                verdict = True

        if not verdict:
            PHONE2 = OTHER_MESSAGE.get('RPhone', [AMBUSH]*3)[2]
            return verdict, f'\"{phone_to_change}\"{PHONE2}\"{self.name.value}\"'

        for index, phone in enumerate(self.phones):

            if phone.value == phone_to_change:
                phone_new_to = Phone()
                phone_new_to.value = phone_new
                self.phones.remove(phone)
                self.phones.insert(index, phone_new_to)

                return True,

    def days_to_birthday(self) -> int:
        """Count the number of days until the next birthday of the user."""
        if self.birthday:

            user_day = datetime(year=datetime.now().date().year, \
                month=self.birthday.value.month, day=self.birthday.value.day)

            days_left = user_day.date() - datetime.now().date()

            if days_left.days <= 0:

                user_day = datetime(year=datetime.now().date().year + 1, \
                    month=self.birthday.value.month, day=self.birthday.value.day)

                return (user_day.date() - datetime.now().date()).days

            return days_left.days

    def remove_birthday(self) -> Union[bool, None]:
        """Deleting a birthday entry from a user entry in the address book."""
        if self.birthday:
            self.birthday = None
            return True

    def remove_phone(self, phone_to_remove: str) -> Union[bool, None]:
        """Deleting a phone entry from a user entry in the address book."""
        phone_to_remove = Phone._Phone__preformating(phone_to_remove)

        for phone in self.phones:

            if phone.value == phone_to_remove:
                self.phones.remove(phone)

                return True

        PHONE2 = OTHER_MESSAGE.get('RPhone', [AMBUSH]*3)[2]
        print(f'\"{phone_to_remove}\"{PHONE2}\"{self.name.value}\"')

    def years_old(self) -> int:
        """Calculate the number of full years of the user on the next birthday."""
        if self.birthday:

            user_day = datetime(year=datetime.now().date().year, \
                month=self.birthday.value.month, day=self.birthday.value.day)

            return datetime.now().year - self.birthday.value.year \
                if (user_day.date() - datetime.now().date()).days > 0 \
                else datetime.now().year + 1 - self.birthday.value.year

def helper_try_open_file(path_file: str) -> str:
    """Checks if the database file exists and checks if the filename is free if not.
    If exist folder with path_file file name, then return new free file name.
    Return unoccupied name of file (string).

        Parameters:
            path_file (str): Is proposed name of file.

        Returns:
            path_file (str): Unoccupied name of file.
    """
    if os.path.isdir(path_file):

        while os.path.isdir(path_file):

            path_file = os.path.join(path_file.parent, TO_NEXT_FILE_NAME + path_file.name)

    return path_file

def helper_try_load_file(path_file: str) -> Union[AddressBook, str]:
    """Create empty address book (AddressBook) if no file on path_file.
    Or, try to load address book database (read) from file.
    Return loaded address book (AddressBook) and path for address book file.

        Parameters:
            path_file (str): Is existed file (name or name with path).

        Returns:
            contact_dictionary (AddressBook): Loaded from file or new empty class.
            path_file (str): The file name to save the address book in the following steps..
                Unoccupied name of file, if an exception occurred.
    """
    if not os.path.exists(path_file):
        contact_dictionary = AddressBook()
        address_book_saver(contact_dictionary, path_file) #  False if can't save file!
        return contact_dictionary, path_file

    try:
        with open(path_file, 'rb') as fh:
            try:
                contact_dictionary = pickle.load(fh)
                return contact_dictionary, path_file
            except pickle.UnpicklingError:
                ERROR_LOAD0 = ERROR_MESSAGE.get('UnpicklingError', [AMBUSH])[0]
                ERROR_LOAD1 = ERROR_MESSAGE.get('UnpicklingError', [AMBUSH]*2)[1]
                print(f'{ERROR_LOAD0}({path_file}){ERROR_LOAD1}')
                contact_dictionary = AddressBook()

            except Exception as error_: # pickle.PickleError inherits Exception.
                ERROR_LOAD0 = ERROR_MESSAGE.get('UnpicklingOthers', [AMBUSH])[0]
                ERROR_LOAD1 = ERROR_MESSAGE.get('UnpicklingOthers', [AMBUSH]*2)[1]
                print(f'{ERROR_LOAD0}({path_file}){ERROR_LOAD1}\n{repr(error_)}')
                contact_dictionary = AddressBook()

    except OSError as error_:
        ERROR_LOAD0 = ERROR_MESSAGE.get('OpenFile', [AMBUSH])[0]
        ERROR_LOAD1 = ERROR_MESSAGE.get('OpenFile', [AMBUSH]*2)[1]
        print(f'{ERROR_LOAD0}({path_file}){ERROR_LOAD1}\n{type(error_)}: {error_}')
        contact_dictionary = AddressBook()

    except Exception as error_:
        ERROR_LOAD0 = ERROR_MESSAGE.get('OpenFile', [AMBUSH])[0]
        ERROR_LOAD1 = ERROR_MESSAGE.get('OpenFile', [AMBUSH]*2)[1]
        print(f'{ERROR_LOAD0}({path_file}){ERROR_LOAD1}\n{repr(error_)}')
        contact_dictionary = AddressBook()

    while os.path.exists(path_file):
        path_file = os.path.join(path_file.parent, TO_NEXT_FILE_NAME + path_file.name)

    return contact_dictionary, path_file

def address_book_saver(contact_dictionary: AddressBook, path_file: str) -> bool:
    """Save a class AddressBook to a file (path_file).

        Parameters:
            contact_dictionary (AddressBook): Instance of AddressBook.
            path_file (str): Is there path and filename of address book.

        Returns:
            File save success marker (bool).
    """
    try:

        with open(path_file, 'wb') as db_file:

            try:

                pickle.dump(contact_dictionary, db_file)

            except pickle.PicklingError:
                ERROR_SAVE0 = ERROR_MESSAGE.get('PicklingError', [AMBUSH])[0]
                ERROR_SAVE1 = ERROR_MESSAGE.get('PicklingError', [AMBUSH]*2)[1]
                print(f'{ERROR_SAVE0}({path_file}){ERROR_SAVE1}')
                return False
                # contact_dictionary = AddressBook()

            except Exception as error_: # pickle.PickleError inherits Exception.
                ERROR_SAVE0 = ERROR_MESSAGE.get('PicklingOthers', [AMBUSH])[0]
                ERROR_SAVE1 = ERROR_MESSAGE.get('PicklingOthers', [AMBUSH]*2)[1]
                print(f'{ERROR_SAVE0}({path_file}){ERROR_SAVE1}\n{repr(error_)}')
                return False
                # contact_dictionary = AddressBook()

    except OSError as error_:
        ERROR_WRITE0 = ERROR_MESSAGE.get('WriteFile', [AMBUSH])[0]
        ERROR_WRITE1 = ERROR_MESSAGE.get('WriteFile', [AMBUSH]*2)[1]
        print(f'{ERROR_WRITE0}({path_file}){ERROR_WRITE1}\n{type(error_)}: {error_}')
        return False

    except Exception as error_:
        ERROR_WRITE0 = ERROR_MESSAGE.get('WriteFile', [AMBUSH])[0]
        ERROR_WRITE1 = ERROR_MESSAGE.get('WriteFile', [AMBUSH]*2)[1]
        print(f'{ERROR_WRITE0}({path_file}){ERROR_WRITE1}\n{repr(error_)}')
        return False

    return True

def find_users(search_strings: List[str], record: Record) -> bool:
    """Check a record for matching the search strings.

        Parameters:
            search_strings (List[str]): The data in the list rows in the user's search query.
            record (Record): Record - User account card.

        Returns:
            True or False (bool): Search result (Search success rate).
    """
    name = f'{record.name}'

    for search_string in search_strings:

        if name.find(search_string) >= 0:

            return True

        if record.birthday:

            birthday = f'{record.birthday}'

            if birthday.find(search_string) >= 0:

                return True

        for phone in record.phones:
            candidate = f"{phone.value}"
            candidate = candidate.replace(
                '-', '').replace('+', '').replace('(', '').replace(')', '')

            if candidate.find(search_string.replace('-', '').replace('+', '').replace('(', '').replace(')', '')) >= 0:

                return True

    return False

class TheNameIsOmitted(Exception):
    pass

class TheContactIsExist(Exception):
    pass

class TheNameIsIncorrect(Exception):
    pass

class ThePhoneIsIncorrect(Exception):
    pass

class TheNameAndPhoneAreMissing(Exception):
    pass

class TheContactIsNotExist(Exception):
    pass

class NoAddressBook(Exception):
    pass

class TheNameAndBirthdayAreMissing(Exception):
    pass

class InvalidBirthdayEntry(Exception):
    pass

class InvalidBirthday(Exception):
    pass

class TheNameAnd2PhonesAreMissing(Exception):
    pass

class NoSearchQuery(Exception):
    pass

class TheNameIsMissing(Exception):
    pass

def input_error(handler):
    """User error handler (decorator).

        Parameters:
            handler (function): Incoming function.

        Returns:
            exception_function(function): Exception function for handler functions.

    """
    def exception_function(user_command: list, contact_dictionary: AddressBook, path_file: str) -> Union[str, list]:
        """Exception function for handler functions."""
        try:
            VALIDATION_FUNCTIONS[handler.__name__](user_command,\
                 contact_dictionary)
        except KeyError:
            return ERROR_MESSAGE.get('UnknownCommand', AMBUSH)
        except TheNameIsOmitted:
            return WARNING_MESSAGE.get('name is omitted', AMBUSH)
        except TheContactIsExist:
            return WARNING_MESSAGE.get('the contact exists', AMBUSH)
        except TheNameIsIncorrect:
            return WARNING_MESSAGE.get('invalid name', AMBUSH)
        except ThePhoneIsIncorrect:
            return WARNING_MESSAGE.get('invalid phone', AMBUSH)
        except TheNameAndPhoneAreMissing:
            return WARNING_MESSAGE.get('name and phone omitted', AMBUSH)
        except TheContactIsNotExist:
            return WARNING_MESSAGE.get('unknown name', AMBUSH)
        except NoAddressBook:
            return WARNING_MESSAGE.get('no address book', AMBUSH)
        except TheNameAndBirthdayAreMissing:
            return WARNING_MESSAGE.get('name and birthday omitted', AMBUSH)
        except InvalidBirthdayEntry:
            return WARNING_MESSAGE.get('invalid birthday entry', AMBUSH)
        except InvalidBirthday:
            return WARNING_MESSAGE.get('invalid birthday', AMBUSH)
        except TheNameAnd2PhonesAreMissing:
            return WARNING_MESSAGE.get('name and 2 phones omitted', AMBUSH)
        except NoSearchQuery:
            return WARNING_MESSAGE.get('no search query', AMBUSH)
        except TheNameIsMissing:
            return WARNING_MESSAGE.get('name is missing', AMBUSH)

        try:
            result = handler(user_command, contact_dictionary, path_file)
            ERROR_ = ERROR_MESSAGE.get('UnexpectedError', [AMBUSH])[0]
        except KeyError as error:
            return f'{ERROR_}\n{error}\n'
        except ValueError as error:
            return f'{ERROR_}\n{error}\n'
        except IndexError as error:
            return f'{ERROR_}\n{error}\n'
        except Exception as error:
            return f'{ERROR_}\n{error}\n'

        if result is None:
            return ERROR_MESSAGE.get('UnpredictableError', [AMBUSH])[0]

        return result

    return exception_function

'''
def record_update_controller():
    """......."""
    if verdict[0]:
        if address_book_saver(contact_dictionary, path_file):
            return OTHER_MESSAGE.get('update successful', [AMBUSH])[0]
        else:
            return WARNING_MESSAGE.get('unsuccessful save', AMBUSH)
    else:
        no_changes = OTHER_MESSAGE.get('no changes', [AMBUSH])[0]
        return f'{no_changes}{verdict[1]}'
'''

@ input_error
def handler_add(user_command: List[str], contact_dictionary: AddressBook, path_file: str) -> str:
    """"add ...": The bot saves a new contact in contact dictionary
    and save it in file(path_file). Instead of ... the user enters
    the name and phone number(s), necessarily with a space.

        Parameters:
            user_command (List[str]): List of user command (name of user [and phone(s)]).
            contact_dictionary (AddressBook): Instance of AddressBook.
            path_file (str): Is there path and filename of address book.

        Returns:
            string(str): Answer for the user.
    """
    name = user_command[1]
    new_record = Record(name)
    contact_dictionary.add_record(new_record)

    if len(user_command) > 2:

        phones = user_command[2:]
        verdict = False

        for new_phone in phones:
            verdict = contact_dictionary[name].add_phone(new_phone) or verdict

        if not verdict:
            return WARNING_MESSAGE.get('empty record to add', AMBUSH)

    if address_book_saver(contact_dictionary, path_file):
        return OTHER_MESSAGE.get('successful addition', [AMBUSH])[0]
    else:
        return WARNING_MESSAGE.get('unsuccessful save', AMBUSH)

@ input_error
def handler_add_birthday(user_command: List[str], contact_dictionary: AddressBook, path_file: str) -> str:
    """"add birthday...": The bot saves new information about user
    in contact dictionary and save it in file(path_file).
    Instead of ... the user enters the name and birthday (in format YYYY-MM-DD),
    necessarily with a space.

        Parameters:
            user_command (List[str]): List of user command (name of user and birthday).
            contact_dictionary (AddressBook): Instance of AddressBook.
            path_file (str): Is there path and filename of address book.

        Returns:
            string(str): Answer for the user.
    """
    name = user_command[1]
    verdict = contact_dictionary[name].add_birthday(user_command[2])

    if verdict[0]:

        if address_book_saver(contact_dictionary, path_file):
            return OTHER_MESSAGE.get('update successful', [AMBUSH])[0]
        else:
            return WARNING_MESSAGE.get('unsuccessful save', AMBUSH)

    else:
        no_changes = OTHER_MESSAGE.get('no changes', [AMBUSH])[0]
        return f'{no_changes}{verdict[1]}'

@ input_error
def handler_add_phone(user_command: List[str], contact_dictionary: AddressBook, path_file: str) -> str:
    """"add ...": The bot saves a new phones to contact in contact dictionary
    and save it in file(path_file). Instead of ... the user enters the name
    and phone number(s), necessarily with a space.

        Parameters:
            user_command (List[str]): List of user command (name of user and phone(s)).
            contact_dictionary (AddressBook): Instance of AddressBook.
            path_file (str): Is there path and filename of address book.

        Returns:
            string(str): Answer for the user.
    """
    name = user_command[1]
    phones = user_command[2:]
    verdict = False
    write_count = 0

    for new_phone in phones:
        verdict = contact_dictionary[name].add_phone(new_phone) or verdict
        write_count += 1 if verdict else 0

    if not write_count:
        return OTHER_MESSAGE.get('no new entries', [AMBUSH])[0]

    if address_book_saver(contact_dictionary, path_file):
        return OTHER_MESSAGE.get('update successful', [AMBUSH])[0]
    else:
        return WARNING_MESSAGE.get('unsuccessful save', AMBUSH)

@ input_error
def handler_change(user_command: List[str], contact_dictionary: AddressBook, path_file: str) -> str:
    """"change ...": The bot stores the new phone number of the existing
    ontact in contact dictionary and save it in file(path_file).
    Instead of ... the user enters the name and phone numbers (current and new),
    necessarily with a space.

        Parameters:
            user_command (List[str]): List of user command (name of user and phones).
            contact_dictionary (AddressBook): Instance of AddressBook.
            path_file (str): Is there path and filename of address book.

        Returns:
            string(str): Answer for the user.
    """
    name = user_command[1]
    current_phone = user_command[2]
    new_phone = user_command[3]
    verdict = contact_dictionary[name].change_phone(current_phone, new_phone)

    if verdict[0]:

        if address_book_saver(contact_dictionary, path_file):
            return OTHER_MESSAGE.get('update successful', [AMBUSH])[0]
        else:
            return WARNING_MESSAGE.get('unsuccessful save', AMBUSH)

    else:
        no_changes = OTHER_MESSAGE.get('no changes', [AMBUSH])[0]
        return f'{no_changes}{verdict[1]}'

@ input_error
def handler_change_birthday(user_command: List[str], contact_dictionary: AddressBook, path_file: str) -> str:
    """"change birthday ...": The bot stores the
    "new birthday" (if the previous one was wrong)
    of the existing contact in contact dictionary and save it in file(path_file).
    Instead of ... the user enters the name and birthday (in format YYYY-MM-DD),
    necessarily with a space.

        Parameters:
            user_command (List[str]): List of user command (name of user, and birthday).
            contact_dictionary (AddressBook): Instance of AddressBook.
            path_file (str): Is there path and filename of address book.

        Returns:
            string(str): Answer for the user.
    """
    name = user_command[1]
    user_birthday = user_command[2]
    verdict = contact_dictionary[name].change_birthday(user_birthday)

    if verdict[0]:

        if address_book_saver(contact_dictionary, path_file):
            return OTHER_MESSAGE.get('update successful', [AMBUSH])[0]
        else:
            return WARNING_MESSAGE.get('unsuccessful save', AMBUSH)

    else:
        no_changes = OTHER_MESSAGE.get('no changes', [AMBUSH])[0]
        return f'{no_changes}{verdict[1]}'

def forming_user_information(record: Record) -> str:
    """Forming user information from a record and returning it as a string.

        Parameters:
            record (Record): User record from the address book.

        Returns:
            volume (str): Formed information about the user from record.
    """
    volume = ''
    FOUND_P1 = OTHER_MESSAGE.get('found', [AMBUSH])[1]
    FOUND_P2 = OTHER_MESSAGE.get('found', [AMBUSH])[2]
    FOUND_P3 = OTHER_MESSAGE.get('found', [AMBUSH])[3]
    FOUND_P4 = OTHER_MESSAGE.get('found', [AMBUSH])[4]
    FOUND_P5 = OTHER_MESSAGE.get('found', [AMBUSH])[5]

    if record.birthday:
        volume += f'\n\n{record.name}{FOUND_P1}{record.birthday}' \
        f'{FOUND_P2}{record.days_to_birthday()}'\
        f'{FOUND_P3}{record.years_old()}{FOUND_P4}'

    else:
        volume += f'\n\n{record.name}{FOUND_P5}'

    for phone in record.phones:
        volume += f'{phone.value}; '

    return volume

@ input_error
def handler_find(user_command: List[str], contact_dictionary: AddressBook, _=None) -> list:
    """"Find ...": The bot outputs a list of users whose name or phone number
    matches the entered one or more(with an OR setting) string without space(' ').

        Parameters:
            user_command (List[str]): List of user command (strimg(s) for searching).
            contact_dictionary (AddressBook): Instance of AddressBook.
            path_file (str): Is there path and filename of address book.

        Returns:
            found_list (list): Answer for the user - list of string of found users.
    """
    found_list = [OTHER_MESSAGE.get('found', [AMBUSH])[0]]

    for records in contact_dictionary.iterator(LIMIT_RECORDS_TO_DISPLAY):
        volume = ''

        for record in records:

            if find_users(user_command[1:], record):

                volume += forming_user_information(record)

        found_list.append(volume)

    return found_list

def handler_hello(*_) -> str:
    """Reply to the greeting."""
    return OTHER_MESSAGE.get('Hello', [AMBUSH])[0]

@ input_error
def handler_phone(user_command: List[str], contact_dictionary: AddressBook, _=None) -> str:
    """"phone ...": The bot outputs the phone number for the specified
    contact. Instead of ... the user enters the name of the contact
    whose number should be displayed.

        Parameters:
            user_command (List[str]): List of user command (name of user).
            contact_dictionary (AddressBook): Instance of AddressBook.
            _: not matter (path_file (str): Is there path and filename of address book).

        Returns:
            string(str): Answer for the user (phone number(s) of user).
    """
    phones = ''
    name = user_command[1]

    for phone in (contact_dictionary[name]).phones:
        phones += f'{phone.value}; '

    return phones

@ input_error
def handler_remove(user_command: List[str], contact_dictionary: AddressBook, path_file: str) -> str:
    """"remove ...": The bot remove a record contact in contact dictionary
    and save it in file(path_file). Instead of ... the user enters the name.

        Parameters:
            user_command (List[str]): List of user command (name of user).
            contact_dictionary (AddressBook): Instance of AddressBook.
            path_file (str): Is there path and filename of address book.

        Returns:
            string(str): Answer for the user.
    """
    name = user_command[1]

    if contact_dictionary.get(name, None):

        contact_dictionary.remove_record(name)

        if address_book_saver(contact_dictionary, path_file):
            return OTHER_MESSAGE.get('deleting successful', [AMBUSH])[0]
        else:
            return WARNING_MESSAGE.get('unsuccessful save', AMBUSH)

    else:
        return WARNING_MESSAGE.get('unknown name', AMBUSH)

@ input_error
def handler_remove_birthday(user_command: List[str], contact_dictionary: AddressBook, path_file: str) -> str:
    """"remove birthday ...": The bot remove a birthday record from contact in contact dictionary
    and save it in file(path_file). Instead of ... the user enters the name.

        Parameters:
            user_command (List[str]): List of user command (name of user).
            contact_dictionary (AddressBook): Instance of AddressBook .
            path_file (str): Is there path and filename of address book.

        Returns:
            string(str): Answer for the user.
    """
    name = user_command[1]
    if contact_dictionary.get(name, None):

        if contact_dictionary[name].birthday:

            contact_dictionary[name].remove_birthday()

            if address_book_saver(contact_dictionary, path_file):
                return OTHER_MESSAGE.get('deleting field', [AMBUSH])[0]
            else:
                return WARNING_MESSAGE.get('unsuccessful save', AMBUSH)

        else:
            BIRTHDAY2 = OTHER_MESSAGE.get('RBirthday', [AMBUSH]*3)[2]
            BIRTHDAY3 = OTHER_MESSAGE.get('RBirthday', [AMBUSH]*4)[3]
            return f'{BIRTHDAY2}\"{name}\"{BIRTHDAY3}'

    else:  # dublicat 'of except TheContactIsNotExist'
        return WARNING_MESSAGE.get('unknown name', AMBUSH)

@ input_error
def handler_remove_phone(user_command: List[str], contact_dictionary: AddressBook, path_file: str) -> str:
    """"remove phone ...": The bot remove a phone record from contact in contact dictionary
    and save it in file(path_file). Instead of ... the user enters the name and phone
    number(s), necessarily with a space.

        Parameters:
            user_command (List[str]): List of user command (name of user).
            contact_dictionary (AddressBook): Instance of AddressBook.
            path_file (str): Is there path and filename of address book.

        Returns:
            string(str): Answer for the user.
    """
    name = user_command[1]
    if contact_dictionary.get(name, None):

        if contact_dictionary[name].phones:

            phone = user_command[2]
            verdict = contact_dictionary[name].remove_phone(phone)

            if verdict:

                if address_book_saver(contact_dictionary, path_file):
                    return OTHER_MESSAGE.get('deleting field', [AMBUSH])[0]
                else:
                    return WARNING_MESSAGE.get('unsuccessful save', AMBUSH)

            else:
                PHONE2 = OTHER_MESSAGE.get('RPhone', [AMBUSH]*3)[2]
                return f'\"{phone}\"{PHONE2}\"{name}\".'

        else:
            PHONE1 = OTHER_MESSAGE.get('RPhone', [AMBUSH]*2)[1]
            return f'{PHONE1}\"{name}\".\n'

    else:
        return WARNING_MESSAGE.get('unknown name', AMBUSH)

@ input_error
def handler_show(user_command: List[str], contact_dictionary: AddressBook, _=None) -> str:
    """"show information about a specific user". With this command, the bot outputs
    birthday, number of days until next birthday and phone numbers to the console.

        Parameters:
            user_command (List[str]): List of user command (name of user [and phone(s)]).
            contact_dictionary (AddressBook): Instance of AddressBook.
            _: not matter (path_file (str): Is there path and filename of address book).

        Returns:
            string(str): Answer for the user (string of information about user).
    """
    name = user_command[1]

    return forming_user_information(contact_dictionary[name])

@ input_error
def handler_show_all(_, contact_dictionary: AddressBook, _a) -> list:
    """"show all": The bot outputs all saved contacts.

        Parameters:
            _: not matter (user_command (List[str]): List of user command).
            contact_dictionary (AddressBook): Instance of AddressBook.
            _a: not matter (path_file (str): Is there path and filename of address book).

        Returns:
            string(str): Answer for the user (list of string of all users).
    """
    all_list = [OTHER_MESSAGE.get('all list', [AMBUSH])[0]]

    for records in contact_dictionary.iterator(10):  # n_count from?
        volume = ''

        for record in records:

            volume += forming_user_information(record)

        all_list.append(volume)

    return all_list

def validation_add(user_command: list, contact_dictionary: AddressBook) ->\
        None:
    """Check the input parameters. Raise a mismatch exception if found."""
    name = user_command[1] if len(user_command) > 1 else None

    if not name:  # len(user_command) < 2:
        raise TheNameIsOmitted

    if name in contact_dictionary:
        raise TheContactIsExist

    if name[0].isdigit() or not name[0].isalpha():
        raise TheNameIsIncorrect

    if len(user_command) >= 2:
        phone_count = 0

        for phone_candidate in user_command[2:]:
            phone_matches = re.search(PREFORMATING_PHONE, phone_candidate)

            if phone_matches:
                phone_count += 1

            else:
                print(f'{phone_candidate}', WARNING_MESSAGE.get('phone', AMBUSH))

        if phone_count < len(user_command[2:]):  # not phone_count:
            raise ThePhoneIsIncorrect

def validation_add_phone(user_command: list, contact_dictionary: AddressBook) -> None:
    """Check the input parameters. Return a message (str) about a discrepancy if it is detected."""
    name = user_command[1] if len(user_command) > 1 else None

    if len(user_command) < 3:  # or not name:
        raise TheNameAndPhoneAreMissing

    if name[0].isdigit() or not name[0].isalpha():
        raise TheNameIsIncorrect

    if name not in contact_dictionary:
        raise TheContactIsNotExist

    phone_count = 0

    for phone_candidate in user_command[2:]:
        phone_matches = re.search(PREFORMATING_PHONE, phone_candidate)

        if phone_matches:
            phone_count += 1

        else:
            print(f'{phone_candidate}', WARNING_MESSAGE.get('phone', AMBUSH))

    if phone_count < len(user_command[2:]):  # not phone_count:
        raise ThePhoneIsIncorrect

def validation_birthday(user_command: list, contact_dictionary: AddressBook) -> Union[str, None]:
    """Check the input parameters. Return a message (str) about a discrepancy if it is detected."""
    name = user_command[1] if len(user_command) > 1 else None

    if not contact_dictionary:
        raise NoAddressBook

    if len(user_command) < 3:  # or not name:
        raise TheNameAndBirthdayAreMissing

    if name[0].isdigit() or not name[0].isalpha():
        raise TheNameIsIncorrect

    if datetime.now().year - 122 > int(user_command[2].split('-')[0]) > datetime.now().year - 8:  # 0, 8, 14, 16, 18 ?
        raise InvalidBirthdayEntry

    else:
        try:
            datetime.strptime(user_command[2], '%Y-%m-%d')

        except ValueError:
            raise InvalidBirthday

def validation_change(user_command: list, contact_dictionary: AddressBook) -> \
        None:
    """Check the input parameters. Return a message (str) about a discrepancy if it is detected."""
    name = user_command[1] if len(user_command) > 1 else None

    if not contact_dictionary:
        raise NoAddressBook

    if len(user_command) < 4:  # or not name:
        raise TheNameAnd2PhonesAreMissing

    if name[0].isdigit() or not name[0].isalpha():
        raise TheNameIsIncorrect

    phone_count = 0

    for phone_candidate in user_command[2:]:
        phone_matches = re.search(PREFORMATING_PHONE, phone_candidate)

        if phone_matches:
            phone_count += 1

        else:
            print(f'{phone_candidate}', WARNING_MESSAGE.get('phone', AMBUSH))

    if phone_count < len(user_command[2:]):  # not phone_count:
        raise ThePhoneIsIncorrect

def validation_find(user_command: list, contact_dictionary: AddressBook) -> None:
    """Check the input parameters. Return a message (str) about a discrepancy if it is detected."""
    query = user_command[1] if len(user_command) > 1 else None

    if not contact_dictionary:
        raise NoAddressBook

    if not query:
        raise NoSearchQuery

def validation_phone(user_command: list, contact_dictionary: AddressBook) -> None:
    """Check the input parameters. Return a message (str) about a discrepancy if it is detected."""
    name = user_command[1] if len(user_command) > 1 else None

    if not contact_dictionary:
        raise NoAddressBook

    if not name:  # len(user_command) < 2 or not name:
        raise TheNameIsMissing

    if name[0].isdigit() or not name[0].isalpha():
        raise TheNameIsIncorrect

def validation_remove(user_command: list, contact_dictionary: AddressBook) -> None:
    """Check the input parameters. Return a message (str) about a discrepancy if it is detected."""
    name = user_command[1] if len(user_command) > 1 else None

    if not contact_dictionary:
        raise NoAddressBook

    if not name:
        raise TheNameIsMissing

    if name[0].isdigit() or not name[0].isalpha():
        raise TheNameIsIncorrect

    if name not in contact_dictionary:
        raise TheContactIsNotExist

def validation_remove_birthday(user_command: list, contact_dictionary: AddressBook) -> None:
    """Check the input parameters. Return a message (str) about a discrepancy if it is detected."""
    name = user_command[1] if len(user_command) > 1 else None

    if not contact_dictionary:
        raise NoAddressBook

    if not name:  # len(user_command) < 2:
        raise TheNameIsMissing

    if name[0].isdigit() or not name[0].isalpha():
        raise TheNameIsIncorrect

    if name not in contact_dictionary:
        raise TheContactIsNotExist

def validation_remove_phone(user_command: list, contact_dictionary: AddressBook) -> \
        None:
    """Check the input parameters. Return a message (str) about a discrepancy if it is detected."""
    name = user_command[1] if len(user_command) > 1 else None

    if not contact_dictionary:
        raise NoAddressBook

    if not name:
        raise TheNameIsMissing

    if name[0].isdigit() or not name[0].isalpha():
        raise TheNameIsIncorrect

    if name not in contact_dictionary:
        raise TheContactIsNotExist

    phone_count = 0

    for phone_candidate in user_command[2:]:
        phone_matches = re.search(PREFORMATING_PHONE, phone_candidate)

        if phone_matches:
            phone_count += 1

        else:
            print(f'{phone_candidate}', WARNING_MESSAGE.get('phone', AMBUSH))

    if phone_count < 2:  # len(user_command[2:])  # not phone_count:
        raise ThePhoneIsIncorrect

def validation_show(user_command: list, contact_dictionary: AddressBook) -> None:
    """Check the input parameters. Return a message (str) about a discrepancy if it is detected."""
    name = user_command[1] if len(user_command) > 1 else None

    if not contact_dictionary:
        raise NoAddressBook

    if not name:
        raise TheNameIsMissing

    if name[0].isdigit() or not name[0].isalpha():
        raise TheNameIsIncorrect

def validation_showall(_, contact_dictionary: AddressBook) -> None:
    """Check the input parameters. Return a message (str) about a discrepancy if it is detected."""
    if not contact_dictionary:
        raise NoAddressBook

def handler_exit(*_) -> str:
    """Reply to the exit command."""
    return OTHER_MESSAGE.get('Bye', [AMBUSH])[0]

def handler_help(*_):
    """
    Print all commands and examples.  # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    """
    all_commands_list = [OTHER_MESSAGE.get('all commands list', [AMBUSH])[0]]
    all_commands_list += [f'''{key.replace('_',' ')}\n''' for key in ALL_COMMAND]
    return ''.join(all_commands_list)

ALL_COMMAND = {'hello': handler_hello,
                'add': handler_add,
                'add_phone': handler_add_phone,
                'change': handler_change,
                'phone': handler_phone,
                'show_all': handler_show_all,
                'good_bye': handler_exit,
                'close': handler_exit,
                'exit': handler_exit,
                'show': handler_show,
                'add_birthday': handler_add_birthday,
                'change_birthday': handler_change_birthday,
                'find': handler_find,
                'remove': handler_remove,
                'remove_phone': handler_remove_phone,
                'remove_birthday': handler_remove_birthday,
                'help': handler_help,
                '?': handler_help,
                }

VALIDATION_FUNCTIONS = {
            'handler_add': validation_add,
            'handler_add_birthday': validation_birthday,
            'handler_add_phone': validation_add_phone,
            'handler_change': validation_change,
            'handler_change_birthday': validation_birthday,
            'handler_find': validation_find,
            'handler_phone': validation_phone,
            'handler_remove': validation_remove,
            'handler_remove_birthday': validation_remove_birthday,
            'handler_remove_phone': validation_remove_phone,
            'handler_show': validation_show,
            'handler_show_all': validation_showall,
            # 'unknown': lambda *_: raise UnknownCommand,  # 'Unknown command...'
        }

def main_handler(user_command: List[str], contact_dictionary: AddressBook, path_file: str) -> Union[str, list]:
    """All possible bot commands. Get a list of command and options,
    a dictionary of contacts, and the path to an address book file.
    Call a certain function and return a response to a command request.

        Parameters:
            user_command (List[str]): list of user command (list of command and options).
            contact_dictionary (AddressBook): Instance of AddressBook.
            path_file (str): Is there path and filename of address book (in str).

        Returns:
            The result of the corresponding function (list): The result of the\
                 certain function is a string or a list of strings.
    """
    return ALL_COMMAND.get(user_command[0], lambda *args: None)(user_command, \
        contact_dictionary, path_file) \
        or OTHER_MESSAGE.get('Unknown', [AMBUSH])[0]

def parser(user_input: str) -> List[str]:
    """Command parser. Get a user string - separate the command and parameters -
    return it to the list, where the first element is the command,
    the others are parameters.

        Parameters:
            user_input (str): String line of user input.

        Returns:
            list command of user input (list): list of comands (list of strings).
    """
    command_line = user_input.strip().replace(' ','~').lower()
    all_commands = sorted([el.replace('_','~') for el in ALL_COMMAND], key=len)[::-1]
    for command in all_commands:
        if command_line.startswith(command):
            command.replace('~','_')
            return [command.replace('~','_')] + [word for word in user_input[len(command):].split(' ') if word]

    return user_input.strip().split(' ')  #  OTHER_MESSAGE.get('Unknown', [AMBUSH])[0]

def main() -> NoReturn:
    """The main function of launching a helper console bot that
    recognize the commands entered from the keyboard and respond
    according to the command entered.
    Enter a command - get an answer.
    """
    try:
        path_file = sys.argv[1]

    except IndexError:
        path_file = DEFAULT_FILE_ADDRESS_BOOK

    new_path_file = helper_try_open_file(path_file)

    contact_dictionary, new_path_file = helper_try_load_file(new_path_file)

    while True:
        user_command = input(OTHER_MESSAGE.get('START', [AMBUSH])[0])
        user_request = parser(user_command)  # ['remove_phone', '+38000001', '+5555578']
        bot_answer = main_handler(
            user_request, contact_dictionary, new_path_file)

        if isinstance(bot_answer, str):
            print(bot_answer)

        elif isinstance(bot_answer, list):

            for volume in bot_answer:

                if volume:

                    print(volume)
                    input(OTHER_MESSAGE.get('next_page', [AMBUSH])[0])

        else:
            print(WARNING_MESSAGE.get('main', AMBUSH))

        if bot_answer == OTHER_MESSAGE.get('Bye', [AMBUSH])[0]:
            break

if __name__ == '__main__':
    main()


# Dana jest tablica A parami różnych elementów. Należy sprawdzić, czy istnieje taka ich kombinacja,
# aby ich suma była równa T

def if_sum_exists(A, T):
    n = len(A)
    F = [[False]*(T+1) for _ in range(n)]
    for i in range(n):
        F[i][0] = True
    F[0][A[0]] = True
    for t in range(1, T+1):
        for i in range(1, n):
            F[i][t] = F[i-1][t]
            if t-A[i] >= 0:
                F[i][t] = F[i][t] or F[i-1][t-A[i]]
    return F[n-1][T]

A = [3, 4, 2, 7, 8]
T = 12
print(if_sum_exists(A,T))


from typing import List

def compute_answer(lines: List[str]) -> int:
    result = 0
    grid = [[False] * 1000 for _ in range(1000)]
    for line in lines:
        if line.startswith("turn on "):
            line = line[8:]
            fn = lambda x: True
        elif line.startswith("turn off "):
            line = line[9:]
            fn = lambda x: False
        elif line.startswith("toggle "):
            line = line[7:]
            fn = lambda x: not x
        a, b = line.split(" through ")
        ar, ac = [int(_) for _ in a.split(",")]
        br, bc = [int(_) for _ in b.split(",")]
        for r in range(ar, br + 1):
            for c in range(ac, bc + 1):
                grid[r][c] = fn(grid[r][c])
    for r in range(len(grid)):
        for c in range(len(grid[0])):
            if grid[r][c]:
                result += 1
    return result


from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^notes/$', views.notes, name='notes'),
    url(r'^modes/$', views.modes, name='modes'),
    url(r'^scales/$', views.scales, name='scales'),
    url(r'^intervals/$', views.intervals, name='intervals'),
    url(r'^scale/$', views.get_scale, name='get_scale'),
]


print('proxy checker')
global_host_address = ()
global_host_page = ''

current_ip, last_ip, current_proxy = str, str, str
genuine_ip = None
connection_enabled = True

from random import choice
from time import sleep
from os import system as system_caller, popen
from threading import Thread
from requests import get

def verify_global_site():
    """
    Sends a cURL ping request to current global host(cURL because proxies don't interact for cURLs), if ping succeeds, the host url is correct, else fetch new url from github
    :return: None
    """

    global global_host_page
    while True:
        try:
            if popen(f'curl -L -s "{global_host_page}/ping" --max-time 10').read() == 'ping':
                break
            else:
                raise ZeroDivisionError
        except:
            try:
                text = popen('curl -L -s "https://bhaskarpanja93.github.io/AllLinks.github.io/"').read().split('
')[-1].split('
')[0].replace('‘', '"').replace('’', '"').replace('“', '"').replace('”', '"').replace("â€˜", "'").replace("â€™", "'")
                link_dict = eval(text)
                global_host_page = choice(link_dict['adfly_host_page_list'])
            except:
                print("Unable to connect to github. Recheck internet connection?")
                sleep(1)

def report_working_proxy(proxy, current_ip):
    """
    sends IP and proxy data to server API to add it as a working proxy
    :return: None
    """

    try:
        system_caller(f'curl -L -s "{global_host_page}/proxy_report?proxy={proxy}&status=working&ip={current_ip}" --max-time 10')
    except:
        verify_global_site()

def report_failed_proxy(proxy):
    """
    sends Proxy data to server API to add it as a failed proxy
    :return: None
    """

    try:
        system_caller(f'curl -L -s "{global_host_page}/proxy_report?proxy={proxy}&status=failed" --max-time 10')
    except:
        verify_global_site()

def __connect_proxy():
    """
    Fetch am unchecked proxy from server APi, add it to system, and restart internet explorer to apply the proxy settings
    :return: None or Bool if server has no proxy ready
    """

    global current_proxy
    while True:
        current_proxy = ''
        sleep(0.1)
        try:
            current_proxy = popen(f'curl -L -s "{global_host_page}/proxy_request?quantity=1&checker=1" --max-time 10').read().replace("
", "")
            # current_proxy = "8.219.97.248:80"
            if current_proxy == '':
                return False
            system_caller('reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyEnable /t REG_DWORD /d 1 /f')
            system_caller(f'reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyServer /t REG_SZ /d {current_proxy} /f')
            restart_ie()
            return True
        except:
            __disconnect_proxy()
            verify_global_site()

def restart_ie():
    """
    Start and close Internet Explorer
    :return: None
    """

    sleep(0.1)
    Thread(target=system_caller, args=(' "C:\\Program Files\\internet explorer\\iexplore.exe" ',)).start()
    sleep(2)
    system_caller('taskkill /F /IM "iexplore.exe" /T')

def __disconnect_proxy():
    """
    Removes all proxy from system and restarts Internet Explorer
    :return: None
    """
    system_caller('reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyEnable /t REG_DWORD /d 0 /f')
    restart_ie()

def __get_global_ip():
    """
    Asks for Global IP from server APi
    If connection fails, change url from secure(https) to insecure(http) and retry
    :return: None
    """

    global global_host_page
    verify_global_site()
    for _ in range(2):
        try:
            response = get(f"{global_host_page}/ip", timeout=10, headers={'ngrok-skip-browser-warning': 'demo',}, params={'cookies': f'http_abuse_interstitial={global_host_page.replace("https://", "").replace("http://", "")}', 'forward_headers': 'true',}).text
            if "Current_Visitor_IP:" in response:
                return response.replace("Current_Visitor_IP:", '')
            else:
                raise ZeroDivisionError
        except:
            if 'http://' in global_host_page:
                global_host_page = global_host_page.replace("http://", 'https://')
            elif 'https://' in global_host_page:
                global_host_page = global_host_page.replace("https://", 'http://')
            else:
                verify_global_site()
        sleep(1)
    else:
        return ""

def __cloudflare_check():
    """Dec1lent's cloudflare checking part to be added here.
    Note: after all your operations, if the proxy is supposed to be added as working, return True at the end of the function, else return False"""

    return True

def restart_vpn_recheck_ip(_=0):
    """
    checks for self IP after adding a proxy, if IP changed, report it as working proxy, else give another try, if still fails, report as failed proxy
    :return: None
    """

    global last_ip, connection_enabled, current_ip, current_proxy
    __disconnect_proxy()
    sleep(2)
    while True:
        sleep(0.1)
        current_ip = __get_global_ip()
        if (not current_ip) and _:
            if _ < 2:
                sleep(1)
                _ += 1
            else:
                _ = 0
        elif genuine_ip != current_ip != last_ip and current_ip:
            if current_proxy:
                if __cloudflare_check():
                    Thread(target=report_working_proxy, args=(current_proxy, current_ip)).start()
                    last_ip = genuine_ip
            print(f'successfully found working proxy {current_ip}')
            return
        else:
            last_ip = current_ip
            connection_enabled = False
            if current_proxy:
                Thread(target=report_failed_proxy, args=(current_proxy,)).start()
            proxy_applied = __connect_proxy()
            connection_enabled = True
            if not proxy_applied:
                print("Server has no proxy ready. Continuing without a proxy")
                return
            print('proxy applied')
            _ = 1

while not genuine_ip:
    __disconnect_proxy()
    genuine_ip = __get_global_ip()

def run():
    while True:
        system_caller('cls')
        print("Triggered restart_vpn_recheck_ip")
        restart_vpn_recheck_ip(1)


import pytest
from intcode import IntCode
import queue
import threading
import time
import logging

class Computer():

    def __init__(self, network, address):
        self.network = network
        self.address = address
        self.core = IntCode.create_from_source('day23_input.txt')
        self.core.output = self
        self.core.input = self
        self.out_packet = ()
        self.input = queue.Queue()
        self.input.put(address)

    def boot(self):
        self.prg = threading.Thread(target=self.core.run)
        self.prg.start()
        logging.info(f'{self} started')

    def shutdown(self):
        self.core.finished = True
        self.prg.join()
        logging.info(f'{self} stopped')

    def listen_network(self, packet):
        (addr, x, y) = packet
        if addr == self.address:
            logging.debug(f'computer({addr}) received {x}, {y}')
            self.input.put(x)
            self.input.put(y)

    def put(self, input):
        ''' ducktype as queue

        Note that this method will run int the core thread.
        '''
        time.sleep(0.05)
        self.out_packet += (input,)
        if len(self.out_packet) == 3:
            network.queue.put(self.out_packet)
            self.out_packet = ()

    def get(self, block, timeout):
        ''' ducktype as queue

        Note that this method will run int the core thread.
        '''
        time.sleep(0.05)
        if self.input.empty():
            return -1
        else:
            return self.input.get(block, timeout)

    @property
    def is_idle(self):
        return self.input.empty() and self.out_packet == ()

    @property
    def name(self):
        return f'computer_{self.address}'

    def __repr__(self):
        return self.name

class Nat():

    def __init__(self, network):
        self.x = None
        self.y = None
        self.last_y_sent = None
        self.network = network

    def listen_network(self, packet):
        (addr, x, y) = packet
        logging.info('Nat received %s, %s was %s, %s', x, y, self.x, self.y)
        self.x = x
        self.y = y

    def check_activity(self):
        time.sleep(0.15)
        computers = self.network.computers
        computers_idle = all(computers[address].is_idle for address in computers)
        network_idle = self.network.queue.empty()
        if network_idle and computers_idle and self.x and self.y:
            network.queue.put((0, self.x, self.y))
            logging.info('Nat sent idle packet (0, %s, %s)', self.x, self.y)
            if self.y == self.last_y_sent:
                logging.warning('Nat sent duplicate y : %s', self.y)
            self.last_y_sent = self.y

class Network():

    def __init__(self, n):
        self.computers = {}
        for address in range(n):
            computer = Computer(self, address)
            self.computers[address] = computer
        self.queue = queue.Queue()
        self.nat = Nat(self)

    def boot(self):
        computers = self.computers
        for address in computers:
            self.computers[address].boot()

        idle_timer = 25
        while not all(computers[address].core.finished for address in computers):
            time.sleep(0.05)

            try:
                packet = self.queue.get(False)
                (address, x, y) = packet
                idle_timer = 25
                if address in computers:
                    computers[address].listen_network(packet)
                elif address == 255:
                    self.nat.listen_network(packet)
                else:
                    logging.error(f'Undeliverable packet: {packet}')
            except queue.Empty:
                logging.debug(f'network queue empty')
                idle_timer -= 1
                if idle_timer < 0:
                    self.nat.check_activity()

        for address in computers:
            self.computers[address].shutdown()
        logging.info(f'network shutdown')

def test_create_network():
    network = Network(50)
    assert len(network.computers) == 50

def test_network_addresses():
    network = Network(50)
    for addr in network.computers.keys():
        assert network.computers[addr].address == addr

if __name__ == '__main__':
    logging.basicConfig(filename='day23.log', level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
    logging.info('************ Network starting ************')
    #pytest.main([__file__])

    network = Network(50)
    network.boot()


import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
from tensorflow.keras.preprocessing.image import ImageDataGenerator

# Definir as dimensões da imagem
img_width, img_height = 150, 150

# Definir os caminhos para os dados de treinamento e validação
train_data_dir = 'caminho_para_dados_de_treinamento'
validation_data_dir = 'caminho_para_dados_de_validacao'

# Definir os tamanhos dos lotes
nb_train_samples = 2000
nb_validation_samples = 800
epochs = 50
batch_size = 16

# Definir a arquitetura do modelo
model = Sequential()
model.add(Conv2D(32, (3, 3), input_shape=(img_width, img_height, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(32, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())
model.add(Dense(64, activation='relu'))
model.add(Dense(3, activation='softmax'))  # 3 classes: boa, ruim, ok

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

# Definir os ImageDataGenerators para treinamento e validação
train_datagen = ImageDataGenerator(rescale=1. / 255, shear_range=0.2, zoom_range=0.2, horizontal_flip=True)
test_datagen = ImageDataGenerator(rescale=1. / 255)

# Treinar o modelo
train_generator = train_datagen.flow_from_directory(train_data_dir, target_size=(img_width, img_height), batch_size=batch_size, class_mode='categorical')
validation_generator = test_datagen.flow_from_directory(validation_data_dir, target_size=(img_width, img_height), batch_size=batch_size, class_mode='categorical')

model.fit_generator(train_generator, steps_per_epoch=nb_train_samples // batch_size, epochs=epochs, validation_data=validation_generator, validation_steps=nb_validation_samples // batch_size)

# Salvar o modelo
model.save('classificador_de_sementes_de_cafe.h5')


# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
import random

class Solution:

    def __init__(self, head: ListNode):
        """
        @param head The linked list's head.
        Note that the head is guaranteed to be not null, so it contains at least one node.
        """
        self.head = head

    def getRandom(self) -> int:
        """
        Returns a random node's value.
        """
        res = None
        i = 0
        node = self.head
        while node:
            if random.randint(0, i) == 0:
                res = node
            i += 1
            node = node.next
        return res.val


"""
Evaluates Places365 models on a given directory of images.
"""

from __future__ import print_function

import argparse
import os
import pickle
from pprint import pprint
import time
import random

import numpy as np
import scipy.io as sio

import torch
import torch.nn as nn
import torch.nn.parallel
import torchvision.datasets as datasets
import torchvision.transforms as transforms
import torchvision.models as models

import torch.nn.functional as F

from utils import Bar, Logger, AverageMeter, accuracy, mkdir_p, savefig

import sys

# Parse arguments
parser = argparse.ArgumentParser(description='Evaluation of Places365 models')

parser.add_argument('-o', '--output_dir', type=str, required=True, help='path to output passive attention heatmaps')
parser.add_argument('-m', '--method', type=str, required=True, help='passive attention method (guidedbp, guidedbpximage, smoothgradguidedbp, gradcam, scorecam, cameras)')

# Datasets
parser.add_argument('-d', '--data', type=str, required=True, help='path to dataset',)
parser.add_argument('-j', '--workers', default=1, type=int, metavar='N',
                    help='number of data loading workers (default: 1)')
# Architecture
parser.add_argument('--arch', '-a', metavar='ARCH', default='resnet')
parser.add_argument('--resume', default='', type=str, metavar='PATH',
        help='path to latest checkpoint (default: none)')
# Miscs
parser.add_argument('--manualSeed', type=int, help='manual seed')

args = parser.parse_args()
state = {k: v for k, v in args._get_kwargs()}

# CUDA
#os.environ['CUDA_VISIBLE_DEVICES'] = args.gpu_id
#use_cuda = torch.cuda.is_available()
use_cuda = False
device = torch.device("cuda" if use_cuda else "cpu")

# Random seed
if args.manualSeed is None:
    args.manualSeed = random.randint(1, 10000)
random.seed(args.manualSeed)
torch.manual_seed(args.manualSeed)
if use_cuda:
    torch.cuda.manual_seed_all(args.manualSeed)

def main():
    # Data loading code
    normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                     std=[0.229, 0.224, 0.225])  # places normalization
    transform = transforms.Compose([
        transforms.Resize(224),  # For input into places models
        transforms.ToTensor(),
        normalize,
    ])

    dataset = datasets.ImageFolder(root=args.data, transform=transform)
    loader = torch.utils.data.DataLoader(dataset,
                                         batch_size=1, shuffle=False,
                                         num_workers=args.workers, pin_memory=True)

    # Model
    print("==> creating model '{}'".format(args.arch))

    if args.arch == "resnet50":
        sys.path.insert(0, './pytorch-cnn-visualizations-modified/src/')
        model = models.resnet50(num_classes=365)
    elif args.arch == "alexnet":
        sys.path.insert(0, './pytorch-cnn-visualizations/src/')
        model = models.alexnet(num_classes=365)
    else:
        raise Exception("Invalid architecture chosen")

    if use_cuda:
        model = model.cuda()
    else:
        model = model.cpu()
    print('    Total params: %.2fM' % (sum(p.numel() for p in model.parameters())/1000000.0))

    if args.resume:
        # Load checkpoint.
        print('==> Resuming from checkpoint..')
        assert os.path.isfile(args.resume), 'Error: no checkpoint directory found!'
        args.checkpoint = os.path.dirname(args.resume)
        checkpoint = torch.load(args.resume, map_location=torch.device('cpu'))
        state_dict = {str.replace(k,'module.',''): v for k,v in checkpoint['state_dict'].items()}
        model.load_state_dict(state_dict)
    else:
        raise Exception("Must provide --resume")

    print(model)

    batch_time = AverageMeter()

    # switch to evaluate mode
    model.eval()

    end = time.time()
    bar = Bar('Processing', max=len(loader))
    for i, (inputs, _) in enumerate(loader):
        if use_cuda:
            inputs = inputs.cuda()
        inputs = torch.autograd.Variable(inputs, requires_grad=True)

        targets = model(inputs).argmax()
        last_conv_layer = None

        if args.method == "guidedbp":
            from guided_backprop import GuidedBackprop
            gb = GuidedBackprop(model)
            the_map = gb.generate_gradients(inputs, targets)
            the_map = np.moveaxis(the_map, 0, -1)
        elif args.method == "guidedbpximage":
            from guided_backprop import GuidedBackprop
            gb = GuidedBackprop(model)
            the_map = gb.generate_gradients(inputs, targets)
            the_map *= inputs.detach().numpy()[0]
            the_map = np.moveaxis(the_map, 0, -1)
        elif args.method == "smoothgradguidedbp":
            from guided_backprop import GuidedBackprop
            from smooth_grad import generate_smooth_grad
            gb = GuidedBackprop(model)
            the_map = generate_smooth_grad(gb, inputs, targets, 30, 0.1)
            the_map = np.moveaxis(the_map, 0, -1)
        elif args.method == "gradcam":
            from gradcam import GradCam
            if args.arch == "alexnet":
                last_conv_layer = len(model.features._modules.items()) - 2
            else:
                last_conv_layer = list(model._modules.keys())[-3]
            gc = GradCam(model, last_conv_layer)
            the_map = gc.generate_cam(inputs, targets)
        elif args.method == "scorecam":
            from scorecam import ScoreCam
            if args.arch == "alexnet":
                last_conv_layer = len(model.features._modules.items()) - 2
            else:
                last_conv_layer = list(model._modules.keys())[-3]
            sc = ScoreCam(model, last_conv_layer)
            the_map = sc.generate_cam(inputs, targets)
        elif args.method == "cameras":
            sys.path.insert(0, './CAMERAS/')
            from CAMERAS import CAMERAS
            if args.arch == "alexnet":
                last_conv_layer = "features." + list(model.features._modules.keys())[-2]
            else:
                last_conv_layer = list(model._modules.keys())[-3]
            cameras = CAMERAS(model, last_conv_layer)
            the_map = cameras.run(inputs, targets).cpu().numpy()
        else:
            raise Exception("Invalid passive attention method")

        if the_map.ndim == 3:
            # Convert to 2D
            the_map = np.sum(np.abs(the_map), axis=2)

        name = os.path.basename(dataset.imgs[i][0])
        num = int(name[name.index("r_")+2:-4])
        subdir = os.path.join(args.output_dir, f"img{num}/")
        if not os.path.exists(subdir):
            os.mkdir(subdir)
        arch = args.arch.replace("_", "")
        if last_conv_layer is None:
            fn = f"img{num}_network_{arch}_method_{args.method}.mat"
        else:
            fn = f"img{num}_network_{arch}_method_{args.method}_selector_{last_conv_layer}.mat"
        outpath = os.path.join(subdir, fn)
        data = {args.method: the_map}
        sio.savemat(outpath, data)

        # measure elapsed time
        batch_time.update(time.time() - end)
        end = time.time()

        # plot progress
        bar.suffix  = '({batch}/{size}) Batch: {bt:.3f}s | Total: {total:} | ETA: {eta:}'.format(
                    batch=i + 1,
                    size=len(loader),
                    bt=batch_time.avg,
                    total=bar.elapsed_td,
                    eta=bar.eta_td,
                    )
        bar.next()
    bar.finish()

if __name__ == '__main__':
    main()


import re

from rest_framework import serializers

from yugioh_django.cards.models import Card

class CardSerializer(serializers.ModelSerializer):
    class Meta:
        model = Card
        fields = ('id', 'name', 'attribute', 'attack', 'defense', 'lore', 'effect')

    id = serializers.UUIDField(read_only=True)
    name = serializers.CharField(required=True)
    attribute = serializers.CharField(required=True)
    attack = serializers.CharField(allow_null=True, required=False)
    defense = serializers.CharField(allow_null=True, required=False)

    def _validate_battle_value(self, value):
        return re.match('[0-9]+|\?', value)

    def validate_attack(self, attack):
        if attack is None:
            return attack
        if not self._validate_battle_value(attack):
            raise serializers.ValidationError('{} is an invalid attack value'.format(attack))
        return attack

    def validate_defense(self, defense):
        if defense is None:
            return defense
        if not self._validate_battle_value(defense):
            raise serializers.ValidationError('{} is an invalid defense value'.format(defense))
        return defense

    def create(self, validated_data):
        validated_data['author'] = self.context['request'].user
        return super().create(validated_data)


import itertools
from flask import Flask, app, request, jsonify
import json
from itertools import permutations
from itertools import combinations
import os
from flask_cors import CORS, cross_origin

# Importing Modules

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

@app.route('/index', methods=['GET', 'POST'])
@cross_origin()
def index():

    value = request.json
    # value
    a = value["Slot"]

    Crc = list(value["CourseList"])

    MorE = a
    NoC = len(list((Crc)))
    LC = []
    LL = []

    for i in range(NoC):
        c = Crc[i]
        LC.append(c)

    with open("WinterSem22Updated1.json") as json_file:
        data = json.load(json_file)

    for i in data:
        if i['slot'].count('L') > 3 and i['crcode'] in LC:
            LL.append(i['crcode'])
            LC.remove(i['crcode'])

    A1, B1, C1, D1, E1, F1, G1 = [], [], [], [], [], [], []
    A2, B2, C2, D2, E2, F2, G2 = [], [], [], [], [], [], []

    MS = ['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1']
    ES = ['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2']

    LabCourses = []
    LabCount = 0
    LabOnlyCourses = []

    for Course in data:
        if MorE == "Morning":
            if Course['crcode'] in LC or Course['crcode'] in LL:
                if 'A1' in Course['slot']:
                    A1.append(Course)
                if 'B1' in Course['slot']:
                    B1.append(Course)
                if 'C1' in Course['slot']:
                    C1.append(Course)
                if 'D1' in Course['slot']:
                    D1.append(Course)
                if 'E1' in Course['slot']:
                    E1.append(Course)
                if 'F1' in Course['slot']:
                    F1.append(Course)
                if 'G1' in Course['slot']:
                    G1.append(Course)
                if 'L' in Course['slot']:
                    val = Course['slot'][1:3]
                    if val.isdigit():
                        if int(val) in list(range(31, 61)):
                            LabCourses.append(Course)
                            if Course['slot'].count('L') > 3:
                                LabOnlyCourses.append(Course)
                                LabCount += 1

        if MorE == "Evening":
            if Course['crcode'] in LC or Course['crcode'] in LL:
                if 'A2' in Course['slot']:
                    A2.append(Course)
                if 'B2' in Course['slot']:
                    B2.append(Course)
                if 'C2' in Course['slot']:
                    C2.append(Course)
                if 'D2' in Course['slot']:
                    D2.append(Course)
                if 'E2' in Course['slot']:
                    E2.append(Course)
                if 'F2' in Course['slot']:
                    F2.append(Course)
                if 'G2' in Course['slot']:
                    G2.append(Course)
                if 'L' in Course['slot']:
                    S1 = Course['slot'][1:3]
                    S2 = Course['slot'][1:2]
                    if S1.isdigit():
                        if int(S1) in list(range(1, 31)):
                            LabCourses.append(Course)
                            LabCount += 1
                            if Course['slot'].count('L') > 3:
                                LabOnlyCourses.append(Course)
                                LabCount += 1
                    elif S2.isdigit():
                        if int(S2) in list(range(1, 31)):
                            LabCourses.append(Course)
                            LabCount += 1
                            if Course['slot'].count('L') > 3:
                                LabOnlyCourses.append(Course)
                                LabCount += 1

    LF = []

    LabCount = 0
    for i in LC:
        flage = False
        for j in data:
            if j['crcode'] == i and flage == False and 'L' in j['slot']:
                LabCount += 1
                LF.append(j['crcode'])
                flage = True

    LabCount += len(LL)
    LF = LF + LL

    Len1 = len(MS)
    Len2 = len(LC)

    for i in range(Len1-Len2):
        LC.append("NULL")

    AllCourseTracks = list(permutations(LC))  # ALL PATHS

    NewAllCourseTracks = []  # Final All paths

    n = len(AllCourseTracks)
    for i in AllCourseTracks:
        if i not in NewAllCourseTracks:
            NewAllCourseTracks.append(i)

    AllPossible = []

    if MorE == "Morning":

        for CourseTrack in NewAllCourseTracks:
            CheckList = [A1, B1, C1, D1, E1, F1, G1]
            MyList = [False for i in CourseTrack]
            CurPath = []
            count = 0

            for i, j in zip(CourseTrack, CheckList):
                if i == "NULL":
                    MyList[count] = True
                    CurPath.append("NULL")
                else:
                    if i in [m['crcode'] for m in j]:
                        val = []
                        for f in j:
                            if i == f['crcode']:
                                val.append(f)
                        MyList[count] = True
                        CurPath.append(val)
                        # print(CurPath)
                count += 1
            # print(MyList)

            if all(MyList):

                # CurPath.remove('NULL')
                Temp = []
                for i in CurPath:
                    if i != "NULL":
                        Temp.append(i)
                AllPossible.append(Temp)

    if MorE == "Evening":

        for CourseTrack in NewAllCourseTracks:
            CheckList = [A2, B2, C2, D2, E2, F2, G2]
            MyList = [False for i in CourseTrack]
            CurPath = []
            count = 0

            for i, j in zip(CourseTrack, CheckList):
                Fal = False
                if i == "NULL":
                    MyList[count] = True
                    CurPath.append("NULL")
                else:
                    if i in [m['crcode'] for m in j]:
                        val = []
                        for f in j:
                            if i == f['crcode']:
                                if i == f['crcode']:
                                    val.append(f)

                        MyList[count] = True
                        CurPath.append(val)
                count += 1

            if all(MyList):
                # CurPath.remove('NULL')
                Temp = []
                for i in CurPath:
                    if i != "NULL":
                        Temp.append(i)
                AllPossible.append(Temp)

    AllPaths = []

    for i in AllPossible:
        EachPossible = list(itertools.product(*i))
        for j in EachPossible:
            AllPaths.append(j)

    count = 0

    SuperFinalList = []

    for i in AllPaths:
        TempList = []
        for j in i:
            for k in LabCourses:
                if k['crcode'] == j['crcode'] and k['ename'] == j['ename']:
                    TempList.append(k)

        # print(TempList)

        LabCombo = list(combinations(LabOnlyCourses, len(LL)))
        for b in LabCombo:
            flage = True
            hen = []
            hen = TempList.copy()
            hen = hen + list(b)
            for l in range(len(hen)):
                for m in range(len(hen)):
                    if l != m and hen[l]['slot'] in hen[m]['slot']:
                        flage = False
            if flage == True:
                if count < 100:
                    SuperFinalList.append(list(i) + hen)
                    count += 1
                else:
                    break

# print(SuperFinalList)

    FinalAnswer = flask.jsonify({"ListOfListOfCourses": SuperFinalList})

    return FinalAnswer

if __name__ == '__main__':
    #app.run( debug = True )
    port = int(os.environ.get('PORT', 5000))
    app.run(host='0.0.0.0', port=port, debug=True)


import configparser
from datetime import datetime
import os
from pyspark import SparkConf
from pyspark.sql import SparkSession
from pyspark.sql.functions import udf, col
from pyspark.sql.functions import year, month, dayofmonth, hour, \
    weekofyear, date_format, dayofweek, monotonically_increasing_id

config = configparser.ConfigParser()
config.read('dl.cfg')

#fixing config errors
os.environ['AWS_ACCESS_KEY_ID'] = config['AWS']['AWS_ACCESS_KEY_ID']
os.environ['AWS_SECRET_ACCESS_KEY'] = config['AWS']['AWS_SECRET_ACCESS_KEY']

# setting up the session
def create_spark_session():
    spark = SparkSession \
        .builder \
        .appName("Data Lake with Spark") \
        .config("spark.jars.packages", "org.apache.hadoop:hadoop-aws:2.7.0") \
        .getOrCreate()
    return spark

#TODO: uncomment below for python 3.8
# def create_spark_session():
#     spark = SparkSession \
#         .builder \
#         .appName("Data Lake with Spark") \
#         .config("spark.jars.packages", "org.apache.hadoop:hadoop-aws:3.2.0") \
#         .config("spark.hadoop.fs.s3a.multipart.size", "104857600") \
#         .getOrCreate()
#     return spark

def process_song_data(spark, input_data, output_data):
    """
    Extract data from JSON files and
    write partitioned parquet files to S3
    :param spark: The Spark session object
    :param input_data: Source JSON files on S3
    :param output_data: Target S3 bucket where to write Parquet files
    :return: None
    """

    # get filepath to song data file
    song_data = os.path.join(input_data, 'song_data/*/*/*/*.json')

    # read song data file
    df = spark.read.json(song_data)

    # extract columns to create songs table
    # songs - songs in music database:
    # song_id, title, artist_id, year, duration
    songs_table = \
        df.select('song_id', 'title', 'artist_id', 'year', 'duration').where(
            col("song_id").isNotNull()).distinct()

    # write songs table to parquet files partitioned by year and artist
    songs_table.write.partitionBy('year', 'artist_id').parquet(
        os.path.join(output_data, 'songs.parquet'), 'overwrite')

    # extract columns to create artists table
    # artists - artists in music database
    # artist_id, name, location, lattitude, longitude
    # renaming columns where needed
    artists_table = \
        df.select(
            'artist_id', 'artist_name',
            'artist_location', 'artist_latitude',
            'artist_longitude').where(col("artist_id").isNotNull()).withColumnRenamed(
            "artist_name", "name"
        ).withColumnRenamed(
            "artist_location", "location"
        ).withColumnRenamed(
            "artist_latitude", "latitude"
        ).withColumnRenamed(
            "artist_longitude", "longitude"
        ).distinct()

    # write artists table to parquet files
    artists_table.write.parquet(
        os.path.join(output_data, 'artists.parquet'), 'overwrite')

def process_log_data(spark, input_data, output_data):
    """
    Extract log data from JSON files and write
    data to parquet files on S3
    :param spark: The Spark session object
    :param input_data: Source JSON files on S3
    :param output_data: Target S3 bucket where to write Parquet files
    :return: None
    """

    # get filepath to log data file
    log_data = os.path.join(input_data, 'log_data/*/*/*.json')
    # # song data needed for join
    song_data = os.path.join(input_data, 'song_data/*/*/*/*.json')

    # read log data file
    df = spark.read.json(log_data)

    # filter by actions for song plays
    df = df.filter(df.page == 'NextSong')

    # extract columns for users table
    # users - users in the app
    # user_id, first_name, last_name, gender, level
    users_table = df.select(
        'userId', 'firstName',
        'lastName', 'gender', 'level').where(col("userId").isNotNull()).withColumnRenamed(
        "userId", "user_id"
    ).withColumnRenamed(
        "firstName", "first_name"
    ).withColumnRenamed(
        "lastName", "last_name"
    ).distinct()

    # write users table to parquet files
    users_table.write.parquet(
        os.path.join(output_data, 'users.parquet'), 'overwrite')

    # create timestamp column from original timestamp column
    get_timestamp = udf(lambda x: int(x)/1000)
    df = df.withColumn('start_time', get_timestamp('ts'))

    # create datetime column from original timestamp column
    get_datetime = udf(lambda x: datetime.fromtimestamp(int(x)/1000))
    df = df.withColumn('datetime', get_datetime('ts'))

    # extract columns to create time table
    # time - timestamps of records in songplays broken down into specific units
    # start_time, hour, day, week, month, year, weekday
    time_table = df.select('start_time', 'datetime').withColumn(
        'hour', hour('datetime')
    ).withColumn(
        'day', dayofmonth('datetime')
    ).withColumn(
        'week', weekofyear('datetime')
    ).withColumn(
        'month', month('datetime')
    ).withColumn(
        'year', year('datetime')
    ).withColumn(
        'weekday', dayofweek('datetime')
    ).distinct()

    # write time table to parquet files partitioned by year and month
    time_table.write.partitionBy('year', 'month').parquet(
        os.path.join(output_data, 'time.parquet'), 'overwrite')

    # read in song data to use for songplays table
    song_df = spark.read.json(song_data).alias('song_df')

    # extract columns from joined song and log datasets to create songplays table
    # songplays - records in log data associated with song plays i.e. records with page NextSong
    # songplay_id, start_time, user_id, level, song_id, artist_id,
    # session_id, location, user_agent
    songplays_table = df.join(song_df, col("artist")
                          == col("song_df.artist_name"), 'inner').select(
        col('start_time'),
        col('userId').alias('user_id'),
        col('level'),
        col('song_df.song_id').alias('song_id'),
        col('song_df.artist_id').alias('artist_id'),
        col('sessionId').alias('session_id'),
        col('location'),
        col('userAgent').alias('user_agent'),
        year('datetime').alias('year'),
        month('datetime').alias('month')
    ).withColumn('songplay_id', monotonically_increasing_id())

    # write songplays table to parquet files partitioned by year and month
    songplays_table.write.partitionBy('year', 'month').parquet(
        os.path.join(output_data, 'songplays.parquet'), 'overwrite')

def main():
    spark = create_spark_session()
    input_data = "s3a://udacity-dend/"
    output_data = config['AWS']['AWS_S3_OUTPUT_BUCKET']

    process_song_data(spark, input_data, output_data)
    process_log_data(spark, input_data, output_data)

if __name__ == "__main__":
    main()


import numpy as np
import cv2
from scipy.interpolate import LinearNDInterpolator

from Camera import *

def compute_fill_factor(imgs):
    '''
    Given K frames, compute time-averaged fill factor fitness.
    Input: imgs: KxWxH array : either RoI or entire Image
    Returns: fill_factor_cost
    '''
    # For one frame
    num_filled = np.asarray([np.count_nonzero(img) for img in imgs])
    fill_factor = np.asarray([(nf/(imgs.shape[1]*imgs.shape[2])) for nf in num_filled])
    fill_factor_cost = np.mean(np.asarray([-np.log(f) for f in fill_factor]))
    return fill_factor_cost

def compute_mean(imgs):
    return mean

def compute_variance(imgs):

    return variance

def compute_energy(imgs):
    '''
    Custom energy function
    '''
    return energy

def compute_fitness(depth, roi = None):
    '''
    Function to compute map fitness across 'k' contiguous frames
    Input:
    depth - (KxMxN) array of K contiguous frames
    roi - Region of interest specified by array indices ()

    '''
    # The fitness function needs to be able to provide a quality metric
    if roi == None:
        roi_depth = depth
    else:
        roi_depth = depth[roi]
    # fitness component 1: Number of holes - Make this differentiable??
    fitness_fill_factor = compute_fill_factor(roi_depth)
    # fitness component 2: Depth map variance
    fitness_map_variance = compute_variance(roi_depth)
    # fitness componene 3: given the variance and fill factor, is there a way to
    # model the image quality in relation to metrology?
    fitness_metrology = compute_energy(roi_depth)

    return fitness

camera = Camera()
camera.start_camera()
camera.load_preset('HighAccuracyPreset.json')
# Get depth data for 'k' frames
k = 1
try:
    while True:
        depth_frameset = []
        count = 0
        while count < k:
            frames = camera.wait_for_frames()
            depth = np.asarray(frames.get_depth_frame().get_data())
            depth_frameset.append(depth)
            count = count + 1
        depth_frameset = np.asarray(depth_frameset)
        fill_factor_cost = compute_fill_factor(depth_frameset)
        params_min, params_max = camera.query_sensor_param_bounds()

finally:
    camera.stop()


#!/usr/bin/python3
# CLIent: Barebones user client for Amoskeag
#
# Commands:
# look: Lists everything you can look at (stuff in stage, and your inventory)
# look <at>: Looks at <at>
# move: Lists where you can move to
# move <dir>: Moves to that location
# talk: List every possible talk command
# talk <cmd>: Talks to that person, or says that response if already talking
# get: List everything you can get
# get <obj>: Gets that object
# status: Lists your current inventory
# Blank command: Displays room info again
# exit: Quits

import requests
import json
import time

server = 'http://localhost:9999'

def get_token():
  global server
  r = requests.get(server + '/users/token').json()
  if ('success' in r):
    return r['token']
  else:
    raise IOError

class Game():
  def __init__(self, token):
    self.token = token
    self.inventory = []

  def _get(self, url):
    r = requests.get(server + url, headers = {
      'Authorization': 'Bearer ' + self.token
    }).json()
    if ('success' in r):
      if (r["success"] == True):
        return r["output"]
      else:
        raise IOError(r["message"])
    else:
      raise IOError()

  def _post(self, url, data):
    r = requests.post(server + url, headers = {
      'Authorization': 'Bearer ' + self.token
    }, json=data).json()
    if ('success' in r):
      if ('output' in r):
        return r['output']
      if ('message' in r):
        raise IOError(r["message"])
    raise IOError(str(r))

  def __update(self, r):
    out = r["desc"]
    if ("exit" in r):
      self.exits = r["exit"]
      if (len(self.exits) != 0):
        out = out + "\n\nExits are " + ','.join([e["label"] for e in self.exits])

    if ("talk" in r):
      self.talks = r["talk"]
      if (len(self.talks) != 0):
        say = []
        opt = 'abcdefghijklmnopqr'
        for idx, e in enumerate(r["talk"]):
          e["say"] = e["label"]
          e["label"] = opt[idx]

    if ("look" in r):
      self.looks = r["look"]
      self.looks.extend(
        ({"label" : e["label"],
          "id" : e["look"]} for e in self.inventory)
      )

    if ("get" in r):
      self.gets = r["get"]

    if ("endgame" in r):
      self.talks = []
      self.exits = []
      self.looks = []
      self.gets = []
      return r["desc"] + "\n\n **** GAME OVER ****"

    if ("title" in r):
      out = r["title"] + "\n\n" + out
    return out

  def __say(self, data):
    labels = [e["label"] for e in data]
    return ', '.join(labels)

  def __gopost(self, data, dest, label):
    try:
      target = next(i["id"] for i in data if i["label"] == dest)
    except StopIteration:
      return "Can't find " + dest
    r = self._post('/game/'+label, {"id": target})
    if (label is "move"):
      r = self._get('/game/look')
    return self.__update(r)

  def look(self):
    r = self._get('/game/look')
    return self.__update(r)

  def talk(self):
    out = ""
    if (len(self.talks) != 0):
      say = []
      opt = 'abcdefghijklmnopqr'
      for idx, e in enumerate(self.talks):
        say.append(opt[idx] + ") " + e["say"])
      out = '\n'.join(say)
    return out

  def lookat(self):
    return self.__say(self.looks)

  def get(self):
    return self.__say(self.gets)

  def move(self):
    return self.__say(self.exits)

  def talk_to(self, to):
    out = self.__gopost(self.talks, to, "talk")
    if (len(self.talks) != 0):
      out = out + "\n\n" + self.talk()
    return out

  def lookat_to(self, to):
    out = self.__gopost(self.looks, to, "look")
    if (len(self.talks) != 0):
      out = out + "\n\n" + self.talk()
    return out

  def get_to(self, to):
    out = self.__gopost(self.gets, to, "get")
    self.look()
    return out

  def move_to(self, to):
    return self.__gopost(self.exits, to, "move")

  def use(self, id, on):
    try:
      item = next(i["id"] for i in self.looks if i["label"] == id)
      target = next(i["id"] for i in self.looks if i["label"] == on)
    except StopIteration:
      return "Can't do that"

    r = self._post('/game/use', {"id":item, "target":target})
    return self.__update(r)

  def consume(self, to):
    return self.__gopost(self.looks, to, "use")

  def status(self):
    r = self._get('/game/status')
    self.inventory = r["inventory"]
    return "Inventory: " + ", ".join([e["label"] for e in r["inventory"]])

  def save(self):
    return str(self._get('/game/save'))

  def saves(self):
    return str(self._get('/game/saves'))

  def load(self, guid):
    return str(self._post('/game/load', {"id": guid}))

cond = True
game = Game(get_token())
time.sleep(0.5)
print("Connected to Amoskeag server at " + server + " with token " + game.token)
print(game.look())
while(cond):
  text = input('$ ')
  try:
    if (text == "exit"):
      cond = False
      print("Thanks for playing!")
    elif (text == "talk"):
      print(game.talk())
    elif (text == "look"):
      print(game.lookat())
    elif (text == "move"):
      print(game.move())
    elif (text == "get"):
      print(game.get())
    elif (text == "save"):
      print(game.save())
    elif (text == "saves"):
      print(game.saves())
    elif (text.startswith("load ")):
      print(game.load(text[5:]))
    elif (text.startswith("look ")):
      print(game.lookat_to(text[5:]))
    elif (text.startswith("talk ")):
      print(game.talk_to(text[5:]))
    elif (text.startswith("move ")):
      print(game.move_to(text[5: ]))
    elif (text.startswith("get ")):
      print(game.get_to(text[4: ]))
      game.status()
    elif (text.startswith("status")):
      print(game.status())
    elif (text.startswith("use ")):
      cmd = text[4:].split(" on ")
      if (len(cmd) < 2):
        print(game.consume(cmd[0]))
      else:
        print(game.use(cmd[0], cmd[1]))
    elif (text == ""):
      print(game.look())
    else:
      print("I don't understand that command.")
  except IOError as e:
    print("Error: " + str(e))


from matplotlib import pyplot as plt
import statistics

f1 = open("MendotaFinalTxt").readlines()
f2 = open("MononaFinalTxt").readlines()
year1 = []
days1 = []

for i in f1:
  row = i.strip().split()
  year1.append(int(row[0]))
  days1.append(int(row[1]))

year1_train = []
days1_train = []
year1_test = []
days1_test = []
for i in range(len(year1)):
  if year1[i] <= 1970:
    year1_train.append(year1[i])
    days1_train.append(days1[i])
  else:
    year1_test.append(year1[i])
    days1_test.append(days1[i])

import math
m1 = statistics.mean(days1_train)
s1 = statistics.stdev(days1_train)
m1 = 0.0
s1 = 0.0
for day in days1_train:
  m1 += day
m1 = float(m1/len(days1_train)-1)
for day in days1_train:
  s1 += math.pow(day-m1,2)
s1 = float(math.sqrt(s1/(len(days1_train)-1)))
print(" Mean for Mendota training set = "+str(m1))
print(" Standard Deviation for Mendota training set = "+str(s1))

norm_days1 = []
for i in days1:
  nday = float((i - m1)/s1)
  norm_days1.append(nday)

year2 = []
days2 = []
for i in f2:
  row = i.strip().split()
  #year1.append(int(row[0]))
  #days1.append(int(row[1]))
  year2.append(int(row[0]))
  days2.append(int(row[1]))

year2_train = []
days2_train = []
year2_test = []
days2_test = []
for i in range(len(year2)):
  if year2[i] <= 1970:
    year2_train.append(year2[i])
    days2_train.append(days2[i])
  else:
    year2_test.append(year2[i])
    days2_test.append(days2[i])

m2 = statistics.mean(days2_train)
s2 = statistics.stdev(days2_train)
m2 = 0.0
s2 = 0.0
for day in days2_train:
  m2 += day
m2 = float(m2/len(days2_train)-1)
for day in days2_train:
  s2 += math.pow(day-m2,2)
s2 = float(math.sqrt(s2/(len(days2_train)-1)))
print("Sample Mean for Monona training set = "+str(m2))
print("Sample Standard Deviation for Monona training set = "+str(s2))

# print(year1_train == year2_train)
# print(year2_train)
term1 = []

import numpy as np
sm = np.array([0,0,0])
x_array = []
for i in range(len(year1_train)):
  x_array.append([1,year1_train[i],days2_train[i]])
x = np.array(x_array)
term1 = np.matmul(x.T,x)
#print(term1)
y_arr = np.array(days1_train)
term2 = np.matmul(x.T,y_arr)
print(term2)

res = np.matmul(np.linalg.inv(term1),term2)
print(res)

# beta = res.tolist()
# y_cap = []
# for i in range(len(days2_test)):
#   pred = beta[0]+beta[1]*year1_test[i]+beta[2]*days2_test[i]
#   y_cap.append(pred)

# mean_sum = 0.0
# for i in range(len(y_cap)):
#   mean_sum += math.pow((y_cap[i]-days1_test[i]),2)
# explained_variance = mean_sum
# mean_sum /= len(y_cap)
# avg_actual_value = 0.0
# for i in days1_test:
#   avg_actual_value += i
# avg_actual_value /= len(days1_test)

# sum_avg_actual_pred = 0.0
# for i in y_cap:
#   sum_avg_actual_pred += math.pow(i - avg_actual_value,2)
# r_squared = 1-(explained_variance/sum_avg_actual_pred)

# print(mean_sum)
# print(r_squared)