"""
Class: CS230-5
Name: Peter Shield
Description: Final Project- Displaying data from the volcanoes csv file
"""

import streamlit as st
import pydeck as pdk
import matplotlib.pyplot as plt
import pandas as pd
import random

st.set_page_config(initial_sidebar_state="collapsed")
VOLCANO_FILE = "volcanoes.csv"
df_volcano = pd.read_csv(VOLCANO_FILE)

# needed to clean up hanging (es) and (s) to compile data
for i in df_volcano['Primary Volcano Type']:
    if i[-4:] == "(es)":
        df_volcano['Primary Volcano Type'] = df_volcano['Primary Volcano Type'].replace(i, i[:-4])
    elif i[-3:] == "(s)":
        df_volcano['Primary Volcano Type'] = df_volcano['Primary Volcano Type'].replace(i, i[:-3])
    else:
        df_volcano['Primary Volcano Type'] = df_volcano['Primary Volcano Type'].replace(i, i.strip("?"))
# needed to format these columns in order for all of the words in the multi-word values to be title case
cols_with_probs = ["Country", "Primary Volcano Type", "Activity Evidence", "Region", "Subregion", "Dominant Rock Type"]
for col in cols_with_probs:
    df_volcano[col] = df_volcano[col].str.title()
df_volcano.rename(columns={"Latitude": 'lat', "Longitude": 'lon'}, inplace=True)
df_volcano = df_volcano.dropna()

st.title("Final Project")

st.sidebar.title("Data Selector")

# returns a dictionary with the unique values as keys and the frequency as values
def dict_count_items(sdf):
    unique_list = []
    for dat in sdf.str.lower().tolist():
        if dat.lower() not in unique_list:
            unique_list.append(dat.lower())
    res_dct = {j.title(): sdf.str.lower().tolist().count(j) for j in unique_list}
    return res_dct

# Creates a list of layers for st.pydeck_chart for each element from dataframes filtered by column or selected element
def create_layers(list_of_df, colors):
    return [pdk.Layer(type='ScatterplotLayer',
                           data=list_of_df[i],
                           get_position='[lon, lat]',
                           radius_scale=6,
                           radius_min_pixels=7,
                           radius_max_pixels=7,
                           pickable=True,
                           filled=True,
                           opacity=0.8,
                           get_fill_color=[255*j for j in colors[i]])
            for i in range(len(list_of_df))]

# Returns a list of dataframes split up by unique element in a given column- to be used in create_layers()
def filter_by_column(df, column_name):
    return [df.loc[(df == i).any(axis=1)] for i in dict_count_items(df[column_name]).keys()]

# Returns a list of top n most frequent items in a dictionary
def top_n_ele(d, n=10):
    out = list(dict(sorted(d.items(), key=lambda item: item[1])).items())[-n:]
    return out

# Returns a list of dataframes split up by selected unique elements in a given column- to be used in create_layers()
def filter_by_ele(df, ele_list):
    return [df.loc[(df == i).any(axis=1)] for i in ele_list]

def main():
    selected_column = st.sidebar.selectbox("Please select the column you want to show data and map for:",
                                           ["", "Country", "Primary Volcano Type", "Activity Evidence",
                                            "Region", "Subregion", "Dominant Rock Type"])

    if selected_column == "":
        st.write("Please select data to view in the sidebar")
    else:
        st.header("Charts")
        stmap = True
        selected_data_view = st.sidebar.selectbox("How would you like to view?",
                                                  ["All Data", "10 Most Frequent", "Select Data Point"])
        if selected_data_view == "Select Data Point":
            stmap = False
            selected_data_points = st.sidebar.multiselect("Which data points would you like to display",
                                                          sorted(dict_count_items(df_volcano[selected_column]).keys()))
            if len(selected_data_points) == 0:
                st.sidebar.warning("Please select at least one data point")
            dict_selected_points = {i: dict_count_items(df_volcano[selected_column])[i] for i in selected_data_points}
            data_point_bool = st.sidebar.radio("Show graph and map with only selected data points?", ["No", "Yes"])

        selected_chart = st.sidebar.radio("Please select the chart you want to show",
                                          ["No Chart", "Bar Chart", "Pie Chart"])
        c = [[random.uniform(0, 1), random.uniform(0, 1), random.uniform(0, 1)] for i
             in dict_count_items(df_volcano[selected_column]).keys()]
        if selected_chart == "Bar Chart":
            if selected_data_view == "10 Most Frequent":
                if len(filter_by_column(df_volcano, selected_column)) >= 10:
                    fig, ax = plt.subplots()
                    ax.bar([i[0] for i in top_n_ele(dict_count_items(df_volcano[selected_column]))],
                           [i[1] for i in top_n_ele(dict_count_items(df_volcano[selected_column]))], color=c)
                    plt.xticks(rotation=30, ha='right')
                    plt.ylabel("Frequency")
                    st.pyplot(fig)
                else:
                    stmap = False
                    st.warning("Unable to show chart; The column you selected has fewer than 10 unique values")
            elif selected_data_view == "Select Data Point" and data_point_bool == "Yes":
                if len(dict_selected_points) == 0:
                    st.warning("Please select at least one data point to display the chart")
                else:
                    fig, ax = plt.subplots()
                    ax.bar(dict_selected_points.keys(),
                           dict_selected_points.values(), color=c)
                    plt.xticks(rotation=30, ha='right')
                    plt.ylabel("Frequency")
                    st.pyplot(fig)
            else:
                fig, ax = plt.subplots()
                ax.bar(dict_count_items(df_volcano[selected_column]).keys(),
                       dict_count_items(df_volcano[selected_column]).values(), color=c)
                plt.xticks(rotation=30, ha='right')
                plt.ylabel("Frequency")
                st.pyplot(fig)
                if len(dict_count_items(df_volcano[selected_column]).keys()) > 20:
                    st.warning("Caution! There many be too many datapoints in the chart. Select the '10 Most Frequent' \
                    view or try selecting fewer data points for better results.")
        elif selected_chart == "Pie Chart":
            if selected_data_view == "10 Most Frequent":
                if len(filter_by_column(df_volcano, selected_column)) >= 10:
                    fig, ax = plt.subplots()
                    ax.pie([i[1] for i in top_n_ele(dict_count_items(df_volcano[selected_column]))],
                           labels=[i[0] for i in top_n_ele(dict_count_items(df_volcano[selected_column]))],
                           autopct="%.1f%%", colors=c)
                    # ax.legend(loc='best', bbox_to_anchor=(0.5, 0., 0.5, 0.5))
                    st.pyplot(fig)
                else:
                    stmap = False
                    st.warning("Unable to show chart; The column you selected has fewer than 10 unique values")
            elif selected_data_view == "Select Data Point" and data_point_bool == "Yes":
                if len(dict_selected_points) == 0:
                    st.warning("Please select at least one data point to display the chart")
                elif sum(dict_selected_points.values()) == 0:
                    st.warning("Warning! The data points you have selected all have a value of 0")
                else:
                    fig, ax = plt.subplots()
                    ax.pie(dict_selected_points.values(),
                           labels=dict_selected_points.keys(),
                           autopct="%.1f%%", colors=c)
                    st.pyplot(fig)
            else:
                fig, ax = plt.subplots()
                ax.pie(dict_count_items(df_volcano[selected_column]).values(),
                       labels=dict_count_items(df_volcano[selected_column]).keys(), autopct="%.1f%%", colors=c)
                st.pyplot(fig)
                if len(dict_count_items(df_volcano[selected_column]).keys()) > 20:
                    st.warning("Caution! There many be too many datapoints in the chart. Select the '10 Most Frequent' \
                    view or try selecting fewer data points for better results.")
        elif selected_chart == "No Chart":
            st.write("No chart is currently being displayed")
        if selected_data_view == "Select Data Point":
            if len(dict_selected_points.keys()) > 20:
                st.warning("Caution! There many be too many datapoints in the chart. Select the '10 Most Frequent' \
                view or try selecting fewer data points for better results.")
            st.write("Totals for above")
            for i in dict_selected_points.keys():
                st.caption(f"{i}: {dict_selected_points[i]}")

        selected_map = st.sidebar.radio("Please select the map", ["No Map", "Simple", "Info", "Selected Data"])

        if selected_map == "Simple":
            st.title('Simple Map')
            st.map(df_volcano)
        elif selected_map == "Info":

            st.title("Informational")

            # Create custom icons
            ICON_URL = "https://cdn4.iconfinder.com/data/icons/nature-life-in-color/128/volcano-eruption-color-512.png"

            # Format your icon
            icon_data = {
                "url": ICON_URL,
                "width": 75,
                "height": 75,
                "anchorY": 0
            }

            # Add icons to your dataframe
            df_volcano["icon_data"] = None
            for i in df_volcano.index:
                df_volcano["icon_data"][i] = icon_data

            # Create a layer with your custom icon
            icon_layer = pdk.Layer(type="IconLayer",
                                   data=df_volcano,
                                   get_icon="icon_data",
                                   get_position='[lon,lat]',
                                   get_size=4,
                                   size_scale=10,
                                   pickable=True)

            # Create a view of the map: https://pydeck.gl/view.html
            view_state = pdk.ViewState(
                latitude=df_volcano["lat"].mean(),
                longitude=df_volcano["lon"].mean(),
                zoom=1,
                pitch=0
            )

            # stylish tool tip: https://pydeck.gl/tooltip.html?highlight=tooltip
            tool_tip = {
                "html": "Name: {Volcano Name}
Location: {Country}
Elevation (m): {Elevation (m)}",
                "style": {"backgroundColor": "blue",
                          "color": "white"}
                }

            icon_map = pdk.Deck(
                map_style='mapbox://styles/mapbox/navigation-day-v1',
                layers=[icon_layer],
                initial_view_state=view_state,
                tooltip=tool_tip)

            st.pydeck_chart(icon_map)
        elif selected_map == "Selected Data":

            st.header("Selected Data")

            # Create a layer with your custom icon
            if selected_data_view == "All Data":
                layer1 = create_layers(filter_by_column(df_volcano, selected_column), c)
            elif selected_data_view == "10 Most Frequent":
                if len(filter_by_column(df_volcano, selected_column)) >= 10:
                    layer1 = create_layers(filter_by_ele(df_volcano, [i[0] for i in top_n_ele(dict_count_items(df_volcano[selected_column]))]), c)
                else:
                    stmap = False
                    st.warning("The column you selected has fewer than 10 unique values")
            elif selected_data_view == "Select Data Point":
                stmap = True
                if data_point_bool == "Yes":
                    layer1 = create_layers(filter_by_ele(df_volcano, dict_selected_points.keys()), c)
                else:
                    layer1 = create_layers(filter_by_column(df_volcano, selected_column), c)
            else:
                layer1 = pdk.Layer(type='ScatterplotLayer',
                                   data=df_volcano,
                                   get_position='[lon, lat]',
                                   radius_scale=6,
                                   radius_min_pixels=7,
                                   radius_max_pixels=7,
                                   pickable=True,
                                   filled=True,
                                   opacity=0.8,
                                   get_fill_color=[0,0,255])
            # Create a view of the map
            view_state = pdk.ViewState(
                latitude=df_volcano["lat"].mean(),
                longitude=df_volcano["lon"].mean(),
                zoom=1,
                pitch=0
            )
            if stmap:
                # stylish tool tip
                html = ("Name: {Volcano Name}
Location: {Country}
Elevation (m): {Elevation (m)}"
                        + f"
{selected_column}: "+"{"+f"{selected_column}"+"}")
                tool_tip = {
                    "html": html,
                    "style": {"backgroundColor": "red",
                              "color": "white"}
                    }

                data_map = pdk.Deck(
                    map_style='mapbox://styles/mapbox/navigation-day-v1',
                    layers=[layer1],
                    initial_view_state=view_state,
                    tooltip=tool_tip)

                st.pydeck_chart(data_map)
    st.header("Volcano Comparison")
    search = [st.text_input("Please enter a name to search by:").title()]
    st.write("To view entire dataframe, enter nothing above.")
    st.dataframe(df_volcano[df_volcano['Volcano Name'].str.findall('^(?:'+'|'.join(search) + ')').apply(len) > 0])
    selected_volcano = st.multiselect("Please choose 2 Volcanoes to compare", sorted(dict_count_items(df_volcano["Volcano Name"]).keys()))
    show_res = st.button("Show comparison", disabled=False)

    if show_res:
        if len(selected_volcano) == 2:
            frame1 = df_volcano[df_volcano['Volcano Name'].str.endswith(tuple([selected_volcano[0]]))]
            frame2 = df_volcano[df_volcano['Volcano Name'].str.endswith(tuple([selected_volcano[1]]))]
            st.dataframe(pd.concat([frame1, frame2]))
        else:
            st.warning("You have to select exactly 2 volcanoes")

    show_comp_map = st.radio("Show map of two volcanoes?", ["No", "Yes"])
    if show_comp_map == "Yes":
        if len(selected_volcano) == 2:
            df1 = pd.concat([df_volcano[df_volcano['Volcano Name'].str.endswith(tuple([selected_volcano[0]]))],
                             df_volcano[df_volcano['Volcano Name'].str.endswith(tuple([selected_volcano[1]]))]])
            # Create a layer with your custom icon
            comp_layer = pdk.Layer(type='ScatterplotLayer',
                                   data=df1,
                                   get_position='[lon, lat]',
                                   radius_scale=6,
                                   radius_min_pixels=7,
                                   radius_max_pixels=7,
                                   pickable=True,
                                   filled=True,
                                   opacity=0.8,
                                   get_fill_color=[255, 165, 0])

            # Create a view of the map: https://pydeck.gl/view.html
            view_state = pdk.ViewState(
                latitude=df1["lat"].mean(),
                longitude=df1["lon"].mean(),
                zoom=1,
                pitch=0
            )
            # stylish tool tip: https://pydeck.gl/tooltip.html?highlight=tooltip
            tool_tip = {
                "html": "Name: {Volcano Name}
Location: {Country}
Elevation (m): {Elevation (m)}",
                "style": {"backgroundColor": "purple",
                          "color": "white"}
            }
            data_map = pdk.Deck(
                map_style='mapbox://styles/mapbox/navigation-day-v1',
                layers=[comp_layer],
                initial_view_state=view_state,
                tooltip=tool_tip)

            st.pydeck_chart(data_map)

            fig, ax = plt.subplots()

            comp_colors = ["", ""]
            for i in df1["Elevation (m)"]:
                st.write()
                if i < 0:
                    comp_colors[df1["Elevation (m)"].tolist().index(i)] = "blue"
                else:
                    comp_colors[df1["Elevation (m)"].tolist().index(i)] = "red"
            ax.bar(df1["Volcano Name"],
                   df1["Elevation (m)"], color=comp_colors)
            plt.ylabel("Elevation (m)")
            st.pyplot(fig)
        else:
            st.warning("You have to select exactly 2 volcanoes")

    st.markdown("***"
                "***")

    balloons = st.button("Celebrate!", disabled=False)
    if balloons:
        st.balloons()

if __name__ == "__main__":
    main()


import logging, os
import MotionStartDetector, UserHandler, MotionTimeUserMatching, FullClipExtractor, TrackerClipExtractor
from Enums import ActionOptions, ClipTypes

logger = logging.getLogger(__name__)  #Set logger to reflect the current file

class Application:
    def __init__(self):
        logger.debug("Appliation created")

    def run(self, arg_input_video_folder, arg_user_root_folder, arg_selection):
        logger.info("Running Application with video folder: " + arg_input_video_folder + " user folder: " + arg_user_root_folder + "\n")

        # Create objects
        tmp_motion_start_detector = MotionStartDetector.MotionStartDetector()
        tmp_user_handler = UserHandler.UserHandler()
        tmp_motion_time_user_matching = MotionTimeUserMatching.MotionTimeUserMatching()
        tmp_full_clip_cut_extractor = FullClipExtractor.FullClipExtractor()
        tmp_tracker_clip_extractor = TrackerClipExtractor.TrackerClipExtractor()

        if not os.path.exists(arg_input_video_folder):
            raise ValueError("Video folder is not a valid folder: " + arg_input_video_folder)
        if not os.path.exists(arg_user_root_folder):
            raise ValueError("User folder is not a valid folder: " + arg_user_root_folder)

        if ActionOptions.GENERATE_MOTION_FILES.value in arg_selection:
            tmp_motion_start_detector.create_motion_start_files(arg_input_video_folder)

        if ActionOptions.INIT_USERS.value in arg_selection:
            tmp_user_handler.init(arg_user_root_folder)

        if ActionOptions.MATCH_LOCATION_IN_MOTION_FILES.value in arg_selection:
            tmp_motion_time_user_matching.match_motion_start_times_with_users(arg_input_video_folder, tmp_user_handler)

        if ActionOptions.GENERATE_FULL_CLIP_OUTPUTS.value in arg_selection:
            clip_specification_list = tmp_user_handler.create_clip_specifications(ClipTypes.FULL_CLIP)
            tmp_full_clip_cut_extractor.extract_clips_from_list(clip_specification_list)

        if ActionOptions.GENERATE_TRACKER_CLIP_OUTPUTS.value in arg_selection:
            clip_specification_list = tmp_user_handler.create_clip_specifications(ClipTypes.TRACKER_CLIP)
            tmp_tracker_clip_extractor.extract_clips_from_list(clip_specification_list)


import sys
sys.stdin = open("input_20207.txt")

# 연속된 두 일자에 각각 일정이 1개 이상 있다면 일정이 연속되었다고 표현
# 연속된 모든 일정은 하나의 직사각형에 포함
# 연속된 일정을 모두 감싸는 작은 직사각형의 크기만큼 코팅지 자름

# n = 일정 개수 / s = 시작날짜 / e = 종료날짜

n = int(input())
calender = [0] * 366

for _ in range(n):
    s, e = map(int, input().split())
    for i in range(s, e+1):
        calender[i] += 1   # 일정 표시하기

# print(calender)
width = 0
height = 0
ans = 0

for i in range(1, 366):
    if calender[i] == 1:
        width += 1

print(width)


"""
These exercises focuses on the creation of a generator.
Write a prime number generator; you can use the prime number program you
wrote earlier in the book but convert it into a generator. The generator should take a
limit to give the maximum size of the loop you use to generate the prime numbers.
You could call this prime_number_generator().
You should be able to run the following code:

number = input('Please input the number:')
if number.isnumeric():
num = int(number)
if num <= 2:
print('Number must be greater than 2')
else:
for prime in prime_number_generator(num):
print(prime, end=', ')
else:
print('Must be a positive integer')
If the user enters 27 then the output would be:
Please input the number:27
2, 3, 5, 7, 11, 13, 17, 19, 23,

Now create the infinite_prime_number_generator(); this generator
does not have a limit and will keep generating prime numbers until it is no longer used.
You should be able to use this prime number generator as follows:

prime = infinite_prime_number_generator()
print(next(prime))
print(next(prime))
print(next(prime))
print(next(prime))
print(next(prime))
"""

def divides(number, candidate):
    if number == 1:
        return True
    if candidate % number == 0 or candidate % 2 == 0:
        return False
    else:
        return divides(number-1, candidate)

def is_prime(num):
    return divides(num - 1, num)

def prime_number_generator(num):
    val = 2
    while val <= num:
        if is_prime(val):
            yield val
            val += 1
        else:
            val += 1

number = input('Please input the number:')
if number.isnumeric():
    num = int(number)
    if num <= 2:
        print('Number must be greater than 2')
    else:
        for prime in prime_number_generator(num):
            print(prime, end=', ')
else:
    print('Must be a positive integer')

30_Iterable, iterators and generators.py


import random, math, re

class Hangman:
    def __init__(self):
        self.tried_list = []
        self.answer_list = ['apple', 'microsoft', 'facebook', 'netflix', 'amazon', 'uber', 'lyft', 'twitter', 'google']
        self.random_number = math.floor(random.random() * len(self.answer_list))
        self.goal = self.answer_list[self.random_number]
        self.chance = len(self.goal)
        self.result = '_' * len(self.goal)

        self.play_game()

    def play_game(self):
        print('welcome to hangman game!\nanswer would be one of the biggest tech company\ngood luck!\n')
        while self.chance > 0:
            letter = input('please enter one of alphabet between \"a\" and \"z\": ' )
            self.update_result(letter)
            if self.result in self.answer_list:
                return self.winning_condition('congraturation!!\nstart again?\nplease enter \'yes\' or \'y\', otherwise enter anykey to exit here: ')

        if self.chance == 0:
            return self.winning_condition('lost game\nstart again?\nplease enter \'yes\' or \'y\', otherwise enter any key to exit here ')

    def update_result(self, letter):
        letter = self.is_valid_length(letter)
        letter = self.is_valid_alpha(letter)
        letter = self.check_duplicate(letter)
        if not self.goal.find(letter.lower()) == -1:
            #found it
            idx = self.goal.find(letter.lower())
            while idx != -1:
                self.result = self.result[0:idx] + letter.lower() + self.result[idx+1:]
                idx = self.goal.find(letter.lower(), idx+1)
            print(f'\n{self.result}\n')
            if not letter in self.tried_list:
                self.tried_list.append(letter)
            else:
                pass
        else:
            #not found it
            print(f'\n{self.result}\n')
            self.chance -= 1
        print(f'\nyou left {self.chance} chance')

    def check_duplicate(self, letter):
        while True:
            if letter in self.tried_list:
                idx = self.tried_list.index(letter)
                letter = input(f'you already used \'{self.tried_list[idx]}\'\nplease enter another alphabet: ' )
            else:
                break;
        return letter

    def is_valid_alpha(self, letter):
        while True:
            if letter.isalpha():
                break;
            else:
                letter = input('please enter alphabet only between \"a\" and \"z\": ' )
        return letter

    def is_valid_length(self, letter):
        while True:
            if len(letter) > 1:
                letter = input('please enter one letter between\"a\" and \"z\": ' )
            else:
                break;
        return letter

    def winning_condition(self, text):
        answer = input(text)
        if answer.lower() == 'yes' or answer.lower() == 'y':
            return Hangman()
        else:
            print('bye bye')
            return

Hangman()


import sys
import csv

def extract_tokens(s):
    extracted_tokens = set(())
    parts = s.split('+')
    for token in parts:
        amount_and_name = token.split()
        if len(amount_and_name) == 4:
            extracted_tokens.add(amount_and_name[1])
            extracted_tokens.add(amount_and_name[3])
        elif len(amount_and_name) == 2:
            extracted_tokens.add(amount_and_name[1])
        elif len(amount_and_name) == 3:
            extracted_tokens.add(amount_and_name[1] + ' ' + amount_and_name[2])
    return extracted_tokens

def extract_values(s):
    values = {}
    parts = s.split('+')
    for token in parts:
        amount_and_name = token.split()
        if len(amount_and_name) == 4:
            values[amount_and_name[1]] = amount_and_name[0].replace(',', '')
            values[amount_and_name[3]] = amount_and_name[2].replace(',', '')
        elif len(amount_and_name) == 2:
            values[amount_and_name[1]] = amount_and_name[0].replace(',', '')
        elif len(amount_and_name) == 3:
            token_name = amount_and_name[1] + ' ' + amount_and_name[2]
            values[token_name] = amount_and_name[0].replace(',', '')
    return values

def extract_all_tokens(csv_file_name):
    all_tokens = set(())
    with open(csv_file_name) as csv_file:
        csv_reader = csv.DictReader(csv_file)
        for r in csv_reader:
            all_tokens.update(extract_tokens(r['Value_IN(Token)']))
            all_tokens.update(extract_tokens(r['Value_OUT(Token)']))
    return all_tokens

def extract_all_rows(csv_file_name):
    all_rows = []
    with open(csv_file_name) as csv_file:
        csv_reader = csv.DictReader(csv_file)
        for row in csv_reader:
            all_rows.append(row)
    return all_rows

if len(sys.argv) != 2:
    print("Please provide the file path as command argument")
else:
    field_names = ['Txhash', 'Blockno', 'DateTime', 'From', 'To',
                   'Historical $Price/Eth', 'Status', 'ErrCode', 'Method',
                   'Value_IN(ETH)', 'Value_OUT(ETH)', 'TxnFee(ETH)',
                   'Balance(ETH)']
    tokens = extract_all_tokens(sys.argv[1])
    for token in tokens:
        field_names.append('Value_IN({})'.format(token))
        field_names.append('Value_OUT({})'.format(token))
        field_names.append('Balance({})'.format(token))
    rows = extract_all_rows(sys.argv[1])
    with open('transactions_rewritten.csv', 'w') as csvfile:
        writer = csv.DictWriter(csvfile, fieldnames=field_names)
        writer.writeheader()
        balances = {'ETH': 0}
        for token in tokens:
            balances[token] = 0
        for row in rows:
            values_in = extract_values(row['Value_IN(Token)'])
            for t in extract_tokens(row['Value_IN(Token)']):
                row['Value_IN({})'.format(t)] = values_in[t]
            values_out = extract_values(row['Value_OUT(Token)'])
            for t in extract_tokens(row['Value_OUT(Token)']):
                row['Value_OUT({})'.format(t)] = values_out[t]
            for token in tokens:
                if 'Value_IN({})'.format(token) not in row:
                    row['Value_IN({})'.format(token)] = 0
                if 'Value_OUT({})'.format(token) not in row:
                    row['Value_OUT({})'.format(token)] = 0
            eth_in = float(row['Value_IN(ETH)'])
            eth_out = float(row['Value_OUT(ETH)'])
            tx_fee = float(row['TxnFee(ETH)'])
            row['Balance(ETH)'] = balances['ETH'] + eth_in - eth_out - tx_fee
            balances['ETH'] = row['Balance(ETH)']
            for token in tokens:
                token_in = float(row['Value_IN({})'.format(token)])
                token_out = float(row['Value_OUT({})'.format(token)])
                token_key = 'Balance({})'.format(token)
                row[token_key] = balances[token] + token_in - token_out
                # handling precision error
                if row[token_key] < 1e-10:
                    row[token_key] = 0
                balances[token] = row['Balance({})'.format(token)]
            row.pop('Value_IN(Token)')
            row.pop('Value_OUT(Token)')
            writer.writerow(row)


import random
import os

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.optim.lr_scheduler import ReduceLROnPlateau
from torch.utils.data import DataLoader

from tqdm.notebook import tqdm

save_path = os.getcwd()
save_path = os.path.join(save_path, "Models/SavedModels")

# from importlib import reload
# import utils
# utils = reload(utils)
# evaluate_metrics = utils.evaluate_metrics

from utils import evaluate_metrics

class EFLSTM(nn.Module):
    def __init__(self, input_size, hidden_size, output_size, dropout):
        super(EFLSTM, self).__init__()
        self.input_size = input_size
        self.hidden_size = hidden_size
        self.output_size = output_size
        self.dropout = nn.Dropout(dropout)

        self.lstm = nn.LSTM(input_size, hidden_size, batch_first = True)
        self.fc1 = nn.Linear(hidden_size, hidden_size)
        self.fc2 = nn.Linear(hidden_size, output_size)
        self.relu = nn.ReLU()

    def forward(self, x):
        x, _ =  self.lstm(x)
        x = x[:, -1, :]
        x = self.fc1(x)
        x = self.relu(x)
        x = self.dropout(x)
        x = self.fc2(x)
        return x.squeeze()

def train_ef(config, model_config = None):

    def train(mode, X_train, y_train, loss_fn, batch_size):
        epoch_loss = 0
        model.train()
        N = X_train.shape[0]
        num_batches = 0
        loader = DataLoader(range(N), batch_size = batch_size, shuffle = True)
        for idx in loader:
            num_batches += 1
            optimizer.zero_grad()
            X_batch = X_train[idx].to(device); y_batch = y_train[idx].to(device)
            y_hat = model(X_batch)
            loss = loss_fn(y_hat, y_batch)
            loss.backward()
            optimizer.step()
            epoch_loss += loss.item()

        return epoch_loss / num_batches

    def evaluate(model, X_valid, y_valid, loss_fn):
        model.eval()
        with torch.no_grad():
            X_valid, y_valid = X_valid.to(device), y_valid.to(device)
            y_hat = model(X_valid)
            loss = loss_fn(y_hat, y_valid)
        return loss.item()

    def predict(model, X_test, y_test, loss_fn):
        model.eval()
        with torch.no_grad():
            X_test, y_test = X_test.to(device), y_test.to(device)
            predictions = model(X_test)
            loss = loss_fn(predictions, y_test)

        return predictions, loss.item()

    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

    X_train = config["X_train"]
    y_train = config["y_train"]
    X_valid = config["X_valid"]
    y_valid = config["y_valid"]
    X_test = config["X_test"]
    X_test_m = config["X_test_m"]
    X_test_s = config["X_test_s"]
    y_test = config["y_test"]

    input_size = X_test.shape[2]

    output_size = 1 if config["dataset_name"] in ["mosi", "mosei"] else 4

    models_config = []

    if model_config:
        models_config.append(model_config)
    else:
        for i in range(3):
            model_config = {
                "batch_size": 32,
                "lr": random.choice([0.0001 ,0.0005, 0.001]),
                "hidden_size": random.choice([64, 128, 256, 512]),
                "dropout": random.choice([0.2, 0.5, 0.7]),
                "epochs": 150}
            models_config.append(model_config)

    best_model = None
    best_model_valdation_loss = 10e10
    for model_config in models_config:
        print("\nNew Model")
        print(model_config)
        hidden_size = model_config["hidden_size"]
        lr = model_config["lr"]
        batch_size = model_config["batch_size"]
        dropout = model_config["dropout"]
        epochs = model_config["epochs"]

        model = EFLSTM(input_size, hidden_size, output_size, dropout)
        optimizer = optim.Adam(model.parameters(),lr=lr)
        loss_fn = nn.L1Loss() if config["dataset_name"] in ["mosi", "mosei"] else nn.CrossEntropyLoss()
        scheduler = ReduceLROnPlateau(optimizer,mode='min',patience=100,factor=0.5,verbose=True)
        model.to(device)

        best_validation_loss = 10e10
        num_trials = 3
        curr_patience = patience = 5

        for epoch in tqdm(range(epochs)):
            train_loss = train(model, X_train, y_train, loss_fn, batch_size)
            validation_loss = evaluate(model, X_valid, y_valid, loss_fn)
            scheduler.step(validation_loss)
            print(f"Epoch {epoch}: train loss {train_loss:.4f} | valid_loss: {validation_loss:.4f}") if epoch % 10 == 0 else None

            if validation_loss <= best_validation_loss:
                best_validation_loss = validation_loss
                torch.save(model.state_dict(), os.path.join(save_path, "model_ef.std"))
                torch.save(optimizer.state_dict(), os.path.join(save_path, 'optim_ef.std'))
                curr_patience = patience
            else:
                curr_patience -= 1
                if curr_patience <= -1:
                    num_trials -= 1
                    curr_patience = patience
                    # ran out of patience, load previous best model
                    model.load_state_dict(torch.load(os.path.join(save_path, "model_ef.std")))
                    optimizer.load_state_dict(torch.load(os.path.join(save_path, "optim_ef.std")))

            if num_trials <= 0:
                print("Running out of patience, early stopping.")
                break

        model.load_state_dict(torch.load(os.path.join(save_path, "model_ef.std")))
        print("Current Best Val Loss", best_validation_loss)

        if best_validation_loss < best_model_valdation_loss:
            best_model_valdation_loss = best_validation_loss
            best_model = model

    print("\n\nEvaluation Metric of Best Model\n" + "-" * 120)
    predictions, test_loss = predict(best_model, X_test, y_test, loss_fn)
    print("\n\nX_test")
    evaluate_metrics(config["dataset_name"], predictions, y_test)
    print("-" * 120)
    if X_test_m != None:
        print("\n\nX_test_m")
        predictions_m, test_loss_m = predict(best_model, X_test_m, y_test, loss_fn)
        evaluate_metrics(config["dataset_name"], predictions_m, y_test)
        print("-" * 120)
    if X_test_s != None:
        predictions_s, test_loss_s = predict(best_model, X_test_s, y_test, loss_fn)
        print("\n\nX_test_s")
        evaluate_metrics(config["dataset_name"], predictions_s, y_test)

        print("-" * 120)


import torch

class stftm_loss(object):
    def __init__(self, frame_size=320, frame_shift=160, loss_type='mae'):
        super(stftm_loss, self).__init__()
        self.frame_size = frame_size
        self.frame_shift = frame_shift
        self.loss_type = loss_type

    def __call__(self, est, data_info):
        # est : est waveform
        mask = data_info[3].cuda()
        est_spec1 = est[0]
        raw_spec = torch.stft(data_info[1].cuda(), n_fft=1024, hop_length=128, win_length=1024,
                             window=torch.hann_window(1024).cuda(), onesided=True,
                             return_complex=False).permute([0,2,1,3])

        if self.loss_type == 'mse':
            loss1 = torch.sum((((est_spec1 - raw_spec) ** 2)*mask)) / torch.sum(mask)

        return loss1

class mag_loss(object):
    def __init__(self, frame_size=320, frame_shift=160, loss_type='mae'):
        self.frame_size = frame_size
        self.frame_shift = frame_shift
        self.loss_type = loss_type
        self.mag_stft = mag_STFT(self.frame_size, self.frame_shift)

    def __call__(self, est, data_info):
        # est : [est_mag,noisy_phase]
        # data_info : [mixture,speech,noise,mask,nframe,len_speech]
        mask = data_info[3].cuda()

        raw_mag = self.mag_stft.transform(data_info[1])[0].permute(0, 2, 1).cuda()
        est_mag = est[0]
        if self.loss_type == 'mse':
            loss = torch.sum((est_mag - raw_mag) ** 2) / torch.sum(mask)
        elif self.loss_type == 'mae':
            loss = torch.sum(torch.abs(est_mag - raw_mag)) / torch.sum(mask)
        return loss

class wavemse_loss(object):
    def __call__(self, est, data_info):
        mask = data_info[3]
        raw = data_info[1]
        loss = torch.sum((est - raw) ** 2) / torch.sum(mask)
        return loss

class sisdr_loss(object):
    def __init__(self):
        self.EPSILON = 1e-7

    def __call__(self, est, data_info):
        raw = data_info[1]
        batch = raw.size(0)
        raw = raw.contiguous().view(-1).unsqueeze(-1)
        est = est.contiguous().view(-1).unsqueeze(-1)
        Rss = torch.mm(raw.T, raw)
        a = (self.EPSILON + torch.mm(raw.T, est)) / (Rss + self.EPSILON)
        e_true = a * raw
        e_res = est - e_true
        Sss = (e_true ** 2).sum()
        Snn = (e_res ** 2).sum()
        sisdr = 10 * torch.log10((self.EPSILON + Sss) / (self.EPSILON + Snn))
        return sisdr

'''
AAMsoftmax loss function copied from voxceleb_trainer: https://github.com/clovaai/voxceleb_trainer/blob/master/loss/aamsoftmax.py
'''

import torch, math
import torch.nn as nn
import torch.nn.functional as F
from utils.tools import *

class AAMsoftmax(nn.Module):
    def __init__(self, n_class, m, s):
        super(AAMsoftmax, self).__init__()
        self.m = m
        self.s = s
        self.weight = torch.nn.Parameter(torch.FloatTensor(n_class, 192), requires_grad=True)
        self.ce = nn.CrossEntropyLoss()
        nn.init.xavier_normal_(self.weight, gain=1)
        self.cos_m = math.cos(self.m)
        self.sin_m = math.sin(self.m)
        self.th = math.cos(math.pi - self.m)
        self.mm = math.sin(math.pi - self.m) * self.m

    def forward(self, x, label=None):
        cosine = F.linear(F.normalize(x), F.normalize(self.weight))
        sine = torch.sqrt((1.0 - torch.mul(cosine, cosine)).clamp(0, 1))
        phi = cosine * self.cos_m - sine * self.sin_m
        phi = torch.where((cosine - self.th) > 0, phi, cosine - self.mm)
        one_hot = torch.zeros_like(cosine)
        one_hot.scatter_(1, label.view(-1, 1), 1)
        output = (one_hot * phi) + ((1.0 - one_hot) * cosine)
        output = output * self.s

        loss = self.ce(output, label)
        prec1 = accuracy(output.detach(), label.detach(), topk=(1,))[0]

        return loss, prec1


class Facebook_data():
    dict = {
        'name': 'Facebook',
        'base_url': 'https://graph.facebook.com/v12.0/',
        'endpoint_mapping': {
            'albums': {
                'endpoint': '',
                'get_fields': {
                    'album_type': 'type',
                    'album_url': 'link',
                    'author': 'from',
                    'can_upload_photos': 'can_upload',
                    'children': 'photos',
                    'comments': 'comments',
                    'count': 'count',
                    'cover_photo_id': 'cover_photo', # not for albums in groups
                    'created_time': 'created_time',
                    'dated': 'backdated_time', #
                    'dated_accuracy': 'backdated_time_granularity', #
                    'description': 'description',
                    'event_on_location': 'event', #
                    'id': 'id',
                    'location_by_id': 'place', #
                    'location_by_name': 'location', #
                    'name': 'name',
                    'photos': 'photos',
                    'updated_time': 'updated_time',
                    'url_to_album': 'link',
                    'visible_to_fb': 'privacy' #
                },
                'paths': {
                    'photos': {
                        'path': 'photos',
                        'post_fields': {
                            'allow_spherical_photo': 'allow_spherical_photo',
                            'alt_text': 'alt_text_custom',
                            'android_key_hash': 'android_key_hash',
                            'attempt': 'attempt',
                            'composer_session_id': 'composer_session_id',
                            'dated': 'backdated_time',
                            'dated_accuracy': 'backdated_time_granularity',
                            'description': 'caption',
                            'feed_targeting': 'feed_targeting',
                            'full_res_is_coming_later': 'full_res_is_coming_later',
                            'ios_bundle_id': 'ios_bundle_id',
                            'is_audience_experience': 'audience_exp',
                            'is_explicit_location': 'is_explicit_location',
                            'is_place_tag': 'is_explicit_place',
                            'is_published': 'published',
                            'is_visual_search': 'is_visual_search',
                            'itunes_app_id': 'application_id',
                            'location_by_id': 'place',
                            'manual_privacy': 'manual_privacy',
                            'no_story': 'no_story',
                            'offline_id': 'offline_id',
                            'open_graph_action_type_id': 'og_action_type_id',
                            'open_graph_icon_id': 'og_icon_id',
                            'open_graph_object_id': 'og_object_id',
                            'open_graph_phrase': 'og_phrase',
                            'open_graph_set_profile_badge': 'og_set_profile_badge',
                            'open_graph_suggestion_mechanism': 'og_suggestion_mechanism',
                            'override_initial_view_heading_degrees': 'initial_view_heading_override_degrees',
                            'override_initial_view_pitch_degrees': 'initial_view_pitch_override_degrees',
                            'override_initial_view_vertical_fov_degrees': 'initial_view_vertical_fov_override_degrees',
                            'photos_waterfall_id': 'qn',
                            'proxied_app_id': 'proxied_app_id',
                            'source_url_of_photo': 'url',
                            'spherical_metadata': 'spherical_metadata',
                            'sponsor_id': 'sponsor_id',
                            'sponsor_boost_status': 'direct_share_status',
                            'sponsor_relationship': 'sponsor_relationship',
                            'tagged_users': 'tags',
                            'timedelta_since_dated': 'time_since_original_post',
                            'unpublished_content_type': 'unpublished_content_type',
                            'user_selected_tags': 'user_selected_tags',
                            'vault_image_id': 'vault_image_id',
                            'visible_to_fb': 'privacy',
                            'allow_for': 'allow',
                            'deny_for': 'deny',
                            'custom_settings': 'description',
                            'allow_for_category': 'friends',
                            'allow_for_network': 'networks',
                            'privacy_value': 'value',
                            'projection_type': 'ProjectionType',
                            'cropped_area_image_width_pixels': 'CroppedAreaImageWidthPixels',
                            'cropped_area_image_height_pixels': 'CroppedAreaImageHeightPixels',
                            'full_pano_width_pixels': 'FullPanoWidthPixels',
                            'full_pano_height_pixels': 'FullPanoHeightPixels',
                            'cropped_area_left_pixels': 'CroppedAreaLeftPixels',
                            'cropped_area_top_pixels': 'CroppedAreaTopPixels',
                            'pose_heading_degrees': 'PoseHeadingDegrees',
                            'pose_pitch_degrees': 'PosePitchDegrees',
                            'pose_roll_degrees': 'PoseRollDegrees',
                            'initial_view_heading_degrees': 'InitialViewHeadingDegrees',
                            'initial_view_pitch_degrees': 'InitialViewPitchDegrees',
                            'initial_vertical_FOV_degrees': 'InitialVerticalFOVDegrees',
                            'initial_horizontal_FOV_degrees': 'InitialHorizontalFOVDegrees',
                            'pre_processor_crop_left_pixels': 'PreProcessCropLeftPixels',
                            'pre_processor_crop_right_pixels': 'PreProcessCropRightPixels',
                            'tag_uid': 'tag_uid',
                            'tag_text': 'tag_text',
                            'x': 'x',
                            'y': 'y'
                        }
                    }
                }
            },
            'events': {
                'endpoint': '',
                'get_fields': {
                    'attending_count': 'attending_count',
                    'author': 'owner',
                    'can_guests_invite': 'can_guests_invite',
                    'can_see_guest_list': 'guest_list_enabled',
                    'category': 'category',
                    'comments': 'comments',
                    'cover_photo': 'cover',
                    'declined_count': 'declined_count',
                    'description': 'description',
                    'discount_code_enabled': 'discount_code_enabled',
                    'end_time': 'end_time',
                    'event_picture': 'picture',
                    'event_times_list': 'event_times',
                    'feed': 'feed',
                    'id': 'id',
                    'interested_count': 'interested_count',
                    'is_canceled': 'is_canceled',
                    'is_draft': 'is_draft',
                    'is_online_event': 'is_online',
                    'is_page_owned': 'is_page_owned',
                    'live_videos': 'live_videos',
                    'location': 'place',
                    'maybe_count': 'maybe_count',
                    'name': 'name',
                    'noreply_count': 'noreply_count',
                    'online_event_format': 'online_event_format',
                    'online_event_third_party_url': 'online_event_third_party_url',
                    'parent_group': 'parent_group',
                    'photos': 'photos',
                    'posts': 'posts',
                    'roles': 'roles',
                    'scheduled_publish_time': 'scheduled_publish_time',
                    'start_time': 'start_time',
                    'ticket_uri': 'ticket_uri',
                    'ticket_uri_start_sales_time': 'ticket_uri_start_sales_time',
                    'ticketing_privacy_policy': 'ticketing_privacy_uri',
                    'ticketing_terms': 'ticketing_terms_uri',
                    'timezone': 'timezone',
                    'type': 'type', # If you remember a better name, update. This parameter tells if event is private, public, group, community or friends. who_can_attend, for_who, audience
                    'updated_time': 'updated_time',
                    'videos': 'videos'
                }
            },
            'groups': {
                'endpoint': '',
                'get_fields': {
                    'albums': 'albums',
                    'cover_photo': 'cover',
                    'company_subdomain': 'subdomain',
                    'created_time': 'created_time',
                    'description': 'description',
                    'docs': 'docs',
                    'email': 'email',
                    'events': 'events',
                    'feed': 'feed',
                    'files': 'files',
                    'group_picture': 'picture',
                    'groups': 'groups',
                    'id': 'id',
                    'is_archived': 'archived',
                    'live_videos': 'live_videos',
                    'location': 'venue',
                    'member_count': 'member_count',
                    'member_request_count': 'member_request_count',
                    'name': 'name',
                    'parent_object': 'parent',
                    'permissions': 'permissions',
                    'privacy_level': 'privacy',
                    'purpose': 'purpose',
                    'updated_time': 'updated_time',
                    'url_icon': 'icon',
                    'videos': 'videos',
                    'website': 'link'
                },
                'paths': {
                    'albums': {
                        'path': 'albums',
                        'post_fields': {
                            'contributors': 'contributors',
                            'description': 'description',
                            'location_by_id': 'place',
                            'location_by_name': 'location',
                            'make_shared_album': 'make_shared_album',
                            'name': 'name',
                            'visible_to_fb': 'privacy',
                            'allow_for': 'allow',
                            'deny_for': 'deny',
                            'custom_settings': 'description',
                            'allow_for_category': 'friends',
                            'allow_for_network': 'networks',
                            'privacy_value': 'value'
                        }
                    },
                    'live_videos': {
                        'path': 'live_videos',
                        'post_fields': {
                            'app_id': 'attribution_app_id',
                            'app_tag': 'app_attribution_tag',
                            'content_tags': 'content_tags',
                            'custom_image_for_schedule': 'schedule_custom_profile_image',
                            'description': 'description',
                            'dont_show_on': 'post_surfaces_blacklist',
                            'enable_backup_ingest': 'enable_backup_ingest',
                            'encoding_settings_identifier': 'encoding_settings',
                            'fisheye_video_cropped': 'fisheye_video_cropped',
                            'front_z_rotation': 'front_z_rotation',
                            'game_id': 'game_id',
                            'game_specs': 'game_specs',
                            'is_360': 'is_spherical',
                            'live_encoders': 'live_encoders',
                            'original_fov': 'original_fov',
                            'projection': 'projection',
                            'spatial_audio_format': 'spatial_audio_format',
                            'status': 'status',
                            'stereoscopic_mode': 'stereoscopic_mode',
                            'stop_on_delete_stream': 'stop_on_delete_stream',
                            'video_title': 'title',
                            'visible_to_fb': 'privacy'
                        }
                    },
                    'photos': {
                        'path': 'photos',
                        'post_fields': {
                            'allow_spherical_photo': 'allow_spherical_photo',
                            'alt_text': 'alt_text_custom',
                            'android_key_hash': 'android_key_hash',
                            'attempt': 'attempt',
                            'composer_session_id': 'composer_session_id',
                            'dated': 'backdated_time',
                            'dated_accuracy': 'backdated_time_granularity',
                            'description': 'caption',
                            'feed_targeting': 'feed_targeting',
                            'full_res_is_coming_later': 'full_res_is_coming_later',
                            'ios_bundle_id': 'ios_bundle_id',
                            'is_audience_experience': 'audience_exp',
                            'is_explicit_location': 'is_explicit_location',
                            'is_place_tag': 'is_explicit_place',
                            'is_published': 'published',
                            'is_visual_search': 'is_visual_search',
                            'itunes_app_id': 'application_id',
                            'location_by_id': 'place',
                            'manual_privacy': 'manual_privacy',
                            'no_story': 'no_story',
                            'offline_id': 'offline_id',
                            'open_graph_action_type_id': 'og_action_type_id',
                            'open_graph_icon_id': 'og_icon_id',
                            'open_graph_object_id': 'og_object_id',
                            'open_graph_phrase': 'og_phrase',
                            'open_graph_set_profile_badge': 'og_set_profile_badge',
                            'open_graph_suggestion_mechanism': 'og_suggestion_mechanism',
                            'override_initial_view_heading_degrees': 'initial_view_heading_override_degrees',
                            'override_initial_view_pitch_degrees': 'initial_view_pitch_override_degrees',
                            'override_initial_view_vertical_fov_degrees': 'initial_view_vertical_fov_override_degrees',
                            'photos_waterfall_id': 'qn',
                            'proxied_app_id': 'proxied_app_id',
                            'scheduled_publish_time': 'scheduled_publish_time',
                            'source_url_of_photo': 'url',
                            'spherical_metadata': 'spherical_metadata',
                            'sponsor_id': 'sponsor_id',
                            'sponsor_boost_status': 'direct_share_status',
                            'sponsor_relationship': 'sponsor_relationship',
                            'tagged_users': 'tags',
                            'targeting': 'targeting',
                            'timedelta_since_dated': 'time_since_original_post',
                            'unpublished_content_type': 'unpublished_content_type',
                            'user_selected_tags': 'user_selected_tags',
                            'vault_image_id': 'vault_image_id',
                            'visible_to_fb': 'privacy',
                            'allow_for': 'allow',
                            'deny_for': 'deny',
                            'custom_settings': 'description',
                            'allow_for_category': 'friends',
                            'allow_for_network': 'networks',
                            'privacy_value': 'value',
                            'projection_type': 'ProjectionType',
                            'cropped_area_image_width_pixels': 'CroppedAreaImageWidthPixels',
                            'cropped_area_image_height_pixels': 'CroppedAreaImageHeightPixels',
                            'full_pano_width_pixels': 'FullPanoWidthPixels',
                            'full_pano_height_pixels': 'FullPanoHeightPixels',
                            'cropped_area_left_pixels': 'CroppedAreaLeftPixels',
                            'cropped_area_top_pixels': 'CroppedAreaTopPixels',
                            'pose_heading_degrees': 'PoseHeadingDegrees',
                            'pose_pitch_degrees': 'PosePitchDegrees',
                            'pose_roll_degrees': 'PoseRollDegrees',
                            'initial_view_heading_degrees': 'InitialViewHeadingDegrees',
                            'initial_view_pitch_degrees': 'InitialViewPitchDegrees',
                            'initial_vertical_FOV_degrees': 'InitialVerticalFOVDegrees',
                            'initial_horizontal_FOV_degrees': 'InitialHorizontalFOVDegrees',
                            'pre_processor_crop_left_pixels': 'PreProcessCropLeftPixels',
                            'pre_processor_crop_right_pixels': 'PreProcessCropRightPixels',
                            'tag_uid': 'tag_uid',
                            'tag_text': 'tag_text',
                            'x': 'x',
                            'y': 'y'
                        }
                    },
                    'posts': {
                        'path': 'feed',
                        'post_fields': {
                            'message': 'message',
                            'link': 'link'
                        }
                    },
                    'videos': {
                        'path': 'videos',
                        'post_fields': {
                            'audio_story_wave_animation_handle': 'audio_story_wave_animation_handle',
                            'content_category': 'content_category',
                            'description': 'description',
                            'embeddable': 'embeddable',
                            'end_offset': 'end_offset',
                            'file_size_in_bytes': 'file_size',
                            'file_url': 'file_url',
                            'fisheye_video_cropped': 'fisheye_video_cropped',
                            'front_z_rotation': 'front_z_rotation',
                            'guide_keyframes_data_for_360': 'guide',
                            'guide_enabled_for_360': 'guide_enabled',
                            'initial_heading_for_360': 'initial_heading',
                            'initial_pitch_for_360': 'initial_pitch',
                            'is_360': 'spherical',
                            'original_fov': 'original_fov',
                            'original_projection_type_for_360': 'original_projection_type',
                            'prompt_id': 'prompt_id',
                            'prompt_tracking_string': 'prompt_tracking_string',
                            'react_mode_metadata': 'react_mode_metadata',
                            'referenced_sticker_id': 'referenced_sticker_id',
                            'scheduled_publish_time': 'scheduled_publish_time',
                            'slideshow_spec': 'slideshow_spec',
                            'source_instagram_media_id': 'source_instagram_media_id',
                            'start_offset': 'start_offset',
                            'swap_mode': 'swap_mode',
                            'transcode_setting_properties': 'transcode_setting_properties',
                            'unpublished_content_type': 'unpublished_content_type',
                            'upload_phase': 'upload_phase',
                            'upload_session_id': 'upload_session_id',
                            'vertical_fov_for_360': 'fov',
                            'video_encoded_as_form_data': 'source', # required
                            'video_file_chunk': 'video_file_chunk', # required during transfer upload phasr
                            'video_id_to_replace': 'replace_video_id',
                            'video_title': 'title',
                            'images_urls': 'images_urls',
                            'duration_ms': 'duration_ms',
                            'transition_ms': 'transition_ms',
                            'reordering_opt_in': 'reordering_opt_in',
                            'music_variations_opt_in': 'music_variations_opt_in'
                        }
                    }
                }
            },
            'links': {
                'endpoint': '',
                'get_fields': {
                    'author': 'from',
                    'comments': 'comments',
                    'created_time': 'created_time',
                    'description': 'description',
                    'id': 'id',
                    'likes': 'likes',
                    'link': 'link',
                    'link_icon_url': 'icon',
                    'message': 'message',
                    'name': 'name',
                    'thumbnail_url': 'picture'
                }
            },
            'live_videos': {
                'endpoint': '',
                'get_fields': {
                    'ad_break_config': 'ad_break_config',
                    'ad_break_failure_reason': 'ad_break_failure_reason',
                    'author': 'from',
                    'broadcast_start_time': 'broadcast_start_time',
                    'comments': 'comments',
                    'creation_time': 'creation_time',
                    'crosspost_shared_pages': 'crosspost_shared_pages',
                    'crossposted_broadcasts': 'crossposted_broadcasts',
                    'dash_ingest_url': 'dash_ingest_url',
                    'dash_preview_url': 'dash_preview_url',
                    'description': 'description',
                    'embed_html': 'embed_html',
                    'id': 'id',
                    'ingest_streams': 'ingest_streams',
                    'is_manual_mode': 'is_manual_mode',
                    'is_reference_only': 'is_reference_only',
                    'live_encoders': 'live_encoders',
                    'live_views_count': 'live_views',
                    'live_video_url': 'permalink_url',
                    'overlay_url': 'overlay_url',
                    'polls': 'polls',
                    'seconds_left': 'seconds_left',
                    'secure_stream_url': 'secure_stream_url',
                    'status': 'status',
                    'stream_url': 'stream_url',
                    'targeting': 'targeting',
                    'video': 'video',
                    'video_title': 'title'
                },
                'post_fields': {
                    'allow_bm_crossposting': 'allow_bm_crossposting',
                    'content_tags': 'content_tags',
                    'crossposting_actions': 'crossposting_actions',
                    'cross_share_to_group_ids': 'cross_share_to_group_ids',
                    'custom_image_for_schedule': 'schedule_custom_profile_image',
                    'custom_background_image_for_schedule': 'schedule_feed_background_image',
                    'custom_labels': 'custom_labels',
                    'description': 'description',
                    'donate_button_charity_id': 'donate_button_charity_id',
                    'embeddable': 'embeddable',
                    'end_live_video': 'end_live_video',
                    'is_disturbing': 'disturbing',
                    'is_manual_mode': 'is_manual_mode',
                    'live_comment_moderation_setting': 'live_comment_moderation_setting',
                    'live_encoders': 'live_encoders',
                    'location': 'place',
                    'master_ingest_stream_id': 'master_ingest_stream_id',
                    'persistent_stream_key_status': 'persistent_stream_key_status',
                    'projection': 'projection',
                    'sponsor_id': 'sponsor_id',
                    'sponsor_boost_status': 'direct_share_status',
                    'sponsor_relationship': 'sponsor_relationship',
                    'status': 'status',
                    'stereoscopic_mode': 'stereoscopic_mode',
                    'stop_on_delete_stream': 'stop_on_delete_stream',
                    'tagged_users': 'tags',
                    'targeting': 'targeting',
                    'video_title': 'title',
                    'visible_to_fb': 'privacy'
                }
            },
            'me': {
                'endpoint': 'me',
                'get_fields': {
                    'account_type': None,
                    'accounts': 'accounts',
                    'ad_studies':'ad_studies',
                    'age_range':'age_range',
                    'albums':'albums',
                    'apprequestformerrecipients':'apprequestformerrecipients',
                    'apprequests':'apprequests',
                    'assigned_business_asset_groups':'assigned_business_asset_groups',
                    'birthday':'birthday',
                    'business_users':'business_users',
                    'businesses':'businesses',
                    'connections':'friends',
                    'created_at': None,
                    'description': None,
                    'email':'email',
                    'events':'events',
                    'first_name_by_location': 'first_name',
                    'favorite_athletes':'favorite_athletes',
                    'favorite_teams':'favorite_teams',
                    'feed':'feed',
                    'first_name':'first_name',
                    'gender':'gender',
                    'groups':'groups',
                    'hometown':'hometown',
                    'id':'id',
                    'inspirational_people':'inspirational_people',
                    'install_type':'install_type',
                    'installed':'installed',
                    'is_guest_user':'is_guest_user',
                    'is_private': None,
                    'languages':'languages',
                    'last_name':'last_name',
                    'last_name_by_location': 'last_name',
                    'liked_pages':'likes',
                    'link':'link',
                    'live_encoders':'live_encoders',
                    'live_videos':'live_videos',
                    'location':'location',
                    'media_count': None,
                    'meeting_for':'meeting_for',
                    'metrics': None,
                    'middle_name':'middle_name',
                    'music':'music',
                    'name':'name',
                    'name_format':'name_format',
                    'pages_with_roles':'accounts',
                    'payment_pricepoints':'payment_pricepoints',
                    'permissions':'permissions',
                    'photos':'photos',
                    'profile_picture':'picture',
                    'posts':'posts',
                    'quotes':'quotes',
                    'rich_media_documents':'rich_media_documents',
                    'shared_login_upgrade_required_by':'shared_login_upgrade_required_by',
                    'short_name':'short_name',
                    'significant_other':'significant_other',
                    'sports':'sports',
                    'supports_donate_button_in_live_video':'supports_donate_button_in_live_video',
                    'url': None,
                    'username': None,
                    'verified': None,
                    'video_upload_limits':'video_upload_limits',
                    'videos':'videos'
                }
            },
            'photos': {
                'endpoint': '',
                'get_fields': {
                    'album': 'album',
                    'alt_text': 'alt_text',
                    'alt_text_custom': 'alt_text_custom',
                    'author': 'from',
                    'can_backdate': 'can_backdate',
                    'can_delete': 'can_delete',
                    'can_tag': 'can_tag',
                    'content_category': None,
                    'created_time': 'created_time',
                    'dated': 'backdated_time',
                    'dated_accuracy': 'backdated_time_granularity',
                    'description': None,
                    'display_icon': 'icon',
                    'event': 'event',
                    'height': 'height',
                    'id': 'id',
                    'image_representations': 'images',
                    'image_url': 'link',
                    'image_webp_representations': 'webp_images',
                    'likes': 'likes',
                    'location': 'place',
                    'name': 'name',
                    'page_story_id': 'page_story_id',
                    'sponsor_tags': 'sponsor_tags',
                    'tagged_names': 'name_tags',
                    'target': 'target',
                    'updated_time': 'updated_time',
                    'url_to_image_file': 'link',
                    'width': 'width'
                }
            },
            'posts': {
                'endpoint': '',
                'get_fields': {
                    'action_links': 'actions',
                    'allowed_advertising_objectives': 'allowed_advertising_objectives',
                    'application': 'application',
                    'attachment_expanded_height': 'expanded_height',
                    'attachment_expanded_width': 'expanded_width',
                    'attachment_height': 'height',
                    'attachment_id': 'object_id',
                    'attachment_info': 'coordinates',
                    'attachment_properties': 'properties',
                    'attachment_width': 'width',
                    'attachments': 'attachments',
                    'author': 'from',
                    'autoselect_link_order': 'multi_share_optimized',
                    'can_reply_privately': 'can_reply_privately',
                    'comments': 'comments',
                    'comments_mirroring_domain': 'comments_mirroring_domain',
                    'created_time': 'created_time',
                    'dated': 'backdated_time',
                    'description': 'description',
                    'display_multi_share_end_card': 'multi_share_end_card',
                    'dynamic_posts': 'dynamic_posts',
                    'event': 'event',
                    'feed_targeting': 'feed_targeting',
                    'full_size_picture': 'full_picture',
                    'id': 'id',
                    'instagram_eligibility': 'instagram_eligibility',
                    'is_360': 'is_spherical',
                    'is_eligible_for_promotion': 'is_eligible_for_promotion',
                    'is_expired': 'is_expired',
                    'is_hidden': 'is_hidden',
                    'is_inline_created': 'is_inline_created',
                    'is_instagram_eligible': 'is_instagram_eligible',
                    'is_popular': 'is_popular',
                    'is_published': 'is_published',
                    'is_user_subscribed': 'subscribed',
                    'link_caption': 'caption',
                    'link_description': 'link',
                    'link_name': 'name',
                    'location_by_id': 'place',
                    'message': 'message',
                    'parent_post_id': 'parent_id',
                    'picture_from_link': 'picture',
                    'post_references_app': 'is_app_share',
                    'post_type': 'type',
                    'post_type_description': 'story', # User updated their profile photo.
                    'post_type_icon': 'icon',
                    'post_url': 'permalink_url',
                    'profile_to_post_to': 'target',
                    'promotable_id': 'promotable_id',
                    'reactions': 'reactions',
                    'scheduled_publish_time': 'scheduled_publish_time',
                    'shared_via': 'via',
                    'sharedposts': 'sharedposts',
                    'shares_count': 'shares',
                    'sponsor_tags': 'sponsor_tags',
                    'staus_update_type': 'status_type',
                    'subshares': 'child_attachments',
                    'tagged_profiles_in_message': 'message_tags',
                    'tags_in_post_type_description': 'story_tags',
                    'targeting': 'targeting',
                    'timeline_visibility': 'timeline_visibility',
                    'updated_time': 'updated_time',
                    'url_to_video_file': 'source',
                    'video_buying_eligibility': 'video_buying_eligibility',
                    'visible_to_fb': 'privacy'
                },
            },
            'users': {
                'endpoint': '',
                'get_fields': {
                    'account_type': None,
                    'ad_studies': 'ad_studies',
                    'age_range': 'age_range',
                    'albums': 'albums',
                    'apprequests': 'apprequests',
                    'assigned_business_asset_groups': 'assigned_business_asset_groups',
                    'assigned_pages': 'assigned_pages',
                    'assigned_product_catalogs': 'assigned_product_catalogs',
                    'birthday': 'birthday',
                    'business_users': 'business_users',
                    'businesses': 'businesses',
                    'conversations': 'conversations',
                    'created_at': None,
                    'custom_labels': 'custom_labels',
                    'description': None,
                    'email': 'email',
                    'favorite_athletes': 'favorite_athletes',
                    'favorite_teams': 'favorite_teams',
                    'feed': 'feed',
                    'first_name': 'first_name',
                    'friends': 'friends',
                    'gender': 'gender',
                    'hometown': 'hometown',
                    'id': 'id',
                    'ids_for_apps': 'ids_for_apps',
                    'ids_for_business': 'ids_for_business',
                    'ids_for_pages': 'ids_for_pages',
                    'inspirational_people': 'inspirational_people',
                    'install_type': 'install_type',
                    'is_installed': 'installed',
                    'is_guest_user': 'is_guest_user',
                    'is_private': None,
                    'languages': 'languages',
                    'last_name': 'last_name',
                    'liked_pages': 'likes',
                    'live_encoders': 'live_encoders',
                    'live_videos': 'live_videos',
                    'location': 'location',
                    'media_count': None,
                    'meeting_for': 'meeting_for',
                    'metrics': None,
                    'middle_name': 'middle_name',
                    'music': 'music',
                    'name': 'name',
                    'name_format': 'name_format',
                    'pages_with_roles': 'accounts',
                    'payment_pricepoints': 'payment_pricepoints',
                    'payment.subscriptions': 'payment.subscriptions',
                    'permissions': 'permissions',
                    'photos': 'photos',
                    'posts': 'feed',
                    'profile_pic_url': 'profile_pic',
                    'quotes': 'quotes',
                    'shared_login_upgrade_required_by': 'shared_login_upgrade_required_by',
                    'short_name': 'short_name',
                    'significant_other': 'significant_other',
                    'sports': 'sports',
                    'supports_donate_button_in_live_video': 'supports_donate_button_in_live_video',
                    'timeline_url': 'link',
                    'token_for_business': 'token_for_business',
                    'url': None,
                    'username': None,
                    'verified': None,
                    'video_upload_limits': 'video_upload_limits',
                    'videos': 'videos'
                },
                'post_fields': {
                    'dismiss_local_news_megaphone': 'local_news_megaphone_dismiss_status',
                    'emoji_color_pref': 'emoji_color_pref',
                    'first_name': 'firstname',
                    'last_name': 'lastname',
                    'set_local_news_notifications': 'local_news_subscription_status'
                },
                'paths': {
                    'live_videos': {
                        'path': 'live_videos',
                        'post_fields': {
                            'content_tags': 'content_tags',
                            'custom_image_for_schedule': 'schedule_custom_profile_image',
                            'description': 'description',
                            'donate_button_charity_id': 'donate_button_charity_id',
                            'enable_backup_ingest': 'enable_backup_ingest',
                            'encoding_settings_identifier': 'encoding_settings',
                            'fisheye_video_cropped': 'fisheye_video_cropped',
                            'front_z_rotation': 'front_z_rotation',
                            'is_360': 'is_spherical',
                            'live_encoders': 'live_encoders',
                            'original_fov': 'original_fov',
                            'projection': 'projection',
                            'spatial_audio_format': 'spatial_audio_format',
                            'status': 'status',
                            'stereoscopic_mode': 'stereoscopic_mode',
                            'stop_on_delete_stream': 'stop_on_delete_stream',
                            'video_title': 'title',
                            'visible_to_fb': 'privacy'
                        }
                    },
                    'videos': {
                        'path': 'videos',
                        'post_fields': {
                            'audio_story_wave_animation_handle': 'audio_story_wave_animation_handle',
                            'content_category': 'content_category',
                            'description': 'description',
                            'embeddable': 'embeddable',
                            'end_offset': 'end_offset',
                            'file_size_in_bytes': 'file_size',
                            'file_url': 'file_url',
                            'fisheye_video_cropped': 'fisheye_video_cropped',
                            'front_z_rotation': 'front_z_rotation',
                            'guide_keyframes_data_for_360': 'guide',
                            'guide_enabled_for_360': 'guide_enabled',
                            'initial_heading_for_360': 'initial_heading',
                            'initial_pitch_for_360': 'initial_pitch',
                            'is_360': 'spherical',
                            'is_voice_clip': 'is_voice_clip',
                            'no_story': 'no_story',
                            'original_fov': 'original_fov',
                            'original_projection_type_for_360': 'original_projection_type',
                            'posting_to_redspace': 'posting_to_redspace',
                            'prompt_id': 'prompt_id',
                            'prompt_tracking_string': 'prompt_tracking_string',
                            'react_mode_metadata': 'react_mode_metadata',
                            'referenced_sticker_id': 'referenced_sticker_id',
                            'slideshow_spec': 'slideshow_spec',
                            'source_instagram_media_id': 'source_instagram_media_id',
                            'sponsor_id': 'sponsor_id',
                            'sponsor_boost_status': 'direct_share_status',
                            'start_offset': 'start_offset',
                            'swap_mode': 'swap_mode',
                            'video_title': 'title',
                            'transcode_setting_properties': 'transcode_setting_properties',
                            'unpublished_content_type': 'unpublished_content_type',
                            'upload_phase': 'upload_phase',
                            'upload_session_id': 'upload_session_id',
                            'vertical_fov_for_360': 'fov',
                            'video_encoded_as_form_data': 'source', # required
                            'video_file_chunk': 'video_file_chunk', # required during transfer upload phasr
                            'video_id_original': 'video_id_original',
                            'video_id_to_replace': 'replace_video_id',
                            'visible_to_fb': 'privacy',
                            'allow_for': 'allow',
                            'deny_for': 'deny',
                            'custom_settings': 'description',
                            'allow_for_category': 'friends',
                            'allow_for_network': 'networks',
                            'privacy_value': 'value',
                            'images_urls': 'images_urls',
                            'duration_ms': 'duration_ms',
                            'transition_ms': 'transition_ms',
                            'reordering_opt_in': 'reordering_opt_in',
                            'music_variations_opt_in': 'music_variations_opt_in'
                        }
                    }
                }
            },
            'videos': {
                'endpoint': '',
                'get_fields': {
                    'ad_breaks': 'ad_breaks',
                    'author': 'from',
                    'captions': 'captions',
                    'comments': 'comments',
                    'content_category': 'content_category',
                    'content_tags': 'content_tags',
                    'created_time': 'created_time',
                    'crosspost_shared_pages': 'crosspost_shared_pages',
                    'custom_labels': 'custom_labels',
                    'dated': 'backdated_time',
                    'dated_accuracy': 'backdated_time_granularity',
                    'description': 'description',
                    'display_icon': 'icon',
                    'embed_html': 'embed_html',
                    'embeddable': 'embeddable',
                    'event': 'event',
                    'formats': 'format',
                    'id': 'id',
                    'is_crosspost_video': 'is_crosspost_video',
                    'is_crossposting_eligible': 'is_crossposting_eligible',
                    'is_episode': 'is_episode',
                    'is_instagram_eligible': 'is_instagram_eligible',
                    'is_published': 'published',
                    'is_reference_only': 'is_reference_only',
                    'length': 'length',
                    'likes': 'likes',
                    'live_status': 'live_status',
                    'location': 'place',
                    'music_video_copyright': 'music_video_copyright',
                    'post_views': 'post_views',
                    'premiere_status': 'premiere_living_room_status',
                    'poll_settings': 'poll_settings',
                    'polls': 'polls',
                    'scheduled_publish_time': 'scheduled_publish_time',
                    'sponsor_tags': 'sponsor_tags',
                    'status': 'status',
                    'tagged_users': 'tags',
                    'thumbnails': 'thumbnails',
                    'universal_video_id': 'universal_video_id',
                    'updated_time': 'updated_time',
                    'url_to_video_file': 'source',
                    'video_insights': 'video_insights',
                    'video_title': 'title',
                    'video_url': 'permalink_url',
                    'views_count': 'views',
                    'visible_to_fb': 'privacy'
                },
                'post_fields': {
                    'ad_breaks': 'ad_breaks',
                    'allow_bm_crossposting': 'allow_bm_crossposting',
                    'allow_crossposting_for_pages': 'allow_crossposting_for_pages',
                    'call_to_action': 'call_to_action',
                    'content_category': 'content_category',
                    'content_tags': 'content_tags',
                    'custom_labels': 'custom_labels',
                    'dated': 'backdated_time',
                    'dated_accuracy': 'backdated_time_granularity',
                    'description': 'description',
                    'embeddable': 'embeddable',
                    'expiration': 'expiration',
                    'expire_now': 'expire_now',
                    'increment_play_count': 'increment_play_count',
                    'is_published': 'published',
                    'preferred_thumbnail_id': 'preferred_thumbnail_id',
                    'publish_to_news_feed': 'publish_to_news_feed',
                    'publish_to_videos_tab_only': 'publish_to_videos_tab',
                    'scheduled_publish_time': 'scheduled_publish_time',
                    'social_actions_disabled': 'social_actions',
                    'sponsor_id': 'sponsor_id',
                    'sponsor_boost_status': 'direct_share_status',
                    'sponsor_relationship': 'sponsor_relationship',
                    'tagged_users': 'tags',
                    'target_video_id': 'target',
                    'universal_video_id': 'universal_video_id',
                    'video_title': 'name',
                    'visible_to_fb': 'privacy'
                }
            }
        }
    }


"""
This file is a palceholder for if new clustering algorithms come into
nussl at some point and need to be tested.
"""

from sklearn import datasets
from sklearn.metrics import adjusted_mutual_info_score
from sklearn.preprocessing import StandardScaler
import sklearn
import numpy as np
import pytest
from nussl.ml import cluster
import matplotlib.pyplot as plt
import nussl

@pytest.fixture(scope="module")
def cluster_data():
    np.random.seed(0)

    # ============
    # Generate datasets. We choose the size big enough to see the scalability
    # of the algorithms, but not too big to avoid too long running times
    # ============
    n_samples = 1500
    noisy_circles = datasets.make_circles(n_samples=n_samples, factor=.5,
                                          noise=.05)
    noisy_moons = datasets.make_moons(n_samples=n_samples, noise=.05)
    blobs = datasets.make_blobs(n_samples=n_samples, random_state=8)

    # Anisotropicly distributed data
    random_state = 170
    X, y = datasets.make_blobs(n_samples=n_samples, random_state=random_state)
    transformation = [[0.6, -0.6], [-0.4, 0.8]]
    X_aniso = np.dot(X, transformation)
    aniso = (X_aniso, y)

    # blobs with varied variances
    varied = datasets.make_blobs(n_samples=n_samples,
                                 cluster_std=[1.0, 2.5, 0.5],
                                 random_state=random_state)

    default_base = {'quantile': .3,
                    'eps': .3,
                    'damping': .9,
                    'preference': -200,
                    'n_neighbors': 10,
                    'n_clusters': 3,
                    'min_samples': 20,
                    'xi': 0.05,
                    'min_cluster_size': 0.1}

    data = [
        ('noisy_circles', noisy_circles, {'damping': .77, 'preference': -240,
                                          'quantile': .2, 'n_clusters': 2,
                                          'min_samples': 20, 'xi': 0.25}),
        ('noisy_moons', noisy_moons, {'damping': .75, 'preference': -220, 'n_clusters': 2}),
        ('varied', varied, {'eps': .18, 'n_neighbors': 2,
                            'min_samples': 5, 'xi': 0.035, 'min_cluster_size': .2}),
        ('aniso', aniso, {'eps': .15, 'n_neighbors': 2,
                          'min_samples': 20, 'xi': 0.1, 'min_cluster_size': .2}),
        ('blobs', blobs, {}),
    ]
    yield data, default_base


import logging

logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)s | %(levelname)s | %(module)s:%(funcName)s:%(lineno)d - %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S",
    handlers=[
        logging.FileHandler(filename="info.log", level=logging.INFO),
        logging.StreamHandler(level=logging.DEBUG),
    ],
)

logger = logging.getLogger(__name__)

def main():
    logger.debug("This is a debug message")
    logger.info("This is an info message")
    logger.warning("This is a warning message")
    logger.error("This is an error message")

if __name__ == "__main__":
    main()


import pygame
import numpy as np
import os
import sys
from pygame.locals import *

# 게임 윈도우 크기
WINDOW_WIDTH = 900
WINDOW_HEIGHT = 1000

# 색 정의
WHITE = (255, 255, 255)
GREY = (200, 200, 200)
BLACK = (0, 0, 0)

# Pygame 초기화
pygame.init()

# 윈도우 제목
pygame.display.set_caption("TicTacToe")

# 윈도우 생성
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))

# 게임 화면 업데이트 속도
clock = pygame.time.Clock()

#박스 크기들과 박스의 사이즈 정의
gap = 15
size = 280

#박스(버튼)의 위치를 정의
pos_x = [(gap), (gap*2 + size), (gap*3 + size*2), (gap), (gap*2 + size), (gap*3 + size*2), (gap), (gap*2 + size), (gap*3 + size*2)]
pos_y = [(gap*3 + size*2), (gap*3 + size*2), (gap*3 + size*2), (gap*2 + size),(gap*2 + size),(gap*2 + size),(gap) ,(gap), (gap)]

# 9개의 버튼을 만들고, board[1]~board[9]까지 저장
# board[7] board[8] board[9]
# board[4] board[5] board[6]
# board[1] board[2] board[3]

losboard = "YOULOSE^^!".split()

# 박스(버튼) 그리기
def drawBoard(board):
    for i in range(0, 9):
        pygame.draw.rect(screen,GREY,[pos_x[i], pos_y[i], size, size])
    for t in range(1, 10):
        ttext = c_font.render(board[t], True, BLACK)
        screen.blit(ttext,(pos_x[t-1]+20, pos_y[t-1]-10))

# player는 O로 고정, computer는 X로 고정
def inputPlayerLetter():
    return ['O', 'X']

# 선공 정하기
# random하게 computer나 player둘중에 골라서 선공을 한다.
def whoGoesFirst():
    # Randomly choose the player who goes first.
    if np.random.randint(0, 2) == 0:
        return 'computer'
    else:
        return 'player'

def makeMove(board, letter, move):
    board[move] = letter

#board(박스)에 letter에 있으면 이기는 경우의 수를 정의했다.
def isWinner(bo, le):
    return ((bo[7] == le and bo[8] == le and bo[9] == le) or
    (bo[4] == le and bo[5] == le and bo[6] == le) or
    (bo[1] == le and bo[2] == le and bo[3] == le) or
    (bo[7] == le and bo[4] == le and bo[1] == le) or
    (bo[8] == le and bo[5] == le and bo[2] == le) or
    (bo[9] == le and bo[6] == le and bo[3] == le) or
    (bo[7] == le and bo[5] == le and bo[3] == le) or
    (bo[9] == le and bo[5] == le and bo[1] == le))

#board(박스) 복사하기
def getBoardCopy(board):
    boardCopy = []
    for i in board:
        boardCopy.append(i)
    return boardCopy

#빈 board(박스)인지 확인하는 함수
def isSpaceFree(board, move):
    return board[move] == ' '

#possibleMoves라는 array를 만들고, 여기에 빈칸인 board들을 넣는다.
#빈칸이 없는 경우를 제외하고, 빈칸이 있는 경우에는 이 possibleMoves 배열에서 random하게 return한다.
def chooseRandomMoveFromList(board, movesList):
    possibleMoves = []
    for i in movesList:
        if isSpaceFree(board, i):
            possibleMoves.append(i)

    if len(possibleMoves) != 0:
        return np.random.choice(possibleMoves)
    else:
        return None

#컴퓨터의 순서에서의 컴퓨터의 동작
def getComputerMove(board, computerLetter):
    playerLetter = 'O'
    computerLetter = 'X'

    #player가 어떤 빈칸을 넣었을 때, 이기는 상황일 때 그 빈칸을 막는다.
    for i in range(1, 10):
        boardCopy = getBoardCopy(board)
        if isSpaceFree(boardCopy, i):
            makeMove(boardCopy, playerLetter, i)
            if isWinner(boardCopy, playerLetter):
                return i

    #제일 승률이 큰 1 3 7 9를 우선으로 고려한다.
    move = chooseRandomMoveFromList(board, [1, 3, 7, 9])
    if move != None:
        return move

    # 그 다음 승률이 큰 중간값인 5를 고려한다.
    if isSpaceFree(board, 5):
        return 5

    # 그 후 남은 2, 4, 6, 8 중 하나를 고른다.
    return chooseRandomMoveFromList(board, [2, 4, 6, 8])

#다 차있으면 true를 아니라면 false를 return한다.
def isBoardFull(board):
    for i in range(1, 10):
        if isSpaceFree(board, i):
            return False
    return True

#폰트
a_font = pygame.font.SysFont('onyx', 50)
b_font = pygame.font.SysFont('onyx', 40)
c_font = pygame.font.SysFont('onyx', 400)
starting_text = a_font.render("Tic Tac Toe", True, BLACK)

# # 게임 종료 전까지 반복
done = False
theBoard = [' '] * 10
playerLetter, computerLetter = inputPlayerLetter()
turn = whoGoesFirst()

showingturntext = b_font.render("The " + turn + " will go first", True, BLACK)

# 게임 반복 구간
while not done:
    # 이벤트 반복 구간
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

        if event.type == MOUSEBUTTONUP: #마우스 버튼이 눌러지고 떠질 때
            mpos = pygame.mouse.get_pos()
            # 사용자 순서
            if turn == 'player':
                drawBoard(theBoard)
                move = ' '

                for i in range(9):
                    if (pos_x[i] <= mpos[0] <= pos_x[i] + size) and (pos_y[i] <=mpos[1] <= pos_y[i] + size):
                        move = i+1

                makeMove(theBoard, playerLetter, move)

                if isWinner(theBoard, playerLetter):
                    drawBoard(theBoard)
                    pygame.time.delay(2000)
                    done = True

                else:
                    if isBoardFull(theBoard):
                        drawBoard(theBoard)
                        pygame.time.delay(2000)
                        done = True
                        break
                    else:
                        turn = 'computer'

            else:
                # 컴퓨터 턴
                move = getComputerMove(theBoard, computerLetter)
                makeMove(theBoard, computerLetter, move)

                if isWinner(theBoard, computerLetter):
                    pygame.time.delay(2000)
                    done = True

                else:
                    if isBoardFull(theBoard):
                        drawBoard(theBoard)
                        done = True
                        pygame.time.delay(2000)
                        break
                    else:
                        turn = 'player'

    screen.fill(WHITE)
    drawBoard(theBoard)
    screen.blit(starting_text, (WINDOW_WIDTH/2 - 100, WINDOW_HEIGHT/2 + 400))
    screen.blit(showingturntext, (WINDOW_WIDTH/2 - 200, WINDOW_HEIGHT/2 + 450))

    # 화면 업데이트
    pygame.display.flip()

    clock.tick(60)

# 게임 종료
pygame.quit()


from FilterLines import FilterLines
from ConvertCase import ConvertCase
from FindWords import FindWords
from NonAlphaFilter import NonAlphaFilter
from CountWords import CountWords
import re
from sys import argv

class DocumentProcessor:
    def __init__(self, builder):
        self.builder = builder
        self.filteredLines = self.builder.lineFilter
        self.convertCase = self.builder.convertCase
        self.findWords = self.builder.findWords
        self.nonAlpha = self.builder.nonAlphaFilter
        self.wordCount = self.builder.countWords

    def process(self, filename,search_str):
        # grep
        if self.convertCase is None:
            return self.filteredLines.process(filename,search_str=search_str)

        elif self.filteredLines is None:
            f = open(filename, "r")
            lines = str(f.readlines())
            second_step = ConvertCase().process(lines)
            third_step = FindWords().process(second_step)
            fourth_step = NonAlphaFilter().process(third_step)
            final_step = CountWords().process(fourth_step)
            return final_step
        else:
            a = self.filteredLines.process(filename,search_str)
            first_step = ConvertCase().process(a)
            second_step = ConvertCase().process(first_step)
            third_step = FindWords().process(second_step)
            fourth_step = NonAlphaFilter().process(third_step)
            final_step = CountWords().process(fourth_step)
            return final_step

    class Builder:
        def __init__(self):
            self.lineFilter = None
            self.convertCase = None
            self.findWords = None
            self.nonAlphaFilter = None
            self.countWords = None

        def setLineFilter(self, lf):
            self.lineFilter = lf
            return self

        def setConvertCase(self, cc):
            self.convertCase = cc
            return self

        def setFindWords(self, fw):
            self.findWords = fw
            return self

        def setNonAlphabetic(self, na):
            self.nonAlphabetic = na
            return self

        def setCountWords(self, cw):
            self.countWords = cw
            return self

        def build(self):
            return DocumentProcessor(self)


'''有大量事件，频繁创建进程会消耗系统资源
进程池实例（爬虫可能会用）'''
'''
定义方法需要在Pool之前
'''

from multiprocessing import Pool,Queue
import os
# new_path = '/home/tarena/PycharmProjects/aid1907/stage2/day09/chat'
# old_path = '/home/tarena/PycharmProjects/aid1907/stage2/day08/群聊聊天室/chat'
# list_file=os.listdir('/home/tarena/PycharmProjects/aid1907/stage2/day08/群聊聊天室/chat')

list_file=os.listdir('/home/tarena/学习笔记/第二阶段/IO网络编程 (1)/IO网络编程/img')
old_path = '/home/tarena/学习笔记/第二阶段/IO网络编程 (1)/IO网络编程/img'
new_path = '/home/tarena/桌面/img'
q = Queue(5)
# 进程池执行
def worker(old,new):
    f = open(old, 'rb')
    f2 = open(new, 'wb')
    f2.write(f.read())
    q.put(os.path.getsize(old))
    f.close()
    f2.close()
size = 0
for i in list_file:
    # print(os.path.getsize())
    size += os.path.getsize(old_path+'/'+i)
def ttime():
    size1 = 0
    print('本次共移动%fM:'%(size/1024/1024))
    while size1<size:
        size1 += q.get()
        print('进度为百分之%.1f'%((size1/size)*100),sep='')
pool1 = Pool()
# 添加事件
pool1.apply_async(ttime)
for i in list_file:
    old = old_path+'/'+i
    new = new_path+'/'+i
    pool1.apply_async(worker,args=(old,new))
# 关闭进程池（不能再添加新事件了）
pool1.close()
# 回收进程池
pool1.join()


# 入力を受け取る
N, M = map(int, input().split())
C = input().split()
D = input().split()
P = list(map(int, input().split()))

# 価格の合計を初期化
total_price = 0

# 各皿の価格を計算して合計に加える
for i in range(N):
    dish_color = C[i]
    if dish_color in D:
        total_price += P[D.index(dish_color) + 1]
    else:
        total_price += P[0]

    # dish_price = P[D.index(dish_color)] if dish_color in D else P[0]
    # total_price += dish_price

# 価格の合計を出力
print(total_price)


# 2진으로 표현하겠다

from sklearn.preprocessing import Binarizer
import numpy as np
binarizer = Binarizer()                         # 임계값을 주지 않음(default 값 : 0)

X = np.array([[1, -1], [-1, 0], [0, -2], [0, 2]])
'''
print("X : \n", X)
print("변환 값 : \n",binarizer.transform(X))     # 숫자를 기준으로 나눔 / 0이상은 1, 0이하는 0으로 반환
'''

binarizer1 = Binarizer(threshold=1.5)           # 임계값을 줌

print("임계값을 주지 않은 변환 : \n", binarizer.transform(X))
print("임계값을 준 변환 : \n", binarizer1.transform(X))


# -*- coding: utf-8 -*-
"""package info."""

title = 'nomadjack'

version_info = (0, 0, 2)
version = '.'.join(map(str, version_info))

license = 'MIT'
copyright = 'Copyright (c) 2023 Yogeshwaran Rajendran'

author = 'Yogeshwaran Rajendran'
email = 'xxx@gmail.com'
github = 'https://github.com/yogeshraja'
uri = 'https://github.com/yogeshraja/nomadjack'

description = 'Sidecar container to run arbitrary scripts inside nomad container'
status = "Development"


# Define function "operation", which that transforms a list of tuples into a list of numbers obtained by applying the operation passed as an argument.
# Example: operation([(1, 4, 6), (2, 4), (4, 1)], lambda x, y: x + y) = [11, 6, 5].

def operation(A, op):
    if not A:
        return []
    if not isinstance(A, list):
        if len(A) == 1:
            return A[0]
        elif len(A) == 2:
            return op(A[0], A[1])
        elif len(A) > 2:
            return op(A[0], operation(A[1:], op))
    else:
        return [operation(A[0], op)] + operation(A[1:], op)

print(operation([(1, 4, 6), (2, 4), (4, 1)], lambda x, y: x + y))