import tkinter as tk
import re
import chardet
import json
import os
import subprocess
import codecs

index = 0

class Application(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.master.geometry("200x400")
        self.master.resizable(True, True)
        self.pack()
        self.create_widgets()
    def create_widgets(self):
        self.text = tk.Label(self, text="Hello", font=("Helvetica", 24))
        self.text.pack(pady=50)
        self.eng_button = tk.Button(self, text="Eng", command=self.load_eng)
        self.eng_button.pack(fill=tk.X, pady=10)
        self.jp_button = tk.Button(self, text="Jp", command=self.load_jp)
        self.jp_button.pack(fill=tk.X, pady=10)
        self.ch_button = tk.Button(self, text="Cn", command=self.load_cn)
        self.ch_button.pack(fill=tk.X, pady=10)
        self.ch_button = tk.Button(self, text="Tw", command=self.load_TW)
        self.ch_button.pack(fill=tk.X, pady=10)

    def load_eng(self):
        global index
        index = 0
        self.load_lang()

    def load_jp(self):
        global index
        index = 1
        self.load_lang()

    def load_cn(self):
        global index
        index = 2
        self.load_lang()

    def load_TW(self):
        global index
        index = 3
        self.load_lang()

    def load_lang(self):
        with open("input.txt", "r", encoding="utf-8") as file:
            data = file.read()
        # Удаляем строку "0 TermData mTerms"
        data = data.replace("0 TermData mTerms\n", "")
        # Удаляем символ новой строки после символа "]"
        data = data.replace("]\n", "]")
        # Удаляем 7 пробелов подряд
        data = data.replace("       ", "")
        with open("output.txt", "w", encoding="utf-8") as file:
            file.write(data)
        with open("input.txt", "r", encoding="utf-8") as file:
            data = file.read()
        # Удаляем строку "0 TermData mTerms"
        data = data.replace("0 TermData mTerms\n", "")
        # Удаляем символ новой строки после символа "]"
        data = data.replace("]\n", "]")
        # Удаляем 7 пробелов подряд
        data = data.replace("       ", "")
        with open("output.txt", "w", encoding="utf-8") as file:
            file.write(data)
        input_file = 'output.txt'
        output_file = 'output2.txt'
        term_regex = re.compile(r'Term = "(.+?)"')
        language_regex = re.compile(rf'\[{index}\]1 string Languages = "((?:<.*?>|\s|[^"]*(?:"[^"]*"[^"]*)*[^"]*)+)"')
        terms = {}
        with open(input_file, 'r', encoding='utf-8') as f_input:
            for line in f_input:
                term_match = term_regex.search(line)
                if term_match:
                    term_name = term_match.group(1)
                    terms[term_name] = None
                else:
                    language_match = language_regex.search(line)
                    if language_match:
                        english_translation = language_match.group(1)
                        if term_name and not terms[term_name]:
                            terms[term_name] = english_translation
        with open(output_file, 'w', encoding='utf-8') as f_output:
            for term in sorted(terms.keys()):
                english_translation = terms[term]
                if english_translation:
                    f_output.write(f'    "{term}": "{english_translation}",\n')
        with open('output2.txt', 'r', encoding='utf-8') as input_file:
            lines = input_file.readlines()
        with open('output2.txt', 'w', encoding='utf-8') as output_file:
            for line in lines:
                start_index = 0
                while True:
                    start_index = line.find('<', start_index)
                    if start_index == -1:
                        break
                    end_index = line.find('>', start_index)
                    if end_index == -1:
                        break
                    content = line[start_index:end_index+1]
                    content = content.replace('"', r'\"')
                    line = line[:start_index] + content + line[end_index+1:]
                    start_index = end_index
                output_file.write(line)

        def process_line(line, last_line=False):

            parts = line.split(': "', 1)
            if len(parts) == 2:
                key = parts[0]
                value = parts[1].rsplit('",', 1)[0]

                # Игнорируем обработку, если в значении встречается \"
                if '\\"' in value:
                    return line

                # Обработка значения, как и ранее
                value = value.replace('"', '\\"')
                return f'{key}: "{value}",' if not last_line else f'{key}: "{value}"'

            return line

        input_filename = 'output2.txt'
        output_filename = 'output2.txt'

        with open(input_filename, 'r', encoding='utf-8') as input_file:
            lines = input_file.readlines()

        # Добавляем { в начало и } на новую строку в конце
        processed_lines = ['{'] + [process_line(line) for line in lines] + ['}']

        with open(output_filename, 'w', encoding='utf-8') as output_file:
            output_file.write('\n'.join(processed_lines))

        def fix_json2_file(file_path):
            with open(file_path, 'r', encoding='utf-8') as f:
                lines = f.readlines()

            if lines:
                joined_lines = ''.join(lines)
                # Ищем последнюю запятую перед фигурной скобкой и удаляем её
                updated_content = joined_lines.rsplit(',', 1)[0] + '\n}'

                # Удаление пустых строк
                updated_content = '\n'.join([line for line in updated_content.split('\n') if line.strip()])

                with open(file_path, 'w', encoding='utf-8') as f:
                    f.write(updated_content)

        # Пример использования
        fix_json2_file('output2.txt')

        # Остальшой код остается неизменным
        with open('output2.txt', encoding='utf-8') as f1, open('old.txt', encoding='utf-8') as f2:
            file1_data = json.load(f1)
            file2_data = json.load(f2)
        for key in file1_data:
            if key in file2_data:
                file1_data[key] = file2_data[key]
            else:
                file1_data[key] = file1_data[key] + " ^"
        with open('data.json', 'w', encoding='utf-8') as f:
            json.dump(file1_data, f, ensure_ascii=False, indent=2)
        os.remove("output.txt")
        filename = 'data.json'
        subprocess.Popen(['notepad.exe', filename])
        old_name = 'output2.txt'
        new_name = 'orig.txt'
        if os.path.exists(new_name):
            os.remove(new_name)
        os.rename(old_name, new_name)

root = tk.Tk()
root.title("EasyTranslateCraftopia")
app = Application(master=root)
app.mainloop()


import datetime
import enum

class AssignmentAppData:
    def __init__(self):
        self.categories = []
        self.finished = []
        self.preferences = {}

    def add_category(self, name, color="#FFFFFF"):
        category = Category(name, color)
        self.categories.append(category)

    def add_assignment(self, category_name, id, title, due_date, notes,
                       priority):
        assignment = Assignment(id, title, due_date, notes, priority)
        for category in self.categories:
            if category.name == category_name:
                category.add_assignment(assignment)

    def add_preference(self, name, value):
        self.preferences[name] = value

    def clear_all_data(self):
        self.categories = []
        self.finished = []

    def complete_assignment(self, assignment):
        for c in self.categories:
            for a in c.assignments:
                if a.id == assignment.id:
                    finished_assignment = FinishedAssignment(
                        assignment, datetime.datetime.now(), c.name)
                    self.finished.append(finished_assignment)
                    c.assignments.remove(assignment)
                    break

    def delete_assignment(self, assignment):
        for c in self.categories:
            for a in c.assignments:
                if a.id == assignment.id:
                    c.assignments.remove(assignment)
                    break

    def get_category_names(self):
        return [category.name for category in self.categories]

    def get_soonest_n_assignments(self, n):
        all_assignments_with_categories = []
        for category in self.categories:
            for assignment in category.assignments:
                all_assignments_with_categories.append(
                    (assignment, category.color))
        all_assignments_with_categories = sorted(
            all_assignments_with_categories, key=lambda x: x[0].due_date)
        return all_assignments_with_categories[:n]

    def __str__(self):
        string = ""
        string += "Categories:\n\n"
        for category in self.categories:
            string += category.name + ", " + category.color + "\n"
            string += str(category.assignments)
            string += "\n"
        # TODO add the other attributes here also
        return string

class Category:
    def __init__(self, name, color):
        self.name = name
        self.color = color
        self.assignments = []  # should be sorted newest to oldest date

    def add_assignment(self, assignment):
        self.assignments.append(assignment)
        self.assignments = sorted(self.assignments, key=lambda a: a.due_date)

class Assignment:
    def __init__(self, id, title, due_date, notes, priority):
        self.id = id  # unique
        self.title = title
        self.due_date = due_date
        self.notes = notes
        self.priority = priority

class FinishedAssignment:
    def __init__(self, assignment, finished_date, category):
        self.assignment = assignment
        self.finished_date = finished_date
        self.category = category

class Priority(enum.Enum):
    none = 0
    low = 1
    medium = 2
    high = 3


"""
Test the general functionality of Pysep
"""
from re import L
import pytest
import os
import yaml
from glob import glob
from pysep import Pysep, logger

@pytest.fixture
def config_file():
    """
    Test config file for a 2009 Anchorage earthquake
    """
    return "./test_data/test_config_anchorage.yaml"

@pytest.fixture
def test_pysep(config_file):
    """
    Test Pysep instance based on a Config file, gather event and StationXML
    """
    pysep = Pysep(config_file=config_file, log_level=None)
    pysep.load()
    pysep.check()
    pysep.c = pysep.get_client()
    pysep.event = pysep.get_event()
    pysep.inv = pysep.get_stations()

    return pysep

def test_get_client(test_pysep):
    """
    Simple check that we're looking at IRIS for our client
    """
    assert(test_pysep.c.base_url == "http://service.iris.edu")

def test_get_event(test_pysep):
    """
    Simple check that the event created by User parameters is right
    """
    assert(test_pysep.event.preferred_magnitude().mag == 4.6)

def test_get_inventory(test_pysep):
    """
    Check that the collected stations are correct
    :param test_pysep:
    :return:
    """
    inv = test_pysep.inv
    assert(len(inv.get_contents()["channels"]) == 9)
    assert(f"{inv[0].code}{inv[0][0].code}{inv[0][0][0].code}" == "AKATKABHE")

def test_get_waveform(test_pysep):
    """
    Get waveforms for a few test stations from IRIS
    :param test_pysep:
    :return:
    """
    st = test_pysep.get_waveforms()
    assert(len(st) == 11)
    assert(st[-1].get_id() == "YV.ALPI..BHZ")

def test_curtail_stations(test_pysep):
    """
    Exclude a station based on maximum distance getting exceeded
    """
    inv = test_pysep.curtail_stations()

    nsta_pre_curtail = len(test_pysep.inv.get_contents()["channels"])
    nsta_post_curtail = len(inv.get_contents()["channels"])

    assert(nsta_pre_curtail - nsta_post_curtail == 6)

def test_config_files_have_correct_parameters(tmpdir, test_pysep):
    """
    Check that all the config files have the correct parameters based on what
    PySEP writes to ensure that the config files are up to date with codebase
    """
    # Write a config file from the Pysep instance and read in the yaml file
    fid = os.path.join(tmpdir, "test_config.yaml")
    test_pysep.write_config(fid=fid)
    config = set(yaml.safe_load(open(fid)).keys())

    # Get the directory containing the example config files
    config_dir = "../configs/"

    # Iterate over all the yaml files in the directory
    for dir_ in glob(os.path.join(config_dir, "*")):
        if not os.path.isdir(dir_):
            continue
        for fid in glob(os.path.join(dir_, "*")):
            if not fid.endswith(".yaml"):
                continue
            with open(fid, "r") as f:
                config_check = set(yaml.safe_load(f).keys())
                assert(config.issubset(config_check)), \
                    f"Config file {fid} does not have the correct parameters"


import pandas as pd
import datetime
from datetime import timedelta
import argparse
import os
import json
from format_input_date import year_list_generation
from create_api_urls import create_urls
from retrieve_calendar_data import retrieve_espncalendardata
from json_to_csv import transform_espn_ncaaf_week_data

parser = argparse. \
    ArgumentParser(description='Input game dates (oldest to newest) to pull NCAA Football calendar weeks')
today = (datetime.datetime.today()).strftime('%Y-%m-%d')
end_date = (datetime.datetime.today()).strftime('%Y-%m-%d')
start_date = (datetime.datetime.today() - datetime.timedelta(6*365/12)).strftime('%Y-%m-%d')
parser.add_argument('--start_date', default=start_date, help='Start date to pull data from')
parser.add_argument('--end_date', default=end_date, help='End date to pull data from')
args = parser.parse_args()
start_date = args.start_date
end_date = args.end_date

def main(start_date=start_date, end_date=end_date):

    # Date generation
    print(start_date)
    print(end_date)
    dates = year_list_generation(start_date, end_date)
    file_name = 'years_'
    if os.path.exists('temp'):
        with open('temp/' + file_name + str(start_date) + '_to_' + str(end_date), 'w') as file:
            for item in dates:
                file.write('%s\n' % item)
    else:
        os.mkdir('temp')
        with open('temp/' + file_name + str(start_date) + '_to_' + str(end_date), 'w') as file:
            for item in dates:
                file.write('%s\n' % item)

    # Create date api urls
    date_prefix = 'http://site.api.espn.com/apis/site/v2/sports/football/college-football/scoreboard?dates='
    date_suffix = ''
    file_name = 'urls_'
    year_urls = create_urls(date_prefix, date_suffix, dates)
    with open('temp/' + file_name + str(start_date) + '_to_' + str(end_date), 'w') as file:
        for item in year_urls:
            file.write('%s\n' % item)

    # Retrieve json play by play data
    dfs = []
    file_name = 'json_calendar'
    for i in range(len(year_urls)):
        json_data = retrieve_espncalendardata(year_urls[i])
        url_split = 'dates='
        url_year = (year_urls[i].split(url_split)[1])
        if os.path.exists('temp/calendarjsons'):
            with open('temp/calendarjsons/' + file_name + '_' + str(url_year) + '.json', 'w') as file:
                json.dump(json_data, file)
        else:
            os.mkdir('temp/calendarjsons')
            with open('temp/calendarjsons/' + file_name + '_' + str(url_year) + '.json', 'w') as file:
                json.dump(json_data, file)
        pd_data = transform_espn_ncaaf_week_data(json_data)
        if pd_data.shape[0] != 0:
            max_date = datetime.datetime.strftime(datetime.datetime.strptime(max(pd_data.week_start_date), '%Y-%m-%d') + \
                                                  timedelta(days=6), '%Y-%m-%d')
            idx = pd.date_range(min(pd_data.week_start_date), max_date)
            date_index_df = pd_data.set_index('week_start_date')
            date_index_df.index = pd.DatetimeIndex(date_index_df.index)
            new_df = date_index_df.reindex(idx, method='ffill').reset_index() \
                .reset_index(drop=True) \
                .rename(columns={'index': 'date'})
            dfs.append(new_df)
        else:
            continue

    df = pd.concat(dfs)

    #df.set_index('id', inplace=True)
    df.to_csv('temp/schedule_' + str(start_date.split('-')[0]) + '_to_' + str(end_date.split('-')[0]) + '.csv', \
              index=False)

if __name__ == '__main__':
    main()


import numpy as np
import trimesh
from pydantic import BaseModel, Field, validator

class Polygon(BaseModel):
    vertices: list[float] = Field(example=[1, 0, 0, 2, 1, 0, 1, 2, 0, 0, 1, 0])
    faces: list[int] = Field(example=[0, 1, 2, 0, 2, 3])

    def trimesh_vertices(self):
        """Converts coordinates to 2d numpy array of 3d points."""
        return np.reshape(self.vertices, (-1, 3))

    def trimesh_faces(self):
        """Converts faces to 2d numpy array."""
        return np.reshape(self.faces, (-1, 3))

    def normal(self):
        """Returns polygon normal vector."""
        p = self.trimesh_vertices()
        n = np.cross(p[1] - p[0], p[2] - p[0])
        n /= np.linalg.norm(n)
        return n

    def trimesh_polygon(self):
        return trimesh.Trimesh(
            vertices=self.trimesh_vertices(), faces=self.trimesh_faces()
        )

    def is_convex(self):
        """Check if polygon is convex."""
        import shapely

        # Project vertices to XY and convert to 2D space (remove Z coordinate)
        vertices_2d = self.trimesh_vertices()[:, 0:2]

        # Create shapely polygon
        polygon_2d = shapely.Polygon(vertices_2d)

        # Check if polygon is equal to its convex hull
        return polygon_2d.equals(polygon_2d.convex_hull)

    @validator("vertices")
    def check_coordinates(cls, v):
        assert len(v) % 3 == 0, "Number of polygon coordinates must be divisible by 3."
        assert len(v) >= 9, "Polygon must have at least 3 points."

        z = v[2::3]
        assert z.count(z[0]) == len(z), "Polygon must lie in XY plane."

        return v

    @validator("faces")
    def check_faces(cls, v):
        assert len(v) % 3 == 0, "Number of faces must be divisible by 3."
        assert len(v) >= 1, "Polygon must have at least 1 face."
        return v

class Plane(BaseModel):
    normal: list[float] = Field(example=[1.0, 0, 0])
    constant: float = Field(example=0.0)

    def point(self):
        """Returns plane point."""
        return self.normal * self.constant

    @validator("normal")
    def check_coefficients(cls, n):
        assert len(n) == 3, "Plane normal must be a 3D vector."
        assert sum(n) != 0, "Plane normal must be a non-zero 3D vector."
        return n / np.linalg.norm(n)


import cv2
import numpy as np
img = cv2.imread("assets/images/data.png")
size = img.shape
image_points_2D = np.array([
        (378, 450),
        (378+581, 450),
        (378, 450),
        (378+581, 450+270),
    ], dtype="double")

figure_points_3D = np.array([
    (0.0, 1.0, 0.0),             # left top
    (1.0, 1.0, 0.0),        # right top
    (0.0, 0.0, 0.0),     # left bottom
    (1.0, 0.0, 0.0),      # right bottom
])

distortion_coeffs = np.zeros((4,1))
focal_length = size[1]
center = (size[1]/2, size[0]/2)
matrix_camera = np.array(
    [[focal_length, 0, center[0]],
    [0, focal_length, center[1]],
    [0, 0, 1]], dtype = "double"
)
success, vector_rotation, vector_translation = cv2.solvePnP(figure_points_3D, image_points_2D, matrix_camera, distortion_coeffs, flags=0)
nose_end_point2D, jacobian = cv2.projectPoints(np.array([(0.0, 0.0, 1000.0)]), vector_rotation, vector_translation, matrix_camera, distortion_coeffs)
for p in image_points_2D:
    cv2.circle(img, (int(p[0]), int(p[1])), 3, (0,0,255), -1)

for i in range(len(image_points_2D)):
    point1 = ( int(image_points_2D[i][0]), int(image_points_2D[i][1]))

    point2 = ( int(nose_end_point2D[0][0][0]), int(nose_end_point2D[0][0][1]))

    cv2.line(img, point1, point2, (255,255,255), 2)

cv2.imwrite('tmp/projection.png', img)
print(vector_rotation, vector_translation)
print(vector_rotation.shape, vector_translation.shape)
np.save('data/vr.npy', vector_rotation)
np.save('data/vt.npy', vector_translation)
# cv2.imshow("Final",img)
# cv2.waitKey(0)
# cv2.destroyAllWindows()


"""The Console represents the engine running the game.

This can be Dolphin (Slippi's Ishiiruka) or an SLP file. The Console object
is your method to start and stop Dolphin, set configs, and get the latest GameState.
"""

from collections import defaultdict
from typing import Optional
from packaging import version

import time
import os
import stat
import configparser
import csv
import subprocess
import platform
import math
import base64
import numpy as np
from pathlib import Path
import shutil
import tempfile

from melee import enums
from melee.enums import Action
from melee.gamestate import GameState, Projectile, PlayerState
from melee.slippstream import SlippstreamClient, EventType
from melee.slpfilestreamer import SLPFileStreamer
from melee import stages

class SlippiVersionTooLow(Exception):
    """Raised when the Slippi version is not recent enough"""
    def __init__(self, message):
        self.message = message

class InvalidDolphinPath(Exception):
    """Raised when given path to Dolphin is invalid"""
    def __init__(self, message):
        self.message = message

def _ignore_fifos(src, names):
    fifos = []
    for name in names:
        path = os.path.join(src, name)
        if stat.S_ISFIFO(os.stat(path).st_mode):
            fifos.append(name)
    return fifos

def _copytree_safe(src, dst):
    shutil.copytree(src, dst, ignore=_ignore_fifos)

def _default_home_path(path: str) -> str:
    if platform.system() == "Darwin":
        return path + "/Contents/Resources/User/"

    # Next check if the home path is in the same dir as the exe
    user_path = path + "/User/"
    if os.path.isdir(user_path):
        return user_path

    # Otherwise, this must be an appimage install. Use the .config
    if platform.system() == "Linux":
        return str(Path.home()) + "/.config/SlippiOnline/"

    raise FileNotFoundError("Could not find dolphin home directory.")

# pylint: disable=too-many-instance-attributes
class Console:
    """The console object that represents your Dolphin / GameCube / SLP file
    """
    def __init__(self,
                 path=None,
                 system="dolphin",
                 dolphin_home_path=None,
                 tmp_home_directory=True,
                 copy_home_directory=True,
                 slippi_address="127.0.0.1",
                 slippi_port=51441,
                 online_delay=2,
                 blocking_input=False,
                 polling_mode=False,
                 allow_old_version=False,
                 logger=None,
                 setup_gecko_codes=True,
                 fullscreen=True,
                 gfx_backend="",
                 disable_audio=False,
                 overclock: Optional[float] = None,
                 save_replays=True,
                ):
        """Create a Console object

        Args:
            path (str): Path to the directory where your dolphin executable is located.
                If None, will assume the dolphin is remote and won't try to configure it.
            dolphin_home_path (str): Path to dolphin user directory. Optional.
            system (string): One of "dolphin", "file", or "gamecube"
            tmp_home_directory (bool): Use a temporary directory for the dolphin User path
                This is useful so instances don't interfere with each other.
            copy_home_directory (bool): Copy an existing home directory on the system.
                Unset to get a fresh directory that doesn't depend on system state.
            slippi_address (str): IP address of the Dolphin / gamecube to connect to.
            slippi_port (int): UDP port that slippi will listen on
            online_delay (int): How many frames of delay to apply in online matches
            blocking_input (bool): Should dolphin block waiting for bot input
                This is only really useful if you're doing ML training.
            polling_mode (bool): Polls input to console rather than blocking for it
                When set, step() will always return immediately, but may be None if no
                gamestate is available yet.
            allow_old_version (bool): Allow SLP versions older than 3.0.0 (rollback era)
                Only enable if you know what you're doing. You probably don't want this.
                Gamestates will be missing key information, come in really late, or possibly not work at all
            logger (logger.Logger): Logger instance to use. None for no logger.
            setup_gecko_codes (bool): Overwrites the user's GALE01r2.ini with libmelee's
                custom gecko codes. Should be used with tmp_home_directory.
            fullscreen (bool): Run melee fullscreen.
            gfx_backend (str): Graphics backend. Leave blank to use default.
            disable_audio (bool): Turn off sound.
            overclock (bool): Overclock the dolphin CPU.
            save_replays (bool): Save slippi replays.
        """
        self.logger = logger
        self.system = system
        self.path = path
        self.dolphin_home_path = dolphin_home_path
        self.temp_dir = None
        if tmp_home_directory and self.system =="dolphin":
            self.temp_dir = tempfile.mkdtemp(prefix='libmelee_')
            home_dir = self.temp_dir + "/User/"
            if copy_home_directory:
                _copytree_safe(self._get_dolphin_home_path(), home_dir)
            self.dolphin_home_path = home_dir

        self.processingtime = 0
        self._frametimestamp = time.time()
        self.slippi_address = slippi_address
        """(str): IP address of the Dolphin / gamecube to connect to."""
        self.slippi_port = slippi_port
        """(int): UDP port of slippi server. Default 51441"""
        self.eventsize = [0] * 0x100
        self.connected = False
        self.nick = ""
        """(str): The nickname the console has given itself."""
        self.version = ""
        """(str): The Slippi version of the console"""
        self.cursor = 0
        self.controllers = []
        self._current_stage = enums.Stage.NO_STAGE
        self._frame = 0
        self._polling_mode = polling_mode
        self.slp_version = "unknown"
        """(str): The SLP version this stream/file currently is."""
        self._allow_old_version = allow_old_version
        self._use_manual_bookends = False
        self._costumes = {0:0, 1:0, 2:0, 3:0}
        self._cpu_level = {0:0, 1:0, 2:0, 3:0}
        self._team_id = {0:0, 1:0, 2:0, 3:0}
        self._invuln_start = {1:(0,0), 2:(0,0), 3:(0,0), 4:(0,0)}
        self._is_teams = False

        self.setup_gecko_codes = setup_gecko_codes
        self.online_delay = online_delay
        self.blocking_input = blocking_input
        self.fullscreen = fullscreen
        self.gfx_backend = gfx_backend
        self.disable_audio = disable_audio
        self.overclock = overclock
        self.save_replays = save_replays

        # Keep a running copy of the last gamestate produced
        self._prev_gamestate = GameState()
        # Half-completed gamestate not yet ready to add to the list
        self._temp_gamestate = None
        self._process = None
        assert(self.system in ["dolphin", "gamecube", "file"])
        if self.system == "dolphin":
            self._slippstream = SlippstreamClient(self.slippi_address, self.slippi_port, True)
            if self.path:
                self._setup_home_directory()
        elif self.system == "gamecube":
            self._slippstream = SlippstreamClient(self.slippi_address, self.slippi_port, False)
        else:
            self._slippstream = SLPFileStreamer(self.path)

        # Prepare some structures for fixing melee data
        path = os.path.dirname(os.path.realpath(__file__))
        with open(path + "/actiondata.csv") as csvfile:
            #A list of dicts containing the frame data
            actiondata = list(csv.DictReader(csvfile))
            #Dict of sets
            self.zero_indices = defaultdict(set)
            for line in actiondata:
                if line["zeroindex"] == "True":
                    self.zero_indices[int(line["character"])].add(int(line["action"]))

        # Read the character data csv
        self.characterdata = dict()
        with open(path + "/characterdata.csv") as csvfile:
            reader = csv.DictReader(csvfile)
            for line in reader:
                del line["Character"]
                #Convert all fields to numbers
                for key, value in line.items():
                    line[key] = float(value)
                self.characterdata[enums.Character(line["CharacterIndex"])] = line

    def connect(self):
        """ Connects to the Slippi server (dolphin or gamecube).

        Returns:
            True is successful, False otherwise
        """
        return self._slippstream.connect()

    def _get_dolphin_home_path(self):
        """Return the path to dolphin's home directory"""
        if self.dolphin_home_path:
            return self.dolphin_home_path

        assert self.path, "Must specify a dolphin path."

        return _default_home_path(self.path)

    def _get_dolphin_config_path(self):
        """ Return the path to dolphin's config directory."""
        return self._get_dolphin_home_path() + "Config/"

    def get_dolphin_pipes_path(self, port):
        """Get the path of the named pipe input file for the given controller port
        """
        if platform.system() == "Windows":
            return '\\\\.\\pipe\\slippibot' + str(port)
        pipes_path = self._get_dolphin_home_path() + "/Pipes/"
        if not os.path.isdir(pipes_path):
            os.makedirs(pipes_path, exist_ok=True)
        return pipes_path + f"slippibot{port}"

    def run(self, iso_path=None, dolphin_user_path=None, environment_vars=None, exe_name=None):
        """Run the Dolphin emulator.

        This starts the Dolphin process, so don't run this if you're connecting to an
        already running Dolphin instance.

        Args:
            iso_path (str, optional): Path to Melee ISO for dolphin to read
            dolphin_user_path (str, optional): Alternative user path for dolphin
                if not using the default
            environment_vars (dict, optional): Dict (string->string) of environment variables to set
            exe_name (str, optional): Name of the dolphin executable.
        """
        assert self.system == "dolphin" and self.path

        dolphin_user_path = dolphin_user_path or self._get_dolphin_home_path()

        exe_name = exe_name or "dolphin-emu"
        if platform.system() == "Windows":
            exe_name = "Slippi Dolphin.exe"
        elif platform.system() == "Darwin":
            exe_name = "Slippi Dolphin"

        exe_path = ""
        if self.path:
            exe_path = self.path
        if platform.system() == "Darwin":
            exe_path += "/Contents/MacOS"
        command = [exe_path + "/" + exe_name]

        # AppImage
        if platform.system() == "Linux" and os.path.isfile(self.path):
            command = [self.path]

        if iso_path is not None:
            command.append("-e")
            command.append(iso_path)
        command.append("-u")
        command.append(dolphin_user_path)
        env = os.environ.copy()
        if environment_vars is not None:
            env.update(environment_vars)
        self._process = subprocess.Popen(command, env=env)

    def stop(self):
        """ Stop the console.

        For Dolphin instances, this will kill the dolphin process.
        For gamecubes and SLP files, it just shuts down our connection
         """
        if self.path:
            self.connected = False
            self._slippstream.shutdown()
            # If dolphin, kill the process
            if self._process is not None:
                self._process.terminate()
                self._process = None

        if self.temp_dir:
            shutil.rmtree(self.temp_dir)
            self.temp_dir = None

    def _setup_home_directory(self,):
        self._setup_dolphin_ini()
        if self.setup_gecko_codes:
            self._setup_gecko_codes()

    def _setup_dolphin_ini(self):
        # Setup some dolphin config options
        config_path = self._get_dolphin_config_path()
        os.makedirs(config_path, exist_ok=True)
        dolphin_ini_path = os.path.join(config_path, "Dolphin.ini")

        config = configparser.ConfigParser()
        if os.path.isfile(dolphin_ini_path):
            config.read(dolphin_ini_path)

        for section in ["Core", "Input", "Display", "DSP"]:
            if not config.has_section(section):
                config.add_section(section)
        config.set("Core", 'slippienablespectator', "True")
        config.set("Core", 'slippispectatorlocalport', str(self.slippi_port))
        # Set online delay
        config.set("Core", 'slippionlinedelay', str(self.online_delay))
        # Turn on background input so we don't need to have window focus on dolphin
        config.set("Input", 'backgroundinput', "True")
        config.set("Core", 'BlockingPipes', str(self.blocking_input))
        config.set("Core", "GFXBackend", self.gfx_backend)
        config.set("Display", "Fullscreen", str(self.fullscreen))
        if self.disable_audio:
            config.set("DSP", "Backend", "No audio output")

        if self.overclock:
            config.set("Core", "Overclock", str(self.overclock))
            config.set("Core", "OverclockEnable", "True")

        config.set("Core", "SlippiSaveReplays", str(self.save_replays))

        with open(dolphin_ini_path, 'w') as dolphinfile:
            config.write(dolphinfile)

    def _setup_gecko_codes(self):
        game_settings_path = os.path.join(self._get_dolphin_home_path(), 'GameSettings')
        os.makedirs(game_settings_path, exist_ok=True)

        libmelee_path = os.path.dirname(os.path.realpath(__file__))
        gale01r2_ini_path = os.path.join(libmelee_path, "GALE01r2.ini")

        shutil.copy(gale01r2_ini_path, game_settings_path)

    def setup_dolphin_controller(self, port, controllertype=enums.ControllerType.STANDARD):
        """Setup the necessary files for dolphin to recognize the player at the given
        controller port and type"""

        pipes_path = self.get_dolphin_pipes_path(port)
        if platform.system() != "Windows" and controllertype == enums.ControllerType.STANDARD:
            if not os.path.exists(pipes_path):
                os.mkfifo(pipes_path)

        #Read in dolphin's controller config file
        controller_config_path = self._get_dolphin_config_path() + "GCPadNew.ini"
        config = configparser.ConfigParser()
        config.read(controller_config_path)

        #Add a bot standard controller config to the given port
        section = "GCPad" + str(port)
        if not config.has_section(section):
            config.add_section(section)

        if controllertype == enums.ControllerType.STANDARD:
            config.set(section, 'Device', 'Pipe/0/slippibot' + str(port))
            config.set(section, 'Buttons/A', 'Button A')
            config.set(section, 'Buttons/B', 'Button B')
            config.set(section, 'Buttons/X', 'Button X')
            config.set(section, 'Buttons/Y', 'Button Y')
            config.set(section, 'Buttons/Z', 'Button Z')
            config.set(section, 'Buttons/L', 'Button L')
            config.set(section, 'Buttons/R', 'Button R')
            config.set(section, 'Buttons/Threshold', '50.00000000000000')
            config.set(section, 'Main Stick/Up', 'Axis MAIN Y +')
            config.set(section, 'Main Stick/Down', 'Axis MAIN Y -')
            config.set(section, 'Main Stick/Left', 'Axis MAIN X -')
            config.set(section, 'Main Stick/Right', 'Axis MAIN X +')
            config.set(section, 'Triggers/L', 'Button L')
            config.set(section, 'Triggers/R', 'Button R')
            config.set(section, 'Main Stick/Modifier', 'Shift_L')
            config.set(section, 'Main Stick/Modifier/Range', '50.000000000000000')
            config.set(section, 'Main Stick/Radius', '100.000000000000000')
            config.set(section, 'D-Pad/Up', 'Button D_UP')
            config.set(section, 'D-Pad/Down', 'Button D_DOWN')
            config.set(section, 'D-Pad/Left', 'Button D_LEFT')
            config.set(section, 'D-Pad/Right', 'Button D_RIGHT')
            config.set(section, 'Buttons/Start', 'Button START')
            config.set(section, 'Buttons/A', 'Button A')
            config.set(section, 'C-Stick/Up', 'Axis C Y +')
            config.set(section, 'C-Stick/Down', 'Axis C Y -')
            config.set(section, 'C-Stick/Left', 'Axis C X -')
            config.set(section, 'C-Stick/Right', 'Axis C X +')
            config.set(section, 'C-Stick/Radius', '100.000000000000000')
            config.set(section, 'Triggers/L-Analog', 'Axis L -+')
            config.set(section, 'Triggers/R-Analog', 'Axis R -+')
            config.set(section, 'Triggers/Threshold', '90.00000000000000')
        #This section is unused if it's not a standard input (I think...)
        else:
            config.set(section, 'Device', 'XInput2/0/Virtual core pointer')

        with open(controller_config_path, 'w') as configfile:
            config.write(configfile)

        dolphin_config_path = self._get_dolphin_config_path() + "Dolphin.ini"
        config = configparser.ConfigParser()
        config.read(dolphin_config_path)
        # Indexed at 0. "6" means standard controller, "12" means GCN Adapter
        #  The enum is scoped to the proper value, here
        config.set("Core", 'SIDevice'+str(port-1), controllertype.value)
        with open(dolphin_config_path, 'w') as dolphinfile:
            config.write(dolphinfile)

    def step(self):
        """ 'step' to the next state of the game and flushes all controllers

        Returns:
            GameState object that represents new current state of the game"""
        self.processingtime = time.time() - self._frametimestamp

        # Flush the controllers
        for controller in self.controllers:
            controller.flush()

        if self._temp_gamestate is None:
            self._temp_gamestate = GameState()

        frame_ended = False
        while not frame_ended:
            message = self._slippstream.dispatch(self._polling_mode)
            if message:
                if message["type"] == "connect_reply":
                    self.connected = True
                    self.nick = message["nick"]
                    self.version = message["version"]
                    self.cursor = message["cursor"]

                elif message["type"] == "game_event":
                    if len(message["payload"]) > 0:
                        if self.system == "dolphin":
                            frame_ended = self.__handle_slippstream_events(base64.b64decode(message["payload"]), self._temp_gamestate)
                        else:
                            frame_ended = self.__handle_slippstream_events(message["payload"], self._temp_gamestate)

                elif message["type"] == "menu_event":
                    if len(message["payload"]) > 0:
                        if self.system == "dolphin":
                            self.__handle_slippstream_menu_event(base64.b64decode(message["payload"]), self._temp_gamestate)
                        else:
                            self.__handle_slippstream_menu_event(message["payload"], self._temp_gamestate)
                        frame_ended = True

                elif self._use_manual_bookends and message["type"] == "frame_end" and self._frame != -10000:
                    frame_ended = True
            else:
                return None

        gamestate = self._temp_gamestate
        self._temp_gamestate = None
        self.__fixframeindexing(gamestate)
        self.__fixiasa(gamestate)
        # Insert some metadata into the gamestate
        gamestate.playedOn = self._slippstream.playedOn
        gamestate.startAt = self._slippstream.timestamp
        gamestate.consoleNick = self._slippstream.consoleNick
        for i, names in self._slippstream.players.items():
            try:
                gamestate.players[int(i)+1].nickName = names["names"]["netplay"]
            except KeyError:
                pass
            try:
                gamestate.players[int(i)+1].connectCode = names["names"]["code"]
            except KeyError:
                pass

        # Start the processing timer now that we're done reading messages
        self._frametimestamp = time.time()
        return gamestate

    def __handle_slippstream_events(self, event_bytes, gamestate):
        """ Handle a series of events, provided sequentially in a byte array """
        gamestate.menu_state = enums.Menu.IN_GAME
        while len(event_bytes) > 0:
            # A null message type means that the rest of the data is padding
            if event_bytes[0] == 0x00:
                return True
            event_size = self.eventsize[event_bytes[0]]
            if len(event_bytes) < event_size:
                print("WARNING: Something went wrong unpacking events. Data is probably missing")
                print("\tDidn't have enough data for event")
                return False
            if EventType(event_bytes[0]) == EventType.PAYLOADS:
                cursor = 0x2
                payload_size = event_bytes[1]
                num_commands = (payload_size - 1) // 3
                for i in range(0, num_commands):
                    command = np.ndarray((1,), ">B", event_bytes, cursor)[0]
                    command_len = np.ndarray((1,), ">H", event_bytes, cursor + 0x1)[0]
                    self.eventsize[command] = command_len+1
                    cursor += 3
                event_bytes = event_bytes[payload_size + 1:]

            elif EventType(event_bytes[0]) == EventType.FRAME_START:
                event_bytes = event_bytes[event_size:]

            elif EventType(event_bytes[0]) == EventType.GAME_START:
                self.__game_start(gamestate, event_bytes)
                event_bytes = event_bytes[event_size:]
                # The game needs to know what to press on the first frame of the game
                #   Just give it empty input. Characters are not actionable anyway.
                for controller in self.controllers:
                    controller.release_all()
                    controller.flush()

            elif EventType(event_bytes[0]) == EventType.GAME_END:
                event_bytes = event_bytes[event_size:]
                return self._use_manual_bookends

            elif EventType(event_bytes[0]) == EventType.PRE_FRAME:
                self.__pre_frame(gamestate, event_bytes)
                event_bytes = event_bytes[event_size:]

            elif EventType(event_bytes[0]) == EventType.POST_FRAME:
                self.__post_frame(gamestate, event_bytes)
                event_bytes = event_bytes[event_size:]

            elif EventType(event_bytes[0]) == EventType.GECKO_CODES:
                event_bytes = event_bytes[event_size:]

            elif EventType(event_bytes[0]) == EventType.FRAME_BOOKEND:
                self.__frame_bookend(gamestate, event_bytes)
                event_bytes = event_bytes[event_size:]
                # If this is an old frame, then don't return it.
                if gamestate.frame <= self._frame:
                    return False
                self._frame = gamestate.frame
                return True

            elif EventType(event_bytes[0]) == EventType.ITEM_UPDATE:
                self.__item_update(gamestate, event_bytes)
                event_bytes = event_bytes[event_size:]

            else:
                print("WARNING: Something went wrong unpacking events. " + \
                    "Data is probably missing")
                print("\tGot invalid event type: ", event_bytes[0])
                return False
        return False

    def __game_start(self, gamestate, event_bytes):
        self._frame = -10000
        major = np.ndarray((1,), ">B", event_bytes, 0x1)[0]
        minor = np.ndarray((1,), ">B", event_bytes, 0x2)[0]
        version_num = np.ndarray((1,), ">B", event_bytes, 0x3)[0]
        self.slp_version = str(major) + "." + str(minor) + "." + str(version_num)
        self._use_manual_bookends = self._allow_old_version and (version.parse(self.slp_version) < version.parse("3.0.0"))
        if major < 3 and not self._allow_old_version:
            raise SlippiVersionTooLow(self.slp_version)
        try:
            self._current_stage = enums.to_internal_stage(np.ndarray((1,), ">H", event_bytes, 0x13)[0])
        except ValueError:
            self._current_stage = enums.Stage.NO_STAGE

        self._is_teams = not (np.ndarray((1,), ">H", event_bytes, 0xD)[0] == 0)

        for i in range(4):
            self._costumes[i] = np.ndarray((1,), ">B", event_bytes, 0x68 + (0x24 * i))[0]

        for i in range(4):
            self._cpu_level[i] = np.ndarray((1,), ">B", event_bytes, 0x74 + (0x24 * i))[0]

        for i in range(4):
            self._team_id[i] = np.ndarray((1,), ">B", event_bytes, 0x6E + (0x24 * i))[0]

        for i in range(4):
            if np.ndarray((1,), ">B", event_bytes, 0x66 + (0x24 * i))[0] != 1:
                self._cpu_level[i] = 0

    def __pre_frame(self, gamestate, event_bytes):
        # Grab the physical controller state and put that into the controller state
        controller_port = np.ndarray((1,), ">B", event_bytes, 0x5)[0] + 1

        if controller_port not in gamestate.players:
            gamestate.players[controller_port] = PlayerState()
        playerstate = gamestate.players[controller_port]

        # Is this Nana?
        if np.ndarray((1,), ">B", event_bytes, 0x6)[0] == 1:
            playerstate.nana = PlayerState()
            playerstate = playerstate.nana

        playerstate.costume = self._costumes[controller_port-1]
        playerstate.cpu_level = self._cpu_level[controller_port-1]
        playerstate.team_id = self._team_id[controller_port-1]

        main_x = (np.ndarray((1,), ">f", event_bytes, 0x19)[0] / 2) + 0.5
        main_y = (np.ndarray((1,), ">f", event_bytes, 0x1D)[0] / 2) + 0.5
        playerstate.controller_state.main_stick = (main_x, main_y)

        c_x = (np.ndarray((1,), ">f", event_bytes, 0x21)[0] / 2) + 0.5
        c_y = (np.ndarray((1,), ">f", event_bytes, 0x25)[0] / 2) + 0.5
        playerstate.controller_state.c_stick = (c_x, c_y)

        # The game interprets both shoulders together, so the processed value will always be the same
        trigger = (np.ndarray((1,), ">f", event_bytes, 0x29)[0])
        playerstate.controller_state.l_shoulder = trigger
        playerstate.controller_state.r_shoulder = trigger

        buttonbits = np.ndarray((1,), ">H", event_bytes, 0x31)[0]
        playerstate.controller_state.button[enums.Button.BUTTON_A] = bool(int(buttonbits) & 0x0100)
        playerstate.controller_state.button[enums.Button.BUTTON_B] = bool(int(buttonbits) & 0x0200)
        playerstate.controller_state.button[enums.Button.BUTTON_X] = bool(int(buttonbits) & 0x0400)
        playerstate.controller_state.button[enums.Button.BUTTON_Y] = bool(int(buttonbits) & 0x0800)
        playerstate.controller_state.button[enums.Button.BUTTON_START] = bool(int(buttonbits) & 0x1000)
        playerstate.controller_state.button[enums.Button.BUTTON_Z] = bool(int(buttonbits) & 0x0010)
        playerstate.controller_state.button[enums.Button.BUTTON_R] = bool(int(buttonbits) & 0x0020)
        playerstate.controller_state.button[enums.Button.BUTTON_L] = bool(int(buttonbits) & 0x0040)
        playerstate.controller_state.button[enums.Button.BUTTON_D_LEFT] = bool(int(buttonbits) & 0x0001)
        playerstate.controller_state.button[enums.Button.BUTTON_D_RIGHT] = bool(int(buttonbits) & 0x0002)
        playerstate.controller_state.button[enums.Button.BUTTON_D_DOWN] = bool(int(buttonbits) & 0x0004)
        playerstate.controller_state.button[enums.Button.BUTTON_D_UP] = bool(int(buttonbits) & 0x0008)
        if self._use_manual_bookends:
            self._frame = gamestate.frame

    def __post_frame(self, gamestate, event_bytes):
        gamestate.stage = self._current_stage
        gamestate.is_teams = self._is_teams
        gamestate.frame = np.ndarray((1,), ">i", event_bytes, 0x1)[0]
        controller_port = np.ndarray((1,), ">B", event_bytes, 0x5)[0] + 1

        if controller_port not in gamestate.players:
            gamestate.players[controller_port] = PlayerState()
        playerstate = gamestate.players[controller_port]

        # Is this Nana?
        if np.ndarray((1,), ">B", event_bytes, 0x6)[0] == 1:
            playerstate.nana = PlayerState()
            playerstate = playerstate.nana

        playerstate.position.x = np.ndarray((1,), ">f", event_bytes, 0xa)[0]
        playerstate.position.y = np.ndarray((1,), ">f", event_bytes, 0xe)[0]

        playerstate.x = playerstate.position.x
        playerstate.y = playerstate.position.y

        playerstate.character = enums.Character(np.ndarray((1,), ">B", event_bytes, 0x7)[0])
        try:
            playerstate.action = enums.Action(np.ndarray((1,), ">H", event_bytes, 0x8)[0])
        except ValueError:
            playerstate.action = enums.Action.UNKNOWN_ANIMATION

        # Melee stores this in a float for no good reason. So we have to convert
        playerstate.facing = np.ndarray((1,), ">f", event_bytes, 0x12)[0] > 0

        playerstate.percent = int(np.ndarray((1,), ">f", event_bytes, 0x16)[0])
        playerstate.shield_strength = np.ndarray((1,), ">f", event_bytes, 0x1A)[0]
        playerstate.stock = np.ndarray((1,), ">B", event_bytes, 0x21)[0]
        playerstate.action_frame = int(np.ndarray((1,), ">f", event_bytes, 0x22)[0])

        try:
            sb4 = int(np.ndarray((1,), ">B", event_bytes, 0x29)[0])
            playerstate.is_powershield = (sb4 & 0x20) == 0x20
        except TypeError:
            playerstate.is_powershield = False

        try:
            playerstate.hitstun_frames_left = int(np.ndarray((1,), ">f", event_bytes, 0x2B)[0])
        except TypeError:
            playerstate.hitstun_frames_left = 0
        except ValueError:
            playerstate.hitstun_frames_left = 0
        try:
            playerstate.on_ground = not bool(np.ndarray((1,), ">B", event_bytes, 0x2F)[0])
        except TypeError:
            playerstate.on_ground = True
        try:
            playerstate.jumps_left = np.ndarray((1,), ">B", event_bytes, 0x32)[0]
        except TypeError:
            playerstate.jumps_left = 1

        try:
            playerstate.invulnerable = int(np.ndarray((1,), ">B", event_bytes, 0x34)[0]) != 0
        except TypeError:
            playerstate.invulnerable = False

        try:
            playerstate.speed_air_x_self = np.ndarray((1,), ">f", event_bytes, 0x35)[0]
        except TypeError:
            playerstate.speed_air_x_self = 0

        try:
            playerstate.speed_y_self = np.ndarray((1,), ">f", event_bytes, 0x39)[0]
        except TypeError:
            playerstate.speed_y_self = 0

        try:
            playerstate.speed_x_attack = np.ndarray((1,), ">f", event_bytes, 0x3D)[0]
        except TypeError:
            playerstate.speed_x_attack = 0

        try:
            playerstate.speed_y_attack = np.ndarray((1,), ">f", event_bytes, 0x41)[0]
        except TypeError:
            playerstate.speed_y_attack = 0

        try:
            playerstate.speed_ground_x_self = np.ndarray((1,), ">f", event_bytes, 0x45)[0]
        except TypeError:
            playerstate.speed_ground_x_self = 0

        try:
            playerstate.hitlag_left = int(np.ndarray((1,), ">f", event_bytes, 0x49)[0])
        except TypeError:
            playerstate.hitlag_left = 0

        # Keep track of a player's invulnerability due to respawn or ledge grab
        if controller_port in self._prev_gamestate.players:
            playerstate.invulnerability_left = max(0, self._invuln_start[controller_port][1] - (gamestate.frame - self._invuln_start[controller_port][0]))
        if playerstate.action == Action.ON_HALO_WAIT:
            playerstate.invulnerability_left = 120
            self._invuln_start[controller_port] = (gamestate.frame, 120)
        # Don't give invulnerability to the first descent
        if playerstate.action == Action.ON_HALO_DESCENT and gamestate.frame > 150:
            playerstate.invulnerability_left = 120
            self._invuln_start[controller_port] = (gamestate.frame, 120)
        if playerstate.action == Action.EDGE_CATCHING and playerstate.action_frame == 1:
            playerstate.invulnerability_left = 36
            self._invuln_start[controller_port] = (gamestate.frame, 36)
        # First frame of the game
        if gamestate.frame == -123:
            playerstate.invulnerability_left = 0
            self._invuln_start[controller_port] = (gamestate.frame, 0)

        if playerstate.invulnerability_left > 0:
            playerstate.invulnerable = True

        # The pre-warning occurs when we first start a dash dance.
        if controller_port in self._prev_gamestate.players:
            if playerstate.action == Action.DASHING and \
                    self._prev_gamestate.players[controller_port].action not in [Action.DASHING, Action.TURNING]:
                playerstate.moonwalkwarning = True

        # Take off the warning if the player does an action other than dashing
        if playerstate.action != Action.DASHING:
            playerstate.moonwalkwarning = False

        # "off_stage" helper
        try:
            if (abs(playerstate.position.x) > stages.EDGE_GROUND_POSITION[gamestate.stage] or \
                    playerstate.y < -6) and not playerstate.on_ground:
                playerstate.off_stage = True
            else:
                playerstate.off_stage = False
        except KeyError:
            playerstate.off_stage = False

        # ECB top edge, x
        ecb_top_x = 0
        ecb_top_y = 0
        try:
            ecb_top_x = np.ndarray((1,), ">f", event_bytes, 0x51)[0]
        except TypeError:
            ecb_top_x = 0
        # ECB Top edge, y
        try:
            ecb_top_y = np.ndarray((1,), ">f", event_bytes, 0x55)[0]
        except TypeError:
            ecb_top_y = 0
        playerstate.ecb.top.x = ecb_top_x
        playerstate.ecb.top.y = ecb_top_y
        playerstate.ecb_top = (ecb_top_x, ecb_top_y)

        # ECB bottom edge, x coord
        ecb_bot_x = 0
        ecb_bot_y = 0
        try:
            ecb_bot_x = np.ndarray((1,), ">f", event_bytes, 0x59)[0]
        except TypeError:
            ecb_bot_x = 0
        # ECB Bottom edge, y coord
        try:
            ecb_bot_y = np.ndarray((1,), ">f", event_bytes, 0x5D)[0]
        except TypeError:
            ecb_bot_y = 0
        playerstate.ecb.bottom.x = ecb_bot_x
        playerstate.ecb.bottom.y = ecb_bot_y
        playerstate.ecb_bottom = (ecb_bot_x, ecb_bot_y)

        # ECB left edge, x coord
        ecb_left_x = 0
        ecb_left_y = 0
        try:
            ecb_left_x = np.ndarray((1,), ">f", event_bytes, 0x61)[0]
        except TypeError:
            ecb_left_x = 0
        # ECB left edge, y coord
        try:
            ecb_left_y = np.ndarray((1,), ">f", event_bytes, 0x65)[0]
        except TypeError:
            ecb_left_y = 0
        playerstate.ecb.left.x = ecb_left_x
        playerstate.ecb.left.y = ecb_left_y
        playerstate.ecb_left = (ecb_left_x, ecb_left_y)

        # ECB right edge, x coord
        ecb_right_x = 0
        ecb_right_y = 0
        try:
            ecb_right_x = np.ndarray((1,), ">f", event_bytes, 0x69)[0]
        except TypeError:
            ecb_right_x = 0
        # ECB right edge, y coord
        try:
            ecb_right_y = np.ndarray((1,), ">f", event_bytes, 0x6D)[0]
        except TypeError:
            ecb_right_y = 0
        playerstate.ecb.right.x = ecb_right_x
        playerstate.ecb.right.y = ecb_right_y
        playerstate.ecb_right = (ecb_right_x, ecb_right_y)
        if self._use_manual_bookends:
            self._frame = gamestate.frame

        # FoD platform heights
        try:
            gamestate._fod_platform_left = np.ndarray((1,), ">f", event_bytes, 0x71)[0]
        except TypeError:
            gamestate._fod_platform_left = 0
        try:
            gamestate._fod_platform_right = np.ndarray((1,), ">f", event_bytes, 0x75)[0]
        except TypeError:
            gamestate._fod_platform_right = 0

    def __frame_bookend(self, gamestate, event_bytes):
        self._prev_gamestate = gamestate
        # Calculate helper distance variable
        #   This is a bit kludgey.... :/
        i = 0
        player_one_x, player_one_y, player_two_x, player_two_y = 0, 0, 0, 0
        for _, player_state in gamestate.players.items():
            if i == 0:
                player_one_x, player_one_y = player_state.position.x, player_state.position.y
            if i == 1:
                player_two_x, player_two_y = player_state.position.x, player_state.position.y
            i += 1
        xdist = player_one_x - player_two_x
        ydist = player_one_y - player_two_y
        gamestate.distance = math.sqrt((xdist**2) + (ydist**2))

    def __item_update(self, gamestate, event_bytes):
        projectile = Projectile()
        projectile.position.x = np.ndarray((1,), ">f", event_bytes, 0x14)[0]
        projectile.position.y = np.ndarray((1,), ">f", event_bytes, 0x18)[0]
        projectile.x = projectile.position.x
        projectile.y = projectile.position.y
        projectile.speed.x = np.ndarray((1,), ">f", event_bytes, 0xc)[0]
        projectile.speed.y = np.ndarray((1,), ">f", event_bytes, 0x10)[0]
        projectile.x_speed = projectile.speed.x
        projectile.y_speed = projectile.speed.y
        try:
            projectile.owner = np.ndarray((1,), ">B", event_bytes, 0x2A)[0] + 1
            if projectile.owner > 4:
                projectile.owner = -1
        except TypeError:
            projectile.owner = -1
        try:
            projectile.type = enums.ProjectileType(np.ndarray((1,), ">H", event_bytes, 0x5)[0])
        except ValueError:
            projectile.type = enums.ProjectileType.UNKNOWN_PROJECTILE

        try:
            projectile.frame = int(np.ndarray((1,), ">f", event_bytes, 0x1E)[0])
        except ValueError:
            projectile.frame = -1

        projectile.subtype = np.ndarray((1,), ">B", event_bytes, 0x7)[0]

        # Ignore exploded Samus bombs. They are subtype 3
        if projectile.type == enums.ProjectileType.SAMUS_BOMB and projectile.subtype == 3:
            return
        # Ignore exploded Samus missles
        if projectile.type == enums.ProjectileType.SAMUS_MISSLE and projectile.subtype in [2, 3]:
            return
        # Ignore Samus charge beam while charging (not firing)
        if projectile.type == enums.ProjectileType.SAMUS_CHARGE_BEAM and projectile.subtype == 0:
            return

        # Add the projectile to the gamestate list
        gamestate.projectiles.append(projectile)

    def __handle_slippstream_menu_event(self, event_bytes, gamestate):
        """ Internal handler for slippstream menu events

        Modifies specified gamestate based on the event bytes
         """
        scene = np.ndarray((1,), ">H", event_bytes, 0x1)[0]
        if scene == 0x02:
            gamestate.menu_state = enums.Menu.CHARACTER_SELECT
            # All the controller ports are active on this screen
            gamestate.players[1] = PlayerState()
            gamestate.players[2] = PlayerState()
            gamestate.players[3] = PlayerState()
            gamestate.players[4] = PlayerState()
        elif scene in [0x0102, 0x0108]:
            gamestate.menu_state = enums.Menu.STAGE_SELECT
            gamestate.players[1] = PlayerState()
            gamestate.players[2] = PlayerState()
            gamestate.players[3] = PlayerState()
            gamestate.players[4] = PlayerState()
        elif scene == 0x0202:
            gamestate.menu_state = enums.Menu.IN_GAME
        elif scene == 0x0001:
            gamestate.menu_state = enums.Menu.MAIN_MENU
        elif scene == 0x0008:
            gamestate.menu_state = enums.Menu.SLIPPI_ONLINE_CSS
            gamestate.players[1] = PlayerState()
            gamestate.players[2] = PlayerState()
            gamestate.players[3] = PlayerState()
            gamestate.players[4] = PlayerState()
        elif scene == 0x0000:
            gamestate.menu_state = enums.Menu.PRESS_START
        elif scene == 0x0402:
            gamestate.menu_state = enums.Menu.POSTGAME_SCORES
        else:
            gamestate.menu_state = enums.Menu.UNKNOWN_MENU

        # controller port statuses at CSS
        if gamestate.menu_state in [enums.Menu.CHARACTER_SELECT, enums.Menu.SLIPPI_ONLINE_CSS]:
            gamestate.players[1].controller_status = enums.ControllerStatus(np.ndarray((1,), ">B", event_bytes, 0x25)[0])
            gamestate.players[2].controller_status = enums.ControllerStatus(np.ndarray((1,), ">B", event_bytes, 0x26)[0])
            gamestate.players[3].controller_status = enums.ControllerStatus(np.ndarray((1,), ">B", event_bytes, 0x27)[0])
            gamestate.players[4].controller_status = enums.ControllerStatus(np.ndarray((1,), ">B", event_bytes, 0x28)[0])

            # CSS Cursors
            gamestate.players[1].cursor_x = np.ndarray((1,), ">f", event_bytes, 0x3)[0]
            gamestate.players[1].cursor_y = np.ndarray((1,), ">f", event_bytes, 0x7)[0]
            gamestate.players[2].cursor_x = np.ndarray((1,), ">f", event_bytes, 0xB)[0]
            gamestate.players[2].cursor_y = np.ndarray((1,), ">f", event_bytes, 0xF)[0]
            gamestate.players[3].cursor_x = np.ndarray((1,), ">f", event_bytes, 0x13)[0]
            gamestate.players[3].cursor_y = np.ndarray((1,), ">f", event_bytes, 0x17)[0]
            gamestate.players[4].cursor_x = np.ndarray((1,), ">f", event_bytes, 0x1B)[0]
            gamestate.players[4].cursor_y = np.ndarray((1,), ">f", event_bytes, 0x1F)[0]

            # Ready to fight banner
            gamestate.ready_to_start = np.ndarray((1,), ">B", event_bytes, 0x23)[0]

            # Character selected
            try:
                gamestate.players[1].character = enums.to_internal(np.ndarray((1,), ">B", event_bytes, 0x29)[0])
                gamestate.players[1].character_selected = gamestate.players[1].character
            except TypeError:
                gamestate.players[1].character = enums.Character.UNKNOWN_CHARACTER
                gamestate.players[1].character_selected = enums.Character.UNKNOWN_CHARACTER
            try:
                gamestate.players[2].character = enums.to_internal(np.ndarray((1,), ">B", event_bytes, 0x2A)[0])
                gamestate.players[2].character_selected = gamestate.players[2].character
            except TypeError:
                gamestate.players[2].character = enums.Character.UNKNOWN_CHARACTER
                gamestate.players[2].character_selected = enums.Character.UNKNOWN_CHARACTER
            try:
                gamestate.players[3].character = enums.to_internal(np.ndarray((1,), ">B", event_bytes, 0x2B)[0])
                gamestate.players[3].character_selected = gamestate.players[3].character

            except TypeError:
                gamestate.players[3].character = enums.Character.UNKNOWN_CHARACTER
                gamestate.players[3].character_selected = enums.Character.UNKNOWN_CHARACTER
            try:
                gamestate.players[4].character = enums.to_internal(np.ndarray((1,), ">B", event_bytes, 0x2C)[0])
                gamestate.players[4].character_selected = gamestate.players[4].character
            except TypeError:
                gamestate.players[4].character = enums.Character.UNKNOWN_CHARACTER
                gamestate.players[4].character_selected = enums.Character.UNKNOWN_CHARACTER

            # Coin down
            try:
                gamestate.players[1].coin_down = np.ndarray((1,), ">B", event_bytes, 0x2D)[0] == 2
            except TypeError:
                gamestate.players[1].coin_down = False
            try:
                gamestate.players[2].coin_down = np.ndarray((1,), ">B", event_bytes, 0x2E)[0] == 2
            except TypeError:
                gamestate.players[2].coin_down = False
            try:
                gamestate.players[3].coin_down = np.ndarray((1,), ">B", event_bytes, 0x2F)[0] == 2
            except TypeError:
                gamestate.players[3].coin_down = False
            try:
                gamestate.players[4].coin_down = np.ndarray((1,), ">B", event_bytes, 0x30)[0] == 2
            except TypeError:
                gamestate.players[4].coin_down = False

        if gamestate.menu_state == enums.Menu.STAGE_SELECT:
            # Stage
            try:
                gamestate.stage = enums.Stage(np.ndarray((1,), ">B", event_bytes, 0x24)[0])
            except ValueError:
                gamestate.stage = enums.Stage.NO_STAGE

            # Stage Select Cursor X, Y
            for _, player in gamestate.players.items():
                player.cursor.x = np.ndarray((1,), ">f", event_bytes, 0x31)[0]
                player.cursor.y = np.ndarray((1,), ">f", event_bytes, 0x35)[0]
                gamestate.stage_select_cursor_x = player.cursor.x
                gamestate.stage_select_cursor_y = player.cursor.y

        # Frame count
        gamestate.frame = np.ndarray((1,), ">i", event_bytes, 0x39)[0]

        # Sub-menu
        try:
            gamestate.submenu = enums.SubMenu(np.ndarray((1,), ">B", event_bytes, 0x3D)[0])
        except TypeError:
            gamestate.submenu = enums.SubMenu.UNKNOWN_SUBMENU
        except ValueError:
            gamestate.submenu = enums.SubMenu.UNKNOWN_SUBMENU

        # Selected menu
        try:
            gamestate.menu_selection = np.ndarray((1,), ">B", event_bytes, 0x3E)[0]
        except TypeError:
            gamestate.menu_selection = 0

        # Online costume chosen
        try:
            if gamestate.menu_state == enums.Menu.SLIPPI_ONLINE_CSS:
                for i in range(4):
                    gamestate.players[i+1].costume = np.ndarray((1,), ">B", event_bytes, 0x3F)[0]
        except TypeError:
            pass

        # This value is 0x05 in the nametag entry
        try:
            if gamestate.menu_state == enums.Menu.SLIPPI_ONLINE_CSS:
                nametag = np.ndarray((1,), ">B", event_bytes, 0x40)[0]
                if nametag == 0x05:
                    gamestate.submenu = enums.SubMenu.NAME_ENTRY_SUBMENU
                elif nametag == 0x00:
                    gamestate.submenu = enums.SubMenu.ONLINE_CSS
        except TypeError:
            pass

        # CPU Level
        try:
            for i in range(4):
                gamestate.players[i+1].cpu_level = np.ndarray((1,), ">B", event_bytes, 0x41 + i)[0]
        except TypeError:
            pass
        except KeyError:
            pass

        # Is Holding CPU Slider
        try:
            for i in range(4):
                gamestate.players[i+1].is_holding_cpu_slider = np.ndarray((1,), ">B", event_bytes, 0x45 + i)[0]
        except TypeError:
            pass
        except KeyError:
            pass

        # Set CPU level to 0 if we're not a CPU
        for port in gamestate.players:
            if gamestate.players[port].controller_status != enums.ControllerStatus.CONTROLLER_CPU:
                gamestate.players[port].cpu_level = 0

    def __fixframeindexing(self, gamestate):
        """ Melee's indexing of action frames is wildly inconsistent.
            Here we adjust all of the frames to be indexed at 1 (so math is easier)"""
        for _, player in gamestate.players.items():
            if player.action.value in self.zero_indices[player.character.value]:
                player.action_frame = player.action_frame + 1

    def __fixiasa(self, gamestate):
        """ The IASA flag doesn't set or reset for special attacks.
            So let's just set IASA to False for all non-A attacks.
        """
        for _, player in gamestate.players.items():
            # Luckily for us, all the A-attacks are in a contiguous place in the enums!
            #   So we don't need to call them out one by one
            if player.action.value < Action.NEUTRAL_ATTACK_1.value or player.action.value > Action.DAIR.value:
                player.iasa = False


from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn import svm
import numpy as np
from sklearn import  linear_model,metrics
from sklearn.metrics import roc_auc_score
from sklearn.metrics import precision_recall_curve
from sklearn.metrics import f1_score
from sklearn.metrics import auc as sklearn_auc
#######  keras #########
import keras,os
from keras.layers import Input, Conv1D, Conv2D, Activation, MaxPool2D, Flatten, Dense, Dropout, BatchNormalization, ZeroPadding2D
from keras.models import load_model
from keras.models import Model
from keras.constraints import max_norm
####### matplotlib ########
import matplotlib
matplotlib.use('Agg')
import matplotlib.cbook as cbook
import matplotlib.pyplot as plt
from matplotlib.pyplot import plot,savefig

globeloc=os.getcwd()

def Confusion_Matrix(true_label,pre_label):
	TP=float(list(true_label+pre_label).count(2))
	FN=float(list(true_label-pre_label).count(1))
	FP=float(list(true_label-pre_label).count(-1))
	TN=float(list(true_label+pre_label).count(0))
	try:
		acc=(TP+TN)/(TP+FN+FP+TN)
	except:
		acc=0
	try:
		pre=(TP)/(TP+FP)
	except:
		pre=0
	try:
		tpr=(TP)/(TP+FN)
	except:
		tpr=0
	try:
		tnr=(TN)/(TN+FP)
	except:
		tnr=0
	try:
		F1=(2*pre*tpr)/(pre+tpr)
	except:
		F1=0
	return TP,FN,FP,TN,acc,pre,tpr,tnr,F1

def model_check(true_label,pre_label,pre_value):
	TP,FN,FP,TN,acc,pre,tpr,tnr,F1=Confusion_Matrix(true_label,pre_label)
	fpr_list, tpr_list, _ = metrics.roc_curve(true_label,pre_value,pos_label=1)
	roc_auc=metrics.auc(fpr_list, tpr_list)
	lr_precision, lr_recall, _ = precision_recall_curve(true_label,pre_value,pos_label=1)
	PR_auc=sklearn_auc(lr_recall, lr_precision)
	return TP,FN,FP,TN,acc,pre,tpr,tnr,F1,roc_auc,PR_auc

def mini_bathc(X_train,y_train):

	indices=np.arange(len(y_train))
	np.random.shuffle(indices)
	tp_y_train=y_train[indices]
	tp_X_train=X_train[indices]
	y_label=tp_y_train[:,1]
	max_num=min([list(y_label).count(0),list(y_label).count(1)])
	pos_ind=np.argwhere(y_label==1)[:max_num]
	neg_ind=np.argwhere(y_label==0)[:max_num]
	tp_new_y=np.append(tp_y_train[pos_ind][:,0],tp_y_train[neg_ind][:,0],axis=0)
	tp_new_x=np.append(tp_X_train[pos_ind][:,0],tp_X_train[neg_ind][:,0],axis=0)
	indices=np.arange(len(tp_new_y))
	np.random.shuffle(indices)
	mini_y_train=tp_new_y[indices]
	mini_x_train=tp_new_x[indices]

	return mini_x_train,mini_y_train

def data_load(file_name,X_train,y_train,factor_group):
	f1=open(file_name,'r')
	m1=f1.readlines()
	f1.close()
	for i in range(1,len(m1)):
		p1=m1[i].strip().split('\t')
		tp=[]
		for j in factor_group:
			tp.append(float(p1[j]))
		X_train.append(np.array(tp))
		if p1[-1]=='1':
			y_train.append([0,1])
		else:
			y_train.append([1,0])
	return X_train,y_train

def socre_label(pre_score):
	pre_label=[]
	for tp in pre_score:
		if tp[0] > tp[1]:
			pre_label.append(0)
		else:
			pre_label.append(1)
	return pre_label

def data_load(file_name,X_train,y_train,factor_group):
	f1=open(file_name,'r')
	m1=f1.readlines()
	f1.close()
	for i in range(1,len(m1)):
		p1=m1[i].strip().split('\t')
		tp=[]
		for j in factor_group:
			tp.append(float(p1[j]))
		X_train.append(np.array(tp))
		y_train.append(int(p1[-1]))
	return X_train,y_train

def data_load_model(file_name,X_train,y_train,factor_group):
	f1=open(file_name,'r')
	m1=f1.readlines()
	f1.close()
	for i in range(1,len(m1)):
		p1=m1[i].strip().split('\t')
		tp=[]
		for j in factor_group:
			tp.append(float(p1[j]))
		X_train.append(np.array(tp))
		if p1[-1]=='1':
			y_train.append([0,1])
		else:
			y_train.append([1,0])
	return X_train,y_train

def plot_AUC(y_true,y_score,figname):
	########## ROC AUC  #################
	fpr, tpr, thresholds_keras = metrics.roc_curve(y_true,y_score,pos_label=1)
	auc=metrics.auc(fpr, tpr)
	print("AUC : ", auc)
	plt.figure(figsize=(6,5))
	plt.plot([0, 1], [0, 1], 'k--')
	plt.plot(fpr, tpr, label='AUC = {:.3f}'.format(auc))
	plt.xlabel('False positive rate')
	plt.ylabel('True positive rate')
	plt.title('ROC curve')
	plt.legend(loc='best')
	plt.savefig(figname+'ROC_AUC.png', dpi=300)
	plt.close('all')
	plt.clf()
	lr_precision, lr_recall, _ = precision_recall_curve(y_true,y_score,pos_label=1)
	lr_auc=sklearn_auc(lr_recall, lr_precision)
	print('PR-AUC=%.3f' %(lr_auc))
	plt.figure(figsize=(5,5))
	plt.plot(lr_recall, lr_precision,label='S3< val (AUC = {:.3f})'.format(lr_auc))
	plt.xlabel('Recall')
	plt.ylabel('Precision')
	plt.legend(loc='best')
	plt.savefig(figname+'PR.png', dpi=300)
	plt.close('all')
	plt.clf()

file1='%s/train_data/5_fold_1.txt'%globeloc
file2='%s/train_data/5_fold_2.txt'%globeloc
file3='%s/train_data/5_fold_3.txt'%globeloc
file4='%s/train_data/5_fold_4.txt'%globeloc
file5='%s/train_data/5_fold_5.txt'%globeloc
file6='%s/train_data/vaildation_data.txt'%globeloc

all_factor=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,16,17,18,19,20,21,22,23,24,25,26,27,28]

data_ind=all_factor

X_train=[]
y_train=[]

X_train,y_train=data_load(file1,X_train,y_train,data_ind)
X_train,y_train=data_load(file2,X_train,y_train,data_ind)
X_train,y_train=data_load(file3,X_train,y_train,data_ind)
X_train,y_train=data_load(file4,X_train,y_train,data_ind)
X_train,y_train=data_load(file5,X_train,y_train,data_ind)

X_val=[]
y_val=[]
X_val,y_val=data_load(file6,X_val,y_val,data_ind)

X_train=np.array(X_train)
y_train=np.array(y_train)
X_val=np.array(X_val)
y_val=np.array(y_val)

clf1 = LogisticRegression(random_state=0).fit(X_train, y_train)
clf2 = RandomForestClassifier(n_estimators=10).fit(X_train, y_train)
clf3 = svm.SVC(probability=True).fit(X_train, y_train)

y_predict1=clf1.predict(X_val)
y_predict_value1=clf1.predict_proba(X_val)[:,1]

y_predict2=clf2.predict(X_val)
y_predict_value2=clf2.predict_proba(X_val)[:,1]

y_predict3=clf3.predict(X_val)
y_predict_value3=clf3.predict_proba(X_val)[:,1]

TP,FN,FP,TN,acc,pre,tpr,tnr,F1,roc_auc,PR_auc	=model_check(y_val,y_predict1,y_predict_value1)

figname='%s/final_model_logit'%globeloc
plot_AUC(y_val,y_predict_value1,figname)

TP,FN,FP,TN,acc,pre,tpr,tnr,F1,roc_auc,PR_auc	=model_check(y_val,y_predict2,y_predict_value2)

figname='%s/final_model_RF'%globeloc
plot_AUC(y_val,y_predict_value2,figname)

TP,FN,FP,TN,acc,pre,tpr,tnr,F1,roc_auc,PR_auc	=model_check(y_val,y_predict3,y_predict_value3)

figname='%s/final_model_SVM'%globeloc
plot_AUC(y_val,y_predict_value3,figname)

X_train=[]
y_train=[]

X_train,y_train=data_load_model(file1,X_train,y_train,data_ind)
X_train,y_train=data_load_model(file2,X_train,y_train,data_ind)
X_train,y_train=data_load_model(file3,X_train,y_train,data_ind)
X_train,y_train=data_load_model(file4,X_train,y_train,data_ind)
X_train,y_train=data_load_model(file5,X_train,y_train,data_ind)

X_val=[]
y_val=[]
X_val,y_val=data_load_model(file6,X_val,y_val,data_ind)

X_train=np.array(X_train)
y_train=np.array(y_train)
X_val=np.array(X_val)
y_val=np.array(y_val)

sample_weights_c=[]
class_weights_c={}
class_number_c=[0,0]
for i in range(0,len(y_train)):
	if y_train[i][1] == 1:
		class_number_c[1]=class_number_c[1]+1
	if y_train[i][1] == 0:
		class_number_c[0]=class_number_c[0]+1

class_bin_c=[1/float(class_number_c[0]),1/float(class_number_c[1])]
class_weights_c['0']=class_bin_c[0]/sum(class_bin_c)
class_weights_c['1']=class_bin_c[1]/sum(class_bin_c)

for i in range(0,len(y_train)):
	if y_train[i][1] ==1:
		sample_weights_c.append(class_weights_c['1'])
	else:
		sample_weights_c.append(class_weights_c['0'])

sample_weights_c=np.array(sample_weights_c)

batch_size=8
epoch=256

## model ##
input_all = Input(shape=(len(X_train[0])))
Dense1 = Dense(128,kernel_regularizer=keras.regularizers.l1_l2(0.0001, 0.0001),activation='hard_sigmoid')(input_all)
Dropout1 = Dropout(0.25)(Dense1)
Batch1 = BatchNormalization()(Dropout1)
Dense2 = Dense(64,kernel_regularizer=keras.regularizers.l1_l2(0.0001, 0.0001),activation='hard_sigmoid')(Batch1)
Dropout2 = Dropout(0.25)(Dense2)
Batch2 = BatchNormalization()(Dropout2)
output = Dense(2, activation='softmax')(Batch2)
model_class = Model(inputs=input_all, outputs=output)

adam=keras.optimizers.Adam(learning_rate=0.0001, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.001)
model_class.compile(loss='binary_crossentropy', metrics=['accuracy'], optimizer=adam)
model_class.fit(X_train, y_train, sample_weight=np.array(sample_weights_c),batch_size=batch_size, epochs=epoch, validation_data=(X_val, y_val),verbose=0)

mp = "%s/T2D_final_model.h5"%globeloc
model_class.save(mp)

pre_score=model_class.predict(X_val)
pre_label=socre_label(pre_score)
y_val_label=np.array(socre_label(y_val))
TP,FN,FP,TN,acc,pre,tpr,tnr,F1,roc_auc,PR_auc=model_check(y_val_label,pre_label,pre_score[:,1])

figname='%s/final_model_model'%globeloc
plot_AUC(y_val_label,pre_score[:,1],figname)