"""
File: test_ch3.py
Purpose: One or more tests for headers in
    Introducing Python chapter 3: PyFilling: Lists, Tuples, Dictionaries & Sets
"""

import unittest
import ch3_pyfilling  # imports all functions in module ch3_pyfilling
from ch3_tiy import names_3_1  # from module ch3_tiy import function names_3_1
from ch3_tiy import greetings_3_2
from ch3_tiy import fav_transportation_3_3
from ch3_tiy import dinner_guest_3_4
from ch3_tiy import dinner_guest_3_5
from ch3_tiy import dinner_guest_3_6
from ch3_tiy import dinner_guest_3_7
from ch3_tiy import seeing_world_3_8
from ch3_tiy import dinner_guest_3_9
from ch3_tiy import show_items_in_list_3_10
from ch3_tiy import change_list_3_10
from ch3_tiy import insert_in_list_3_10
from ch3_tiy import del_from_list_3_10
from ch3_tiy import remove_by_value_3_10
from ch3_tiy import remove_by_label_3_10
from ch3_tiy import remove_by_pop_3_10
from ch3_tiy import len_3_10
from ch3_tiy import sort_list_unchanged_3_10
from ch3_tiy import sort_list_changed_3_10
from ch3_tiy import append_3_10
from ch3_tiy import reverse_3_10
from ch3_tiy import sort_list_reverse_3_10

class TestCh3TIY(unittest.TestCase):
    """ Class TestCh3TIT (Test It Yourself) """

    def setUp(self):
        pass

    def tearDown(self):
        pass

    # Lists
    def test_names_3_1(self):
        """ See title """
        print("\nDinner_guest_3_1 =======================================")
        transport_list = ["Moe", "Larry", "Curley", "Stan"]
        tn_result = names_3_1(0)
        self.assertEqual(tn_result, transport_list[0])
        tn_result = names_3_1(1)
        self.assertEqual(tn_result, transport_list[1])
        tn_result = names_3_1(2)
        self.assertEqual(tn_result, transport_list[2])
        # Next two lines show error
        # tn_result = names_3_1(3)
        # self.assertEqual(tn_result, transport_list[3])

    def test_greetings_3_2(self):
        """ See title """
        print("\nDinner_guest_3_2 =======================================")
        transport_list = ["Moe", "Larry", "Curley", "Stan"]
        m_print_1 = "Greetings, "
        m_print_2 = " Uncle Sam would like you to travel the world."
        tg_result = m_print_1 + transport_list[0] + m_print_2
        self.assertEqual(tg_result,
                         greetings_3_2(0))
        tg_result = m_print_1 + transport_list[1] + m_print_2
        self.assertEqual(tg_result,
                         greetings_3_2(1))
        tg_result = m_print_1 + transport_list[2] + m_print_2
        self.assertEqual(tg_result,
                         greetings_3_2(2))

    def test_fav_transportation_3_3(self):
        """ See title """
        print("\nDinner_guest_3_3 =======================================")
        transport_list = ["Car", "foot", "Segway"]
        m_print_1 = "I like to get places using "
        m_print_2 = " to travel the world."
        tf_result = m_print_1 + transport_list[0] + m_print_2
        self.assertEqual(tf_result,
                         fav_transportation_3_3(0))
        tf_result = m_print_1 + transport_list[1] + m_print_2
        self.assertEqual(tf_result,
                         fav_transportation_3_3(1))
        tf_result = m_print_1 + transport_list[2] + m_print_2
        self.assertEqual(tf_result,
                         fav_transportation_3_3(2))

    def test_dinner_guest_3_4(self):
        """ See title """
        print("\nDinner_guest_3_4 =======================================")
        guest_list = ["Larry da Vinci", "Ben Franklin", "Genghis Khan"]
        m_print_1 = "Dear "
        m_print_2 = " could you attend a BBQ at my house on 4 July 2019."
        td_result = m_print_1 + guest_list[0] + m_print_2
        self.assertEqual(td_result,
                         dinner_guest_3_4(0))
        td_result = m_print_1 + guest_list[1] + m_print_2
        self.assertEqual(td_result,
                         dinner_guest_3_4(1))
        td_result = m_print_1 + guest_list[2] + m_print_2
        self.assertEqual(td_result,
                         dinner_guest_3_4(2))

    def test_dinner_guest_3_5(self):
        """ See title """
        print("\nDinner_guest_3_5 =======================================")
        guest_list = \
            ["Larry da Vinci", "Ben Franklin", "Genghis Khan", "Hellen Keller"]
        m_print_t = "Who can attend:"
        m_print_f = "Who can not attend:"
        #
        ret_result = dinner_guest_3_5(2, "F")
        tret_result = guest_list[2]
        tret_result = m_print_f + tret_result
        self.assertEqual(ret_result, tret_result)
        #
        ret_result = dinner_guest_3_5(2, "T")
        tret_result = guest_list[3]
        tret_result = m_print_t + tret_result
        self.assertEqual(ret_result, tret_result)
        #
        ret_result = dinner_guest_3_5(0, "T")
        tret_result = guest_list[0]
        tret_result = m_print_t + tret_result
        self.assertEqual(ret_result, tret_result)
        #
        ret_result = dinner_guest_3_5(1, "T")
        tret_result = guest_list[1]
        tret_result = m_print_t + tret_result
        self.assertEqual(ret_result, tret_result)
        #
        ret_result = dinner_guest_3_5(2, "T")
        tret_result = guest_list[3]
        tret_result = m_print_t + tret_result
        self.assertEqual(ret_result, tret_result)

    def test_dinner_guest_3_6(self):
        """ See title """
        print("\nDinner_guest_3_6 =======================================")
        guest_list = \
            ["Larry da Vinci", "Ben Franklin", "Hellen Keller"]
        guest_list.insert(0, "Al Einstein")
        guest_list.insert(2, "Prof Uncle Eric")
        guest_list.append("Dear Old Dad")

        m_print_0 = "A bigger table was found!  Here are all the guests:"
        #
        td_result = m_print_0 + "\n" + str(guest_list)
        self.assertEqual(td_result, dinner_guest_3_6())

    def test_dinner_guest_3_7(self):
        """ See title """
        print("\nDinner_guest_3_7 =======================================")
        guest_list = \
            ["Larry da Vinci", "Ben Franklin", "Hellen Keller"]
        guest_list.insert(0, "Al Einstein")
        guest_list.insert(2, "Prof Uncle Eric")
        guest_list.append(" Dear Old Dad")

        m_print_0 = "Sorry only 2 guests."
        guest_list.pop(0)
        guest_list.pop(0)
        guest_list.pop(0)
        guest_list.pop(0)
        #
        m_print_0 = "Remaining guests are:"
        td_result = m_print_0 + "\n" + str(guest_list)
        guest_list.pop(0)
        guest_list.pop(0)
        #
        td_result = str(guest_list)
        self.assertEqual(td_result, dinner_guest_3_7())

    def test_seeing_world_3_8(self):
        """ See title """
        print("\nSeeing the world 3_8 =======================================")
        world_list = \
            ["Frankfort", "Richmond", "Joisey", "Normandy", "Auschwitz"]

        # Change order of list via sorted and show original list unchanged
        # List in original order
        list_to_verify = world_list[:]  # Copy w_l to l_t_v

        # Next executable line alphabetizes w_l and assigns to n_l
        #    w_l unchanged
        new_list = sorted(world_list)
        list_to_verify.append(new_list)  # adds new object, n_l to end of l_t_v
        # list_to_verify.attach(new_list) #  adds 5 items viz n_l to l_t_v

        # Reverse order of list via sorted and show original list unchanged
        new_list = sorted(world_list, reverse=True)
        list_to_verify.append(new_list)
        #
        # Change order of list via reverse() and show original list changed
        new_list = world_list[:]
        new_list.reverse()  # Reverses new_list
        list_to_verify.append(new_list)
        #
        # Change order of list via reverse() and show back to original list
        new_list.reverse()  # Re-reverses n_l restoring original
        list_to_verify.append(new_list)
        #
        # Change list to alphabetical order via sort
        new_list = world_list[:]  # Copy w_l to n_l
        new_list.sort()
        list_to_verify.append(new_list)
        #
        # Change list to reverse alphabetical order via sort
        new_list.sort(reverse=True)
        list_to_verify.append(new_list)
        self.assertEqual(list_to_verify, seeing_world_3_8())

    def test_dinner_guest_3_9(self):
        """ See title """
        print("\ndinner_guests_3_9 =======================================")
        guest_list = ["Larry da Vinci", "Ben Franklin", "Hellen Keller"]
        self.assertEqual(len(guest_list), dinner_guest_3_9())

    def test_show_items_in_list_3_10(self):
        """ 14 commands tested for 3-10 Every Function.  Form of all tests:
        - Make BEFORE list
        - Send to dinner_guest_3_10()
        - ASSERT that returned value is ER
        - Naming convention is DESCRIPTION_3_10
        - DESCRIPTIONS:
          show_items_in_list      change_list           insert   del
          remove_by_value         remove_by_label       pop      len
          sort_list_unchanged     sorted_list_changed   append   reverse
          reversed_list_changed
        """
        print("\ntest_show_items_in_list_3_10")
        my_list = ["Teach Python", "Build boxes", "Create workshop"]
    # Show items in list (first, last and in-between)
        results_all_list = my_list[0]
        results_all_list = results_all_list + my_list[2]
        results_all_list = results_all_list + my_list[1]
        returned_list = show_items_in_list_3_10(0)
        returned_list = returned_list + show_items_in_list_3_10(2)
        returned_list = returned_list + show_items_in_list_3_10(1)

        self.assertEqual(results_all_list, returned_list)

    def test_change_list_3_10(self):
        """ See title   """
        print("\ntest_change_list_3_10")
        my_list = ["Teach Python", "Build boxes", "Create workshop"]
        # Change items in list (first, last and in-between)
        result_list = my_list[:]
        result_list[0] = "Learn Python"
        result_list[1] = "Build jigs"
        result_list[2] = "Modular workspaces"
        returned_list = my_list[:]
        returned_list = change_list_3_10(returned_list, 0, "Learn Python")
        returned_list = change_list_3_10(returned_list, 1, "Build jigs")
        returned_list = change_list_3_10(returned_list, 2,
                                         "Modular workspaces")

        self.assertEqual(result_list, returned_list)

    def test_insert_in_list_3_10(self):
        """ See title   """
        # Add item to specified place in list
        my_list = ["Teach Python", "Build boxes", "Create workshop"]
        returned_list = my_list[:]
        my_list.insert(1, "very well")
        returned_list = insert_in_list_3_10(returned_list, 1, "very well")

        self.assertEqual(my_list, returned_list)

    def test_del_from_list_3_10(self):
        """ See title   """
        # del from specified place in list
        my_list = ["Teach Python", "Build boxes", "Create workshop"]
        returned_list = my_list[:]
        del my_list[1]
        returned_list = del_from_list_3_10(returned_list, 1)

        self.assertEqual(my_list, returned_list)

    def test_remove_by_value_3_10(self):
        """ See title   """
        my_list = ["Teach Python", "Build boxes", "Create workshop"]
        returned_list = my_list[:]
        my_list.remove("Build boxes")
        returned_list = remove_by_value_3_10(returned_list, "Build boxes")

        self.assertEqual(my_list, returned_list)

    def test_remove_by_label_3_10(self):
        """ See title   """
        my_list = ["Teach Python", "Build boxes", "Create workshop"]
        returned_list = my_list[:]
        already_done = "Build boxes"
        my_list.remove(already_done)
        returned_list = remove_by_label_3_10(returned_list, already_done)

        self.assertEqual(my_list, returned_list)

    def test_remove_by_pop_3_10(self):
        """ See title   """
        my_list = ["Teach Python", "Build boxes", "Create workshop"]
        returned_list = my_list[:]
        my_list.pop(1)
        returned_list = remove_by_pop_3_10(returned_list, 1)

        self.assertEqual(my_list, returned_list)

    def test_len_3_10(self):
        """ See title   """
        my_list = ["Teach Python", "Build boxes", "Create workshop"]
        returned_list = my_list[:]
        my_len = len(my_list)
        list_len = len_3_10(returned_list)

        self.assertEqual(my_len, list_len)

    def test_sort_list_unchanged_3_10(self):
        """ See title   """
        my_list = ["Teach Python", "Build boxes", "Create workshop"]
        returned_list = sort_list_unchanged_3_10(my_list)

        self.assertEqual(my_list, returned_list)

    def test_sort_list_changed_3_10(self):
        """ See title   """
        my_list = ["Teach Python", "Build boxes", "Create workshop"]
        my_list.sort()
        returned_list = sort_list_changed_3_10(my_list)
        my_list.sort()

        self.assertEqual(my_list, returned_list)

    def test_append_3_10(self):
        """ See title   """
        my_list = ["Teach Python", "Build boxes", "Create workshop"]
        sent_list = my_list[:]
        returned_list = append_3_10(sent_list, "FTJ")
        my_list.append("FTJ")

        self.assertEqual(my_list, returned_list)

    def test_reverse_3_10(self):
        """ See title   """
        # reversed_list_changed
        my_list = ["Teach Python", "Build boxes", "Create workshop"]
        sent_list = my_list[:]
        returned_list = reverse_3_10(sent_list)
        my_list.reverse()

        self.assertEqual(my_list, returned_list)

    def test_sort_list_reverse_3_10(self):
        """ See title   """
        my_list = ["Teach Python", "Build boxes", "Create workshop"]
        sent_list = my_list[:]
        returned_list = sort_list_reverse_3_10(sent_list)
        my_list.sort(reverse=True)
        self.assertEqual(my_list, returned_list)

class TestCh3(unittest.TestCase):
    """" dclass TestCh3 """

    def setUp(self):
        pass

    def tearDown(self):
        pass

    # Lists
    def test_empty_list_creation(self):
        """ See title """
        el_result = ch3_pyfilling.empty_list_creation()
        self.assertEqual(el_result, [])

    def test_empty_list_creation_2(self):
        """ See title """
        el_result = ch3_pyfilling.empty_list_creation_2()
        self.assertEqual(el_result, [])

    # Convert Other Data Types to List with list()
    def test_create_list_other_types(self):
        """ See title """
        el_result = ch3_pyfilling.create_list_other_types('cat')
        self.assertEqual(el_result, ['c', 'a', 't'])

    # Get an Item by Using [offset]
    def test_get_list_item_via_offset(self):
        """ See title """
        el_result = ch3_pyfilling.get_list_item_via_offset(0)
        self.assertEqual(el_result, 'Groucho')
        el_result = ch3_pyfilling.get_list_item_via_offset(-3)
        self.assertEqual(el_result, 'Groucho')
        el_result = ch3_pyfilling.get_list_item_via_offset(1)
        self.assertEqual(el_result, 'Chico')
        el_result = ch3_pyfilling.get_list_item_via_offset(-2)
        self.assertEqual(el_result, 'Chico')
        el_result = ch3_pyfilling.get_list_item_via_offset(2)
        self.assertEqual(el_result, 'Harpo')
        el_result = ch3_pyfilling.get_list_item_via_offset(-1)
        self.assertEqual(el_result, 'Harpo')

    # Lists of Lists
    def test_get_list(self):
        """ See title """
        item_1 = ['a']
        gl_result = ch3_pyfilling.get_list(0)
        self.assertEqual(gl_result, item_1)

    def test_get_list_inside_list(self):
        """ See title """
        gi_result = ch3_pyfilling.get_list_inside_list(1, 0)
        self.assertEqual(gi_result, 'b')
        gi_result = ch3_pyfilling.get_list_inside_list(1, 1)
        self.assertEqual(gi_result, 'c')

    # Change an Item by [offset]
    def test_change_list(self):
        """ See title """
        cl_result = ch3_pyfilling.change_list('b')
        self.assertEqual(cl_result, 'b')

    # Get a Slice to Extract Items by Offset Range
    def test_get_list_slice(self):
        """ See title """
        marxes = ['Groucho', 'Chico', 'Harpo']
        my_list = ch3_pyfilling.get_list_slice(0, 2)
        self.assertEqual(my_list, ['Groucho', 'Chico'])
        self.assertEqual(marxes[1:3], ['Chico', 'Harpo'])
        self.assertEqual(marxes[0:-2], ['Groucho'])
        # why marxes[2:0] returns [] != 'Harpo' is a mystery TBD
        self.assertEqual(marxes[2:], ['Harpo'])

    # Add item to end with append()
    def test_append_list(self):
        """ See title """
        marxes_local = ['Groucho', 'Chico', 'Harpo']
        # Holy horseradish Batman!  Updating marxes_local updates marxes
        # marxes = marxes_local
        marxes = list(marxes_local)  # this does copy to new instance
        to_be_added = ['Zeppo']
        marxes_local.append(to_be_added)
        ch3_pyfilling.append_list(marxes, to_be_added)
        self.assertEqual(marxes, marxes_local)

    def test_combine_lists(self):
        """ See title """
        marxes_local = ['Groucho', 'Chico', 'Harpo', 'Zeppo']
        marxes = list(marxes_local)  # this does a copy to new instance
        to_be_added = ["Gummo"]
        marxes_local += to_be_added
        ch3_pyfilling.combine_list(marxes, to_be_added)
        self.assertEqual(marxes, marxes_local)

    def test_insert_list(self):
        """ See title """
        marxes_local = ['Groucho', 'Chico', 'Harpo', 'Zeppo']
        marxes = list(marxes_local)  # this does a copy to new instance
        where_be_added = 1
        marxes_local.insert(where_be_added, 'Karl')
        ch3_pyfilling.insert_list(marxes, where_be_added, 'Karl')
        self.assertEqual(marxes, marxes_local)

    def test_delete_item_from_list(self):
        """ See title """
        marxes_local = ['Groucho', 'Karl', 'Chico', 'Harpo', 'Zeppo']
        marxes = list(marxes_local)  # this does a copy to new instance
        del marxes_local[1]
        ch3_pyfilling.delete_item_from_list(marxes, 1)
        self.assertEqual(marxes, marxes_local)

    def test_delete_list_item_by_value(self):
        """ See title """
        marxes_local = ['Groucho', 'Karl', 'Chico', 'Harpo', 'Zeppo']
        marxes = list(marxes_local)  # this does a copy to new instance
        marxes_local.remove('Karl')
        ch3_pyfilling.delete_list_item_by_value(marxes, 'Karl')
        self.assertEqual(marxes, marxes_local)

    def test_pop_item(self):
        """ See title """
        marxes = ['Groucho', 'Karl', 'Chico', 'Harpo', 'Zeppo']
        marxes_local = ['Groucho', 'Chico', 'Harpo', 'Zeppo']
        index_to_pop = 1
        ch3_pyfilling.pop_item(marxes, index_to_pop)
        self.assertEqual(marxes, marxes_local)

    def test_find_list_offset(self):
        """ See title """
        marxes = ['Groucho', 'Chico', 'Harpo', 'Zeppo']
        fl_result = ch3_pyfilling.find_list_offset(marxes, 'Harpo')
        self.assertEqual(fl_result, 2)

    def test_in_list(self):
        """ See title """
        marxes = ['Groucho', 'Chico', 'Harpo', 'Zeppo']
        in_result = ch3_pyfilling.in_list(marxes, 'Harpo')
        self.assertEqual(in_result, True)
        in_result = ch3_pyfilling.in_list(marxes, 'ZHarpo')
        self.assertEqual(in_result, False)
        in_result = ch3_pyfilling.in_list(marxes, 'Harp')
        self.assertEqual(in_result, False)

    def test_count_items_in_list(self):
        """ See title """
        marxes = ['Groucho', 'Chico', 'Harpo']
        ci_result = ch3_pyfilling.count_items_in_list(marxes, 'Harpo')
        self.assertEqual(ci_result, 1)
        ci_result = ch3_pyfilling.count_items_in_list(marxes, 'Bob')
        self.assertEqual(ci_result, 0)

    def test_join_and_split_1ist(self):
        """ See title """
        marxes = ['Groucho', 'Chico', 'Harpo']
        separator = ' * '
        ci_result = ch3_pyfilling.join_and_split_1ist(marxes, separator)
        local_join = separator.join(marxes)
        self.assertEqual(ci_result, local_join)

    def test_join_and_split_list_2(self):
        """ See title """
        marxes = ['Groucho', 'Chico', 'Harpo']
        separator = " * "
        local_join = separator.join(marxes)
        js_result = ch3_pyfilling.join_and_split_list_2(local_join, separator)
        self.assertEqual(js_result, marxes)

    def test_sorted_list(self):
        """ See title """
        marxes = ['Groucho', 'Chico', 'Harpo']
        sorted_marxes = ['Chico', 'Groucho', 'Harpo']
        sl_result = ch3_pyfilling.sorted_list(marxes)
        self.assertEqual(sl_result, sorted_marxes)

    def test_sort_list(self):
        """ See title """
        marxes = ['Groucho', 'Chico', 'Harpo']
        so_result = ch3_pyfilling.sort_list(marxes)
        marxes.sort()
        self.assertEqual(so_result, marxes)

    def test_len_list(self):
        """ See title """
        marxes = ['Groucho', 'Chico', 'Harpo']
        ll_result = ch3_pyfilling.len_list(marxes)
        self.assertEqual(ll_result, 3)

    def test_copy_list_slice(self):
        """ See title """
        my_list = [1, 2, 3]
        cl_result = ch3_pyfilling.copy_list_slice(my_list)
        self.assertEqual(cl_result, ['firstSurprise', 2, 3])
        # Next two lines are correct according to Introducing Python, pg 53
        #   but they fail when run
        #        cl_result = ch3_pyfilling.copy_list_slice_copy(my_list)
        #        self.assertEqual(cl_result, [1, 2, 3])  # new_list unchanged
        cl_result = ch3_pyfilling.copy_list_slice_list(my_list)
        self.assertEqual(cl_result, ['surprise', 2, 3])
        cl_result = ch3_pyfilling.copy_list_slice_slice(my_list)
        self.assertEqual(cl_result, ['differentSurprise', 2, 3])

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


#Libraries Used.......................
import pyodbc
'''
Using Pyodbc we make connection to the MS-SSMS to get access to the database in our server.
'''
def make_connection():
    conn = pyodbc.connect('Driver={SQL Server};'
                                      'Server=ASINMDLB6P5T72;'
                                      'Database=coats_wba_p4i_hk;'
                                      'Trusted_Connection=yes;')
    return(conn)
if __name__=="__main__":
    print("DELPHI CONNECTION SCRIPT")


import heapq
from collections import defaultdict
import matplotlib.pyplot as plt
from tqdm import tqdm

maxlen = 2 * 10**6

class Contraction_Hierarchies:
    def __init__(self, n, adj, cost):
        # See description of these parameters in the starter for friend_suggestion
        self.n = n
        self.INFINITY = n * maxlen
        self.adj = adj
        self.cost = cost
        self.bidistance = [[self.INFINITY] * n, [self.INFINITY] * n]
        self.visited = [[False]*n,[False]*n]    # visited[v] == True iff v was visited by forward or backward search
        self.workset = set()           # All the nodes visited by forward or backward search
        self.q = []
        # Levels of nodes for node ordering heuristics
        self.level = [0] * n
        # Positions of nodes in the node ordering
        self.rank = [-1] * n
        # Number of contracted Neighbors
        self.contracted_neighbors = [0] * n

        # Implement preprocessing here

    def pretrained(self,rank,cost,adj):
        self.rank = rank
        self.cost = cost
        self.adj = adj

    def process_graph(self):
        self.preImportance()
        self.preprocess()

    def preImportance(self):
        for v in range(self.n):
            importance,_ = self.shortcut(v)
            heapq.heappush(self.q, (importance, v))

    def preprocess(self):
        rank1 = 0
        with tqdm(total=self.n) as pbar:
            while self.q:
                _, first  = heapq.heappop(self.q)
                if self.q:
                    importance2, second = heapq.heappop(self.q)
                    importance1,shortcuts = self.shortcut(first)
                    if importance1 <= importance2:
                        for shortcut in shortcuts:
                            self.add_arc(shortcut[0], shortcut[1], shortcut[2])
                        for i,u in enumerate(self.adj[0][first]):
                            self.level[u] = max(self.level[u], self.level[first] + 1)
                            self.contracted_neighbors[u] += 1
                        for i,u in enumerate(self.adj[1][first]):
                            self.level[u] = max(self.level[u], self.level[first] + 1)
                            self.contracted_neighbors[u] += 1
                        self.rank[first] = rank1
                        rank1 += 1
                        pbar.update(1)
                    else:
                        heapq.heappush(self.q, (importance1, first))
                    heapq.heappush(self.q, (importance2, second))
                elif self.rank[first] == -1:
                    _,shortcuts = self.shortcut(first)
                    for shortcut in shortcuts:
                        self.add_arc(shortcut[0], shortcut[1], shortcut[2])
                        for i,u in enumerate(self.adj[0][first]):
                            self.level[u] = max(self.level[u], self.level[first] + 1)
                            self.contracted_neighbors[u] += 1
                        for i,u in enumerate(self.adj[1][first]):
                            self.level[u] = max(self.level[u], self.level[first] + 1)
                            self.contracted_neighbors[u] += 1
                    self.rank[first] = rank1
                    rank1 += 1
                    pbar.update(1)

    def add_arc(self, u, v, c):
        def update(adj, cost, u, v, c):
            for i in range(len(adj[u])):
                if adj[u][i] == v:
                    cost[u][i] = min(cost[u][i], c)
                    return
            adj[u].append(v)
            cost[u].append(c)

        update(self.adj[0], self.cost[0], u, v, c)
        update(self.adj[1], self.cost[1], v, u, c)

    # Makes shortcuts for contracting node v
    def shortcut(self, v):
        # Compute the node importance in the end
        shortcut_cover_set = set()
        shortcuts = []
        # Compute correctly the values for the above heuristics before computing the node importance
        maxOutgoing = max(self.cost[0][v]) if len(self.adj[0][v]) else 0
        #maxIncoming = max(self.cost[1][v]) if len(self.adj[1][v]) else 0
        for i,source in enumerate(self.adj[1][v]):
            if self.rank[source] != -1:
                continue
            Incoming = self.cost[1][v][i]
            dist = self.dijkstra(v, source, Incoming + maxOutgoing)
            for j,target in enumerate(self.adj[0][v]):
                if self.rank[target] != -1:
                    continue
                if self.cost[1][v][i] + self.cost[0][v][j] <= dist[target]:
                    shortcuts.append((source, target, self.cost[1][v][i] + self.cost[0][v][j]))
                    shortcut_cover_set.add(source)
                    shortcut_cover_set.add(target)

        edge_difference = len(shortcuts) - len(self.adj[0][v]) - len(self.adj[1][v])
        neighbors = self.contracted_neighbors[v]
        shortcut_cover = len(shortcut_cover_set)
        level = self.level[v]

        a,b,c,d = 3,1,1,4
        importance = a*edge_difference + b*neighbors + c*shortcut_cover + d*level
        return importance, shortcuts

    def dijkstra(self, v, s, max_dist):
        dist = defaultdict(lambda: self.INFINITY)
        queue = []
        jumps = 1000
        dist[s] = 0
        heapq.heappush(queue, (0, s,jumps))
        while queue:
            d, u,j = heapq.heappop(queue)
            if j ==0:
                continue
            if d>max_dist :
                break
            for i,w in enumerate(self.adj[0][u]):
                if w != v and dist[w] > d + self.cost[0][u][i]:
                    dist[w] = d + self.cost[0][u][i]
                    heapq.heappush(queue, (dist[w], w,j-1))
        return dist

    # See description of this method in the starter for friend_suggestion
    def clear(self):
        for v in self.workset:
            self.bidistance[0][v] = self.bidistance[1][v] = self.INFINITY
            self.visited[0][v]    = self.visited[1][v]    = False
        self.workset = set()

    # See description of this method in the starter for friend_suggestion
    def visit(self,queues, side, v, dist):
        # Implement this method yourself
        self.bidistance[side][v] = dist
        for u,w in zip(self.adj[side][v], self.cost[side][v]):
            if not self.visited[side][u] and self.rank[v] < self.rank[u]:
                heapq.heappush(queues[side], (dist + w, u))

    # Returns the distance from s to t in the graph
    def query(self, s, t):
        if s == t:
            return 0
        self.clear()
        queues = [[],[]]
        estimate = self.INFINITY

        self.workset.add(s)
        self.workset.add(t)
        heapq.heappush(queues[0], (0, s))
        heapq.heappush(queues[1], (0, t))

        while queues[0] or queues[1]:
            if queues[0]:
                dist,u = heapq.heappop(queues[0])
                if not self.visited[0][u]:
                    self.visit(queues, 0, u, dist)
                    self.visited[0][u] = True
                    self.workset.add(u)
                if self.visited[1][u]:
                    estimate = min(estimate, self.bidistance[0][u] + self.bidistance[1][u])
            if queues[1]:
                dist,u = heapq.heappop(queues[1])
                if not self.visited[1][u]:
                    self.visit(queues, 1, u, dist)
                    self.visited[1][u] = True
                    self.workset.add(u)
                if self.visited[0][u]:
                    estimate = min(estimate, self.bidistance[0][u] + self.bidistance[1][u])

        return -1 if estimate >= self.INFINITY else estimate

    def query1(self, s, t, x, y):
        if s == t:
            return 0
        self.clear()
        queues = [[],[]]
        estimate = self.INFINITY

        self.workset.add(s)
        self.workset.add(t)
        heapq.heappush(queues[0], (0, s))
        heapq.heappush(queues[1], (0, t))
        travelledx = []
        travelledy = []
        while queues[0] or queues[1]:
            if queues[0]:
                dist,u = heapq.heappop(queues[0])
                if not self.visited[0][u]:
                    self.visit(queues, 0, u, dist)
                    self.visited[0][u] = True
                    self.workset.add(u)
                    travelledx.append(x[u])
                    travelledy.append(y[u])
                if self.visited[1][u]:
                    estimate = min(estimate, self.bidistance[0][u] + self.bidistance[1][u])
            if queues[1]:
                dist,u = heapq.heappop(queues[1])
                if not self.visited[1][u]:
                    self.visit(queues, 1, u, dist)
                    self.visited[1][u] = True
                    self.workset.add(u)
                    travelledx.append(x[u])
                    travelledy.append(y[u])
                if self.visited[0][u]:
                    estimate = min(estimate, self.bidistance[0][u] + self.bidistance[1][u])
        plt.scatter(x,y,s = 0.1)
        plt.scatter(travelledx,travelledy,s=0.1,c='r')
        plt.scatter(x[s],y[s],c = 'black')
        plt.scatter(x[t],y[t],c = 'black')
        return -1 if estimate >= self.INFINITY else estimate


import matplotlib.pyplot as plt
from matplotlib.lines import Line2D

import numpy as np
import pandas as pd
from sklearn import tree

from modt.utility import pickle_disjoint_data

# Colors of the regions. Need to be visible below the scatter points.
COLOR_SCHEME_REGIONS = ["#E24A33",
                        "#8EBA42",
                        "#81D0DB",
                        "#FBC15E",
                        "#B97357",
                        "#988ED5",
                        "#348ABD",
                        "#808a89",]

COLOR_SCHEME_SCATTER = ["#440154", # dark purple
                        "#21918c", # blue green
                        "#fde725", # neon yellow
                        "#5ec962", # green
                        "#ffbaab", # pastel
                        "#ff0000", # red
                        "#f7f7f7", # white grey
                        "#f700ff", # pink
                        "#4dff00", # ugly green
                        "#000000", # black
                        "#3b528b", # blue
                        "#276921", # dark green
                        "#87ffdf", # turquoise
                        "#016685", # dark blue
                        "#313985", # dark purple blue
                        ]

def color_coder(x):
    idx = x % len(COLOR_SCHEME_REGIONS)
    return COLOR_SCHEME_REGIONS[idx]

def color_coder_scatter(x):
    idx = x % len(COLOR_SCHEME_SCATTER)
    return COLOR_SCHEME_SCATTER[idx]

def rand_jitter(arr):
    """Add small amount of noise to array."""
    stdev = .005 * (max(arr) - min(arr))
    return arr + np.random.randn(len(arr)) * stdev

def plot_gating(modt,
                iteration,
                point_size=4,
                rasterize=False,
                title=True,
                axis_digits=False,
                axis_ticks=True,
                jitter=False,
                inverse_transform_standardization=False,
                legend=False,
                legend_classes=False):

    #plt.figure(figsize=(3,2))
    ax = plt.gca()
    y = modt.y

    if modt.use_2_dim_gate_based_on is not None:
        X = modt.X_2_dim
    else:
        X = modt.X_original
        if X.shape[1] != 2:
            raise ValueError("X must have 2 dimensions for visualization. Use 2D gate if dataset has more dimensions.")

    if jitter:
        ax.scatter(rand_jitter(X[:, 0]), rand_jitter(X[:, 1]), color=list(map(color_coder_scatter, y)), s=point_size, clim=(y.min(), y.max()), zorder=3, rasterized=rasterize)
    else:
        ax.scatter(X[:, 0], X[:, 1], color=list(map(color_coder_scatter, y)), s=point_size, clim=(y.min(), y.max()), zorder=3, rasterized=rasterize)

    ax.axis('tight')
    if not axis_ticks:
        ax.axis('off')
    xlim = ax.get_xlim()
    ylim = ax.get_ylim()

    # Add feature names to axis
    if modt.feature_names_one_hot is not None:
        feature_names = modt.feature_names_one_hot
    else:
        feature_names = modt.feature_names
    if feature_names is None:
        ...
        #print("Warning: Dataset does not include feature names.")
    else:
        names_selected_features = feature_names[modt.X_top_2_mask[:-1]]
        ax.set_xlabel(names_selected_features[0], fontsize=12)
        ax.set_ylabel(names_selected_features[1], fontsize=12)

    # Overwrite axis ticks by reversing the standardization of the original ticks
    if inverse_transform_standardization:
        mask = modt.X_top_2_mask[:-1]
        placeholder = np.zeros((len(ax.get_xticks()),modt.X.shape[1]-1))
        placeholder[:,mask[0]] = ax.get_xticks()
        new_x_ticks = modt.scaler.inverse_transform(placeholder)[:,mask[0]]
        new_x_ticks = np.around(new_x_ticks,1)
        ax.set_xticklabels(new_x_ticks)

        placeholder = np.zeros((len(ax.get_yticks()),modt.X.shape[1]-1))
        placeholder[:,mask[1]] = ax.get_yticks()
        new_y_ticks = modt.scaler.inverse_transform(placeholder)[:,mask[1]]
        new_y_ticks = np.around(new_y_ticks,1)
        ax.set_yticklabels(new_y_ticks)

    if not axis_digits:
        ax.set_yticklabels([])
        ax.set_xticklabels([])

    # Create 200*200 sample points.
    xx, yy = np.meshgrid(np.linspace(*xlim, num=200),
                         np.linspace(*ylim, num=200))
    grid = np.c_[xx.ravel(), yy.ravel()]

    if modt.use_2_dim_gate_based_on is not None:
        grid = np.append(grid, np.ones([grid.shape[0], 1]), axis=1) # Bias

    Z = modt.get_expert(grid, iteration, plotting=True).reshape(xx.shape)

    # Create a contour plot with the results Z -> regions
    n_classes = len(np.unique(Z))
    ax.contourf(xx, yy, Z, alpha=0.6,
                           levels=np.arange(modt.n_experts + 1) - 0.5,
                           colors=COLOR_SCHEME_REGIONS,
                           zorder=1)

    if legend:
        legend_elements = []
        for region in np.unique(Z):
            legend_elements.append(Line2D([], [], color=color_coder(region), marker='$\\blacksquare$', linestyle='None', markersize=12, label="DT {}".format(str(region))))
        legend_regions = ax.legend(handles=legend_elements, bbox_to_anchor=(1, 1.02), loc="upper left")
        ax.add_artist(legend_regions)

    # Class names
    if modt.class_names is None:
        class_names = list(np.unique(modt.y_original))
    else:
        class_names = list(modt.class_names)

    if legend_classes:
        legend_elements_classes = []
        for class0 in np.unique(modt.y):
            legend_elements_classes.append(Line2D([], [], color=color_coder_scatter(class0), marker='o',
                                                  linestyle='None', markersize=10, label= class_names[class0] ))
        lengend_classes = plt.legend(handles=legend_elements_classes, bbox_to_anchor=(1, -0.02), loc="lower left")
        ax.add_artist(lengend_classes)

    if title:
        plt.title("iteration: {}".format(iteration))

def plot_initialization(modt,
                        point_size=4,
                        rasterize=False,
                        true_labels=False,
                        jitter=False):

    #plt.figure(figsize=(3,2))
    ax = plt.gca()

    if true_labels:
        y = modt.y
    elif modt.init_labels is not None:
        y = modt.init_labels
    else:
        y = np.zeros(modt.y.shape[0])

    if modt.use_2_dim_gate_based_on is not None:
        X = modt.X_2_dim
    else:
        X = modt.X_original
        if X.shape[1] != 2:
            raise ValueError("X must have 2 dimensions for visualization. Use 2D gate if dataset has more dimensions.")

    if jitter:
        ax.scatter(rand_jitter(X[:, 0]), rand_jitter(X[:, 1]), color=list(map(color_coder_scatter, y)), s=point_size,
                        clim=(y.min(), y.max()), rasterized=rasterize)
    else:
        ax.scatter(X[:, 0], X[:, 1], color=list(map(color_coder_scatter, y)), s=point_size, clim=(y.min(), y.max()), rasterized=rasterize)

    ax.axis('tight')
    ax.set_yticklabels([])
    ax.set_xticklabels([])

def visualize_decision_area(modt,
                point_size=4,
                rasterize=False,
                axis_digits=False,
                axis_ticks=True,
                jitter=False,
                inverse_transform_standardization=False):
    """
    Plot prediction class areas in 2D.
    Only possible for native 2D datasets.
    """

    iteration = modt.best_iteration

    ax = plt.gca()
    y = modt.y

    X = modt.X_original
    if X.shape[1] != 2:
        raise ValueError("X must have 2 dimensions for decision area visualization.")

    if modt.use_2_dim_gate_based_on is not None:
        raise ValueError("Set modt.use_2_dim_gate_based_on to None.")

    if jitter:
        ax.scatter(rand_jitter(X[:, 0]), rand_jitter(X[:, 1]), color=list(map(color_coder_scatter, y)), s=point_size, clim=(y.min(), y.max()), zorder=3, rasterized=rasterize)
    else:
        ax.scatter(X[:, 0], X[:, 1], color=list(map(color_coder_scatter, y)), s=point_size, clim=(y.min(), y.max()), zorder=3, rasterized=rasterize)

    ax.axis('tight')
    if not axis_ticks:
        ax.axis('off')
    xlim = ax.get_xlim()
    ylim = ax.get_ylim()

    # Add feature names to axis
    if modt.feature_names_one_hot is not None:
        feature_names = modt.feature_names_one_hot
    else:
        feature_names = modt.feature_names
    if feature_names is None:
        ...
        #print("Warning: Dataset does not include feature names.")
    else:
        names_selected_features = feature_names[modt.X_top_2_mask[:-1]]
        ax.set_xlabel(names_selected_features[0], fontsize=12)
        ax.set_ylabel(names_selected_features[1], fontsize=12)

    # Overwrite axis ticks by reversing the standardization of the original ticks
    if inverse_transform_standardization:
        mask = modt.X_top_2_mask[:-1]
        placeholder = np.zeros((len(ax.get_xticks()),modt.X.shape[1]-1))
        placeholder[:,mask[0]] = ax.get_xticks()
        new_x_ticks = modt.scaler.inverse_transform(placeholder)[:,mask[0]]
        new_x_ticks = np.around(new_x_ticks,1)
        ax.set_xticklabels(new_x_ticks)

        placeholder = np.zeros((len(ax.get_yticks()),modt.X.shape[1]-1))
        placeholder[:,mask[1]] = ax.get_yticks()
        new_y_ticks = modt.scaler.inverse_transform(placeholder)[:,mask[1]]
        new_y_ticks = np.around(new_y_ticks,1)
        ax.set_yticklabels(new_y_ticks)

    if not axis_digits:
        ax.set_yticklabels([])
        ax.set_xticklabels([])

    # Create 200*200 sample points.
    xx, yy = np.meshgrid(np.linspace(*xlim, num=200),
                         np.linspace(*ylim, num=200))
    grid = np.c_[xx.ravel(), yy.ravel()]

    Z = modt.predict(grid, preprocessing=True).reshape(xx.shape)

    # Create a contour plot with the results Z -> regions
    n_classes = len(np.unique(Z))
    ax.contourf(xx, yy, Z, alpha=0.6,
                           levels=np.arange(n_classes + 1) - 0.5,
                           #colors=COLOR_SCHEME_REGIONS,
                           zorder=1)

def plot_initialization_gates(modt, point_size=3, rasterize=False):
    plt.subplot(1, 2, 1)
    plot_initialization(modt,point_size=point_size, rasterize=rasterize)
    plt.subplot(1, 2, 2)
    plot_gating(modt,iteration=0, point_size=point_size, rasterize=rasterize, title=False, axis_digits=False, inverse_transform_standardization=False)

def plot_training(modt):
    plt.subplot(1, 3, 1)
    accuracy_line(modt)
    plt.subplot(1, 3, 2)
    plt.plot(modt.all_likelihood)
    plt.subplot(1, 3, 3)
    theta_development(modt)

def accuracy_line(modt, color="#348ABD"):
    accuracy = modt.all_accuracies
    print("Min: ", min(accuracy), "Max: ", max(accuracy))
    plt.plot(accuracy, c=color)

def theta_development(modt):
    theta = np.array(modt.all_theta_gating)
    for theta_variable in (theta.reshape(theta.shape[0] , -1).T):
        plt.plot(theta_variable.flatten())

def plot_dt(modt, expert, size=(15,10), iteration="best",feature_names=None,class_names=None):
    if iteration is None:
        iteration = modt.iterations - 1

    plt.figure(figsize=size)
    dt = modt.all_DTs[iteration][expert]
    tree.plot_tree(dt, feature_names=feature_names, class_names=class_names, filled=True, rounded = True)

def plot_disjoint_dt(modt, expert, asymmetric=False, size=(15,10), feature_names=None, class_names=None):

    if feature_names is None:
        feature_names = modt.feature_names
    if class_names is None:
        class_names = modt.class_names

    if asymmetric:
        DT = modt.DT_experts_alternative_algorithm[expert]
    else:
        DT = modt.DT_experts_disjoint[expert]

    plt.figure(figsize=size)
    try:  # Plotting fails if filled=True and tree empty
        tree.plot_tree(DT, feature_names=feature_names, class_names=class_names, filled=True, rounded=True)
    except:
        tree.plot_tree(DT)

def plot_dt_dtreeviz(modt, expert, colors="pretty", fancy="True", asymmetric=False):
    """DT plotting using dtreeviz"""

    from dtreeviz.trees import dtreeviz

    if modt.X_contains_categorical:
        raise Exception("Currently cannot print trees with categorical values.")

    colors_pretty = {'classes': [
        None, # 0 classes
        None, # 1 class
        ["#E24A33","#8EBA42"],
        ["#E24A33","#8EBA42","#81D0DB"],
        ["#E24A33","#8EBA42","#81D0DB","#FBC15E"],
        ["#E24A33","#8EBA42","#81D0DB","#FBC15E","#B97357"],
        ["#E24A33","#8EBA42","#81D0DB","#FBC15E","#B97357","#988ED5"],
        ["#E24A33","#8EBA42","#81D0DB","#FBC15E","#B97357","#988ED5","#348ABD"],
        ["#FEFEBB",'#edf8b1','#c7e9b4','#7fcdbb','#1d91c0','#225ea8','#fdae61','#f46d43'], # 8
        ["#FEFEBB",'#c7e9b4','#41b6c4','#74add1','#4575b4','#313695','#fee090','#fdae61','#f46d43'], # 9
        ["#FEFEBB",'#c7e9b4','#41b6c4','#74add1','#4575b4','#313695','#fee090','#fdae61','#f46d43','#d73027'] # 10
        ]}

    # colors that can be seen on the colored gates
    colors_visible = {'classes':   [
        None, # 0 classes
        None, # 1 class
        ["#440154", "#21918c"],
        ["#440154", "#21918c", "#fde725"],
        ["#440154", "#21918c", "#fde725", "#5ec962"],
        ["#440154", "#21918c", "#fde725", "#5ec962", "#ffbaab"],
        ["#440154", "#21918c", "#fde725", "#5ec962", "#ffbaab", "#ff0000"],
        ["#440154", "#21918c", "#fde725", "#5ec962", "#ffbaab", "#ff0000", "#f7f7f7"],
        ["#440154", "#21918c", "#fde725", "#5ec962", "#ffbaab", "#ff0000", "#f7f7f7", "#f700ff"],
        ["#440154", "#21918c", "#fde725", "#5ec962", "#ffbaab", "#ff0000", "#f7f7f7", "#f700ff", "#4dff00"],
        ["#440154", "#21918c", "#fde725", "#5ec962", "#ffbaab", "#ff0000", "#f7f7f7", "#f700ff", "#4dff00", "#000000"]
        ]}

    if colors == "pretty":
        color_scheme = colors_pretty
    elif colors == "visible":
        color_scheme = colors_visible
    else:
        color_scheme = {}

    pickle_disjoint_data(modt, modt.best_iteration)

    df = pd.read_pickle("output/disjoint_data_e_{}.pd".format(expert))
    df["target"] = modt._map_y(df["target"],reverse=True)

    df = df.sort_values(by="target")

    if modt.class_names is None:
        class_names = list(np.unique(modt.y_original))
    else:
        class_names=list(modt.class_names)

    if modt.feature_names is None:
        feature_names = ["feature" + str(x) for x in range(modt.X_original.shape[1])]
    else:
        feature_names = modt.feature_names

    if asymmetric:
        if modt.DT_experts_alternative_algorithm is None:
            raise Exception("Train asymmetric trees first.")
        else:
            classifier = modt.DT_experts_alternative_algorithm[expert]
    else:
        classifier = modt.DT_experts_disjoint[expert]
    try:
        viz = dtreeviz(classifier,
                    df.iloc[:,:-1],
                    df["target"],
                    feature_names=feature_names,
                    class_names=class_names,
                    fancy=fancy,
                    colors=color_scheme
                    )
        viz.view()
    except Exception as e:
        print("Plotting failed. Exception:", e)


#!/usr/bin/python2

# Markov chain stuff

import bisect
import collections
import itertools
import functools
import random

class State :
    def __init__(self, *transitions) :
        self.transitions = transitions

    def __str__(self) :
        return str(self.transitions)

    def normalise(self) :
        n = float(sum(self.transitions))
        self.transitions = tuple(t/n for t in self.transitions)

    def update(self) :
        pass

    def __getitem__(self, i) :
        return self.transitions[i]

    def vector(self) :
        return self.transitions[:]

KEY = {'W':0, 'D':1, 'L':2}
class Team :
    def __init__(self, name) :
        self.name = name
        self.last_result = 'D'
        self.wins = 0
        self.draws = 0
        self.defeats = 0
        # Each state is {p(win), p(draw), p(lose)}
        # Each transition = P(win|won last), P(win|draw_last), ... etc
        self.transitions = {'W':State(1,1,1), 'D':State(1,1,1), 'L':State(1,1,1)}
        for t in list(self.transitions.values()) :
            t.normalise()

    def details(self) :
        print(self.name)
        print('   win-transitions =',self.transitions['W'])
        print('  draw-transitions =',self.transitions['D'])
        print('  lose-transitions =',self.transitions['L'])
        print('       last-result =', self.last_result)

    def get_transitions(self) :
        return self.transitions[self.last_result]

    def set_transitions(self, **tx) :
        for k,v in tx.items() :
            if k in self.transitions :
                s = State(*v)
                s.normalise()
                self.transitions[k] = s

    def win(self) :
        self.wins += 1
        self.last_result = 'W'

    def draw(self) :
        self.draws += 1
        self.last_result = 'D'

    def lose(self) :
        self.defeats += 1
        self.last_result = 'L'

    def points(self) :
        return 3*self.wins + self.draws

    def __str__(self) :
        return str(self.name)

    def __repr__(self) :
        return repr(self.name)

    def __hash__(self) :
        return hash(self.name)

    def __eq__(self, other) :
        return self.name == other.name

def league_order(a, b) :
    return cmp((a.points(), a.wins, a.draws, a.name), (b.points(), b.wins, b.draws, b.name))

def league_key(a):
    return (a.points(), a.wins, a.draws, a.name)

def print_league(league) :
    unsorted_teams = league.values()
    teams = sorted(unsorted_teams, key=league_key, reverse=True)
    longest = max(len(t.name) for t in teams)
    fmt = '{:%s} |  W |  D |  L | Pts |' % longest
    s = fmt.format('Team')
    print(('=' * len(s)))
    print(s)
    print(('=' * len(s)))
    fmt = '{:%s} | {:2d} | {:2d} | {:2d} | {:3d} |' % longest
    for t in teams :
        print(fmt.format(t.name, t.wins, t.draws, t.defeats, t.points()))
    print(('=' * len(s)))

def make_league() :
    # need an even number
    names = ['Chelsea',
             'Liverpool',
             'Arsenal',
             'Manchester City',
             'Tottenham',
             'Everton',
             'Manchester United',
             'Newcastle United',
             'Southampton',
             'West Ham',
             'Hull City',
             'Stoke City',
             'Swansea City',
             'Aston Villa',
             'Norwich City',
             'Crystal Palace',
             'West Brom',
             'Sunderland',
             'Cardiff City',
             'Fulham']

    teams = {}
    for name in names :
        teams[name] = Team(name)

    # randomise the teams
    for n in names:
        teams[n].set_transitions(W=(random.uniform(0,1), random.uniform(0,1), random.uniform(0,1)))
        teams[n].set_transitions(L=(random.uniform(0,1), random.uniform(0,1), random.uniform(0,1)))
        teams[n].set_transitions(D=(random.uniform(0,1), random.uniform(0,1), random.uniform(0,1)))

    return teams

def make_schedule(teams) :
    n = len(teams)
    n2 = n//2
    names = list(teams.keys())
    homes, aways = names[:n2], names[n2:]

    # round-robin scheduling using homes[0] as the pivot,
    # this generates the first half of the season only,
    # so we simultaneously construct the second half by mirroring.
    first = []
    second = []
    for i in range(n-1) :
        first.append([(teams[homes[j]], teams[aways[j]]) for j in range(n2)])
        second.append([(teams[aways[j]], teams[homes[j]]) for j in range(n2)])
        x = homes.pop(-1)
        y = aways.pop(0)
        homes.insert(1, y)
        aways.append(x)

    # full schedule = first half + reversed of second half
    return first + list(reversed(second))

def play(home, away) :
    # arrange the probabilities in a wheel of 6 slices:
    # 3 home transitions then 3 away transitions.
    # then normalise and compute a pdf
    p = home.get_transitions().vector() + away.get_transitions().vector()
    n = float(sum(p))
    p = [t/n for t in p]
    pdf = [0] * len(p)
    pdf[0] = p[0]
    for i in range(1, len(p)) :
        pdf[i] = pdf[i-1] + p[i]
    outcome = random.uniform(0, 1)
    index = bisect.bisect_left(pdf, outcome)
    if index == 0 or index == 5 :
        home.win()
        away.lose()
    elif index == 2 or index == 3:
        home.lose()
        away.win()
    else :
        home.draw()
        away.draw()

if __name__ == '__main__' :
    import sys
    try:
        random.seed(int(sys.argv[1]))
        print('Using seed', sys.argv[1])
    except:
         print('Not setting seed')
    league = make_league()
    schedule = make_schedule(league)
    for rnd in schedule :
        for match in rnd :
            play(*match)
            # then update probabilities to model form...
    print('')
    print('Season over:')
    print_league(league)


import os, shutil, threading
import torch, rospy

from collections import Counter

# Project Folder (ROOT Project Location)
FOLDER = os.path.abspath(os.path.join(os.path.dirname(__file__),"../.."))

def count_occurrences(vector, recognition_percentage):

    """ Count Occurrences of Each Element """

    # Count Occurrences of Each Element in the Vector
    count = Counter(vector)

    # Find the Most Frequent Element
    more_frequent_el, high_freq = count.most_common(1)[0]

    # Compute Frequency Percentage in respect to Vector Length
    freq_percentage = (high_freq / len(vector)) * 100

    # Check if the Most Frequent Element is Present for at least 80% of the Cases
    if freq_percentage >= recognition_percentage:

        print(f'Gesture Recognized {more_frequent_el}')
        return more_frequent_el

    else:

        # Clean Gesture Vector
        print('Gesture Not Recognized')
        return None

def classifierNetwork(input, model, device):

    """ Classify the Gesture """

    input = torch.tensor(input, dtype=torch.float32, device=device)
    output = model(input)
    prediction = output.argmax(dim=0)
    command = prediction.item()
    print(f'Prediction: {command}')

    return command

class MyThread(threading.Thread):

    def __init__(self):
        super().__init__()
        self.stop_event = threading.Event()
        self.paused = threading.Event()
        self.paused.set()
        self.time = 0

    def run(self):

        while not self.stop_event.is_set() and not rospy.is_shutdown():
            self.paused.wait()
            self.time += 1
            rospy.sleep(1)
            if not self.time  == 0: print("Counter", self.time)

    def resume(self):
        self.paused.set()

    def pause(self):
        self.paused.clear()

    def stop(self):
        self.stop_event.set()
        self.time = 0

def delete_pycache_folders(verbose:bool=False):

  """ Delete Python `__pycache__` Folders Function """

  if verbose: print('\n\nDeleting `__pycache__` Folders...\n\n')

  # Walk Through the Project Folders
  for root, dirs, files in os.walk(FOLDER):

    if "__pycache__" in dirs:

      # Get `__pycache__` Path
      pycache_folder = os.path.join(root, "__pycache__")
      if verbose: print(f"{pycache_folder}")

      # Delete `__pycache__`
      try: shutil.rmtree(pycache_folder)
      except Exception as e: print(f"An error occurred while deleting {pycache_folder}: {e}")

  if verbose: print('\n\n')


import torch
import torch.nn as nn
import torch.nn.functional as F

class base_cnn_model(nn.Module):
    '''
    Architecture built identical to base cnn model given to us.
    After some googling - it seems that for:
        [x] - kernel_initializer - as its set to init its the same as the default
        [ ] - bias_regularizer - that it set in the optimizer
    '''
    def __init__(self):
        super(base_cnn_model, self).__init__()
        self.cn1 = nn.Conv2d(1,16,3)
        self.cn2 = nn.Conv2d(16,32,3)
        self.fc1 = nn.Linear(5760,128)
        self.fc2 = nn.Linear(128, 32)
        self.fc3 = nn.Linear(32,1)

        self.maxpool = nn.MaxPool2d((2,2))

    def forward(self, x):
        batch_size = x.shape[0]
        x = x.permute(0,3,1,2)
        x = self.maxpool(F.relu(self.cn1(x)))
        x = self.maxpool(F.relu(self.cn2(x)))
        x = torch.flatten(x).reshape(batch_size,-1)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        return torch.sigmoid(self.fc3(x))


num = int(input())
result = 0

for i in range(1, num+1):
    if i <= 99:
        result += 1
    else:
        nums = list(map(int, str(i)))
        if nums[0] - nums[1] == nums[1] - nums[2]:
            result += 1
print(result)


from flask import jsonify
from flask.views import MethodView, request
from marshmallow import ValidationError

from repos import LeadRepo
from entities import LeadEntity
from actions.error import UnprocessableEntity

class Create(MethodView):
    def post(self):
        json_data = request.get_json()
        try:
            params = {
                "company_name": json_data.get("company_name"),
                "role": json_data.get("role"),
                "contacts": json_data.get("contacts"),
                "description": json_data.get("description"),
                "status": json_data.get("status"),
                "reference": json_data.get("reference"),
            }

            data = LeadEntity().load(params)

            lead = LeadRepo.create(**data)
            return (LeadEntity.as_json(lead), 201)
        except ValidationError as err:
            # this should be abstracted to an error handler
            error = UnprocessableEntity(errors=[err.messages])
            return error.as_json(), error.http_code


#-------------------------------------------
#-- Oathkeeper Xavius
#-------------------------------------------
# -*- coding: utf-8 -*-

#----------------------------------------------------
# Main Loop
#----------------------------------------------------
def t400517_1():
    """ State 0,1 """
    assert GetCurrentStateElapsedTime() > 1
    """ State 2 """
    while True:
        call = t400517_x0() # Host Player
        assert IsClientPlayer() == 1
        """ State 3 """
        call = t400517_x1() # Client Player
        assert not IsClientPlayer()

# Host Player
def t400517_x0():
    """ State 0,1 """
    while True:
        call = t400517_x3()

# Client Player
def t400517_x1():
    """ State 0,1 """
    assert t400517_x2() # Clear Talk State
    """ State 2 """
    return 0

# Clear Talk State
def t400517_x2():
    """ State 0,1 """
    if not CheckSpecificPersonTalkHasEnded(0):
        """ State 7 """
        ClearTalkProgressData()
        StopEventAnimWithoutForcingConversationEnd(0)
        """ State 6 """
        ReportConversationEndToHavokBehavior()
    else:
        pass
    """ State 2 """
    if CheckSpecificPersonGenericDialogIsOpen(0) == 1:
        """ State 3 """
        ForceCloseGenericDialog()
    else:
        pass
    """ State 4 """
    if CheckSpecificPersonMenuIsOpen(-1, 0) == 1 and not CheckSpecificPersonGenericDialogIsOpen(0):
        """ State 5 """
        ForceCloseMenu()
    else:
        pass
    """ State 8 """
    return 0

# Check Death
def t400517_x3():
    """ State 0,1 """
    call = t400517_x4() # NPC Loop
    assert CheckSelfDeath() == 1
    return 0

# NPC Loop
def t400517_x4():
    """ State 0,5 """
    while True:
        call = t400517_x5() # Interaction State
        if call.Done():
            """ State 3 """
            call = t400517_x8() # Menu Pre-loop
            if call.Done():
                pass
            elif IsAttackedBySomeone() == 1:
                """ State 1 """
                Label('L0')
                call = t400517_x6() # Attack Check
                def ExitPause():
                    RemoveMyAggro()
                if call.Done():
                    pass
                elif IsPlayerDead() == 1:
                    break
            elif IsPlayerDead() == 1:
                break
            elif GetDistanceToPlayer() > 2 or GetPlayerYDistance() > 0.25:
                """ State 4 """
                call = t400517_x7() # Distance Check
                if call.Done() and (GetDistanceToPlayer() < 1.5 and GetPlayerYDistance() < 0.249):
                    pass
                elif IsAttackedBySomeone() == 1:
                    Goto('L0')
        elif IsAttackedBySomeone() == 1:
            Goto('L0')
        elif IsPlayerDead() == 1:
            break
    """ State 2 """
    t400517_x2() # Clear Talk State

# Interaction State
def t400517_x5():
    """ State 0,1 """
    while True:
        assert (not GetOneLineHelpStatus() and not IsTalkingToSomeoneElse() and not IsClientPlayer()
                and not IsPlayerDead() and not IsCharacterDisabled())
        """ State 2 """
        if (not (not GetOneLineHelpStatus() and not IsTalkingToSomeoneElse() and not IsClientPlayer()
            and not IsPlayerDead() and not IsCharacterDisabled())):
            pass
        elif CheckActionButtonArea(6120):
            break
    """ State 4 """
    return 0

# Attack Check
def t400517_x6():
    """ State 0,6 """
    assert t400517_x2() # Clear Talk State
    """ State 3 """
    assert GetCurrentStateElapsedFrames() > 1
    """ State 2 """
    if GetDistanceToPlayer() > 3:
        """ State 7 """
        assert t400517_x2() # Clear Talk State
    else:
        """ State 5 """
        pass
    """ State 9 """
    return 0

# Distance Check
def t400517_x7():
    """ State 0,1 """
    if (CheckSpecificPersonMenuIsOpen(-1, 0) == 1 and not
        CheckSpecificPersonGenericDialogIsOpen(0)):
        """ State 2,5 """
        if GetDistanceToPlayer() > 3:
            """ State 4 """
            Label('L0')
            assert t400517_x2() # Clear Talk State
    else:
        """ State 3 """
        Goto('L0')
    """ State 6 """
    return 0

# Menu Pre-loop
def t400517_x8():
    """ State 0,1 """
    assert t400517_x9()
    """ State 24 """
    return 0

# Menu Loop
def t400517_x9():
    c1110()
    while True:
        ClearTalkListData()

        #---- Gauntlet
        # Enter the Gauntlet - Ordered
        AddTalkListDataIf(GetEventStatus(25003200) == 1, 60, 99060110, -1)

        # Enter the Gauntlet - Random
        AddTalkListDataIf(GetEventStatus(25003201) == 1, 61, 99060110, -1)

        # Enter the Gauntlet - Endless
        AddTalkListDataIf(GetEventStatus(25003202) == 1, 62, 99060110, -1)

        # Enter the Gauntlet - Reverse Ordered
        AddTalkListDataIf(GetEventStatus(25003203) == 1, 63, 99060110, -1)

        # Enter the Gauntlet - Reverse Endless
        AddTalkListDataIf(GetEventStatus(25003204) == 1, 64, 99060110, -1)

        # Enter the Gauntlet - Boss Select
        AddTalkListDataIf(GetEventStatus(25003205) == 1, 65, 99060110, -1)

        # Gauntlet Configuration
        AddTalkListData(53, 99060126, -1)

        # Browse Inventory
        AddTalkListData(54, 99060127, -1)

        # Reallocate Attributes
        AddTalkListData(55, 15027010, -1)

        # Talk
        AddTalkListData(2, 15000000, -1)

        # Leave
        AddTalkListData(99, 15000005, -1)

        assert (not CheckSpecificPersonGenericDialogIsOpen(2) and not (CheckSpecificPersonMenuIsOpen(-1,
                2) == 1 and not CheckSpecificPersonGenericDialogIsOpen(2)))
        ShowShopMessage(1)

        # Gauntlet Configuration
        if GetTalkListEntryResult() == 53:
            assert t400517_x40()
            continue
        # Browse Inventory
        elif GetTalkListEntryResult() == 54:
            assert t400517_x50()
            continue
        # Respec
        elif GetTalkListEntryResult() == 55:
            c1113()
            SetEventState(25009400, 1) # Reset Masteries
            continue
        # Enter the Gauntlet - Ordered
        elif GetTalkListEntryResult() == 60:
            GiveSpEffectToPlayer(260120000)
            return 0
        # Enter the Gauntlet - Random
        elif GetTalkListEntryResult() == 61:
            GiveSpEffectToPlayer(260120010)
            return 0
        # Enter the Gauntlet - Endless
        elif GetTalkListEntryResult() == 62:
            GiveSpEffectToPlayer(260120020)
            GiveSpEffectToPlayer(260120000)
            return 0
        # Enter the Gauntlet - Reversed Ordered
        elif GetTalkListEntryResult() == 63:
            GiveSpEffectToPlayer(260120000)
            return 0
        # Enter the Gauntlet - Reversed Endless
        elif GetTalkListEntryResult() == 64:
            GiveSpEffectToPlayer(260120020)
            GiveSpEffectToPlayer(260120000)
            return 0
        # Enter the Gauntlet - Boss Select
        elif GetTalkListEntryResult() == 65:
            assert t400517_x60()
            continue
        # Talk
        elif GetTalkListEntryResult() == 2:
            assert t400517_x10(text1=10134000, flag1=0, mode1=0)
            continue
        # Leave
        elif GetTalkListEntryResult() == 99:
            ReportConversationEndToHavokBehavior()
            return 0
        elif not (CheckSpecificPersonMenuIsOpen(-1, 0) == 1 and not CheckSpecificPersonGenericDialogIsOpen(0)):
            return 0

# Talk Function
def t400517_x10(text1=_, flag1=0, mode1=_):
    """ State 0,4 """
    assert t400517_x11() and CheckSpecificPersonTalkHasEnded(0) == 1
    """ State 1 """
    TalkToPlayer(text1, -1, -1, flag1)
    assert CheckSpecificPersonTalkHasEnded(0) == 1
    """ State 3 """
    if not mode1:
        pass
    else:
        """ State 2 """
        ReportConversationEndToHavokBehavior()
    """ State 5 """
    return 0

# Talk Cleanup
def t400517_x11():
    """ State 0,1 """
    ClearTalkProgressData()
    StopEventAnimWithoutForcingConversationEnd(0)
    ForceCloseGenericDialog()
    ForceCloseMenu()
    ReportConversationEndToHavokBehavior()
    """ State 2 """
    return 0

#----------------------------------------------------
# Utility
#----------------------------------------------------

# Gauntlet Type
def t400517_x30():
    c1110()
    while True:
        ClearTalkListData()

        # Ordered
        AddTalkListDataIf(GetEventStatus(25003200) == 0, 1, 99060150, -1)

        # Random
        AddTalkListDataIf(GetEventStatus(25003201) == 0, 2, 99060151, -1)

        # Endless
        AddTalkListDataIf(GetEventStatus(25003202) == 0, 3, 99060152, -1)

        # Reverse Ordered
        AddTalkListDataIf(GetEventStatus(25003203) == 0, 4, 99060153, -1)

        # Reverse Endless
        AddTalkListDataIf(GetEventStatus(25003204) == 0, 5, 99060154, -1)

        # Boss Select
        AddTalkListDataIf(GetEventStatus(25003205) == 0, 6, 99060155, -1)

        # Return
        AddTalkListData(99, 15000006, -1)

        assert (not CheckSpecificPersonGenericDialogIsOpen(2) and not (CheckSpecificPersonMenuIsOpen(-1, 2) == 1 and not CheckSpecificPersonGenericDialogIsOpen(2)))
        ShowShopMessage(1)

        # Ordered
        if GetTalkListEntryResult() == 1:
            OpenGenericDialog(1, 99060160, 0, 0, 0)
            SetEventState(25003200, 1)
            SetEventState(25003201, 0)
            SetEventState(25003202, 0)
            SetEventState(25003203, 0)
            SetEventState(25003204, 0)
            SetEventState(25003205, 0)
            GiveSpEffectToPlayer(260120020) # Reset progress if done
            continue
        # Random
        elif GetTalkListEntryResult() == 2:
            OpenGenericDialog(1, 99060161, 0, 0, 0)
            SetEventState(25003200, 0)
            SetEventState(25003201, 1)
            SetEventState(25003202, 0)
            SetEventState(25003203, 0)
            SetEventState(25003204, 0)
            SetEventState(25003205, 0)
            GiveSpEffectToPlayer(260120020) # Reset progress if done
            continue
        # Endless
        elif GetTalkListEntryResult() == 3:
            OpenGenericDialog(1, 99060162, 0, 0, 0)
            SetEventState(25003200, 0)
            SetEventState(25003201, 0)
            SetEventState(25003202, 1)
            SetEventState(25003203, 0)
            SetEventState(25003204, 0)
            SetEventState(25003205, 0)
            GiveSpEffectToPlayer(260120020) # Reset progress if done
            continue
        # Reversed Ordered
        elif GetTalkListEntryResult() == 4:
            OpenGenericDialog(1, 99060163, 0, 0, 0)
            SetEventState(25003200, 0)
            SetEventState(25003201, 0)
            SetEventState(25003202, 0)
            SetEventState(25003203, 1)
            SetEventState(25003204, 0)
            SetEventState(25003205, 0)
            GiveSpEffectToPlayer(260120020) # Reset progress if done
            continue
        # Reversed Endless
        elif GetTalkListEntryResult() == 5:
            OpenGenericDialog(1, 99060164, 0, 0, 0)
            SetEventState(25003200, 0)
            SetEventState(25003201, 0)
            SetEventState(25003202, 0)
            SetEventState(25003203, 0)
            SetEventState(25003204, 1)
            SetEventState(25003205, 0)
            GiveSpEffectToPlayer(260120020) # Reset progress if done
            continue
        # Boss Select
        elif GetTalkListEntryResult() == 6:
            OpenGenericDialog(1, 99060165, 0, 0, 0)
            SetEventState(25003200, 0)
            SetEventState(25003201, 0)
            SetEventState(25003202, 0)
            SetEventState(25003203, 0)
            SetEventState(25003204, 0)
            SetEventState(25003205, 1)
            GiveSpEffectToPlayer(260120020) # Reset progress if done
            continue
        # Leave
        elif GetTalkListEntryResult() == 99:
            ReportConversationEndToHavokBehavior()
            return 0

# Gauntlet Configuration
def t400517_x40():
    """ State 0,8 """
    c1110()
    """ State 1 """
    while True:
        ClearTalkListData()
        """ State 2 """

        # Switch Gauntlet Type
        AddTalkListData(1, 99060125, -1)

        # Reset Progress
        AddTalkListData(2, 15013005, -1)

        # Enable DLC Bosses
        AddTalkListDataIf(GetEventStatus(25009805) == 1, 3, 99060128, -1)

        # Disable DLC Bosses
        AddTalkListDataIf(GetEventStatus(25009805) == 0, 4, 99060129, -1)

        # Return
        AddTalkListData(99, 15000006, -1)

        assert (not CheckSpecificPersonGenericDialogIsOpen(2) and not (CheckSpecificPersonMenuIsOpen(-1, 2) == 1 and not CheckSpecificPersonGenericDialogIsOpen(2)))
        """ State 3 """
        ShowShopMessage(1)

        # Switch Gauntlet Type
        if GetTalkListEntryResult() == 1:
            assert t400517_x30()
            continue
        # Reset Progress
        elif GetTalkListEntryResult() == 2:
            ClearTalkListData()

            AddTalkListData(1, 15013006, -1)
            AddTalkListData(2, 15013007, -1)

            OpenConversationChoicesMenu(0)

            assert not (CheckSpecificPersonMenuIsOpen(12, 0) == 1 and not CheckSpecificPersonGenericDialogIsOpen(0))

            if GetTalkListEntryResult() == 1:
                GiveSpEffectToPlayer(260120020)
                OpenGenericDialog(1, 15013008, 0, 0, 0)
                return 0
            else:
                pass

            return 0
        # Enable DLC Bosses
        elif GetTalkListEntryResult() == 3:
            OpenGenericDialog(1, 99060130, 0, 0, 0)
            SetEventState(25009805, 0)
            continue
        # Disable DLC Bosses
        elif GetTalkListEntryResult() == 4:
            OpenGenericDialog(1, 99060131, 0, 0, 0)
            SetEventState(25009805, 1)
            continue
        # Leave
        elif GetTalkListEntryResult() == 99:
            ReportConversationEndToHavokBehavior()
            return 0

# Inventory
def t400517_x50():
    """ State 0,8 """
    c1110()
    """ State 1 """
    while True:
        ClearTalkListData()
        """ State 2 """

        # Browse Weapons
        AddTalkListData(1, 15013001, -1)

        # Browse Spells
        AddTalkListData(2, 15013002, -1)

        # Browse Armor
        AddTalkListData(3, 15013003, -1)

        # Browse Accessories
        AddTalkListData(4, 15013004, -1)

        # Browse Covenant Accessories
        AddTalkListData(6, 15013011, -1)

        # Browse Items
        AddTalkListData(5, 15013009, -1)

        # Return
        AddTalkListData(99, 15000006, -1)

        assert (not CheckSpecificPersonGenericDialogIsOpen(2) and not (CheckSpecificPersonMenuIsOpen(-1, 2) == 1 and not CheckSpecificPersonGenericDialogIsOpen(2)))
        """ State 3 """
        ShowShopMessage(1)

        # Browse Weapons
        if GetTalkListEntryResult() == 1:
            c1111(800000, 800999)
            continue
        # Browse Spells
        elif GetTalkListEntryResult() == 2:
            c1111(803000, 803999)
            continue
        # Browse Armor
        elif GetTalkListEntryResult() == 3:
            c1111(801000, 801999)
            continue
        # Browse Accessories
        elif GetTalkListEntryResult() == 4:
            c1111(802000, 802999)
            continue
        # Browse Covenant Accessories
        elif GetTalkListEntryResult() == 6:
            c1111(804500, 804699)
            continue
        # Purchase Item
        elif GetTalkListEntryResult() == 5:
            OpenRegularShop(804000, 804499)
            continue
        # Leave
        elif GetTalkListEntryResult() == 99:
            ReportConversationEndToHavokBehavior()
            return 0

# Boss Select
def t400517_x60():
    """ State 0,8 """
    c1110()
    """ State 1 """
    while True:
        ClearTalkListData()
        """ State 2 """

        # Corrupted Gundyr
        AddTalkListDataIf(GetEventStatus(25002001) == 0, 1, 99060200, -1)

        # Vordt
        AddTalkListDataIf(GetEventStatus(25002002) == 0, 2, 99060201, -1)

        # Curse-rotted Greatwood
        AddTalkListDataIf(GetEventStatus(25002003) == 0, 3, 99060202, -1)

        # Crystal Sage
        AddTalkListDataIf(GetEventStatus(25002004) == 0, 4, 99060203, -1)

        # Deacons
        AddTalkListDataIf(GetEventStatus(25002005) == 0, 5, 99060204, -1)

        # Abyss Watchers
        AddTalkListDataIf(GetEventStatus(25002006) == 0, 6, 99060205, -1)

        # High Lord Wolnir
        AddTalkListDataIf(GetEventStatus(25002007) == 0, 7, 99060206, -1)

        # Old Demon King
        AddTalkListDataIf(GetEventStatus(25002008) == 0, 8, 99060207, -1)

        # Pontiff Sulyvahn
        AddTalkListDataIf(GetEventStatus(25002009) == 0, 9, 99060208, -1)

        # Aldrich
        AddTalkListDataIf(GetEventStatus(25002010) == 0, 10, 99060209, -1)

        # Yhorm
        AddTalkListDataIf(GetEventStatus(25002011) == 0, 11, 99060210, -1)

        # Dancer
        AddTalkListDataIf(GetEventStatus(25002012) == 0, 12, 99060211, -1)

        # Oceiros
        AddTalkListDataIf(GetEventStatus(25002013) == 0, 13, 99060212, -1)

        # Dragonslayer Armour
        AddTalkListDataIf(GetEventStatus(25002014) == 0, 14, 99060213, -1)

        # Ancient Wyvern
        AddTalkListDataIf(GetEventStatus(25002015) == 0, 15, 99060214, -1)

        # Nameless King
        AddTalkListDataIf(GetEventStatus(25002016) == 0, 16, 99060215, -1)

        # Champion Gundyr
        AddTalkListDataIf(GetEventStatus(25002017) == 0, 17, 99060216, -1)

        # Twin Princes
        AddTalkListDataIf(GetEventStatus(25002018) == 0, 18, 99060217, -1)

        # Soul of Cinder
        AddTalkListDataIf(GetEventStatus(25002019) == 0, 19, 99060218, -1)

        # Sister Friede
        AddTalkListDataIf(GetEventStatus(25002020) == 0 and GetEventStatus(25009805) == 0, 20, 99060219, -1)

        # Lordran Remnants
        AddTalkListDataIf(GetEventStatus(25002021) == 0, 21, 99060220, -1)

        # Demon Prince
        AddTalkListDataIf(GetEventStatus(25002022) == 0 and GetEventStatus(25009805) == 0, 22, 99060221, -1)

        # Darkeater Midir
        AddTalkListDataIf(GetEventStatus(25002023) == 0 and GetEventStatus(25009805) == 0, 23, 99060222, -1)

        # Slave Knight Gael
        AddTalkListDataIf(GetEventStatus(25002024) == 0 and GetEventStatus(25009805) == 0, 24, 99060223, -1)

        # Halflight
        AddTalkListDataIf(GetEventStatus(25002025) == 0 and GetEventStatus(25009805) == 0, 25, 99060224, -1)

        # Prince Dorthinus
        AddTalkListDataIf(GetEventStatus(25002026) == 0 and GetEventStatus(25009805) == 0, 26, 99060225, -1)

        # Cathedral Guardian
        AddTalkListDataIf(GetEventStatus(25002027) == 0, 27, 99060226, -1)

        # Mirror Knight
        AddTalkListDataIf(GetEventStatus(25002028) == 0, 28, 99060227, -1)

        # Aborr
        AddTalkListDataIf(GetEventStatus(25002029) == 0, 29, 99060228, -1)

        # Princess Yngvil
        AddTalkListDataIf(GetEventStatus(25002030) == 0 and GetEventStatus(25009805) == 0, 30, 99060229, -1)

        # The Rock
        AddTalkListDataIf(GetEventStatus(25002031) == 0, 31, 99060230, -1)

        # Twisted Knight
        AddTalkListDataIf(GetEventStatus(25002032) == 0, 32, 99060231, -1)

        # Fallen Protector
        AddTalkListDataIf(GetEventStatus(25002033) == 0, 33, 99060232, -1)

        # Titanite Abomination
        # AddTalkListDataIf(GetEventStatus(25002034) == 0, 34, 99060233, -1)

        # The Marauder
        AddTalkListDataIf(GetEventStatus(25002035) == 0, 35, 99060234, -1)

        # Return
        AddTalkListData(99, 15000006, -1)

        assert (not CheckSpecificPersonGenericDialogIsOpen(2) and not (CheckSpecificPersonMenuIsOpen(-1, 2) == 1 and not CheckSpecificPersonGenericDialogIsOpen(2)))
        """ State 3 """
        ShowShopMessage(1)

        # Corrupted Gundyr
        if GetTalkListEntryResult() == 1:
            GiveSpEffectToPlayer(260100010)
            return 0
        # Vordt
        elif GetTalkListEntryResult() == 2:
            GiveSpEffectToPlayer(260100020)
            return 0
        # Curse-rotted Greatwood
        elif GetTalkListEntryResult() == 3:
            GiveSpEffectToPlayer(260100030)
            return 0
        # Crystal Sage
        elif GetTalkListEntryResult() == 4:
            GiveSpEffectToPlayer(260100040)
            return 0
        # Deacons
        elif GetTalkListEntryResult() == 5:
            GiveSpEffectToPlayer(260100050)
            return 0
        # Abyss Watchers
        elif GetTalkListEntryResult() == 6:
            GiveSpEffectToPlayer(260100060)
            return 0
        # High Lord Wolnir
        elif GetTalkListEntryResult() == 7:
            GiveSpEffectToPlayer(260100070)
            return 0
        # Old Demon King
        elif GetTalkListEntryResult() == 8:
            GiveSpEffectToPlayer(260100080)
            return 0
        # Pontiff Sulyvahn
        elif GetTalkListEntryResult() == 9:
            GiveSpEffectToPlayer(260100090)
            return 0
        # Aldrich
        elif GetTalkListEntryResult() == 10:
            GiveSpEffectToPlayer(260100100)
            return 0
        # Yhorm
        elif GetTalkListEntryResult() == 11:
            GiveSpEffectToPlayer(260100110)
            return 0
        # Dancer
        elif GetTalkListEntryResult() == 12:
            GiveSpEffectToPlayer(260100120)
            return 0
        # Oceiros
        elif GetTalkListEntryResult() == 13:
            GiveSpEffectToPlayer(260100130)
            return 0
        # Dragonslayer Armour
        elif GetTalkListEntryResult() == 14:
            GiveSpEffectToPlayer(260100140)
            return 0
        # Ancient Wyvern
        elif GetTalkListEntryResult() == 15:
            GiveSpEffectToPlayer(260100150)
            return 0
        # Nameless King
        elif GetTalkListEntryResult() == 16:
            GiveSpEffectToPlayer(260100160)
            return 0
        # Champion Gundyr
        elif GetTalkListEntryResult() == 17:
            GiveSpEffectToPlayer(260100170)
            return 0
        # Twin Princes
        elif GetTalkListEntryResult() == 18:
            GiveSpEffectToPlayer(260100180)
            return 0
        # Soul of Cinder
        elif GetTalkListEntryResult() == 19:
            GiveSpEffectToPlayer(260100190)
            return 0
        # Sister Friede
        elif GetTalkListEntryResult() == 20:
            GiveSpEffectToPlayer(260100200)
            return 0
        # Lordran Remnants
        elif GetTalkListEntryResult() == 21:
            GiveSpEffectToPlayer(260100210)
            return 0
        # Demon Prince
        elif GetTalkListEntryResult() == 22:
            GiveSpEffectToPlayer(260100220)
            return 0
        # Darkeater Midir
        elif GetTalkListEntryResult() == 23:
            GiveSpEffectToPlayer(260100230)
            return 0
        # Slave Knight Gael
        elif GetTalkListEntryResult() == 24:
            GiveSpEffectToPlayer(260100240)
            return 0
        # Halflight
        elif GetTalkListEntryResult() == 25:
            GiveSpEffectToPlayer(260100250)
            return 0
        # Prince Dorthinus
        elif GetTalkListEntryResult() == 26:
            GiveSpEffectToPlayer(260100270)
            return 0
        # Cathedral Guardian
        elif GetTalkListEntryResult() == 27:
            GiveSpEffectToPlayer(260100280)
            return 0
        # Mirror Knight
        elif GetTalkListEntryResult() == 28:
            GiveSpEffectToPlayer(260100290)
            return 0
        # Aborr
        elif GetTalkListEntryResult() == 29:
            GiveSpEffectToPlayer(260100300)
            return 0
        # Princess Yngvil
        elif GetTalkListEntryResult() == 30:
            GiveSpEffectToPlayer(260100310)
            return 0
        # The Rock
        elif GetTalkListEntryResult() == 31:
            GiveSpEffectToPlayer(260100320)
            return 0
        # Twisted Knight
        elif GetTalkListEntryResult() == 32:
            GiveSpEffectToPlayer(260100330)
            return 0
        # Fallen Protector
        elif GetTalkListEntryResult() == 33:
            GiveSpEffectToPlayer(260100340)
            return 0
        # Titanite Abomination
        # elif GetTalkListEntryResult() == 34:
            # GiveSpEffectToPlayer(260100350)
            # return 0
        # The Marauder
        elif GetTalkListEntryResult() == 35:
            GiveSpEffectToPlayer(260100360)
            return 0

        # Leave
        elif GetTalkListEntryResult() == 99:
            ReportConversationEndToHavokBehavior()
            return 0


import unittest
from unittest.mock import call
from unittest.mock import patch

from parameterized import parameterized

from sample_size.metrics import BooleanMetric
from sample_size.metrics import NumericMetric
from sample_size.metrics import RatioMetric
from sample_size.sample_size_calculator import DEFAULT_ALPHA
from sample_size.sample_size_calculator import DEFAULT_POWER
from sample_size.sample_size_calculator import DEFAULT_VARIANTS
from sample_size.sample_size_calculator import RANDOM_STATE
from sample_size.sample_size_calculator import SampleSizeCalculator
from tests.sample_size.test_metrics import ALTERNATIVE

class SampleSizeCalculatorTestCase(unittest.TestCase):
    def test_sample_size_calculator_constructor_sets_params(self):
        test_alpha = 0.1
        test_variants = 2
        test_power = 0.9
        calculator = SampleSizeCalculator(
            test_alpha,
            test_variants,
            test_power,
        )

        self.assertEqual(calculator.alpha, test_alpha)
        self.assertEqual(calculator.power, test_power)
        self.assertEqual(calculator.metrics, [])

    def test_sample_size_calculator_constructor_sets_params_with_default_params(self):
        calculator = SampleSizeCalculator()

        self.assertEqual(calculator.alpha, DEFAULT_ALPHA)
        self.assertEqual(calculator.variants, DEFAULT_VARIANTS)
        self.assertEqual(calculator.power, DEFAULT_POWER)
        self.assertEqual(calculator.metrics, [])

    @patch("statsmodels.stats.power.NormalIndPower.solve_power")
    def test_get_single_sample_size_normal(self, mock_solve_power):
        test_probability = 0.05
        test_mde = 0.02
        test_sample_size = 2000
        test_metric = BooleanMetric(
            test_probability,
            test_mde,
            ALTERNATIVE,
        )
        mock_solve_power.return_value = test_sample_size

        calculator = SampleSizeCalculator()
        sample_size = calculator._get_single_sample_size(test_metric, calculator.alpha)

        self.assertEqual(sample_size, test_sample_size)
        mock_solve_power.assert_called_once_with(
            effect_size=0.09176629354822471,
            alpha=DEFAULT_ALPHA,
            power=DEFAULT_POWER,
            ratio=1,
            alternative="two-sided",
        )

    @patch("statsmodels.stats.power.TTestIndPower.solve_power")
    def test_get_single_sample_size_ttest(self, mock_solve_power):
        test_variance = 1000
        test_mde = 5
        test_sample_size = 2000
        test_metric = NumericMetric(
            test_variance,
            test_mde,
            ALTERNATIVE,
        )
        mock_solve_power.return_value = test_sample_size
        calculator = SampleSizeCalculator()

        sample_size = calculator._get_single_sample_size(test_metric, calculator.alpha)

        self.assertEqual(sample_size, test_sample_size)
        mock_solve_power.assert_called_once_with(
            effect_size=0.15811388300841897,
            alpha=DEFAULT_ALPHA,
            power=DEFAULT_POWER,
            ratio=1,
            alternative="two-sided",
        )

    @parameterized.expand(
        [
            ("boolean", {"probability": 0.05, "mde": 0.02, "alternative": "two-sided"}),
            ("numeric", {"variance": 500, "mde": 5, "alternative": "smaller"}),
            (
                "ratio",
                {
                    "numerator_mean": 2000,
                    "numerator_variance": 100000,
                    "denominator_mean": 200,
                    "denominator_variance": 2000,
                    "covariance": 5000,
                    "mde": 10,
                    "alternative": "larger",
                },
            ),
        ]
    )
    @patch("sample_size.sample_size_calculator.SampleSizeCalculator.get_multiple_sample_size")
    @patch("sample_size.sample_size_calculator.SampleSizeCalculator._get_single_sample_size")
    def test_get_sample_size_single(
        self, metric_type, metadata, mock_get_single_sample_size, mock_get_multiple_sample_size
    ):
        test_metric_type = metric_type
        test_sample_size = 2000
        mock_get_single_sample_size.return_value = test_sample_size

        test_mde = metadata["mde"]
        test_metric_metadata = metadata
        calculator = SampleSizeCalculator()
        calculator.register_metrics([{"metric_type": test_metric_type, "metric_metadata": test_metric_metadata}])

        sample_size = calculator.get_sample_size()

        self.assertEqual(sample_size, test_sample_size)
        mock_get_multiple_sample_size.assert_not_called()
        mock_get_single_sample_size.assert_called_once()
        self.assertEqual(mock_get_single_sample_size.call_args[0][0], calculator.metrics[0])
        self.assertEqual(mock_get_single_sample_size.call_args[0][0].mde, test_mde)

    @patch("sample_size.sample_size_calculator.SampleSizeCalculator.get_multiple_sample_size")
    @patch("sample_size.sample_size_calculator.SampleSizeCalculator._get_single_sample_size")
    def test_get_sample_size_multiple(self, mock_get_single_sample_size, mock_get_multiple_sample_size):
        test_metric_type = "boolean"
        test_sample_size = 2000
        mock_get_multiple_sample_size.return_value = test_sample_size
        mock_get_single_sample_size.return_value = test_sample_size
        test_metric_metadata = {"probability": 0.05, "mde": 0.02, "alternative": ALTERNATIVE}
        calculator = SampleSizeCalculator()
        calculator.register_metrics(
            [
                {"metric_type": test_metric_type, "metric_metadata": test_metric_metadata},
                {"metric_type": test_metric_type, "metric_metadata": test_metric_metadata},
            ]
        )

        sample_size = calculator.get_sample_size()

        self.assertEqual(sample_size, test_sample_size)
        self.assertEqual(mock_get_single_sample_size.call_count, 4)
        mock_get_single_sample_size.assert_has_calls(
            [
                call(calculator.metrics[0], calculator.alpha),
                call(calculator.metrics[1], calculator.alpha),
                call(calculator.metrics[0], calculator.alpha / 2),
                call(calculator.metrics[1], calculator.alpha / 2),
            ]
        )
        mock_get_multiple_sample_size.assert_called_once_with(test_sample_size, test_sample_size, RANDOM_STATE)

    # TODO: parameterize register metric functions
    def test_register_metric_boolean(self):
        test_metric_type = "boolean"
        test_probability = 0.05
        test_mde = 0.02
        test_metric_metadata = {"probability": test_probability, "mde": test_mde, "alternative": "larger"}

        calculator = SampleSizeCalculator()
        calculator.register_metrics([{"metric_type": test_metric_type, "metric_metadata": test_metric_metadata}])
        self.assertIsInstance(calculator.metrics[0], BooleanMetric)
        self.assertEqual(len(calculator.metrics), 1)
        self.assertEqual(calculator.metrics[0].variance, 0.0475)
        self.assertEqual(calculator.metrics[0].mde, test_mde)

        calculator.register_metrics([{"metric_type": test_metric_type, "metric_metadata": test_metric_metadata}])
        self.assertEqual(len(calculator.metrics), 2)

    def test_register_metric_numeric(self):
        test_metric_type = "numeric"
        test_variance = 5000.0
        test_mde = 5.0
        test_metric_metadata = {"variance": test_variance, "mde": test_mde, "alternative": "two-sided"}

        calculator = SampleSizeCalculator()
        calculator.register_metrics([{"metric_type": test_metric_type, "metric_metadata": test_metric_metadata}])
        self.assertIsInstance(calculator.metrics[0], NumericMetric)
        self.assertEqual(len(calculator.metrics), 1)
        self.assertEqual(calculator.metrics[0].variance, test_variance)
        self.assertEqual(calculator.metrics[0].mde, test_mde)

        calculator.register_metrics([{"metric_type": test_metric_type, "metric_metadata": test_metric_metadata}])
        self.assertEqual(len(calculator.metrics), 2)

    def test_register_metric_ratio(self):
        test_metric_type = "ratio"
        test_numerator_mean = 2000.0
        test_numerator_variance = 100000.0
        test_denominator_mean = 200.0
        test_denominator_variance = 2000.0
        test_covariance = 5000.0
        test_mde = 5.0
        test_variance = 5
        test_metric_metadata = {
            "numerator_mean": test_numerator_mean,
            "numerator_variance": test_numerator_variance,
            "denominator_mean": test_denominator_mean,
            "denominator_variance": test_denominator_variance,
            "covariance": test_covariance,
            "mde": test_mde,
            "alternative": "smaller",
        }

        calculator = SampleSizeCalculator()
        calculator.register_metrics([{"metric_type": test_metric_type, "metric_metadata": test_metric_metadata}])
        self.assertIsInstance(calculator.metrics[0], RatioMetric)
        self.assertEqual(len(calculator.metrics), 1)
        self.assertEqual(calculator.metrics[0].variance, test_variance)
        self.assertEqual(calculator.metrics[0].mde, test_mde)

        calculator.register_metrics([{"metric_type": test_metric_type, "metric_metadata": test_metric_metadata}])
        self.assertEqual(len(calculator.metrics), 2)

    def test_register_metric_invalid_metadata(self):
        test_metric_type = "numeric"

        calculator = SampleSizeCalculator()
        with self.assertRaises(Exception):
            calculator.register_metrics([{"metric_type": test_metric_type}])


from django.http import HttpResponse, HttpResponseForbidden
from django.core.urlresolvers import reverse
from django.views.generic import create_update
from django.shortcuts import get_object_or_404, redirect
from django.db.models import Q

from kecupuapp_base.shortcuts import render_response
from kecupuapp_base.decorators import has_role
from kecupuapp_base.forms import process_form

from haystack.query import SearchQuerySet
from haystack.views import basic_search

from cari.forms import TextSearchForm

from jazzpos.models import Customer, Store, Patient, Treatment, StoreSettings
from jazzpos.forms import CustomerForm, PatientForm, TreatmentForm, StoreSettingsForm
from xpos.views import main as xpos_views

from gfbv import list_detail

@has_role('staff')
def index(request):
    return render_response(request, 'index.html')

@has_role('staff')
def list_customers(request):
    ctx = {}
    qs = Customer.objects.all()

    if request.GET.get('q', None) is not None:
        form = TextSearchForm(request.GET)
        if form.is_valid():
            q = form.cleaned_data['q']
            qs = qs.filter(Q(name__icontains=q) | Q(patient__icno=q))

    ctx['customer_list'] = qs.order_by('-id')

    return render_response(
        request,
        'jazzpos/customer_list.html',
        ctx
    )

@has_role('staff')
def add_customer(request):
    ctx = {}
    redirect_to = reverse('jazzpos.views.list_customers')
    initial = {
        'store': request.session['store_id'],
        'customer_type': 'patient',
    }
    ctx['form'] = process_form(request, CustomerForm, initial=initial, redirect_to=redirect_to)
    return render_response(
        request,
        'customer_add.html',
        ctx
    )

@has_role('staff')
def edit_customer(request, customer_id):
    customer = get_object_or_404(Customer, pk=customer_id)

    # allow only customer own store except for admin
    if not request.user.is_superuser:
        if customer.store != request.store:
            return HttpResponseForbidden()

    ctx = {}
    redirect_to = reverse('jazzpos.views.view_customer', args=(customer_id,))
    initial = {
        'store': request.session['store_id'],
    }
    ctx['form'] = process_form(request, CustomerForm, initial=initial, redirect_to=redirect_to, instance=customer)
    ctx['customer'] = customer
    return render_response(
        request,
        'customer_edit.html',
        ctx
    )

@has_role('staff')
def edit_patient(request, customer_id):
    patient = get_object_or_404(Patient, customer=customer_id)

    # allow only customer own store except for admin
    if not request.user.is_superuser:
        if patient.customer.store != request.store:
            return HttpResponseForbidden()

    ctx = {}
    redirect_to = reverse('jazzpos.views.view_customer', args=(customer_id,))
    initial = {
        'store': request.session['store_id'],
    }
    ctx['form'] = process_form(request, PatientForm, initial=initial, redirect_to=redirect_to, instance=patient)
    ctx['patient'] = patient
    return render_response(
        request,
        'patient_edit.html',
        ctx
    )

@has_role('staff')
def view_customer(request, customer_id):
    return list_detail.object_detail(
        request,
        queryset=Customer.objects.all(),
        object_id=customer_id,
        template_name='customer_detail.html',
        template_object_name='customer',
    )

def list_treatments(request, customer_id):
    ctx = {}
    patient = get_object_or_404(Patient, customer=customer_id)
    ctx['patient'] = patient
    ctx['treatments'] = patient.treatment_set.all().order_by('-id')
    return render_response(
        request,
        'treatment_list.html',
        ctx
    )

@has_role('staff')
def edit_treatment(request, treatment_id):
    treatment = get_object_or_404(Treatment, pk=treatment_id)

    # allow only customer own store except for admin
    if not request.user.is_superuser:
        if treatment.store != request.store:
            return HttpResponseForbidden()

    ctx = {}
    redirect_to = reverse('jazzpos.views.list_treatments', args=(treatment.patient.customer_id,))
    initial = {
        'store': request.session['store_id'],
    }
    ctx['form'] = process_form(request, TreatmentForm, initial=initial, redirect_to=redirect_to, instance=treatment)
    ctx['treatment'] = treatment
    ctx['patient'] = treatment.patient
    ctx['action'] = 'Edit'
    return render_response(
        request,
        'treatment_edit.html',
        ctx
    )

@has_role('staff')
def add_treatment(request, patient_id):
    patient = get_object_or_404(Patient, pk=patient_id)
    ctx = {}
    redirect_to = reverse('jazzpos.views.list_treatments', args=(patient.customer_id,))
    initial = {
        'store': request.session['store_id'],
        'patient': patient,
    }
    ctx['form'] = process_form(request, TreatmentForm, initial=initial, redirect_to=redirect_to)
    ctx['patient'] = patient
    ctx['action'] = 'Tambah'
    return render_response(
        request,
        'treatment_edit.html',
        ctx
    )

@has_role('staff')
def list_orders(request, customer_id):
    return xpos_views.list_orders(request, customer_id)

@has_role('staff')
def add_order(request, customer_id):
    return create_update.create_object(
        request,
        model=Order,
        post_save_redirect=reverse('jazzpos.views.list_customers'),
        template_name='customer_add.html',
    )

def switch_store(request, store_id=None):
    try:
        store_id = int(store_id)
    except:
        store_id = None

    if store_id is None:
        return render_response(
            request,
            'stores_switch.html',
        )

    store = get_object_or_404(Store, pk=store_id)
    redirect_to = request.GET.get('redirect_to', '/')
    request.session['store_id'] = store.id
    return redirect(redirect_to)

@has_role('staff')
def store_settings(request, object_id=None):
    if object_id:
        return create_update.update_object(
            request,
            form_class=StoreSettingsForm,
            object_id=object_id,
            post_save_redirect=reverse('jazzpos-store-settings'),
        )

    return list_detail.object_list(
        request,
        queryset=StoreSettings.objects.filter(store=request.store),
    )


class Solution:
    def threeSumMulti(self, arr: List[int], target: int) -> int:
        d = [0] * 300
        res = 0
        for i in range(len(arr)):
            res += d[target-arr[i]] if target-arr[i] >=0 else 0
            res %= (10**9+7)
            for j in range(i):
                d[arr[i] + arr[j]] += 1
        return res % (10**9+7)


import csv
from random import randint

data = []
with open("data.csv", 'r') as csvfile:
		reader = csv.reader(csvfile, delimiter=',')
		for row in reader:
			data.append({
				"firstname" : row[0],
				"lastname" : row[1],
				"gender" : row[2],
				"age" : row[3],
				"email" : row[4],
				"phone" : row[5],
				"address" : row[6] + ", " + row[7]
			})

print(data[randint(0, len(data)-1)])