import requests as requests
import bs4
import emoji
import random
import json

from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler

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

# get contact info from config file
with open("config.json") as json_data_file:
    data = json.load(json_data_file)
    url = data['secret']['url']

# create function that get chat id
def get_chat_id(update):
    chat_id = update['message']["chat"]["id"]
    return chat_id

# create function that get message text
def get_message_text(update):
    message_text = update["message"]["text"]
    return message_text

# create function that get last_update
def last_update(req):
    response = requests.get(req + "getUpdates")
    response = response.json()
    result = response["result"]
    total_updates = len(result) - 1
    return result[total_updates]  # get last record message update

# create function that let bot send message to user
def send_message(chat_id, message_text):
    params = {"chat_id": chat_id, "text": message_text}
    response = requests.post(url + "sendMessage", data=params)
    return response

# create main function for navigate or reply message back
def main():
    update_id = last_update(url)["update_id"]
    while True:
        update = last_update(url)

        sick = emoji.emojize(':mask:', use_aliases=True)
        beer = emoji.emojize(':beers:', use_aliases=True)
        wave = emoji.emojize(':wave:', use_aliases=True)
        poop = emoji.emojize(':poop:', use_aliases=True)

        if update_id == update["update_id"]:

            if get_message_text(update).lower() == "menu" or get_message_text(update).lower() == "/start":
                send_message(get_chat_id(update), """Cheers! """ + beer + """ Welcome to Corona bot """ + wave + """
*************************************
Type WORLD to see amount of all Corona cases and deaths caused by Corona in the world """ + sick + """
*************************************
Type CONTINENT to see Corona stats of each continent """ + sick + """
*************************************
Type FINLAND to see Corona stats in Finland """ + sick + """
*************************************
Type MEME to see memes related to Corona virus """ + poop + sick + """
*************************************
Or you can type MENU to get this view at anytime!""")

            elif get_message_text(update).lower() == "world":
                res = requests.get('https://www.worldometers.info/coronavirus/')
                soup = bs4.BeautifulSoup(res.text, 'lxml')

                stats = soup.select('title')
                msg = stats[0].text
                msg = msg.replace('-', '')
                msg = msg.replace('Worldometer', '')

                u = soup.select('div')
                updated = str(u[14].text)

                earth = emoji.emojize(':earth_americas:', use_aliases=True)

                send_message(get_chat_id(update), earth + "" + msg + "" + earth)

            elif get_message_text(update).lower() == "continent":
                res = requests.get('https://www.worldometers.info/coronavirus/')
                soup = bs4.BeautifulSoup(res.text, 'lxml' )

                stats = soup.select('td')
                print(stats)
                u = soup.select('div')
                updated = str(u[14].text)

                one = emoji.emojize(':one:', use_aliases=True)
                two = emoji.emojize(':two:', use_aliases=True)
                three = emoji.emojize(':three:', use_aliases=True)
                four = emoji.emojize(':four:', use_aliases=True)
                five = emoji.emojize(':five:', use_aliases=True)
                six = emoji.emojize(':six:', use_aliases=True)

                #sound = emoji.emojize('/play story', use_aliases=True)

                bullet = emoji.emojize(':o:', use_aliases=True)
                earth = emoji.emojize(':earth_americas:', use_aliases=True)

                d1 = "NONE"
                d2 = "NONE"
                d3 = "NONE"

                if stats[3].text != "":
                    d1=stats[3].text
                if stats[16].text != "":
                    d2 = stats[16].text
                if stats[29].text != "":
                    d3 = stats[29].text
                if stats[42].text != "":
                    d4=stats[42].text
                if stats[55].text != "":
                    d5 = stats[55].text
                if stats[68].text != "":
                    d6 = stats[68].text

                n1="NONE"
                n2 = "NONE"
                n3 = "NONE"

                if stats[2].text != "":
                    n1=stats[2].text
                if stats[15].text != "":
                    n2 = stats[15].text
                if stats[28].text != "":
                    n3 = stats[28].text
                if stats[41].text != "":
                    n4=stats[41].text
                if stats[54].text != "":
                    n5 = stats[54].text
                if stats[67].text != "":
                    n6 = stats[67].text

                send_message(get_chat_id(update),
                             earth + "Below continents in order of confirmed Corona cases" + earth)
                send_message(get_chat_id(update),
                             one + stats[0].text + "\nTotal cases:\n " + bullet + stats[1].text + "\nNew cases:\n" +  bullet + n1 + "\nTotal deaths:\n" +   bullet + d1 + "\nTotal recovered:\n" + bullet + stats[5].text + "\nActive cases:\n" + bullet + stats[6].text)
                send_message(get_chat_id(update),
                             two + stats[13].text + "\nTotal cases:\n " + bullet + stats[14].text + "\nNew cases:\n" +  bullet + n2 + "\nTotal deaths:\n" + bullet + d2 + "\nTotal recovered:\n" + bullet + stats[18].text + "\nActive cases:\n" + bullet + stats[19].text)
                send_message(get_chat_id(update),
                             three + stats[26].text + "\nTotal cases:\n " + bullet + stats[27].text + "\nNew cases:\n" +  bullet + n3 + "\nTotal deaths:\n" + bullet + d3 + "\nTotal recovered:\n" + bullet + stats[31].text + "\nActive cases:\n" + bullet + stats[32].text)
                send_message(get_chat_id(update),
                             four + stats[39].text + "\nTotal cases:\n " + bullet + stats[40].text + "\nNew cases:\n" +  bullet + n4 + "\nTotal deaths:\n" + bullet + d4 + "\nTotal recovered:\n" + bullet + stats[44].text + "\nActive cases:\n" + bullet + stats[45].text)
                send_message(get_chat_id(update),
                             five + stats[65].text + "\nTotal cases:\n " + bullet + stats[66].text + "\nNew cases:\n" +  bullet + n6 + "\nTotal deaths:\n" + bullet + d6 + "\nTotal recovered:\n" + bullet + stats[70].text + "\nActive cases:\n" + bullet + stats[71].text)
                send_message(get_chat_id(update),
                             six + stats[52].text + "\nTotal cases:\n " + bullet + stats[53].text + "\nNew cases:\n" +  bullet + n5 + "\nTotal deaths:\n" + bullet + d5 + "\nTotal recovered:\n" + bullet + stats[57].text + "\nActive cases:\n" + bullet + stats[58].text)

            elif get_message_text(update).lower() == "daily":
                res = requests.get('https://www.worldometers.info/coronavirus/')
                soup = bs4.BeautifulSoup(res.text, 'lxml')

                stats = soup.select('td')
                u = soup.select('div')
                updated = str(u[14].text)

                leader = 0
                lnbr = 0
                second = 0
                snbr = 0
                third = 0
                tnbr = 0

                x = -7

                while x < 1340:

                    variable = str(stats[x+9].text)
                    print(variable)
                    variable = variable.replace("+", "")
                    variable = variable.replace(",", "")

                    if variable == '':
                        variable = 1

                    print(variable)
                    variable = int(variable)

                    if variable > leader:
                        second = leader
                        snbr = lnbr
                        leader = variable
                        lnbr = int(x+9)

                    elif  leader > variable > second:
                        third = second
                        tnbr = snbr
                        second = variable
                        snbr = x+9

                    elif  second > variable > third:
                        third = variable
                        tnbr = x+9

                    x = x+9

                # share of total cases

                variable1 = str(stats[lnbr-1].text)
                variable1 = variable1.replace("+", "")
                variable1 = variable1.replace(",", "")
                variable1 = int(variable1)
                variable2 = str(stats[snbr-1].text)
                variable2 = variable2.replace("+", "")
                variable2 = variable2.replace(",", "")
                variable2 = int(variable2)
                variable3 = str(stats[tnbr-1].text)
                variable3 = variable3.replace("+", "")
                variable3 = variable3.replace(",", "")
                variable3 = int(variable3)

                share1 = round(leader/variable1, 2)*100
                share2 = round(second/variable2, 2)*100
                share3 = round(third/variable3, 2)*100

                one = emoji.emojize(':one:', use_aliases=True)
                two = emoji.emojize(':two:', use_aliases=True)
                three = emoji.emojize(':three:', use_aliases=True)

                bullet = emoji.emojize(':o:', use_aliases=True)
                earth = emoji.emojize(':earth_americas:', use_aliases=True)

                d1 = "NONE"
                d2 = "NONE"
                d3 = "NONE"

                if stats[lnbr+2].text != "":
                    d1=stats[lnbr+2].text
                if stats[snbr+2].text != "":
                    d2 = stats[snbr+2].text
                if stats[tnbr+2].text != "":
                    d3 = stats[tnbr+2].text

                send_message(get_chat_id(update),
                             earth + "Below top 3 countries in sense of confirmed Corona cases today" + earth)
                send_message(get_chat_id(update),
                             one + str(stats[lnbr-2].text) + one + "\nNew cases today:\n" + bullet + "+" +  str(leader) + "\nNew deaths today:\n" + bullet + d1 + "\nShare of total cases:\n" + bullet + str(share1) + "%")
                send_message(get_chat_id(update),
                             two + stats[snbr-2].text + two + "\nNew cases today:\n" + bullet + "+" + str(second) + "\nNew deaths today:\n" + bullet + d2 + "\nShare of total cases:\n" + bullet + str(share2) + "%")
                send_message(get_chat_id(update),
                             three + stats[tnbr-2].text + three + "\nNew cases today:\n" + bullet + "+" + str(third) + "\nNew deaths today:\n" + bullet + d3 + "\nShare of total cases:\n" + bullet + str(share3) + "%")

            elif get_message_text(update).lower() == "finland":
                res = requests.get('https://www.worldometers.info/coronavirus/')
                soup = bs4.BeautifulSoup(res.text, 'lxml')

                stats = soup.select('td')
                u = soup.select('div')
                updated = str(u[14].text)

                x = -9
                f = 0

                while x < 1340:

                    variable = str(stats[x+9].text)
                    print(variable)

                    if variable == 'Finland':
                        f = int(x + 9)
                        print("osuma")

                    x = x + 9

                bullet = emoji.emojize(':o:', use_aliases=True)
                #fi = emoji.emojize(':fi:', use_aliases=True)

                d = "NONE"
                n = "NONE"

                if stats[f+3].text != "":
                    d = stats[f+3].text
                if stats[f+2].text != "":
                     n = stats[f+2].text

                send_message(get_chat_id(update),
                            "SUOMI PERKELE!"+ "\nTotal cases:\n" + bullet + stats[
                            f+1].text + "\nNew cases:\n" + bullet + n + "\nTotal deaths:\n" + bullet +
                            d + "\nTotal recovered:\n" + bullet + stats[f+5].text + "\nActive cases:\n" + bullet + stats[f+6].text)

            elif get_message_text(update).lower() == "meme":
                res = requests.get("https://ruinmyweek.com/memes/coronavirus-meme-list/")
                res2 = requests.get("https://ruinmyweek.com/memes/coronavirus-meme-list/2/")

                soup = bs4.BeautifulSoup(res.text, 'lxml')
                image = soup.select('img')
                image2 = soup.select('img')

                count = 0
                count2 = 0
                images = []
                images2 = []

                for x in range(0, len(image)):
                    if 22 > x > 0:
                        if x % 2 == 0:
                            images.append(image[x]['src'])

                for x in range(0, len(image2)):
                    if 22 > x > 0:
                        if x % 2 == 0:
                            images2.append(image2[x]['src'])

                for img in images:
                    print(img)

                print("\n\n**************  Lista 2  **************\n\n")

                for img2 in images2:
                    print(img2)

                nbr = random.randint(0, 9)
                print(nbr)

                send_message(get_chat_id(update),images[nbr])

            else:
                send_message(get_chat_id(update), "Sorry, not understanding what you're saying:( Try to type 'MENU' for example")
            update_id += 1

# call the function to make it reply
main()

def meme():
    res = requests.get("https://ruinmyweek.com/memes/coronavirus-meme-list/")
    print(res.content)

    soup = bs4.BeautifulSoup(res.text, 'lxml')
    image = soup.select('img')
    print(image['src'])

    count = 0
    images = []

    for x in range(0, len(image)):
        if 16 > x > 2:
            if x % 2 == 0:
                images.append(image[x]['src'])

    for img in images:
        print(img)

#meme()

def update():
    res = requests.get('https://www.worldometers.info/coronavirus/')
    soup = bs4.BeautifulSoup(res.text, 'lxml')

    stats = soup.select('td')
    print(stats)

    x = -9
    f = 0

    while x < 1340:

        variable = str(stats[x + 9].text)
        print(variable)

        if variable == ' Finland ':
            f = int(x + 9)

        x = x + 9

    bullet = emoji.emojize(':o:', use_aliases=True)
    # fi = emoji.emojize(':fi:', use_aliases=True)

    d = "NONE"
    n = "NONE"

    if stats[f + 3].text != " ":
        d = stats[f + 3].text
    if stats[f + 2].text != " ":
        n = stats[f + 2].text

#update()


# Find the Factorial of the given Number ==========>
# ==================================================

# Noramal Way ============>
# =========================

n = 5
factorial = 1

for i in range(1, n + 1):
    factorial = factorial * i
    i = i + 1

print(factorial)     # ====> 120

# By using Function ============>
# ===============================

def factorial(num):
    prod = 1
    for i in range(num):
        prod = prod * (i + 1)
    return factorial

fact = factorial(5)
print(fact)

# By using Recursion ============>
# ================================

def fact_rec(n):
    if n == 1 or n == 0:
        return n

    return n * fact_rec(n - 1)

factorial = fact_rec(5)
print(factorial)

# ====> 120


from accounts.models.City import City
from accounts.api.serializers.CitySerializer import CitySerializer

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import AllowAny

class CitiesOfCountry(APIView):
    permission_classes = (AllowAny,)

    def get(self, request, pk ,  format=None):

        try:

            cities= City.objects.filter(country=pk)

            citiesDeatils = CitySerializer(cities , many=True)
            status_code = status.HTTP_200_OK
            response = { 'cities' : citiesDeatils.data , }
            return Response(response , status_code)

        except Exception as err:
            status_code = status.HTTP_404_NOT_FOUND
            response = {'error' : str (err) ,}
            return Response (response , status_code)

class AllCities(APIView):
    permission_classes = (AllowAny,)

    def get(self, request ,  format=None):

        try:

            cities= City.objects.all()

            citiesDeatils = CitySerializer(cities, many=True)

            status_code = status.HTTP_200_OK
            response = {'cities' : citiesDeatils.data ,}
            return Response(response , status_code)

        except Exception as err:
            status_code = status.HTTP_404_NOT_FOUND
            response = {'error' : str (err) ,}
            return Response (response , status_code)


# SPDX-License-Identifier: GPL-3.0-or-later
import logging
from typing import Optional

import boto3
from botocore.response import StreamingBody

log = logging.getLogger(__name__)

def get_object_from_s3_bucket(
    s3_key_prefix: str,
    s3_file_name: str,
    bucket_name: str,
) -> Optional[StreamingBody]:
    """
    Get object from AWS S3 bucket.

    :param str s3_key_prefix: the logical location of the file in the S3 bucket
    :param str s3_file_name: the name of the file in S3 bucket
    :param str bucket_name: the name of the S3 bucket to fetch the file from
    :return: the body of the S3 object or None
    :rtype: botocore.response.StreamingBody
    """
    file_name = f'{s3_key_prefix}/{s3_file_name}'
    log.info('getting file from s3 : %s', file_name)
    s3 = boto3.resource(service_name='s3')
    try:
        response = s3.meta.client.get_object(Bucket=bucket_name, Key=file_name)
    except Exception as error:
        log.exception('Unable to fetch object %s from bucket %s: %s', file_name, bucket_name, error)
        return None
    return response['Body']


import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from matplotlib.colors import Normalize
import imp
import scipy.stats as sc
from scipy.signal import butter, filtfilt
from scipy.signal import hilbert
from uncertainties import ufloat
import streamlit as st
import time
from bokeh.plotting import figure, output_file, show
import matplotlib
import io
import os
from PIL import Image
import processing.procswi as proc_swi #these are the custom functions for the single worm imaging analysis
import plotting.plotting_SWI as plot_SWI
try:
    from pip._internal.operations import freeze
except ImportError:  # pip < 10.0
    from pip.operations import freeze

st.set_option('deprecation.showfileUploaderEncoding', False) # to suppress the warning for file_uploader

#make text interpretable for adobe illustrator
matplotlib.rcParams['pdf.fonttype'] = 42
matplotlib.rcParams['ps.fonttype'] = 42

#set linewidth and labelsize for plots
linewidth = 15
linewidth_sidebar = 2
labelsize = 15

#frontend image on top of page
@st.cache()
def show_worm_image():
    image = Image.open(os.path.dirname(__file__) + "/SWI_chambers_OP50_202020215.png")
    return image

image = show_worm_image()
st.image(image, caption='', use_column_width=True)

#title on top of page
st.title(":microscope: :snake: :microscope: :snake: SWI Analyzer :snake: :microscope: :snake: :microscope:")

#add information for user
if st.sidebar.checkbox("Show useful information on how to work with this tool"):
    str_1 = "This tool is designed to analyze single worm imaging data. It relies on lethargus data in the format of a csv file where the columns indicate the individual worms and the rows represent time points. "
    str_2 = "The lethargus data is usually generated manually by checking whether the worm pumps (=1) or not (=0) at each time point. "
    str_3 = "The GFP data should be in the tidy format, where Timepoints are in the first column (Frame), worms in the second (Position) and GFP intensity in the third column (Intensity_BGsub). "
    str_4 = "The tool is structured in an interactive way through the sidebar. The idea is to go through the steps from top to bottom by first loading in the raw data and then performing the lethargus analysis. "
    str_5 = "After the lethargus analysis the raw GFP data is plotted with the lethargus times in red. It is then possible to clean the data from worms that did not survive the assay or escape during the imaging. "
    str_6 = "All further calculations and plots will be done using the cleaned data. Finally, it is possible to save the figures as pdf or png and the results in csv format to a desired location."
    st.info(str_1 + str_2 + str_3 + str_4 + str_5 + str_6)

#Load the data
st.sidebar.title("Import the data")

@st.cache()
def load_lethargus(uploaded_file_leth):
    return pd.read_csv(uploaded_file_leth)

uploaded_file_leth = st.sidebar.file_uploader("Choose file for lethargus data", type="csv")
if uploaded_file_leth is not None:
    leth = load_lethargus(uploaded_file_leth)

uploaded_file_GFP = st.sidebar.file_uploader("Choose file for GFP data", type="csv")
if uploaded_file_GFP is not None:
    gfpdata_original = pd.read_csv(uploaded_file_GFP)
    gfpdata = gfpdata_original.pivot("Frame","Position", "Intensity_BGsub")

#Display the data
st.sidebar.title("Display raw data")

if st.sidebar.checkbox("show lethargus data"):
    st.header("Raw data input")
    st.subheader("Lethargus data:")
    st.dataframe(leth)

if st.sidebar.checkbox("show GFP data"):
    st.header("Raw data input")
    st.subheader("GFP data:")
    st.dataframe(gfpdata)

#run the lethargus analysis
st.sidebar.title("Lethargus analysis")

if st.sidebar.checkbox("start lethargus analysis"):
    intmolts, molts = proc_swi.lethargus_analysis(leth)
    st.success("Lethargus analysis successful!")

#choose developmental length
    st.sidebar.subheader("choose developmental length (in time points) for GFP analysis")
    dev_length = st.sidebar.number_input("", 0, 360 - int(np.max(intmolts[0,0,:])), 231)
    #231 is default because example data works best with 231

#plot raw data
st.sidebar.title("Raw data plotting")
if st.sidebar.checkbox("plot GFP data with molts"):

    st.subheader("Raw GFP data with molts in red")
    st.write("""This plot is an interactive bokeh plot. Using the panels on the
    right you can zoom in, move or reset the view. The individual black lines represent
    GFP intensities of individual animals with the molts indicated in red.""")

    #adjusted gfp data to start from hatch for every worm individually
    gfp_adj = proc_swi.adjust_gfp(gfpdata, intmolts, dev_length)

    #plot GFP raw data
    figure_raw_gfp = plot_SWI.bokeh_plot_gfp_raw(gfpdata, gfp_adj, molts, intmolts, dev_length)
    st.bokeh_chart(figure_raw_gfp, use_container_width=True)

    #######run GFP analysis#########

    # calculations (could still be improved with dataframes etc)
    # interpolate gfp data
    f_clean = proc_swi.interpolate_gfp(gfpdata, intmolts, dev_length)

    # select valid worms
    valid_worms = proc_swi.set_up_valid_worms(gfpdata)

    if st.sidebar.checkbox("filter out bad worms"):
        worm_to_check = st.sidebar.number_input("worm number", 1 , step = 1) - 1

        #plot individual worm in sidebar
        evaluated = plot_SWI.plot_ind_worm_sidebar(gfpdata, f_clean, dev_length, molts, intmolts, worm_to_check, linewidth_sidebar)
        evaluated = st.sidebar.checkbox("valid worm", value = True)
        valid_worms[worm_to_check] = evaluated
        valid_worms_df = pd.DataFrame({"worm": gfpdata.columns, "valid": valid_worms})

    #filter gfpdata and lethargus for valid samples
    leth_clean = leth.iloc[:,1:].loc[:,valid_worms==True]
    leth_clean.insert(loc=0, column='Timepoint', value=leth["Timepoint"])

    f_clean_df = pd.DataFrame(f_clean).T
    f_clean_df_clean = f_clean_df.loc[:,valid_worms==True]
    intmolts_clean = intmolts[:,:,valid_worms==True]
    molts_clean = molts[:,:,valid_worms==True]
    gfpdata_clean = gfpdata.loc[:,valid_worms == True]

    #plot f_clean (interpolated data) to investigate molts and developmental length in more detail
    if st.sidebar.checkbox("Cleaned data: highlight molt times in comparison to developmental length"):
        st.subheader("Cleaned GFP data with molts")

        def color_zero_red(val):

            color = 'red' if val == 0 else 'black'
            return 'color: %s' % color

        st.dataframe(valid_worms_df.T.style.applymap(color_zero_red))

        alpha_gfp = st.sidebar.slider("transparency of single worm GFP", 0,100,40)
        alpha_molt = st.sidebar.slider("transparency of molts", 0,100,40)
        alpha_mean = st.sidebar.slider("transparency of mean", 0,100,90)
        alpha_std = st.sidebar.slider("transparency of standard deviation", 0,100,20)
        #plot
        plot_SWI.plot_gfp_and_molts(gfpdata, dev_length, f_clean_df_clean, alpha_mean, alpha_gfp, alpha_molt, alpha_std, molts_clean, intmolts_clean, labelsize, linewidth)

    #Larval stage durations
    st.sidebar.title("Plot developmental durations")

    larval_stage_dur, molt_dur, intermolt_dur = proc_swi.calculate_durations(leth_clean, intmolts_clean, molts_clean)
    #larval stage durations plotting
    if st.sidebar.checkbox("plot molt, intermolt and larval stage duration"):
        st.subheader("Molt, Intermolt and Larval stage durations in hours")
        #let user choose y-limits
        y_lim_low_molt = st.sidebar.number_input("molt y-axis lower limit", 0,100, 0)
        y_lim_high_molt = st.sidebar.number_input("molt y-axis upper limit", 0,100, 5)
        y_lim_low_intermolt = st.sidebar.number_input("intermolt y-axis lower limit", 0,100, 0)
        y_lim_high_intermolt = st.sidebar.number_input("intermolt y-axis upper limit", 0,100, 17)
        y_lim_low_larvalstage = st.sidebar.number_input("larval stage y-axis lower limit", 0,100, 0)
        y_lim_high_larvalstage = st.sidebar.number_input("larval stage y-axis upper limit", 0,100, 17)
        #plot larval stage durations
        plot_SWI.plot_durations(molt_dur, intermolt_dur, larval_stage_dur, y_lim_low_molt, y_lim_high_molt, y_lim_low_intermolt, y_lim_high_intermolt, y_lim_low_larvalstage, y_lim_high_larvalstage)

    #Scale the data to each individual larval stage according to mean length of larval stage (not working yet)
    #scaled_all, new_molt_mean, new_molt_std = scale_data(intmolts_clean, molts_clean, gfpdata_clean)

    #hilbert analysis of gfp signals
    st.sidebar.title("Hilbert analysis for phases at molt entry and exit")

    if st.sidebar.checkbox("plot phase from Hilbert at molt entry and exit"):
        #Sample rate and desired cutoff frequencies (in 1/h). Experienced users can choose
        st.sidebar.subheader("parameters: only for advanced users!")
        if st.sidebar.checkbox("set parameters for BW filter and hilbert transform"):
            st.sidebar.warning("only for advanced users")
            fs = st.sidebar.number_input("sample frequency (tp/h)", 1,12, 6) #default = 6
            lowcut = 1/st.sidebar.number_input("upper limit period (h)", 5,20, 14) #default = 14
            highcut = 1/st.sidebar.number_input("lower limit period (h)", 1,10, 5) #default = 5

        else:
            fs = 6 #default:6
            lowcut = 1/14 #default 1/14 --> 14 hour period
            highcut = 1/5 #default 1/5 --> 5 hour period

        my_phase, PeriodoverTime, phase_melt = proc_swi.run_hilbert(f_clean_df_clean, leth_clean, lowcut, highcut, fs, dev_length)

        #obtain phase at molt entry and exit
        molt_entr_ph_L1, molt_entr_ph_L2, molt_entr_ph_L3, molt_entr_ph_L4, molt_exit_ph_L1, molt_exit_ph_L2, molt_exit_ph_L3, molt_exit_ph_L4 = proc_swi.phase_molt_entry_exit(gfpdata_clean, intmolts_clean, my_phase)

        #correct (switch) phase
        corr_molt_entr_ph_L1, corr_molt_entr_ph_L2, corr_molt_entr_ph_L3, corr_molt_entr_ph_L4, corr_molt_exit_ph_L1, corr_molt_exit_ph_L2, corr_molt_exit_ph_L3, corr_molt_exit_ph_L4 = proc_swi.correct_phase(molt_entr_ph_L1,
                                                                                molt_entr_ph_L2,
                                                                                molt_entr_ph_L3,
                                                                                molt_entr_ph_L4,
                                                                                molt_exit_ph_L1,
                                                                                molt_exit_ph_L2,
                                                                                molt_exit_ph_L3,
                                                                                molt_exit_ph_L4)

        #sort lethargus (optional, not used for plotting)
        leth_new_sorted = proc_swi.sort_lethargus(leth_clean, intmolts_clean)

        #calculate period per larval stage
        period_L2, period_L3, period_L4 = proc_swi.period_per_LS(PeriodoverTime,
                                                                gfpdata_clean,
                                                                intmolts_clean)

        #Error propagation of the phase calling
        prop_err_entry, prop_err_exit = proc_swi.error_prop(larval_stage_dur.loc[larval_stage_dur["variable"]=="L2",:]["value"].values,
                                                            larval_stage_dur.loc[larval_stage_dur["variable"]=="L3",:]["value"].values,
                                                            larval_stage_dur.loc[larval_stage_dur["variable"]=="L4",:]["value"].values,
                                                            intermolt_dur.loc[intermolt_dur["variable"]=="IM2",:]["value"].values,
                                                            intermolt_dur.loc[intermolt_dur["variable"]=="IM3",:]["value"].values,
                                                            intermolt_dur.loc[intermolt_dur["variable"]=="IM4",:]["value"].values,
                                                            period_L2,
                                                            period_L3,
                                                            period_L4)

        #plot 2
        st.subheader("Phases at molt entry and exit")

        molt_phases_normal = proc_swi.use_phases(molt_entr_ph_L1,
                                                molt_entr_ph_L2,
                                                molt_entr_ph_L3,
                                                molt_entr_ph_L4,
                                                molt_exit_ph_L1,
                                                molt_exit_ph_L2,
                                                molt_exit_ph_L3,
                                                molt_exit_ph_L4)

        molt_phases_corr = proc_swi.use_corrected_phases(corr_molt_entr_ph_L1,
                                                        corr_molt_entr_ph_L2,
                                                        corr_molt_entr_ph_L3,
                                                        corr_molt_entr_ph_L4,
                                                        corr_molt_exit_ph_L1,
                                                        corr_molt_exit_ph_L2,
                                                        corr_molt_exit_ph_L3,
                                                        corr_molt_exit_ph_L4)

        st.sidebar.subheader("adjust y-axis limits")

        ylim_phase_min = st.sidebar.number_input("phase ylim minimum", -6, 6, -4)
        ylim_phase_max = st.sidebar.number_input("phase ylim minimum", -6, 6, 4)
        cmap = cm.magma
        norm = Normalize(vmin=-np.pi, vmax=np.pi)

        #plot phases in color with molt in thick scatters
        plot_SWI.plot_phases(molt_phases_normal, molt_phases_corr, cmap, norm, ylim_phase_min, ylim_phase_max, gfpdata_clean, dev_length, my_phase, molts_clean, intmolts_clean, corr_molt_entr_ph_L1,corr_molt_entr_ph_L2, corr_molt_entr_ph_L3, corr_molt_entr_ph_L4, corr_molt_exit_ph_L1, corr_molt_exit_ph_L2, corr_molt_exit_ph_L3, corr_molt_exit_ph_L4, molt_entr_ph_L1, molt_entr_ph_L2, molt_entr_ph_L3, molt_entr_ph_L4, molt_exit_ph_L1, molt_exit_ph_L2, molt_exit_ph_L3, molt_exit_ph_L4)

        #period and larval stage duration and error propagated plots
        #prepare error propagated data
        st.subheader("Larval stage vs osc period and error propagation")

        if st.checkbox("use flipped phases for error propagation", value = False):
            std_phases_all = proc_swi.combine_stds(molt_phases_corr.loc[molt_phases_corr["Molt"]=="entry",:], prop_err_entry, molt_phases_corr.loc[molt_phases_corr["Molt"]=="exit",:], prop_err_exit)
        else:
            std_phases_all = proc_swi.combine_stds(molt_phases_normal.loc[molt_phases_normal["Molt"]=="entry",:], prop_err_entry, molt_phases_normal.loc[molt_phases_normal["Molt"]=="exit",:], prop_err_exit)

        #plot
        plot_SWI.plot_period_and_error_prop(larval_stage_dur, period_L2, period_L3, period_L4, std_phases_all)

    #export results and parameters

    st.sidebar.title("export results")
    if st.sidebar.checkbox("Save results in following directory"):

        params_hilbert = pd.DataFrame({"sample frequency (tp)": fs,
                                        "lower period limit (h)": 1/highcut,
                                        "upper period limit (h)": 1/lowcut}, index = ["value"]).T

        save_dir_data = st.sidebar.text_input("add location", "")
        phase_melt.to_csv(save_dir_data + "phase_melt.csv")
        larval_stage_dur.to_csv(save_dir_data + "Larval_stage_durations.csv")
        molt_dur.to_csv(save_dir_data + "Molt_durations.csv")
        intermolt_dur.to_csv(save_dir_data + "Intermolt_durations.csv")
        params_hilbert.to_csv(save_dir_data + "parameters_used_for_hilbert_analysis.csv")
        valid_worms_df.to_csv(save_dir_data + "valid_worms.csv")
        pd.DataFrame(molt_phases_normal).to_csv(save_dir_data + "phases_at_molt_normal.csv")
        pd.DataFrame(molt_phases_corr).to_csv(save_dir_data + "phases_at_molt_flipped.csv")
        #save version infos
        def save_session_info():
            session_info = freeze.freeze()
            versions = []
            for p in session_info:
                versions.append(p)
            return pd.DataFrame(versions)

        version_info = save_session_info()
        version_info.to_csv(save_dir_data + "session_info.txt", header=False, index = False)


import customtkinter
import tkinter
from chatsection import ChatSection
import threading
import sys
from client import Client

HOST = '10.57.33.117'  #IP address server machine
PORT = 3042

class Clientui(customtkinter.CTk):
    def __init__(self):
        super().__init__()

        self.geometry("500x700")
        self.title("Chatbot d'avril")
        self.minsize(500, 700)
        self.maxsize(500, 700)
        self._set_appearance_mode("dark")

        self._pseudo = None
        self._user = Client(HOST,PORT)

        # color
        self.primary_color = "#242424"

        # Font parameter
        self.send_button_font = customtkinter.CTkFont(family="Arial", size=18, weight="bold")
        self.chat_text_font = customtkinter.CTkFont(family="Arial", size=18, weight="normal")

        self.create_menu()

        self._reload_pseudo = False

        self.label_error = tkinter.Label(master=self,text= "Test", font=self.chat_text_font)
    def create_chatpage(self):
        """
            Crée une page de chat et l'affiche.
        """
        chat_page = tkinter.Frame(self, bg=self.primary_color)
        chat_page.pack(side="top")
        chat_section = ChatSection(chat_page, self.send_button_font, self.chat_text_font, self, self._user)
        threading.Thread(target=chat_section.display_messages).start()

    def create_menu(self):
        """
            Crée une page de menu avec des boutons pour rejoindre le salon de discussion ou quitter l'application.
        """
        page = tkinter.Frame(self, bg=self.primary_color, width=500, height=700,pady=275)
        page.pack(side="top")

        chat = customtkinter.CTkButton(master=page, text="Rejoindre le salon", command =lambda: self.go_pseudo(page))
        chat.pack(side="top")

        quit = customtkinter.CTkButton(master=page, text="Quitter", command =lambda: sys.exit()) # Remplacer par la fonction déconnecte
        quit.pack(side= "top")

    def create_pseudo_menu(self):
        """
            Crée un formulaire permettant à l'utilisateur d'entrer son pseudo pour se connecter au salon de discussion.

        """
        page = tkinter.Frame(self, bg=self.primary_color, width=500, height=700,pady=275)
        page.pack(side="top")

        label_pseudo = customtkinter.CTkLabel(master=page, text="Entrez votre pseudo", font=self.chat_text_font, text_color="#ffffff")
        label_pseudo.pack(side="top")

        input_pseudo = customtkinter.CTkEntry(master=page, placeholder_text="Pseudo...") # On entre le pseudo
        input_pseudo.pack(side="top")

        chat = customtkinter.CTkButton(master=page, text="Rejoindre le salon", command =lambda: self.check_pseudo(input_pseudo.get(), page)) # Quand on clique on va vers le chat
        chat.pack(side="top")

    def check_pseudo(self, pseudo, page):
        """
            Vérifie si le pseudo fourni est valide et tente de se connecter au serveur avec le pseudo fourni.

            Parameter:
                pseudo (str): Le pseudo fourni par l'utilisateur.
                page (tkinter.Frame): La page parent du bouton.

            Returns:
                None

        """
        if(len(pseudo)>20 or len(pseudo) <= 0 or " " in pseudo): # Verif côté client
            self.generate_error("Pas d'espace et pas plus de 20 caractères")
        else:
            if (self._user.connect(pseudo,self._reload_pseudo)): # Verif côté sersveur
                if self.label_error.winfo_ismapped():
                    self.label_error.destroy()
                self.go_chat(page)
            else:
                self.generate_error("Pseudo déjà pris :(")
                self._reload_pseudo = True

    def generate_error(self, message):
        """
            Affiche un message d'erreur sur l'interface graphique.

            Parameter:
                message (str): Le message d'erreur à afficher.

            Returns:
                None
        """
        if self.label_error.winfo_ismapped():
            self.label_error.destroy()
        self.label_error = tkinter.Label(master=self,text= message, font=self.chat_text_font)
        self.label_error.pack(side="top")

    def go_chat(self, old_page):
        """
            Détruit la page actuelle et crée la page de chat où l'utilisateur pourra rejoindre le salon de discussion.

            Parameter:
                old_page (tkinter.Frame): La page actuelle qui doit être détruite.

            Returns:
                None
        """
        old_page.destroy()
        self.create_chatpage()

    def go_pseudo(self, old_page):
        """
            Détruit la page actuelle et crée la page de connexion où l'utilisateur pourra entrer son pseudo.

            Parameter:
                old_page (tkinter.Frame): La page actuelle qui doit être détruite.

            Returns:
                None
        """
        old_page.destroy()
        self.create_pseudo_menu()

    def on_closing(self):
        """
           Déconnecte l'utilisateur et ferme le script python
        """
        if tkinter.messagebox.askokcancel("Quit", "Voulez-vous vous déconnecter ?"):
            self._user.disconnect()
            app.destroy()
            sys.exit()

if __name__ == "__main__":
    app = Clientui()
    app.protocol("WM_DELETE_WINDOW", app.on_closing) #Execute function on_closing() when tkinter window is closed
    app.mainloop()


#  filename: main.py
#  author: Yonah Aviv
#  date created: 2020-11-10 6:21 p.m.
#  last modified: 2020-11-18
#  Pydash: Similar to Geometry Dash, a rhythm based platform game, but programmed using the pygame library in Python

"""CONTROLS
Anywhere -> ESC: exit
Main menu -> 1: go to previous level. 2: go to next level. SPACE: start game.
Game -> SPACE/UP: jump, and activate orb
    orb: jump in midair when activated
If you die or beat the level, press SPACE to restart or go to the next level

"""

import csv
import os
import random

# import the pygame module
import pygame

# will make it easier to use pygame functions
from pygame.math import Vector2
from pygame.draw import rect

# initializes the pygame module
pygame.init()

# creates a screen variable of size 800 x 600
screen = pygame.display.set_mode([800, 600])

# controls the main game while loop
done = False

# controls whether or not to start the game from the main menu
start = False

# sets the frame rate of the program
clock = pygame.time.Clock()

"""
CONSTANTS
"""
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)

"""lambda functions are anonymous functions that you can assign to a variable.
e.g.
1. x = lambda x: x + 2  # takes a parameter x and adds 2 to it
2. print(x(4))
>>6
"""
color = lambda: tuple([random.randint(0, 255) for i in range(3)])  # lambda function for random color, not a constant.
GRAVITY = Vector2(0, 0.86)  # Vector2 is a pygame

"""
Main player class
"""

class Player(pygame.sprite.Sprite):
    """Class for player. Holds update method, win and die variables, collisions and more."""
    win: bool
    died: bool

    def __init__(self, image, platforms, pos, *groups):
        """
        :param image: block face avatar
        :param platforms: obstacles such as coins, blocks, spikes, and orbs
        :param pos: starting position
        :param groups: takes any number of sprite groups.
        """
        super().__init__(*groups)
        self.onGround = False  # player on ground?
        self.platforms = platforms  # obstacles but create a class variable for it
        self.died = False  # player died?
        self.win = False  # player beat level?

        self.image = pygame.transform.smoothscale(image, (32, 32))
        self.rect = self.image.get_rect(center=pos)  # get rect gets a Rect object from the image
        self.jump_amount = 10  # jump strength
        self.particles = []  # player trail
        self.isjump = False  # is the player jumping?
        self.vel = Vector2(0, 0)  # velocity starts at zero

    def draw_particle_trail(self, x, y, color=(255, 255, 255)):
        """draws a trail of particle-rects in a line at random positions behind the player"""

        self.particles.append(
                [[x - 5, y - 8], [random.randint(0, 25) / 10 - 1, random.choice([0, 0])],
                 random.randint(5, 8)])

        for particle in self.particles:
            particle[0][0] += particle[1][0]
            particle[0][1] += particle[1][1]
            particle[2] -= 0.5
            particle[1][0] -= 0.4
            rect(alpha_surf, color,
                 ([int(particle[0][0]), int(particle[0][1])], [int(particle[2]) for i in range(2)]))
            if particle[2] <= 0:
                self.particles.remove(particle)

    def collide(self, yvel, platforms):
        global coins

        for p in platforms:
            if pygame.sprite.collide_rect(self, p):
                """pygame sprite builtin collision method,
                sees if player is colliding with any obstacles"""
                if isinstance(p, Orb) and (keys[pygame.K_UP] or keys[pygame.K_SPACE]):
                    pygame.draw.circle(alpha_surf, (255, 255, 0), p.rect.center, 18)
                    screen.blit(pygame.image.load("images/editor-0.9s-47px.gif"), p.rect.center)
                    self.jump_amount = 12  # gives a little boost when hit orb
                    self.jump()
                    self.jump_amount = 10  # return jump_amount to normal

                if isinstance(p, End):
                    self.win = True

                if isinstance(p, Spike):
                    self.died = True  # die on spike

                if isinstance(p, Coin):
                    # keeps track of all coins throughout the whole game(total of 6 is possible)
                    coins += 1

                    # erases a coin
                    p.rect.x = 0
                    p.rect.y = 0

                if isinstance(p, Platform):  # these are the blocks (may be confusing due to self.platforms)

                    if yvel > 0:
                        """if player is going down(yvel is +)"""
                        self.rect.bottom = p.rect.top  # dont let the player go through the ground
                        self.vel.y = 0  # rest y velocity because player is on ground

                        # set self.onGround to true because player collided with the ground
                        self.onGround = True

                        # reset jump
                        self.isjump = False
                    elif yvel < 0:
                        """if yvel is (-),player collided while jumping"""
                        self.rect.top = p.rect.bottom  # player top is set the bottom of block like it hits it head
                    else:
                        """otherwise, if player collides with a block, he/she dies."""
                        self.vel.x = 0
                        self.rect.right = p.rect.left  # dont let player go through walls
                        self.died = True

    def jump(self):
        self.vel.y = -self.jump_amount  # players vertical velocity is negative so ^

    def update(self):
        """update player"""
        if self.isjump:
            if self.onGround:
                """if player wants to jump and player is on the ground: only then is jump allowed"""
                self.jump()

        if not self.onGround:  # only accelerate with gravity if in the air
            self.vel += GRAVITY  # Gravity falls

            # max falling speed
            if self.vel.y > 100: self.vel.y = 100

        # do x-axis collisions
        self.collide(0, self.platforms)

        # increment in y direction
        self.rect.top += self.vel.y

        # assuming player in the air, and if not it will be set to inversed after collide
        self.onGround = False

        # do y-axis collisions
        self.collide(self.vel.y, self.platforms)

        # check if we won or if player won
        eval_outcome(self.win, self.died)

"""
Obstacle classes
"""

# Parent class
class Draw(pygame.sprite.Sprite):
    """parent class to all obstacle classes; Sprite class"""

    def __init__(self, image, pos, *groups):
        super().__init__(*groups)
        self.image = image
        self.rect = self.image.get_rect(topleft=pos)

#  ====================================================================================================================#
#  classes of all obstacles. this may seem repetitive but it is useful(to my knowledge)
#  ====================================================================================================================#
# children
class Platform(Draw):
    """block"""

    def __init__(self, image, pos, *groups):
        super().__init__(image, pos, *groups)

class Spike(Draw):
    """spike"""

    def __init__(self, image, pos, *groups):
        super().__init__(image, pos, *groups)

class Coin(Draw):
    """coin. get 6 and you win the game"""

    def __init__(self, image, pos, *groups):
        super().__init__(image, pos, *groups)

class Orb(Draw):
    """orb. click space or up arrow while on it to jump in midair"""

    def __init__(self, image, pos, *groups):
        super().__init__(image, pos, *groups)

class Trick(Draw):
    """block, but its a trick because you can go through it"""

    def __init__(self, image, pos, *groups):
        super().__init__(image, pos, *groups)

class End(Draw):
    "place this at the end of the level"

    def __init__(self, image, pos, *groups):
        super().__init__(image, pos, *groups)

"""
Functions
"""

def init_level(map):
    """this is similar to 2d lists. it goes through a list of lists, and creates instances of certain obstacles
    depending on the item in the list"""
    x = 0
    y = 0

    for row in map:
        for col in row:

            if col == "0":
                Platform(block, (x, y), elements)

            if col == "Coin":
                Coin(coin, (x, y), elements)

            if col == "Spike":
                Spike(spike, (x, y), elements)
            if col == "Orb":
                orbs.append([x, y])

                Orb(orb, (x, y), elements)

            if col == "T":
                Trick(trick, (x, y), elements)

            if col == "End":
                End(avatar, (x, y), elements)
            x += 32
        y += 32
        x = 0

def blitRotate(surf, image, pos, originpos: tuple, angle: float):
    """
    rotate the player
    :param surf: Surface
    :param image: image to rotate
    :param pos: position of image
    :param originpos: x, y of the origin to rotate about
    :param angle: angle to rotate
    """
    # calcaulate the axis aligned bounding box of the rotated image
    w, h = image.get_size()
    box = [Vector2(p) for p in [(0, 0), (w, 0), (w, -h), (0, -h)]]
    box_rotate = [p.rotate(angle) for p in box]

    # make sure the player does not overlap, uses a few lambda functions(new things that we did not learn about number1)
    min_box = (min(box_rotate, key=lambda p: p[0])[0], min(box_rotate, key=lambda p: p[1])[1])
    max_box = (max(box_rotate, key=lambda p: p[0])[0], max(box_rotate, key=lambda p: p[1])[1])
    # calculate the translation of the pivot
    pivot = Vector2(originpos[0], -originpos[1])
    pivot_rotate = pivot.rotate(angle)
    pivot_move = pivot_rotate - pivot

    # calculate the upper left origin of the rotated image
    origin = (pos[0] - originpos[0] + min_box[0] - pivot_move[0], pos[1] - originpos[1] - max_box[1] + pivot_move[1])

    # get a rotated image
    rotated_image = pygame.transform.rotozoom(image, angle, 1)

    # rotate and blit the image
    surf.blit(rotated_image, origin)

def won_screen():
    """show this screen when beating a level"""
    global attempts, level, fill
    attempts = 0
    player_sprite.clear(player.image, screen)
    screen.fill(pygame.Color("yellow"))
    txt_win1 = txt_win2 = "Nothing"
    if level == 1:
        if coins == 6:
            txt_win1 = f"Coin{coins}/6! "
            txt_win2 = "the game, Congratulations"
    else:
        txt_win1 = f"level{level}"
        txt_win2 = f"Coins: {coins}/6. "
    txt_win = f"{txt_win1} You beat {txt_win2}! Press SPACE to restart, or ESC to exit"

    won_game = font.render(txt_win, True, BLUE)

    screen.blit(won_game, (200, 300))
    level += 1

    wait_for_key()
    reset()

def death_screen():
    """show this screenon death"""
    global attempts, fill
    fill = 0
    player_sprite.clear(player.image, screen)
    attempts += 1
    game_over = font.render("Game Over. [SPACE] to restart", True, WHITE)

    screen.fill(pygame.Color("sienna1"))
    screen.blits([[game_over, (100, 100)], [tip, (100, 400)]])

    wait_for_key()
    reset()

def eval_outcome(won: bool, died: bool):
    """simple function to run the win or die screen after checking won or died"""
    if won:
        won_screen()
    if died:
        death_screen()

def block_map(level_num):
    """
    :type level_num: rect(screen, BLACK, (0, 0, 32, 32))
    open a csv file that contains the right level map
    """
    lvl = []
    with open(level_num, newline='') as csvfile:
        trash = csv.reader(csvfile, delimiter=',', quotechar='"')
        for row in trash:
            lvl.append(row)
    return lvl

def start_screen():
    """main menu. option to switch level, and controls guide, and game overview."""
    global level
    if not start:
        screen.fill(BLACK)
        if pygame.key.get_pressed()[pygame.K_1]:
            level = 0
        if pygame.key.get_pressed()[pygame.K_2]:
            level = 1

        welcome = font.render(f"Welcome to Pydash. choose level({level + 1}) by keypad", True, WHITE)

        controls = font.render("Controls: jump: Space/Up exit: Esc", True, GREEN)

        screen.blits([[welcome, (100, 100)], [controls, (100, 400)], [tip, (100, 500)]])

        level_memo = font.render(f"Level {level + 1}.", True, (255, 255, 0))
        screen.blit(level_memo, (100, 200))

def reset():
    """resets the sprite groups, music, etc. for death and new level"""
    global player, elements, player_sprite, level

    if level == 1:
        pygame.mixer.music.load(os.path.join("music", "castle-town.mp3"))
    pygame.mixer_music.play()
    player_sprite = pygame.sprite.Group()
    elements = pygame.sprite.Group()
    player = Player(avatar, elements, (150, 150), player_sprite)
    init_level(
            block_map(
                    level_num=levels[level]))

def move_map():
    """moves obstacles along the screen"""
    for sprite in elements:
        sprite.rect.x -= CameraX

def draw_stats(surf, money=0):
    """
    draws progress bar for level, number of attempts, displays coins collected, and progressively changes progress bar
    colors
    """
    global fill
    progress_colors = [pygame.Color("red"), pygame.Color("orange"), pygame.Color("yellow"), pygame.Color("lightgreen"),
                       pygame.Color("green")]

    tries = font.render(f" Attempt {str(attempts)}", True, WHITE)
    BAR_LENGTH = 600
    BAR_HEIGHT = 10
    for i in range(1, money):
        screen.blit(coin, (BAR_LENGTH, 25))
    fill += 0.5
    outline_rect = pygame.Rect(0, 0, BAR_LENGTH, BAR_HEIGHT)
    fill_rect = pygame.Rect(0, 0, fill, BAR_HEIGHT)
    col = progress_colors[int(fill / 100)]
    rect(surf, col, fill_rect, 0, 4)
    rect(surf, WHITE, outline_rect, 3, 4)
    screen.blit(tries, (BAR_LENGTH, 0))

def wait_for_key():
    """separate game loop for waiting for a key press while still running game loop
    """
    global level, start
    waiting = True
    while waiting:
        clock.tick(60)
        pygame.display.flip()

        if not start:
            start_screen()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    start = True
                    waiting = False
                if event.key == pygame.K_ESCAPE:
                    pygame.quit()

def coin_count(coins):
    """counts coins"""
    if coins >= 3:
        coins = 3
    coins += 1
    return coins

def resize(img, size=(32, 32)):
    """resize images
    :param img: image to resize
    :type img: im not sure, probably an object
    :param size: default is 32 because that is the tile size
    :type size: tuple
    :return: resized img

    :rtype:object?
    """
    resized = pygame.transform.smoothscale(img, size)
    return resized

"""
Global variables
"""
font = pygame.font.SysFont("lucidaconsole", 20)

# square block face is main character the icon of the window is the block face
avatar = pygame.image.load(os.path.join("images", "avatar.png"))  # load the main character
pygame.display.set_icon(avatar)
#  this surface has an alpha value with the colors, so the player trail will fade away using opacity
alpha_surf = pygame.Surface(screen.get_size(), pygame.SRCALPHA)

# sprite groups
player_sprite = pygame.sprite.Group()
elements = pygame.sprite.Group()

# images
spike = pygame.image.load(os.path.join("images", "obj-spike.png"))
spike = resize(spike)
coin = pygame.image.load(os.path.join("images", "coin.png"))
coin = pygame.transform.smoothscale(coin, (32, 32))
block = pygame.image.load(os.path.join("images", "block_1.png"))
block = pygame.transform.smoothscale(block, (32, 32))
orb = pygame.image.load((os.path.join("images", "orb-yellow.png")))
orb = pygame.transform.smoothscale(orb, (32, 32))
trick = pygame.image.load((os.path.join("images", "obj-breakable.png")))
trick = pygame.transform.smoothscale(trick, (32, 32))

#  ints
fill = 0
num = 0
CameraX = 0
attempts = 0
coins = 0
angle = 0
level = 0

# list
particles = []
orbs = []
win_cubes = []

# initialize level with
levels = ["level_1.csv", "level_2.csv"]
level_list = block_map(levels[level])
level_width = (len(level_list[0]) * 32)
level_height = len(level_list) * 32
init_level(level_list)

# set window title suitable for game
pygame.display.set_caption('Pydash: Geometry Dash in Python')

# initialize the font variable to draw text later
text = font.render('image', False, (255, 255, 0))

# music
music = pygame.mixer_music.load(os.path.join("music", "bossfight-Vextron.mp3"))
pygame.mixer_music.play()

# bg image
bg = pygame.image.load(os.path.join("images", "bg.png"))

# create object of player class
player = Player(avatar, elements, (150, 150), player_sprite)

# show tip on start and on death
tip = font.render("tip: tap and hold for the first few seconds of the level", True, BLUE)

while not done:
    keys = pygame.key.get_pressed()

    if not start:
        wait_for_key()
        reset()

        start = True

    player.vel.x = 6

    eval_outcome(player.win, player.died)
    if keys[pygame.K_UP] or keys[pygame.K_SPACE]:
        player.isjump = True

    # Reduce the alpha of all pixels on this surface each frame.
    # Control the fade2 speed with the alpha value.

    alpha_surf.fill((255, 255, 255, 1), special_flags=pygame.BLEND_RGBA_MULT)

    player_sprite.update()
    CameraX = player.vel.x  # for moving obstacles
    move_map()  # apply CameraX to all elements

    screen.blit(bg, (0, 0))  # Clear the screen(with the bg)

    player.draw_particle_trail(player.rect.left - 1, player.rect.bottom + 2,
                               WHITE)
    screen.blit(alpha_surf, (0, 0))  # Blit the alpha_surf onto the screen.
    draw_stats(screen, coin_count(coins))

    if player.isjump:
        """rotate the player by an angle and blit it if player is jumping"""
        angle -= 8.1712  # this may be the angle needed to do a 360 deg turn in the length covered in one jump by player
        blitRotate(screen, player.image, player.rect.center, (16, 16), angle)
    else:
        """if player.isjump is false, then just blit it normally(by using Group().draw() for sprites"""
        player_sprite.draw(screen)  # draw player sprite group
    elements.draw(screen)  # draw all other obstacles

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                """User friendly exit"""
                done = True
            if event.key == pygame.K_2:
                """change level by keypad"""
                player.jump_amount += 1

            if event.key == pygame.K_1:
                """change level by keypad"""

                player.jump_amount -= 1

    pygame.display.flip()
    clock.tick(60)
pygame.quit()


from typing import (
    Any,
    Callable,
    cast,
    Dict,
    IO,
    Iterable,
    List,
    Optional,
    Tuple,
    TypeVar,
    Union,
)
import io
import json
import shutil
import time
import threading
from io import BytesIO, TextIOWrapper
import pandas as pd
from scipy import sparse
import torch
from accern_xyme.types import MinimalQueueStatsResponse, QueueStatus

VERBOSE = False
FILE_UPLOAD_CHUNK_SIZE = 100 * 1024  # 100kb
FILE_HASH_CHUNK_SIZE = FILE_UPLOAD_CHUNK_SIZE
MAX_RETRY = 20
RETRY_SLEEP = 5.0

RT = TypeVar('RT')

ByteResponse = Union[pd.DataFrame, dict, IO[bytes], List[dict]]

def set_verbose() -> None:
    global VERBOSE

    import logging
    import http.client as http_client

    http_client.HTTPConnection.debuglevel = 1  # type: ignore
    logging.basicConfig()
    logging.getLogger().setLevel(logging.DEBUG)
    requests_log = logging.getLogger("requests.packages.urllib3")
    requests_log.setLevel(logging.DEBUG)
    requests_log.propagate = True
    VERBOSE = True

def is_verbose() -> bool:
    return VERBOSE

MINUTE = 60.0
HOUR = 60.0 * MINUTE
DAY = 24.0 * HOUR
WEEK = 7.0 * DAY
YEAR = 365.0 * DAY

def get_age(cur_time: float, other_time: Optional[float]) -> str:
    if other_time is None:
        return "never"
    diff = cur_time - other_time
    if diff < 0.0:
        return "soon"
    if diff < 0.1:
        return "now"
    if diff < 1.0:
        return "<1s"
    if diff < MINUTE:
        return "<1m"
    if diff < HOUR:
        return f"{diff // MINUTE:.0f}m"
    if diff < DAY:
        return f"{diff // HOUR:.0f}h"
    if diff < WEEK:
        return f"{diff // DAY:.0f}d"
    if diff < YEAR:
        return f"{diff // WEEK:.0f}w"
    return f"{diff // YEAR:.0f}y"

def safe_opt_num(num: Optional[float]) -> Tuple[bool, float]:
    if num is None:
        return (False, 0.0)
    return (True, num)

def set_file_upload_chunk_size(size: int) -> None:
    global FILE_UPLOAD_CHUNK_SIZE

    FILE_UPLOAD_CHUNK_SIZE = size

def get_file_upload_chunk_size() -> int:
    return FILE_UPLOAD_CHUNK_SIZE

def set_file_hash_chunk_size(size: int) -> None:
    global FILE_HASH_CHUNK_SIZE

    FILE_HASH_CHUNK_SIZE = size

def get_file_hash_chunk_size() -> int:
    return FILE_HASH_CHUNK_SIZE

def get_max_retry() -> int:
    """Returns the maximum number of retries on connection errors.

    Returns:
        int -- The number of times a connection tries to be established.
    """
    return MAX_RETRY

def get_retry_sleep() -> float:
    return RETRY_SLEEP

def maybe_timestamp(timestamp: Optional[str]) -> Optional[pd.Timestamp]:
    return None if timestamp is None else pd.Timestamp(timestamp)

def df_to_csv(df: pd.DataFrame) -> BytesIO:
    bio = BytesIO()
    wrap = TextIOWrapper(bio, encoding="utf-8", write_through=True)
    df.to_csv(wrap, index=False)
    wrap.detach()
    bio.seek(0)
    return bio

MPL_SETUP = False

def setup_matplotlib() -> None:
    global MPL_SETUP

    if MPL_SETUP:
        return
    from pandas.plotting import register_matplotlib_converters

    register_matplotlib_converters()
    MPL_SETUP = True

IS_JUPYTER: Optional[bool] = None

def is_jupyter() -> bool:
    global IS_JUPYTER

    if IS_JUPYTER is not None:
        return IS_JUPYTER

    try:
        from IPython import get_ipython

        IS_JUPYTER = get_ipython() is not None
    except (NameError, ModuleNotFoundError) as _:
        IS_JUPYTER = False
    return IS_JUPYTER

def get_progress_bar(out: Optional[IO[Any]]) -> Callable[[float, bool], None]:
    # pylint: disable=unused-argument

    def no_bar(progress: float, final: bool) -> None:
        return

    if out is None:
        return no_bar

    io_out: IO[Any] = out

    if is_jupyter():
        from IPython.display import ProgressBar

        mul = 1000
        bar = ProgressBar(mul)
        bar.display()

        def jupyter_bar(progress: float, final: bool) -> None:
            bar.progress = int(progress * mul)
            end = "\n" if final else "\r"
            io_out.write(f"{progress * 100.0:.2f}%{end}")

        return jupyter_bar

    cols, _ = shutil.get_terminal_size((80, 20))
    max_len = len(" 100.00%")
    border = "|"

    def stdout_bar(progress: float, final: bool) -> None:
        pstr = f" {progress * 100.0:.2f}%"
        cur_len = len(pstr)
        if cur_len < max_len:
            pstr = f"{' ' * (max_len - cur_len)}{pstr}"
        end = "\n" if final else "\r"
        full_len = len(border) * 2 + len(pstr) + len(end)
        bar = "█" * int(progress * (cols - full_len))
        mid = ' ' * max(0, cols - full_len - len(bar))
        io_out.write(f"{border}{bar}{mid}{border}{pstr}{end}")

    return stdout_bar

def get_file_hash(buff: IO[bytes]) -> str:
    """Return sha224 hash of data files

    Args:
        buff (IO[bytes]): Data used to generate the hash.

    Returns:
        str: A sha224 hashed string.
    """
    import hashlib

    sha = hashlib.sha224()
    chunk_size = FILE_HASH_CHUNK_SIZE
    init_pos = buff.seek(0, io.SEEK_CUR)
    while True:
        chunk = buff.read(chunk_size)
        if not chunk:
            break
        sha.update(chunk)
    buff.seek(init_pos, io.SEEK_SET)
    return sha.hexdigest()

def interpret_ctype(data: IO[bytes], ctype: str) -> ByteResponse:
    if ctype == "application/json":
        return json.load(data)
    if ctype == "application/problem+json":
        res = json.load(data)
        raise ServerSideError(res["errMessage"])
    if ctype == "application/parquet":
        return pd.read_parquet(data)
    if ctype == "application/torch":
        return torch.load(data)
    if ctype == "application/npz":
        return sparse.load_npz(data)
    if ctype == "application/jsonl":
        return [
            json.load(BytesIO(line))
            for line in data
        ]
    content = BytesIO(data.read())
    if ctype == "application/octet-stream":
        return content
    # NOTE: try best guess...
    try:
        return pd.read_parquet(content)
    except OSError:
        pass
    content.seek(0)
    try:
        return json.load(content)
    except json.decoder.JSONDecodeError:
        pass
    except UnicodeDecodeError:
        pass
    content.seek(0)
    try:
        return [
            json.load(BytesIO(line))
            for line in content
        ]
    except json.decoder.JSONDecodeError:
        pass
    except UnicodeDecodeError:
        pass
    content.seek(0)
    return content

def merge_ctype(datas: List[ByteResponse], ctype: str) -> ByteResponse:
    if ctype == "application/json":
        return cast(ByteResponse, datas)
    if ctype == "application/parquet":
        return pd.concat(datas)
    if ctype == "application/torch":
        return torch.cat(datas, dim=0)  # pylint: disable=no-member
    if ctype == "application/npz":
        return sparse.vstack(datas)
    if ctype == "application/jsonl":
        return [
            cast(Any, obj)
            for arr in datas
            for obj in arr
        ]
    return cast(ByteResponse, datas)

def async_compute(
        arr: List[Any],
        start: Callable[[List[Any]], List[RT]],
        get: Callable[[RT], ByteResponse],
        check_queue: Callable[[], MinimalQueueStatsResponse],
        get_status: Callable[[List[RT]], Dict[RT, QueueStatus]],
        max_buff: int,
        block_size: int,
        num_threads: int) -> Iterable[ByteResponse]:
    assert max_buff > 0
    assert block_size > 0
    assert num_threads > 0
    arr = list(arr)
    done: List[bool] = [False]
    end_produce: List[bool] = [False]
    exc: List[Optional[BaseException]] = [None]
    cond = threading.Condition()
    ids: Dict[RT, int] = {}
    res: Dict[int, ByteResponse] = {}
    min_size_th = 20
    main_threads = 3

    def get_waiting_count(remote_queue: MinimalQueueStatsResponse) -> int:
        return remote_queue["total"] - remote_queue["active"]

    def can_push_more() -> bool:
        if exc[0] is not None:
            return True
        if len(ids) < max_buff:
            return True
        try:
            waiting_count = get_waiting_count(check_queue())
        except BaseException as e:  # pylint: disable=broad-except
            if exc[0] is None:
                exc[0] = e
            return True
        return waiting_count < max_buff

    def push(cur: List[Any], start_pos: int) -> None:
        if len(cur) <= min_size_th * block_size:
            try:
                for block_ix in range(0, len(cur), block_size):
                    ids.update({
                        cur_id: cur_ix + start_pos + block_ix
                        for (cur_ix, cur_id) in enumerate(
                            start(cur[block_ix:block_ix + block_size]))
                    })
            except BaseException as e:  # pylint: disable=broad-except
                if exc[0] is None:
                    exc[0] = e
        else:
            half_ix: int = len(cur) // 2
            args = (cur[half_ix:], start_pos + half_ix)
            push_th = threading.Thread(target=push, args=args)
            push_th.start()
            push(cur[:half_ix], start_pos)
            push_th.join()

    def produce() -> None:
        try:
            pos = 0
            while pos < len(arr):
                with cond:
                    while not cond.wait_for(can_push_more, timeout=0.1):
                        pass
                if exc[0] is not None:
                    break
                start_pos = pos
                try:
                    remote_queue = check_queue()
                except BaseException as e:  # pylint: disable=broad-except
                    if exc[0] is None:
                        exc[0] = e
                    continue
                waiting_count = get_waiting_count(remote_queue)
                add_more = max(
                    max_buff - len(ids),
                    max_buff - waiting_count)
                if add_more > 0:
                    cur = arr[pos:pos + add_more]
                    pos += len(cur)
                    push(cur, start_pos)
                with cond:
                    cond.notify_all()
        finally:
            end_produce[0] = True
            with cond:
                cond.notify_all()

    def get_one(t_ix: int, t_id: RT) -> None:
        try:
            res[t_ix] = get(t_id)
        except KeyError:
            pass
        except BaseException as e:  # pylint: disable=broad-except
            if exc[0] is None:
                exc[0] = e

    def consume() -> None:
        while not done[0]:
            with cond:
                while not cond.wait_for(
                        lambda: exc[0] is not None or done[0] or len(ids) > 0,
                        timeout=0.1):
                    pass
            do_wait = False
            while ids:
                do_wait = True
                sorted_ids = sorted(ids.items(), key=lambda v: v[1])
                lookahead = main_threads * num_threads
                check_ids = [v[0] for v in sorted_ids[0:lookahead]]
                if not check_ids:
                    continue
                status = get_status(check_ids)
                ths: List[threading.Thread] = []
                for (t_id, t_status) in status.items():
                    if t_status in ("waiting", "running"):
                        continue
                    do_wait = False
                    try:
                        t_ix = ids.pop(t_id)
                        args = (t_ix, t_id)
                        r_th = threading.Thread(target=get_one, args=args)
                        r_th.start()
                        ths.append(r_th)
                    except KeyError:
                        pass
                for r_th in ths:
                    r_th.join()
                if do_wait:
                    time.sleep(0.1)
                else:
                    with cond:
                        cond.notify_all()

    try:
        prod_th = threading.Thread(target=produce)
        prod_th.start()
        consume_ths = [
            threading.Thread(target=consume)
            for _ in range(main_threads)
        ]
        for th in consume_ths:
            th.start()
        with cond:
            cond.notify_all()
        yield_ix = 0
        while yield_ix < len(arr):
            with cond:
                while not cond.wait_for(
                        lambda: exc[0] is not None or bool(res), timeout=0.1):
                    pass
            if exc[0] is not None:
                break
            try:
                while res:
                    yield res.pop(yield_ix)
                    yield_ix += 1
            except KeyError:
                pass
        if exc[0] is not None:
            with cond:
                cond.wait_for(lambda: end_produce[0])
    finally:
        done[0] = True
    with cond:
        cond.notify_all()
    prod_th.join()
    for th in consume_ths:
        th.join()
    raise_e = exc[0]
    if isinstance(raise_e, BaseException):
        raise raise_e  # pylint: disable=raising-bad-type

class ServerSideError(Exception):
    def __init__(self, message: str) -> None:
        self._message = message
        super().__init__(self._message)

    def __str__(self) -> str:
        return f"Error from xyme backend: \n{self._message}"


import scrapy
from scrapy import Request
import json
import time
from .cookies import Crawler
from ..io import *
import sys

class IrapSpider(scrapy.Spider):
    name = 'irap'
    crawler = Crawler('syy@yzig.com.cn', '!QAZ2wsx')
    cookies = crawler.get_cookies()['value']
    expiry = time.time_ns() / 1e9 + 7200
    io = jsonIO(scrapy.Spider.logger, config={"data": "entity"})
    _io = MongoIO(scrapy.Spider.logger)
    cnt = 1

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.API = self.name
        self.entities = self.getEntities()
        self.keys = self.getCrawled()

    def getEntities(self):
        data = self.io.readData("entities")['data']
        return [item['code'] for item in data]

    def getCrawled(self):
        return self._io.readDataKeys(self.name)

    def updateCookie(self):
        if time.time_ns() / 1e9 > self.expiry + 100:
            self.cookies = self.crawler.get_cookies()['value']
            self.expiry = time.time_ns() / 1e9 + 7200

    def start_requests(self):
        with open("iRAPcrawler/spiders/headers.json", 'r') as fp:
            headers_dict = json.load(fp)
        val = headers_dict[self.API]
        self.updateCookie()
        val['headers']["authorization"] = "Bearer {}".format(self.cookies)
        val['headers']["cookies"] = "antd-pro-authority=ROLE_IEWS_ANALYST;Authentication={}".format(self.cookies)

        for entity in self.entities:
            if entity in self.keys:
                continue
            yield Request(method=val['method'],
                          url=val['url'],
                          callback=self.parse,
                          headers=val['headers'],
                          body=val['body'] % entity)
            # if self.cnt < 2:
            #     self.cnt += 1
            # else:
            #     break

    def parse(self, response, **kwargs):
        return {"tag": self.API, "data": json.loads(response.text.strip(r'"').replace(r'\"', r'"'))}

class RiskRegionSpider(IrapSpider):
    name = 'RISK_REGION'

    def parse(self, response, **kwargs):
        s = json.loads(response.text.strip(r'"').replace(r'\"', r'"'))
        if len(s['data']) == 0:
            return {"tag": self.API, "data": {}}
        return {"tag": self.API, "data": {s['data'][0][0]["entityCode"]: s['data'][0]}}

class RiskRegionIndustrySpider(IrapSpider):
    name = 'RISK_REGION_INDUSTRY'

    def parse(self, response, **kwargs):
        s = json.loads(response.text.strip(r'"').replace(r'\"', r'"'))
        if len(s['data']) == 0:
            return {"tag": self.API, "data": {}}
        return {"tag": self.API, "data": {s['data'][0][0]["entityCode"]: s['data'][0]}}

class CumDefaultRateSpider(IrapSpider):
    name = 'CUM_Default_Rate'

    def parse(self, response, **kwargs):
        s = json.loads(response.text.strip(r'"').replace(r'\"', r'"'))
        if len(s['data']) == 0:
            return {"tag": self.API, "data": {}}
        return {"tag": self.API, "data": {s['data'][0][0]["objectCode"]: s['data'][0]}}

class RiskFactor(IrapSpider):
    name = 'RiskFactor'

    def parse(self, response, **kwargs):
        s = json.loads(response.text.strip(r'"').replace(r'\"', r'"'))
        if len(s['data']) == 0:
            return {"tag": self.API, "data": {}}
        return {"tag": self.API, "data": {s['data'][0][0]["objectCode"]: s['data'][0]}}

class DefaultRateTimeSeries(IrapSpider):
    name = 'DefaultRateTimeSeries'

    def parse(self, response, **kwargs):
        s = json.loads(response.text.strip(r'"').replace(r'\"', r'"'))
        if len(s['data']) == 0:
            return {"tag": self.API, "data": {}}
        return {"tag": self.API, "data": {s['data'][0][0]["objectCode"]: s['data'][0]}}

class RISK_FACTOR(IrapSpider):
    name = 'RISK_FACTOR'

    def parse(self, response, **kwargs):
        s = json.loads(response.text.strip(r'"').replace(r'\"', r'"'))
        if len(s['data']) == 0:
            return {"tag": self.API, "data": {}}
        return {"tag": self.API, "data": {s['data'][0][0]["objectCode"]: s['data'][0]}}

class DEFAULT_STRUCTURE(IrapSpider):
    name = 'DEFAULT_STRUCTURE'

    def parse(self, response, **kwargs):
        s = json.loads(response.text.strip(r'"').replace(r'\"', r'"'))
        if len(s['data']) == 0:
            return {"tag": self.API, "data": {}}
        return {"tag": self.API, "data": {s['data'][0][0]["objectCode"]: s['data'][0]}}

class GETDATA(IrapSpider):
    name = 'GETDATA'

    def parse(self, response, **kwargs):
        s = json.loads(response.text.strip(r'"').replace(r'\"', r'"'))
        # if len(s['data']) == 0:
        #     return {"tag": self.API, "data": {}}
        return {"tag": self.API, "data": {1: s}}

class DEFAULT_ANALYSIS(IrapSpider):
    name = 'DEFAULT_ANALYSIS'

    def parse(self, response, **kwargs):
        s = json.loads(response.text.strip(r'"').replace(r'\"', r'"'))
        if len(s['data']) == 0:
            return {"tag": self.API, "data": {}}
        return {"tag": self.API, "data": {s['data'][0][0]["objectCode"]: s['data'][0]}}

class DTD_LEVEL(IrapSpider):
    name = "DTD_LEVEL"

    def parse(self, response, **kwargs):
        s = json.loads(response.text.strip(r'"').replace(r'\"', r'"'))
        if len(s['data']) == 0:
            return {"tag": self.API, "data": {}}
        return {"tag": self.API, "data": {s['data'][0][0]["objectCode"]: s['data'][0]}}


def primes(n):
    sieve = [True for i in range(int(n))]
    for i in range(3,int(n**0.5)+1,2):
        if sieve[i]:
            sieve[i*i::2*i] = [False for i in range(int((n-i*i-1)/(2*i))+1)]
    return [2] + [i for i in range(3,n,2) if sieve[i]]

primeslist = primes(2**16)

def tran(num, base):
    number = 0
    num = str(num)
    length = len(num)
    for i in range(length):
        number += int(num[i])*base**(length-i-1)
    return number

def large(N,J):
    count = 0
    for i in range(2**(N-1)+1,2**N,2):
        out = str(bin(i))[2:]
        for j in range(2,11):
            num = tran(str(bin(i))[2:],j)
            div = divisor(num)
            if not div:
                out = None
                break
            else:
                out = out + " " + str(div)
        if out:
            print(out)
            count += 1
            if count >= J:
                break
    return

def divisor(num):
    for i in primeslist:
        if num % i == 0 and i < num:
            return i
    return None

T = int(input())

for index in range(T):
    N, J = map(int, input().split())
    print("Case #"+str(index+1)+": ")
    large(N,J)


"""
Student facing code for Tantrix Solitaire
http://www.jaapsch.net/puzzles/tantrix.htm

Game is played on a grid of hexagonal tiles.
All ten tiles for Tantrix Solitaire and place in a corner of the grid.
Click on a tile to rotate it.  Cick and drag to move a tile.

Goal is to position the 10 provided tiles to form
a yellow, red or  blue loop of length 10
"""

# Core modeling idea - a triangular grid of hexagonal tiles are
# model by integer tuples of the form (i, j, k)
# where i + j + k == size and i, j, k >= 0.

# Each hexagon has a neighbor in one of six directions
# These directions are modeled by the differences between the
# tuples of these adjacent tiles

# Numbered directions for hexagonal grid, ordered clockwise at 60 degree intervals
DIRECTIONS = {0 : (-1, 0, 1), 1 : (-1, 1, 0), 2 : (0, 1, -1),
              3 : (1, 0, -1), 4 : (1, -1, 0), 5 : (0,  -1, 1)}

def reverse_direction(direction):
    """
    Helper function that returns opposite direction on hexagonal grid
    """
    num_directions = len(DIRECTIONS)
    return (direction + num_directions / 2) % num_directions

# Color codes for ten tiles in Tantrix Solitaire
# "B" denotes "Blue", "R" denotes "Red", "Y" denotes "Yellow"
SOLITAIRE_CODES = ["BBRRYY", "BBRYYR", "BBYRRY", "BRYBYR", "RBYRYB",
                "YBRYRB", "BBRYRY", "BBYRYR", "YYBRBR", "YYRBRB"]

# Minimal size of grid to allow placement of 10 tiles
MINIMAL_GRID_SIZE = 4

class Tantrix:
    """
    Basic Tantrix game class
    """

    def __init__(self, size):
        """
        Create a triangular grid of hexagons with size + 1 tiles on each side.
        """
        assert size >= MINIMAL_GRID_SIZE
        self._tiling_size = size

        # Initialize dictionary tile_value to contain codes for ten
        # tiles in Solitaire Tantrix in one 4x4 corner of grid
        self._tile_value = {}
        counter = 0
        for index_i in range(MINIMAL_GRID_SIZE):
            for index_j in range(MINIMAL_GRID_SIZE - index_i):
                index_k = self._tiling_size - (index_i + index_j)
                grid_index = (index_i, index_j, index_k)
                self.place_tile(grid_index, SOLITAIRE_CODES[counter])
                counter += 1

    def __str__(self):
        """
        Return string of dictionary of tile positions and values
        """
        return str(self._tile_value)

    def get_tiling_size(self):
        """
        Return size of board for GUI
        """
        return self._tiling_size

    def tile_exists(self, index):
        """
        Return whether a tile with given index exists
        """
        return self._tile_value.has_key(index)

    def place_tile(self, index, code):
        """
        Play a tile with code at cell with given index
        """
        self._tile_value[index] = code

    def remove_tile(self, index):
        """
        Remove a tile at cell with given index
        and return the code value for that tile
        """
        return self._tile_value.pop(index)

    def rotate_tile(self, index):
        """
        Rotate a tile clockwise at cell with given index
        """
        value = self._tile_value[index]
        new_value = value[-1] + value[:-1]
        self._tile_value[index] = new_value

    def get_code(self, index):
        """
        Return the code of the tile at cell with given index
        """
        return self._tile_value[index]

    def get_neighbor(self, index, direction):
        """
        Return the index of the tile neighboring the tile with given index in given direction
        """
        neighbor_offset = DIRECTIONS[direction]
        neighbor_index = tuple([index[dim] + neighbor_offset[dim] for dim in range(3)])
        return neighbor_index

    def is_legal(self):
        """
        Check whether a tile configuration obeys color matching rules for adjacent tiles
        """

        for tile_index in self._tile_value.keys():
            tile_code = self._tile_value[tile_index]
            for direction in DIRECTIONS.keys():
                neighbor_index = self.get_neighbor(tile_index, direction)
                if self.tile_exists(neighbor_index):
                    neighbor_code = self.get_code(neighbor_index)
                    if tile_code[direction] != neighbor_code[reverse_direction(direction)]:
                        return False
        return True

    def has_loop(self, color):
        """
        Check whether a tile configuration has a loop of size 10 of given color
        """
        if not self.is_legal():
            return False

        # choose arbitrary starting point
        tile_indices = self._tile_value.keys()
        start_index = tile_indices[0]
        start_code = self._tile_value[start_index]
        next_direction = start_code.find(color)
        next_index = self.get_neighbor(start_index, next_direction)
        current_length = 1

        # loop through neighboring tiles that match given color
        while start_index != next_index:
            current_index = next_index
            if not self.tile_exists(current_index):
                return False
            current_code = self._tile_value[current_index]
            if current_code.find(color) == reverse_direction(next_direction):
                next_direction = current_code.rfind(color)
            else:
                next_direction = current_code.find(color)
            next_index = self.get_neighbor(current_index, next_direction)
            current_length += 1

        return current_length == len(SOLITAIRE_CODES)

# run GUI for Tantrix
import poc_tantrix_gui
poc_tantrix_gui.TantrixGUI(Tantrix(6))


import requests
import random
import json
import csv
from time import sleep
from bs4 import BeautifulSoup

# url = "https://health-diet.ru/table_calorie/?utm_source=leftMenu&utm_medium=table_calorie"

headers = {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
    "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/114.0"
}

# req = requests.get(url, headers=headers)
# src = req.text
# # print(src)

# with open("index.html", "w") as file:
#     file.write(src)

# with open("index.html") as file:
#     src = file.read()

# soup = BeautifulSoup(src, "lxml")

# all_products_hrefs = soup.find_all(class_="mzr-tc-group-item-href")
# all_categories_dict = {}

# for item in all_products_hrefs:
#     item_text = item.text
#     item_url = "https://health-diet.ru" + item.get("href")

#     all_categories_dict[item_text] = item_url

# with open("all_categories_dict.json", "w") as file:
#     json.dump(all_categories_dict, file, indent=4, ensure_ascii=False)

with open("all_categories_dict.json") as file:
    all_categories = json.load(file)

rep = ["'", "-", " ", ","]
iteration_count = int(len(all_categories)) - 1
count = 0
print(f"The number of iterations: {iteration_count}")

for category_name, category_href in all_categories.items():
    for item in rep:
        if item in category_name:
            category_name = category_name.replace(item, "_")

    req = requests.get(url=category_href, headers=headers)
    src = req.text

    with open(f"data/{count}_{category_name}.html", "w") as file:
        file.write(src)

    with open(f"data/{count}_{category_name}.html") as file:
        src = file.read()

    soup = BeautifulSoup(src, "lxml")

    alert_block = soup.find(class_="uk-alert-danger")
    if alert_block is not None:
    	continue

    table_head = soup.find(class_="uk-table mzr-tc-group-table uk-table-hover uk-table-striped uk-table-condensed").find("tr").find_all("th")

    product = table_head[0].text
    calories = table_head[1].text
    proteins = table_head[2].text
    fats = table_head[3].text
    carbohydrates = table_head[4].text

    with open(f"data/{count}_{category_name}.csv", "w", encoding="utf-8") as file:
        writer = csv.writer(file)
        writer.writerow(
            (
                product,
                calories,
                proteins,
                fats,
                carbohydrates
            )
        )

    products_data = soup.find(class_="mzr-tc-group-table").find("tbody").find_all("tr")

    product_info = []
    for item in products_data:
        product_tds = item.find_all("td")

        title = product_tds[0].find("a").text
        calories = product_tds[1].text
        proteins = product_tds[2].text
        fats = product_tds[3].text
        carbohydrates = product_tds[4].text

        product_info.append(
            {
                "Title": title,
                "Calories": calories,
                "Proteins": proteins,
                "Fats": fats,
                "Carbohydrates": carbohydrates
            }
        )

        with open(f"data/{count}_{category_name}.csv", "a", encoding="utf-8") as file:
            writer = csv.writer(file)
            writer.writerow(
                (
                    title,
                    calories,
                    proteins,
                    fats,
                    carbohydrates
                )
            )
    with open(f"data/{count}_{category_name}.json", "a", encoding="utf-8") as file:
    	json.dump(product_info, file, indent=4, ensure_ascii=False)

    count += 1
    print(f"# Iteration {count}. {category_name} was written...")
    iteration_count = iteration_count - 1

    if iteration_count == 0:
    	print("Finish")
    	break

    print(f"Remained iterations: {iteration_count}")
    sleep(0.1)


from pyspark import SparkContext, SparkConf
from pyspark.sql import SparkSession

spark_context = SparkContext(master="local",appName="exam")

def mrLog(lines):
    # lines = '201224233712 - INFO -  DSE512002 - AUDIO_ISSUE - noise/audio issue by 2018AP0453 logged for 2018AP0453'
    event_issues = ['TEST_INTERRUPTION', 'AUDIO_ISSUE', 'VIDEO_ISSUE']
    lines_split = lines.split(" - ")
    time_stamp = lines_split[0]
    subject = lines_split[2]
    log_event = lines_split[3]
    description = lines_split[4]
    if description.__contains__("dur"):
        text = description.split(" for ")[1]
        text = text.split("dur = ")
        student_id = text[0]
        chat_duration = int(text[1].strip('s'))
    else:
        student_id = description.split(" for ")[1]
        chat_duration = 0
    if log_event in event_issues or description.__contains__("failed"):
        is_issue = 1
    else:
        is_issue = 0

    return time_stamp, subject, student_id, log_event, description, chat_duration, is_issue

# print(time_stamp, subject, log_event, description, student_id, chat_duration)
if __name__ == '__main__':
    x = spark_context.textFile("hdfs://localhost:9000/logs/FlumeData.*").map(mrLog)
    # print(x.collect())
    spark = SparkSession.builder.appName("exam").enableHiveSupport().getOrCreate()
    df = spark.createDataFrame(x, ['time_stamp', 'subject', 'student_id', 'log_event', 'description', 'chat_duration',
                                   'is_issue'])
    df.show()
    df.createOrReplaceTempView("table1")
    spark.sql("drop table if exists exam_log")
    spark.sql("create table exam_log as select * from table1")


from textwrap import indent
import requests
import json
url = 'https://zoo-animal-api.herokuapp.com/animals/rand'
list = []
for i in range(10):
    randomRequests = requests.get(url).json()
    list.append(randomRequests)

dictionary={}
dictionary['practice'] = list

jsonAnimalObjejct = json.dumps(dictionary, indent=4)
jsonAnimalFile = open('animal.json', 'w')
jsonAnimalFile.write(jsonAnimalObjejct)
jsonAnimalFile.close()

jsonData = open('animal.json', 'r', encoding='utf-8')
animalData = json.load(jsonData)
jsonData.close()

# I am going to sort information of animals
listAnimal = animalData['practice']
l = len(listAnimal)
newListAnimalData = []
for i in range(l):
    oneAnimalData = {}
    oneAnimalData['animalName'] = listAnimal[i]['name']
    oneAnimalData['animalType'] = listAnimal[i]['animal_type']
    oneAnimalData['imageLink'] = listAnimal[i]['image_link']
    oneAnimalData['lifeSpan'] = listAnimal[i]['lifespan']
    newListAnimalData.append(oneAnimalData)

newAnimalData = {}
newAnimalData['dataOfSeveralAnimals'] = newListAnimalData

writeJson = json.dumps(newAnimalData, indent=4)
newAnimal = open('newAnimal.json', 'w')
newAnimal.write(writeJson)
newAnimal.close()


from . import BaseRepository
from models import BalanceMovement
from db import connection

class BalanceMovementRepository(BaseRepository):
    def basic_table_config(self):
        self.cursor.execute(
            """CREATE TABLE IF NOT EXISTS Balance_Movement
             (id TEXT, value REAL, type TEXT, description TEXT, person_id TEXT)"""
        )

    def insert(self, balance: BalanceMovement):
        insert_stmt = "INSERT INTO Balance_Movement (id, value, type, description, person_id) VALUES (?,?,?,?,?);"
        data_tuple = (
            str(balance.id),
            balance.value,
            balance.type.value,
            balance.description,
            balance.person_id,
        )
        self.cursor.execute(insert_stmt, data_tuple)
        self.commit()

    def get_by_id(self, id: str):
        select_stmt = "SELECT * FROM Balance_Movement WHERE ID = ?"
        self.cursor.execute(select_stmt, (id,))
        return self.cursor.fetchone()

    def get_by_person_id(self, id: str):
        select_stmt = "SELECT * FROM Balance_Movement WHERE person_id = ?"
        self.cursor.execute(select_stmt, (id,))
        return self.cursor.fetchall()

    def get_all(self):
        select_stmt = "SELECT * FROM Balance_Movement"
        self.cursor.execute(select_stmt)
        return self.cursor.fetchall()

balance_movement_repository = BalanceMovementRepository(connection)


# https://pytorch.org/docs/stable/onnx.html

import numpy as np
import onnxruntime as ort

ort_session = ort.InferenceSession('tmp.onnx')

x = {
    'a': np.random.randn(1, 4).astype(np.float32),
    'b': np.random.randn(1, 4).astype(np.float32),
}

outputs = ort_session.run(None, x)

print(outputs)
print([o.shape for o in outputs])


from __future__ import annotations
from typing import List, Callable, Iterable, Optional, Tuple, Union

import routingblocks
from .cluster_removal import ClusterRemovalOperator, DistanceBasedClusterMemberSelector

class StationSeedSelector:
    def __init__(self, stations: List[routingblocks.Vertex], randgen: Optional[routingblocks.Randgen] = None):
        self._stations = stations
        self._randgen = randgen

    def _get_station_locations(self, solution: routingblocks.Solution):
        return [
            y for x in self._stations for y in solution.find(x.vertex_id)
        ]

    def __call__(self, evaluation: routingblocks.Evaluation, solution: routingblocks.Solution,
                 removed_vertices: List[routingblocks.NodeLocation]) -> routingblocks.NodeLocation:
        # Get all stations in the solution not removed yet
        stations = [x for x in self._get_station_locations(solution) if
                    x not in removed_vertices]
        if len(stations) == 0:
            raise StopIteration
        # Return a random one
        picked_station_location = stations[self._randgen.randint(0, len(stations) - 1)]
        return picked_station_location

class StationVicinityRemovalOperator(routingblocks.DestroyOperator):
    """
    Station vicinity removal is a specialized cluster removal operator designed to reorder customer visits in the
    vicinity of replenishment stations. The operator defines the vicinity of a station by selecting a random radius
    based on a percentage of the maximum distance between vertices. It then randomly chooses a recharging station
    and removes the station along with vertices within the selected radius, repeating this process until the
    desired number of vertices are removed.
    """

    def __init__(self, instance: routingblocks.Instance,
                 get_distance: Callable[[routingblocks.Vertex, routingblocks.Vertex], float],
                 min_radius_factor: float, max_radius_factor: float,
                 randgen: Optional[routingblocks.Randgen]):
        """
        :param instance: Instance the operator will be applied to
        :param get_distance: A function taking two vertices and returning the distance between them. The distance can be arbitrary, i.e., does not have to correspond to the evaluation function.
        :param min_radius_factor: Minimum of the interval the radius is picked from
        :param max_radius_factor: Maximum of the interval the radius is picked from
        :param randgen: Random number generator
        """
        routingblocks.DestroyOperator.__init__(self)
        self._cluster_removal_operator = ClusterRemovalOperator(
            seed_selector=StationSeedSelector(list(instance.stations), randgen),
            cluster_member_selector=DistanceBasedClusterMemberSelector(
                vertices=[*instance.stations, *instance.customers],
                get_distance=get_distance,
                min_radius_factor=min_radius_factor,
                max_radius_factor=max_radius_factor,
                randgen=randgen)
        )

    def can_apply_to(self, solution: routingblocks.Solution) -> bool:
        """
        Station vicinity removal can be applied to any solution that contains at least one station.
        """
        return any(node.vertex.is_station
                   for route in solution.routes for node in route)

    def name(self) -> str:
        return "StationVicinityRemovalOperator"

    def apply(self, evaluation: routingblocks.Evaluation, solution: routingblocks.Solution,
              number_of_removed_vertices: int) -> List[int]:
        return self._cluster_removal_operator.apply(evaluation, solution, number_of_removed_vertices)


import math
#input = open("input.txt","r").readline

river = [[i,0] for i in range(1001)]

for i in range(int(input())):
	river[int(input())][1] += 1

river = sorted(river,key=lambda x:x[1],reverse=True)
#print(river)
stuff = {}
for i in range(len(river)):
	freq = river[i][1]
	if freq not in stuff:
		stuff[freq] = [river[i][0]]
	else:

		stuff[freq].append(river[i][0])

for i in stuff:
	stuff[i]=stuff[i][::-1]

#print(stuff)
if len(stuff[max(stuff)]) > 1:
	print(abs(stuff[max(stuff)][0]-stuff[max(stuff)][-1]))
else:
	one = stuff[max(stuff)][0]

	stuff.pop(max(stuff))
	best = -1*math.inf
	for n in stuff[max(stuff)]:
		if abs(one-n) > best:
			best = abs(one-n)
	print(best)


# -*- coding: utf-8 -*-
__author__ = "Paul Schifferer <dm@sweetrpg.com>"
"""
"""

from .manager import PersonList, PersonDetail, PersonVolumeRelationship
from ...blueprints import api

def setup_routes(app):
    # app.logger.info("Registering person models...")
    # for model_name, model_info in person_model_info.items():
    #     APIData.add_model(model_name, model_info)

    app.logger.info("Setting up routes for Persons API")
    # api = Api(app)
    api.route(PersonList, "person_list", "/persons/")
    api.route(PersonDetail, "person_detail", "/persons/<id>")
    api.route(PersonVolumeRelationship, "person_volumes", "/persons/<id>/relationships/volumes")


def binarySearch(num):
    start = 0
    end = N-1
    while start <= end:
        mid = (start+end)//2
        if num == book1[mid]:
            return 1
        if num < book1[mid]:
            end = mid - 1
        else:
            start = mid + 1

    return 0

T = int(input())
for tc in range(1, T+1):
    N = int(input())
    book1 = sorted(list(map(int, input().split())))

    M = int(input())
    book2 = list(map(int, input().split()))

    for num in book2:
        if(binarySearch(num)):
            print(1)
        else:
            print(0)