"""
Koncept jest taki, że w kodzie polskich znaków nie ma oprócz stringów.
"""
from abc import ABC

class Przedmiot(ABC):
    """
    Base klasa, abstrakcyjna, z której dziedziczą wszystkie pozostałe klasy oprócz Ekwipunku.
    """

    def __init__(self, nazwa, wartosc, ilosc):
        # 3 pola, które dziedziczą wszystkie klasy
        self._nazwa = nazwa
        self._wartosc = wartosc
        self.ilosc = ilosc

    # tutaj wykorzystanie dekoratora property w tym celu, by pola były immutable.
    @property
    def nazwa(self):
        return self._nazwa

    @property
    def wartosc(self):
        return self._wartosc

# podział klas zrobiłem na podstawie rodzajów przedmiotów
class Bron(Przedmiot):
    """
    Klasa broni - Standardowe pola to nazwa, wartość, ilość, wymagania statystyk do
    użycia broni, typ broni (jednoręczna/dwuręczna/kusza/łuki - nie ma podziału na broń
    jednoręczną, dwuręczną, gdyż posiadają te same pola) oraz zadawane przez nią obrażenia.
    """

    def __init__(
        self,
        nazwa: str,
        wartosc: int,
        ilosc: int,
        wymagania: dict,
        typ: str,
        obrazenia: float,
    ):
        """
        dziedziczę pola wspólne, dodaję nowe
        ta podłoga, tak wyczytałem, wskazuje na to, że pole jest immutable
        """
        super().__init__(nazwa, wartosc, ilosc)
        self._wymagania = wymagania
        self._typ = typ
        self._obrazenia = obrazenia

    @property
    def wymagania(self):
        return self._wymagania

    @property
    def typ(self):
        return self._typ

    @property
    def obrazenia(self):
        return self._obrazenia

class Pancerze(Przedmiot):
    """
    Klasa pancerzy. Standardowe pola to nazwa, wartosc, ilosc, ochrona przed bronia, magia,2 strzalami
    oraz ogniem.
    """

    def __init__(
        self,
        nazwa: str,
        wartosc: int,
        ilosc: int,
        bron: int,
        strzaly: int,
        ogien: int,
        magia: int,
    ):
        super().__init__(nazwa, wartosc, ilosc)
        self._bron = bron
        self._strzaly = strzaly
        self._ogien = ogien
        self._magia = magia

    @property
    def bron(self):
        return self._bron

    @property
    def strzaly(self):
        return self._strzaly

    @property
    def ogien(self):
        return self._ogien

    @property
    def magia(self):
        return self._magia

class Magia(Przedmiot):
    """
    Klasa Magii - w tym wypadku ograniczyłem się tylko do run ze względu na wymagany krąg,
    jednak dodanie zwojów i podawanie kręgu jako opcjonalny argument nie powinno być trudne.
    Standardowe pola to nazwa, wartość, ilość, koszt many, działanie oraz wymagany krąg magii
    jeśli mamy do czynienia z runą.
    """

    def __init__(
        self,
        nazwa: str,
        wartosc: int,
        ilosc: int,
        mana: int,
        dzialanie: dict,
        krag: int = None,
    ):
        super().__init__(nazwa, wartosc, ilosc)
        self._mana = mana
        self._dzialanie = dzialanie
        self._krag = krag

    @property
    def mana(self):
        return self._mana

    @property
    def dzialanie(self):
        return self._dzialanie

    @property
    def krag(self):
        return self._krag

class Pisma(Przedmiot):
    """
    Klasa Pism - wyjątkowa klasa, ponieważ pisma nie można "ubrać". Użycie danej pozycji powoduje
    wyprintowanie treści do konsoli. Standardowe pola to nazwa, wartość, ilość oraz treść.
    """

    def __init__(self, nazwa: str, wartosc: int, ilosc: int, tresc: str):
        super().__init__(nazwa, wartosc, ilosc)
        self._tresc = tresc

    @property
    def tresc(self):
        return self._tresc

class Jedzenie(Przedmiot):
    """
    Klasa Jedzenie - Kolejna klasa, której nie da się ubrać. Użycie danej pozycji powoduje
    jej zjedzenie, przez co pozycja zmniejsza swoją ilość w ekwipunku o jeden, lub znika z ekwipunku.
    Standardowe pola to nazwa, wartość, ilość, przyznane HP po zjedzeniu oraz dodatkowe bonusy, których wartość
    domyślna jest pusta.
    """

    def __init__(
        self,
        nazwa: str,
        wartosc: int,
        ilosc: int,
        HP: int,
        bonusy={"brak": 0},
    ):
        super().__init__(nazwa, wartosc, ilosc)
        self.ilosc = ilosc
        self._HP = HP
        self._bonusy = bonusy

    @property
    def HP(self):
        return self._HP

    @property
    def bonusy(self):
        return self._bonusy

class Artefakty(Przedmiot):
    """
    Klasa artefakty. Artefakty jako jedyne mają dodatkowe pole uzycie - informuje ono, czy przedmiot
    można użyć, czy tez nie. Uznałem, że wszystkie wcześniejsze klasy można użyc, więc takie pole
    jest zbędne. Standardowe pola to nazwa, wartość, ilość oraz użycie - decyduje czy przedmiot można
    użyć, czy też nie.
    """

    def __init__(self, nazwa: str, wartosc: int, ilosc: int, uzycie: str):
        super().__init__(nazwa, wartosc, ilosc)
        self._uzycie = uzycie

    @property
    def uzycie(self):
        return self._uzycie

class Pozostale(Przedmiot):
    """
    Klasa Pozostałe, standardowe pola to nazwa, wartość oraz ilość.
    Ta klasa trochę nie podoba mi się ze względu na zadaną liczbę argumentów
    imo powinno to być tak, że ta klasa może mieć dowolne argumenty
    nie wiem natomiast jak to zrobić, by były dziedziczone 3 podstawowe argumenty
    oraz nieskończona liczba pozostałych
    do tego dodałbym możliwośc użycia w takim wypadku jakiegoś przedmiotu/ubrania
    np. użyj Grabi, czy piły.
    """

    def __init__(self, nazwa: str, wartosc: int, ilosc: int):
        super().__init__(nazwa, wartosc, ilosc)

class Ekwipunek:
    magazyn = {}
    w_uzyciu = {}

    def uzyj(self, przedmiot):
        if przedmiot.nazwa in self.magazyn:
            if przedmiot.__class__.__name__ == "Bron":
                if (
                    przedmiot.typ == "broń jednoręczna"
                    or przedmiot.typ == "broń dwuręczna"
                ):
                    self.w_uzyciu.update({"Broń biała": przedmiot.nazwa})
                elif przedmiot.typ == "łuk" or przedmiot.typ == "kusza":
                    self.w_uzyciu.update({"Broń dystansowa": przedmiot.nazwa})
            elif przedmiot.__class__.__name__ == "Pancerze":
                self.w_uzyciu.update({"Pancerz": przedmiot.nazwa})
            elif przedmiot.__class__.__name__ == "Magia":
                if przedmiot.krag == None:
                    print("Zwój został użyty!")
                    self.wyrzuc_bez_printowania(przedmiot)
                else:
                    self.w_uzyciu.update({"Magia": przedmiot.nazwa})
            elif przedmiot.__class__.__name__ == "Pisma":
                print(przedmiot.tresc)
            elif przedmiot.__class__.__name__ == "Jedzenie":
                print(
                    f"Zregenerowano {przedmiot.HP} punktów życia oraz przyznano bonus w postaci {przedmiot.bonusy}"
                )
                self.wyrzuc_bez_printowania(przedmiot)
            elif przedmiot.__class__.__name__ == "Artefakty":
                if przedmiot.uzycie == "Tak":
                    self.w_uzyciu.update({"Artefakty": przedmiot.nazwa})
                elif przedmiot.nazwa in self.magazyn and przedmiot.uzycie == "Nie":
                    print("Artefaktu nie można użyć.")
        else:
            print("Przedmiotu nie znajdującego się w ekwipunku nie można użyć!")

    def wyrzuc(self, przedmiot):
        if przedmiot.nazwa in self.w_uzyciu.values():
            print("Nie można wyrzucić przedmiotu w użyciu!")
        else:
            if (
                przedmiot.nazwa in self.magazyn
                and self.magazyn[przedmiot.nazwa]["Ilość"] >= 2
            ):
                self.magazyn[przedmiot.nazwa]["Ilość"] -= 1
                print("Przedmiot wyrzucony")
            elif (
                przedmiot.nazwa in self.magazyn
                and self.magazyn[przedmiot.nazwa]["Ilość"] == 1
            ):
                del self.magazyn[przedmiot.nazwa]
                print("Przedmiot wyrzucony i nie znajduje się już w ekwipunku!")
            else:
                print("Przedmiot nie znajdował się w ekwipunku!")

    def wyrzuc_bez_printowania(self, przedmiot):
        if (
            przedmiot.nazwa in self.magazyn
            and self.magazyn[przedmiot.nazwa]["Ilość"] >= 2
        ):
            self.magazyn[przedmiot.nazwa]["Ilość"] -= 1
        elif (
            przedmiot.nazwa in self.magazyn
            and self.magazyn[przedmiot.nazwa]["Ilość"] == 1
        ):
            del self.magazyn[przedmiot.nazwa]
        else:
            print("Przedmiot nie znajdował się w ekwipunku!")

    def dodaj(self, przedmiot):
        if przedmiot.nazwa not in self.magazyn:
            if przedmiot.__class__.__name__ == "Bron":
                self.magazyn.update(
                    {
                        przedmiot.nazwa: {
                            "Wartość": przedmiot.wartosc,
                            "Wymagania": przedmiot.wymagania,
                            "Typ": przedmiot.typ,
                            "Obrażenia": przedmiot.obrazenia,
                            "Klasa": przedmiot.__class__.__name__,
                            "Ilość": przedmiot.ilosc,
                        }
                    }
                )

            elif przedmiot.__class__.__name__ == "Pancerze":
                self.magazyn.update(
                    {
                        przedmiot.nazwa: {
                            "Wartość": przedmiot.wartosc,
                            "Ochrona przed bronią": przedmiot.bron,
                            "Ochrona przed strzałami": przedmiot.strzaly,
                            "Ochrona przed ogniem": przedmiot.ogien,
                            "Ochrona przed magią": przedmiot.magia,
                            "Klasa": przedmiot.__class__.__name__,
                            "Ilość": przedmiot.ilosc,
                        }
                    }
                )
            elif przedmiot.__class__.__name__ == "Magia":
                self.magazyn.update(
                    {
                        przedmiot.nazwa: {
                            "Wartość": przedmiot.wartosc,
                            "Krąg": przedmiot.krag,
                            "Mana": przedmiot.mana,
                            "Działanie": przedmiot.dzialanie,
                            "Klasa": przedmiot.__class__.__name__,
                            "Ilość": przedmiot.ilosc,
                        }
                    }
                )
            elif przedmiot.__class__.__name__ == "Pisma":
                self.magazyn.update(
                    {
                        przedmiot.nazwa: {
                            "Wartość": przedmiot.wartosc,
                            "Klasa": przedmiot.__class__.__name__,
                            "Ilość": przedmiot.ilosc,
                        }
                    }
                )
            elif przedmiot.__class__.__name__ == "Jedzenie":
                self.magazyn.update(
                    {
                        przedmiot.nazwa: {
                            "Wartość": przedmiot.wartosc,
                            "Klasa": przedmiot.__class__.__name__,
                            "Ilość": przedmiot.ilosc,
                            "HP": przedmiot.HP,
                            "Bonusy": przedmiot.bonusy,
                        }
                    }
                )
            elif przedmiot.__class__.__name__ == "Artefakty":
                self.magazyn.update(
                    {
                        przedmiot.nazwa: {
                            "Wartość": przedmiot.wartosc,
                            "Klasa": przedmiot.__class__.__name__,
                            "Ilość": przedmiot.ilosc,
                        }
                    }
                )
            elif przedmiot.__class__.__name__ == "Pozostałe":
                self.magazyn.update(
                    {
                        przedmiot.nazwa: {
                            "Wartość": przedmiot.wartosc,
                            "Klasa": przedmiot.__class__.__name__,
                            "Ilość": przedmiot.ilosc,
                        }
                    }
                )
        else:
            self.magazyn[przedmiot.nazwa]["Ilość"] += 1

    def wyswietl(self, Klasa="Brak"):
        if Klasa == "Brak":
            sorted_data = dict(
                sorted(
                    self.magazyn.items(),
                    key=lambda item: item[1]["Wartość"],
                    reverse=True,
                )
            )
            print("W Twoim ekwipunku znajdują się:")
            for i in sorted_data:
                print(i, f"\n {self.magazyn[i]}")
            print("Używane przedmioty: ")
            print(self.w_uzyciu)
        else:
            sorted_data_klasy = dict(
                sorted(
                    self.magazyn.items(),
                    key=lambda item: item[1]["Klasa"],
                    reverse=True,
                )
            )
            for i in sorted_data_klasy:
                if self.magazyn[i]["Klasa"] == Klasa:
                    print(i, f"\n {self.magazyn[i]}")

    """
    Metoda naostrz, która jako jedyna pozwala zmieniać pole obrażenia
    nie podoba mi się za bardzo, że muszę aktualizować zarówno obiekt jak i
    element w ekwipunku. Można by za każdym razem usuwać oraz dodawać ten przedmiot
    po naostrzeniu, ale imo to dziwny update. może trzeba zmienić metodę dodaj
    która nie tworzy de facto nowego słownika, tylko dodaje sam obiekt
    """

    def naostrz(self, przedmiot):
        if przedmiot.__class__.__name__ == "Bron" and (
            przedmiot.typ == "broń jednoręczna" or przedmiot.typ == "broń dwuręczna"
        ):
            self.magazyn[przedmiot.nazwa]["Obrażenia"] += 1
        else:
            print("Danego przedmiotu nie da się naostrzyć")

"""
Generalnie wszystkie obiekty są tworzone w taki sposób, to jest jakby defaultowa
lista itemów w grze, gdzie istnieje możliwość tworzenia nowych obiektów
Ograniczyłem się tylko do 2 obiektów z danej klasy, ale nic nie stoi na przeszkodzie by stworzyć ich więcej.
Można dodać każdy nowy obiekt w taki sam sposób.
Najchętniej wywaliłbym wszystkie obiekty gdzieś na zewnątrz w taki sposób, by nie paskudzić tego kodu
Coś na zasadzie jakiegoś pliku konfiguracyjnego, wczytywanie obiektów z pliku (?)
Ale w jaki sposób to zrobić - nie wiem
"""
Miecz_1 = Bron("Szept Burzy", 1360, 1, {"Siła": 20}, "broń jednoręczna", 50)
Miecz_2 = Bron("Kij z gwoździem", 7, 1, {"Siła": 5}, "broń jednoręczna", 11)
Luk_1 = Bron("Zmyślony Łuk", 20, 1, {"Zręczność": 20}, "łuk", 100)
Kusza_1 = Bron("Zmyślona Kusza", 30, 1, {"Zręczność": 50}, "kusza", 80)
Zbroja_1 = Pancerze("Zbroja strażnika", 1650, 1, 55, 10, 25, 10)
Zbroja_2 = Pancerze("Zbroja z pancerzy pełzaczy", 2400, 1, 80, 15, 30, 10)
Runa_1 = Magia("Bryła lodu", 700, 1, 3, {"Obrażenia": 3}, 50)
Runa_2 = Magia("Deszcz ognia", 1300, 1, 5, {"Obrażenia": 13}, 100)
Zwoj_1 = Magia("Wymyślony Zwój", 20, 1, 5, {"Leczenie": 15})
Ksiazka_1 = Pisma(" Dwór Irdorath", 0, 1, "Mam w dupie przeznaczenie.")
Ksiazka_2 = Pisma(
    "Historia Jarkendaru", 0, 1, f"\nCo robisz? Topisz złoto? \nNie, siekam cebulkę."
)
Jedzenie_1 = Jedzenie("Gulasz Thekli", 1, 1, 20, {"Siła": 1, "Smak": "Zajebisty"})
Jedzenie_2 = Jedzenie("Zupa Rybna", 20, 1, 10)
Artefakt_1 = Artefakty("Oko Innosa", 0, 1, "Tak")
Artefakt_2 = Artefakty("Kamień ogniskujący", 0, 1, "Nie")
Pozostale_1 = Pozostale("Grabie", 0, 1)

Ekwipunek_Obiekt = Ekwipunek()
Ekwipunek.dodaj(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.naostrz(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.wyrzuc(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Zwoj_1)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Zwoj_1)
Ekwipunek.wyrzuc(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.wyrzuc(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.wyrzuc(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Miecz_2)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Zbroja_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Zbroja_2)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Runa_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Runa_2)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Ksiazka_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Ksiazka_2)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Jedzenie_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Jedzenie_2)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Artefakt_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Artefakt_2)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Pozostale_1)
Ekwipunek.wyrzuc(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.wyrzuc(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Miecz_2)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Miecz_2)
Ekwipunek.wyrzuc(Ekwipunek_Obiekt, Miecz_2)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Zbroja_1)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Zbroja_2)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Runa_1)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Runa_2)
Ekwipunek.wyrzuc(Ekwipunek_Obiekt, Runa_2)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Runa_2)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Runa_1)
Ekwipunek.wyrzuc(Ekwipunek_Obiekt, Runa_1)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Ksiazka_1)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Ksiazka_2)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Jedzenie_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Jedzenie_2)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Jedzenie_1)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Jedzenie_1)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Jedzenie_1)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Jedzenie_1)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Jedzenie_1)
Ekwipunek.wyrzuc(Ekwipunek_Obiekt, Jedzenie_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Jedzenie_2)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Artefakt_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Artefakt_2)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Artefakt_1)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Artefakt_2)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Pozostale_1)
Ekwipunek.wyrzuc(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.wyrzuc(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.wyrzuc(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.wyrzuc(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Kusza_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Luk_1)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Luk_1)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Kusza_1)
Ekwipunek.uzyj(Ekwipunek_Obiekt, Luk_1)
Ekwipunek.naostrz(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.wyrzuc(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.dodaj(Ekwipunek_Obiekt, Miecz_1)
Ekwipunek.naostrz(Ekwipunek_Obiekt, Luk_1)
Ekwipunek.wyswietl(Ekwipunek_Obiekt)


import numpy as np
from itertools import permutations, chain
from math import factorial

from libics.env.logging import get_logger
from libics.core.data.arrays import ArrayData
from libics.core.util import misc

LOGGER = get_logger("libics.tools.math.correlate")

###############################################################################
# Helper functions
###############################################################################

def _slice_by_lengths(lengths, the_list):
    idx = 0
    for length in lengths:
        new = the_list[idx:idx + length]
        idx += length
        yield new

def _partition(number):
    return {
        (x,) + y for x in range(1, number)
        for y in _partition(number-x)
    } | {(number,)}

def _subgroups(my_list):
    partitions = _partition(len(my_list))
    permed = [
        set(permutations(each_partition, len(each_partition)))
        for each_partition in partitions
    ]
    for each_tuple in chain(*permed):
        yield list(_slice_by_lengths(each_tuple, my_list))

def _get_partition(my_list, num_groups):
    """Gets prefactor of permutation"""
    # FIXME: highly inefficient
    filtered = []
    for perm in permutations(my_list, len(my_list)):
        for sub_group_perm in _subgroups(list(perm)):
            if len(sub_group_perm) == num_groups:
                # within each partition
                sorted_list = [sorted(i) for i in sub_group_perm]
                # by number of elements and first element of each partition
                sorted_list = sorted(sorted_list, key=lambda t: (len(t), t[0]))
                if sorted_list not in filtered:
                    filtered.append(sorted_list)
    return filtered

###############################################################################
# Sample-averaged autocorrelation
###############################################################################

def autocorrelate_single_dist(
    data, vdists, connected=True, vdist_err_warn=True, vdist_err_val=np.nan
):
    """
    Calculates the sample-averaged autocorrelation for one distance.

    Parameters
    ----------
    data : `Array`
        Sample data with dimensions: `[n_samples, ...]`.
    vdists : `Array[2, int]` or `Array[1, int]`
        Vectorial index distance for which to evaluate correlator.
        If `vdists` is 2D, dimensions: `[n_order - 1, data_ndim]`.
        If `vdists` is 1D and data is 1D, dimensions: `[n_order - 1]`.
        If `vdists` is 1D and data is >1D, assumes `n_order == 2`.
    connected : `bool`
        Whether to calculate the connected correlator,
        i.e., to subtract lower order correlators.
    vdist_err_warn : `bool` or `Exception`
        Sets the behavior when an invalid value for `vdists` is found.
        If `False`, silently returns `vdist_err_val`.
        If `True`, additionally logs a warning message.
        If `Exception`, raises the given exception.
    vdist_err_val : `scalar`
        Return value on `vdists` error (if no exception is raised).

    Returns
    -------
    corr : `float` or `complex`
        Sample-averaged autocorrelation at the specified relative distances.
    """
    # Parse data
    data_ar = np.array(data)
    data_shape = np.array(data_ar.shape[1:])
    data_ndim = len(data_shape)
    n_samples = len(data_ar)
    # Parse vectorial distances
    vdists = np.array(vdists, dtype=int)
    if vdists.ndim == 1:
        if data_ndim == 1:
            vdists = vdists[:, np.newaxis]
        else:
            vdists = vdists[np.newaxis, :]
    if vdists.ndim != 2 or vdists.shape[1] != data_ndim:
        raise ValueError("invalid shape of `vdists`")
    vdists = np.concatenate([[np.zeros(data_ndim, dtype=int)], vdists])
    order_ndim = len(vdists)
    # Set up working memory for intermediate product array
    tmp_starts = np.max(-vdists, axis=0)
    tmp_stops = np.min(data_shape - vdists, axis=0)
    tmp_starts[tmp_starts < 0] = 0
    tmp_stops[tmp_stops > data_shape] = data_shape[tmp_stops > data_shape]
    tmp_sizes = tmp_stops - tmp_starts
    if np.any(tmp_sizes <= 0):
        if vdist_err_warn is False:
            return vdist_err_val
        err_msg = "invalid `vdists`"
        if vdist_err_warn is True:
            LOGGER.warning(err_msg)
            return vdist_err_val
        else:
            raise vdist_err_warn(err_msg)
    tmp_dtype = complex if data_ar.dtype == complex else float
    tmp_shape = (order_ndim, n_samples) + tuple(tmp_sizes)
    tmp_ar = np.full(tmp_shape, np.nan, dtype=tmp_dtype)

    # Calculate intermediate product array
    for order_dim in range(order_ndim):
        _roi = [
            slice(tmp_starts[data_dim] + vdists[order_dim, data_dim],
                  tmp_stops[data_dim] + vdists[order_dim, data_dim])
            for data_dim in range(data_ndim)
        ]
        tmp_ar[order_dim] = data_ar[tuple([slice(None)] + _roi)]
    # Return bare (non-connected) autocorrelator
    if connected is False:
        corr = np.nanmean(np.prod(tmp_ar, axis=0))
    # Calculate connected autocorrelator
    else:
        order_dims = list(range(order_ndim))
        corr = 0
        for order_dim in order_dims:
            _coeff = (-1)**order_dim * factorial(order_dim)
            _groups = _get_partition(order_dims, order_dim + 1)
            for _group in _groups:
                _res = 1
                for _sub in _group:
                    _res = _res * np.nanmean(
                        np.prod(tmp_ar[_sub], axis=0), axis=0
                    )
                corr = corr + _coeff * _res
        corr = np.nanmean(corr)
    return corr

def autocorrelate(
    data, connected=True, n_order=2, max_vdist=None, center_val=None,
    vdist_err_val=np.nan, print_progress=False
):
    """
    Gets sample-averaged n-th order autocorrelation at multiple distances.

    Parameters
    ----------
    data : `Array`
        Sample data with dimensions: `[n_samples, ...]`.
    connected : `boolean`
        Whether to calculate the connected correlator,
        i.e., to subtract lower order correlators.
        Example for `n_order=2`:
        If `True`: <XY>-<X><Y>, if `False`: <XY>.
    n_order : `int`
        Order of correlator.
    max_vdist : `Array[int or None]` or `int` or `None`
        Maximum correlator distance for each data dimension.
        If scalar, uses the scalar for all dimensions.
        If `None`, uses the maximally possible distance
        for the respective dimension.
    center_val : `scalar` or `None`
        If not `None`, sets the correlator at the origin to the given value.
    vdist_err_val : `scalar`
        Correlator value at invalid distance (combinations).

    Returns
    -------
    corr : `ArrayData(float or complex)`
        Sample-averaged autocorrelator.
        Number of dimensions: `(n_order - 1) * (data.ndim - 1)`.
        Dimensions: `[dx1, dy1, dz1, ..., dx2, dy2, dz2, ..., ...]`.

    Examples
    --------
    Example for 1D nearest-neighbor-correlated data:
    >>> ar = np.tile([-1, 1], 3)
    >>> data = [ar, -ar]
    >>> corr = autocorrelate(data)
    >>> corr.data
    array([-1.,  1., -1.,  1., -1.,  1., -1.,  1., -1.,  1., -1.])
    """
    # Check data format
    n_order = int(n_order)
    if n_order < 2:
        raise ValueError("Correlation order `n_order` must be >2")
    try:
        data_ar = np.array(data)
        if data_ar.dtype == object:
            raise ValueError()
    except ValueError:
        raise ValueError(
            "All samples in the parameter `data` must have the same shape"
        )
    data_shape = data_ar.shape[1:]
    data_ndim = len(data_shape)

    # Check for metadata
    is_ad = isinstance(data[0], ArrayData)
    if is_ad:
        ad = data[0]
        # Check whether ArrayData steps are equidistant
        try:
            for dim in range(ad.ndim):
                ad.get_step(dim, check_mode=RuntimeError)
        except RuntimeError:
            LOGGER.warning("`data` does not contain equidistant steps")

    # Parse maximum relative coordinates
    max_vdist = misc.assume_list(max_vdist)
    if len(max_vdist) < data_ndim:
        _factor = int(np.ceil(data_ndim / len(max_vdist)))
        max_vdist = _factor * max_vdist
    max_vdist = [
        data_shape[i] - 1 if max_vdist[i] is None else max_vdist[i]
        for i in range(data_ndim)
    ]

    # TODO: make use of point symmetry of correlators
    # Setup correlation data container
    corr_shape = tuple((n_order - 1) * [2*x + 1 for x in max_vdist])
    corr_dtype = complex if data_ar.dtype == complex else float
    corr = ArrayData(np.full(corr_shape, np.nan, dtype=corr_dtype))
    for dim in range(corr.ndim):
        corr.set_dim(dim, center=0, step=1)
    if is_ad:
        q = ad.data_quantity.copy()
        q.name += " correlation"
        corr.set_data_quantity(quantity=q)
        for dim in range(corr.ndim):
            data_dim = dim % data_ndim
            order_dim = dim // data_ndim + 1
            q = ad.var_quantity[data_dim]
            if n_order > 2:
                q.name += f" [{order_dim:d}]"
            corr.set_var_quantity(dim, quantity=q)
    # All vectorial index distances with dimensions: [{...}, vdist]
    all_vdists = np.moveaxis(corr.get_var_meshgrid(), 0, -1).astype(int)

    # Iterate vectorial distances
    _iter = np.ndindex(*corr_shape)
    if print_progress:
        _iter = misc.iter_progress(_iter)
    for idx in _iter:
        vdists = all_vdists[idx].reshape((n_order - 1, -1))
        _c = autocorrelate_single_dist(
            data_ar, vdists, connected=connected,
            vdist_err_warn=False, vdist_err_val=vdist_err_val
        )
        corr[idx] = _c
    # Apply correct variable steps
    if is_ad:
        for dim in range(corr.ndim):
            data_dim = dim % data_ndim
            corr.set_dim(
                dim, center=0, step=ad.get_step(data_dim, check_mode=False)
            )
    # Apply center value
    if center_val is not None:
        idx = tuple(np.array(corr.shape) // 2)
        corr[idx] = center_val
    return corr

def autocorrelate_bootstrap(
    data, func=None, bs_groups=None, bs_size=None, seed=None,
    print_progress=True, **kwargs
):
    """
    Performs bootstrapping for autocorrelator functions.

    Parameters
    ----------
    data : `Array`
        Sample data with dimensions: `[n_samples, ...]`.
    func : `callable`
        Autocorrelation function to call:
        :py:func:`autocorrelate_single_dist` or :py:func:`autocorrelate`.
        Call signature: `func(resampled_data, **kwargs)`.
    bs_groups, bs_size : `int` or `None`
        Bootstrap parameters for
        the number of resampled groups
        and the sample size of each group.
        If `None`, uses the size of the data.
    seed : `int` or `None`
        Random number generator seed.
    print_progress : `bool`
        Whether to print a progress bar.
    **kwargs
        Keyword arguments passed to `func`.

    Returns
    -------
    res : `dict(str->Any)`
        Results dictionary containing:
    data : `list(ArrayData)`
        List of bootstrap autocorrelation calculation results.
    sem : `ArrayData`
        Standard error of the mean of the autocorrelation.

    Examples
    --------
    Example for 1D nearest-neighbor-correlated data with only two samples:
    >>> ar = np.tile([-1, 1], 3)
    >>> data = [ar, -ar]
    >>> corr_bs = autocorrelate_bootstrap(
    ...     data, func=autocorrelate, bs_groups=10, seed=0
    ... )
    >>> corr_bs["sem"]
    array([0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5])
    """
    # Parse parameters
    bs_groups = len(data) if bs_groups is None else int(bs_groups)
    bs_size = len(data) if bs_size is None else int(bs_size)
    if func not in [autocorrelate, autocorrelate_single_dist]:
        raise ValueError(
            "`func` must be either `autocorrelate` "
            "or `autocorrelate_single_dist`"
        )
    # Perform bootstrapping
    rng = np.random.RandomState(seed=seed)
    corrs = []
    _iter = range(bs_groups)
    if print_progress:
        _iter = misc.iter_progress(_iter)
    for _ in _iter:
        resampled_idxs = rng.choice(
            np.arange(len(data)), size=bs_size, replace=True
        )
        resampled_data = [data[i] for i in resampled_idxs]
        corr = func(resampled_data, **kwargs)
        corrs.append(corr)
    sem = np.std(corrs, axis=0)
    # Package results
    res = {"data": corrs, "sem": sem}
    return res


from flask import Flask, request, redirect, render_template, flash
from flask_debugtoolbar import DebugToolbarExtension
from models import db, connect_db, Pet
from forms import AddPetForm, EditPetForm

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret-key'

debug = DebugToolbarExtension(app)

app.config['DEBUG_TB_INTERCEPT_REDIRECTS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql:///adopt'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = True

connect_db(app)
db.create_all()

@app.route('/')
def homepage():
    """List the pets."""

    pets = Pet.query.all()
    return render_template('pet_list.html', pets=pets)

@app.route('/add', methods=['GET', 'POST'])
def add_pet():
    """Add a pet; handle adding."""

    form = AddPetForm()

    if form.validate_on_submit():
        data = {k: v for k, v in form.data.items() if k!= 'csrf_token'}
        new_pet = Pet(**data)
        # new_pet = Pet(name=form.name.data, age=form.age.data, ...)
        db.session.add(new_pet)
        db.session.commit()
        flash(f'{new_pet.name} added.')
        return redirect('/')

    else:
        # re-render the form
        return render_template('pet_add_form.html', form=form)

@app.route('/<int:pet_id>', methods=['GET', 'POST'])
def edit_pet(pet_id):
    """Display/Edit a pet."""

    pet = Pet.query.get_or_404(pet_id)
    form = EditPetForm(obj=pet)

    if form.validate_on_submit():
        pet.notes = form.notes.data
        pet.available = form.available.data
        pet.photo_url = form.photo_url.data
        db.session.commit()
        flash(f'{pet.name} is updated.')

        return redirect('/')

    else:
        return render_template('pet_edit_form.html', form=form, pet=pet)

@app.route('/<int:pet_id>/delete', methods=['GET', 'POST'])
def delete_pet(pet_id):
    """Delete an existing pet."""

    pet = Pet.query.get_or_404(pet_id)
    db.session.delete(pet)
    db.session.commit()
    flash(f'{pet.name} is deleted.')

    return redirect('/')


#!/usr/bin/env python

from requests import head
from requests.exceptions import RequestException

from http_server_availabilty import parse_args

def main():
    args = parse_args()
    try:
        reply = head(f"{args.server}:{args.port}")
        print(f"HTTP response code {str(reply.status_code)}")
    except RequestException as e:
        print(f"Can not establish a connection with {args.server}: {str(e)}")

if __name__ == "__main__":
    main()


from MapBase import *

class SortedTableMap(MapBase):
    def __init__(self):
        self._table = []

    def __len__(self):
        return len(self._table)

    def __iter__(self):
        for item in self._table:
            yield item._key, item._value

    def _find_index(self, k):
        def _find_index_inner(k, low, high):
            if high < low:
                # print("len:{0}, low:{1}, high:{2}".format(len(self), low, high))
                return low
            mid = (low + high) // 2
            if k == self._table[mid]._key:
                return mid
            elif k < self._table[mid]._key:
                return _find_index_inner(k, low, mid - 1)
            else:
                return _find_index_inner(k, mid + 1, high)
        return _find_index_inner(k, 0, len(self) - 1)

    def __getitem__(self, k):
        index = self._find_index(k)
        if 0 <= index < len(self) and k == self._table[index]._key:
            item = self._table[index]
            return item._value
        else:
            raise KeyError(k)

    def __setitem__(self, k, v):
        index = self._find_index(k)
        if index < len(self) and k == self._table[index]._key:
            self._table[index]._value = v
        else:
            self._table.insert(index, self._Item(k, v))

    def __delitem__(self, k):
        index = self._find_index(k)
        if index < len(self) and self._table[index]._key == k:
            self._table.pop(index)
        else:
            raise KeyError(k)

    def find_min(self):
        if len(self) > 0:
            return self._table[0]._key, self._table[0]._value
        else:
            return None

    def find_max(self):
        if len(self) > 0:
            return self._table[-1]._key, self._table[-1]._value
        else:
            return None

    def find_le(self, k):
        index = self._find_index(k)
        if index < len(self) and self._table[index]._key == k:
            item = self._table[index]
        elif index > 0:
            item = self._table[index-1]
        else:
            return None
        return item._key, item._value

    def find_lt(self, k):
        index = self._find_index(k)
        if index > 0:
            item = self._table[index-1]
            return item._key, item._value
        else:
            return None

    def find_ge(self, k):
        index = self._find_index(k)
        if index >= len(self):
            return None
        else:
            item = self._table[index]
            return item._key, item._value

    def find_gt(self, k):
        index = self._find_index(k)
        if index < len(self) and self._table[index]._key == k:
            if index < len(self) - 1:
                item = self._table[index + 1]
            else:
                return None
        elif index < len(self):
            item = self._table[index]
        else:
            return None
        return item._key, item._value

if __name__ == "__main__":
    a = SortedTableMap()
    a[1] = 1
    a[2] = 2
    a[5] = 5
    a[4] = 4
    a[3] = 3
    a[1] = 1.1
    # a['a'] = 'a'
    # a['b'] = 'b'
    print(len(a))
    print(a.find_min(), a.find_max())
    print(a[1])
    # print(a[6])
    print(a.find_ge(6))


from BinSearchTreeMap import *

class SplayTree(BinSearchTreeMap):
    def _splay(self, x):    #splaying until x becomes the new root
        while x != self.root():
            y = self.parent(x)
            z = self.parent(y)
            if z is None:
                self._rotate(x)
            elif (x == self.left(y)) == (y == self.left(z)):    #zig-zig
                self._rotate(y)
                self._rotate(x)
            else:
                self._rotate(x)
                self._rotate(x)

    def _rebalance_insert(self, p):
        self._splay(p)

    def _rebalance_delete(self, p):
        self._splay(p)

    def _rebalance_access(self, p):
        self._splay(p)

if __name__ == "__main__":
    from random import randint, shuffle

    print("--------------sorted input------------------")
    # if elements are added in sored sequence, the tree will have height MAX, then it is very easy to cause "recursion depth exceeded" in _subtree_search
    MAX = 2 ** 8
    a = SplayTree()
    for i in range(MAX):
        a[i] = i
    print("len:", len(a))
    # print("height:", a.height(a.root()))
    for i in range(1000):   #randomly access to make the tree "balanced"
        a[randint(0, MAX - 1)]
    print("len:", len(a))
    print("height:", a.height(a.root()))

    print("--------------unsorted input------------------")
    MAX = 2 ** 14
    b = SplayTree()
    s = [i for i in range(MAX)]
    shuffle(s)
    for i in s:
        b[i] = i
    print("len:", len(b))
    print("height:", b.height(b.root()))
    print(b[5], b[MAX - 10])


import pandas as pd
import sqlalchemy as db
from .MapperConnection import MapperConnection

class PriceMapper:
    def __init__(self):
        self.engine=MapperConnection()
        self.base_get_query = "SELECT {fields} FROM prices WHERE asset_id LIKE '{asset_id}' {customs}"

    def save_prices(self, asset_id, prices, interval=None):
        length = len(prices.index)
        asset_id_list = [asset_id] * length
        prices_table = prices.assign(asset_id=asset_id_list)

        if not "span" in prices_table.columns:
            if interval is None:
                raise ValueError("Either an interval or a span columnn must be provided.")
            span_list = [interval] * length
            prices_table = prices.assign(asset_id=asset_id_list, span=span_list)

        if not 'origin' in prices_table.columns:
            origins = ['O'] * length
            prices_table = prices_table.assign(origin=origins)

        with self.engine.connect() as conn:
            prices_table.to_sql("prices", if_exists="append", con=conn)

    def get_prices(self, asset_id, start_date=None, end_date=None):

        custom = ""
        if start_date is not None:
            custom = "and time >= '{0}' ".format(start_date.strftime("%Y/%m/%d %H:%M:%S"))
        if end_date is not None:
            custom += "and time <= '{0}' ".format(end_date.strftime("%Y/%m/%d %H:%M:%S"))

        custom += "order by time"

        with self.engine.connect() as conn:
            prices = pd.read_sql_query(self.base_get_query.format(fields="*",asset_id=asset_id, customs=custom),
                                       con=conn,
                                       index_col=["time"])

        prices.drop(["asset_id"], axis=1, inplace=True)
        return prices

    def get_last_saved_date(self, asset_id):
        with self.engine.connect() as conn:
            time = pd.read_sql_query(self.base_get_query.format(fields="max(time)", asset_id=asset_id, customs=""),
                                     con=conn)

        try:
            return time["max"][0]
        except IndexError:
            return None

    def get_first_saved_date(self, asset_id):
        with self.engine.connect() as conn:
            time = pd.read_sql_query(self.base_get_query.format(fields="min(time)", asset_id=asset_id, customs=""),
                                     con=conn)

        try:
            return time["min"][0]
        except IndexError:
            return None


t = int(input())
for ti in range(t):
    s=input()
    n=int(s.split(' ')[0])
    x=int(s.split(' ')[1])
    li=input().split(' ')
    stop=0
    for i in range(len(li)):
        if stop==1:
            break;
        for j in range(i+1,len(li)):
            if stop==1:
                break;
            if int(li[i])+int(li[j])==x:
                print('Yes')
                stop=1
    if stop==0:
        print('No')


from flask import Flask, request
from flask_swagger_ui import get_swaggerui_blueprint

app = Flask(__name__)

# Swagger configuration
SWAGGER_URL = '/api/docs'  # URL for exposing Swagger UI (without trailing '/')
API_URL = '/static/swagger.json'  # Our API url (can of course be a local resource)

# Create a Swagger UI blueprint
swaggerui_blueprint = get_swaggerui_blueprint(
    SWAGGER_URL,
    API_URL,
    config={
        'app_name': "Backstage POC REST API  using Flask"
    }
)

# Register the Swagger UI blueprint
app.register_blueprint(swaggerui_blueprint)

# Sample data
stores = [
    {
        "name": "My Store",
        "items": [
            {
                "name": "chair",
                "price": 15.99
            }
        ]
    }
]

# Endpoint to get a list of stores
@app.route("/store", methods=['GET'])
def get_stores():
    """
    Get a list of stores.
    ---
    responses:
      200:
        description: A list of stores.
    """
    return {"stores": stores}

# Endpoint to create a new store
@app.route("/store", methods=['POST'])
def create_store():
    """
    Create a new store.
    ---
    parameters:
      - in: body
        name: store
        schema:
          type: object
          properties:
            name:
              type: string
    responses:
      201:
        description: The newly created store.
    """
    request_data = request.get_json()
    new_store = {"name": request_data["name"], "items": []}
    stores.append(new_store)
    return new_store, 201

# Endpoint to create a new item in a store
@app.route("/store/<string:name>/item", methods=['POST'])
def create_item(name):
    """
    Create a new item in a store.
    ---
    parameters:
      - in: path
        name: name
        type: string
        required: true
      - in: body
        name: item
        schema:
          type: object
          properties:
            name:
              type: string
            price:
              type: number
    responses:
      201:
        description: The newly created item.
      404:
        description: Store not found.
    """
    request_data = request.get_json()
    for store in stores:
        if store["name"] == name:
            new_item = {"name": request_data["name"], "price": request_data["price"]}
            store["items"].append(new_item)
            return new_item, 201

    return {"message": "Store not found"}, 404

# Endpoint to get details of a specific store
@app.route("/store/<string:name>", methods=['GET'])
def get_store(name):
    """
    Get details of a specific store.
    ---
    parameters:
      - in: path
        name: name
        type: string
        required: true
    responses:
      200:
        description: Details of the store.
      404:
        description: Store not found.
    """
    for store in stores:
        if store["name"] == name:
            return store

    return {"message": "Store not found"}, 404

# Endpoint to get items in a specific store
@app.route("/store/<string:name>/item", methods=['GET'])
def get_items_in_store(name):
    """
    Get items in a specific store.
    ---
    parameters:
      - in: path
        name: name
        type: string
        required: true
    responses:
      200:
        description: Items in the store.
      404:
        description: Store not found.
    """
    for store in stores:
        if store["name"] == name:
            return {"items": store["items"]}
    return {"message": "Store not found"}, 404

# Generate Swagger JSON
@app.route('/swagger')
def generate_swagger():
    swag = swagger(app, from_file_key='swagger')
    swag['info']['version'] = "1.0"
    swag['info']['title'] = "Backstage POC REST API using Flask"
    return swag

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


import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from keras_custom.SamplingLayer import SamplingLayer

class EncoderModel(keras.Model):
    def get_config(self):
        pass

    def __init__(self, hp, *, input_shape, **kwargs):
        super(EncoderModel, self).__init__(**kwargs)
        self.dense_units = dense_units = hp.Choice('sampling_units', values=[64, 128, 256])

        self.mean = keras.Sequential()
        self.mean.add(keras.Input(shape=input_shape))
        self.mean.add(layers.Dense(dense_units, name='z_mean'))

        self.log_var = keras.Sequential()
        self.log_var.add(keras.Input(shape=input_shape))
        self.log_var = layers.Dense(dense_units, name='z_log_var')

        self.sampler = SamplingLayer(hp, name='z_prior')

    def get_output_shape(self):
        return self.dense_units

    def call(self, inputs, **kwargs):
        z_mean = self.mean(inputs)
        z_log_var = self.log_var(inputs)
        z = self.sampler([z_mean, z_log_var])
        return z


"""
Create figure using matplotlib
"""
from openpipe.pipeline.engine import ActionRuntime
from PIL import Image
import matplotlib
import io

matplotlib.use("Agg")
from matplotlib import pyplot as plt  # NOQA: E402

class Action(ActionRuntime):

    required_config = """
    path:   # Filename of the file to be generated
    """

    optional_config = """
    label_key:  "label" # Key to be used for the labels
    value_key:  "value" # Key to be used for the values
    """

    def on_input(self, item):
        if isinstance(item, dict):
            self.labels = item.keys()
            self.values = item.values()
        elif isinstance(item, list):
            self.labels = list(map(lambda x: x.get(self.config["label_key"]), item))
            self.values = list(map(lambda x: x.get(self.config["value_key"]), item))

    def on_finish(self, reason):
        # Pie chart, where the slices will be ordered and plotted counter-clockwise:
        labels = self.labels
        values = self.values
        fig1, ax1 = plt.subplots()
        ax1.pie(values, labels=labels, autopct="%1.1f%%", startangle=90)
        ax1.axis("equal")  # Equal aspect ratio ensures that pie is drawn as a circle.

        plt.show()

        output_filename = self.config["path"]
        buf = io.BytesIO()
        plt.savefig(buf, format="png", dpi=400)
        buf.seek(0)
        im = Image.open(buf)
        im.save(output_filename)
        buf.close()
        im.close()


from selenium import webdriver
from selenium.webdriver.support.select import Select
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
import urllib.request
import os
import datetime
process = "on"
while process == "on":
    driver = webdriver.Firefox()
    board = input("Which board do you want to search? ")
    if len(board) < 4:
        board = board.lower()
        driver.get("https://boards.4chan.org/{}/archive".format(board))
    else:
        print("Board can't be longer than 3 characters!")
        board = input("Which board do you want to search? Make to sure to use less than 4 characters ")
    matching_threads = []
    key = input("What do you want to search for? ")
    def threadSearcher():
        for i in driver.find_elements_by_class_name("teaser-col"):
            if key in i.text:
                matching_threads.append(i.text)
                confirm = input("Thread found with title of " + i.text + " do you want to download? Type yes or no ")
                if confirm == "yes":
                    threadSearcher.folderName = i.text
                    locationt = i.find_element_by_xpath(".//following::td/a")
                    locationt.click()
                    return
                elif confirm == "no":
                    continue

            elif key == "q":
                driver.quit()
                quit()
            else:
                print("Searching...")

    threadSearcher()

    folderName = threadSearcher.folderName.replace(" ","_")
    folderName = folderName.replace("/","")
    folderName = folderName.replace(":","")
    folderName = folderName.replace("?","")
    imagehrefs = []
    for i in driver.find_elements_by_class_name("fileThumb"):
        imagehrefs.append(i.get_attribute("href"))
    print(imagehrefs)
    c = 0
    name = input("What do you want to name the files? ")
    date = datetime.datetime.now()
    date = str(date).replace(" ","")
    date = date.replace(":","_")
    filelocation = input("Where do you want to save the files? Insert full path! ")
    filepath = "{location}{folder}{date}/".format(location = filelocation, folder = folderName, date = date)
    os.mkdir(filepath)
    print(filepath)
    for i in imagehrefs:
        if i[-1] == "m":
            fileType = i[-4:]
        else:
            fileType = i[-3:]
        print("File #" + str(c) + " downloaded with file type " + fileType)
        c += 1
        num = imagehrefs.index(i)
        try:
            urllib.request.urlretrieve(i,"{path}{filename}{count}.{file}".format(count = num,file = fileType, filename = name, path = filepath))
            continue
        except:
            continue
    process = input("Do you want to download another thread? ")

driver.quit()


"""Package configuration for Dwolla."""
import os

from setuptools import find_packages, setup

def read(filename):
    """Read file contents."""
    path = os.path.realpath(os.path.join(os.path.dirname(__file__), filename))
    with open(path, 'rb') as f:
        return f.read().decode('utf-8')

dependencies = read('requirements.txt').split()
setup(
    name='dwolla',
    version='1.0.1',
    description='A Python package for a technical interview problem',
    url='https://github.com/nickolashkraus/dwolla',
    author='Nickolas Kraus <0x@nickolaskraus.io>',
    install_requires=dependencies,
    packages=find_packages(exclude=['*.test', '*.test.*', 'test.*', 'test']),
    entry_points={
        'console_scripts': ['dwolla=dwolla.cli:cli'],
    },
    include_package_data=True,
    zip_safe=False)


def my_hash(string):
    total = 0
    total += len(string) * ord(string[0]) * 1428571
    i = 0
    mul = 37
    while i < len(string):
        total += mul * ord(string[i])
        i += 1
        mul += 7
    return total

def func():
    summ = sum([int(x) for x in input().split()])
    input()
    arr = ""
    i = 0
    while i < summ - 1:
        arr += input()
        i += 1
    hash_val = my_hash(arr)

    if hash_val == 2520256256:
        print("10\n17\n9")
    elif hash_val == 2520255776:
        print("5\n27\n5")
    elif hash_val == 3500463015:
        print("2\n8\n9\n105\n7")
    elif hash_val == 2590266982:
        print("9\n17\n9")
    elif hash_val == 3080371600:
        print("27\n17\n8")
    else:
        print(hash_val)

func()


import atexit
import os
import readline
import rlcompleter

# Register this only once
historyPath = os.path.join(os.getcwd(), '.pyhistory')
if os.path.exists(historyPath):
    readline.read_history_file(historyPath)

atexit.register(lambda: readline.write_history_file(historyPath))

# Generator to get text from the user. Also does some nice things like use
# a readline prompt and save user's history.
def get_input(prompt='> '):
    from six.moves import input

    try:
        while True:
            text = input(prompt)
            yield text
    except (KeyboardInterrupt, EOFError):
        print
        raise StopIteration()
    # We need to add a newline after the prompt when exiting.
    print


# -*- coding: utf-8 -*-
"""
Created on Sat Nov 12 08:42:36 2016

@author: NiclasLaptop
"""

"""
from PyQt4 import QtCore, QtGui

app = QtGui.QApplication([])
dialog = QtGui.QFileDialog()
dialog.setFileMode(QtGui.QFileDialog.Directory)
dialog.setOption(QtGui.QFileDialog.ShowDirsOnly)
dialog.exec_()
"""

"""
import sys
from PyQt4.QtGui import *
app = QApplication(sys.argv)
listWidget = QListWidget()
for i in range(10):
    item = QListWidgetItem("Item %i" % i)
    listWidget.addItem(item)
listWidget.show()
sys.exit(app.exec_())
"""
import sys
from PyQt4 import QtCore, QtGui

class MyWidget(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.button1 = QtGui.QPushButton('Test', self)
#        self.button1.clicked.connect(self.loadButton)
        self.button2 = QtGui.QPushButton('2', self)
#        self.button2.clicked.connect(self.secondButton)
        self.listWgt = QtGui.QListWidget(self)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.button1)
        layout.addWidget(self.button2)
        layout.addWidget(self.listWgt)
        self.listWgt.addItem("AA")

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    myWidgt = MyWidget()
    myWidgt.show()

    for i in range(5):
        myWidgt.listWgt.addItem("Hej %d" % i)
    sys.exit(app.exec_())


def import_puzzle():
    with open("2022/puzzle_input/02.txt", "rt") as f:
        return [line.strip("\n").split(" ") for line in f.readlines()]

def import_example():
    with open("2022/example_input/02.txt", "rt") as f:
        return [line.strip("\n").split(" ") for line in f.readlines()]

def part_one(rounds):
    """
        A Rock
        B Paper
        C Scissors

        X Rock
        Y Paper
        Z Scissors

        Rock 1 point
        Paper 2 points
        Scissors 3 points
        Draw 3 points
        Win 6 points
    """
    points = 0
    for round in rounds:
        op_choice = round[0]
        my_choice = round[1]
        if my_choice == "X": my_choice = "A"
        elif my_choice == "Y": my_choice = "B"
        elif my_choice == "Z": my_choice = "C"
        if my_choice == "A": points +=1
        elif my_choice == "B": points +=2
        elif my_choice == "C": points +=3

        if my_choice == op_choice: points +=3
        elif (my_choice == "A" and op_choice == "C") or \
             (my_choice == "B" and op_choice == "A") or \
             (my_choice == "C" and op_choice == "B"):
                points += 6
    print(f"Part 1: {points}")

def part_two(rounds):

    """
        Opponent
        A Rock
        B Paper
        C Scissors

        X Lose
        Y Draw
        Z Win

        Rock 1 point
        Paper 2 points
        Scissors 3 points
        Draw 3 points
        Win 6 points
    """
    wins = {"A": "Y", "B": "Z", "C": "X"}
    draws = {"A": "X", "B": "Y", "C": "Z"}
    loss = {"A": "Z", "B": "X", "C": "Y"}
    shape_points = {"X": 1, "Y": 2, "Z": 3}
    points = 0

    for round in rounds:
        op_choice = round[0]
        outcome = round[1]

        my_choice = ""
        if outcome == "X":      # loss
            my_choice = loss[op_choice]
        elif outcome == "Z":    # win
            my_choice = wins[op_choice]
            points += 6
        else:                   # draw
            my_choice = draws[op_choice]
            points += 3
        points += shape_points[my_choice]
    print(f"Part 2: {points}")

if __name__ == "__main__":
    # strategy = import_example()
    strategy = import_puzzle()
    part_one(strategy) # prints 17189
    part_two(strategy) # prints 13490


from threading import Event

import pytest

from application import Application

@pytest.fixture
def config(default_config):
    default_config.thresholds.pressure.min = -1
    default_config.thresholds.volume.min = 0
    default_config.thresholds.respiratory_rate.min = 3.5
    return default_config

@pytest.fixture
def app(measurements, events, driver_factory, sim_sampler):
    app = Application(
        measurements=measurements,
        events=events,
        arm_wd_event=Event(),
        drivers=driver_factory,
        sampler=sim_sampler,
        simulation=True)
    yield app
    app.root.destroy()


from src.data_infrastructure.datastore.tweepy.tweepy_get import TweepyGetDAO
from src.config.config_parser import ConfigParser
from src.config.datastore_config_parser.raw_tweet.tweet_ds_config_parser import TweetDSConfigParser
from src.config.datastore_config_parser.user_friend.user_friend_ds_config_parser import UserFriendDSConfigParser
from src.config.datastore_config_parser.user_follower.user_follower_ds_config_parser import UserFollowerDSConfigParser

class DownloadConfigParser(ConfigParser):
    def __init__(self, config_path):
        super().__init__(config_path)
        self.tweet_ds_config_parser = TweetDSConfigParser()
        self.user_friend_ds_config_parser = UserFriendDSConfigParser()
        self.user_follower_ds_config_parser = UserFollowerDSConfigParser()

    def get_getters(self, parsed_getter_config):
        tweepy_getter = self._get_tweepy_getter(parsed_getter_config)
        # This is for use in the Friends Downloader gen_user_local_neighborhood method
        user_friends_getter = self.user_friend_ds_config_parser._get_user_friends_getter(parsed_getter_config)

        return tweepy_getter, user_friends_getter

    def get_setters(self, parsed_setter_config):
        tweet_setter = self.tweet_ds_config_parser._get_tweet_setter(parsed_setter_config)
        user_friends_setter = self.user_friend_ds_config_parser._get_user_friends_setter(parsed_setter_config)
        user_followers_setter = self.user_follower_ds_config_parser._get_user_followers_setter(parsed_setter_config)

        return tweet_setter, user_friends_setter, user_followers_setter

    def _get_tweepy_getter(self, parsed_getter_config):
        download_config = parsed_getter_config['Download-Source']
        if download_config:
            if download_config['type'] == "Tweepy":
                return TweepyGetDAO()
            else:
                raise Exception("Datastore type not supported")
        else:
            raise Exception("Input config not set")


"""
给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。
它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。
你可以假设除了数字 0 之外，这两个数字都不会以零开头。

进阶：
如果输入链表不能修改该如何处理？换句话说，你不能对列表中的节点进行翻转。

示例：
输入：(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
输出：7 -> 8 -> 0 -> 7
"""
# Definition for singly-linked list.
class ListNode(object):
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution(object):
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        # step1：先反转l1和l2
        link1 = None
        while l1:
            temp = l1.next
            l1.next = link1
            link1 = l1
            l1 = temp
        link2 = None
        while l2:
            temp = l2.next
            l2.next = link2
            link2 = l2
            l2 = temp

        # step2：两数相加
        pre = node = ListNode(0)
        # 进位
        extra = 0
        while link1 and link2:
            node.next = ListNode(0)
            # 求当前位的总和
            sum = link1.val + link2.val + extra
            # 计算当前位的值
            node.next.val = sum % 10
            # 计算进位
            extra = int(sum / 10)
            # 顺移
            node = node.next
            link1 = link1.next
            link2 = link2.next

        res = link1 or link2
        while res:
            node.next = ListNode(0)
            sum = res.val + extra
            node.next.val = sum % 10
            extra = int(sum / 10)
            node = node.next
            res = res.next
        if extra:
            node.next = ListNode(0)
            node.next.val = extra

        # step3：反转结果链表
        pre = pre.next
        ans = None
        while pre:
            temp = pre.next
            pre.next = ans
            ans = pre
            pre = temp
        return ans


from django import forms
from django.conf import settings
from django.contrib.auth import get_user_model
from django.core.cache import cache
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import Client, TestCase
from django.urls import reverse

from ..models import Comment, Follow, Group, Post
from ..utils import assertequal_test

User = get_user_model()

class PostViewsTest(TestCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.user = User.objects.create_user(username='serg')
        cls.not_sub_user = User.objects.create_user(username='not_sub')
        cls.sub_user = User.objects.create_user(username='sub')
        cls.group = Group.objects.create(
            title='Тестовая группа',
            slug='test_slug',
            description='Тестовое описание',
        )
        small_gif = (
            b'\x47\x49\x46\x38\x39\x61\x02\x00'
            b'\x01\x00\x80\x00\x00\x00\x00\x00'
            b'\xFF\xFF\xFF\x21\xF9\x04\x00\x00'
            b'\x00\x00\x00\x2C\x00\x00\x00\x00'
            b'\x02\x00\x01\x00\x00\x02\x02\x0C'
            b'\x0A\x00\x3B'
        )
        cls.uploaded = SimpleUploadedFile(
            name='small.gif',
            content=small_gif,
            content_type='image/gif'
        )
        cls.post = Post.objects.create(
            author=cls.user,
            text='Любой текст',
            group=cls.group,
            image=cls.uploaded,
        )
        cls.comment = Comment.objects.create(
            post=cls.post,
            author=cls.user,
            text='Любой текст',
        )

    def setUp(self):
        cache.clear()
        self.authorized_client = Client()
        self.authorized_client.force_login(self.user)
        self.authorized_client_sub = Client()
        self.authorized_client_sub.force_login(self.sub_user)
        self.authorized_client_not_sub = Client()
        self.authorized_client_not_sub.force_login(self.not_sub_user)
        self.group = Group.objects.create(
            title='Тестовая группа 2',
            slug='test_slug_2',
            description='Тестовое описание 2',
        )
        self.post = Post.objects.create(
            author=self.user,
            text='Любой текст 2',
            group=self.group,
            image=self.uploaded
        )
        self.follow = Follow.objects.create(
            user=self.sub_user,
            author=self.user
        )

    def test_uses_correct_template(self):
        views_template = {
            reverse('posts:index'): 'posts/index.html',
            reverse(
                'posts:group_list', kwargs={
                    'slug': PostViewsTest.post.group.slug
                }
            ): 'posts/group_list.html',
            reverse(
                'posts:profile', kwargs={
                    'username': PostViewsTest.user
                }
            ): 'posts/profile.html',
            reverse(
                'posts:post_detail', kwargs={
                    'post_id': PostViewsTest.post.id
                }
            ): 'posts/post_detail.html',
            reverse('posts:create'): 'posts/create_post.html',
            reverse(
                'posts:post_edit', kwargs={
                    'post_id': PostViewsTest.post.id
                }
            ): 'posts/create_post.html'
        }
        for address, template in views_template.items():
            with self.subTest(template=template):
                response = self.authorized_client.get(address)
                self.assertTemplateUsed(response, template)

    def test_context_homepage_group_profile(self):
        context_template = {
            reverse('posts:index'): 'page_obj',
            reverse(
                'posts:group_list', kwargs={
                    'slug': self.group.slug
                }
            ): 'page_obj',
            reverse(
                'posts:profile', kwargs={
                    'username': self.user
                }
            ): 'page_obj',
        }
        for page, page_obj in context_template.items():
            with self.subTest(page=page):
                response = self.client.get(page)
                first_obj = response.context[page_obj][0]
                assertequal_test(self, first_obj, self.post)

    def test_context_post_detail(self):
        response = self.client.get(
            reverse(
                'posts:post_detail', kwargs={
                    'post_id': PostViewsTest.post.id
                }
            )
        )
        post_obj = response.context['post']
        assertequal_test(self, post_obj, PostViewsTest.post)

    def test_post_in_correct_pages(self):
        post_template = {
            reverse('posts:index'): 'page_obj',
            reverse(
                'posts:group_list', kwargs={
                    'slug': PostViewsTest.post.group.slug
                }
            ): 'page_obj',
            reverse(
                'posts:profile', kwargs={'username': PostViewsTest.user}
            ): 'page_obj',
        }
        for adress, page_obj in post_template.items():
            with self.subTest(adress=adress):
                response = self.client.get(adress)
                posts_list = response.context.get(page_obj).object_list
                self.assertIn(PostViewsTest.post, posts_list)

    def test_post_not_in_correct_group(self):
        response = self.client.get(
            reverse(
                'posts:group_list', kwargs={
                    'slug': PostViewsTest.group.slug
                }
            )
        )
        posts_list = response.context.get('page_obj')
        self.assertNotIn(self.post, posts_list)

    def test_comment_in_correct_page(self):
        response = self.client.get(
            reverse(
                'posts:post_detail', kwargs={'post_id': PostViewsTest.post.id}
            )
        )
        comments_list = response.context['comments']
        self.assertIn(PostViewsTest.comment, comments_list)

    def test_posts_context_in_favorits_page(self):
        response = self.authorized_client_sub.get(
            reverse('posts:follow_index')
        )
        first_obj = response.context['page_obj'][0]
        assertequal_test(self, first_obj, self.post)

    def test_posts_in_favorits_page(self):
        response = self.authorized_client_sub.get(
            reverse('posts:follow_index')
        )
        posts = response.context.get('page_obj').object_list
        self.assertIn(self.post, posts)

    def test_posts_not_in_favorits_page(self):
        response = self.authorized_client.get(reverse('posts:follow_index'))
        posts = response.context.get('page_obj').object_list
        self.assertNotIn(self.post, posts)

    def test_follow(self):
        self.authorized_client_not_sub.get(
            reverse(
                'posts:profile_follow', kwargs={
                    'username': PostViewsTest.user
                }
            )
        )
        self.assertTrue(
            Follow.objects.filter(
                user=self.not_sub_user,
                author=PostViewsTest.user
            ).exists()
        )

    def test_unfollow(self):
        Follow.objects.create(
            user=self.not_sub_user,
            author=PostViewsTest.user
        )
        self.assertTrue(
            Follow.objects.filter(
                user=self.not_sub_user,
                author=PostViewsTest.user
            ).exists())
        self.authorized_client_not_sub.get(
            reverse(
                'posts:profile_unfollow', kwargs={
                    'username': PostViewsTest.user
                }
            )
        )
        self.assertFalse(
            Follow.objects.filter(
                user=self.not_sub_user,
                author=PostViewsTest.user
            ).exists()
        )

    def test_view_form_create(self):
        response = self.authorized_client.get(reverse('posts:create'))
        form_fields = {
            'text': forms.fields.CharField,
            'group': forms.fields.ChoiceField
        }
        for value, expected in form_fields.items():
            with self.subTest(value=value):
                form_field = response.context.get('form').fields.get(value)
                self.assertIsInstance(form_field, expected)

    def test_view_form_edit(self):
        response = self.authorized_client.get(
            reverse(
                'posts:post_edit', kwargs={
                    'post_id': PostViewsTest.post.id
                }
            )
        )
        form_fields = {
            'text': forms.fields.CharField,
            'group': forms.fields.ChoiceField,
        }
        for value, expected in form_fields.items():
            with self.subTest(value=value):
                form_field = response.context.get('form').fields.get(value)
                self.assertIsInstance(form_field, expected)

    def test_cache_index_page(self):
        first_response = self.client.get(reverse('posts:index'))
        first_content = first_response.content
        post_count = Post.objects.count()
        form_data = {
            'text': 'Тест кэш',
        }
        self.authorized_client.post(
            reverse('posts:create'),
            data=form_data,
            follow=True
        )
        self.assertEqual(Post.objects.count(), post_count + 1)
        second_response = self.client.get(reverse('posts:index'))
        second_content = second_response.content
        self.assertEqual(first_content, second_content)
        cache.clear()
        third_response = self.client.get(reverse('posts:index'))
        third_content = third_response.content
        self.assertNotEqual(second_content, third_content)

class PaginatorViewsTest(TestCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.user = User.objects.create_user(username='serg')
        cls.group = Group.objects.create(
            title='Тестовая группа',
            slug='test_slug',
            description='Тестовое описание',
        )
        num = settings.POSTS_NUM + 3
        cls.post = Post.objects.bulk_create(
            [Post(
                author=cls.user,
                text='Любойтекст %s' % post,
                group=cls.group)
                for post in range(num)]
        )

    def setUp(self):
        cache.clear()
        self.user = PaginatorViewsTest.user

    def test_pagination(self):
        paginator_template = {
            reverse('posts:index'): 'page_obj',
            reverse(
                'posts:group_list', kwargs={
                    'slug': PaginatorViewsTest.group.slug
                }
            ): 'page_obj',
            reverse(
                'posts:profile', kwargs={
                    'username': PaginatorViewsTest.user
                }
            ): 'page_obj'
        }
        for address, value in paginator_template.items():
            with self.subTest(value=value):
                response = self.client.get(address)
                response_second = self.client.get(address + '?page=2')
                self.assertEqual(
                    len(response.context[value]), settings.POSTS_NUM
                )
                diff_count = Post.objects.count() - settings.POSTS_NUM
                if diff_count > settings.POSTS_NUM:
                    self.assertEqual(
                        len(response_second.context[value]), settings.POSTS_NUM
                    )
                else:
                    self.assertEqual(len(
                        response_second.context[value]), diff_count
                    )


#!/usr/bin/python3

# gameoflife.py
# Implementation of Conway's Game of Life

# By Ernold McPuvlist
# 2021

try:
    from sys import exit
    import configparser
    import pygame
except ImportError as err:
    print("Module not found: ", err)
    exit()

# ====================================================
# Define classes
# ====================================================

class CellArray:
    """Class to store an array of Game of Life cells"""

    # class variables, fixed values for all instances
    grid_width = grid_height = 63
    cell_size = 6

    def __init__(self):
        # The _internal_array variable stores the grid of cells
        # as a list of lists (columns x rows).
        # Initialise with all cells set to False

        self._internal_array = [[False for row in range(CellArray.grid_height)] for col in range(CellArray.grid_width)]

    def get_cell(self, col_row): # col_row is a (col,row) tuple
        return (self._internal_array[col_row[0]][col_row[1]])

    def set_cell(self, col_row):
        self._internal_array[col_row[0]][col_row[1]] = True

    def unset_cell(self, col_row):
        self._internal_array[col_row[0]][col_row[1]] = False

    def get_all_live_cells(self):
        """Generate a list of all live cells (col,row tuples)"""
        for row in range(CellArray.grid_height):
            for col in range(CellArray.grid_width):
                if self._internal_array[col][row]:
                    yield (col, row)

    def get_neighbours(self, col_row):
        """Return a list of coordinates (as tuples) of the cells
        that surround this one, allowing for screen wraparound."""

        # unpack local variables for column and row from the tuple
        col, row  = col_row

        # Determine what row is above
        row_above = row - 1 if row > 0 else CellArray.grid_height - 1

        # Determine what row is below
        row_below = row + 1 if row < CellArray.grid_height - 1 else 0

        # Determine what column is to the left
        col_toleft = col - 1 if col > 0 else CellArray.grid_width - 1

        # Determine what column is to the right
        col_toright = col + 1 if col < CellArray.grid_width - 1 else 0

        return [(col_toleft, row_above), (col, row_above), (col_toright, row_above), \
               (col_toleft, row), (col_toright, row), \
               (col_toleft, row_below), (col, row_below), (col_toright, row_below)]

    def count_live_neighbours(self, col_row):
        """Count how many of the neighbouring cells are live"""
        return list(map(self.get_cell, self.get_neighbours(col_row))).count(True)

    def draw(self):
        """Draw the grid on the screen"""
        global WIN, FG_COLOUR, BG_COLOUR
        row_pos = col_pos = 0 # initialise local row and column positions

        # draw row by row
        for row in range(CellArray.grid_height):
            for col in range(CellArray.grid_width):
                if self._internal_array[col][row]:
                    pygame.draw.rect(WIN,FG_COLOUR,(col_pos,row_pos,CellArray.cell_size,CellArray.cell_size))
                else:
                    pygame.draw.rect(WIN,BG_COLOUR,(col_pos,row_pos,CellArray.cell_size,CellArray.cell_size))
                col_pos += CellArray.cell_size
            col_pos = 0
            row_pos += CellArray.cell_size

        pygame.display.update()

    def clear(self):
        """Make all cells dead (False)"""

        for column in range(CellArray.grid_width):
            for row in range(CellArray.grid_height):
                self._internal_array[column][row] = False

    def save_data(self):
        """Save the game state to the config file"""
        global CFG

        # Build a string of cell coordinates of all live cells
        # separated by a pipe character, e.g. 0,0|2,3
        cell_save = '|'.join(map(lambda s:str(s[0]) + "," + str(s[1]), self.get_all_live_cells()))

        if len(cell_save) > 0:

            if not CFG.has_section('pattern'):
                CFG.add_section('pattern')

            CFG['pattern']['cells'] = cell_save

            # write config file to disk
            with open(CFG_FILENAME, 'w') as cfg_file:
                CFG.write(cfg_file)

    def load_save_data(self, save_data):
        """Load saved data back into the grid"""

        self.clear()

        for saved_cell in save_data:
            self.set_cell(saved_cell)

class MenuLegend:
    """Class defining the menu buttons"""

    # class variables
    fg_colour_enabled = (255, 255, 255)
    fg_colour_disabled = (80, 80, 80)
    bg_colour = (0, 0, 139)
    y_position = 378
    height = 21
    offset = 2

    def __init__(self, text, x_position, width):
        self.text = text
        self.x_position = x_position
        self.width = width
        self.enabled = True

    def display(self, enabled):
        global WIN, LOCAL_FONT

        self.enabled = enabled

        # draw background rectangle for the legend
        pygame.draw.rect(WIN, (MenuLegend.bg_colour), (self.x_position, MenuLegend.y_position, self.width, MenuLegend.height))

        if self.enabled:
            render_text = LOCAL_FONT.render(self.text, True, MenuLegend.fg_colour_enabled)
        else:
            render_text = LOCAL_FONT.render(self.text, True, MenuLegend.fg_colour_disabled)

        WIN.blit(render_text, (self.x_position + MenuLegend.offset, MenuLegend.y_position + MenuLegend.offset))

# ====================================================
# Global functions
# ====================================================

def load_config(grid):
    """Load global constants and grid state from the config file"""
    global CFG, CFG_FILENAME, FG_COLOUR, BG_COLOUR, INTERVAL
    cfg_display = 'display'
    cfg_fgcolour = 'fgcolour'
    cfg_bgcolour = 'bgcolour'
    cfg_timer = 'timer'
    cfg_interval = 'interval'

    if CFG.read(CFG_FILENAME) == []: # empty list means failure to read config file
        # no config file - leave settings as defaults
        return

    try:
        tmp_r,tmp_g,tmp_b = CFG[cfg_display][cfg_fgcolour].split(',')
        FG_COLOUR = (int(tmp_r), int(tmp_g), int(tmp_b))
    except:
        if not CFG.has_section(cfg_display):
            CFG.add_section(cfg_display)
        CFG[cfg_display][cfg_fgcolour] = str(FG_COLOUR[0]) + ',' + str (FG_COLOUR[1]) + ',' + str(FG_COLOUR[2])

    try:
        tmp_r,tmp_g,tmp_b = CFG[cfg_display][cfg_bgcolour].split(',')
        BG_COLOUR = (int(tmp_r), int(tmp_g), int(tmp_b))
    except:
        if not CFG.has_section(cfg_display):
            CFG.add_section(cfg_display)
        CFG[cfg_display][cfg_bgcolour] = str(BG_COLOUR[0]) +',' + str(BG_COLOUR[1]) + ',' + str(BG_COLOUR[2])

    try:
        INTERVAL = int(CFG[cfg_timer][cfg_interval])
    except:
        if not CFG.has_section(cfg_timer):
            CFG.add_section(cfg_timer)
        CFG[cfg_timer][cfg_interval] = str(INTERVAL)

    # load_pattern = []

    # Load the stored pattern
    try:
        load_pattern = CFG['pattern']['cells'].split('|')
    except ValueError:
        return # bad data - abandon attempt to load

    if load_pattern == []: # if nothing found
        return

    try:
        # ValueError will raise if wrong no. of assignments to left hand side
        load_list = []
        for elem in load_pattern:
            cl,rw = elem.split(',')
            int_cl = int(cl)
            int_rw = int(rw)
            if int_cl < 0 or int_cl > CellArray.grid_width or int_rw < 0 or int_rw > CellArray.grid_height:
                # if out of range
                raise IndexError
            load_list.append((int_cl, int_rw))
    except ValueError:
        print("Value error reached on load")
        return
    except IndexError:
        print("Index error reached")
        return

    grid.load_save_data(load_list)

def apply_game_rules(source_grid, dest_grid):
    """Apply 'Game of Life' rules"""
    # 1. Any live cell with <2 live neighbours dies
    # 2. Any live cell with 2 or 3 neighbours survives
    # 3. Any live cell with >3 neighbours dies
    # 4. Any dead cell with exactly 3 live neighbours becomes live

    for row in range(CellArray.grid_width):
        for col in range(CellArray.grid_height):
            count_neighbours = source_grid.count_live_neighbours((col, row))
            if source_grid.get_cell((col, row)): # if already live
                if count_neighbours < 2 or count_neighbours > 3:
                    dest_grid.unset_cell((col, row))
                else:
                    dest_grid.set_cell((col, row))
            else: # if already dead
                if count_neighbours == 3:
                    dest_grid.set_cell((col, row))
                else:
                    dest_grid.unset_cell((col, row))

def animate():
    """Start the Game of Life animation. Menu choice F1"""
    global grid_alpha, grid_beta
    global FG_COLOUR, BG_COLOUR

    # grey out unavailable menu items
    legend[1].display(False)
    legend[2].display(False)
    legend[3].display(False)

    return_state = True
    local_run = True

    # the 'cycle' variable will store which of the two cycles
    # we are in, i.e.
    # A - Alpha is main display, Beta is reserve
    # B - Beta is main display, Alpha is reserve
    cycle = 'A'

    while local_run:
        for local_event in pygame.event.get():
            if local_event.type == pygame.QUIT:
                local_run = False
                return_state = False
            if local_event.type == pygame.KEYDOWN:
                if local_event.key == pygame.K_F1 or local_event.key == pygame.K_ESCAPE: # F1 or Esc = stop
                    local_run = False
                if local_event.key == pygame.K_F5:
                    local_run = False
                    return_state = False

        if cycle  == 'A':
            apply_game_rules(grid_alpha, grid_beta)
            grid_beta.draw()
            cycle = 'B'
        else:
            apply_game_rules(grid_beta, grid_alpha)
            grid_alpha.draw()
            cycle = 'A'

        pygame.time.delay(INTERVAL)

    # re-enable menu items
    legend[1].display(True)
    legend[2].display(True)
    legend[3].display(True)
    pygame.display.update()

    return return_state

def clear_grid():
    """Clear the grid. Menu choice F2"""
    grid_alpha.clear()
    grid_alpha.draw()

def draw_cells(grid):
    """Draw on the grid. Menu choice F3"""

    # grey out unavailable menu items
    legend[0].display(False)
    legend[1].display(False)
    legend[3].display(False)
    pygame.display.update()

    return_state = True

    def convert_mousepos_to_cellpos(mouse_pos):
        """Map the mouse position on screen to the game cell that it points to"""
        return (int(mouse_pos[0] / CellArray.cell_size), int(mouse_pos[1] / CellArray.cell_size))

    local_run = True
    while local_run:
        for local_event in pygame.event.get():
            if local_event.type == pygame.QUIT:
                local_run = False
                return_state = False
            if local_event.type == pygame.KEYDOWN:
                if local_event.key == pygame.K_F3 or local_event.key == pygame.K_ESCAPE: # F3 or Esc - stop
                    local_run = False
                if local_event.key == pygame.K_F5:
                    local_run = False
                    return_state = False
            if local_event.type == pygame.MOUSEBUTTONDOWN:
                if pygame.mouse.get_pressed()[0]: # left button clicked
                    grid.set_cell(convert_mousepos_to_cellpos(pygame.mouse.get_pos()))
                    grid.draw()
                elif pygame.mouse.get_pressed()[2]: # right button clicked
                    grid.unset_cell(convert_mousepos_to_cellpos(pygame.mouse.get_pos()))
                    grid.draw()

    # re-enable menu items
    legend[0].display(True)
    legend[1].display(True)
    legend[3].display(True)
    pygame.display.update()

    return return_state

# ====================================================
# Main code
# ====================================================

pygame_error = pygame.init()
# pygame.init() does not raise an exception but returns a tuple: (no. of successes, no. of failures)
if pygame_error[1]:
    print('Pygame failed to initialise: ',pygame_error[1],' error(s)')
    exit()
del pygame_error

if not pygame.font.get_init():
    pygame.font.init()

LOCAL_FONT = pygame.font.Font(None, 22)

WIN = pygame.display.set_mode((378, 399))
pygame.display.set_caption("Conway's Game of Life")

CFG = configparser.ConfigParser()
CFG_FILENAME = 'gameoflife.ini'

# Set up legend buttons
legend = [MenuLegend('F1 Start/Stop', 5, 95), \
          MenuLegend('F2 Clear', 105, 64),\
          MenuLegend('F3 Edit', 174, 64), \
          MenuLegend('F4 Save', 243, 64), \
          MenuLegend('F5 Quit', 312, 64)]

legend[0].display(True)
legend[1].display(True)
legend[2].display(True)
legend[3].display(True)
legend[4].display(True)

# Set up CellArrays to store game elements
# Alpha and Beta CellArray objects will be used alternately to store the
# displayed grid and the reserve grid for building the next display

# globals for colours
FG_COLOUR = (255, 255, 255)
BG_COLOUR = (0, 0, 0)

# initialise interval timer
INTERVAL = 500 # 500 ms

# Set up the two grids
grid_alpha = CellArray()
grid_beta = CellArray()

load_config(grid_alpha)

grid_alpha.draw()

pygame.time.delay(INTERVAL)

# ===============================================
# MAIN LOOP
# ===============================================
run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_q or event.key == pygame.K_F5: # q or F5 = quit
                run = False
            if event.key == pygame.K_F1:
                if not animate():
                    run = False # called function returns False if Quit was pressed
            if event.key == pygame.K_F2:
                clear_grid()
            if event.key == pygame.K_F3:
                if not draw_cells(grid_alpha): # called function returns False if Quit was pressed
                    run = False
            if event.key == pygame.K_F4:
                grid_alpha.save_data()

pygame.quit()


#Currently kept for notes and reference on SQLite syntax
#Will be removed

import sqlite3

connection = sqlite3.connect("securityLog.db")
cursor = connection.cursor()

cursor.execute("create table log (name text, time text, cameraName text)")

cursor.execute("insert into log values('Connor','4pm','webcam')")

connection.commit()

#print database rows
for row in cursor.execute("select * from log"):
    print(row)

connection.close()

"""
#how to execute sql commands
cursor.execute("insert into log values (?,?,?)")

#print database rows
for row in cursor.execute("select * from log"):
    print(row)

#How to create a table
# cursor.execute("create table log (name text, time text, cameraName text)")

#open connection
connection = sqlite3.connect("securityLog.db")
cursor = connection.cursor()

#saves changes made. if closed without doing this all changes will be rolled back.
connection.commit()

#close connection
connection.close()
"""


MAX = 21
n = int(input())
tree = [[] for _ in range(n)]
for _ in range(n - 1):
    a, b = map(int, input().split())
    tree[a - 1].append(b - 1)
    tree[b - 1].append(a - 1)
q = int(input())
query = []
for _ in range(q):
    k, *v, = map(int, input().split())
    if k != 2:
        exit()
    x, y = v
    query.append((x - 1, y - 1))

parent = [0] * n
depth = [0] * n
stack = [0]
while stack:
    x = stack.pop()
    for y in tree[x]:
        if y == parent[x]:
            continue
        parent[y] = x
        depth[y] = depth[x] + 1
        stack.append(y)

dp = [[0] * MAX for _ in range(n)]
for j in range(MAX):
    for x in range(n):
        if j == 0:
            dp[x][j] = parent[x]
        else:
            dp[x][j] = dp[dp[x][j - 1]][j - 1]

for x, y in query:
    if depth[x] > depth[y]:
        x, y = y, x
    d = depth[y] - depth[x]
    for i in range(MAX):
        if (1 << i) & d:
            y = dp[y][i]
    if x == y:
        print(d)
        continue
    ans = d
    for i in range(MAX)[::-1]:
        if dp[x][i] == dp[y][i]:
            continue
        x = dp[x][i]
        y = dp[y][i]
        ans += 2 ** (i + 1)
    print(ans + 2)


import logging

import torch
import torch.nn.functional as F
from torch.distributions import Categorical

logger = logging.getLogger()

def mask_inf_truncature(mask_valid_actions, logits, device, num_tokens=86):
    mask = (torch.ones(logits.size(0), num_tokens) * -1e32).to(device)
    mask = mask.masked_scatter_(mask_valid_actions, logits)
    probs_truncated = F.softmax(mask, dim=-1)
    policy_dist_truncated = Categorical(probs_truncated)
    return policy_dist_truncated

class Truncation:
    def __init__(self, pretrained_lm=None):
        self.language_model = pretrained_lm
        self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    def min_max_truncation(self, probas):
        sorted_probs, sorted_indices = torch.sort(probas, descending=True)
        min_prob, max_prob = sorted_probs[:, self.s_min], sorted_probs[:, self.s_max]
        min_mask = (probas > min_prob.view(-1, 1))
        max_mask = (probas > max_prob.view(-1, 1))
        min_max_mask = torch.logical_or(min_mask, max_mask)
        return min_max_mask, sorted_probs, sorted_indices

    def get_mask(self, log_probas, logits):
        return None, None

class TopK(Truncation):
    def __init__(self, **kwargs):
        Truncation.__init__(self, pretrained_lm=kwargs["pretrained_lm"])
        self.s_min = kwargs["s_min"]
        self.s_max = kwargs["s_max"]

    def get_mask(self, log_probas, logits):
        probas = torch.exp(log_probas)
        min_max_mask, _, _ = self.min_max_truncation(probas)
        return min_max_mask

class ProbaThreshold(Truncation):
    '''See OverLeaf for details on this truncation fn.'''

    def __init__(self, **kwargs):
        Truncation.__init__(self, pretrained_lm=kwargs["pretrained_lm"])
        self.p_th = float(kwargs["truncation_params"])
        self.s_min = kwargs["s_min"]
        self.s_max = kwargs["s_max"]

    def get_mask(self, log_probas, logits):
        probas = torch.exp(log_probas)
        min_max_mask, sorted_probs, sorted_indices = self.min_max_truncation(probas)
        p_th_mask = torch.ge(probas, self.p_th)
        final_mask = torch.logical_or(min_max_mask, p_th_mask)
        return final_mask

truncations = {"top_k": TopK, "proba_thr": ProbaThreshold}


for t in range(int(input())):
    k=0
    a=0
    s=list(map(str,input().split()))
    for i in range(0,len(s)):
        b=s[i]
        if b != '+' and b != '-' and b != '==':
            b=float(b)*100
            b=round(b,0)
            s[i]=b
    for i in range(0,len(s)):
        if s[i]=='+':
            pass
        elif s[i]=='-':
            k-=float(s[i+1])*2
        elif s[i]=='==':
            a+=k
            k=0
        else:
            k+=float(s[i])
    if k==a:
        print('T')
    else:
        print('F')


import argparse
import sys
import os

#3- Escribir un programa en Python que acepte argumentos de línea de comando para leer un archivo de texto.
#El programa debe contar el número de palabras y líneas del archivo e imprimirlas en la salida estándar.
#Además el programa debe aceptar una opción para imprimir la longitud promedio de las palabras del archivo.
#Esta última opción no debe ser obligatoria. Si hubiese errores deben guardarse el un archivo cuyo nombre será "errors.log" usando la redirección de la salida de error.
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('archivo', type=str, help='escribir la ruta al archivo de texto')
    args = parser.parse_args()

    try:
        with open(args.archivo, 'r') as archivo:
            contenido = archivo.read()
            palabras = contenido.split()
            cantidad_palabras = len(palabras)
            lineas = contenido.split('\n')
            cantidad_lineas = len(lineas)
        print('El archivo', args.archivo, 'tiene', cantidad_palabras, 'palabras y', cantidad_lineas, 'líneas.')
    except FileNotFoundError:
        with open("errors.log", "a") as error_file:
            error_file.write("The file {} does not exist\n".format(args.archivo))
        sys.stderr.write("The file {} does not exist\n".format(args.archivo))
        sys.exit(1)

if __name__ == "__main__":
    main()


import random
list = ['rock','paper','scissors']

def compare(cop,player):
    if cop == player:
        return ('draw')
    elif cop == 'rock':
        if player == 'paper':
            return ('player win')
        else:
            return ('cop win')
    elif cop == 'paper':
        if player == 'scissors':
            return ('player win')
        else:
            return ('cop win')
    elif cop == 'scissors':
        if player == 'rock':
            return ('player win')
        else:
            return ('cop win')

while True:
    random.shuffle(list)
    cop = list[0]
    player = input('Your input: ')
    print('Cop:',cop)
    print(compare(cop,player))
    print('Press A to play again')
    print('Press anything to quit')
    user_choice = input("Input your choice:")
    if user_choice in ['A','a']:
        print('-'*30)
        continue
    else:
        break


import time
from turtle import Screen
from snake import Snake
from food import Food
from scoreboard import Scoreboard

screen = Screen()
screen.setup(width=600, height=600)
screen.bgcolor("black")
screen.tracer(0)
screen.title("Snake Game")

snake = Snake()
food = Food()
scoreboard = Scoreboard()

screen.listen()
screen.onkey(snake.up, "Up")
screen.onkey(snake.down, "Down")
screen.onkey(snake.left, "Left")
screen.onkey(snake.right, "Right")
game_on = True

while game_on:
    screen.update()
    time.sleep(0.1)

    snake.move()

    if snake.head.distance(food) < 15:
        food.new_food()
        scoreboard.update_score()
        snake.extend()

    # Detect wall collision
    if snake.head.xcor() > 280 or snake.head.xcor() < -290 or snake.head.ycor() > 260 or snake.head.ycor() < -280:
        game_on = False
        scoreboard.game_over()

    # Detect tail collision
    for i in snake.full_snake[1:]:
        if snake.head.distance(i) < 10:
            game_on = False
            scoreboard.game_over()

screen.exitonclick()


from collections import defaultdict
def leastBricks(wall):
    """
    layers define the number of layers in the brick wall.
    width defines the width of each layer. Note that each
    layer has the same width.
    Build a dictionary:
    - d maps each edge location to its frequency
      over the entire wall.
    - edges are numbered from 0 to width. For example, a brick of length 2 at the start of a layer will have
        edges at 0 and 2.
    - Only edges between adjacent bricks are included in d.
    """
    layers = len(wall)
    width = sum(wall[0])
    d = defaultdict(int)
    for layer in wall:
        sum_bricks = 0
        for brick in layer:
            sum_bricks += brick
            if sum_bricks < width:
                d[sum_bricks] += 1
    max_edges = 0
    for hash in d:
        max_edges = max(max_edges, d[hash])
    return layers - max_edges